Project import
diff --git a/toybox/.config b/toybox/.config
new file mode 100644
index 0000000..ce30a8e
--- /dev/null
+++ b/toybox/.config
@@ -0,0 +1,348 @@
+#
+# Manually-generated.
+# ToyBox version: KCONFIG_VERSION
+#
+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_UTMPX is not set
+
+#
+# Posix commands
+#
+CONFIG_BASENAME=y
+CONFIG_CAL=y
+CONFIG_CAT=y
+CONFIG_CAT_V=y
+# CONFIG_CATV is not set
+CONFIG_CHGRP=y
+CONFIG_CHOWN=y
+CONFIG_CHMOD=y
+CONFIG_CKSUM=y
+CONFIG_CMP=y
+CONFIG_COMM=y
+CONFIG_CP=y
+CONFIG_CP_MORE=y
+CONFIG_CP_PRESERVE=y
+CONFIG_MV=y
+CONFIG_MV_MORE=y
+CONFIG_INSTALL=y
+CONFIG_CPIO=y
+CONFIG_CUT=y
+CONFIG_DATE=y
+CONFIG_DF=y
+CONFIG_DIRNAME=y
+CONFIG_DU=y
+CONFIG_ECHO=y
+CONFIG_ENV=y
+CONFIG_EXPAND=y
+CONFIG_FALSE=y
+CONFIG_FILE=y
+CONFIG_FIND=y
+CONFIG_GREP=y
+CONFIG_EGREP=y
+CONFIG_FGREP=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_KILL=y
+# CONFIG_KILLALL5 is not set
+# CONFIG_LINK is not set
+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_PWD=y
+CONFIG_RENICE=y
+CONFIG_RM=y
+CONFIG_RMDIR=y
+CONFIG_SED=y
+CONFIG_SLEEP=y
+CONFIG_SLEEP_FLOAT=y
+CONFIG_SORT=y
+CONFIG_SORT_BIG=y
+CONFIG_SORT_FLOAT=y
+CONFIG_SPLIT=y
+CONFIG_STRINGS=y
+CONFIG_TAIL=y
+CONFIG_TAIL_SEEK=y
+CONFIG_TASKSET=y
+CONFIG_TEE=y
+CONFIG_TIME=y
+CONFIG_TOUCH=y
+CONFIG_TRUE=y
+CONFIG_TTY=y
+CONFIG_ULIMIT=y
+CONFIG_UNAME=y
+CONFIG_UNIQ=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
+# CONFIG_XARGS_PEDANTIC is not set
+
+#
+# pending (see toys/pending/README)
+#
+# CONFIG_ARP is not set
+# CONFIG_ARPING is not set
+# CONFIG_BOOTCHARTD is not set
+# CONFIG_BRCTL is not set
+# CONFIG_COMPRESS is not set
+# CONFIG_GZIP is not set
+# CONFIG_GZIP_D is not set
+# CONFIG_DECOMPRESS is not set
+# CONFIG_ZCAT is not set
+# CONFIG_GUNZIP is not set
+# CONFIG_CROND is not set
+# CONFIG_CRONTAB is not set
+CONFIG_DD=y
+# CONFIG_DHCP6 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_DUMPLEASES is not set
+CONFIG_EXPR=y
+# CONFIG_FDISK is not set
+# CONFIG_FOLD is not set
+# CONFIG_FSCK is not set
+# CONFIG_FTPGET is not set
+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_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_KLOGD is not set
+# CONFIG_KLOGD_SOURCE_RING_BUFFER is not set
+# CONFIG_LAST is not set
+# CONFIG_LOGGER is not set
+CONFIG_LSOF=y
+# CONFIG_MDEV is not set
+# CONFIG_MDEV_CONF is not set
+# CONFIG_MKE2FS is not set
+# CONFIG_MKE2FS_JOURNAL is not set
+# CONFIG_MKE2FS_GEN is not set
+# CONFIG_MKE2FS_LABEL is not set
+# CONFIG_MKE2FS_EXTENDED is not set
+# CONFIG_MODPROBE is not set
+CONFIG_MORE=y
+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_ROUTE is not set
+# 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_TELNETD is not set
+# CONFIG_TEST is not set
+# 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_WGET is not set
+# CONFIG_XZCAT is not set
+
+#
+# Other commands
+#
+CONFIG_ACPI=y
+CONFIG_BASE64=y
+CONFIG_BLKID=y
+# CONFIG_FSTYPE is not set
+CONFIG_BLOCKDEV=y
+CONFIG_BUNZIP2=y
+CONFIG_BZCAT=y
+CONFIG_CHCON=y
+CONFIG_CHROOT=y
+# CONFIG_CHVT is not set
+CONFIG_CLEAR=y
+# CONFIG_COUNT is not set
+CONFIG_DOS2UNIX=y
+CONFIG_UNIX2DOS=y
+# CONFIG_EJECT is not set
+# CONFIG_FACTOR is not set
+CONFIG_FALLOCATE=y
+CONFIG_FLOCK=y
+CONFIG_FREE=y
+CONFIG_FREERAMDISK=y
+CONFIG_FSFREEZE=y
+# CONFIG_FSYNC is not set
+CONFIG_HELP=y
+CONFIG_HELP_EXTRAS=y
+# CONFIG_HOSTID is not set
+CONFIG_IFCONFIG=y
+CONFIG_INOTIFYD=y
+CONFIG_INSMOD=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_TEXT=y
+CONFIG_LSUSB=y
+CONFIG_MAKEDEVS=y
+# CONFIG_MIX is not set
+# CONFIG_MKPASSWD is not set
+CONFIG_MKSWAP=y
+CONFIG_MODINFO=y
+CONFIG_MOUNTPOINT=y
+CONFIG_NBD_CLIENT=y
+CONFIG_NETCAT=y
+CONFIG_NETCAT_LISTEN=y
+# CONFIG_UNSHARE is not set
+# CONFIG_NSENTER is not set
+# CONFIG_ONEIT is not set
+CONFIG_PARTPROBE=y
+CONFIG_PIVOT_ROOT=y
+CONFIG_PMAP=y
+CONFIG_PRINTENV=y
+CONFIG_PWDX=y
+# CONFIG_READAHEAD is not set
+CONFIG_READLINK=y
+CONFIG_REALPATH=y
+# CONFIG_REBOOT is not set
+CONFIG_REV=y
+CONFIG_RFKILL=y
+CONFIG_RMMOD=y
+CONFIG_SETSID=y
+# CONFIG_SHRED is not set
+CONFIG_STAT=y
+CONFIG_SWAPOFF=y
+CONFIG_SWAPON=y
+# CONFIG_SWITCH_ROOT is not set
+CONFIG_SYSCTL=y
+CONFIG_TAC=y
+CONFIG_TASKSET=y
+CONFIG_TIMEOUT=y
+CONFIG_TRUNCATE=y
+CONFIG_UPTIME=y
+CONFIG_USLEEP=y
+CONFIG_VCONFIG=y
+CONFIG_VMSTAT=y
+# CONFIG_W is not set
+CONFIG_WHICH=y
+CONFIG_XXD=y
+CONFIG_YES=y
+
+#
+# Linux Standard Base commands
+#
+CONFIG_DMESG=y
+CONFIG_HOSTNAME=y
+CONFIG_KILLALL=y
+CONFIG_MD5SUM=y
+CONFIG_SHA1SUM=y
+CONFIG_SHA224SUM=y
+CONFIG_SHA256SUM=y
+CONFIG_SHA384SUM=y
+CONFIG_SHA512SUM=y
+CONFIG_MKNOD=y
+CONFIG_MKTEMP=y
+CONFIG_MOUNT=y
+# CONFIG_PASSWD is not set
+CONFIG_PIDOF=y
+CONFIG_SEQ=y
+# CONFIG_SU is not set
+CONFIG_SYNC=y
+CONFIG_UMOUNT=y
+
+#
+# Example commands
+#
+# CONFIG_HELLO is not set
+# CONFIG_SKELETON is not set
+# CONFIG_SKELETON_ALIAS is not set
+# CONFIG_TEST_HUMAN_READABLE is not set
+# CONFIG_TEST_MANY_OPTIONS is not set
+# CONFIG_TEST_SCANKEY is not set
+
+#
+# Android
+#
+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
+
+#
+# 
+#
+
+#
+# Toybox global settings
+#
+CONFIG_TOYBOX=y
+CONFIG_TOYBOX_SUID=y
+# CONFIG_TOYBOX_LSM_NONE is not set
+CONFIG_TOYBOX_SELINUX=y
+# CONFIG_TOYBOX_SMACK is not set
+CONFIG_TOYBOX_FLOAT=y
+CONFIG_TOYBOX_HELP=y
+CONFIG_TOYBOX_HELP_DASHDASH=y
+CONFIG_TOYBOX_I18N=y
+CONFIG_TOYBOX_LIBCRYPTO=y
+# CONFIG_TOYBOX_FREE is not set
+CONFIG_TOYBOX_NORECURSE=y
+# CONFIG_TOYBOX_DEBUG is not set
+CONFIG_TOYBOX_UID_SYS=100
+CONFIG_TOYBOX_UID_USR=500
+# CONFIG_TOYBOX_MUSL_NOMMU_IS_BROKEN is not set
diff --git a/toybox/Android.mk b/toybox/Android.mk
new file mode 100644
index 0000000..7738dc4
--- /dev/null
+++ b/toybox/Android.mk
@@ -0,0 +1,386 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+#
+# To update:
+#
+
+#  git remote add toybox https://github.com/landley/toybox.git
+#  git fetch toybox
+#  git merge toybox/master
+#  mm -j32
+#  # (Make any necessary Android.mk changes and test the new toybox.)
+#  repo upload .
+#  git push aosp HEAD:refs/for/master  # Push to gerrit for review.
+#  git push aosp HEAD:master  # Push directly, avoiding gerrit.
+#
+#  # Now commit any necessary Android.mk changes like normal:
+#  repo start post-sync .
+#  git commit -a
+
+
+#
+# To add a toy:
+#
+
+#  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.
+#  # If you want this toy to have a symbolic link in /system/bin, add the toy to ALL_TOOLS.
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    lib/args.c \
+    lib/dirtree.c \
+    lib/getmountlist.c \
+    lib/help.c \
+    lib/interestingtimes.c \
+    lib/lib.c \
+    lib/linestack.c \
+    lib/llist.c \
+    lib/net.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/md5sum.c \
+    toys/lsb/mknod.c \
+    toys/lsb/mktemp.c \
+    toys/lsb/mount.c \
+    toys/lsb/pidof.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/other/acpi.c \
+    toys/other/base64.c \
+    toys/other/blkid.c \
+    toys/other/blockdev.c \
+    toys/other/bzcat.c \
+    toys/other/chcon.c \
+    toys/other/chroot.c \
+    toys/other/clear.c \
+    toys/other/dos2unix.c \
+    toys/other/fallocate.c \
+    toys/other/flock.c \
+    toys/other/free.c \
+    toys/other/freeramdisk.c \
+    toys/other/fsfreeze.c \
+    toys/other/help.c \
+    toys/other/hwclock.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/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/partprobe.c \
+    toys/other/pivot_root.c \
+    toys/other/pmap.c \
+    toys/other/printenv.c \
+    toys/other/pwdx.c \
+    toys/other/readlink.c \
+    toys/other/realpath.c \
+    toys/other/rev.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/sysctl.c \
+    toys/other/tac.c \
+    toys/other/taskset.c \
+    toys/other/timeout.c \
+    toys/other/truncate.c \
+    toys/other/uptime.c \
+    toys/other/usleep.c \
+    toys/other/vconfig.c \
+    toys/other/vmstat.c \
+    toys/other/which.c \
+    toys/other/xxd.c \
+    toys/other/yes.c \
+    toys/pending/dd.c \
+    toys/pending/expr.c \
+    toys/pending/getfattr.c \
+    toys/pending/lsof.c \
+    toys/pending/more.c \
+    toys/pending/tar.c \
+    toys/pending/tr.c \
+    toys/pending/traceroute.c \
+    toys/posix/basename.c \
+    toys/posix/cal.c \
+    toys/posix/cat.c \
+    toys/posix/chgrp.c \
+    toys/posix/chmod.c \
+    toys/posix/cksum.c \
+    toys/posix/cmp.c \
+    toys/posix/comm.c \
+    toys/posix/cp.c \
+    toys/posix/cpio.c \
+    toys/posix/cut.c \
+    toys/posix/date.c \
+    toys/posix/df.c \
+    toys/posix/dirname.c \
+    toys/posix/du.c \
+    toys/posix/echo.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/id.c \
+    toys/posix/kill.c \
+    toys/posix/ln.c \
+    toys/posix/ls.c \
+    toys/posix/mkdir.c \
+    toys/posix/mkfifo.c \
+    toys/posix/nice.c \
+    toys/posix/nl.c \
+    toys/posix/nohup.c \
+    toys/posix/od.c \
+    toys/posix/paste.c \
+    toys/posix/patch.c \
+    toys/posix/printf.c \
+    toys/posix/ps.c \
+    toys/posix/pwd.c \
+    toys/posix/renice.c \
+    toys/posix/rm.c \
+    toys/posix/rmdir.c \
+    toys/posix/sed.c \
+    toys/posix/sleep.c \
+    toys/posix/sort.c \
+    toys/posix/split.c \
+    toys/posix/strings.c \
+    toys/posix/tail.c \
+    toys/posix/tee.c \
+    toys/posix/time.c \
+    toys/posix/touch.c \
+    toys/posix/true.c \
+    toys/posix/tty.c \
+    toys/posix/ulimit.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)"'
+
+LOCAL_CLANG := true
+
+LOCAL_SHARED_LIBRARIES := libcutils libselinux libcrypto
+
+# This doesn't actually prevent us from dragging in libc++ at runtime
+# because libnetd_client.so is C++.
+LOCAL_CXX_STL := none
+
+LOCAL_MODULE := toybox
+
+# dupes: dd
+# useless?: freeramdisk fsfreeze install makedevs mkfifo nbd-client
+#           partprobe pivot_root pwdx rev rfkill vconfig
+# prefer BSD netcat instead?: nc netcat
+# prefer efs2progs instead?: blkid chattr lsattr
+
+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 \
+    file \
+    find \
+    flock \
+    free \
+    getenforce \
+    getprop \
+    groups \
+    head \
+    hostname \
+    hwclock \
+    id \
+    ifconfig \
+    inotifyd \
+    insmod \
+    ionice \
+    iorenice \
+    kill \
+    killall \
+    load_policy \
+    ln \
+    log \
+    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 \
+    ps \
+    pwd \
+    readlink \
+    realpath \
+    renice \
+    restorecon \
+    rm \
+    rmdir \
+    rmmod \
+    runcon \
+    sed \
+    sendevent \
+    seq \
+    setenforce \
+    setprop \
+    setsid \
+    sha1sum \
+    sha224sum \
+    sha256sum \
+    sha384sum \
+    sha512sum \
+    sleep \
+    sort \
+    split \
+    start \
+    stat \
+    stop \
+    strings \
+    swapoff \
+    swapon \
+    sync \
+    sysctl \
+    tac \
+    tail \
+    tar \
+    taskset \
+    tee \
+    time \
+    timeout \
+    top \
+    touch \
+    tr \
+    true \
+    truncate \
+    tty \
+    ulimit \
+    umount \
+    uname \
+    uniq \
+    unix2dos \
+    uptime \
+    usleep \
+    vmstat \
+    wc \
+    which \
+    whoami \
+    xargs \
+    xxd \
+    yes \
+
+# Install the symlinks.
+LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(ALL_TOOLS),ln -sf toybox $(TARGET_OUT)/bin/$(t);)
+
+include $(BUILD_EXECUTABLE)
diff --git a/toybox/Config.in b/toybox/Config.in
new file mode 100644
index 0000000..76b2ef1
--- /dev/null
+++ b/toybox/Config.in
@@ -0,0 +1,165 @@
+mainmenu "Toybox Configuration"
+
+
+source generated/Config.probed
+source generated/Config.in
+
+comment ""
+
+menu "Toybox global settings"
+
+# This entry controls the multiplexer, disabled for single command builds
+config TOYBOX
+	bool
+	default y
+	help
+	  usage: toybox [--long | --version | [command] [arguments...]]
+
+	  With no arguments, shows available commands. First argument is
+	  name of a command to run, followed by any arguments to that command.
+
+	  --long	Show path to each command
+	  --version	Show toybox version
+
+	  To install command symlinks, try:
+	    for i in $(/bin/toybox --long); do ln -s /bin/toybox $i; done
+
+config TOYBOX_SUID
+	bool "SUID support"
+	default y
+	help
+	  Support for the Set User ID bit, to install toybox suid root and drop
+	  permissions for commands which do not require root access. To use
+	  this change ownership of the file to the root user and set the suid
+	  bit in the file permissions:
+
+	  chown root:root toybox; chmod +s toybox
+
+choice
+	prompt "Security Blanket"
+	default TOYBOX_LSM_NONE
+	help
+	  Select a Linux Security Module to complicate your system
+	  until you can't find holes in it.
+
+config TOYBOX_LSM_NONE
+	bool "None"
+	help
+          Don't try to achieve "watertight" by plugging the holes in a
+          collander, instead use conventional unix security (and possibly
+          Linux Containers) for a simple straightforward system.
+	  
+config TOYBOX_SELINUX
+	bool "SELinux support"
+	help
+	  Include SELinux options in commands such as ls, and add
+	  SELinux-specific commands such as chcon to the Android menu.
+
+config TOYBOX_SMACK
+	bool "SMACK support"
+	help
+	  Include SMACK options in commands like ls for systems like Tizen.
+
+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
+	help
+	  Include floating point support infrastructure and commands that
+	  require it.
+
+config TOYBOX_HELP
+	bool "Help messages"
+	default y
+	help
+	  Include help text for each command.
+
+config TOYBOX_HELP_DASHDASH
+	bool "--help"
+	default y
+	depends on TOYBOX_HELP
+	help
+	  Support --help argument in all commands, even ones with a NULL
+	  optstring. Produces the same output as "help command".
+
+config TOYBOX_I18N
+	bool "Internationalization support"
+	default y
+	help
+	  Support for UTF-8 character sets, and some locale support.
+
+config TOYBOX_FREE
+	bool "Free memory unnecessarily"
+	default n
+	help
+	  When a program exits, the operating system will clean up after it
+	  (free memory, close files, etc). To save size, toybox usually relies
+	  on this behavior. If you're running toybox under a debugger or
+	  without a real OS (ala newlib+libgloss), enable this to make toybox
+	  clean up after itself.
+
+config TOYBOX_NORECURSE
+	bool "Disable recursive execution"
+	default n
+	help
+	  When one toybox command calls another, usually it just calls the new
+	  command's main() function rather than searching the $PATH and calling
+	  exec on another file (which is much slower).
+
+	  This disables that optimization, so toybox will run external commands
+          even when it has a built-in version of that command. This requires
+          toybox symlinks to be installed in the $PATH, or re-invoking the
+          "toybox" multiplexer command by name.
+
+config TOYBOX_DEBUG
+	bool "Debugging tests"
+	default n
+	help
+	  Enable extra checks for debugging purposes. All of them catch
+	  things that can only go wrong at development time, not runtime.
+
+config TOYBOX_UID_SYS
+	int "First system UID"
+	default 100
+	help
+	  When commands like useradd/groupadd allocate system IDs, start here.
+
+config TOYBOX_UID_USR
+	int "First user UID"
+	default 500
+	help
+	  When commands like useradd/groupadd allocate user IDs, start here.
+
+config TOYBOX_MUSL_NOMMU_IS_BROKEN
+	bool "Workaround for musl-libc breakage on nommu systems."
+	default n
+	help
+	  When using musl-libc on a nommu system, you'll need to say "y" here.
+
+	  Although uclibc lets you detect support for things like fork() and
+	  daemon() at compile time, musl intentionally includes broken versions
+	  that always return -ENOSYS on nommu systems, and goes out of its way
+	  to prevent any cross-compile compatible compile-time probes for a
+	  nommu system.
+
+	  Musl does this despite the fact that a nommu system can't even run
+	  standard ELF binaries, and requires specially packaged executables.
+	  (You can't even check a #define to see that you're building against
+	  musl, due to its maintainer's policy that musl never has bugs that
+	  require workarounds.)
+
+	  So our only choice is to manually provide a musl nommu bug workaround
+	  you can manually select to enable (larger, slower) nommu support with
+	  musl.
+
+	  You don't need this for uClibc, we have a compile time probe that
+	  autodetects nommu support there.
+
+endmenu
diff --git a/toybox/LICENSE b/toybox/LICENSE
new file mode 100644
index 0000000..861a0a8
--- /dev/null
+++ b/toybox/LICENSE
@@ -0,0 +1,16 @@
+Copyright (C) 2006, 2013 by Rob Landley <rob@landley.net>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+(Note: some build infrastructure in the kconfig directory is still GPLv2,
+cleaning that out is a TODO item, but it doesn't affect the resulting
+binary.)
diff --git a/toybox/MODULE_LICENSE_BSD b/toybox/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toybox/MODULE_LICENSE_BSD
diff --git a/toybox/Makefile b/toybox/Makefile
new file mode 100644
index 0000000..711d624
--- /dev/null
+++ b/toybox/Makefile
@@ -0,0 +1,84 @@
+# Makefile for toybox.
+# Copyright 2006 Rob Landley <rob@landley.net>
+
+# If people set these on the make command line, use 'em
+# Note that CC defaults to "cc" so the one in configure doesn't get
+# used when scripts/make.sh and care called through "make".
+
+HOSTCC?=cc
+
+export CROSS_COMPILE CFLAGS OPTIMIZE LDOPTIMIZE CC HOSTCC V
+
+all: toybox
+
+KCONFIG_CONFIG ?= .config
+
+toybox_stuff: $(KCONFIG_CONFIG) *.[ch] lib/*.[ch] toys/*.h toys/*/*.c scripts/*.sh
+
+toybox generated/unstripped/toybox: toybox_stuff
+	scripts/make.sh
+
+.PHONY: clean distclean baseline bloatcheck install install_flat \
+	uinstall uninstall_flat tests help toybox_stuff change \
+	list list_working list_pending
+
+include kconfig/Makefile
+-include .singlemake
+
+$(KCONFIG_CONFIG): $(KCONFIG_TOP)
+$(KCONFIG_TOP): generated/Config.in
+generated/Config.in: toys/*/*.c scripts/genconfig.sh
+	scripts/genconfig.sh
+
+# Development targets
+baseline: generated/unstripped/toybox
+	@cp generated/unstripped/toybox generated/unstripped/toybox_old
+
+bloatcheck: toybox_old generated/unstripped/toybox
+	@scripts/bloatcheck generated/unstripped/toybox_old generated/unstripped/toybox
+
+install_flat:
+	scripts/install.sh --symlink --force
+
+install:
+	scripts/install.sh --long --symlink --force
+
+uninstall_flat:
+	scripts/install.sh --uninstall
+
+uninstall:
+	scripts/install.sh --long --uninstall
+
+change:
+	scripts/change.sh
+
+clean::
+	rm -rf toybox generated change .singleconfig*
+
+distclean: clean
+	rm -f toybox_old .config* .singlemake
+
+tests:
+	scripts/test.sh
+
+help::
+	@echo  '  toybox          - Build toybox.'
+	@echo  '  COMMANDNAME     - Build individual toybox command as a standalone binary.'
+	@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  '  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.'
+	@echo  "  distclean       - Delete everything that isn't shipped."
+	@echo  '  install_flat    - Install toybox into $$PREFIX directory.'
+	@echo  '  install         - Install toybox into subdirectories of $$PREFIX.'
+	@echo  '  uninstall_flat  - Remove toybox from $$PREFIX directory.'
+	@echo  '  uninstall       - Remove toybox from subdirectories of $$PREFIX.'
+	@echo  ''
+	@echo  'example: CFLAGS="--static" CROSS_COMPILE=armv5l- make defconfig toybox install'
+	@echo  ''
diff --git a/toybox/NOTICE b/toybox/NOTICE
new file mode 100644
index 0000000..861a0a8
--- /dev/null
+++ b/toybox/NOTICE
@@ -0,0 +1,16 @@
+Copyright (C) 2006, 2013 by Rob Landley <rob@landley.net>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+(Note: some build infrastructure in the kconfig directory is still GPLv2,
+cleaning that out is a TODO item, but it doesn't affect the resulting
+binary.)
diff --git a/toybox/README b/toybox/README
new file mode 100644
index 0000000..5823309
--- /dev/null
+++ b/toybox/README
@@ -0,0 +1,178 @@
+Toybox: all-in-one Linux command line.
+
+--- Getting started
+
+You can download static binaries for various targets from:
+
+  http://landley.net/toybox/bin
+
+The special name "." indicates the current directory (just like ".." means
+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/toybox/bin/toybox-x86_64
+  chmod +x toybox-x86_64
+  ./toybox-x86_64 echo hello world
+
+--- Building toybox
+
+Type "make help" for build instructions.
+
+Toybox uses the "make menuconfig; make; make install" idiom same as
+the Linux kernel. Usually you want something like:
+
+  make defconfig
+  make
+  make install
+
+Or maybe:
+
+  LDFLAGS="--static" CROSS_COMPILE=armv5l- make defconfig toybox
+  PREFIX=/path/to/root/filesystem/bin make install_flat
+
+The file "configure" defines default values for many environment
+variables that control the toybox build; if you set a value for any of
+these, your value is used instead of the default in that file.
+
+The CROSS_COMPILE argument above is optional, the default builds a version of
+toybox to run on the current machine. Cross compiling requires an appropriately
+prefixed cross compiler toolchain, several example toolchains are available at:
+
+  http;//landley.net/aboriginal/bin
+
+For the "CROSS_COMPILE=armv5l-" example above, download
+cross-compiler-armv5l.tar.bz2, extract it, and add its "bin" subdirectory to
+your $PATH. (And yes, the trailing - is significant, because the prefix
+includes a dash.)
+
+For more about cross compiling, see:
+
+  http://landley.net/writing/docs/cross-compiling.html
+  http://landley.net/aboriginal/architectures.html
+
+For a more thorough description of the toybox build process, see
+http://landley.net/toybox/code.html#building
+
+--- Using toybox
+
+The toybox build produces a multicall binary, a "swiss-army-knife" program
+that acts differently depending on the name it was called by (cp, mv, cat...).
+Installing toybox adds symlinks for each command name to the $PATH.
+
+The special "toybox" command treats its first argument as the command to run.
+With no arguments, it lists available commands. This allows you to use toybox
+without installing it. This is the only command that can have an arbitrary
+suffix (hence "toybox-armv5l").
+
+The "help" command provides information about each command (ala "help cat").
+
+--- Configuring toybox
+
+It works like the Linux kernel: allnoconfig, defconfig, and menuconfig edit
+a ".config" file that selects which features to include in the resulting
+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.
+
+--- Creating a Toybox-based Linux system
+
+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,
+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. (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
+can run even if they're the only file in the filesystem. Otherwise,
+the "dynamically" linked programs require the library files to be present on
+the target system ("man ldd" and "man ld.so" for details).
+
+An example toybox-based system is Aboriginal Linux:
+
+  http://landley.net/aboriginal/about.html
+
+That's designed to run under qemu, emulating several different hardware
+architectures (x86, x86-64, arm, mips, sparc, powerpc, sh4). Each toybox
+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. (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?" talk at the Embedded Linux Conference in 2013
+
+    video: http://youtu.be/SGmtP5Lg_t0
+    outline: http://landley.net/talks/celf-2013.txt
+    linked from http://landley.net/toybox/ in nav bar on left as "Why is it?"
+    - march 21, 2013 entry has section links.
+
+2) "Why Public Domain?" The rise and fall of copyleft, Ohio LinuxFest 2013
+
+    audio: https://archive.org/download/OhioLinuxfest2013/24-Rob_Landley-The_Rise_and_Fall_of_Copyleft.mp3
+    outline: http://landley.net/talks/ohio-2013.txt
+
+3) Why did I do Aboriginal Linux (which led me here)
+
+    260 slide presentation:
+    https://speakerdeck.com/landley/developing-for-non-x86-targets-using-qemu
+
+    How and why to make android self-hosting:
+      http://landley.net/aboriginal/about.html#selfhost
+
+4) What's new with toybox (ELC 2015 status update):
+
+    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?)
diff --git a/toybox/configure b/toybox/configure
new file mode 100644
index 0000000..7b10f6e
--- /dev/null
+++ b/toybox/configure
@@ -0,0 +1,25 @@
+# Toybox configuration file.
+
+# This sets environment variables used by scripts/make.sh
+
+# A synonym.
+[ -z "$CROSS_COMPILE" ] && CROSS_COMPILE="$CROSS"
+
+# CFLAGS and OPTIMIZE are different so you can add extra CFLAGS without
+# disabling default optimizations
+[ -z "$CFLAGS" ] && CFLAGS="-Wall -Wundef -Wno-char-subscripts"
+# Required for our expected ABI. we're 8-bit clean thus "char" must be unsigned.
+CFLAGS="$CFLAGS -funsigned-char"
+[ -z "$OPTIMIZE" ] && OPTIMIZE="-Os -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-strict-aliasing"
+
+# We accept LDFLAGS, but by default don't have anything in it
+[ -z "$LDOPTIMIZE" ] && LDOPTIMIZE="-Wl,--gc-sections"
+
+# The makefile provides defaults for these, so this only gets used if
+# you call scripts/make.sh and friends directly.
+
+[ -z "$CC" ] && CC=cc
+
+# If HOSTCC needs CFLAGS or LDFLAGS, just add them to the variable
+# ala HOSTCC="blah-cc --static"
+[ -z "$HOSTCC" ] && HOSTCC=cc
diff --git a/toybox/generated/config.h b/toybox/generated/config.h
new file mode 100644
index 0000000..8669a30
--- /dev/null
+++ b/toybox/generated/config.h
@@ -0,0 +1,622 @@
+#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_UTMPX 0
+#define USE_TOYBOX_UTMPX(...)
+#define CFG_BASENAME 1
+#define USE_BASENAME(...) __VA_ARGS__
+#define CFG_CAL 1
+#define USE_CAL(...) __VA_ARGS__
+#define CFG_CAT 1
+#define USE_CAT(...) __VA_ARGS__
+#define CFG_CAT_V 1
+#define USE_CAT_V(...) __VA_ARGS__
+#define CFG_CATV 0
+#define USE_CATV(...)
+#define CFG_CHGRP 1
+#define USE_CHGRP(...) __VA_ARGS__
+#define CFG_CHOWN 1
+#define USE_CHOWN(...) __VA_ARGS__
+#define CFG_CHMOD 1
+#define USE_CHMOD(...) __VA_ARGS__
+#define CFG_CKSUM 1
+#define USE_CKSUM(...) __VA_ARGS__
+#define CFG_CMP 1
+#define USE_CMP(...) __VA_ARGS__
+#define CFG_COMM 1
+#define USE_COMM(...) __VA_ARGS__
+#define CFG_CP 1
+#define USE_CP(...) __VA_ARGS__
+#define CFG_CP_MORE 1
+#define USE_CP_MORE(...) __VA_ARGS__
+#define CFG_CP_PRESERVE 1
+#define USE_CP_PRESERVE(...) __VA_ARGS__
+#define CFG_MV 1
+#define USE_MV(...) __VA_ARGS__
+#define CFG_MV_MORE 1
+#define USE_MV_MORE(...) __VA_ARGS__
+#define CFG_INSTALL 1
+#define USE_INSTALL(...) __VA_ARGS__
+#define CFG_CPIO 1
+#define USE_CPIO(...) __VA_ARGS__
+#define CFG_CUT 1
+#define USE_CUT(...) __VA_ARGS__
+#define CFG_DATE 1
+#define USE_DATE(...) __VA_ARGS__
+#define CFG_DF 1
+#define USE_DF(...) __VA_ARGS__
+#define CFG_DIRNAME 1
+#define USE_DIRNAME(...) __VA_ARGS__
+#define CFG_DU 1
+#define USE_DU(...) __VA_ARGS__
+#define CFG_ECHO 1
+#define USE_ECHO(...) __VA_ARGS__
+#define CFG_ENV 1
+#define USE_ENV(...) __VA_ARGS__
+#define CFG_EXPAND 1
+#define USE_EXPAND(...) __VA_ARGS__
+#define CFG_FALSE 1
+#define USE_FALSE(...) __VA_ARGS__
+#define CFG_FILE 1
+#define USE_FILE(...) __VA_ARGS__
+#define CFG_FIND 1
+#define USE_FIND(...) __VA_ARGS__
+#define CFG_GREP 1
+#define USE_GREP(...) __VA_ARGS__
+#define CFG_EGREP 1
+#define USE_EGREP(...) __VA_ARGS__
+#define CFG_FGREP 1
+#define USE_FGREP(...) __VA_ARGS__
+#define CFG_HEAD 1
+#define USE_HEAD(...) __VA_ARGS__
+#define CFG_ID 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_LOGNAME(...) __VA_ARGS__
+#define CFG_WHOAMI 1
+#define USE_WHOAMI(...) __VA_ARGS__
+#define CFG_KILL 1
+#define USE_KILL(...) __VA_ARGS__
+#define CFG_KILLALL5 0
+#define USE_KILLALL5(...)
+#define CFG_LINK 0
+#define USE_LINK(...)
+#define CFG_LN 1
+#define USE_LN(...) __VA_ARGS__
+#define CFG_LS 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_MKDIR_Z(...) __VA_ARGS__
+#define CFG_MKFIFO 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_PASTE(...) __VA_ARGS__
+#define CFG_PATCH 1
+#define USE_PATCH(...) __VA_ARGS__
+#define CFG_PRINTF 1
+#define USE_PRINTF(...) __VA_ARGS__
+#define CFG_PS 1
+#define USE_PS(...) __VA_ARGS__
+#define CFG_TTOP 0
+#define USE_TTOP(...)
+#define CFG_PWD 1
+#define USE_PWD(...) __VA_ARGS__
+#define CFG_RENICE 1
+#define USE_RENICE(...) __VA_ARGS__
+#define CFG_RM 1
+#define USE_RM(...) __VA_ARGS__
+#define CFG_RMDIR 1
+#define USE_RMDIR(...) __VA_ARGS__
+#define CFG_SED 1
+#define USE_SED(...) __VA_ARGS__
+#define CFG_SLEEP 1
+#define USE_SLEEP(...) __VA_ARGS__
+#define CFG_SLEEP_FLOAT 1
+#define USE_SLEEP_FLOAT(...) __VA_ARGS__
+#define CFG_SORT 1
+#define USE_SORT(...) __VA_ARGS__
+#define CFG_SORT_BIG 1
+#define USE_SORT_BIG(...) __VA_ARGS__
+#define CFG_SORT_FLOAT 1
+#define USE_SORT_FLOAT(...) __VA_ARGS__
+#define CFG_SPLIT 1
+#define USE_SPLIT(...) __VA_ARGS__
+#define CFG_STRINGS 1
+#define USE_STRINGS(...) __VA_ARGS__
+#define CFG_TAIL 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_TIME(...) __VA_ARGS__
+#define CFG_TOUCH 1
+#define USE_TOUCH(...) __VA_ARGS__
+#define CFG_TRUE 1
+#define USE_TRUE(...) __VA_ARGS__
+#define CFG_TTY 1
+#define USE_TTY(...) __VA_ARGS__
+#define CFG_ULIMIT 1
+#define USE_ULIMIT(...) __VA_ARGS__
+#define CFG_UNAME 1
+#define USE_UNAME(...) __VA_ARGS__
+#define CFG_UNIQ 1
+#define USE_UNIQ(...) __VA_ARGS__
+#define CFG_UNLINK 0
+#define USE_UNLINK(...)
+#define CFG_UUDECODE 0
+#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_WHO(...)
+#define CFG_XARGS 1
+#define USE_XARGS(...) __VA_ARGS__
+#define CFG_XARGS_PEDANTIC 0
+#define USE_XARGS_PEDANTIC(...)
+#define CFG_ARP 0
+#define USE_ARP(...)
+#define CFG_ARPING 0
+#define USE_ARPING(...)
+#define CFG_BOOTCHARTD 0
+#define USE_BOOTCHARTD(...)
+#define CFG_BRCTL 0
+#define USE_BRCTL(...)
+#define CFG_COMPRESS 0
+#define USE_COMPRESS(...)
+#define CFG_GZIP 0
+#define USE_GZIP(...)
+#define CFG_GZIP_D 0
+#define USE_GZIP_D(...)
+#define CFG_DECOMPRESS 0
+#define USE_DECOMPRESS(...)
+#define CFG_ZCAT 0
+#define USE_ZCAT(...)
+#define CFG_GUNZIP 0
+#define USE_GUNZIP(...)
+#define CFG_CROND 0
+#define USE_CROND(...)
+#define CFG_CRONTAB 0
+#define USE_CRONTAB(...)
+#define CFG_DD 1
+#define USE_DD(...) __VA_ARGS__
+#define CFG_DHCP6 0
+#define USE_DHCP6(...)
+#define CFG_DHCP 0
+#define USE_DHCP(...)
+#define CFG_DHCPD 0
+#define USE_DHCPD(...)
+#define CFG_DEBUG_DHCP 0
+#define USE_DEBUG_DHCP(...)
+#define CFG_DIFF 0
+#define USE_DIFF(...)
+#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_FOLD 0
+#define USE_FOLD(...)
+#define CFG_FSCK 0
+#define USE_FSCK(...)
+#define CFG_FTPGET 0
+#define USE_FTPGET(...)
+#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_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_IPCRM(...)
+#define CFG_IPCS 0
+#define USE_IPCS(...)
+#define CFG_KLOGD 0
+#define USE_KLOGD(...)
+#define CFG_KLOGD_SOURCE_RING_BUFFER 0
+#define USE_KLOGD_SOURCE_RING_BUFFER(...)
+#define CFG_LAST 0
+#define USE_LAST(...)
+#define CFG_LOGGER 0
+#define USE_LOGGER(...)
+#define CFG_LSOF 1
+#define USE_LSOF(...) __VA_ARGS__
+#define CFG_MDEV 0
+#define USE_MDEV(...)
+#define CFG_MDEV_CONF 0
+#define USE_MDEV_CONF(...)
+#define CFG_MKE2FS 0
+#define USE_MKE2FS(...)
+#define CFG_MKE2FS_JOURNAL 0
+#define USE_MKE2FS_JOURNAL(...)
+#define CFG_MKE2FS_GEN 0
+#define USE_MKE2FS_GEN(...)
+#define CFG_MKE2FS_LABEL 0
+#define USE_MKE2FS_LABEL(...)
+#define CFG_MKE2FS_EXTENDED 0
+#define USE_MKE2FS_EXTENDED(...)
+#define CFG_MODPROBE 0
+#define USE_MODPROBE(...)
+#define CFG_MORE 1
+#define USE_MORE(...) __VA_ARGS__
+#define CFG_NETSTAT 1
+#define USE_NETSTAT(...) __VA_ARGS__
+#define CFG_OPENVT 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_ROUTE 0
+#define USE_ROUTE(...)
+#define CFG_SH 0
+#define USE_SH(...)
+#define CFG_EXIT 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_SYSLOGD(...)
+#define CFG_TAR 1
+#define USE_TAR(...) __VA_ARGS__
+#define CFG_TCPSVD 0
+#define USE_TCPSVD(...)
+#define CFG_TELNET 0
+#define USE_TELNET(...)
+#define CFG_TELNETD 0
+#define USE_TELNETD(...)
+#define CFG_TEST 0
+#define USE_TEST(...)
+#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_TR(...) __VA_ARGS__
+#define CFG_USERADD 0
+#define USE_USERADD(...)
+#define CFG_USERDEL 0
+#define USE_USERDEL(...)
+#define CFG_WATCH 0
+#define USE_WATCH(...)
+#define CFG_WGET 0
+#define USE_WGET(...)
+#define CFG_XZCAT 0
+#define USE_XZCAT(...)
+#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_BLOCKDEV 1
+#define USE_BLOCKDEV(...) __VA_ARGS__
+#define CFG_BUNZIP2 1
+#define USE_BUNZIP2(...) __VA_ARGS__
+#define CFG_BZCAT 1
+#define USE_BZCAT(...) __VA_ARGS__
+#define CFG_CHCON 1
+#define USE_CHCON(...) __VA_ARGS__
+#define CFG_CHROOT 1
+#define USE_CHROOT(...) __VA_ARGS__
+#define CFG_CHVT 0
+#define USE_CHVT(...)
+#define CFG_CLEAR 1
+#define USE_CLEAR(...) __VA_ARGS__
+#define CFG_COUNT 0
+#define USE_COUNT(...)
+#define CFG_DOS2UNIX 1
+#define USE_DOS2UNIX(...) __VA_ARGS__
+#define CFG_UNIX2DOS 1
+#define USE_UNIX2DOS(...) __VA_ARGS__
+#define CFG_EJECT 0
+#define USE_EJECT(...)
+#define CFG_FACTOR 0
+#define USE_FACTOR(...)
+#define CFG_FALLOCATE 1
+#define USE_FALLOCATE(...) __VA_ARGS__
+#define CFG_FLOCK 1
+#define USE_FLOCK(...) __VA_ARGS__
+#define CFG_FREE 1
+#define USE_FREE(...) __VA_ARGS__
+#define CFG_FREERAMDISK 1
+#define USE_FREERAMDISK(...) __VA_ARGS__
+#define CFG_FSFREEZE 1
+#define USE_FSFREEZE(...) __VA_ARGS__
+#define CFG_FSYNC 0
+#define USE_FSYNC(...)
+#define CFG_HELP 1
+#define USE_HELP(...) __VA_ARGS__
+#define CFG_HELP_EXTRAS 1
+#define USE_HELP_EXTRAS(...) __VA_ARGS__
+#define CFG_HOSTID 0
+#define USE_HOSTID(...)
+#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_LOGIN 0
+#define USE_LOGIN(...)
+#define CFG_LOSETUP 1
+#define USE_LOSETUP(...) __VA_ARGS__
+#define CFG_LSATTR 1
+#define USE_LSATTR(...) __VA_ARGS__
+#define CFG_CHATTR 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_TEXT 1
+#define USE_LSPCI_TEXT(...) __VA_ARGS__
+#define CFG_LSUSB 1
+#define USE_LSUSB(...) __VA_ARGS__
+#define CFG_MAKEDEVS 1
+#define USE_MAKEDEVS(...) __VA_ARGS__
+#define CFG_MIX 0
+#define USE_MIX(...)
+#define CFG_MKPASSWD 0
+#define USE_MKPASSWD(...)
+#define CFG_MKSWAP 1
+#define USE_MKSWAP(...) __VA_ARGS__
+#define CFG_MODINFO 1
+#define USE_MODINFO(...) __VA_ARGS__
+#define CFG_MOUNTPOINT 1
+#define USE_MOUNTPOINT(...) __VA_ARGS__
+#define CFG_NBD_CLIENT 1
+#define USE_NBD_CLIENT(...) __VA_ARGS__
+#define CFG_NETCAT 1
+#define USE_NETCAT(...) __VA_ARGS__
+#define CFG_NETCAT_LISTEN 1
+#define USE_NETCAT_LISTEN(...) __VA_ARGS__
+#define CFG_UNSHARE 0
+#define USE_UNSHARE(...)
+#define CFG_NSENTER 0
+#define USE_NSENTER(...)
+#define CFG_ONEIT 0
+#define USE_ONEIT(...)
+#define CFG_PARTPROBE 1
+#define USE_PARTPROBE(...) __VA_ARGS__
+#define CFG_PIVOT_ROOT 1
+#define USE_PIVOT_ROOT(...) __VA_ARGS__
+#define CFG_PMAP 1
+#define USE_PMAP(...) __VA_ARGS__
+#define CFG_PRINTENV 1
+#define USE_PRINTENV(...) __VA_ARGS__
+#define CFG_PWDX 1
+#define USE_PWDX(...) __VA_ARGS__
+#define CFG_READAHEAD 0
+#define USE_READAHEAD(...)
+#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_REV 1
+#define USE_REV(...) __VA_ARGS__
+#define CFG_RFKILL 1
+#define USE_RFKILL(...) __VA_ARGS__
+#define CFG_RMMOD 1
+#define USE_RMMOD(...) __VA_ARGS__
+#define CFG_SETSID 1
+#define USE_SETSID(...) __VA_ARGS__
+#define CFG_SHRED 0
+#define USE_SHRED(...)
+#define CFG_STAT 1
+#define USE_STAT(...) __VA_ARGS__
+#define CFG_SWAPOFF 1
+#define USE_SWAPOFF(...) __VA_ARGS__
+#define CFG_SWAPON 1
+#define USE_SWAPON(...) __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_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_UPTIME 1
+#define USE_UPTIME(...) __VA_ARGS__
+#define CFG_USLEEP 1
+#define USE_USLEEP(...) __VA_ARGS__
+#define CFG_VCONFIG 1
+#define USE_VCONFIG(...) __VA_ARGS__
+#define CFG_VMSTAT 1
+#define USE_VMSTAT(...) __VA_ARGS__
+#define CFG_W 0
+#define USE_W(...)
+#define CFG_WHICH 1
+#define USE_WHICH(...) __VA_ARGS__
+#define CFG_XXD 1
+#define USE_XXD(...) __VA_ARGS__
+#define CFG_YES 1
+#define USE_YES(...) __VA_ARGS__
+#define CFG_DMESG 1
+#define USE_DMESG(...) __VA_ARGS__
+#define CFG_HOSTNAME 1
+#define USE_HOSTNAME(...) __VA_ARGS__
+#define CFG_KILLALL 1
+#define USE_KILLALL(...) __VA_ARGS__
+#define CFG_MD5SUM 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_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_PIDOF 1
+#define USE_PIDOF(...) __VA_ARGS__
+#define CFG_SEQ 1
+#define USE_SEQ(...) __VA_ARGS__
+#define CFG_SU 0
+#define USE_SU(...)
+#define CFG_SYNC 1
+#define USE_SYNC(...) __VA_ARGS__
+#define CFG_UMOUNT 1
+#define USE_UMOUNT(...) __VA_ARGS__
+#define CFG_HELLO 0
+#define USE_HELLO(...)
+#define CFG_SKELETON 0
+#define USE_SKELETON(...)
+#define CFG_SKELETON_ALIAS 0
+#define USE_SKELETON_ALIAS(...)
+#define CFG_TEST_HUMAN_READABLE 0
+#define USE_TEST_HUMAN_READABLE(...)
+#define CFG_TEST_MANY_OPTIONS 0
+#define USE_TEST_MANY_OPTIONS(...)
+#define CFG_TEST_SCANKEY 0
+#define USE_TEST_SCANKEY(...)
+#define CFG_GETENFORCE 1
+#define USE_GETENFORCE(...) __VA_ARGS__
+#define CFG_GETPROP 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_SUID(...) __VA_ARGS__
+#define CFG_TOYBOX_LSM_NONE 0
+#define USE_TOYBOX_LSM_NONE(...)
+#define CFG_TOYBOX_SELINUX 1
+#define USE_TOYBOX_SELINUX(...) __VA_ARGS__
+#define CFG_TOYBOX_SMACK 0
+#define USE_TOYBOX_SMACK(...)
+#define CFG_TOYBOX_FLOAT 1
+#define USE_TOYBOX_FLOAT(...) __VA_ARGS__
+#define CFG_TOYBOX_HELP 1
+#define USE_TOYBOX_HELP(...) __VA_ARGS__
+#define CFG_TOYBOX_HELP_DASHDASH 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 1
+#define USE_TOYBOX_NORECURSE(...) __VA_ARGS__
+#define CFG_TOYBOX_DEBUG 0
+#define USE_TOYBOX_DEBUG(...)
+#define CFG_TOYBOX_UID_SYS 100
+#define CFG_TOYBOX_UID_USR 500
+#define CFG_TOYBOX_MUSL_NOMMU_IS_BROKEN 0
+#define USE_TOYBOX_MUSL_NOMMU_IS_BROKEN(...)
diff --git a/toybox/generated/flags.h b/toybox/generated/flags.h
new file mode 100644
index 0000000..3363e24
--- /dev/null
+++ b/toybox/generated/flags.h
@@ -0,0 +1,5754 @@
+#undef FORCED_FLAG
+#undef FORCED_FLAGLL
+#ifdef FORCE_FLAGS
+#define FORCED_FLAG 1
+#define FORCED_FLAGLL 1LL
+#else
+#define FORCED_FLAG 0
+#define FORCED_FLAGLL 0
+#endif
+
+// acpi abctV abctV
+#undef OPTSTR_acpi
+#define OPTSTR_acpi "abctV"
+#ifdef CLEANUP_acpi
+#undef CLEANUP_acpi
+#undef FOR_acpi
+#undef FLAG_V
+#undef FLAG_t
+#undef FLAG_c
+#undef FLAG_b
+#undef FLAG_a
+#endif
+
+// arp   vi:nDsdap:A:H:[+Ap][!sd]
+#undef OPTSTR_arp
+#define OPTSTR_arp "vi:nDsdap:A:H:[+Ap][!sd]"
+#ifdef CLEANUP_arp
+#undef CLEANUP_arp
+#undef FOR_arp
+#undef FLAG_H
+#undef FLAG_A
+#undef FLAG_p
+#undef FLAG_a
+#undef FLAG_d
+#undef FLAG_s
+#undef FLAG_D
+#undef FLAG_n
+#undef FLAG_i
+#undef FLAG_v
+#endif
+
+// arping   <1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]
+#undef OPTSTR_arping
+#define OPTSTR_arping "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]"
+#ifdef CLEANUP_arping
+#undef CLEANUP_arping
+#undef FOR_arping
+#undef FLAG_f
+#undef FLAG_q
+#undef FLAG_b
+#undef FLAG_D
+#undef FLAG_U
+#undef FLAG_A
+#undef FLAG_c
+#undef FLAG_w
+#undef FLAG_I
+#undef FLAG_s
+#endif
+
+// base64 diw#<0=76[!dw] diw#<0=76[!dw]
+#undef OPTSTR_base64
+#define OPTSTR_base64 "diw#<0=76[!dw]"
+#ifdef CLEANUP_base64
+#undef CLEANUP_base64
+#undef FOR_base64
+#undef FLAG_w
+#undef FLAG_i
+#undef FLAG_d
+#endif
+
+// basename <1>2 <1>2
+#undef OPTSTR_basename
+#define OPTSTR_basename "<1>2"
+#ifdef CLEANUP_basename
+#undef CLEANUP_basename
+#undef FOR_basename
+#endif
+
+// blkid    
+#undef OPTSTR_blkid
+#define OPTSTR_blkid 0
+#ifdef CLEANUP_blkid
+#undef CLEANUP_blkid
+#undef FOR_blkid
+#endif
+
+// blockdev <1>1(setro)(setrw)(getro)(getss)(getbsz)(setbsz)#<0(getsz)(getsize)(getsize64)(flushbufs)(rereadpt) <1>1(setro)(setrw)(getro)(getss)(getbsz)(setbsz)#<0(getsz)(getsize)(getsize64)(flushbufs)(rereadpt)
+#undef OPTSTR_blockdev
+#define OPTSTR_blockdev "<1>1(setro)(setrw)(getro)(getss)(getbsz)(setbsz)#<0(getsz)(getsize)(getsize64)(flushbufs)(rereadpt)"
+#ifdef CLEANUP_blockdev
+#undef CLEANUP_blockdev
+#undef FOR_blockdev
+#undef FLAG_rereadpt
+#undef FLAG_flushbufs
+#undef FLAG_getsize64
+#undef FLAG_getsize
+#undef FLAG_getsz
+#undef FLAG_setbsz
+#undef FLAG_getbsz
+#undef FLAG_getss
+#undef FLAG_getro
+#undef FLAG_setrw
+#undef FLAG_setro
+#endif
+
+// bootchartd    
+#undef OPTSTR_bootchartd
+#define OPTSTR_bootchartd 0
+#ifdef CLEANUP_bootchartd
+#undef CLEANUP_bootchartd
+#undef FOR_bootchartd
+#endif
+
+// brctl   <1
+#undef OPTSTR_brctl
+#define OPTSTR_brctl "<1"
+#ifdef CLEANUP_brctl
+#undef CLEANUP_brctl
+#undef FOR_brctl
+#endif
+
+// bunzip2 cftkv cftkv
+#undef OPTSTR_bunzip2
+#define OPTSTR_bunzip2 "cftkv"
+#ifdef CLEANUP_bunzip2
+#undef CLEANUP_bunzip2
+#undef FOR_bunzip2
+#undef FLAG_v
+#undef FLAG_k
+#undef FLAG_t
+#undef FLAG_f
+#undef FLAG_c
+#endif
+
+// bzcat    
+#undef OPTSTR_bzcat
+#define OPTSTR_bzcat 0
+#ifdef CLEANUP_bzcat
+#undef CLEANUP_bzcat
+#undef FOR_bzcat
+#endif
+
+// cal >2 >2
+#undef OPTSTR_cal
+#define OPTSTR_cal ">2"
+#ifdef CLEANUP_cal
+#undef CLEANUP_cal
+#undef FOR_cal
+#endif
+
+// cat uvte uvte
+#undef OPTSTR_cat
+#define OPTSTR_cat "uvte"
+#ifdef CLEANUP_cat
+#undef CLEANUP_cat
+#undef FOR_cat
+#undef FLAG_e
+#undef FLAG_t
+#undef FLAG_v
+#undef FLAG_u
+#endif
+
+// catv   vte
+#undef OPTSTR_catv
+#define OPTSTR_catv "vte"
+#ifdef CLEANUP_catv
+#undef CLEANUP_catv
+#undef FOR_catv
+#undef FLAG_e
+#undef FLAG_t
+#undef FLAG_v
+#endif
+
+// cd    
+#undef OPTSTR_cd
+#define OPTSTR_cd 0
+#ifdef CLEANUP_cd
+#undef CLEANUP_cd
+#undef FOR_cd
+#endif
+
+// chattr    
+#undef OPTSTR_chattr
+#define OPTSTR_chattr 0
+#ifdef CLEANUP_chattr
+#undef CLEANUP_chattr
+#undef FOR_chattr
+#endif
+
+// chcon <2hvR <2hvR
+#undef OPTSTR_chcon
+#define OPTSTR_chcon "<2hvR"
+#ifdef CLEANUP_chcon
+#undef CLEANUP_chcon
+#undef FOR_chcon
+#undef FLAG_R
+#undef FLAG_v
+#undef FLAG_h
+#endif
+
+// chgrp <2hPLHRfv[-HLP] <2hPLHRfv[-HLP]
+#undef OPTSTR_chgrp
+#define OPTSTR_chgrp "<2hPLHRfv[-HLP]"
+#ifdef CLEANUP_chgrp
+#undef CLEANUP_chgrp
+#undef FOR_chgrp
+#undef FLAG_v
+#undef FLAG_f
+#undef FLAG_R
+#undef FLAG_H
+#undef FLAG_L
+#undef FLAG_P
+#undef FLAG_h
+#endif
+
+// chmod <2?vRf[-vf] <2?vRf[-vf]
+#undef OPTSTR_chmod
+#define OPTSTR_chmod "<2?vRf[-vf]"
+#ifdef CLEANUP_chmod
+#undef CLEANUP_chmod
+#undef FOR_chmod
+#undef FLAG_f
+#undef FLAG_R
+#undef FLAG_v
+#endif
+
+// chroot ^<1 ^<1
+#undef OPTSTR_chroot
+#define OPTSTR_chroot "^<1"
+#ifdef CLEANUP_chroot
+#undef CLEANUP_chroot
+#undef FOR_chroot
+#endif
+
+// chvt   <1
+#undef OPTSTR_chvt
+#define OPTSTR_chvt "<1"
+#ifdef CLEANUP_chvt
+#undef CLEANUP_chvt
+#undef FOR_chvt
+#endif
+
+// cksum HIPLN HIPLN
+#undef OPTSTR_cksum
+#define OPTSTR_cksum "HIPLN"
+#ifdef CLEANUP_cksum
+#undef CLEANUP_cksum
+#undef FOR_cksum
+#undef FLAG_N
+#undef FLAG_L
+#undef FLAG_P
+#undef FLAG_I
+#undef FLAG_H
+#endif
+
+// clear    
+#undef OPTSTR_clear
+#define OPTSTR_clear 0
+#ifdef CLEANUP_clear
+#undef CLEANUP_clear
+#undef FOR_clear
+#endif
+
+// cmp <2>2ls[!ls] <2>2ls[!ls]
+#undef OPTSTR_cmp
+#define OPTSTR_cmp "<2>2ls[!ls]"
+#ifdef CLEANUP_cmp
+#undef CLEANUP_cmp
+#undef FOR_cmp
+#undef FLAG_s
+#undef FLAG_l
+#endif
+
+// comm <2>2321 <2>2321
+#undef OPTSTR_comm
+#define OPTSTR_comm "<2>2321"
+#ifdef CLEANUP_comm
+#undef CLEANUP_comm
+#undef FOR_comm
+#undef FLAG_1
+#undef FLAG_2
+#undef FLAG_3
+#endif
+
+// compress   zcd9lrg[-cd][!zgLr]
+#undef OPTSTR_compress
+#define OPTSTR_compress "zcd9lrg[-cd][!zgLr]"
+#ifdef CLEANUP_compress
+#undef CLEANUP_compress
+#undef FOR_compress
+#undef FLAG_g
+#undef FLAG_r
+#undef FLAG_l
+#undef FLAG_9
+#undef FLAG_d
+#undef FLAG_c
+#undef FLAG_z
+#endif
+
+// count    
+#undef OPTSTR_count
+#define OPTSTR_count 0
+#ifdef CLEANUP_count
+#undef CLEANUP_count
+#undef FOR_count
+#endif
+
+// cp <2(preserve):;RHLPprdaslvnF(remove-destination)fi[-HLPd][-ni] <2(preserve):;RHLPprdaslvnF(remove-destination)fi[-HLPd][-ni]
+#undef OPTSTR_cp
+#define OPTSTR_cp "<2(preserve):;RHLPprdaslvnF(remove-destination)fi[-HLPd][-ni]"
+#ifdef CLEANUP_cp
+#undef CLEANUP_cp
+#undef FOR_cp
+#undef FLAG_i
+#undef FLAG_f
+#undef FLAG_remove_destination
+#undef FLAG_F
+#undef FLAG_n
+#undef FLAG_v
+#undef FLAG_l
+#undef FLAG_s
+#undef FLAG_a
+#undef FLAG_d
+#undef FLAG_r
+#undef FLAG_p
+#undef FLAG_P
+#undef FLAG_L
+#undef FLAG_H
+#undef FLAG_R
+#undef FLAG_preserve
+#endif
+
+// cpio (no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF] (no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]
+#undef OPTSTR_cpio
+#define OPTSTR_cpio "(no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]"
+#ifdef CLEANUP_cpio
+#undef CLEANUP_cpio
+#undef FOR_cpio
+#undef FLAG_o
+#undef FLAG_verbose
+#undef FLAG_v
+#undef FLAG_F
+#undef FLAG_t
+#undef FLAG_i
+#undef FLAG_p
+#undef FLAG_H
+#undef FLAG_u
+#undef FLAG_d
+#undef FLAG_m
+#undef FLAG_no_preserve_owner
+#endif
+
+// crond   fbSl#<0=8d#<0L:c:[-bf][-LS][-ld]
+#undef OPTSTR_crond
+#define OPTSTR_crond "fbSl#<0=8d#<0L:c:[-bf][-LS][-ld]"
+#ifdef CLEANUP_crond
+#undef CLEANUP_crond
+#undef FOR_crond
+#undef FLAG_c
+#undef FLAG_L
+#undef FLAG_d
+#undef FLAG_l
+#undef FLAG_S
+#undef FLAG_b
+#undef FLAG_f
+#endif
+
+// crontab   c:u:elr[!elr]
+#undef OPTSTR_crontab
+#define OPTSTR_crontab "c:u:elr[!elr]"
+#ifdef CLEANUP_crontab
+#undef CLEANUP_crontab
+#undef FOR_crontab
+#undef FLAG_r
+#undef FLAG_l
+#undef FLAG_e
+#undef FLAG_u
+#undef FLAG_c
+#endif
+
+// cut b:|c:|f:|d:sn[!cbf] b:|c:|f:|d:sn[!cbf]
+#undef OPTSTR_cut
+#define OPTSTR_cut "b:|c:|f:|d:sn[!cbf]"
+#ifdef CLEANUP_cut
+#undef CLEANUP_cut
+#undef FOR_cut
+#undef FLAG_n
+#undef FLAG_s
+#undef FLAG_d
+#undef FLAG_f
+#undef FLAG_c
+#undef FLAG_b
+#endif
+
+// date d:D:r:u[!dr] d:D:r:u[!dr]
+#undef OPTSTR_date
+#define OPTSTR_date "d:D:r:u[!dr]"
+#ifdef CLEANUP_date
+#undef CLEANUP_date
+#undef FOR_date
+#undef FLAG_u
+#undef FLAG_r
+#undef FLAG_D
+#undef FLAG_d
+#endif
+
+// dd    
+#undef OPTSTR_dd
+#define OPTSTR_dd 0
+#ifdef CLEANUP_dd
+#undef CLEANUP_dd
+#undef FOR_dd
+#endif
+
+// deallocvt   >1
+#undef OPTSTR_deallocvt
+#define OPTSTR_deallocvt ">1"
+#ifdef CLEANUP_deallocvt
+#undef CLEANUP_deallocvt
+#undef FOR_deallocvt
+#endif
+
+// df HPkht*a[-HPkh] HPkht*a[-HPkh]
+#undef OPTSTR_df
+#define OPTSTR_df "HPkht*a[-HPkh]"
+#ifdef CLEANUP_df
+#undef CLEANUP_df
+#undef FOR_df
+#undef FLAG_a
+#undef FLAG_t
+#undef FLAG_h
+#undef FLAG_k
+#undef FLAG_P
+#undef FLAG_H
+#endif
+
+// dhcp   V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf
+#undef OPTSTR_dhcp
+#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
+#undef FLAG_f
+#undef FLAG_b
+#undef FLAG_n
+#undef FLAG_q
+#undef FLAG_v
+#undef FLAG_o
+#undef FLAG_a
+#undef FLAG_C
+#undef FLAG_R
+#undef FLAG_B
+#undef FLAG_S
+#undef FLAG_i
+#undef FLAG_p
+#undef FLAG_s
+#undef FLAG_t
+#undef FLAG_T
+#undef FLAG_A
+#undef FLAG_O
+#undef FLAG_r
+#undef FLAG_x
+#undef FLAG_F
+#undef FLAG_H
+#undef FLAG_V
+#endif
+
+// dhcp6   r:A#<0T#<0t#<0s:p:i:SRvqnbf
+#undef OPTSTR_dhcp6
+#define OPTSTR_dhcp6 "r:A#<0T#<0t#<0s:p:i:SRvqnbf"
+#ifdef CLEANUP_dhcp6
+#undef CLEANUP_dhcp6
+#undef FOR_dhcp6
+#undef FLAG_f
+#undef FLAG_b
+#undef FLAG_n
+#undef FLAG_q
+#undef FLAG_v
+#undef FLAG_R
+#undef FLAG_S
+#undef FLAG_i
+#undef FLAG_p
+#undef FLAG_s
+#undef FLAG_t
+#undef FLAG_T
+#undef FLAG_A
+#undef FLAG_r
+#endif
+
+// dhcpd   >1P#<0>65535fi:S46[!46]
+#undef OPTSTR_dhcpd
+#define OPTSTR_dhcpd ">1P#<0>65535fi:S46[!46]"
+#ifdef CLEANUP_dhcpd
+#undef CLEANUP_dhcpd
+#undef FOR_dhcpd
+#undef FLAG_6
+#undef FLAG_4
+#undef FLAG_S
+#undef FLAG_i
+#undef FLAG_f
+#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
+#undef OPTSTR_diff
+#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
+#undef FLAG_unified
+#undef FLAG_U
+#undef FLAG_recursive
+#undef FLAG_r
+#undef FLAG_new_file
+#undef FLAG_N
+#undef FLAG_starting_file
+#undef FLAG_S
+#undef FLAG_label
+#undef FLAG_L
+#undef FLAG_text
+#undef FLAG_a
+#undef FLAG_brief
+#undef FLAG_q
+#undef FLAG_report_identical_files
+#undef FLAG_s
+#undef FLAG_initial_tab
+#undef FLAG_T
+#undef FLAG_ignore_case
+#undef FLAG_i
+#undef FLAG_ignore_all_space
+#undef FLAG_w
+#undef FLAG_expand_tabs
+#undef FLAG_t
+#undef FLAG_u
+#undef FLAG_ignore_space_change
+#undef FLAG_b
+#undef FLAG_minimal
+#undef FLAG_d
+#undef FLAG_ignore_blank_lines
+#undef FLAG_B
+#endif
+
+// dirname <1 <1
+#undef OPTSTR_dirname
+#define OPTSTR_dirname "<1"
+#ifdef CLEANUP_dirname
+#undef CLEANUP_dirname
+#undef FOR_dirname
+#endif
+
+// dmesg trs#<1n#c[!tr] trs#<1n#c[!tr]
+#undef OPTSTR_dmesg
+#define OPTSTR_dmesg "trs#<1n#c[!tr]"
+#ifdef CLEANUP_dmesg
+#undef CLEANUP_dmesg
+#undef FOR_dmesg
+#undef FLAG_c
+#undef FLAG_n
+#undef FLAG_s
+#undef FLAG_r
+#undef FLAG_t
+#endif
+
+// dos2unix    
+#undef OPTSTR_dos2unix
+#define OPTSTR_dos2unix 0
+#ifdef CLEANUP_dos2unix
+#undef CLEANUP_dos2unix
+#undef FOR_dos2unix
+#endif
+
+// du d#<0hmlcaHkKLsx[-HL][-kKmh] d#<0hmlcaHkKLsx[-HL][-kKmh]
+#undef OPTSTR_du
+#define OPTSTR_du "d#<0hmlcaHkKLsx[-HL][-kKmh]"
+#ifdef CLEANUP_du
+#undef CLEANUP_du
+#undef FOR_du
+#undef FLAG_x
+#undef FLAG_s
+#undef FLAG_L
+#undef FLAG_K
+#undef FLAG_k
+#undef FLAG_H
+#undef FLAG_a
+#undef FLAG_c
+#undef FLAG_l
+#undef FLAG_m
+#undef FLAG_h
+#undef FLAG_d
+#endif
+
+// dumpleases   >0arf:[!ar]
+#undef OPTSTR_dumpleases
+#define OPTSTR_dumpleases ">0arf:[!ar]"
+#ifdef CLEANUP_dumpleases
+#undef CLEANUP_dumpleases
+#undef FOR_dumpleases
+#undef FLAG_f
+#undef FLAG_r
+#undef FLAG_a
+#endif
+
+// echo ^?en ^?en
+#undef OPTSTR_echo
+#define OPTSTR_echo "^?en"
+#ifdef CLEANUP_echo
+#undef CLEANUP_echo
+#undef FOR_echo
+#undef FLAG_n
+#undef FLAG_e
+#endif
+
+// eject   >1stT[!tT]
+#undef OPTSTR_eject
+#define OPTSTR_eject ">1stT[!tT]"
+#ifdef CLEANUP_eject
+#undef CLEANUP_eject
+#undef FOR_eject
+#undef FLAG_T
+#undef FLAG_t
+#undef FLAG_s
+#endif
+
+// env ^iu* ^iu*
+#undef OPTSTR_env
+#define OPTSTR_env "^iu*"
+#ifdef CLEANUP_env
+#undef CLEANUP_env
+#undef FOR_env
+#undef FLAG_u
+#undef FLAG_i
+#endif
+
+// exit    
+#undef OPTSTR_exit
+#define OPTSTR_exit 0
+#ifdef CLEANUP_exit
+#undef CLEANUP_exit
+#undef FOR_exit
+#endif
+
+// expand t* t*
+#undef OPTSTR_expand
+#define OPTSTR_expand "t*"
+#ifdef CLEANUP_expand
+#undef CLEANUP_expand
+#undef FOR_expand
+#undef FLAG_t
+#endif
+
+// expr    
+#undef OPTSTR_expr
+#define OPTSTR_expr 0
+#ifdef CLEANUP_expr
+#undef CLEANUP_expr
+#undef FOR_expr
+#endif
+
+// factor    
+#undef OPTSTR_factor
+#define OPTSTR_factor 0
+#ifdef CLEANUP_factor
+#undef CLEANUP_factor
+#undef FOR_factor
+#endif
+
+// fallocate >1l#| >1l#|
+#undef OPTSTR_fallocate
+#define OPTSTR_fallocate ">1l#|"
+#ifdef CLEANUP_fallocate
+#undef CLEANUP_fallocate
+#undef FOR_fallocate
+#undef FLAG_l
+#endif
+
+// false    
+#undef OPTSTR_false
+#define OPTSTR_false 0
+#ifdef CLEANUP_false
+#undef CLEANUP_false
+#undef FOR_false
+#endif
+
+// fdisk   C#<0H#<0S#<0b#<512ul
+#undef OPTSTR_fdisk
+#define OPTSTR_fdisk "C#<0H#<0S#<0b#<512ul"
+#ifdef CLEANUP_fdisk
+#undef CLEANUP_fdisk
+#undef FOR_fdisk
+#undef FLAG_l
+#undef FLAG_u
+#undef FLAG_b
+#undef FLAG_S
+#undef FLAG_H
+#undef FLAG_C
+#endif
+
+// file <1 <1
+#undef OPTSTR_file
+#define OPTSTR_file "<1"
+#ifdef CLEANUP_file
+#undef CLEANUP_file
+#undef FOR_file
+#endif
+
+// find ?^HL[-HL] ?^HL[-HL]
+#undef OPTSTR_find
+#define OPTSTR_find "?^HL[-HL]"
+#ifdef CLEANUP_find
+#undef CLEANUP_find
+#undef FOR_find
+#undef FLAG_L
+#undef FLAG_H
+#endif
+
+// flock <1>1nsux[-sux] <1>1nsux[-sux]
+#undef OPTSTR_flock
+#define OPTSTR_flock "<1>1nsux[-sux]"
+#ifdef CLEANUP_flock
+#undef CLEANUP_flock
+#undef FOR_flock
+#undef FLAG_x
+#undef FLAG_u
+#undef FLAG_s
+#undef FLAG_n
+#endif
+
+// fold   bsuw#<1
+#undef OPTSTR_fold
+#define OPTSTR_fold "bsuw#<1"
+#ifdef CLEANUP_fold
+#undef CLEANUP_fold
+#undef FOR_fold
+#undef FLAG_w
+#undef FLAG_u
+#undef FLAG_s
+#undef FLAG_b
+#endif
+
+// free htgmkb[!htgmkb] htgmkb[!htgmkb]
+#undef OPTSTR_free
+#define OPTSTR_free "htgmkb[!htgmkb]"
+#ifdef CLEANUP_free
+#undef CLEANUP_free
+#undef FOR_free
+#undef FLAG_b
+#undef FLAG_k
+#undef FLAG_m
+#undef FLAG_g
+#undef FLAG_t
+#undef FLAG_h
+#endif
+
+// freeramdisk <1>1 <1>1
+#undef OPTSTR_freeramdisk
+#define OPTSTR_freeramdisk "<1>1"
+#ifdef CLEANUP_freeramdisk
+#undef CLEANUP_freeramdisk
+#undef FOR_freeramdisk
+#endif
+
+// fsck   ?t:ANPRTVsC#
+#undef OPTSTR_fsck
+#define OPTSTR_fsck "?t:ANPRTVsC#"
+#ifdef CLEANUP_fsck
+#undef CLEANUP_fsck
+#undef FOR_fsck
+#undef FLAG_C
+#undef FLAG_s
+#undef FLAG_V
+#undef FLAG_T
+#undef FLAG_R
+#undef FLAG_P
+#undef FLAG_N
+#undef FLAG_A
+#undef FLAG_t
+#endif
+
+// fsfreeze <1>1f|u|[!fu] <1>1f|u|[!fu]
+#undef OPTSTR_fsfreeze
+#define OPTSTR_fsfreeze "<1>1f|u|[!fu]"
+#ifdef CLEANUP_fsfreeze
+#undef CLEANUP_fsfreeze
+#undef FOR_fsfreeze
+#undef FLAG_u
+#undef FLAG_f
+#endif
+
+// fstype   <1
+#undef OPTSTR_fstype
+#define OPTSTR_fstype "<1"
+#ifdef CLEANUP_fstype
+#undef CLEANUP_fstype
+#undef FOR_fstype
+#endif
+
+// fsync   <1d
+#undef OPTSTR_fsync
+#define OPTSTR_fsync "<1d"
+#ifdef CLEANUP_fsync
+#undef CLEANUP_fsync
+#undef FOR_fsync
+#undef FLAG_d
+#endif
+
+// ftpget   <2cvu:p:P#<0=21>65535
+#undef OPTSTR_ftpget
+#define OPTSTR_ftpget "<2cvu:p:P#<0=21>65535"
+#ifdef CLEANUP_ftpget
+#undef CLEANUP_ftpget
+#undef FOR_ftpget
+#undef FLAG_P
+#undef FLAG_p
+#undef FLAG_u
+#undef FLAG_v
+#undef FLAG_c
+#endif
+
+// getenforce >0 >0
+#undef OPTSTR_getenforce
+#define OPTSTR_getenforce ">0"
+#ifdef CLEANUP_getenforce
+#undef CLEANUP_getenforce
+#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"
+#ifdef CLEANUP_getprop
+#undef CLEANUP_getprop
+#undef FOR_getprop
+#undef FLAG_Z
+#endif
+
+// getty   <2t#<0H:I:l:f:iwnmLh
+#undef OPTSTR_getty
+#define OPTSTR_getty "<2t#<0H:I:l:f:iwnmLh"
+#ifdef CLEANUP_getty
+#undef CLEANUP_getty
+#undef FOR_getty
+#undef FLAG_h
+#undef FLAG_L
+#undef FLAG_m
+#undef FLAG_n
+#undef FLAG_w
+#undef FLAG_i
+#undef FLAG_f
+#undef FLAG_l
+#undef FLAG_I
+#undef FLAG_H
+#undef FLAG_t
+#endif
+
+// grep C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw] C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]
+#undef OPTSTR_grep
+#define OPTSTR_grep "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]"
+#ifdef CLEANUP_grep
+#undef CLEANUP_grep
+#undef FOR_grep
+#undef FLAG_x
+#undef FLAG_m
+#undef FLAG_f
+#undef FLAG_e
+#undef FLAG_q
+#undef FLAG_l
+#undef FLAG_c
+#undef FLAG_w
+#undef FLAG_v
+#undef FLAG_s
+#undef FLAG_r
+#undef FLAG_o
+#undef FLAG_n
+#undef FLAG_i
+#undef FLAG_h
+#undef FLAG_b
+#undef FLAG_a
+#undef FLAG_H
+#undef FLAG_F
+#undef FLAG_E
+#undef FLAG_z
+#undef FLAG_Z
+#undef FLAG_A
+#undef FLAG_B
+#undef FLAG_C
+#endif
+
+// groupadd   <1>2g#<0S
+#undef OPTSTR_groupadd
+#define OPTSTR_groupadd "<1>2g#<0S"
+#ifdef CLEANUP_groupadd
+#undef CLEANUP_groupadd
+#undef FOR_groupadd
+#undef FLAG_S
+#undef FLAG_g
+#endif
+
+// groupdel   <1>2
+#undef OPTSTR_groupdel
+#define OPTSTR_groupdel "<1>2"
+#ifdef CLEANUP_groupdel
+#undef CLEANUP_groupdel
+#undef FOR_groupdel
+#endif
+
+// groups    
+#undef OPTSTR_groups
+#define OPTSTR_groups 0
+#ifdef CLEANUP_groups
+#undef CLEANUP_groups
+#undef FOR_groups
+#endif
+
+// gunzip   cflqStv
+#undef OPTSTR_gunzip
+#define OPTSTR_gunzip "cflqStv"
+#ifdef CLEANUP_gunzip
+#undef CLEANUP_gunzip
+#undef FOR_gunzip
+#undef FLAG_v
+#undef FLAG_t
+#undef FLAG_S
+#undef FLAG_q
+#undef FLAG_l
+#undef FLAG_f
+#undef FLAG_c
+#endif
+
+// gzip   d19dcflqStvgLRz[!gLRz]
+#undef OPTSTR_gzip
+#define OPTSTR_gzip "d19dcflqStvgLRz[!gLRz]"
+#ifdef CLEANUP_gzip
+#undef CLEANUP_gzip
+#undef FOR_gzip
+#undef FLAG_z
+#undef FLAG_R
+#undef FLAG_L
+#undef FLAG_g
+#undef FLAG_v
+#undef FLAG_t
+#undef FLAG_S
+#undef FLAG_q
+#undef FLAG_l
+#undef FLAG_f
+#undef FLAG_c
+#undef FLAG_d
+#undef FLAG_9
+#undef FLAG_1
+#undef FLAG_d
+#endif
+
+// head ?n#<0=10 ?n#<0=10
+#undef OPTSTR_head
+#define OPTSTR_head "?n#<0=10"
+#ifdef CLEANUP_head
+#undef CLEANUP_head
+#undef FOR_head
+#undef FLAG_n
+#endif
+
+// hello    
+#undef OPTSTR_hello
+#define OPTSTR_hello 0
+#ifdef CLEANUP_hello
+#undef CLEANUP_hello
+#undef FOR_hello
+#endif
+
+// help ah ah
+#undef OPTSTR_help
+#define OPTSTR_help "ah"
+#ifdef CLEANUP_help
+#undef CLEANUP_help
+#undef FOR_help
+#undef FLAG_h
+#undef FLAG_a
+#endif
+
+// hexedit   <1>1r
+#undef OPTSTR_hexedit
+#define OPTSTR_hexedit "<1>1r"
+#ifdef CLEANUP_hexedit
+#undef CLEANUP_hexedit
+#undef FOR_hexedit
+#undef FLAG_r
+#endif
+
+// host   <1>2avt:
+#undef OPTSTR_host
+#define OPTSTR_host "<1>2avt:"
+#ifdef CLEANUP_host
+#undef CLEANUP_host
+#undef FOR_host
+#undef FLAG_t
+#undef FLAG_v
+#undef FLAG_a
+#endif
+
+// hostid   >0
+#undef OPTSTR_hostid
+#define OPTSTR_hostid ">0"
+#ifdef CLEANUP_hostid
+#undef CLEANUP_hostid
+#undef FOR_hostid
+#endif
+
+// hostname bF: bF:
+#undef OPTSTR_hostname
+#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]
+#undef OPTSTR_hwclock
+#define OPTSTR_hwclock ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]"
+#ifdef CLEANUP_hwclock
+#undef CLEANUP_hwclock
+#undef FOR_hwclock
+#undef FLAG_systohc
+#undef FLAG_w
+#undef FLAG_show
+#undef FLAG_r
+#undef FLAG_hctosys
+#undef FLAG_s
+#undef FLAG_systz
+#undef FLAG_t
+#undef FLAG_localtime
+#undef FLAG_l
+#undef FLAG_utc
+#undef FLAG_u
+#undef FLAG_rtc
+#undef FLAG_f
+#undef FLAG_fast
+#endif
+
+// iconv   cst:f:
+#undef OPTSTR_iconv
+#define OPTSTR_iconv "cst:f:"
+#ifdef CLEANUP_iconv
+#undef CLEANUP_iconv
+#undef FOR_iconv
+#undef FLAG_f
+#undef FLAG_t
+#undef FLAG_s
+#undef FLAG_c
+#endif
+
+// id >1ZnGgru[!ZGgu] >1ZnGgru[!ZGgu]
+#undef OPTSTR_id
+#define OPTSTR_id ">1ZnGgru[!ZGgu]"
+#ifdef CLEANUP_id
+#undef CLEANUP_id
+#undef FOR_id
+#undef FLAG_u
+#undef FLAG_r
+#undef FLAG_g
+#undef FLAG_G
+#undef FLAG_n
+#undef FLAG_Z
+#endif
+
+// ifconfig ^?a ^?a
+#undef OPTSTR_ifconfig
+#define OPTSTR_ifconfig "^?a"
+#ifdef CLEANUP_ifconfig
+#undef CLEANUP_ifconfig
+#undef FOR_ifconfig
+#undef FLAG_a
+#endif
+
+// init    
+#undef OPTSTR_init
+#define OPTSTR_init 0
+#ifdef CLEANUP_init
+#undef CLEANUP_init
+#undef FOR_init
+#endif
+
+// inotifyd <2 <2
+#undef OPTSTR_inotifyd
+#define OPTSTR_inotifyd "<2"
+#ifdef CLEANUP_inotifyd
+#undef CLEANUP_inotifyd
+#undef FOR_inotifyd
+#endif
+
+// insmod <1 <1
+#undef OPTSTR_insmod
+#define OPTSTR_insmod "<1"
+#ifdef CLEANUP_insmod
+#undef CLEANUP_insmod
+#undef FOR_insmod
+#endif
+
+// install <1cdDpsvm:o:g: <1cdDpsvm:o:g:
+#undef OPTSTR_install
+#define OPTSTR_install "<1cdDpsvm:o:g:"
+#ifdef CLEANUP_install
+#undef CLEANUP_install
+#undef FOR_install
+#undef FLAG_g
+#undef FLAG_o
+#undef FLAG_m
+#undef FLAG_v
+#undef FLAG_s
+#undef FLAG_p
+#undef FLAG_D
+#undef FLAG_d
+#undef FLAG_c
+#endif
+
+// ionice ^tc#<0>3=2n#<0>7=5p# ^tc#<0>3=2n#<0>7=5p#
+#undef OPTSTR_ionice
+#define OPTSTR_ionice "^tc#<0>3=2n#<0>7=5p#"
+#ifdef CLEANUP_ionice
+#undef CLEANUP_ionice
+#undef FOR_ionice
+#undef FLAG_p
+#undef FLAG_n
+#undef FLAG_c
+#undef FLAG_t
+#endif
+
+// iorenice ?<1>3 ?<1>3
+#undef OPTSTR_iorenice
+#define OPTSTR_iorenice "?<1>3"
+#ifdef CLEANUP_iorenice
+#undef CLEANUP_iorenice
+#undef FOR_iorenice
+#endif
+
+// iotop   >0AaKOk*o*p*u*s#<1=7d#=3<1n#<1bq
+#undef OPTSTR_iotop
+#define OPTSTR_iotop ">0AaKOk*o*p*u*s#<1=7d#=3<1n#<1bq"
+#ifdef CLEANUP_iotop
+#undef CLEANUP_iotop
+#undef FOR_iotop
+#undef FLAG_q
+#undef FLAG_b
+#undef FLAG_n
+#undef FLAG_d
+#undef FLAG_s
+#undef FLAG_u
+#undef FLAG_p
+#undef FLAG_o
+#undef FLAG_k
+#undef FLAG_O
+#undef FLAG_K
+#undef FLAG_a
+#undef FLAG_A
+#endif
+
+// ip    
+#undef OPTSTR_ip
+#define OPTSTR_ip 0
+#ifdef CLEANUP_ip
+#undef CLEANUP_ip
+#undef FOR_ip
+#endif
+
+// ipcrm   m*M*s*S*q*Q*
+#undef OPTSTR_ipcrm
+#define OPTSTR_ipcrm "m*M*s*S*q*Q*"
+#ifdef CLEANUP_ipcrm
+#undef CLEANUP_ipcrm
+#undef FOR_ipcrm
+#undef FLAG_Q
+#undef FLAG_q
+#undef FLAG_S
+#undef FLAG_s
+#undef FLAG_M
+#undef FLAG_m
+#endif
+
+// ipcs   acptulsqmi#
+#undef OPTSTR_ipcs
+#define OPTSTR_ipcs "acptulsqmi#"
+#ifdef CLEANUP_ipcs
+#undef CLEANUP_ipcs
+#undef FOR_ipcs
+#undef FLAG_i
+#undef FLAG_m
+#undef FLAG_q
+#undef FLAG_s
+#undef FLAG_l
+#undef FLAG_u
+#undef FLAG_t
+#undef FLAG_p
+#undef FLAG_c
+#undef FLAG_a
+#endif
+
+// kill ?ls:  ?ls: 
+#undef OPTSTR_kill
+#define OPTSTR_kill "?ls: "
+#ifdef CLEANUP_kill
+#undef CLEANUP_kill
+#undef FOR_kill
+#undef FLAG_s
+#undef FLAG_l
+#endif
+
+// killall ?s:lqvi ?s:lqvi
+#undef OPTSTR_killall
+#define OPTSTR_killall "?s:lqvi"
+#ifdef CLEANUP_killall
+#undef CLEANUP_killall
+#undef FOR_killall
+#undef FLAG_i
+#undef FLAG_v
+#undef FLAG_q
+#undef FLAG_l
+#undef FLAG_s
+#endif
+
+// killall5   ?o*ls: [!lo][!ls]
+#undef OPTSTR_killall5
+#define OPTSTR_killall5 "?o*ls: [!lo][!ls]"
+#ifdef CLEANUP_killall5
+#undef CLEANUP_killall5
+#undef FOR_killall5
+#undef FLAG_s
+#undef FLAG_l
+#undef FLAG_o
+#endif
+
+// klogd   c#<1>8n
+#undef OPTSTR_klogd
+#define OPTSTR_klogd "c#<1>8n"
+#ifdef CLEANUP_klogd
+#undef CLEANUP_klogd
+#undef FOR_klogd
+#undef FLAG_n
+#undef FLAG_c
+#endif
+
+// last   f:W
+#undef OPTSTR_last
+#define OPTSTR_last "f:W"
+#ifdef CLEANUP_last
+#undef CLEANUP_last
+#undef FOR_last
+#undef FLAG_W
+#undef FLAG_f
+#endif
+
+// link   <2>2
+#undef OPTSTR_link
+#define OPTSTR_link "<2>2"
+#ifdef CLEANUP_link
+#undef CLEANUP_link
+#undef FOR_link
+#endif
+
+// ln <1vnfs <1vnfs
+#undef OPTSTR_ln
+#define OPTSTR_ln "<1vnfs"
+#ifdef CLEANUP_ln
+#undef CLEANUP_ln
+#undef FOR_ln
+#undef FLAG_s
+#undef FLAG_f
+#undef FLAG_n
+#undef FLAG_v
+#endif
+
+// load_policy <1>1 <1>1
+#undef OPTSTR_load_policy
+#define OPTSTR_load_policy "<1>1"
+#ifdef CLEANUP_load_policy
+#undef CLEANUP_load_policy
+#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 "st:p:"
+#ifdef CLEANUP_logger
+#undef CLEANUP_logger
+#undef FOR_logger
+#undef FLAG_p
+#undef FLAG_t
+#undef FLAG_s
+#endif
+
+// login   >1f:ph:
+#undef OPTSTR_login
+#define OPTSTR_login ">1f:ph:"
+#ifdef CLEANUP_login
+#undef CLEANUP_login
+#undef FOR_login
+#undef FLAG_h
+#undef FLAG_p
+#undef FLAG_f
+#endif
+
+// logname >0 >0
+#undef OPTSTR_logname
+#define OPTSTR_logname ">0"
+#ifdef CLEANUP_logname
+#undef CLEANUP_logname
+#undef FOR_logname
+#endif
+
+// losetup >2S(sizelimit)#s(show)ro#j:fdca[!afj] >2S(sizelimit)#s(show)ro#j:fdca[!afj]
+#undef OPTSTR_losetup
+#define OPTSTR_losetup ">2S(sizelimit)#s(show)ro#j:fdca[!afj]"
+#ifdef CLEANUP_losetup
+#undef CLEANUP_losetup
+#undef FOR_losetup
+#undef FLAG_a
+#undef FLAG_c
+#undef FLAG_d
+#undef FLAG_f
+#undef FLAG_j
+#undef FLAG_o
+#undef FLAG_r
+#undef FLAG_show
+#undef FLAG_s
+#undef FLAG_sizelimit
+#undef FLAG_S
+#endif
+
+// 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):;ZgoACFHLRSabcdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][!qb]"
+#ifdef CLEANUP_ls
+#undef CLEANUP_ls
+#undef FOR_ls
+#undef FLAG_1
+#undef FLAG_x
+#undef FLAG_u
+#undef FLAG_t
+#undef FLAG_s
+#undef FLAG_r
+#undef FLAG_q
+#undef FLAG_p
+#undef FLAG_n
+#undef FLAG_m
+#undef FLAG_l
+#undef FLAG_k
+#undef FLAG_i
+#undef FLAG_h
+#undef FLAG_f
+#undef FLAG_d
+#undef FLAG_c
+#undef FLAG_b
+#undef FLAG_a
+#undef FLAG_S
+#undef FLAG_R
+#undef FLAG_L
+#undef FLAG_H
+#undef FLAG_F
+#undef FLAG_C
+#undef FLAG_A
+#undef FLAG_o
+#undef FLAG_g
+#undef FLAG_Z
+#undef FLAG_color
+#endif
+
+// lsattr vldaR vldaR
+#undef OPTSTR_lsattr
+#define OPTSTR_lsattr "vldaR"
+#ifdef CLEANUP_lsattr
+#undef CLEANUP_lsattr
+#undef FOR_lsattr
+#undef FLAG_R
+#undef FLAG_a
+#undef FLAG_d
+#undef FLAG_l
+#undef FLAG_v
+#endif
+
+// lsmod    
+#undef OPTSTR_lsmod
+#define OPTSTR_lsmod 0
+#ifdef CLEANUP_lsmod
+#undef CLEANUP_lsmod
+#undef FOR_lsmod
+#endif
+
+// lsof lp*t lp*t
+#undef OPTSTR_lsof
+#define OPTSTR_lsof "lp*t"
+#ifdef CLEANUP_lsof
+#undef CLEANUP_lsof
+#undef FOR_lsof
+#undef FLAG_t
+#undef FLAG_p
+#undef FLAG_l
+#endif
+
+// lspci   emkn@i:
+#undef OPTSTR_lspci
+#define OPTSTR_lspci "emkn@i:"
+#ifdef CLEANUP_lspci
+#undef CLEANUP_lspci
+#undef FOR_lspci
+#undef FLAG_i
+#undef FLAG_n
+#undef FLAG_k
+#undef FLAG_m
+#undef FLAG_e
+#endif
+
+// lsusb    
+#undef OPTSTR_lsusb
+#define OPTSTR_lsusb 0
+#ifdef CLEANUP_lsusb
+#undef CLEANUP_lsusb
+#undef FOR_lsusb
+#endif
+
+// makedevs <1>1d: <1>1d:
+#undef OPTSTR_makedevs
+#define OPTSTR_makedevs "<1>1d:"
+#ifdef CLEANUP_makedevs
+#undef CLEANUP_makedevs
+#undef FOR_makedevs
+#undef FLAG_d
+#endif
+
+// md5sum bc*[!bc] bc*[!bc]
+#undef OPTSTR_md5sum
+#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 "s"
+#ifdef CLEANUP_mdev
+#undef CLEANUP_mdev
+#undef FOR_mdev
+#undef FLAG_s
+#endif
+
+// mix   c:d:l#r#
+#undef OPTSTR_mix
+#define OPTSTR_mix "c:d:l#r#"
+#ifdef CLEANUP_mix
+#undef CLEANUP_mix
+#undef FOR_mix
+#undef FLAG_r
+#undef FLAG_l
+#undef FLAG_d
+#undef FLAG_c
+#endif
+
+// mkdir <1Z:vpm: <1Z:vpm:
+#undef OPTSTR_mkdir
+#define OPTSTR_mkdir "<1Z:vpm:"
+#ifdef CLEANUP_mkdir
+#undef CLEANUP_mkdir
+#undef FOR_mkdir
+#undef FLAG_m
+#undef FLAG_p
+#undef FLAG_v
+#undef FLAG_Z
+#endif
+
+// mke2fs   <1>2g:Fnqm#N#i#b#
+#undef OPTSTR_mke2fs
+#define OPTSTR_mke2fs "<1>2g:Fnqm#N#i#b#"
+#ifdef CLEANUP_mke2fs
+#undef CLEANUP_mke2fs
+#undef FOR_mke2fs
+#undef FLAG_b
+#undef FLAG_i
+#undef FLAG_N
+#undef FLAG_m
+#undef FLAG_q
+#undef FLAG_n
+#undef FLAG_F
+#undef FLAG_g
+#endif
+
+// mkfifo <1Z:m: <1Z:m:
+#undef OPTSTR_mkfifo
+#define OPTSTR_mkfifo "<1Z:m:"
+#ifdef CLEANUP_mkfifo
+#undef CLEANUP_mkfifo
+#undef FOR_mkfifo
+#undef FLAG_m
+#undef FLAG_Z
+#endif
+
+// mknod <2>4m(mode):Z: <2>4m(mode):Z:
+#undef OPTSTR_mknod
+#define OPTSTR_mknod "<2>4m(mode):Z:"
+#ifdef CLEANUP_mknod
+#undef CLEANUP_mknod
+#undef FOR_mknod
+#undef FLAG_Z
+#undef FLAG_mode
+#undef FLAG_m
+#endif
+
+// mkpasswd   >2S:m:P#=0<0
+#undef OPTSTR_mkpasswd
+#define OPTSTR_mkpasswd ">2S:m:P#=0<0"
+#ifdef CLEANUP_mkpasswd
+#undef CLEANUP_mkpasswd
+#undef FOR_mkpasswd
+#undef FLAG_P
+#undef FLAG_m
+#undef FLAG_S
+#endif
+
+// mkswap <1>1L: <1>1L:
+#undef OPTSTR_mkswap
+#define OPTSTR_mkswap "<1>1L:"
+#ifdef CLEANUP_mkswap
+#undef CLEANUP_mkswap
+#undef FOR_mkswap
+#undef FLAG_L
+#endif
+
+// mktemp >1uqd(directory)p(tmpdir): >1uqd(directory)p(tmpdir):
+#undef OPTSTR_mktemp
+#define OPTSTR_mktemp ">1uqd(directory)p(tmpdir):"
+#ifdef CLEANUP_mktemp
+#undef CLEANUP_mktemp
+#undef FOR_mktemp
+#undef FLAG_tmpdir
+#undef FLAG_p
+#undef FLAG_directory
+#undef FLAG_d
+#undef FLAG_q
+#undef FLAG_u
+#endif
+
+// modinfo <1b:k:F:0 <1b:k:F:0
+#undef OPTSTR_modinfo
+#define OPTSTR_modinfo "<1b:k:F:0"
+#ifdef CLEANUP_modinfo
+#undef CLEANUP_modinfo
+#undef FOR_modinfo
+#undef FLAG_0
+#undef FLAG_F
+#undef FLAG_k
+#undef FLAG_b
+#endif
+
+// modprobe   alrqvsDb
+#undef OPTSTR_modprobe
+#define OPTSTR_modprobe "alrqvsDb"
+#ifdef CLEANUP_modprobe
+#undef CLEANUP_modprobe
+#undef FOR_modprobe
+#undef FLAG_b
+#undef FLAG_D
+#undef FLAG_s
+#undef FLAG_v
+#undef FLAG_q
+#undef FLAG_r
+#undef FLAG_l
+#undef FLAG_a
+#endif
+
+// more    
+#undef OPTSTR_more
+#define OPTSTR_more 0
+#ifdef CLEANUP_more
+#undef CLEANUP_more
+#undef FOR_more
+#endif
+
+// mount ?O:afnrvwt:o*[-rw] ?O:afnrvwt:o*[-rw]
+#undef OPTSTR_mount
+#define OPTSTR_mount "?O:afnrvwt:o*[-rw]"
+#ifdef CLEANUP_mount
+#undef CLEANUP_mount
+#undef FOR_mount
+#undef FLAG_o
+#undef FLAG_t
+#undef FLAG_w
+#undef FLAG_v
+#undef FLAG_r
+#undef FLAG_n
+#undef FLAG_f
+#undef FLAG_a
+#undef FLAG_O
+#endif
+
+// mountpoint <1qdx[-dx] <1qdx[-dx]
+#undef OPTSTR_mountpoint
+#define OPTSTR_mountpoint "<1qdx[-dx]"
+#ifdef CLEANUP_mountpoint
+#undef CLEANUP_mountpoint
+#undef FOR_mountpoint
+#undef FLAG_x
+#undef FLAG_d
+#undef FLAG_q
+#endif
+
+// mv <2vnF(remove-destination)fi[-ni] <2vnF(remove-destination)fi[-ni]
+#undef OPTSTR_mv
+#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
+#endif
+
+// nbd_client <3>3ns <3>3ns
+#undef OPTSTR_nbd_client
+#define OPTSTR_nbd_client "<3>3ns"
+#ifdef CLEANUP_nbd_client
+#undef CLEANUP_nbd_client
+#undef FOR_nbd_client
+#undef FLAG_s
+#undef FLAG_n
+#endif
+
+// netcat ^tlLw#p#s:q#f: ^tlLw#p#s:q#f:
+#undef OPTSTR_netcat
+#define OPTSTR_netcat "^tlLw#p#s:q#f:"
+#ifdef CLEANUP_netcat
+#undef CLEANUP_netcat
+#undef FOR_netcat
+#undef FLAG_f
+#undef FLAG_q
+#undef FLAG_s
+#undef FLAG_p
+#undef FLAG_w
+#undef FLAG_L
+#undef FLAG_l
+#undef FLAG_t
+#endif
+
+// netstat pWrxwutneal pWrxwutneal
+#undef OPTSTR_netstat
+#define OPTSTR_netstat "pWrxwutneal"
+#ifdef CLEANUP_netstat
+#undef CLEANUP_netstat
+#undef FOR_netstat
+#undef FLAG_l
+#undef FLAG_a
+#undef FLAG_e
+#undef FLAG_n
+#undef FLAG_t
+#undef FLAG_u
+#undef FLAG_w
+#undef FLAG_x
+#undef FLAG_r
+#undef FLAG_W
+#undef FLAG_p
+#endif
+
+// nice ^<1n# ^<1n#
+#undef OPTSTR_nice
+#define OPTSTR_nice "^<1n#"
+#ifdef CLEANUP_nice
+#undef CLEANUP_nice
+#undef FOR_nice
+#undef FLAG_n
+#endif
+
+// nl v#<1=1l#b:n:s:w#<0=6E v#<1=1l#b:n:s:w#<0=6E
+#undef OPTSTR_nl
+#define OPTSTR_nl "v#<1=1l#b:n:s:w#<0=6E"
+#ifdef CLEANUP_nl
+#undef CLEANUP_nl
+#undef FOR_nl
+#undef FLAG_E
+#undef FLAG_w
+#undef FLAG_s
+#undef FLAG_n
+#undef FLAG_b
+#undef FLAG_l
+#undef FLAG_v
+#endif
+
+// nohup <1^ <1^
+#undef OPTSTR_nohup
+#define OPTSTR_nohup "<1^"
+#ifdef CLEANUP_nohup
+#undef CLEANUP_nohup
+#undef FOR_nohup
+#endif
+
+// nproc   (all)
+#undef OPTSTR_nproc
+#define OPTSTR_nproc "(all)"
+#ifdef CLEANUP_nproc
+#undef CLEANUP_nproc
+#undef FOR_nproc
+#undef FLAG_all
+#endif
+
+// 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 "<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_user
+#undef FLAG_U
+#undef FLAG_uts
+#undef FLAG_u
+#undef FLAG_pid
+#undef FLAG_p
+#undef FLAG_net
+#undef FLAG_n
+#undef FLAG_mount
+#undef FLAG_m
+#undef FLAG_ipc
+#undef FLAG_i
+#undef FLAG_target
+#undef FLAG_t
+#undef FLAG_no_fork
+#undef FLAG_F
+#endif
+
+// od j#vw#<1=16N#xsodcbA:t* j#vw#<1=16N#xsodcbA:t*
+#undef OPTSTR_od
+#define OPTSTR_od "j#vw#<1=16N#xsodcbA:t*"
+#ifdef CLEANUP_od
+#undef CLEANUP_od
+#undef FOR_od
+#undef FLAG_t
+#undef FLAG_A
+#undef FLAG_b
+#undef FLAG_c
+#undef FLAG_d
+#undef FLAG_o
+#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 "^<1nc:p3[!pn]"
+#ifdef CLEANUP_oneit
+#undef CLEANUP_oneit
+#undef FOR_oneit
+#undef FLAG_3
+#undef FLAG_p
+#undef FLAG_c
+#undef FLAG_n
+#endif
+
+// openvt   c#<1>63sw
+#undef OPTSTR_openvt
+#define OPTSTR_openvt "c#<1>63sw"
+#ifdef CLEANUP_openvt
+#undef CLEANUP_openvt
+#undef FOR_openvt
+#undef FLAG_w
+#undef FLAG_s
+#undef FLAG_c
+#endif
+
+// partprobe <1 <1
+#undef OPTSTR_partprobe
+#define OPTSTR_partprobe "<1"
+#ifdef CLEANUP_partprobe
+#undef CLEANUP_partprobe
+#undef FOR_partprobe
+#endif
+
+// passwd   >1a:dlu
+#undef OPTSTR_passwd
+#define OPTSTR_passwd ">1a:dlu"
+#ifdef CLEANUP_passwd
+#undef CLEANUP_passwd
+#undef FOR_passwd
+#undef FLAG_u
+#undef FLAG_l
+#undef FLAG_d
+#undef FLAG_a
+#endif
+
+// paste d:s d:s
+#undef OPTSTR_paste
+#define OPTSTR_paste "d:s"
+#ifdef CLEANUP_paste
+#undef CLEANUP_paste
+#undef FOR_paste
+#undef FLAG_s
+#undef FLAG_d
+#endif
+
+// patch (dry-run)d:ulp#i:R (dry-run)xd:ulp#i:R
+#undef OPTSTR_patch
+#define OPTSTR_patch "(dry-run)d:ulp#i:R"
+#ifdef CLEANUP_patch
+#undef CLEANUP_patch
+#undef FOR_patch
+#undef FLAG_R
+#undef FLAG_i
+#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]
+#undef OPTSTR_pgrep
+#define OPTSTR_pgrep "?cld:u*U*t*s*P*g*G*fnovxL:[-no]"
+#ifdef CLEANUP_pgrep
+#undef CLEANUP_pgrep
+#undef FOR_pgrep
+#undef FLAG_L
+#undef FLAG_x
+#undef FLAG_v
+#undef FLAG_o
+#undef FLAG_n
+#undef FLAG_f
+#undef FLAG_G
+#undef FLAG_g
+#undef FLAG_P
+#undef FLAG_s
+#undef FLAG_t
+#undef FLAG_U
+#undef FLAG_u
+#undef FLAG_d
+#undef FLAG_l
+#undef FLAG_c
+#endif
+
+// pidof <1so: <1so:
+#undef OPTSTR_pidof
+#define OPTSTR_pidof "<1so:"
+#ifdef CLEANUP_pidof
+#undef CLEANUP_pidof
+#undef FOR_pidof
+#undef FLAG_o
+#undef FLAG_s
+#endif
+
+// ping   <1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]
+#undef OPTSTR_ping
+#define OPTSTR_ping "<1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]"
+#ifdef CLEANUP_ping
+#undef CLEANUP_ping
+#undef FOR_ping
+#undef FLAG_6
+#undef FLAG_4
+#undef FLAG_q
+#undef FLAG_w
+#undef FLAG_W
+#undef FLAG_I
+#undef FLAG_s
+#undef FLAG_c
+#undef FLAG_t
+#endif
+
+// pivot_root <2>2 <2>2
+#undef OPTSTR_pivot_root
+#define OPTSTR_pivot_root "<2>2"
+#ifdef CLEANUP_pivot_root
+#undef CLEANUP_pivot_root
+#undef FOR_pivot_root
+#endif
+
+// 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]"
+#ifdef CLEANUP_pkill
+#undef CLEANUP_pkill
+#undef FOR_pkill
+#undef FLAG_l
+#undef FLAG_x
+#undef FLAG_v
+#undef FLAG_o
+#undef FLAG_n
+#undef FLAG_f
+#undef FLAG_G
+#undef FLAG_g
+#undef FLAG_P
+#undef FLAG_s
+#undef FLAG_t
+#undef FLAG_U
+#undef FLAG_u
+#undef FLAG_V
+#endif
+
+// pmap <1xq <1xq
+#undef OPTSTR_pmap
+#define OPTSTR_pmap "<1xq"
+#ifdef CLEANUP_pmap
+#undef CLEANUP_pmap
+#undef FOR_pmap
+#undef FLAG_q
+#undef FLAG_x
+#endif
+
+// printenv 0(null) 0(null)
+#undef OPTSTR_printenv
+#define OPTSTR_printenv "0(null)"
+#ifdef CLEANUP_printenv
+#undef CLEANUP_printenv
+#undef FOR_printenv
+#undef FLAG_null
+#undef FLAG_0
+#endif
+
+// printf <1?^ <1?^
+#undef OPTSTR_printf
+#define OPTSTR_printf "<1?^"
+#ifdef CLEANUP_printf
+#undef CLEANUP_printf
+#undef FOR_printf
+#endif
+
+// ps k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO] k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]
+#undef OPTSTR_ps
+#define OPTSTR_ps "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]"
+#ifdef CLEANUP_ps
+#undef CLEANUP_ps
+#undef FOR_ps
+#undef FLAG_Z
+#undef FLAG_w
+#undef FLAG_G
+#undef FLAG_g
+#undef FLAG_U
+#undef FLAG_u
+#undef FLAG_T
+#undef FLAG_t
+#undef FLAG_s
+#undef FLAG_pid
+#undef FLAG_p
+#undef FLAG_O
+#undef FLAG_o
+#undef FLAG_n
+#undef FLAG_M
+#undef FLAG_l
+#undef FLAG_f
+#undef FLAG_e
+#undef FLAG_d
+#undef FLAG_A
+#undef FLAG_a
+#undef FLAG_ppid
+#undef FLAG_P
+#undef FLAG_sort
+#undef FLAG_k
+#endif
+
+// pwd >0LP[-LP] >0LP[-LP]
+#undef OPTSTR_pwd
+#define OPTSTR_pwd ">0LP[-LP]"
+#ifdef CLEANUP_pwd
+#undef CLEANUP_pwd
+#undef FOR_pwd
+#undef FLAG_P
+#undef FLAG_L
+#endif
+
+// pwdx <1a <1a
+#undef OPTSTR_pwdx
+#define OPTSTR_pwdx "<1a"
+#ifdef CLEANUP_pwdx
+#undef CLEANUP_pwdx
+#undef FOR_pwdx
+#undef FLAG_a
+#endif
+
+// readahead    
+#undef OPTSTR_readahead
+#define OPTSTR_readahead 0
+#ifdef CLEANUP_readahead
+#undef CLEANUP_readahead
+#undef FOR_readahead
+#endif
+
+// readlink <1>1fenq[-fe] <1>1fenq[-fe]
+#undef OPTSTR_readlink
+#define OPTSTR_readlink "<1>1fenq[-fe]"
+#ifdef CLEANUP_readlink
+#undef CLEANUP_readlink
+#undef FOR_readlink
+#undef FLAG_q
+#undef FLAG_n
+#undef FLAG_e
+#undef FLAG_f
+#endif
+
+// realpath <1 <1
+#undef OPTSTR_realpath
+#define OPTSTR_realpath "<1"
+#ifdef CLEANUP_realpath
+#undef CLEANUP_realpath
+#undef FOR_realpath
+#endif
+
+// reboot   fn
+#undef OPTSTR_reboot
+#define OPTSTR_reboot "fn"
+#ifdef CLEANUP_reboot
+#undef CLEANUP_reboot
+#undef FOR_reboot
+#undef FLAG_n
+#undef FLAG_f
+#endif
+
+// renice <1gpun#| <1gpun#|
+#undef OPTSTR_renice
+#define OPTSTR_renice "<1gpun#|"
+#ifdef CLEANUP_renice
+#undef CLEANUP_renice
+#undef FOR_renice
+#undef FLAG_n
+#undef FLAG_u
+#undef FLAG_p
+#undef FLAG_g
+#endif
+
+// reset    
+#undef OPTSTR_reset
+#define OPTSTR_reset 0
+#ifdef CLEANUP_reset
+#undef CLEANUP_reset
+#undef FOR_reset
+#endif
+
+// restorecon <1DFnRrv <1DFnRrv
+#undef OPTSTR_restorecon
+#define OPTSTR_restorecon "<1DFnRrv"
+#ifdef CLEANUP_restorecon
+#undef CLEANUP_restorecon
+#undef FOR_restorecon
+#undef FLAG_v
+#undef FLAG_r
+#undef FLAG_R
+#undef FLAG_n
+#undef FLAG_F
+#undef FLAG_D
+#endif
+
+// rev    
+#undef OPTSTR_rev
+#define OPTSTR_rev 0
+#ifdef CLEANUP_rev
+#undef CLEANUP_rev
+#undef FOR_rev
+#endif
+
+// rfkill <1>2 <1>2
+#undef OPTSTR_rfkill
+#define OPTSTR_rfkill "<1>2"
+#ifdef CLEANUP_rfkill
+#undef CLEANUP_rfkill
+#undef FOR_rfkill
+#endif
+
+// rm fiRr[-fi] fiRr[-fi]
+#undef OPTSTR_rm
+#define OPTSTR_rm "fiRr[-fi]"
+#ifdef CLEANUP_rm
+#undef CLEANUP_rm
+#undef FOR_rm
+#undef FLAG_r
+#undef FLAG_R
+#undef FLAG_i
+#undef FLAG_f
+#endif
+
+// rmdir <1p <1p
+#undef OPTSTR_rmdir
+#define OPTSTR_rmdir "<1p"
+#ifdef CLEANUP_rmdir
+#undef CLEANUP_rmdir
+#undef FOR_rmdir
+#undef FLAG_p
+#endif
+
+// rmmod <1wf <1wf
+#undef OPTSTR_rmmod
+#define OPTSTR_rmmod "<1wf"
+#ifdef CLEANUP_rmmod
+#undef CLEANUP_rmmod
+#undef FOR_rmmod
+#undef FLAG_f
+#undef FLAG_w
+#endif
+
+// route   ?neA:
+#undef OPTSTR_route
+#define OPTSTR_route "?neA:"
+#ifdef CLEANUP_route
+#undef CLEANUP_route
+#undef FOR_route
+#undef FLAG_A
+#undef FLAG_e
+#undef FLAG_n
+#endif
+
+// runcon <2 <2
+#undef OPTSTR_runcon
+#define OPTSTR_runcon "<2"
+#ifdef CLEANUP_runcon
+#undef CLEANUP_runcon
+#undef FOR_runcon
+#endif
+
+// sed (version)e*f*inEr[+Er] (version)e*f*inEr[+Er]
+#undef OPTSTR_sed
+#define OPTSTR_sed "(version)e*f*inEr[+Er]"
+#ifdef CLEANUP_sed
+#undef CLEANUP_sed
+#undef FOR_sed
+#undef FLAG_r
+#undef FLAG_E
+#undef FLAG_n
+#undef FLAG_i
+#undef FLAG_f
+#undef FLAG_e
+#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]"
+#ifdef CLEANUP_seq
+#undef CLEANUP_seq
+#undef FOR_seq
+#undef FLAG_w
+#undef FLAG_s
+#undef FLAG_f
+#endif
+
+// setenforce <1>1 <1>1
+#undef OPTSTR_setenforce
+#define OPTSTR_setenforce "<1>1"
+#ifdef CLEANUP_setenforce
+#undef CLEANUP_setenforce
+#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"
+#ifdef CLEANUP_setprop
+#undef CLEANUP_setprop
+#undef FOR_setprop
+#endif
+
+// setsid ^<1t ^<1t
+#undef OPTSTR_setsid
+#define OPTSTR_setsid "^<1t"
+#ifdef CLEANUP_setsid
+#undef CLEANUP_setsid
+#undef FOR_setsid
+#undef FLAG_t
+#endif
+
+// sh   c:i
+#undef OPTSTR_sh
+#define OPTSTR_sh "c:i"
+#ifdef CLEANUP_sh
+#undef CLEANUP_sh
+#undef FOR_sh
+#undef FLAG_i
+#undef FLAG_c
+#endif
+
+// sha1sum bc*[!bc] bc*[!bc]
+#undef OPTSTR_sha1sum
+#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 "<1zxus#<1n#<1o#<0f"
+#ifdef CLEANUP_shred
+#undef CLEANUP_shred
+#undef FOR_shred
+#undef FLAG_f
+#undef FLAG_o
+#undef FLAG_n
+#undef FLAG_s
+#undef FLAG_u
+#undef FLAG_x
+#undef FLAG_z
+#endif
+
+// skeleton   (walrus)(blubber):;(also):e@d*c#b:a
+#undef OPTSTR_skeleton
+#define OPTSTR_skeleton "(walrus)(blubber):;(also):e@d*c#b:a"
+#ifdef CLEANUP_skeleton
+#undef CLEANUP_skeleton
+#undef FOR_skeleton
+#undef FLAG_a
+#undef FLAG_b
+#undef FLAG_c
+#undef FLAG_d
+#undef FLAG_e
+#undef FLAG_also
+#undef FLAG_blubber
+#undef FLAG_walrus
+#endif
+
+// skeleton_alias   b#dq
+#undef OPTSTR_skeleton_alias
+#define OPTSTR_skeleton_alias "b#dq"
+#ifdef CLEANUP_skeleton_alias
+#undef CLEANUP_skeleton_alias
+#undef FOR_skeleton_alias
+#undef FLAG_q
+#undef FLAG_d
+#undef FLAG_b
+#endif
+
+// sleep <1 <1
+#undef OPTSTR_sleep
+#define OPTSTR_sleep "<1"
+#ifdef CLEANUP_sleep
+#undef CLEANUP_sleep
+#undef FOR_sleep
+#endif
+
+// sort gS:T:mo:k*t:xbMcszdfirun gS:T:mo:k*t:xbMcszdfirun
+#undef OPTSTR_sort
+#define OPTSTR_sort "gS:T:mo:k*t:xbMcszdfirun"
+#ifdef CLEANUP_sort
+#undef CLEANUP_sort
+#undef FOR_sort
+#undef FLAG_n
+#undef FLAG_u
+#undef FLAG_r
+#undef FLAG_i
+#undef FLAG_f
+#undef FLAG_d
+#undef FLAG_z
+#undef FLAG_s
+#undef FLAG_c
+#undef FLAG_M
+#undef FLAG_b
+#undef FLAG_x
+#undef FLAG_t
+#undef FLAG_k
+#undef FLAG_o
+#undef FLAG_m
+#undef FLAG_T
+#undef FLAG_S
+#undef FLAG_g
+#endif
+
+// split >2a#<1=2>9b#<1l#<1 >2a#<1=2>9b#<1l#<1
+#undef OPTSTR_split
+#define OPTSTR_split ">2a#<1=2>9b#<1l#<1"
+#ifdef CLEANUP_split
+#undef CLEANUP_split
+#undef FOR_split
+#undef FLAG_l
+#undef FLAG_b
+#undef FLAG_a
+#endif
+
+// 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: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"
+#ifdef CLEANUP_strings
+#undef CLEANUP_strings
+#undef FOR_strings
+#undef FLAG_o
+#undef FLAG_f
+#undef FLAG_n
+#undef FLAG_a
+#endif
+
+// su   lmpc:s:
+#undef OPTSTR_su
+#define OPTSTR_su "lmpc:s:"
+#ifdef CLEANUP_su
+#undef CLEANUP_su
+#undef FOR_su
+#undef FLAG_s
+#undef FLAG_c
+#undef FLAG_p
+#undef FLAG_m
+#undef FLAG_l
+#endif
+
+// sulogin   t#<0=0
+#undef OPTSTR_sulogin
+#define OPTSTR_sulogin "t#<0=0"
+#ifdef CLEANUP_sulogin
+#undef CLEANUP_sulogin
+#undef FOR_sulogin
+#undef FLAG_t
+#endif
+
+// swapoff <1>1 <1>1
+#undef OPTSTR_swapoff
+#define OPTSTR_swapoff "<1>1"
+#ifdef CLEANUP_swapoff
+#undef CLEANUP_swapoff
+#undef FOR_swapoff
+#endif
+
+// swapon <1>1p#<0>32767d <1>1p#<0>32767d
+#undef OPTSTR_swapon
+#define OPTSTR_swapon "<1>1p#<0>32767d"
+#ifdef CLEANUP_swapon
+#undef CLEANUP_swapon
+#undef FOR_swapon
+#undef FLAG_d
+#undef FLAG_p
+#endif
+
+// switch_root   <2c:h
+#undef OPTSTR_switch_root
+#define OPTSTR_switch_root "<2c:h"
+#ifdef CLEANUP_switch_root
+#undef CLEANUP_switch_root
+#undef FOR_switch_root
+#undef FLAG_h
+#undef FLAG_c
+#endif
+
+// sync    
+#undef OPTSTR_sync
+#define OPTSTR_sync 0
+#ifdef CLEANUP_sync
+#undef CLEANUP_sync
+#undef FOR_sync
+#endif
+
+// sysctl ^neNqwpaA[!ap][!aq][!aw][+aA] ^neNqwpaA[!ap][!aq][!aw][+aA]
+#undef OPTSTR_sysctl
+#define OPTSTR_sysctl "^neNqwpaA[!ap][!aq][!aw][+aA]"
+#ifdef CLEANUP_sysctl
+#undef CLEANUP_sysctl
+#undef FOR_sysctl
+#undef FLAG_A
+#undef FLAG_a
+#undef FLAG_p
+#undef FLAG_w
+#undef FLAG_q
+#undef FLAG_N
+#undef FLAG_e
+#undef FLAG_n
+#endif
+
+// syslogd   >0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD
+#undef OPTSTR_syslogd
+#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
+#undef FLAG_D
+#undef FLAG_L
+#undef FLAG_K
+#undef FLAG_S
+#undef FLAG_n
+#undef FLAG_a
+#undef FLAG_f
+#undef FLAG_p
+#undef FLAG_O
+#undef FLAG_m
+#undef FLAG_s
+#undef FLAG_b
+#undef FLAG_R
+#undef FLAG_l
+#endif
+
+// tac    
+#undef OPTSTR_tac
+#define OPTSTR_tac 0
+#ifdef CLEANUP_tac
+#undef CLEANUP_tac
+#undef FOR_tac
+#endif
+
+// tail ?fc-n-[-cn] ?fc-n-[-cn]
+#undef OPTSTR_tail
+#define OPTSTR_tail "?fc-n-[-cn]"
+#ifdef CLEANUP_tail
+#undef CLEANUP_tail
+#undef FOR_tail
+#undef FLAG_n
+#undef FLAG_c
+#undef FLAG_f
+#endif
+
+// tar &(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc] &(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc]
+#undef OPTSTR_tar
+#define OPTSTR_tar "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc]"
+#ifdef CLEANUP_tar
+#undef CLEANUP_tar
+#undef FOR_tar
+#undef FLAG_file
+#undef FLAG_f
+#undef FLAG_directory
+#undef FLAG_C
+#undef FLAG_files_from
+#undef FLAG_T
+#undef FLAG_exclude_from
+#undef FLAG_X
+#undef FLAG_touch
+#undef FLAG_m
+#undef FLAG_to_stdout
+#undef FLAG_O
+#undef FLAG_gzip
+#undef FLAG_z
+#undef FLAG_verbose
+#undef FLAG_v
+#undef FLAG_list
+#undef FLAG_t
+#undef FLAG_extract
+#undef FLAG_x
+#undef FLAG_dereference
+#undef FLAG_h
+#undef FLAG_create
+#undef FLAG_c
+#undef FLAG_keep_old
+#undef FLAG_k
+#undef FLAG_same_permissions
+#undef FLAG_p
+#undef FLAG_no_same_owner
+#undef FLAG_o
+#undef FLAG_to_command
+#undef FLAG_exclude
+#undef FLAG_overwrite
+#undef FLAG_no_same_permissions
+#undef FLAG_numeric_owner
+#undef FLAG_no_recursion
+#endif
+
+// taskset <1^pa <1^pa
+#undef OPTSTR_taskset
+#define OPTSTR_taskset "<1^pa"
+#ifdef CLEANUP_taskset
+#undef CLEANUP_taskset
+#undef FOR_taskset
+#undef FLAG_a
+#undef FLAG_p
+#endif
+
+// tcpsvd   ^<3c#=30<1C:b#=20<0u:l:hEv
+#undef OPTSTR_tcpsvd
+#define OPTSTR_tcpsvd "^<3c#=30<1C:b#=20<0u:l:hEv"
+#ifdef CLEANUP_tcpsvd
+#undef CLEANUP_tcpsvd
+#undef FOR_tcpsvd
+#undef FLAG_v
+#undef FLAG_E
+#undef FLAG_h
+#undef FLAG_l
+#undef FLAG_u
+#undef FLAG_b
+#undef FLAG_C
+#undef FLAG_c
+#endif
+
+// tee ia ia
+#undef OPTSTR_tee
+#define OPTSTR_tee "ia"
+#ifdef CLEANUP_tee
+#undef CLEANUP_tee
+#undef FOR_tee
+#undef FLAG_a
+#undef FLAG_i
+#endif
+
+// telnet   <1>2
+#undef OPTSTR_telnet
+#define OPTSTR_telnet "<1>2"
+#ifdef CLEANUP_telnet
+#undef CLEANUP_telnet
+#undef FOR_telnet
+#endif
+
+// telnetd   w#<0b:p#<0>65535=23f:l:FSKi[!wi]
+#undef OPTSTR_telnetd
+#define OPTSTR_telnetd "w#<0b:p#<0>65535=23f:l:FSKi[!wi]"
+#ifdef CLEANUP_telnetd
+#undef CLEANUP_telnetd
+#undef FOR_telnetd
+#undef FLAG_i
+#undef FLAG_K
+#undef FLAG_S
+#undef FLAG_F
+#undef FLAG_l
+#undef FLAG_f
+#undef FLAG_p
+#undef FLAG_b
+#undef FLAG_w
+#endif
+
+// test    
+#undef OPTSTR_test
+#define OPTSTR_test 0
+#ifdef CLEANUP_test
+#undef CLEANUP_test
+#undef FOR_test
+#endif
+
+// test_human_readable   <1>1ibs
+#undef OPTSTR_test_human_readable
+#define OPTSTR_test_human_readable "<1>1ibs"
+#ifdef CLEANUP_test_human_readable
+#undef CLEANUP_test_human_readable
+#undef FOR_test_human_readable
+#undef FLAG_s
+#undef FLAG_b
+#undef FLAG_i
+#endif
+
+// test_many_options   ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba
+#undef OPTSTR_test_many_options
+#define OPTSTR_test_many_options "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
+#ifdef CLEANUP_test_many_options
+#undef CLEANUP_test_many_options
+#undef FOR_test_many_options
+#undef FLAG_a
+#undef FLAG_b
+#undef FLAG_c
+#undef FLAG_d
+#undef FLAG_e
+#undef FLAG_f
+#undef FLAG_g
+#undef FLAG_h
+#undef FLAG_i
+#undef FLAG_j
+#undef FLAG_k
+#undef FLAG_l
+#undef FLAG_m
+#undef FLAG_n
+#undef FLAG_o
+#undef FLAG_p
+#undef FLAG_q
+#undef FLAG_r
+#undef FLAG_s
+#undef FLAG_t
+#undef FLAG_u
+#undef FLAG_v
+#undef FLAG_w
+#undef FLAG_x
+#undef FLAG_y
+#undef FLAG_z
+#undef FLAG_A
+#undef FLAG_B
+#undef FLAG_C
+#undef FLAG_D
+#undef FLAG_E
+#undef FLAG_F
+#undef FLAG_G
+#undef FLAG_H
+#undef FLAG_I
+#undef FLAG_J
+#undef FLAG_K
+#undef FLAG_L
+#undef FLAG_M
+#undef FLAG_N
+#undef FLAG_O
+#undef FLAG_P
+#undef FLAG_Q
+#undef FLAG_R
+#undef FLAG_S
+#undef FLAG_T
+#undef FLAG_U
+#undef FLAG_V
+#undef FLAG_W
+#undef FLAG_X
+#undef FLAG_Y
+#undef FLAG_Z
+#endif
+
+// test_scankey    
+#undef OPTSTR_test_scankey
+#define OPTSTR_test_scankey 0
+#ifdef CLEANUP_test_scankey
+#undef CLEANUP_test_scankey
+#undef FOR_test_scankey
+#endif
+
+// tftp   <1b#<8>65464r:l:g|p|[!gp]
+#undef OPTSTR_tftp
+#define OPTSTR_tftp "<1b#<8>65464r:l:g|p|[!gp]"
+#ifdef CLEANUP_tftp
+#undef CLEANUP_tftp
+#undef FOR_tftp
+#undef FLAG_p
+#undef FLAG_g
+#undef FLAG_l
+#undef FLAG_r
+#undef FLAG_b
+#endif
+
+// tftpd   rcu:l
+#undef OPTSTR_tftpd
+#define OPTSTR_tftpd "rcu:l"
+#ifdef CLEANUP_tftpd
+#undef CLEANUP_tftpd
+#undef FOR_tftpd
+#undef FLAG_l
+#undef FLAG_u
+#undef FLAG_c
+#undef FLAG_r
+#endif
+
+// time <1^p <1^p
+#undef OPTSTR_time
+#define OPTSTR_time "<1^p"
+#ifdef CLEANUP_time
+#undef CLEANUP_time
+#undef FOR_time
+#undef FLAG_p
+#endif
+
+// timeout <2^vk:s:  <2^vk:s: 
+#undef OPTSTR_timeout
+#define OPTSTR_timeout "<2^vk:s: "
+#ifdef CLEANUP_timeout
+#undef CLEANUP_timeout
+#undef FOR_timeout
+#undef FLAG_s
+#undef FLAG_k
+#undef FLAG_v
+#endif
+
+// 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 ">0mO*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]"
+#ifdef CLEANUP_top
+#undef CLEANUP_top
+#undef FOR_top
+#undef FLAG_q
+#undef FLAG_b
+#undef FLAG_n
+#undef FLAG_d
+#undef FLAG_s
+#undef FLAG_u
+#undef FLAG_p
+#undef FLAG_o
+#undef FLAG_k
+#undef FLAG_H
+#undef FLAG_O
+#undef FLAG_m
+#endif
+
+// touch acd:mr:t:h[!dtr] acd:mr:t:h[!dtr]
+#undef OPTSTR_touch
+#define OPTSTR_touch "acd:mr:t:h[!dtr]"
+#ifdef CLEANUP_touch
+#undef CLEANUP_touch
+#undef FOR_touch
+#undef FLAG_h
+#undef FLAG_t
+#undef FLAG_r
+#undef FLAG_m
+#undef FLAG_d
+#undef FLAG_c
+#undef FLAG_a
+#endif
+
+// toybox    
+#undef OPTSTR_toybox
+#define OPTSTR_toybox 0
+#ifdef CLEANUP_toybox
+#undef CLEANUP_toybox
+#undef FOR_toybox
+#endif
+
+// tr ^>2<1Ccsd[+cC] ^>2<1Ccsd[+cC]
+#undef OPTSTR_tr
+#define OPTSTR_tr "^>2<1Ccsd[+cC]"
+#ifdef CLEANUP_tr
+#undef CLEANUP_tr
+#undef FOR_tr
+#undef FLAG_d
+#undef FLAG_s
+#undef FLAG_c
+#undef FLAG_C
+#endif
+
+// 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 <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
+#undef OPTSTR_traceroute
+#define OPTSTR_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"
+#ifdef CLEANUP_traceroute
+#undef CLEANUP_traceroute
+#undef FOR_traceroute
+#undef FLAG_4
+#undef FLAG_6
+#undef FLAG_F
+#undef FLAG_U
+#undef FLAG_I
+#undef FLAG_l
+#undef FLAG_d
+#undef FLAG_n
+#undef FLAG_v
+#undef FLAG_r
+#undef FLAG_m
+#undef FLAG_p
+#undef FLAG_q
+#undef FLAG_s
+#undef FLAG_t
+#undef FLAG_w
+#undef FLAG_g
+#undef FLAG_z
+#undef FLAG_f
+#undef FLAG_i
+#endif
+
+// true    
+#undef OPTSTR_true
+#define OPTSTR_true 0
+#ifdef CLEANUP_true
+#undef CLEANUP_true
+#undef FOR_true
+#endif
+
+// truncate <1s:|c <1s:|c
+#undef OPTSTR_truncate
+#define OPTSTR_truncate "<1s:|c"
+#ifdef CLEANUP_truncate
+#undef CLEANUP_truncate
+#undef FOR_truncate
+#undef FLAG_c
+#undef FLAG_s
+#endif
+
+// tty s s
+#undef OPTSTR_tty
+#define OPTSTR_tty "s"
+#ifdef CLEANUP_tty
+#undef CLEANUP_tty
+#undef FOR_tty
+#undef FLAG_s
+#endif
+
+// ulimit >1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc] >1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]
+#undef OPTSTR_ulimit
+#define OPTSTR_ulimit ">1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]"
+#ifdef CLEANUP_ulimit
+#undef CLEANUP_ulimit
+#undef FOR_ulimit
+#undef FLAG_c
+#undef FLAG_d
+#undef FLAG_e
+#undef FLAG_f
+#undef FLAG_i
+#undef FLAG_l
+#undef FLAG_m
+#undef FLAG_n
+#undef FLAG_p
+#undef FLAG_q
+#undef FLAG_R
+#undef FLAG_r
+#undef FLAG_s
+#undef FLAG_t
+#undef FLAG_u
+#undef FLAG_v
+#undef FLAG_a
+#undef FLAG_H
+#undef FLAG_S
+#undef FLAG_P
+#endif
+
+// umount ndDflrat*v[!na] ndDflrat*v[!na]
+#undef OPTSTR_umount
+#define OPTSTR_umount "ndDflrat*v[!na]"
+#ifdef CLEANUP_umount
+#undef CLEANUP_umount
+#undef FOR_umount
+#undef FLAG_v
+#undef FLAG_t
+#undef FLAG_a
+#undef FLAG_r
+#undef FLAG_l
+#undef FLAG_f
+#undef FLAG_D
+#undef FLAG_d
+#undef FLAG_n
+#endif
+
+// uname oamvrns[+os] oamvrns[+os]
+#undef OPTSTR_uname
+#define OPTSTR_uname "oamvrns[+os]"
+#ifdef CLEANUP_uname
+#undef CLEANUP_uname
+#undef FOR_uname
+#undef FLAG_s
+#undef FLAG_n
+#undef FLAG_r
+#undef FLAG_v
+#undef FLAG_m
+#undef FLAG_a
+#undef FLAG_o
+#endif
+
+// uniq f#s#w#zicdu f#s#w#zicdu
+#undef OPTSTR_uniq
+#define OPTSTR_uniq "f#s#w#zicdu"
+#ifdef CLEANUP_uniq
+#undef CLEANUP_uniq
+#undef FOR_uniq
+#undef FLAG_u
+#undef FLAG_d
+#undef FLAG_c
+#undef FLAG_i
+#undef FLAG_z
+#undef FLAG_w
+#undef FLAG_s
+#undef FLAG_f
+#endif
+
+// unix2dos    
+#undef OPTSTR_unix2dos
+#define OPTSTR_unix2dos 0
+#ifdef CLEANUP_unix2dos
+#undef CLEANUP_unix2dos
+#undef FOR_unix2dos
+#endif
+
+// unlink   <1>1
+#undef OPTSTR_unlink
+#define OPTSTR_unlink "<1>1"
+#ifdef CLEANUP_unlink
+#undef CLEANUP_unlink
+#undef FOR_unlink
+#endif
+
+// 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 "<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
+#undef FLAG_user
+#undef FLAG_U
+#undef FLAG_uts
+#undef FLAG_u
+#undef FLAG_pid
+#undef FLAG_p
+#undef FLAG_net
+#undef FLAG_n
+#undef FLAG_mount
+#undef FLAG_m
+#undef FLAG_ipc
+#undef FLAG_i
+#undef FLAG_map_root_user
+#undef FLAG_r
+#undef FLAG_fork
+#undef FLAG_f
+#endif
+
+// uptime    
+#undef OPTSTR_uptime
+#define OPTSTR_uptime 0
+#ifdef CLEANUP_uptime
+#undef CLEANUP_uptime
+#undef FOR_uptime
+#endif
+
+// useradd   <1>2u#<0G:s:g:h:SDH
+#undef OPTSTR_useradd
+#define OPTSTR_useradd "<1>2u#<0G:s:g:h:SDH"
+#ifdef CLEANUP_useradd
+#undef CLEANUP_useradd
+#undef FOR_useradd
+#undef FLAG_H
+#undef FLAG_D
+#undef FLAG_S
+#undef FLAG_h
+#undef FLAG_g
+#undef FLAG_s
+#undef FLAG_G
+#undef FLAG_u
+#endif
+
+// userdel   <1>1r
+#undef OPTSTR_userdel
+#define OPTSTR_userdel "<1>1r"
+#ifdef CLEANUP_userdel
+#undef CLEANUP_userdel
+#undef FOR_userdel
+#undef FLAG_r
+#endif
+
+// usleep <1 <1
+#undef OPTSTR_usleep
+#define OPTSTR_usleep "<1"
+#ifdef CLEANUP_usleep
+#undef CLEANUP_usleep
+#undef FOR_usleep
+#endif
+
+// uudecode   >1o:
+#undef OPTSTR_uudecode
+#define OPTSTR_uudecode ">1o:"
+#ifdef CLEANUP_uudecode
+#undef CLEANUP_uudecode
+#undef FOR_uudecode
+#undef FLAG_o
+#endif
+
+// uuencode   <1>2m
+#undef OPTSTR_uuencode
+#define OPTSTR_uuencode "<1>2m"
+#ifdef CLEANUP_uuencode
+#undef CLEANUP_uuencode
+#undef FOR_uuencode
+#undef FLAG_m
+#endif
+
+// vconfig <2>4 <2>4
+#undef OPTSTR_vconfig
+#define OPTSTR_vconfig "<2>4"
+#ifdef CLEANUP_vconfig
+#undef CLEANUP_vconfig
+#undef FOR_vconfig
+#endif
+
+// vi   <1>1
+#undef OPTSTR_vi
+#define OPTSTR_vi "<1>1"
+#ifdef CLEANUP_vi
+#undef CLEANUP_vi
+#undef FOR_vi
+#endif
+
+// vmstat >2n >2n
+#undef OPTSTR_vmstat
+#define OPTSTR_vmstat ">2n"
+#ifdef CLEANUP_vmstat
+#undef CLEANUP_vmstat
+#undef FOR_vmstat
+#undef FLAG_n
+#endif
+
+// w    
+#undef OPTSTR_w
+#define OPTSTR_w 0
+#ifdef CLEANUP_w
+#undef CLEANUP_w
+#undef FOR_w
+#endif
+
+// watch   ^<1n#<0=2te
+#undef OPTSTR_watch
+#define OPTSTR_watch "^<1n#<0=2te"
+#ifdef CLEANUP_watch
+#undef CLEANUP_watch
+#undef FOR_watch
+#undef FLAG_e
+#undef FLAG_t
+#undef FLAG_n
+#endif
+
+// wc mcwl mcwl
+#undef OPTSTR_wc
+#define OPTSTR_wc "mcwl"
+#ifdef CLEANUP_wc
+#undef CLEANUP_wc
+#undef FOR_wc
+#undef FLAG_l
+#undef FLAG_w
+#undef FLAG_c
+#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"
+#ifdef CLEANUP_which
+#undef CLEANUP_which
+#undef FOR_which
+#undef FLAG_a
+#endif
+
+// who   a
+#undef OPTSTR_who
+#define OPTSTR_who "a"
+#ifdef CLEANUP_who
+#undef CLEANUP_who
+#undef FOR_who
+#undef FLAG_a
+#endif
+
+// xargs ^I:E:L#ptxrn#<1s#0 ^I:E:L#ptxrn#<1s#0
+#undef OPTSTR_xargs
+#define OPTSTR_xargs "^I:E:L#ptxrn#<1s#0"
+#ifdef CLEANUP_xargs
+#undef CLEANUP_xargs
+#undef FOR_xargs
+#undef FLAG_0
+#undef FLAG_s
+#undef FLAG_n
+#undef FLAG_r
+#undef FLAG_x
+#undef FLAG_t
+#undef FLAG_p
+#undef FLAG_L
+#undef FLAG_E
+#undef FLAG_I
+#endif
+
+// 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=2prs#[!rs]"
+#ifdef CLEANUP_xxd
+#undef CLEANUP_xxd
+#undef FOR_xxd
+#undef FLAG_s
+#undef FLAG_r
+#undef FLAG_p
+#undef FLAG_g
+#undef FLAG_l
+#undef FLAG_c
+#endif
+
+// xzcat    
+#undef OPTSTR_xzcat
+#define OPTSTR_xzcat 0
+#ifdef CLEANUP_xzcat
+#undef CLEANUP_xzcat
+#undef FOR_xzcat
+#endif
+
+// yes    
+#undef OPTSTR_yes
+#define OPTSTR_yes 0
+#ifdef CLEANUP_yes
+#undef CLEANUP_yes
+#undef FOR_yes
+#endif
+
+// zcat    
+#undef OPTSTR_zcat
+#define OPTSTR_zcat 0
+#ifdef CLEANUP_zcat
+#undef CLEANUP_zcat
+#undef FOR_zcat
+#endif
+
+#ifdef FOR_acpi
+#ifndef TT
+#define TT this.acpi
+#endif
+#define FLAG_V (1<<0)
+#define FLAG_t (1<<1)
+#define FLAG_c (1<<2)
+#define FLAG_b (1<<3)
+#define FLAG_a (1<<4)
+#endif
+
+#ifdef FOR_arp
+#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)
+#endif
+
+#ifdef FOR_arping
+#ifndef TT
+#define TT this.arping
+#endif
+#define FLAG_f (FORCED_FLAG<<0)
+#define FLAG_q (FORCED_FLAG<<1)
+#define FLAG_b (FORCED_FLAG<<2)
+#define FLAG_D (FORCED_FLAG<<3)
+#define FLAG_U (FORCED_FLAG<<4)
+#define FLAG_A (FORCED_FLAG<<5)
+#define FLAG_c (FORCED_FLAG<<6)
+#define FLAG_w (FORCED_FLAG<<7)
+#define FLAG_I (FORCED_FLAG<<8)
+#define FLAG_s (FORCED_FLAG<<9)
+#endif
+
+#ifdef FOR_base64
+#ifndef TT
+#define TT this.base64
+#endif
+#define FLAG_w (1<<0)
+#define FLAG_i (1<<1)
+#define FLAG_d (1<<2)
+#endif
+
+#ifdef FOR_basename
+#ifndef TT
+#define TT this.basename
+#endif
+#endif
+
+#ifdef FOR_blkid
+#ifndef TT
+#define TT this.blkid
+#endif
+#endif
+
+#ifdef FOR_blockdev
+#ifndef TT
+#define TT this.blockdev
+#endif
+#define FLAG_rereadpt (1<<0)
+#define FLAG_flushbufs (1<<1)
+#define FLAG_getsize64 (1<<2)
+#define FLAG_getsize (1<<3)
+#define FLAG_getsz (1<<4)
+#define FLAG_setbsz (1<<5)
+#define FLAG_getbsz (1<<6)
+#define FLAG_getss (1<<7)
+#define FLAG_getro (1<<8)
+#define FLAG_setrw (1<<9)
+#define FLAG_setro (1<<10)
+#endif
+
+#ifdef FOR_bootchartd
+#ifndef TT
+#define TT this.bootchartd
+#endif
+#endif
+
+#ifdef FOR_brctl
+#ifndef TT
+#define TT this.brctl
+#endif
+#endif
+
+#ifdef FOR_bunzip2
+#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)
+#endif
+
+#ifdef FOR_bzcat
+#ifndef TT
+#define TT this.bzcat
+#endif
+#endif
+
+#ifdef FOR_cal
+#ifndef TT
+#define TT this.cal
+#endif
+#endif
+
+#ifdef FOR_cat
+#ifndef TT
+#define TT this.cat
+#endif
+#define FLAG_e (1<<0)
+#define FLAG_t (1<<1)
+#define FLAG_v (1<<2)
+#define FLAG_u (1<<3)
+#endif
+
+#ifdef FOR_catv
+#ifndef TT
+#define TT this.catv
+#endif
+#define FLAG_e (FORCED_FLAG<<0)
+#define FLAG_t (FORCED_FLAG<<1)
+#define FLAG_v (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_cd
+#ifndef TT
+#define TT this.cd
+#endif
+#endif
+
+#ifdef FOR_chattr
+#ifndef TT
+#define TT this.chattr
+#endif
+#endif
+
+#ifdef FOR_chcon
+#ifndef TT
+#define TT this.chcon
+#endif
+#define FLAG_R (1<<0)
+#define FLAG_v (1<<1)
+#define FLAG_h (1<<2)
+#endif
+
+#ifdef FOR_chgrp
+#ifndef TT
+#define TT this.chgrp
+#endif
+#define FLAG_v (1<<0)
+#define FLAG_f (1<<1)
+#define FLAG_R (1<<2)
+#define FLAG_H (1<<3)
+#define FLAG_L (1<<4)
+#define FLAG_P (1<<5)
+#define FLAG_h (1<<6)
+#endif
+
+#ifdef FOR_chmod
+#ifndef TT
+#define TT this.chmod
+#endif
+#define FLAG_f (1<<0)
+#define FLAG_R (1<<1)
+#define FLAG_v (1<<2)
+#endif
+
+#ifdef FOR_chroot
+#ifndef TT
+#define TT this.chroot
+#endif
+#endif
+
+#ifdef FOR_chvt
+#ifndef TT
+#define TT this.chvt
+#endif
+#endif
+
+#ifdef FOR_cksum
+#ifndef TT
+#define TT this.cksum
+#endif
+#define FLAG_N (1<<0)
+#define FLAG_L (1<<1)
+#define FLAG_P (1<<2)
+#define FLAG_I (1<<3)
+#define FLAG_H (1<<4)
+#endif
+
+#ifdef FOR_clear
+#ifndef TT
+#define TT this.clear
+#endif
+#endif
+
+#ifdef FOR_cmp
+#ifndef TT
+#define TT this.cmp
+#endif
+#define FLAG_s (1<<0)
+#define FLAG_l (1<<1)
+#endif
+
+#ifdef FOR_comm
+#ifndef TT
+#define TT this.comm
+#endif
+#define FLAG_1 (1<<0)
+#define FLAG_2 (1<<1)
+#define FLAG_3 (1<<2)
+#endif
+
+#ifdef FOR_compress
+#ifndef TT
+#define TT this.compress
+#endif
+#define FLAG_g (FORCED_FLAG<<0)
+#define FLAG_r (FORCED_FLAG<<1)
+#define FLAG_l (FORCED_FLAG<<2)
+#define FLAG_9 (FORCED_FLAG<<3)
+#define FLAG_d (FORCED_FLAG<<4)
+#define FLAG_c (FORCED_FLAG<<5)
+#define FLAG_z (FORCED_FLAG<<6)
+#endif
+
+#ifdef FOR_count
+#ifndef TT
+#define TT this.count
+#endif
+#endif
+
+#ifdef FOR_cp
+#ifndef TT
+#define TT this.cp
+#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)
+#define FLAG_l (1<<5)
+#define FLAG_s (1<<6)
+#define FLAG_a (1<<7)
+#define FLAG_d (1<<8)
+#define FLAG_r (1<<9)
+#define FLAG_p (1<<10)
+#define FLAG_P (1<<11)
+#define FLAG_L (1<<12)
+#define FLAG_H (1<<13)
+#define FLAG_R (1<<14)
+#define FLAG_preserve (1<<15)
+#endif
+
+#ifdef FOR_cpio
+#ifndef TT
+#define TT this.cpio
+#endif
+#define FLAG_o (1<<0)
+#define FLAG_verbose (1<<1)
+#define FLAG_v (1<<1)
+#define FLAG_F (1<<2)
+#define FLAG_t (1<<3)
+#define FLAG_i (1<<4)
+#define FLAG_p (1<<5)
+#define FLAG_H (1<<6)
+#define FLAG_u (1<<7)
+#define FLAG_d (1<<8)
+#define FLAG_m (1<<9)
+#define FLAG_no_preserve_owner (1<<10)
+#endif
+
+#ifdef FOR_crond
+#ifndef TT
+#define TT this.crond
+#endif
+#define FLAG_c (FORCED_FLAG<<0)
+#define FLAG_L (FORCED_FLAG<<1)
+#define FLAG_d (FORCED_FLAG<<2)
+#define FLAG_l (FORCED_FLAG<<3)
+#define FLAG_S (FORCED_FLAG<<4)
+#define FLAG_b (FORCED_FLAG<<5)
+#define FLAG_f (FORCED_FLAG<<6)
+#endif
+
+#ifdef FOR_crontab
+#ifndef TT
+#define TT this.crontab
+#endif
+#define FLAG_r (FORCED_FLAG<<0)
+#define FLAG_l (FORCED_FLAG<<1)
+#define FLAG_e (FORCED_FLAG<<2)
+#define FLAG_u (FORCED_FLAG<<3)
+#define FLAG_c (FORCED_FLAG<<4)
+#endif
+
+#ifdef FOR_cut
+#ifndef TT
+#define TT this.cut
+#endif
+#define FLAG_n (1<<0)
+#define FLAG_s (1<<1)
+#define FLAG_d (1<<2)
+#define FLAG_f (1<<3)
+#define FLAG_c (1<<4)
+#define FLAG_b (1<<5)
+#endif
+
+#ifdef FOR_date
+#ifndef TT
+#define TT this.date
+#endif
+#define FLAG_u (1<<0)
+#define FLAG_r (1<<1)
+#define FLAG_D (1<<2)
+#define FLAG_d (1<<3)
+#endif
+
+#ifdef FOR_dd
+#ifndef TT
+#define TT this.dd
+#endif
+#endif
+
+#ifdef FOR_deallocvt
+#ifndef TT
+#define TT this.deallocvt
+#endif
+#endif
+
+#ifdef FOR_df
+#ifndef TT
+#define TT this.df
+#endif
+#define FLAG_a (1<<0)
+#define FLAG_t (1<<1)
+#define FLAG_h (1<<2)
+#define FLAG_k (1<<3)
+#define FLAG_P (1<<4)
+#define FLAG_H (1<<5)
+#endif
+
+#ifdef FOR_dhcp
+#ifndef TT
+#define TT this.dhcp
+#endif
+#define FLAG_f (FORCED_FLAG<<0)
+#define FLAG_b (FORCED_FLAG<<1)
+#define FLAG_n (FORCED_FLAG<<2)
+#define FLAG_q (FORCED_FLAG<<3)
+#define FLAG_v (FORCED_FLAG<<4)
+#define FLAG_o (FORCED_FLAG<<5)
+#define FLAG_a (FORCED_FLAG<<6)
+#define FLAG_C (FORCED_FLAG<<7)
+#define FLAG_R (FORCED_FLAG<<8)
+#define FLAG_B (FORCED_FLAG<<9)
+#define FLAG_S (FORCED_FLAG<<10)
+#define FLAG_i (FORCED_FLAG<<11)
+#define FLAG_p (FORCED_FLAG<<12)
+#define FLAG_s (FORCED_FLAG<<13)
+#define FLAG_t (FORCED_FLAG<<14)
+#define FLAG_T (FORCED_FLAG<<15)
+#define FLAG_A (FORCED_FLAG<<16)
+#define FLAG_O (FORCED_FLAG<<17)
+#define FLAG_r (FORCED_FLAG<<18)
+#define FLAG_x (FORCED_FLAG<<19)
+#define FLAG_F (FORCED_FLAG<<20)
+#define FLAG_H (FORCED_FLAG<<21)
+#define FLAG_V (FORCED_FLAG<<22)
+#endif
+
+#ifdef FOR_dhcp6
+#ifndef TT
+#define TT this.dhcp6
+#endif
+#define FLAG_f (FORCED_FLAG<<0)
+#define FLAG_b (FORCED_FLAG<<1)
+#define FLAG_n (FORCED_FLAG<<2)
+#define FLAG_q (FORCED_FLAG<<3)
+#define FLAG_v (FORCED_FLAG<<4)
+#define FLAG_R (FORCED_FLAG<<5)
+#define FLAG_S (FORCED_FLAG<<6)
+#define FLAG_i (FORCED_FLAG<<7)
+#define FLAG_p (FORCED_FLAG<<8)
+#define FLAG_s (FORCED_FLAG<<9)
+#define FLAG_t (FORCED_FLAG<<10)
+#define FLAG_T (FORCED_FLAG<<11)
+#define FLAG_A (FORCED_FLAG<<12)
+#define FLAG_r (FORCED_FLAG<<13)
+#endif
+
+#ifdef FOR_dhcpd
+#ifndef TT
+#define TT this.dhcpd
+#endif
+#define FLAG_6 (FORCED_FLAG<<0)
+#define FLAG_4 (FORCED_FLAG<<1)
+#define FLAG_S (FORCED_FLAG<<2)
+#define FLAG_i (FORCED_FLAG<<3)
+#define FLAG_f (FORCED_FLAG<<4)
+#define FLAG_P (FORCED_FLAG<<5)
+#endif
+
+#ifdef FOR_diff
+#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)
+#endif
+
+#ifdef FOR_dirname
+#ifndef TT
+#define TT this.dirname
+#endif
+#endif
+
+#ifdef FOR_dmesg
+#ifndef TT
+#define TT this.dmesg
+#endif
+#define FLAG_c (1<<0)
+#define FLAG_n (1<<1)
+#define FLAG_s (1<<2)
+#define FLAG_r (1<<3)
+#define FLAG_t (1<<4)
+#endif
+
+#ifdef FOR_dos2unix
+#ifndef TT
+#define TT this.dos2unix
+#endif
+#endif
+
+#ifdef FOR_du
+#ifndef TT
+#define TT this.du
+#endif
+#define FLAG_x (1<<0)
+#define FLAG_s (1<<1)
+#define FLAG_L (1<<2)
+#define FLAG_K (1<<3)
+#define FLAG_k (1<<4)
+#define FLAG_H (1<<5)
+#define FLAG_a (1<<6)
+#define FLAG_c (1<<7)
+#define FLAG_l (1<<8)
+#define FLAG_m (1<<9)
+#define FLAG_h (1<<10)
+#define FLAG_d (1<<11)
+#endif
+
+#ifdef FOR_dumpleases
+#ifndef TT
+#define TT this.dumpleases
+#endif
+#define FLAG_f (FORCED_FLAG<<0)
+#define FLAG_r (FORCED_FLAG<<1)
+#define FLAG_a (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_echo
+#ifndef TT
+#define TT this.echo
+#endif
+#define FLAG_n (1<<0)
+#define FLAG_e (1<<1)
+#endif
+
+#ifdef FOR_eject
+#ifndef TT
+#define TT this.eject
+#endif
+#define FLAG_T (FORCED_FLAG<<0)
+#define FLAG_t (FORCED_FLAG<<1)
+#define FLAG_s (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_env
+#ifndef TT
+#define TT this.env
+#endif
+#define FLAG_u (1<<0)
+#define FLAG_i (1<<1)
+#endif
+
+#ifdef FOR_exit
+#ifndef TT
+#define TT this.exit
+#endif
+#endif
+
+#ifdef FOR_expand
+#ifndef TT
+#define TT this.expand
+#endif
+#define FLAG_t (1<<0)
+#endif
+
+#ifdef FOR_expr
+#ifndef TT
+#define TT this.expr
+#endif
+#endif
+
+#ifdef FOR_factor
+#ifndef TT
+#define TT this.factor
+#endif
+#endif
+
+#ifdef FOR_fallocate
+#ifndef TT
+#define TT this.fallocate
+#endif
+#define FLAG_l (1<<0)
+#endif
+
+#ifdef FOR_false
+#ifndef TT
+#define TT this.false
+#endif
+#endif
+
+#ifdef FOR_fdisk
+#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)
+#endif
+
+#ifdef FOR_file
+#ifndef TT
+#define TT this.file
+#endif
+#endif
+
+#ifdef FOR_find
+#ifndef TT
+#define TT this.find
+#endif
+#define FLAG_L (1<<0)
+#define FLAG_H (1<<1)
+#endif
+
+#ifdef FOR_flock
+#ifndef TT
+#define TT this.flock
+#endif
+#define FLAG_x (1<<0)
+#define FLAG_u (1<<1)
+#define FLAG_s (1<<2)
+#define FLAG_n (1<<3)
+#endif
+
+#ifdef FOR_fold
+#ifndef TT
+#define TT this.fold
+#endif
+#define FLAG_w (FORCED_FLAG<<0)
+#define FLAG_u (FORCED_FLAG<<1)
+#define FLAG_s (FORCED_FLAG<<2)
+#define FLAG_b (FORCED_FLAG<<3)
+#endif
+
+#ifdef FOR_free
+#ifndef TT
+#define TT this.free
+#endif
+#define FLAG_b (1<<0)
+#define FLAG_k (1<<1)
+#define FLAG_m (1<<2)
+#define FLAG_g (1<<3)
+#define FLAG_t (1<<4)
+#define FLAG_h (1<<5)
+#endif
+
+#ifdef FOR_freeramdisk
+#ifndef TT
+#define TT this.freeramdisk
+#endif
+#endif
+
+#ifdef FOR_fsck
+#ifndef TT
+#define TT this.fsck
+#endif
+#define FLAG_C (FORCED_FLAG<<0)
+#define FLAG_s (FORCED_FLAG<<1)
+#define FLAG_V (FORCED_FLAG<<2)
+#define FLAG_T (FORCED_FLAG<<3)
+#define FLAG_R (FORCED_FLAG<<4)
+#define FLAG_P (FORCED_FLAG<<5)
+#define FLAG_N (FORCED_FLAG<<6)
+#define FLAG_A (FORCED_FLAG<<7)
+#define FLAG_t (FORCED_FLAG<<8)
+#endif
+
+#ifdef FOR_fsfreeze
+#ifndef TT
+#define TT this.fsfreeze
+#endif
+#define FLAG_u (1<<0)
+#define FLAG_f (1<<1)
+#endif
+
+#ifdef FOR_fstype
+#ifndef TT
+#define TT this.fstype
+#endif
+#endif
+
+#ifdef FOR_fsync
+#ifndef TT
+#define TT this.fsync
+#endif
+#define FLAG_d (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_ftpget
+#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)
+#endif
+
+#ifdef FOR_getenforce
+#ifndef TT
+#define TT this.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
+#endif
+#define FLAG_Z (1<<0)
+#endif
+
+#ifdef FOR_getty
+#ifndef TT
+#define TT this.getty
+#endif
+#define FLAG_h (FORCED_FLAG<<0)
+#define FLAG_L (FORCED_FLAG<<1)
+#define FLAG_m (FORCED_FLAG<<2)
+#define FLAG_n (FORCED_FLAG<<3)
+#define FLAG_w (FORCED_FLAG<<4)
+#define FLAG_i (FORCED_FLAG<<5)
+#define FLAG_f (FORCED_FLAG<<6)
+#define FLAG_l (FORCED_FLAG<<7)
+#define FLAG_I (FORCED_FLAG<<8)
+#define FLAG_H (FORCED_FLAG<<9)
+#define FLAG_t (FORCED_FLAG<<10)
+#endif
+
+#ifdef FOR_grep
+#ifndef TT
+#define TT this.grep
+#endif
+#define FLAG_x (1<<0)
+#define FLAG_m (1<<1)
+#define FLAG_f (1<<2)
+#define FLAG_e (1<<3)
+#define FLAG_q (1<<4)
+#define FLAG_l (1<<5)
+#define FLAG_c (1<<6)
+#define FLAG_w (1<<7)
+#define FLAG_v (1<<8)
+#define FLAG_s (1<<9)
+#define FLAG_r (1<<10)
+#define FLAG_o (1<<11)
+#define FLAG_n (1<<12)
+#define FLAG_i (1<<13)
+#define FLAG_h (1<<14)
+#define FLAG_b (1<<15)
+#define FLAG_a (1<<16)
+#define FLAG_H (1<<17)
+#define FLAG_F (1<<18)
+#define FLAG_E (1<<19)
+#define FLAG_z (1<<20)
+#define FLAG_Z (1<<21)
+#define FLAG_A (1<<22)
+#define FLAG_B (1<<23)
+#define FLAG_C (1<<24)
+#endif
+
+#ifdef FOR_groupadd
+#ifndef TT
+#define TT this.groupadd
+#endif
+#define FLAG_S (FORCED_FLAG<<0)
+#define FLAG_g (FORCED_FLAG<<1)
+#endif
+
+#ifdef FOR_groupdel
+#ifndef TT
+#define TT this.groupdel
+#endif
+#endif
+
+#ifdef FOR_groups
+#ifndef TT
+#define TT this.groups
+#endif
+#endif
+
+#ifdef FOR_gunzip
+#ifndef TT
+#define TT this.gunzip
+#endif
+#define FLAG_v (FORCED_FLAG<<0)
+#define FLAG_t (FORCED_FLAG<<1)
+#define FLAG_S (FORCED_FLAG<<2)
+#define FLAG_q (FORCED_FLAG<<3)
+#define FLAG_l (FORCED_FLAG<<4)
+#define FLAG_f (FORCED_FLAG<<5)
+#define FLAG_c (FORCED_FLAG<<6)
+#endif
+
+#ifdef FOR_gzip
+#ifndef TT
+#define TT this.gzip
+#endif
+#define FLAG_z (FORCED_FLAG<<0)
+#define FLAG_R (FORCED_FLAG<<1)
+#define FLAG_L (FORCED_FLAG<<2)
+#define FLAG_g (FORCED_FLAG<<3)
+#define FLAG_v (FORCED_FLAG<<4)
+#define FLAG_t (FORCED_FLAG<<5)
+#define FLAG_S (FORCED_FLAG<<6)
+#define FLAG_q (FORCED_FLAG<<7)
+#define FLAG_l (FORCED_FLAG<<8)
+#define FLAG_f (FORCED_FLAG<<9)
+#define FLAG_c (FORCED_FLAG<<10)
+#define FLAG_d (FORCED_FLAG<<11)
+#define FLAG_9 (FORCED_FLAG<<12)
+#define FLAG_1 (FORCED_FLAG<<13)
+#define FLAG_d (FORCED_FLAG<<14)
+#endif
+
+#ifdef FOR_head
+#ifndef TT
+#define TT this.head
+#endif
+#define FLAG_n (1<<0)
+#endif
+
+#ifdef FOR_hello
+#ifndef TT
+#define TT this.hello
+#endif
+#endif
+
+#ifdef FOR_help
+#ifndef TT
+#define TT this.help
+#endif
+#define FLAG_h (1<<0)
+#define FLAG_a (1<<1)
+#endif
+
+#ifdef FOR_hexedit
+#ifndef TT
+#define TT this.hexedit
+#endif
+#define FLAG_r (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_host
+#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)
+#endif
+
+#ifdef FOR_hostid
+#ifndef TT
+#define TT this.hostid
+#endif
+#endif
+
+#ifdef FOR_hostname
+#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.hwclock
+#endif
+#define FLAG_systohc (1<<0)
+#define FLAG_w (1<<0)
+#define FLAG_show (1<<1)
+#define FLAG_r (1<<1)
+#define FLAG_hctosys (1<<2)
+#define FLAG_s (1<<2)
+#define FLAG_systz (1<<3)
+#define FLAG_t (1<<3)
+#define FLAG_localtime (1<<4)
+#define FLAG_l (1<<4)
+#define FLAG_utc (1<<5)
+#define FLAG_u (1<<5)
+#define FLAG_rtc (1<<6)
+#define FLAG_f (1<<6)
+#define FLAG_fast (1<<7)
+#endif
+
+#ifdef FOR_iconv
+#ifndef TT
+#define TT this.iconv
+#endif
+#define FLAG_f (FORCED_FLAG<<0)
+#define FLAG_t (FORCED_FLAG<<1)
+#define FLAG_s (FORCED_FLAG<<2)
+#define FLAG_c (FORCED_FLAG<<3)
+#endif
+
+#ifdef FOR_id
+#ifndef TT
+#define TT this.id
+#endif
+#define FLAG_u (1<<0)
+#define FLAG_r (1<<1)
+#define FLAG_g (1<<2)
+#define FLAG_G (1<<3)
+#define FLAG_n (1<<4)
+#define FLAG_Z (1<<5)
+#endif
+
+#ifdef FOR_ifconfig
+#ifndef TT
+#define TT this.ifconfig
+#endif
+#define FLAG_a (1<<0)
+#endif
+
+#ifdef FOR_init
+#ifndef TT
+#define TT this.init
+#endif
+#endif
+
+#ifdef FOR_inotifyd
+#ifndef TT
+#define TT this.inotifyd
+#endif
+#endif
+
+#ifdef FOR_insmod
+#ifndef TT
+#define TT this.insmod
+#endif
+#endif
+
+#ifdef FOR_install
+#ifndef TT
+#define TT this.install
+#endif
+#define FLAG_g (1<<0)
+#define FLAG_o (1<<1)
+#define FLAG_m (1<<2)
+#define FLAG_v (1<<3)
+#define FLAG_s (1<<4)
+#define FLAG_p (1<<5)
+#define FLAG_D (1<<6)
+#define FLAG_d (1<<7)
+#define FLAG_c (1<<8)
+#endif
+
+#ifdef FOR_ionice
+#ifndef TT
+#define TT this.ionice
+#endif
+#define FLAG_p (1<<0)
+#define FLAG_n (1<<1)
+#define FLAG_c (1<<2)
+#define FLAG_t (1<<3)
+#endif
+
+#ifdef FOR_iorenice
+#ifndef TT
+#define TT this.iorenice
+#endif
+#endif
+
+#ifdef FOR_iotop
+#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)
+#endif
+
+#ifdef FOR_ip
+#ifndef TT
+#define TT this.ip
+#endif
+#endif
+
+#ifdef FOR_ipcrm
+#ifndef TT
+#define TT this.ipcrm
+#endif
+#define FLAG_Q (FORCED_FLAG<<0)
+#define FLAG_q (FORCED_FLAG<<1)
+#define FLAG_S (FORCED_FLAG<<2)
+#define FLAG_s (FORCED_FLAG<<3)
+#define FLAG_M (FORCED_FLAG<<4)
+#define FLAG_m (FORCED_FLAG<<5)
+#endif
+
+#ifdef FOR_ipcs
+#ifndef TT
+#define TT this.ipcs
+#endif
+#define FLAG_i (FORCED_FLAG<<0)
+#define FLAG_m (FORCED_FLAG<<1)
+#define FLAG_q (FORCED_FLAG<<2)
+#define FLAG_s (FORCED_FLAG<<3)
+#define FLAG_l (FORCED_FLAG<<4)
+#define FLAG_u (FORCED_FLAG<<5)
+#define FLAG_t (FORCED_FLAG<<6)
+#define FLAG_p (FORCED_FLAG<<7)
+#define FLAG_c (FORCED_FLAG<<8)
+#define FLAG_a (FORCED_FLAG<<9)
+#endif
+
+#ifdef FOR_kill
+#ifndef TT
+#define TT this.kill
+#endif
+#define FLAG_s (1<<0)
+#define FLAG_l (1<<1)
+#endif
+
+#ifdef FOR_killall
+#ifndef TT
+#define TT this.killall
+#endif
+#define FLAG_i (1<<0)
+#define FLAG_v (1<<1)
+#define FLAG_q (1<<2)
+#define FLAG_l (1<<3)
+#define FLAG_s (1<<4)
+#endif
+
+#ifdef FOR_killall5
+#ifndef TT
+#define TT this.killall5
+#endif
+#define FLAG_s (FORCED_FLAG<<0)
+#define FLAG_l (FORCED_FLAG<<1)
+#define FLAG_o (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_klogd
+#ifndef TT
+#define TT this.klogd
+#endif
+#define FLAG_n (FORCED_FLAG<<0)
+#define FLAG_c (FORCED_FLAG<<1)
+#endif
+
+#ifdef FOR_last
+#ifndef TT
+#define TT this.last
+#endif
+#define FLAG_W (FORCED_FLAG<<0)
+#define FLAG_f (FORCED_FLAG<<1)
+#endif
+
+#ifdef FOR_link
+#ifndef TT
+#define TT this.link
+#endif
+#endif
+
+#ifdef FOR_ln
+#ifndef TT
+#define TT this.ln
+#endif
+#define FLAG_s (1<<0)
+#define FLAG_f (1<<1)
+#define FLAG_n (1<<2)
+#define FLAG_v (1<<3)
+#endif
+
+#ifdef FOR_load_policy
+#ifndef TT
+#define TT this.load_policy
+#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
+#endif
+#define FLAG_p (FORCED_FLAG<<0)
+#define FLAG_t (FORCED_FLAG<<1)
+#define FLAG_s (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_login
+#ifndef TT
+#define TT this.login
+#endif
+#define FLAG_h (FORCED_FLAG<<0)
+#define FLAG_p (FORCED_FLAG<<1)
+#define FLAG_f (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_logname
+#ifndef TT
+#define TT this.logname
+#endif
+#endif
+
+#ifdef FOR_losetup
+#ifndef TT
+#define TT this.losetup
+#endif
+#define FLAG_a (1<<0)
+#define FLAG_c (1<<1)
+#define FLAG_d (1<<2)
+#define FLAG_f (1<<3)
+#define FLAG_j (1<<4)
+#define FLAG_o (1<<5)
+#define FLAG_r (1<<6)
+#define FLAG_show (1<<7)
+#define FLAG_s (1<<7)
+#define FLAG_sizelimit (1<<8)
+#define FLAG_S (1<<8)
+#endif
+
+#ifdef FOR_ls
+#ifndef TT
+#define TT this.ls
+#endif
+#define FLAG_1 (1<<0)
+#define FLAG_x (1<<1)
+#define FLAG_u (1<<2)
+#define FLAG_t (1<<3)
+#define FLAG_s (1<<4)
+#define FLAG_r (1<<5)
+#define FLAG_q (1<<6)
+#define FLAG_p (1<<7)
+#define FLAG_n (1<<8)
+#define FLAG_m (1<<9)
+#define FLAG_l (1<<10)
+#define FLAG_k (1<<11)
+#define FLAG_i (1<<12)
+#define FLAG_h (1<<13)
+#define FLAG_f (1<<14)
+#define FLAG_d (1<<15)
+#define FLAG_c (1<<16)
+#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.lsattr
+#endif
+#define FLAG_R (1<<0)
+#define FLAG_a (1<<1)
+#define FLAG_d (1<<2)
+#define FLAG_l (1<<3)
+#define FLAG_v (1<<4)
+#endif
+
+#ifdef FOR_lsmod
+#ifndef TT
+#define TT this.lsmod
+#endif
+#endif
+
+#ifdef FOR_lsof
+#ifndef TT
+#define TT this.lsof
+#endif
+#define FLAG_t (1<<0)
+#define FLAG_p (1<<1)
+#define FLAG_l (1<<2)
+#endif
+
+#ifdef FOR_lspci
+#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)
+#endif
+
+#ifdef FOR_lsusb
+#ifndef TT
+#define TT this.lsusb
+#endif
+#endif
+
+#ifdef FOR_makedevs
+#ifndef TT
+#define TT this.makedevs
+#endif
+#define FLAG_d (1<<0)
+#endif
+
+#ifdef FOR_md5sum
+#ifndef TT
+#define TT this.md5sum
+#endif
+#define FLAG_c (1<<0)
+#define FLAG_b (1<<1)
+#endif
+
+#ifdef FOR_mdev
+#ifndef TT
+#define TT this.mdev
+#endif
+#define FLAG_s (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_mix
+#ifndef TT
+#define TT this.mix
+#endif
+#define FLAG_r (FORCED_FLAG<<0)
+#define FLAG_l (FORCED_FLAG<<1)
+#define FLAG_d (FORCED_FLAG<<2)
+#define FLAG_c (FORCED_FLAG<<3)
+#endif
+
+#ifdef FOR_mkdir
+#ifndef TT
+#define TT this.mkdir
+#endif
+#define FLAG_m (1<<0)
+#define FLAG_p (1<<1)
+#define FLAG_v (1<<2)
+#define FLAG_Z (1<<3)
+#endif
+
+#ifdef FOR_mke2fs
+#ifndef TT
+#define TT this.mke2fs
+#endif
+#define FLAG_b (FORCED_FLAG<<0)
+#define FLAG_i (FORCED_FLAG<<1)
+#define FLAG_N (FORCED_FLAG<<2)
+#define FLAG_m (FORCED_FLAG<<3)
+#define FLAG_q (FORCED_FLAG<<4)
+#define FLAG_n (FORCED_FLAG<<5)
+#define FLAG_F (FORCED_FLAG<<6)
+#define FLAG_g (FORCED_FLAG<<7)
+#endif
+
+#ifdef FOR_mkfifo
+#ifndef TT
+#define TT this.mkfifo
+#endif
+#define FLAG_m (1<<0)
+#define FLAG_Z (1<<1)
+#endif
+
+#ifdef FOR_mknod
+#ifndef TT
+#define TT this.mknod
+#endif
+#define FLAG_Z (1<<0)
+#define FLAG_mode (1<<1)
+#define FLAG_m (1<<1)
+#endif
+
+#ifdef FOR_mkpasswd
+#ifndef TT
+#define TT this.mkpasswd
+#endif
+#define FLAG_P (FORCED_FLAG<<0)
+#define FLAG_m (FORCED_FLAG<<1)
+#define FLAG_S (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_mkswap
+#ifndef TT
+#define TT this.mkswap
+#endif
+#define FLAG_L (1<<0)
+#endif
+
+#ifdef FOR_mktemp
+#ifndef TT
+#define TT this.mktemp
+#endif
+#define FLAG_tmpdir (1<<0)
+#define FLAG_p (1<<0)
+#define FLAG_directory (1<<1)
+#define FLAG_d (1<<1)
+#define FLAG_q (1<<2)
+#define FLAG_u (1<<3)
+#endif
+
+#ifdef FOR_modinfo
+#ifndef TT
+#define TT this.modinfo
+#endif
+#define FLAG_0 (1<<0)
+#define FLAG_F (1<<1)
+#define FLAG_k (1<<2)
+#define FLAG_b (1<<3)
+#endif
+
+#ifdef FOR_modprobe
+#ifndef TT
+#define TT this.modprobe
+#endif
+#define FLAG_b (FORCED_FLAG<<0)
+#define FLAG_D (FORCED_FLAG<<1)
+#define FLAG_s (FORCED_FLAG<<2)
+#define FLAG_v (FORCED_FLAG<<3)
+#define FLAG_q (FORCED_FLAG<<4)
+#define FLAG_r (FORCED_FLAG<<5)
+#define FLAG_l (FORCED_FLAG<<6)
+#define FLAG_a (FORCED_FLAG<<7)
+#endif
+
+#ifdef FOR_more
+#ifndef TT
+#define TT this.more
+#endif
+#endif
+
+#ifdef FOR_mount
+#ifndef TT
+#define TT this.mount
+#endif
+#define FLAG_o (1<<0)
+#define FLAG_t (1<<1)
+#define FLAG_w (1<<2)
+#define FLAG_v (1<<3)
+#define FLAG_r (1<<4)
+#define FLAG_n (1<<5)
+#define FLAG_f (1<<6)
+#define FLAG_a (1<<7)
+#define FLAG_O (1<<8)
+#endif
+
+#ifdef FOR_mountpoint
+#ifndef TT
+#define TT this.mountpoint
+#endif
+#define FLAG_x (1<<0)
+#define FLAG_d (1<<1)
+#define FLAG_q (1<<2)
+#endif
+
+#ifdef FOR_mv
+#ifndef TT
+#define TT this.mv
+#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)
+#endif
+
+#ifdef FOR_nbd_client
+#ifndef TT
+#define TT this.nbd_client
+#endif
+#define FLAG_s (1<<0)
+#define FLAG_n (1<<1)
+#endif
+
+#ifdef FOR_netcat
+#ifndef TT
+#define TT this.netcat
+#endif
+#define FLAG_f (1<<0)
+#define FLAG_q (1<<1)
+#define FLAG_s (1<<2)
+#define FLAG_p (1<<3)
+#define FLAG_w (1<<4)
+#define FLAG_L (1<<5)
+#define FLAG_l (1<<6)
+#define FLAG_t (1<<7)
+#endif
+
+#ifdef FOR_netstat
+#ifndef TT
+#define TT this.netstat
+#endif
+#define FLAG_l (1<<0)
+#define FLAG_a (1<<1)
+#define FLAG_e (1<<2)
+#define FLAG_n (1<<3)
+#define FLAG_t (1<<4)
+#define FLAG_u (1<<5)
+#define FLAG_w (1<<6)
+#define FLAG_x (1<<7)
+#define FLAG_r (1<<8)
+#define FLAG_W (1<<9)
+#define FLAG_p (1<<10)
+#endif
+
+#ifdef FOR_nice
+#ifndef TT
+#define TT this.nice
+#endif
+#define FLAG_n (1<<0)
+#endif
+
+#ifdef FOR_nl
+#ifndef TT
+#define TT this.nl
+#endif
+#define FLAG_E (1<<0)
+#define FLAG_w (1<<1)
+#define FLAG_s (1<<2)
+#define FLAG_n (1<<3)
+#define FLAG_b (1<<4)
+#define FLAG_l (1<<5)
+#define FLAG_v (1<<6)
+#endif
+
+#ifdef FOR_nohup
+#ifndef TT
+#define TT this.nohup
+#endif
+#endif
+
+#ifdef FOR_nproc
+#ifndef TT
+#define TT this.nproc
+#endif
+#define FLAG_all (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_nsenter
+#ifndef TT
+#define TT this.nsenter
+#endif
+#define FLAG_user (FORCED_FLAG<<0)
+#define FLAG_U (FORCED_FLAG<<0)
+#define FLAG_uts (FORCED_FLAG<<1)
+#define FLAG_u (FORCED_FLAG<<1)
+#define FLAG_pid (FORCED_FLAG<<2)
+#define FLAG_p (FORCED_FLAG<<2)
+#define FLAG_net (FORCED_FLAG<<3)
+#define FLAG_n (FORCED_FLAG<<3)
+#define FLAG_mount (FORCED_FLAG<<4)
+#define FLAG_m (FORCED_FLAG<<4)
+#define FLAG_ipc (FORCED_FLAG<<5)
+#define FLAG_i (FORCED_FLAG<<5)
+#define FLAG_target (FORCED_FLAG<<6)
+#define FLAG_t (FORCED_FLAG<<6)
+#define FLAG_no_fork (FORCED_FLAG<<7)
+#define FLAG_F (FORCED_FLAG<<7)
+#endif
+
+#ifdef FOR_od
+#ifndef TT
+#define TT this.od
+#endif
+#define FLAG_t (1<<0)
+#define FLAG_A (1<<1)
+#define FLAG_b (1<<2)
+#define FLAG_c (1<<3)
+#define FLAG_d (1<<4)
+#define FLAG_o (1<<5)
+#define FLAG_s (1<<6)
+#define FLAG_x (1<<7)
+#define FLAG_N (1<<8)
+#define FLAG_w (1<<9)
+#define FLAG_v (1<<10)
+#define FLAG_j (1<<11)
+#endif
+
+#ifdef FOR_oneit
+#ifndef TT
+#define TT this.oneit
+#endif
+#define FLAG_3 (FORCED_FLAG<<0)
+#define FLAG_p (FORCED_FLAG<<1)
+#define FLAG_c (FORCED_FLAG<<2)
+#define FLAG_n (FORCED_FLAG<<3)
+#endif
+
+#ifdef FOR_openvt
+#ifndef TT
+#define TT this.openvt
+#endif
+#define FLAG_w (FORCED_FLAG<<0)
+#define FLAG_s (FORCED_FLAG<<1)
+#define FLAG_c (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_partprobe
+#ifndef TT
+#define TT this.partprobe
+#endif
+#endif
+
+#ifdef FOR_passwd
+#ifndef TT
+#define TT this.passwd
+#endif
+#define FLAG_u (FORCED_FLAG<<0)
+#define FLAG_l (FORCED_FLAG<<1)
+#define FLAG_d (FORCED_FLAG<<2)
+#define FLAG_a (FORCED_FLAG<<3)
+#endif
+
+#ifdef FOR_paste
+#ifndef TT
+#define TT this.paste
+#endif
+#define FLAG_s (1<<0)
+#define FLAG_d (1<<1)
+#endif
+
+#ifdef FOR_patch
+#ifndef TT
+#define TT this.patch
+#endif
+#define FLAG_R (1<<0)
+#define FLAG_i (1<<1)
+#define FLAG_p (1<<2)
+#define FLAG_l (1<<3)
+#define FLAG_u (1<<4)
+#define FLAG_d (1<<5)
+#define FLAG_x (FORCED_FLAG<<6)
+#define FLAG_dry_run (1<<7)
+#endif
+
+#ifdef FOR_pgrep
+#ifndef TT
+#define TT this.pgrep
+#endif
+#define FLAG_L (1<<0)
+#define FLAG_x (1<<1)
+#define FLAG_v (1<<2)
+#define FLAG_o (1<<3)
+#define FLAG_n (1<<4)
+#define FLAG_f (1<<5)
+#define FLAG_G (1<<6)
+#define FLAG_g (1<<7)
+#define FLAG_P (1<<8)
+#define FLAG_s (1<<9)
+#define FLAG_t (1<<10)
+#define FLAG_U (1<<11)
+#define FLAG_u (1<<12)
+#define FLAG_d (1<<13)
+#define FLAG_l (1<<14)
+#define FLAG_c (1<<15)
+#endif
+
+#ifdef FOR_pidof
+#ifndef TT
+#define TT this.pidof
+#endif
+#define FLAG_o (1<<0)
+#define FLAG_s (1<<1)
+#endif
+
+#ifdef FOR_ping
+#ifndef TT
+#define TT this.ping
+#endif
+#define FLAG_6 (FORCED_FLAG<<0)
+#define FLAG_4 (FORCED_FLAG<<1)
+#define FLAG_q (FORCED_FLAG<<2)
+#define FLAG_w (FORCED_FLAG<<3)
+#define FLAG_W (FORCED_FLAG<<4)
+#define FLAG_I (FORCED_FLAG<<5)
+#define FLAG_s (FORCED_FLAG<<6)
+#define FLAG_c (FORCED_FLAG<<7)
+#define FLAG_t (FORCED_FLAG<<8)
+#endif
+
+#ifdef FOR_pivot_root
+#ifndef TT
+#define TT this.pivot_root
+#endif
+#endif
+
+#ifdef FOR_pkill
+#ifndef TT
+#define TT this.pkill
+#endif
+#define FLAG_l (1<<0)
+#define FLAG_x (1<<1)
+#define FLAG_v (1<<2)
+#define FLAG_o (1<<3)
+#define FLAG_n (1<<4)
+#define FLAG_f (1<<5)
+#define FLAG_G (1<<6)
+#define FLAG_g (1<<7)
+#define FLAG_P (1<<8)
+#define FLAG_s (1<<9)
+#define FLAG_t (1<<10)
+#define FLAG_U (1<<11)
+#define FLAG_u (1<<12)
+#define FLAG_V (1<<13)
+#endif
+
+#ifdef FOR_pmap
+#ifndef TT
+#define TT this.pmap
+#endif
+#define FLAG_q (1<<0)
+#define FLAG_x (1<<1)
+#endif
+
+#ifdef FOR_printenv
+#ifndef TT
+#define TT this.printenv
+#endif
+#define FLAG_null (1<<0)
+#define FLAG_0 (1<<0)
+#endif
+
+#ifdef FOR_printf
+#ifndef TT
+#define TT this.printf
+#endif
+#endif
+
+#ifdef FOR_ps
+#ifndef TT
+#define TT this.ps
+#endif
+#define FLAG_Z (1<<0)
+#define FLAG_w (1<<1)
+#define FLAG_G (1<<2)
+#define FLAG_g (1<<3)
+#define FLAG_U (1<<4)
+#define FLAG_u (1<<5)
+#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
+#ifndef TT
+#define TT this.pwd
+#endif
+#define FLAG_P (1<<0)
+#define FLAG_L (1<<1)
+#endif
+
+#ifdef FOR_pwdx
+#ifndef TT
+#define TT this.pwdx
+#endif
+#define FLAG_a (1<<0)
+#endif
+
+#ifdef FOR_readahead
+#ifndef TT
+#define TT this.readahead
+#endif
+#endif
+
+#ifdef FOR_readlink
+#ifndef TT
+#define TT this.readlink
+#endif
+#define FLAG_q (1<<0)
+#define FLAG_n (1<<1)
+#define FLAG_e (1<<2)
+#define FLAG_f (1<<3)
+#endif
+
+#ifdef FOR_realpath
+#ifndef TT
+#define TT this.realpath
+#endif
+#endif
+
+#ifdef FOR_reboot
+#ifndef TT
+#define TT this.reboot
+#endif
+#define FLAG_n (FORCED_FLAG<<0)
+#define FLAG_f (FORCED_FLAG<<1)
+#endif
+
+#ifdef FOR_renice
+#ifndef TT
+#define TT this.renice
+#endif
+#define FLAG_n (1<<0)
+#define FLAG_u (1<<1)
+#define FLAG_p (1<<2)
+#define FLAG_g (1<<3)
+#endif
+
+#ifdef FOR_reset
+#ifndef TT
+#define TT this.reset
+#endif
+#endif
+
+#ifdef FOR_restorecon
+#ifndef TT
+#define TT this.restorecon
+#endif
+#define FLAG_v (1<<0)
+#define FLAG_r (1<<1)
+#define FLAG_R (1<<2)
+#define FLAG_n (1<<3)
+#define FLAG_F (1<<4)
+#define FLAG_D (1<<5)
+#endif
+
+#ifdef FOR_rev
+#ifndef TT
+#define TT this.rev
+#endif
+#endif
+
+#ifdef FOR_rfkill
+#ifndef TT
+#define TT this.rfkill
+#endif
+#endif
+
+#ifdef FOR_rm
+#ifndef TT
+#define TT this.rm
+#endif
+#define FLAG_r (1<<0)
+#define FLAG_R (1<<1)
+#define FLAG_i (1<<2)
+#define FLAG_f (1<<3)
+#endif
+
+#ifdef FOR_rmdir
+#ifndef TT
+#define TT this.rmdir
+#endif
+#define FLAG_p (1<<0)
+#endif
+
+#ifdef FOR_rmmod
+#ifndef TT
+#define TT this.rmmod
+#endif
+#define FLAG_f (1<<0)
+#define FLAG_w (1<<1)
+#endif
+
+#ifdef FOR_route
+#ifndef TT
+#define TT this.route
+#endif
+#define FLAG_A (FORCED_FLAG<<0)
+#define FLAG_e (FORCED_FLAG<<1)
+#define FLAG_n (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_runcon
+#ifndef TT
+#define TT this.runcon
+#endif
+#endif
+
+#ifdef FOR_sed
+#ifndef TT
+#define TT this.sed
+#endif
+#define FLAG_r (1<<0)
+#define FLAG_E (1<<1)
+#define FLAG_n (1<<2)
+#define FLAG_i (1<<3)
+#define FLAG_f (1<<4)
+#define FLAG_e (1<<5)
+#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
+#define FLAG_w (1<<0)
+#define FLAG_s (1<<1)
+#define FLAG_f (1<<2)
+#endif
+
+#ifdef FOR_setenforce
+#ifndef TT
+#define TT this.setenforce
+#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
+#endif
+#endif
+
+#ifdef FOR_setsid
+#ifndef TT
+#define TT this.setsid
+#endif
+#define FLAG_t (1<<0)
+#endif
+
+#ifdef FOR_sh
+#ifndef TT
+#define TT this.sh
+#endif
+#define FLAG_i (FORCED_FLAG<<0)
+#define FLAG_c (FORCED_FLAG<<1)
+#endif
+
+#ifdef FOR_sha1sum
+#ifndef TT
+#define TT this.sha1sum
+#endif
+#define FLAG_c (1<<0)
+#define FLAG_b (1<<1)
+#endif
+
+#ifdef FOR_shred
+#ifndef TT
+#define TT this.shred
+#endif
+#define FLAG_f (FORCED_FLAG<<0)
+#define FLAG_o (FORCED_FLAG<<1)
+#define FLAG_n (FORCED_FLAG<<2)
+#define FLAG_s (FORCED_FLAG<<3)
+#define FLAG_u (FORCED_FLAG<<4)
+#define FLAG_x (FORCED_FLAG<<5)
+#define FLAG_z (FORCED_FLAG<<6)
+#endif
+
+#ifdef FOR_skeleton
+#ifndef TT
+#define TT this.skeleton
+#endif
+#define FLAG_a (FORCED_FLAG<<0)
+#define FLAG_b (FORCED_FLAG<<1)
+#define FLAG_c (FORCED_FLAG<<2)
+#define FLAG_d (FORCED_FLAG<<3)
+#define FLAG_e (FORCED_FLAG<<4)
+#define FLAG_also (FORCED_FLAG<<5)
+#define FLAG_blubber (FORCED_FLAG<<6)
+#define FLAG_walrus (FORCED_FLAG<<7)
+#endif
+
+#ifdef FOR_skeleton_alias
+#ifndef TT
+#define TT this.skeleton_alias
+#endif
+#define FLAG_q (FORCED_FLAG<<0)
+#define FLAG_d (FORCED_FLAG<<1)
+#define FLAG_b (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_sleep
+#ifndef TT
+#define TT this.sleep
+#endif
+#endif
+
+#ifdef FOR_sort
+#ifndef TT
+#define TT this.sort
+#endif
+#define FLAG_n (1<<0)
+#define FLAG_u (1<<1)
+#define FLAG_r (1<<2)
+#define FLAG_i (1<<3)
+#define FLAG_f (1<<4)
+#define FLAG_d (1<<5)
+#define FLAG_z (1<<6)
+#define FLAG_s (1<<7)
+#define FLAG_c (1<<8)
+#define FLAG_M (1<<9)
+#define FLAG_b (1<<10)
+#define FLAG_x (1<<11)
+#define FLAG_t (1<<12)
+#define FLAG_k (1<<13)
+#define FLAG_o (1<<14)
+#define FLAG_m (1<<15)
+#define FLAG_T (1<<16)
+#define FLAG_S (1<<17)
+#define FLAG_g (1<<18)
+#endif
+
+#ifdef FOR_split
+#ifndef TT
+#define TT this.split
+#endif
+#define FLAG_l (1<<0)
+#define FLAG_b (1<<1)
+#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_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.strings
+#endif
+#define FLAG_o (1<<0)
+#define FLAG_f (1<<1)
+#define FLAG_n (1<<2)
+#define FLAG_a (1<<3)
+#endif
+
+#ifdef FOR_su
+#ifndef TT
+#define TT this.su
+#endif
+#define FLAG_s (FORCED_FLAG<<0)
+#define FLAG_c (FORCED_FLAG<<1)
+#define FLAG_p (FORCED_FLAG<<2)
+#define FLAG_m (FORCED_FLAG<<3)
+#define FLAG_l (FORCED_FLAG<<4)
+#endif
+
+#ifdef FOR_sulogin
+#ifndef TT
+#define TT this.sulogin
+#endif
+#define FLAG_t (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_swapoff
+#ifndef TT
+#define TT this.swapoff
+#endif
+#endif
+
+#ifdef FOR_swapon
+#ifndef TT
+#define TT this.swapon
+#endif
+#define FLAG_d (1<<0)
+#define FLAG_p (1<<1)
+#endif
+
+#ifdef FOR_switch_root
+#ifndef TT
+#define TT this.switch_root
+#endif
+#define FLAG_h (FORCED_FLAG<<0)
+#define FLAG_c (FORCED_FLAG<<1)
+#endif
+
+#ifdef FOR_sync
+#ifndef TT
+#define TT this.sync
+#endif
+#endif
+
+#ifdef FOR_sysctl
+#ifndef TT
+#define TT this.sysctl
+#endif
+#define FLAG_A (1<<0)
+#define FLAG_a (1<<1)
+#define FLAG_p (1<<2)
+#define FLAG_w (1<<3)
+#define FLAG_q (1<<4)
+#define FLAG_N (1<<5)
+#define FLAG_e (1<<6)
+#define FLAG_n (1<<7)
+#endif
+
+#ifdef FOR_syslogd
+#ifndef TT
+#define TT this.syslogd
+#endif
+#define FLAG_D (FORCED_FLAG<<0)
+#define FLAG_L (FORCED_FLAG<<1)
+#define FLAG_K (FORCED_FLAG<<2)
+#define FLAG_S (FORCED_FLAG<<3)
+#define FLAG_n (FORCED_FLAG<<4)
+#define FLAG_a (FORCED_FLAG<<5)
+#define FLAG_f (FORCED_FLAG<<6)
+#define FLAG_p (FORCED_FLAG<<7)
+#define FLAG_O (FORCED_FLAG<<8)
+#define FLAG_m (FORCED_FLAG<<9)
+#define FLAG_s (FORCED_FLAG<<10)
+#define FLAG_b (FORCED_FLAG<<11)
+#define FLAG_R (FORCED_FLAG<<12)
+#define FLAG_l (FORCED_FLAG<<13)
+#endif
+
+#ifdef FOR_tac
+#ifndef TT
+#define TT this.tac
+#endif
+#endif
+
+#ifdef FOR_tail
+#ifndef TT
+#define TT this.tail
+#endif
+#define FLAG_n (1<<0)
+#define FLAG_c (1<<1)
+#define FLAG_f (1<<2)
+#endif
+
+#ifdef FOR_tar
+#ifndef TT
+#define TT this.tar
+#endif
+#define FLAG_file (1<<0)
+#define FLAG_f (1<<0)
+#define FLAG_directory (1<<1)
+#define FLAG_C (1<<1)
+#define FLAG_files_from (1<<2)
+#define FLAG_T (1<<2)
+#define FLAG_exclude_from (1<<3)
+#define FLAG_X (1<<3)
+#define FLAG_touch (1<<4)
+#define FLAG_m (1<<4)
+#define FLAG_to_stdout (1<<5)
+#define FLAG_O (1<<5)
+#define FLAG_gzip (1<<6)
+#define FLAG_z (1<<6)
+#define FLAG_verbose (1<<7)
+#define FLAG_v (1<<7)
+#define FLAG_list (1<<8)
+#define FLAG_t (1<<8)
+#define FLAG_extract (1<<9)
+#define FLAG_x (1<<9)
+#define FLAG_dereference (1<<10)
+#define FLAG_h (1<<10)
+#define FLAG_create (1<<11)
+#define FLAG_c (1<<11)
+#define FLAG_keep_old (1<<12)
+#define FLAG_k (1<<12)
+#define FLAG_same_permissions (1<<13)
+#define FLAG_p (1<<13)
+#define FLAG_no_same_owner (1<<14)
+#define FLAG_o (1<<14)
+#define FLAG_to_command (1<<15)
+#define FLAG_exclude (1<<16)
+#define FLAG_overwrite (1<<17)
+#define FLAG_no_same_permissions (1<<18)
+#define FLAG_numeric_owner (1<<19)
+#define FLAG_no_recursion (1<<20)
+#endif
+
+#ifdef FOR_taskset
+#ifndef TT
+#define TT this.taskset
+#endif
+#define FLAG_a (1<<0)
+#define FLAG_p (1<<1)
+#endif
+
+#ifdef FOR_tcpsvd
+#ifndef TT
+#define TT this.tcpsvd
+#endif
+#define FLAG_v (FORCED_FLAG<<0)
+#define FLAG_E (FORCED_FLAG<<1)
+#define FLAG_h (FORCED_FLAG<<2)
+#define FLAG_l (FORCED_FLAG<<3)
+#define FLAG_u (FORCED_FLAG<<4)
+#define FLAG_b (FORCED_FLAG<<5)
+#define FLAG_C (FORCED_FLAG<<6)
+#define FLAG_c (FORCED_FLAG<<7)
+#endif
+
+#ifdef FOR_tee
+#ifndef TT
+#define TT this.tee
+#endif
+#define FLAG_a (1<<0)
+#define FLAG_i (1<<1)
+#endif
+
+#ifdef FOR_telnet
+#ifndef TT
+#define TT this.telnet
+#endif
+#endif
+
+#ifdef FOR_telnetd
+#ifndef TT
+#define TT this.telnetd
+#endif
+#define FLAG_i (FORCED_FLAG<<0)
+#define FLAG_K (FORCED_FLAG<<1)
+#define FLAG_S (FORCED_FLAG<<2)
+#define FLAG_F (FORCED_FLAG<<3)
+#define FLAG_l (FORCED_FLAG<<4)
+#define FLAG_f (FORCED_FLAG<<5)
+#define FLAG_p (FORCED_FLAG<<6)
+#define FLAG_b (FORCED_FLAG<<7)
+#define FLAG_w (FORCED_FLAG<<8)
+#endif
+
+#ifdef FOR_test
+#ifndef TT
+#define TT this.test
+#endif
+#endif
+
+#ifdef FOR_test_human_readable
+#ifndef TT
+#define TT this.test_human_readable
+#endif
+#define FLAG_s (FORCED_FLAG<<0)
+#define FLAG_b (FORCED_FLAG<<1)
+#define FLAG_i (FORCED_FLAG<<2)
+#endif
+
+#ifdef FOR_test_many_options
+#ifndef TT
+#define TT this.test_many_options
+#endif
+#define FLAG_a (FORCED_FLAG<<0)
+#define FLAG_b (FORCED_FLAG<<1)
+#define FLAG_c (FORCED_FLAG<<2)
+#define FLAG_d (FORCED_FLAG<<3)
+#define FLAG_e (FORCED_FLAG<<4)
+#define FLAG_f (FORCED_FLAG<<5)
+#define FLAG_g (FORCED_FLAG<<6)
+#define FLAG_h (FORCED_FLAG<<7)
+#define FLAG_i (FORCED_FLAG<<8)
+#define FLAG_j (FORCED_FLAG<<9)
+#define FLAG_k (FORCED_FLAG<<10)
+#define FLAG_l (FORCED_FLAG<<11)
+#define FLAG_m (FORCED_FLAG<<12)
+#define FLAG_n (FORCED_FLAG<<13)
+#define FLAG_o (FORCED_FLAG<<14)
+#define FLAG_p (FORCED_FLAG<<15)
+#define FLAG_q (FORCED_FLAG<<16)
+#define FLAG_r (FORCED_FLAG<<17)
+#define FLAG_s (FORCED_FLAG<<18)
+#define FLAG_t (FORCED_FLAG<<19)
+#define FLAG_u (FORCED_FLAG<<20)
+#define FLAG_v (FORCED_FLAG<<21)
+#define FLAG_w (FORCED_FLAG<<22)
+#define FLAG_x (FORCED_FLAG<<23)
+#define FLAG_y (FORCED_FLAG<<24)
+#define FLAG_z (FORCED_FLAG<<25)
+#define FLAG_A (FORCED_FLAG<<26)
+#define FLAG_B (FORCED_FLAG<<27)
+#define FLAG_C (FORCED_FLAG<<28)
+#define FLAG_D (FORCED_FLAG<<29)
+#define FLAG_E (FORCED_FLAG<<30)
+#define FLAG_F (FORCED_FLAG<<31)
+#define FLAG_G (FORCED_FLAGLL<<32)
+#define FLAG_H (FORCED_FLAGLL<<33)
+#define FLAG_I (FORCED_FLAGLL<<34)
+#define FLAG_J (FORCED_FLAGLL<<35)
+#define FLAG_K (FORCED_FLAGLL<<36)
+#define FLAG_L (FORCED_FLAGLL<<37)
+#define FLAG_M (FORCED_FLAGLL<<38)
+#define FLAG_N (FORCED_FLAGLL<<39)
+#define FLAG_O (FORCED_FLAGLL<<40)
+#define FLAG_P (FORCED_FLAGLL<<41)
+#define FLAG_Q (FORCED_FLAGLL<<42)
+#define FLAG_R (FORCED_FLAGLL<<43)
+#define FLAG_S (FORCED_FLAGLL<<44)
+#define FLAG_T (FORCED_FLAGLL<<45)
+#define FLAG_U (FORCED_FLAGLL<<46)
+#define FLAG_V (FORCED_FLAGLL<<47)
+#define FLAG_W (FORCED_FLAGLL<<48)
+#define FLAG_X (FORCED_FLAGLL<<49)
+#define FLAG_Y (FORCED_FLAGLL<<50)
+#define FLAG_Z (FORCED_FLAGLL<<51)
+#endif
+
+#ifdef FOR_test_scankey
+#ifndef TT
+#define TT this.test_scankey
+#endif
+#endif
+
+#ifdef FOR_tftp
+#ifndef TT
+#define TT this.tftp
+#endif
+#define FLAG_p (FORCED_FLAG<<0)
+#define FLAG_g (FORCED_FLAG<<1)
+#define FLAG_l (FORCED_FLAG<<2)
+#define FLAG_r (FORCED_FLAG<<3)
+#define FLAG_b (FORCED_FLAG<<4)
+#endif
+
+#ifdef FOR_tftpd
+#ifndef TT
+#define TT this.tftpd
+#endif
+#define FLAG_l (FORCED_FLAG<<0)
+#define FLAG_u (FORCED_FLAG<<1)
+#define FLAG_c (FORCED_FLAG<<2)
+#define FLAG_r (FORCED_FLAG<<3)
+#endif
+
+#ifdef FOR_time
+#ifndef TT
+#define TT this.time
+#endif
+#define FLAG_p (1<<0)
+#endif
+
+#ifdef FOR_timeout
+#ifndef TT
+#define TT this.timeout
+#endif
+#define FLAG_s (1<<0)
+#define FLAG_k (1<<1)
+#define FLAG_v (1<<2)
+#endif
+
+#ifdef FOR_top
+#ifndef TT
+#define TT this.top
+#endif
+#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_H (1<<9)
+#define FLAG_O (1<<10)
+#define FLAG_m (1<<11)
+#endif
+
+#ifdef FOR_touch
+#ifndef TT
+#define TT this.touch
+#endif
+#define FLAG_h (1<<0)
+#define FLAG_t (1<<1)
+#define FLAG_r (1<<2)
+#define FLAG_m (1<<3)
+#define FLAG_d (1<<4)
+#define FLAG_c (1<<5)
+#define FLAG_a (1<<6)
+#endif
+
+#ifdef FOR_toybox
+#ifndef TT
+#define TT this.toybox
+#endif
+#endif
+
+#ifdef FOR_tr
+#ifndef TT
+#define TT this.tr
+#endif
+#define FLAG_d (1<<0)
+#define FLAG_s (1<<1)
+#define FLAG_c (1<<2)
+#define FLAG_C (1<<3)
+#endif
+
+#ifdef FOR_traceroute
+#ifndef TT
+#define TT this.traceroute
+#endif
+#define FLAG_4 (1<<0)
+#define FLAG_6 (1<<1)
+#define FLAG_F (1<<2)
+#define FLAG_U (1<<3)
+#define FLAG_I (1<<4)
+#define FLAG_l (1<<5)
+#define FLAG_d (1<<6)
+#define FLAG_n (1<<7)
+#define FLAG_v (1<<8)
+#define FLAG_r (1<<9)
+#define FLAG_m (1<<10)
+#define FLAG_p (1<<11)
+#define FLAG_q (1<<12)
+#define FLAG_s (1<<13)
+#define FLAG_t (1<<14)
+#define FLAG_w (1<<15)
+#define FLAG_g (1<<16)
+#define FLAG_z (1<<17)
+#define FLAG_f (1<<18)
+#define FLAG_i (1<<19)
+#endif
+
+#ifdef FOR_true
+#ifndef TT
+#define TT this.true
+#endif
+#endif
+
+#ifdef FOR_truncate
+#ifndef TT
+#define TT this.truncate
+#endif
+#define FLAG_c (1<<0)
+#define FLAG_s (1<<1)
+#endif
+
+#ifdef FOR_tty
+#ifndef TT
+#define TT this.tty
+#endif
+#define FLAG_s (1<<0)
+#endif
+
+#ifdef FOR_ulimit
+#ifndef TT
+#define TT this.ulimit
+#endif
+#define FLAG_c (1<<0)
+#define FLAG_d (1<<1)
+#define FLAG_e (1<<2)
+#define FLAG_f (1<<3)
+#define FLAG_i (1<<4)
+#define FLAG_l (1<<5)
+#define FLAG_m (1<<6)
+#define FLAG_n (1<<7)
+#define FLAG_p (1<<8)
+#define FLAG_q (1<<9)
+#define FLAG_R (1<<10)
+#define FLAG_r (1<<11)
+#define FLAG_s (1<<12)
+#define FLAG_t (1<<13)
+#define FLAG_u (1<<14)
+#define FLAG_v (1<<15)
+#define FLAG_a (1<<16)
+#define FLAG_H (1<<17)
+#define FLAG_S (1<<18)
+#define FLAG_P (1<<19)
+#endif
+
+#ifdef FOR_umount
+#ifndef TT
+#define TT this.umount
+#endif
+#define FLAG_v (1<<0)
+#define FLAG_t (1<<1)
+#define FLAG_a (1<<2)
+#define FLAG_r (1<<3)
+#define FLAG_l (1<<4)
+#define FLAG_f (1<<5)
+#define FLAG_D (1<<6)
+#define FLAG_d (1<<7)
+#define FLAG_n (1<<8)
+#endif
+
+#ifdef FOR_uname
+#ifndef TT
+#define TT this.uname
+#endif
+#define FLAG_s (1<<0)
+#define FLAG_n (1<<1)
+#define FLAG_r (1<<2)
+#define FLAG_v (1<<3)
+#define FLAG_m (1<<4)
+#define FLAG_a (1<<5)
+#define FLAG_o (1<<6)
+#endif
+
+#ifdef FOR_uniq
+#ifndef TT
+#define TT this.uniq
+#endif
+#define FLAG_u (1<<0)
+#define FLAG_d (1<<1)
+#define FLAG_c (1<<2)
+#define FLAG_i (1<<3)
+#define FLAG_z (1<<4)
+#define FLAG_w (1<<5)
+#define FLAG_s (1<<6)
+#define FLAG_f (1<<7)
+#endif
+
+#ifdef FOR_unix2dos
+#ifndef TT
+#define TT this.unix2dos
+#endif
+#endif
+
+#ifdef FOR_unlink
+#ifndef TT
+#define TT this.unlink
+#endif
+#endif
+
+#ifdef FOR_unshare
+#ifndef TT
+#define TT this.unshare
+#endif
+#define FLAG_user (FORCED_FLAG<<0)
+#define FLAG_U (FORCED_FLAG<<0)
+#define FLAG_uts (FORCED_FLAG<<1)
+#define FLAG_u (FORCED_FLAG<<1)
+#define FLAG_pid (FORCED_FLAG<<2)
+#define FLAG_p (FORCED_FLAG<<2)
+#define FLAG_net (FORCED_FLAG<<3)
+#define FLAG_n (FORCED_FLAG<<3)
+#define FLAG_mount (FORCED_FLAG<<4)
+#define FLAG_m (FORCED_FLAG<<4)
+#define FLAG_ipc (FORCED_FLAG<<5)
+#define FLAG_i (FORCED_FLAG<<5)
+#define FLAG_map_root_user (FORCED_FLAG<<6)
+#define FLAG_r (FORCED_FLAG<<6)
+#define FLAG_fork (FORCED_FLAG<<7)
+#define FLAG_f (FORCED_FLAG<<7)
+#endif
+
+#ifdef FOR_uptime
+#ifndef TT
+#define TT this.uptime
+#endif
+#endif
+
+#ifdef FOR_useradd
+#ifndef TT
+#define TT this.useradd
+#endif
+#define FLAG_H (FORCED_FLAG<<0)
+#define FLAG_D (FORCED_FLAG<<1)
+#define FLAG_S (FORCED_FLAG<<2)
+#define FLAG_h (FORCED_FLAG<<3)
+#define FLAG_g (FORCED_FLAG<<4)
+#define FLAG_s (FORCED_FLAG<<5)
+#define FLAG_G (FORCED_FLAG<<6)
+#define FLAG_u (FORCED_FLAG<<7)
+#endif
+
+#ifdef FOR_userdel
+#ifndef TT
+#define TT this.userdel
+#endif
+#define FLAG_r (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_usleep
+#ifndef TT
+#define TT this.usleep
+#endif
+#endif
+
+#ifdef FOR_uudecode
+#ifndef TT
+#define TT this.uudecode
+#endif
+#define FLAG_o (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_uuencode
+#ifndef TT
+#define TT this.uuencode
+#endif
+#define FLAG_m (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_vconfig
+#ifndef TT
+#define TT this.vconfig
+#endif
+#endif
+
+#ifdef FOR_vi
+#ifndef TT
+#define TT this.vi
+#endif
+#endif
+
+#ifdef FOR_vmstat
+#ifndef TT
+#define TT this.vmstat
+#endif
+#define FLAG_n (1<<0)
+#endif
+
+#ifdef FOR_w
+#ifndef TT
+#define TT this.w
+#endif
+#endif
+
+#ifdef FOR_watch
+#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)
+#endif
+
+#ifdef FOR_wc
+#ifndef TT
+#define TT this.wc
+#endif
+#define FLAG_l (1<<0)
+#define FLAG_w (1<<1)
+#define FLAG_c (1<<2)
+#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
+#endif
+#define FLAG_a (1<<0)
+#endif
+
+#ifdef FOR_who
+#ifndef TT
+#define TT this.who
+#endif
+#define FLAG_a (FORCED_FLAG<<0)
+#endif
+
+#ifdef FOR_xargs
+#ifndef TT
+#define TT this.xargs
+#endif
+#define FLAG_0 (1<<0)
+#define FLAG_s (1<<1)
+#define FLAG_n (1<<2)
+#define FLAG_r (1<<3)
+#define FLAG_x (1<<4)
+#define FLAG_t (1<<5)
+#define FLAG_p (1<<6)
+#define FLAG_L (1<<7)
+#define FLAG_E (1<<8)
+#define FLAG_I (1<<9)
+#endif
+
+#ifdef FOR_xxd
+#ifndef TT
+#define TT this.xxd
+#endif
+#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
+#ifndef TT
+#define TT this.xzcat
+#endif
+#endif
+
+#ifdef FOR_yes
+#ifndef TT
+#define TT this.yes
+#endif
+#endif
+
+#ifdef FOR_zcat
+#ifndef TT
+#define TT this.zcat
+#endif
+#endif
+
diff --git a/toybox/generated/globals.h b/toybox/generated/globals.h
new file mode 100644
index 0000000..8a9be04
--- /dev/null
+++ b/toybox/generated/globals.h
@@ -0,0 +1,1497 @@
+// toys/android/getprop.c
+
+struct getprop_data {
+  size_t size;
+  char **nv; // name/value pairs: even=name, odd=value
+  struct selabel_handle *handle;
+};
+
+// toys/android/log.c
+
+struct log_data {
+  char *tag;
+  char *pri;
+};
+
+// toys/example/hello.c
+
+struct hello_data {
+  int unused;
+};
+
+// toys/example/skeleton.c
+
+struct skeleton_data {
+  union {
+    struct {
+      char *b_string;
+      long c_number;
+      struct arg_list *d_list;
+      long e_count;
+      char *also_string;
+      char *blubber_string;
+    } s;
+    struct {
+      long b_number;
+    } a;
+  };
+
+  int more_globals;
+};
+
+// toys/lsb/dmesg.c
+
+struct dmesg_data {
+  long level;
+  long size;
+};
+
+// toys/lsb/hostname.c
+
+struct hostname_data {
+  char *fname;
+};
+
+// toys/lsb/killall.c
+
+struct killall_data {
+  char *sig;
+
+  int signum;
+  pid_t cur_pid;
+  char **names;
+  short *err;
+};
+
+// 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;
+  union {
+    char c[64];
+    unsigned i[16];
+  } buffer;
+};
+
+// toys/lsb/mknod.c
+
+struct mknod_data {
+  char *arg_context;
+  char *m;
+};
+
+// toys/lsb/mktemp.c
+
+struct mktemp_data {
+  char *tmpdir;
+};
+
+// toys/lsb/mount.c
+
+struct mount_data {
+  struct arg_list *optlist;
+  char *type;
+  char *bigO;
+
+  unsigned long flags;
+  char *opts;
+  int okuser;
+};
+
+// toys/lsb/passwd.c
+
+struct passwd_data {
+  char *algo;
+};
+
+// toys/lsb/pidof.c
+
+struct pidof_data {
+  char *omit;
+};
+
+// toys/lsb/seq.c
+
+struct seq_data {
+  char *sep;
+  char *fmt;
+};
+
+// toys/lsb/su.c
+
+struct su_data {
+  char *s;
+  char *c;
+};
+
+// toys/lsb/umount.c
+
+struct umount_data {
+  struct arg_list *t;
+
+  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/other/acpi.c
+
+struct acpi_data {
+  int ac, bat, therm, cool;
+  char *cpath;
+};
+
+// toys/other/base64.c
+
+struct base64_data {
+  long columns;
+
+  unsigned total;
+};
+
+// toys/other/blockdev.c
+
+struct blockdev_data {
+  long bsz;
+};
+
+// toys/other/dos2unix.c
+
+struct dos2unix_data {
+  char *tempfile;
+};
+
+// toys/other/fallocate.c
+
+struct fallocate_data {
+  long size;
+};
+
+// toys/other/free.c
+
+struct free_data {
+  unsigned bits;
+  unsigned long long units;
+  char *buf;
+};
+
+// toys/other/hexedit.c
+
+struct hexedit_data {
+  char *data;
+  long long len, base;
+  int numlen, undo, undolen;
+  unsigned height;
+};
+
+// toys/other/hwclock.c
+
+struct hwclock_data {
+  char *fname;
+
+  int utc;
+};
+
+// toys/other/ionice.c
+
+struct ionice_data {
+  long pid;
+  long level;
+  long class;
+};
+
+// toys/other/login.c
+
+struct login_data {
+  char *hostname;
+  char *username;
+
+  int login_timeout, login_fail_timeout;
+};
+
+// toys/other/losetup.c
+
+struct losetup_data {
+  char *jfile;
+  long offset;
+  long size;
+
+  int openflags;
+  dev_t jdev;
+  ino_t jino;
+};
+
+// toys/other/lspci.c
+
+struct lspci_data {
+  char *ids;
+  long numeric;
+
+  FILE *db;
+};
+
+// toys/other/makedevs.c
+
+struct makedevs_data {
+  char *fname;
+};
+
+// toys/other/mix.c
+
+struct mix_data {
+   long right;
+   long level;
+   char *dev;
+   char *chan;
+};
+
+// toys/other/mkpasswd.c
+
+struct mkpasswd_data {
+  long pfd;
+  char *method;
+  char *salt;
+};
+
+// toys/other/mkswap.c
+
+struct mkswap_data {
+  char *L;
+};
+
+// toys/other/modinfo.c
+
+struct modinfo_data {
+  char *field;
+  char *knam;
+  char *base;
+
+  long mod;
+};
+
+// toys/other/nsenter.c
+
+struct nsenter_data {
+  char *nsnames[6];
+  long targetpid;
+};
+
+// toys/other/oneit.c
+
+struct oneit_data {
+  char *console;
+};
+
+// toys/other/setfattr.c
+
+struct setfattr_data {
+  char *x, *v, *n;
+};
+
+// toys/other/shred.c
+
+struct shred_data {
+  long offset;
+  long iterations;
+  long size;
+
+  int ufd;
+};
+
+// toys/other/stat.c
+
+struct stat_data {
+  char *fmt;
+
+  union {
+    struct stat st;
+    struct statfs sf;
+  } stat;
+  char *file, *pattern;
+  int patlen;
+};
+
+// toys/other/swapon.c
+
+struct swapon_data {
+  long priority;
+};
+
+// toys/other/switch_root.c
+
+struct switch_root_data {
+  char *console;
+
+  dev_t rootdev;
+};
+
+// toys/other/timeout.c
+
+struct timeout_data {
+  char *s_signal;
+  char *k_timeout;
+
+  int nextsig;
+  pid_t pid;
+  struct timeval ktv;
+  struct itimerval itv;
+};
+
+// toys/other/truncate.c
+
+struct truncate_data {
+  char *s;
+
+  long size;
+  int type;
+};
+
+// toys/other/xxd.c
+
+struct xxd_data {
+  long s;
+  long g;
+  long l;
+  long c;
+};
+
+// toys/pending/arp.c
+
+struct arp_data {
+    char *hw_type;
+    char *af_type_A;
+    char *af_type_p;
+    char *interface;
+    
+    int sockfd;
+    char *device;
+};
+
+// toys/pending/arping.c
+
+struct arping_data {
+    long count;
+    unsigned long time_out;
+    char *iface;
+    char *src_ip;
+
+    int sockfd;
+    unsigned long start, end;
+    unsigned sent_at, sent_nr, rcvd_nr, brd_sent, rcvd_req, brd_rcv,
+             unicast_flag;
+};
+
+// toys/pending/bootchartd.c
+
+struct bootchartd_data {
+  char buf[32];
+  long smpl_period_usec;
+  int proc_accounting;
+  int is_login;
+
+  void *head;
+};
+
+// toys/pending/brctl.c
+
+struct brctl_data {
+    int sockfd;
+};
+
+// toys/pending/compress.c
+
+struct compress_data {
+  // Huffman codes: base offset and extra bits tables (length and distance)
+  char lenbits[29], distbits[30];
+  unsigned short lenbase[29], distbase[30];
+  void *fixdisthuff, *fixlithuff;
+
+  // CRC
+  void (*crcfunc)(char *data, int len);
+  unsigned crc;
+
+  // Compressed data buffer
+  char *data;
+  unsigned pos, len;
+  int infd, outfd;
+
+  // Tables only used for deflation
+  unsigned short *hashhead, *hashchain;
+};
+
+// toys/pending/crond.c
+
+struct crond_data {
+  char *crontabs_dir;
+  char *logfile;
+  int loglevel_d;
+  int loglevel;
+
+  time_t crontabs_dir_mtime;
+  uint8_t flagd;
+};
+
+// toys/pending/crontab.c
+
+struct crontab_data {
+  char *user;
+  char *cdir;
+};
+
+// toys/pending/dd.c
+
+struct dd_data {
+  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
+
+struct dhcp_data {
+    char *iface;
+    char *pidfile;
+    char *script;
+    long retries;
+    long timeout;
+    long tryagain;
+    struct arg_list *req_opt;
+    char *req_ip;
+    struct arg_list *pkt_opt;
+    char *fdn_name;
+    char *hostname;
+    char *vendor_cls;
+};
+
+// toys/pending/dhcp6.c
+
+struct dhcp6_data {
+  char *interface_name, *pidfile, *script;
+  long retry, timeout, errortimeout;
+  char *req_ip;
+  int length, state, request_length, sock, sock1, status, retval, retries;
+  struct timeval tv;
+  uint8_t transction_id[3];
+  struct sockaddr_in6 input_socket6;
+};
+
+// toys/pending/dhcpd.c
+
+struct dhcpd_data {
+    char *iface;
+    long port;
+};;
+
+// toys/pending/diff.c
+
+struct diff_data {
+  long ct;
+  char *start;
+  struct arg_list *L_list;
+
+  int dir_num, size, is_binary, status, change, len[2];
+  int *offset[2];
+};
+
+// toys/pending/dumpleases.c
+
+struct dumpleases_data {
+    char *file;
+};
+
+// toys/pending/expr.c
+
+struct expr_data {
+  char **tok; // current token, not on the stack since recursive calls mutate it
+
+  char *refree;
+};
+
+// toys/pending/fdisk.c
+
+struct fdisk_data {
+  long sect_sz;
+  long sectors;
+  long heads;
+  long cylinders;
+};
+
+// toys/pending/fold.c
+
+struct fold_data {
+  int width;
+};
+
+// toys/pending/fsck.c
+
+struct fsck_data {
+  int fd_num;
+  char *t_list;
+
+  struct double_list *devices;
+  char *arr_flag;
+  char **arr_type;
+  int negate;
+  int sum_status;
+  int nr_run;
+  int sig_num;
+  long max_nr_run;
+};
+
+// toys/pending/ftpget.c
+
+struct ftpget_data {
+  long port; //  char *port;
+  char *password;
+  char *username;
+
+  FILE *sockfp;
+  int c;
+  int isget;
+  char buf[sizeof(struct sockaddr_storage)];
+};
+
+// toys/pending/getfattr.c
+
+struct getfattr_data {
+  char *n;
+};
+
+// toys/pending/getty.c
+
+struct getty_data {
+  char *issue_str;
+  char *login_str;
+  char *init_str;
+  char *host_str; 
+  long timeout;
+  
+  char *tty_name;  
+  int  speeds[20];
+  int  sc;              
+  struct termios termios;
+  char buff[128];
+};
+
+// toys/pending/groupadd.c
+
+struct groupadd_data {
+  long gid;
+};
+
+// toys/pending/host.c
+
+struct host_data {
+  char *type_str;
+};
+
+// toys/pending/iconv.c
+
+struct iconv_data {
+  char *from;
+  char *to;
+
+  void *ic;
+};
+
+// toys/pending/ip.c
+
+struct ip_data {
+  char stats, singleline, flush, *filter_dev, gbuf[8192];
+  int sockfd, connected, from_ok, route_cmd;
+  int8_t addressfamily, is_addr;
+};
+
+// toys/pending/ipcrm.c
+
+struct ipcrm_data {
+  struct arg_list *qkey;
+  struct arg_list *qid;
+  struct arg_list *skey;
+  struct arg_list *sid;
+  struct arg_list *mkey;
+  struct arg_list *mid;
+};
+
+// toys/pending/ipcs.c
+
+struct ipcs_data {
+  int id;
+};
+
+// toys/pending/klogd.c
+
+struct klogd_data {
+  long level;
+
+  int fd;
+};
+
+// toys/pending/last.c
+
+struct last_data {
+  char *file;
+
+  struct arg_list *list;
+};
+
+// toys/pending/logger.c
+
+struct logger_data {
+  char *priority_arg;
+  char *ident;
+};
+
+// toys/pending/lsof.c
+
+struct lsof_data {
+  struct arg_list *p;
+
+  struct stat *sought_files;
+
+  struct double_list *all_sockets;
+  struct double_list *files;
+  int last_shown_pid;
+  int shown_header;
+};
+
+// toys/pending/mke2fs.c
+
+struct mke2fs_data {
+  // Command line arguments.
+  long blocksize;
+  long bytes_per_inode;
+  long inodes;           // Total inodes in filesystem.
+  long reserved_percent; // Integer precent of space to reserve for root.
+  char *gendir;          // Where to read dirtree from.
+
+  // Internal data.
+  struct dirtree *dt;    // Tree of files to copy into the new filesystem.
+  unsigned treeblocks;   // Blocks used by dt
+  unsigned treeinodes;   // Inodes used by dt
+
+  unsigned blocks;       // Total blocks in the filesystem.
+  unsigned freeblocks;   // Free blocks in the filesystem.
+  unsigned inodespg;     // Inodes per group
+  unsigned groups;       // Total number of block groups.
+  unsigned blockbits;    // Bits per block.  (Also blocks per group.)
+
+  // For gene2fs
+  unsigned nextblock;    // Next data block to allocate
+  unsigned nextgroup;    // Next group we'll be allocating from
+  int fsfd;              // File descriptor of filesystem (to output to).
+
+  struct ext2_superblock sb;
+};
+
+// toys/pending/modprobe.c
+
+struct modprobe_data {
+  struct arg_list *probes;
+  struct arg_list *dbase[256];
+  char *cmdopts;
+  int nudeps;
+  uint8_t symreq;
+  void (*dbg)(char *format, ...);
+};
+
+// toys/pending/more.c
+
+struct more_data {
+  struct termios inf;
+  int cin_fd;
+};
+
+// toys/pending/openvt.c
+
+struct openvt_data {
+  unsigned long vt_num;
+};
+
+// toys/pending/ping.c
+
+struct ping_data {
+  long wait_exit;
+  long wait_resp;
+  char *iface;
+  long size;
+  long count;
+  long ttl;
+
+  int sock;
+};
+
+// toys/pending/route.c
+
+struct route_data {
+  char *family;
+};
+
+// toys/pending/sh.c
+
+struct sh_data {
+  char *command;
+
+  long lineno;
+};
+
+// toys/pending/sulogin.c
+
+struct sulogin_data {
+  long timeout;
+  struct termios crntio;
+};
+
+// toys/pending/syslogd.c
+
+struct syslogd_data {
+  char *socket;
+  char *config_file;
+  char *unix_socket;
+  char *logfile;
+  long interval;
+  long rot_size;
+  long rot_count;
+  char *remote_log;
+  long log_prio;
+
+  struct unsocks *lsocks;  // list of listen sockets
+  struct logfile *lfiles;  // list of write logfiles
+  int sigfd[2];
+};
+
+// toys/pending/tar.c
+
+struct tar_data {
+  char *fname;
+  char *dir;
+  struct arg_list *inc_file;
+  struct arg_list *exc_file;
+  char *tocmd;
+  struct arg_list *exc;
+
+  struct arg_list *inc, *pass;
+  void *inodes, *handle;
+};
+
+// toys/pending/tcpsvd.c
+
+struct tcpsvd_data {
+  char *name;
+  char *user;
+  long bn;
+  char *nmsg;
+  long cn;
+
+  int maxc;
+  int count_all;
+  int udp;
+};
+
+// toys/pending/telnet.c
+
+struct telnet_data {
+  int port;
+  int sfd;
+  char buff[128];
+  int pbuff;
+  char iac[256];
+  int piac;
+  char *ttype;
+  struct termios def_term;
+  struct termios raw_term;
+  uint8_t term_ok;
+  uint8_t term_mode;
+  uint8_t flags;
+  unsigned win_width;
+  unsigned win_height;
+};
+
+// toys/pending/telnetd.c
+
+struct telnetd_data {
+    char *login_path;
+    char *issue_path;
+    int port;
+    char *host_addr;
+    long w_sec;
+
+    int gmax_fd;
+    pid_t fork_pid;
+};
+
+// toys/pending/tftp.c
+
+struct tftp_data {
+  char *local_file;
+  char *remote_file;
+  long block_size;
+
+  struct sockaddr_storage inaddr;
+  int af;
+};
+
+// toys/pending/tftpd.c
+
+struct tftpd_data {
+  char *user;
+
+  long sfd;
+  struct passwd *pw;
+};
+
+// toys/pending/tr.c
+
+struct tr_data {
+  short map[256]; //map of chars
+  int len1, len2;
+};
+
+// toys/pending/traceroute.c
+
+struct traceroute_data {
+  long max_ttl;
+  long port;
+  long ttl_probes;
+  char *src_ip;
+  long tos;
+  long wait_time;
+  struct arg_list *loose_source;
+  long pause_time;
+  long first_ttl;
+  char *iface;
+
+  uint32_t gw_list[9];
+  int recv_sock;
+  int snd_sock;
+  unsigned msg_len;
+  char *packet;
+  uint32_t ident;
+  int istraceroute6;
+};
+
+// toys/pending/useradd.c
+
+struct useradd_data {
+  char *dir;
+  char *gecos;
+  char *shell;
+  char *u_grp;
+  long uid;
+
+  long gid;
+};
+
+// toys/pending/vi.c
+
+struct vi_data {
+  struct linestack *ls;
+  char *statline;
+};
+
+// toys/pending/watch.c
+
+struct watch_data {
+  int interval;
+};
+
+// toys/pending/wget.c
+
+struct wget_data {
+  char *filename;
+};
+
+// toys/posix/chgrp.c
+
+struct chgrp_data {
+  uid_t owner;
+  gid_t group;
+  char *owner_name, *group_name;
+  int symfollow;
+};
+
+// toys/posix/chmod.c
+
+struct chmod_data {
+  char *mode;
+};
+
+// toys/posix/cksum.c
+
+struct cksum_data {
+  unsigned crc_table[256];
+};
+
+// toys/posix/cmp.c
+
+struct cmp_data {
+  int fd;
+  char *name;
+};
+
+// toys/posix/cp.c
+
+struct cp_data {
+  union {
+    struct {
+      // install's options
+      char *group;
+      char *user;
+      char *mode;
+    } i;
+    struct {
+      char *preserve;
+    } c;
+  };
+
+  char *destname;
+  struct stat top;
+  int (*callback)(struct dirtree *try);
+  uid_t uid;
+  gid_t gid;
+  int pflags;
+};
+
+// toys/posix/cpio.c
+
+struct cpio_data {
+  char *archive;
+  char *pass;
+  char *fmt;
+};
+
+// toys/posix/cut.c
+
+struct cut_data {
+  char *delim;
+  char *flist;
+  char *clist;
+  char *blist;
+
+  void *slist_head;
+  unsigned nelem;
+  void (*do_cut)(int fd);
+};
+
+// toys/posix/date.c
+
+struct date_data {
+  char *file;
+  char *setfmt;
+  char *showdate;
+
+  char *tz;
+  unsigned nano;
+};
+
+// toys/posix/df.c
+
+struct df_data {
+  struct arg_list *fstype;
+
+  long units;
+  int column_widths[5];
+  int header_shown;
+};
+
+// toys/posix/du.c
+
+struct du_data {
+  long maxdepth;
+
+  long depth, total;
+  dev_t st_dev;
+  void *inodes;
+};
+
+// toys/posix/env.c
+
+struct env_data {
+  struct arg_list *u;
+};;
+
+// toys/posix/expand.c
+
+struct expand_data {
+  struct arg_list *tabs;
+
+  unsigned tabcount, *tab;
+};
+
+// toys/posix/file.c
+
+struct file_data {
+  int max_name_len;
+};
+
+// toys/posix/find.c
+
+struct find_data {
+  char **filter;
+  struct double_list *argdata;
+  int topdir, xdev, depth;
+  time_t now;
+};
+
+// toys/posix/grep.c
+
+struct grep_data {
+  long m;
+  struct arg_list *f;
+  struct arg_list *e;
+  long a;
+  long b;
+  long c;
+
+  char indelim, outdelim;
+};
+
+// toys/posix/head.c
+
+struct head_data {
+  long lines;
+  int file_no;
+};
+
+// toys/posix/id.c
+
+struct id_data {
+  int is_groups;
+};
+
+// toys/posix/kill.c
+
+struct kill_data {
+  char *signame;
+  struct arg_list *olist;
+};
+
+// toys/posix/ls.c
+
+struct ls_data {
+  char *color;
+
+  struct dirtree *files, *singledir;
+
+  unsigned screen_width;
+  int nl_title;
+  char *escmore;
+};
+
+// toys/posix/mkdir.c
+
+struct mkdir_data {
+  char *arg_mode;
+  char *arg_context;
+};
+
+// toys/posix/mkfifo.c
+
+struct mkfifo_data {
+  char *m_string;
+  char *Z;
+
+  mode_t mode;
+};
+
+// toys/posix/nice.c
+
+struct nice_data {
+  long priority;
+};
+
+// toys/posix/nl.c
+
+struct nl_data {
+  long w;
+  char *s;
+  char *n;
+  char *b;
+  long l;
+  long v;
+
+  // Count of consecutive blank lines for -l has to persist between files
+  long lcount;
+};
+
+// toys/posix/od.c
+
+struct od_data {
+  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; // Points to buffers[0] or buffers[1].
+  char *bufs[2]; // Used to detect duplicate lines.
+  off_t pos;
+};
+
+// toys/posix/paste.c
+
+struct paste_data {
+  char *delim;
+};
+
+// toys/posix/patch.c
+
+struct patch_data {
+  char *infile;
+  long prefix;
+  char *dir;
+
+  struct double_list *current_hunk;
+  long oldline, oldlen, newline, newlen;
+  long linenum;
+  int context, state, filein, fileout, filepatch, hunknum;
+  char *tempname;
+};
+
+// toys/posix/ps.c
+
+struct ps_data {
+  union {
+    struct {
+      struct arg_list *G;
+      struct arg_list *g;
+      struct arg_list *U;
+      struct arg_list *u;
+      struct arg_list *t;
+      struct arg_list *s;
+      struct arg_list *p;
+      struct arg_list *O;
+      struct arg_list *o;
+      struct arg_list *P;
+      struct arg_list *k;
+    } ps;
+    struct {
+      long n;
+      long d;
+      long s;
+      struct arg_list *u;
+      struct arg_list *p;
+      struct arg_list *o;
+      struct arg_list *k;
+      struct arg_list *O;
+    } top;
+    struct {
+      char *L;
+      struct arg_list *G;
+      struct arg_list *g;
+      struct arg_list *P;
+      struct arg_list *s;
+      struct arg_list *t;
+      struct arg_list *U;
+      struct arg_list *u;
+      char *d;
+
+      void *regexes, *snapshot;
+      int signal;
+      pid_t self, match;
+    } pgrep;
+  };
+
+  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;
+  long long ticks, bits, time;
+  int kcount, forcek, sortpos;
+  int (*match_process)(long long *slot);
+  void (*show_process)(void *tb);
+};
+
+// toys/posix/renice.c
+
+struct renice_data {
+  long nArgu;
+};
+
+// toys/posix/sed.c
+
+struct sed_data {
+  struct arg_list *f;
+  struct arg_list *e;
+
+  // processed pattern list
+  struct double_list *pattern;
+
+  char *nextline, *remember;
+  void *restart, *lastregex;
+  long nextlen, rememberlen, count;
+  int fdout, noeol;
+  unsigned xx;
+};
+
+// toys/posix/sort.c
+
+struct sort_data {
+  char *key_separator;
+  struct arg_list *raw_keys;
+  char *outfile;
+  char *ignore1, ignore2;   // GNU compatability NOPs for -S and -T.
+
+  void *key_list;
+  int linecount;
+  char **lines;
+};
+
+// toys/posix/split.c
+
+struct split_data {
+  long lines;
+  long bytes;
+  long suflen;
+
+  char *outfile;
+};
+
+// toys/posix/strings.c
+
+struct strings_data {
+  long num;
+};
+
+// toys/posix/tail.c
+
+struct tail_data {
+  long lines;
+  long bytes;
+
+  int file_no, ffd, *files;
+};
+
+// toys/posix/tee.c
+
+struct tee_data {
+  void *outputs;
+};
+
+// toys/posix/touch.c
+
+struct touch_data {
+  char *time;
+  char *file;
+  char *date;
+};
+
+// toys/posix/ulimit.c
+
+struct ulimit_data {
+  long pid;
+};
+
+// toys/posix/uniq.c
+
+struct uniq_data {
+  long maxchars;
+  long nchars;
+  long nfields;
+  long repeats;
+};
+
+// toys/posix/uudecode.c
+
+struct uudecode_data {
+  char *o;
+};
+
+// toys/posix/wc.c
+
+struct wc_data {
+  unsigned long totals[4];
+};
+
+// toys/posix/xargs.c
+
+struct xargs_data {
+  long max_bytes;
+  long max_entries;
+  long L;
+  char *eofstr;
+  char *I;
+
+  long entries, bytes;
+  char delim;
+};
+
+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 mktemp_data mktemp;
+	struct mount_data mount;
+	struct passwd_data passwd;
+	struct pidof_data pidof;
+	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 acpi_data acpi;
+	struct base64_data base64;
+	struct blockdev_data blockdev;
+	struct dos2unix_data dos2unix;
+	struct fallocate_data fallocate;
+	struct free_data free;
+	struct hexedit_data hexedit;
+	struct hwclock_data hwclock;
+	struct ionice_data ionice;
+	struct login_data login;
+	struct losetup_data losetup;
+	struct lspci_data lspci;
+	struct makedevs_data makedevs;
+	struct mix_data mix;
+	struct mkpasswd_data mkpasswd;
+	struct mkswap_data mkswap;
+	struct modinfo_data modinfo;
+	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 switch_root_data switch_root;
+	struct timeout_data timeout;
+	struct truncate_data truncate;
+	struct xxd_data xxd;
+	struct arp_data arp;
+	struct arping_data arping;
+	struct bootchartd_data bootchartd;
+	struct brctl_data brctl;
+	struct compress_data compress;
+	struct crond_data crond;
+	struct crontab_data crontab;
+	struct dd_data dd;
+	struct dhcp_data dhcp;
+	struct dhcp6_data dhcp6;
+	struct dhcpd_data dhcpd;
+	struct diff_data diff;
+	struct dumpleases_data dumpleases;
+	struct expr_data expr;
+	struct fdisk_data fdisk;
+	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 iconv_data iconv;
+	struct ip_data ip;
+	struct ipcrm_data ipcrm;
+	struct ipcs_data ipcs;
+	struct klogd_data klogd;
+	struct last_data last;
+	struct logger_data logger;
+	struct lsof_data lsof;
+	struct mke2fs_data mke2fs;
+	struct modprobe_data modprobe;
+	struct more_data more;
+	struct openvt_data openvt;
+	struct ping_data ping;
+	struct route_data route;
+	struct sh_data sh;
+	struct sulogin_data sulogin;
+	struct syslogd_data syslogd;
+	struct tar_data tar;
+	struct tcpsvd_data tcpsvd;
+	struct telnet_data telnet;
+	struct telnetd_data telnetd;
+	struct tftp_data tftp;
+	struct tftpd_data tftpd;
+	struct tr_data tr;
+	struct traceroute_data traceroute;
+	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 cmp_data cmp;
+	struct cp_data cp;
+	struct cpio_data cpio;
+	struct cut_data cut;
+	struct date_data date;
+	struct df_data df;
+	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;
+	struct id_data id;
+	struct kill_data kill;
+	struct ls_data ls;
+	struct mkdir_data mkdir;
+	struct mkfifo_data mkfifo;
+	struct nice_data nice;
+	struct nl_data nl;
+	struct od_data od;
+	struct paste_data paste;
+	struct patch_data patch;
+	struct ps_data ps;
+	struct renice_data renice;
+	struct sed_data sed;
+	struct sort_data sort;
+	struct split_data split;
+	struct strings_data strings;
+	struct tail_data tail;
+	struct tee_data tee;
+	struct touch_data touch;
+	struct ulimit_data ulimit;
+	struct uniq_data uniq;
+	struct uudecode_data uudecode;
+	struct wc_data wc;
+	struct xargs_data xargs;
+} this;
diff --git a/toybox/generated/help.h b/toybox/generated/help.h
new file mode 100644
index 0000000..62277f1
--- /dev/null
+++ b/toybox/generated/help.h
@@ -0,0 +1,582 @@
+#define HELP_toybox_musl_nommu_is_broken "When using musl-libc on a nommu system, you'll need to say \"y\" here.\n\nAlthough uclibc lets you detect support for things like fork() and\ndaemon() at compile time, musl intentionally includes broken versions\nthat always return -ENOSYS on nommu systems, and goes out of its way\nto prevent any cross-compile compatible compile-time probes for a\nnommu system.\n\nMusl does this despite the fact that a nommu system can't even run\nstandard ELF binaries, and requires specially packaged executables.\n(You can't even check a #define to see that you're building against\nmusl, due to its maintainer's policy that musl never has bugs that\nrequire workarounds.)\n\nSo our only choice is to manually provide a musl nommu bug workaround\nyou can manually select to enable (larger, slower) nommu support with\nmusl.\n\nYou don't need this for uClibc, we have a compile time probe that\nautodetects nommu support there.\n\n"
+
+#define HELP_toybox_uid_usr "When commands like useradd/groupadd allocate user IDs, start here.\n\n"
+
+#define HELP_toybox_uid_sys "When commands like useradd/groupadd allocate system IDs, start here.\n\n"
+
+#define HELP_toybox_debug "Enable extra checks for debugging purposes. All of them catch\nthings that can only go wrong at development time, not runtime.\n\n"
+
+#define HELP_toybox_norecurse "When one toybox command calls another, usually it just calls the new\ncommand's main() function rather than searching the $PATH and calling\nexec on another file (which is much slower).\n\nThis disables that optimization, so toybox will run external commands\n       even when it has a built-in version of that command. This requires\n       toybox symlinks to be installed in the $PATH, or re-invoking the\n       \"toybox\" multiplexer command by name.\n\n"
+
+#define HELP_toybox_free "When a program exits, the operating system will clean up after it\n(free memory, close files, etc). To save size, toybox usually relies\non this behavior. If you're running toybox under a debugger or\nwithout a real OS (ala newlib+libgloss), enable this to make toybox\nclean up after itself.\n\n"
+
+#define HELP_toybox_i18n "Support for UTF-8 character sets, and some locale support.\n\n"
+
+#define HELP_toybox_help_dashdash "Support --help argument in all commands, even ones with a NULL\noptstring. Produces the same output as \"help command\".\n\n"
+
+#define HELP_toybox_help "Include help text for each command.\n\n"
+
+#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_lsm_none "Don't try to achieve \"watertight\" by plugging the holes in a\ncollander, instead use conventional unix security (and possibly\nLinux Containers) for a simple straightforward system.\n\n"
+
+#define HELP_toybox_suid "Support for the Set User ID bit, to install toybox suid root and drop\npermissions for commands which do not require root access. To use\nthis change ownership of the file to the root user and set the suid\nbit in the file permissions:\n\nchown root:root toybox; chmod +s toybox\n\nprompt \"Security Blanket\"\ndefault TOYBOX_LSM_NONE\nhelp\nSelect a Linux Security Module to complicate your system\nuntil you can't find holes in it.\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_getenforce "usage: getenforce\n\nShows whether SELinux is disabled, enforcing, or permissive.\n\n"
+
+#define HELP_test_scankey "usage: test_scankey\n\nMove a letter around the screen. Hit ESC to exit.\n\n\n"
+
+#define HELP_test_many_options "usage: test_many_options -[a-zA-Z]\n\nPrint the optflags value of the command arguments, in hex.\n\n"
+
+#define HELP_test_human_readable "usage: test_human_readable [-sbi] NUMBER\n\n"
+
+#define HELP_skeleton_alias "usage: skeleton_alias [-dq] [-b NUMBER]\n\nExample of a second command with different arguments in the same source\nfile as the first. This allows shared infrastructure not added to lib/.\n\n"
+
+#define HELP_skeleton "usage: skeleton [-a] [-b STRING] [-c NUMBER] [-d LIST] [-e COUNT] [...]\n\nTemplate for new commands. You don't need this.\n\nWhen creating a new command, copy this file and delete the parts you\ndon't need. Be sure to replace all instances of \"skeleton\" (upper and lower\ncase) with your new command name.\n\nFor simple commands, \"hello.c\" is probably a better starting point.\n\n"
+
+#define HELP_hello "usage: hello [-s]\n\nA hello world program.  You don't need this.\n\nMostly used as a simple template for adding new commands.\nOccasionally nice to smoketest kernel booting via \"init=/usr/bin/hello\".\n\n"
+
+#define HELP_umount "usage: umount [-a [-t TYPE[,TYPE...]]] [-vrfD] [DIR...]\n\nUnmount the listed filesystems.\n\n-a	Unmount all mounts in /proc/mounts instead of command line list\n-D  Don't free loopback device(s).\n-f  Force unmount.\n-l  Lazy unmount (detach from filesystem now, close when last user does).\n-n	Don't use /proc/mounts\n-r  Remount read only if unmounting fails.\n-t	Restrict \"all\" to mounts of TYPE (or use \"noTYPE\" to skip)\n-v	Verbose\n\n\n"
+
+#define HELP_sync "usage: sync\n\nWrite pending cached data to disk (synchronize), blocking until done.\n\n"
+
+#define HELP_su "usage: su [-lmp] [-c CMD] [-s SHELL] [USER [ARGS...]]\n\nSwitch to user (or root) and run shell (with optional command line).\n\n-s	shell to use\n-c	command to pass to shell with -c\n-l	login shell\n-(m|p)	preserve environment\n\n"
+
+#define HELP_seq "usage: seq [-w|-f fmt_str] [-s sep_str] [first] [increment] last\n\nCount from first to last, by increment. Omitted arguments default\nto 1. Two arguments are used as first and last. Arguments can be\nnegative or floating point.\n\n-f	Use fmt_str as a printf-style floating point format string\n-s	Use sep_str as separator, default is a newline character\n-w	Pad to equal width with leading zeroes.\n\n"
+
+#define HELP_pidof "usage: pidof [-s] [-o omitpid[,omitpid...]] [NAME]...\n\nPrint the PIDs of all processes with the given names.\n\n-s	single shot, only return one pid.\n-o	omit PID(s)\n\n"
+
+#define HELP_passwd_sad "Password changes are checked to make sure they don't include the entire\nusername (but not a subset of it), and the entire previous password\n(but changing password1, password2, password3 is fine). This heuristic\naccepts \"aaaaaa\" as a password.\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 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 [-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_sha384sum "See sha1sum\n\n"
+
+#define HELP_sha256sum "See sha1sum\n\n"
+
+#define HELP_sha224sum "See sha1sum\n\n"
+
+#define HELP_sha1sum "usage: sha?sum [-b] [-c FILE] [FILE]...\n\ncalculate sha hash for each input file, reading from stdin if none. Output\none hash (40 hex digits for sha1, 56 for sha224, 64 for sha256, 96 for sha384,\nand 128 for sha512) for each input file, followed by filename.\n\n-b	brief (hash only, no filename)\n-c	Check each line of FILE is the same hash+filename we'd output.\n\n"
+
+#define HELP_md5sum "usage: md5sum [-b] [-c FILE] [FILE]...\n\nCalculate md5 hash for each input file, reading from stdin if none.\nOutput one hash (32 hex digits) for each input file, followed by filename.\n\n-b	brief (hash only, no filename)\n-c	Check each line of FILE is the same hash+filename we'd output.\n\n"
+
+#define HELP_killall "usage: killall [-l] [-iqv] [-SIGNAL|-s SIGNAL] PROCESS_NAME...\n\nSend a signal (default: TERM) to all processes with the given names.\n\n-i	ask for confirmation before killing\n-l	print list of all available signals\n-q	don't print any warnings or error messages\n-s	send SIGNAL instead of SIGTERM\n-v	report if the signal was successfully sent\n\n"
+
+#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_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\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_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_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] [-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_w "usage: w\n\nShow who is logged on and since how long they logged in.\n\n"
+
+#define HELP_vmstat "usage: vmstat [-n] [DELAY [COUNT]]\n\nPrint virtual memory statistics, repeating each DELAY seconds, COUNT times.\n(With no DELAY, prints one line. With no COUNT, repeats until killed.)\n\nShow processes running and blocked, kilobytes swapped, free, buffered, and\ncached, kilobytes swapped in and out per second, file disk blocks input and\noutput per second, interrupts and context switches per second, percent\nof CPU time spent running user code, system code, idle, and awaiting I/O.\nFirst line is since system started, later lines are since last line.\n\n-n	Display the header only once\n\n"
+
+#define HELP_vconfig "usage: vconfig COMMAND [OPTIONS]\n\nCreate and remove virtual ethernet devices\n\nadd             [interface-name] [vlan_id]\nrem             [vlan-name]\nset_flag        [interface-name] [flag-num]       [0 | 1]\nset_egress_map  [vlan-name]      [skb_priority]   [vlan_qos]\nset_ingress_map [vlan-name]      [skb_priority]   [vlan_qos]\nset_name_type   [name-type]\n\n"
+
+#define HELP_usleep "usage: usleep MICROSECONDS\n\nPause for MICROSECONDS microseconds.\n\n"
+
+#define HELP_uptime "usage: uptime\n\nTell how long the system has been running and the system load\naverages for the past 1, 5 and 15 minutes.\n\n"
+
+#define HELP_truncate "usage: truncate [-c] -s SIZE file...\n\nSet length of file(s), extending sparsely if necessary.\n\n-c	Don't create file if it doesn't exist.\n-s	New size (with optional prefix and suffix)\n\nSIZE prefix: + add, - subtract, < shrink to, > expand to,\n             / multiple rounding down, % multiple rounding up\nSIZE suffix: k=1024, m=1024^2, g=1024^3, t=1024^4, p=1024^5, e=1024^6\n\n"
+
+#define HELP_timeout "usage: timeout [-k LENGTH] [-s SIGNAL] LENGTH COMMAND...\n\nRun command line as a child process, sending child a signal if the\ncommand doesn't exit soon enough.\n\nLength can be a decimal fraction. An optional suffix can be \"m\"\n(minutes), \"h\" (hours), \"d\" (days), or \"s\" (seconds, the default).\n\n-s	Send specified signal (default TERM)\n-k	Send KILL signal if child still running this long after first signal.\n-v	Verbose\n\n"
+
+#define HELP_taskset "usage: taskset [-ap] [mask] [PID | cmd [args...]]\n\nLaunch a new task which may only run on certain processors, or change\nthe processor affinity of an exisitng PID.\n\nMask is a hex string where each bit represents a processor the process\nis allowed to run on. PID without a mask displays existing affinity.\n\n-p	Set/get the affinity of given PID instead of a new command.\n-a	Set/get the affinity of all threads of the PID.\n\n"
+
+#define HELP_nproc "usage: nproc [--all]\n\nPrint number of processors.\n\n--all	Show all processors, not just ones this task can run on.\n\n"
+
+#define HELP_tac "usage: tac [FILE...]\n\nOutput lines in reverse order.\n\n"
+
+#define HELP_sysctl "usage: sysctl [-aAeNnqw] [-p [FILE] | KEY[=VALUE]...]\n\nRead/write system control data (under /proc/sys).\n\n-a,A	Show all values\n-e	Don't warn about unknown keys\n-N	Don't print key values\n-n	Don't print key names\n-p	Read values from FILE (default /etc/sysctl.conf)\n-q	Don't show value after write\n-w	Only write values (object to reading)\n\n"
+
+#define HELP_switch_root "usage: switch_root [-c /dev/console] NEW_ROOT NEW_INIT...\n\nUse from PID 1 under initramfs to free initramfs, chroot to NEW_ROOT,\nand exec NEW_INIT.\n\n-c	Redirect console to device in NEW_ROOT\n-h	Hang instead of exiting on failure (avoids kernel panic)\n\n"
+
+#define HELP_swapon "usage: swapon [-d] [-p priority] filename\n\nEnable swapping on a given device/file.\n\n-d	Discard freed SSD pages\n\n"
+
+#define HELP_swapoff "usage: swapoff swapregion\n\nDisable swapping on a given swapregion.\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_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_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_reset "usage: reset\n\nreset the terminal\n\n"
+
+#define HELP_reboot "usage: reboot/halt/poweroff [-fn]\n\nRestart, halt or powerdown the system.\n\n-f	Don't signal init\n-n	Don't sync before stopping the system.\n\n"
+
+#define HELP_realpath "usage: realpath FILE...\n\nDisplay the canonical absolute pathname\n\n"
+
+#define HELP_readlink "usage: readlink FILE\n\nWith no options, show what symlink points to, return error if not symlink.\n\nOptions for producing cannonical paths (all symlinks/./.. resolved):\n\n-e	cannonical path to existing entry (fail if missing)\n-f	full path (fail if directory missing)\n-n	no trailing newline\n-q	quiet (no output, just error code)\n\n"
+
+#define HELP_readahead "usage: readahead FILE...\n\nPreload files into disk cache.\n\n"
+
+#define HELP_pwdx "usage: pwdx PID...\n\nPrint working directory of processes listed on command line.\n\n"
+
+#define HELP_printenv "usage: printenv [-0] [env_var...]\n\nPrint environment variables.\n\n-0	Use \\0 as delimiter instead of \\n\n\n"
+
+#define HELP_pmap "usage: pmap [-xq] [pids...]\n\nReports the memory map of a process or processes.\n\n-x Show the extended format.\n-q Do not display some header/footer lines.\n\n"
+
+#define HELP_pivot_root "usage: pivot_root OLD NEW\n\nSwap OLD and NEW filesystems (as if by simultaneous mount --move), and\nmove all processes with chdir or chroot under OLD into NEW (including\nkernel threads) so OLD may be unmounted.\n\nThe directory NEW must exist under OLD. This doesn't work on initramfs,\nwhich can't be moved (about the same way PID 1 can't be killed; see\nswitch_root instead).\n\n"
+
+#define HELP_partprobe "usage: partprobe DEVICE...\n\nTell the kernel about partition table changes\n\nAsk the kernel to re-read the partition table on the specified devices.\n\n"
+
+#define HELP_oneit "usage: oneit [-p] [-c /dev/tty0] command [...]\n\nSimple init program that runs a single supplied command line with a\ncontrolling tty (so CTRL-C can kill it).\n\n-c	Which console device to use (/dev/console doesn't do CTRL-C, etc).\n-p	Power off instead of rebooting when command exits.\n-r	Restart child when it exits.\n-3	Write 32 bit PID of each exiting reparented process to fd 3 of child.\n	(Blocking writes, child must read to avoid eventual deadlock.)\n\nSpawns a single child process (because PID 1 has signals blocked)\nin its own session, reaps zombies until the child exits, then\nreboots the system (or powers off with -p, or restarts the child with -r).\n\nResponds to SIGUSR1 by halting the system, SIGUSR2 by powering off,\nand SIGTERM or SIGINT reboot.\n\n"
+
+#define HELP_nsenter "usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND...\n\nRun COMMAND in an existing (set of) namespace(s).\n\n-t  PID to take namespaces from    (--target)\n-F  don't fork, even if -p is used (--no-fork)\n\nThe namespaces to switch are:\n\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, will fork unless -F is used (--pid)\n-u	Host and domain names (--uts)\n-U	UIDs, GIDs, capabilities (--user)\n\nIf -t isn't specified, each namespace argument must provide a path\nto a namespace file, ala \"-i=/proc/$PID/ns/ipc\"\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_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_modinfo "usage: modinfo [-0] [-b basedir] [-k kernrelease] [-F field] [modulename...]\n\nDisplay module fields for all specified modules, looking in\n<basedir>/lib/modules/<kernrelease>/ (kernrelease defaults to uname -r).\n\n"
+
+#define HELP_mkswap "usage: mkswap [-L LABEL] DEVICE\n\nSets up a Linux swap area on a device or file.\n\n"
+
+#define HELP_mkpasswd "usage: mkpasswd [-P FD] [-m TYPE] [-S SALT] [PASSWORD] [SALT]\n\nCrypt PASSWORD using crypt(3)\n\n-P FD   Read password from file descriptor FD\n-m TYPE Encryption method (des, md5, sha256, or sha512; default is des)\n-S SALT\n\n"
+
+#define HELP_mix "usage: mix [-d DEV] [-c CHANNEL] [-l VOL] [-r RIGHT]\n\nList OSS sound channels (module snd-mixer-oss), or set volume(s).\n\n-c CHANNEL	Set/show volume of CHANNEL (default first channel found)\n-d DEV		Device node (default /dev/mixer)\n-l VOL		Volume level\n-r RIGHT	Volume of right stereo channel (with -r, -l sets left volume)\n\n"
+
+#define HELP_makedevs "usage: makedevs [-d device_table] rootdir\n\nCreate a range of special files as specified in a device table.\n\n-d	file containing device table (default reads from stdin)\n\nEach line of of the device table has the fields:\n<name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count>\nWhere name is the file name, and type is one of the following:\n\nb	Block device\nc	Character device\nd	Directory\nf	Regular file\np	Named pipe (fifo)\n\nOther fields specify permissions, user and group id owning the file,\nand additional fields for device special files. Use '-' for blank entries,\nunspecified fields are treated as '-'.\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_lsmod "usage: lsmod\n\nDisplay the currently loaded modules, their sizes and their dependencies.\n\n"
+
+#define HELP_chattr "usage: chattr [-R] [-+=AacDdijsStTu] [-v version] [File...]\n\nChange file attributes on a Linux second extended file system.\n\nOperators:\n  '-' Remove attributes.\n  '+' Add attributes.\n  '=' Set attributes.\n\nAttributes:\n  A  Don't track atime.\n  a  Append mode only.\n  c  Enable compress.\n  D  Write dir contents synchronously.\n  d  Don't backup with dump.\n  i  Cannot be modified (immutable).\n  j  Write all data to journal first.\n  s  Zero disk storage when deleted.\n  S  Write file contents synchronously.\n  t  Disable tail-merging of partial blocks with other files.\n  u  Allow file to be undeleted.\n  -R Recurse.\n  -v Set the file's version/generation number.\n\n\n"
+
+#define HELP_lsattr "usage: lsattr [-Radlv] [Files...]\n\nList file attributes on a Linux second extended file system.\n\n-R Recursively list attributes of directories and their contents.\n-a List all files in directories, including files that start with '.'.\n-d List directories like other files, rather than listing their contents.\n-l List long flag names.\n-v List the file's version/generation number.\n\n"
+
+#define HELP_losetup "usage: losetup [-cdrs] [-o OFFSET] [-S SIZE] {-d DEVICE...|-j FILE|-af|{DEVICE FILE}}\n\nAssociate a loopback device with a file, or show current file (if any)\nassociated with a loop device.\n\nInstead of a device:\n-a	Iterate through all loopback devices\n-f	Find first unused loop device (may create one)\n-j	Iterate through all loopback devices associated with FILE\n\nexisting:\n-c	Check capacity (file size changed)\n-d	Detach loopback device\n\nnew:\n-s	Show device name (alias --show)\n-o	Start assocation at OFFSET into FILE\n-r	Read only\n-S	Limit SIZE of loopback association (alias --sizelimit)\n\n"
+
+#define HELP_login "usage: login [-p] [-h host] [-f USERNAME] [USERNAME]\n\nLog in as a user, prompting for username and password if necessary.\n\n-p	Preserve environment\n-h	The name of the remote host for this login\n-f	login as USERNAME without authentication\n\n"
+
+#define HELP_iorenice "usage: iorenice PID [CLASS] [PRIORITY]\n\nDisplay or change I/O priority of existing process. CLASS can be\n\"rt\" for realtime, \"be\" for best effort, \"idle\" for only when idle, or\n\"none\" to leave it alone. PRIORITY can be 0-7 (0 is highest, default 4).\n\n"
+
+#define HELP_ionice "usage: ionice [-t] [-c CLASS] [-n LEVEL] [COMMAND...|-p PID]\n\nChange the I/O scheduling priority of a process. With no arguments\n(or just -p), display process' existing I/O class/priority.\n\n-c	CLASS = 1-3: 1(realtime), 2(best-effort, default), 3(when-idle)\n-n	LEVEL = 0-7: (0 is highest priority, default = 5)\n-p	Affect existing PID instead of spawning new child\n-t	Ignore failure to set I/O priority\n\nSystem default iopriority is generally -c 2 -n 4.\n\n"
+
+#define HELP_insmod "usage: insmod MODULE [MODULE_OPTIONS]\n\nLoad the module named MODULE passing options if given.\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_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_hexedit "usage: hexedit FILENAME\n\nHexadecimal file editor. All changes are written to disk immediately.\n\n-r	Read only (display but don't edit)\n\nKeys:\nArrows        Move left/right/up/down by one line/column\nPg Up/Pg Dn   Move up/down by one page\n0-9, a-f      Change current half-byte to hexadecimal value\nu             Undo\nq/^c/^d/<esc> Quit\n\n"
+
+#define HELP_help "usage: help [-ah] [command]\n\nShow usage information for toybox commands.\nRun \"toybox\" with no arguments for a list of available commands.\n\n-h	HTML output\n-a	All commands\n"
+
+#define HELP_fsync "usage: fsync [-d] [FILE...]\n\nSynchronize a file's in-core state with storage device.\n\n-d	Avoid syncing metadata.\n\n"
+
+#define HELP_fsfreeze "usage: fsfreeze {-f | -u} MOUNTPOINT\n\nFreeze or unfreeze a filesystem.\n\n-f	freeze\n-u	unfreeze\n\n"
+
+#define HELP_freeramdisk "usage: freeramdisk [RAM device]\n\nFree all memory allocated to specified ramdisk\n\n"
+
+#define HELP_free "usage: free [-bkmgt]\n\nDisplay the total, free and used amount of physical memory and swap space.\n\n-bkmgt	Output units (default is bytes)\n-h	Human readable\n\n"
+
+#define HELP_flock "usage: flock [-sxun] fd\n\nManage advisory file locks.\n\n-s	Shared lock.\n-x	Exclusive lock (default).\n-u	Unlock.\n-n	Non-blocking: fail rather than wait for the lock.\n\n"
+
+#define HELP_fallocate "usage: fallocate [-l size] file\n\nTell the filesystem to allocate space for a file.\n\n"
+
+#define HELP_factor "usage: factor NUMBER...\n\nFactor integers.\n\n"
+
+#define HELP_eject "usage: eject [-stT] [DEVICE]\n\nEject DEVICE or default /dev/cdrom\n\n-s	SCSI device\n-t	Close tray\n-T	Open/close tray (toggle).\n\n"
+
+#define HELP_unix2dos "usage: unix2dos [FILE...]\n\nConvert newline format from unix \"\\n\" to dos \"\\r\\n\".\nIf no files listed copy from stdin, \"-\" is a synonym for stdin.\n\n"
+
+#define HELP_dos2unix "usage: dos2unix [FILE...]\n\nConvert newline format from dos \"\\r\\n\" to unix \"\\n\".\nIf no files listed copy from stdin, \"-\" is a synonym for stdin.\n\n"
+
+#define HELP_count "usage: count\n\nCopy stdin to stdout, displaying simple progress indicator to stderr.\n\n"
+
+#define HELP_clear "Clear the screen.\n\n"
+
+#define HELP_chvt "usage: chvt N\n\nChange to virtual terminal number N. (This only works in text mode.)\n\nVirtual terminals are the Linux VGA text mode displays, ordinarily\nswitched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch\nfrom X to a virtual terminal, and alt-F6 (or F7, or F8) to get back.\n\n"
+
+#define HELP_chroot "usage: chroot NEWPATH [commandline...]\n\nRun command within a new root directory. If no command, run /bin/sh.\n\n"
+
+#define HELP_chcon "usage: chcon [-hRv] CONTEXT FILE...\n\nChange the SELinux security context of listed file[s].\n\n-h change symlinks instead of what they point to.\n-R recurse into subdirectories.\n-v verbose output.\n\n"
+
+#define HELP_bzcat "usage: bzcat [FILE...]\n\nDecompress listed files to stdout. Use stdin if no files listed.\n\n"
+
+#define HELP_bunzip2 "usage: bunzip2 [-cftkv] [FILE...]\n\nDecompress listed files (file.bz becomes file) deleting archive file(s).\nRead from stdin if no files listed.\n\n-c	force output to stdout\n-f	force decompression. (If FILE doesn't end in .bz, replace original.)\n-k	keep input files (-c and -t imply this)\n-t  test integrity\n-v	verbose\n\n"
+
+#define HELP_blockdev "usage: blockdev --OPTION... BLOCKDEV...\n\nCall ioctl(s) on each listed block device\n\nOPTIONs:\n--setro		Set read only\n--setrw		Set read write\n--getro		Get read only\n--getss		Get sector size\n--getbsz	Get block size\n--setbsz	BYTES	Set block size\n--getsz		Get device size in 512-byte sectors\n--getsize	Get device size in sectors (deprecated)\n--getsize64	Get device size in bytes\n--flushbufs	Flush buffers\n--rereadpt	Reread partition table\n\n"
+
+#define HELP_fstype "usage: fstype DEV...\n\nPrints type of filesystem on a block device or image.\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 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_userdel "usage: userdel [-r] USER\nusage: deluser [-r] USER\n\nOptions:\n-r remove home directory\nDelete USER from the SYSTEM\n\n"
+
+#define HELP_useradd "usage: useradd [-SDH] [-h DIR] [-s SHELL] [-G GRP] [-g NAME] [-u UID] USER [GROUP]\n\nCreate new user, or add USER to GROUP\n\n-D       Don't assign a password\n-g NAME  Real name\n-G GRP   Add user to existing group\n-h DIR   Home directory\n-H       Don't create home directory\n-s SHELL Login shell\n-S       Create a system user\n-u UID   User id\n\n"
+
+#define HELP_tr "usage: tr [-cds] SET1 [SET2]\n\nTranslate, squeeze, or delete characters from stdin, writing to stdout\n\n-c/-C  Take complement of SET1\n-d     Delete input characters coded SET1\n-s     Squeeze multiple output characters of SET2 into one character\n\n"
+
+#define HELP_traceroute "usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n[-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES]\n\ntraceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC]\n  [-i IFACE] HOST [BYTES]\n\nTrace the route to HOST\n\n-4,-6 Force IP or IPv6 name resolution\n-F    Set the don't fragment bit (supports IPV4 only)\n-U    Use UDP datagrams instead of ICMP ECHO (supports IPV4 only)\n-I    Use ICMP ECHO instead of UDP datagrams (supports IPV4 only)\n-l    Display the TTL value of the returned packet (supports IPV4 only)\n-d    Set SO_DEBUG options to socket\n-n    Print numeric addresses\n-v    verbose\n-r    Bypass routing tables, send directly to HOST\n-m    Max time-to-live (max number of hops)(RANGE 1 to 255)\n-p    Base UDP port number used in probes(default 33434)(RANGE 1 to 65535)\n-q    Number of probes per TTL (default 3)(RANGE 1 to 255)\n-s    IP address to use as the source address\n-t    Type-of-service in probe packets (default 0)(RANGE 0 to 255)\n-w    Time in seconds to wait for a response (default 3)(RANGE 0 to 86400)\n-g    Loose source route gateway (8 max) (supports IPV4 only)\n-z    Pause Time in milisec (default 0)(RANGE 0 to 86400) (supports IPV4 only)\n-f    Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only)\n-i    Specify a network interface to operate with\n\n"
+
+#define HELP_tftpd "usage: tftpd [-cr] [-u USER] [DIR]\n\nTransfer file from/to tftp server.\n\n-r	read only\n-c	Allow file creation via upload\n-u	run as USER\n-l	Log to syslog (inetd mode requires this)\n\n"
+
+#define HELP_tftp "usage: tftp [OPTIONS] HOST [PORT]\n\nTransfer file from/to tftp server.\n\n-l FILE Local FILE\n-r FILE Remote FILE\n-g    Get file\n-p    Put file\n-b SIZE Transfer blocks of SIZE octets(8 <= SIZE <= 65464)\n\n"
+
+#define HELP_test "usage: test [-bcdefghLPrSsuwx PATH] [-nz STRING] [-t FD] [X ?? Y]\n\nReturn true or false by performing tests. (With no arguments return false.)\n\n--- Tests with a single argument (after the option):\nPATH is/has:\n  -b  block device   -f  regular file   -p  fifo           -u  setuid bit\n  -c  char device    -g  setgid         -r  read bit       -w  write bit\n  -d  directory      -h  symlink        -S  socket         -x  execute bit\n  -e  exists         -L  symlink        -s  nonzero size\nSTRING is:\n  -n  nonzero size   -z  zero size      (STRING by itself implies -n)\nFD (integer file descriptor) is:\n  -t  a TTY\n\n--- Tests with one argument on each side of an operator:\nTwo strings:\n  =  are identical	 !=  differ\nTwo integers:\n  -eq  equal         -gt  first > second    -lt  first < second\n  -ne  not equal     -ge  first >= second   -le  first <= second\n\n--- Modify or combine tests:\n  ! EXPR     not (swap true/false)   EXPR -a EXPR    and (are both true)\n  ( EXPR )   evaluate this first     EXPR -o EXPR    or (is either true)\n\n"
+
+#define HELP_telnetd "Handle incoming telnet connections\n\n-l LOGIN  Exec LOGIN on connect\n-f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue\n-K Close connection as soon as login exits\n-p PORT   Port to listen on\n-b ADDR[:PORT]  Address to bind to\n-F Run in foreground\n-i Inetd mode\n-w SEC    Inetd 'wait' mode, linger time SEC\n-S Log to syslog (implied by -i or without -F and -w)\n\n"
+
+#define HELP_telnet "usage: telnet HOST [PORT]\n\nConnect to telnet server\n\n"
+
+#define HELP_tcpsvd "usage: tcpsvd [-hEv] [-c N] [-C N[:MSG]] [-b N] [-u User] [-l Name] IP Port Prog\nusage: udpsvd [-hEv] [-c N] [-u User] [-l Name] IP Port Prog\n\nCreate TCP/UDP socket, bind to IP:PORT and listen for incoming connection.\nRun PROG for each connection.\n\nIP            IP to listen on, 0 = all\nPORT          Port to listen on\nPROG ARGS     Program to run\n-l NAME       Local hostname (else looks up local hostname in DNS)\n-u USER[:GRP] Change to user/group after bind\n-c N          Handle up to N (> 0) connections simultaneously\n-b N          (TCP Only) Allow a backlog of approximately N TCP SYNs\n-C N[:MSG]    (TCP Only) Allow only up to N (> 0) connections from the same IP\n              New connections from this IP address are closed\n              immediately. MSG is written to the peer before close\n-h            Look up peer's hostname\n-E            Don't set up environment variables\n-v            Verbose\n\n"
+
+#define HELP_tar "usage: tar -[cxtzhmvO] [-X FILE] [-T FILE] [-f TARFILE] [-C DIR]\n\nCreate, extract, or list files from a tar file\n\nOperation:\nc Create\nf Name of TARFILE ('-' for stdin/out)\nh Follow symlinks\nm Don't restore mtime\nt List\nv Verbose\nx Extract\nz (De)compress using gzip\nC Change to DIR before operation\nO Extract to stdout\nexclude=FILE File to exclude\nX File with names to exclude\nT File with names to include\n\n"
+
+#define HELP_syslogd "usage: syslogd  [-a socket] [-O logfile] [-f config file] [-m interval]\n                [-p socket] [-s SIZE] [-b N] [-R HOST] [-l N] [-nSLKD]\n\nSystem logging utility\n\n-a      Extra unix socket for listen\n-O FILE Default log file <DEFAULT: /var/log/messages>\n-f FILE Config file <DEFAULT: /etc/syslog.conf>\n-p      Alternative unix domain socket <DEFAULT : /dev/log>\n-n      Avoid auto-backgrounding.\n-S      Smaller output\n-m MARK interval <DEFAULT: 20 minutes> (RANGE: 0 to 71582787)\n-R HOST Log to IP or hostname on PORT (default PORT=514/UDP)\"\n-L      Log locally and via network (default is network only if -R)\"\n-s SIZE Max size (KB) before rotation (default:200KB, 0=off)\n-b N    rotated logs to keep (default:1, max=99, 0=purge)\n-K      Log to kernel printk buffer (use dmesg to read it)\n-l N    Log only messages more urgent than prio(default:8 max:8 min:1)\n-D      Drop duplicates\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_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_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_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_mke2fs_extended "usage: mke2fs [-E stride=###] [-O option[,option]]\n\n-E stride= Set RAID stripe size (in blocks)\n-O [opts]  Specify fewer ext2 option flags (for old kernels)\n           All of these are on by default (as appropriate)\n   none         Clear default options (all but journaling)\n   dir_index    Use htree indexes for large directories\n   filetype     Store file type info in directory entry\n   has_journal  Set by -j\n   journal_dev  Set by -J device=XXX\n   sparse_super Don't allocate huge numbers of redundant superblocks\n\n"
+
+#define HELP_mke2fs_label "usage: mke2fs [-L label] [-M path] [-o string]\n\n-L         Volume label\n-M         Path to mount point\n-o         Created by\n\n"
+
+#define HELP_mke2fs_gen "usage: gene2fs [options] device filename\n\nThe [options] are the same as mke2fs.\n\n"
+
+#define HELP_mke2fs_journal "usage: mke2fs [-j] [-J size=###,device=XXX]\n\n-j         Create journal (ext3)\n-J         Journal options\n           size: Number of blocks (1024-102400)\n           device: Specify an external journal\n\n"
+
+#define HELP_mke2fs "usage: mke2fs [-Fnq] [-b ###] [-N|i ###] [-m ###] device\n\nCreate an ext2 filesystem on a block device or filesystem image.\n\n-F         Force to run on a mounted device\n-n         Don't write to device\n-q         Quiet (no output)\n-b size    Block size (1024, 2048, or 4096)\n-N inodes  Allocate this many inodes\n-i bytes   Allocate one inode for every XXX bytes of device\n-m percent Reserve this percent of filesystem space for root user\n\n"
+
+#define HELP_mdev_conf "The mdev config file (/etc/mdev.conf) contains lines that look like:\nhd[a-z][0-9]* 0:3 660\n\nEach line must contain three whitespace separated fields. The first\nfield is a regular expression matching one or more device names,\nthe second and third fields are uid:gid and file permissions for\nmatching devies.\n\n"
+
+#define HELP_mdev "usage: mdev [-s]\n\nCreate devices in /dev using information from /sys.\n\n-s	Scan all entries in /sys to populate /dev.\n\n"
+
+#define HELP_lsof "usage: lsof [-lt] [-p PID1,PID2,...] [NAME]...\n\nLists open files. If names are given on the command line, only\nthose files will be shown.\n\n-l	list uids numerically\n-p	for given comma-separated pids only (default all pids)\n-t	terse (pid only) output\n\n"
+
+#define HELP_logger "usage: logger [-s] [-t tag] [-p [facility.]priority] [message]\n\nLog message (or stdin) to syslog.\n\n"
+
+#define HELP_last "usage: last [-W] [-f FILE]\n\nShow listing of last logged in users.\n\n-W      Display the information without host-column truncation.\n-f FILE Read from file FILE instead of /var/log/wtmp.\n\n"
+
+#define HELP_klogd "usage: klogd [-n] [-c N]\n\n-c  N   Print to console messages more urgent than prio N (1-8)\"\n-n    Run in foreground.\n\n"
+
+#define HELP_ipcs "usage: ipcs [[-smq] -i shmid] | [[-asmq] [-tcplu]]\n\n-i Show specific resource\nResource specification:\n-a All (default)\n-m Shared memory segments\n-q Message queues\n-s Semaphore arrays\nOutput format:\n-c Creator\n-l Limits\n-p Pid\n-t Time\n-u Summary\n\n"
+
+#define HELP_ipcrm "usage: ipcrm [ [-q msqid] [-m shmid] [-s semid]\n          [-Q msgkey] [-M shmkey] [-S semkey] ... ]\n\n-mM Remove memory segment after last detach\n-qQ Remove message queue\n-sS Remove semaphore\n\n"
+
+#define HELP_ip "usage: ip [ OPTIONS ] OBJECT { COMMAND }\n\nShow / manipulate routing, devices, policy routing and tunnels.\n\nwhere OBJECT := {address | link | route | rule | tunnel}\nOPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }\n\n"
+
+#define HELP_init "usage: init\n\nSystem V style init.\n\nFirst program to run (as PID 1) when the system comes up, reading\n/etc/inittab to determine actions.\n\n"
+
+#define HELP_iconv "usage: iconv [-f FROM] [-t TO] [FILE...]\n\nConvert character encoding of files.\n\n-f  convert from (default utf8)\n-t  convert to   (default utf8)\n\n"
+
+#define HELP_host "usage: host [-av] [-t TYPE] NAME [SERVER]\n\nPerform DNS lookup on NAME, which can be a domain name to lookup,\nor an ipv4 dotted or ipv6 colon seprated address to reverse lookup.\nSERVER (if present) is the DNS server to use.\n\n-a	no idea\n-t	not a clue\n-v	verbose\n\n"
+
+#define HELP_groupdel "usage: groupdel [USER] GROUP\n\nDelete a group or remove a user from a group\n\n"
+
+#define HELP_groupadd "usage: groupadd [-S] [-g GID] [USER] GROUP\n\nAdd a group or add a user to a group\n\n  -g GID Group id\n  -S     Create a system group\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_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_dumpleases "usage: dumpleases [-r|-a] [-f LEASEFILE]\n\nDisplay DHCP leases granted by udhcpd\n-f FILE,  Lease file\n-r        Show remaining time\n-a        Show expiration time\n\n"
+
+#define HELP_diff "usage: diff [-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2\n\n-a  Treat all files as text\n-b  Ignore changes in the amount of whitespace\n-B  Ignore changes whose lines are all blank\n-d  Try hard to find a smaller set of changes\n-i  Ignore case differences\n-L  Use LABEL instead of the filename in the unified header\n-N  Treat absent files as empty\n-q  Output only whether files differ\n-r  Recurse\n-S  Start with FILE when comparing directories\n-T  Make tabs line up by prefixing a tab when necessary\n-s  Report when two files are the same\n-t  Expand tabs to spaces in output\n-U  Output LINES lines of context\n-w  Ignore all whitespace\n\n"
+
+#define HELP_dhcpd "usage: dhcpd [-46fS] [-i IFACE] [-P N] [CONFFILE]\n\n -f    Run in foreground\n -i Interface to use\n -S    Log to syslog too\n -P N  Use port N (default ipv4 67, ipv6 547)\n -4, -6    Run as a DHCPv4 or DHCPv6 server\n\n"
+
+#define HELP_dhcp "usage: dhcp [-fbnqvoCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n            [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL] [-O OPT]\n\n     Configure network dynamicaly using DHCP.\n\n   -i Interface to use (default eth0)\n   -p Create pidfile\n   -s Run PROG at DHCP events (default /usr/share/dhcp/default.script)\n   -B Request broadcast replies\n   -t Send up to N discover packets\n   -T Pause between packets (default 3 seconds)\n   -A Wait N seconds after failure (default 20)\n   -f Run in foreground\n   -b Background if lease is not obtained\n   -n Exit if lease is not obtained\n   -q Exit after obtaining lease\n   -R Release IP on exit\n   -S Log to syslog too\n   -a Use arping to validate offered address\n   -O Request option OPT from server (cumulative)\n   -o Don't request any options (unless -O is given)\n   -r Request this IP address\n   -x OPT:VAL  Include option OPT in sent packets (cumulative)\n   -F Ask server to update DNS mapping for NAME\n   -H Send NAME as client hostname (default none)\n   -V VENDOR Vendor identifier (default 'toybox VERSION')\n   -C Don't send MAC as client identifier\n   -v Verbose\n\n   Signals:\n   USR1  Renew current lease\n   USR2  Release current lease\n\n\n"
+
+#define HELP_dhcp6 "usage: dhcp6 [-fbnqvR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n\n      Configure network dynamicaly using DHCP.\n\n    -i Interface to use (default eth0)\n    -p Create pidfile\n    -s Run PROG at DHCP events\n    -t Send up to N Solicit packets\n    -T Pause between packets (default 3 seconds)\n    -A Wait N seconds after failure (default 20)\n    -f Run in foreground\n    -b Background if lease is not obtained\n    -n Exit if lease is not obtained\n    -q Exit after obtaining lease\n    -R Release IP on exit\n    -S Log to syslog too\n    -r Request this IP address\n    -v Verbose\n\n    Signals:\n    USR1  Renew current lease\n    USR2  Release current lease\n\n"
+
+#define HELP_dd "usage: dd [if=FILE] [of=FILE] [ibs=N] [obs=N] [bs=N] [count=N] [skip=N]\n        [seek=N] [conv=notrunc|noerror|sync|fsync] [status=noxfer|none]\n\nOptions:\nif=FILE   Read from FILE instead of stdin\nof=FILE   Write to FILE instead of stdout\nbs=N      Read and write N bytes at a time\nibs=N     Read N bytes at a time\nobs=N     Write N bytes at a time\ncount=N   Copy only N input blocks\nskip=N    Skip N input blocks\nseek=N    Skip N output blocks\nconv=notrunc  Don't truncate output file\nconv=noerror  Continue after read errors\nconv=sync     Pad blocks with zeros\nconv=fsync    Physically write data out before finishing\nstatus=noxfer Don't show transfer rate\nstatus=none   Don't show transfer rate or records in/out\n\nNumbers may be suffixed by c (*1), w (*2), b (*512), kD (*1000), k (*1024),\nMD (*1000*1000), M (*1024*1024), GD (*1000*1000*1000) or G (*1024*1024*1024).\n\n"
+
+#define HELP_crontab "usage: crontab [-u user] FILE\n               [-u user] [-e | -l | -r]\n               [-c dir]\n\nFiles used to schedule the execution of programs.\n\n-c crontab dir\n-e edit user's crontab\n-l list user's crontab\n-r delete user's crontab\n-u user\nFILE Replace crontab by FILE ('-': stdin)\n\n"
+
+#define HELP_crond "usage: crond [-fbS] [-l N] [-d N] [-L LOGFILE] [-c DIR]\n\nA daemon to execute scheduled commands.\n\n-b Background (default)\n-c crontab dir\n-d Set log level, log to stderr\n-f Foreground\n-l Set log level. 0 is the most verbose, default 8\n-S Log to syslog (default)\n-L Log to file\n\n"
+
+#define HELP_gunzip "usage: gunzip [-cflqStv] [FILE...]\n\nDecompess (deflate) file(s). With no files, compress stdin to stdout.\n\nOn successful decompression, compressed files are replaced with the\nuncompressed version. The input file is removed and replaced with\na new file without the .gz extension (with same ownership/permissions).\n\n-c	cat to stdout (act as zcat)\n-f	force (output file exists, input is tty, unrecognized extension)\n-l	list compressed/uncompressed/ratio/name for each input file.\n-q	quiet (no warnings)\n-S	specify exension (default .*)\n-t	test compressed file(s)\n-v	verbose (like -l, but decompress files)\n\n"
+
+#define HELP_zcat "usage: zcat [FILE...]\n\nDecompress deflated file(s) to stdout\n\n"
+
+#define HELP_decompress "usage: compress [-zglrcd9] [FILE]\n\nCompress or decompress file (or stdin) using \"deflate\" algorithm.\n\n-c	compress with -g gzip (default)  -l zlib  -r raw  -z zip\n-d	decompress (autodetects type)\n\n\n"
+
+#define HELP_gzip_d "usage: gzip [-d]\n\n-d	decompress (act as gunzip)\n\n"
+
+#define HELP_gzip "usage: gzip [-19cfqStvzgLR] [FILE...]\n\nCompess (deflate) file(s). With no files, compress stdin to stdout.\n\nOn successful decompression, compressed files are replaced with the\nuncompressed version. The input file is removed and replaced with\na new file without the .gz extension (with same ownership/permissions).\n\n-1	Minimal compression (fastest)\n-9	Max compression (default)\n-c	cat to stdout (act as zcat)\n-f	force (if output file exists, input is tty, unrecognized extension)\n-q	quiet (no warnings)\n-S	specify exension (default .*)\n-t	test compressed file(s)\n-v	verbose (like -l, but compress files)\n\nCompression type:\n-g gzip (default)    -L zlib    -R raw    -z zip\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_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_arping "usage: arping [-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP\n\nSend ARP requests/replies\n\n-f         Quit on first ARP reply\n-q         Quiet\n-b         Keep broadcasting, don't go unicast\n-D         Duplicated address detection mode\n-U         Unsolicited ARP mode, update your neighbors\n-A         ARP answer mode, update your neighbors\n-c N       Stop after sending N ARP requests\n-w TIMEOUT Time to wait for ARP reply, seconds\n-I IFACE   Interface to use (default eth0)\n-s SRC_IP  Sender IP address\nDST_IP     Target IP address\n\n"
+
+#define HELP_arp "Usage: arp\n[-vn] [-H HWTYPE] [-i IF] -a [HOSTNAME]\n[-v]              [-i IF] -d HOSTNAME [pub]\n[-v]  [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [temp]\n[-v]  [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [netmask MASK] pub\n[-v]  [-H HWTYPE] [-i IF] -Ds HOSTNAME IFACE [netmask MASK] pub\n\nManipulate ARP cache\n\n-a    Display (all) hosts\n-s    Set new ARP entry\n-d    Delete a specified entry\n-v    Verbose\n-n    Don't resolve names\n-i IF Network interface\n-D    Read <hwaddr> from given device\n-A,-p AF  Protocol family\n-H    HWTYPE Hardware address type\n\n\n"
+
+#define HELP_xargs_pedantic "This version supports insane posix whitespace handling rendered obsolete\nby -0 mode.\n\n\n"
+
+#define HELP_xargs "usage: xargs [-ptxr0] [-s NUM] [-n NUM] [-L NUM] [-E STR] COMMAND...\n\nRun command line one or more times, appending arguments from stdin.\n\nIf command exits with 255, don't launch another even if arguments remain.\n\n-s	Size in bytes per command line\n-n	Max number of arguments per command\n-0	Each argument is NULL terminated, no whitespace or quote processing\n#-p	Prompt for y/n from tty before running each command\n#-t	Trace, print command line to stderr\n#-x	Exit if can't fit everything in one command\n#-r	Don't run command with empty input\n#-L	Max number of lines of input per command\n-E	stop at line matching string\n\n"
+
+#define HELP_who "usage: who\n\nPrint logged user information on system\n\n"
+
+#define HELP_wc "usage: wc -lwcm [FILE...]\n\nCount lines, words, and characters in input.\n\n-l	show lines\n-w	show words\n-c	show bytes\n-m	show characters\n\nBy default outputs lines, words, bytes, and filename for each\nargument (or from stdin if none). Displays only either bytes\nor characters.\n\n"
+
+#define HELP_uuencode "usage: uuencode [-m] [file] encode-filename\n\nUuencode stdin (or file) to stdout, with encode-filename in the output.\n\n-m	base64-encode\n\n"
+
+#define HELP_uudecode "usage: uudecode [-o OUTFILE] [INFILE]\n\nDecode file from stdin (or INFILE).\n\n-o	write to OUTFILE instead of filename in header\n\n"
+
+#define HELP_unlink "usage: unlink FILE\n\nDeletes one file.\n\n"
+
+#define HELP_uniq "usage: uniq [-cduiz] [-w maxchars] [-f fields] [-s char] [input_file [output_file]]\n\nReport or filter out repeated lines in a file\n\n-c	show counts before each line\n-d	show only lines that are repeated\n-u	show only lines that are unique\n-i	ignore case when comparing lines\n-z	lines end with \\0 not \\n\n-w	compare maximum X chars per line\n-f	ignore first X fields\n-s	ignore first X chars\n\n"
+
+#define HELP_uname "usage: uname [-asnrvm]\n\nPrint system information.\n\n-s	System name\n-n	Network (domain) name\n-r	Kernel Release number\n-v	Kernel Version\n-m	Machine (hardware) name\n-a	All of the above\n\n"
+
+#define HELP_ulimit "usage: ulimit [-P PID] [-SHRacdefilmnpqrstuv] [LIMIT]\n\nPrint or set resource limits for process number PID. If no LIMIT specified\n(or read-only -ap selected) display current value (sizes in bytes).\nDefault is ulimit -P $PPID -Sf\" (show soft filesize of your shell).\n\n-S  Set/show soft limit          -H  Set/show hard (maximum) limit\n-a  Show all limits              -c  Core file size\n-d  Process data segment         -e  Max scheduling priority\n-f  Output file size             -i  Pending signal count\n-l  Locked memory                -m  Resident Set Size\n-n  Number of open files         -p  Pipe buffer\n-q  Posix message queue          -r  Max Real-time priority\n-R  Realtime latency (usec)      -s  Stack size\n-t  Total CPU time (in seconds)  -u  Maximum processes (under this UID)\n-v  Virtual memory size          -P  PID to affect (default $PPID)\n\n"
+
+#define HELP_tty "usage: tty [-s]\n\nShow filename of terminal connected to stdin.\n\nPrints \"not a tty\" and exits with nonzero status if no terminal\nis connected to stdin.\n\n-s	silent, exit code only\n\n"
+
+#define HELP_true "Return zero.\n\n"
+
+#define HELP_touch "usage: touch [-amch] [-d DATE] [-t TIME] [-r FILE] FILE...\n\nUpdate the access and modification times of each FILE to the current time.\n\n-a	change access time\n-m	change modification time\n-c	don't create file\n-h	change symlink\n-d	set time to DATE (in YYYY-MM-DDThh:mm:SS[.frac][tz] format)\n-t	set time to TIME (in [[CC]YY]MMDDhhmm[.ss][frac] format)\n-r	set time same as reference FILE\n\n"
+
+#define HELP_time "usage: time [-p] COMMAND [ARGS...]\n\nRun command line and report real, user, and system time elapsed in seconds.\n(real = clock on the wall, user = cpu used by command's code,\nsystem = cpu used by OS on behalf of command.)\n\n-p	posix mode (ignored)\n\n"
+
+#define HELP_tee "usage: tee [-ai] [file...]\n\nCopy stdin to each listed file, and also to stdout.\nFilename \"-\" is a synonym for stdout.\n\n-a	append to files.\n-i	ignore SIGINT.\n\n"
+
+#define HELP_tail_seek "This version uses lseek, which is faster on large files.\n\n"
+
+#define HELP_tail "usage: tail [-n|c NUMBER] [-f] [FILE...]\n\nCopy last lines from files to stdout. If no files listed, copy from\nstdin. Filename \"-\" is a synonym for stdin.\n\n-n	output the last NUMBER lines (default 10), +X counts from start.\n-c	output the last NUMBER bytes, +NUMBER counts from start\n-f	follow FILE(s), waiting for more data to be appended\n\n"
+
+#define HELP_strings "usage: strings [-fo] [-n LEN] [FILE...]\n\nDisplay printable strings in a binary file\n\n-f	Precede strings with filenames\n-n	At least LEN characters form a string (default 4)\n-o	Precede strings with decimal offsets\n\n"
+
+#define HELP_split "usage: split [-a SUFFIX_LEN] [-b BYTES] [-l LINES] [INPUT [OUTPUT]]\n\nCopy INPUT (or stdin) data to a series of OUTPUT (or \"x\") files with\nalphabetically increasing suffix (aa, ab, ac... az, ba, bb...).\n\n-a	Suffix length (default 2)\n-b	BYTES/file (10, 10k, 10m, 10g...)\n-l	LINES/file (default 1000)\n\n"
+
+#define HELP_sort "usage: sort [-Mbcdfginrsuz] [-k#[,#[x]] [-t X]] [-o FILE] [FILE...]\n\nSort all lines of text from input files (or stdin) to stdout.\n\n-M	month sort (jan, feb, etc).\n-b	ignore leading blanks (or trailing blanks in second part of key)\n-c	check whether input is sorted\n-d	dictionary order (use alphanumeric and whitespace chars only)\n-f	force uppercase (case insensitive sort)\n-g	general numeric sort (double precision with nan and inf)\n-i	ignore nonprinting characters\n-k	sort by \"key\" (see below)\n-n	numeric order (instead of alphabetical)\n-o	output to FILE instead of stdout\n-r	reverse\n-s	skip fallback sort (only sort with keys)\n-t	use a key separator other than whitespace\n-u	unique lines only\n-x	Hexadecimal numerical sort\n-z	zero (null) terminated lines\n\nSorting by key looks at a subset of the words on each line.  -k2\nuses the second word to the end of the line, -k2,2 looks at only\nthe second word, -k2,4 looks from the start of the second to the end\nof the fourth word.  Specifying multiple keys uses the later keys as\ntie breakers, in order.  A type specifier appended to a sort key\n(such as -2,2n) applies only to sorting that key.\n"
+
+#define HELP_sleep_float "Length can be a decimal fraction.\n\n"
+
+#define HELP_sleep "usage: sleep LENGTH\n\nWait before exiting. An optional suffix can be \"m\" (minutes), \"h\" (hours),\n\"d\" (days), or \"s\" (seconds, the default).\n\n\n"
+
+#define HELP_sed "usage: sed [-inrE] [-e SCRIPT]...|SCRIPT [-f SCRIPT_FILE]... [FILE...]\n\nStream editor. Apply one or more editing SCRIPTs to each line of input\n(from FILE or stdin) producing output (by default to stdout).\n\n-e	add SCRIPT to list\n-f	add contents of SCRIPT_FILE to list\n-i	Edit each file in place.\n-n	No default output. (Use the p command to output matched lines.)\n-r	Use extended regular expression syntax.\n-E	Alias for -r.\n-s	Treat input files separately (implied by -i)\n\nA SCRIPT is a series of one or more COMMANDs separated by newlines or\nsemicolons. All -e SCRIPTs are concatenated together as if separated\nby newlines, followed by all lines from -f SCRIPT_FILEs, in order.\nIf no -e or -f SCRIPTs are specified, the first argument is the SCRIPT.\n\nEach COMMAND may be preceded by an address which limits the command to\napply only to the specified line(s). Commands without an address apply to\nevery line. Addresses are of the form:\n\n  [ADDRESS[,ADDRESS]]COMMAND\n\nThe ADDRESS may be a decimal line number (starting at 1), a /regular\nexpression/ within a pair of forward slashes, or the character \"$\" which\nmatches the last line of input. (In -s or -i mode this matches the last\nline of each file, otherwise just the last line of the last file.) A single\naddress matches one line, a pair of comma separated addresses match\neverything from the first address to the second address (inclusive). If\nboth addresses are regular expressions, more than one range of lines in\neach file can match.\n\nREGULAR EXPRESSIONS in sed are started and ended by the same character\n(traditionally / but anything except a backslash or a newline works).\nBackslashes may be used to escape the delimiter if it occurs in the\nregex, and for the usual printf escapes (\\abcefnrtv and octal, hex,\nand unicode). An empty regex repeats the previous one. ADDRESS regexes\n(above) require the first delimeter to be escaped with a backslash when\nit isn't a forward slash (to distinguish it from the COMMANDs below).\n\nSed mostly operates on individual lines one at a time. It reads each line,\nprocesses it, and either writes it to the output or discards it before\nreading the next line. Sed can remember one additional line in a separate\nbuffer (using the h, H, g, G, and x commands), and can read the next line\nof input early (using the n and N command), but other than that command\nscripts operate on individual lines of text.\n\nEach COMMAND starts with a single character. The following commands take\nno arguments:\n\n  {  Start a new command block, continuing until a corresponding \"}\".\n     Command blocks may nest. If the block has an address, commands within\n     the block are only run for lines within the block's address range.\n\n  }  End command block (this command cannot have an address)\n\n  d  Delete this line and move on to the next one\n     (ignores remaining COMMANDs)\n\n  D  Delete one line of input and restart command SCRIPT (same as \"d\"\n     unless you've glued lines together with \"N\" or similar)\n\n  g  Get remembered line (overwriting current line)\n\n  G  Get remembered line (appending to current line)\n\n  h  Remember this line (overwriting remembered line)\n\n  H  Remember this line (appending to remembered line, if any)\n\n  l  Print line, escaping \\abfrtv (but not newline), octal escaping other\n     nonprintable characters, wrapping lines to terminal width with a\n     backslash, and appending $ to actual end of line.\n\n  n  Print default output and read next line, replacing current line\n     (If no next line available, quit processing script)\n\n  N  Append next line of input to this line, separated by a newline\n     (This advances the line counter for address matching and \"=\", if no\n     next line available quit processing script without default output)\n\n  p  Print this line\n\n  P  Print this line up to first newline (from \"N\")\n\n  q  Quit (print default output, no more commands processed or lines read)\n\n  x  Exchange this line with remembered line (overwrite in both directions)\n\n  =  Print the current line number (followed by a newline)\n\nThe following commands (may) take an argument. The \"text\" arguments (to\nthe \"a\", \"b\", and \"c\" commands) may end with an unescaped \"\\\" to append\nthe next line (for which leading whitespace is not skipped), and also\ntreat \";\" as a literal character (use \"\\;\" instead).\n\n  a [text]   Append text to output before attempting to read next line\n\n  b [label]  Branch, jumps to :label (or with no label, to end of SCRIPT)\n\n  c [text]   Delete line, output text at end of matching address range\n             (ignores remaining COMMANDs)\n\n  i [text]   Print text\n\n  r [file]   Append contents of file to output before attempting to read\n             next line.\n\n  s/S/R/F    Search for regex S, replace matched text with R using flags F.\n             The first character after the \"s\" (anything but newline or\n             backslash) is the delimiter, escape with \\ to use normally.\n\n             The replacement text may contain \"&\" to substitute the matched\n             text (escape it with backslash for a literal &), or \\1 through\n             \\9 to substitute a parenthetical subexpression in the regex.\n             You can also use the normal backslash escapes such as \\n and\n             a backslash at the end of the line appends the next line.\n\n             The flags are:\n\n             [0-9]    A number, substitute only that occurrence of pattern\n             g        Global, substitute all occurrences of pattern\n             i        Ignore case when matching\n             p        Print the line if match was found and replaced\n             w [file] Write (append) line to file if match replaced\n\n  t [label]  Test, jump to :label only if an \"s\" command found a match in\n             this line since last test (replacing with same text counts)\n\n  T [label]  Test false, jump only if \"s\" hasn't found a match.\n\n  w [file]   Write (append) line to file\n\n  y/old/new/ Change each character in 'old' to corresponding character\n             in 'new' (with standard backslash escapes, delimiter can be\n             any repeated character except \\ or \\n)\n\n  : [label]  Labeled target for jump commands\n\n  #  Comment, ignore rest of this line of SCRIPT\n\nDeviations from posix: allow extended regular expressions with -r,\nediting in place with -i, separate with -s, printf escapes in text, line\ncontinuations, semicolons after all commands, 2-address anywhere an\naddress is allowed, \"T\" command, multiline continuations for [abc],\n\\; to end [abc] argument before end of line.\n\n"
+
+#define HELP_rmdir "usage: rmdir [-p] [dirname...]\n\nRemove one or more directories.\n\n-p	Remove path.\n\n"
+
+#define HELP_rm "usage: rm [-fiRr] FILE...\n\nRemove each argument from the filesystem.\n\n-f	force: remove without confirmation, no error if it doesn't exist\n-i	interactive: prompt for confirmation\n-rR	recursive: remove directory contents\n\n"
+
+#define HELP_renice "usage: renice [-gpu] -n increment ID ...\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_pgkill_common "usage: * [-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: * [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\n-b	Batch mode (no tty)\n-d	Delay SECONDS between each cycle (default 3)\n-n	Exit after NUMBER iterations\n-p	Show these PIDs\n-u	Show these USERs\n-q	Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
+
+#define HELP_iotop "usage: iotop [-AaKO]\n\nRank processes by I/O.\n\n-A	All I/O, not just disk\n-a	Accumulated I/O (not percentage)\n-K	Kilobytes\n-k	Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)\n-O	Only show processes doing I/O\n-o	Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)\n-s	Sort by field number (0-X, default 6)\n\n"
+
+#define HELP_top "usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]\n\nShow process activity in real time.\n\n-H	Show threads\n-k	Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)\n-o	Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)\n-O	Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)\n-s	Sort by field number (1-X, default 9)\n\n"
+
+#define HELP_ps "usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]\n\nList processes.\n\nWhich processes to show (selections may be comma separated lists):\n\n-A	All processes\n-a	Processes with terminals that aren't session leaders\n-d	All processes that aren't session leaders\n-e	Same as -A\n-g	Belonging to GROUPs\n-G	Belonging to real GROUPs (before sgid)\n-p	PIDs (--pid)\n-P	Parent PIDs (--ppid)\n-s	In session IDs\n-t	Attached to selected TTYs\n-T	Show threads\n-u	Owned by USERs\n-U	Owned by real USERs (before suid)\n\nOutput modifiers:\n\n-k	Sort FIELDs in +increasing or -decreasting order (--sort)\n-M	Measure field widths (expanding as necessary)\n-n	Show numeric USER and GROUP\n-w	Wide output (don't truncate at terminal width)\n\nWhich FIELDs to show. (Default = -o PID,TTY,TIME,CMD)\n\n-f	Full listing (-o USER:8=UID,PID,PPID,C,STIME,TTY,TIME,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 [-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 #] [-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_nl "usage: nl [-E] [-l #] [-b MODE] [-n STYLE] [-s SEPARATOR] [-w WIDTH] [FILE...]\n\nNumber lines of input.\n\n-E	Use extended regex syntax (when doing -b pREGEX)\n-b	which lines to number: a (all) t (non-empty, default) pREGEX (pattern)\n-l	Only count last of this many consecutive blank lines\n-n	number STYLE: ln (left justified) rn (right justified) rz (zero pad)\n-s	Separator to use between number and line (instead of TAB)\n-w	Width of line numbers (default 6)\n\n"
+
+#define HELP_nice "usage: nice [-n PRIORITY] command [args...]\n\nRun a command line at an increased or decreased scheduling priority.\n\nHigher numbers make a program yield more CPU time, from -20 (highest\npriority) to 19 (lowest).  By default processes inherit their parent's\nniceness (usually 0).  By default this command adds 10 to the parent's\npriority.  Only root can set a negative niceness level.\n\n"
+
+#define HELP_mkfifo "usage: mkfifo [-Z CONTEXT] [NAME...]\n\nCreate FIFOs (named pipes).\n\n-Z	Security context\n"
+
+#define HELP_mkdir_z "usage: [-Z context]\n\n-Z	set security context\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    -b  escape nongraphic chars\n-c  use ctime for timestamps       -d  directory, not contents\n-i  inode number                   -k  block sizes in kilobytes\n-p  put a '/' after dir names      -q  unprintable chars as '?'\n-s  size (in blocks)               -u  use access time for timestamps\n-A  list all files but . and ..    -H  follow command line symlinks\n-L  follow symlinks                -R  recursively list files in subdirs\n-F  append /dir *exe @sym |FIFO    -Z  security context\n\noutput formats:\n-1  list one file per line         -C  columns (sorted vertically)\n-g  like -l but no owner           -h  human readable sizes\n-l  long (show full details)       -m  comma separated\n-n  like -l but numeric uid/gid    -o  like -l but no group\n-x  columns (horizontal sort)\n\nsorting (default is alphabetical):\n-f  unsorted    -r  reverse    -t  timestamp    -S  size\n"
+
+#define HELP_ls "usage: ls --color[=auto] [-ACFHLRSZacdfhiklmnpqrstux1] [directory...]\n\nlist files\n\nwhat to show:\n-a  all files including .hidden    -b  escape nongraphic chars\n-c  use ctime for timestamps       -d  directory, not contents\n-i  inode number                   -k  block sizes in kilobytes\n-p  put a '/' after dir names      -q  unprintable chars as '?'\n-s  size (in blocks)               -u  use access time for timestamps\n-A  list all files but . and ..    -H  follow command line symlinks\n-L  follow symlinks                -R  recursively list files in subdirs\n-F  append /dir *exe @sym |FIFO    -Z  security context\n\noutput formats:\n-1  list one file per line         -C  columns (sorted vertically)\n-g  like -l but no owner           -h  human readable sizes\n-l  long (show full details)       -m  comma separated\n-n  like -l but numeric uid/gid    -o  like -l but no group\n-x  columns (horizontal sort)\n\nsorting (default is alphabetical):\n-f  unsorted    -r  reverse    -t  timestamp    -S  size\n--color  device=yellow  symlink=turquoise/red  dir=blue  socket=purple\n         files: exe=green  suid=red  suidfile=redback  stickydir=greenback\n         =auto means detect if output is a tty.\n\n"
+
+#define HELP_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_link "usage: link FILE NEWLINK\n\nCreate hardlink to a file.\n\n"
+
+#define HELP_killall5 "usage: killall5 [-l [SIGNAL]] [-SIGNAL|-s SIGNAL] [-o PID]...\n\nSend a signal to all processes outside current session.\n\n-l     List signal name(s) and number(s)\n-o PID Omit PID\n-s     send SIGNAL (default SIGTERM)\n\n"
+
+#define HELP_kill "usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] pid...\n\nSend signal to process(es).\n\n-l	List signal name(s) and number(s)\n-s	Send SIGNAL (default SIGTERM)\n\n"
+
+#define HELP_whoami "usage: whoami\n\nPrint the current user name.\n\n"
+
+#define HELP_logname "usage: logname\n\nPrint the current user name.\n\n"
+
+#define HELP_groups "usage: groups [user]\n\nPrint the groups a user is in.\n\n"
+
+#define HELP_id "usage: id [-GZgnru] \n\nPrint user and group ID.\n-G	Show only the group IDs\n-Z	Show only security context\n-g	Show only the effective group ID\n-n	print names instead of numeric IDs (to be used with -Ggu)\n-r	Show real ID instead of effective ID\n-u	Show only the effective user ID\n"
+
+#define HELP_head "usage: head [-n number] [file...]\n\nCopy first lines from files to stdout. If no files listed, copy from\nstdin. Filename \"-\" is a synonym for stdin.\n\n-n	Number of lines to copy.\n\n"
+
+#define HELP_grep "usage: grep [-EFivwcloqsHbhn] [-A NUM] [-m MAX] [-e REGEX]... [-f REGFILE] [FILE]...\n\nShow lines matching regular expressions. If no -e, first argument is\nregular expression to match. With no files (or \"-\" filename) read stdin.\nReturns 0 if matched, 1 if no match found.\n\n-e  Regex to match. (May be repeated.)\n-f  File containing regular expressions to match.\n\nmatch type:\n-A  Show NUM lines after     -B  Show NUM lines before match\n-C  NUM lines context (A+B)  -E  extended regex syntax\n-F  fixed (literal match)    -i  case insensitive\n-m  match MAX many lines     -r  recursive (on dir)\n-v  invert match             -w  whole word (implies -E)\n-x  whole line               -z  input NUL terminated\n\ndisplay modes: (default: matched line)\n-c  count of matching lines  -l  show matching filenames\n-o  only matching part       -q  quiet (errors only)\n-s  silent (no error msg)    -Z  output NUL terminated\n\noutput prefix (default: filename if checking more than 1 file)\n-H  force filename           -b  byte offset of match\n-h  hide filename            -n  line number of match\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 [file...]\n\nExamine the given files and describe their content types.\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_env "usage: env [-i] [-u NAME] [NAME=VALUE...] [command [option...]]\n\nSet the environment for command invocation.\n\n-i	Clear existing environment.\n-u NAME	Remove NAME from the environment\n\n"
+
+#define HELP_echo "usage: echo [-ne] [args...]\n\nWrite each argument to stdout, with one space between each, followed\nby a newline.\n\n-n	No trailing newline.\n-e	Process the following escape sequences:\n	\\\\	backslash\n	\\0NNN	octal values (1 to 3 digits)\n	\\a	alert (beep/flash)\n	\\b	backspace\n	\\c	stop output here (avoids trailing newline)\n	\\f	form feed\n	\\n	newline\n	\\r	carriage return\n	\\t	horizontal tab\n	\\v	vertical tab\n	\\xHH	hexadecimal values (1 to 2 digits)\n\n"
+
+#define HELP_du "usage: du [-d N] [-askxHLlmc] [file...]\n\nShow disk usage, space consumed by files and directories.\n\nSize in:\n-k    1024 byte blocks (default)\n-K    512 byte blocks (posix)\n-m    megabytes\n-h    human readable format (e.g., 1K 243M 2G )\n\nWhat to show:\n-a    all files, not just directories\n-H    follow symlinks on cmdline\n-L    follow all symlinks\n-s    only total size of each argument\n-x    don't leave this filesystem\n-c    cumulative total\n-d N  only depth < N\n-l    disable hardlink filter\n\n"
+
+#define HELP_dirname "usage: dirname PATH\n\nShow directory portion of path.\n\n"
+
+#define HELP_df "usage: df [-HPkh] [-t type] [FILESYSTEM ...]\n\nThe \"disk free\" command shows total/used/available disk space for\neach filesystem listed on the command line, or all currently mounted\nfilesystems.\n\n-P	The SUSv3 \"Pedantic\" option\n-k	Sets units back to 1024 bytes (the default without -P)\n-h	Human readable output (K=1024)\n-H	Human readable output (k=1000)\n-t type	Display only filesystems of this type.\n\nPedantic provides a slightly less useful output format dictated by Posix,\nand sets the units to 512 bytes instead of the default 1024 bytes.\n\n"
+
+#define HELP_date "usage: date [-u] [-r FILE] [-d DATE] [+DISPLAY_FORMAT] [-D SET_FORMAT] [SET]\n\nSet/get the current date/time. With no SET shows the current date.\n\nDefault SET format is \"MMDDhhmm[[CC]YY][.ss]\", that's (2 digits each)\nmonth, day, hour (0-23), and minute. Optionally century, year, and second.\nAlso accepts \"@UNIXTIME[.FRACTION]\" as seconds since midnight Jan 1 1970.\n\n-d	Show DATE instead of current time (convert date format)\n-D	+FORMAT for SET or -d (instead of MMDDhhmm[[CC]YY][.ss])\n-r	Use modification time of FILE instead of current date\n-u	Use UTC instead of current timezone\n\n+FORMAT specifies display format string using these escapes:\n\n%% literal %             %n newline              %t tab\n%S seconds (00-60)       %M minute (00-59)       %m month (01-12)\n%H hour (0-23)           %I hour (01-12)         %p AM/PM\n%y short year (00-99)    %Y year                 %C century\n%a short weekday name    %A weekday name         %u day of week (1-7, 1=mon)\n%b short month name      %B month name           %Z timezone name\n%j day of year (001-366) %d day of month (01-31) %e day of month ( 1-31)\n%s seconds past the Epoch\n\n%U Week of year (0-53 start sunday)   %W Week of year (0-53 start monday)\n%V Week of year (1-53 start monday, week < 4 days not part of this year)\n\n%D = \"%m/%d/%y\"    %r = \"%I : %M : %S %p\"   %T = \"%H:%M:%S\"   %h = \"%b\"\n%x locale date     %X locale time           %c locale date/time\n\n"
+
+#define HELP_cut "usage: cut OPTION... [FILE]...\n\nPrint selected parts of lines from each FILE to standard output.\n\n-b LIST	select only these bytes from LIST.\n-c LIST	select only these characters from LIST.\n-f LIST	select only these fields.\n-d DELIM	use DELIM instead of TAB for field delimiter.\n-s	do not print lines not containing delimiters.\n-n	don't split multibyte characters (Ignored).\n\n"
+
+#define HELP_cpio "usage: cpio -{o|t|i|p DEST} [-v] [--verbose] [-F FILE] [--no-preserve-owner]\n       [ignored: -mdu -H newc]\n\ncopy files into and out of a \"newc\" format cpio archive\n\n-F FILE	use archive FILE instead of stdin/stdout\n-p DEST	copy-pass mode, copy stdin file list to directory DEST\n-i	extract from archive into file system (stdin=archive)\n-o	create archive (stdin=list of files, stdout=archive)\n-t	test files (list only, stdin=archive, stdout=list of files)\n-v	verbose (list files during create/extract)\n--no-preserve-owner (don't set ownership during extract)\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 [-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 "--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] [-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"
+
+#define HELP_cmp "usage: cmp [-l] [-s] FILE1 FILE2\n\nCompare the contents of two files.\n\n-l	show all differing bytes\n-s	silent\n\n"
+
+#define HELP_cksum "usage: cksum [-IPLN] [file...]\n\nFor each file, output crc32 checksum value, length and name of file.\nIf no files listed, copy from stdin.  Filename \"-\" is a synonym for stdin.\n\n-H	Hexadecimal checksum (defaults to decimal)\n-L	Little endian (defaults to big endian)\n-P	Pre-inversion\n-I	Skip post-inversion\n-N	Do not include length in CRC calculation\n\n"
+
+#define HELP_chmod "usage: chmod [-R] MODE FILE...\n\nChange mode of listed file[s] (recursively with -R).\n\nMODE can be (comma-separated) stanzas: [ugoa][+-=][rwxstXugo]\n\nStanzas are applied in order: For each category (u = user,\ng = group, o = other, a = all three, if none specified default is a),\nset (+), clear (-), or copy (=), r = read, w = write, x = execute.\ns = u+s = suid, g+s = sgid, o+s = sticky. (+t is an alias for o+s).\nsuid/sgid: execute as the user/group who owns the file.\nsticky: can't delete files you don't own out of this directory\nX = x for directories or if any category already has x set.\n\nOr MODE can be an octal value up to 7777	ug uuugggooo	top +\nbit 1 = o+x, bit 1<<8 = u+w, 1<<11 = g+1	sstrwxrwxrwx	bottom\n\nExamples:\nchmod u+w file - allow owner of \"file\" to write to it.\nchmod 744 file - user can read/write/execute, everyone else read only\n\n"
+
+#define HELP_chown "see: chgrp\n\n"
+
+#define HELP_chgrp "usage: chgrp/chown [-RHLP] [-fvh] group file...\n\nChange group of one or more files.\n\n-f	suppress most error messages.\n-h	change symlinks instead of what they point to\n-R	recurse into subdirectories (implies -h).\n-H	with -R change target of symlink, follow command line symlinks\n-L	with -R change target of symlink, follow all symlinks\n-P	with -R change symlink, do not follow symlinks (default)\n-v	verbose output.\n\n"
+
+#define HELP_catv "usage: catv [-evt] [filename...]\n\nDisplay nonprinting characters as escape sequences. Use M-x for\nhigh ascii characters (>127), and ^x for other nonprinting chars.\n\n-e  Mark each newline with $\n-t  Show tabs as ^I\n-v  Don't use ^x or M-x escapes.\n\n"
+
+#define HELP_cat "usage: cat [-etuv] [file...]\n\nCopy (concatenate) files to stdout.  If no files listed, copy from stdin.\nFilename \"-\" is a synonym for stdin.\n\n-e	Mark each newline with $\n-t	Show tabs as ^I\n-u	Copy one byte at a time (slow).\n-v	Display nonprinting characters as escape sequences. Use M-x for\n	high ascii characters (>127), and ^x for other nonprinting chars.\n"
+
+#define HELP_cal "usage: cal [[month] year]\n\nPrint a calendar.\n\nWith one argument, prints all months of the specified year.\nWith two arguments, prints calendar for month and year.\n\n"
+
+#define HELP_basename "usage: basename string [suffix]\n\nReturn non-directory portion of a pathname removing suffix\n\n"
+
diff --git a/toybox/generated/newtoys.h b/toybox/generated/newtoys.h
new file mode 100644
index 0000000..b541278
--- /dev/null
+++ b/toybox/generated/newtoys.h
@@ -0,0 +1,279 @@
+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|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#<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_BOOTCHARTD(NEWTOY(bootchartd, 0, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
+USE_BRCTL(NEWTOY(brctl, "<1", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_BUNZIP2(NEWTOY(bunzip2, "cftkv", TOYFLAG_USR|TOYFLAG_BIN))
+USE_BZCAT(NEWTOY(bzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN))
+USE_CAT(NEWTOY(cat, "u"USE_CAT_V("vte"), TOYFLAG_BIN))
+USE_CATV(NEWTOY(catv, USE_CATV("vte"), TOYFLAG_USR|TOYFLAG_BIN))
+USE_SH(NEWTOY(cd, NULL, TOYFLAG_NOFORK))
+USE_CHATTR(NEWTOY(chattr, NULL, TOYFLAG_BIN))
+USE_CHCON(NEWTOY(chcon, "<2hvR", TOYFLAG_USR|TOYFLAG_BIN))
+USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv[-HLP]", TOYFLAG_BIN))
+USE_CHMOD(NEWTOY(chmod, "<2?vRf[-vf]", TOYFLAG_BIN))
+USE_CHOWN(OLDTOY(chown, chgrp, TOYFLAG_BIN))
+USE_CHROOT(NEWTOY(chroot, "^<1", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_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[!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):;")"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_CUT(NEWTOY(cut, "b:|c:|f:|d:sn[!cbf]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_DATE(NEWTOY(date, "d:D:r:u[!dr]", TOYFLAG_BIN))
+USE_DD(NEWTOY(dd, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+USE_GROUPDEL(OLDTOY(delgroup, groupdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_USERDEL(OLDTOY(deluser, userdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_DF(NEWTOY(df, "HPkht*a[-HPkh]", TOYFLAG_SBIN))
+USE_DHCP(NEWTOY(dhcp, "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
+USE_DHCP6(NEWTOY(dhcp6, "r:A#<0T#<0t#<0s:p:i:SRvqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
+USE_DHCPD(NEWTOY(dhcpd, ">1P#<0>65535fi:S46[!46]", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
+USE_DIFF(NEWTOY(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", TOYFLAG_USR|TOYFLAG_BIN))
+USE_DIRNAME(NEWTOY(dirname, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_DMESG(NEWTOY(dmesg, "trs#<1n#c[!tr]", TOYFLAG_BIN))
+USE_DOS2UNIX(NEWTOY(dos2unix, 0, TOYFLAG_BIN))
+USE_DU(NEWTOY(du, "d#<0hmlcaHkKLsx[-HL][-kKmh]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_DUMPLEASES(NEWTOY(dumpleases, ">0arf:[!ar]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_ECHO(NEWTOY(echo, "^?en", TOYFLAG_BIN))
+USE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
+USE_EJECT(NEWTOY(eject, ">1stT[!tT]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_ENV(NEWTOY(env, "^iu*", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SH(NEWTOY(exit, NULL, TOYFLAG_NOFORK))
+USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_EXPR(NEWTOY(expr, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_FACTOR(NEWTOY(factor, 0, TOYFLAG_USR|TOYFLAG_BIN))
+USE_FALLOCATE(NEWTOY(fallocate, ">1l#|", TOYFLAG_USR|TOYFLAG_BIN))
+USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN|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_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_FREE(NEWTOY(free, "htgmkb[!htgmkb]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_FREERAMDISK(NEWTOY(freeramdisk, "<1>1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_FSCK(NEWTOY(fsck, "?t:ANPRTVsC#", TOYFLAG_USR|TOYFLAG_BIN))
+USE_FSFREEZE(NEWTOY(fsfreeze, "<1>1f|u|[!fu]", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_FSTYPE(NEWTOY(fstype, "<1", TOYFLAG_BIN))
+USE_FSYNC(NEWTOY(fsync, "<1d", TOYFLAG_BIN))
+USE_FTPGET(NEWTOY(ftpget, "<2cvu:p:P#<0=21>65535", TOYFLAG_BIN))
+USE_FTPGET(OLDTOY(ftpput, ftpget, TOYFLAG_BIN))
+USE_GETENFORCE(NEWTOY(getenforce, ">0", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_GETFATTR(NEWTOY(getfattr, "dhn:", TOYFLAG_USR|TOYFLAG_BIN))
+USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_GETTY(NEWTOY(getty, "<2t#<0H:I:l:f:iwnmLh",TOYFLAG_SBIN))
+USE_GREP(NEWTOY(grep, "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
+USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_GROUPDEL(NEWTOY(groupdel, "<1>2", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_GROUPS(NEWTOY(groups, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_GUNZIP(NEWTOY(gunzip, "cflqStv", TOYFLAG_USR|TOYFLAG_BIN))
+USE_GZIP(NEWTOY(gzip, USE_GZIP_D("d")"19dcflqStvgLRz[!gLRz]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_REBOOT(OLDTOY(halt, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_HEAD(NEWTOY(head, "?n#<0=10", TOYFLAG_USR|TOYFLAG_BIN))
+USE_HELLO(NEWTOY(hello, 0, TOYFLAG_USR|TOYFLAG_BIN))
+USE_HELP(NEWTOY(help, ""USE_HELP_EXTRAS("ah"), 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, "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_IFCONFIG(NEWTOY(ifconfig, "^?a", TOYFLAG_SBIN))
+USE_INIT(NEWTOY(init, "", TOYFLAG_SBIN))
+USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
+USE_INSMOD(NEWTOY(insmod, "<1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_INSTALL(NEWTOY(install, "<1cdDpsvm:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IONICE(NEWTOY(ionice, "^tc#<0>3=2n#<0>7=5p#", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IORENICE(NEWTOY(iorenice, "?<1>3", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IOTOP(NEWTOY(iotop, ">0AaKO" "k*o*p*u*s#<1=7d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
+USE_IP(NEWTOY(ip, NULL, TOYFLAG_SBIN))
+USE_IP(OLDTOY(ipaddr, ip, TOYFLAG_SBIN))
+USE_IPCRM(NEWTOY(ipcrm, "m*M*s*S*q*Q*", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IPCS(NEWTOY(ipcs, "acptulsqmi#", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IP(OLDTOY(iplink, ip, TOYFLAG_SBIN))
+USE_IP(OLDTOY(iproute, ip, TOYFLAG_SBIN))
+USE_IP(OLDTOY(iprule, ip, TOYFLAG_SBIN))
+USE_IP(OLDTOY(iptunnel, ip, TOYFLAG_SBIN))
+USE_KILL(NEWTOY(kill, "?ls: ", TOYFLAG_BIN))
+USE_KILLALL(NEWTOY(killall, "?s:lqvi", TOYFLAG_USR|TOYFLAG_BIN))
+USE_KILLALL5(NEWTOY(killall5, "?o*ls: [!lo][!ls]", TOYFLAG_SBIN))
+USE_KLOGD(NEWTOY(klogd, "c#<1>8n", TOYFLAG_SBIN))
+USE_LAST(NEWTOY(last, "f:W", TOYFLAG_BIN))
+USE_LINK(NEWTOY(link, "<2>2", TOYFLAG_USR|TOYFLAG_BIN))
+USE_LN(NEWTOY(ln, "<1vnfs", TOYFLAG_BIN))
+USE_LOAD_POLICY(NEWTOY(load_policy, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_LOG(NEWTOY(log, "<1p:t:", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_LOGGER(NEWTOY(logger, "st:p:", TOYFLAG_USR|TOYFLAG_BIN))
+USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+USE_LOGNAME(NEWTOY(logname, ">0", TOYFLAG_USR|TOYFLAG_BIN))
+USE_LOSETUP(NEWTOY(losetup, ">2S(sizelimit)#s(show)ro#j:fdca[!afj]", TOYFLAG_SBIN))
+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_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, "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_MKE2FS(NEWTOY(mke2fs, "<1>2g:Fnqm#N#i#b#", TOYFLAG_SBIN))
+USE_MKFIFO(NEWTOY(mkfifo, "<1"USE_MKFIFO_Z("Z:")"m:", TOYFLAG_USR|TOYFLAG_BIN))
+USE_MKNOD(NEWTOY(mknod, "<2>4m(mode):"USE_MKNOD_Z("Z:"), TOYFLAG_BIN|TOYFLAG_UMASK))
+USE_MKPASSWD(NEWTOY(mkpasswd, ">2S:m:P#=0<0", TOYFLAG_USR|TOYFLAG_BIN))
+USE_MKSWAP(NEWTOY(mkswap, "<1>1L:", TOYFLAG_SBIN))
+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, 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, "<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_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#p#s:q#f:", TOYFLAG_BIN))
+USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN))
+USE_NICE(NEWTOY(nice, "^<1n#", TOYFLAG_USR|TOYFLAG_BIN))
+USE_NL(NEWTOY(nl, "v#<1=1l#b:n:s:w#<0=6E", 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#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, "(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_PMAP(NEWTOY(pmap, "<1xq", TOYFLAG_BIN))
+USE_REBOOT(OLDTOY(poweroff, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_PRINTENV(NEWTOY(printenv, "0(null)", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PRINTF(NEWTOY(printf, "<1?^", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!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_READLINK(NEWTOY(readlink, "<1>1fenq[-fe]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|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_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_RM(NEWTOY(rm, "fiRr[-fi]", TOYFLAG_BIN))
+USE_RMDIR(NEWTOY(rmdir, "<1p", TOYFLAG_BIN))
+USE_RMMOD(NEWTOY(rmmod, "<1wf", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_ROUTE(NEWTOY(route, "?neA:", TOYFLAG_BIN))
+USE_RUNCON(NEWTOY(runcon, "<2", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_SED(NEWTOY(sed, "(version)e*f*inEr[+Er]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_SENDEVENT(NEWTOY(sendevent, "<4>4", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_SEQ(NEWTOY(seq, "<1>3?f:s:w[!fw]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SETENFORCE(NEWTOY(setenforce, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_SETFATTR(NEWTOY(setfattr, "hn:|v:x:|[!xv]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_SETSID(NEWTOY(setsid, "^<1t", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN))
+USE_SHA1SUM(NEWTOY(sha1sum, "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_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_SWAPOFF(NEWTOY(swapoff, "<1>1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_SWAPON(NEWTOY(swapon, "<1>1p#<0>32767d", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_SWITCH_ROOT(NEWTOY(switch_root, "<2c:h", TOYFLAG_SBIN))
+USE_SYNC(NEWTOY(sync, NULL, TOYFLAG_BIN))
+USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_SBIN))
+USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT))
+USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_TAIL(NEWTOY(tail, "?fc-n-[-cn]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TAR(NEWTOY(tar, "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_BIN|TOYFLAG_STAYROOT))
+USE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1C:b#=20<0u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TEE(NEWTOY(tee, "ia", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TELNET(NEWTOY(telnet, "<1>2", TOYFLAG_BIN))
+USE_TELNETD(NEWTOY(telnetd, "w#<0b:p#<0>65535=23f:l:FSKi[!wi]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TEST(NEWTOY(test, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_TEST_HUMAN_READABLE(NEWTOY(test_human_readable, "<1>1ibs", 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" "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|TOYFLAG_NOHELP))
+USE_TRUNCATE(NEWTOY(truncate, "<1s:|c", TOYFLAG_BIN))
+USE_TTY(NEWTOY(tty, "s", 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_UNAME(NEWTOY(uname, "oamvrns[+os]", TOYFLAG_BIN))
+USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_USR|TOYFLAG_BIN))
+USE_UNIX2DOS(NEWTOY(unix2dos, 0, TOYFLAG_BIN))
+USE_UNLINK(NEWTOY(unlink, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_UNSHARE(NEWTOY(unshare, "<1^f(fork);r(map-root-user);i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
+USE_UPTIME(NEWTOY(uptime, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_USERADD(NEWTOY(useradd, "<1>2u#<0G:s:g:h:SDH", TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
+USE_USERDEL(NEWTOY(userdel, "<1>1r", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_USLEEP(NEWTOY(usleep, "<1", TOYFLAG_BIN))
+USE_UUDECODE(NEWTOY(uudecode, ">1o:", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK))
+USE_UUENCODE(NEWTOY(uuencode, "<1>2m", TOYFLAG_USR|TOYFLAG_BIN))
+USE_VCONFIG(NEWTOY(vconfig, "<2>4", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_VI(NEWTOY(vi, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_VMSTAT(NEWTOY(vmstat, ">2n", TOYFLAG_BIN))
+USE_W(NEWTOY(w, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_WATCH(NEWTOY(watch, "^<1n#<0=2te", TOYFLAG_USR|TOYFLAG_BIN))
+USE_WC(NEWTOY(wc, "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=2prs#[!rs]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_XZCAT(NEWTOY(xzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_YES(NEWTOY(yes, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_ZCAT(NEWTOY(zcat, 0, TOYFLAG_USR|TOYFLAG_BIN))
diff --git a/toybox/generated/tags.h b/toybox/generated/tags.h
new file mode 100644
index 0000000..31e7773
--- /dev/null
+++ b/toybox/generated/tags.h
@@ -0,0 +1,192 @@
+#define CP_mode                                     0
+#define _CP_mode                                    (1<<0)
+#define CP_ownership                                1
+#define _CP_ownership                               (1<<1)
+#define CP_timestamps                               2
+#define _CP_timestamps                              (1<<2)
+#define CP_context                                  3
+#define _CP_context                                 (1<<3)
+#define CP_xattr                                    4
+#define _CP_xattr                                   (1<<4)
+#define PS_PID                                      0
+#define _PS_PID                                     (1<<0)
+#define PS_PPID                                     1
+#define _PS_PPID                                    (1<<1)
+#define PS_PRI                                      2
+#define _PS_PRI                                     (1<<2)
+#define PS_NI                                       3
+#define _PS_NI                                      (1<<3)
+#define PS_ADDR                                     4
+#define _PS_ADDR                                    (1<<4)
+#define PS_SZ                                       5
+#define _PS_SZ                                      (1<<5)
+#define PS_RSS                                      6
+#define _PS_RSS                                     (1<<6)
+#define PS_PGID                                     7
+#define _PS_PGID                                    (1<<7)
+#define PS_VSZ                                      8
+#define _PS_VSZ                                     (1<<8)
+#define PS_MAJFL                                    9
+#define _PS_MAJFL                                   (1<<9)
+#define PS_MINFL                                    10
+#define _PS_MINFL                                   (1<<10)
+#define PS_PR                                       11
+#define _PS_PR                                      (1<<11)
+#define PS_PSR                                      12
+#define _PS_PSR                                     (1<<12)
+#define PS_RTPRIO                                   13
+#define _PS_RTPRIO                                  (1<<13)
+#define PS_SCH                                      14
+#define _PS_SCH                                     (1<<14)
+#define PS_CPU                                      15
+#define _PS_CPU                                     (1<<15)
+#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_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
+#define _KEY_DOWN                                    (1<<1)
+#define KEY_RIGHT                                    2
+#define _KEY_RIGHT                                   (1<<2)
+#define KEY_LEFT                                     3
+#define _KEY_LEFT                                    (1<<3)
+#define KEY_PGUP                                     4
+#define _KEY_PGUP                                    (1<<4)
+#define KEY_PGDN                                     5
+#define _KEY_PGDN                                    (1<<5)
+#define KEY_HOME                                     6
+#define _KEY_HOME                                    (1<<6)
+#define KEY_END                                      7
+#define _KEY_END                                     (1<<7)
+#define KEY_INSERT                                   8
+#define _KEY_INSERT                                  (1<<8)
+#define KEY_F1                                       9
+#define _KEY_F1                                      (1<<9)
+#define KEY_F2                                       10
+#define _KEY_F2                                      (1<<10)
+#define KEY_F3                                       11
+#define _KEY_F3                                      (1<<11)
+#define KEY_F4                                       12
+#define _KEY_F4                                      (1<<12)
+#define KEY_F5                                       13
+#define _KEY_F5                                      (1<<13)
+#define KEY_F6                                       14
+#define _KEY_F6                                      (1<<14)
+#define KEY_F7                                       15
+#define _KEY_F7                                      (1<<15)
+#define KEY_F8                                       16
+#define _KEY_F8                                      (1<<16)
+#define KEY_F9                                       17
+#define _KEY_F9                                      (1<<17)
+#define KEY_SUP                                      18
+#define _KEY_SUP                                     (1<<18)
+#define KEY_AUP                                      19
+#define _KEY_AUP                                     (1<<19)
+#define KEY_CUP                                      20
+#define _KEY_CUP                                     (1<<20)
+#define KEY_SDOWN                                    21
+#define _KEY_SDOWN                                   (1<<21)
+#define KEY_ADOWN                                    22
+#define _KEY_ADOWN                                   (1<<22)
+#define KEY_CDOWN                                    23
+#define _KEY_CDOWN                                   (1<<23)
+#define KEY_SRIGHT                                   24
+#define _KEY_SRIGHT                                  (1<<24)
+#define KEY_ARIGHT                                   25
+#define _KEY_ARIGHT                                  (1<<25)
+#define KEY_CRIGHT                                   26
+#define _KEY_CRIGHT                                  (1<<26)
+#define KEY_SLEFT                                    27
+#define _KEY_SLEFT                                   (1<<27)
+#define KEY_ALEFT                                    28
+#define _KEY_ALEFT                                   (1<<28)
+#define KEY_CLEFT                                    29
+#define _KEY_CLEFT                                   (1<<29)
+#define KEY_SF1                                      30
+#define _KEY_SF1                                     (1<<30)
+#define KEY_AF1                                      31
+#define _KEY_AF1                                     (1<<31)
+#define KEY_CF1                                      32
+#define _KEY_CF1                                     (1LL<<32)
diff --git a/toybox/kconfig/Makefile b/toybox/kconfig/Makefile
new file mode 100644
index 0000000..7466d03
--- /dev/null
+++ b/toybox/kconfig/Makefile
@@ -0,0 +1,69 @@
+# ===========================================================================
+# Kernel configuration targets
+# These targets are used from top-level makefile
+
+KCONFIG_TOP = Config.in
+KCONFIG_PROJECT = ToyBox
+obj = ./kconfig
+PHONY += clean help oldconfig menuconfig config silentoldconfig \
+	randconfig allyesconfig allnoconfig allmodconfig defconfig
+
+menuconfig: $(obj)/mconf $(KCONFIG_TOP)
+	$< $(KCONFIG_TOP)
+
+config: $(obj)/conf $(KCONFIG_TOP)
+	$< $(KCONFIG_TOP)
+
+oldconfig: $(obj)/conf $(KCONFIG_TOP)
+	$< -o $(KCONFIG_TOP)
+
+silentoldconfig: $(obj)/conf $(KCONFIG_TOP)
+	$< -s $(KCONFIG_TOP)
+
+randconfig: $(obj)/conf $(KCONFIG_TOP)
+	$< -r $(KCONFIG_TOP) > /dev/null
+
+allyesconfig: $(obj)/conf $(KCONFIG_TOP)
+	$< -y $(KCONFIG_TOP) > /dev/null
+
+allnoconfig: $(obj)/conf $(KCONFIG_TOP)
+	$< -n $(KCONFIG_TOP) > /dev/null
+
+defconfig: $(obj)/conf $(KCONFIG_TOP)
+	$< -D /dev/null $(KCONFIG_TOP) > /dev/null
+
+# Help text used by make help
+help::
+	@echo  '  config	  - Update current config utilising a line-oriented program'
+	@echo  '  menuconfig	  - Update current config utilising a menu based program'
+	@echo  '  oldconfig	  - Update current config utilising a provided .config as base'
+	@echo  '  silentoldconfig - Same as oldconfig, but quietly'
+	@echo  '  randconfig	  - New config with random answer to all options'
+	@echo  '  defconfig	  - New config with default answer to all options'
+	@echo  '                    This is the maximum sane configuration.'
+	@echo  '  allyesconfig	  - New config where all options are accepted with yes'
+	@echo  "                    This may not actually compile, it's a starting point"
+	@echo  '                    for further configuration (probably with menuconfig)'
+	@echo  '  allnoconfig	  - New config where all options are answered with no'
+	@echo  '                    (NOP binary, starting point for further configuration)'
+
+# Cheesy build
+
+SHIPPED = kconfig/zconf.tab.c kconfig/lex.zconf.c kconfig/zconf.hash.c
+
+%.c: %.c_shipped
+	@ln -s $(notdir $<) $@
+
+gen_config.h: .config
+
+kconfig/mconf: $(SHIPPED)
+	$(HOSTCC) -o $@ kconfig/mconf.c kconfig/zconf.tab.c \
+		kconfig/lxdialog/*.c -lcurses -DCURSES_LOC="<ncurses.h>" \
+		-DKBUILD_NO_NLS=1 -DPROJECT_NAME=\"$(KCONFIG_PROJECT)\"
+
+kconfig/conf: $(SHIPPED)
+	$(HOSTCC) -o $@ kconfig/conf.c kconfig/zconf.tab.c -DKBUILD_NO_NLS=1 \
+		-DPROJECT_NAME=\"$(KCONFIG_PROJECT)\"
+
+clean::
+	rm -f $(wildcard kconfig/*zconf*.c) kconfig/conf kconfig/mconf
diff --git a/toybox/kconfig/README b/toybox/kconfig/README
new file mode 100644
index 0000000..8809bbf
--- /dev/null
+++ b/toybox/kconfig/README
@@ -0,0 +1,26 @@
+This is a snapshot of linux 2.6.12 kconfig as washed through busybox and
+further modified by Rob Landley.
+
+Way back when I tried to push my local changes to kconfig upstream
+in 2005 https://lwn.net/Articles/161086/
+and 2006 http://lkml.iu.edu/hypermail/linux/kernel/0607.0/1805.html
+and 2007 http://lkml.iu.edu/hypermail/linux/kernel/0707.1/1741.html
+each of which spawned long "I think you should go do this and this and this
+but I'm not going to lift a finger personally" threads from the kernel
+developers. Twice I came back a year later to see if there was any interest
+in what I _had_ done, and the third thread was the longest of the lot but
+no code was merged as a result.
+
+*shrug* That's the linux-kernel community for you. I had an easier time
+than the author of squashfs, who spent 5 years actively trying to get his code
+merged, finally quitting his job to spend an unpaid year working on upstreaming
+squashfs _after_ after every major Linux distro had been locally carrying it
+for years. No really, here's where he wrote about it himself:
+
+https://lwn.net/Articles/563578/
+
+This code is _going_away_. Rewriting it is low priority, but removing it is a
+checklist item for the 1.0 toybox release. This directory contains the only
+GPL code left in the tree, and none of its code winds up in the resulting
+binary. It's just an editor that reads our Config.in files to update the top
+level .config file; you can edit they by hand if you really want to.
diff --git a/toybox/kconfig/conf.c b/toybox/kconfig/conf.c
new file mode 100644
index 0000000..72940e1
--- /dev/null
+++ b/toybox/kconfig/conf.c
@@ -0,0 +1,624 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum {
+	ask_all,
+	ask_new,
+	ask_silent,
+	set_default,
+	set_yes,
+	set_mod,
+	set_no,
+	set_random
+} input_mode = ask_all;
+char *defconfig_file;
+
+static int indent = 1;
+static int valid_stdin = 1;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
+
+static void strip(char *str)
+{
+	char *p = str;
+	int l;
+
+	while ((isspace(*p)))
+		p++;
+	l = strlen(p);
+	if (p != str)
+		memmove(str, p, l + 1);
+	if (!l)
+		return;
+	p = str + l - 1;
+	while ((isspace(*p)))
+		*p-- = 0;
+}
+
+static void check_stdin(void)
+{
+	if (!valid_stdin && input_mode == ask_silent) {
+		printf(_("aborted!\n\n"));
+		printf(_("Console input/output is redirected. "));
+		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+		exit(1);
+	}
+}
+
+static void conf_askvalue(struct symbol *sym, const char *def)
+{
+	enum symbol_type type = sym_get_type(sym);
+	tristate val;
+
+	if (!sym_has_value(sym))
+		printf("(NEW) ");
+
+	line[0] = '\n';
+	line[1] = 0;
+
+	if (!sym_is_changable(sym)) {
+		printf("%s\n", def);
+		line[0] = '\n';
+		line[1] = 0;
+		return;
+	}
+
+	switch (input_mode) {
+	case set_no:
+	case set_mod:
+	case set_yes:
+	case set_random:
+		if (sym_has_value(sym)) {
+			printf("%s\n", def);
+			return;
+		}
+		break;
+	case ask_new:
+	case ask_silent:
+		if (sym_has_value(sym)) {
+			printf("%s\n", def);
+			return;
+		}
+		check_stdin();
+	case ask_all:
+		fflush(stdout);
+		fgets(line, 128, stdin);
+		return;
+	case set_default:
+		printf("%s\n", def);
+		return;
+	default:
+		break;
+	}
+
+	switch (type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		printf("%s\n", def);
+		return;
+	default:
+		;
+	}
+	switch (input_mode) {
+	case set_yes:
+		if (sym_tristate_within_range(sym, yes)) {
+			line[0] = 'y';
+			line[1] = '\n';
+			line[2] = 0;
+			break;
+		}
+	case set_mod:
+		if (type == S_TRISTATE) {
+			if (sym_tristate_within_range(sym, mod)) {
+				line[0] = 'm';
+				line[1] = '\n';
+				line[2] = 0;
+				break;
+			}
+		} else {
+			if (sym_tristate_within_range(sym, yes)) {
+				line[0] = 'y';
+				line[1] = '\n';
+				line[2] = 0;
+				break;
+			}
+		}
+	case set_no:
+		if (sym_tristate_within_range(sym, no)) {
+			line[0] = 'n';
+			line[1] = '\n';
+			line[2] = 0;
+			break;
+		}
+	case set_random:
+		do {
+			val = (tristate)(random() % 3);
+		} while (!sym_tristate_within_range(sym, val));
+		switch (val) {
+		case no: line[0] = 'n'; break;
+		case mod: line[0] = 'm'; break;
+		case yes: line[0] = 'y'; break;
+		}
+		line[1] = '\n';
+		line[2] = 0;
+		break;
+	default:
+		break;
+	}
+	printf("%s", line);
+}
+
+int conf_string(struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	const char *def, *help;
+
+	while (1) {
+		printf("%*s%s ", indent - 1, "", menu->prompt->text);
+		printf("(%s) ", sym->name);
+		def = sym_get_string_value(sym);
+		if (sym_get_string_value(sym))
+			printf("[%s] ", def);
+		conf_askvalue(sym, def);
+		switch (line[0]) {
+		case '\n':
+			break;
+		case '?':
+			/* print help */
+			if (line[1] == '\n') {
+				help = nohelp_text;
+				if (menu->sym->help)
+					help = menu->sym->help;
+				printf("\n%s\n", menu->sym->help);
+				def = NULL;
+				break;
+			}
+		default:
+			line[strlen(line)-1] = 0;
+			def = line;
+		}
+		if (def && sym_set_string_value(sym, def))
+			return 0;
+	}
+}
+
+static int conf_sym(struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	int type;
+	tristate oldval, newval;
+	const char *help;
+
+	while (1) {
+		printf("%*s%s ", indent - 1, "", menu->prompt->text);
+		if (sym->name)
+			printf("(%s) ", sym->name);
+		type = sym_get_type(sym);
+		putchar('[');
+		oldval = sym_get_tristate_value(sym);
+		switch (oldval) {
+		case no:
+			putchar('N');
+			break;
+		case mod:
+			putchar('M');
+			break;
+		case yes:
+			putchar('Y');
+			break;
+		}
+		if (oldval != no && sym_tristate_within_range(sym, no))
+			printf("/n");
+		if (oldval != mod && sym_tristate_within_range(sym, mod))
+			printf("/m");
+		if (oldval != yes && sym_tristate_within_range(sym, yes))
+			printf("/y");
+		if (sym->help)
+			printf("/?");
+		printf("] ");
+		conf_askvalue(sym, sym_get_string_value(sym));
+		strip(line);
+
+		switch (line[0]) {
+		case 'n':
+		case 'N':
+			newval = no;
+			if (!line[1] || !strcmp(&line[1], "o"))
+				break;
+			continue;
+		case 'm':
+		case 'M':
+			newval = mod;
+			if (!line[1])
+				break;
+			continue;
+		case 'y':
+		case 'Y':
+			newval = yes;
+			if (!line[1] || !strcmp(&line[1], "es"))
+				break;
+			continue;
+		case 0:
+			newval = oldval;
+			break;
+		case '?':
+			goto help;
+		default:
+			continue;
+		}
+		if (sym_set_tristate_value(sym, newval))
+			return 0;
+help:
+		help = nohelp_text;
+		if (sym->help)
+			help = sym->help;
+		printf("\n%s\n", help);
+	}
+}
+
+static int conf_choice(struct menu *menu)
+{
+	struct symbol *sym, *def_sym;
+	struct menu *child;
+	int type;
+	bool is_new;
+
+	sym = menu->sym;
+	type = sym_get_type(sym);
+	is_new = !sym_has_value(sym);
+	if (sym_is_changable(sym)) {
+		conf_sym(menu);
+		sym_calc_value(sym);
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
+			return 0;
+		case yes:
+			break;
+		}
+	} else {
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
+			printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+			return 0;
+		case yes:
+			break;
+		}
+	}
+
+	while (1) {
+		int cnt, def;
+
+		printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+		def_sym = sym_get_choice_value(sym);
+		cnt = def = 0;
+		line[0] = 0;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
+				continue;
+			if (!child->sym) {
+				printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+				continue;
+			}
+			cnt++;
+			if (child->sym == def_sym) {
+				def = cnt;
+				printf("%*c", indent, '>');
+			} else
+				printf("%*c", indent, ' ');
+			printf(" %d. %s", cnt, menu_get_prompt(child));
+			if (child->sym->name)
+				printf(" (%s)", child->sym->name);
+			if (!sym_has_value(child->sym))
+				printf(" (NEW)");
+			printf("\n");
+		}
+		printf("%*schoice", indent - 1, "");
+		if (cnt == 1) {
+			printf("[1]: 1\n");
+			goto conf_childs;
+		}
+		printf("[1-%d", cnt);
+		if (sym->help)
+			printf("?");
+		printf("]: ");
+		switch (input_mode) {
+		case ask_new:
+		case ask_silent:
+			if (!is_new) {
+				cnt = def;
+				printf("%d\n", cnt);
+				break;
+			}
+			check_stdin();
+		case ask_all:
+			fflush(stdout);
+			fgets(line, 128, stdin);
+			strip(line);
+			if (line[0] == '?') {
+				printf("\n%s\n", menu->sym->help ?
+					menu->sym->help : nohelp_text);
+				continue;
+			}
+			if (!line[0])
+				cnt = def;
+			else if (isdigit(line[0]))
+				cnt = atoi(line);
+			else
+				continue;
+			break;
+		case set_random:
+			def = (random() % cnt) + 1;
+		case set_default:
+		case set_yes:
+		case set_mod:
+		case set_no:
+			cnt = def;
+			printf("%d\n", cnt);
+			break;
+		}
+
+	conf_childs:
+		for (child = menu->list; child; child = child->next) {
+			if (!child->sym || !menu_is_visible(child))
+				continue;
+			if (!--cnt)
+				break;
+		}
+		if (!child)
+			continue;
+		if (line[strlen(line) - 1] == '?') {
+			printf("\n%s\n", child->sym->help ?
+				child->sym->help : nohelp_text);
+			continue;
+		}
+		sym_set_choice_value(sym, child->sym);
+		if (child->list) {
+			indent += 2;
+			conf(child->list);
+			indent -= 2;
+		}
+		return 1;
+	}
+}
+
+static void conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (prop) {
+		const char *prompt;
+
+		switch (prop->type) {
+		case P_MENU:
+			if (input_mode == ask_silent && rootEntry != menu) {
+				check_conf(menu);
+				return;
+			}
+		case P_COMMENT:
+			prompt = menu_get_prompt(menu);
+			if (prompt)
+				printf("%*c\n%*c %s\n%*c\n",
+					indent, '*',
+					indent, '*', prompt,
+					indent, '*');
+		default:
+			;
+		}
+	}
+
+	if (!sym)
+		goto conf_childs;
+
+	if (sym_is_choice(sym)) {
+		conf_choice(menu);
+		if (sym->curr.tri != mod)
+			return;
+		goto conf_childs;
+	}
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		conf_string(menu);
+		break;
+	default:
+		conf_sym(menu);
+		break;
+	}
+
+conf_childs:
+	if (sym)
+		indent += 2;
+	for (child = menu->list; child; child = child->next)
+		conf(child);
+	if (sym)
+		indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct menu *child;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	if (sym && !sym_has_value(sym)) {
+		if (sym_is_changable(sym) ||
+		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+			if (!conf_cnt++)
+				printf(_("*\n* Restart config...\n*\n"));
+			rootEntry = menu_get_parent_menu(menu);
+			conf(rootEntry);
+		}
+	}
+
+	for (child = menu->list; child; child = child->next)
+		check_conf(child);
+}
+
+int main(int ac, char **av)
+{
+	int i = 1;
+	const char *name;
+	struct stat tmpstat;
+
+	if (ac > i && av[i][0] == '-') {
+		switch (av[i++][1]) {
+		case 'o':
+			input_mode = ask_new;
+			break;
+		case 's':
+			input_mode = ask_silent;
+			valid_stdin = isatty(0) && isatty(1) && isatty(2);
+			break;
+		case 'd':
+			input_mode = set_default;
+			break;
+		case 'D':
+			input_mode = set_default;
+			defconfig_file = av[i++];
+			if (!defconfig_file) {
+				printf(_("%s: No default config file specified\n"),
+					av[0]);
+				exit(1);
+			}
+			break;
+		case 'n':
+			input_mode = set_no;
+			break;
+		case 'm':
+			input_mode = set_mod;
+			break;
+		case 'y':
+			input_mode = set_yes;
+			break;
+		case 'r':
+			input_mode = set_random;
+			srandom(time(NULL));
+			break;
+		case 'h':
+		case '?':
+			fprintf(stderr, "See README for usage info\n");
+			exit(0);
+		}
+	}
+  	name = av[i];
+	if (!name) {
+		printf(_("%s: Kconfig file missing\n"), av[0]);
+		exit(1);
+	}
+	conf_parse(name);
+	//zconfdump(stdout);
+	switch (input_mode) {
+	case set_default:
+		if (!defconfig_file)
+			defconfig_file = conf_get_default_confname();
+		if (conf_read(defconfig_file)) {
+			printf("***\n"
+				"*** Can't find default configuration \"%s\"!\n"
+				"***\n", defconfig_file);
+			exit(1);
+		}
+		break;
+	case ask_silent:
+		if (stat(".config", &tmpstat)) {
+			printf(_("***\n"
+				"*** You have not yet configured your "PROJECT_NAME"!\n"
+				"***\n"
+				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+				"*** \"make menuconfig\" or \"make xconfig\").\n"
+				"***\n"));
+			exit(1);
+		}
+	case ask_all:
+	case ask_new:
+		conf_read(NULL);
+		break;
+	case set_no:
+	case set_mod:
+	case set_yes:
+	case set_random:
+		name = getenv("KCONFIG_ALLCONFIG");
+		if (name && !stat(name, &tmpstat)) {
+			conf_read_simple(name, S_DEF_USER);
+			break;
+		}
+		switch (input_mode) {
+		case set_no:	 name = "allno.config"; break;
+		case set_mod:	 name = "allmod.config"; break;
+		case set_yes:	 name = "allyes.config"; break;
+		case set_random: name = "allrandom.config"; break;
+		default: break;
+		}
+		if (!stat(name, &tmpstat))
+			conf_read_simple(name, S_DEF_USER);
+		else if (!stat("all.config", &tmpstat))
+			conf_read_simple("all.config", S_DEF_USER);
+		break;
+	default:
+		break;
+	}
+
+	if (input_mode != ask_silent) {
+		rootEntry = &rootmenu;
+		conf(&rootmenu);
+		if (input_mode == ask_all) {
+			input_mode = ask_silent;
+			valid_stdin = 1;
+		}
+	} else if (sym_change_count) {
+		name = getenv("KCONFIG_NOSILENTUPDATE");
+		if (name && *name) {
+			fprintf(stderr, _("\n*** "PROJECT_NAME" configuration requires explicit update.\n\n"));
+			return 1;
+		}
+	} else
+		goto skip_check;
+
+	do {
+		conf_cnt = 0;
+		check_conf(&rootmenu);
+	} while (conf_cnt);
+
+	if (!conf_write(NULL)) {
+skip_check:
+		if (!(input_mode == ask_silent && conf_write_autoconf()))
+			return 0;
+	}
+	fprintf(stderr, _("\n*** Error writing "PROJECT_NAME" configuration.\n\n"));
+	return 1;
+}
diff --git a/toybox/kconfig/confdata.c b/toybox/kconfig/confdata.c
new file mode 100644
index 0000000..91c1ed5
--- /dev/null
+++ b/toybox/kconfig/confdata.c
@@ -0,0 +1,806 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf_warning(const char *fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+#ifndef conf_defname
+const char conf_defname[] = "arch/$ARCH/defconfig";
+#endif
+
+#ifndef CONFIG_PREFIX
+#define CONFIG_PREFIX "CONFIG_"
+#endif
+
+static void conf_warning(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	conf_warnings++;
+}
+
+const char *conf_get_configname(void)
+{
+	char *name = getenv("KCONFIG_CONFIG");
+
+	return name ? name : ".config";
+}
+
+static char *conf_expand_value(const char *in)
+{
+	struct symbol *sym;
+	const char *src;
+	static char res_value[SYMBOL_MAXLENGTH];
+	char *dst, name[SYMBOL_MAXLENGTH];
+
+	res_value[0] = 0;
+	dst = name;
+	while ((src = strchr(in, '$'))) {
+		strncat(res_value, in, src - in);
+		src++;
+		dst = name;
+		while (isalnum(*src) || *src == '_')
+			*dst++ = *src++;
+		*dst = 0;
+		sym = sym_lookup(name, 0);
+		sym_calc_value(sym);
+		strcat(res_value, sym_get_string_value(sym));
+		in = src;
+	}
+	strcat(res_value, in);
+
+	return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+	struct stat buf;
+	static char fullname[PATH_MAX+1];
+	char *env, *name;
+
+	name = conf_expand_value(conf_defname);
+	env = getenv(SRCTREE);
+	if (env) {
+		sprintf(fullname, "%s/%s", env, name);
+		if (!stat(fullname, &buf))
+			return fullname;
+	}
+	return name;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+	FILE *in = NULL;
+	char line[1024];
+	char *p, *p2;
+	struct symbol *sym;
+	int i, def_flags;
+
+	if (name) {
+		in = zconf_fopen(name);
+	} else {
+		struct property *prop;
+
+		name = conf_get_configname();
+		in = zconf_fopen(name);
+		if (in)
+			goto load;
+		sym_change_count++;
+		if (!sym_defconfig_list)
+			return 1;
+
+		for_all_defaults(sym_defconfig_list, prop) {
+			if (expr_calc_value(prop->visible.expr) == no ||
+			    prop->expr->type != E_SYMBOL)
+				continue;
+			name = conf_expand_value(prop->expr->left.sym->name);
+			in = zconf_fopen(name);
+			if (in) {
+				printf(_("#\n"
+					 "# using defaults found in %s\n"
+					 "#\n"), name);
+				goto load;
+			}
+		}
+	}
+	if (!in)
+		return 1;
+
+load:
+	conf_filename = name;
+	conf_lineno = 0;
+	conf_warnings = 0;
+	conf_unsaved = 0;
+
+	def_flags = SYMBOL_DEF << def;
+	for_all_symbols(i, sym) {
+		sym->flags |= SYMBOL_CHANGED;
+		sym->flags &= ~(def_flags|SYMBOL_VALID);
+		if (sym_is_choice(sym))
+			sym->flags |= def_flags;
+		switch (sym->type) {
+		case S_INT:
+		case S_HEX:
+		case S_STRING:
+			if (sym->def[def].val)
+				free(sym->def[def].val);
+		default:
+			sym->def[def].val = NULL;
+			sym->def[def].tri = no;
+		}
+	}
+
+	while (fgets(line, sizeof(line), in)) {
+		conf_lineno++;
+		sym = NULL;
+		switch (line[0]) {
+		case '#':
+			if (line[1]!=' ' || memcmp(line + 2, CONFIG_PREFIX,
+					       	strlen(CONFIG_PREFIX))) {
+				continue;
+			}
+			p = strchr(line + 2 + strlen(CONFIG_PREFIX), ' ');
+			if (!p)
+				continue;
+			*p++ = 0;
+			if (strncmp(p, "is not set", 10))
+				continue;
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + 2 + strlen(CONFIG_PREFIX));
+				if (!sym) {
+					conf_warning("trying to assign nonexistent symbol %s", line + 2 + strlen(CONFIG_PREFIX));
+					break;
+				}
+			} else {
+				sym = sym_lookup(line + 9, 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_BOOLEAN;
+			}
+			if (sym->flags & def_flags) {
+				conf_warning("trying to reassign symbol %s", sym->name);
+				break;
+			}
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				sym->def[def].tri = no;
+				sym->flags |= def_flags;
+				break;
+			default:
+				;
+			}
+			break;
+		case 'A' ... 'Z':
+			if (memcmp(line, CONFIG_PREFIX, strlen(CONFIG_PREFIX))) {
+				conf_warning("unexpected data");
+				continue;
+			}
+			p = strchr(line + strlen(CONFIG_PREFIX), '=');
+			if (!p)
+				continue;
+			*p++ = 0;
+			p2 = strchr(p, '\n');
+			if (p2) {
+				*p2-- = 0;
+				if (*p2 == '\r')
+					*p2 = 0;
+			}
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + strlen(CONFIG_PREFIX));
+				if (!sym) {
+					conf_warning("trying to assign nonexistent symbol %s", line + 7);
+					break;
+				}
+			} else {
+				sym = sym_lookup(line + strlen(CONFIG_PREFIX), 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_OTHER;
+			}
+			if (sym->flags & def_flags) {
+				conf_warning("trying to reassign symbol %s", sym->name);
+				break;
+			}
+			switch (sym->type) {
+			case S_TRISTATE:
+				if (p[0] == 'm') {
+					sym->def[def].tri = mod;
+					sym->flags |= def_flags;
+					break;
+				}
+			case S_BOOLEAN:
+				if (p[0] == 'y') {
+					sym->def[def].tri = yes;
+					sym->flags |= def_flags;
+					break;
+				}
+				if (p[0] == 'n') {
+					sym->def[def].tri = no;
+					sym->flags |= def_flags;
+					break;
+				}
+				conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+				break;
+			case S_OTHER:
+				if (*p != '"') {
+					for (p2 = p; *p2 && !isspace(*p2); p2++)
+						;
+					sym->type = S_STRING;
+					goto done;
+				}
+			case S_STRING:
+				if (*p++ != '"')
+					break;
+				for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+					if (*p2 == '"') {
+						*p2 = 0;
+						break;
+					}
+					memmove(p2, p2 + 1, strlen(p2));
+				}
+				if (!p2) {
+					conf_warning("invalid string found");
+					continue;
+				}
+			case S_INT:
+			case S_HEX:
+			done:
+				if (sym_string_valid(sym, p)) {
+					sym->def[def].val = strdup(p);
+					sym->flags |= def_flags;
+				} else {
+					conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+					continue;
+				}
+				break;
+			default:
+				;
+			}
+			break;
+		case '\r':
+		case '\n':
+			break;
+		default:
+			conf_warning("unexpected data");
+			continue;
+		}
+		if (sym && sym_is_choice_value(sym)) {
+			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+			switch (sym->def[def].tri) {
+			case no:
+				break;
+			case mod:
+				if (cs->def[def].tri == yes) {
+					conf_warning("%s creates inconsistent choice state", sym->name);
+					cs->flags &= ~def_flags;
+				}
+				break;
+			case yes:
+				if (cs->def[def].tri != no) {
+					conf_warning("%s creates inconsistent choice state", sym->name);
+					cs->flags &= ~def_flags;
+				} else
+					cs->def[def].val = sym;
+				break;
+			}
+			cs->def[def].tri = E_OR(cs->def[def].tri, sym->def[def].tri);
+		}
+	}
+	fclose(in);
+
+	if (modules_sym)
+		sym_calc_value(modules_sym);
+	return 0;
+}
+
+int conf_read(const char *name)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *e;
+	int i, flags;
+
+	sym_change_count = 0;
+
+	if (conf_read_simple(name, S_DEF_USER))
+		return 1;
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+			goto sym_ok;
+		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+			/* check that calculated value agrees with saved value */
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
+					break;
+				if (!sym_is_choice(sym))
+					goto sym_ok;
+			default:
+				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+					goto sym_ok;
+				break;
+			}
+		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+			/* no previous value and not saved */
+			goto sym_ok;
+		conf_unsaved++;
+		/* maybe print value in verbose mode... */
+	sym_ok:
+		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+			if (sym->visible == no)
+				sym->flags &= ~SYMBOL_DEF_USER;
+			switch (sym->type) {
+			case S_STRING:
+			case S_INT:
+			case S_HEX:
+				if (!sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+					sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+			default:
+				break;
+			}
+		}
+		if (!sym_is_choice(sym))
+			continue;
+		prop = sym_get_choice_prop(sym);
+		flags = sym->flags;
+		for (e = prop->expr; e; e = e->left.expr)
+			if (e->right.sym->visible != no)
+				flags &= e->right.sym->flags;
+		sym->flags &= flags | ~SYMBOL_DEF_USER;
+	}
+
+	sym_change_count += conf_warnings || conf_unsaved;
+
+	return 0;
+}
+
+struct menu *next_menu(struct menu *menu)
+{
+	if (menu->list) return menu->list;
+	do {
+		if (menu->next) {
+			menu = menu->next;
+			break;
+		}
+	} while ((menu = menu->parent));
+
+	return menu;
+}
+
+#define SYMBOL_FORCEWRITE (1<<31)
+
+int conf_write(const char *name)
+{
+	FILE *out;
+	struct symbol *sym;
+	struct menu *menu;
+	const char *basename;
+	char dirname[128], tmpname[128], newname[128];
+	int type, l, writetype;
+	const char *str;
+	time_t now;
+	int use_timestamp = 1;
+	char *env;
+
+	dirname[0] = 0;
+	if (name && name[0]) {
+		struct stat st;
+		char *slash;
+
+		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+			strcpy(dirname, name);
+			strcat(dirname, "/");
+			basename = conf_get_configname();
+		} else if ((slash = strrchr(name, '/'))) {
+			int size = slash - name + 1;
+			memcpy(dirname, name, size);
+			dirname[size] = 0;
+			if (slash[1])
+				basename = slash + 1;
+			else
+				basename = conf_get_configname();
+		} else
+			basename = name;
+	} else
+		basename = conf_get_configname();
+
+	sprintf(newname, "%s%s", dirname, basename);
+	env = getenv("KCONFIG_OVERWRITECONFIG");
+	if (!env || !*env) {
+		sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+		out = fopen(tmpname, "w");
+	} else {
+		*tmpname = 0;
+		out = fopen(newname, "w");
+	}
+	if (!out)
+		return 1;
+
+	sym = sym_lookup("KCONFIG_VERSION", 0);
+	sym_calc_value(sym);
+	time(&now);
+	env = getenv("KCONFIG_NOTIMESTAMP");
+	if (env && *env)
+		use_timestamp = 0;
+
+	fprintf(out, _("#\n"
+		       "# Automatically generated make config: don't edit\n"
+		       "# "PROJECT_NAME" version: %s\n"
+		       "%s%s"
+		       "#\n"),
+		     sym_get_string_value(sym),
+		     use_timestamp ? "# " : "",
+		     use_timestamp ? ctime(&now) : "");
+
+	if (!sym_change_count)
+		sym_clear_all_valid();
+
+	// Write out all symbols (even in closed sub-menus).
+	if (1) {
+		for (menu = rootmenu.list; menu; menu = next_menu(menu))
+			if (menu->sym) menu->sym->flags |= SYMBOL_FORCEWRITE;
+		writetype = SYMBOL_FORCEWRITE;
+
+	// Don't write  out symbols in closed menus.
+
+	} else writetype = SYMBOL_WRITE;
+
+
+	menu = rootmenu.list;
+	while (menu) {
+		sym = menu->sym;
+		if (!sym) {
+			if (!menu_is_visible(menu))
+				goto next;
+			str = menu_get_prompt(menu);
+			fprintf(out, "\n"
+				     "#\n"
+				     "# %s\n"
+				     "#\n", str);
+		} else if (!(sym->flags & SYMBOL_CHOICE)) {
+			sym_calc_value(sym);
+			if (!(sym->flags & writetype))
+				goto next;
+			sym->flags &= ~writetype;
+			type = sym->type;
+			if (type == S_TRISTATE) {
+				sym_calc_value(modules_sym);
+				if (modules_sym->curr.tri == no)
+					type = S_BOOLEAN;
+			}
+			switch (type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				switch (sym_get_tristate_value(sym)) {
+				case no:
+					fprintf(out, "# "CONFIG_PREFIX"%s is not set\n", sym->name);
+					break;
+				case mod:
+					fprintf(out, CONFIG_PREFIX"%s=m\n", sym->name);
+					break;
+				case yes:
+					fprintf(out, CONFIG_PREFIX"%s=y\n", sym->name);
+					break;
+				}
+				break;
+			case S_STRING:
+				str = sym_get_string_value(sym);
+				fprintf(out, CONFIG_PREFIX"%s=\"", sym->name);
+				while (1) {
+					l = strcspn(str, "\"\\");
+					if (l) {
+						fwrite(str, l, 1, out);
+						str += l;
+					}
+					if (!*str)
+						break;
+					fprintf(out, "\\%c", *str++);
+				}
+				fputs("\"\n", out);
+				break;
+			case S_HEX:
+				str = sym_get_string_value(sym);
+				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+					fprintf(out, CONFIG_PREFIX"%s=%s\n", sym->name, *str ? str : "0");
+					break;
+				}
+			case S_INT:
+				str = sym_get_string_value(sym);
+				fprintf(out, CONFIG_PREFIX"%s=%s\n", sym->name, *str ? str : "0");
+				break;
+			}
+		}
+
+	next:
+		if (writetype == SYMBOL_WRITE) {
+			if (menu->list) {
+				menu = menu->list;
+				continue;
+			}
+			if (menu->next)
+				menu = menu->next;
+			else while ((menu = menu->parent)) {
+				if (menu->next) {
+					menu = menu->next;
+					break;
+				}
+			}
+		} else
+			menu = next_menu(menu);
+	}
+	fclose(out);
+
+	if (*tmpname) {
+		strcat(dirname, basename);
+		strcat(dirname, ".old");
+		rename(newname, dirname);
+		if (rename(tmpname, newname))
+			return 1;
+	}
+
+	printf(_("#\n"
+		 "# configuration written to %s\n"
+		 "#\n"), newname);
+
+	sym_change_count = 0;
+
+	return 0;
+}
+
+int conf_split_config(void)
+{
+	char *name, path[128];
+	char *s, *d, c;
+	struct symbol *sym;
+	struct stat sb;
+	int res, i, fd;
+
+	name = getenv("KCONFIG_AUTOCONFIG");
+	if (!name)
+		name = "include/config/auto.conf";
+	conf_read_simple(name, S_DEF_AUTO);
+
+	if (chdir("include/config"))
+		return 1;
+
+	res = 0;
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+			continue;
+		if (sym->flags & SYMBOL_WRITE) {
+			if (sym->flags & SYMBOL_DEF_AUTO) {
+				/*
+				 * symbol has old and new value,
+				 * so compare them...
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) ==
+					    sym->def[S_DEF_AUTO].tri)
+						continue;
+					break;
+				case S_STRING:
+				case S_HEX:
+				case S_INT:
+					if (!strcmp(sym_get_string_value(sym),
+						    sym->def[S_DEF_AUTO].val))
+						continue;
+					break;
+				default:
+					break;
+				}
+			} else {
+				/*
+				 * If there is no old value, only 'no' (unset)
+				 * is allowed as new value.
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) == no)
+						continue;
+					break;
+				default:
+					break;
+				}
+			}
+		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
+			/* There is neither an old nor a new value. */
+			continue;
+		/* else
+		 *	There is an old value, but no new value ('no' (unset)
+		 *	isn't saved in auto.conf, so the old value is always
+		 *	different from 'no').
+		 */
+
+		/* Replace all '_' and append ".h" */
+		s = sym->name;
+		d = path;
+		while ((c = *s++)) {
+			c = tolower(c);
+			*d++ = (c == '_') ? '/' : c;
+		}
+		strcpy(d, ".h");
+
+		/* Assume directory path already exists. */
+		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+		if (fd == -1) {
+			if (errno != ENOENT) {
+				res = 1;
+				break;
+			}
+			/*
+			 * Create directory components,
+			 * unless they exist already.
+			 */
+			d = path;
+			while ((d = strchr(d, '/'))) {
+				*d = 0;
+				if (stat(path, &sb) && mkdir(path, 0755)) {
+					res = 1;
+					goto out;
+				}
+				*d++ = '/';
+			}
+			/* Try it again. */
+			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+			if (fd == -1) {
+				res = 1;
+				break;
+			}
+		}
+		close(fd);
+	}
+out:
+	if (chdir("../.."))
+		return 1;
+
+	return res;
+}
+
+int conf_write_autoconf(void)
+{
+	struct symbol *sym;
+	const char *str;
+	char *name;
+	FILE *out, *out_h;
+	time_t now;
+	int i, l;
+
+	sym_clear_all_valid();
+
+	file_write_dep("include/config/auto.conf.cmd");
+
+	if (conf_split_config())
+		return 1;
+
+	out = fopen(".tmpconfig", "w");
+	if (!out)
+		return 1;
+
+	out_h = fopen(".tmpconfig.h", "w");
+	if (!out_h) {
+		fclose(out);
+		return 1;
+	}
+
+	sym = sym_lookup("KCONFIG_VERSION", 0);
+	sym_calc_value(sym);
+	time(&now);
+	fprintf(out, "#\n"
+		     "# Automatically generated make config: don't edit\n"
+		     "# "PROJECT_NAME" version: %s\n"
+		     "# %s"
+		     "#\n",
+		     sym_get_string_value(sym), ctime(&now));
+	fprintf(out_h, "/*\n"
+		       " * Automatically generated C config: don't edit\n"
+		       " * "PROJECT_NAME" version: %s\n"
+		       " * %s"
+		       " */\n"
+		       // "#define AUTOCONF_INCLUDED\n"
+		       , sym_get_string_value(sym), ctime(&now));
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
+			continue;
+		switch (sym->type) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			switch (sym_get_tristate_value(sym)) {
+			case no:
+				break;
+			case mod:
+				fprintf(out, CONFIG_PREFIX"%s=m\n", sym->name);
+				fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
+				break;
+			case yes:
+				fprintf(out, CONFIG_PREFIX"%s=y\n", sym->name);
+				fprintf(out_h, "#define "CONFIG_PREFIX"%s 1\n", sym->name);
+				break;
+			}
+			break;
+		case S_STRING:
+			str = sym_get_string_value(sym);
+			fprintf(out, CONFIG_PREFIX"%s=\"", sym->name);
+			fprintf(out_h, "#define "CONFIG_PREFIX"%s \"", sym->name);
+			while (1) {
+				l = strcspn(str, "\"\\");
+				if (l) {
+					fwrite(str, l, 1, out);
+					fwrite(str, l, 1, out_h);
+					str += l;
+				}
+				if (!*str)
+					break;
+				fprintf(out, "\\%c", *str);
+				fprintf(out_h, "\\%c", *str);
+				str++;
+			}
+			fputs("\"\n", out);
+			fputs("\"\n", out_h);
+			break;
+		case S_HEX:
+			str = sym_get_string_value(sym);
+			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+				fprintf(out, CONFIG_PREFIX"%s=%s\n", sym->name, str);
+				fprintf(out_h, "#define "CONFIG_PREFIX"%s 0x%s\n", sym->name, str);
+				break;
+			}
+		case S_INT:
+			str = sym_get_string_value(sym);
+			fprintf(out, CONFIG_PREFIX"%s=%s\n", sym->name, str);
+			fprintf(out_h, "#define "CONFIG_PREFIX"%s %s\n", sym->name, str);
+			break;
+		default:
+			break;
+		}
+	}
+	fclose(out);
+	fclose(out_h);
+
+	name = getenv("KCONFIG_AUTOHEADER");
+	if (!name)
+		name = "include/linux/autoconf.h";
+	if (rename(".tmpconfig.h", name))
+		return 1;
+	name = getenv("KCONFIG_AUTOCONFIG");
+	if (!name)
+		name = "include/config/auto.conf";
+	/*
+	 * This must be the last step, kbuild has a dependency on auto.conf
+	 * and this marks the successful completion of the previous steps.
+	 */
+	if (rename(".tmpconfig", name))
+		return 1;
+
+	return 0;
+}
diff --git a/toybox/kconfig/expr.c b/toybox/kconfig/expr.c
new file mode 100644
index 0000000..6f98dbf
--- /dev/null
+++ b/toybox/kconfig/expr.c
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR	0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = E_SYMBOL;
+	e->left.sym = sym;
+	return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.expr = ce;
+	return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.expr = e1;
+	e->right.expr = e2;
+	return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+	struct expr *e = malloc(sizeof(*e));
+	memset(e, 0, sizeof(*e));
+	e->type = type;
+	e->left.sym = s1;
+	e->right.sym = s2;
+	return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+	if (!e1)
+		return e2;
+	return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+	if (!e1)
+		return e2;
+	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(struct expr *org)
+{
+	struct expr *e;
+
+	if (!org)
+		return NULL;
+
+	e = malloc(sizeof(*org));
+	memcpy(e, org, sizeof(*org));
+	switch (org->type) {
+	case E_SYMBOL:
+		e->left = org->left;
+		break;
+	case E_NOT:
+		e->left.expr = expr_copy(org->left.expr);
+		break;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		e->left.sym = org->left.sym;
+		e->right.sym = org->right.sym;
+		break;
+	case E_AND:
+	case E_OR:
+	case E_CHOICE:
+		e->left.expr = expr_copy(org->left.expr);
+		e->right.expr = expr_copy(org->right.expr);
+		break;
+	default:
+		printf("can't copy type %d\n", e->type);
+		free(e);
+		e = NULL;
+		break;
+	}
+
+	return e;
+}
+
+void expr_free(struct expr *e)
+{
+	if (!e)
+		return;
+
+	switch (e->type) {
+	case E_SYMBOL:
+		break;
+	case E_NOT:
+		expr_free(e->left.expr);
+		return;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		break;
+	case E_OR:
+	case E_AND:
+		expr_free(e->left.expr);
+		expr_free(e->right.expr);
+		break;
+	default:
+		printf("how to free type %d?\n", e->type);
+		break;
+	}
+	free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+	if (e1->type == type) {
+		__expr_eliminate_eq(type, &e1->left.expr, &e2);
+		__expr_eliminate_eq(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		__expr_eliminate_eq(type, &e1, &e2->left.expr);
+		__expr_eliminate_eq(type, &e1, &e2->right.expr);
+		return;
+	}
+	if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+	    e1->left.sym == e2->left.sym &&
+	    (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+		return;
+	if (!expr_eq(e1, e2))
+		return;
+	trans_count++;
+	expr_free(e1); expr_free(e2);
+	switch (type) {
+	case E_OR:
+		e1 = expr_alloc_symbol(&symbol_no);
+		e2 = expr_alloc_symbol(&symbol_no);
+		break;
+	case E_AND:
+		e1 = expr_alloc_symbol(&symbol_yes);
+		e2 = expr_alloc_symbol(&symbol_yes);
+		break;
+	default:
+		;
+	}
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+	if (!e1 || !e2)
+		return;
+	switch (e1->type) {
+	case E_OR:
+	case E_AND:
+		__expr_eliminate_eq(e1->type, ep1, ep2);
+	default:
+		;
+	}
+	if (e1->type != e2->type) switch (e2->type) {
+	case E_OR:
+	case E_AND:
+		__expr_eliminate_eq(e2->type, ep1, ep2);
+	default:
+		;
+	}
+	e1 = expr_eliminate_yn(e1);
+	e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+	int res, old_count;
+
+	if (e1->type != e2->type)
+		return 0;
+	switch (e1->type) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+		return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+	case E_SYMBOL:
+		return e1->left.sym == e2->left.sym;
+	case E_NOT:
+		return expr_eq(e1->left.expr, e2->left.expr);
+	case E_AND:
+	case E_OR:
+		e1 = expr_copy(e1);
+		e2 = expr_copy(e2);
+		old_count = trans_count;
+		expr_eliminate_eq(&e1, &e2);
+		res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+		       e1->left.sym == e2->left.sym);
+		expr_free(e1);
+		expr_free(e2);
+		trans_count = old_count;
+		return res;
+	case E_CHOICE:
+	case E_RANGE:
+	case E_NONE:
+		/* panic */;
+	}
+
+	if (DEBUG_EXPR) {
+		expr_fprint(e1, stdout);
+		printf(" = ");
+		expr_fprint(e2, stdout);
+		printf(" ?\n");
+	}
+
+	return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+	struct expr *tmp;
+
+	if (e) switch (e->type) {
+	case E_AND:
+		e->left.expr = expr_eliminate_yn(e->left.expr);
+		e->right.expr = expr_eliminate_yn(e->right.expr);
+		if (e->left.expr->type == E_SYMBOL) {
+			if (e->left.expr->left.sym == &symbol_no) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				e->right.expr = NULL;
+				return e;
+			} else if (e->left.expr->left.sym == &symbol_yes) {
+				free(e->left.expr);
+				tmp = e->right.expr;
+				*e = *(e->right.expr);
+				free(tmp);
+				return e;
+			}
+		}
+		if (e->right.expr->type == E_SYMBOL) {
+			if (e->right.expr->left.sym == &symbol_no) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				e->right.expr = NULL;
+				return e;
+			} else if (e->right.expr->left.sym == &symbol_yes) {
+				free(e->right.expr);
+				tmp = e->left.expr;
+				*e = *(e->left.expr);
+				free(tmp);
+				return e;
+			}
+		}
+		break;
+	case E_OR:
+		e->left.expr = expr_eliminate_yn(e->left.expr);
+		e->right.expr = expr_eliminate_yn(e->right.expr);
+		if (e->left.expr->type == E_SYMBOL) {
+			if (e->left.expr->left.sym == &symbol_no) {
+				free(e->left.expr);
+				tmp = e->right.expr;
+				*e = *(e->right.expr);
+				free(tmp);
+				return e;
+			} else if (e->left.expr->left.sym == &symbol_yes) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				e->right.expr = NULL;
+				return e;
+			}
+		}
+		if (e->right.expr->type == E_SYMBOL) {
+			if (e->right.expr->left.sym == &symbol_no) {
+				free(e->right.expr);
+				tmp = e->left.expr;
+				*e = *(e->left.expr);
+				free(tmp);
+				return e;
+			} else if (e->right.expr->left.sym == &symbol_yes) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				e->right.expr = NULL;
+				return e;
+			}
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_AND:
+	case E_OR:
+	case E_NOT:
+		e->left.expr = expr_trans_bool(e->left.expr);
+		e->right.expr = expr_trans_bool(e->right.expr);
+		break;
+	case E_UNEQUAL:
+		// FOO!=n -> FOO
+		if (e->left.sym->type == S_TRISTATE) {
+			if (e->right.sym == &symbol_no) {
+				e->type = E_SYMBOL;
+				e->right.sym = NULL;
+			}
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+	struct expr *tmp;
+	struct symbol *sym1, *sym2;
+
+	if (expr_eq(e1, e2))
+		return expr_copy(e1);
+	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+		return NULL;
+	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+		return NULL;
+	if (e1->type == E_NOT) {
+		tmp = e1->left.expr;
+		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+			return NULL;
+		sym1 = tmp->left.sym;
+	} else
+		sym1 = e1->left.sym;
+	if (e2->type == E_NOT) {
+		if (e2->left.expr->type != E_SYMBOL)
+			return NULL;
+		sym2 = e2->left.expr->left.sym;
+	} else
+		sym2 = e2->left.sym;
+	if (sym1 != sym2)
+		return NULL;
+	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+		return NULL;
+	if (sym1->type == S_TRISTATE) {
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+		     (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+			// (a='y') || (a='m') -> (a!='n')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+		}
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+			// (a='y') || (a='n') -> (a!='m')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+		}
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+			// (a='m') || (a='n') -> (a!='y')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+		}
+	}
+	if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+		if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+		    (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+			return expr_alloc_symbol(&symbol_yes);
+	}
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") || (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
+	return NULL;
+}
+
+struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+	struct expr *tmp;
+	struct symbol *sym1, *sym2;
+
+	if (expr_eq(e1, e2))
+		return expr_copy(e1);
+	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+		return NULL;
+	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+		return NULL;
+	if (e1->type == E_NOT) {
+		tmp = e1->left.expr;
+		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+			return NULL;
+		sym1 = tmp->left.sym;
+	} else
+		sym1 = e1->left.sym;
+	if (e2->type == E_NOT) {
+		if (e2->left.expr->type != E_SYMBOL)
+			return NULL;
+		sym2 = e2->left.expr->left.sym;
+	} else
+		sym2 = e2->left.sym;
+	if (sym1 != sym2)
+		return NULL;
+	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+		return NULL;
+
+	if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+	    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+		// (a) && (a='y') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+		// (a) && (a!='n') -> (a)
+		return expr_alloc_symbol(sym1);
+
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+		// (a) && (a!='m') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+	if (sym1->type == S_TRISTATE) {
+		if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+			sym2 = e1->right.sym;
+			if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+				return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+							     : expr_alloc_symbol(&symbol_no);
+		}
+		if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+			sym2 = e2->right.sym;
+			if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+				return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+							     : expr_alloc_symbol(&symbol_no);
+		}
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+			// (a!='y') && (a!='n') -> (a='m')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+			    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+			// (a!='y') && (a!='m') -> (a='n')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+			// (a!='m') && (a!='n') -> (a='m')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+		if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+		    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+		    (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+		    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+			return NULL;
+	}
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") && (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
+	return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	struct expr *tmp;
+
+	if (e1->type == type) {
+		expr_eliminate_dups1(type, &e1->left.expr, &e2);
+		expr_eliminate_dups1(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_eliminate_dups1(type, &e1, &e2->left.expr);
+		expr_eliminate_dups1(type, &e1, &e2->right.expr);
+		return;
+	}
+	if (e1 == e2)
+		return;
+
+	switch (e1->type) {
+	case E_OR: case E_AND:
+		expr_eliminate_dups1(e1->type, &e1, &e1);
+	default:
+		;
+	}
+
+	switch (type) {
+	case E_OR:
+		tmp = expr_join_or(e1, e2);
+		if (tmp) {
+			expr_free(e1); expr_free(e2);
+			e1 = expr_alloc_symbol(&symbol_no);
+			e2 = tmp;
+			trans_count++;
+		}
+		break;
+	case E_AND:
+		tmp = expr_join_and(e1, e2);
+		if (tmp) {
+			expr_free(e1); expr_free(e2);
+			e1 = expr_alloc_symbol(&symbol_yes);
+			e2 = tmp;
+			trans_count++;
+		}
+		break;
+	default:
+		;
+	}
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	struct expr *tmp, *tmp1, *tmp2;
+
+	if (e1->type == type) {
+		expr_eliminate_dups2(type, &e1->left.expr, &e2);
+		expr_eliminate_dups2(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_eliminate_dups2(type, &e1, &e2->left.expr);
+		expr_eliminate_dups2(type, &e1, &e2->right.expr);
+	}
+	if (e1 == e2)
+		return;
+
+	switch (e1->type) {
+	case E_OR:
+		expr_eliminate_dups2(e1->type, &e1, &e1);
+		// (FOO || BAR) && (!FOO && !BAR) -> n
+		tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+		tmp2 = expr_copy(e2);
+		tmp = expr_extract_eq_and(&tmp1, &tmp2);
+		if (expr_is_yes(tmp1)) {
+			expr_free(e1);
+			e1 = expr_alloc_symbol(&symbol_no);
+			trans_count++;
+		}
+		expr_free(tmp2);
+		expr_free(tmp1);
+		expr_free(tmp);
+		break;
+	case E_AND:
+		expr_eliminate_dups2(e1->type, &e1, &e1);
+		// (FOO && BAR) || (!FOO || !BAR) -> y
+		tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+		tmp2 = expr_copy(e2);
+		tmp = expr_extract_eq_or(&tmp1, &tmp2);
+		if (expr_is_no(tmp1)) {
+			expr_free(e1);
+			e1 = expr_alloc_symbol(&symbol_yes);
+			trans_count++;
+		}
+		expr_free(tmp2);
+		expr_free(tmp1);
+		expr_free(tmp);
+		break;
+	default:
+		;
+	}
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+	int oldcount;
+	if (!e)
+		return e;
+
+	oldcount = trans_count;
+	while (1) {
+		trans_count = 0;
+		switch (e->type) {
+		case E_OR: case E_AND:
+			expr_eliminate_dups1(e->type, &e, &e);
+			expr_eliminate_dups2(e->type, &e, &e);
+		default:
+			;
+		}
+		if (!trans_count)
+			break;
+		e = expr_eliminate_yn(e);
+	}
+	trans_count = oldcount;
+	return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+	struct expr *tmp;
+
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+	case E_SYMBOL:
+	case E_CHOICE:
+		break;
+	default:
+		e->left.expr = expr_transform(e->left.expr);
+		e->right.expr = expr_transform(e->right.expr);
+	}
+
+	switch (e->type) {
+	case E_EQUAL:
+		if (e->left.sym->type != S_BOOLEAN)
+			break;
+		if (e->right.sym == &symbol_no) {
+			e->type = E_NOT;
+			e->left.expr = expr_alloc_symbol(e->left.sym);
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_mod) {
+			printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+			e->type = E_SYMBOL;
+			e->left.sym = &symbol_no;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_yes) {
+			e->type = E_SYMBOL;
+			e->right.sym = NULL;
+			break;
+		}
+		break;
+	case E_UNEQUAL:
+		if (e->left.sym->type != S_BOOLEAN)
+			break;
+		if (e->right.sym == &symbol_no) {
+			e->type = E_SYMBOL;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_mod) {
+			printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+			e->type = E_SYMBOL;
+			e->left.sym = &symbol_yes;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_yes) {
+			e->type = E_NOT;
+			e->left.expr = expr_alloc_symbol(e->left.sym);
+			e->right.sym = NULL;
+			break;
+		}
+		break;
+	case E_NOT:
+		switch (e->left.expr->type) {
+		case E_NOT:
+			// !!a -> a
+			tmp = e->left.expr->left.expr;
+			free(e->left.expr);
+			free(e);
+			e = tmp;
+			e = expr_transform(e);
+			break;
+		case E_EQUAL:
+		case E_UNEQUAL:
+			// !a='x' -> a!='x'
+			tmp = e->left.expr;
+			free(e);
+			e = tmp;
+			e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+			break;
+		case E_OR:
+			// !(a || b) -> !a && !b
+			tmp = e->left.expr;
+			e->type = E_AND;
+			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+			tmp->type = E_NOT;
+			tmp->right.expr = NULL;
+			e = expr_transform(e);
+			break;
+		case E_AND:
+			// !(a && b) -> !a || !b
+			tmp = e->left.expr;
+			e->type = E_OR;
+			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+			tmp->type = E_NOT;
+			tmp->right.expr = NULL;
+			e = expr_transform(e);
+			break;
+		case E_SYMBOL:
+			if (e->left.expr->left.sym == &symbol_yes) {
+				// !'y' -> 'n'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				break;
+			}
+			if (e->left.expr->left.sym == &symbol_mod) {
+				// !'m' -> 'm'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_mod;
+				break;
+			}
+			if (e->left.expr->left.sym == &symbol_no) {
+				// !'n' -> 'y'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				break;
+			}
+			break;
+		default:
+			;
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+	if (!dep)
+		return 0;
+
+	switch (dep->type) {
+	case E_AND:
+	case E_OR:
+		return expr_contains_symbol(dep->left.expr, sym) ||
+		       expr_contains_symbol(dep->right.expr, sym);
+	case E_SYMBOL:
+		return dep->left.sym == sym;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		return dep->left.sym == sym ||
+		       dep->right.sym == sym;
+	case E_NOT:
+		return expr_contains_symbol(dep->left.expr, sym);
+	default:
+		;
+	}
+	return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+	if (!dep)
+		return false;
+
+	switch (dep->type) {
+	case E_AND:
+		return expr_depends_symbol(dep->left.expr, sym) ||
+		       expr_depends_symbol(dep->right.expr, sym);
+	case E_SYMBOL:
+		return dep->left.sym == sym;
+	case E_EQUAL:
+		if (dep->left.sym == sym) {
+			if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+				return true;
+		}
+		break;
+	case E_UNEQUAL:
+		if (dep->left.sym == sym) {
+			if (dep->right.sym == &symbol_no)
+				return true;
+		}
+		break;
+	default:
+		;
+	}
+ 	return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+	struct expr *tmp = NULL;
+	expr_extract_eq(E_AND, &tmp, ep1, ep2);
+	if (tmp) {
+		*ep1 = expr_eliminate_yn(*ep1);
+		*ep2 = expr_eliminate_yn(*ep2);
+	}
+	return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+	struct expr *tmp = NULL;
+	expr_extract_eq(E_OR, &tmp, ep1, ep2);
+	if (tmp) {
+		*ep1 = expr_eliminate_yn(*ep1);
+		*ep2 = expr_eliminate_yn(*ep2);
+	}
+	return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	if (e1->type == type) {
+		expr_extract_eq(type, ep, &e1->left.expr, &e2);
+		expr_extract_eq(type, ep, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_extract_eq(type, ep, ep1, &e2->left.expr);
+		expr_extract_eq(type, ep, ep1, &e2->right.expr);
+		return;
+	}
+	if (expr_eq(e1, e2)) {
+		*ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+		expr_free(e2);
+		if (type == E_AND) {
+			e1 = expr_alloc_symbol(&symbol_yes);
+			e2 = expr_alloc_symbol(&symbol_yes);
+		} else if (type == E_OR) {
+			e1 = expr_alloc_symbol(&symbol_no);
+			e2 = expr_alloc_symbol(&symbol_no);
+		}
+	}
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+	struct expr *e1, *e2;
+
+	if (!e) {
+		e = expr_alloc_symbol(sym);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	}
+	switch (e->type) {
+	case E_AND:
+		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+		if (sym == &symbol_yes)
+			e = expr_alloc_two(E_AND, e1, e2);
+		if (sym == &symbol_no)
+			e = expr_alloc_two(E_OR, e1, e2);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	case E_OR:
+		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+		if (sym == &symbol_yes)
+			e = expr_alloc_two(E_OR, e1, e2);
+		if (sym == &symbol_no)
+			e = expr_alloc_two(E_AND, e1, e2);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	case E_NOT:
+		return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+	case E_UNEQUAL:
+	case E_EQUAL:
+		if (type == E_EQUAL) {
+			if (sym == &symbol_yes)
+				return expr_copy(e);
+			if (sym == &symbol_mod)
+				return expr_alloc_symbol(&symbol_no);
+			if (sym == &symbol_no)
+				return expr_alloc_one(E_NOT, expr_copy(e));
+		} else {
+			if (sym == &symbol_yes)
+				return expr_alloc_one(E_NOT, expr_copy(e));
+			if (sym == &symbol_mod)
+				return expr_alloc_symbol(&symbol_yes);
+			if (sym == &symbol_no)
+				return expr_copy(e);
+		}
+		break;
+	case E_SYMBOL:
+		return expr_alloc_comp(type, e->left.sym, sym);
+	case E_CHOICE:
+	case E_RANGE:
+	case E_NONE:
+		/* panic */;
+	}
+	return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+	tristate val1, val2;
+	const char *str1, *str2;
+
+	if (!e)
+		return yes;
+
+	switch (e->type) {
+	case E_SYMBOL:
+		sym_calc_value(e->left.sym);
+		return e->left.sym->curr.tri;
+	case E_AND:
+		val1 = expr_calc_value(e->left.expr);
+		val2 = expr_calc_value(e->right.expr);
+		return E_AND(val1, val2);
+	case E_OR:
+		val1 = expr_calc_value(e->left.expr);
+		val2 = expr_calc_value(e->right.expr);
+		return E_OR(val1, val2);
+	case E_NOT:
+		val1 = expr_calc_value(e->left.expr);
+		return E_NOT(val1);
+	case E_EQUAL:
+		sym_calc_value(e->left.sym);
+		sym_calc_value(e->right.sym);
+		str1 = sym_get_string_value(e->left.sym);
+		str2 = sym_get_string_value(e->right.sym);
+		return !strcmp(str1, str2) ? yes : no;
+	case E_UNEQUAL:
+		sym_calc_value(e->left.sym);
+		sym_calc_value(e->right.sym);
+		str1 = sym_get_string_value(e->left.sym);
+		str2 = sym_get_string_value(e->right.sym);
+		return !strcmp(str1, str2) ? no : yes;
+	default:
+		printf("expr_calc_value: %d?\n", e->type);
+		return no;
+	}
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+	return 1;
+#else
+	if (t1 == t2)
+		return 0;
+	switch (t1) {
+	case E_EQUAL:
+	case E_UNEQUAL:
+		if (t2 == E_NOT)
+			return 1;
+	case E_NOT:
+		if (t2 == E_AND)
+			return 1;
+	case E_AND:
+		if (t2 == E_OR)
+			return 1;
+	case E_OR:
+		if (t2 == E_CHOICE)
+			return 1;
+	case E_CHOICE:
+		if (t2 == 0)
+			return 1;
+	default:
+		return -1;
+	}
+	printf("[%dgt%d?]", t1, t2);
+	return 0;
+#endif
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
+{
+	if (!e) {
+		fn(data, NULL, "y");
+		return;
+	}
+
+	if (expr_compare_type(prevtoken, e->type) > 0)
+		fn(data, NULL, "(");
+	switch (e->type) {
+	case E_SYMBOL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		break;
+	case E_NOT:
+		fn(data, NULL, "!");
+		expr_print(e->left.expr, fn, data, E_NOT);
+		break;
+	case E_EQUAL:
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, "=");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_UNEQUAL:
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, "!=");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_OR:
+		expr_print(e->left.expr, fn, data, E_OR);
+		fn(data, NULL, " || ");
+		expr_print(e->right.expr, fn, data, E_OR);
+		break;
+	case E_AND:
+		expr_print(e->left.expr, fn, data, E_AND);
+		fn(data, NULL, " && ");
+		expr_print(e->right.expr, fn, data, E_AND);
+		break;
+	case E_CHOICE:
+		fn(data, e->right.sym, e->right.sym->name);
+		if (e->left.expr) {
+			fn(data, NULL, " ^ ");
+			expr_print(e->left.expr, fn, data, E_CHOICE);
+		}
+		break;
+	case E_RANGE:
+		fn(data, NULL, "[");
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, " ");
+		fn(data, e->right.sym, e->right.sym->name);
+		fn(data, NULL, "]");
+		break;
+	default:
+	  {
+		char buf[32];
+		sprintf(buf, "<unknown type %d>", e->type);
+		fn(data, NULL, buf);
+		break;
+	  }
+	}
+	if (expr_compare_type(prevtoken, e->type) > 0)
+		fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+	fwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+	expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
+{
+	str_append((struct gstr*)data, str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+	expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
diff --git a/toybox/kconfig/expr.h b/toybox/kconfig/expr.h
new file mode 100644
index 0000000..6084525
--- /dev/null
+++ b/toybox/kconfig/expr.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+	struct file *next;
+	struct file *parent;
+	char *name;
+	int lineno;
+	int flags;
+};
+
+#define FILE_BUSY		0x0001
+#define FILE_SCANNED		0x0002
+#define FILE_PRINTED		0x0004
+
+typedef enum tristate {
+	no, mod, yes
+} tristate;
+
+enum expr_type {
+	E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+	struct expr *expr;
+	struct symbol *sym;
+};
+
+struct expr {
+	enum expr_type type;
+	union expr_data left, right;
+};
+
+#define E_OR(dep1, dep2)	(((dep1)>(dep2))?(dep1):(dep2))
+#define E_AND(dep1, dep2)	(((dep1)<(dep2))?(dep1):(dep2))
+#define E_NOT(dep)		(2-(dep))
+
+struct expr_value {
+	struct expr *expr;
+	tristate tri;
+};
+
+struct symbol_value {
+	void *val;
+	tristate tri;
+};
+
+enum symbol_type {
+	S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+enum {
+	S_DEF_USER,		/* main user value */
+	S_DEF_AUTO,
+};
+
+struct symbol {
+	struct symbol *next;
+	char *name;
+	char *help;
+	enum symbol_type type;
+	struct symbol_value curr;
+	struct symbol_value def[4];
+	tristate visible;
+	int flags;
+	struct property *prop;
+	struct expr *dep, *dep2;
+	struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_CONST		0x0001
+#define SYMBOL_CHECK		0x0008
+#define SYMBOL_CHOICE		0x0010
+#define SYMBOL_CHOICEVAL	0x0020
+#define SYMBOL_PRINTED		0x0040
+#define SYMBOL_VALID		0x0080
+#define SYMBOL_OPTIONAL		0x0100
+#define SYMBOL_WRITE		0x0200
+#define SYMBOL_CHANGED		0x0400
+#define SYMBOL_AUTO		0x1000
+#define SYMBOL_CHECKED		0x2000
+#define SYMBOL_WARNED		0x8000
+#define SYMBOL_DEF		0x10000
+#define SYMBOL_DEF_USER		0x10000
+#define SYMBOL_DEF_AUTO		0x20000
+#define SYMBOL_DEF3		0x40000
+#define SYMBOL_DEF4		0x80000
+
+#define SYMBOL_MAXLENGTH	256
+#define SYMBOL_HASHSIZE		257
+#define SYMBOL_HASHMASK		0xff
+
+enum prop_type {
+	P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE
+};
+
+struct property {
+	struct property *next;
+	struct symbol *sym;
+	enum prop_type type;
+	const char *text;
+	struct expr_value visible;
+	struct expr *expr;
+	struct menu *menu;
+	struct file *file;
+	int lineno;
+};
+
+#define for_all_properties(sym, st, tok) \
+	for (st = sym->prop; st; st = st->next) \
+		if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+	for (st = sym->prop; st; st = st->next) \
+		if (st->text)
+
+struct menu {
+	struct menu *next;
+	struct menu *parent;
+	struct menu *list;
+	struct symbol *sym;
+	struct property *prompt;
+	struct expr *dep;
+	unsigned int flags;
+	//char *help;
+	struct file *file;
+	int lineno;
+	void *data;
+};
+
+#define MENU_CHANGED		0x0001
+#define MENU_ROOT		0x0002
+
+#ifndef SWIG
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+	return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/toybox/kconfig/lex.zconf.c_shipped b/toybox/kconfig/lex.zconf.c_shipped
new file mode 100644
index 0000000..800f8c7
--- /dev/null
+++ b/toybox/kconfig/lex.zconf.c_shipped
@@ -0,0 +1,2350 @@
+
+#line 3 "scripts/kconfig/lex.zconf.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE zconfrestart(zconfin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via zconfrestart()), so that the user can continue scanning by
+	 * just pointing zconfin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file  );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size  );
+void zconf_delete_buffer (YY_BUFFER_STATE b  );
+void zconf_flush_buffer (YY_BUFFER_STATE b  );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len  );
+
+void *zconfalloc (yy_size_t  );
+void *zconfrealloc (void *,yy_size_t  );
+void zconffree (void *  );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        zconfensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        zconfensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap() 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+    {
+    {
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+    },
+
+    {
+      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
+    },
+
+    {
+       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
+    },
+
+    {
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
+    },
+
+    {
+       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
+
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
+    },
+
+    {
+       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
+    },
+
+    {
+       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
+      -18,  -18,  -18,   44,  -18,  -18,  -18
+    },
+
+    {
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+
+    },
+
+    {
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
+    },
+
+    {
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
+    },
+
+    {
+       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
+    },
+
+    {
+       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
+
+    },
+
+    {
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
+    },
+
+    {
+       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
+    },
+
+    {
+       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
+    },
+
+    {
+       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
+      -28,  -28,  -28,  -28,   53,  -28,  -28
+    },
+
+    {
+       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
+
+    },
+
+    {
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+    },
+
+    {
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
+    },
+
+    {
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
+    },
+
+    {
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
+    },
+
+    {
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
+
+    },
+
+    {
+       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
+      -35,   57,   57,   57,  -35,  -35,  -35
+    },
+
+    {
+       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
+    },
+
+    {
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
+    },
+
+    {
+       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
+      -38,  -38,  -38,  -38,  -38,  -38,   59
+    },
+
+    {
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
+
+    },
+
+    {
+       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
+    },
+
+    {
+       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
+      -44,  -44,  -44,   44,  -44,  -44,  -44
+
+    },
+
+    {
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+    },
+
+    {
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
+    },
+
+    {
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
+
+    },
+
+    {
+       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
+    },
+
+    {
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
+    },
+
+    {
+       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
+    },
+
+    {
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
+    },
+
+    {
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+
+    },
+
+    {
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
+    },
+
+    {
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
+    },
+
+    {
+       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
+      -57,   57,   57,   57,  -57,  -57,  -57
+    },
+
+    {
+       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
+    },
+
+    {
+       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
+
+    },
+
+    {
+       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
+      -60,   57,   57,   57,  -60,  -60,  -60
+    },
+
+    } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	zconfleng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[61] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    1,    7,    8,    9,
+       10,    1,    1,    1,   11,   12,   12,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,    1,    1,    1,
+       14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
+
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *zconftext;
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE	16
+
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+        struct buffer *parent;
+        YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+void new_string(void)
+{
+	text = malloc(START_STRSIZE);
+	text_asize = START_STRSIZE;
+	text_size = 0;
+	*text = 0;
+}
+
+void append_string(const char *str, int size)
+{
+	int new_size = text_size + size + 1;
+	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
+		text = realloc(text, new_size);
+		text_asize = new_size;
+	}
+	memcpy(text + text_size, str, size);
+	text_size += size;
+	text[text_size] = 0;
+}
+
+void alloc_string(const char *str, int size)
+{
+	text = malloc(size + 1);
+	memcpy(text, str, size);
+	text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( zconftext, zconfleng, 1, zconfout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	errno=0; \
+	while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+	{ \
+		if( errno != EINTR) \
+		{ \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+			break; \
+		} \
+		errno=0; \
+		clearerr(zconfin); \
+	}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+	int str = 0;
+	int ts, i;
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! zconfin )
+			zconfin = stdin;
+
+		if ( ! zconfout )
+			zconfout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			zconfensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				zconf_create_buffer(zconfin,YY_BUF_SIZE );
+		}
+
+		zconf_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of zconftext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 )
+			++yy_cp;
+
+		yy_current_state = -yy_current_state;
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+	current_file->lineno++;
+	return T_EOL;
+}
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+	BEGIN(COMMAND);
+}
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+	unput(zconftext[0]);
+	BEGIN(COMMAND);
+}
+	YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+	YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
+	YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+		str = zconftext[0];
+		new_string();
+		BEGIN(STRING);
+	}
+	YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+	YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+	YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+	}
+	YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		append_string(zconftext + 1, zconfleng - 1);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+		append_string(zconftext + 1, zconfleng - 1);
+	}
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+		if (str == zconftext[0]) {
+			BEGIN(PARAM);
+			zconflval.string = text;
+			return T_WORD_QUOTE;
+		} else
+			append_string(zconftext, 1);
+	}
+	YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		current_file->lineno++;
+		BEGIN(INITIAL);
+		return T_EOL;
+	}
+	YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+		ts = 0;
+		for (i = 0; i < zconfleng; i++) {
+			if (zconftext[i] == '\t')
+				ts = (ts & ~7) + 8;
+			else
+				ts++;
+		}
+		last_ts = ts;
+		if (first_ts) {
+			if (ts < first_ts) {
+				zconf_endhelp();
+				return T_HELPTEXT;
+			}
+			ts -= first_ts;
+			while (ts > 8) {
+				append_string("        ", 8);
+				ts -= 8;
+			}
+			append_string("        ", ts);
+		}
+	}
+	YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		current_file->lineno++;
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+		current_file->lineno++;
+		append_string("\n", 1);
+	}
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+		if (!first_ts)
+			first_ts = last_ts;
+	}
+	YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+	if (current_file) {
+		zconf_endfile();
+		return T_EOL;
+	}
+	fclose(zconfin);
+	yyterminate();
+}
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+	YY_BREAK
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed zconfin at a new source and called
+			 * zconflex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( zconfwrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * zconftext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of zconflex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			zconfrestart(zconfin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    
+	yy_current_state = yy_nxt[yy_current_state][1];
+	yy_is_jam = (yy_current_state <= 0);
+
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up zconftext */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					zconfrestart(zconfin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( zconfwrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve zconftext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void zconfrestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        zconfensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            zconf_create_buffer(zconfin,YY_BUF_SIZE );
+	}
+
+	zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+	zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void zconf_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		zconfpop_buffer_state();
+	 *		zconfpush_buffer_state(new_buffer);
+     */
+	zconfensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	zconf_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (zconfwrap()) processing, but the only time this flag
+	 * is looked at is after zconfwrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE zconf_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	zconf_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ * 
+ */
+    void zconf_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		zconffree((void *) b->yy_ch_buf  );
+
+	zconffree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+    static void zconf_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	zconf_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then zconf_init_buffer was _probably_
+     * called from zconfrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void zconf_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		zconf_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	zconfensure_buffer_stack();
+
+	/* This block is copied from zconf_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from zconf_switch_to_buffer. */
+	zconf_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void zconfpop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	zconf_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		zconf_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+	int num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	zconf_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
+{
+    
+	return zconf_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) zconfalloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = zconf_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		zconftext[zconfleng] = (yy_hold_char); \
+		(yy_c_buf_p) = zconftext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		zconfleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int zconfget_lineno  (void)
+{
+        
+    return zconflineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *zconfget_in  (void)
+{
+        return zconfin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *zconfget_out  (void)
+{
+        return zconfout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+int zconfget_leng  (void)
+{
+        return zconfleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *zconfget_text  (void)
+{
+        return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void zconfset_lineno (int  line_number )
+{
+    
+    zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE *  in_str )
+{
+        zconfin = in_str ;
+}
+
+void zconfset_out (FILE *  out_str )
+{
+        zconfout = out_str ;
+}
+
+int zconfget_debug  (void)
+{
+        return zconf_flex_debug;
+}
+
+void zconfset_debug (int  bdebug )
+{
+        zconf_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from zconflex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    zconfin = stdin;
+    zconfout = stdout;
+#else
+    zconfin = (FILE *) 0;
+    zconfout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * zconflex_init()
+     */
+    return 0;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		zconf_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		zconfpop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	zconffree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * zconflex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *zconfrealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void zconffree (void * ptr )
+{
+	free( (char *) ptr );	/* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+void zconf_starthelp(void)
+{
+	new_string();
+	last_ts = first_ts = 0;
+	BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+	zconflval.string = text;
+	BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+	char *env, fullname[PATH_MAX+1];
+	FILE *f;
+
+	f = fopen(name, "r");
+	if (!f && name[0] != '/') {
+		env = getenv(SRCTREE);
+		if (env) {
+			sprintf(fullname, "%s/%s", env, name);
+			f = fopen(fullname, "r");
+		}
+	}
+	return f;
+}
+
+void zconf_initscan(const char *name)
+{
+	zconfin = zconf_fopen(name);
+	if (!zconfin) {
+		printf("can't find file %s\n", name);
+		exit(1);
+	}
+
+	current_buf = malloc(sizeof(*current_buf));
+	memset(current_buf, 0, sizeof(*current_buf));
+
+	current_file = file_lookup(name);
+	current_file->lineno = 1;
+	current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+	struct file *file = file_lookup(name);
+	struct buffer *buf = malloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
+
+	current_buf->state = YY_CURRENT_BUFFER;
+	zconfin = zconf_fopen(name);
+	if (!zconfin) {
+		printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+		exit(1);
+	}
+	zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	if (file->flags & FILE_BUSY) {
+		printf("recursive scan (%s)?\n", name);
+		exit(1);
+	}
+	if (file->flags & FILE_SCANNED) {
+		printf("file %s already scanned?\n", name);
+		exit(1);
+	}
+	file->flags |= FILE_BUSY;
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+	struct buffer *parent;
+
+	current_file->flags |= FILE_SCANNED;
+	current_file->flags &= ~FILE_BUSY;
+	current_file = current_file->parent;
+
+	parent = current_buf->parent;
+	if (parent) {
+		fclose(zconfin);
+		zconf_delete_buffer(YY_CURRENT_BUFFER);
+		zconf_switch_to_buffer(parent->state);
+	}
+	free(current_buf);
+	current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+	return current_pos.lineno;
+}
+
+char *zconf_curname(void)
+{
+	return current_pos.file ? current_pos.file->name : "<none>";
+}
+
diff --git a/toybox/kconfig/lkc.h b/toybox/kconfig/lkc.h
new file mode 100644
index 0000000..9b629ff
--- /dev/null
+++ b/toybox/kconfig/lkc.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+// Make some warnings go away
+#define YYENABLE_NLS 0
+#define YYLTYPE_IS_TRIVIAL 0
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LKC_DIRECT_LINK
+#define P(name,type,arg)	extern type name arg
+#else
+#include "lkc_defs.h"
+#define P(name,type,arg)	extern type (*name ## _p) arg
+#endif
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+#define PACKAGE "linux"
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+
+#define TF_COMMAND	0x0001
+#define TF_PARAM	0x0002
+#define TF_OPTION	0x0004
+
+#define T_OPT_MODULES		1
+#define T_OPT_DEFCONFIG_LIST	2
+
+struct kconf_id {
+	int name;
+	int token;
+	unsigned int flags;
+	enum symbol_type stype;
+};
+
+int zconfparse(void);
+void zconfdump(FILE *out);
+
+extern int zconfdebug;
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+char *zconf_curname(void);
+
+/* confdata.c */
+char *conf_get_default_confname(void);
+
+/* kconfig_load.c */
+void kconfig_load(void);
+
+/* menu.c */
+void menu_init(void);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+
+struct gstr {
+	size_t len;
+	char  *s;
+};
+struct gstr str_new(void);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+	return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+	return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+	return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
diff --git a/toybox/kconfig/lkc_proto.h b/toybox/kconfig/lkc_proto.h
new file mode 100644
index 0000000..a263746
--- /dev/null
+++ b/toybox/kconfig/lkc_proto.h
@@ -0,0 +1,42 @@
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name, int));
+P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_visible,bool,(struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+P(sym_change_count,int,);
+
+P(sym_lookup,struct symbol *,(const char *name, int isconst));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
diff --git a/toybox/kconfig/lxdialog/BIG.FAT.WARNING b/toybox/kconfig/lxdialog/BIG.FAT.WARNING
new file mode 100644
index 0000000..a8999d8
--- /dev/null
+++ b/toybox/kconfig/lxdialog/BIG.FAT.WARNING
@@ -0,0 +1,4 @@
+This is NOT the official version of dialog.  This version has been
+significantly modified from the original.  It is for use by the Linux
+kernel configuration script.  Please do not bother Savio Lam with 
+questions about this program.
diff --git a/toybox/kconfig/lxdialog/check-lxdialog.sh b/toybox/kconfig/lxdialog/check-lxdialog.sh
new file mode 100644
index 0000000..120d624
--- /dev/null
+++ b/toybox/kconfig/lxdialog/check-lxdialog.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+	$cc -print-file-name=libncursesw.so | grep -q /
+	if [ $? -eq 0 ]; then
+		echo '-lncursesw'
+		exit
+	fi
+	$cc -print-file-name=libncurses.so | grep -q /
+	if [ $? -eq 0 ]; then
+		echo '-lncurses'
+		exit
+	fi
+	$cc -print-file-name=libcurses.so | grep -q /
+	if [ $? -eq 0 ]; then
+		echo '-lcurses'
+		exit
+	fi
+	exit 1
+}
+
+# Where is ncurses.h?
+ccflags()
+{
+	if [ -f /usr/include/ncurses/ncurses.h ]; then
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
+	elif [ -f /usr/include/ncurses/curses.h ]; then
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
+	elif [ -f /usr/include/ncurses.h ]; then
+		echo '-DCURSES_LOC="<ncurses.h>"'
+	else
+		echo '-DCURSES_LOC="<curses.h>"'
+	fi
+}
+
+# Temp file, try to clean up after us
+tmp=.lxdialog.tmp
+trap "rm -f $tmp" 0 1 2 3 15
+
+# Check if we can link to ncurses
+check() {
+	echo "main() {}" | $cc -xc - -o $tmp 2> /dev/null
+	if [ $? != 0 ]; then
+		echo " *** Unable to find the ncurses libraries."          1>&2
+		echo " *** make menuconfig require the ncurses libraries"  1>&2
+		echo " *** "                                               1>&2
+		echo " *** Install ncurses (ncurses-devel) and try again"  1>&2
+		echo " *** "                                               1>&2
+		exit 1
+	fi
+}
+
+usage() {
+	printf "Usage: $0 [-check compiler options|-header|-library]\n"
+}
+
+if [ $# == 0 ]; then
+	usage
+	exit 1
+fi
+
+cc=""
+case "$1" in
+	"-check")
+		shift
+		cc="$@"
+		check
+		;;
+	"-ccflags")
+		ccflags
+		;;
+	"-ldflags")
+		shift
+		cc="$@"
+		ldflags
+		;;
+	"*")
+		usage
+		exit 1
+		;;
+esac
diff --git a/toybox/kconfig/lxdialog/checklist.c b/toybox/kconfig/lxdialog/checklist.c
new file mode 100644
index 0000000..cf69708
--- /dev/null
+++ b/toybox/kconfig/lxdialog/checklist.c
@@ -0,0 +1,325 @@
+/*
+ *  checklist.c -- implements the checklist box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+	int i;
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, choice, 0);
+	for (i = 0; i < list_width; i++)
+		waddch(win, ' ');
+
+	wmove(win, choice, check_x);
+	wattrset(win, selected ? dlg.check_selected.atr
+		 : dlg.check.atr);
+	wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+	mvwaddch(win, choice, item_x, item_str()[0]);
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	waddstr(win, (char *)item_str() + 1);
+	if (selected) {
+		wmove(win, choice, check_x + 1);
+		wrefresh(win);
+	}
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+	     int y, int x, int height)
+{
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+
+	if ((height < item_no) && (scroll + choice < item_no - 1)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+}
+
+/*
+ *  Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, "Select", y, x, selected == 0);
+	print_button(dialog, " Help ", y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height)
+{
+	int i, x, y, box_x, box_y;
+	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+	WINDOW *dialog, *list;
+
+	/* which item to highlight */
+	item_foreach() {
+		if (item_is_tag('X'))
+			choice = item_n();
+		if (item_is_selected()) {
+			choice = item_n();
+			break;
+		}
+	}
+
+do_resize:
+	if (getmaxy(stdscr) < (height + 6))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 6))
+		return -ERRDISPLAYTOOSMALL;
+
+	max_choice = MIN(list_height, item_count());
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	list_width = width - 6;
+	box_y = height - list_height - 5;
+	box_x = (width - list_width) / 2 - 1;
+
+	/* create new window for the list */
+	list = subwin(dialog, list_height, list_width, y + box_y + 1,
+	              x + box_x + 1);
+
+	keypad(list, TRUE);
+
+	/* draw a box around the list items */
+	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+	         dlg.menubox_border.atr, dlg.menubox.atr);
+
+	/* Find length of longest item in order to center checklist */
+	check_x = 0;
+	item_foreach()
+		check_x = MAX(check_x, strlen(item_str()) + 4);
+
+	check_x = (list_width - check_x) / 2;
+	item_x = check_x + 4;
+
+	if (choice >= list_height) {
+		scroll = choice - list_height + 1;
+		choice -= scroll;
+	}
+
+	/* Print the list */
+	for (i = 0; i < max_choice; i++) {
+		item_set(scroll + i);
+		print_item(list, i, i == choice);
+	}
+
+	print_arrows(dialog, choice, item_count(), scroll,
+		     box_y, box_x + check_x + 5, list_height);
+
+	print_buttons(dialog, height, width, 0);
+
+	wnoutrefresh(dialog);
+	wnoutrefresh(list);
+	doupdate();
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		for (i = 0; i < max_choice; i++) {
+			item_set(i + scroll);
+			if (toupper(key) == toupper(item_str()[0]))
+				break;
+		}
+
+		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+		    key == '+' || key == '-') {
+			if (key == KEY_UP || key == '-') {
+				if (!choice) {
+					if (!scroll)
+						continue;
+					/* Scroll list down */
+					if (list_height > 1) {
+						/* De-highlight current first item */
+						item_set(scroll);
+						print_item(list, 0, FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, -1);
+						scrollok(list, FALSE);
+					}
+					scroll--;
+					item_set(scroll);
+					print_item(list, 0, TRUE);
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice - 1;
+			} else if (key == KEY_DOWN || key == '+') {
+				if (choice == max_choice - 1) {
+					if (scroll + choice >= item_count() - 1)
+						continue;
+					/* Scroll list up */
+					if (list_height > 1) {
+						/* De-highlight current last item before scrolling up */
+						item_set(scroll + max_choice - 1);
+						print_item(list,
+							    max_choice - 1,
+							    FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, 1);
+						scrollok(list, FALSE);
+					}
+					scroll++;
+					item_set(scroll + max_choice - 1);
+					print_item(list, max_choice - 1, TRUE);
+
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice + 1;
+			}
+			if (i != choice) {
+				/* De-highlight current item */
+				item_set(scroll + choice);
+				print_item(list, choice, FALSE);
+				/* Highlight new item */
+				choice = i;
+				item_set(scroll + choice);
+				print_item(list, choice, TRUE);
+				wnoutrefresh(dialog);
+				wrefresh(list);
+			}
+			continue;	/* wait for another key press */
+		}
+		switch (key) {
+		case 'H':
+		case 'h':
+		case '?':
+			button = 1;
+			/* fall-through */
+		case 'S':
+		case 's':
+		case ' ':
+		case '\n':
+			item_foreach()
+				item_set_selected(0);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			delwin(list);
+			delwin(dialog);
+			return button;
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(list);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+
+		/* Now, update everything... */
+		doupdate();
+	}
+	delwin(list);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/toybox/kconfig/lxdialog/dialog.h b/toybox/kconfig/lxdialog/dialog.h
new file mode 100644
index 0000000..fd695e1
--- /dev/null
+++ b/toybox/kconfig/lxdialog/dialog.h
@@ -0,0 +1,224 @@
+/*
+ *  dialog.h -- common declarations for all dialog modules
+ *
+ *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked.  This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses.  The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef  wbkgdset
+#define wbkgdset(w,p)		/*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ *   Color definitions
+ */
+struct dialog_color {
+	chtype atr;	/* Color attribute */
+	int fg;		/* foreground */
+	int bg;		/* background */
+	int hl;		/* highlight this item */
+};
+
+struct dialog_info {
+	const char *backtitle;
+	struct dialog_color screen;
+	struct dialog_color shadow;
+	struct dialog_color dialog;
+	struct dialog_color title;
+	struct dialog_color border;
+	struct dialog_color button_active;
+	struct dialog_color button_inactive;
+	struct dialog_color button_key_active;
+	struct dialog_color button_key_inactive;
+	struct dialog_color button_label_active;
+	struct dialog_color button_label_inactive;
+	struct dialog_color inputbox;
+	struct dialog_color inputbox_border;
+	struct dialog_color searchbox;
+	struct dialog_color searchbox_title;
+	struct dialog_color searchbox_border;
+	struct dialog_color position_indicator;
+	struct dialog_color menubox;
+	struct dialog_color menubox_border;
+	struct dialog_color item;
+	struct dialog_color item_selected;
+	struct dialog_color tag;
+	struct dialog_color tag_selected;
+	struct dialog_color tag_key;
+	struct dialog_color tag_key_selected;
+	struct dialog_color check;
+	struct dialog_color check_selected;
+	struct dialog_color uarrow;
+	struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+	char str[MAXITEMSTR];	/* promtp displayed */
+	char tag;
+	void *data;	/* pointer to menu item - used by menubox+checklist */
+	int selected;	/* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+	struct dialog_item node;
+	struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+	for (item_cur = item_head ? item_head: item_cur; \
+	     item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+void init_dialog(const char *backtitle);
+void reset_dialog(void);
+void end_dialog(void);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+	      chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+		  int width, int pause);
+int dialog_textbox(const char *title, const char *file, int height, int width);
+int dialog_menu(const char *title, const char *prompt,
+		const void *selected, int *s_scroll);
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height);
+extern char dialog_input_result[];
+int dialog_inputbox(const char *title, const char *prompt, int height,
+		    int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ *   -- the first 32 are used as numbers, in addition to '0'-'9'
+ *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
diff --git a/toybox/kconfig/lxdialog/inputbox.c b/toybox/kconfig/lxdialog/inputbox.c
new file mode 100644
index 0000000..05e7206
--- /dev/null
+++ b/toybox/kconfig/lxdialog/inputbox.c
@@ -0,0 +1,238 @@
+/*
+ *  inputbox.c -- implements the input box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ *  Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, "  Ok  ", y, x, selected == 0);
+	print_button(dialog, " Help ", y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+                    const char *init)
+{
+	int i, x, y, box_y, box_x, box_width;
+	int input_x = 0, scroll = 0, key = 0, button = -1;
+	char *instr = dialog_input_result;
+	WINDOW *dialog;
+
+	if (!init)
+		instr[0] = '\0';
+	else
+		strcpy(instr, init);
+
+do_resize:
+	if (getmaxy(stdscr) <= (height - 2))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) <= (width - 2))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	/* Draw the input field box */
+	box_width = width - 6;
+	getyx(dialog, y, x);
+	box_y = y + 2;
+	box_x = (width - box_width) / 2;
+	draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+		 dlg.border.atr, dlg.dialog.atr);
+
+	print_buttons(dialog, height, width, 0);
+
+	/* Set up the initial value */
+	wmove(dialog, box_y, box_x);
+	wattrset(dialog, dlg.inputbox.atr);
+
+	input_x = strlen(instr);
+
+	if (input_x >= box_width) {
+		scroll = input_x - box_width + 1;
+		input_x = box_width - 1;
+		for (i = 0; i < box_width - 1; i++)
+			waddch(dialog, instr[scroll + i]);
+	} else {
+		waddstr(dialog, instr);
+	}
+
+	wmove(dialog, box_y, box_x + input_x);
+
+	wrefresh(dialog);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		if (button == -1) {	/* Input box selected */
+			switch (key) {
+			case TAB:
+			case KEY_UP:
+			case KEY_DOWN:
+				break;
+			case KEY_LEFT:
+				continue;
+			case KEY_RIGHT:
+				continue;
+			case KEY_BACKSPACE:
+			case 127:
+				if (input_x || scroll) {
+					wattrset(dialog, dlg.inputbox.atr);
+					if (!input_x) {
+						scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++)
+							waddch(dialog,
+							       instr[scroll + input_x + i] ?
+							       instr[scroll + input_x + i] : ' ');
+						input_x = strlen(instr) - scroll;
+					} else
+						input_x--;
+					instr[scroll + input_x] = '\0';
+					mvwaddch(dialog, box_y, input_x + box_x, ' ');
+					wmove(dialog, box_y, input_x + box_x);
+					wrefresh(dialog);
+				}
+				continue;
+			default:
+				if (key < 0x100 && isprint(key)) {
+					if (scroll + input_x < MAX_LEN) {
+						wattrset(dialog, dlg.inputbox.atr);
+						instr[scroll + input_x] = key;
+						instr[scroll + input_x + 1] = '\0';
+						if (input_x == box_width - 1) {
+							scroll++;
+							wmove(dialog, box_y, box_x);
+							for (i = 0; i < box_width - 1; i++)
+								waddch(dialog, instr [scroll + i]);
+						} else {
+							wmove(dialog, box_y, input_x++ + box_x);
+							waddch(dialog, key);
+						}
+						wrefresh(dialog);
+					} else
+						flash();	/* Alarm user about overflow */
+					continue;
+				}
+			}
+		}
+		switch (key) {
+		case 'O':
+		case 'o':
+			delwin(dialog);
+			return 0;
+		case 'H':
+		case 'h':
+			delwin(dialog);
+			return 1;
+		case KEY_UP:
+		case KEY_LEFT:
+			switch (button) {
+			case -1:
+				button = 1;	/* Indicates "Cancel" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 0:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			case 1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			}
+			break;
+		case TAB:
+		case KEY_DOWN:
+		case KEY_RIGHT:
+			switch (button) {
+			case -1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			case 0:
+				button = 1;	/* Indicates "Cancel" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 1:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			}
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return (button == -1 ? 0 : button);
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return KEY_ESC;		/* ESC pressed */
+}
diff --git a/toybox/kconfig/lxdialog/menubox.c b/toybox/kconfig/lxdialog/menubox.c
new file mode 100644
index 0000000..0d83159
--- /dev/null
+++ b/toybox/kconfig/lxdialog/menubox.c
@@ -0,0 +1,434 @@
+/*
+ *  menubox.c -- implements the menu box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Changes by Clifford Wolf (god@clifford.at)
+ *
+ *  [ 1998-06-13 ]
+ *
+ *    *)  A bugfix for the Page-Down problem
+ *
+ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set 
+ *        to the first position in the menu box.  Now lxdialog is a bit
+ *        smarter and works more like other menu systems (just have a look at
+ *        it).
+ *
+ *    *)  Formerly if I selected something my scrolling would be broken because
+ *        lxdialog is re-invoked by the Menuconfig shell script, can't
+ *        remember the last scrolling position, and just sets it so that the
+ *        cursor is at the bottom of the box.  Now it writes the temporary file
+ *        lxdialog.scrltmp which contains this information. The file is
+ *        deleted by lxdialog if the user leaves a submenu or enters a new
+ *        one, but it would be nice if Menuconfig could make another "rm -f"
+ *        just to be sure.  Just try it out - you will recognise a difference!
+ *
+ *  [ 1998-06-14 ]
+ *
+ *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ *        and menus change their size on the fly.
+ *
+ *    *)  If for some reason the last scrolling position is not saved by
+ *        lxdialog, it sets the scrolling so that the selected item is in the
+ *        middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+                          int selected, int hotkey)
+{
+	int j;
+	char *menu_item = malloc(menu_width + 1);
+
+	strncpy(menu_item, item, menu_width - item_x);
+	menu_item[menu_width - item_x] = '\0';
+	j = first_alpha(menu_item, "YyNnMmHh");
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, line_y, 0);
+#if OLD_NCURSES
+	{
+		int i;
+		for (i = 0; i < menu_width; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	mvwaddstr(win, line_y, item_x, menu_item);
+	if (hotkey) {
+		wattrset(win, selected ? dlg.tag_key_selected.atr
+			 : dlg.tag_key.atr);
+		mvwaddch(win, line_y, item_x + j, menu_item[j]);
+	}
+	if (selected) {
+		wmove(win, line_y, item_x + 1);
+	}
+	free(menu_item);
+	wrefresh(win);
+}
+
+#define print_item(index, choice, selected)				\
+do {									\
+	item_set(index);						\
+	do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+			 int height)
+{
+	int cur_y, cur_x;
+
+	getyx(win, cur_y, cur_x);
+
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+	wrefresh(win);
+
+	if ((height < item_no) && (scroll + height < item_no)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	wmove(win, cur_y, cur_x);
+	wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+	int x = width / 2 - 16;
+	int y = height - 2;
+
+	print_button(win, "Select", y, x, selected == 0);
+	print_button(win, " Exit ", y, x + 12, selected == 1);
+	print_button(win, " Help ", y, x + 24, selected == 2);
+
+	wmove(win, y, x + 1 + 12 * selected);
+	wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+	/* Scroll menu up */
+	scrollok(win, TRUE);
+	wscrl(win, n);
+	scrollok(win, FALSE);
+	*scroll = *scroll + n;
+	wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt,
+                const void *selected, int *s_scroll)
+{
+	int i, j, x, y, box_x, box_y;
+	int height, width, menu_height;
+	int key = 0, button = 0, scroll = 0, choice = 0;
+	int first_item =  0, max_choice;
+	WINDOW *dialog, *menu;
+
+do_resize:
+	height = getmaxy(stdscr);
+	width = getmaxx(stdscr);
+	if (height < 15 || width < 65)
+		return -ERRDISPLAYTOOSMALL;
+
+	height -= 4;
+	width  -= 5;
+	menu_height = height - 10;
+
+	max_choice = MIN(menu_height, item_count());
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	menu_width = width - 6;
+	box_y = height - menu_height - 5;
+	box_x = (width - menu_width) / 2 - 1;
+
+	/* create new window for the menu */
+	menu = subwin(dialog, menu_height, menu_width,
+		      y + box_y + 1, x + box_x + 1);
+	keypad(menu, TRUE);
+
+	/* draw a box around the menu items */
+	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	if (menu_width >= 80)
+		item_x = (menu_width - 70) / 2;
+	else
+		item_x = 4;
+
+	/* Set choice to default item */
+	item_foreach()
+		if (selected && (selected == item_data()))
+			choice = item_n();
+	/* get the saved scroll info */
+	scroll = *s_scroll;
+	if ((scroll <= choice) && (scroll + max_choice > choice) &&
+	   (scroll >= 0) && (scroll + max_choice <= item_count())) {
+		first_item = scroll;
+		choice = choice - scroll;
+	} else {
+		scroll = 0;
+	}
+	if ((choice >= max_choice)) {
+		if (choice >= item_count() - max_choice / 2)
+			scroll = first_item = item_count() - max_choice;
+		else
+			scroll = first_item = choice - max_choice / 2;
+		choice = choice - scroll;
+	}
+
+	/* Print the menu */
+	for (i = 0; i < max_choice; i++) {
+		print_item(first_item + i, i, i == choice);
+	}
+
+	wnoutrefresh(menu);
+
+	print_arrows(dialog, item_count(), scroll,
+		     box_y, box_x + item_x + 1, menu_height);
+
+	print_buttons(dialog, height, width, 0);
+	wmove(menu, choice, item_x + 1);
+	wrefresh(menu);
+
+	while (key != KEY_ESC) {
+		key = wgetch(menu);
+
+		if (key < 256 && isalpha(key))
+			key = tolower(key);
+
+		if (strchr("ynmh", key))
+			i = max_choice;
+		else {
+			for (i = choice + 1; i < max_choice; i++) {
+				item_set(scroll + i);
+				j = first_alpha(item_str(), "YyNnMmHh");
+				if (key == tolower(item_str()[j]))
+					break;
+			}
+			if (i == max_choice)
+				for (i = 0; i < max_choice; i++) {
+					item_set(scroll + i);
+					j = first_alpha(item_str(), "YyNnMmHh");
+					if (key == tolower(item_str()[j]))
+						break;
+				}
+		}
+
+		if (i < max_choice ||
+		    key == KEY_UP || key == KEY_DOWN ||
+		    key == '-' || key == '+' ||
+		    key == KEY_PPAGE || key == KEY_NPAGE) {
+			/* Remove highligt of current item */
+			print_item(scroll + choice, choice, FALSE);
+
+			if (key == KEY_UP || key == '-') {
+				if (choice < 2 && scroll) {
+					/* Scroll menu down */
+					do_scroll(menu, &scroll, -1);
+
+					print_item(scroll, 0, FALSE);
+				} else
+					choice = MAX(choice - 1, 0);
+
+			} else if (key == KEY_DOWN || key == '+') {
+				print_item(scroll+choice, choice, FALSE);
+
+				if ((choice > max_choice - 3) &&
+				    (scroll + max_choice < item_count())) {
+					/* Scroll menu up */
+					do_scroll(menu, &scroll, 1);
+
+					print_item(scroll+max_choice - 1,
+						   max_choice - 1, FALSE);
+				} else
+					choice = MIN(choice + 1, max_choice - 1);
+
+			} else if (key == KEY_PPAGE) {
+				scrollok(menu, TRUE);
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll > 0) {
+						do_scroll(menu, &scroll, -1);
+						print_item(scroll, 0, FALSE);
+					} else {
+						if (choice > 0)
+							choice--;
+					}
+				}
+
+			} else if (key == KEY_NPAGE) {
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll + max_choice < item_count()) {
+						do_scroll(menu, &scroll, 1);
+						print_item(scroll+max_choice-1,
+							   max_choice - 1, FALSE);
+					} else {
+						if (choice + 1 < max_choice)
+							choice++;
+					}
+				}
+			} else
+				choice = i;
+
+			print_item(scroll + choice, choice, TRUE);
+
+			print_arrows(dialog, item_count(), scroll,
+				     box_y, box_x + item_x + 1, menu_height);
+
+			wnoutrefresh(dialog);
+			wrefresh(menu);
+
+			continue;	/* wait for another key press */
+		}
+
+		switch (key) {
+		case KEY_LEFT:
+		case TAB:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 2 : (button > 2 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(menu);
+			break;
+		case ' ':
+		case 's':
+		case 'y':
+		case 'n':
+		case 'm':
+		case '/':
+			/* save scroll info */
+			*s_scroll = scroll;
+			delwin(menu);
+			delwin(dialog);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			switch (key) {
+			case 's':
+				return 3;
+			case 'y':
+				return 3;
+			case 'n':
+				return 4;
+			case 'm':
+				return 5;
+			case ' ':
+				return 6;
+			case '/':
+				return 7;
+			}
+			return 0;
+		case 'h':
+		case '?':
+			button = 2;
+		case '\n':
+			*s_scroll = scroll;
+			delwin(menu);
+			delwin(dialog);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			return button;
+		case 'e':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(menu);
+			break;
+		case KEY_RESIZE:
+			on_key_resize();
+			delwin(menu);
+			delwin(dialog);
+			goto do_resize;
+		}
+	}
+	delwin(menu);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/toybox/kconfig/lxdialog/textbox.c b/toybox/kconfig/lxdialog/textbox.c
new file mode 100644
index 0000000..fabfc1a
--- /dev/null
+++ b/toybox/kconfig/lxdialog/textbox.c
@@ -0,0 +1,391 @@
+/*
+ *  textbox.c -- implements the text box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW * win, int height, int width);
+static void print_line(WINDOW * win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static const char *buf;
+static const char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+							  int cur_y, int cur_x)
+{
+	print_page(box, boxh, boxw);
+	print_position(dialog);
+	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+	wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(const char *title, const char *tbuf,
+		   int initial_height, int initial_width)
+{
+	int i, x, y, cur_x, cur_y, key = 0;
+	int height, width, boxh, boxw;
+	int passed_end;
+	WINDOW *dialog, *box;
+
+	begin_reached = 1;
+	end_reached = 0;
+	page_length = 0;
+	hscroll = 0;
+	buf = tbuf;
+	page = buf;	/* page is pointer to start of page to be displayed */
+
+do_resize:
+	getmaxyx(stdscr, height, width);
+	if (height < 8 || width < 8)
+		return -ERRDISPLAYTOOSMALL;
+	if (initial_height != 0)
+		height = initial_height;
+	else
+		if (height > 4)
+			height -= 4;
+		else
+			height = 0;
+	if (initial_width != 0)
+		width = initial_width;
+	else
+		if (width > 5)
+			width -= 5;
+		else
+			width = 0;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	/* Create window for box region, used for scrolling text */
+	boxh = height - 4;
+	boxw = width - 2;
+	box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+	wattrset(box, dlg.dialog.atr);
+	wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+	keypad(box, TRUE);
+
+	/* register the new window, along with its borders */
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
+	wnoutrefresh(dialog);
+	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
+
+	/* Print first page of text */
+	attr_clear(box, boxh, boxw, dlg.dialog.atr);
+	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+
+	while ((key != KEY_ESC) && (key != '\n')) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'E':	/* Exit */
+		case 'e':
+		case 'X':
+		case 'x':
+			delwin(box);
+			delwin(dialog);
+			return 0;
+		case 'g':	/* First page */
+		case KEY_HOME:
+			if (!begin_reached) {
+				begin_reached = 1;
+				page = buf;
+				refresh_text_box(dialog, box, boxh, boxw,
+						 cur_y, cur_x);
+			}
+			break;
+		case 'G':	/* Last page */
+		case KEY_END:
+
+			end_reached = 1;
+			/* point to last char in buf */
+			page = buf + strlen(buf);
+			back_lines(boxh);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'K':	/* Previous line */
+		case 'k':
+		case KEY_UP:
+			if (!begin_reached) {
+				back_lines(page_length + 1);
+
+				/* We don't call print_page() here but use
+				 * scrolling to ensure faster screen update.
+				 * However, 'end_reached' and 'page_length'
+				 * should still be updated, and 'page' should
+				 * point to start of next page. This is done
+				 * by calling get_line() in the following
+				 * 'for' loop. */
+				scrollok(box, TRUE);
+				wscrl(box, -1);	/* Scroll box region down one line */
+				scrollok(box, FALSE);
+				page_length = 0;
+				passed_end = 0;
+				for (i = 0; i < boxh; i++) {
+					if (!i) {
+						/* print first line of page */
+						print_line(box, 0, boxw);
+						wnoutrefresh(box);
+					} else
+						/* Called to update 'end_reached' and 'page' */
+						get_line();
+					if (!passed_end)
+						page_length++;
+					if (end_reached && !passed_end)
+						passed_end = 1;
+				}
+
+				print_position(dialog);
+				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+				wrefresh(dialog);
+			}
+			break;
+		case 'B':	/* Previous page */
+		case 'b':
+		case KEY_PPAGE:
+			if (begin_reached)
+				break;
+			back_lines(page_length + boxh);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'J':	/* Next line */
+		case 'j':
+		case KEY_DOWN:
+			if (!end_reached) {
+				begin_reached = 0;
+				scrollok(box, TRUE);
+				scroll(box);	/* Scroll box region up one line */
+				scrollok(box, FALSE);
+				print_line(box, boxh - 1, boxw);
+				wnoutrefresh(box);
+				print_position(dialog);
+				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+				wrefresh(dialog);
+			}
+			break;
+		case KEY_NPAGE:	/* Next page */
+		case ' ':
+			if (end_reached)
+				break;
+
+			begin_reached = 0;
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case '0':	/* Beginning of line */
+		case 'H':	/* Scroll left */
+		case 'h':
+		case KEY_LEFT:
+			if (hscroll <= 0)
+				break;
+
+			if (key == '0')
+				hscroll = 0;
+			else
+				hscroll--;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case 'L':	/* Scroll right */
+		case 'l':
+		case KEY_RIGHT:
+			if (hscroll >= MAX_LEN)
+				break;
+			hscroll++;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			back_lines(height);
+			delwin(box);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+	delwin(box);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+	int i;
+
+	begin_reached = 0;
+	/* Go back 'n' lines */
+	for (i = 0; i < n; i++) {
+		if (*page == '\0') {
+			if (end_reached) {
+				end_reached = 0;
+				continue;
+			}
+		}
+		if (page == buf) {
+			begin_reached = 1;
+			return;
+		}
+		page--;
+		do {
+			if (page == buf) {
+				begin_reached = 1;
+				return;
+			}
+			page--;
+		} while (*page != '\n');
+		page++;
+	}
+}
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+static void print_page(WINDOW * win, int height, int width)
+{
+	int i, passed_end = 0;
+
+	page_length = 0;
+	for (i = 0; i < height; i++) {
+		print_line(win, i, width);
+		if (!passed_end)
+			page_length++;
+		if (end_reached && !passed_end)
+			passed_end = 1;
+	}
+	wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text. Called by dialog_textbox() and print_page().
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+	int y, x;
+	char *line;
+
+	line = get_line();
+	line += MIN(strlen(line), hscroll);	/* Scroll horizontally */
+	wmove(win, row, 0);	/* move cursor to correct line */
+	waddch(win, ' ');
+	waddnstr(win, line, MIN(strlen(line), width - 2));
+
+	getyx(win, y, x);
+	/* Clear 'residue' of previous line */
+#if OLD_NCURSES
+	{
+		int i;
+		for (i = 0; i < width - x; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+	int i = 0;
+	static char line[MAX_LEN + 1];
+
+	end_reached = 0;
+	while (*page != '\n') {
+		if (*page == '\0') {
+			if (!end_reached) {
+				end_reached = 1;
+				break;
+			}
+		} else if (i < MAX_LEN)
+			line[i++] = *(page++);
+		else {
+			/* Truncate lines longer than MAX_LEN characters */
+			if (i == MAX_LEN)
+				line[i++] = '\0';
+			page++;
+		}
+	}
+	if (i <= MAX_LEN)
+		line[i] = '\0';
+	if (!end_reached)
+		page++;		/* move pass '\n' */
+
+	return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win)
+{
+	int percent;
+
+	wattrset(win, dlg.position_indicator.atr);
+	wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+	percent = (page - buf) * 100 / strlen(buf);
+	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+	wprintw(win, "(%3d%%)", percent);
+}
diff --git a/toybox/kconfig/lxdialog/util.c b/toybox/kconfig/lxdialog/util.c
new file mode 100644
index 0000000..ebc781b
--- /dev/null
+++ b/toybox/kconfig/lxdialog/util.c
@@ -0,0 +1,642 @@
+/*
+ *  util.c
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+	dlg.screen.atr = A_NORMAL;
+	dlg.shadow.atr = A_NORMAL;
+	dlg.dialog.atr = A_NORMAL;
+	dlg.title.atr = A_BOLD;
+	dlg.border.atr = A_NORMAL;
+	dlg.button_active.atr = A_REVERSE;
+	dlg.button_inactive.atr = A_DIM;
+	dlg.button_key_active.atr = A_REVERSE;
+	dlg.button_key_inactive.atr = A_BOLD;
+	dlg.button_label_active.atr = A_REVERSE;
+	dlg.button_label_inactive.atr = A_NORMAL;
+	dlg.inputbox.atr = A_NORMAL;
+	dlg.inputbox_border.atr = A_NORMAL;
+	dlg.searchbox.atr = A_NORMAL;
+	dlg.searchbox_title.atr = A_BOLD;
+	dlg.searchbox_border.atr = A_NORMAL;
+	dlg.position_indicator.atr = A_BOLD;
+	dlg.menubox.atr = A_NORMAL;
+	dlg.menubox_border.atr = A_NORMAL;
+	dlg.item.atr = A_NORMAL;
+	dlg.item_selected.atr = A_REVERSE;
+	dlg.tag.atr = A_BOLD;
+	dlg.tag_selected.atr = A_REVERSE;
+	dlg.tag_key.atr = A_BOLD;
+	dlg.tag_key_selected.atr = A_REVERSE;
+	dlg.check.atr = A_BOLD;
+	dlg.check_selected.atr = A_REVERSE;
+	dlg.uarrow.atr = A_BOLD;
+	dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do {                               \
+	dlg.dialog.fg = (f);       \
+	dlg.dialog.bg = (b);       \
+	dlg.dialog.hl = (h);       \
+} while (0)
+
+static void set_classic_theme(void)
+{
+	DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
+	DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
+	DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
+	DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
+	DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+	DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+}
+
+static void set_blackbg_theme(void)
+{
+	DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
+	DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+	DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
+	DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+	DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
+	DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
+
+	DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
+	DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
+
+	DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
+
+	DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+	DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+	set_classic_theme();
+	DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
+	DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
+	DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+	int use_color = 1;
+	if (!theme)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "classic") == 0)
+		set_classic_theme();
+	else if (strcmp(theme, "bluetitle") == 0)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "blackbg") == 0)
+		set_blackbg_theme();
+	else if (strcmp(theme, "mono") == 0)
+		use_color = 0;
+
+	return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+	static int pair = 0;
+
+	pair++;
+	init_pair(pair, color->fg, color->bg);
+	if (color->hl)
+		color->atr = A_BOLD | COLOR_PAIR(pair);
+	else
+		color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+	init_one_color(&dlg.screen);
+	init_one_color(&dlg.shadow);
+	init_one_color(&dlg.dialog);
+	init_one_color(&dlg.title);
+	init_one_color(&dlg.border);
+	init_one_color(&dlg.button_active);
+	init_one_color(&dlg.button_inactive);
+	init_one_color(&dlg.button_key_active);
+	init_one_color(&dlg.button_key_inactive);
+	init_one_color(&dlg.button_label_active);
+	init_one_color(&dlg.button_label_inactive);
+	init_one_color(&dlg.inputbox);
+	init_one_color(&dlg.inputbox_border);
+	init_one_color(&dlg.searchbox);
+	init_one_color(&dlg.searchbox_title);
+	init_one_color(&dlg.searchbox_border);
+	init_one_color(&dlg.position_indicator);
+	init_one_color(&dlg.menubox);
+	init_one_color(&dlg.menubox_border);
+	init_one_color(&dlg.item);
+	init_one_color(&dlg.item_selected);
+	init_one_color(&dlg.tag);
+	init_one_color(&dlg.tag_selected);
+	init_one_color(&dlg.tag_key);
+	init_one_color(&dlg.tag_key_selected);
+	init_one_color(&dlg.check);
+	init_one_color(&dlg.check_selected);
+	init_one_color(&dlg.uarrow);
+	init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+	if (set_theme(theme)) {
+		if (has_colors()) {	/* Terminal supports color? */
+			start_color();
+			init_dialog_colors();
+		}
+	}
+	else
+	{
+		set_mono_theme();
+	}
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+	int i, j;
+
+	wattrset(win, attr);
+	for (i = 0; i < height; i++) {
+		wmove(win, i, 0);
+		for (j = 0; j < width; j++)
+			waddch(win, ' ');
+	}
+	touchwin(win);
+}
+
+void dialog_clear(void)
+{
+	attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+	/* Display background title if it exists ... - SLH */
+	if (dlg.backtitle != NULL) {
+		int i;
+
+		wattrset(stdscr, dlg.screen.atr);
+		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+		wmove(stdscr, 1, 1);
+		for (i = 1; i < COLS - 1; i++)
+			waddch(stdscr, ACS_HLINE);
+	}
+	wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+void init_dialog(const char *backtitle)
+{
+	dlg.backtitle = backtitle;
+	color_setup(getenv("MENUCONFIG_COLOR"));
+}
+
+void reset_dialog(void)
+{
+	initscr();		/* Init curses */
+	keypad(stdscr, TRUE);
+	cbreak();
+	noecho();
+	dialog_clear();
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(void)
+{
+	endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+	if (title) {
+		int tlen = MIN(width - 2, strlen(title));
+		wattrset(dialog, dlg.title.atr);
+		mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+		mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+		waddch(dialog, ' ');
+	}
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces.  We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+	int newl, cur_x, cur_y;
+	int i, prompt_len, room, wlen;
+	char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+	strcpy(tempstr, prompt);
+
+	prompt_len = strlen(tempstr);
+
+	/*
+	 * Remove newlines
+	 */
+	for (i = 0; i < prompt_len; i++) {
+		if (tempstr[i] == '\n')
+			tempstr[i] = ' ';
+	}
+
+	if (prompt_len <= width - x * 2) {	/* If prompt is short */
+		wmove(win, y, (width - prompt_len) / 2);
+		waddstr(win, tempstr);
+	} else {
+		cur_x = x;
+		cur_y = y;
+		newl = 1;
+		word = tempstr;
+		while (word && *word) {
+			sp = index(word, ' ');
+			if (sp)
+				*sp++ = 0;
+
+			/* Wrap to next line if either the word does not fit,
+			   or it is the first word of a new sentence, and it is
+			   short, and the next word does not fit. */
+			room = width - cur_x;
+			wlen = strlen(word);
+			if (wlen > room ||
+			    (newl && wlen < 4 && sp
+			     && wlen + 1 + strlen(sp) > room
+			     && (!(sp2 = index(sp, ' '))
+				 || wlen + 1 + (sp2 - sp) > room))) {
+				cur_y++;
+				cur_x = x;
+			}
+			wmove(win, cur_y, cur_x);
+			waddstr(win, word);
+			getyx(win, cur_y, cur_x);
+			cur_x++;
+			if (sp && *sp == ' ') {
+				cur_x++;	/* double space */
+				while (*++sp == ' ') ;
+				newl = 1;
+			} else
+				newl = 0;
+			word = sp;
+		}
+	}
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+	int i, temp;
+
+	wmove(win, y, x);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, "<");
+	temp = strspn(label, " ");
+	label += temp;
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	for (i = 0; i < temp; i++)
+		waddch(win, ' ');
+	wattrset(win, selected ? dlg.button_key_active.atr
+		 : dlg.button_key_inactive.atr);
+	waddch(win, label[0]);
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	waddstr(win, (char *)label + 1);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, ">");
+	wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+	 chtype box, chtype border)
+{
+	int i, j;
+
+	wattrset(win, 0);
+	for (i = 0; i < height; i++) {
+		wmove(win, y + i, x);
+		for (j = 0; j < width; j++)
+			if (!i && !j)
+				waddch(win, border | ACS_ULCORNER);
+			else if (i == height - 1 && !j)
+				waddch(win, border | ACS_LLCORNER);
+			else if (!i && j == width - 1)
+				waddch(win, box | ACS_URCORNER);
+			else if (i == height - 1 && j == width - 1)
+				waddch(win, box | ACS_LRCORNER);
+			else if (!i)
+				waddch(win, border | ACS_HLINE);
+			else if (i == height - 1)
+				waddch(win, box | ACS_HLINE);
+			else if (!j)
+				waddch(win, border | ACS_VLINE);
+			else if (j == width - 1)
+				waddch(win, box | ACS_VLINE);
+			else
+				waddch(win, box | ' ');
+	}
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+	int i;
+
+	if (has_colors()) {	/* Whether terminal supports color? */
+		wattrset(win, dlg.shadow.atr);
+		wmove(win, y + height, x + 2);
+		for (i = 0; i < width; i++)
+			waddch(win, winch(win) & A_CHARTEXT);
+		for (i = y + 1; i < y + height + 1; i++) {
+			wmove(win, i, x + width);
+			waddch(win, winch(win) & A_CHARTEXT);
+			waddch(win, winch(win) & A_CHARTEXT);
+		}
+		wnoutrefresh(win);
+	}
+}
+
+/*
+ *  Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+	int i, in_paren = 0, c;
+
+	for (i = 0; i < strlen(string); i++) {
+		c = tolower(string[i]);
+
+		if (strchr("<[(", c))
+			++in_paren;
+		if (strchr(">])", c) && in_paren > 0)
+			--in_paren;
+
+		if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+			return i;
+	}
+
+	return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+	int key;
+	int key2;
+	int key3;
+
+	nodelay(win, TRUE);
+	keypad(win, FALSE);
+	key = wgetch(win);
+	key2 = wgetch(win);
+	do {
+		key3 = wgetch(win);
+	} while (key3 != ERR);
+	nodelay(win, FALSE);
+	keypad(win, TRUE);
+	if (key == KEY_ESC && key2 == ERR)
+		return KEY_ESC;
+	else if (key != ERR && key != KEY_ESC && key2 == ERR)
+		ungetch(key);
+
+	return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+	dialog_clear();
+	return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+	struct dialog_list *p, *next;
+
+	for (p = item_head; p; p = next) {
+		next = p->next;
+		free(p);
+	}
+	item_head = NULL;
+	item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+	va_list ap;
+	struct dialog_list *p = malloc(sizeof(*p));
+
+	if (item_head)
+		item_cur->next = p;
+	else
+		item_head = p;
+	item_cur = p;
+	memset(p, 0, sizeof(*p));
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+	va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+	va_list ap;
+        size_t avail;
+
+	avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+		  avail, fmt, ap);
+	item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+	va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+	item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+	item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+	item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+	item_foreach()
+		if (item_is_selected())
+			return 1;
+	return 0;
+}
+
+void *item_data(void)
+{
+	return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+	return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next)
+		n++;
+	return n;
+}
+
+void item_set(int n)
+{
+	int i = 0;
+	item_foreach()
+		if (i++ == n)
+			return;
+}
+
+int item_n(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next) {
+		if (p == item_cur)
+			return n;
+		n++;
+	}
+	return 0;
+}
+
+const char *item_str(void)
+{
+	return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+	return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+	return (item_cur->node.tag == tag);
+}
diff --git a/toybox/kconfig/lxdialog/yesno.c b/toybox/kconfig/lxdialog/yesno.c
new file mode 100644
index 0000000..ee0a04e
--- /dev/null
+++ b/toybox/kconfig/lxdialog/yesno.c
@@ -0,0 +1,114 @@
+/*
+ *  yesno.c -- implements the yes/no box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 10;
+	int y = height - 2;
+
+	print_button(dialog, " Yes ", y, x, selected == 0);
+	print_button(dialog, "  No  ", y, x + 13, selected == 1);
+
+	wmove(dialog, y, x + 1 + 13 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+	int i, x, y, key = 0, button = 0;
+	WINDOW *dialog;
+
+do_resize:
+	if (getmaxy(stdscr) < (height + 4))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 4))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (COLS - width) / 2;
+	y = (LINES - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	print_buttons(dialog, height, width, 0);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'Y':
+		case 'y':
+			delwin(dialog);
+			return 0;
+		case 'N':
+		case 'n':
+			delwin(dialog);
+			return 1;
+
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return button;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/toybox/kconfig/mconf.c b/toybox/kconfig/mconf.c
new file mode 100644
index 0000000..c2acdc0
--- /dev/null
+++ b/toybox/kconfig/mconf.c
@@ -0,0 +1,919 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <locale.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "lxdialog/dialog.h"
+
+static char menu_backtitle[128];
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"Some features may be built directly into the project.\n"
+"Some may be made into loadable runtime modules.  Some features\n"
+"may be completely removed altogether.  There are also certain\n"
+"parameters which are not really features, but must be\n"
+"entered in as decimal or hexadecimal numbers or possibly text.\n"
+"\n"
+"Menu items beginning with [*], <M> or [ ] represent features\n"
+"configured to be built in, modularized or removed respectively.\n"
+"Pointed brackets <> represent module capable features.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+"   you wish to change or submenu wish to select and press <Enter>.\n"
+"   Submenus are designated by \"--->\".\n"
+"\n"
+"   Shortcut: Press the option's highlighted letter (hotkey).\n"
+"             Pressing a hotkey more than once will sequence\n"
+"             through all visible items which use that hotkey.\n"
+"\n"
+"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+"   unseen options into view.\n"
+"\n"
+"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
+"   and press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+"             using those letters.  You may press a single <ESC>, but\n"
+"             there is a delayed response which you may find annoying.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+"   <Exit> and <Help>\n"
+"\n"
+"o  To get help with an item, use the cursor keys to highlight <Help>\n"
+"   and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"\n"
+"Radiolists  (Choice lists)\n"
+"-----------\n"
+"o  Use the cursor keys to select the option you wish to set and press\n"
+"   <S> or the <SPACE BAR>.\n"
+"\n"
+"   Shortcut: Press the first letter of the option you wish to set then\n"
+"             press <S> or <SPACE BAR>.\n"
+"\n"
+"o  To see available help for the item, use the cursor keys to highlight\n"
+"   <Help> and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+"   <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o  Enter the requested information and press <ENTER>\n"
+"   If you are entering hexadecimal values, it is not necessary to\n"
+"   add the '0x' prefix to the entry.\n"
+"\n"
+"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
+"   and press <ENTER>.  You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box    (Help Window)\n"
+"--------\n"
+"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
+"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
+"   who are familiar with less and lynx.\n"
+"\n"
+"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"At the end of the main menu you will find two options.  One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a Menuconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry.  I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment.  Some distributions\n"
+"export those variables via /etc/profile.  Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single\n"
+"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
+"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"
+"Different color themes available\n"
+"--------------------------------\n"
+"It is possible to select different color themes using the variable\n"
+"MENUCONFIG_COLOR. To select a theme use:\n"
+"\n"
+"make MENUCONFIG_COLOR=<theme> menuconfig\n"
+"\n"
+"Available themes are\n"
+" mono       => selects colors suitable for monochrome displays\n"
+" blackbg    => selects a color scheme with black background\n"
+" classic    => theme with blue background. The classic look\n"
+" bluetitle  => a LCD friendly version of classic. (default)\n"
+"\n"),
+menu_instructions[] = N_(
+	"Arrow keys navigate the menu.  "
+	"<Enter> selects submenus --->.  "
+	"Highlighted letters are hotkeys.  "
+	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
+	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
+	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
+radiolist_instructions[] = N_(
+	"Use the arrow keys to navigate this window or "
+	"press the hotkey of the item you wish to select "
+	"followed by the <SPACE BAR>. "
+	"Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
+	"Please enter a decimal value. "
+	"Fractions will not be accepted.  "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
+	"Please enter a hexadecimal value. "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
+	"Please enter a string value. "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
+	"This feature depends on another which has been configured as a module.\n"
+	"As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+	"There is no help available for this option.\n"),
+load_config_text[] = N_(
+	"Enter the name of the configuration file you wish to load.  "
+	"Accept the name shown to restore the configuration you "
+	"last retrieved.  Leave blank to abort."),
+load_config_help[] = N_(
+	"\n"
+	"For various reasons, one may wish to keep several different\n"
+	"configurations available on a single machine.\n"
+	"\n"
+	"If you have saved a previous configuration in a file other than the\n"
+	"default, entering the name of the file here will allow you\n"
+	"to modify that configuration.\n"
+	"\n"
+	"If you are uncertain, then you have probably never used alternate\n"
+	"configuration files.  You should therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
+	"Enter a filename to which this configuration should be saved "
+	"as an alternate.  Leave blank to abort."),
+save_config_help[] = N_(
+	"\n"
+	"For various reasons, one may wish to keep different\n"
+	"configurations available on a single machine.\n"
+	"\n"
+	"Entering a file name here will allow you to later retrieve, modify\n"
+	"and use the current configuration as an alternate to whatever\n"
+	"configuration options you have selected at that time.\n"
+	"\n"
+	"If you are uncertain what all this means then you should probably\n"
+	"leave this blank.\n"),
+search_help[] = N_(
+	"\n"
+	"Search for CONFIG_ symbols and display their relations.\n"
+	"Regular expressions are allowed.\n"
+	"Example: search for \"^FOO\"\n"
+	"Result:\n"
+	"-----------------------------------------------------------------\n"
+	"Symbol: FOO [=m]\n"
+	"Prompt: Foo bus is used to drive the bar HW\n"
+	"Defined at drivers/pci/Kconfig:47\n"
+	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+	"Location:\n"
+	"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+	"    -> PCI support (PCI [=y])\n"
+	"      -> PCI access mode (<choice> [=y])\n"
+	"Selects: LIBCRC32\n"
+	"Selected by: BAR\n"
+	"-----------------------------------------------------------------\n"
+	"o The line 'Prompt:' shows the text used in the menu structure for\n"
+	"  this CONFIG_ symbol\n"
+	"o The 'Defined at' line tell at what file / line number the symbol\n"
+	"  is defined\n"
+	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
+	"  this symbol to be visible in the menu (selectable)\n"
+	"o The 'Location:' lines tell where in the menu structure this symbol\n"
+	"  is located\n"
+	"    A location followed by a [=y] indicate that this is a selectable\n"
+	"    menu item - and current value is displayed inside brackets.\n"
+	"o The 'Selects:' line tell what symbol will be automatically\n"
+	"  selected if this symbol is selected (y or m)\n"
+	"o The 'Selected by' line tell what symbol has selected this symbol\n"
+	"\n"
+	"Only relevant lines are shown.\n"
+	"\n\n"
+	"Search examples:\n"
+	"Examples: USB	=> find all CONFIG_ symbols containing USB\n"
+	"          ^USB => find all CONFIG_ symbols starting with USB\n"
+	"          USB$ => find all CONFIG_ symbols ending with USB\n"
+	"\n");
+
+static char filename[PATH_MAX+1] = ".config";
+static int indent;
+static struct termios ios_org;
+static int rows = 0, cols = 0;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+
+static void init_wsize(void)
+{
+	struct winsize ws;
+	char *env;
+
+	if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
+		rows = ws.ws_row;
+		cols = ws.ws_col;
+	}
+
+	if (!rows) {
+		env = getenv("LINES");
+		if (env)
+			rows = atoi(env);
+		if (!rows)
+			rows = 24;
+	}
+	if (!cols) {
+		env = getenv("COLUMNS");
+		if (env)
+			cols = atoi(env);
+		if (!cols)
+			cols = 80;
+	}
+
+	if (rows < 19 || cols < 80) {
+		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+		exit(1);
+	}
+
+	rows -= 4;
+	cols -= 5;
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+	int i, j;
+	struct menu *submenu[8], *menu;
+
+	str_printf(r, "Prompt: %s\n", prop->text);
+	str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
+		prop->menu->lineno);
+	if (!expr_is_yes(prop->visible.expr)) {
+		str_append(r, "  Depends on: ");
+		expr_gstr_print(prop->visible.expr, r);
+		str_append(r, "\n");
+	}
+	menu = prop->menu->parent;
+	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+		submenu[i++] = menu;
+	if (i > 0) {
+		str_printf(r, "  Location:\n");
+		for (j = 4; --i >= 0; j += 2) {
+			menu = submenu[i];
+			str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
+			if (menu->sym) {
+				str_printf(r, " (%s [=%s])", menu->sym->name ?
+					menu->sym->name : "<choice>",
+					sym_get_string_value(menu->sym));
+			}
+			str_append(r, "\n");
+		}
+	}
+}
+
+static void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+	bool hit;
+	struct property *prop;
+
+	str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+	                               sym_get_string_value(sym));
+	for_all_prompts(sym, prop)
+		get_prompt_str(r, prop);
+	hit = false;
+	for_all_properties(sym, prop, P_SELECT) {
+		if (!hit) {
+			str_append(r, "  Selects: ");
+			hit = true;
+		} else
+			str_printf(r, " && ");
+		expr_gstr_print(prop->expr, r);
+	}
+	if (hit)
+		str_append(r, "\n");
+	if (sym->rev_dep.expr) {
+		str_append(r, "  Selected by: ");
+		expr_gstr_print(sym->rev_dep.expr, r);
+		str_append(r, "\n");
+	}
+	str_append(r, "\n\n");
+}
+
+static struct gstr get_relations_str(struct symbol **sym_arr)
+{
+	struct symbol *sym;
+	struct gstr res = str_new();
+	int i;
+
+	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+		get_symbol_str(&res, sym);
+	if (!i)
+		str_append(&res, "No matches found.\n");
+	return res;
+}
+
+static void search_conf(void)
+{
+	struct symbol **sym_arr;
+	struct gstr res;
+	int dres;
+again:
+	dialog_clear();
+	dres = dialog_inputbox(_("Search Configuration Parameter"),
+			      _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
+			      10, 75, "");
+	switch (dres) {
+	case 0:
+		break;
+	case 1:
+		show_helptext(_("Search Configuration"), search_help);
+		goto again;
+	default:
+		return;
+	}
+
+	sym_arr = sym_re_search(dialog_input_result);
+	res = get_relations_str(sym_arr);
+	free(sym_arr);
+	show_textbox(_("Search Results"), str_get(&res), 0, 0);
+	str_free(&res);
+}
+
+static void build_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+	int type, tmp, doint = 2;
+	tristate val;
+	char ch;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (!sym) {
+		if (prop && menu != current_menu) {
+			const char *prompt = menu_get_prompt(menu);
+			switch (prop->type) {
+			case P_MENU:
+				child_count++;
+				if (single_menu_mode) {
+					item_make("%s%*c%s",
+						  menu->data ? "-->" : "++>",
+						  indent + 1, ' ', prompt);
+				} else
+					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
+
+				item_set_tag('m');
+				item_set_data(menu);
+				if (single_menu_mode && menu->data)
+					goto conf_childs;
+				return;
+			default:
+				if (prompt) {
+					child_count++;
+					item_make("---%*c%s", indent + 1, ' ', prompt);
+					item_set_tag(':');
+					item_set_data(menu);
+				}
+			}
+		} else
+			doint = 0;
+		goto conf_childs;
+	}
+
+	type = sym_get_type(sym);
+	if (sym_is_choice(sym)) {
+		struct symbol *def_sym = sym_get_choice_value(sym);
+		struct menu *def_menu = NULL;
+
+		child_count++;
+		for (child = menu->list; child; child = child->next) {
+			if (menu_is_visible(child) && child->sym == def_sym)
+				def_menu = child;
+		}
+
+		val = sym_get_tristate_value(sym);
+		if (sym_is_changable(sym)) {
+			switch (type) {
+			case S_BOOLEAN:
+				item_make("[%c]", val == no ? ' ' : '*');
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes: ch = '*'; break;
+				case mod: ch = 'M'; break;
+				default:  ch = ' '; break;
+				}
+				item_make("<%c>", ch);
+				break;
+			}
+			item_set_tag('t');
+			item_set_data(menu);
+		} else {
+			item_make("   ");
+			item_set_tag(def_menu ? 't' : ':');
+			item_set_data(menu);
+		}
+
+		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+		if (val == yes) {
+			if (def_menu) {
+				item_add_str(" (%s)", menu_get_prompt(def_menu));
+				item_add_str("  --->");
+				if (def_menu->list) {
+					indent += 2;
+					build_conf(def_menu);
+					indent -= 2;
+				}
+			}
+			return;
+		}
+	} else {
+		if (menu == current_menu) {
+			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+			item_set_tag(':');
+			item_set_data(menu);
+			goto conf_childs;
+		}
+		child_count++;
+		val = sym_get_tristate_value(sym);
+		if (sym_is_choice_value(sym) && val == yes) {
+			item_make("   ");
+			item_set_tag(':');
+			item_set_data(menu);
+		} else {
+			switch (type) {
+			case S_BOOLEAN:
+				if (sym_is_changable(sym))
+					item_make("[%c]", val == no ? ' ' : '*');
+				else
+					item_make("---");
+				item_set_tag('t');
+				item_set_data(menu);
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes: ch = '*'; break;
+				case mod: ch = 'M'; break;
+				default:  ch = ' '; break;
+				}
+				if (sym_is_changable(sym))
+					item_make("<%c>", ch);
+				else
+					item_make("---");
+				item_set_tag('t');
+				item_set_data(menu);
+				break;
+			default:
+				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+				item_make("(%s)", sym_get_string_value(sym));
+				tmp = indent - tmp + 4;
+				if (tmp < 0)
+					tmp = 0;
+				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
+					     "" : " (NEW)");
+				item_set_tag('s');
+				item_set_data(menu);
+				goto conf_childs;
+			}
+		}
+		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
+			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
+			  "" : " (NEW)");
+		if (menu->prompt->type == P_MENU) {
+			item_add_str("  --->");
+			return;
+		}
+	}
+
+conf_childs:
+	indent += doint;
+	for (child = menu->list; child; child = child->next)
+		build_conf(child);
+	indent -= doint;
+}
+
+static void conf(struct menu *menu)
+{
+	struct menu *submenu;
+	const char *prompt = menu_get_prompt(menu);
+	struct symbol *sym;
+	struct menu *active_menu = NULL;
+	int res;
+	int s_scroll = 0;
+
+	while (1) {
+		item_reset();
+		current_menu = menu;
+		build_conf(menu);
+		if (!child_count)
+			break;
+		if (menu == &rootmenu) {
+			item_make("--- ");
+			item_set_tag(':');
+			item_make(_("    Load an Alternate Configuration File"));
+			item_set_tag('L');
+			item_make(_("    Save an Alternate Configuration File"));
+			item_set_tag('S');
+		}
+		dialog_clear();
+		res = dialog_menu(prompt ? prompt : _("Main Menu"),
+				  _(menu_instructions),
+				  active_menu, &s_scroll);
+		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+			break;
+		if (!item_activate_selected())
+			continue;
+		if (!item_tag())
+			continue;
+
+		submenu = item_data();
+		active_menu = item_data();
+		if (submenu)
+			sym = submenu->sym;
+		else
+			sym = NULL;
+
+		switch (res) {
+		case 0:
+			switch (item_tag()) {
+			case 'm':
+				if (single_menu_mode)
+					submenu->data = (void *) (long) !submenu->data;
+				else
+					conf(submenu);
+				break;
+			case 't':
+				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+					conf_choice(submenu);
+				else if (submenu->prompt->type == P_MENU)
+					conf(submenu);
+				break;
+			case 's':
+				conf_string(submenu);
+				break;
+			case 'L':
+				conf_load();
+				break;
+			case 'S':
+				conf_save();
+				break;
+			}
+			break;
+		case 2:
+			if (sym)
+				show_help(submenu);
+			else
+				show_helptext("README", _(mconf_readme));
+			break;
+		case 3:
+			if (item_is_tag('t')) {
+				if (sym_set_tristate_value(sym, yes))
+					break;
+				if (sym_set_tristate_value(sym, mod))
+					show_textbox(NULL, setmod_text, 6, 74);
+			}
+			break;
+		case 4:
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, no);
+			break;
+		case 5:
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, mod);
+			break;
+		case 6:
+			if (item_is_tag('t'))
+				sym_toggle_tristate_value(sym);
+			else if (item_is_tag('m'))
+				conf(submenu);
+			break;
+		case 7:
+			search_conf();
+			break;
+		}
+	}
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+	dialog_clear();
+	dialog_textbox(title, text, r, c);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+	show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+	struct gstr help = str_new();
+	struct symbol *sym = menu->sym;
+
+	if (sym->help)
+	{
+		if (sym->name) {
+			str_printf(&help, "CONFIG_%s:\n\n", sym->name);
+			str_append(&help, _(sym->help));
+			str_append(&help, "\n");
+		}
+	} else {
+		str_append(&help, nohelp_text);
+	}
+	get_symbol_str(&help, sym);
+	show_helptext(menu_get_prompt(menu), str_get(&help));
+	str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+	const char *prompt = menu_get_prompt(menu);
+	struct menu *child;
+	struct symbol *active;
+
+	active = sym_get_choice_value(menu->sym);
+	while (1) {
+		int res;
+		int selected;
+		item_reset();
+
+		current_menu = menu;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
+				continue;
+			item_make("%s", menu_get_prompt(child));
+			item_set_data(child);
+			if (child->sym == active)
+				item_set_selected(1);
+			if (child->sym == sym_get_choice_value(menu->sym))
+				item_set_tag('X');
+		}
+		dialog_clear();
+		res = dialog_checklist(prompt ? prompt : _("Main Menu"),
+					_(radiolist_instructions),
+					 15, 70, 6);
+		selected = item_activate_selected();
+		switch (res) {
+		case 0:
+			if (selected) {
+				child = item_data();
+				sym_set_tristate_value(child->sym, yes);
+			}
+			return;
+		case 1:
+			if (selected) {
+				child = item_data();
+				show_help(child);
+				active = child->sym;
+			} else
+				show_help(menu);
+			break;
+		case KEY_ESC:
+			return;
+		case -ERRDISPLAYTOOSMALL:
+			return;
+		}
+	}
+}
+
+static void conf_string(struct menu *menu)
+{
+	const char *prompt = menu_get_prompt(menu);
+
+	while (1) {
+		int res;
+		char *heading;
+
+		switch (sym_get_type(menu->sym)) {
+		case S_INT:
+			heading = (char *)_(inputbox_instructions_int);
+			break;
+		case S_HEX:
+			heading = (char *)_(inputbox_instructions_hex);
+			break;
+		case S_STRING:
+			heading = (char *)_(inputbox_instructions_string);
+			break;
+		default:
+			heading = "Internal mconf error!";
+		}
+		dialog_clear();
+		res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
+				      heading, 10, 75,
+				      sym_get_string_value(menu->sym));
+		switch (res) {
+		case 0:
+			if (sym_set_string_value(menu->sym, dialog_input_result))
+				return;
+			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+			break;
+		case 1:
+			show_help(menu);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_load(void)
+{
+
+	while (1) {
+		int res;
+		dialog_clear();
+		res = dialog_inputbox(NULL, load_config_text,
+				      11, 55, filename);
+		switch(res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_read(dialog_input_result))
+				return;
+			show_textbox(NULL, _("File does not exist!"), 5, 38);
+			break;
+		case 1:
+			show_helptext(_("Load Alternate Configuration"), load_config_help);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_save(void)
+{
+	while (1) {
+		int res;
+		dialog_clear();
+		res = dialog_inputbox(NULL, save_config_text,
+				      11, 55, filename);
+		switch(res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_write(dialog_input_result))
+				return;
+			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
+			break;
+		case 1:
+			show_helptext(_("Save Alternate Configuration"), save_config_help);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_cleanup(void)
+{
+	tcsetattr(1, TCSAFLUSH, &ios_org);
+}
+
+int main(int ac, char **av)
+{
+	struct symbol *sym;
+	char *mode;
+	int res;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	conf_parse(av[1] ? av[1] : "");
+	conf_read(NULL);
+
+	sym = sym_lookup("KERNELVERSION", 0);
+	sym_calc_value(sym);
+	sprintf(menu_backtitle, _(PROJECT_NAME" v%s Configuration"),
+		sym_get_string_value(sym));
+
+	mode = getenv("MENUCONFIG_MODE");
+	if (mode) {
+		if (!strcasecmp(mode, "single_menu"))
+			single_menu_mode = 1;
+	}
+
+	tcgetattr(1, &ios_org);
+	atexit(conf_cleanup);
+	init_wsize();
+	reset_dialog();
+	init_dialog(menu_backtitle);
+	do {
+		conf(&rootmenu);
+		dialog_clear();
+		res = dialog_yesno(NULL,
+				   _("Do you wish to save your "
+				     "new "PROJECT_NAME" configuration?\n"
+				     "<ESC><ESC> to continue."),
+				   6, 60);
+	} while (res == KEY_ESC);
+	end_dialog();
+	if (res == 0) {
+		if (conf_write(NULL)) {
+			fprintf(stderr, _("\n\n"
+				"Error writing "PROJECT_NAME" configuration.\n"
+				"Your configuration changes were NOT saved."
+				"\n\n"));
+			return 1;
+		}
+		printf(_("\n\n"
+			"*** End of "PROJECT_NAME" configuration.\n"
+			"*** Execute 'make' to build, or try 'make help'."
+			"\n\n"));
+	} else {
+		fprintf(stderr, _("\n\n"
+			"Your configuration changes were NOT saved."
+			"\n\n"));
+	}
+
+	return 0;
+}
diff --git a/toybox/kconfig/menu.c b/toybox/kconfig/menu.c
new file mode 100644
index 0000000..c86c27f
--- /dev/null
+++ b/toybox/kconfig/menu.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+static void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+void menu_init(void)
+{
+	current_entry = current_menu = &rootmenu;
+	last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+	struct menu *menu;
+
+	menu = malloc(sizeof(*menu));
+	memset(menu, 0, sizeof(*menu));
+	menu->sym = sym;
+	menu->parent = current_menu;
+	menu->file = current_file;
+	menu->lineno = zconf_lineno();
+
+	*last_entry_ptr = menu;
+	last_entry_ptr = &menu->next;
+	current_entry = menu;
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+	menu_end_entry();
+	last_entry_ptr = &current_entry->list;
+	return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+	last_entry_ptr = &current_menu->next;
+	current_menu = current_menu->parent;
+}
+
+struct expr *menu_check_dep(struct expr *e)
+{
+	if (!e)
+		return e;
+
+	switch (e->type) {
+	case E_NOT:
+		e->left.expr = menu_check_dep(e->left.expr);
+		break;
+	case E_OR:
+	case E_AND:
+		e->left.expr = menu_check_dep(e->left.expr);
+		e->right.expr = menu_check_dep(e->right.expr);
+		break;
+	case E_SYMBOL:
+		/* change 'm' into 'm' && MODULES */
+		if (e->left.sym == &symbol_mod)
+			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+		break;
+	default:
+		break;
+	}
+	return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+	struct symbol *sym = current_entry->sym;
+
+	if (sym->type == type)
+		return;
+	if (sym->type == S_UNKNOWN) {
+		sym->type = type;
+		return;
+	}
+	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
+	    sym->name ? sym->name : "<choice>",
+	    sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+	struct property *prop = prop_alloc(type, current_entry->sym);
+
+	prop->menu = current_entry;
+	prop->expr = expr;
+	prop->visible.expr = menu_check_dep(dep);
+
+	if (prompt) {
+		if (isspace(*prompt)) {
+			prop_warn(prop, "leading whitespace ignored");
+			while (isspace(*prompt))
+				prompt++;
+		}
+		if (current_entry->prompt)
+			prop_warn(prop, "prompt redefined");
+		current_entry->prompt = prop;
+	}
+	prop->text = prompt;
+
+	return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+	return menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+	menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void menu_add_option(int token, char *arg)
+{
+	struct property *prop;
+
+	switch (token) {
+	case T_OPT_MODULES:
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(current_entry->sym);
+		break;
+	case T_OPT_DEFCONFIG_LIST:
+		if (!sym_defconfig_list)
+			sym_defconfig_list = current_entry->sym;
+		else if (sym_defconfig_list != current_entry->sym)
+			zconf_error("trying to redefine defconfig symbol");
+		break;
+	}
+}
+
+static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+{
+	return sym2->type == S_INT || sym2->type == S_HEX ||
+	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+void sym_check_prop(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *sym2;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		switch (prop->type) {
+		case P_DEFAULT:
+			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+			    prop->expr->type != E_SYMBOL)
+				prop_warn(prop,
+				    "default for config symbol '%'"
+				    " must be a single symbol", sym->name);
+			break;
+		case P_SELECT:
+			sym2 = prop_get_symbol(prop);
+			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+				prop_warn(prop,
+				    "config symbol '%s' uses select, but is "
+				    "not boolean or tristate", sym->name);
+			else if (sym2->type == S_UNKNOWN)
+				prop_warn(prop,
+				    "'select' used by config symbol '%s' "
+				    "refer to undefined symbol '%s'",
+				    sym->name, sym2->name);
+			else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
+				prop_warn(prop,
+				    "'%s' has wrong type. 'select' only "
+				    "accept arguments of boolean and "
+				    "tristate type", sym2->name);
+			break;
+		case P_RANGE:
+			if (sym->type != S_INT && sym->type != S_HEX)
+				prop_warn(prop, "range is only allowed "
+				                "for int or hex symbols");
+			if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
+			    !menu_range_valid_sym(sym, prop->expr->right.sym))
+				prop_warn(prop, "range is invalid");
+			break;
+		default:
+			;
+		}
+	}
+}
+
+void menu_finalize(struct menu *parent)
+{
+	struct menu *menu, *last_menu;
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+	sym = parent->sym;
+	if (parent->list) {
+		if (sym && sym_is_choice(sym)) {
+			/* find the first choice value and find out choice type */
+			for (menu = parent->list; menu; menu = menu->next) {
+				if (menu->sym) {
+					current_entry = parent;
+					menu_set_type(menu->sym->type);
+					current_entry = menu;
+					menu_set_type(sym->type);
+					break;
+				}
+			}
+			parentdep = expr_alloc_symbol(sym);
+		} else if (parent->prompt)
+			parentdep = parent->prompt->visible.expr;
+		else
+			parentdep = parent->dep;
+
+		for (menu = parent->list; menu; menu = menu->next) {
+			basedep = expr_transform(menu->dep);
+			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+			basedep = expr_eliminate_dups(basedep);
+			menu->dep = basedep;
+			if (menu->sym)
+				prop = menu->sym->prop;
+			else
+				prop = menu->prompt;
+			for (; prop; prop = prop->next) {
+				if (prop->menu != menu)
+					continue;
+				dep = expr_transform(prop->visible.expr);
+				dep = expr_alloc_and(expr_copy(basedep), dep);
+				dep = expr_eliminate_dups(dep);
+				if (menu->sym && menu->sym->type != S_TRISTATE)
+					dep = expr_trans_bool(dep);
+				prop->visible.expr = dep;
+				if (prop->type == P_SELECT) {
+					struct symbol *es = prop_get_symbol(prop);
+					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+				}
+			}
+		}
+		for (menu = parent->list; menu; menu = menu->next)
+			menu_finalize(menu);
+	} else if (sym) {
+		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+		basedep = expr_eliminate_dups(expr_transform(basedep));
+		last_menu = NULL;
+		for (menu = parent->next; menu; menu = menu->next) {
+			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+			if (!expr_contains_symbol(dep, sym))
+				break;
+			if (expr_depends_symbol(dep, sym))
+				goto next;
+			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+			dep = expr_eliminate_dups(expr_transform(dep));
+			dep2 = expr_copy(basedep);
+			expr_eliminate_eq(&dep, &dep2);
+			expr_free(dep);
+			if (!expr_is_yes(dep2)) {
+				expr_free(dep2);
+				break;
+			}
+			expr_free(dep2);
+		next:
+			menu_finalize(menu);
+			menu->parent = parent;
+			last_menu = menu;
+		}
+		if (last_menu) {
+			parent->list = parent->next;
+			parent->next = last_menu->next;
+			last_menu->next = NULL;
+		}
+	}
+	for (menu = parent->list; menu; menu = menu->next) {
+		if (sym && sym_is_choice(sym) && menu->sym) {
+			menu->sym->flags |= SYMBOL_CHOICEVAL;
+			if (!menu->prompt)
+				menu_warn(menu, "choice value must have a prompt");
+			for (prop = menu->sym->prop; prop; prop = prop->next) {
+				if (prop->type == P_PROMPT && prop->menu != menu) {
+					prop_warn(prop, "choice values "
+					    "currently only support a "
+					    "single prompt");
+				}
+				if (prop->type == P_DEFAULT)
+					prop_warn(prop, "defaults for choice "
+					    "values not supported");
+			}
+			current_entry = menu;
+			menu_set_type(sym->type);
+			menu_add_symbol(P_CHOICE, sym, NULL);
+			prop = sym_get_choice_prop(sym);
+			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+				;
+			*ep = expr_alloc_one(E_CHOICE, NULL);
+			(*ep)->right.sym = menu->sym;
+		}
+		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+			for (last_menu = menu->list; ; last_menu = last_menu->next) {
+				last_menu->parent = parent;
+				if (!last_menu->next)
+					break;
+			}
+			last_menu->next = menu->next;
+			menu->next = menu->list;
+			menu->list = NULL;
+		}
+	}
+
+	if (sym && !(sym->flags & SYMBOL_WARNED)) {
+		if (sym->type == S_UNKNOWN)
+			menu_warn(parent, "config symbol defined without type");
+
+		if (sym_is_choice(sym) && !parent->prompt)
+			menu_warn(parent, "choice must have a prompt");
+
+		/* Check properties connected to this symbol */
+		sym_check_prop(sym);
+		sym->flags |= SYMBOL_WARNED;
+	}
+
+	if (sym && !sym_is_optional(sym) && parent->prompt) {
+		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+				expr_alloc_and(parent->prompt->visible.expr,
+					expr_alloc_symbol(&symbol_mod)));
+	}
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+	struct menu *child;
+	struct symbol *sym;
+	tristate visible;
+
+	if (!menu->prompt)
+		return false;
+	sym = menu->sym;
+	if (sym) {
+		sym_calc_value(sym);
+		visible = menu->prompt->visible.tri;
+	} else
+		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+	if (visible != no)
+		return true;
+	if (!sym || sym_get_tristate_value(menu->sym) == no)
+		return false;
+
+	for (child = menu->list; child; child = child->next)
+		if (menu_is_visible(child))
+			return true;
+	return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+	if (menu->prompt)
+		return _(menu->prompt->text);
+	else if (menu->sym)
+		return _(menu->sym->name);
+	return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+	return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+	enum prop_type type;
+
+	for (; menu != &rootmenu; menu = menu->parent) {
+		type = menu->prompt ? menu->prompt->type : 0;
+		if (type == P_MENU)
+			break;
+	}
+	return menu;
+}
+
diff --git a/toybox/kconfig/symbol.c b/toybox/kconfig/symbol.c
new file mode 100644
index 0000000..ee225ce
--- /dev/null
+++ b/toybox/kconfig/symbol.c
@@ -0,0 +1,882 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+	.name = "y",
+	.curr = { "y", yes },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_mod = {
+	.name = "m",
+	.curr = { "m", mod },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_no = {
+	.name = "n",
+	.curr = { "n", no },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_empty = {
+	.name = "",
+	.curr = { "", no },
+	.flags = SYMBOL_VALID,
+};
+
+int sym_change_count;
+struct symbol *sym_defconfig_list;
+struct symbol *modules_sym;
+tristate modules_val;
+
+void sym_add_default(struct symbol *sym, const char *def)
+{
+	struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+	prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
+}
+
+void sym_init(void)
+{
+	struct symbol *sym;
+	struct utsname uts;
+	char *p;
+	static bool inited = false;
+
+	if (inited)
+		return;
+	inited = true;
+
+	uname(&uts);
+
+	sym = sym_lookup("ARCH", 0);
+	sym->type = S_STRING;
+	sym->flags |= SYMBOL_AUTO;
+	p = getenv("ARCH");
+	if (p)
+		sym_add_default(sym, p);
+
+	sym = sym_lookup("KERNELVERSION", 0);
+	sym->type = S_STRING;
+	sym->flags |= SYMBOL_AUTO;
+	p = getenv("KERNELVERSION");
+	if (p)
+		sym_add_default(sym, p);
+
+	sym = sym_lookup("UNAME_RELEASE", 0);
+	sym->type = S_STRING;
+	sym->flags |= SYMBOL_AUTO;
+	sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+	enum symbol_type type = sym->type;
+
+	if (type == S_TRISTATE) {
+		if (sym_is_choice_value(sym) && sym->visible == yes)
+			type = S_BOOLEAN;
+		else if (modules_val == no)
+			type = S_BOOLEAN;
+	}
+	return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+	switch (type) {
+	case S_BOOLEAN:
+		return "boolean";
+	case S_TRISTATE:
+		return "tristate";
+	case S_INT:
+		return "integer";
+	case S_HEX:
+		return "hex";
+	case S_STRING:
+		return "string";
+	case S_UNKNOWN:
+		return "unknown";
+	case S_OTHER:
+		break;
+	}
+	return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_choices(sym, prop)
+		return prop;
+	return NULL;
+}
+
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+struct property *sym_get_range_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_RANGE) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+static int sym_get_range_val(struct symbol *sym, int base)
+{
+	sym_calc_value(sym);
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		break;
+	}
+	return strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+	struct property *prop;
+	int base, val, val2;
+	char str[64];
+
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		return;
+	}
+	prop = sym_get_range_prop(sym);
+	if (!prop)
+		return;
+	val = strtol(sym->curr.val, NULL, base);
+	val2 = sym_get_range_val(prop->expr->left.sym, base);
+	if (val >= val2) {
+		val2 = sym_get_range_val(prop->expr->right.sym, base);
+		if (val <= val2)
+			return;
+	}
+	if (sym->type == S_INT)
+		sprintf(str, "%d", val2);
+	else
+		sprintf(str, "0x%x", val2);
+	sym->curr.val = strdup(str);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+	struct property *prop;
+	tristate tri;
+
+	/* any prompt visible? */
+	tri = no;
+	for_all_prompts(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		tri = E_OR(tri, prop->visible.tri);
+	}
+	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+		tri = yes;
+	if (sym->visible != tri) {
+		sym->visible = tri;
+		sym_set_changed(sym);
+	}
+	if (sym_is_choice_value(sym))
+		return;
+	tri = no;
+	if (sym->rev_dep.expr)
+		tri = expr_calc_value(sym->rev_dep.expr);
+	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+		tri = yes;
+	if (sym->rev_dep.tri != tri) {
+		sym->rev_dep.tri = tri;
+		sym_set_changed(sym);
+	}
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+	struct symbol *def_sym;
+	struct property *prop;
+	struct expr *e;
+
+	/* is the user choice visible? */
+	def_sym = sym->def[S_DEF_USER].val;
+	if (def_sym) {
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* any of the defaults visible? */
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri == no)
+			continue;
+		def_sym = prop_get_symbol(prop);
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* just get the first visible value */
+	prop = sym_get_choice_prop(sym);
+	for (e = prop->expr; e; e = e->left.expr) {
+		def_sym = e->right.sym;
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* no choice? reset tristate value */
+	sym->curr.tri = no;
+	return NULL;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+	struct symbol_value newval, oldval;
+	struct property *prop;
+	struct expr *e;
+
+	if (!sym)
+		return;
+
+	if (sym->flags & SYMBOL_VALID)
+		return;
+	sym->flags |= SYMBOL_VALID;
+
+	oldval = sym->curr;
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		newval = symbol_empty.curr;
+		break;
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		newval = symbol_no.curr;
+		break;
+	default:
+		sym->curr.val = sym->name;
+		sym->curr.tri = no;
+		return;
+	}
+	if (!sym_is_choice_value(sym))
+		sym->flags &= ~SYMBOL_WRITE;
+
+	sym_calc_visibility(sym);
+
+	/* set default if recursively called */
+	sym->curr = newval;
+
+	switch (sym_get_type(sym)) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		if (sym_is_choice_value(sym) && sym->visible == yes) {
+			prop = sym_get_choice_prop(sym);
+			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+		} else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
+			sym->flags |= SYMBOL_WRITE;
+			if (sym_has_value(sym))
+				newval.tri = sym->def[S_DEF_USER].tri;
+			else if (!sym_is_choice(sym)) {
+				prop = sym_get_default_prop(sym);
+				if (prop)
+					newval.tri = expr_calc_value(prop->expr);
+			}
+			newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
+		} else if (!sym_is_choice(sym)) {
+			prop = sym_get_default_prop(sym);
+			if (prop) {
+				sym->flags |= SYMBOL_WRITE;
+				newval.tri = expr_calc_value(prop->expr);
+			}
+		}
+		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+			newval.tri = yes;
+		break;
+	case S_STRING:
+	case S_HEX:
+	case S_INT:
+		if (sym->visible != no) {
+			sym->flags |= SYMBOL_WRITE;
+			if (sym_has_value(sym)) {
+				newval.val = sym->def[S_DEF_USER].val;
+				break;
+			}
+		}
+		prop = sym_get_default_prop(sym);
+		if (prop) {
+			struct symbol *ds = prop_get_symbol(prop);
+			if (ds) {
+				sym->flags |= SYMBOL_WRITE;
+				sym_calc_value(ds);
+				newval.val = ds->curr.val;
+			}
+		}
+		break;
+	default:
+		;
+	}
+
+	sym->curr = newval;
+	if (sym_is_choice(sym) && newval.tri == yes)
+		sym->curr.val = sym_calc_choice(sym);
+	sym_validate_range(sym);
+
+	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+		sym_set_changed(sym);
+		if (modules_sym == sym) {
+			sym_set_all_changed();
+			modules_val = modules_sym->curr.tri;
+		}
+	}
+
+	if (sym_is_choice(sym)) {
+		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
+		prop = sym_get_choice_prop(sym);
+		for (e = prop->expr; e; e = e->left.expr) {
+			e->right.sym->flags |= flags;
+			if (flags & SYMBOL_CHANGED)
+				sym_set_changed(e->right.sym);
+		}
+	}
+}
+
+void sym_clear_all_valid(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym->flags &= ~SYMBOL_VALID;
+	sym_change_count++;
+	if (modules_sym)
+		sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+	struct property *prop;
+
+	sym->flags |= SYMBOL_CHANGED;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu)
+			prop->menu->flags |= MENU_CHANGED;
+	}
+}
+
+void sym_set_all_changed(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+	int type = sym_get_type(sym);
+
+	if (sym->visible == no)
+		return false;
+
+	if (type != S_BOOLEAN && type != S_TRISTATE)
+		return false;
+
+	if (type == S_BOOLEAN && val == mod)
+		return false;
+	if (sym->visible <= sym->rev_dep.tri)
+		return false;
+	if (sym_is_choice_value(sym) && sym->visible == yes)
+		return val == yes;
+	return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+	tristate oldval = sym_get_tristate_value(sym);
+
+	if (oldval != val && !sym_tristate_within_range(sym, val))
+		return false;
+
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
+		sym_set_changed(sym);
+	}
+	/*
+	 * setting a choice value also resets the new flag of the choice
+	 * symbol and all other choice values.
+	 */
+	if (sym_is_choice_value(sym) && val == yes) {
+		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+		struct property *prop;
+		struct expr *e;
+
+		cs->def[S_DEF_USER].val = sym;
+		cs->flags |= SYMBOL_DEF_USER;
+		prop = sym_get_choice_prop(cs);
+		for (e = prop->expr; e; e = e->left.expr) {
+			if (e->right.sym->visible != no)
+				e->right.sym->flags |= SYMBOL_DEF_USER;
+		}
+	}
+
+	sym->def[S_DEF_USER].tri = val;
+	if (oldval != val)
+		sym_clear_all_valid();
+
+	return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+	tristate oldval, newval;
+
+	oldval = newval = sym_get_tristate_value(sym);
+	do {
+		switch (newval) {
+		case no:
+			newval = mod;
+			break;
+		case mod:
+			newval = yes;
+			break;
+		case yes:
+			newval = no;
+			break;
+		}
+		if (sym_set_tristate_value(sym, newval))
+			break;
+	} while (oldval != newval);
+	return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+	signed char ch;
+
+	switch (sym->type) {
+	case S_STRING:
+		return true;
+	case S_INT:
+		ch = *str++;
+		if (ch == '-')
+			ch = *str++;
+		if (!isdigit(ch))
+			return false;
+		if (ch == '0' && *str != 0)
+			return false;
+		while ((ch = *str++)) {
+			if (!isdigit(ch))
+				return false;
+		}
+		return true;
+	case S_HEX:
+		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+			str += 2;
+		ch = *str++;
+		do {
+			if (!isxdigit(ch))
+				return false;
+		} while ((ch = *str++));
+		return true;
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (str[0]) {
+		case 'y': case 'Y':
+		case 'm': case 'M':
+		case 'n': case 'N':
+			return true;
+		}
+		return false;
+	default:
+		return false;
+	}
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+	struct property *prop;
+	int val;
+
+	switch (sym->type) {
+	case S_STRING:
+		return sym_string_valid(sym, str);
+	case S_INT:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtol(str, NULL, 10);
+		return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 10);
+	case S_HEX:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtol(str, NULL, 16);
+		return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 16);
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (str[0]) {
+		case 'y': case 'Y':
+			return sym_tristate_within_range(sym, yes);
+		case 'm': case 'M':
+			return sym_tristate_within_range(sym, mod);
+		case 'n': case 'N':
+			return sym_tristate_within_range(sym, no);
+		}
+		return false;
+	default:
+		return false;
+	}
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+	const char *oldval;
+	char *val;
+	int size;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (newval[0]) {
+		case 'y': case 'Y':
+			return sym_set_tristate_value(sym, yes);
+		case 'm': case 'M':
+			return sym_set_tristate_value(sym, mod);
+		case 'n': case 'N':
+			return sym_set_tristate_value(sym, no);
+		}
+		return false;
+	default:
+		;
+	}
+
+	if (!sym_string_within_range(sym, newval))
+		return false;
+
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
+		sym_set_changed(sym);
+	}
+
+	oldval = sym->def[S_DEF_USER].val;
+	size = strlen(newval) + 1;
+	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+		size += 2;
+		sym->def[S_DEF_USER].val = val = malloc(size);
+		*val++ = '0';
+		*val++ = 'x';
+	} else if (!oldval || strcmp(oldval, newval))
+		sym->def[S_DEF_USER].val = val = malloc(size);
+	else
+		return true;
+
+	strcpy(val, newval);
+	free((void *)oldval);
+	sym_clear_all_valid();
+
+	return true;
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+	tristate val;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		val = sym_get_tristate_value(sym);
+		switch (val) {
+		case no:
+			return "n";
+		case mod:
+			return "m";
+		case yes:
+			return "y";
+		}
+		break;
+	default:
+		;
+	}
+	return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+	return sym->visible > sym->rev_dep.tri;
+}
+
+struct symbol *sym_lookup(const char *name, int isconst)
+{
+	struct symbol *symbol;
+	const char *ptr;
+	char *new_name;
+	int hash = 0;
+
+	if (name) {
+		if (name[0] && !name[1]) {
+			switch (name[0]) {
+			case 'y': return &symbol_yes;
+			case 'm': return &symbol_mod;
+			case 'n': return &symbol_no;
+			}
+		}
+		for (ptr = name; *ptr; ptr++)
+			hash += *ptr;
+		hash &= 0xff;
+
+		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+			if (!strcmp(symbol->name, name)) {
+				if ((isconst && symbol->flags & SYMBOL_CONST) ||
+				    (!isconst && !(symbol->flags & SYMBOL_CONST)))
+					return symbol;
+			}
+		}
+		new_name = strdup(name);
+	} else {
+		new_name = NULL;
+		hash = 256;
+	}
+
+	symbol = malloc(sizeof(*symbol));
+	memset(symbol, 0, sizeof(*symbol));
+	symbol->name = new_name;
+	symbol->type = S_UNKNOWN;
+	if (isconst)
+		symbol->flags |= SYMBOL_CONST;
+
+	symbol->next = symbol_hash[hash];
+	symbol_hash[hash] = symbol;
+
+	return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+	struct symbol *symbol = NULL;
+	const char *ptr;
+	int hash = 0;
+
+	if (!name)
+		return NULL;
+
+	if (name[0] && !name[1]) {
+		switch (name[0]) {
+		case 'y': return &symbol_yes;
+		case 'm': return &symbol_mod;
+		case 'n': return &symbol_no;
+		}
+	}
+	for (ptr = name; *ptr; ptr++)
+		hash += *ptr;
+	hash &= 0xff;
+
+	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+		if (!strcmp(symbol->name, name) &&
+		    !(symbol->flags & SYMBOL_CONST))
+				break;
+	}
+
+	return symbol;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+	struct symbol *sym, **sym_arr = NULL;
+	int i, cnt, size;
+	regex_t re;
+
+	cnt = size = 0;
+	/* Skip if empty */
+	if (strlen(pattern) == 0)
+		return NULL;
+	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+		return NULL;
+
+	for_all_symbols(i, sym) {
+		if (sym->flags & SYMBOL_CONST || !sym->name)
+			continue;
+		if (regexec(&re, sym->name, 0, NULL, 0))
+			continue;
+		if (cnt + 1 >= size) {
+			void *tmp = sym_arr;
+			size += 16;
+			sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+			if (!sym_arr) {
+				free(tmp);
+				return NULL;
+			}
+		}
+		sym_arr[cnt++] = sym;
+	}
+	if (sym_arr)
+		sym_arr[cnt] = NULL;
+	regfree(&re);
+
+	return sym_arr;
+}
+
+
+struct symbol *sym_check_deps(struct symbol *sym);
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+	struct symbol *sym;
+
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_OR:
+	case E_AND:
+		sym = sym_check_expr_deps(e->left.expr);
+		if (sym)
+			return sym;
+		return sym_check_expr_deps(e->right.expr);
+	case E_NOT:
+		return sym_check_expr_deps(e->left.expr);
+	case E_EQUAL:
+	case E_UNEQUAL:
+		sym = sym_check_deps(e->left.sym);
+		if (sym)
+			return sym;
+		return sym_check_deps(e->right.sym);
+	case E_SYMBOL:
+		return sym_check_deps(e->left.sym);
+	default:
+		break;
+	}
+	printf("Oops! How to check %d?\n", e->type);
+	return NULL;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+	struct symbol *sym2;
+	struct property *prop;
+
+	if (sym->flags & SYMBOL_CHECK) {
+		printf("Warning! Found recursive dependency: %s", sym->name);
+		return sym;
+	}
+	if (sym->flags & SYMBOL_CHECKED)
+		return NULL;
+
+	sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+	if (sym2)
+		goto out;
+
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->type == P_CHOICE || prop->type == P_SELECT)
+			continue;
+		sym2 = sym_check_expr_deps(prop->visible.expr);
+		if (sym2)
+			goto out;
+		if (prop->type != P_DEFAULT || sym_is_choice(sym))
+			continue;
+		sym2 = sym_check_expr_deps(prop->expr);
+		if (sym2)
+			goto out;
+	}
+out:
+	if (sym2) {
+		printf(" %s", sym->name);
+		if (sym2 == sym) {
+			printf("\n");
+			sym2 = NULL;
+		}
+	}
+	sym->flags &= ~SYMBOL_CHECK;
+	return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+	struct property *prop;
+	struct property **propp;
+
+	prop = malloc(sizeof(*prop));
+	memset(prop, 0, sizeof(*prop));
+	prop->type = type;
+	prop->sym = sym;
+	prop->file = current_file;
+	prop->lineno = zconf_lineno();
+
+	/* append property to the prop list of symbol */
+	if (sym) {
+		for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+			;
+		*propp = prop;
+	}
+
+	return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+	if (prop->expr && (prop->expr->type == E_SYMBOL ||
+			   prop->expr->type == E_CHOICE))
+		return prop->expr->left.sym;
+	return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+	switch (type) {
+	case P_PROMPT:
+		return "prompt";
+	case P_COMMENT:
+		return "comment";
+	case P_MENU:
+		return "menu";
+	case P_DEFAULT:
+		return "default";
+	case P_CHOICE:
+		return "choice";
+	case P_SELECT:
+		return "select";
+	case P_RANGE:
+		return "range";
+	case P_UNKNOWN:
+		break;
+	}
+	return "unknown";
+}
diff --git a/toybox/kconfig/util.c b/toybox/kconfig/util.c
new file mode 100644
index 0000000..e3f28b9
--- /dev/null
+++ b/toybox/kconfig/util.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+	struct file *file;
+
+	for (file = file_list; file; file = file->next) {
+		if (!strcmp(name, file->name))
+			return file;
+	}
+
+	file = malloc(sizeof(*file));
+	memset(file, 0, sizeof(*file));
+	file->name = strdup(name);
+	file->next = file_list;
+	file_list = file;
+	return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+	struct file *file;
+	FILE *out;
+
+	if (!name)
+		name = ".kconfig.d";
+	out = fopen("..config.tmp", "w");
+	if (!out)
+		return 1;
+	fprintf(out, "deps_config := \\\n");
+	for (file = file_list; file; file = file->next) {
+		if (file->next)
+			fprintf(out, "\t%s \\\n", file->name);
+		else
+			fprintf(out, "\t%s\n", file->name);
+	}
+	fprintf(out, "\ninclude/config/auto.conf: \\\n"
+		     "\t$(deps_config)\n\n"
+		     "$(deps_config): ;\n");
+	fclose(out);
+	rename("..config.tmp", name);
+	return 0;
+}
+
+
+/* Allocate initial growable sting */
+struct gstr str_new(void)
+{
+	struct gstr gs;
+	gs.s = malloc(sizeof(char) * 64);
+	gs.len = 16;
+	strcpy(gs.s, "\0");
+	return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+	struct gstr gs;
+	gs.s = strdup(s);
+	gs.len = strlen(s) + 1;
+	return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+	if (gs->s)
+		free(gs->s);
+	gs->s = NULL;
+	gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+	size_t l = strlen(gs->s) + strlen(s) + 1;
+	if (l > gs->len) {
+		gs->s   = realloc(gs->s, l);
+		gs->len = l;
+	}
+	strcat(gs->s, s);
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+	va_list ap;
+	char s[10000]; /* big enough... */
+	va_start(ap, fmt);
+	vsnprintf(s, sizeof(s), fmt, ap);
+	str_append(gs, s);
+	va_end(ap);
+}
+
+/* Retrieve value of growable string */
+const char *str_get(struct gstr *gs)
+{
+	return gs->s;
+}
+
diff --git a/toybox/kconfig/zconf.hash.c_shipped b/toybox/kconfig/zconf.hash.c_shipped
new file mode 100644
index 0000000..1fffcbb
--- /dev/null
+++ b/toybox/kconfig/zconf.hash.c_shipped
@@ -0,0 +1,239 @@
+/* ANSI-C code produced by gperf version 3.0.1 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+struct kconf_id;
+/* maximum key range = 45, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 25, 30, 15,
+       0, 15,  0, 47,  5, 15, 47, 47, 30, 20,
+       5,  0, 25, 15,  0,  0, 10, 35, 47, 47,
+       5, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("on")];
+    char kconf_id_strings_str6[sizeof("string")];
+    char kconf_id_strings_str7[sizeof("default")];
+    char kconf_id_strings_str8[sizeof("def_bool")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("def_boolean")];
+    char kconf_id_strings_str12[sizeof("def_tristate")];
+    char kconf_id_strings_str13[sizeof("hex")];
+    char kconf_id_strings_str14[sizeof("defconfig_list")];
+    char kconf_id_strings_str16[sizeof("option")];
+    char kconf_id_strings_str17[sizeof("if")];
+    char kconf_id_strings_str18[sizeof("optional")];
+    char kconf_id_strings_str20[sizeof("endif")];
+    char kconf_id_strings_str21[sizeof("choice")];
+    char kconf_id_strings_str22[sizeof("endmenu")];
+    char kconf_id_strings_str23[sizeof("requires")];
+    char kconf_id_strings_str24[sizeof("endchoice")];
+    char kconf_id_strings_str26[sizeof("config")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("int")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str31[sizeof("prompt")];
+    char kconf_id_strings_str32[sizeof("depends")];
+    char kconf_id_strings_str33[sizeof("tristate")];
+    char kconf_id_strings_str34[sizeof("bool")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str36[sizeof("select")];
+    char kconf_id_strings_str37[sizeof("boolean")];
+    char kconf_id_strings_str39[sizeof("help")];
+    char kconf_id_strings_str41[sizeof("source")];
+    char kconf_id_strings_str42[sizeof("comment")];
+    char kconf_id_strings_str43[sizeof("mainmenu")];
+    char kconf_id_strings_str46[sizeof("enable")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "on",
+    "string",
+    "default",
+    "def_bool",
+    "range",
+    "def_boolean",
+    "def_tristate",
+    "hex",
+    "defconfig_list",
+    "option",
+    "if",
+    "optional",
+    "endif",
+    "choice",
+    "endmenu",
+    "requires",
+    "endchoice",
+    "config",
+    "modules",
+    "int",
+    "menu",
+    "prompt",
+    "depends",
+    "tristate",
+    "bool",
+    "menuconfig",
+    "select",
+    "boolean",
+    "help",
+    "source",
+    "comment",
+    "mainmenu",
+    "enable"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 33,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 14,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 46
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_ON,		TF_PARAM},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_TYPE,		TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,		T_RANGE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,		T_TYPE,		TF_COMMAND, S_HEX},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,	T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,		T_OPTION,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,		T_IF,		TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,	T_OPTIONAL,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20,		T_ENDIF,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_CHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,	T_ENDMENU,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,	T_REQUIRES,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str24,	T_ENDCHOICE,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,		T_CONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,		T_TYPE,		TF_COMMAND, S_INT},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_PROMPT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_DEPENDS,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,	T_MENUCONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,		T_SELECT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39,		T_HELP,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_SOURCE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42,	T_COMMENT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43,	T_MAINMENU,	TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,		T_SELECT,	TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+
diff --git a/toybox/kconfig/zconf.tab.c_shipped b/toybox/kconfig/zconf.tab.c_shipped
new file mode 100644
index 0000000..34ccabd
--- /dev/null
+++ b/toybox/kconfig/zconf.tab.c_shipped
@@ -0,0 +1,2345 @@
+/* A Bison parser, made by GNU Bison 2.1.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Written by Richard Stallman by simplifying the original so called
+   ``semantic'' parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.1"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse zconfparse
+#define yylex   zconflex
+#define yyerror zconferror
+#define yylval  zconflval
+#define yychar  zconfchar
+#define yydebug zconfdebug
+#define yynerrs zconfnerrs
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     T_MAINMENU = 258,
+     T_MENU = 259,
+     T_ENDMENU = 260,
+     T_SOURCE = 261,
+     T_CHOICE = 262,
+     T_ENDCHOICE = 263,
+     T_COMMENT = 264,
+     T_CONFIG = 265,
+     T_MENUCONFIG = 266,
+     T_HELP = 267,
+     T_HELPTEXT = 268,
+     T_IF = 269,
+     T_ENDIF = 270,
+     T_DEPENDS = 271,
+     T_REQUIRES = 272,
+     T_OPTIONAL = 273,
+     T_PROMPT = 274,
+     T_TYPE = 275,
+     T_DEFAULT = 276,
+     T_SELECT = 277,
+     T_RANGE = 278,
+     T_OPTION = 279,
+     T_ON = 280,
+     T_WORD = 281,
+     T_WORD_QUOTE = 282,
+     T_UNEQUAL = 283,
+     T_CLOSE_PAREN = 284,
+     T_OPEN_PAREN = 285,
+     T_EOL = 286,
+     T_OR = 287,
+     T_AND = 288,
+     T_EQUAL = 289,
+     T_NOT = 290
+   };
+#endif
+/* Tokens.  */
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_MENUCONFIG 266
+#define T_HELP 267
+#define T_HELPTEXT 268
+#define T_IF 269
+#define T_ENDIF 270
+#define T_DEPENDS 271
+#define T_REQUIRES 272
+#define T_OPTIONAL 273
+#define T_PROMPT 274
+#define T_TYPE 275
+#define T_DEFAULT 276
+#define T_SELECT 277
+#define T_RANGE 278
+#define T_OPTION 279
+#define T_ON 280
+#define T_WORD 281
+#define T_WORD_QUOTE 282
+#define T_UNEQUAL 283
+#define T_CLOSE_PAREN 284
+#define T_OPEN_PAREN 285
+#define T_EOL 286
+#define T_OR 287
+#define T_AND 288
+#define T_EQUAL 289
+#define T_NOT 290
+
+
+
+
+/* Copy the first part of user declarations.  */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD		0x0001
+#define DEBUG_PARSE	0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[257];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+
+typedef union YYSTYPE {
+	char *string;
+	struct file *file;
+	struct symbol *symbol;
+	struct expr *expr;
+	struct menu *menu;
+	struct kconf_id *id;
+} YYSTYPE;
+/* Line 196 of yacc.c.  */
+
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 219 of yacc.c.  */
+
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus))
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if defined (__STDC__) || defined (__cplusplus)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     define YYINCLUDED_STDLIB_H
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning. */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1)
+#  endif
+#  ifdef __cplusplus
+extern "C" {
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \
+	&& (defined (__STDC__) || defined (__cplusplus)))
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \
+	&& (defined (__STDC__) || defined (__cplusplus)))
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifdef __cplusplus
+}
+#  endif
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+	 || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short int yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short int) + sizeof (YYSTYPE))			\
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined (__GNUC__) && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+   typedef signed char yysigned_char;
+#else
+   typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL  3
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   275
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS  36
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS  45
+/* YYNRULES -- Number of rules. */
+#define YYNRULES  110
+/* YYNRULES -- Number of states. */
+#define YYNSTATES  183
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   290
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const unsigned char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const unsigned short int yyprhs[] =
+{
+       0,     0,     3,     5,     6,     9,    12,    15,    20,    23,
+      28,    33,    37,    39,    41,    43,    45,    47,    49,    51,
+      53,    55,    57,    59,    61,    63,    67,    70,    74,    77,
+      81,    84,    85,    88,    91,    94,    97,   100,   103,   107,
+     112,   117,   122,   128,   132,   133,   137,   138,   141,   144,
+     147,   149,   153,   154,   157,   160,   163,   166,   169,   174,
+     178,   181,   186,   187,   190,   194,   196,   200,   201,   204,
+     207,   210,   214,   217,   219,   223,   224,   227,   230,   233,
+     237,   241,   244,   247,   250,   251,   254,   257,   260,   265,
+     269,   273,   274,   277,   279,   281,   284,   287,   290,   292,
+     295,   296,   299,   301,   305,   309,   313,   316,   320,   324,
+     326
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+      37,     0,    -1,    38,    -1,    -1,    38,    40,    -1,    38,
+      54,    -1,    38,    65,    -1,    38,     3,    75,    77,    -1,
+      38,    76,    -1,    38,    26,     1,    31,    -1,    38,    39,
+       1,    31,    -1,    38,     1,    31,    -1,    16,    -1,    19,
+      -1,    20,    -1,    22,    -1,    18,    -1,    23,    -1,    21,
+      -1,    31,    -1,    60,    -1,    69,    -1,    43,    -1,    45,
+      -1,    67,    -1,    26,     1,    31,    -1,     1,    31,    -1,
+      10,    26,    31,    -1,    42,    46,    -1,    11,    26,    31,
+      -1,    44,    46,    -1,    -1,    46,    47,    -1,    46,    48,
+      -1,    46,    73,    -1,    46,    71,    -1,    46,    41,    -1,
+      46,    31,    -1,    20,    74,    31,    -1,    19,    75,    78,
+      31,    -1,    21,    79,    78,    31,    -1,    22,    26,    78,
+      31,    -1,    23,    80,    80,    78,    31,    -1,    24,    49,
+      31,    -1,    -1,    49,    26,    50,    -1,    -1,    34,    75,
+      -1,     7,    31,    -1,    51,    55,    -1,    76,    -1,    52,
+      57,    53,    -1,    -1,    55,    56,    -1,    55,    73,    -1,
+      55,    71,    -1,    55,    31,    -1,    55,    41,    -1,    19,
+      75,    78,    31,    -1,    20,    74,    31,    -1,    18,    31,
+      -1,    21,    26,    78,    31,    -1,    -1,    57,    40,    -1,
+      14,    79,    77,    -1,    76,    -1,    58,    61,    59,    -1,
+      -1,    61,    40,    -1,    61,    65,    -1,    61,    54,    -1,
+       4,    75,    31,    -1,    62,    72,    -1,    76,    -1,    63,
+      66,    64,    -1,    -1,    66,    40,    -1,    66,    65,    -1,
+      66,    54,    -1,     6,    75,    31,    -1,     9,    75,    31,
+      -1,    68,    72,    -1,    12,    31,    -1,    70,    13,    -1,
+      -1,    72,    73,    -1,    72,    31,    -1,    72,    41,    -1,
+      16,    25,    79,    31,    -1,    16,    79,    31,    -1,    17,
+      79,    31,    -1,    -1,    75,    78,    -1,    26,    -1,    27,
+      -1,     5,    31,    -1,     8,    31,    -1,    15,    31,    -1,
+      31,    -1,    77,    31,    -1,    -1,    14,    79,    -1,    80,
+      -1,    80,    34,    80,    -1,    80,    28,    80,    -1,    30,
+      79,    29,    -1,    35,    79,    -1,    79,    32,    79,    -1,
+      79,    33,    79,    -1,    26,    -1,    27,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const unsigned short int yyrline[] =
+{
+       0,   105,   105,   107,   109,   110,   111,   112,   113,   114,
+     115,   119,   123,   123,   123,   123,   123,   123,   123,   127,
+     128,   129,   130,   131,   132,   136,   137,   143,   151,   157,
+     165,   175,   177,   178,   179,   180,   181,   182,   185,   193,
+     199,   209,   215,   221,   224,   226,   237,   238,   243,   252,
+     257,   265,   268,   270,   271,   272,   273,   274,   277,   283,
+     294,   300,   310,   312,   317,   325,   333,   336,   338,   339,
+     340,   345,   352,   357,   365,   368,   370,   371,   372,   375,
+     383,   390,   397,   403,   410,   412,   413,   414,   417,   422,
+     427,   435,   437,   442,   443,   446,   447,   448,   452,   453,
+     456,   457,   460,   461,   462,   463,   464,   465,   466,   469,
+     470
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT",
+  "T_SELECT", "T_RANGE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE",
+  "T_UNEQUAL", "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND",
+  "T_EQUAL", "T_NOT", "$accept", "input", "stmt_list", "option_name",
+  "common_stmt", "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "symbol_option", "symbol_option_list",
+  "symbol_option_arg", "choice", "choice_entry", "choice_end",
+  "choice_stmt", "choice_option_list", "choice_option", "choice_block",
+  "if_entry", "if_end", "if_stmt", "if_block", "menu", "menu_entry",
+  "menu_end", "menu_stmt", "menu_block", "source_stmt", "comment",
+  "comment_stmt", "help_start", "help", "depends_list", "depends",
+  "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", "symbol", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const unsigned short int yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const unsigned char yyr1[] =
+{
+       0,    36,    37,    38,    38,    38,    38,    38,    38,    38,
+      38,    38,    39,    39,    39,    39,    39,    39,    39,    40,
+      40,    40,    40,    40,    40,    41,    41,    42,    43,    44,
+      45,    46,    46,    46,    46,    46,    46,    46,    47,    47,
+      47,    47,    47,    48,    49,    49,    50,    50,    51,    52,
+      53,    54,    55,    55,    55,    55,    55,    55,    56,    56,
+      56,    56,    57,    57,    58,    59,    60,    61,    61,    61,
+      61,    62,    63,    64,    65,    66,    66,    66,    66,    67,
+      68,    69,    70,    71,    72,    72,    72,    72,    73,    73,
+      73,    74,    74,    75,    75,    76,    76,    76,    77,    77,
+      78,    78,    79,    79,    79,    79,    79,    79,    79,    80,
+      80
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const unsigned char yyr2[] =
+{
+       0,     2,     1,     0,     2,     2,     2,     4,     2,     4,
+       4,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     3,     2,     3,     2,     3,
+       2,     0,     2,     2,     2,     2,     2,     2,     3,     4,
+       4,     4,     5,     3,     0,     3,     0,     2,     2,     2,
+       1,     3,     0,     2,     2,     2,     2,     2,     4,     3,
+       2,     4,     0,     2,     3,     1,     3,     0,     2,     2,
+       2,     3,     2,     1,     3,     0,     2,     2,     2,     3,
+       3,     2,     2,     2,     0,     2,     2,     2,     4,     3,
+       3,     0,     2,     1,     1,     2,     2,     2,     1,     2,
+       0,     2,     1,     3,     3,     3,     2,     3,     3,     1,
+       1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const unsigned char yydefact[] =
+{
+       3,     0,     0,     1,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    12,    16,    13,    14,
+      18,    15,    17,     0,    19,     0,     4,    31,    22,    31,
+      23,    52,    62,     5,    67,    20,    84,    75,     6,    24,
+      84,    21,     8,    11,    93,    94,     0,     0,    95,     0,
+      48,    96,     0,     0,     0,   109,   110,     0,     0,     0,
+     102,    97,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    98,     7,    71,    79,    80,    27,    29,     0,
+     106,     0,     0,    64,     0,     0,     9,    10,     0,     0,
+       0,     0,     0,    91,     0,     0,     0,    44,     0,    37,
+      36,    32,    33,     0,    35,    34,     0,     0,    91,     0,
+      56,    57,    53,    55,    54,    63,    51,    50,    68,    70,
+      66,    69,    65,    86,    87,    85,    76,    78,    74,    77,
+      73,    99,   105,   107,   108,   104,   103,    26,    82,     0,
+       0,     0,   100,     0,   100,   100,   100,     0,     0,     0,
+      83,    60,   100,     0,   100,     0,    89,    90,     0,     0,
+      38,    92,     0,     0,   100,    46,    43,    25,     0,    59,
+       0,    88,   101,    39,    40,    41,     0,     0,    45,    58,
+      61,    42,    47
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short int yydefgoto[] =
+{
+      -1,     1,     2,    25,    26,   100,    27,    28,    29,    30,
+      64,   101,   102,   148,   178,    31,    32,   116,    33,    66,
+     112,    67,    34,   120,    35,    68,    36,    37,   128,    38,
+      70,    39,    40,    41,   103,   104,    69,   105,   143,   144,
+      42,    73,   159,    59,    60
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -135
+static const short int yypact[] =
+{
+    -135,     2,   170,  -135,   -14,    56,    56,    -8,    56,    24,
+      67,    56,     7,    14,    62,    97,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,   156,  -135,   166,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,   138,   151,  -135,   152,
+    -135,  -135,   163,   167,   176,  -135,  -135,    62,    62,   185,
+     -19,  -135,   188,   190,    42,   103,   194,    85,    70,   222,
+      70,   132,  -135,   191,  -135,  -135,  -135,  -135,  -135,   127,
+    -135,    62,    62,   191,   104,   104,  -135,  -135,   193,   203,
+       9,    62,    56,    56,    62,   161,   104,  -135,   196,  -135,
+    -135,  -135,  -135,   233,  -135,  -135,   204,    56,    56,   221,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,   219,  -135,  -135,  -135,  -135,  -135,    62,
+     209,   212,   240,   224,   240,    -1,   240,   104,    41,   225,
+    -135,  -135,   240,   226,   240,   218,  -135,  -135,    62,   227,
+    -135,  -135,   228,   229,   240,   230,  -135,  -135,   231,  -135,
+     232,  -135,   112,  -135,  -135,  -135,   234,    56,  -135,  -135,
+    -135,  -135,  -135
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const short int yypgoto[] =
+{
+    -135,  -135,  -135,  -135,    94,   -45,  -135,  -135,  -135,  -135,
+     237,  -135,  -135,  -135,  -135,  -135,  -135,  -135,   -54,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,     1,
+    -135,  -135,  -135,  -135,  -135,   195,   235,   -44,   159,    -5,
+      98,   210,  -134,   -53,   -77
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -82
+static const short int yytable[] =
+{
+      46,    47,     3,    49,    79,    80,    52,   135,   136,    84,
+     161,   162,   163,   158,   119,    85,   127,    43,   168,   147,
+     170,   111,   114,    48,   124,   125,   124,   125,   133,   134,
+     176,    81,    82,    53,   139,    55,    56,   140,   141,    57,
+      54,   145,   -28,    88,    58,   -28,   -28,   -28,   -28,   -28,
+     -28,   -28,   -28,   -28,    89,    50,   -28,   -28,    90,    91,
+     -28,    92,    93,    94,    95,    96,    97,   165,    98,   121,
+     164,   129,   166,    99,     6,     7,     8,     9,    10,    11,
+      12,    13,    44,    45,    14,    15,   155,   142,    55,    56,
+       7,     8,    57,    10,    11,    12,    13,    58,    51,    14,
+      15,    24,   152,   -30,    88,   172,   -30,   -30,   -30,   -30,
+     -30,   -30,   -30,   -30,   -30,    89,    24,   -30,   -30,    90,
+      91,   -30,    92,    93,    94,    95,    96,    97,    61,    98,
+      55,    56,   -81,    88,    99,   -81,   -81,   -81,   -81,   -81,
+     -81,   -81,   -81,   -81,    81,    82,   -81,   -81,    90,    91,
+     -81,   -81,   -81,   -81,   -81,   -81,   132,    62,    98,    81,
+      82,   115,   118,   123,   126,   117,   122,    63,   130,    72,
+      -2,     4,   182,     5,     6,     7,     8,     9,    10,    11,
+      12,    13,    74,    75,    14,    15,    16,   146,    17,    18,
+      19,    20,    21,    22,    76,    88,    23,   149,    77,   -49,
+     -49,    24,   -49,   -49,   -49,   -49,    89,    78,   -49,   -49,
+      90,    91,   106,   107,   108,   109,    72,    81,    82,    86,
+      98,    87,   131,    88,   137,   110,   -72,   -72,   -72,   -72,
+     -72,   -72,   -72,   -72,   138,   151,   -72,   -72,    90,    91,
+     156,    81,    82,   157,    81,    82,   150,   154,    98,   171,
+      81,    82,    82,   123,   158,   160,   167,   169,   173,   174,
+     175,   113,   179,   180,   177,   181,    65,   153,     0,    83,
+       0,     0,     0,     0,     0,    71
+};
+
+static const short int yycheck[] =
+{
+       5,     6,     0,     8,    57,    58,    11,    84,    85,    28,
+     144,   145,   146,    14,    68,    34,    70,    31,   152,    96,
+     154,    66,    66,    31,    69,    69,    71,    71,    81,    82,
+     164,    32,    33,    26,    25,    26,    27,    90,    91,    30,
+      26,    94,     0,     1,    35,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    31,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    26,    26,    68,
+     147,    70,    31,    31,     4,     5,     6,     7,     8,     9,
+      10,    11,    26,    27,    14,    15,   139,    92,    26,    27,
+       5,     6,    30,     8,     9,    10,    11,    35,    31,    14,
+      15,    31,   107,     0,     1,   158,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    31,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    31,    26,
+      26,    27,     0,     1,    31,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    32,    33,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    29,     1,    26,    32,
+      33,    67,    68,    31,    70,    67,    68,     1,    70,    31,
+       0,     1,   177,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    31,    31,    14,    15,    16,    26,    18,    19,
+      20,    21,    22,    23,    31,     1,    26,     1,    31,     5,
+       6,    31,     8,     9,    10,    11,    12,    31,    14,    15,
+      16,    17,    18,    19,    20,    21,    31,    32,    33,    31,
+      26,    31,    31,     1,    31,    31,     4,     5,     6,     7,
+       8,     9,    10,    11,    31,    31,    14,    15,    16,    17,
+      31,    32,    33,    31,    32,    33,    13,    26,    26,    31,
+      32,    33,    33,    31,    14,    31,    31,    31,    31,    31,
+      31,    66,    31,    31,    34,    31,    29,   108,    -1,    59,
+      -1,    -1,    -1,    -1,    -1,    40
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const unsigned char yystos[] =
+{
+       0,    37,    38,     0,     1,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    14,    15,    16,    18,    19,    20,
+      21,    22,    23,    26,    31,    39,    40,    42,    43,    44,
+      45,    51,    52,    54,    58,    60,    62,    63,    65,    67,
+      68,    69,    76,    31,    26,    27,    75,    75,    31,    75,
+      31,    31,    75,    26,    26,    26,    27,    30,    35,    79,
+      80,    31,     1,     1,    46,    46,    55,    57,    61,    72,
+      66,    72,    31,    77,    31,    31,    31,    31,    31,    79,
+      79,    32,    33,    77,    28,    34,    31,    31,     1,    12,
+      16,    17,    19,    20,    21,    22,    23,    24,    26,    31,
+      41,    47,    48,    70,    71,    73,    18,    19,    20,    21,
+      31,    41,    56,    71,    73,    40,    53,    76,    40,    54,
+      59,    65,    76,    31,    41,    73,    40,    54,    64,    65,
+      76,    31,    29,    79,    79,    80,    80,    31,    31,    25,
+      79,    79,    75,    74,    75,    79,    26,    80,    49,     1,
+      13,    31,    75,    74,    26,    79,    31,    31,    14,    78,
+      31,    78,    78,    78,    80,    26,    31,    31,    78,    31,
+      78,    31,    79,    31,    31,    31,    78,    34,    50,    31,
+      31,    31,    75
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (0)
+
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)				\
+    do									\
+      if (N)								\
+	{								\
+	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
+	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
+	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
+	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
+	}								\
+      else								\
+	{								\
+	  (Current).first_line   = (Current).last_line   =		\
+	    YYRHSLOC (Rhs, 0).last_line;				\
+	  (Current).first_column = (Current).last_column =		\
+	    YYRHSLOC (Rhs, 0).last_column;				\
+	}								\
+    while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)			\
+     fprintf (File, "%d.%d-%d.%d",			\
+              (Loc).first_line, (Loc).first_column,	\
+              (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (0)
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)		\
+do {								\
+  if (yydebug)							\
+    {								\
+      YYFPRINTF (stderr, "%s ", Title);				\
+      yysymprint (stderr,					\
+                  Type, Value);	\
+      YYFPRINTF (stderr, "\n");					\
+    }								\
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    short int *bottom;
+    short int *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (/* Nothing. */; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+    int yyrule;
+#endif
+{
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ",
+             yyrule - 1, yylno);
+  /* Print the symbols being reduced, and their result.  */
+  for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+    YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+  YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (Rule);		\
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      size_t yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+#endif /* YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+  YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+      case 52: /* "choice_entry" */
+
+        {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+        break;
+      case 58: /* "if_entry" */
+
+        {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+        break;
+      case 63: /* "menu_entry" */
+
+        {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		(yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+	if (current_menu == (yyvaluep->menu))
+		menu_end_menu();
+};
+
+        break;
+
+      default:
+        break;
+    }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+  void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+    ;
+#endif
+#endif
+{
+  
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  short int yyssa[YYINITDEPTH];
+  short int *yyss = yyssa;
+  short int *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule.  */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack. Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	short int *yyss1 = yyss;
+
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	short int *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a look-ahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 8:
+
+    { zconf_error("unexpected end statement"); ;}
+    break;
+
+  case 9:
+
+    { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); ;}
+    break;
+
+  case 10:
+
+    {
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[-2].id)->name);
+;}
+    break;
+
+  case 11:
+
+    { zconf_error("invalid statement"); ;}
+    break;
+
+  case 25:
+
+    { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); ;}
+    break;
+
+  case 26:
+
+    { zconf_error("invalid option"); ;}
+    break;
+
+  case 27:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+;}
+    break;
+
+  case 28:
+
+    {
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 29:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+;}
+    break;
+
+  case 30:
+
+    {
+	if (current_entry->prompt)
+		current_entry->prompt->type = P_MENU;
+	else
+		zconfprint("warning: menuconfig statement without prompt");
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 38:
+
+    {
+	menu_set_type((yyvsp[-2].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[-2].id)->stype);
+;}
+    break;
+
+  case 39:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 40:
+
+    {
+	menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr));
+	if ((yyvsp[-3].id)->stype != S_UNKNOWN)
+		menu_set_type((yyvsp[-3].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[-3].id)->stype);
+;}
+    break;
+
+  case 41:
+
+    {
+	menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 42:
+
+    {
+	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 45:
+
+    {
+	struct kconf_id *id = kconf_id_lookup((yyvsp[-1].string), strlen((yyvsp[-1].string)));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, (yyvsp[0].string));
+	else
+		zconfprint("warning: ignoring unknown option %s", (yyvsp[-1].string));
+	free((yyvsp[-1].string));
+;}
+    break;
+
+  case 46:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+  case 47:
+
+    { (yyval.string) = (yyvsp[0].string); ;}
+    break;
+
+  case 48:
+
+    {
+	struct symbol *sym = sym_lookup(NULL, 0);
+	sym->flags |= SYMBOL_CHOICE;
+	menu_add_entry(sym);
+	menu_add_expr(P_CHOICE, NULL, NULL);
+	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 49:
+
+    {
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 50:
+
+    {
+	if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 58:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 59:
+
+    {
+	if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) {
+		menu_set_type((yyvsp[-2].id)->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			(yyvsp[-2].id)->stype);
+	} else
+		YYERROR;
+;}
+    break;
+
+  case 60:
+
+    {
+	current_entry->sym->flags |= SYMBOL_OPTIONAL;
+	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 61:
+
+    {
+	if ((yyvsp[-3].id)->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
+;}
+    break;
+
+  case 64:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+	menu_add_entry(NULL);
+	menu_add_dep((yyvsp[-1].expr));
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 65:
+
+    {
+	if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 71:
+
+    {
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 72:
+
+    {
+	(yyval.menu) = menu_add_menu();
+;}
+    break;
+
+  case 73:
+
+    {
+	if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+	}
+;}
+    break;
+
+  case 79:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+	zconf_nextfile((yyvsp[-1].string));
+;}
+    break;
+
+  case 80:
+
+    {
+	menu_add_entry(NULL);
+	menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 81:
+
+    {
+	menu_end_entry();
+;}
+    break;
+
+  case 82:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+	zconf_starthelp();
+;}
+    break;
+
+  case 83:
+
+    {
+	current_entry->sym->help = (yyvsp[0].string);
+;}
+    break;
+
+  case 88:
+
+    {
+	menu_add_dep((yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 89:
+
+    {
+	menu_add_dep((yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 90:
+
+    {
+	menu_add_dep((yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
+;}
+    break;
+
+  case 92:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr));
+;}
+    break;
+
+  case 95:
+
+    { (yyval.id) = (yyvsp[-1].id); ;}
+    break;
+
+  case 96:
+
+    { (yyval.id) = (yyvsp[-1].id); ;}
+    break;
+
+  case 97:
+
+    { (yyval.id) = (yyvsp[-1].id); ;}
+    break;
+
+  case 100:
+
+    { (yyval.expr) = NULL; ;}
+    break;
+
+  case 101:
+
+    { (yyval.expr) = (yyvsp[0].expr); ;}
+    break;
+
+  case 102:
+
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); ;}
+    break;
+
+  case 103:
+
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
+    break;
+
+  case 104:
+
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
+    break;
+
+  case 105:
+
+    { (yyval.expr) = (yyvsp[-1].expr); ;}
+    break;
+
+  case 106:
+
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); ;}
+    break;
+
+  case 107:
+
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
+    break;
+
+  case 108:
+
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
+    break;
+
+  case 109:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); ;}
+    break;
+
+  case 110:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 1); free((yyvsp[0].string)); ;}
+    break;
+
+
+      default: break;
+    }
+
+/* Line 1126 of yacc.c.  */
+
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+
+
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (YYPACT_NINF < yyn && yyn < YYLAST)
+	{
+	  int yytype = YYTRANSLATE (yychar);
+	  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+	  YYSIZE_T yysize = yysize0;
+	  YYSIZE_T yysize1;
+	  int yysize_overflow = 0;
+	  char *yymsg = 0;
+#	  define YYERROR_VERBOSE_ARGS_MAXIMUM 5
+	  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+	  int yyx;
+
+#if 0
+	  /* This is so xgettext sees the translatable formats that are
+	     constructed on the fly.  */
+	  YY_("syntax error, unexpected %s");
+	  YY_("syntax error, unexpected %s, expecting %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+#endif
+	  char *yyfmt;
+	  char const *yyf;
+	  static char const yyunexpected[] = "syntax error, unexpected %s";
+	  static char const yyexpecting[] = ", expecting %s";
+	  static char const yyor[] = " or %s";
+	  char yyformat[sizeof yyunexpected
+			+ sizeof yyexpecting - 1
+			+ ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+			   * (sizeof yyor - 1))];
+	  char const *yyprefix = yyexpecting;
+
+	  /* Start YYX at -YYN if negative to avoid negative indexes in
+	     YYCHECK.  */
+	  int yyxbegin = yyn < 0 ? -yyn : 0;
+
+	  /* Stay within bounds of both yycheck and yytname.  */
+	  int yychecklim = YYLAST - yyn;
+	  int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+	  int yycount = 1;
+
+	  yyarg[0] = yytname[yytype];
+	  yyfmt = yystpcpy (yyformat, yyunexpected);
+
+	  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	      {
+		if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+		  {
+		    yycount = 1;
+		    yysize = yysize0;
+		    yyformat[sizeof yyunexpected - 1] = '\0';
+		    break;
+		  }
+		yyarg[yycount++] = yytname[yyx];
+		yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+		yysize_overflow |= yysize1 < yysize;
+		yysize = yysize1;
+		yyfmt = yystpcpy (yyfmt, yyprefix);
+		yyprefix = yyor;
+	      }
+
+	  yyf = YY_(yyformat);
+	  yysize1 = yysize + yystrlen (yyf);
+	  yysize_overflow |= yysize1 < yysize;
+	  yysize = yysize1;
+
+	  if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM)
+	    yymsg = (char *) YYSTACK_ALLOC (yysize);
+	  if (yymsg)
+	    {
+	      /* Avoid sprintf, as that infringes on the user's name space.
+		 Don't have undefined behavior even if the translation
+		 produced a string with the wrong number of "%s"s.  */
+	      char *yyp = yymsg;
+	      int yyi = 0;
+	      while ((*yyp = *yyf))
+		{
+		  if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		    {
+		      yyp += yytnamerr (yyp, yyarg[yyi++]);
+		      yyf += 2;
+		    }
+		  else
+		    {
+		      yyp++;
+		      yyf++;
+		    }
+		}
+	      yyerror (yymsg);
+	      YYSTACK_FREE (yymsg);
+	    }
+	  else
+	    {
+	      yyerror (YY_("syntax error"));
+	      goto yyexhaustedlab;
+	    }
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror (YY_("syntax error"));
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+        }
+      else
+	{
+	  yydestruct ("Error: discarding", yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (0)
+     goto yyerrorlab;
+
+yyvsp -= yylen;
+  yyssp -= yylen;
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping", yystos[yystate], yyvsp);
+      YYPOPSTACK;
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token. */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK;
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+	struct symbol *sym;
+	int i;
+
+	zconf_initscan(name);
+
+	sym_init();
+	menu_init();
+	modules_sym = sym_lookup(NULL, 0);
+	modules_sym->type = S_BOOLEAN;
+	modules_sym->flags |= SYMBOL_AUTO;
+	rootmenu.prompt = menu_add_prompt(P_MENU, PROJECT_NAME" Configuration", NULL);
+
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
+	zconfparse();
+	if (zconfnerrs)
+		exit(1);
+	if (!modules_sym->prop) {
+		struct property *prop;
+
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+	}
+	menu_finalize(&rootmenu);
+	for_all_symbols(i, sym) {
+		sym_check_deps(sym);
+        }
+
+	sym_change_count = 1;
+}
+
+const char *zconf_tokenname(int token)
+{
+	switch (token) {
+	case T_MENU:		return "menu";
+	case T_ENDMENU:		return "endmenu";
+	case T_CHOICE:		return "choice";
+	case T_ENDCHOICE:	return "endchoice";
+	case T_IF:		return "if";
+	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
+	}
+	return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	if (current_menu->file != current_file) {
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+void print_quoted_string(FILE *out, const char *str)
+{
+	const char *p;
+	int len;
+
+	putc('"', out);
+	while ((p = strchr(str, '"'))) {
+		len = p - str;
+		if (len)
+			fprintf(out, "%.*s", len, str);
+		fputs("\\\"", out);
+		str = p + 1;
+	}
+	fputs(str, out);
+	putc('"', out);
+}
+
+void print_symbol(FILE *out, struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	struct property *prop;
+
+	if (sym_is_choice(sym))
+		fprintf(out, "choice\n");
+	else
+		fprintf(out, "config %s\n", sym->name);
+	switch (sym->type) {
+	case S_BOOLEAN:
+		fputs("  boolean\n", out);
+		break;
+	case S_TRISTATE:
+		fputs("  tristate\n", out);
+		break;
+	case S_STRING:
+		fputs("  string\n", out);
+		break;
+	case S_INT:
+		fputs("  integer\n", out);
+		break;
+	case S_HEX:
+		fputs("  hex\n", out);
+		break;
+	default:
+		fputs("  ???\n", out);
+		break;
+	}
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu != menu)
+			continue;
+		switch (prop->type) {
+		case P_PROMPT:
+			fputs("  prompt ", out);
+			print_quoted_string(out, prop->text);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_DEFAULT:
+			fputs( "  default ", out);
+			expr_fprint(prop->expr, out);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_CHOICE:
+			fputs("  #choice value\n", out);
+			break;
+		default:
+			fprintf(out, "  unknown prop %d!\n", prop->type);
+			break;
+		}
+	}
+	if (sym->help) {
+		int len = strlen(sym->help);
+		while (sym->help[--len] == '\n')
+			sym->help[len] = 0;
+		fprintf(out, "  help\n%s\n", sym->help);
+	}
+	fputc('\n', out);
+}
+
+void zconfdump(FILE *out)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct menu *menu;
+
+	menu = rootmenu.list;
+	while (menu) {
+		if ((sym = menu->sym))
+			print_symbol(out, menu);
+		else if ((prop = menu->prompt)) {
+			switch (prop->type) {
+			case P_COMMENT:
+				fputs("\ncomment ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			case P_MENU:
+				fputs("\nmenu ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			default:
+				;
+			}
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs("  depends ", out);
+				expr_fprint(prop->visible.expr, out);
+				fputc('\n', out);
+			}
+			fputs("\n", out);
+		}
+
+		if (menu->list)
+			menu = menu->list;
+		else if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->prompt && menu->prompt->type == P_MENU)
+				fputs("\nendmenu\n", out);
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
+
diff --git a/toybox/lib/args.c b/toybox/lib/args.c
new file mode 100644
index 0000000..e6378be
--- /dev/null
+++ b/toybox/lib/args.c
@@ -0,0 +1,497 @@
+/* args.c - Command line argument parsing.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+// NOTE: If option parsing segfaults, switch on TOYBOX_DEBUG in menuconfig.
+
+// Enabling TOYBOX_DEBUG in .config adds syntax checks to option string parsing
+// which aren't needed in the final code (your option string is hardwired and
+// should be correct when you ship), but are useful for development.
+
+#include "toys.h"
+
+// Design goals:
+//   Don't use getopt() out of libc.
+//   Don't permute original arguments (screwing up ps/top output).
+//   Integrated --long options "(noshort)a(along)b(blong1)(blong2)"
+
+/* This uses a getopt-like option string, but not getopt() itself. We call
+ * it the get_opt string.
+ *
+ * Each option in the get_opt string corresponds to a bit position in the
+ * return value. The rightmost argument is (1<<0), the next to last is (1<<1)
+ * and so on. If the option isn't seen in argv[], its bit remains 0.
+ *
+ * Options which have an argument fill in the corresponding slot in the global
+ * union "this" (see generated/globals.h), which it treats as an array of longs
+ * (note that sizeof(long)==sizeof(pointer) is guaranteed by LP64).
+ *
+ * You don't have to free the option strings, which point into the environment
+ * space. List objects should be freed by main() when command_main() returns.
+ *
+ * Example:
+ *   Calling get_optflags() when toys.which->options="ab:c:d" and
+ *   argv = ["command", "-b", "fruit", "-d", "walrus"] results in:
+ *
+ *     Changes to struct toys:
+ *       toys.optflags = 5 (I.E. 0101 so -b = 4 | -d = 1)
+ *       toys.optargs[0] = "walrus" (leftover argument)
+ *       toys.optargs[1] = NULL (end of list)
+ *       toys.optc = 1 (there was 1 leftover argument)
+ *
+ *     Changes to union this:
+ *       this[0]=NULL (because -c didn't get an argument this time)
+ *       this[1]="fruit" (argument to -b)
+ */
+
+// What you can put in a get_opt string:
+//   Any otherwise unused character (all letters, unprefixed numbers) specify
+//   an option that sets a flag. The bit value is the same as the binary digit
+//   if you string the option characters together in order.
+//   So in "abcdefgh" a = 128, h = 1
+//
+//   Suffixes specify that this option takes an argument (stored in GLOBALS):
+//       Note that pointer and long are always the same size, even on 64 bit.
+//     : plus a string argument, keep most recent if more than one
+//     * plus a string argument, appended to a list
+//     # plus a signed long argument
+//       <LOW     - die if less than LOW
+//       >HIGH    - die if greater than HIGH
+//       =DEFAULT - value if not specified
+//     - plus a signed long argument defaulting to negative (say + for positive)
+//     . plus a double precision floating point argument (with CFG_TOYBOX_FLOAT)
+//       Chop this option out with USE_TOYBOX_FLOAT() in option string
+//       Same <LOW>HIGH=DEFAULT as #
+//     @ plus an occurrence counter (which is a long)
+//     (longopt)
+//     | this is required. If more than one marked, only one required.
+//     ; long option's argument is optional (can only be supplied with --opt=)
+//     ^ Stop parsing after encountering this argument
+//    " " (space char) the "plus an argument" must be separate
+//        I.E. "-j 3" not "-j3". So "kill -stop" != "kill -s top"
+//
+//   At the beginning of the get_opt string (before any options):
+//     ^ stop at first nonoption argument
+//     <0 die if less than # leftover arguments (default 0)
+//     >9 die if > # leftover arguments (default MAX_INT)
+//     ? Allow unknown arguments (pass them through to command).
+//     & first argument has imaginary dash (ala tar/ps)
+//       If given twice, all arguments have imaginary dash
+//
+//   At the end: [groups] of previously seen options
+//     - Only one in group (switch off)    [-abc] means -ab=-b, -ba=-a, -abc=-c
+//     + Synonyms (switch on all)          [+abc] means -ab=-abc, -c=-abc
+//     ! More than one in group is error   [!abc] means -ab calls error_exit()
+//       primarily useful if you can switch things back off again.
+
+// Notes from getopt man page
+//   - and -- cannot be arguments.
+//     -- force end of arguments
+//     - is a synonym for stdin in file arguments
+//   -abcd means -a -b -c -d (but if -b takes an argument, then it's -a -b cd)
+
+// Linked list of all known options (option string parsed into this).
+// Hangs off getoptflagstate, freed at end of option parsing.
+struct opts {
+  struct opts *next;
+  long *arg;         // Pointer into union "this" to store arguments at.
+  int c;             // Argument character to match
+  int flags;         // |=1, ^=2, " "=4, ;=8
+  unsigned long long dex[3]; // bits to disable/enable/exclude in toys.optflags
+  char type;         // Type of arguments to store union "this"
+  union {
+    long l;
+    FLOAT f;
+  } val[3];          // low, high, default - range of allowed values
+};
+
+// linked list of long options. (Hangs off getoptflagstate, free at end of
+// option parsing, details about flag to set and global slot to fill out
+// stored in related short option struct, but if opt->c = -1 the long option
+// is "bare" (has no corresponding short option).
+struct longopts {
+  struct longopts *next;
+  struct opts *opt;
+  char *str;
+  int len;
+};
+
+// State during argument parsing.
+struct getoptflagstate
+{
+  int argc, minargs, maxargs, nodash;
+  char *arg;
+  struct opts *opts;
+  struct longopts *longopts;
+  int noerror, nodash_now, stopearly;
+  unsigned excludes, requires;
+};
+
+// Use getoptflagstate to parse parse one command line option from argv
+static int gotflag(struct getoptflagstate *gof, struct opts *opt)
+{
+  int type;
+
+  // Did we recognize this option?
+  if (!opt) {
+    if (gof->noerror) return 1;
+    help_exit("Unknown option %s", gof->arg);
+  }
+
+  // Might enabling this switch off something else?
+  if (toys.optflags & opt->dex[0]) {
+    struct opts *clr;
+    unsigned long long i = 1;
+
+    // Forget saved argument for flag we switch back off
+    for (clr=gof->opts, i=1; clr; clr = clr->next, i<<=1)
+      if (clr->arg && (i & toys.optflags & opt->dex[0])) *clr->arg = 0;
+    toys.optflags &= ~opt->dex[0];
+  }
+
+  // Set flags
+  toys.optflags |= opt->dex[1];
+  gof->excludes |= opt->dex[2];
+  if (opt->flags&2) gof->stopearly=2;
+
+  if (toys.optflags & gof->excludes) {
+    struct opts *bad;
+    unsigned i = 1;
+
+    for (bad=gof->opts, i=1; ;bad = bad->next, i<<=1) {
+      if (opt == bad || !(i & toys.optflags)) continue;
+      if (toys.optflags & bad->dex[2]) break;
+    }
+    help_exit("No '%c' with '%c'", opt->c, bad->c);
+  }
+
+  // Does this option take an argument?
+  if (!gof->arg) {
+    if (opt->flags & 8) return 0;
+    gof->arg = "";
+  } else gof->arg++;
+  type = opt->type;
+
+  if (type == '@') ++*(opt->arg);
+  else if (type) {
+    char *arg = gof->arg;
+
+    // Handle "-xblah" and "-x blah", but also a third case: "abxc blah"
+    // to make "tar xCjfv blah1 blah2 thingy" work like
+    // "tar -x -C blah1 -j -f blah2 -v thingy"
+
+    if (gof->nodash_now || (!arg[0] && !(opt->flags & 8)))
+      arg = toys.argv[++gof->argc];
+    if (!arg) {
+      char *s = "Missing argument to ";
+      struct longopts *lo;
+
+      if (opt->c != -1) help_exit("%s-%c", s, opt->c);
+
+      for (lo = gof->longopts; lo->opt != opt; lo = lo->next);
+      help_exit("%s--%.*s", s, lo->len, lo->str);
+    }
+
+    if (type == ':') *(opt->arg) = (long)arg;
+    else if (type == '*') {
+      struct arg_list **list;
+
+      list = (struct arg_list **)opt->arg;
+      while (*list) list=&((*list)->next);
+      *list = xzalloc(sizeof(struct arg_list));
+      (*list)->arg = arg;
+    } else if (type == '#' || type == '-') {
+      long l = atolx(arg);
+      if (type == '-' && !ispunct(*arg)) l*=-1;
+      if (l < opt->val[0].l) help_exit("-%c < %ld", opt->c, opt->val[0].l);
+      if (l > opt->val[1].l) help_exit("-%c > %ld", opt->c, opt->val[1].l);
+
+      *(opt->arg) = l;
+    } else if (CFG_TOYBOX_FLOAT && type == '.') {
+      FLOAT *f = (FLOAT *)(opt->arg);
+
+      *f = strtod(arg, &arg);
+      if (opt->val[0].l != LONG_MIN && *f < opt->val[0].f)
+        help_exit("-%c < %lf", opt->c, (double)opt->val[0].f);
+      if (opt->val[1].l != LONG_MAX && *f > opt->val[1].f)
+        help_exit("-%c > %lf", opt->c, (double)opt->val[1].f);
+    }
+
+    if (!gof->nodash_now) gof->arg = "";
+  }
+
+  return 0;
+}
+
+// Parse this command's options string into struct getoptflagstate, which
+// includes a struct opts linked list in reverse order (I.E. right-to-left)
+void parse_optflaglist(struct getoptflagstate *gof)
+{
+  char *options = toys.which->options;
+  long *nextarg = (long *)&this;
+  struct opts *new = 0;
+  int idx;
+
+  // Parse option format string
+  memset(gof, 0, sizeof(struct getoptflagstate));
+  gof->maxargs = INT_MAX;
+  if (!options) return;
+
+  // Parse leading special behavior indicators
+  for (;;) {
+    if (*options == '^') gof->stopearly++;
+    else if (*options == '<') gof->minargs=*(++options)-'0';
+    else if (*options == '>') gof->maxargs=*(++options)-'0';
+    else if (*options == '?') gof->noerror++;
+    else if (*options == '&') gof->nodash++;
+    else break;
+    options++;
+  }
+
+  // Parse option string into a linked list of options with attributes.
+
+  if (!*options) gof->stopearly++;
+  while (*options) {
+    char *temp;
+
+    // Option groups come after all options are defined
+    if (*options == '[') break;
+
+    // Allocate a new list entry when necessary
+    if (!new) {
+      new = xzalloc(sizeof(struct opts));
+      new->next = gof->opts;
+      gof->opts = new;
+      new->val[0].l = LONG_MIN;
+      new->val[1].l = LONG_MAX;
+    }
+    // Each option must start with "(" or an option character.  (Bare
+    // longopts only come at the start of the string.)
+    if (*options == '(' && new->c != -1) {
+      char *end;
+      struct longopts *lo;
+
+      // Find the end of the longopt
+      for (end = ++options; *end && *end != ')'; end++);
+      if (CFG_TOYBOX_DEBUG && !*end) error_exit("(longopt) didn't end");
+
+      // init a new struct longopts
+      lo = xmalloc(sizeof(struct longopts));
+      lo->next = gof->longopts;
+      lo->opt = new;
+      lo->str = options;
+      lo->len = end-options;
+      gof->longopts = lo;
+      options = ++end;
+
+      // Mark this struct opt as used, even when no short opt.
+      if (!new->c) new->c = -1;
+
+      continue;
+
+    // If this is the start of a new option that wasn't a longopt,
+
+    } else if (strchr(":*#@.-", *options)) {
+      if (CFG_TOYBOX_DEBUG && new->type)
+        error_exit("multiple types %c:%c%c", new->c, new->type, *options);
+      new->type = *options;
+    } else if (-1 != (idx = stridx("|^ ;", *options))) new->flags |= 1<<idx;
+    // bounds checking
+    else if (-1 != (idx = stridx("<>=", *options))) {
+      if (new->type == '#') {
+        long l = strtol(++options, &temp, 10);
+        if (temp != options) new->val[idx].l = l;
+      } else if (CFG_TOYBOX_FLOAT && new->type == '.') {
+        FLOAT f = strtod(++options, &temp);
+        if (temp != options) new->val[idx].f = f;
+      } else if (CFG_TOYBOX_DEBUG) error_exit("<>= only after .#");
+      options = --temp;
+
+    // At this point, we've hit the end of the previous option.  The
+    // current character is the start of a new option.  If we've already
+    // assigned an option to this struct, loop to allocate a new one.
+    // (It'll get back here afterwards and fall through to next else.)
+    } else if (new->c) {
+      new = 0;
+      continue;
+
+    // Claim this option, loop to see what's after it.
+    } else new->c = *options;
+
+    options++;
+  }
+
+  // Initialize enable/disable/exclude masks and pointers to store arguments.
+  // (This goes right to left so we need the whole list before we can start.)
+  idx = 0;
+  for (new = gof->opts; new; new = new->next) {
+    unsigned long long u = 1L<<idx++;
+
+    if (new->c == 1) new->c = 0;
+    new->dex[1] = u;
+    if (new->flags & 1) gof->requires |= u;
+    if (new->type) {
+      new->arg = (void *)nextarg;
+      *(nextarg++) = new->val[2].l;
+    }
+  }
+
+  // Parse trailing group indicators
+  while (*options) {
+    unsigned bits = 0;
+
+    if (CFG_TOYBOX_DEBUG && *options != '[') error_exit("trailing %s", options);
+
+    idx = stridx("-+!", *++options);
+    if (CFG_TOYBOX_DEBUG && idx == -1) error_exit("[ needs +-!");
+    if (CFG_TOYBOX_DEBUG && (options[1] == ']' || !options[1]))
+      error_exit("empty []");
+
+    // Don't advance past ] but do process it once in loop.
+    while (*options++ != ']') {
+      struct opts *opt;
+      int i;
+
+      if (CFG_TOYBOX_DEBUG && !*options) error_exit("[ without ]");
+      // Find this option flag (in previously parsed struct opt)
+      for (i=0, opt = gof->opts; ; i++, opt = opt->next) {
+        if (*options == ']') {
+          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) {
+            bits |= 1<<i;
+            break;
+          }
+        }
+      }
+    }
+  }
+}
+
+// Fill out toys.optflags, toys.optargs, and this[] from toys.argv
+
+void get_optflags(void)
+{
+  struct getoptflagstate gof;
+  struct opts *catch;
+  unsigned long long saveflags;
+  char *letters[]={"s",""};
+
+  // Option parsing is a two stage process: parse the option string into
+  // a struct opts list, then use that list to process argv[];
+
+  // Allocate memory for optargs
+  saveflags = 0;
+  while (toys.argv[saveflags++]);
+  toys.optargs = xzalloc(sizeof(char *)*saveflags);
+
+  parse_optflaglist(&gof);
+
+  // Iterate through command line arguments, skipping argv[0]
+  for (gof.argc=1; toys.argv[gof.argc]; gof.argc++) {
+    gof.arg = toys.argv[gof.argc];
+    catch = NULL;
+
+    // Parse this argument
+    if (gof.stopearly>1) goto notflag;
+
+    gof.nodash_now = 0;
+
+    // Various things with dashes
+    if (*gof.arg == '-') {
+
+      // Handle -
+      if (!gof.arg[1]) goto notflag;
+      gof.arg++;
+      if (*gof.arg=='-') {
+        struct longopts *lo;
+
+        gof.arg++;
+        // Handle --
+        if (!*gof.arg) {
+          gof.stopearly += 2;
+          continue;
+        }
+
+        // do we match a known --longopt?
+        for (lo = gof.longopts; lo; lo = lo->next) {
+          if (!strncmp(gof.arg, lo->str, lo->len)) {
+            if (!gof.arg[lo->len]) gof.arg = 0;
+            else if (gof.arg[lo->len] == '=' && lo->opt->type)
+              gof.arg += lo->len;
+            else continue;
+            // It's a match.
+            catch = lo->opt;
+            break;
+          }
+        }
+
+        // Should we handle this --longopt as a non-option argument?
+        if (!lo && gof.noerror) {
+          gof.arg -= 2;
+          goto notflag;
+        }
+
+        // Long option parsed, handle option.
+        gotflag(&gof, catch);
+        continue;
+      }
+
+    // Handle things that don't start with a dash.
+    } else {
+      if (gof.nodash && (gof.nodash>1 || gof.argc == 1)) gof.nodash_now = 1;
+      else goto notflag;
+    }
+
+    // At this point, we have the args part of -args.  Loop through
+    // each entry (could be -abc meaning -a -b -c)
+    saveflags = toys.optflags;
+    while (*gof.arg) {
+
+      // Identify next option char.
+      for (catch = gof.opts; catch; catch = catch->next)
+        if (*gof.arg == catch->c)
+          if (!((catch->flags&4) && gof.arg[1])) break;
+
+      // Handle option char (advancing past what was used)
+      if (gotflag(&gof, catch) ) {
+        toys.optflags = saveflags;
+        gof.arg = toys.argv[gof.argc];
+        goto notflag;
+      }
+    }
+    continue;
+
+    // Not a flag, save value in toys.optargs[]
+notflag:
+    if (gof.stopearly) gof.stopearly++;
+    toys.optargs[toys.optc++] = toys.argv[gof.argc];
+  }
+
+  // Sanity check
+  if (toys.optc<gof.minargs)
+    help_exit("Need%s %d argument%s", letters[!!(gof.minargs-1)],
+      gof.minargs, letters[!(gof.minargs-1)]);
+  if (toys.optc>gof.maxargs)
+    help_exit("Max %d argument%s", gof.maxargs, letters[!(gof.maxargs-1)]);
+  if (gof.requires && !(gof.requires & toys.optflags)) {
+    struct opts *req;
+    char needs[32], *s = needs;
+
+    for (req = gof.opts; req; req = req->next)
+      if (req->flags & 1) *(s++) = req->c;
+    *s = 0;
+
+    help_exit("Needs %s-%s", s[1] ? "one of " : "", needs);
+  }
+
+  if (CFG_TOYBOX_FREE) {
+    llist_traverse(gof.opts, free);
+    llist_traverse(gof.longopts, free);
+  }
+}
diff --git a/toybox/lib/dirtree.c b/toybox/lib/dirtree.c
new file mode 100644
index 0000000..8f235ed
--- /dev/null
+++ b/toybox/lib/dirtree.c
@@ -0,0 +1,191 @@
+/* dirtree.c - Functions for dealing with directory trees.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ */
+
+#include "toys.h"
+
+static int notdotdot(char *name)
+{
+  if (name[0]=='.' && (!name[1] || (name[1]=='.' && !name[2]))) return 0;
+
+  return 1;
+}
+
+// Default callback, filters out "." and "..".
+
+int dirtree_notdotdot(struct dirtree *catch)
+{
+  // Should we skip "." and ".."?
+  return notdotdot(catch->name)*(DIRTREE_SAVE|DIRTREE_RECURSE);
+}
+
+// Create a dirtree node from a path, with stat and symlink info.
+// (This doesn't open directory filehandles yet so as not to exhaust the
+// filehandle space on large trees, dirtree_handle_callback() does that.)
+
+struct dirtree *dirtree_add_node(struct dirtree *parent, char *name, int flags)
+{
+  struct dirtree *dt = NULL;
+  struct stat st;
+  int len = 0, linklen = 0;
+
+  if (name) {
+    // open code this because haven't got node to call dirtree_parentfd() on yet
+    int fd = parent ? parent->dirfd : AT_FDCWD;
+
+    if (fstatat(fd, name, &st, AT_SYMLINK_NOFOLLOW*!(flags&DIRTREE_SYMFOLLOW)))
+      goto error;
+    if (S_ISLNK(st.st_mode)) {
+      if (0>(linklen = readlinkat(fd, name, libbuf, 4095))) goto error;
+      libbuf[linklen++]=0;
+    }
+    len = strlen(name);
+  }
+  dt = xzalloc((len = sizeof(struct dirtree)+len+1)+linklen);
+  dt->parent = parent;
+  if (name) {
+    memcpy(&(dt->st), &st, sizeof(struct stat));
+    strcpy(dt->name, name);
+
+    if (linklen) dt->symlink = memcpy(len+(char *)dt, libbuf, linklen);
+  }
+
+  return dt;
+
+error:
+  if (!(flags&DIRTREE_SHUTUP) && notdotdot(name)) {
+    char *path = parent ? dirtree_path(parent, 0) : "";
+
+    perror_msg("%s%s%s", path, parent ? "/" : "", name);
+    if (parent) free(path);
+  }
+  if (parent) parent->symlink = (char *)1;
+  free(dt);
+  return 0;
+}
+
+// Return path to this node, assembled recursively.
+
+// Initial call can pass in NULL to plen, or point to an int initialized to 0
+// to return the length of the path, or a value greater than 0 to allocate
+// extra space if you want to append your own text to the string.
+
+char *dirtree_path(struct dirtree *node, int *plen)
+{
+  char *path;
+  int len;
+
+  if (!node) {
+    path = xmalloc(*plen);
+    *plen = 0;
+    return path;
+  }
+
+  len = (plen ? *plen : 0)+strlen(node->name)+1;
+  path = dirtree_path(node->parent, &len);
+  if (len && path[len-1] != '/') path[len++]='/';
+  len = (stpcpy(path+len, node->name) - path);
+  if (plen) *plen = len;
+
+  return path;
+}
+
+int dirtree_parentfd(struct dirtree *node)
+{
+  return node->parent ? node->parent->dirfd : AT_FDCWD;
+}
+
+// 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 DIRTREE_ABORTVAL;
+  if (!callback) return new;
+  flags = callback(new);
+
+  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)) {
+    free(new);
+    new = NULL;
+  }
+
+  return (flags & DIRTREE_ABORT)==DIRTREE_ABORT ? DIRTREE_ABORTVAL : new;
+}
+
+// Recursively read/process children of directory node, filtering through
+// callback(). Uses and closes supplied ->dirfd.
+
+int dirtree_recurse(struct dirtree *node,
+          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);
+      perror_msg("No %s", path);
+      free(path);
+    }
+    close(node->dirfd);
+
+    return flags;
+  }
+
+  // according to the fddir() man page, the filehandle in the DIR * can still
+  // be externally used by things that don't lseek() it.
+
+  // The extra parentheses are to shut the stupid compiler up.
+  while ((entry = readdir(dir))) {
+    if (!(new = dirtree_add_node(node, entry->d_name, flags))) continue;
+    new = dirtree_handle_callback(new, callback);
+    if (new == DIRTREE_ABORTVAL) break;
+    if (new) {
+      *ddt = new;
+      ddt = &((*ddt)->next);
+    }
+  }
+
+  if (flags & DIRTREE_COMEAGAIN) {
+    node->again++;
+    flags = callback(node);
+  }
+
+  // This closes filehandle as well, so note it
+  closedir(dir);
+  node->dirfd = -1;
+
+  return flags;
+}
+
+// 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_handle_callback(dirtree_add_node(0, path, flags), callback);
+}
+
+// Common case
+struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node))
+{
+  return dirtree_flagread(path, 0, callback);
+}
diff --git a/toybox/lib/getmountlist.c b/toybox/lib/getmountlist.c
new file mode 100644
index 0000000..332852a
--- /dev/null
+++ b/toybox/lib/getmountlist.c
@@ -0,0 +1,193 @@
+/* getmountlist.c - Get a linked list of mount points, with stat information.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+#include "toys.h"
+#include <mntent.h>
+
+// Traverse arg_list of csv, calling callback on each value
+void comma_args(struct arg_list *al, void *data, char *err,
+  char *(*callback)(void *data, char *str, int len))
+{
+  char *next, *arg;
+  int len;
+
+  if (CFG_TOYBOX_DEBUG && !err) err = "INTERNAL";
+
+  while (al) {
+    arg = al->arg;
+    while ((next = comma_iterate(&arg, &len)))
+      if ((next = callback(data, next, len)))
+        error_exit("%s '%s'\n%*c", err, al->arg,
+          (int)(5+strlen(toys.which->name)+strlen(err)+next-al->arg), '^');
+    al = al->next;
+  }
+}
+
+// Realloc *old with oldstring,newstring
+
+void comma_collate(char **old, char *new)
+{
+  char *temp, *atold = *old;
+
+  // Only add a comma if old string didn't end with one
+  if (atold && *atold) {
+    char *comma = ",";
+
+    if (atold[strlen(atold)-1] == ',') comma = "";
+    temp = xmprintf("%s%s%s", atold, comma, new);
+  } else temp = xstrdup(new);
+  free (atold);
+  *old = temp;
+}
+
+// iterate through strings in a comma separated list.
+// returns start of next entry or NULL if none
+// sets *len to length of entry (not including comma)
+// advances *list to start of next entry
+char *comma_iterate(char **list, int *len)
+{
+  char *start = *list, *end;
+
+  if (!*list || !**list) return 0;
+
+  if (!(end = strchr(*list, ','))) {
+    *len = strlen(*list);
+    *list = 0;
+  } else *list += (*len = end-start)+1;
+
+  return start;
+}
+
+static void octal_deslash(char *s)
+{
+  char *o = s;
+
+  while (*s) {
+    if (*s == '\\') {
+      int i, oct = 0;
+
+      for (i = 1; i < 4; i++) {
+        if (!isdigit(s[i])) break;
+        oct = (oct<<3)+s[i]-'0';
+      }
+      if (i == 4) {
+        *o++ = oct;
+        s += i;
+        continue;
+      }
+    }
+    *o++ = *s++;
+  }
+
+  *o = 0;
+}
+
+// check all instances of opt and "no"opt in optlist, return true if opt
+// found and last instance wasn't no. If clean, remove each instance from list.
+int comma_scan(char *optlist, char *opt, int clean)
+{
+  int optlen = strlen(opt), len, no, got = 0;
+
+  if (optlist) for (;;) {
+    char *s = comma_iterate(&optlist, &len);
+
+    if (!s) break;
+    no = 2*(*s == 'n' && s[1] == 'o');
+    if (optlen == len-no && !strncmp(opt, s+no, optlen)) {
+      got = !no;
+      if (clean && optlist) memmove(s, optlist, strlen(optlist)+1);
+    }
+  }
+
+  return got;
+}
+
+// return true if all scanlist options enabled in optlist
+int comma_scanall(char *optlist, char *scanlist)
+{
+  int i = 1;
+
+  while (scanlist && *scanlist) {
+    char *opt = comma_iterate(&scanlist, &i), *s = xstrndup(opt, i);
+
+    i = comma_scan(optlist, s, 0);
+    free(s);
+    if (!i) break;
+  }
+
+  return i;
+}
+
+// Check if this type matches list.
+// Odd syntax: typelist all yes = if any, typelist all no = if none.
+
+int mountlist_istype(struct mtab_list *ml, char *typelist)
+{
+  int len, skip;
+  char *t;
+
+  if (!typelist) return 1;
+
+  skip = strncmp(typelist, "no", 2);
+
+  for (;;) {
+    if (!(t = comma_iterate(&typelist, &len))) break;
+    if (!skip) {
+      // If one -t starts with "no", the rest must too
+      if (strncmp(t, "no", 2)) error_exit("bad typelist");
+      if (!strncmp(t+2, ml->type, len-2)) {
+        skip = 1;
+        break;
+      }
+    } else if (!strncmp(t, ml->type, len) && !ml->type[len]) {
+      skip = 0;
+      break;
+    }
+  }
+
+  return !skip;
+}
+
+// Get list of mounted filesystems, including stat and statvfs info.
+// Returns a reversed list, which is good for finding overmounts and such.
+
+struct mtab_list *xgetmountlist(char *path)
+{
+  struct mtab_list *mtlist = 0, *mt;
+  struct mntent *me;
+  FILE *fp;
+  char *p = path ? path : "/proc/mounts";
+
+  if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
+
+  // The "test" part of the loop is done before the first time through and
+  // again after each "increment", so putting the actual load there avoids
+  // duplicating it. If the load was NULL, the loop stops.
+
+  while ((me = getmntent(fp))) {
+    mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
+      strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
+    dlist_add_nomalloc((void *)&mtlist, (void *)mt);
+
+    // Collect details about mounted filesystem
+    // Don't report errors, just leave data zeroed
+    if (!path) {
+      stat(me->mnt_dir, &(mt->stat));
+      statvfs(me->mnt_dir, &(mt->statvfs));
+    }
+
+    // Remember information from /proc/mounts
+    mt->dir = stpcpy(mt->type, me->mnt_type)+1;
+    mt->device = stpcpy(mt->dir, me->mnt_dir)+1;
+    mt->opts = stpcpy(mt->device, me->mnt_fsname)+1;
+    strcpy(mt->opts, me->mnt_opts);
+
+    octal_deslash(mt->dir);
+    octal_deslash(mt->device);
+  }
+  endmntent(fp);
+
+  return mtlist;
+}
diff --git a/toybox/lib/help.c b/toybox/lib/help.c
new file mode 100644
index 0000000..87a3df9
--- /dev/null
+++ b/toybox/lib/help.c
@@ -0,0 +1,37 @@
+// Function to display help text
+
+#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"
+;
+
+void show_help(FILE *out)
+{
+  int i = toys.which-toy_list;
+  char *s;
+
+  for (;;) {
+    s = help_data;
+    while (i--) s += strlen(s) + 1;
+    // If it's an alias, restart search for real name
+    if (*s != 255) break;
+    i = toy_find(++s)-toy_list;
+  }
+
+  fprintf(out, "%s", s);
+}
+#endif
diff --git a/toybox/lib/interestingtimes.c b/toybox/lib/interestingtimes.c
new file mode 100644
index 0000000..62670cb
--- /dev/null
+++ b/toybox/lib/interestingtimes.c
@@ -0,0 +1,243 @@
+/* interestingtimes.c - cursor control
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ */
+
+#include "toys.h"
+
+int xgettty(void)
+{
+  int i, j;
+
+  for (i = 0; i<3; i++) if (isatty(j = (i+1)%3)) return j;
+
+  return xopen("/dev/tty", O_RDWR);
+}
+
+// Quick and dirty query size of terminal, doesn't do ANSI probe fallback.
+// set x=80 y=25 before calling to provide defaults. Returns 0 if couldn't
+// determine size.
+
+int terminal_size(unsigned *xx, unsigned *yy)
+{
+  struct winsize ws;
+  unsigned i, x = 0, y = 0;
+  char *s;
+
+  // stdin, stdout, stderr
+  for (i=0; i<3; i++) {
+    memset(&ws, 0, sizeof(ws));
+    if (!ioctl(i, TIOCGWINSZ, &ws)) {
+      if (ws.ws_col) x = ws.ws_col;
+      if (ws.ws_row) y = ws.ws_row;
+
+      break;
+    }
+  }
+  s = getenv("COLUMNS");
+  if (s) sscanf(s, "%u", &x);
+  s = getenv("LINES");
+  if (s) sscanf(s, "%u", &y);
+
+  // Never return 0 for either value, leave it at default instead.
+  if (xx && x) *xx = x;
+  if (yy && y) *yy = y;
+
+  return x || y;
+}
+
+// Query terminal size, sending ANSI probe if necesary. (Probe queries xterm
+// size through serial connection, when local TTY doesn't know but remote does.)
+// Returns 0 if ANSI probe sent, 1 if size determined from tty or environment
+
+int terminal_probesize(unsigned *xx, unsigned *yy)
+{
+  if (terminal_size(xx, yy) && (!xx || *xx) && (!yy || *yy)) return 1;
+
+  // Send probe: bookmark cursor position, jump to bottom right,
+  // query position, return cursor to bookmarked position.
+  xprintf("\e[s\e[999C\e[999B\e[6n\e[u");
+
+  return 0;
+}
+
+// Wrapper that parses results from ANSI probe to update screensize.
+// Otherwise acts like scan_key()
+int scan_key_getsize(char *scratch, int miliwait, unsigned *xx, unsigned *yy)
+{
+  int key;
+
+  if (512&(key = scan_key(scratch, miliwait))) {
+    if (key>0) {
+      if (xx) *xx = (key>>10)&1023;
+      if (yy) *yy = (key>>20)&1023;
+      toys.signal = SIGWINCH;
+
+      return -3;
+    }
+  }
+
+  return key;
+}
+
+// Reset terminal to known state, saving copy of old state if old != NULL.
+int set_terminal(int fd, int raw, struct termios *old)
+{
+  struct termios termio;
+
+  // Fetch local copy of old terminfo, and copy struct contents to *old if set
+  if (!tcgetattr(fd, &termio) && old) *old = termio;
+
+  // the following are the bits set for an xterm. Linux text mode TTYs by
+  // default add two additional bits that only matter for serial processing
+  // (turn serial line break into an interrupt, and XON/XOFF flow control)
+
+  // Any key unblocks output, swap CR and NL on input
+  termio.c_iflag = IXANY|ICRNL|INLCR;
+  if (toys.which->flags & TOYFLAG_LOCALE) termio.c_iflag |= IUTF8;
+
+  // Output appends CR to NL, does magic undocumented postprocessing
+  termio.c_oflag = ONLCR|OPOST;
+
+  // Leave serial port speed alone
+  // termio.c_cflag = C_READ|CS8|EXTB;
+
+  // Generate signals, input entire line at once, echo output
+  // erase, line kill, escape control characters with ^
+  // erase line char at a time
+  // "extended" behavior: ctrl-V quotes next char, ctrl-R reprints unread chars,
+  // ctrl-W erases word
+  termio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN;
+
+  if (raw) cfmakeraw(&termio);
+
+  return tcsetattr(fd, TCSANOW, &termio);
+}
+
+void xset_terminal(int fd, int raw, struct termios *old)
+{
+  if (-1 == set_terminal(fd, raw, old)) perror_exit("bad tty fd#%d", fd);
+}
+
+struct scan_key_list {
+  char *name, *seq;
+} static const scan_key_list[] = TAGGED_ARRAY(KEY,
+  // up down right left pgup pgdn home end ins
+  {"UP", "\033[A"}, {"DOWN", "\033[B"}, {"RIGHT", "\033[C"}, {"LEFT", "\033[D"},
+  {"PGUP", "\033[5~"}, {"PGDN", "\033[6~"}, {"HOME", "\033OH"},
+  {"END", "\033OF"}, {"INSERT", "\033[2~"},
+
+  {"F1", "\033OP"}, {"F2", "\033OQ"}, {"F3", "\033OR"}, {"F4", "\033OS"},
+  {"F5", "\033[15~"}, {"F6", "\033[17~"}, {"F7", "\033[18~"},
+  {"F8", "\033[19~"}, {"F9", "\033[20~"},
+
+  {"SUP", "\033[1;2A"}, {"AUP", "\033[1;3A"}, {"CUP", "\033[1;5A"},
+  {"SDOWN", "\033[1;2B"}, {"ADOWN", "\033[1;3B"}, {"CDOWN", "\033[1;5B"},
+  {"SRIGHT", "\033[1;2C"}, {"ARIGHT", "\033[1;3C"}, {"CRIGHT", "\033[1;5C"},
+  {"SLEFT", "\033[1;2D"}, {"ALEFT", "\033[1;3D"}, {"CLEFT", "\033[1;5D"},
+
+  {"SF1", "\033O1;2P"}, {"AF1", "\033O1;3P"}, {"CF1", "\033[1;5P"}
+);
+
+// Scan stdin for a keypress, parsing known escape sequences
+// Blocks for miliwait miliseconds, none 0, forever if -1
+// Returns: 0-255=literal, -1=EOF, -2=NONE, 256-...=index into scan_key_list
+// >512 is x<<9+y<<21
+// scratch space is necessary because last char of !seq could start new seq
+// Zero out first byte of scratch before first call to scan_key
+// block=0 allows fetching multiple characters before updating display
+int scan_key(char *scratch, int miliwait)
+{
+  struct pollfd pfd;
+  int maybe, i, j;
+  char *test;
+
+  for (;;) {
+    pfd.fd = 0;
+    pfd.events = POLLIN;
+    pfd.revents = 0;
+
+    maybe = 0;
+    if (*scratch) {
+      int pos[6];
+      unsigned x, y;
+
+      // Check for return from terminal size probe
+      memset(pos, 0, 6*sizeof(int));
+      scratch[(1+*scratch)&15] = 0;
+      sscanf(scratch+1, "\033%n[%n%3u%n;%n%3u%nR%n", pos, pos+1, &y,
+             pos+2, pos+3, &x, pos+4, pos+5);
+      if (pos[5]) {
+        // Recognized X/Y position, consume and return
+        *scratch = 0;
+        return 512+(x<<10)+(y<<20);
+      } else for (i=0; i<6; i++) if (pos[i]==*scratch) maybe = 1;
+
+      // Check sequences
+      for (i = 0; i<ARRAY_LEN(scan_key_list); i++) {
+        test = scan_key_list[i].seq;
+        for (j = 0; j<*scratch; j++) if (scratch[j+1] != test[j]) break;
+        if (j == *scratch) {
+          maybe = 1;
+          if (!test[j]) {
+            // We recognized current sequence: consume and return
+            *scratch = 0;
+            return 256+i;
+          }
+        }
+      }
+
+      // If current data can't be a known sequence, return next raw char
+      if (!maybe) break;
+    }
+
+    // Need more data to decide
+
+    // 30 miliseconds is about the gap between characters at 300 baud 
+    if (maybe || miliwait != -1)
+      if (!xpoll(&pfd, 1, maybe ? 30 : miliwait)) break;
+
+    // Read 1 byte so we don't overshoot sequence match. (We can deviate
+    // and fail to match, but match consumes entire buffer.)
+    if (toys.signal || 1 != read(0, scratch+1+*scratch, 1))
+      return toys.signal ? -3 : -1;
+    ++*scratch;
+  }
+
+  // Was not a sequence
+  if (!*scratch) return -2;
+  i = scratch[1];
+  if (--*scratch) memmove(scratch+1, scratch+2, *scratch);
+
+  return i;
+}
+
+void tty_esc(char *s)
+{
+  printf("\033[%s", s);
+}
+
+void tty_jump(int x, int y)
+{
+  char s[32];
+
+  sprintf(s, "%d;%dH", y+1, x+1);
+  tty_esc(s);
+}
+
+void tty_reset(void)
+{
+  set_terminal(0, 0, 0);
+  tty_esc("?25h");
+  tty_esc("0m");
+  tty_jump(0, 999);
+  tty_esc("K");
+  fflush(0);
+}
+
+// If you call set_terminal(), use sigatexit(tty_sigreset);
+void tty_sigreset(int i)
+{
+  tty_reset();
+  _exit(i ? 128+i : 0);
+}
diff --git a/toybox/lib/lib.c b/toybox/lib/lib.c
new file mode 100644
index 0000000..8f8b4a3
--- /dev/null
+++ b/toybox/lib/lib.c
@@ -0,0 +1,1209 @@
+/* lib.c - various reusable stuff.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+#include "toys.h"
+
+void verror_msg(char *msg, int err, va_list va)
+{
+  char *s = ": %s";
+
+  fprintf(stderr, "%s: ", toys.which->name);
+  if (msg) vfprintf(stderr, msg, va);
+  else s+=2;
+  if (err) fprintf(stderr, s, strerror(err));
+  if (msg || err) putc('\n', stderr);
+  if (!toys.exitval) toys.exitval++;
+}
+
+// These functions don't collapse together because of the va_stuff.
+
+void error_msg(char *msg, ...)
+{
+  va_list va;
+
+  va_start(va, msg);
+  verror_msg(msg, 0, va);
+  va_end(va);
+}
+
+void perror_msg(char *msg, ...)
+{
+  va_list va;
+
+  va_start(va, msg);
+  verror_msg(msg, errno, va);
+  va_end(va);
+}
+
+// Die with an error message.
+void error_exit(char *msg, ...)
+{
+  va_list va;
+
+  va_start(va, msg);
+  verror_msg(msg, 0, va);
+  va_end(va);
+
+  xexit();
+}
+
+// Die with an error message and strerror(errno)
+void perror_exit(char *msg, ...)
+{
+  va_list va;
+
+  va_start(va, msg);
+  verror_msg(msg, errno, va);
+  va_end(va);
+
+  xexit();
+}
+
+// Exit with an error message after showing help text.
+void help_exit(char *msg, ...)
+{
+  va_list va;
+
+  if (CFG_TOYBOX_HELP) show_help(stderr);
+
+  if (msg) {
+    va_start(va, msg);
+    verror_msg(msg, 0, va);
+    va_end(va);
+  }
+
+  xexit();
+}
+
+// If you want to explicitly disable the printf() behavior (because you're
+// printing user-supplied data, or because android's static checker produces
+// false positives for 'char *s = x ? "blah1" : "blah2"; printf(s);' and it's
+// -Werror there for policy reasons).
+void error_msg_raw(char *msg)
+{
+  error_msg("%s", msg);
+}
+
+void perror_msg_raw(char *msg)
+{
+  perror_msg("%s", msg);
+}
+
+void error_exit_raw(char *msg)
+{
+  error_exit("%s", msg);
+}
+
+void perror_exit_raw(char *msg)
+{
+  perror_exit("%s", msg);
+}
+
+// Keep reading until full or EOF
+ssize_t readall(int fd, void *buf, size_t len)
+{
+  size_t count = 0;
+
+  while (count<len) {
+    int i = read(fd, (char *)buf+count, len-count);
+    if (!i) break;
+    if (i<0) return i;
+    count += i;
+  }
+
+  return count;
+}
+
+// Keep writing until done or EOF
+ssize_t writeall(int fd, void *buf, size_t len)
+{
+  size_t count = 0;
+  while (count<len) {
+    int i = write(fd, count+(char *)buf, len-count);
+    if (i<1) return i;
+    count += i;
+  }
+
+  return count;
+}
+
+// skip this many bytes of input. Return 0 for success, >0 means this much
+// left after input skipped.
+off_t lskip(int fd, off_t offset)
+{
+  off_t cur = lseek(fd, 0, SEEK_CUR);
+
+  if (cur != -1) {
+    off_t end = lseek(fd, 0, SEEK_END) - cur;
+
+    if (end > 0 && end < offset) return offset - end;
+    end = offset+cur;
+    if (end == lseek(fd, end, SEEK_SET)) return 0;
+    perror_exit("lseek");
+  }
+
+  while (offset>0) {
+    int try = offset>sizeof(libbuf) ? sizeof(libbuf) : offset, or;
+
+    or = readall(fd, libbuf, try);
+    if (or < 0) perror_exit("lskip to %lld", (long long)offset);
+    else offset -= or;
+    if (or < try) break;
+  }
+
+  return offset;
+}
+
+// flags: 1=make last dir (with mode lastmode, otherwise skips last component)
+//        2=make path (already exists is ok)
+//        4=verbose
+// returns 0 = path ok, 1 = error
+int mkpathat(int atfd, char *dir, mode_t lastmode, int flags)
+{
+  struct stat buf;
+  char *s;
+
+  // mkdir -p one/two/three is not an error if the path already exists,
+  // but is if "three" is a file. The others we dereference and catch
+  // not-a-directory along the way, but the last one we must explicitly
+  // test for. Might as well do it up front.
+
+  if (!fstatat(atfd, dir, &buf, 0) && !S_ISDIR(buf.st_mode)) {
+    errno = EEXIST;
+    return 1;
+  }
+
+  for (s = dir; ;s++) {
+    char save = 0;
+    mode_t mode = (0777&~toys.old_umask)|0300;
+
+    // find next '/', but don't try to mkdir "" at start of absolute path
+    if (*s == '/' && (flags&2) && s != dir) {
+      save = *s;
+      *s = 0;
+    } else if (*s) continue;
+
+    // Use the mode from the -m option only for the last directory.
+    if (!save) {
+      if (flags&1) mode = lastmode;
+      else break;
+    }
+
+    if (mkdirat(atfd, dir, mode)) {
+      if (!(flags&2) || errno != EEXIST) return 1;
+    } else if (flags&4)
+      fprintf(stderr, "%s: created directory '%s'\n", toys.which->name, dir);
+
+    if (!(*s = save)) break;
+  }
+
+  return 0;
+}
+
+// Split a path into linked list of components, tracking head and tail of list.
+// Filters out // entries with no contents.
+struct string_list **splitpath(char *path, struct string_list **list)
+{
+  char *new = path;
+
+  *list = 0;
+  do {
+    int len;
+
+    if (*path && *path != '/') continue;
+    len = path-new;
+    if (len > 0) {
+      *list = xmalloc(sizeof(struct string_list) + len + 1);
+      (*list)->next = 0;
+      memcpy((*list)->str, new, len);
+      (*list)->str[len] = 0;
+      list = &(*list)->next;
+    }
+    new = path+1;
+  } while (*path++);
+
+  return list;
+}
+
+// Find all file in a colon-separated path with access type "type" (generally
+// X_OK or R_OK).  Returns a list of absolute paths to each file found, in
+// order.
+
+struct string_list *find_in_path(char *path, char *filename)
+{
+  struct string_list *rlist = NULL, **prlist=&rlist;
+  char *cwd;
+
+  if (!path) return 0;
+
+  cwd = xgetcwd();
+  for (;;) {
+    char *next = strchr(path, ':');
+    int len = next ? next-path : strlen(path);
+    struct string_list *rnext;
+    struct stat st;
+
+    rnext = xmalloc(sizeof(void *) + strlen(filename)
+      + (len ? len : strlen(cwd)) + 2);
+    if (!len) sprintf(rnext->str, "%s/%s", cwd, filename);
+    else {
+      char *res = rnext->str;
+
+      memcpy(res, path, len);
+      res += len;
+      *(res++) = '/';
+      strcpy(res, filename);
+    }
+
+    // Confirm it's not a directory.
+    if (!stat(rnext->str, &st) && S_ISREG(st.st_mode)) {
+      *prlist = rnext;
+      rnext->next = NULL;
+      prlist = &(rnext->next);
+    } else free(rnext);
+
+    if (!next) break;
+    path += len;
+    path++;
+  }
+  free(cwd);
+
+  return rlist;
+}
+
+long long estrtol(char *str, char **end, int base)
+{
+  errno = 0;
+
+  return strtoll(str, end, base);
+}
+
+long long xstrtol(char *str, char **end, int base)
+{
+  long long l = estrtol(str, end, base);
+
+  if (errno) perror_exit_raw(str);
+
+  return l;
+}
+
+// atol() with the kilo/mega/giga/tera/peta/exa extensions.
+// (zetta and yotta don't fit in 64 bits.)
+long long atolx(char *numstr)
+{
+  char *c = numstr, *suffixes="cbkmgtpe", *end;
+  long long val;
+
+  val = xstrtol(numstr, &c, 0);
+  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 long atolx_range(char *numstr, long long low, long long high)
+{
+  long long val = atolx(numstr);
+
+  if (val < low) error_exit("%lld < %lld", val, low);
+  if (val > high) error_exit("%lld > %lld", val, high);
+
+  return val;
+}
+
+int stridx(char *haystack, char needle)
+{
+  char *off;
+
+  if (!needle) return -1;
+  off = strchr(haystack, needle);
+  if (!off) return -1;
+
+  return off-haystack;
+}
+
+char *strlower(char *s)
+{
+  char *try, *new;
+
+  if (!CFG_TOYBOX_I18N) {
+    try = new = xstrdup(s);
+    for (; *s; s++) *(new++) = tolower(*s);
+  } else {
+    // I can't guarantee the string _won't_ expand during reencoding, so...?
+    try = new = xmalloc(strlen(s)*2+1);
+
+    while (*s) {
+      wchar_t c;
+      int len = mbrtowc(&c, s, MB_CUR_MAX, 0);
+
+      if (len < 1) *(new++) = *(s++);
+      else {
+        s += len;
+        // squash title case too
+        c = towlower(c);
+
+        // if we had a valid utf8 sequence, convert it to lower case, and can't
+        // encode back to utf8, something is wrong with your libc. But just
+        // in case somebody finds an exploit...
+        len = wcrtomb(new, c, 0);
+        if (len < 1) error_exit("bad utf8 %x", (int)c);
+        new += len;
+      }
+    }
+    *new = 0;
+  }
+
+  return try;
+}
+
+// strstr but returns pointer after match
+char *strafter(char *haystack, char *needle)
+{
+  char *s = strstr(haystack, needle);
+
+  return s ? s+strlen(needle) : s;
+}
+
+// Remove trailing \n
+char *chomp(char *s)
+{
+  char *p = strrchr(s, '\n');
+
+  if (p && !p[1]) *p = 0;
+  return s;
+}
+
+int unescape(char c)
+{
+  char *from = "\\abefnrtv", *to = "\\\a\b\033\f\n\r\t\v";
+  int idx = stridx(from, c);
+
+  return (idx == -1) ? 0 : to[idx];
+}
+
+// If *a starts with b, advance *a past it and return 1, else return 0;
+int strstart(char **a, char *b)
+{
+  int len = strlen(b), i = !strncmp(*a, b, len);
+
+  if (i) *a += len;
+
+  return i;
+}
+
+// Return how long the file at fd is, if there's any way to determine it.
+off_t fdlength(int fd)
+{
+  struct stat st;
+  off_t base = 0, range = 1, expand = 1, old;
+
+  if (!fstat(fd, &st) && S_ISREG(st.st_mode)) return st.st_size;
+
+  // If the ioctl works for this, return it.
+  // TODO: is blocksize still always 512, or do we stat for it?
+  // unsigned int size;
+  // if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L;
+
+  // If not, do a binary search for the last location we can read.  (Some
+  // block devices don't do BLKGETSIZE right.)  This should probably have
+  // a CONFIG option...
+
+  // If not, do a binary search for the last location we can read.
+
+  old = lseek(fd, 0, SEEK_CUR);
+  do {
+    char temp;
+    off_t pos = base + range / 2;
+
+    if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) {
+      off_t delta = (pos + 1) - base;
+
+      base += delta;
+      if (expand) range = (expand <<= 1) - base;
+      else range -= delta;
+    } else {
+      expand = 0;
+      range = pos - base;
+    }
+  } while (range > 0);
+
+  lseek(fd, old, SEEK_SET);
+
+  return base;
+}
+
+// Read contents of file as a single nul-terminated string.
+// measure file size if !len, allocate buffer if !buf
+// 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;
+  int fd;
+  char *buf, *rbuf;
+
+  // Unsafe to probe for size with a supplied buffer, don't ever do that.
+  if (CFG_TOYBOX_DEBUG && (ibuf ? !*plen : *plen)) error_exit("bad readfileat");
+
+  if (-1 == (fd = openat(dirfd, name, O_RDONLY))) return 0;
+
+  // If we dunno the length, probe it. If we can't probe, start with 1 page.
+  if (!*plen) {
+    if ((len = fdlength(fd))>0) *plen = len;
+    else len = 4096;
+  } else len = *plen-1;
+
+  if (!ibuf) buf = xmalloc(len+1);
+  else buf = ibuf;
+
+  for (rbuf = buf;;) {
+    rlen = readall(fd, rbuf, len);
+    if (*plen || rlen<len) break;
+
+    // If reading unknown size, expand buffer by 1.5 each time we fill it up.
+    rlen += rbuf-buf;
+    buf = xrealloc(buf, len = (rlen*3)/2);
+    rbuf = buf+rlen;
+    len -= rlen;
+  }
+  *plen = len = rlen+(rbuf-buf);
+  close(fd);
+
+  if (rlen<0) {
+    if (ibuf != buf) free(buf);
+    buf = 0;
+  } else buf[len] = 0;
+
+  return buf;
+}
+
+char *readfile(char *name, char *ibuf, off_t len)
+{
+  return readfileat(AT_FDCWD, name, ibuf, &len);
+}
+
+// Sleep for this many thousandths of a second
+void msleep(long miliseconds)
+{
+  struct timespec ts;
+
+  ts.tv_sec = miliseconds/1000;
+  ts.tv_nsec = (miliseconds%1000)*1000000;
+  nanosleep(&ts, &ts);
+}
+
+// Inefficient, but deals with unaligned access
+int64_t peek_le(void *ptr, unsigned size)
+{
+  int64_t ret = 0;
+  char *c = ptr;
+  int i;
+
+  for (i=0; i<size; i++) ret |= ((int64_t)c[i])<<(i*8);
+  return ret;
+}
+
+int64_t peek_be(void *ptr, unsigned size)
+{
+  int64_t ret = 0;
+  char *c = ptr;
+  int i;
+
+  for (i=0; i<size; i++) ret = (ret<<8)|(c[i]&0xff);
+  return ret;
+}
+
+int64_t peek(void *ptr, unsigned size)
+{
+  return IS_BIG_ENDIAN ? peek_be(ptr, size) : peek_le(ptr, size);
+}
+
+void poke(void *ptr, uint64_t val, int size)
+{
+  if (size & 8) {
+    volatile uint64_t *p = (uint64_t *)ptr;
+    *p = val;
+  } else if (size & 4) {
+    volatile int *p = (int *)ptr;
+    *p = val;
+  } else if (size & 2) {
+    volatile short *p = (short *)ptr;
+    *p = val;
+  } else {
+    volatile char *p = (char *)ptr;
+    *p = val;
+  }
+}
+
+// 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
+// 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,
+  void (*function)(int fd, char *name))
+{
+  int fd;
+
+  // If no arguments, read from stdin.
+  if (!*argv) function((flags & O_ACCMODE) != O_RDONLY ? 1 : 0, "-");
+  else do {
+    // 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) {
+      perror_msg_raw(*argv);
+      continue;
+    }
+    function(fd, *argv);
+    if ((flags & O_CLOEXEC) && fd) close(fd);
+  } while (*++argv);
+}
+
+// Call loopfiles_rw with O_RDONLY|O_CLOEXEC and !failok (common case).
+void loopfiles(char **argv, void (*function)(int fd, char *name))
+{
+  loopfiles_rw(argv, O_RDONLY|O_CLOEXEC, 0, 0, function);
+}
+
+// Slow, but small.
+
+char *get_rawline(int fd, long *plen, char end)
+{
+  char c, *buf = NULL;
+  long len = 0;
+
+  for (;;) {
+    if (1>read(fd, &c, 1)) break;
+    if (!(len & 63)) buf=xrealloc(buf, len+65);
+    if ((buf[len++]=c) == end) break;
+  }
+  if (buf) buf[len]=0;
+  if (plen) *plen = len;
+
+  return buf;
+}
+
+char *get_line(int fd)
+{
+  long len;
+  char *buf = get_rawline(fd, &len, '\n');
+
+  if (buf && buf[--len]=='\n') buf[len]=0;
+
+  return buf;
+}
+
+int wfchmodat(int fd, char *name, mode_t mode)
+{
+  int rc = fchmodat(fd, name, mode, 0);
+
+  if (rc) {
+    perror_msg("chmod '%s' to %04o", name, mode);
+    toys.exitval=1;
+  }
+  return rc;
+}
+
+static char *tempfile2zap;
+static void tempfile_handler(void)
+{
+  if (1 < (long)tempfile2zap) unlink(tempfile2zap);
+}
+
+// Open a temporary file to copy an existing file into.
+int copy_tempfile(int fdin, char *name, char **tempname)
+{
+  struct stat statbuf;
+  int fd;
+
+  *tempname = xmprintf("%s%s", name, "XXXXXX");
+  if(-1 == (fd = mkstemp(*tempname))) error_exit("no temp file");
+  if (!tempfile2zap) sigatexit(tempfile_handler);
+  tempfile2zap = *tempname;
+
+  // Set permissions of output file
+
+  fstat(fdin, &statbuf);
+  fchmod(fd, statbuf.st_mode);
+
+  return fd;
+}
+
+// Abort the copy and delete the temporary file.
+void delete_tempfile(int fdin, int fdout, char **tempname)
+{
+  close(fdin);
+  close(fdout);
+  if (*tempname) unlink(*tempname);
+  tempfile2zap = (char *)1;
+  free(*tempname);
+  *tempname = NULL;
+}
+
+// Copy the rest of the data and replace the original with the copy.
+void replace_tempfile(int fdin, int fdout, char **tempname)
+{
+  char *temp = xstrdup(*tempname);
+
+  temp[strlen(temp)-6]=0;
+  if (fdin != -1) {
+    xsendfile(fdin, fdout);
+    xclose(fdin);
+  }
+  xclose(fdout);
+  rename(*tempname, temp);
+  tempfile2zap = (char *)1;
+  free(*tempname);
+  free(temp);
+  *tempname = NULL;
+}
+
+// Create a 256 entry CRC32 lookup table.
+
+void crc_init(unsigned int *crc_table, int little_endian)
+{
+  unsigned int i;
+
+  // Init the CRC32 table (big endian)
+  for (i=0; i<256; i++) {
+    unsigned int j, c = little_endian ? i : i<<24;
+    for (j=8; j; j--)
+      if (little_endian) c = (c&1) ? (c>>1)^0xEDB88320 : c>>1;
+      else c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1);
+    crc_table[i] = c;
+  }
+}
+
+// Init base64 table
+
+void base64_init(char *p)
+{
+  int i;
+
+  for (i = 'A'; i != ':'; i++) {
+    if (i == 'Z'+1) i = 'a';
+    if (i == 'z'+1) i = '0';
+    *(p++) = i;
+  }
+  *(p++) = '+';
+  *(p++) = '/';
+}
+
+int yesno(int def)
+{
+  char buf;
+
+  fprintf(stderr, " (%c/%c):", def ? 'Y' : 'y', def ? 'n' : 'N');
+  fflush(stderr);
+  while (fread(&buf, 1, 1, stdin)) {
+    int new;
+
+    // The letter changes the value, the newline (or space) returns it.
+    if (isspace(buf)) break;
+    if (-1 != (new = stridx("ny", tolower(buf)))) def = new;
+  }
+
+  return def;
+}
+
+struct signame {
+  int num;
+  char *name;
+};
+
+// Signals required by POSIX 2008:
+// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
+
+#define SIGNIFY(x) {SIG##x, #x}
+
+static struct signame signames[] = {
+  SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
+  SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
+  SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
+  SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
+  SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
+
+  // Start of non-terminal signals
+
+  SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
+  SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG)
+};
+
+// not in posix: SIGNIFY(STKFLT), SIGNIFY(WINCH), SIGNIFY(IO), SIGNIFY(PWR)
+// obsolete: SIGNIFY(PROF) SIGNIFY(POLL)
+
+// Handler that sets toys.signal, and writes to toys.signalfd if set
+void generic_signal(int sig)
+{
+  if (toys.signalfd) {
+    char c = sig;
+
+    writeall(toys.signalfd, &c, 1);
+  }
+  toys.signal = sig;
+}
+
+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, exit_signal);
+  al->next = toys.xexit;
+  al->arg = handler;
+  toys.xexit = al;
+}
+
+// Convert name to signal number.  If name == NULL print names.
+int sig_to_num(char *pidstr)
+{
+  int i;
+
+  if (pidstr) {
+    char *s;
+
+    i = estrtol(pidstr, &s, 10);
+    if (!errno && !*s) return i;
+
+    if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3;
+  }
+  for (i = 0; i < sizeof(signames)/sizeof(struct signame); i++)
+    if (!pidstr) xputs(signames[i].name);
+    else if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
+
+  return -1;
+}
+
+char *num_to_sig(int sig)
+{
+  int i;
+
+  for (i=0; i<sizeof(signames)/sizeof(struct signame); i++)
+    if (signames[i].num == sig) return signames[i].name;
+  return NULL;
+}
+
+// premute mode bits based on posix mode strings.
+mode_t string_to_mode(char *modestr, mode_t mode)
+{
+  char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu",
+       *s, *str = modestr;
+  mode_t extrabits = mode & ~(07777);
+
+  // Handle octal mode
+  if (isdigit(*str)) {
+    mode = estrtol(str, &s, 8);
+    if (errno || *s || (mode & ~(07777))) goto barf;
+
+    return mode | extrabits;
+  }
+
+  // Gaze into the bin of permission...
+  for (;;) {
+    int i, j, dowho, dohow, dowhat, amask;
+
+    dowho = dohow = dowhat = amask = 0;
+
+    // Find the who, how, and what stanzas, in that order
+    while (*str && (s = strchr(whos, *str))) {
+      dowho |= 1<<(s-whos);
+      str++;
+    }
+    // If who isn't specified, like "a" but honoring umask.
+    if (!dowho) {
+      dowho = 8;
+      umask(amask=umask(0));
+    }
+    if (!*str || !(s = strchr(hows, *str))) goto barf;
+    dohow = *(str++);
+
+    if (!dohow) goto barf;
+    while (*str && (s = strchr(whats, *str))) {
+      dowhat |= 1<<(s-whats);
+      str++;
+    }
+
+    // Convert X to x for directory or if already executable somewhere
+    if ((dowhat&32) &&  (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
+
+    // Copy mode from another category?
+    if (!dowhat && *str && (s = strchr(whys, *str))) {
+      dowhat = (mode>>(3*(s-whys)))&7;
+      str++;
+    }
+
+    // Are we ready to do a thing yet?
+    if (*str && *(str++) != ',') goto barf;
+
+    // Ok, apply the bits to the mode.
+    for (i=0; i<4; i++) {
+      for (j=0; j<3; j++) {
+        mode_t bit = 0;
+        int where = 1<<((3*i)+j);
+
+        if (amask & where) continue;
+
+        // Figure out new value at this location
+        if (i == 3) {
+          // suid/sticky bit.
+          if (j) {
+            if ((dowhat & 8) && (dowho&(8|(1<<i)))) bit++;
+          } else if (dowhat & 16) bit++;
+        } else {
+          if (!(dowho&(8|(1<<i)))) continue;
+          if (dowhat&(1<<j)) bit++;
+        }
+
+        // When selection active, modify bit
+
+        if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
+        if (bit && dohow != '-') mode |= where;
+      }
+    }
+
+    if (!*str) break;
+  }
+
+  return mode|extrabits;
+barf:
+  error_exit("bad mode '%s'", modestr);
+}
+
+// Format access mode into a drwxrwxrwx string
+void mode_to_string(mode_t mode, char *buf)
+{
+  char c, d;
+  int i, bit;
+
+  buf[10]=0;
+  for (i=0; i<9; i++) {
+    bit = mode & (1<<i);
+    c = i%3;
+    if (!c && (mode & (1<<((d=i/3)+9)))) {
+      c = "tss"[d];
+      if (!bit) c &= ~0x20;
+    } else c = bit ? "xwr"[c] : '-';
+    buf[9-i] = c;
+  }
+
+  if (S_ISDIR(mode)) c = 'd';
+  else if (S_ISBLK(mode)) c = 'b';
+  else if (S_ISCHR(mode)) c = 'c';
+  else if (S_ISLNK(mode)) c = 'l';
+  else if (S_ISFIFO(mode)) c = 'p';
+  else if (S_ISSOCK(mode)) c = 's';
+  else c = '-';
+  *buf = c;
+}
+
+// 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;
+}
+
+// Execute a callback for each PID that matches a process name from a list.
+void names_to_pid(char **names, int (*callback)(pid_t pid, char *name))
+{
+  DIR *dp;
+  struct dirent *entry;
+
+  if (!(dp = opendir("/proc"))) perror_exit("opendir");
+
+  while ((entry = readdir(dp))) {
+    unsigned u;
+    char *cmd, **curname;
+
+    if (!(u = atoi(entry->d_name))) continue;
+    sprintf(libbuf, "/proc/%u/cmdline", u);
+    if (!(cmd = readfile(libbuf, libbuf, sizeof(libbuf)))) continue;
+
+    for (curname = names; *curname; curname++)
+      if (**curname == '/' ? !strcmp(cmd, *curname)
+          : !strcmp(getbasename(cmd), getbasename(*curname)))
+        if (callback(u, *curname)) break;
+    if (*curname) break;
+  }
+  closedir(dp);
+}
+
+// display first few digits of number with power of two units
+int human_readable(char *buf, unsigned long long num, int style)
+{
+  unsigned long long snap = 0;
+  int len, unit, divisor = (style&HR_1000) ? 1000 : 1024;
+
+  // Divide rounding up until we have 3 or fewer digits. Since the part we
+  // print is decimal, the test is 999 even when we divide by 1024.
+  // We can't run out of units because 2<<64 is 18 exabytes.
+  // test 5675 is 5.5k not 5.6k.
+  for (unit = 0; num > 999; unit++) num = ((snap = num)+(divisor/2))/divisor;
+  len = sprintf(buf, "%llu", num);
+  if (unit && len == 1) {
+    // Redo rounding for 1.2M case, this works with and without HR_1000.
+    num = snap/divisor;
+    snap -= num*divisor;
+    snap = ((snap*100)+50)/divisor;
+    snap /= 10;
+    len = sprintf(buf, "%llu.%llu", num, snap);
+  }
+  if (style & HR_SPACE) buf[len++] = ' ';
+  if (unit) {
+    unit = " kMGTPE"[unit];
+
+    if (!(style&HR_1000)) unit = toupper(unit);
+    buf[len++] = unit;
+  } else if (style & HR_B) buf[len++] = 'B';
+  buf[len] = 0;
+
+  return len;
+}
+
+// The qsort man page says you can use alphasort, the posix committee
+// disagreed, and doubled down: http://austingroupbugs.net/view.php?id=142
+// So just do our own. (The const is entirely to humor the stupid compiler.)
+int qstrcmp(const void *a, const void *b)
+{
+  return strcmp(*(char **)a, *(char **)b);
+}
+
+// According to http://www.opengroup.org/onlinepubs/9629399/apdxa.htm
+// we should generate a uuid structure by reading a clock with 100 nanosecond
+// precision, normalizing it to the start of the gregorian calendar in 1582,
+// and looking up our eth0 mac address.
+//
+// On the other hand, we have 128 bits to come up with a unique identifier, of
+// which 6 have a defined value.  /dev/urandom it is.
+
+void create_uuid(char *uuid)
+{
+  // Read 128 random bits
+  int fd = xopenro("/dev/urandom");
+  xreadall(fd, uuid, 16);
+  close(fd);
+
+  // Claim to be a DCE format UUID.
+  uuid[6] = (uuid[6] & 0x0F) | 0x40;
+  uuid[8] = (uuid[8] & 0x3F) | 0x80;
+
+  // rfc2518 section 6.4.1 suggests if we're not using a macaddr, we should
+  // set bit 1 of the node ID, which is the mac multicast bit.  This means we
+  // should never collide with anybody actually using a macaddr.
+  uuid[11] |= 128;
+}
+
+char *show_uuid(char *uuid)
+{
+  char *out = libbuf;
+  int i;
+
+  for (i=0; i<16; i++) out+=sprintf(out, "-%02x"+!(0x550&(1<<i)), uuid[i]);
+  *out = 0;
+
+  return libbuf;
+}
+
+// Returns pointer to letter at end, 0 if none. *start = initial %
+char *next_printf(char *s, char **start)
+{
+  for (; *s; s++) {
+    if (*s != '%') continue;
+    if (*++s == '%') continue;
+    if (start) *start = s-1;
+    while (0 <= stridx("0'#-+ ", *s)) s++;
+    while (isdigit(*s)) s++;
+    if (*s == '.') s++;
+    while (isdigit(*s)) s++;
+
+    return s;
+  }
+
+  return 0;
+}
+
+// Posix inexplicably hasn't got this, so find str in line.
+char *strnstr(char *line, char *str)
+{
+  long len = strlen(str);
+  char *s;
+
+  for (s = line; *s; s++) if (!strncasecmp(s, str, len)) break;
+
+  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;
+}
+
diff --git a/toybox/lib/lib.h b/toybox/lib/lib.h
new file mode 100644
index 0000000..43d6b1f
--- /dev/null
+++ b/toybox/lib/lib.h
@@ -0,0 +1,331 @@
+/* lib.h - header file for lib directory
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+struct ptr_len {
+  void *ptr;
+  long len;
+};
+
+struct str_len {
+  char *str;
+  long len;
+};
+
+// llist.c
+
+// All these list types can be handled by the same code because first element
+// is always next pointer, so next = (mytype *)&struct. (The payloads are
+// named differently to catch using the wrong type early.)
+
+struct string_list {
+  struct string_list *next;
+  char str[0];
+};
+
+struct arg_list {
+  struct arg_list *next;
+  char *arg;
+};
+
+struct double_list {
+  struct double_list *next, *prev;
+  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 *llist_pop(void *list);  // actually void **list
+void *dlist_pop(void *list);  // actually struct double_list **list
+void dlist_add_nomalloc(struct double_list **list, struct double_list *new);
+struct double_list *dlist_add(struct double_list **list, char *data);
+void *dlist_terminate(void *list);
+struct num_cache *get_num_cache(struct num_cache *cache, long long num);
+struct num_cache *add_num_cache(struct num_cache **cache, long long num,
+  void *data, int len);
+
+// args.c
+void get_optflags(void);
+
+// dirtree.c
+
+// Values returnable from callback function (bitfield, or them together)
+// Default with no callback is 0
+
+// Add this node to the tree
+#define DIRTREE_SAVE         1
+// Recurse into children
+#define DIRTREE_RECURSE      2
+// Call again after handling all children of this directory
+// (Ignored for non-directories, sets linklen = -1 before second call.)
+#define DIRTREE_COMEAGAIN    4
+// Follow symlinks to directories
+#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
+
+#define DIRTREE_ABORTVAL ((struct dirtree *)1)
+
+struct dirtree {
+  struct dirtree *next, *parent, *child;
+  long extra; // place for user to store their stuff (can be pointer)
+  struct stat st;
+  char *symlink;
+  int dirfd;
+  char again;
+  char name[];
+};
+
+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);
+int dirtree_recurse(struct dirtree *node, int (*callback)(struct dirtree *node),
+  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);
+
+// 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 *xrealloc(void *ptr, size_t size);
+char *xstrndup(char *s, size_t n);
+char *xstrdup(char *s);
+void *xmemdup(void *s, long len);
+char *xmprintf(char *format, ...) printf_format;
+void xprintf(char *format, ...) printf_format;
+void xputs(char *s);
+void xputc(char c);
+void xflush(void);
+void xexec(char **argv);
+pid_t xpopen_both(char **argv, int *pipes);
+int xwaitpid(pid_t pid);
+int xpclose_both(pid_t pid, int *pipes);
+pid_t xpopen(char **argv, int *pipe, int stdout);
+pid_t xpclose(pid_t pid, int pipe);
+int xrun(char **argv);
+int xpspawn(char **argv, int*pipes);
+void xaccess(char *path, int flags);
+void xunlink(char *path);
+int xcreate(char *path, int flags, int mode);
+int xopen(char *path, int flags);
+int xcreate_stdio(char *path, int flags, int mode);
+int xopen_stdio(char *path, int flags);
+int xopenro(char *path);
+void xpipe(int *pp);
+void xclose(int fd);
+int xdup(int fd);
+FILE *xfdopen(int fd, char *mode);
+FILE *xfopen(char *path, char *mode);
+size_t xread(int fd, void *buf, size_t len);
+void xreadall(int fd, void *buf, size_t len);
+void xwrite(int fd, void *buf, size_t len);
+off_t xlseek(int fd, off_t offset, int whence);
+char *xreadfile(char *name, char *buf, off_t len);
+int xioctl(int fd, int request, void *data);
+char *xgetcwd(void);
+void xstat(char *path, struct stat *st);
+char *xabspath(char *path, int exact);
+void xchdir(char *path);
+void xchroot(char *path);
+struct passwd *xgetpwuid(uid_t uid);
+struct group *xgetgrgid(gid_t gid);
+struct passwd *xgetpwnam(char *name);
+struct group *xgetgrnam(char *name);
+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);
+void xpidfile(char *name);
+void xregcomp(regex_t *preg, char *rexec, int cflags);
+char *xtzset(char *new);
+void xsignal(int signal, void *handler);
+
+// lib.c
+void verror_msg(char *msg, int err, va_list va);
+void error_msg(char *msg, ...) printf_format;
+void perror_msg(char *msg, ...) printf_format;
+void error_exit(char *msg, ...) printf_format noreturn;
+void perror_exit(char *msg, ...) printf_format noreturn;
+void help_exit(char *msg, ...) printf_format noreturn;
+void error_msg_raw(char *msg);
+void perror_msg_raw(char *msg);
+void error_exit_raw(char *msg);
+void perror_exit_raw(char *msg);
+ssize_t readall(int fd, void *buf, size_t len);
+ssize_t writeall(int fd, void *buf, size_t len);
+off_t lskip(int fd, off_t offset);
+int mkpathat(int atfd, char *dir, mode_t lastmode, int flags);
+struct string_list **splitpath(char *path, struct string_list **list);
+char *readfileat(int dirfd, char *name, char *buf, off_t *len);
+char *readfile(char *name, char *buf, off_t len);
+void msleep(long miliseconds);
+int64_t peek_le(void *ptr, unsigned size);
+int64_t peek_be(void *ptr, unsigned size);
+int64_t peek(void *ptr, unsigned size);
+void poke(void *ptr, uint64_t val, int size);
+struct string_list *find_in_path(char *path, char *filename);
+long 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);
+char *chomp(char *s);
+int unescape(char c);
+int strstart(char **a, char *b);
+off_t fdlength(int fd);
+void loopfiles_rw(char **argv, int flags, int permissions, int failok,
+  void (*function)(int fd, char *name));
+void loopfiles(char **argv, void (*function)(int fd, char *name));
+void xsendfile(int in, int out);
+int wfchmodat(int rc, char *name, mode_t mode);
+int copy_tempfile(int fdin, char *name, char **tempname);
+void delete_tempfile(int fdin, int fdout, char **tempname);
+void replace_tempfile(int fdin, int fdout, char **tempname);
+void crc_init(unsigned int *crc_table, int little_endian);
+void base64_init(char *p);
+int yesno(int def);
+int qstrcmp(const void *a, const void *b);
+void create_uuid(char *uuid);
+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);
+
+#define HR_SPACE 1 // Space between number and units
+#define HR_B     2 // Use "B" for single byte units
+#define HR_1000  4 // Use decimal instead of binary units
+int human_readable(char *buf, unsigned long long num, int style);
+
+// linestack.c
+
+struct linestack {
+  long len, max;
+  struct ptr_len idx[];
+};
+
+void linestack_addstack(struct linestack **lls, struct linestack *throw,
+  long pos);
+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_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
+int xgettty(void);
+int terminal_size(unsigned *xx, unsigned *yy);
+int terminal_probesize(unsigned *xx, unsigned *yy);
+int scan_key_getsize(char *scratch, int miliwait, unsigned *xx, unsigned *yy);
+int set_terminal(int fd, int raw, struct termios *old);
+void xset_terminal(int fd, int raw, struct termios *old);
+int scan_key(char *scratch, int miliwait);
+void tty_esc(char *s);
+void tty_jump(int x, int y);
+void tty_reset(void);
+void tty_sigreset(int i);
+
+// net.c
+int xsocket(int domain, int type, int protocol);
+void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len);
+int xconnect(char *host, char *port, int family, int socktype, int protocol,
+  int flags);
+int xpoll(struct pollfd *fds, int nfds, int timeout);
+
+// password.c
+int get_salt(char *salt, char * algo);
+
+// getmountlist.c
+struct mtab_list {
+  struct mtab_list *next, *prev;
+  struct stat stat;
+  struct statvfs statvfs;
+  char *dir;
+  char *device;
+  char *opts;
+  char type[0];
+};
+
+void comma_args(struct arg_list *al, void *data, char *err,
+  char *(*callback)(void *data, char *str, int len));
+void comma_collate(char **old, char *new);
+char *comma_iterate(char **list, int *len);
+int comma_scan(char *optlist, char *opt, int clean);
+int comma_scanall(char *optlist, char *scanlist);
+int mountlist_istype(struct mtab_list  *ml, char *typelist);
+struct mtab_list *xgetmountlist(char *path);
+
+// signal
+
+void generic_signal(int signal);
+void exit_signal(int signal);
+void sigatexit(void *handler);
+int sig_to_num(char *pidstr);
+char *num_to_sig(int sig);
+
+mode_t string_to_mode(char *mode_str, mode_t base);
+void mode_to_string(mode_t mode, char *buf);
+char *getbasename(char *name);
+void names_to_pid(char **names, int (*callback)(pid_t pid, char *name));
+
+pid_t xvforkwrap(pid_t pid);
+#define XVFORK() xvforkwrap(vfork())
+
+// Wrapper to make xfuncs() return (via longjmp) instead of exiting.
+// Assigns true/false "did it exit" value to first argument.
+#define WOULD_EXIT(y, x) do { jmp_buf _noexit; \
+  int _noexit_res; \
+  toys.rebound = &_noexit; \
+  _noexit_res = setjmp(_noexit); \
+  if (!_noexit_res) do {x;} while(0); \
+  toys.rebound = 0; \
+  y = _noexit_res; \
+} while(0);
+
+// Wrapper that discards true/false "did it exit" value.
+#define NOEXIT(x) WOULD_EXIT(_noexit_res, x)
+
+// Functions in need of further review/cleanup
+#include "lib/pending.h"
diff --git a/toybox/lib/linestack.c b/toybox/lib/linestack.c
new file mode 100644
index 0000000..eef790b
--- /dev/null
+++ b/toybox/lib/linestack.c
@@ -0,0 +1,187 @@
+#include "toys.h"
+
+// Insert one stack into another before position in old stack.
+// (Does not copy contents of strings, just shuffles index array contents.)
+void linestack_addstack(struct linestack **lls, struct linestack *throw,
+  long pos)
+{
+  struct linestack *catch = *lls;
+
+  if (CFG_TOYBOX_DEBUG)
+    if (pos > catch->len) error_exit("linestack_addstack past end.");
+
+  // Make a hole, allocating more space if necessary.
+  if (catch->len+throw->len >= catch->max) {
+    // New size rounded up to next multiple of 64, allocate and copy start.
+    catch->max = ((catch->len+throw->len)|63)+1;
+    *lls = xmalloc(sizeof(struct linestack)+catch->max*sizeof(struct ptr_len));
+    memcpy(*lls, catch, sizeof(struct linestack)+pos*sizeof(struct ptr_len));
+  }
+
+  // Copy end (into new allocation if necessary)
+  if (pos != catch->len)
+    memmove((*lls)->idx+pos+throw->len, catch->idx+pos,
+      (catch->len-pos)*sizeof(struct ptr_len));
+
+  // Cleanup if we had to realloc.
+  if (catch != *lls) {
+    free(catch);
+    catch = *lls;
+  }
+
+  memcpy(catch->idx+pos, throw->idx, throw->len*sizeof(struct ptr_len));
+  catch->len += throw->len;
+}
+
+void linestack_insert(struct linestack **lls, long pos, char *line, long len)
+{
+  // alloca() was in 32V and Turbo C for DOS, but isn't in posix or c99.
+  // I'm not thrashing the heap for this, but this should work even if
+  // a broken compiler adds gratuitous padding.
+  struct {
+    struct linestack ls;
+    struct ptr_len pl;
+  } ls;
+
+  ls.ls.len = ls.ls.max = 1;
+  ls.ls.idx[0].ptr = line;
+  ls.ls.idx[0].len = len;
+  linestack_addstack(lls, &ls.ls, pos);
+}
+
+void linestack_append(struct linestack **lls, char *line)
+{
+  linestack_insert(lls, (*lls)->len, line, strlen(line));
+}
+
+struct linestack *linestack_load(char *name)
+{
+  FILE *fp = fopen(name, "r");
+  struct linestack *ls;
+
+  if (!fp) return 0;
+
+  ls = xzalloc(sizeof(struct linestack));
+
+  for (;;) {
+    char *line = 0;
+    ssize_t len;
+
+    if ((len = getline(&line, (void *)&len, fp))<1) break;
+    if (line[len-1]=='\n') len--;
+    linestack_insert(&ls, ls->len, line, len);
+  }
+  fclose(fp);
+
+  return ls;
+}
+
+// Show width many columns, negative means from right edge.
+// If out=0 just measure
+// 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, char *escmore,
+  int (*escout)(FILE *out, int cols, int wc))
+{
+  int columns = 0, col, bytes;
+  char *start, *end;
+
+  for (end = start = *str; *end; columns += col, end += bytes) {
+    wchar_t wc;
+
+    if ((bytes = mbrtowc(&wc, end, MB_CUR_MAX, 0))>0 && (col = wcwidth(wc))>=0)
+    {
+      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, crunch_rev_escape);
+}
+
+// Return utf8 columns
+int utf8len(char *str)
+{
+  return crunch_str(&str, INT_MAX, 0, 0, crunch_rev_escape);
+}
+
+// Return bytes used by (up to) this many columns
+int utf8skip(char *str, int width)
+{
+  char *s = str;
+
+  crunch_str(&s, width, 0, 0, crunch_rev_escape);
+
+  return s-str;
+}
+
+// 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_esc(char *str, int padto, int width, char *escmore,
+  int (*escout)(FILE *out, int cols, int wc))
+{
+  int apad = abs(padto), len = utf8len(str);
+
+  if (padto<0 && len>width) str += utf8skip(str, len-width);
+  if (len>width) len = width;
+
+  // Left pad if right justified 
+  if (padto>0 && apad>len) printf("%*s", apad-len, "");
+  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);
+}
diff --git a/toybox/lib/llist.c b/toybox/lib/llist.c
new file mode 100644
index 0000000..dbb5352
--- /dev/null
+++ b/toybox/lib/llist.c
@@ -0,0 +1,130 @@
+/* llist.c - Linked list functions
+ *
+ * Linked list structures have a next pointer as their first element.
+ */
+
+#include "toys.h"
+
+// Callback function to free data pointer of double_list or arg_list
+
+void llist_free_arg(void *node)
+{
+  struct arg_list *d = node;
+
+  free(d->arg);
+  free(d);
+}
+
+void llist_free_double(void *node)
+{
+  struct double_list *d = node;
+
+  free(d->data);
+  free(d);
+}
+
+// Call a function (such as free()) on each element of a linked list.
+void llist_traverse(void *list, void (*using)(void *node))
+{
+  void *old = list;
+
+  while (list) {
+    void *pop = llist_pop(&list);
+    using(pop);
+
+    // End doubly linked list too.
+    if (old == list) break;
+  }
+}
+
+// Return the first item from the list, advancing the list (which must be called
+// as &list)
+void *llist_pop(void *list)
+{
+  // I'd use a void ** for the argument, and even accept the typecast in all
+  // callers as documentation you need the &, except the stupid compiler
+  // would then scream about type-punned pointers.  Screw it.
+  void **llist = (void **)list;
+  void **next = (void **)*llist;
+  *llist = *next;
+
+  return (void *)next;
+}
+
+void *dlist_pop(void *list)
+{
+  struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist;
+
+  if (dlist->next == dlist) *pdlist = 0;
+  else {
+    dlist->next->prev = dlist->prev;
+    dlist->prev->next = *pdlist = dlist->next;
+  }
+
+  return dlist;
+}
+
+void dlist_add_nomalloc(struct double_list **list, struct double_list *new)
+{
+  if (*list) {
+    new->next = *list;
+    new->prev = (*list)->prev;
+    (*list)->prev->next = new;
+    (*list)->prev = new;
+  } else *list = new->next = new->prev = new;
+}
+
+
+// Add an entry to the end of a doubly linked list
+struct double_list *dlist_add(struct double_list **list, char *data)
+{
+  struct double_list *new = xmalloc(sizeof(struct double_list));
+
+  new->data = data;
+  dlist_add_nomalloc(list, new);
+
+  return new;
+}
+
+// Terminate circular list for traversal in either direction. Returns end *.
+void *dlist_terminate(void *list)
+{
+  struct double_list *end = list;
+
+  if (!list) return 0;
+
+  end = end->prev;
+  end->next->prev = 0;
+  end->next = 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;
+}
diff --git a/toybox/lib/lsm.h b/toybox/lib/lsm.h
new file mode 100644
index 0000000..e21d424
--- /dev/null
+++ b/toybox/lib/lsm.h
@@ -0,0 +1,118 @@
+/* lsm.h - header file for lib directory
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ */
+
+#include <sys/xattr.h>
+
+#if CFG_TOYBOX_SELINUX
+#include <selinux/selinux.h>
+#else
+#define is_selinux_enabled() 0
+#define setfscreatecon(...) (-1)
+#define getcon(...) (-1)
+#define getfilecon(...) (-1)
+#define lgetfilecon(...) (-1)
+#define fgetfilecon(...) (-1)
+#define setfilecon(...) (-1)
+#define lsetfilecon(...) (-1)
+#define fsetfilecon(...) (-1)
+#endif
+
+#if CFG_TOYBOX_SMACK
+#include <sys/smack.h>
+#include <linux/xattr.h>
+#else
+#ifndef XATTR_NAME_SMACK
+#define XATTR_NAME_SMACK 0
+#endif
+//ssize_t fgetxattr (int fd, char *name, void *value, size_t size);
+#define smack_smackfs_path(...) (-1)
+#define smack_new_label_from_self(...) (-1)
+#define smack_new_label_from_path(...) (-1)
+#define smack_new_label_from_file(...) (-1)
+#define smack_set_label_for_self(...) (-1)
+#define smack_set_label_for_path(...) (-1)
+#define smack_set_label_for_file(...) (-1)
+#endif
+
+// This turns into "return 0" when no LSM and lets code optimize out.
+static inline int lsm_enabled(void)
+{
+  if (CFG_TOYBOX_SMACK) return !!smack_smackfs_path();
+  else return is_selinux_enabled() == 1;
+}
+
+static inline char *lsm_name(void)
+{
+  if (CFG_TOYBOX_SMACK) return "Smack";
+  if (CFG_TOYBOX_SELINUX) return "SELinux";
+
+  return "LSM";
+}
+
+// Fetch this process's lsm context
+static inline char *lsm_context(void)
+{
+  int ok = 0;
+  char *result;
+
+  if (CFG_TOYBOX_SMACK) ok = smack_new_label_from_self(&result) > 0;
+  else ok = getcon(&result) == 0;
+
+  return ok ? result : strdup("?");
+}
+
+// Set default label to apply to newly created stuff (NULL to clear it)
+static inline int lsm_set_create(char *context)
+{
+  if (CFG_TOYBOX_SMACK) return smack_set_label_for_self(context);
+  else return setfscreatecon(context);
+}
+
+// Label a file, following symlinks
+static inline int lsm_set_context(char *filename, char *context)
+{
+  if (CFG_TOYBOX_SMACK)
+    return smack_set_label_for_path(filename, XATTR_NAME_SMACK, 1, context);
+  else return setfilecon(filename, context);
+}
+
+// Label a file, don't follow symlinks
+static inline int lsm_lset_context(char *filename, char *context)
+{
+  if (CFG_TOYBOX_SMACK)
+    return smack_set_label_for_path(filename, XATTR_NAME_SMACK, 0, context);
+  else return lsetfilecon(filename, context);
+}
+
+// Label a file by filehandle
+static inline int lsm_fset_context(int file, char *context)
+{
+  if (CFG_TOYBOX_SMACK)
+    return smack_set_label_for_file(file, XATTR_NAME_SMACK, context);
+  else return fsetfilecon(file, context);
+}
+
+// returns -1 in case of error or else the length of the context */
+// context can be NULL to get the length only */
+static inline int lsm_get_context(char *filename, char **context)
+{
+  if (CFG_TOYBOX_SMACK)
+    return smack_new_label_from_path(filename, XATTR_NAME_SMACK, 1, context);
+  else return getfilecon(filename, context);
+}
+
+static inline int lsm_lget_context(char *filename, char **context)
+{
+  if (CFG_TOYBOX_SMACK)
+    return smack_new_label_from_path(filename, XATTR_NAME_SMACK, 0, context);
+  else return lgetfilecon(filename, context);
+}
+
+static inline int lsm_fget_context(int file, char **context)
+{
+  if (CFG_TOYBOX_SMACK)
+    return smack_new_label_from_file(file, XATTR_NAME_SMACK, context);
+  return fgetfilecon(file, context);
+}
diff --git a/toybox/lib/net.c b/toybox/lib/net.c
new file mode 100644
index 0000000..2e72b26
--- /dev/null
+++ b/toybox/lib/net.c
@@ -0,0 +1,57 @@
+#include "toys.h"
+
+int xsocket(int domain, int type, int protocol)
+{
+  int fd = socket(domain, type, protocol);
+
+  if (fd < 0) perror_exit("socket %x %x", type, protocol);
+  return fd;
+}
+
+void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len)
+{
+  if (-1 == setsockopt(fd, level, opt, val, len)) perror_exit("setsockopt");
+}
+
+int xconnect(char *host, char *port, int family, int socktype, int protocol,
+             int flags)
+{
+  struct addrinfo info, *ai, *ai2;
+  int fd;
+
+  memset(&info, 0, sizeof(struct addrinfo));
+  info.ai_family = family;
+  info.ai_socktype = socktype;
+  info.ai_protocol = protocol;
+  info.ai_flags = flags;
+
+  fd = getaddrinfo(host, port, &info, &ai);
+  if (fd || !ai)
+    error_exit("Connect '%s%s%s': %s", host, port ? ":" : "", port ? port : "",
+      fd ? gai_strerror(fd) : "not found");
+
+  // Try all the returned addresses. Report errors if last entry can't connect.
+  for (ai2 = ai; ai; ai = ai->ai_next) {
+    fd = (ai->ai_next ? socket : xsocket)(ai->ai_family, ai->ai_socktype,
+      ai->ai_protocol);
+    if (!connect(fd, ai->ai_addr, ai->ai_addrlen)) break;
+    else if (!ai2->ai_next) perror_exit("connect");
+    close(fd);
+  }
+  freeaddrinfo(ai2);
+
+  return fd;
+}
+
+int xpoll(struct pollfd *fds, int nfds, int timeout)
+{
+  int i;
+
+  for (;;) {
+    if (0>(i = poll(fds, nfds, timeout))) {
+      if (toys.signal) return i;
+      if (errno != EINTR && errno != ENOMEM) perror_exit("xpoll");
+      else if (timeout>0) timeout--;
+    } else return i;
+  }
+}
diff --git a/toybox/lib/password.c b/toybox/lib/password.c
new file mode 100644
index 0000000..eab2d66
--- /dev/null
+++ b/toybox/lib/password.c
@@ -0,0 +1,200 @@
+/* password.c - password read/update helper functions.
+ *
+ * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
+ *
+ * TODO: cleanup
+ */
+
+#include "toys.h"
+#include <time.h>
+
+// generate appropriate random salt string for given encryption algorithm.
+int get_salt(char *salt, char *algo)
+{
+  struct {
+    char *type, id, len;
+  } al[] = {{"des", 0, 2}, {"md5", 1, 8}, {"sha256", 5, 16}, {"sha512", 6, 16}};
+  int i;
+
+  for (i = 0; i < ARRAY_LEN(al); i++) {
+    if (!strcmp(algo, al[i].type)) {
+      int len = al[i].len;
+      char *s = salt;
+
+      if (al[i].id) s += sprintf(s, "$%c$", '0'+al[i].id);
+
+      // Read appropriate number of random bytes for salt
+      i = xopenro("/dev/urandom");
+      xreadall(i, libbuf, ((len*6)+7)/8);
+      close(i);
+
+      // Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z
+      for (i=0; i<len; i++) {
+        int bitpos = i*6, bits = bitpos/8;
+
+        bits = ((libbuf[i]+(libbuf[i+1]<<8)) >> (bitpos&7)) & 0x3f;
+        bits += 46;
+        if (bits > 57) bits += 7;
+        if (bits > 90) bits += 6;
+
+        s[i] = bits;
+      }
+      salt[len] = 0;
+
+      return s-salt;
+    }
+  }
+
+  return -1;
+}
+
+// Prompt with mesg, read password into buf, return 0 for success 1 for fail
+int read_password(char *buf, int buflen, char *mesg)
+{
+  struct termios oldtermio;
+  struct sigaction sa, oldsa;
+  int i, ret = 1;
+
+  // NOP signal handler to return from the read
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = generic_signal;
+  sigaction(SIGINT, &sa, &oldsa);
+
+  tcflush(0, TCIFLUSH);
+  set_terminal(0, 1, &oldtermio);
+
+  xprintf("%s", mesg);
+
+  for (i=0; i < buflen-1; i++) {
+    if ((ret = read(0, buf+i, 1)) < 0 || (!ret && !i)) {
+      i = 0;
+      ret = 1;
+
+      break;
+    } else if (!ret || buf[i] == '\n' || buf[i] == '\r') {
+      ret = 0;
+
+      break;
+    } else if (buf[i] == 8 || buf[i] == 127) i -= i ? 2 : 1;
+  }
+
+  // Restore terminal/signal state, terminate string
+  sigaction(SIGINT, &oldsa, NULL);
+  tcsetattr(0, TCSANOW, &oldtermio);
+  buf[i] = 0;
+  xputc('\n');
+
+  return ret;
+}
+
+static char *get_nextcolon(char *line, int cnt)
+{
+  while (cnt--) {
+    if (!(line = strchr(line, ':'))) error_exit("Invalid Entry\n");
+    line++; //jump past the colon
+  }
+  return line;
+}
+
+/*update_password is used by multiple utilities to update /etc/passwd,
+ * /etc/shadow, /etc/group and /etc/gshadow files,
+ * which are used as user, group databeses
+ * entry can be
+ * 1. encrypted password, when updating user password.
+ * 2. complete entry for user details, when creating new user
+ * 3. group members comma',' separated list, when adding user to group
+ * 4. complete entry for group details, when creating new group
+ * 5. entry = NULL, delete the named entry user/group
+ */
+int update_password(char *filename, char* username, char* entry)
+{
+  char *filenamesfx = NULL, *namesfx = NULL, *shadow = NULL,
+       *sfx = NULL, *line = NULL;
+  FILE *exfp, *newfp;
+  int ret = -1, found = 0;
+  struct flock lock;
+
+  shadow = strstr(filename, "shadow");
+  filenamesfx = xmprintf("%s+", filename);
+  sfx = strchr(filenamesfx, '+');
+
+  exfp = fopen(filename, "r+");
+  if (!exfp) {
+    perror_msg("Couldn't open file %s",filename);
+    goto free_storage;
+  }
+
+  *sfx = '-';
+  unlink(filenamesfx);
+  ret = link(filename, filenamesfx);
+  if (ret < 0) error_msg("can't create backup file");
+
+  *sfx = '+';
+  lock.l_type = F_WRLCK;
+  lock.l_whence = SEEK_SET;
+  lock.l_start = 0;
+  lock.l_len = 0;
+
+  ret = fcntl(fileno(exfp), F_SETLK, &lock);
+  if (ret < 0) perror_msg("Couldn't lock file %s",filename);
+
+  lock.l_type = F_UNLCK; //unlocking at a later stage
+
+  newfp = fopen(filenamesfx, "w+");
+  if (!newfp) {
+    error_msg("couldn't open file for writing");
+    ret = -1;
+    fclose(exfp);
+    goto free_storage;
+  }
+
+  ret = 0;
+  namesfx = xmprintf("%s:",username);
+  while ((line = get_line(fileno(exfp))) != NULL)
+  {
+    if (strncmp(line, namesfx, strlen(namesfx)))
+      fprintf(newfp, "%s\n", line);
+    else if (entry) {
+      char *current_ptr = NULL;
+
+      found = 1;
+      if (!strcmp(toys.which->name, "passwd")) {
+        fprintf(newfp, "%s%s:",namesfx, entry);
+        current_ptr = get_nextcolon(line, 2); //past passwd
+        if (shadow) {
+          fprintf(newfp, "%u:",(unsigned)(time(NULL))/(24*60*60));
+          current_ptr = get_nextcolon(current_ptr, 1);
+          fprintf(newfp, "%s\n",current_ptr);
+        } else fprintf(newfp, "%s\n",current_ptr);
+      } else if (!strcmp(toys.which->name, "groupadd") ||
+          !strcmp(toys.which->name, "addgroup") ||
+          !strcmp(toys.which->name, "delgroup") ||
+          !strcmp(toys.which->name, "groupdel")){
+        current_ptr = get_nextcolon(line, 3); //past gid/admin list
+        *current_ptr = '\0';
+        fprintf(newfp, "%s", line);
+        fprintf(newfp, "%s\n", entry);
+      }
+    }
+    free(line);
+  }
+  free(namesfx);
+  if (!found && entry) fprintf(newfp, "%s\n", entry);
+  fcntl(fileno(exfp), F_SETLK, &lock);
+  fclose(exfp);
+
+  errno = 0;
+  fflush(newfp);
+  fsync(fileno(newfp));
+  fclose(newfp);
+  rename(filenamesfx, filename);
+  if (errno) {
+    perror_msg("File Writing/Saving failed: ");
+    unlink(filenamesfx);
+    ret = -1;
+  }
+
+free_storage:
+  free(filenamesfx);
+  return ret;
+}
diff --git a/toybox/lib/pending.h b/toybox/lib/pending.h
new file mode 100644
index 0000000..fbcc47c
--- /dev/null
+++ b/toybox/lib/pending.h
@@ -0,0 +1,14 @@
+// pending.h - header for pending.c
+
+// password.c
+#define MAX_SALT_LEN  20 //3 for id, 16 for key, 1 for '\0'
+int read_password(char * buff, int buflen, char* mesg);
+int update_password(char *filename, char* username, char* encrypted);
+
+// lib.c
+// These should be switched to posix-2008 getline() and getdelim()
+char *get_rawline(int fd, long *plen, char end);
+char *get_line(int fd);
+
+
+// TODO this goes away when lib/password.c cleaned up
diff --git a/toybox/lib/portability.c b/toybox/lib/portability.c
new file mode 100644
index 0000000..78e500b
--- /dev/null
+++ b/toybox/lib/portability.c
@@ -0,0 +1,94 @@
+/* portability.c - code to workaround the deficiencies of various platforms.
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ * Copyright 2012 Georgi Chorbadzhiyski <gf@unixsol.org>
+ */
+
+#include "toys.h"
+
+// We can't fork() on nommu systems, and vfork() requires an exec() or exit()
+// before resuming the parent (because they share a heap until then). And no,
+// we can't implement our own clone() call that does the equivalent of fork()
+// because nommu heaps use physical addresses so if we copy the heap all our
+// pointers are wrong. (You need an mmu in order to map two heaps to the same
+// address range without interfering with each other.) In the absence of
+// a portable way to tell malloc() to start a new heap without freeing the old
+// one, you pretty much need the exec().)
+
+// So we exec ourselves (via /proc/self/exe, if anybody knows a way to
+// re-exec self without depending on the filesystem, I'm all ears),
+// and use the arguments to signal reentry.
+
+#if CFG_TOYBOX_FORK
+pid_t xfork(void)
+{
+  pid_t pid = fork();
+
+  if (pid < 0) perror_exit("fork");
+
+  return pid;
+}
+#endif
+
+#if defined(__APPLE__)
+ssize_t getdelim(char **linep, size_t *np, int delim, FILE *stream)
+{
+  int ch;
+  size_t new_len;
+  ssize_t i = 0;
+  char *line, *new_line;
+
+  // Invalid input
+  if (!linep || !np) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (*linep == NULL || *np == 0) {
+    *np = 1024;
+    *linep = calloc(1, *np);
+    if (*linep == NULL) return -1;
+  }
+  line = *linep;
+
+  while ((ch = getc(stream)) != EOF) {
+    if (i > *np) {
+      // Need more space
+      new_len = *np + 1024;
+      new_line = realloc(*linep, new_len);
+      if (!new_line) return -1;
+      *np = new_len;
+      line = *linep = new_line;
+    }
+
+    line[i] = ch;
+    if (ch == delim) break;
+    i += 1;
+  }
+
+  if (i > *np) {
+    // Need more space
+    new_len  = i + 2;
+    new_line = realloc(*linep, new_len);
+    if (!new_line) return -1;
+    *np = new_len;
+    line = *linep = new_line;
+  }
+  line[i + 1] = '\0';
+
+  return i > 0 ? i : -1;
+}
+
+ssize_t getline(char **linep, size_t *np, FILE *stream)
+{
+  return getdelim(linep, np, '\n', stream);
+}
+
+extern char **environ;
+
+int clearenv(void)
+{
+  *environ = NULL;
+  return 0;
+}
+#endif
diff --git a/toybox/lib/portability.h b/toybox/lib/portability.h
new file mode 100644
index 0000000..afe02c1
--- /dev/null
+++ b/toybox/lib/portability.h
@@ -0,0 +1,278 @@
+// Workarounds for horrible build environment idiosyncrasies.
+
+// Instead of polluting the code with strange #ifdefs to work around bugs
+// in specific compiler, library, or OS versions, localize all that here
+// and in portability.c
+
+// For musl
+#define _ALL_SOURCE
+
+// Test for gcc (using compiler builtin #define)
+
+#ifdef __GNUC__
+#define noreturn	__attribute__((noreturn))
+#define printf_format	__attribute__((format(printf, 1, 2)))
+#else
+#define noreturn
+#define printf_format
+#endif
+
+// Always use long file support.
+#define _FILE_OFFSET_BITS 64
+
+// This isn't in the spec, but it's how we determine what libc we're using.
+
+#include <features.h>
+
+// Types various replacement prototypes need
+#include <sys/types.h>
+
+// Various constants old build environments might not have even if kernel does
+
+#ifndef AT_FDCWD
+#define AT_FDCWD -100
+#endif
+
+#ifndef AT_SYMLINK_NOFOLLOW
+#define AT_SYMLINK_NOFOLLOW 0x100
+#endif
+
+#ifndef AT_REMOVEDIR
+#define AT_REMOVEDIR 0x200
+#endif
+
+#ifndef RLIMIT_RTTIME
+#define RLIMIT_RTTIME 15
+#endif
+
+// We don't define GNU_dammit because we're not part of the gnu project, and
+// don't want to get any FSF on us. Unfortunately glibc (gnu libc)
+// won't give us Linux syscall wrappers without claiming to be part of the
+// gnu project (because Stallman's "GNU owns Linux" revisionist history
+// crusade includes the kernel, even though Linux was inspired by Minix).
+
+// We use most non-posix Linux syscalls directly through the syscall() wrapper,
+// but even many posix-2008 functions aren't provided by glibc unless you
+// claim it's in the name of Gnu.
+
+#if defined(__GLIBC__)
+// "Function prototypes shall be provided." but aren't.
+// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html
+char *crypt(const char *key, const char *salt);
+
+// According to posix, #include header, get a function definition. But glibc...
+// http://pubs.opengroup.org/onlinepubs/9699919799/functions/wcwidth.html
+#include <wchar.h>
+int wcwidth(wchar_t wc);
+
+// see http://pubs.opengroup.org/onlinepubs/9699919799/functions/strptime.html
+#include <time.h>
+char *strptime(const char *buf, const char *format, struct tm *tm);
+
+// They didn't like posix basename so they defined another function with the
+// same name and if you include libgen.h it #defines basename to something
+// else (where they implemented the real basename), and that define breaks
+// the table entry for the basename command. They didn't make a new function
+// with a different name for their new behavior because gnu.
+//
+// Solution: don't use their broken header, provide an inline to redirect the
+// correct name to the broken name.
+
+char *dirname(char *path);
+char *__xpg_basename(char *path);
+static inline char *basename(char *path) { return __xpg_basename(path); }
+
+// uClibc pretends to be glibc and copied a lot of its bugs, but has a few more
+#if defined(__UCLIBC__)
+#include <unistd.h>
+#include <stdio.h>
+ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
+char *stpcpy(char *dest, const char *src);
+pid_t getsid(pid_t pid);
+
+// uClibc's last-ever release was in 2012, so of course it doesn't define
+// any flag newer than MS_MOVE, which was added in 2001 (linux 2.5.0.5),
+// eleven years earlier.
+
+#include <sys/mount.h>
+#ifndef MS_MOVE
+#define MS_MOVE       (1<<13)
+#endif
+#ifndef MS_REC
+#define MS_REC        (1<<14)
+#endif
+#ifndef MS_SILENT
+#define MS_SILENT     (1<<15)
+#endif
+#ifndef MS_UNBINDABLE
+#define MS_UNBINDABLE (1<<17)
+#endif
+#ifndef MS_PRIVATE
+#define MS_PRIVATE    (1<<18)
+#endif
+#ifndef MS_SLAVE
+#define MS_SLAVE      (1<<19)
+#endif
+#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
+#define fstatat fstatat64
+int fstatat64(int dirfd, const char *pathname, void *buf, int flags);
+int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
+char *stpcpy(char *dest, const char *src);
+#include <sys/stat.h>
+int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
+int openat(int dirfd, const char *pathname, int flags, ...);
+#include <dirent.h>
+DIR *fdopendir(int fd);
+#include <unistd.h>
+int fchownat(int dirfd, const char *pathname,
+                    uid_t owner, gid_t group, int flags);
+int isblank(int c);
+int unlinkat(int dirfd, const char *pathname, int flags);
+#include <stdio.h>
+ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
+
+// Straight from posix-2008, things old glibc had but didn't prototype
+
+int faccessat(int fd, const char *path, int amode, int flag);
+int linkat(int fd1, const char *path1, int fd2, const char *path2, int flag);
+int mkdirat(int fd, const char *path, mode_t mode);
+int symlinkat(const char *path1, int fd, const char *path2);
+int mknodat(int fd, const char *path, mode_t mode, dev_t dev);
+#include <sys/time.h>
+int futimens(int fd, const struct timespec times[2]);
+int utimensat(int fd, const char *path, const struct timespec times[2], int flag);
+
+#ifndef MNT_DETACH
+#define MNT_DETACH 2
+#endif
+#endif // Old glibc
+
+#endif // glibc in general
+
+#if !defined(__GLIBC__)
+// POSIX basename.
+#include <libgen.h>
+#endif
+
+// Work out how to do endianness
+
+#ifndef __APPLE__
+#include <byteswap.h>
+#include <endian.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define IS_BIG_ENDIAN 1
+#else
+#define IS_BIG_ENDIAN 0
+#endif
+
+int clearenv(void);
+#else
+
+#ifdef __BIG_ENDIAN__
+#define IS_BIG_ENDIAN 1
+#else
+#define IS_BIG_ENDIAN 0
+#endif
+
+#endif
+
+#if IS_BIG_ENDIAN
+#define IS_LITTLE_ENDIAN 0
+#define SWAP_BE16(x) (x)
+#define SWAP_BE32(x) (x)
+#define SWAP_BE64(x) (x)
+#define SWAP_LE16(x) bswap_16(x)
+#define SWAP_LE32(x) bswap_32(x)
+#define SWAP_LE64(x) bswap_64(x)
+#else
+#define IS_LITTLE_ENDIAN 1
+#define SWAP_BE16(x) bswap_16(x)
+#define SWAP_BE32(x) bswap_32(x)
+#define SWAP_BE64(x) bswap_64(x)
+#define SWAP_LE16(x) (x)
+#define SWAP_LE32(x) (x)
+#define SWAP_LE64(x) (x)
+#endif
+
+#if defined(__APPLE__) \
+    || (defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 10)
+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>
+#include <sys/swap.h>
+
+// Android is missing some headers and functions
+// "generated/config.h" is included first
+#if CFG_TOYBOX_SHADOW
+#include <shadow.h>
+#endif
+#if CFG_TOYBOX_UTMPX
+#include <utmpx.h>
+#else
+struct utmpx {int ut_type;};
+#define USER_PROCESS 0
+static inline struct utmpx *getutxent(void) {return 0;}
+static inline void setutxent(void) {;}
+static inline void endutxent(void) {;}
+#endif
+
+// Some systems don't define O_NOFOLLOW, and it varies by architecture, so...
+#include <fcntl.h>
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0
+#endif
+
+#ifndef O_NOATIME
+#define O_NOATIME 01000000
+#endif
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 02000000
+#endif
+
+#ifndef O_PATH
+#define O_PATH   010000000
+#endif
+
+// Glibc won't give you linux-kernel constants unless you say "no, a BUD lite"
+// even though linux has nothing to do with the FSF and never has.
+#ifndef F_SETPIPE_SZ
+#define F_SETPIPE_SZ 1031
+#endif
+
+#ifndef F_GETPIPE_SZ
+#define F_GETPIPE_SZ 1032
+#endif
+
+#if defined(__SIZEOF_DOUBLE__) && defined(__SIZEOF_LONG__) \
+    && __SIZEOF_DOUBLE__ <= __SIZEOF_LONG__
+typedef double FLOAT;
+#else
+typedef float FLOAT;
+#endif
+
+#ifndef __uClinux__
+pid_t xfork(void);
+#endif
+
+//#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
diff --git a/toybox/lib/toyflags.h b/toybox/lib/toyflags.h
new file mode 100644
index 0000000..e809901
--- /dev/null
+++ b/toybox/lib/toyflags.h
@@ -0,0 +1,30 @@
+/* Flags values for the third argument of NEWTOY()
+ *
+ * Included from both main.c (runs in toys.h context) and scripts/install.c
+ * (which may build on crazy things like macosx when cross compiling).
+ */
+
+// Flags describing command behavior.
+
+#define TOYFLAG_USR      (1<<0)
+#define TOYFLAG_BIN      (1<<1)
+#define TOYFLAG_SBIN     (1<<2)
+#define TOYMASK_LOCATION ((1<<4)-1)
+
+// This is a shell built-in function, running in the same process context.
+#define TOYFLAG_NOFORK   (1<<4)
+
+// Start command with a umask of 0 (saves old umask in this.old_umask)
+#define TOYFLAG_UMASK    (1<<5)
+
+// This command runs as root.
+#define TOYFLAG_STAYROOT (1<<6)
+#define TOYFLAG_NEEDROOT (1<<7)
+#define TOYFLAG_ROOTONLY (TOYFLAG_STAYROOT|TOYFLAG_NEEDROOT)
+
+// Call setlocale to listen to environment variables.
+// This invalidates sprintf("%.*s", size, string) as a valid length constraint.
+#define TOYFLAG_LOCALE   (1<<8)
+
+// Suppress default --help processing
+#define TOYFLAG_NOHELP   (1<<9)
diff --git a/toybox/lib/xwrap.c b/toybox/lib/xwrap.c
new file mode 100644
index 0000000..48e0296
--- /dev/null
+++ b/toybox/lib/xwrap.c
@@ -0,0 +1,792 @@
+/* xwrap.c - wrappers around existing library functions.
+ *
+ * Functions with the x prefix are wrappers that either succeed or kill the
+ * program with an error message, but never return failure. They usually have
+ * the same arguments and return value as the function they wrap.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+#include "toys.h"
+
+// strcpy and strncat with size checking. Size is the total space in "dest",
+// including null terminator. Exit if there's not enough space for the string
+// (including space for the null terminator), because silently truncating is
+// still broken behavior. (And leaving the string unterminated is INSANE.)
+void xstrncpy(char *dest, char *src, size_t size)
+{
+  if (strlen(src)+1 > size) error_exit("'%s' > %ld bytes", src, (long)size);
+  strcpy(dest, src);
+}
+
+void xstrncat(char *dest, char *src, size_t size)
+{
+  long len = strlen(dest);
+
+  if (len+strlen(src)+1 > size)
+    error_exit("'%s%s' > %ld bytes", dest, src, (long)size);
+  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)
+{
+  // 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");
+  _xexit();
+}
+
+// Die unless we can allocate memory.
+void *xmalloc(size_t size)
+{
+  void *ret = malloc(size);
+  if (!ret) error_exit("xmalloc(%ld)", (long)size);
+
+  return ret;
+}
+
+// Die unless we can allocate prezeroed memory.
+void *xzalloc(size_t size)
+{
+  void *ret = xmalloc(size);
+  memset(ret, 0, size);
+  return ret;
+}
+
+// Die unless we can change the size of an existing allocation, possibly
+// moving it.  (Notice different arguments from libc function.)
+void *xrealloc(void *ptr, size_t size)
+{
+  ptr = realloc(ptr, size);
+  if (!ptr) error_exit("xrealloc");
+
+  return ptr;
+}
+
+// Die unless we can allocate a copy of this many bytes of string.
+char *xstrndup(char *s, size_t n)
+{
+  char *ret = strndup(s, ++n);
+
+  if (!ret) error_exit("xstrndup");
+  ret[--n] = 0;
+
+  return ret;
+}
+
+// Die unless we can allocate a copy of this string.
+char *xstrdup(char *s)
+{
+  return xstrndup(s, strlen(s));
+}
+
+void *xmemdup(void *s, long len)
+{
+  void *ret = xmalloc(len);
+  memcpy(ret, s, len);
+
+  return ret;
+}
+
+// Die unless we can allocate enough space to sprintf() into.
+char *xmprintf(char *format, ...)
+{
+  va_list va, va2;
+  int len;
+  char *ret;
+
+  va_start(va, format);
+  va_copy(va2, va);
+
+  // How long is it?
+  len = vsnprintf(0, 0, format, va);
+  len++;
+  va_end(va);
+
+  // Allocate and do the sprintf()
+  ret = xmalloc(len);
+  vsnprintf(ret, len, format, va2);
+  va_end(va2);
+
+  return ret;
+}
+
+void xprintf(char *format, ...)
+{
+  va_list va;
+  va_start(va, format);
+
+  vprintf(format, va);
+  va_end(va);
+  if (fflush(stdout) || ferror(stdout)) perror_exit("write");
+}
+
+void xputs(char *s)
+{
+  if (EOF == puts(s) || fflush(stdout) || ferror(stdout)) perror_exit("write");
+}
+
+void xputc(char c)
+{
+  if (EOF == fputc(c, stdout) || fflush(stdout) || ferror(stdout))
+    perror_exit("write");
+}
+
+void xflush(void)
+{
+  if (fflush(stdout) || ferror(stdout)) perror_exit("write");;
+}
+
+// This is called through the XVFORK macro because parent/child of vfork
+// share a stack, so child returning from a function would stomp the return
+// address parent would need. Solution: make vfork() an argument so processes
+// diverge before function gets called.
+pid_t xvforkwrap(pid_t pid)
+{
+  if (pid == -1) perror_exit("vfork");
+
+  // Signal to xexec() and friends that we vforked so can't recurse
+  toys.stacktop = 0;
+
+  return pid;
+}
+
+// Die unless we can exec argv[] (or run builtin command).  Note that anything
+// with a path isn't a builtin, so /bin/sh won't match the builtin sh.
+void xexec(char **argv)
+{
+  // Only recurse to builtin when we have multiplexer and !vfork context.
+  if (CFG_TOYBOX && !CFG_TOYBOX_NORECURSE && toys.stacktop) toy_exec(argv);
+  execvp(argv[0], argv);
+
+  perror_msg("exec %s", argv[0]);
+  toys.exitval = 127;
+  if (!CFG_TOYBOX_FORK) _exit(toys.exitval);
+  xexit();
+}
+
+// Spawn child process, capturing stdin/stdout.
+// argv[]: command to exec. If null, child re-runs original program with
+//         toys.stacktop zeroed.
+// pipes[2]: stdin, stdout of new process, only allocated if zero on way in,
+//           pass NULL to skip pipe allocation entirely.
+// return: pid of child process
+pid_t xpopen_both(char **argv, int *pipes)
+{
+  int cestnepasun[4], pid;
+
+  // Make the pipes? Note this won't set either pipe to 0 because if fds are
+  // allocated in order and if fd0 was free it would go to cestnepasun[0]
+  if (pipes) {
+    for (pid = 0; pid < 2; pid++) {
+      if (pipes[pid] != 0) continue;
+      if (pipe(cestnepasun+(2*pid))) perror_exit("pipe");
+      pipes[pid] = cestnepasun[pid+1];
+    }
+  }
+
+  // Child process.
+  if (!(pid = CFG_TOYBOX_FORK ? xfork() : XVFORK())) {
+    // Dance of the stdin/stdout redirection.
+    if (pipes) {
+      // if we had no stdin/out, pipe handles could overlap, so test for it
+      // and free up potentially overlapping pipe handles before reuse
+      if (pipes[1] != -1) close(cestnepasun[2]);
+      if (pipes[0] != -1) {
+        close(cestnepasun[1]);
+        if (cestnepasun[0]) {
+          dup2(cestnepasun[0], 0);
+          close(cestnepasun[0]);
+        }
+      }
+      if (pipes[1] != -1) {
+        dup2(cestnepasun[3], 1);
+        dup2(cestnepasun[3], 2);
+        if (cestnepasun[3] > 2 || !cestnepasun[3]) close(cestnepasun[3]);
+      }
+    }
+    if (argv) xexec(argv);
+
+    // In fork() case, force recursion because we know it's us.
+    if (CFG_TOYBOX_FORK) {
+      toy_init(toys.which, toys.argv);
+      toys.stacktop = 0;
+      toys.which->toy_main();
+      xexit();
+    // In vfork() case, exec /proc/self/exe with high bit of first letter set
+    // to tell main() we reentered.
+    } else {
+      char *s = "/proc/self/exe";
+
+      // We did a nommu-friendly vfork but must exec to continue.
+      // setting high bit of argv[0][0] to let new process know
+      **toys.argv |= 0x80;
+      execv(s, toys.argv);
+      perror_msg_raw(s);
+
+      _exit(127);
+    }
+  }
+
+  // Parent process
+  if (!CFG_TOYBOX_FORK) **toys.argv &= 0x7f;
+  if (pipes) {
+    if (pipes[0] != -1) close(cestnepasun[0]);
+    if (pipes[1] != -1) close(cestnepasun[3]);
+  }
+
+  return pid;
+}
+
+// Wait for child process to exit, then return adjusted exit code.
+int xwaitpid(pid_t pid)
+{
+  int status;
+
+  while (-1 == waitpid(pid, &status, 0) && errno == EINTR);
+
+  return WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+127;
+}
+
+int xpclose_both(pid_t pid, int *pipes)
+{
+  if (pipes) {
+    close(pipes[0]);
+    close(pipes[1]);
+  }
+
+  return xwaitpid(pid);
+}
+
+// Wrapper to xpopen with a pipe for just one of stdin/stdout
+pid_t xpopen(char **argv, int *pipe, int stdout)
+{
+  int pipes[2], pid;
+
+  pipes[!stdout] = -1;
+  pipes[!!stdout] = 0;
+  pid = xpopen_both(argv, pipes);
+  *pipe = pid ? pipes[!!stdout] : -1;
+
+  return pid;
+}
+
+int xpclose(pid_t pid, int pipe)
+{
+  close(pipe);
+
+  return xpclose_both(pid, 0);
+}
+
+// Call xpopen and wait for it to finish, keeping existing stdin/stdout.
+int xrun(char **argv)
+{
+  return xpclose_both(xpopen_both(argv, 0), 0);
+}
+
+void xaccess(char *path, int flags)
+{
+  if (access(path, flags)) perror_exit("Can't access '%s'", path);
+}
+
+// Die unless we can delete a file.  (File must exist to be deleted.)
+void xunlink(char *path)
+{
+  if (unlink(path)) perror_exit("unlink '%s'", path);
+}
+
+// Die unless we can open/create a file, returning file descriptor.
+int xcreate_stdio(char *path, int flags, int mode)
+{
+  int fd = open(path, flags^O_CLOEXEC, mode);
+
+  if (fd == -1) perror_exit_raw(path);
+  return fd;
+}
+
+// Die unless we can open a file, returning file descriptor.
+int xopen_stdio(char *path, int flags)
+{
+  return xcreate_stdio(path, flags, 0);
+}
+
+void xpipe(int *pp)
+{
+  if (pipe(pp)) perror_exit("xpipe");
+}
+
+void xclose(int fd)
+{
+  if (close(fd)) perror_exit("xclose");
+}
+
+int xdup(int fd)
+{
+  if (fd != -1) {
+    fd = dup(fd);
+    if (fd == -1) perror_exit("xdup");
+  }
+  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)
+{
+  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.
+int xopenro(char *path)
+{
+  if (!strcmp(path, "-")) return 0;
+
+  return xopen(path, O_RDONLY);
+}
+
+FILE *xfdopen(int fd, char *mode)
+{
+  FILE *f = fdopen(fd, mode);
+
+  if (!f) perror_exit("xfdopen");
+
+  return f;
+}
+
+// Die unless we can open/create a file, returning FILE *.
+FILE *xfopen(char *path, char *mode)
+{
+  FILE *f = fopen(path, mode);
+  if (!f) perror_exit("No file %s", path);
+  return f;
+}
+
+// Die if there's an error other than EOF.
+size_t xread(int fd, void *buf, size_t len)
+{
+  ssize_t ret = read(fd, buf, len);
+  if (ret < 0) perror_exit("xread");
+
+  return ret;
+}
+
+void xreadall(int fd, void *buf, size_t len)
+{
+  if (len != readall(fd, buf, len)) perror_exit("xreadall");
+}
+
+// There's no xwriteall(), just xwrite().  When we read, there may or may not
+// be more data waiting.  When we write, there is data and it had better go
+// somewhere.
+
+void xwrite(int fd, void *buf, size_t len)
+{
+  if (len != writeall(fd, buf, len)) perror_exit("xwrite");
+}
+
+// Die if lseek fails, probably due to being called on a pipe.
+
+off_t xlseek(int fd, off_t offset, int whence)
+{
+  offset = lseek(fd, offset, whence);
+  if (offset<0) perror_exit("lseek");
+
+  return offset;
+}
+
+char *xgetcwd(void)
+{
+  char *buf = getcwd(NULL, 0);
+  if (!buf) perror_exit("xgetcwd");
+
+  return buf;
+}
+
+void xstat(char *path, struct stat *st)
+{
+  if(stat(path, st)) perror_exit("Can't stat %s", path);
+}
+
+// Cannonicalize path, even to file with one or more missing components at end.
+// if exact, require last path component to exist
+char *xabspath(char *path, int exact)
+{
+  struct string_list *todo, *done = 0;
+  int try = 9999, dirfd = open("/", 0);;
+  char *ret;
+
+  // If this isn't an absolute path, start with cwd.
+  if (*path != '/') {
+    char *temp = xgetcwd();
+
+    splitpath(path, splitpath(temp, &todo));
+    free(temp);
+  } else splitpath(path, &todo);
+
+  // Iterate through path components
+  while (todo) {
+    struct string_list *new = llist_pop(&todo), **tail;
+    ssize_t len;
+
+    if (!try--) {
+      errno = ELOOP;
+      goto error;
+    }
+
+    // Removable path componenents.
+    if (!strcmp(new->str, ".") || !strcmp(new->str, "..")) {
+      int x = new->str[1];
+
+      free(new);
+      if (x) {
+        if (done) free(llist_pop(&done));
+        len = 0;
+      } else continue;
+
+    // Is this a symlink?
+    } else len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf));
+
+    if (len>4095) goto error;
+    if (len<1) {
+      int fd;
+      char *s = "..";
+
+      // For .. just move dirfd
+      if (len) {
+        // Not a symlink: add to linked list, move dirfd, fail if error
+        if ((exact || todo) && errno != EINVAL) goto error;
+        new->next = done;
+        done = new;
+        if (errno == EINVAL && !todo) break;
+        s = new->str;
+      }
+      fd = openat(dirfd, s, 0);
+      if (fd == -1 && (exact || todo || errno != ENOENT)) goto error;
+      close(dirfd);
+      dirfd = fd;
+      continue;
+    }
+
+    // If this symlink is to an absolute path, discard existing resolved path
+    libbuf[len] = 0;
+    if (*libbuf == '/') {
+      llist_traverse(done, free);
+      done=0;
+      close(dirfd);
+      dirfd = open("/", 0);
+    }
+    free(new);
+
+    // prepend components of new path. Note symlink to "/" will leave new NULL
+    tail = splitpath(libbuf, &new);
+
+    // symlink to "/" will return null and leave tail alone
+    if (new) {
+      *tail = todo;
+      todo = new;
+    }
+  }
+  close(dirfd);
+
+  // At this point done has the path, in reverse order. Reverse list while
+  // calculating buffer length.
+
+  try = 2;
+  while (done) {
+    struct string_list *temp = llist_pop(&done);;
+
+    if (todo) try++;
+    try += strlen(temp->str);
+    temp->next = todo;
+    todo = temp;
+  }
+
+  // Assemble return buffer
+
+  ret = xmalloc(try);
+  *ret = '/';
+  ret [try = 1] = 0;
+  while (todo) {
+    if (try>1) ret[try++] = '/';
+    try = stpcpy(ret+try, todo->str) - ret;
+    free(llist_pop(&todo));
+  }
+
+  return ret;
+
+error:
+  close(dirfd);
+  llist_traverse(todo, free);
+  llist_traverse(done, free);
+
+  return NULL;
+}
+
+void xchdir(char *path)
+{
+  if (chdir(path)) error_exit("chdir '%s'", path);
+}
+
+void xchroot(char *path)
+{
+  if (chroot(path)) error_exit("chroot '%s'", path);
+  xchdir("/");
+}
+
+struct passwd *xgetpwuid(uid_t uid)
+{
+  struct passwd *pwd = getpwuid(uid);
+  if (!pwd) error_exit("bad uid %ld", (long)uid);
+  return pwd;
+}
+
+struct group *xgetgrgid(gid_t gid)
+{
+  struct group *group = getgrgid(gid);
+
+  if (!group) perror_exit("gid %ld", (long)gid);
+  return group;
+}
+
+unsigned xgetuid(char *name)
+{
+  struct passwd *up = getpwnam(name);
+  char *s = 0;
+  long uid;
+
+  if (up) return up->pw_uid;
+
+  uid = estrtol(name, &s, 10);
+  if (!errno && s && !*s && uid>=0 && uid<=UINT_MAX) return uid;
+
+  error_exit("bad user '%s'", name);
+}
+
+unsigned xgetgid(char *name)
+{
+  struct group *gr = getgrnam(name);
+  char *s = 0;
+  long gid;
+
+  if (gr) return gr->gr_gid;
+
+  gid = estrtol(name, &s, 10);
+  if (!errno && s && !*s && gid>=0 && gid<=UINT_MAX) return gid;
+
+  error_exit("bad group '%s'", name);
+}
+
+struct passwd *xgetpwnam(char *name)
+{
+  struct passwd *up = getpwnam(name);
+
+  if (!up) perror_exit("user '%s'", name);
+  return up;
+}
+
+struct group *xgetgrnam(char *name)
+{
+  struct group *gr = getgrnam(name);
+
+  if (!gr) perror_exit("group '%s'", name);
+  return gr;
+}
+
+// setuid() can fail (for example, too many processes belonging to that user),
+// which opens a security hole if the process continues as the original user.
+
+void xsetuser(struct passwd *pwd)
+{
+  if (initgroups(pwd->pw_name, pwd->pw_gid) || setgid(pwd->pw_uid)
+      || setuid(pwd->pw_uid)) perror_exit("xsetuser '%s'", pwd->pw_name);
+}
+
+// This can return null (meaning file not found).  It just won't return null
+// for memory allocation reasons.
+char *xreadlink(char *name)
+{
+  int len, size = 0;
+  char *buf = 0;
+
+  // Grow by 64 byte chunks until it's big enough.
+  for(;;) {
+    size +=64;
+    buf = xrealloc(buf, size);
+    len = readlink(name, buf, size);
+
+    if (len<0) {
+      free(buf);
+      return 0;
+    }
+    if (len<size) {
+      buf[len]=0;
+      return buf;
+    }
+  }
+}
+
+char *xreadfile(char *name, char *buf, off_t len)
+{
+  if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name);
+
+  return buf;
+}
+
+int xioctl(int fd, int request, void *data)
+{
+  int rc;
+
+  errno = 0;
+  rc = ioctl(fd, request, data);
+  if (rc == -1 && errno) perror_exit("ioctl %x", request);
+
+  return rc;
+}
+
+// Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
+// exists and is this executable.
+void xpidfile(char *name)
+{
+  char pidfile[256], spid[32];
+  int i, fd;
+  pid_t pid;
+
+  sprintf(pidfile, "/var/run/%s.pid", name);
+  // Try three times to open the sucker.
+  for (i=0; i<3; i++) {
+    fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
+    if (fd != -1) break;
+
+    // If it already existed, read it.  Loop for race condition.
+    fd = open(pidfile, O_RDONLY);
+    if (fd == -1) continue;
+
+    // Is the old program still there?
+    spid[xread(fd, spid, sizeof(spid)-1)] = 0;
+    close(fd);
+    pid = atoi(spid);
+    if (pid < 1 || (kill(pid, 0) && errno == ESRCH)) unlink(pidfile);
+
+    // An else with more sanity checking might be nice here.
+  }
+
+  if (i == 3) error_exit("xpidfile %s", name);
+
+  xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
+  close(fd);
+}
+
+// Copy the rest of in to out and close both files.
+
+void xsendfile(int in, int out)
+{
+  long len;
+
+  if (in<0) return;
+  for (;;) {
+    len = xread(in, libbuf, sizeof(libbuf));
+    if (len<1) break;
+    xwrite(out, libbuf, len);
+  }
+}
+
+// parse fractional seconds with optional s/m/h/d suffix
+long xparsetime(char *arg, long units, long *fraction)
+{
+  double d;
+  long l;
+
+  if (CFG_TOYBOX_FLOAT) d = strtod(arg, &arg);
+  else l = strtoul(arg, &arg, 10);
+
+  // Parse suffix
+  if (*arg) {
+    int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg);
+
+    if (i == -1) error_exit("Unknown suffix '%c'", *arg);
+    if (CFG_TOYBOX_FLOAT) d *= ismhd[i];
+    else l *= ismhd[i];
+  }
+
+  if (CFG_TOYBOX_FLOAT) {
+    l = (long)d;
+    if (fraction) *fraction = units*(d-l);
+  } else if (fraction) *fraction = 0;
+
+  return l;
+}
+
+// Compile a regular expression into a regex_t
+void xregcomp(regex_t *preg, char *regex, int cflags)
+{
+  int rc = regcomp(preg, regex, cflags);
+
+  if (rc) {
+    regerror(rc, preg, libbuf, sizeof(libbuf));
+    error_exit("xregcomp: %s", libbuf);
+  }
+}
+
+char *xtzset(char *new)
+{
+  char *old = getenv("TZ");
+
+  if (old) old = xstrdup(old);
+  if (new ? setenv("TZ", new, 1) : unsetenv("TZ")) perror_exit("setenv");
+  tzset();
+
+  return old;
+}
+
+// Set a signal handler
+void xsignal(int signal, void *handler)
+{
+  struct sigaction *sa = (void *)libbuf;
+
+  memset(sa, 0, sizeof(struct sigaction));
+  sa->sa_handler = handler;
+
+  if (sigaction(signal, sa, 0)) perror_exit("xsignal %d", signal);
+}
diff --git a/toybox/main.c b/toybox/main.c
new file mode 100644
index 0000000..c0c1b82
--- /dev/null
+++ b/toybox/main.c
@@ -0,0 +1,233 @@
+/* Toybox infrastructure.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+#include "toys.h"
+
+#ifndef TOYBOX_VERSION
+#define TOYBOX_VERSION "0.7.1"
+#endif
+
+// Populate toy_list[].
+
+#undef NEWTOY
+#undef OLDTOY
+#define NEWTOY(name, opts, flags) {#name, name##_main, OPTSTR_##name, flags},
+#define OLDTOY(name, oldname, flags) \
+  {#name, oldname##_main, OPTSTR_##oldname, flags},
+
+struct toy_list toy_list[] = {
+#include "generated/newtoys.h"
+};
+
+// global context for this command.
+
+struct toy_context toys;
+union global_union this;
+char toybuf[4096], libbuf[4096];
+
+struct toy_list *toy_find(char *name)
+{
+  int top, bottom, middle;
+
+  if (!CFG_TOYBOX) return 0;
+
+  // If the name starts with "toybox" accept that as a match.  Otherwise
+  // skip the first entry, which is out of order.
+
+  if (!strncmp(name,"toybox",6)) return toy_list;
+  bottom = 1;
+
+  // Binary search to find this command.
+
+  top = ARRAY_LEN(toy_list)-1;
+  for (;;) {
+    int result;
+
+    middle = (top+bottom)/2;
+    if (middle<bottom || middle>top) return NULL;
+    result = strcmp(name,toy_list[middle].name);
+    if (!result) return toy_list+middle;
+    if (result<0) top=--middle;
+    else bottom = ++middle;
+  }
+}
+
+// Figure out whether or not anything is using the option parsing logic,
+// because the compiler can't figure out whether or not to optimize it away
+// on its' own.  NEED_OPTIONS becomes a constant allowing if() to optimize
+// stuff out via dead code elimination.
+
+#undef NEWTOY
+#undef OLDTOY
+#define NEWTOY(name, opts, flags) opts ||
+#define OLDTOY(name, oldname, flags) OPTSTR_##oldname ||
+static const int NEED_OPTIONS =
+#include "generated/newtoys.h"
+0;  // Ends the opts || opts || opts...
+
+// Setup toybox global state for this command.
+static void toy_singleinit(struct toy_list *which, char *argv[])
+{
+  toys.which = which;
+  toys.argv = argv;
+
+  if (CFG_TOYBOX_I18N) setlocale(LC_ALL, "C"+!!(which->flags & TOYFLAG_LOCALE));
+
+  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);
+    xexit();
+  }
+
+  if (NEED_OPTIONS && which->options) get_optflags();
+  else {
+    toys.optargs = argv+1;
+    for (toys.optc = 0; toys.optargs[toys.optc]; toys.optc++);
+  }
+  toys.old_umask = umask(0);
+  if (!(which->flags & TOYFLAG_UMASK)) umask(toys.old_umask);
+  toys.signalfd--;
+  toys.toycount = ARRAY_LEN(toy_list);
+}
+
+// Full init needed by multiplexer or reentrant calls, calls singleinit at end
+void toy_init(struct toy_list *which, char *argv[])
+{
+  void *oldwhich = toys.which;
+
+  // Drop permissions for non-suid commands.
+
+  if (CFG_TOYBOX_SUID) {
+    if (!toys.which) toys.which = toy_list;
+
+    uid_t uid = getuid(), euid = geteuid();
+
+    if (!(which->flags & TOYFLAG_STAYROOT)) {
+      if (uid != euid) {
+        if (setuid(uid)) perror_exit("setuid %d->%d", euid, uid); // drop root
+        euid = uid;
+        toys.wasroot++;
+      }
+    } else if (CFG_TOYBOX_DEBUG && uid && which != toy_list)
+      error_msg("Not installed suid root");
+
+    if ((which->flags & TOYFLAG_NEEDROOT) && euid) help_exit("Not root");
+  }
+
+  // Free old toys contents (to be reentrant), but leave rebound if any
+  // don't blank old optargs if our new argc lives in the old optargs.
+  if (argv<toys.optargs || argv>toys.optargs+toys.optc) free(toys.optargs);
+  memset(&toys, 0, offsetof(struct toy_context, rebound));
+  if (oldwhich) memset(&this, 0, sizeof(this));
+
+  // Continue to portion of init needed by standalone commands
+  toy_singleinit(which, argv);
+}
+
+// Like exec() but runs an internal toybox command instead of another file.
+// Only returns if it can't run command internally, otherwise exit() when done.
+void toy_exec(char *argv[])
+{
+  struct toy_list *which;
+
+  // Return if we can't find it (which includes no multiplexer case),
+  if (!(which = toy_find(*argv))) return;
+
+  // Return if stack depth getting noticeable (proxy for leaked heap, etc).
+
+  // 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;
+
+  // Run command
+  toy_init(which, argv);
+  if (toys.which) toys.which->toy_main();
+  xexit();
+}
+
+// Multiplexer command, first argument is command to run, rest are args to that.
+// If first argument starts with - output list of command install paths.
+void toybox_main(void)
+{
+  static char *toy_paths[]={"usr/","bin/","sbin/",0};
+  int i, len = 0;
+
+  // fast path: try to exec immediately.
+  // (Leave toys.which null to disable suid return logic.)
+  if (toys.argv[1]) toy_exec(toys.argv+1);
+
+  // For early error reporting
+  toys.which = toy_list;
+
+  if (toys.argv[1]) {
+    if (!strcmp("--version", toys.argv[1])) {
+      xputs(TOYBOX_VERSION);
+      xexit();
+    }
+    if (toys.argv[1][0] != '-') {
+      toys.exitval = 127;
+      error_exit("Unknown command %s", toys.argv[1]);
+    }
+  }
+
+  // Output list of command.
+  for (i=1; i<ARRAY_LEN(toy_list); i++) {
+    int fl = toy_list[i].flags;
+    if (fl & TOYMASK_LOCATION) {
+      if (toys.argv[1]) {
+        int j;
+        for (j=0; toy_paths[j]; j++)
+          if (fl & (1<<j)) len += printf("%s", toy_paths[j]);
+      }
+      len += printf("%s",toy_list[i].name);
+      if (++len > 65) len = 0;
+      xputc(len ? ' ' : '\n');
+    }
+  }
+  xputc('\n');
+}
+
+int main(int argc, char *argv[])
+{
+  if (!*argv) return 127;
+
+  // Snapshot stack location so we can detect recursion depth later.
+  // This is its own block so probe doesn't permanently consume stack.
+  else {
+    int stack;
+
+    toys.stacktop = &stack;
+  }
+  *argv = getbasename(*argv);
+
+  // If nommu can't fork, special reentry path.
+  // Use !stacktop to signal "vfork happened", both before and after xexec()
+  if (!CFG_TOYBOX_FORK) {
+    if (0x80 & **argv) {
+      **argv &= 0x7f;
+      toys.stacktop = 0;
+    }
+  }
+
+  if (CFG_TOYBOX) {
+    // Call the multiplexer, adjusting this argv[] to be its' argv[1].
+    // (It will adjust it back before calling toy_exec().)
+    toys.argv = argv-1;
+    toybox_main();
+  } else {
+    // a single toybox command built standalone with no multiplexer
+    toy_singleinit(toy_list, argv);
+    toy_list->toy_main();
+  }
+
+  xexit();
+}
diff --git a/toybox/scripts/bloatcheck b/toybox/scripts/bloatcheck
new file mode 100755
index 0000000..fff4690
--- /dev/null
+++ b/toybox/scripts/bloatcheck
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+if [ $# -ne 2 ]
+then
+  echo "usage: bloatcheck old new"
+  exit 1
+fi
+
+addline()
+{
+  NEXT="$(printf "%s% $((50-${#LASTNAME}))d% 10d %10d" "$LASTNAME" "$OLD" "$NEW" "$DELTA")"
+  [ -z "$STUFF" ] &&
+    STUFF="$NEXT" ||
+    STUFF="$(printf "%s\n%s" "$STUFF" "$NEXT")"
+}
+
+do_bloatcheck()
+{
+  LASTNAME=
+  DELTA=0
+  TOTAL=0
+  OLD=0
+  NEW=0
+  STUFF=
+
+  printf "name% 46s% 10s% 11s\n" old new delta
+  echo "-----------------------------------------------------------------------"
+  while read a b c d
+  do
+    THISNAME=$(echo "$d" | sed 's/[.][0-9]*$//')
+
+    if [ "$LASTNAME" != "$THISNAME" ]
+    then
+      TOTAL=$(($TOTAL+$DELTA))
+      [ $DELTA -ne 0 ] && addline
+      LASTNAME="$THISNAME"
+      DELTA=0
+      OLD=0
+      NEW=0
+    fi
+
+    SIZE=$(printf "%d" "0x$b")
+    if [ "$a" == "-" ]
+    then
+      OLD=$(($OLD+$SIZE))
+      SIZE=$((-1*$SIZE))
+    else
+      NEW=$(($NEW+$SIZE))
+    fi
+    DELTA=$(($DELTA+$SIZE))
+  done
+
+  TOTAL=$(($TOTAL+$DELTA))
+  [ $DELTA -ne 0 ] && addline
+
+  echo "$STUFF" | sort -k4,4nr
+  echo "-----------------------------------------------------------------------"
+  printf "% 71d total\n" "$TOTAL"
+}
+
+DIFF1=`mktemp base.XXXXXXX`
+DIFF2=`mktemp bloat.XXXXXXX`
+trap "rm $DIFF1 $DIFF2" EXIT
+nm --size-sort "$1" | sort -k3,3 > $DIFF1
+nm --size-sort "$2" | sort -k3,3 > $DIFF2
+diff -U 0 $DIFF1 $DIFF2 | tail -n +3 | sed -n 's/^\([-+]\)/\1 /p' \
+  | sort -k4,4 | do_bloatcheck
diff --git a/toybox/scripts/change.sh b/toybox/scripts/change.sh
new file mode 100755
index 0000000..99dcfde
--- /dev/null
+++ b/toybox/scripts/change.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# build each command as a standalone executable
+
+NOBUILD=1 scripts/make.sh > /dev/null &&
+${HOSTCC:-cc} -I . scripts/install.c -o generated/instlist &&
+export PREFIX=${PREFIX:-change/} &&
+mkdir -p "$PREFIX" || exit 1
+
+# Build all the commands standalone except:
+
+# sh - shell builtins like "cd" and "exit" need the multiplexer
+# help - needs to know what other commands are enabled (use command --help)
+
+for i in $(generated/instlist | egrep -vw "sh|help")
+do
+  echo -n " $i" &&
+  scripts/single.sh $i > /dev/null 2>$PREFIX/${i}.bad &&
+    rm $PREFIX/${i}.bad || echo -n '*'
+done
+echo
diff --git a/toybox/scripts/config2help.c b/toybox/scripts/config2help.c
new file mode 100644
index 0000000..6ec5e84
--- /dev/null
+++ b/toybox/scripts/config2help.c
@@ -0,0 +1,415 @@
+//#include "toys.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <regex.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"
+
+// Humor toys.h (lie through our teeth, C's linker doesn't care).
+char toys[4096], libbuf[4096], toybuf[4096];
+void show_help(FILE *out) {;}
+void toy_exec(char *argv[]) {;}
+void toy_init(void *which, char *argv[]) {;}
+
+// Parse config files into data structures.
+
+struct symbol {
+  struct symbol *next;
+  int enabled, help_indent;
+  char *name, *depends;
+  struct double_list *help;
+} *sym;
+
+// remove leading spaces
+char *trim(char *s)
+{
+  while (isspace(*s)) s++;
+
+  return s;
+}
+
+// if line starts with name (as whole word) return pointer after it, else NULL
+char *keyword(char *name, char *line)
+{
+  int len = strlen(name);
+
+  line = trim(line);
+  if (strncmp(name, line, len)) return 0;
+  line += len;
+  if (*line && !isspace(*line)) return 0;
+  line = trim(line);
+
+  return line;
+}
+
+// dlist_pop() freeing wrapper structure for you.
+char *dlist_zap(struct double_list **help)
+{
+  struct double_list *dd = dlist_pop(help);
+  char *s = dd->data;
+
+  free(dd);
+  
+  return s;
+}
+
+int zap_blank_lines(struct double_list **help)
+{
+  int got = 0;
+
+  while (*help) {
+    char *s;
+
+    s = trim((*help)->data);
+
+    if (*s) break;
+    got++;
+    free(dlist_zap(help));
+  }
+
+  return got;
+}
+
+// Collect "-a blah" description lines following a blank line (or start).
+// Returns array of removed lines with *len entries (0 for none).
+
+// Moves *help to new start of text (in case dash lines were at beginning).
+// Sets *from to where dash lines removed from (in case they weren't).
+// Discards blank lines before and after dashlines.
+
+// If no prefix, *help NULL. If no postfix, *from == *help
+// if no dashlines returned *from == *help.
+
+char **grab_dashlines(struct double_list **help, struct double_list **from,
+                      int *len)
+{
+  struct double_list *dd;
+  char *s, **list;
+  int count = 0;
+
+  *len = 0;
+  zap_blank_lines(help);
+  *from = *help;
+
+  // Find start of dash block. Must be at start or after blank line.
+  for (;;) {
+    s = trim((*from)->data);
+    if (*s == '-' && s[1] != '-' && !count) break;
+
+    if (!*s) count = 0;
+    else count++;
+
+    *from = (*from)->next;
+    if (*from == *help) return 0;
+  }
+
+  // If there was whitespace before this, zap it. This can't take out *help
+  // because zap_blank_lines skipped blank lines, and we had to have at least
+  // one non-blank line (a dash line) to get this far.
+  while (!*trim((*from)->prev->data)) {
+    *from = (*from)->prev;
+    free(dlist_zap(from));
+  }
+
+  // Count number of dashlines, copy out to array, zap trailing whitespace
+  // If *help was at start of dashblock, move it with *from
+  count = 0;
+  dd = *from;
+  if (*help == *from) *help = 0;
+  for (;;) {
+   if (*trim(dd->data) != '-') break;
+   count++;
+   if (*from == (dd = dd->next)) break;
+  }
+
+  list = xmalloc(sizeof(char *)*count);
+  *len = count;
+  while (count) list[--count] = dlist_zap(from);
+
+  return list;
+}
+
+void parse(char *filename)
+{
+  FILE *fp = xfopen(filename, "r");
+  struct symbol *new = 0;
+
+  for (;;) {
+    char *s, *line = NULL;
+    size_t len;
+
+    // Read line, trim whitespace at right edge.
+    if (getline(&line, &len, fp) < 1) break;
+    s = line+strlen(line);
+    while (--s >= line) {
+      if (!isspace(*s)) break;
+      *s = 0;
+    }
+
+    // source or config keyword at left edge?
+    if (*line && !isspace(*line)) {
+      if ((s = keyword("config", line))) {
+        new = xzalloc(sizeof(struct symbol));
+        new->next = sym;
+        new->name = s;
+        sym = new;
+      } else if ((s = keyword("source", line))) parse(s);
+
+      continue;
+    }
+    if (!new) continue;
+
+    if (sym && sym->help_indent) {
+      dlist_add(&(new->help), line);
+      if (sym->help_indent < 0) {
+        sym->help_indent = 0;
+        while (isspace(line[sym->help_indent])) sym->help_indent++;
+      }
+    }
+    else if ((s = keyword("depends", line)) && (s = keyword("on", s)))
+      new->depends = s;
+    else if (keyword("help", line)) sym->help_indent = -1;
+  }
+
+  fclose(fp);
+}
+
+int charsort(void *a, void *b)
+{
+  char *aa = a, *bb = b;
+
+  if (*aa < *bb) return -1;
+  if (*aa > *bb) return 1;
+  return 0;
+}
+
+int dashsort(char **a, char **b)
+{
+  char *aa = *a, *bb = *b;
+
+  if (aa[1] < bb[1]) return -1;
+  if (aa[1] > bb[1]) return 1;
+  return 0;
+}
+
+int dashlinesort(char **a, char **b)
+{
+  return strcmp(*a, *b);
+}
+
+int main(int argc, char *argv[])
+{
+  FILE *fp;
+
+  if (argc != 3) {
+    fprintf(stderr, "usage: config2help Config.in .config\n");
+    exit(1);
+  }
+
+  // Read Config.in
+  parse(argv[1]);
+
+  // read .config
+  fp = xfopen(argv[2], "r");
+  for (;;) {
+    char *line = NULL;
+    size_t len;
+
+    if (getline(&line, &len, fp) < 1) break;
+    if (!strncmp("CONFIG_", line, 7)) {
+      struct symbol *try;
+      char *s = line+7;
+
+      for (try=sym; try; try=try->next) {
+        len = strlen(try->name);
+        if (!strncmp(try->name, s, len) && s[len]=='=' && s[len+1]=='y') {
+          try->enabled++;
+          break;
+        } 
+      }
+    }
+  }
+
+  // Collate help according to usage, depends, and .config
+
+  // Loop through each entry, finding duplicate enabled "usage:" names
+  // This is in reverse order, so last entry gets collated with previous
+  // entry until we run out of matching pairs.
+  for (;;) {
+    struct symbol *throw = 0, *catch;
+    char *this, *that, *cusage, *tusage, *name;
+    int len;
+
+    // find a usage: name and collate all enabled entries with that name
+    for (catch = sym; catch; catch = catch->next) {
+      if (catch->enabled != 1) continue;
+      if (catch->help && (that = keyword("usage:", catch->help->data))) {
+        struct double_list *cfrom, *tfrom, *anchor;
+        char *try, **cdashlines, **tdashlines;
+        int clen, tlen;
+
+        // Align usage: lines, finding a matching pair so we can suck help
+        // text out of throw into catch, copying from this to that
+        if (!throw) name = that;
+        else if (strncmp(name, that, len) || !isspace(that[len])) continue;
+        catch->enabled++;
+        while (!isspace(*that) && *that) that++;
+        if (!throw) len = that-name;
+        that = trim(that);
+        if (!throw) {
+          throw = catch;
+          this = that;
+
+          continue;
+        }
+
+        // Grab option description lines to collate from catch and throw
+        tusage = dlist_zap(&throw->help);
+        tdashlines = grab_dashlines(&throw->help, &tfrom, &tlen);
+        cusage = dlist_zap(&catch->help);
+        cdashlines = grab_dashlines(&catch->help, &cfrom, &clen);
+        anchor = catch->help;
+
+        // If we've got both, collate and alphebetize
+        if (cdashlines && tdashlines) {
+          char **new = xmalloc(sizeof(char *)*(clen+tlen));
+
+          memcpy(new, cdashlines, sizeof(char *)*clen);
+          memcpy(new+clen, tdashlines, sizeof(char *)*tlen);
+          free(cdashlines);
+          free(tdashlines);
+          qsort(new, clen+tlen, sizeof(char *), (void *)dashlinesort);
+          cdashlines = new;
+
+        // If just one, make sure it's in catch.
+        } else if (tdashlines) cdashlines = tdashlines;
+
+        // If throw had a prefix, insert it before dashlines, with a
+        // blank line if catch had a prefix.
+        if (tfrom && tfrom != throw->help) {
+          if (throw->help || catch->help) dlist_add(&cfrom, strdup(""));
+          else {
+            dlist_add(&cfrom, 0);
+            anchor = cfrom->prev;
+          }
+          while (throw->help && throw->help != tfrom)
+            dlist_add(&cfrom, dlist_zap(&throw->help));
+          if (cfrom && cfrom->prev->data && *trim(cfrom->prev->data))
+            dlist_add(&cfrom, strdup(""));
+        }
+        if (!anchor) {
+          dlist_add(&cfrom, 0);
+          anchor = cfrom->prev;
+        }
+
+        // Splice sorted lines back in place
+        if (cdashlines) {
+          tlen += clen;
+
+          for (clen = 0; clen < tlen; clen++) 
+            dlist_add(&cfrom, cdashlines[clen]);
+        }
+
+        // If there were no dashlines, text would be considered prefix, so
+        // the list is definitely no longer empty, so discard placeholder.
+        if (!anchor->data) dlist_zap(&anchor);
+
+        // zap whitespace at end of catch help text
+        while (!*trim(anchor->prev->data)) {
+          anchor = anchor->prev;
+          free(dlist_zap(&anchor));
+        }
+
+        // Append trailing lines.
+        while (tfrom) dlist_add(&anchor, dlist_zap(&tfrom));
+
+        // Collate first [-abc] option block in usage: lines
+        try = 0;
+        if (*this == '[' && this[1] == '-' && this[2] != '-' &&
+            *that == '[' && that[1] == '-' && that[2] != '-')
+        {
+          char *from = this+2, *to = that+2;
+          int ff = strcspn(from, " ]"), tt = strcspn(to, " ]");
+
+          if (from[ff] == ']' && to[tt] == ']') {
+            try = xmprintf("[-%.*s%.*s] ", ff, from, tt, to);
+            qsort(try+2, ff+tt, 1, (void *)charsort);
+            this = trim(this+ff+3);
+            that = trim(that+tt+3);
+          }
+        }
+
+        // The list is definitely no longer empty, so discard placeholder.
+        if (!anchor->data) dlist_zap(&anchor);
+
+        // Add new collated line (and whitespace).
+        dlist_add(&anchor, xmprintf("%*cusage: %.*s %s%s%s%s",
+                  catch->help_indent, ' ', len, name, try ? try : "",
+                  this, *this ? " " : "", that));
+        free(try);
+        dlist_add(&anchor, strdup(""));
+        free(cusage);
+        free(tusage);
+        throw->enabled = 0;
+        throw = catch;
+        throw->help = anchor->prev->prev;
+
+        throw = catch;
+        this = throw->help->data + throw->help_indent + 8 + len;
+      }
+    }
+
+    // Did we find one?
+
+    if (!throw) break;
+  }
+
+  // Print out help #defines
+  while (sym) {
+    struct double_list *dd;
+
+    if (sym->help) {
+      int i;
+      char *s = xstrdup(sym->name);
+
+      for (i = 0; s[i]; i++) s[i] = tolower(s[i]);
+      printf("#define HELP_%s \"", s);
+      free(s);
+
+      dd = sym->help;
+      for (;;) {
+        i = sym->help_indent;
+
+        // Trim leading whitespace
+        s = dd->data;
+        while (isspace(*s) && i) {
+          s++;
+          i--;
+        }
+        for (i=0; s[i]; i++) {
+          if (s[i] == '"' || s[i] == '\\') putchar('\\');
+          putchar(s[i]);
+        }
+        putchar('\\');
+        putchar('n');
+        dd = dd->next;
+        if (dd == sym->help) break;
+      }
+      printf("\"\n\n");
+    }
+    sym = sym->next;
+  }
+
+  return 0;
+}
diff --git a/toybox/scripts/findglobals.sh b/toybox/scripts/findglobals.sh
new file mode 100755
index 0000000..2c63164
--- /dev/null
+++ b/toybox/scripts/findglobals.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# Quick and dirty check to see if anybody's leaked global variables.
+# We should have this, toy_list, toybuf, and toys.
+
+nm toybox_unstripped | grep '[0-9A-Fa-f]* [BCDGRS]' | cut -d ' ' -f 3
diff --git a/toybox/scripts/genconfig.sh b/toybox/scripts/genconfig.sh
new file mode 100755
index 0000000..c55e7d1
--- /dev/null
+++ b/toybox/scripts/genconfig.sh
@@ -0,0 +1,154 @@
+#!/bin/bash
+
+# This has to be a separate file from scripts/make.sh so it can be called
+# before menuconfig.  (It's called again from scripts/make.sh just to be sure.)
+
+mkdir -p generated
+
+source configure
+
+probecc()
+{
+  ${CROSS_COMPILE}${CC} $CFLAGS -xc -o /dev/null $1 -
+}
+
+# Probe for a single config symbol with a "compiles or not" test.
+# Symbol name is first argument, flags second, feed C file to stdin
+probesymbol()
+{
+  probecc $2 2>/dev/null && DEFAULT=y || DEFAULT=n
+  rm a.out 2>/dev/null
+  echo -e "config $1\n\tbool" || exit 1
+  echo -e "\tdefault $DEFAULT\n" || exit 1
+}
+
+probeconfig()
+{
+  > generated/cflags
+  # llvm produces its own really stupid warnings about things that aren't wrong,
+  # and although you can turn the warning off, gcc reacts badly to command line
+  # arguments it doesn't understand. So probe.
+  [ -z "$(probecc -Wno-string-plus-int <<< \#warn warn 2>&1 | grep string-plus-int)" ] &&
+    echo -Wno-string-plus-int >> generated/cflags
+
+  # Probe for container support on target
+  probesymbol TOYBOX_CONTAINER << EOF
+    #include <linux/sched.h>
+    int x=CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET;
+
+    int main(int argc, char *argv[]) { return unshare(x); }
+EOF
+
+  probesymbol TOYBOX_FIFREEZE -c << EOF
+    #include <linux/fs.h>
+    #ifndef FIFREEZE
+    #error nope
+    #endif
+EOF
+
+  # Work around some uClibc limitations
+  probesymbol TOYBOX_ICONV -c << EOF
+    #include "iconv.h"
+EOF
+  probesymbol TOYBOX_FALLOCATE << EOF
+    #include <fcntl.h>
+
+    int main(int argc, char *argv[]) { return posix_fallocate(0,0,0); }
+EOF
+  
+  # Android and some other platforms miss utmpx
+  probesymbol TOYBOX_UTMPX -c << EOF
+    #include <utmpx.h>
+    #ifndef BOOT_TIME
+    #error nope
+    #endif
+    int main(int argc, char *argv[]) {
+      struct utmpx *a; 
+      if (0 != (a = getutxent())) return 0;
+      return 1;
+    }
+EOF
+
+  # Android is missing shadow.h
+  probesymbol TOYBOX_SHADOW -c << EOF
+    #include <shadow.h>
+    int main(int argc, char *argv[]) {
+      struct spwd *a = getspnam("root"); return 0;
+    }
+EOF
+
+  # Some commands are android-specific
+  probesymbol TOYBOX_ON_ANDROID -c << EOF
+    #ifndef __ANDROID__
+    #error nope
+    #endif
+EOF
+
+  # nommu support
+  probesymbol TOYBOX_FORK << EOF
+    #include <unistd.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 -s -r)
+  do
+    DIR="$(dirname "$j")"
+
+    [ $(ls "$DIR" | wc -l) -lt 2 ] && continue
+
+    echo "menu \"$(head -n 1 $j)\""
+    echo
+
+    # extract config stanzas from each source file, in alphabetical order
+    for i in $(ls -1 $DIR/*.c)
+    do
+      # Grab the config block for Config.in
+      echo "# $i"
+      sed -n '/^\*\//q;/^config [A-Z]/,$p' $i || return 1
+      echo
+    done
+
+    echo endmenu
+  done
+}
+
+probeconfig > generated/Config.probed || rm generated/Config.probed
+genconfig > generated/Config.in || rm generated/Config.in
+
+# Find names of commands that can be built standalone in these C files
+toys()
+{
+  grep 'TOY(.*)' "$@" | grep -v TOYFLAG_NOFORK | grep -v "0))" | \
+    sed -rn 's/([^:]*):.*(OLD|NEW)TOY\( *([a-zA-Z][^,]*) *,.*/\1:\3/p'
+}
+
+WORKING=
+PENDING=
+toys toys/*/*.c | (
+while IFS=":" read FILE NAME
+do
+  [ "$NAME" == help ] && continue
+  [ "$NAME" == install ] && continue
+  echo -e "$NAME: $FILE *.[ch] lib/*.[ch]\n\tscripts/single.sh $NAME\n"
+  echo -e "test_$NAME:\n\tscripts/test.sh $NAME\n"
+  [ "${FILE/pending//}" != "$FILE" ] &&
+    PENDING="$PENDING $NAME" ||
+    WORKING="$WORKING $NAME"
+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
diff --git a/toybox/scripts/install.c b/toybox/scripts/install.c
new file mode 100644
index 0000000..3ffb867
--- /dev/null
+++ b/toybox/scripts/install.c
@@ -0,0 +1,37 @@
+/* Wrapper to make installation easier with cross-compiling.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+#include <stdio.h>
+#include "generated/config.h"
+#include "lib/toyflags.h"
+
+#define NEWTOY(name, opts, flags) {#name, flags},
+#define OLDTOY(name, oldname, flags) {#name, flags},
+
+// Populate toy_list[].
+
+struct {char *name; int flags;} toy_list[] = {
+#include "generated/newtoys.h"
+};
+
+int main(int argc, char *argv[])
+{
+  static char *toy_paths[]={"usr/","bin/","sbin/",0};
+  int i, len = 0;
+
+  // Output list of applets.
+  for (i=1; i<sizeof(toy_list)/sizeof(*toy_list); i++) {
+    int fl = toy_list[i].flags;
+    if (fl & TOYMASK_LOCATION) {
+      if (argc>1) {
+        int j;
+        for (j=0; toy_paths[j]; j++)
+          if (fl & (1<<j)) len += printf("%s", toy_paths[j]);
+      }
+      len += printf("%s\n",toy_list[i].name);
+    }
+  }
+  return 0;
+}
diff --git a/toybox/scripts/install.sh b/toybox/scripts/install.sh
new file mode 100755
index 0000000..961341e
--- /dev/null
+++ b/toybox/scripts/install.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+# Grab default values for $CFLAGS and such.
+
+source ./configure
+
+[ -z "$PREFIX" ] && PREFIX="/usr/toybox"
+
+# Parse command line arguments.
+
+LONG_PATH=""
+while [ ! -z "$1" ]
+do
+  # Create symlinks instead of hardlinks?
+  [ "$1" == "--symlink" ] && LINK_TYPE="-s"
+
+  # Uninstall?
+  [ "$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?
+  [ "$1" == "--long" ] && LONG_PATH="bin/"
+
+  shift
+done
+
+echo "Compile instlist..."
+
+$DEBUG $HOSTCC -I . scripts/install.c -o generated/instlist || exit 1
+COMMANDS="$(generated/instlist $LONG_PATH)"
+
+echo "${UNINSTALL:-Install} commands..."
+
+# Copy toybox itself
+
+if [ -z "$UNINSTALL" ]
+then
+  mkdir -p "${PREFIX}/${LONG_PATH}" &&
+  rm -f "${PREFIX}/${LONG_PATH}/toybox" &&
+  cp toybox ${PREFIX}/${LONG_PATH} || exit 1
+else
+  rm -f "${PREFIX}/${LONG_PATH}/toybox" 2>/dev/null
+fi
+cd "$PREFIX" || exit 1
+
+# Make links to toybox
+
+EXIT=0
+
+for i in $COMMANDS
+do
+  # Figure out target of link
+
+  if [ -z "$LONG_PATH" ]
+  then
+    DOTPATH=""
+  else
+    # Create subdirectory for command to go in (if necessary)
+
+    DOTPATH="$(dirname "$i")"/
+    if [ -z "$UNINSTALL" ]
+    then
+      mkdir -p "$DOTPATH" || exit 1
+    fi
+
+    if [ -z "$LINK_TYPE" ]
+    then
+      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
+    fi
+  fi
+
+  # Create link
+  if [ -z "$UNINSTALL" ]
+  then
+    ln $DO_FORCE $LINK_TYPE ${DOTPATH}toybox $i || EXIT=1
+  else
+    rm -f $i || EXIT=1
+  fi
+done
+
+exit $EXIT
diff --git a/toybox/scripts/make.sh b/toybox/scripts/make.sh
new file mode 100755
index 0000000..50415e5
--- /dev/null
+++ b/toybox/scripts/make.sh
@@ -0,0 +1,340 @@
+#!/bin/bash
+
+# Grab default values for $CFLAGS and such.
+
+export LANG=c
+export LC_ALL=C
+set -o pipefail
+source ./configure
+
+[ -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.
+[ -z "$CPUS" ] &&
+  CPUS=$((($(echo /sys/devices/system/cpu/cpu[0-9]* | wc -w)*3)/2))
+
+# Respond to V= by echoing command lines as well as running them
+DOTPROG=
+do_loudly()
+{
+  [ ! -z "$V" ] && echo "$@" || echo -n "$DOTPROG"
+  "$@"
+}
+
+# Is anything under directory $2 newer than file $1
+isnewer()
+{
+  CHECK="$1"
+  shift
+  [ ! -z "$(find "$@" -newer "$CHECK" 2>/dev/null || echo yes)" ]
+}
+
+echo "Generate headers from toys/*/*.c..."
+
+mkdir -p generated/unstripped
+
+if isnewer generated/Config.in toys
+then
+  echo "Extract configuration information from toys/*.c files..."
+  scripts/genconfig.sh
+fi
+
+# Create a list of all the commands toybox can provide. Note that the first
+# entry is out of order on purpose (the toybox multiplexer command must be the
+# first element of the array). The rest must be sorted in alphabetical order
+# for fast binary search.
+
+if isnewer generated/newtoys.h toys
+then
+  echo -n "generated/newtoys.h "
+
+  echo "USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT))" > generated/newtoys.h
+  sed -n -e 's/^USE_[A-Z0-9_]*(/&/p' toys/*/*.c \
+	| sed 's/\(.*TOY(\)\([^,]*\),\(.*\)/\2 \1\2,\3/' | sort -s -k 1,1 \
+	| sed 's/[^ ]* //'  >> generated/newtoys.h || exit 1
+fi
+
+[ ! -z "$V" ] && echo "Which C files to build..."
+
+# Extract a list of toys/*/*.c files to compile from the data in $KCONFIG_CONFIG
+# (First command names, then filenames with relevant {NEW,OLD}TOY() macro.)
+
+GITHASH="$(git describe --tags --abbrev=12 2>/dev/null)"
+[ ! -z "$GITHASH" ] && GITHASH="-DTOYBOX_VERSION=\"$GITHASH\""
+TOYFILES="$(sed -n 's/^CONFIG_\([^=]*\)=.*/\1/p' "$KCONFIG_CONFIG" | xargs | tr ' [A-Z]' '|[a-z]')"
+TOYFILES="$(egrep -l "TOY[(]($TOYFILES)[ ,]" toys/*/*.c)"
+CFLAGS="$CFLAGS $(cat generated/cflags)"
+BUILD="$(echo ${CROSS_COMPILE}${CC} $CFLAGS -I . $OPTIMIZE $GITHASH)"
+LIBFILES="$(ls lib/*.c | grep -v lib/help.c)"
+TOYFILES="lib/help.c main.c $TOYFILES"
+
+if [ "${TOYFILES/pending//}" != "$TOYFILES" ]
+then
+  echo -e "\n\033[1;31mwarning: using unfinished code from toys/pending\033[0m"
+fi
+
+genbuildsh()
+{
+  # Write a canned build line for use on crippled build machines.
+
+  echo "#!/bin/sh"
+  echo
+  echo "BUILD='$BUILD'"
+  echo
+  echo "FILES='$LIBFILES $TOYFILES'"
+  echo
+  echo "LINK='$LINK'"
+  echo
+  echo
+  echo '$BUILD $FILES $LINK'
+}
+
+if ! cmp -s <(genbuildsh | head -n 3) \
+          <(head -n 3 generated/build.sh 2>/dev/null)
+then
+  echo -n "Library probe"
+
+  # We trust --as-needed to remove each library if we don't use any symbols
+  # out of it, this loop is because the compiler has no way to ignore a library
+  # that doesn't exist, so we have to detect and skip nonexistent libraries
+  # for it.
+
+  > generated/optlibs.dat
+  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 &&
+    echo -l$i >> generated/optlibs.dat
+    echo -n .
+  done
+  rm -f generated/libprobe
+  echo
+fi
+
+# LINK needs optlibs.dat, above
+
+LINK="$(echo $LDOPTIMIZE $LDFLAGS -o "$UNSTRIPPED" -Wl,--as-needed $(cat generated/optlibs.dat))"
+genbuildsh > generated/build.sh && chmod +x generated/build.sh || 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
+
+# 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.)
+
+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.
+
+  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
+
+function getglobals()
+{
+  for i in toys/*/*.c
+  do
+    NAME="$(echo $i | sed 's@.*/\(.*\)\.c@\1@')"
+    DATA="$(sed -n -e '/^GLOBALS(/,/^)/b got;b;:got' \
+            -e 's/^GLOBALS(/struct '"$NAME"'_data {/' \
+            -e 's/^)/};/' -e 'p' $i)"
+
+    [ ! -z "$DATA" ] && echo -e "// $i\n\n$DATA\n"
+  done
+}
+
+if isnewer generated/globals.h toys
+then
+  echo -n "generated/globals.h "
+  GLOBSTRUCT="$(getglobals)"
+  (
+    echo "$GLOBSTRUCT"
+    echo
+    echo "extern union global_union {"
+    echo "$GLOBSTRUCT" | \
+      sed -n 's/struct \(.*\)_data {/	struct \1_data \1;/p'
+    echo "} this;"
+  ) > generated/globals.h
+fi
+
+if [ generated/mktags -ot scripts/mktags.c ]
+then
+  do_loudly $HOSTCC scripts/mktags.c -o generated/mktags || exit 1
+fi
+
+if isnewer generated/tags.h toys
+then
+  echo -n "generated/tags.h "
+
+  sed -n '/TAGGED_ARRAY(/,/^)/{s/.*TAGGED_ARRAY[(]\([^,]*\),/\1/;p}' \
+    toys/*/*.c lib/*.c | generated/mktags > generated/tags.h
+fi
+
+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
+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
+
+echo -n "Compile toybox"
+[ ! -z "$V" ] && echo
+DOTPROG=.
+
+# This is a parallel version of: do_loudly $BUILD $FILES $LINK || exit 1
+
+# Any headers newer than the oldest generated/obj file?
+X="$(ls -1t generated/obj/* 2>/dev/null | tail -n 1)"
+# TODO: redo this
+if [ ! -e "$X" ] || [ ! -z "$(find toys -name "*.h" -newer "$X")" ]
+then
+  rm -rf generated/obj && mkdir -p generated/obj || exit 1
+else
+  rm -f generated/obj/{main,lib_help}.o || exit 1
+fi
+
+# build each generated/obj/*.o file in parallel
+
+PENDING=
+LNKFILES=
+DONE=0
+COUNT=0
+CLICK=
+
+for i in $LIBFILES click $TOYFILES
+do
+  [ "$i" == click ] && CLICK=1 && continue
+
+  X=${i/lib\//lib_}
+  X=${X##*/}
+  OUT="generated/obj/${X%%.c}.o"
+  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
+
+  for j in $PENDING
+  do
+    [ "$COUNT" -lt "$CPUS" ] && break;
+
+    wait $j
+    DONE=$(($DONE+$?))
+    COUNT=$(($COUNT-1))
+    PENDING="${PENDING## $j}"
+  done
+  [ $DONE -ne 0 ] && break
+done
+
+# wait for all background jobs, detecting errors
+
+for i in $PENDING
+do
+  wait $i
+  DONE=$(($DONE+$?))
+done
+
+[ $DONE -ne 0 ] && exit 1
+
+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 "$UNSTRIPPED" "$OUTNAME" ||
+  exit 1
+fi
+
+# gcc 4.4's strip command is buggy, and doesn't set the executable bit on
+# 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 "$OUTNAME" || exit 1
+
+echo
diff --git a/toybox/scripts/minicom.sh b/toybox/scripts/minicom.sh
new file mode 100755
index 0000000..1a9b0d8
--- /dev/null
+++ b/toybox/scripts/minicom.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# If you want to use toybox netcat to talk to a serial port, use this.
+
+if [ ! -c "$1" ]
+then
+  echo "Usage: minicom.sh /dev/ttyS0"
+  exit 1
+fi
+
+SPEED="$2"
+[ -z "$SPEED" ] && SPEED=115200
+
+stty $SPEED -F "$1"
+stty raw -echo -ctlecho -F "$1"
+stty raw -echo  # Need to do it on stdin, too.
+./toybox netcat -f "$1"
+stty cooked echo  # Put stdin back.
diff --git a/toybox/scripts/mkflags.c b/toybox/scripts/mkflags.c
new file mode 100644
index 0000000..39b935b
--- /dev/null
+++ b/toybox/scripts/mkflags.c
@@ -0,0 +1,220 @@
+// Take three word input lines on stdin (the three space separated words are
+// command name, option string with current config, option string from
+// allyesconfig; space separated, the last two are and double quotes)
+// and produce flag #defines to stdout.
+
+// This is intentionally crappy code because we control the inputs. It leaks
+// memory like a sieve and segfaults if malloc returns null, but does the job.
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+struct flag {
+  struct flag *next;
+  char *command;
+  struct flag *lopt;
+};
+
+// replace chopped out USE_BLAH() sections with low-ascii characters
+// showing how many flags got skipped
+
+char *mark_gaps(char *flags, char *all)
+{
+  char *n, *new, c;
+
+  // Shell feeds in " " for blank args, leading space not meaningful.
+  while (isspace(*flags)) flags++;
+  while (isspace(*all)) all++;
+
+  n = new = strdup(all);
+  while (*all) {
+    if (*flags == *all) {
+      *(new++) = *(all++);
+      *flags++;
+      continue;
+    }
+
+    c = *(all++);
+    if (strchr("?&^-:#|@*; ", c));
+    else if (strchr("=<>", c)) while (isdigit(*all)) all++;
+    else if (c == '(') while(*(all++) != ')');
+    else *(new++) = 1;
+  }
+  *new = 0;
+
+  return n;
+}
+
+// Break down a command string into struct flag list.
+
+struct flag *digest(char *string)
+{
+  struct flag *list = NULL;
+  char *err = string;
+
+  while (*string) {
+    // Groups must be at end.
+    if (*string == '[') break;
+
+    // Longopts
+    if (*string == '(') {
+      struct flag *new = calloc(sizeof(struct flag), 1);
+
+      new->command = ++string;
+
+      // Attach longopt to previous short opt, if any.
+      if (list && list->command) {
+        new->next = list->lopt;
+        list->lopt = new;
+      } else {
+        struct flag *blank = calloc(sizeof(struct flag), 1);
+
+        blank->next = list;
+        blank->lopt = new;
+        list = blank;
+      }
+      // An empty longopt () would break this.
+      while (*++string != ')') if (*string == '-') *string = '_';
+      *(string++) = 0;
+      continue;
+    }
+
+    if (strchr("?&^-:#|@*; ", *string)) string++;
+    else if (strchr("=<>", *string)) {
+      if (!isdigit(string[1])) {
+        fprintf(stderr, "%c without number in '%s'", *string, err);
+        exit(1);
+      }
+      while (isdigit(*++string)) {
+        if (!list) {
+           string++;
+           break;
+        }
+      }
+    } else {
+      struct flag *new = calloc(sizeof(struct flag), 1);
+
+      new->command = string++;
+      new->next = list;
+      list = new;
+    }
+  }
+
+  return list;
+}
+
+int main(int argc, char *argv[])
+{
+  char command[256], flags[1023], allflags[1024];
+  char *out, *outbuf = malloc(1024*1024);
+
+  // Yes, the output buffer is 1 megabyte with no bounds checking.
+  // See "intentionally crappy", above.
+  if (!(out = outbuf)) return 1;
+
+  printf("#undef FORCED_FLAG\n#undef FORCED_FLAGLL\n"
+    "#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n#define FORCED_FLAGLL 1LL\n"
+    "#else\n#define FORCED_FLAG 0\n#define FORCED_FLAGLL 0\n#endif\n\n");
+
+  for (;;) {
+    struct flag *flist, *aflist, *offlist;
+    char *mgaps = 0;
+    unsigned bit;
+
+    *command = *flags = *allflags = 0;
+    bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
+                    command, flags, allflags);
+
+    if (getenv("DEBUG"))
+      fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
+        command, flags, allflags);
+
+    if (!*command) break;
+    if (bit != 3) {
+      fprintf(stderr, "\nError in %s (see generated/flags.raw)\n", command);
+      exit(1);
+    }
+
+    bit = 0;
+    printf("// %s %s %s\n", command, flags, allflags);
+    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);
+
+    printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n",
+           command, command, command);
+
+    while (offlist) {
+      struct flag *f = offlist->lopt;
+      while (f) {
+        printf("#undef FLAG_%s\n", f->command);
+        f = f->next;
+      }
+      if (offlist->command) printf("#undef FLAG_%c\n", *offlist->command);
+      offlist = offlist->next;
+    }
+    printf("#endif\n\n");
+
+    sprintf(out, "#ifdef FOR_%s\n#ifndef TT\n#define TT this.%s\n#endif\n",
+            command, command);
+    out += strlen(out);
+
+    while (aflist) {
+      char *llstr = bit>31 ? "LL" : "";
+
+      // Output flag macro for bare longopts
+      if (aflist->lopt) {
+        if (flist && flist->lopt &&
+            !strcmp(flist->lopt->command, aflist->lopt->command))
+        {
+          sprintf(out, "#define FLAG_%s (1%s<<%d)\n", flist->lopt->command,
+            llstr, bit);
+          flist->lopt = flist->lopt->next;
+        } else sprintf(out, "#define FLAG_%s (FORCED_FLAG%s<<%d)\n",
+                       aflist->lopt->command, llstr, bit);
+        aflist->lopt = aflist->lopt->next;
+        if (!aflist->command) {
+          aflist = aflist->next;
+          bit++;
+          if (flist) flist = flist->next;
+        }
+      // Output normal flag macro
+      } else if (aflist->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);
+          flist = flist->next;
+        } else sprintf(out, "#define FLAG_%c (FORCED_FLAG%s<<%d)\n",
+                       *aflist->command, llstr, bit);
+        bit++;
+        aflist = aflist->next;
+      }
+      out += strlen(out);
+    }
+    out = stpcpy(out, "#endif\n\n");
+  }
+
+  if (fflush(0) && ferror(stdout)) return 1;
+
+  out = outbuf;
+  while (*out) {
+    int i = write(1, outbuf, strlen(outbuf));
+
+    if (i<0) return 1;
+    out += i;
+  }
+
+  return 0;
+}
diff --git a/toybox/scripts/mkstatus.py b/toybox/scripts/mkstatus.py
new file mode 100755
index 0000000..c1b325e
--- /dev/null
+++ b/toybox/scripts/mkstatus.py
@@ -0,0 +1,131 @@
+#!/usr/bin/python
+
+# Create status.html
+
+import subprocess,sys
+
+def readit(args, shell=False):
+  ret={}
+  arr=[]
+  blob=subprocess.Popen(args, stdout=subprocess.PIPE, shell=shell)
+  for i in blob.stdout.read().split("\n"):
+    if not i: continue
+    i=i.split()
+    try: ret[i[0]].extend(i[1:])
+    except: ret[i[0]]=i[1:]
+    arr.extend(i)
+  return ret,arr
+
+# Run sed on roadmap and source to get command lists, and run toybox too
+# This gives us a dictionary of types, each with a list of commands
+
+print "Collecting data..."
+
+stuff,blah=readit(["sed","-n", 's/<span id=\\([a-z_]*\\)>/\\1 /;t good;d;:good;h;:loop;n;s@</span>@@;t out;H;b loop;:out;g;s/\\n/ /g;p', "www/roadmap.html", "www/status.html"])
+blah,toystuff=readit(["./toybox"])
+blah,pending=readit(["sed -n 's/[^ \\t].*TOY(\\([^,]*\\),.*/\\1/p' toys/pending/*.c"], 1)
+blah,version=readit(["git","describe","--tags"])
+
+print "Analyzing..."
+
+# Create reverse mappings: reverse["command"] gives list of categories it's in
+
+reverse={}
+for i in stuff:
+  for j in stuff[i]:
+    try: reverse[j].append(i)
+    except: reverse[j]=[i]
+print "all commands=%s" % len(reverse)
+
+# Run a couple sanity checks on input
+
+for i in toystuff:
+  if (i in pending): print "barf %s" % i
+
+unknowns=[]
+for i in toystuff + pending:
+  if not i in reverse: unknowns.append(i)
+
+if unknowns: print "uncategorized: %s" % " ".join(unknowns)
+
+conv = [("posix", '<a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/%s.html">%%s</a>', "[%s]"),
+        ("lsb", '<a href="http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/%s.html">%%s</a>', '&lt;%s&gt;'),
+        ("development", '<a href="http://linux.die.net/man/1/%s">%%s</a>', '(%s)'),
+        ("toolbox", "", '{%s}'), ("klibc_cmd", "", '=%s='),
+        ("sash_cmd", "", '#%s#'), ("sbase_cmd", "", '@%s@'),
+        ("beastiebox_cmd", "", '*%s*'), ("tizen", "", '$%s$'),
+        ("shell", "", "%%%s%%"),
+        ("request", '<a href="http://linux.die.net/man/1/%s">%%s</a>', '+%s+')]
+
+
+def categorize(reverse, i, skippy=""):
+  linky = "%s"
+  out = i
+
+  if skippy: types = filter(lambda a: a != skippy, reverse[i])
+  else: types = reverse[i]
+
+  for j in conv:
+    if j[0] in types:
+      if j[1]: linky = j[1] % i
+      out = j[2] % out
+      if not skippy: break
+  if (not skippy) and out == i:
+    sys.stderr.write("unknown %s %s\n" % (i,reverse[i]))
+
+  return linky % out
+
+# Sort/annotate done, pending, and todo item lists
+
+allcmd=[]
+done=[]
+pend=[]
+todo=[]
+blah=list(reverse)
+blah.sort()
+for i in blah:
+  out=categorize(reverse, i)
+  allcmd.append(out)
+  if i in toystuff or i in pending:
+    if i in toystuff: done.append(out)
+    else: pend.append(out)
+    out='<strike>%s</strike>' % out
+  else: todo.append(out)
+
+print "implemented=%s" % len(toystuff)
+
+# Write data to output file
+
+outfile=open("www/status.gen", "w")
+outfile.write("<h1>Status of toybox %s</h1>\n" % version[0]);
+outfile.write("<h3>Legend: [posix] &lt;lsb&gt; (development) {android}\n")
+outfile.write("=klibc= #sash# @sbase@ *beastiebox* $tizen$ %shell% +request+ other\n")
+outfile.write("<strike>pending</strike></h3>\n");
+
+outfile.write("<a name=done><h2><a href=#done>Completed</a></h2><blockquote><p>%s</p></blockquote>\n" % "\n".join(done))
+outfile.write("<a name=part><h2><a href=#part>Partially implemented</a></h2><blockquote><p>%s</p></blockquote>\n" % "\n".join(pend))
+outfile.write("<a name=todo><h2><a href=#todo>Not started yet</a></h2><blockquote><p>%s</p></blockquote>\n" % "\n".join(todo))
+
+# Output unfinished commands by category
+
+outfile.write("<hr><h2>Categories of remaining todo items</h2>")
+
+for i in stuff:
+  todo = []
+
+  for j in stuff[i]:
+    if j in toystuff: continue
+    if j in pending: todo.append('<strike>%s</strike>' % j)
+    else: todo.append(categorize(reverse,j,i))
+
+  if todo:
+    k = i
+    for j in conv:
+      if j[0] == i:
+        k = j[2] % i
+
+    outfile.write("<a name=%s><h2><a href=#%s>%s<a></h2><blockquote><p>" % (i,i,k))
+    outfile.write(" ".join(todo))
+    outfile.write("</p></blockquote>\n")
+
+outfile.write("<hr><a name=all><h2><a href=#all>All commands together in one big list</a></h2><blockquote><p>%s</p></blockquote>\n" % "\n".join(allcmd))
diff --git a/toybox/scripts/mktags.c b/toybox/scripts/mktags.c
new file mode 100644
index 0000000..9c23cf1
--- /dev/null
+++ b/toybox/scripts/mktags.c
@@ -0,0 +1,58 @@
+// Process TAGGED_ARRAY() macros to emit TAG_STRING index macros.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+int main(int argc, char *argv[])
+{
+  char *tag = 0;
+  int idx = 0;
+
+  for (;;) {
+    char *line = 0, *s;
+    ssize_t len;
+
+    len = getline(&line, &len, stdin);
+    if (len<0) break;
+    while (len && isspace(line[len-1])) line[--len]=0;
+
+    // Very simple parser: If we haven't got a TAG then first line is TAG.
+    // Then look for { followed by "str" (must be on same line, may have
+    // more than one per line), for each one emit #define. Current TAG ended
+    // by ) at start of line.
+
+    if (!tag) {
+      if (!isalpha(*line)) {
+        fprintf(stderr, "bad tag %s\n", line);
+        exit(1);
+      }
+      tag = strdup(line);
+      idx = 0;
+
+      continue;
+    }
+
+    for (s = line; isspace(*s); s++);
+    if (*s == ')') tag = 0;
+    else for (;;) {
+      char *start;
+
+      while (*s && *s != '{') s++;
+      while (*s && *s != '"') s++;
+      if (!*s) break;
+
+      start = ++s;
+      while (*s && *s != '"') {
+        if (!isalpha(*s) && !isdigit(*s)) *s = '_';
+        s++;
+      }
+      printf("#define %s_%*.*s %d\n", tag, -40, (int)(s-start), start, idx);
+      printf("#define _%s_%*.*s (1%s<<%d)\n", tag, -39, (int)(s-start), start,
+        idx>31 ? "LL": "", idx);
+      idx++;
+    }
+    free(line);
+  }
+}
diff --git a/toybox/scripts/runtest.sh b/toybox/scripts/runtest.sh
new file mode 100644
index 0000000..13b82f1
--- /dev/null
+++ b/toybox/scripts/runtest.sh
@@ -0,0 +1,174 @@
+# Simple test harness infrastructure
+#
+# Copyright 2005 by Rob Landley
+
+# This file defines two functions, "testing" and "optionflag"
+
+# The following environment variables enable optional behavior in "testing":
+#    DEBUG - Show every command run by test script.
+#    VERBOSE - Print the diff -u of each failed test case.
+#              If equal to "fail", stop after first failed test.
+#    SKIP - do not perform this test (this is set by "optionflag")
+#
+# The "testing" function takes five arguments:
+#	$1) Description to display when running command
+#	$2) Command line arguments to command
+#	$3) Expected result (on stdout)
+#	$4) Data written to file "input"
+#	$5) Data written to stdin
+#
+# The exit value of testing is the exit value of the command it ran.
+#
+# The environment variable "FAILCOUNT" contains a cumulative total of the
+# number of failed tests.
+
+# The "optional" function is used to skip certain tests, ala:
+#   optionflag CFG_THINGY
+#
+# The "optional" function checks the environment variable "OPTIONFLAGS",
+# which is either empty (in which case it always clears SKIP) or
+# else contains a colon-separated list of features (in which case the function
+# clears SKIP if the flag was found, or sets it to 1 if the flag was not found).
+
+export FAILCOUNT=0
+export SKIP=
+
+# Helper functions
+
+# Check config to see if option is enabled, set SKIP if not.
+
+SHOWPASS=PASS
+SHOWFAIL=FAIL
+SHOWSKIP=SKIP
+
+if tty -s <&1
+then
+  SHOWPASS="$(echo -e "\033[1;32m${SHOWPASS}\033[0m")"
+  SHOWFAIL="$(echo -e "\033[1;31m${SHOWFAIL}\033[0m")"
+  SHOWSKIP="$(echo -e "\033[1;33m${SHOWSKIP}\033[0m")"
+fi
+
+optional()
+{
+  option=`echo "$OPTIONFLAGS" | egrep "(^|:)$1(:|\$)"`
+  # Not set?
+  if [ -z "$1" ] || [ -z "$OPTIONFLAGS" ] || [ ${#option} -ne 0 ]
+  then
+    SKIP=""
+    return
+  fi
+  SKIP=1
+}
+
+# The testing function
+
+testing()
+{
+  NAME="$CMDNAME $1"
+  [ -z "$1" ] && NAME=$2
+
+  if [ $# -ne 5 ]
+  then
+    echo "Test $NAME has the wrong number of arguments ($# $*)" >&2
+    exit
+  fi
+
+  [ -n "$DEBUG" ] && set -x
+
+  if [ -n "$SKIP" ] || ( [ -n "$SKIP_HOST" ] && [ -n "$TEST_HOST" ])
+  then
+    [ ! -z "$VERBOSE" ] && echo "$SHOWSKIP: $NAME"
+    return 0
+  fi
+
+  echo -ne "$3" > expected
+  echo -ne "$4" > input
+  echo -ne "$5" | ${EVAL:-eval} "$2" > actual
+  RETVAL=$?
+
+  # Catch segfaults
+  [ $RETVAL -gt 128 ] && [ $RETVAL -lt 255 ] &&
+    echo "exited with signal (or returned $RETVAL)" >> actual
+ 
+  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' |$EVAL $2"
+      echo "$DIFF"
+      [ "$VERBOSE" == fail ] && exit 1
+    fi
+  else
+    echo "$SHOWPASS: $NAME"
+  fi
+  rm -f input expected actual
+
+  [ -n "$DEBUG" ] && set +x
+
+  return $RETVAL
+}
+
+# Recursively grab an executable and all the libraries needed to run it.
+# Source paths beginning with / will be copied into destpath, otherwise
+# the file is assumed to already be there and only its library dependencies
+# are copied.
+
+mkchroot()
+{
+  [ $# -lt 2 ] && return
+
+  echo -n .
+
+  dest=$1
+  shift
+  for i in "$@"
+  do
+    [ "${i:0:1}" == "/" ] || i=$(which $i)
+    [ -f "$dest/$i" ] && continue
+    if [ -e "$i" ]
+    then
+      d=`echo "$i" | grep -o '.*/'` &&
+      mkdir -p "$dest/$d" &&
+      cat "$i" > "$dest/$i" &&
+      chmod +x "$dest/$i"
+    else
+      echo "Not found: $i"
+    fi
+    mkchroot "$dest" $(ldd "$i" | egrep -o '/.* ')
+  done
+}
+
+# Set up a chroot environment and run commands within it.
+# Needed commands listed on command line
+# Script fed to stdin.
+
+dochroot()
+{
+  mkdir tmpdir4chroot
+  mount -t ramfs tmpdir4chroot tmpdir4chroot
+  mkdir -p tmpdir4chroot/{etc,sys,proc,tmp,dev}
+  cp -L testing.sh tmpdir4chroot
+
+  # Copy utilities from command line arguments
+
+  echo -n "Setup chroot"
+  mkchroot tmpdir4chroot $*
+  echo
+
+  mknod tmpdir4chroot/dev/tty c 5 0
+  mknod tmpdir4chroot/dev/null c 1 3
+  mknod tmpdir4chroot/dev/zero c 1 5
+
+  # Copy script from stdin
+
+  cat > tmpdir4chroot/test.sh
+  chmod +x tmpdir4chroot/test.sh
+  chroot tmpdir4chroot /test.sh
+  umount -l tmpdir4chroot
+  rmdir tmpdir4chroot
+}
+
diff --git a/toybox/scripts/showasm b/toybox/scripts/showasm
new file mode 100755
index 0000000..75a6efd
--- /dev/null
+++ b/toybox/scripts/showasm
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Copyright 2006 Rob Landley <rob@landley.net>
+
+# Dumb little utility function to print out the assembly dump of a single
+# function, or list the functions so dumpable in an executable.  You'd think
+# there would be a way to get objdump to do this, but I can't find it.
+
+[ $# -lt 1 ] || [ $# -gt 2 ] && { echo "usage: showasm file function"; exit 1; }
+
+[ ! -f $1 ] && { echo "File $1 not found"; exit 1; }
+
+if [ $# -eq 1 ]
+then
+  objdump -d $1 | sed -n -e 's/^[0-9a-fA-F]* <\(.*\)>:$/\1/p'
+  exit 0
+fi
+
+objdump -d $1 | sed -n -e '/./{H;$!d}' -e "x;/^.[0-9a-fA-F]* <$2>:/p"
+
diff --git a/toybox/scripts/single.sh b/toybox/scripts/single.sh
new file mode 100755
index 0000000..cadb2fc
--- /dev/null
+++ b/toybox/scripts/single.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Build a standalone toybox command
+
+if [ -z "$1" ]
+then
+  echo "usage: single.sh command..." >&2
+  exit 1
+fi
+
+# Harvest TOYBOX_* symbols from .config
+if [ ! -e .config ]
+then
+  echo "Need .config for toybox global settings. Run defconfig/menuconfig." >&2
+  exit 1
+fi
+
+export KCONFIG_CONFIG=.singleconfig
+for i in "$@"
+do
+  echo -n "$i:"
+  TOYFILE="$(egrep -l "TOY[(]($i)[ ,]" toys/*/*.c)"
+
+  if [ -z "$TOYFILE" ]
+  then
+    echo "Unknown command '$i'" >&2
+    exit 1
+  fi
+
+  # 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/" \
+    "$KCONFIG_CONFIG" &&
+  echo "# CONFIG_TOYBOX is not set" >> "$KCONFIG_CONFIG" &&
+  grep "CONFIG_TOYBOX_" .config >> "$KCONFIG_CONFIG" &&
+
+  rm -f "$PREFIX$i" &&
+  OUTNAME="$PREFIX$i" scripts/make.sh || exit 1
+done
diff --git a/toybox/scripts/test.sh b/toybox/scripts/test.sh
new file mode 100755
index 0000000..1337c52
--- /dev/null
+++ b/toybox/scripts/test.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+TOPDIR="$PWD"
+FILES="$PWD"/tests/files
+
+trap 'kill $(jobs -p) 2>/dev/null; exit 1' INT
+
+rm -rf generated/testdir
+mkdir -p generated/testdir/testdir
+
+if [ -z "$TEST_HOST" ]
+then
+  if [ $# -ne 0 ]
+  then
+    PREFIX=generated/testdir/ scripts/single.sh "$@" || exit 1
+  else
+    make install_flat PREFIX=generated/testdir || exit 1
+  fi
+fi
+
+cd generated/testdir
+PATH="$PWD:$PATH"
+cd testdir
+export LC_COLLATE=C
+
+. "$TOPDIR"/scripts/runtest.sh
+[ -f "$TOPDIR/generated/config.h" ] && export OPTIONFLAGS=:$(echo $(sed -nr 's/^#define CFG_(.*) 1/\1/p' "$TOPDIR/generated/config.h") | sed 's/ /:/g')
+
+if [ $# -ne 0 ]
+then
+  for i in "$@"
+  do
+    CMDNAME="${i##*/}"
+    CMDNAME="${CMDNAME%.test}"
+    . "$TOPDIR"/tests/$i.test
+  done
+else
+  for i in "$TOPDIR"/tests/*.test
+  do
+    CMDNAME="${i##*/}"
+    CMDNAME="${CMDNAME%.test}"
+    if [ -h ../$CMDNAME ] || [ ! -z "$TEST_HOST" ]
+    then
+      cd .. && rm -rf testdir && mkdir testdir && cd testdir || exit 1
+      . $i
+    else
+      echo "$CMDNAME disabled"
+    fi
+  done
+fi
diff --git a/toybox/tests/base64.test b/toybox/tests/base64.test
new file mode 100755
index 0000000..2058198
--- /dev/null
+++ b/toybox/tests/base64.test
@@ -0,0 +1,24 @@
+#!/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" ""
diff --git a/toybox/tests/basename.test b/toybox/tests/basename.test
new file mode 100755
index 0000000..ab2cc20
--- /dev/null
+++ b/toybox/tests/basename.test
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Removal of extra /'s
+testing "/-only" "basename ///////" "/\n" "" ""
+testing "trailing /" "basename a//////" "a\n" "" ""
+testing "combined" "basename /////a///b///c///d/////" "d\n" "" ""
+
+# Standard suffix behavior.
+testing "suffix" "basename a/b/c/d.suffix .suffix" "d\n" "" ""
+
+# A suffix cannot be the entire result.
+testing "suffix=result" "basename .txt .txt" ".txt\n" "" ""
+
+# Deal with suffix appearing in the filename
+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 "invalid suffix" "basename isthisasuffix? suffix" "isthisasuffix?\n" "" ""
+
+# Zero-length suffix
+testing "zero-length suffix" "basename a/b/c ''" "c\n" "" ""
diff --git a/toybox/tests/blkid.test b/toybox/tests/blkid.test
new file mode 100755
index 0000000..d3bf6a1
--- /dev/null
+++ b/toybox/tests/blkid.test
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+BDIR="$FILES/blkid"
+
+bzcat "$BDIR"/squashfs.bz2 > temp.img
+testing "file" "blkid temp.img" 'temp.img: TYPE="squashfs"\n' "" ""
+rm temp.img
+
+testing "cramfs" 'bzcat "$BDIR"/cramfs.bz2 | blkid -' \
+  '-: LABEL="mycramfs" TYPE="cramfs"\n' "" ""
+testing "ext2" 'bzcat "$BDIR"/ext2.bz2 | blkid -' \
+  '-: LABEL="myext2" UUID="e59093ba-4135-4fdb-bcc4-f20beae4dfaf" TYPE="ext2"\n' \
+  "" "" 
+testing "ext3" 'bzcat "$BDIR"/ext3.bz2 | blkid -' \
+  '-: LABEL="myext3" UUID="79d1c877-1a0f-4e7d-b21d-fc32ae3ef101" TYPE="ext3"\n' \
+  "" "" 
+testing "ext4" 'bzcat "$BDIR"/ext4.bz2 | blkid -' \
+  '-: LABEL="myext4" UUID="dc4b7c00-c0c0-4600-af7e-0335f09770fa" TYPE="ext4"\n' \
+  "" ""
+testing "f2fs" 'bzcat "$BDIR"/f2fs.bz2 | blkid -' \
+  '-: LABEL="" UUID="b53d3619-c204-4c0b-8504-36363578491c" TYPE="f2fs"\n' \
+  "" ""
+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 "reiserfs" 'bzcat "$BDIR"/reiser3.bz2 | blkid -' \
+  '-: LABEL="myreiser" UUID="a5b99bec-45cc-41d7-986e-32f4b6fc28f2" TYPE="reiserfs"\n' \
+  "" ""
+testing "squashfs" 'bzcat "$BDIR"/squashfs.bz2 | blkid -' \
+  '-: TYPE="squashfs"\n' "" ""
+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 "minix" 'bzcat "$BDIR"/minix.bz2 | blkid -'
+#adfs bfs btrfs cramfs jfs nilfs romfs
+#vfat  // fat32 fat12 fat16
diff --git a/toybox/tests/bzcat.test b/toybox/tests/bzcat.test
new file mode 100755
index 0000000..0975f3d
--- /dev/null
+++ b/toybox/tests/bzcat.test
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+testing "2 known files" \
+ 'bzcat "$FILES/blkid/"{minix,ntfs}.bz2 | sha1sum | '"awk '{print \$1}'" \
+ 'c0b7469c9660d6056a988ef8a7fe73925efc9266\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" "" ""
diff --git a/toybox/tests/cat.test b/toybox/tests/cat.test
new file mode 100755
index 0000000..8845070
--- /dev/null
+++ b/toybox/tests/cat.test
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+echo "one" > file1
+echo "two" > file2
+testing "cat" "cat && echo yes" "oneyes\n" "" "one"
+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 "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 "file1" \
+        'cat "$FILE" > file1 && cmp "$FILE" file1 && echo yes' \
+        "yes\n" "" ""
+
+testing "- file1" \
+        "cat - file1 | diff -a -U 0 - file1 | tail -n 1" \
+        "-hello\n" "" "hello\n"
+
+testing "> /dev/full" \
+        "cat - > /dev/full 2>stderr && echo ok; cat stderr; rm stderr" \
+        "cat: xwrite: No space left on device\n" "" "zero\n"
+
+rm file1 file2
diff --git a/toybox/tests/chattr.test b/toybox/tests/chattr.test
new file mode 100755
index 0000000..067014d
--- /dev/null
+++ b/toybox/tests/chattr.test
@@ -0,0 +1,133 @@
+#!/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
diff --git a/toybox/tests/chgrp.test b/toybox/tests/chgrp.test
new file mode 100755
index 0000000..16cd776
--- /dev/null
+++ b/toybox/tests/chgrp.test
@@ -0,0 +1,102 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+if [ "$(id -u)" -ne 0 ]
+then
+  echo "$SHOWSKIP: chgrp (not root)"
+  continue 2>/dev/null
+  exit
+fi
+
+# We chgrp between "root" and the last group in /etc/group.
+
+GRP="$(sed -n '$s/:.*//p' /etc/group)"
+
+# Set up a little testing hierarchy
+
+rm -rf testdir &&
+mkdir -p testdir/dir/dir/dir testdir/dir2 &&
+touch testdir/dir/file &&
+ln -s ../dir/dir testdir/dir2/dir &&
+ln -s ../dir/file testdir/dir2/file || exit 1
+
+# Wrapper to reset groups and return results
+
+IN="cd testdir && chgrp -R $GRP dir dir2 &&"
+OUT="&& cd .. && echo \$(ls -lR testdir | awk '{print \$4}')"
+
+# The groups returned by $OUT are, in order:
+# dir dir2 dir/dir dir/file dir/dir/dir dir2/dir dir2/file
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Basic smoketest
+testing "dir" "$IN chgrp root dir $OUT" \
+	"root $GRP $GRP $GRP $GRP $GRP $GRP\n" "" ""
+testing "file" "$IN chgrp root dir/file $OUT" \
+	"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
+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 "symlink->file" "$IN chgrp root dir2/file $OUT" \
+	"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
+testing "symlink->dir" "$IN chgrp root dir2/dir $OUT" \
+	"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
+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 "-h symlink->file" "$IN chgrp -h root dir2/file $OUT" \
+	"$GRP $GRP $GRP $GRP $GRP $GRP root\n" "" ""
+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 "-R dir" "$IN chgrp -R root dir $OUT" \
+	"root $GRP root root root $GRP $GRP\n" "" ""
+testing "-R dir2" "$IN chgrp -R root dir2 $OUT" \
+	"$GRP root $GRP $GRP $GRP root root\n" "" ""
+testing "-R symlink->dir" "$IN chgrp -R root dir2/dir $OUT" \
+	"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
+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 "-RP dir2" "$IN chgrp -RP root dir2 $OUT" \
+	"$GRP root $GRP $GRP $GRP root root\n" "" ""
+testing "-RP symlink->dir" "$IN chgrp -RP root dir2/dir $OUT" \
+	"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
+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 "-RH dir2" "$IN chgrp -RH root dir2 $OUT" \
+	"$GRP root root root $GRP $GRP $GRP\n" "" ""
+testing "-RH symlink->dir" "$IN chgrp -RH root dir2/dir $OUT" \
+	"$GRP $GRP root $GRP root $GRP $GRP\n" "" ""
+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 "-RL dir2" "$IN chgrp -RL root dir2 $OUT" \
+	"$GRP root root root root $GRP $GRP\n" "" ""
+testing "-RL symlink->dir" "$IN chgrp -RL root dir2/dir $OUT" \
+	"$GRP $GRP root $GRP root $GRP $GRP\n" "" ""
+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 "-H without -R" "$IN chgrp -H root dir2/dir $OUT" \
+	"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
+testing "-L without -R" "$IN chgrp -L root dir2/dir $OUT" \
+	"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
+testing "-P without -R" "$IN chgrp -P root dir2/dir $OUT" \
+	"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
+
+rm -rf testdir
diff --git a/toybox/tests/chmod.test b/toybox/tests/chmod.test
new file mode 100755
index 0000000..c2b64bd
--- /dev/null
+++ b/toybox/tests/chmod.test
@@ -0,0 +1,246 @@
+#!/bin/bash
+
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+
+#testing "name" "command" "result" "infile" "stdin"
+
+umask 022
+
+PERM="---""--x""-w-""-wx""r--""r-x""rw-""rwx"
+
+num2perm()
+{
+  for i in 0 1 2
+  do
+    num=${1:$i:1}
+    printf "%s" ${PERM:$(($num*3)):3}
+  done
+  echo
+}
+
+# Creating test files to test chmod command
+mkdir dir
+touch file
+
+# We don't need to test all 512 permissions
+for u in 0 1 2 3 4 5 6 7
+do
+  for g in 0 3 6
+  do
+    for o in 0 7
+    do
+      if [ "$type" == file ]
+      then
+        type=dir
+        rm -rf "./$type" && mkdir $type
+        DASH=d
+      else
+        type=file
+        rm -f "./$type" && touch $type
+        DASH=-
+      fi
+      DASHES=$(num2perm $u$g$o)
+      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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "=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 "=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 "=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 "+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 "+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 "+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 "-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 "-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 "-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
+rm -rf dir file
diff --git a/toybox/tests/chown.test b/toybox/tests/chown.test
new file mode 100755
index 0000000..95ad727
--- /dev/null
+++ b/toybox/tests/chown.test
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+if [ "$(id -u)" -ne 0 ]
+then
+  echo "$SHOWSKIP: chown (not root)"
+  continue 2>/dev/null
+  exit
+fi
+
+# We chown between user "root" and the last user in /etc/passwd,
+# and group "root" and the last group in /etc/group.
+
+USR="$(sed -n '$s/:.*//p' /etc/passwd)"
+GRP="$(sed -n '$s/:.*//p' /etc/group)"
+
+# Set up a little testing hierarchy
+
+rm -rf testdir &&
+mkdir testdir &&
+touch testdir/file
+F=testdir/file
+
+# Wrapper to reset groups and return results
+
+OUT="&& echo \$(ls -l testdir/file | awk '{print \$3,\$4}')"
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Basic smoketest
+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 ":grp"    "chown root:root $F && chown :$GRP $F $OUT" \
+    "root $GRP\n" "" ""
+testing ":"       "chown $USR:$GRP $F && chown : $F $OUT" \
+    "$USR $GRP\n" "" ""
+
+rm -rf testdir
diff --git a/toybox/tests/cksum.test b/toybox/tests/cksum.test
new file mode 100755
index 0000000..01938f4
--- /dev/null
+++ b/toybox/tests/cksum.test
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Default behavior on stdin and on files.
+testing "on stdin" "echo -n hello | cksum" "3287646509 5\n" "" ""
+echo -n "hello" > tmpfile
+testing "on file" "cksum tmpfile" "3287646509 5 tmpfile\n" "" ""
+rm -f tmpfile
+touch one two
+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 "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 "on no data post-inversion" "echo -n "" | cksum" "4294967295 0\n" "" ""
+# If we do preinversion we will then get 0.
+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 "on no data no inversion" "echo -n "" | cksum -I" "0 0\n" "" ""
+# Two wrongs make a right.
+testing "on no data pre-inversion" "echo -n "" | cksum -PI" "4294967295 0\n" "" ""
diff --git a/toybox/tests/cmp.test b/toybox/tests/cmp.test
new file mode 100755
index 0000000..c3e8f5b
--- /dev/null
+++ b/toybox/tests/cmp.test
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+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 "directory [fail]" "cmp dir dir 2>/dev/null || echo yes" \
+	#"yes\n" "" ""
+#rmdir dir
+
+echo "ab
+c" > input2
+
+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 "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 "diff, stdout" "cmp input input2" "input input2 differ: char 4, line 2\n" "ab\nx\nx" ""
+testing "diff, return code" "cmp input input2 > /dev/null || echo yes" "yes\n" "ab\nx\nx" ""
+
+testing "-s EOF, return code" "cmp -s input input2 || echo yes"  "yes\n" "ab\nc\nx" ""
+testing "-s diff, return code" "cmp -s input input2 || echo yes" "yes\n" "ab\nx\nx" ""
+
+testing "-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" ""
+
+rm input2
+
+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"
+
diff --git a/toybox/tests/cp.test b/toybox/tests/cp.test
new file mode 100755
index 0000000..2b89e2f
--- /dev/null
+++ b/toybox/tests/cp.test
@@ -0,0 +1,101 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+# Create test file
+dd if=/dev/urandom of=random bs=64 count=1 2> /dev/null
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "not enough arguments [fail]" "cp one 2>/dev/null || echo yes" \
+	"yes\n" "" ""
+testing "-missing source [fail]" "cp missing two 2>/dev/null || echo yes" \
+	"yes\n" "" ""
+testing "file->file" "cp random two && cmp random two && echo yes" \
+	"yes\n" "" ""
+rm two
+
+mkdir two
+testing "file->dir" "cp random two && cmp random two/random && echo yes" \
+	"yes\n" "" ""
+rm two/random
+testing "file->dir/file" \
+	"cp random two/random && cmp random two/random && echo yes" \
+	"yes\n" "" ""
+testing "-r dir->missing" \
+	"cp -r two three && cmp random three/random && echo yes" \
+	"yes\n" "" ""
+touch walrus
+testing "-r dir->file [fail]" \
+	"cp -r two walrus 2>/dev/null || echo yes" "yes\n" "" ""
+touch two/three
+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 "file->inaccessable [fail]" \
+	"cp random two 2>/dev/null || echo yes" "yes\n" "" ""
+rm -f two
+
+touch two
+chmod 000 two
+testing "-f file->inaccessable" \
+	"cp -f random two && cmp random two && echo yes" "yes\n" "" ""
+mkdir sub
+chmod 000 sub
+testing "file->inaccessable_dir [fail]" \
+	"cp random sub 2>/dev/null || echo yes" "yes\n" "" ""
+rm two
+rmdir sub
+
+# This test fails because our -rf deletes existing target files without
+# regard to what we'd be copying over it. Posix says to only do that if
+# we'd be copying a file over the file, but does not say _why_.
+
+#mkdir dir
+#touch file
+#testing "-rf dir file [fail]" "cp -rf dir file 2>/dev/null || echo yes" \
+#	"yes\n" "" ""
+#rm -rf dir file
+
+touch one two
+testing "file1 file2 missing [fail]" \
+	"cp one two missing 2>/dev/null || echo yes" "yes\n" "" ""
+mkdir dir
+testing "dir file missing [fail]" \
+	"cp dir two missing 2>/dev/null || echo yes" "yes\n" "" ""
+testing "-rf dir file missing [fail]" \
+	"cp dir two missing 2>/dev/null || echo yes" "yes\n" "" ""
+testing "file1 file2 file [fail]" \
+	"cp random one two 2>/dev/null || echo yes" "yes\n" "" ""
+testing "file1 file2 dir" \
+	"cp random one dir && cmp random dir/random && cmp one dir/one && echo yes" \
+	"yes\n" "" ""
+rm one two random
+rm -rf dir
+
+mkdir -p one/two/three/four
+touch one/two/three/five
+touch one/{six,seven,eight}
+testing "-r /abspath dest" \
+	"cp -r \"$(readlink -f one)\" dir && diff -r one dir && echo yes" \
+	"yes\n" "" ""
+testing "-r dir again" "cp -r one/. dir && diff -r one dir && echo yes" \
+	"yes\n" "" ""
+mkdir dir2
+testing "-r dir1/* dir2" \
+	"cp -r one/* dir2 && diff -r one dir2 && echo yes" "yes\n" "" ""
+rm -rf one dir dir2
+
+# cp -r ../source destdir
+# cp -r one/two/three missing
+# cp -r one/two/three two
+# mkdir one; touch one/two; ln -s two one/three
+# cp file1 file2 dir
+# cp file1 missing file2 -> dir
+
+# Make sure it's truncating existing file
+# copy with -d at top level, with -d in directory, without -d at top level,
+#      without -d in directory
diff --git a/toybox/tests/cpio.test b/toybox/tests/cpio.test
new file mode 100755
index 0000000..5158efa
--- /dev/null
+++ b/toybox/tests/cpio.test
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+# We need to test name and file padding.
+# This means all possible values of strlen(name)+1 % 4,
+# plus file sizes of at least 0-4.
+
+touch a bb ccc dddd
+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 "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
+printf '1' >bb
+printf '22' >ccc
+printf '333' >dddd
+# With the proper padding, header length, and file length, 
+# 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 "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 "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 "archives unreadable empty files" "cpio -o -H newc|cpio -it" "a\nb\n" "" "a\nb\n"
+chmod u+rw a; rm -f a b
+
+
diff --git a/toybox/tests/cut.test b/toybox/tests/cut.test
new file mode 100755
index 0000000..f84acea
--- /dev/null
+++ b/toybox/tests/cut.test
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+# Copyright 2013  Kyungwan.Han <asura321@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+#set -x
+
+# Creating test file for testing cut
+echo "one:two:three:four:five:six:seven
+alpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu
+the quick brown fox jumps over the lazy dog" >abc.txt
+
+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 "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 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 "with -c (a,b,c)" "cut -c 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
+031762:Marketing:Nasium:Jim
+636496:Research:Ancholie:Mel
+396082:Sales:Jucacion:Ed" >abc.txt
+
+testing "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 && echo yes" "yes\n" "" ""
+
+testing "with -d -f(a) -s" "cut -da -f3 -s 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
diff --git a/toybox/tests/date.test b/toybox/tests/date.test
new file mode 100644
index 0000000..213174e
--- /dev/null
+++ b/toybox/tests/date.test
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Test Unix date parsing.
+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 "-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 "-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 "Unix time missing @" "TZ=UTC date 1438053157 2>/dev/null || echo no" \
+  "no\n" "" ""
+# But some invalid dates are more subtle, like Febuary 29th in a non-leap year.
+testing "Feb 29th" "TZ=UTC date 022900001975 2>/dev/null || echo no" \
+  "no\n" "" ""
diff --git a/toybox/tests/dd.test b/toybox/tests/dd.test
new file mode 100755
index 0000000..9da2108
--- /dev/null
+++ b/toybox/tests/dd.test
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+# 'dd' command, stderr prints redirecting to /dev/null
+opt="2>/dev/null"
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Test suffixed number parsing; `count` is representative.
+testing "count=2" "dd if=input count=2 ibs=1 $opt" "hi" "high\n" ""
+testing "count= 2" "dd if=input 'count= 2' ibs=1 $opt" "hi" "high\n" ""
+testing "count=0x2" "dd if=input 'count=0x2' ibs=1 $opt" "hi" "high\n" ""
+testing "count=-2" "dd if=input 'count=-2' ibs=1 2>&1" "dd: invalid number '-2'\n" "" ""
+
+testing "if=(file)" "dd if=input $opt" "I WANT\n" "I WANT\n" ""
+testing "of=(file)" "dd of=file $opt && cat file" "I WANT\n" "" "I WANT\n"
+testing "if=file of=file" "dd if=input of=foo $opt && cat foo && rm -f foo" \
+  "I WANT\n" "I WANT\n" ""
+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 "(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 "if=file of=(null)" \
+  "dd if=input of=/dev/null $opt && echo 'yes'" "yes\n" "I WANT\n" ""
+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 "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 "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 "if=softlink" "dd if=softlink $opt" "I WANT\n" "I WANT\n" ""
+unlink softlink
+
+ln -s file softlink
+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 "if=file of=file (same file)" "dd if=input of=input $opt &&
+   [ -f input ] && cat input && echo 'yes'" "yes\n" "I WANT\n" ""
+testing "same file notrunc" \
+  "dd if=input of=input conv=notrunc $opt && cat input" \
+  "I WANT\n" "I WANT\n" ""
+
+testing "with ibs obs bs" "dd ibs=2 obs=5 bs=9 $opt" "I WANT\n" "" "I WANT\n"
+testing "with ibs obs bs if" "dd ibs=2 obs=5 bs=9 if=input $opt" \
+  "I WANT\n" "I WANT\n" ""
+
+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 "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 "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" ""
+
+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 "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 "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 "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 "conv=sync" "dd conv=sync $opt | head -n 1" "I WANT\n" "" "I WANT\n"
+testing "conv=sync with IF" "dd conv=sync if=input $opt | head -n 1" "I WANT\n" \
+  "I WANT\n" ""
+
+# status=noxfer|none
+testing "status=noxfer" "dd if=input status=noxfer ibs=1 2>&1" "input\n6+0 records in\n0+1 records out\n" "input\n" ""
+testing "status=none" "dd if=input status=none ibs=1 2>&1" "input\n" "input\n" ""
diff --git a/toybox/tests/diff.test b/toybox/tests/diff.test
new file mode 100755
index 0000000..ca0b682
--- /dev/null
+++ b/toybox/tests/diff.test
@@ -0,0 +1,30 @@
+#!/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" "" ""
diff --git a/toybox/tests/dirname.test b/toybox/tests/dirname.test
new file mode 100755
index 0000000..3ea8919
--- /dev/null
+++ b/toybox/tests/dirname.test
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+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" "" ""
diff --git a/toybox/tests/du.test b/toybox/tests/du.test
new file mode 100755
index 0000000..a096074
--- /dev/null
+++ b/toybox/tests/du.test
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# we only test with -k since getting POSIX version is variable
+# POSIXLY_CORRECT is sometimes needed, sometimes -P is needed,
+# while -k is the default on most Linux systems
+
+mkdir -p du_test/test du_2/foo
+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 "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 "-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 "-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
+
diff --git a/toybox/tests/echo.test b/toybox/tests/echo.test
new file mode 100755
index 0000000..5849964
--- /dev/null
+++ b/toybox/tests/echo.test
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+# This one's tricky both because echo is a shell builtin (so $PATH is
+# irrelevant) and because the "result" field is parsed with echo -e.
+# To make it work, "$CMD" is an explicit path to the command being tested,
+# so "result" keeps using the shell builtin but we test the one in toybox.
+
+CMD="$(which echo)"
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "echo" "$CMD && echo yes" "\nyes\n" "" ""
+testing "1 2 3" "$CMD one  two	three" "one two three\n" "" ""
+testing "with spaces" "$CMD 'one  two	three'" \
+	"one  two	three\n" "" ""
+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 "-nex hello" "$CMD -nex hello" "-nex hello\n" "" ""
+
+# Octal formatting tests
+testing "-e octal values" \
+	"$CMD -ne '\01234 \0060 \060 \0130\0131\0132 \077\012'" \
+	"S4 0 0 XYZ ?\n" "" ""
+
+# Hexadecimal value tests
+testing "-e hexadecimal values" \
+	"$CMD -ne '\x534 \x30 \x58\x59\x5a \x3F\x0A'"\
+	"S4 0 XYZ ?\n" "" ""
+
+testing "-e \p" "$CMD -e '\\p'" "\\p\n" "" ""
diff --git a/toybox/tests/expand.test b/toybox/tests/expand.test
new file mode 100755
index 0000000..d93d070
--- /dev/null
+++ b/toybox/tests/expand.test
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# POSIX 2008 compliant expand tests.
+# Copyright 2012 by Jonathan Clairembault <jonathan@clairembault.fr>
+
+[ -f testing.sh ] && . testing.sh
+
+# some basic tests
+
+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
+
+POW=15
+TABSTOP=1
+BIGTAB=" "
+for i in $(seq $POW); do
+    BIGTAB=$BIGTAB$BIGTAB
+    TABSTOP=$[$TABSTOP*2]
+done
+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 "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 "
+for i in $(seq $POW); do
+    BIGLINE=$BIGLINE$BIGLINE
+done
+if [ $POW -gt 0 ]; then
+    EXPANDLINE="${BIGLINE}        foo\n"
+else
+    EXPANDLINE="${BIGLINE}    foo\n"
+fi
+BIGLINE="${BIGLINE}\tfoo\n"
+testing "long line single" "expand input" \
+        "${EXPANDLINE}" "$BIGLINE" ""
diff --git a/toybox/tests/expr.test b/toybox/tests/expr.test
new file mode 100755
index 0000000..da3feea
--- /dev/null
+++ b/toybox/tests/expr.test
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+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" "" ""
diff --git a/toybox/tests/factor.test b/toybox/tests/factor.test
new file mode 100755
index 0000000..2ec557a
--- /dev/null
+++ b/toybox/tests/factor.test
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+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 "10000000018" "factor 10000000018" \
+        "10000000018: 2 131 521 73259\n" "" ""
+testing "10000000019" "factor 10000000019" \
+        "10000000019: 10000000019\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"
+
diff --git a/toybox/tests/file.test b/toybox/tests/file.test
new file mode 100644
index 0000000..234282f
--- /dev/null
+++ b/toybox/tests/file.test
@@ -0,0 +1,21 @@
+#!/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
+
+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" "" ""
+
+rm empty bash.script bash.script2 env.python.script ascii java.class
diff --git a/toybox/tests/files/blkid/cramfs.bz2 b/toybox/tests/files/blkid/cramfs.bz2
new file mode 100644
index 0000000..37438fe
--- /dev/null
+++ b/toybox/tests/files/blkid/cramfs.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/ext2.bz2 b/toybox/tests/files/blkid/ext2.bz2
new file mode 100644
index 0000000..e27c4d7
--- /dev/null
+++ b/toybox/tests/files/blkid/ext2.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/ext3.bz2 b/toybox/tests/files/blkid/ext3.bz2
new file mode 100644
index 0000000..be7f11f
--- /dev/null
+++ b/toybox/tests/files/blkid/ext3.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/ext4.bz2 b/toybox/tests/files/blkid/ext4.bz2
new file mode 100644
index 0000000..a8314f9
--- /dev/null
+++ b/toybox/tests/files/blkid/ext4.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/f2fs.bz2 b/toybox/tests/files/blkid/f2fs.bz2
new file mode 100644
index 0000000..4111e87
--- /dev/null
+++ b/toybox/tests/files/blkid/f2fs.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/minix.bz2 b/toybox/tests/files/blkid/minix.bz2
new file mode 100644
index 0000000..b2f022e
--- /dev/null
+++ b/toybox/tests/files/blkid/minix.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/msdos.bz2 b/toybox/tests/files/blkid/msdos.bz2
new file mode 100644
index 0000000..26c9b66
--- /dev/null
+++ b/toybox/tests/files/blkid/msdos.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/ntfs.bz2 b/toybox/tests/files/blkid/ntfs.bz2
new file mode 100644
index 0000000..b654ecd
--- /dev/null
+++ b/toybox/tests/files/blkid/ntfs.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/reiser3.bz2 b/toybox/tests/files/blkid/reiser3.bz2
new file mode 100644
index 0000000..b2adfc8
--- /dev/null
+++ b/toybox/tests/files/blkid/reiser3.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/squashfs.bz2 b/toybox/tests/files/blkid/squashfs.bz2
new file mode 100644
index 0000000..2f1b793
--- /dev/null
+++ b/toybox/tests/files/blkid/squashfs.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/vfat.bz2 b/toybox/tests/files/blkid/vfat.bz2
new file mode 100644
index 0000000..1df8b89
--- /dev/null
+++ b/toybox/tests/files/blkid/vfat.bz2
Binary files differ
diff --git a/toybox/tests/files/blkid/xfs.bz2 b/toybox/tests/files/blkid/xfs.bz2
new file mode 100644
index 0000000..a757196
--- /dev/null
+++ b/toybox/tests/files/blkid/xfs.bz2
Binary files differ
diff --git a/toybox/tests/files/bzcat/overflow.bz2 b/toybox/tests/files/bzcat/overflow.bz2
new file mode 100644
index 0000000..9ac7947
--- /dev/null
+++ b/toybox/tests/files/bzcat/overflow.bz2
Binary files differ
diff --git a/toybox/tests/files/utf8/0xabad1dea.txt b/toybox/tests/files/utf8/0xabad1dea.txt
new file mode 100644
index 0000000..e05345d
--- /dev/null
+++ b/toybox/tests/files/utf8/0xabad1dea.txt
@@ -0,0 +1 @@
+‮ ασσιλέΜ ‭
diff --git a/toybox/tests/files/utf8/arabic.txt b/toybox/tests/files/utf8/arabic.txt
new file mode 100644
index 0000000..0acf66c
--- /dev/null
+++ b/toybox/tests/files/utf8/arabic.txt
@@ -0,0 +1,2 @@
+بلدي الحوامات مليء الثعابين
+وأنا لن شراء هذه السجائر مخدوش ذلك.
\ No newline at end of file
diff --git a/toybox/tests/files/utf8/bad.txt b/toybox/tests/files/utf8/bad.txt
new file mode 100644
index 0000000..1a91e8a
--- /dev/null
+++ b/toybox/tests/files/utf8/bad.txt
@@ -0,0 +1 @@
+Áï¿¿
diff --git a/toybox/tests/files/utf8/japan.txt b/toybox/tests/files/utf8/japan.txt
new file mode 100644
index 0000000..dcc4439
--- /dev/null
+++ b/toybox/tests/files/utf8/japan.txt
@@ -0,0 +1 @@
+私はガラスを食べられます。それは私を傷つけません。
\ No newline at end of file
diff --git a/toybox/tests/files/utf8/test1.txt b/toybox/tests/files/utf8/test1.txt
new file mode 100644
index 0000000..b5d1bb8
--- /dev/null
+++ b/toybox/tests/files/utf8/test1.txt
@@ -0,0 +1 @@
+l̴̗̞̠ȩ̸̩̥ṱ̴͍̻ ̴̲͜ͅt̷͇̗̮h̵̥͉̝e̴̡̺̼ ̸̤̜͜ŗ̴͓͉i̶͉͓͎t̷̞̝̻u̶̻̫̗a̴̺͎̯l̴͍͜ͅ ̵̩̲̱c̷̩̟̖o̴̠͍̻m̸͚̬̘ṃ̷̢͜e̵̗͎̫n̸̨̦̖c̷̰̩͎e̴̱̞̗
diff --git a/toybox/tests/files/utf8/test2.txt b/toybox/tests/files/utf8/test2.txt
new file mode 100644
index 0000000..1926c5e
--- /dev/null
+++ b/toybox/tests/files/utf8/test2.txt
@@ -0,0 +1,2 @@
+l̴̗̞̠ȩ̸̩̥ṱ̴͍̻ ̴̲͜ͅt̷͇̗̮h̵̥͉̝e̴̡̺̼ ̸̤̜͜ŗ̴͓͉i̶͉͓͎t̷̞̝̻u̶̻̫̗a̴̺͎̯l̴͍͜ͅ ̵̩̲̱c̷̩̟̖o̴̠͍̻m̸͚̬̘ṃ̷̢͜e̵̗͎̫n̸̨̦̖c̷̰̩͎e̴̱̞̗
+the̡ ҉̷ŕ͠͡į͞ţų͠al͘ ̛͏i͘҉s̛ ͜͞ḉ͏om̶͏pl̵͜ęt̴͠e̛
diff --git a/toybox/tests/find.test b/toybox/tests/find.test
new file mode 100755
index 0000000..25c2440
--- /dev/null
+++ b/toybox/tests/find.test
@@ -0,0 +1,97 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+mkdir dir
+cd dir
+touch file
+mkfifo fifo
+ln -s fifo link
+cd ..
+touch b
+
+mkdir perm
+touch perm/all-read-only
+chmod a=r perm/all-read-only
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Testing operators
+
+testing "-type l -a -type d -o -type p" \
+	"find dir -type l -a -type d -o -type p" "dir/fifo\n" "" ""
+testing "-type l -type d -o -type p" "find dir -type l -type d -o -type p" \
+	"dir/fifo\n" "" ""
+testing "-type l -o -type d -a -type p" \
+	"find dir -type l -o -type d -a -type p" "dir/link\n" "" ""
+testing "-type l -o -type d -type p" "find dir -type l -o -type d -type p" \
+	"dir/link\n" "" ""
+testing "-type l ( -type d -o -type l )" \
+	"find dir -type l \( -type d -o -type l \)" "dir/link\n" "" ""
+testing "extra parentheses" \
+	"find dir \( \( -type l \) \( -type d -o \( \( -type l \) \) \) \)" \
+	"dir/link\n" "" ""
+testing "( -type p -o -type d ) -type p" \
+	"find dir \( -type p -o -type d \) -type p" "dir/fifo\n" "" ""
+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 "-type f -a -print" \
+	"find dir -type f -a -print" "dir/file\n" "" ""
+testing "-print -o -print" \
+	"find dir -type f -a \( -print -o -print \)" "dir/file\n" "" ""
+
+# these were erroring or segfaulting:
+# find -type f -user nobody -exec : \;
+# find -type f -user nobody -exec : -exec : \;
+
+# Testing previous failures
+
+testing "-type f -user -exec" \
+  "find dir -type f -user $USER -exec ls {} \\;" "dir/file\n" "" ""
+testing "-type l -newer -exec" \
+  "find dir -type l -newer dir/file -exec ls {} \\;" "dir/link\n" "" ""
+testing "-perm (exact success)" \
+  "find perm -type f -perm 0444" "perm/all-read-only\n" "" ""
+testing "-perm (exact failure)" \
+  "find perm -type f -perm 0400" "" "" ""
+testing "-perm (min success)" \
+  "find perm -type f -perm -0400" "perm/all-read-only\n" "" ""
+testing "-perm (min failure)" \
+  "find perm -type f -perm -0600" "" "" ""
+testing "-perm (any success)" \
+  "find perm -type f -perm -0444" "perm/all-read-only\n" "" ""
+testing "-perm (any failure)" \
+  "find perm -type f -perm -0222" "" "" ""
+
+# Still fails
+
+testing "unterminated -exec {}" \
+  "find dir -type f -exec ls {} 2>/dev/null || echo bad" "bad\n" "" ""
+testing "-exec {} +" \
+  "find dir -type f -exec ls {} +" "dir/file\n" "" ""
+
+# `find . -iname` was segfaulting
+testing "-name file" \
+  "find dir -name file" "dir/file\n" "" ""
+testing "-name FILE" \
+  "find dir -name FILE" "" "" ""
+
+testing "-iname file" \
+  "find dir -iname FILE" "dir/file\n" "" ""
+testing "-iname FILE" \
+  "find dir -iname FILE" "dir/file\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
diff --git a/toybox/tests/fstype.test b/toybox/tests/fstype.test
new file mode 100755
index 0000000..3df26b1
--- /dev/null
+++ b/toybox/tests/fstype.test
@@ -0,0 +1,23 @@
+#!/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
diff --git a/toybox/tests/getfattr.test b/toybox/tests/getfattr.test
new file mode 100755
index 0000000..cb0f947
--- /dev/null
+++ b/toybox/tests/getfattr.test
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+mkdir attrs
+touch attrs/file
+setfattr -n user.empty attrs/file
+setfattr -n user.data -v hello attrs/file
+
+testing "" "getfattr attrs/file" \
+    "# file: attrs/file\nuser.data\nuser.empty\n\n" "" ""
+testing "-d" "getfattr -d attrs/file" \
+    "# file: attrs/file\nuser.data=\"hello\"\nuser.empty\n\n" "" ""
+testing "-n" "getfattr -n user.empty attrs/file" \
+    "# file: attrs/file\nuser.empty\n\n" "" ""
+testing "-d -n" "getfattr -d -n user.data attrs/file" \
+    "# file: attrs/file\nuser.data=\"hello\"\n\n" "" ""
+
+rm -rf attrs
diff --git a/toybox/tests/grep.test b/toybox/tests/grep.test
new file mode 100755
index 0000000..2a4f178
--- /dev/null
+++ b/toybox/tests/grep.test
@@ -0,0 +1,145 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+# Copyright 2013 by Kyungsu Kim <kaspyx@gmail.com>
+# Copyright 2013 by Kyungwan Han <asura321@gmail.com>
+
+#testing "name" "command" "result" "infile" "stdin"
+
+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 "-l" "grep -l test foo foo2 foo3" "foo\nfoo2\n" "" ""
+rm foo foo2 foo3
+
+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 "-e" "grep -e '[0-9]' input" "1234123asdfas123123\n1\n" \
+  "1234123asdfas123123\nabc\n1\nabcde" ""
+testing "-e -e" "grep -e one -e two -e three input" \
+  "two\ntwo\nthree\none\n" "two\ntwo\nthree\nand\none\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 "-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 "-b" "grep -b is input" "0:this is test\n13:this is test2\n" \
+  "this is test\nthis is test2\ntest case" ""
+testing "-i" "grep -i is input" "thisIs test\nthis is test2\n" \
+  "thisIs test\nthis is test2\ntest case" ""
+testing "-n" "grep -n is input" "1:this is test\n2:this is test2\n" \
+  "this is test\nthis is test2\ntest case" ""
+testing "-o" "grep -o is input" "is\nis\nis\nis\n" \
+  "this is test\nthis is test2\ntest case" ""
+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 "-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 "-x" "grep -x abc input" "abc\n" \
+  "aabcc\nabc\n" ""
+
+testing "-H (standard input)" "grep -H abc" "(standard input):abc\n" \
+  "" "abc\n"
+testing "-l (standard input)" "grep -l abc" "(standard input)\n" \
+  "" "abc\n"
+testing "-n two inputs" "grep -hn def - input" "2:def\n2:def\n" \
+  "abc\ndef\n" "abc\ndef\n"
+
+testing "pattern with newline" "grep 'abc
+def' input" "aabcc\nddeff\n" \
+  "aaaa\naabcc\n\dddd\nddeff\nffff\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 "-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 "-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 "-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 "-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 "-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 "-e blah -e ''" "grep -e blah -e '' input" "one one one\n" \
+  "one one one\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 "-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 "-B" "grep -B 1 yes" "no\nyes\n--\nno\nyes\nno\nyes\n" \
+  "" "no\nno\nno\nyes\nno\nno\nyes\nno\nyes"
+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 "-HnC" "grep -HnC1 two" \
+  "(standard input)-1-one\n(standard input):2:two\n(standard input)-3-three\n" \
+  "" "one\ntwo\nthree"
+
+# Context lines weren't showing -b
+testing "-HnbB1" "grep -HnbB1 f input" \
+  "input-3-8-three\ninput:4:14:four\ninput:5:19:five\n" \
+  "one\ntwo\nthree\nfour\nfive\n" ""
+
+testing "-q match overrides error" \
+  "grep -q hello missing input 2>/dev/null && echo yes" "yes\n" "hello\n" ""
+testing "-q not found is 1" \
+  'grep -q hello input || echo $?' "1\n" "" ""
+testing "-q missing is 2" \
+  'grep -q hello missing missing 2>/dev/null || echo $?' "2\n" "" ""
+testing "-q missing survives exists but not found" \
+  'grep -q hello missing missing input 2>/dev/null || echo $?' "2\n" "" ""
+testing "not found retained past match" \
+  'grep hello missing input 2>/dev/null || echo $?' \
+  "input:hello\n2\n" "hello\n" ""
+touch empty
+testing "one match good enough for 0" \
+  'grep hello input empty && echo $?' 'input:hello\n0\n' 'hello\n' ''
+rm empty
+
+testing "-o ''" "grep -o ''" "" "" "one two three\none two\none\n"
+testing '' "grep -o -e '' -e two" "two\ntwo\n" "" \
+  "one two three\none two\none\n"
+
+echo "one\ntwo\nthree" > test
+testing "-l trumps -C" "grep -l -C1 two test input" "test\ninput\n" \
+  "three\ntwo\none\n" ""
+rm test
+
+# match after NUL byte
+testing "match after NUL byte" "grep -a two" "one\0and two three\n" \
+  "" 'one\0and two three'
diff --git a/toybox/tests/groupadd.test b/toybox/tests/groupadd.test
new file mode 100755
index 0000000..091dccf
--- /dev/null
+++ b/toybox/tests/groupadd.test
@@ -0,0 +1,56 @@
+#!/bin/bash
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+# 70 characters long string; hereafter, we will use it as per our need.
+_s70="abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz123456789"
+
+echo "# usage: addgroup [-g GID] [USER] GROUP
+# Add a group or add a user to a group."
+
+# Redirecting all output to /dev/null for grep and delgroup
+arg="&>/dev/null"
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "group_name (text)" "groupadd toyTestGroup &&
+   grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
+   echo 'yes'" "yes\n" "" ""
+testing "group_name (alphanumeric)" "groupadd toy1Test2Group3 &&
+   grep '^toy1Test2Group3:' /etc/group $arg && groupdel toy1Test2Group3 $arg &&
+   echo 'yes'" "yes\n" "" ""
+testing "group_name (numeric)" "groupadd 987654321 &&
+   grep '^987654321:' /etc/group $arg && groupdel 987654321 $arg &&
+   echo 'yes'" "yes\n" "" ""
+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 "group_name (long string)" "groupadd $_s210 &&
+   grep '^$_s210:' /etc/group $arg && groupdel $_s210 $arg && echo 'yes'" \
+  "yes\n" "" ""
+testing "group_name with group_id" "groupadd -g 49999 toyTestGroup &&
+   grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
+   echo 'yes'" "yes\n" "" ""
+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 "group_name (system_group)" "groupadd -S toyTestGroup &&
+   grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
+   echo 'yes'" "yes\n" "" ""
+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 &&
+   grep '^toyTestGroup:' /etc/group $arg || echo 'yes'" "yes\n" "" ""
+
+ echo "Testing to add single group multiple times after removing it..."
+ for each in {01..20}
+ do
+   testing "group_name ($each)" "groupadd toyTestGroup &&
+      grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
+      echo 'yes'" "yes\n" "" ""
+ done
diff --git a/toybox/tests/groupdel.test b/toybox/tests/groupdel.test
new file mode 100755
index 0000000..ea9ee9a
--- /dev/null
+++ b/toybox/tests/groupdel.test
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+# Redirecting all output to /dev/null for grep and delgroup
+arg="&>/dev/null"
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "group_name (text)" "groupadd toyTestGroup &&
+   grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
+   echo 'yes'" "yes\n" "" ""
+testing "group_name (alphanumeric)" "groupadd toy1Test2Group3 &&
+   grep '^toy1Test2Group3:' /etc/group $arg && groupdel toy1Test2Group3 $arg &&
+   echo 'yes'" "yes\n" "" ""
+testing "group_name (numeric)" "groupadd 987654321 &&
+   grep '^987654321:' /etc/group $arg && groupdel 987654321 $arg &&
+   echo 'yes'" "yes\n" "" ""
+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 "group_name with group_id" "groupadd -g 49999 toyTestGroup &&
+   grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
+   echo 'yes'" "yes\n" "" ""
diff --git a/toybox/tests/head.test b/toybox/tests/head.test
new file mode 100755
index 0000000..83d9399
--- /dev/null
+++ b/toybox/tests/head.test
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+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 "-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"
+
+echo "foo
+bar
+baz" > file1
+testing "head, multiple files" "head -n 2 input file1" "==> input <==\none\ntwo\n\n==> file1 <==\nfoo\nbar\n" "one\ntwo\nthree\n" ""
+rm file1
+
diff --git a/toybox/tests/hostname.test b/toybox/tests/hostname.test
new file mode 100755
index 0000000..5107ce2
--- /dev/null
+++ b/toybox/tests/hostname.test
@@ -0,0 +1,18 @@
+#!/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"
+
+# Get system hostname
+hostnameExe=`which hostname`
+hostnameOut=`$hostnameExe`
+
+# New hostname
+NewHostname="NewHostName.system"
+
+testing "get" "hostname" "$hostnameOut\n" "" ""
+testing "set, Get and then Reset" "hostname $NewHostname; hostname; hostname $hostnameOut; hostname" "$NewHostname\n$hostnameOut\n" "" ""
diff --git a/toybox/tests/ifconfig.test b/toybox/tests/ifconfig.test
new file mode 100755
index 0000000..34fcde0
--- /dev/null
+++ b/toybox/tests/ifconfig.test
@@ -0,0 +1,192 @@
+#!/bin/bash
+# Copyright 2014 Cynthia Rempel <cynthia@rtems.org>
+#
+# Brief: Some cursery coverage tests of ifconfig...
+# Note: requires permissions to run modprobe and all ifconfig options
+# Commands used: grep, grep -i, ip link, ip tuntap, wc -l
+#
+# Possible improvements:
+# 1. Verify the dummy interface actually has the modified characteristics
+#    instead of relying on ifconfig output
+# 2. Introduce more error cases, to verify ifconfig fails gracefully
+# 3. Do more complex calls to ifconfig, while mixing the order of the
+#    arguments
+# 4. Cover more ifconfig options:
+#    hw ether|infiniband ADDRESS - set LAN hardware address (AA:BB:CC...)
+#    txqueuelen LEN - number of buffered packets before output blocks
+#    Obsolete fields included for historical purposes:
+#    irq|io_addr|mem_start ADDR - micromanage obsolete hardware
+#    outfill|keepalive INTEGER - SLIP analog dialup line quality monitoring
+#    metric INTEGER - added to Linux 0.9.10 with comment "never used", still true
+
+[ -f testing.sh ] && . testing.sh
+
+if [ "$(id -u)" -ne 0 ]
+then
+  echo "$SHOWSKIP: ifconfig (not root)"
+  continue 2>/dev/null
+  exit
+fi
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Add a dummy interface to test with
+ifconfig dummy0 up
+
+# Test Description: Disable the dummy0 interface
+# Results Expected: After calling ifconfig, no lines with dummy0 are displayed
+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 "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 "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 "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 "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 "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 "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 "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 "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 "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 "dummy0 del ::2" \
+"ifconfig dummy0 del ::2/126 && ifconfig dummy0 | grep \:\:2 | wc -l" \
+"0\n" "" ""
+
+# Test Description: Remove the noarp flag and bring the interface down in
+#                   preparation for the next test
+# Results Expected: After calling ifconfig dummy0, there are no lines with the
+#                   NOARP flag
+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 "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 "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" "" ""
+
+####### Flags you can set on an interface (or -remove by prefixing with -): ###############
+
+# Test Description: Enable allmulti mode on the interface
+# Results Expected: After calling ifconfig dummy0, there is one line with the
+#                   allmulti flag
+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 "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 "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 "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 "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 "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 "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 "dummy0 -promisc" \
+"ifconfig dummy0 -promisc && ifconfig dummy0 | grep -i promisc | wc -l" "0\n" \
+"" ""
+
+# Disable the dummy interface
+ifconfig dummy0 down
diff --git a/toybox/tests/link.test b/toybox/tests/link.test
new file mode 100755
index 0000000..d91b794
--- /dev/null
+++ b/toybox/tests/link.test
@@ -0,0 +1,26 @@
+#!/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 "" >foo
+testing "fails on non-existent file" "link foo/foo baz || echo GOOD" "GOOD\n" "" ""
+rm -f foo bar
+
+echo file1 > file
+testing "create_hardlink" "link file hlink && [ file -ef hlink ] &&
+          echo 'yes'; rm  -rf hlink" "yes\n" "" ""
+
+echo hlink1 > hlink
+set +e
+testing "preserves_hardlinks" "link file hlink 2>/dev/null || echo 'yes'; rm -rf hlink" \
+          "yes\n" "" ""
+
+echo file1 > file
+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" "" ""
diff --git a/toybox/tests/ln.test b/toybox/tests/ln.test
new file mode 100755
index 0000000..3e70cd8
--- /dev/null
+++ b/toybox/tests/ln.test
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+#set -x
+
+echo file1 > file
+testing "create_hardlink" "ln file hlink && [ file -ef hlink ] &&
+          echo 'yes'" "yes\n" "" ""
+testing "create_softlink" "ln -s file slink && [ -L slink ] &&
+          readlink slink" "file\n" "" ""
+rm slink hlink
+
+echo hlink1 > hlink
+testing "force_create_hardlink" "ln -f file hlink &&
+          [ file -ef hlink ] && cat hlink 2>/dev/null" "file1\n" "" ""
+
+echo slink1 > 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 "preserves_hardlinks" "ln file hlink 2>/dev/null || echo 'yes'" \
+          "yes\n" "" ""
+
+echo slink1 > slink
+set +e
+testing "preserves_softlinks" "ln -s file slink 2>/dev/null || echo 'yes'" \
+          "yes\n" "" ""
+rm slink hlink
+
+mkdir dir
+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 "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 "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 "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 "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 "create_hardlink_and_remove_sourcefile" "ln file hlink &&
+          [ file -ef hlink ] && rm file && [ -f hlink ] && echo 'yes'" \
+          "yes\n" "" ""
+rm -f file hlink
diff --git a/toybox/tests/losetup.test b/toybox/tests/losetup.test
new file mode 100755
index 0000000..651c693
--- /dev/null
+++ b/toybox/tests/losetup.test
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+if [ "$(id -u)" -ne 0 ]
+then
+  echo "$SHOWSKIP: losetup (not root)"
+  continue 2>/dev/null
+  exit
+fi
+
+#testing "name" "command" "result" "infile" "stdin"
+
+truncate -s 1M blah.img &&
+FILE="$(readlink -f blah.img)"
+DEV="$(printf '%04d' $(stat -t blah.img | awk '{print $7}'))"
+NODE="$(awk '{print $7}')"
+
+losetup -f 
+losetup -f -s
+losetup -f file
+
+losetup -d
+
+rm blah.img
diff --git a/toybox/tests/ls.test b/toybox/tests/ls.test
new file mode 100755
index 0000000..07850de
--- /dev/null
+++ b/toybox/tests/ls.test
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+#set -x
+
+# Creating test-file/dir for testing ls
+mkdir -p lstest/dir1 lstest/dir2 || exit 1
+echo "test file1" > lstest/file1.txt
+echo "test file2" > lstest/file2.txt
+echo "hidden file1" > lstest/.hfile1
+
+IN="cd lstest"
+OUT="cd .. "
+
+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 "with -A" "$IN && ls -A; $OUT" \
+        "dir1\ndir2\nfile1.txt\nfile2.txt\n.hfile1\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 "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 "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 "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 "with -i" "$IN && ls -i 2>/dev/null; $OUT" "$INODE file1.txt\n" "" ""
+unset INODE
+
+# Removing test dir for cleanup purpose
+rm -rf lstest
diff --git a/toybox/tests/lsattr.test b/toybox/tests/lsattr.test
new file mode 100755
index 0000000..c2c7c61
--- /dev/null
+++ b/toybox/tests/lsattr.test
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# lsattr - Testcases
+mkdir dir && cd dir && touch file
+chattr +A file &>/dev/null
+
+_p=$PWD
+_b="-------------"
+_A="-------A-----"
+
+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 "-l file" "lsattr -l file" "file  $sp_44 No_Atime\n" "" ""
+_v="12345"
+testing "-v file" "chattr -v $_v * && lsattr -v file" \
+  "$_v $_A file\n" "" ""
+testing "-v file_path" "chattr -v $_v * && lsattr -v $_p/file" \
+  "$_v $_A $_p/file\n" "" ""
+testing "-Radlv file1 file2" "chattr -v $_v * &&
+   lsattr -Radlv file input" \
+  "$_v file  $sp_44 No_Atime\n$_v input $sp_44 ---\n" "" ""
+
+# Cleanup
+chattr -AacDdijsStTu file && cd ..
+rm -rf dir
diff --git a/toybox/tests/md5sum.test b/toybox/tests/md5sum.test
new file mode 100755
index 0000000..f159d1e
--- /dev/null
+++ b/toybox/tests/md5sum.test
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# These tests are from RFC 1321 appendix 5, reshuffled slightly to test
+# varying argument numbers
+
+testing "''" "md5sum" "d41d8cd98f00b204e9800998ecf8427e  -\n" "" ""
+testing "infile" "md5sum input" \
+  "0cc175b9c0f1b6a831c399e269772661  input\n" "a" ""
+testing "two files" "md5sum - input" \
+  "900150983cd24fb0d6963f7d28e17f72  -\nf96b697d7cb7938d525a2f31aaf161d0  input\n" \
+  "message digest" "abc"
+testing "4" "md5sum" "c3fcd3d76192e4007dfb496cca67e13b  -\n" \
+  "" "abcdefghijklmnopqrstuvwxyz"
+testing "5" "md5sum" "d174ab98d277d9f5a5611c2c9f419d9f  -\n" \
+  "" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+testing "6" "md5sum" "57edf4a22be3c955ac49da2e2107b67a  -\n" \
+  "" "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+
+echo -n "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" > "te st"
+touch empty
+testing "-c spaces" "md5sum -c input || echo ok" \
+  "te st: OK\nempty: FAILED\n-: OK\nok\n" \
+"$(printf "d174ab98d277d9f5a5611c2c9f419d9f te st\n12345678901234567890123456789012 empty\nd41d8cd98f00b204e9800998ecf8427e -\n")" ""
+rm "te st" empty
+
+testing "-c nolines" "md5sum -c input 2>/dev/null || echo ok" "ok\n" "" ""
diff --git a/toybox/tests/mkdir.test b/toybox/tests/mkdir.test
new file mode 100755
index 0000000..e1bdb88
--- /dev/null
+++ b/toybox/tests/mkdir.test
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "mkdir" "mkdir one && [ -d one ] && echo yes" "yes\n" "" ""
+rmdir one
+
+touch existing
+testing "existing" \
+	"mkdir existing 2> /dev/null || [ -f existing ] && echo yes" "yes\n" "" ""
+rm existing
+
+testing "one two" \
+	"mkdir one two && [ -d one ] && [ -d two ] && echo yes" "yes\n" "" ""
+rmdir one two
+
+testing "missing/one" \
+	"mkdir missing/one 2> /dev/null || [ ! -d missing ] && echo yes" "yes\n" "" ""
+
+testing "-p" \
+	"mkdir -p one/two/three && [ -d one/two/three ] && echo yes" "yes\n" "" ""
+rm -rf one
+
+mkdir existing
+testing "-p existing" "mkdir -p existing && echo yes" "yes\n" "" ""
+rmdir existing
+
+umask 123
+testing "(default permissions)" \
+	"mkdir one && stat -c %a one" "654\n" "" ""
+rmdir one
+
+testing "-m 124" \
+	"mkdir -m 124 one && stat -c %a one" "124\n" "" ""
+rmdir one
+
+umask 000
+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 "-p one/two/ (trailing slash)" \
+	"mkdir -p one/two/ &&  [ -d one/two ] && echo yes" "yes\n" "" ""
+rm -rf one
+
+umask 022
+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 "-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 "-vp" "mkdir -vp walrus 2>&1" \
+	"mkdir: created directory 'walrus'\n" "" ""
+
+testing "-vp exists" "mkdir -vp walrus 2>&1" \
+	"" "" ""
+rm -rf walrus
+
+touch two
+testing "continue after fail" \
+	"mkdir -m 777 one two three 2>/dev/null || stat -c %a three" \
+	"777\n" "" ""
+rm -rf one two three
diff --git a/toybox/tests/mkfifo.test b/toybox/tests/mkfifo.test
new file mode 100755
index 0000000..faaad1f
--- /dev/null
+++ b/toybox/tests/mkfifo.test
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "mkfifo" "mkfifo one && [ -p one ] && echo yes" "yes\n" "" ""
+rm one
+
+touch existing
+testing "existing" \
+	"mkfifo existing 2> /dev/null || [ -f existing ] && echo yes" "yes\n" "" ""
+rm existing
+
+testing "one two" \
+	"mkfifo one two && [ -p one ] && [ -p two ] && echo yes" "yes\n" "" ""
+rm one two
+
+umask 123
+testing "(default permissions)" \
+	"mkfifo one && stat -c %a one" "644\n" "" ""
+rm one
+
+umask 000
+
+testing "-m 124" \
+	"mkfifo -m 124 one && stat -c %a one" "124\n" "" ""
+rm -f one
diff --git a/toybox/tests/modinfo.test b/toybox/tests/modinfo.test
new file mode 100755
index 0000000..0a8c2be
--- /dev/null
+++ b/toybox/tests/modinfo.test
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+[ -e /proc/modules ] || { echo "Skipping test because modules are not supported"; exit 1; }
+
+# modinfo does not need to output fields in a specified order.
+# Instead, there are labelled fields.  We can use sort to make up for this.
+# Other issues to beware of are the volatile nature of srcversion and vermagic,
+# which change from kernel to kernel and can be disabled. 
+# We grep to remove these.
+
+#We expect they have ne2k-pci as a module.
+
+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 "-F filename gets absolute path" "[ -e `modinfo -F filename ne2k-pci` ] && echo ne2k-pci " "ne2k-pci\n" "" ""
+
+testing "supports multiple modules" "modinfo -F filename ne2k-pci 8390 | wc -l" "2\n" "" ""
+
+testing "does not output filename for bad module" "modinfo -F filename zxcvbnm__9753" "" "" ""
+
+
+
diff --git a/toybox/tests/more.test b/toybox/tests/more.test
new file mode 100755
index 0000000..4dcf6d8
--- /dev/null
+++ b/toybox/tests/more.test
@@ -0,0 +1,14 @@
+#!/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
diff --git a/toybox/tests/mount.test b/toybox/tests/mount.test
new file mode 100755
index 0000000..6590b94
--- /dev/null
+++ b/toybox/tests/mount.test
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+root_fs=`df | grep "\/$" | awk '{print $1}'`
+root_fs_type=`file -sL $root_fs | awk '{print $5}'`
+
+tmp_b_fs="tmp_b_fs"
+tmp_b_fs_type="ext3"
+
+reCreateTmpFs() {
+  rm -rf $tmp_b_fs
+  mknod $tmp_b_fs b 1 0
+  mkfs.ext3 $tmp_b_fs >/dev/null 2>&1
+}
+reCreateTmpFs
+
+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 "$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 "$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 "$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 "-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 "-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 "-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 "$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 "-o bind dir1 dir2" \
+  'mount -o bind testDir1 testDir >/dev/null 2>&1 && \
+   cat testDir/testDir2/testFile && sleep 1 && umount testDir' \
+  "abcdefghijklmnopqrstuvwxyz\n" "" ""
+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 "-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 "-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 "-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 "-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 "-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
+
+umount testDir1
+rm -f $tmp_b_fs
diff --git a/toybox/tests/mv.test b/toybox/tests/mv.test
new file mode 100755
index 0000000..036fd48
--- /dev/null
+++ b/toybox/tests/mv.test
@@ -0,0 +1,157 @@
+#!/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>
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+touch file
+testing "file to file" \
+  "mv file file1 && [ ! -e file -a -f file1 ] && echo yes" \
+  "yes\n" "" ""
+rm -f file*
+
+touch file
+mkdir dir
+testing "file to dir" \
+  "mv file dir && [ ! -e file -a -f dir/file ] && echo yes" \
+  "yes\n" "" ""
+rm -rf file* dir*
+
+mkdir dir
+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 "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*
+
+dd if=/dev/zero of=file1 seek=10k count=1 >/dev/null 2>&1
+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 "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 "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 "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 "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 "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 "dir to existing dir" \
+  "mv dir1 dir2 && [ ! -e dir1 -a -d dir2/dir1 ] && echo yes" \
+  "yes\n" "" ""
+rm -rf dir*
+
+touch file1 file2
+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
+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 "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*
diff --git a/toybox/tests/nl.test b/toybox/tests/nl.test
new file mode 100755
index 0000000..499734d
--- /dev/null
+++ b/toybox/tests/nl.test
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "nl" "nl" "     1\tone\n     2\ttwo\n     3\tthree\n" \
+  "" "one\ntwo\nthree\n"
+
+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 "-nln" "nl -nln" "1     \tone\n2     \ttwo\n3     \tthree\n" \
+  "" "one\ntwo\nthree\n"
+testing "-nln -w" "nl -nln -w 8" \
+  "1       \tone\n2       \ttwo\n3       \tthree\n" "" "one\ntwo\nthree\n"
+
+testing "-nrz" "nl -nrz" "000001\tone\n000002\ttwo\n000003\tthree\n" \
+  "" "one\ntwo\nthree\n"
+
+testing "-nrz -w" "nl -w3 -nrz" "001\tone\n002\ttwo\n003\tthree\n" \
+  "" "one\ntwo\nthree\n"
+
+
+# For non-matching lines the separator is "suppressed" meaning it...
+# turns into spaces! And the tab turns into one space, and -d boom turns
+# into 4 spaces, but these:
+#   nl -s"$(echo -e 'bo\tom')" -bpand README
+#   nl -w 3 -bpthe README
+# Yeah. And I doubt utf8 fontmetrics are used either.
+
+testing "-b t" "nl -b t" "       \n     1\tone\n       \n     2\ttwo\n" \
+  "" "\none\n\ntwo\n"
+testing "-b n" "nl -b n" "       one\n       two\n       three\n" \
+  "" "one\ntwo\nthree\n"
+testing "-sook -b p" "nl -sook -bpoing" \
+  "         one\n     1ookboing\n     2ooksproingy\n" \
+  "" "one\nboing\nsproingy\n"
+
+testing "-v" "nl -v 42" "    42\tone\n    43\ttwo\n    44\tthree\n" \
+  "" "one\ntwo\nthree\n"
+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 "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 "-E" "nl -w2 -sx -Ebp'(one|two)'" " 1x" "one\nand\ntwo\n"
diff --git a/toybox/tests/pgrep.test b/toybox/tests/pgrep.test
new file mode 100755
index 0000000..3319c79
--- /dev/null
+++ b/toybox/tests/pgrep.test
@@ -0,0 +1,37 @@
+#!/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"
+
+# Starting processes to test pgrep command
+yes >/dev/null &
+proc=$!
+#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"
+
+# Testcases for pgrep command
+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
diff --git a/toybox/tests/pkill.test b/toybox/tests/pkill.test
new file mode 100755
index 0000000..3f20d26
--- /dev/null
+++ b/toybox/tests/pkill.test
@@ -0,0 +1,107 @@
+#!/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" "" ""
+
diff --git a/toybox/tests/printf.test b/toybox/tests/printf.test
new file mode 100755
index 0000000..a333174
--- /dev/null
+++ b/toybox/tests/printf.test
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Disable shell builtin
+PRINTF="$(which printf)"
+
+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 "%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 "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 "%x" "$PRINTF '%x\n' 0x2a" "2a\n" "" ""
+
+testing "%d 42" "$PRINTF %d 42" "42" "" ""
+testing "%d 0x2a" "$PRINTF %d 0x2a" "42" "" ""
+testing "%d 052" "$PRINTF %d 052" "42" "" ""
+
+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 "extra args" "$PRINTF 'abc%s!%ddef\n' X 42 ARG 36" \
+	"abcX!42def\nabcARG!36def\n" "" ""
+
+testing "'%3c'" "$PRINTF '%3c' x" "  x" "" ""
+testing "'%-3c'" "$PRINTF '%-3c' x" "x  " "" ""
+testing "'%+d'" "$PRINTF '%+d' 5" "+5" "" ""
+
+
+testing "'%5d%4d' 1 21 321 4321 54321" \
+  "$PRINTF '%5d%4d' 1 21 321 4321 54321" "    1  21  321432154321   0" "" ""
+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 "'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 "'%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 "%.s acts like %.0s" "$PRINTF %.s_ 1 2 3 4 5" "_____" "" ""
+testing "corner case" "$PRINTF '\\8'" '\8' '' ''
+
+# The posix spec explicitly specifies inconsistent behavior,
+# so treating the \0066 in %b like the \0066 not in %b is wrong because posix.
+testing "printf posix inconsistency" "$PRINTF '\\0066-%b' '\\0066'" "\x066-6" \
+  "" ""
diff --git a/toybox/tests/pwd.test b/toybox/tests/pwd.test
new file mode 100755
index 0000000..68d22e3
--- /dev/null
+++ b/toybox/tests/pwd.test
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+#TODO: Find better tests
+
+testing "pwd" "[ $(stat -c %i "$(pwd)") = $(stat -c %i .) ] && echo yes" \
+	"yes\n" "" ""
+testing "-P" "[ $(stat -c %i "$(pwd -P)") = $(stat -c %i .) ] && echo yes" \
+	"yes\n" "" ""
+
+
+ln -s . sym
+cd sym
+testing "pwd" "[ $(stat -c %i "$(pwd)") = $(stat -c %i "$PWD") ] && echo yes" \
+	"yes\n" "" ""
+testing "-P" "[ $(stat -c %i "$(pwd -P)") = $(stat -c %i "$PWD") ] || echo yes" \
+	"yes\n" "" ""
+cd ..
+rm sym
+
+export PWD=walrus
+testing "(bad PWD)" "[ "$(pwd)" = "$(cd . ; pwd)" ] && echo yes" \
+	"yes\n" "" ""
diff --git a/toybox/tests/readlink.test b/toybox/tests/readlink.test
new file mode 100755
index 0000000..bb25985
--- /dev/null
+++ b/toybox/tests/readlink.test
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+APWD="$(pwd -P)"
+
+testing "missing" "readlink notfound || echo yes" "yes\n" "" ""
+
+# simple tests on a file
+
+touch file
+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 "link" "readlink link" "notfound\n" "" ""
+testing "link->missing" "readlink -f link" "$APWD/notfound\n" "" ""
+ln -sf ../../ link
+testing "stays relative" "readlink link" "../../\n" "" ""
+rm link
+ln -sf file link
+testing "-f link->file" "readlink -f link" "$APWD/file\n" "" ""
+ln -sf . link
+testing "-f link->dir" "readlink -f link" "$APWD\n" "" ""
+ln -snf link link
+testing "link->link (recursive)" "readlink link" "link\n" "" ""
+testing "-f link->link (recursive)" \
+  "readlink -f link 2>/dev/null || echo yes" "yes\n" "" ""
+
+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 "-nf ." "readlink -nf ." "$APWD" "" ""
+
+mkdir sub &&
+ln -s . here &&
+ln -s ./sub dir &&
+touch sub/bang || exit 1
+testing "-f multi" "readlink -f dir/../here/dir/bang" \
+  "$APWD/sub/bang\n" "" ""
+testing "-f link/missing" "readlink -f dir/boing" \
+  "$APWD/sub/boing\n" "" ""
+testing "-f /dev/null/file" \
+  "readlink -f /dev/null/file 2>/dev/null || echo yes" "yes\n" "" ""
+ln -sf / link || exit 1
+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 "recurse" "readlink link" "link\n" "" ""
+
+rm file link sub/bang dir here
+rmdir sub
+
+# Make sure circular links don't run away.
+
+ln -s link1 link2
+ln -s link2 link1
+testing "follow recursive2" "readlink -f link1 || echo yes" \
+	"yes\n" "" ""
+rm link1 link2
diff --git a/toybox/tests/renice.test b/toybox/tests/renice.test
new file mode 100755
index 0000000..e350c27
--- /dev/null
+++ b/toybox/tests/renice.test
@@ -0,0 +1,110 @@
+#!/bin/bash
+
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+fun_nice_val() 
+{
+  for each_proc in $@
+  do
+    echo `awk '{ print $18 }' /proc/${each_proc}/stat`
+  done
+}
+
+# creating processes as a test data
+yes >/dev/null &
+proc1=$!
+yes >/dev/null &
+proc2=$!
+yes >/dev/null &
+proc3=$!
+yes >/dev/null &
+proc4=$!
+yes >/dev/null &
+proc5=$!
+
+n_val1=`fun_nice_val $proc1`
+n_val2=`fun_nice_val $proc2`
+n_val3=`fun_nice_val $proc3`
+n_val4=`fun_nice_val $proc4`
+n_val5=`fun_nice_val $proc5`
+
+# Redirecting errors to /dev/null
+arg="2>/dev/null"
+
+for n_v in "-1" "1"
+do
+  for n_o in "" " -p"
+  do
+    nice_val1=$((`fun_nice_val $proc1` + $n_v))
+    nice_val2=$((`fun_nice_val $proc2` + $n_v))
+    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 "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_val1=$((`fun_nice_val $proc1` + $n_v))
+    nice_val2=$((`fun_nice_val $proc2` + $n_v))
+    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 "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" "" ""
+  done
+done
+
+# Starting Boundary Test Here .. 
+loop_cnt=2
+echo -n "TEST: Boundary value test for Id($proc1)..[old_nice_val/new_nice_val]:"
+cnt=0
+n_val=1
+while [ $cnt -gt -1 ]
+do
+  old_nice_val=`fun_nice_val $proc1`
+  new_nice_val=`renice -n $n_val $proc1 >/dev/null 2>&1 && fun_nice_val $proc1`
+  echo -n "[$old_nice_val/$new_nice_val],"
+  if [ $old_nice_val -eq 39 -a $old_nice_val -eq $new_nice_val ]
+  then
+    echo -n " [Equals 39,doing -1] "
+    n_val="-1"
+  elif [ $old_nice_val -eq 0 -a $old_nice_val -eq $new_nice_val ]
+  then
+    echo -n " [Equals 0,doing +1] "
+    n_val="1"
+  elif [ $new_nice_val -gt 39 -o $new_nice_val -lt 0 ]
+  then
+    echo " [Test Fail] "
+    echo "FAIL: renice with step 1 ($proc1) (boundary value)"
+    cnt="-1"
+  elif [ $new_nice_val -eq $n_val1 -a $new_nice_val -eq $(($old_nice_val+1)) ]
+  then
+    cnt=$(($cnt + 1))
+    if [ $cnt -eq $loop_cnt ]
+    then
+      echo " [Test Pass] "
+      echo "PASS: renice with step 1 ($proc1) (boundary value)"
+      cnt="-1"
+    fi
+  else
+    dif=`echo $(($new_nice_val-$old_nice_val))`
+    dif=`echo ${dif/-}`
+    if [ $dif -ne 1 ]
+    then
+      echo " [Test Fail] "
+      echo "FAIL: renice with step 1 ($proc1) (boundary value)"
+      cnt="-1"
+    fi
+  fi
+done
+# Boundary test End
+
+killall yes >/dev/null 2>&1
diff --git a/toybox/tests/rev.test b/toybox/tests/rev.test
new file mode 100755
index 0000000..ede78c2
--- /dev/null
+++ b/toybox/tests/rev.test
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+echo -e "one" > file1 
+echo -e "two" > file2
+testing "rev" "rev && echo yes" "orez\nyes\n" "" "zero\n"
+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 "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 "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"
+
+rm file1 file2
\ No newline at end of file
diff --git a/toybox/tests/rm.test b/toybox/tests/rm.test
new file mode 100755
index 0000000..624d60f
--- /dev/null
+++ b/toybox/tests/rm.test
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+echo "abcdefghijklmnopqrstuvwxyz" > file.txt
+testing "text-file" "rm file.txt && [ ! -e file.txt ] && echo 'yes'" "yes\n" "" ""
+rm -f file*
+
+mkdir dir
+testing "empty directory" "rm -r dir && [ ! -d dir ] && echo 'yes'" "yes\n" "" ""
+rm -rf dir
+
+echo "abcdefghijklmnopqrstuvwxyz" > file.txt && chmod 000 file.txt
+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 "-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" "" ""
+rm -rf file* dir*
+
+touch file1.txt file2.txt
+mkdir dir1 dir2
+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" "" ""
+rm -rf file* dir*
+
+# 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 "-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*
+
diff --git a/toybox/tests/rmdir.test b/toybox/tests/rmdir.test
new file mode 100755
index 0000000..5b36bbc
--- /dev/null
+++ b/toybox/tests/rmdir.test
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+mkdir one
+testing "rmdir" "rmdir one && [ ! -d one ] && echo yes" "yes\n" "" ""
+
+touch walrus
+testing "file" \
+	"rmdir walrus 2> /dev/null || [ -f walrus ] && echo yes" "yes\n" "" ""
+
+mkdir one two
+testing "one two" \
+	"rmdir one two 2> /dev/null && [ ! -d one ] && [ ! -d two ] && echo yes" \
+	"yes\n" "" ""
+
+mkdir one two 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 "mode 000" "rmdir one && [ ! -d one ] && echo yes" "yes\n" "" ""
+
+mkdir temp
+touch temp/thing
+testing "non-empty" \
+	"rmdir temp 2>/dev/null || [ -d temp ] && echo yes" "yes\n" "" ""
+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 "-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 "-p one/two/three" \
+	"rmdir -p one/two/three && [ ! -e one ] && echo yes" "yes\n" "" ""
+
+mkdir -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 "-p one/two/three" \
+#	"rmdir -p one/two/three && [ ! -e one ] && echo yes" "yes\n" "" ""
diff --git a/toybox/tests/sed.test b/toybox/tests/sed.test
new file mode 100755
index 0000000..d25148e
--- /dev/null
+++ b/toybox/tests/sed.test
@@ -0,0 +1,158 @@
+#!/bin/echo Run scripts/test.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+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 '-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 '-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 '$ 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'
+testing '' 'sed -n /one/,2p' 'one\ntwo\n' '' 'one\ntwo\nthree'
+testing '' 'sed -n 1,/one/p' 'one\ntwo\nthree' '' 'one\ntwo\nthree'
+testing '' 'sed -n /one/,1p' 'one\n' '' 'one\ntwo\nthree'
+testing 'sed -n /two/,$p' 'sed -n /two/,\$p' 'two\nthree' '' 'one\ntwo\nthree'
+
+
+# Fun with newlines!
+testing '' 'sed -n 3p' "three" "" "one\ntwo\nthree"
+testing 'prodigal newline' "sed -n '1,\$p' - input" \
+	"one\ntwo\nthree\nfour\n" "four\n" "one\ntwo\nthree"
+testing 'Newline only added if further output' "sed -n 3p - input" "three" \
+	"four\n" "one\ntwo\nthree"
+
+# Fun with match delimiters and escapes
+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 '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 'end match/start match mixing number/letter' \
+	"sed -n '2,/two/p'" "two\nthree" "" "one\ntwo\nthree"
+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 'regex address overlap' 'sed -n /on/,/off/p' "on\nzap\noffon\n" "" \
+	'on\nzap\noffon\nping\noff\n'
+
+# gGhHlnNpPqrstwxy:=
+# s///#comment
+# abcdDi
+
+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 "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 "c {range}" "sed -e '2,4{c blah' -e '}'" \
+	"one\nblah\nblah\nblah\nfive\nsix" \
+        "" "one\ntwo\nthree\nfour\nfive\nsix"
+testing "c multiple continuation" \
+	"sed -e 'c\\' -e 'two\\' -e ''" "two\n\n" "" "hello"
+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 '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' \
+#	'one\nyes really\n' '' 'one\n'
+
+# all the s/// test
+
+testing "match empty line" "sed -e 's/^\$/@/'" "@\n" "" "\n"
+
+testing '\1' "sed 's/t\\(w\\)o/za\\1py/'" "one\nzawpy\nthree" "" \
+	"one\ntwo\nthree"
+testing '\1 p' "sed 's/t\\(w\\)o/za\\1py/p'" "one\nzawpy\nzawpy\nthree" \
+	"" "one\ntwo\nthree"
+testing '\1 no newline' "sed 's/t\\(w\\)o/za\\1py/'" "one\nzawpy" "" \
+	"one\ntwo"
+testing '\1 p no newline' "sed 's/t\\(w\\)o/za\\1py/p'" \
+	"one\nzawpy\nzawpy" "" "one\ntwo"
+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 'backref error' \
+	"sed 's/w/ale \2 ha/' >/dev/null 2>/dev/null || echo no" \
+	"no\n" "" "one\ntwo\nthree"
+testing 'empty match after nonempty match' "sed -e 's/a*/c/g'" 'cbcncgc' \
+	'' 'baaang'
+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 'N flushes pending a and advances match counter' \
+	"sed -e 'a woo' -e 'N;\$p'" 'woo\none\ntwo\none\ntwo' "" 'one\ntwo'
+testing "delimiter in regex [char range] doesn't count" "sed -e 's/[/]//'" \
+	"onetwo\n" "" 'one/two\n'
+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 "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"
+
+# Different ways of parsing line continuations
+
+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 "[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 "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 "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
diff --git a/toybox/tests/seq.test b/toybox/tests/seq.test
new file mode 100755
index 0000000..7107978
--- /dev/null
+++ b/toybox/tests/seq.test
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+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 "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 "two arguments equal, arbitrary positive step" "seq 1 +15 1" \
+        "1\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 "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 "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 "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 "filter reject -f '$i'" \
+    "seq -f '$i' 1 3 2>/dev/null || echo no" "no\n" "" ""
+done
diff --git a/toybox/tests/setfattr.test b/toybox/tests/setfattr.test
new file mode 100755
index 0000000..6a044ea
--- /dev/null
+++ b/toybox/tests/setfattr.test
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+mkdir attrs
+touch attrs/file
+setfattr -n user.empty attrs/file
+setfattr -n user.data -v hello attrs/file
+setfattr -n user.delete-me -v hello attrs/file
+
+testing "-x" \
+    "setfattr -x user.delete-me attrs/file && getfattr attrs/file" \
+    "# file: attrs/file\nuser.data\nuser.empty\n\n" "" ""
+testing "-n" "setfattr -n user.new attrs/file && getfattr -d attrs/file" \
+    "# file: attrs/file\nuser.data=\"hello\"\nuser.empty\nuser.new\n\n" "" ""
+testing "-n -v" "setfattr -n user.new -v data attrs/file && getfattr -d attrs/file" \
+    "# file: attrs/file\nuser.data=\"hello\"\nuser.empty\nuser.new=\"data\"\n\n" "" ""
+
+rm -rf attrs
diff --git a/toybox/tests/sh.test b/toybox/tests/sh.test
new file mode 100755
index 0000000..4f1ecb2
--- /dev/null
+++ b/toybox/tests/sh.test
@@ -0,0 +1,55 @@
+#!/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' '' ''
diff --git a/toybox/tests/sha1sum.test b/toybox/tests/sha1sum.test
new file mode 100755
index 0000000..b4d4b75
--- /dev/null
+++ b/toybox/tests/sha1sum.test
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# These tests are based on RFC3174 which were based on FIPS PUB 180-1
+
+testing "TEST1" \
+        "sha1sum" \
+        "a9993e364706816aba3e25717850c26c9cd0d89d  -\n" \
+        "" "abc"
+
+testing "TEST2" \
+        "sha1sum" \
+        "84983e441c3bd26ebaae4aa1f95129e5e54670f1  -\n" \
+        "" "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+
+testing "TEST3" \
+        'dd if=/dev/zero bs=1000 count=1000 2>/dev/null | tr \\0 a | sha1sum' \
+        "34aa973cd4c4daa4f61eeb2bdbad27316534016f  -\n" \
+        "" ""
+
+testing "TEST4" \
+        'for i in `seq 1 10`; do echo -n 0123456701234567012345670123456701234567012345670123456701234567 ; done | sha1sum' \
+        "dea356a2cddd90c7a7ecedc5ebb563934f460452  -\n" \
+        "" ""
+
+echo -n "abc" > file1
+echo -n "def" > file2
+testing "sha1sum" \
+        "sha1sum" \
+        "a9993e364706816aba3e25717850c26c9cd0d89d  -\n" \
+        "" "abc"
+
+testing "-" \
+        "sha1sum -" \
+        "a9993e364706816aba3e25717850c26c9cd0d89d  -\n" \
+        "" "abc"
+
+testing "file" \
+        "sha1sum file1" \
+        "a9993e364706816aba3e25717850c26c9cd0d89d  file1\n" \
+        "" ""
+
+testing "file1 file2" \
+        "sha1sum file1 file2" \
+        "a9993e364706816aba3e25717850c26c9cd0d89d  file1\n589c22335a381f122d129225f5c0ba3056ed5811  file2\n" \
+        "" ""
+
+testing "file1 file2 -" \
+        "sha1sum file1 file2 -" \
+        "a9993e364706816aba3e25717850c26c9cd0d89d  file1\n589c22335a381f122d129225f5c0ba3056ed5811  file2\na9993e364706816aba3e25717850c26c9cd0d89d  -\n" \
+        "" "abc"
+
+rm -f file1 file2
+
diff --git a/toybox/tests/sort.test b/toybox/tests/sort.test
new file mode 100755
index 0000000..cda3db5
--- /dev/null
+++ b/toybox/tests/sort.test
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+# SUSv4 compliant sort tests.
+# Copyright 2005, 2012 by Rob Landley <rob@landley.net>
+
+[ -f testing.sh ] && . testing.sh
+
+# The basic tests.  These should work even with the small config.
+
+testing "sort" "sort input" "a\nb\nc\n" "c\na\nb\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.
+
+optional SORT_BIG
+# Longish chunk of data re-used by the next few tests.  The expected output
+# varies, but the input (this) is the same.
+
+data="42	1	3	woot
+42	1	010	zoology
+egg	1	2	papyrus
+7	3	42	soup
+999	3	0	algebra
+"
+
+# Sorting with keys
+
+testing "one key" "sort -k4,4 input" \
+"999	3	0	algebra
+egg	1	2	papyrus
+7	3	42	soup
+42	1	3	woot
+42	1	010	zoology
+" "$data" ""
+
+# The numeric sort orders field 2, ignores field 3 (because numeric sort stops
+# at the whitespace), then the global fallback sort does an alpha sort on
+# the whole string (starting at the beginning of the line).
+
+testing "key range with numeric option" "sort -k2,3n input" \
+"42	1	010	zoology
+42	1	3	woot
+egg	1	2	papyrus
+7	3	42	soup
+999	3	0	algebra
+" "$data" ""
+
+# 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 "key range with numeric option and global reverse" \
+"sort -k2,3n -r input" \
+"egg	1	2	papyrus
+42	1	3	woot
+42	1	010	zoology
+999	3	0	algebra
+7	3	42	soup
+" "$data" ""
+
+# Reversed numeric sort on field 2 (numeric ignores field 3), then
+# break ties with alpha sort on whole line.
+
+testing "key range with multiple options" "sort -k2,3rn input" \
+"7	3	42	soup
+999	3	0	algebra
+42	1	010	zoology
+42	1	3	woot
+egg	1	2	papyrus
+" "$data" ""
+
+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 "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
+" "" "/usr/lib/finish-install.d/1
+/usr/lib/prebaseconfig.d/2
+/usr/lib/finish-install.d/4
+/usr/lib/prebaseconfig.d/6
+"
+
+testing "-x" "sort -x" "010\na0\n 0c0\n" "" "a0\n010\n 0c0\n"
+
+# Test that -f applies to key or fallback independently
+
+testing "" "sort -k2,2f" "A b b\na B C\na B a\n" "" "a B a\nA b b\na B C\n"
+testing "" "sort -k2,2" "a B C\na B a\nA b b\n" "" "a B a\nA b b\na B C\n"
+testing "" "sort -f -k2,2" "A b b\na B C\na B a\n" "" "a B a\nA b b\na B C\n" 
+
+optional SORT_FLOAT
+
+# not numbers < NaN < -infinity < numbers < +infinity
+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"
+
+
diff --git a/toybox/tests/split.test b/toybox/tests/split.test
new file mode 100755
index 0000000..2a27c09
--- /dev/null
+++ b/toybox/tests/split.test
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "split" "seq 1 12345 | split && ls xa[a-z] | wc -l" "13\n" "" ""
+rm xa[a-z]
+
+testing "-" "seq 1 12345 | split - && ls xa[a-z] | wc -l" "13\n" "" ""
+rm xa[a-z]
+
+seq 1 12345 > file
+testing "file" "split file && ls xa[a-z] | wc -l" "13\n" "" ""
+rm xa[a-z]
+
+testing "-l" "split file -l 10k && wc -l xab" "2105 xab\n" "" ""
+rm xa[ab]
+
+testing "suffix exhaustion" \
+  "split file -l 10 -a 1 walrus 2>/dev/null || ls walrus* | wc -l" "26\n" "" ""
+rm walrus*
+
+testing "bytes" \
+  "toybox seq 1 20000 | split -b 100 -a 3 - whang && ls whang* | wc -l && wc -c whangbpw" "1089\n94 whangbpw\n" "" ""
+
+testing "reassembly" \
+  'diff -u <(ls whang* | sort | xargs cat) <(seq 1 20000) && echo yes' \
+  "yes\n" "" ""
+
+rm file whang*
diff --git a/toybox/tests/tac.test b/toybox/tests/tac.test
new file mode 100755
index 0000000..5c095b4
--- /dev/null
+++ b/toybox/tests/tac.test
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+
+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 - && 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 "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 "no trailing newline" "tac -" "defabc\n" "" "abc\ndef"
+
+# xputs used by tac does not propagate this error condition properly. 
+#testing "> /dev/full" \
+#        "tac - > /dev/full 2>stderr && echo ok; cat stderr; rm stderr" \
+#        "tac: write: No space left on device\n" "" "zero\n"
+
+# 
+
+rm file1 file2
\ No newline at end of file
diff --git a/toybox/tests/tail.test b/toybox/tests/tail.test
new file mode 100755
index 0000000..81dc871
--- /dev/null
+++ b/toybox/tests/tail.test
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+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 "file" "tail file1" \
+	"two\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\neleven\n" "" ""
+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 "-n+ outof bounds" "tail -n +999 file1" "" "" ""
+testing "-c in bounds" "tail -c 27 file1" \
+	"even\neight\nnine\nten\neleven\n" "" ""
+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 "-c+ out of bonds" "tail -c +999 file1" "" "" ""
+testing "-N" "tail -1 file1" "eleven\n" "" ""
+rm file1
+
+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 "noseek -n in bounds" "tail -n 3" "nine\nten\neleven\n" \
+	"" "$BIGTEST"
+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 "noseek -n+ outof bounds" "tail -n +999" "" "" "$BIGTEST"
+testing "noseek -c in bounds" "tail -c 27" \
+	"even\neight\nnine\nten\neleven\n" "" "$BIGTEST"
+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 "noseek -c+ out of bonds" "tail -c +999" "" "" "$BIGTEST"
+
+makebigfile()
+{
+
+  for j in $(seq 1 100)
+  do
+    printf "%s " $j
+    for i in $(seq 1 100)
+    do
+      printf %s 123456789abcefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+    done
+    echo
+  done
+}
+makebigfile > bigfile
+
+testing "-c 12345 -n 3 bigfile" "tail -c 12345 -n 3 bigfile | md5sum" \
+  "347bbdcbad8a313f4dc7bd558c5bfcb8  -\n" "" ""
+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
diff --git a/toybox/tests/tar.test b/toybox/tests/tar.test
new file mode 100755
index 0000000..80ba555
--- /dev/null
+++ b/toybox/tests/tar.test
@@ -0,0 +1,90 @@
+#!/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"
+
+#Creating  dir
+mkdir dir/dir1 -p
+echo "This is testdata" > dir/dir1/file
+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.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 "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 "- 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 "- 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 "-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 
+mkdir -p dir/dir1 dir/dir2 dir/dir3 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
+echo -ne "dir/dir4\ndir/dir3/file2\n" > exclude_file
+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 "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 "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 
+mkdir dir/dir1 -p ;  mkdir dir/dir2 ;  mkdir dir/dir3 ; mkdir dir/dir4 ; mkdir temp_dir
+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 "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 "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 "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 "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 "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" "" ""
diff --git a/toybox/tests/test.test b/toybox/tests/test.test
new file mode 100755
index 0000000..40a9086
--- /dev/null
+++ b/toybox/tests/test.test
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# TODO: Should also have device and socket files
+
+mkdir d
+touch f
+ln -s /dev/null L
+echo nonempty > s
+mkfifo p
+
+type_test()
+{
+  result=""
+  for i in d f L s p n
+  do
+    if test $* $i
+    then
+      result=$result$i
+    fi
+  done
+  printf "%s" $result
+}
+
+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 "-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 -1 $1 1 && echo l
+  test 0 $1 0 && echo e
+  test -3 $1 -5 && echo g
+}
+
+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 \)
+# test \( ! = \) -o a
diff --git a/toybox/tests/test_human_readable.test b/toybox/tests/test_human_readable.test
new file mode 100755
index 0000000..0f1bfb7
--- /dev/null
+++ b/toybox/tests/test_human_readable.test
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+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 "test_human_readable" "test_human_readable 267350" "261K\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" "" ""
diff --git a/toybox/tests/top.test b/toybox/tests/top.test
new file mode 100755
index 0000000..11eea33
--- /dev/null
+++ b/toybox/tests/top.test
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "batch termination" "top -b -n1 | tail -c 1" "\n" "" ""
diff --git a/toybox/tests/touch.test b/toybox/tests/touch.test
new file mode 100755
index 0000000..d193d7c
--- /dev/null
+++ b/toybox/tests/touch.test
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "touch" "touch walrus && [ -e walrus ] && echo yes" "yes\n" "" ""
+testing "1 2 3" "touch one two three && rm one two three && echo yes" "yes\n" \
+  "" ""
+testing "-c" "touch -c walrus && [ -e walrus ] && echo yes" "yes\n" "" ""
+testing "-c missing" "touch -c warrus && [ ! -e warrus ] && echo yes" \
+  "yes\n" "" ""
+
+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 "-d nanoseconds" \
+  "touch -d 2009-02-13T23:31:30.123456789Z walrus && date -r walrus +%s.%N" \
+  "1234567890.123456789\n" "" ""
+
+testing "-r" \
+  "touch -r walrus walrus2 && date -r walrus2 +%s.%N" \
+   "1234567890.123456789\n" "" ""
+
+#testing "-a"
+#testing "-m"
+#testing "-am"
+#testing "-t"
+rm walrus walrus2
diff --git a/toybox/tests/truncate.test b/toybox/tests/truncate.test
new file mode 100755
index 0000000..1d19aa1
--- /dev/null
+++ b/toybox/tests/truncate.test
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+SIZE='&& stat -c %s 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 -s 1k freep && truncate -s +1k freep $SIZE" \
+	"2048\n" "" ""
+testing "-" "truncate -s 4k freep && truncate -s -1k freep $SIZE" \
+	"3072\n" "" ""
+testing "< hit" \
+	"truncate -s 5k freep && truncate -s \<4k freep $SIZE" "4096\n" "" ""
+testing "< miss" \
+	"truncate -s 4k freep && truncate -s \<6k freep $SIZE" "4096\n" "" ""
+testing "> hit" \
+	"truncate -s 3k freep && truncate -s \>4k freep $SIZE" "4096\n" "" ""
+testing "> miss" \
+	"truncate -s 4k freep && truncate -s \>2k freep $SIZE" "4096\n" "" ""
+testing "/" "truncate -s 7k freep && truncate -s /3k freep $SIZE" \
+	"6144\n" "" ""
+testing "%" "truncate -s 7k freep && truncate -s %3k freep $SIZE" \
+	"9216\n" "" ""
diff --git a/toybox/tests/useradd.test b/toybox/tests/useradd.test
new file mode 100755
index 0000000..d0b68ee
--- /dev/null
+++ b/toybox/tests/useradd.test
@@ -0,0 +1,104 @@
+#!/bin/bash
+
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+
+[ -f testing.sh ] && . testing.sh
+
+if [ "$(id -u)" -ne 0 ]
+then
+  echo "$SHOWSKIP: useradd (not root)"
+  continue 2>/dev/null
+  exit
+fi
+
+# Redirecting all output to /dev/null for grep, adduser and deluser
+arg="&>/dev/null"
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Default password for adding user is: 'password'
+pass=`echo -ne 'password\npassword\n'`
+
+user="toyTestUser"
+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 "(alphanumeric)" "useradd $user $arg ||
+   grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
+
+user="987654321"
+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 "(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 "(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 "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 "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 "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 "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 "(system user)" "useradd -S $user $arg ||
+   grep '^$user:.*:.*:.*' /etc/passwd $arg && [ ! -e /home/$user ] && 
+   echo 'yes'" "yes\n" "" "$pass"   
+userdel -r $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 "-H" "useradd -H $user $arg ||
+   grep '^$user:.*:.*:.*' /etc/passwd $arg && [ ! -e /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $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 "-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
+
diff --git a/toybox/tests/uudecode.test b/toybox/tests/uudecode.test
new file mode 100755
index 0000000..2c3bba6
--- /dev/null
+++ b/toybox/tests/uudecode.test
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "uu empty file" "uudecode -o /dev/stdout && echo yes" \
+	"yes\n" "" "begin 744 test\n\`\nend\n"
+testing "uu 1-char" "uudecode -o /dev/stdout" "a" "" \
+	"begin 744 test\n!80  \n\`\nend\n"
+testing "uu 2-char" "uudecode -o /dev/stdout" "ab" "" \
+	"begin 744 test\n\"86( \n\`\nend\n"
+testing "uu 3-char" "uudecode -o /dev/stdout" "abc" "" \
+	"begin 744 test\n#86)C\n\`\nend\n" 
+
+testing "b64 empty file" "uudecode -o /dev/stdout && echo yes" \
+        "yes\n" "" "begin-base64 744 test\n====\n" 
+testing "b64 1-char" "uudecode -o /dev/stdout" "a" "" \
+	"begin-base64 744 test\nYQ==\n====\n"
+testing "b64 2-char" "uudecode -o /dev/stdout" "ab" "" \
+	"begin-base64 744 test\nYWI=\n====\n"
+testing "b64 3-char" "uudecode -o /dev/stdout" "abc" "" \
+	"begin-base64 744 test\nYWJj\n====\n"
+
+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"
+
diff --git a/toybox/tests/uuencode.test b/toybox/tests/uuencode.test
new file mode 100755
index 0000000..b2a61dc
--- /dev/null
+++ b/toybox/tests/uuencode.test
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "not enough args [fail]" "uuencode 2>/dev/null" "" "" ""
+
+testing "uu empty file" "uuencode test" \
+	"begin 744 test\nend\n" "" "" 
+testing "uu 1-char" "uuencode test" \
+	"begin 744 test\n!80\`\`\nend\n" "" "a" 
+testing "uu 2-char" "uuencode test" \
+	"begin 744 test\n\"86(\`\nend\n" "" "ab" 
+testing "uu 3-char" "uuencode test" \
+	"begin 744 test\n#86)C\nend\n" "" "abc" 
+
+testing "b64 empty file" "uuencode -m test" \
+	"begin-base64 744 test\n====\n" "" "" 
+testing "b64 1-char" "uuencode -m test" \
+	"begin-base64 744 test\nYQ==\n====\n" "" "a" 
+testing "b64 2-char" "uuencode -m test" \
+	"begin-base64 744 test\nYWI=\n====\n" "" "ab" 
+testing "b64 3-char" "uuencode -m test" \
+	"begin-base64 744 test\nYWJj\n====\n" "" "abc" 
+
diff --git a/toybox/tests/wc.test b/toybox/tests/wc.test
new file mode 100755
index 0000000..d227b9c
--- /dev/null
+++ b/toybox/tests/wc.test
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+cat >file1 <<EOF
+some words	. 
+
+some
+lines
+EOF
+
+testing "wc" "wc >/dev/null && echo yes" "yes\n" "" ""
+testing "empty file" "wc" "      0       0       0\n" "" ""
+testing "standard input" "wc" "      1       3       5\n" "" "a b\nc"
+testing "-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
+then
+
+printf " " > file1
+for i in $(seq 1 8192)
+do
+  printf "ü" >> file1
+done
+testing "-m" "wc -m file1" "8193 file1\n" "" ""
+testing "-m 2" 'cat "$FILES/utf8/test2.txt" | wc -m' "169\n" "" ""
+printf " " > file1
+for i in $(seq 1 8192)
+do
+  printf "ü" >> file1
+done
+testing "-m (invalid chars)" "wc -m file1" "8193 file1\n" "" ""
+NOSPACE=1 testing "-mlw" "wc -mlw input" " 1 2 11 input\n" "hello, 世界!\n" ""
+
+else
+printf "skipping tests for wc -m"
+fi
+
+rm file1
diff --git a/toybox/tests/xargs.test b/toybox/tests/xargs.test
new file mode 100755
index 0000000..966bc5d
--- /dev/null
+++ b/toybox/tests/xargs.test
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "xargs" "xargs && echo yes" "hello\nyes\n" "" "hello"
+testing "spaces" "xargs" \
+	"one two three four\n" "" "one two\tthree  \nfour\n\n"
+
+testing "-n 0" "xargs -n 0 2>/dev/null || echo ok" "ok\n" \
+	"" "one \ntwo\n 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 "-s too long" "xargs -s 9 echo 2>/dev/null || echo ok" \
+	"one\ntwo\nok\n" "" "one two 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 "command -opt" "xargs -n2 ls -1" "one\ntwo\nthree\n" "" \
+	"one two three"
+rm one two three
+
+#testing "-n exact match"
+#testing "-s exact match"
+#testing "-s 0"
+#testing "-s impossible"
+
+# xargs command_not_found - returns 127
+# xargs false - returns 1
diff --git a/toybox/tests/xxd.test b/toybox/tests/xxd.test
new file mode 100644
index 0000000..5f43b8b
--- /dev/null
+++ b/toybox/tests/xxd.test
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+echo "this is some text" > file1
+echo -n > file2
+
+# Note that the xxd in vim-common on Ubuntu 14 uses %07x for the file offset.
+
+testing "file1" "xxd file1" \
+    "00000000: 7468 6973 2069 7320 736f 6d65 2074 6578  this is some tex\n00000010: 740a                                     t.\n" \
+    "" ""
+testing "file1 -l" "xxd -l 2 file1" \
+    "00000000: 7468                                     th\n" \
+    "" ""
+testing "file2" "xxd file2" "" "" ""
+testing "-" "xxd -" \
+    "00000000: 6865 6c6c 6f                             hello\n" "" "hello"
+testing "xxd" "xxd" \
+    "00000000: 776f 726c 64                             world\n" "" "world"
+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 "-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 "-p" "xxd -p file1" "7468697320697320736f6d6520746578740a\n" "" ""
+
+testing "-s" "xxd -s 13 file1" "0000000d: 7465 7874 0a                             text.\n" "" ""
+
+testing "-r" "xxd file1 | xxd -r" "this is some text\n" "" ""
+testing "-r -p" "xxd -p file1 | xxd -r -p" "this is some text\n" "" ""
+
+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 "-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 "-r -p long" \
+    "echo '40404040404040404040404040404040404040404040404040404040404040404040404040404040' | xxd -r -p -" \
+    "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" "" ""
+
+rm file1 file2
diff --git a/toybox/tests/xzcat.test b/toybox/tests/xzcat.test
new file mode 100755
index 0000000..4aaf35f
--- /dev/null
+++ b/toybox/tests/xzcat.test
@@ -0,0 +1,26 @@
+#!/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.xz file
+# Get system xzcat
+xzcatExe=`which xzcat`
+$xzcatExe file.xz > xzcatOut
+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
+echo "hi" > file2
+echo "Hi, Good morning !! I am a xzcat tester" > file3
+tar -cJf file1.xz file1
+tar -cJf file2.xz file2
+tar -cJf file3.xz file3
+# Get system xzcat
+xzcatExe=`which xzcat`
+$xzcatExe file1.xz file2.xz file3.xz > xzcatOut
+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" "" ""
diff --git a/toybox/tests/zcat.test b/toybox/tests/zcat.test
new file mode 100755
index 0000000..ccd472c
--- /dev/null
+++ b/toybox/tests/zcat.test
@@ -0,0 +1,26 @@
+#!/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 -czf file.gz file
+# Get system zcat
+zcatExe=`which zcat`
+$zcatExe file.gz > zcatOut
+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
+echo "hi" > file2
+echo "Hi, Good morning !! I am a bzcat tester" > file3
+tar -czf file1.gz file1
+tar -czf file2.gz file2
+tar -czf file3.gz file3
+# Get system zcat
+zcatExe=`which zcat`
+$zcatExe file1.gz file2.gz file3.gz > zcatOut
+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" "" ""
diff --git a/toybox/toys.h b/toybox/toys.h
new file mode 100644
index 0000000..414f439
--- /dev/null
+++ b/toybox/toys.h
@@ -0,0 +1,128 @@
+/* Toybox infrastructure.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+// Stuff that needs to go before the standard headers
+
+#include "generated/config.h"
+#include "lib/portability.h"
+
+// General posix-2008 headers
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <math.h>
+#include <pwd.h>
+#include <regex.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+
+// Posix networking
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+// Internationalization support (also in POSIX and LSB)
+
+#include <locale.h>
+#include <wchar.h>
+#include <wctype.h>
+
+// LSB 4.1 headers
+#include <pty.h>
+#include <sys/ioctl.h>
+#include <sys/statfs.h>
+#include <sys/sysinfo.h>
+
+#include "lib/lib.h"
+#include "lib/lsm.h"
+#include "lib/toyflags.h"
+#include "toys/e2fs.h"
+
+// Get list of function prototypes for all enabled command_main() functions.
+
+#define NEWTOY(name, opts, flags) void name##_main(void);
+#define OLDTOY(name, oldname, flags) void oldname##_main(void);
+#include "generated/newtoys.h"
+#include "generated/flags.h"
+#include "generated/globals.h"
+#include "generated/tags.h"
+
+// These live in main.c
+
+struct toy_list *toy_find(char *name);
+void toy_init(struct toy_list *which, char *argv[]);
+void toy_exec(char *argv[]);
+
+// Array of available commands
+
+extern struct toy_list {
+  char *name;
+  void (*toy_main)(void);
+  char *options;
+  int flags;
+} toy_list[];
+
+// Global context shared by all commands.
+
+extern struct toy_context {
+  struct toy_list *which;  // Which entry in toy_list is this one?
+  char **argv;             // Original command line arguments
+  char **optargs;          // Arguments left over from get_optflags()
+  unsigned long long optflags; // Command line option flags from get_optflags()
+  int exitval;             // Value error_exit feeds to exit()
+  int optc;                // Count of optargs
+  int old_umask;           // Old umask preserved by TOYFLAG_UMASK
+  short toycount;          // Total number of commands in this build
+  short signal;            // generic_signal() records what signal it saw here
+  int signalfd;            // and writes signal to this fd, if set
+  int wasroot;             // dropped setuid
+
+  // 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;
+
+// Two big temporary buffers: one for use by commands, one for library functions
+
+extern char toybuf[4096], libbuf[4096];
+
+extern char **environ;
+
+#define GLOBALS(...)
+#define ARRAY_LEN(array) (sizeof(array)/sizeof(*array))
+#define TAGGED_ARRAY(X, ...) {__VA_ARGS__}
diff --git a/toybox/toys/android/README b/toybox/toys/android/README
new file mode 100644
index 0000000..d471a20
--- /dev/null
+++ b/toybox/toys/android/README
@@ -0,0 +1,5 @@
+Android
+
+Commands primarily used by Android, not vanilla Linux. (Also SELinux stuff.)
+
+Bug Elliott Hughes <enh@google.com> about this.
diff --git a/toybox/toys/android/getenforce.c b/toybox/toys/android/getenforce.c
new file mode 100644
index 0000000..b828ce5
--- /dev/null
+++ b/toybox/toys/android/getenforce.c
@@ -0,0 +1,29 @@
+/* getenforce.c - Get the current SELinux mode
+ *
+ * Copyright 2014 The Android Open Source Project
+
+USE_GETENFORCE(NEWTOY(getenforce, ">0", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config GETENFORCE
+  bool "getenforce"
+  default y
+  depends on TOYBOX_SELINUX
+  help
+    usage: getenforce
+
+    Shows whether SELinux is disabled, enforcing, or permissive.
+*/
+
+#define FOR_getenforce
+#include "toys.h"
+
+void getenforce_main(void)
+{
+  if (!is_selinux_enabled()) puts("Disabled");
+  else {
+    int ret = security_getenforce();
+
+    if (ret == -1) perror_exit("Couldn't get enforcing status");
+    else puts(ret ? "Enforcing" : "Permissive");
+  }
+}
diff --git a/toybox/toys/android/getprop.c b/toybox/toys/android/getprop.c
new file mode 100644
index 0000000..9675d9f
--- /dev/null
+++ b/toybox/toys/android/getprop.c
@@ -0,0 +1,112 @@
+/* getprop.c - Get an Android system property
+ *
+ * Copyright 2015 The Android Open Source Project
+
+USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config GETPROP
+  bool "getprop"
+  default y
+  depends on TOYBOX_ON_ANDROID
+  help
+    usage: getprop [NAME [DEFAULT]]
+
+    Gets an Android system property, or lists them all.
+*/
+
+#define FOR_getprop
+#include "toys.h"
+
+#if defined(__ANDROID__)
+
+#include <cutils/properties.h>
+
+#include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
+
+GLOBALS(
+  size_t size;
+  char **nv; // name/value pairs: even=name, odd=value
+  struct selabel_handle *handle;
+)
+
+static char *get_property_context(char *property)
+{
+  char *context = NULL;
+
+  if (selabel_lookup(TT.handle, &context, property, 1)) {
+    perror_exit("unable to lookup label for \"%s\"", property);
+  }
+  return context;
+}
+
+static void add_property(char *name, char *value, void *unused)
+{
+  if (!(TT.size&31)) TT.nv = xrealloc(TT.nv, (TT.size+32)*2*sizeof(char *));
+
+  TT.nv[2*TT.size] = xstrdup(name);
+  if (toys.optflags & FLAG_Z) {
+    TT.nv[1+2*TT.size++] = get_property_context(name);
+  } else {
+    TT.nv[1+2*TT.size++] = xstrdup(value);
+  }
+}
+
+// Needed to supress extraneous "Loaded property_contexts from" message
+static int selinux_log_callback_local(int type, const char *fmt, ...)
+{
+  va_list ap;
+
+  if (type == SELINUX_INFO) return 0;
+  va_start(ap, fmt);
+  verror_msg(fmt, 0, ap);
+  va_end(ap);
+  return 0;
+}
+
+void getprop_main(void)
+{
+  if (toys.optflags & FLAG_Z) {
+    union selinux_callback cb;
+
+    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");
+  }
+
+  if (*toys.optargs) {
+    if (toys.optflags & FLAG_Z) {
+      char *context = get_property_context(*toys.optargs);
+
+      puts(context);
+      if (CFG_TOYBOX_FREE) free(context);
+    } else {
+      property_get(*toys.optargs, toybuf, toys.optargs[1] ? toys.optargs[1] : "");
+      puts(toybuf);
+    }
+  } else {
+    size_t i;
+
+    if (property_list((void *)add_property, 0)) error_exit("property_list");
+    qsort(TT.nv, TT.size, 2*sizeof(char *), qstrcmp);
+    for (i = 0; i<TT.size; i++) printf("[%s]: [%s]\n", TT.nv[i*2],TT.nv[1+i*2]);
+    if (CFG_TOYBOX_FREE) {
+      for (i = 0; i<TT.size; i++) {
+        free(TT.nv[i*2]);
+        free(TT.nv[1+i*2]);
+      }
+      free(TT.nv);
+    }
+  }
+  if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_Z)) selabel_close(TT.handle);
+}
+
+#else
+
+void getprop_main(void)
+{
+}
+
+#endif
diff --git a/toybox/toys/android/load_policy.c b/toybox/toys/android/load_policy.c
new file mode 100644
index 0000000..d9ff148
--- /dev/null
+++ b/toybox/toys/android/load_policy.c
@@ -0,0 +1,31 @@
+/* load_policy.c - Load a policy file
+ *
+ * Copyright 2015 The Android Open Source Project
+
+USE_LOAD_POLICY(NEWTOY(load_policy, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config LOAD_POLICY
+  bool "load_policy"
+  depends on TOYBOX_SELINUX
+  default y
+  help
+    usage: load_policy FILE
+
+    Load the specified policy file.
+*/
+
+#define FOR_load_policy
+#include "toys.h"
+
+void load_policy_main(void)
+{
+  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", *toys.optargs);
+
+  munmap(policy_data, policy_len);
+}
diff --git a/toybox/toys/android/log.c b/toybox/toys/android/log.c
new file mode 100644
index 0000000..7da37b6
--- /dev/null
+++ b/toybox/toys/android/log.c
@@ -0,0 +1,58 @@
+/* log.c - Log to logcat.
+ *
+ * Copyright 2016 The Android Open Source Project
+
+USE_LOG(NEWTOY(log, "<1p:t:", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config LOG
+  bool "log"
+  depends on TOYBOX_ON_ANDROID
+  default y
+  help
+    usage: log [-p PRI] [-t TAG] MESSAGE...
+
+    Logs message to logcat.
+
+    -p	use the given priority instead of INFO:
+    	d: DEBUG  e: ERROR  f: FATAL  i: INFO  v: VERBOSE  w: WARN  s: SILENT
+    -t	use the given tag instead of "log"
+*/
+
+#define FOR_log
+#include "toys.h"
+#include <android/log.h>
+
+GLOBALS(
+  char *tag;
+  char *pri;
+)
+
+void log_main(void)
+{
+  android_LogPriority pri = ANDROID_LOG_INFO;
+  char *s = toybuf;
+  int i;
+
+  if (TT.pri) {
+    i = stridx("defisvw", tolower(*TT.pri));
+    if (i==-1 || strlen(TT.pri)!=1) error_exit("bad -p '%s'", TT.pri);
+    pri = (android_LogPriority []){ANDROID_LOG_DEBUG, ANDROID_LOG_ERROR,
+      ANDROID_LOG_FATAL, ANDROID_LOG_INFO, ANDROID_LOG_SILENT,
+      ANDROID_LOG_VERBOSE, ANDROID_LOG_WARN}[i];
+  }
+  if (!TT.tag) TT.tag = "log";
+
+  for (i = 0; toys.optargs[i]; i++) {
+    if (i) *s++ = ' ';
+    if ((s-toybuf)+strlen(toys.optargs[i])>=1024) {
+      memcpy(s, toys.optargs[i], 1024-(s-toybuf));
+      toybuf[1024] = 0;
+      perror_msg("log cut at 1024 bytes");
+
+      break;
+    }
+    s = stpcpy(s, toys.optargs[i]);
+  }
+
+  __android_log_write(pri, TT.tag, toybuf);
+}
diff --git a/toybox/toys/android/restorecon.c b/toybox/toys/android/restorecon.c
new file mode 100644
index 0000000..5ea6b3f
--- /dev/null
+++ b/toybox/toys/android/restorecon.c
@@ -0,0 +1,47 @@
+/* restorecon.c - Restore default security contexts for files
+ *
+ * Copyright 2015 The Android Open Source Project
+
+USE_RESTORECON(NEWTOY(restorecon, "<1DFnRrv", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config RESTORECON
+  bool "restorecon"
+  depends on TOYBOX_SELINUX
+  default y
+  help
+    usage: restorecon [-D] [-F] [-R] [-n] [-v] FILE...
+
+    Restores the default security contexts for the given files.
+
+    -D	apply to /data/data too
+    -F	force reset
+    -R	recurse into directories
+    -n	don't make any changes; useful with -v to see what would change
+    -v	verbose: show any changes
+*/
+
+#define FOR_restorecon
+#include "toys.h"
+
+#if defined(__ANDROID__)
+#include <selinux/android.h>
+#endif
+
+void restorecon_main(void)
+{
+#if defined(__ANDROID__)
+  char **s;
+  int flags = 0;
+
+  if (toys.optflags & FLAG_D) flags |= SELINUX_ANDROID_RESTORECON_DATADATA;
+  if (toys.optflags & FLAG_F) flags |= SELINUX_ANDROID_RESTORECON_FORCE;
+  if (toys.optflags & (FLAG_R|FLAG_r))
+    flags |= SELINUX_ANDROID_RESTORECON_RECURSE;
+  if (toys.optflags & FLAG_n) flags |= SELINUX_ANDROID_RESTORECON_NOCHANGE;
+  if (toys.optflags & FLAG_v) flags |= SELINUX_ANDROID_RESTORECON_VERBOSE;
+
+  for (s = toys.optargs; *s; s++)
+    if (selinux_android_restorecon(*s, flags) < 0)
+      perror_msg("restorecon failed: %s", *s);
+#endif
+}
diff --git a/toybox/toys/android/runcon.c b/toybox/toys/android/runcon.c
new file mode 100644
index 0000000..8831cbf
--- /dev/null
+++ b/toybox/toys/android/runcon.c
@@ -0,0 +1,28 @@
+/* runcon.c - Run command in specified security context
+ *
+ * Copyright 2015 The Android Open Source Project
+
+USE_RUNCON(NEWTOY(runcon, "<2", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config RUNCON
+  bool "runcon"
+  depends on TOYBOX_SELINUX
+  default y
+  help
+    usage: runcon CONTEXT COMMAND [ARGS...]
+
+    Run a command in a specified security context.
+*/
+
+#define FOR_runcon
+#include "toys.h"
+
+void runcon_main(void)
+{
+  char *context = *toys.optargs;
+
+  if (setexeccon(context)) perror_exit("Could not set context to %s", context);
+
+  toys.stacktop = 0;
+  xexec(++toys.optargs);
+}
diff --git a/toybox/toys/android/sendevent.c b/toybox/toys/android/sendevent.c
new file mode 100644
index 0000000..8e982e0
--- /dev/null
+++ b/toybox/toys/android/sendevent.c
@@ -0,0 +1,37 @@
+/* sendevent.c - Send Linux input events.
+ *
+ * Copyright 2016 The Android Open Source Project
+
+USE_SENDEVENT(NEWTOY(sendevent, "<4>4", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config SENDEVENT
+  bool "sendevent"
+  default y
+  depends on TOYBOX_ON_ANDROID
+  help
+    usage: sendevent DEVICE TYPE CODE VALUE
+
+    Sends a Linux input event.
+*/
+
+#define FOR_sendevent
+#include "toys.h"
+
+#include <linux/input.h>
+
+void sendevent_main(void)
+{
+  int fd = xopen(*toys.optargs, O_RDWR);
+  int version;
+  struct input_event ev;
+
+  if (ioctl(fd, EVIOCGVERSION, &version))
+    perror_exit("EVIOCGVERSION failed for %s", *toys.optargs);
+  
+  memset(&ev, 0, sizeof(ev));
+  // TODO: error checking and support for named constants.
+  ev.type = atoi(toys.optargs[1]);
+  ev.code = atoi(toys.optargs[2]);
+  ev.value = atoi(toys.optargs[3]);
+  xwrite(fd, &ev, sizeof(ev));
+}
diff --git a/toybox/toys/android/setenforce.c b/toybox/toys/android/setenforce.c
new file mode 100644
index 0000000..8194484
--- /dev/null
+++ b/toybox/toys/android/setenforce.c
@@ -0,0 +1,32 @@
+/* setenforce.c - Set the current SELinux mode
+ *
+ * Copyright 2014 The Android Open Source Project
+
+USE_SETENFORCE(NEWTOY(setenforce, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config SETENFORCE
+  bool "setenforce"
+  default y
+  depends on TOYBOX_SELINUX
+  help
+    usage: setenforce [enforcing|permissive|1|0]
+
+    Sets whether SELinux is enforcing (1) or permissive (0).
+*/
+
+#define FOR_setenforce
+#include "toys.h"
+
+void setenforce_main(void)
+{
+  char *new = *toys.optargs;
+  int state, ret;
+
+  if (!is_selinux_enabled()) error_exit("SELinux is disabled");
+  else if (!strcmp(new, "1") || !strcasecmp(new, "enforcing")) state = 1;
+  else if (!strcmp(new, "0") || !strcasecmp(new, "permissive")) state = 0;
+  else error_exit("Invalid state: %s", new);
+
+  ret = security_setenforce(state);
+  if (ret == -1) perror_msg("Couldn't set enforcing status to '%s'", new);
+}
diff --git a/toybox/toys/android/setprop.c b/toybox/toys/android/setprop.c
new file mode 100644
index 0000000..34e0de4
--- /dev/null
+++ b/toybox/toys/android/setprop.c
@@ -0,0 +1,59 @@
+/* setprop.c - Set an Android system property
+ *
+ * Copyright 2015 The Android Open Source Project
+
+USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config SETPROP
+  bool "setprop"
+  default y
+  depends on TOYBOX_ON_ANDROID
+  help
+    usage: setprop NAME VALUE
+
+    Sets an Android system property.
+*/
+
+#define FOR_setprop
+#include "toys.h"
+
+#if defined(__ANDROID__)
+
+#include <cutils/properties.h>
+
+void setprop_main(void)
+{
+  char *name = toys.optargs[0], *value = toys.optargs[1];
+  char *p;
+  size_t name_len = strlen(name), value_len = strlen(value);
+
+  // property_set doesn't tell us why it failed, and actually can't
+  // recognize most failures (because it doesn't wait for init), so
+  // we duplicate all of init's checks here to help the user.
+
+  if (name_len >= PROP_NAME_MAX)
+    error_exit("name '%s' too long; try '%.*s'",
+               name, PROP_NAME_MAX - 1, name);
+  if (value_len >= PROP_VALUE_MAX)
+    error_exit("value '%s' too long; try '%.*s'",
+               value, PROP_VALUE_MAX - 1, value);
+
+  if (*name == '.' || name[name_len - 1] == '.')
+    error_exit("property names must not start or end with '.'");
+  if (strstr(name, ".."))
+    error_exit("'..' is not allowed in a property name");
+  for (p = name; *p; ++p)
+    if (!isalnum(*p) && !strchr("_.-", *p))
+      error_exit("invalid character '%c' in name '%s'", *p, name);
+
+  if (property_set(name, value))
+    error_msg("failed to set property '%s' to '%s'", name, value);
+}
+
+#else
+
+void setprop_main(void)
+{
+}
+
+#endif
diff --git a/toybox/toys/android/start.c b/toybox/toys/android/start.c
new file mode 100644
index 0000000..20fa2b9
--- /dev/null
+++ b/toybox/toys/android/start.c
@@ -0,0 +1,61 @@
+/* start.c - Start/stop system services.
+ *
+ * Copyright 2016 The Android Open Source Project
+
+USE_START(NEWTOY(start, "", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_STOP(NEWTOY(stop, "", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config START
+  bool "start"
+  depends on TOYBOX_ON_ANDROID
+  default y
+  help
+    usage: start [SERVICE...]
+
+    Starts the given system service, or netd/surfaceflinger/zygotes.
+
+config STOP
+  bool "stop"
+  depends on TOYBOX_ON_ANDROID
+  default y
+  help
+    usage: stop [SERVICE...]
+
+    Stop the given system service, or netd/surfaceflinger/zygotes.
+*/
+
+#define FOR_start
+#include "toys.h"
+
+#include <cutils/properties.h>
+
+static void start_stop(int start)
+{
+  char *property = start ? "ctl.start" : "ctl.stop";
+  // null terminated in both directions
+  char *services[] = {0,"netd","surfaceflinger","zygote","zygote_secondary",0},
+       **ss = toys.optargs;
+  int direction = 1;
+
+  if (getuid()) error_exit("must be root");
+
+  if (!*ss) {
+    // If we don't have optargs, iterate through services forward/backward.
+    ss = services+1;
+    if (!start) ss = services+ARRAY_LEN(services)-2, direction = -1;
+  }
+
+  for (; *ss; ss += direction)
+    if (property_set(property, *ss))
+      error_exit("failed to set property '%s' to '%s'", property, *ss);
+}
+
+void start_main(void)
+{
+  start_stop(1);
+}
+
+void stop_main(void)
+{
+  start_stop(0);
+}
diff --git a/toybox/toys/e2fs.h b/toybox/toys/e2fs.h
new file mode 100644
index 0000000..4359411
--- /dev/null
+++ b/toybox/toys/e2fs.h
@@ -0,0 +1,142 @@
+/* mke2fs.h - Headers for ext2
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ */
+
+// Stuff defined in linux/ext2_fs.h
+
+#define EXT2_SUPER_MAGIC  0xEF53
+
+struct ext2_superblock {
+  uint32_t inodes_count;      // Inodes count
+  uint32_t blocks_count;      // Blocks count
+  uint32_t r_blocks_count;    // Reserved blocks count
+  uint32_t free_blocks_count; // Free blocks count
+  uint32_t free_inodes_count; // Free inodes count
+  uint32_t first_data_block;  // First Data Block
+  uint32_t log_block_size;    // Block size
+  uint32_t log_frag_size;     // Fragment size
+  uint32_t blocks_per_group;  // Blocks per group
+  uint32_t frags_per_group;   // Fragments per group
+  uint32_t inodes_per_group;  // Inodes per group
+  uint32_t mtime;             // Mount time
+  uint32_t wtime;             // Write time
+  uint16_t mnt_count;         // Mount count
+  uint16_t max_mnt_count;     // Maximal mount count
+  uint16_t magic;             // Magic signature
+  uint16_t state;             // File system state
+  uint16_t errors;            // Behaviour when detecting errors
+  uint16_t minor_rev_level;   // minor revision level
+  uint32_t lastcheck;         // time of last check
+  uint32_t checkinterval;     // max. time between checks
+  uint32_t creator_os;        // OS
+  uint32_t rev_level;         // Revision level
+  uint16_t def_resuid;        // Default uid for reserved blocks
+  uint16_t def_resgid;        // Default gid for reserved blocks
+  uint32_t first_ino;         // First non-reserved inode
+  uint16_t inode_size;        // size of inode structure
+  uint16_t block_group_nr;    // block group # of this superblock
+  uint32_t feature_compat;    // compatible feature set
+  uint32_t feature_incompat;  // incompatible feature set
+  uint32_t feature_ro_compat; // readonly-compatible feature set
+  char     uuid[16];          // 128-bit uuid for volume
+  char     volume_name[16];   // volume name
+  char     last_mounted[64];  // directory where last mounted
+  uint32_t alg_usage_bitmap;  // For compression
+  // For EXT2_COMPAT_PREALLOC
+  uint8_t  prealloc_blocks;   // Nr of blocks to try to preallocate
+  uint8_t  prealloc_dir_blocks; //Nr to preallocate for dirs
+  uint16_t padding1;
+  // For EXT3_FEATURE_COMPAT_HAS_JOURNAL
+  uint8_t  journal_uuid[16];   // uuid of journal superblock
+  uint32_t journal_inum;       // inode number of journal file
+  uint32_t journal_dev;        // device number of journal file
+  uint32_t last_orphan;        // start of list of inodes to delete
+  uint32_t hash_seed[4];       // HTREE hash seed
+  uint8_t  def_hash_version;   // Default hash version to use
+  uint8_t  padding2[3];
+  uint32_t default_mount_opts;
+  uint32_t first_meta_bg;      // First metablock block group
+  uint32_t mkfs_time;          // Creation timestamp
+  uint32_t jnl_blocks[17];     // Backup of journal inode
+  // uint32_t reserved[172];      // Padding to the end of the block
+};
+
+struct ext2_group
+{
+  uint32_t block_bitmap;       // Block number of block bitmap
+  uint32_t inode_bitmap;       // Block number of inode bitmap
+  uint32_t inode_table;        // Block number of inode table
+  uint16_t free_blocks_count;  // How many free blocks in this group?
+  uint16_t free_inodes_count;  // How many free inodes in this group?
+  uint16_t used_dirs_count;    // How many directories?
+  uint16_t reserved[7];        // pad to 32 bytes
+};
+
+struct ext2_dentry {
+  uint32_t inode;         // Inode number
+  uint16_t rec_len;       // Directory entry length
+  uint8_t  name_len;      // Name length
+  uint8_t  file_type;
+  char     name[0];     // File name
+};
+
+struct ext2_inode {
+  uint16_t mode;        // File mode
+  uint16_t uid;         // Low 16 bits of Owner Uid
+  uint32_t size;        // Size in bytes
+  uint32_t atime;       // Access time
+  uint32_t ctime;       // Creation time
+  uint32_t mtime;       // Modification time
+  uint32_t dtime;       // Deletion Time
+  uint16_t gid;         // Low 16 bits of Group Id
+  uint16_t links_count; // Links count
+  uint32_t blocks;      // Blocks count
+  uint32_t flags;       // File flags
+  uint32_t reserved1;
+  uint32_t block[15];   // Pointers to blocks
+  uint32_t generation;  // File version (for NFS)
+  uint32_t file_acl;    // File ACL
+  uint32_t dir_acl;     // Directory ACL (or top bits of file length)
+  uint32_t faddr;       // Last block in file
+  uint8_t  frag;        // Fragment number
+  uint8_t  fsize;       // Fragment size
+  uint16_t pad1;
+  uint16_t uid_high;    // High bits of uid
+  uint16_t gid_high;    // High bits of gid
+  uint32_t reserved2;
+};
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC	0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES	0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR		0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INO		0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX		0x0020
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG		0x0010
+
+#define EXT2_NAME_LEN 255
+
+// Ext2 directory file types.  Only the low 3 bits are used.  The
+// other bits are reserved for now.
+
+enum {
+  EXT2_FT_UNKNOWN,
+  EXT2_FT_REG_FILE,
+  EXT2_FT_DIR,
+  EXT2_FT_CHRDEV,
+  EXT2_FT_BLKDEV,
+  EXT2_FT_FIFO,
+  EXT2_FT_SOCK,
+  EXT2_FT_SYMLINK,
+  EXT2_FT_MAX
+};
diff --git a/toybox/toys/example/README b/toybox/toys/example/README
new file mode 100644
index 0000000..d0f6631
--- /dev/null
+++ b/toybox/toys/example/README
@@ -0,0 +1,4 @@
+Example commands
+
+You probably don't want to deploy this, but it shows how to use the
+toybox infrastructure and provides templates for new commands.
diff --git a/toybox/toys/example/hello.c b/toybox/toys/example/hello.c
new file mode 100644
index 0000000..3b7d27b
--- /dev/null
+++ b/toybox/toys/example/hello.c
@@ -0,0 +1,35 @@
+/* hello.c - A hello world program. (Simple template for new commands.)
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
+
+USE_HELLO(NEWTOY(hello, 0, TOYFLAG_USR|TOYFLAG_BIN))
+
+config HELLO
+  bool "hello"
+  default n
+  help
+    usage: hello [-s]
+
+    A hello world program.  You don't need this.
+
+    Mostly used as a simple template for adding new commands.
+    Occasionally nice to smoketest kernel booting via "init=/usr/bin/hello".
+*/
+
+#define FOR_hello
+#include "toys.h"
+
+GLOBALS(
+  int unused;
+)
+
+void hello_main(void)
+{
+  xprintf("Hello world\n");
+
+  // Avoid kernel panic if run as init.
+  if (getpid() == 1) wait(&TT.unused);
+}
diff --git a/toybox/toys/example/skeleton.c b/toybox/toys/example/skeleton.c
new file mode 100644
index 0000000..ee67b58
--- /dev/null
+++ b/toybox/toys/example/skeleton.c
@@ -0,0 +1,104 @@
+/* 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>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
+
+// Accept many different kinds of command line argument (see top of lib/args.c)
+// Demonstrate two commands in the same file (see www/documentation.html)
+
+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))
+
+config SKELETON
+  bool "skeleton"
+  default n
+  help
+    usage: skeleton [-a] [-b STRING] [-c NUMBER] [-d LIST] [-e COUNT] [...]
+
+    Template for new commands. You don't need this.
+
+    When creating a new command, copy this file and delete the parts you
+    don't need. Be sure to replace all instances of "skeleton" (upper and lower
+    case) with your new command name.
+
+    For simple commands, "hello.c" is probably a better starting point.
+
+config SKELETON_ALIAS
+  bool "skeleton_alias"
+  default n
+  help
+    usage: skeleton_alias [-dq] [-b NUMBER]
+
+    Example of a second command with different arguments in the same source
+    file as the first. This allows shared infrastructure not added to lib/.
+*/
+
+#define FOR_skeleton
+#include "toys.h"
+
+// The union lets lib/args.c store arguments for either command.
+// It's customary to put a space between argument variables and other globals.
+GLOBALS(
+  union {
+    struct {
+      char *b_string;
+      long c_number;
+      struct arg_list *d_list;
+      long e_count;
+      char *also_string;
+      char *blubber_string;
+    } s;
+    struct {
+      long b_number;
+    } a;
+  };
+
+  int more_globals;
+)
+
+// Don't blindly build allyesconfig. The maximum _sane_ config is defconfig.
+#warning skeleton.c is just an example, not something to deploy.
+
+// Parse many different kinds of command line argument:
+void skeleton_main(void)
+{
+  char **optargs;
+
+  printf("Ran %s\n", toys.which->name);
+
+  // 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=%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);
+  while (TT.s.d_list) {
+    printf("d=%s\n", TT.s.d_list->arg);
+    TT.s.d_list = TT.s.d_list->next;
+  }
+  if (TT.s.e_count) printf("e was seen %ld times\n", TT.s.e_count);
+  for (optargs = toys.optargs; *optargs; optargs++)
+    printf("optarg=%s\n", *optargs);
+  if (toys.optflags & FLAG_walrus) printf("Saw --walrus\n");
+  if (TT.s.blubber_string) printf("--blubber=%s\n", TT.s.blubber_string);
+
+  printf("Other globals should start zeroed: %d\n", TT.more_globals);
+}
+
+// Switch gears from skeleton to skeleton_alias (swap FLAG macros).
+#define CLEANUP_skeleton
+#define FOR_skeleton_alias
+#include "generated/flags.h"
+
+void skeleton_alias_main(void)
+{
+  printf("Ran %s\n", toys.which->name);
+  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.
+  if (toys.optflags & FLAG_b) printf("b=%ld", TT.a.b_number);
+}
diff --git a/toybox/toys/example/test_human_readable.c b/toybox/toys/example/test_human_readable.c
new file mode 100644
index 0000000..9fff262
--- /dev/null
+++ b/toybox/toys/example/test_human_readable.c
@@ -0,0 +1,23 @@
+/* test_human_readable.c - Expose lib/lib.c human_readable() for testing.
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+
+USE_TEST_HUMAN_READABLE(NEWTOY(test_human_readable, "<1>1ibs", TOYFLAG_BIN))
+
+config TEST_HUMAN_READABLE
+  bool "test_human_readable"
+  default n
+  help
+    usage: test_human_readable [-sbi] NUMBER
+*/
+
+#define FOR_test_human_readable
+#include "toys.h"
+
+void test_human_readable_main(void)
+{
+  char *c;
+
+  human_readable(toybuf, strtoll(*toys.optargs, &c, 0), toys.optflags);
+  printf("%s\n", toybuf);
+}
diff --git a/toybox/toys/example/test_many_options.c b/toybox/toys/example/test_many_options.c
new file mode 100644
index 0000000..e071d26
--- /dev/null
+++ b/toybox/toys/example/test_many_options.c
@@ -0,0 +1,22 @@
+/* test_many_options.c - test more than 32 bits worth of option flags
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+
+USE_TEST_MANY_OPTIONS(NEWTOY(test_many_options, "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba", TOYFLAG_BIN))
+
+config TEST_MANY_OPTIONS
+  bool "test_many_options"
+  default n
+  help
+    usage: test_many_options -[a-zA-Z]
+
+    Print the optflags value of the command arguments, in hex.
+*/
+
+#define FOR_test_many_options
+#include "toys.h"
+
+void test_many_options_main(void)
+{
+  xprintf("optflags=%llx\n", toys.optflags);
+}
diff --git a/toybox/toys/example/test_scankey.c b/toybox/toys/example/test_scankey.c
new file mode 100644
index 0000000..db90027
--- /dev/null
+++ b/toybox/toys/example/test_scankey.c
@@ -0,0 +1,80 @@
+/* test_scankey.c - collate incoming ansi escape sequences.
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ *
+ * TODO sigwinch
+
+USE_TEST_SCANKEY(NEWTOY(test_scankey, 0, TOYFLAG_BIN))
+
+config TEST_SCANKEY
+  bool "test_scankey"
+  default n
+  help
+    usage: test_scankey
+
+    Move a letter around the screen. Hit ESC to exit.
+*/
+
+#define FOR_test_scankey
+#include "toys.h"
+
+void test_scankey_main(void)
+{
+  time_t t[2];
+  unsigned width, height, tick;
+  char c = 'X', scratch[16];
+  int key, x, y;
+
+  t[0] = t[1] = x = tick = 0;
+  memset(scratch, 0, 16);
+  y = 1;
+
+  sigatexit(tty_sigreset);  // Make ctrl-c restore tty
+  tty_esc("?25l");          // hide cursor
+  tty_esc("0m");            // reset color to default
+  tty_esc("2J");            // Clear screen
+  xset_terminal(1, 1, 0);    // Raw mode
+
+  for (;;) {
+    tty_jump(x, y);
+    xputc(c);
+    t[1&++tick] = time(0);
+    if (t[0] != t[1]) terminal_probesize(&width, &height);
+    // Don't block first time through, to force header print
+    key = scan_key_getsize(scratch, -1*!!t[0], &width, &height);
+    tty_jump(0, 0);
+    printf("ESC to exit: ");
+    // Print unknown escape sequence
+    if (*scratch) {
+      printf("key=[ESC");
+      // Fetch rest of sequence after deviation, time gap determines end
+      while (0<(key = scan_key_getsize(scratch, 0, &width, &height)))
+        printf("%c", key);
+      printf("] ");
+    } else printf("key=%d ", key);
+    printf("x=%d y=%d width=%d height=%d\033[K", x, y, width, height);
+    fflush(0);
+
+    if (key == -2) continue;
+    if (key <= ' ') break;
+    if (key>=256) {
+      tty_jump(x, y);
+      xputc(' ');
+
+      key -= 256;
+      if (key==KEY_UP) y--;
+      else if (key==KEY_DOWN) y++;
+      else if (key==KEY_RIGHT) x++;
+      else if (key==KEY_LEFT) x--;
+      else if (key==KEY_PGUP) y = 0;
+      else if (key==KEY_PGDN) y = 999;
+      else if (key==KEY_HOME) x = 0;
+      else if (key==KEY_END) x = 999;
+      if (y<1) y = 1;
+      if (y>=height) y = height-1;
+      if (x<0) x = 0;
+      if (x>=width) x = width-1;
+    } else c = key;
+  }
+  tty_reset();
+}
diff --git a/toybox/toys/lsb/README b/toybox/toys/lsb/README
new file mode 100644
index 0000000..9ddd027
--- /dev/null
+++ b/toybox/toys/lsb/README
@@ -0,0 +1,7 @@
+Linux Standard Base commands
+
+Commands defined in the Linux Standard Base 4.1:
+http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
+
+Downloadable as one big file from:
+http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic.html
diff --git a/toybox/toys/lsb/dmesg.c b/toybox/toys/lsb/dmesg.c
new file mode 100644
index 0000000..d608446
--- /dev/null
+++ b/toybox/toys/lsb/dmesg.c
@@ -0,0 +1,71 @@
+/* dmesg.c - display/control kernel ring buffer.
+ *
+ * Copyright 2006, 2007 Rob Landley <rob@landley.net>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html
+
+// We care that FLAG_c is 1, so keep c at the end.
+USE_DMESG(NEWTOY(dmesg, "trs#<1n#c[!tr]", TOYFLAG_BIN))
+
+config DMESG
+  bool "dmesg"
+  default y
+  help
+    usage: dmesg [-c] [-r|-t] [-n LEVEL] [-s SIZE]
+
+    Print or control the kernel ring buffer.
+
+    -c	Clear the ring buffer after printing
+    -n	Set kernel logging LEVEL (1-9)
+    -r	Raw output (with <level markers>)
+    -s	Show the last SIZE many bytes
+    -t	Don't print kernel's timestamps
+*/
+
+#define FOR_dmesg
+#include "toys.h"
+#include <sys/klog.h>
+
+GLOBALS(
+  long level;
+  long size;
+)
+
+void dmesg_main(void)
+{
+  // For -n just tell kernel to which messages to keep.
+  if (toys.optflags & FLAG_n) {
+    if (klogctl(8, NULL, TT.level)) perror_exit("klogctl");
+  } else {
+    char *data, *to, *from;
+    int size;
+
+    // Figure out how much data we need, and fetch it.
+    size = TT.size;
+    if (!size && 1>(size = klogctl(10, 0, 0))) perror_exit("klogctl");;
+    data = to = from = xmalloc(size+1);
+    size = klogctl(3 + (toys.optflags & FLAG_c), data, size);
+    if (size < 0) perror_exit("klogctl");
+    data[size] = 0;
+
+    // Filter out level markers and optionally time markers
+    if (!(toys.optflags & FLAG_r)) while ((from - data) < size) {
+      if (from == data || from[-1] == '\n') {
+        char *to;
+
+        if (*from == '<' && (to = strchr(from, '>'))) from = ++to;
+        if ((toys.optflags&FLAG_t) && *from == '[' && (to = strchr(from, ']')))
+          from = to+1+(to[1]==' ');
+      }
+      *(to++) = *(from++);
+    } else to = data+size;
+
+    // Write result. The odds of somebody requesting a buffer of size 3 and
+    // getting "<1>" are remote, but don't segfault if they do.
+    if (to != data) {
+      xwrite(1, data, to-data);
+      if (to[-1] != '\n') xputc('\n');
+    }
+    if (CFG_TOYBOX_FREE) free(data);
+  }
+}
diff --git a/toybox/toys/lsb/hostname.c b/toybox/toys/lsb/hostname.c
new file mode 100644
index 0000000..f30d1fb
--- /dev/null
+++ b/toybox/toys/lsb/hostname.c
@@ -0,0 +1,51 @@
+/* hostname.c - Get/Set the hostname
+ *
+ * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/hostname.html
+
+USE_HOSTNAME(NEWTOY(hostname, "bF:", TOYFLAG_BIN))
+
+config HOSTNAME
+  bool "hostname"
+  default y
+  help
+    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)
+{
+  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 '%s'", hostname);
+  } else {
+    if (gethostname(toybuf, sizeof(toybuf)-1)) perror_exit("gethostname");
+    xputs(toybuf);
+  }
+}
diff --git a/toybox/toys/lsb/killall.c b/toybox/toys/lsb/killall.c
new file mode 100644
index 0000000..2772b43
--- /dev/null
+++ b/toybox/toys/lsb/killall.c
@@ -0,0 +1,101 @@
+/* killall.c - Send signal (default: TERM) to all processes with given names.
+ *
+ * Copyright 2012 Andreas Heck <aheck@gmx.de>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/killall.html
+
+USE_KILLALL(NEWTOY(killall, "?s:lqvi", TOYFLAG_USR|TOYFLAG_BIN))
+
+config KILLALL
+  bool "killall"
+  default y
+  help
+    usage: killall [-l] [-iqv] [-SIGNAL|-s SIGNAL] PROCESS_NAME...
+
+    Send a signal (default: TERM) to all processes with the given names.
+
+    -i	ask for confirmation before killing
+    -l	print list of all available signals
+    -q	don't print any warnings or error messages
+    -s	send SIGNAL instead of SIGTERM
+    -v	report if the signal was successfully sent
+*/
+
+#define FOR_killall
+#include "toys.h"
+
+GLOBALS(
+  char *sig;
+
+  int signum;
+  pid_t cur_pid;
+  char **names;
+  short *err;
+)
+
+static int kill_process(pid_t pid, char *name)
+{
+  int offset = 0;
+
+  if (pid == TT.cur_pid) return 0;
+
+  if (toys.optflags & FLAG_i) {
+    fprintf(stderr, "Signal %s(%d)", name, (int)pid);
+    if (!yesno(0)) return 0;
+  }
+
+  errno = 0;
+  kill(pid, TT.signum);
+  for (;;) {
+    if (TT.names[offset] == name) {
+      TT.err[offset] = errno;
+      break;
+    } else offset++;
+  }
+  if (errno) {
+    if (!(toys.optflags & FLAG_q)) perror_msg("pid %d", (int)pid);
+  } else if (toys.optflags & FLAG_v)
+    printf("Killed %s(%d) with signal %d\n", name, pid, TT.signum);
+
+  return 0;
+}
+
+void killall_main(void)
+{
+  int i;
+
+  TT.names = toys.optargs;
+  TT.signum = SIGTERM;
+
+  if (toys.optflags & FLAG_l) {
+    sig_to_num(NULL);
+    return;
+  }
+
+  if (TT.sig || (*TT.names && **TT.names == '-')) {
+    if (0 > (TT.signum = sig_to_num(TT.sig ? TT.sig : (*TT.names)+1))) {
+      if (toys.optflags & FLAG_q) exit(1);
+      error_exit("Invalid signal");
+    }
+    if (!TT.sig) {
+      TT.names++;
+      toys.optc--;
+    }
+  }
+
+  if (!(toys.optflags & FLAG_l) && !toys.optc) help_exit("no name");
+
+  TT.cur_pid = getpid();
+
+  TT.err = xmalloc(2*toys.optc);
+  for (i=0; i<toys.optc; i++) TT.err[i] = ESRCH;
+  names_to_pid(TT.names, kill_process);
+  for (i=0; i<toys.optc; i++) {
+    if (TT.err[i]) {
+      toys.exitval = 1;
+      errno = TT.err[i];
+      perror_msg_raw(TT.names[i]);
+    }
+  }
+  if (CFG_TOYBOX_FREE) free(TT.err);
+}
diff --git a/toybox/toys/lsb/md5sum.c b/toybox/toys/lsb/md5sum.c
new file mode 100644
index 0000000..9efdc87
--- /dev/null
+++ b/toybox/toys/lsb/md5sum.c
@@ -0,0 +1,424 @@
+/* md5sum.c - Calculate RFC 1321 md5 hash and sha1 hash.
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/md5sum.html
+ * and http://www.ietf.org/rfc/rfc1321.txt
+ *
+ * They're combined this way to share infrastructure, and because md5sum is
+ * 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, "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 [-b] [-c FILE] [FILE]...
+
+    Calculate md5 hash for each input file, reading from stdin if none.
+    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: sha?sum [-b] [-c FILE] [FILE]...
+
+    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;
+  union {
+    char c[64];
+    unsigned i[16];
+  } buffer;
+)
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+// for(i=0; i<64; i++) md5table[i] = abs(sin(i+1))*(1<<32);  But calculating
+// that involves not just floating point but pulling in -lm (and arguing with
+// C about whether 1<<32 is a valid thing to do on 32 bit platforms) so:
+
+static uint32_t md5table[64] = {
+  0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
+  0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+  0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
+  0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+  0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
+  0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+  0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
+  0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
+  0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+  0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+static const uint8_t md5rot[64] = {
+  7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+  5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
+  4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+  6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+};
+
+// Mix next 64 bytes of data into md5 hash
+
+static void md5_transform(void)
+{
+  unsigned x[4], *b = TT.buffer.i;
+  int i;
+
+  memcpy(x, TT.state, sizeof(x));
+
+  for (i=0; i<64; i++) {
+    unsigned int in, temp, swap;
+    if (i<16) {
+      in = i;
+      temp = x[1];
+      temp = (temp & x[2]) | ((~temp) & x[3]);
+    } else if (i<32) {
+      in = (1+(5*i))&15;
+      temp = x[3];
+      temp = (x[1] & temp) | (x[2] & ~temp);
+    } else if (i<48) {
+      in = (3*i+5)&15;
+      temp = x[1] ^ x[2] ^ x[3];
+    } else {
+      in = (7*i)&15;
+      temp = x[2] ^ (x[1] | ~x[3]);
+    }
+    temp += x[0] + b[in] + md5table[i];
+    swap = x[3];
+    x[3] = x[2];
+    x[2] = x[1];
+    x[1] += rol(temp, md5rot[i]);
+    x[0] = swap;
+  }
+  for (i=0; i<4; i++) TT.state[i] += x[i];
+}
+
+// Mix next 64 bytes of data into sha1 hash.
+
+static const unsigned rconsts[]={0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6};
+
+static void sha1_transform(void)
+{
+  int i, j, k, count;
+  unsigned *block = TT.buffer.i;
+  unsigned *rot[5], *temp;
+
+  // Copy context->state[] to working vars
+  for (i=0; i<5; i++) {
+    TT.oldstate[i] = TT.state[i];
+    rot[i] = TT.state + i;
+  }
+  // 4 rounds of 20 operations each.
+  for (i=count=0; i<4; i++) {
+    for (j=0; j<20; j++) {
+      unsigned work;
+
+      work = *rot[2] ^ *rot[3];
+      if (!i) work = (work & *rot[1]) ^ *rot[3];
+      else {
+        if (i==2) work = ((*rot[1]|*rot[2])&*rot[3])|(*rot[1]&*rot[2]);
+        else work ^= *rot[1];
+      }
+
+      if (!i && j<16)
+        work += block[count] = (rol(block[count],24)&0xFF00FF00)
+                             | (rol(block[count],8)&0x00FF00FF);
+      else
+        work += block[count&15] = rol(block[(count+13)&15]
+              ^ block[(count+8)&15] ^ block[(count+2)&15] ^ block[count&15], 1);
+      *rot[4] += work + rol(*rot[0],5) + rconsts[i];
+      *rot[1] = rol(*rot[1],30);
+
+      // Rotate by one for next time.
+      temp = rot[4];
+      for (k=4; k; k--) rot[k] = rot[k-1];
+      *rot = temp;
+      count++;
+    }
+  }
+  // Add the previous values of state[]
+  for (i=0; i<5; i++) TT.state[i] += TT.oldstate[i];
+}
+
+// Fill the 64-byte working buffer and call transform() when full.
+
+static void hash_update(char *data, unsigned int len, void (*transform)(void))
+{
+  unsigned int i, j;
+
+  j = TT.count & 63;
+  TT.count += len;
+
+  for (;;) {
+    // Grab next chunk of data, return if it's not enough to process a frame
+    i = 64 - j;
+    if (i>len) i = len;
+    memcpy(TT.buffer.c+j, data, i);
+    if (j+i != 64) break;
+
+    // Process a frame
+    if (IS_BIG_ENDIAN)
+      for (j=0; j<16; j++) TT.buffer.i[j] = SWAP_LE32(TT.buffer.i[j]);
+    transform();
+    j=0;
+    data += i;
+    len -= i;
+  }
+}
+
+// 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_builtin_hash(int fd, char *name)
+{
+  uint64_t count;
+  int i, sha1=toys.which->name[0]=='s';
+  char buf;
+  void (*transform)(void);
+
+  /* SHA1 initialization constants  (md5sum uses first 4) */
+  TT.state[0] = 0x67452301;
+  TT.state[1] = 0xEFCDAB89;
+  TT.state[2] = 0x98BADCFE;
+  TT.state[3] = 0x10325476;
+  TT.state[4] = 0xC3D2E1F0;
+  TT.count = 0;
+
+  transform = sha1 ? sha1_transform : md5_transform;
+  for (;;) {
+    i = read(fd, toybuf, sizeof(toybuf));
+    if (i<1) break;
+    hash_update(toybuf, i, transform);
+  }
+
+  count = TT.count << 3;
+
+  // End the message by appending a "1" bit to the data, ending with the
+  // message size (in bits, big endian), and adding enough zero bits in
+  // between to pad to the end of the next 64-byte frame.
+  //
+  // Since our input up to now has been in whole bytes, we can deal with
+  // bytes here too.
+
+  buf = 0x80;
+  do {
+    hash_update(&buf, 1, transform);
+    buf = 0;
+  } while ((TT.count & 63) != 56);
+  count = sha1 ? SWAP_BE64(count) : SWAP_LE64(count);
+  hash_update((void *)&count, 8, transform);
+
+  if (sha1)
+    for (i = 0; i < 20; 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.state, 0, sizeof(TT)-((long)TT.state-(long)&TT));
+  i = strlen(toybuf)+1;
+  memset(toybuf+i, 0, sizeof(toybuf)-i);
+}
+
+// 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)
+{
+  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)
+{
+  md5sum_main();
+}
diff --git a/toybox/toys/lsb/mknod.c b/toybox/toys/lsb/mknod.c
new file mode 100644
index 0000000..8148c85
--- /dev/null
+++ b/toybox/toys/lsb/mknod.c
@@ -0,0 +1,58 @@
+/* mknod.c - make block or character special file
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mknod.html
+
+USE_MKNOD(NEWTOY(mknod, "<2>4m(mode):"USE_MKNOD_Z("Z:"), TOYFLAG_BIN|TOYFLAG_UMASK))
+
+config MKNOD
+  bool "mknod"
+  default y
+  help
+    usage: mknod [-m MODE] NAME TYPE [MAJOR MINOR]
+
+    Create a special file NAME with a given type. TYPE is b for block device,
+    c or u for character device, p for named pipe (which ignores MAJOR/MINOR).
+
+    -m	Mode (file permissions) of new device, in octal or u+x format
+
+config MKNOD_Z
+  bool
+  default y
+  depends on MKNOD && !TOYBOX_LSM_NONE
+  help
+    usage: mknod [-Z CONTEXT] ...
+
+    -Z	Set security context to created file
+*/
+
+#define FOR_mknod
+#include "toys.h"
+
+GLOBALS(
+  char *arg_context;
+  char *m;
+)
+
+void mknod_main(void)
+{
+  mode_t modes[] = {S_IFIFO, S_IFCHR, S_IFCHR, S_IFBLK};
+  int major=0, minor=0, type;
+  int mode = TT.m ? string_to_mode(TT.m, 0777) : 0660;
+
+  type = stridx("pcub", *toys.optargs[1]);
+  if (type == -1) perror_exit("bad type '%c'", *toys.optargs[1]);
+  if (type) {
+    if (toys.optc != 4) perror_exit("need major/minor");
+
+    major = atoi(toys.optargs[2]);
+    minor = atoi(toys.optargs[3]);
+  }
+
+  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], dev_makedev(major, minor)))
+    perror_exit_raw(*toys.optargs);
+}
diff --git a/toybox/toys/lsb/mktemp.c b/toybox/toys/lsb/mktemp.c
new file mode 100644
index 0000000..118dacc
--- /dev/null
+++ b/toybox/toys/lsb/mktemp.c
@@ -0,0 +1,57 @@
+/* mktemp.c - Create a temporary file or directory.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mktemp.html
+
+USE_MKTEMP(NEWTOY(mktemp, ">1uqd(directory)p(tmpdir):", TOYFLAG_BIN))
+
+config MKTEMP
+  bool "mktemp"
+  default y
+  help
+    usage: mktemp [-dqu] [-p DIR] [TEMPLATE]
+
+    Safely create a new file "DIR/TEMPLATE" and print its name.
+
+    -d	Create directory instead of file (--directory)
+    -p	Put new file in DIR (--tmpdir)
+    -q	Quiet, no error messages
+    -u	Don't create anything, just print what would be created
+
+    Each X in TEMPLATE is replaced with a random printable character. The
+    default TEMPLATE is tmp.XXXXXX, and the default DIR is $TMPDIR if set,
+    else "/tmp".
+*/
+
+#define FOR_mktemp
+#include "toys.h"
+
+GLOBALS(
+  char *tmpdir;
+)
+
+void mktemp_main(void)
+{
+  int d_flag = toys.optflags & FLAG_d;
+  char *template = *toys.optargs;
+
+  if (!template) template = "tmp.XXXXXX";
+
+  if (!TT.tmpdir) TT.tmpdir = getenv("TMPDIR");
+  if (!TT.tmpdir || !*TT.tmpdir) TT.tmpdir = "/tmp";
+
+  template = strchr(template, '/') ? xstrdup(template)
+             : xmprintf("%s/%s", TT.tmpdir, template);
+
+  if (d_flag ? !mkdtemp(template) : mkstemp(template) == -1) {
+    if (toys.optflags & FLAG_q) toys.exitval = 1;
+    else perror_exit("Failed to create %s %s/%s",
+                     d_flag ? "directory" : "file", TT.tmpdir, template);
+  } else {
+    if (toys.optflags & FLAG_u) unlink(template);
+    xputs(template);
+  }
+
+  if (CFG_TOYBOX_FREE) free(template);
+}
diff --git a/toybox/toys/lsb/mount.c b/toybox/toys/lsb/mount.c
new file mode 100644
index 0000000..525d0ab
--- /dev/null
+++ b/toybox/toys/lsb/mount.c
@@ -0,0 +1,383 @@
+/* mount.c - mount filesystems
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * 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))
+
+config MOUNT
+  bool "mount"
+  default y
+  help
+    usage: mount [-afFrsvw] [-t TYPE] [-o OPTION,] [[DEVICE] DIR]
+
+    Mount new filesystem(s) on directories. With no arguments, display existing
+    mounts.
+
+    -a	mount all entries in /etc/fstab (with -t, only entries of that TYPE)
+    -O	only mount -a entries that have this option
+    -f	fake it (don't actually mount)
+    -r	read only (same as -o ro)
+    -w	read/write (default, same as -o rw)
+    -t	specify filesystem type
+    -v	verbose
+
+    OPTIONS is a comma separated list of options, which can also be supplied
+    as --longopts.
+
+    This mount autodetects loopback mounts (a file on a directory) and
+    bind mounts (file on file, directory on directory), so you don't need
+    to say --bind or --loop. You can also "mount -a /path" to mount everything
+    in /etc/fstab under /path, even if it's noauto.
+
+#config NFSMOUNT
+#  bool "nfsmount"
+#  default n
+#  help
+#    usage: nfsmount SHARE DIR
+#
+#    Invoke an eldrich horror from the dawn of time.
+*/
+
+#define FOR_mount
+#include "toys.h"
+
+GLOBALS(
+  struct arg_list *optlist;
+  char *type;
+  char *bigO;
+
+  unsigned long flags;
+  char *opts;
+  int okuser;
+)
+
+// mount.tests should check for all of this:
+// TODO detect existing identical mount (procfs with different dev name?)
+// TODO user, users, owner, group, nofail
+// TODO -p (passfd)
+// TODO -a -t notype,type2
+// TODO --subtree
+// TODO --rbind, -R
+// TODO make "mount --bind,ro old new" work (implicit -o remount)
+// TODO mount -a
+// TODO mount -o remount
+// TODO fstab: lookup default options for mount
+// TODO implement -v
+// TODO "mount -a -o remount,ro" should detect overmounts
+// TODO work out how that differs from "mount -ar"
+// TODO what if you --bind mount a block device somewhere (file, dir, dev)
+// TODO "touch servername; mount -t cifs servername path"
+// TODO mount -o remount a user mount
+// TODO mount image.img sub (auto-loopback) then umount image.img
+
+// Strip flags out of comma separated list of options, return flags,.
+static long flag_opts(char *new, long flags, char **more)
+{
+  struct {
+    char *name;
+    long flags;
+  } opts[] = {
+    // NOPs (we autodetect --loop and --bind)
+    {"loop", 0}, {"bind", 0}, {"defaults", 0}, {"quiet", 0},
+    {"user", 0}, {"nouser", 0}, // checked in fstab, ignored in -o
+    {"ro", MS_RDONLY}, {"rw", ~MS_RDONLY},
+    {"nosuid", MS_NOSUID}, {"suid", ~MS_NOSUID},
+    {"nodev", MS_NODEV}, {"dev", ~MS_NODEV},
+    {"noexec", MS_NOEXEC}, {"exec", ~MS_NOEXEC},
+    {"sync", MS_SYNCHRONOUS}, {"async", ~MS_SYNCHRONOUS},
+    {"noatime", MS_NOATIME}, {"atime", ~MS_NOATIME},
+    {"norelatime", ~MS_RELATIME}, {"relatime", MS_RELATIME},
+    {"nodiratime", MS_NODIRATIME}, {"diratime", ~MS_NODIRATIME},
+    {"loud", ~MS_SILENT},
+    {"shared", MS_SHARED}, {"rshared", MS_SHARED|MS_REC},
+    {"slave", MS_SLAVE}, {"rslave", MS_SLAVE|MS_REC},
+    {"private", MS_PRIVATE}, {"rprivate", MS_SLAVE|MS_REC},
+    {"unbindable", MS_UNBINDABLE}, {"runbindable", MS_UNBINDABLE|MS_REC},
+    {"remount", MS_REMOUNT}, {"move", MS_MOVE},
+    // mand dirsync rec iversion strictatime
+  };
+
+  if (new) for (;;) {
+    char *comma = strchr(new, ',');
+    int i;
+
+    if (comma) *comma = 0;
+
+    // If we recognize an option, apply flags
+    for (i = 0; i < ARRAY_LEN(opts); i++) if (!strcasecmp(opts[i].name, new)) {
+      long ll = opts[i].flags;
+
+      if (ll < 0) flags &= ll;
+      else flags |= ll;
+
+      break;
+    }
+
+    // If we didn't recognize it, keep string version
+    if (more && i == ARRAY_LEN(opts)) {
+      i = *more ? strlen(*more) : 0;
+      *more = xrealloc(*more, i + strlen(new) + 2);
+      if (i) (*more)[i++] = ',';
+      strcpy(i+*more, new);
+    }
+
+    if (!comma) break;
+    *comma = ',';
+    new = comma + 1;
+  }
+
+  return flags;
+}
+
+static void mount_filesystem(char *dev, char *dir, char *type,
+  unsigned long flags, char *opts)
+{
+  FILE *fp = 0;
+  int rc = EINVAL;
+  char *buf = 0;
+
+  if (toys.optflags & FLAG_f) return;
+
+  if (getuid()) {
+    if (TT.okuser) TT.okuser = 0;
+    else {
+      error_msg("'%s' not user mountable in fstab", dev);
+
+      return;
+    }
+  }
+
+  // Autodetect bind mount or filesystem type
+
+  if (type && !strcmp(type, "auto")) type = 0;
+  if (flags & MS_MOVE) {
+    if (type) error_exit("--move with -t");
+  } else if (!type) {
+    struct stat stdev, stdir;
+
+    // file on file or dir on dir is a --bind mount.
+    if (!stat(dev, &stdev) && !stat(dir, &stdir)
+        && ((S_ISREG(stdev.st_mode) && S_ISREG(stdir.st_mode))
+            || (S_ISDIR(stdev.st_mode) && S_ISDIR(stdir.st_mode))))
+    {
+      flags |= MS_BIND;
+    } else fp = xfopen("/proc/filesystems", "r");
+  } else if (!strcmp(type, "ignore")) return;
+  else if (!strcmp(type, "swap"))
+    toys.exitval |= xrun((char *[]){"swapon", "--", dev, 0});
+
+  for (;;) {
+    int fd = -1, ro = 0;
+
+    // If type wasn't specified, try all of them in order.
+    if (fp && !buf) {
+      size_t i;
+
+      if (getline(&buf, &i, fp)<0) break;
+      type = buf;
+      // skip nodev devices
+      if (!isspace(*type)) {
+        free(buf);
+        buf = 0;
+
+        continue;
+      }
+      // trim whitespace
+      while (isspace(*type)) type++;
+      i = strlen(type);
+      if (i) type[i-1] = 0;
+    }
+    if (toys.optflags & FLAG_v)
+      printf("try '%s' type '%s' on '%s'\n", dev, type, dir);
+    for (;;) {
+      rc = mount(dev, dir, type, flags, opts);
+      // Did we succeed, fail unrecoverably, or already try read-only?
+      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 (fd == -1) {
+        if (toys.optflags & FLAG_v)
+          printf("trying BLKROSET ioctl on '%s'\n", dev);
+        if (-1 != (fd = open(dev, O_RDONLY))) {
+          rc = ioctl(fd, BLKROSET, &ro);
+          close(fd);
+          if (!rc) continue;
+        }
+      }
+      fprintf(stderr, "'%s' is read-only\n", dev);
+      flags |= MS_RDONLY;
+    }
+
+    // Trying to autodetect loop mounts like bind mounts above (file on dir)
+    // isn't good enough because "mount -t ext2 fs.img dir" is valid, but if
+    // you _do_ accept loop mounts with -t how do you tell "-t cifs" isn't
+    // looking for a block device if it's not in /proc/filesystems yet
+    // because the module that won't be loaded until you try the mount, and
+    // if you can't then DEVICE existing as a file would cause a false
+    // positive loopback mount (so "touch servername" becomes a potential
+    // denial of service attack...)
+    //
+    // Solution: try the mount, let the kernel tell us it wanted a block
+    // device, then do the loopback setup and retry the mount.
+
+    if (rc && errno == ENOTBLK) {
+      char *losetup[] = {"losetup", "-fs", dev, 0};
+      int pipe, len;
+      pid_t pid;
+
+      if (flags & MS_RDONLY) losetup[1] = "-fsr";
+      pid = xpopen(losetup, &pipe, 1);
+      len = readall(pipe, toybuf, sizeof(toybuf)-1);
+      rc = xpclose(pid, pipe);
+      if (!rc && len > 1) {
+        if (toybuf[len-1] == '\n') --len;
+        toybuf[len] = 0;
+        dev = toybuf;
+
+        continue;
+      }
+      error_msg("losetup failed %d", rc);
+
+      break;
+    }
+
+    free(buf);
+    buf = 0;
+    if (!rc) break;
+    if (fp && (errno == EINVAL || errno == EBUSY)) continue;
+
+    perror_msg("'%s'->'%s'", dev, dir);
+
+    break;
+  }
+  if (fp) fclose(fp);
+}
+
+void mount_main(void)
+{
+  char *opts = 0, *dev = 0, *dir = 0, **ss;
+  long flags = MS_SILENT;
+  struct arg_list *o;
+  struct mtab_list *mtl, *mtl2 = 0, *mm, *remount;
+
+// TODO
+// remount
+//   - overmounts
+// shared subtree
+// -o parsed after fstab options
+// test if mountpoint already exists (-o noremount?)
+
+  // First pass; just accumulate string, don't parse flags yet. (This is so
+  // we can modify fstab entries with -a, or mtab with remount.)
+  for (o = TT.optlist; o; o = o->next) comma_collate(&opts, o->arg);
+  if (toys.optflags & FLAG_r) comma_collate(&opts, "ro");
+  if (toys.optflags & FLAG_w) comma_collate(&opts, "rw");
+
+  // Treat each --option as -o option
+  for (ss = toys.optargs; *ss; ss++) {
+    char *sss = *ss;
+
+    // If you realy, really want to mount a file named "--", we support it.
+    if (sss[0]=='-' && sss[1]=='-' && sss[2]) comma_collate(&opts, sss+2);
+    else if (!dev) dev = sss;
+    else if (!dir) dir = sss;
+    // same message as lib/args.c ">2" which we can't use because --opts count
+    else error_exit("Max 2 arguments\n");
+  }
+
+  if ((toys.optflags & FLAG_a) && dir) error_exit("-a with >1 arg");
+
+  // For remount we need _last_ match (in case of overmounts), so traverse
+  // in reverse order. (Yes I'm using remount as a boolean for a bit here,
+  // the double cast is to get gcc to shut up about it.)
+  remount = (void *)(long)comma_scan(opts, "remount", 1);
+  if (((toys.optflags & FLAG_a) && !access("/proc/mounts", R_OK)) || remount) {
+    mm = dlist_terminate(mtl = mtl2 = xgetmountlist(0));
+    if (remount) remount = mm;
+  }
+
+  // Do we need to do an /etc/fstab trawl?
+  // This covers -a, -o remount, one argument, all user mounts
+  if ((toys.optflags & FLAG_a) || (dev && (!dir || getuid() || remount))) {
+    if (!remount) dlist_terminate(mtl = xgetmountlist("/etc/fstab"));
+
+    for (mm = remount ? remount : mtl; mm; mm = (remount ? mm->prev : mm->next))
+    {
+      char *aopts = 0;
+      struct mtab_list *mmm = 0;
+      int aflags, noauto, len;
+
+      // Check for noauto and get it out of the option list. (Unknown options
+      // that make it to the kernel give filesystem drivers indigestion.)
+      noauto = comma_scan(mm->opts, "noauto", 1);
+
+      if (toys.optflags & FLAG_a) {
+        // "mount -a /path" to mount all entries under /path
+        if (dev) {
+           len = strlen(dev);
+           if (strncmp(dev, mm->dir, len)
+               || (mm->dir[len] && mm->dir[len] != '/')) continue;
+        } else if (noauto) continue; // never present in the remount case
+        if (!mountlist_istype(mm,TT.type) || !comma_scanall(mm->opts,TT.bigO))
+          continue;
+      } else {
+        if (dir && strcmp(dir, mm->dir)) continue;
+        if (dev && strcmp(dev, mm->device) && (dir || strcmp(dev, mm->dir)))
+          continue;
+      }
+
+      // Don't overmount the same dev on the same directory
+      // (Unless root explicitly says to in non -a mode.)
+      if (mtl2 && !remount)
+        for (mmm = mtl2; mmm; mmm = mmm->next)
+          if (!strcmp(mm->dir, mmm->dir) && !strcmp(mm->device, mmm->device))
+            break;
+ 
+      // user only counts from fstab, not opts.
+      if (!mmm) {
+        TT.okuser = comma_scan(mm->opts, "user", 1);
+        aflags = flag_opts(mm->opts, flags, &aopts);
+        aflags = flag_opts(opts, aflags, &aopts);
+
+        mount_filesystem(mm->device, mm->dir, mm->type, aflags, aopts);
+      } // TODO else if (getuid()) error_msg("already there") ?
+      free(aopts);
+
+      if (!(toys.optflags & FLAG_a)) break;
+    }
+    if (CFG_TOYBOX_FREE) {
+      llist_traverse(mtl, free);
+      llist_traverse(mtl2, free);
+    }
+    if (!mm && !(toys.optflags & FLAG_a))
+      error_exit("'%s' not in %s", dir ? dir : dev,
+                 remount ? "/proc/mounts" : "fstab");
+
+  // show mounts from /proc/mounts
+  } else if (!dev) {
+    for (mtl = xgetmountlist(0); mtl && (mm = dlist_pop(&mtl)); free(mm)) {
+      char *s = 0;
+
+      if (TT.type && strcmp(TT.type, mm->type)) continue;
+      if (*mm->device == '/') s = xabspath(mm->device, 0);
+      xprintf("%s on %s type %s (%s)\n",
+              s ? s : mm->device, mm->dir, mm->type, mm->opts);
+      free(s);
+    }
+
+  // two arguments
+  } else {
+    char *more = 0;
+
+    flags = flag_opts(opts, flags, &more);
+    mount_filesystem(dev, dir, TT.type, flags, more);
+    if (CFG_TOYBOX_FREE) free(more);
+  }
+}
diff --git a/toybox/toys/lsb/passwd.c b/toybox/toys/lsb/passwd.c
new file mode 100644
index 0000000..687d4c0
--- /dev/null
+++ b/toybox/toys/lsb/passwd.c
@@ -0,0 +1,191 @@
+/* passwd.c - Program to update user password.
+ *
+ * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
+ * Modified 2012 Jason Kyungwan Han <asura321@gmail.com>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/passwd.html
+
+USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
+
+config PASSWD
+  bool "passwd"
+  default y
+  depends on TOYBOX_SHADOW
+  help
+    usage: passwd [-a ALGO] [-dlu] <account name>
+
+    update user's authentication tokens. Default : current user
+
+    -a ALGO	Encryption method (des, md5, sha256, sha512) default: des
+    -d		Set password to ''
+    -l		Lock (disable) account
+    -u		Unlock (enable) account
+
+config PASSWD_SAD
+  bool "Add sad password checking heuristics"
+  default n
+  depends on PASSWD
+  help
+    Password changes are checked to make sure they don't include the entire
+    username (but not a subset of it), and the entire previous password
+    (but changing password1, password2, password3 is fine). This heuristic
+    accepts "aaaaaa" as a password.
+*/
+
+#define FOR_passwd
+#include "toys.h"
+
+GLOBALS(
+  char *algo;
+)
+
+static int str_check(char *s, char *p)
+{
+  if (strnstr(s, p) || strnstr(p, s)) return 1;
+  return 0;
+}
+
+// Insane heuristic won't find password1 password2 password3...?
+static void strength_check(char *newp, char *oldp, char *user)
+{
+  char *msg = NULL;
+
+  if (strlen(newp) < 6) { //Min passwd len
+    msg = "too short";
+    xprintf("BAD PASSWORD: %s\n",msg);
+  }
+  if (!newp[0]) return; //passwd is empty
+
+  if (str_check(newp, user)) {
+    msg = "user based password";
+    xprintf("BAD PASSWORD: %s\n",msg);
+  }
+
+  if (oldp[0] && str_check(newp, oldp)) {
+    msg = "based on old passwd";
+    xprintf("BAD PASSWORD: %s\n",msg);
+  }
+}
+
+static int verify_passwd(char * pwd)
+{
+  char * pass;
+
+  if (!pwd) return 1;
+  if (pwd[0] == '!' || pwd[0] == '*') return 1;
+
+  pass = crypt(toybuf, pwd);
+  if (pass  && !strcmp(pass, pwd)) return 0;
+
+  return 1;
+}
+
+static char *new_password(char *oldp, char *user)
+{
+  char *newp = NULL;
+
+  if (read_password(toybuf, sizeof(toybuf), "New password:"))
+    return NULL; //may be due to Ctrl-C
+
+  newp = xstrdup(toybuf);
+  if (CFG_PASSWD_SAD) strength_check(newp, oldp, user);
+  if (read_password(toybuf, sizeof(toybuf), "Retype password:")) {
+    free(newp);
+    return NULL; //may be due to Ctrl-C
+  }
+
+  if (!strcmp(newp, toybuf)) return newp;
+  else error_msg("Passwords do not match.\n");
+  // Failure Case
+  free(newp);
+  return NULL;
+}
+
+void passwd_main(void)
+{
+  uid_t myuid;
+  struct passwd *pw;
+  struct spwd *sp;
+  char *name = NULL, *pass = NULL, *encrypted = NULL, *newp = NULL,
+       *orig = (char *)"", salt[MAX_SALT_LEN];
+  int ret = -1;
+
+  myuid = getuid();
+  if (myuid && (toys.optflags & (FLAG_l | FLAG_u | FLAG_d)))
+    error_exit("Not root");
+
+  pw = xgetpwuid(myuid);
+
+  if (*toys.optargs) name = toys.optargs[0];
+  else name = xstrdup(pw->pw_name);
+
+  pw = xgetpwnam(name);
+
+  if (myuid && (myuid != pw->pw_uid)) error_exit("Not root");
+
+  pass = pw->pw_passwd;
+  if (pw->pw_passwd[0] == 'x') {
+    //get shadow passwd
+    sp = getspnam(name);
+    if (sp) pass = sp->sp_pwdp;
+  }
+
+
+  if (!(toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) {
+    
+    if (!(toys.optflags & FLAG_a)) TT.algo = "des";
+    if (get_salt(salt, TT.algo) == -1)
+      error_exit("Error: Unkown encryption algorithm\n");
+
+    printf("Changing password for %s\n",name);
+    if (myuid && pass[0] == '!')
+      error_exit("Can't change, password is locked for %s",name);
+    if (myuid) {
+      //Validate user 
+
+      if (read_password(toybuf, sizeof(toybuf), "Origial password:")) {
+        if (!toys.optargs[0]) free(name);
+        return;
+      }
+      orig = toybuf;
+      if (verify_passwd(pass)) error_exit("Authentication failed\n");
+    }
+
+    orig = xstrdup(orig);
+
+    // Get new password
+    newp = new_password(orig, name);
+    if (!newp) {
+      free(orig);
+      if (!toys.optargs[0]) free(name);
+      return; //new password is not set well.
+    }
+
+    encrypted = crypt(newp, salt);
+    free(newp);
+    free(orig);
+  } else if (toys.optflags & FLAG_l) {
+    if (pass[0] == '!') error_exit("password is already locked for %s",name);
+    printf("Locking password for %s\n",name);
+    encrypted = xmprintf("!%s",pass);
+  } else if (toys.optflags & FLAG_u) {
+    if (pass[0] != '!') error_exit("password is already unlocked for %s",name);
+
+    printf("Unlocking password for %s\n",name);
+    encrypted = xstrdup(&pass[1]);
+  } else if (toys.optflags & FLAG_d) {
+    printf("Deleting password for %s\n",name);
+    encrypted = xstrdup(""); //1 = "", 2 = '\0'
+  }
+
+  // Update the passwd
+  if (pw->pw_passwd[0] == 'x')
+    ret = update_password("/etc/shadow", name, encrypted);
+  else ret = update_password("/etc/passwd", name, encrypted);
+
+  if ((toys.optflags & (FLAG_l | FLAG_u | FLAG_d))) free(encrypted);
+
+  if (!toys.optargs[0]) free(name);
+  if (!ret) error_msg("Success");
+  else error_msg("Failure");
+}
diff --git a/toybox/toys/lsb/pidof.c b/toybox/toys/lsb/pidof.c
new file mode 100644
index 0000000..e1facfa
--- /dev/null
+++ b/toybox/toys/lsb/pidof.c
@@ -0,0 +1,44 @@
+/* pidof.c - Print the Process IDs of all processes with the given names.
+ *
+ * Copyright 2012 Andreas Heck <aheck@gmx.de>
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/pidof.html
+
+USE_PIDOF(NEWTOY(pidof, "<1so:", TOYFLAG_BIN))
+
+config PIDOF
+  bool "pidof"
+  default y
+  help
+    usage: pidof [-s] [-o omitpid[,omitpid...]] [NAME]...
+
+    Print the PIDs of all processes with the given names.
+
+    -s	single shot, only return one pid.
+    -o	omit PID(s)
+*/
+
+#define FOR_pidof
+#include "toys.h"
+
+GLOBALS(
+  char *omit;
+)
+
+static int print_pid(pid_t pid, char *name)
+{
+  sprintf(toybuf, "%d", (int)pid);
+  if (comma_scan(TT.omit, toybuf, 0)) return 0;
+  xprintf(" %s"+!!toys.exitval, toybuf);
+  toys.exitval = 0;
+
+  return toys.optflags & FLAG_s;
+}
+
+void pidof_main(void)
+{
+  toys.exitval = 1;
+  names_to_pid(toys.optargs, print_pid);
+  if (!toys.exitval) xputc('\n');
+}
diff --git a/toybox/toys/lsb/seq.c b/toybox/toys/lsb/seq.c
new file mode 100644
index 0000000..0e0f460
--- /dev/null
+++ b/toybox/toys/lsb/seq.c
@@ -0,0 +1,93 @@
+/* seq.c - Count from first to last, by increment.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/seq.html
+
+USE_SEQ(NEWTOY(seq, "<1>3?f:s:w[!fw]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SEQ
+  bool "seq"
+  depends on TOYBOX_FLOAT
+  default y
+  help
+    usage: seq [-w|-f fmt_str] [-s sep_str] [first] [increment] last
+
+    Count from first to last, by increment. Omitted arguments default
+    to 1. Two arguments are used as first and last. Arguments can be
+    negative or floating point.
+
+    -f	Use fmt_str as a printf-style floating point format string
+    -s	Use sep_str as separator, default is a newline character
+    -w	Pad to equal width with leading zeroes.
+*/
+
+#define FOR_seq
+#include "toys.h"
+
+GLOBALS(
+  char *sep;
+  char *fmt;
+)
+
+// Ensure there's one %f escape with correct attributes
+static void insanitize(char *f)
+{
+  char *s = next_printf(f, 0);
+
+  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'@%d", f, (int)(s-f+1));
+  }
+}
+
+void seq_main(void)
+{
+  double first, increment, last, dd;
+  char *sep_str = "\n", *fmt_str = "%g";
+  int output = 0;
+
+  // Parse command line arguments, with appropriate defaults.
+  // Note that any non-numeric arguments are treated as zero.
+  first = increment = 1;
+  switch (toys.optc) {
+    case 3: increment = atof(toys.optargs[1]);
+    case 2: first = atof(*toys.optargs);
+    default: last = atof(toys.optargs[toys.optc-1]);
+  }
+
+  // Pad to largest width
+  if (toys.optflags & FLAG_w) {
+    char *s;
+    int i, len, dot, left = 0, right = 0;
+
+    for (i=0; i<3; i++) {
+      dd = (double []){first, increment, last}[i];
+
+      len = sprintf(toybuf, "%g", dd);
+      if ((s = strchr(toybuf, '.'))) {
+        dot = s-toybuf;
+        if (left<dot) left = dot;
+        dot = len-dot-1;
+        if (right<dot) right = dot;
+      } else if (len>left) left = len;
+    }
+
+    sprintf(fmt_str = toybuf, "%%0%d.%df", left+right+!!right, right);
+  }
+  if (toys.optflags & FLAG_f) insanitize(fmt_str = TT.fmt);
+  if (toys.optflags & FLAG_s) sep_str = TT.sep;
+
+  // Yes, we're looping on a double.  Yes rounding errors can accumulate if
+  // you use a non-integer increment.  Deal with it.
+  for (dd=first; (increment>0 && dd<=last) || (increment<0 && dd>=last);
+    dd+=increment)
+  {
+    if (dd != first) printf("%s", sep_str);
+    printf(fmt_str, dd);
+    output = 1;
+  }
+
+  if (output) printf("\n");
+}
diff --git a/toybox/toys/lsb/su.c b/toybox/toys/lsb/su.c
new file mode 100644
index 0000000..7ab2487
--- /dev/null
+++ b/toybox/toys/lsb/su.c
@@ -0,0 +1,99 @@
+/* su.c - switch user
+ *
+ * Copyright 2013 CE Strake <strake888@gmail.com>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/su.html
+ * TODO: log su attempts
+
+USE_SU(NEWTOY(su, "lmpc:s:", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
+
+config SU
+  bool "su"
+  default y
+  depends on TOYBOX_SHADOW
+  help
+    usage: su [-lmp] [-c CMD] [-s SHELL] [USER [ARGS...]]
+
+    Switch to user (or root) and run shell (with optional command line).
+
+    -s	shell to use
+    -c	command to pass to shell with -c
+    -l	login shell
+    -(m|p)	preserve environment
+*/
+
+#define FOR_su
+#include "toys.h"
+
+GLOBALS(
+  char *s;
+  char *c;
+)
+
+static char *snapshot_env(char *name)
+{
+  char *s = getenv(name);
+
+  if (s) return xmprintf("%s=%s", name, s);
+
+  return 0;
+}
+
+void su_main()
+{
+  char *name, *passhash = 0, **argu, **argv;
+  struct passwd *up;
+  struct spwd *shp;
+
+  if (*toys.optargs && !strcmp("-", *toys.optargs)) {
+    toys.optflags |= FLAG_l;
+    toys.optargs++;
+  }
+
+  if (*toys.optargs) name = *(toys.optargs++);
+  else name = "root";
+
+  if (!(shp = getspnam(name))) perror_exit("no '%s'", name);
+  if (getuid()) {
+    if (*shp->sp_pwdp != '$') goto deny;
+    if (read_password(toybuf, sizeof(toybuf), "Password: ")) goto deny;
+    passhash = crypt(toybuf, shp->sp_pwdp);
+    memset(toybuf, 0, sizeof(toybuf));
+    if (!passhash || strcmp(passhash, shp->sp_pwdp)) goto deny;
+  }
+
+  up = xgetpwnam(name);
+  xsetuser(up);
+
+  argv = argu = xmalloc(sizeof(char *)*(toys.optc + 4));
+  *(argv++) = TT.s ? TT.s : up->pw_shell;
+
+  if (toys.optflags & FLAG_l) {
+    int i;
+    char *stuff[] = {snapshot_env("TERM"), snapshot_env("DISPLAY"),
+      snapshot_env("COLORTERM"), snapshot_env("XAUTHORITY")};
+
+    clearenv();
+    for (i=0; i < ARRAY_LEN(stuff); i++) if (stuff[i]) putenv(stuff[i]);
+    *(argv++) = "-l";
+    xchdir(up->pw_dir);
+  } else unsetenv("IFS");
+  setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
+  if (!(toys.optflags & (FLAG_m|FLAG_p))) {
+    setenv("HOME", up->pw_dir, 1);
+    setenv("SHELL", up->pw_shell, 1);
+    setenv("USER", up->pw_name, 1);
+    setenv("LOGNAME", up->pw_name, 1);
+  } else unsetenv("IFS");
+
+  if (toys.optflags & FLAG_c) {
+    *(argv++) = "-c";
+    *(argv++) = TT.c;
+  }
+  while ((*(argv++) = *(toys.optargs++)));
+  xexec(argu);
+
+deny:
+  puts("No.");
+  toys.exitval = 1;
+}
diff --git a/toybox/toys/lsb/sync.c b/toybox/toys/lsb/sync.c
new file mode 100644
index 0000000..b12a8cc
--- /dev/null
+++ b/toybox/toys/lsb/sync.c
@@ -0,0 +1,23 @@
+/* sync.c - Write all pending data to disk.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/sync.html
+
+USE_SYNC(NEWTOY(sync, NULL, TOYFLAG_BIN))
+
+config SYNC
+  bool "sync"
+  default y
+  help
+    usage: sync
+
+    Write pending cached data to disk (synchronize), blocking until done.
+*/
+
+#include "toys.h"
+
+void sync_main(void)
+{
+  sync();
+}
diff --git a/toybox/toys/lsb/umount.c b/toybox/toys/lsb/umount.c
new file mode 100644
index 0000000..e6994f1
--- /dev/null
+++ b/toybox/toys/lsb/umount.c
@@ -0,0 +1,152 @@
+/* umount.c - Unmount a mount point.
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/umount.html
+ *
+ * Note: -n (/etc/mtab) is obsolete, /proc/mounts replaced it. Neither chroot
+ * nor per-process mount namespaces can work sanely with mtab. The kernel
+ * tracks mount points now, a userspace application can't do so anymore.
+
+USE_UMOUNT(NEWTOY(umount, "ndDflrat*v[!na]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
+
+config UMOUNT
+  bool "umount"
+  default y
+  help
+    usage: umount [-a [-t TYPE[,TYPE...]]] [-vrfD] [DIR...]
+
+    Unmount the listed filesystems.
+
+    -a	Unmount all mounts in /proc/mounts instead of command line list
+    -D  Don't free loopback device(s).
+    -f  Force unmount.
+    -l  Lazy unmount (detach from filesystem now, close when last user does).
+    -n	Don't use /proc/mounts
+    -r  Remount read only if unmounting fails.
+    -t	Restrict "all" to mounts of TYPE (or use "noTYPE" to skip)
+    -v	Verbose
+*/
+
+#define FOR_umount
+#include "toys.h"
+
+GLOBALS(
+  struct arg_list *t;
+
+  char *types;
+)
+
+// todo (done?)
+//   borrow df code to identify filesystem?
+//   umount -a from fstab
+//   umount when getpid() not 0, according to fstab
+//   lookup mount: losetup -d, bind, file, block
+//   loopback delete
+//   fstab -o user
+
+// TODO
+// swapon, swapoff
+
+static void do_umount(char *dir, char *dev, int flags)
+{
+  // is it ok for this user to umount this mount?
+  if (CFG_TOYBOX_SUID && getuid()) {
+    struct mtab_list *mt = dlist_terminate(xgetmountlist("/etc/fstab"));
+    int len, user = 0;
+
+    while (mt) {
+      struct mtab_list *mtemp = mt;
+      char *s;
+
+      if (!strcmp(mt->dir, dir)) while ((s = comma_iterate(&mt->opts, &len))) {
+        if (len == 4 && strncmp(s, "user", 4)) user = 1;
+        else if (len == 6 && strncmp(s, "nouser", 6)) user = 0;  
+      }
+
+      mt = mt->next;
+      free(mtemp);
+    }
+
+    if (!user) {
+      error_msg("not root");
+
+      return;
+    }
+  }
+
+  if (!umount2(dir, flags)) {
+    if (toys.optflags & FLAG_v) xprintf("%s unmounted\n", dir);
+
+    // Attempt to disassociate loopback device. This ioctl should be ignored
+    // for anything else, because lanana allocated ioctl range 'L' to loopback
+    if (dev && !(toys.optflags & FLAG_D)) {
+      int lfd = open(dev, O_RDONLY);
+
+      if (lfd != -1) {
+        // This is LOOP_CLR_FD, fetching it from headers is awkward
+        if (!ioctl(lfd, 0x4C01) && (toys.optflags & FLAG_v))
+          xprintf("%s cleared\n", dev);
+        close(lfd);
+      }
+    }
+
+    return;
+  }
+
+  if (toys.optflags & FLAG_r) {
+    if (!mount("", dir, "", MS_REMOUNT|MS_RDONLY, "")) {
+      if (toys.optflags & FLAG_v) xprintf("%s remounted ro\n", dir);
+      return;
+    }
+  }
+
+  perror_msg_raw(dir);
+}
+
+void umount_main(void)
+{
+  char **optargs, *pm = "/proc/mounts";
+  struct mtab_list *mlsave = 0, *mlrev = 0, *ml;
+  int flags=0;
+
+  if (!toys.optc && !(toys.optflags & FLAG_a))
+    error_exit("Need 1 arg or -a");
+
+  if (toys.optflags & FLAG_f) flags |= MNT_FORCE;
+  if (toys.optflags & FLAG_l) flags |= MNT_DETACH;
+
+  // Load /proc/mounts and get a reversed list (newest first)
+  // We use the list both for -a, and to umount /dev/name or do losetup -d
+  if (!(toys.optflags & FLAG_n) && !access(pm, R_OK))
+    mlrev = dlist_terminate(mlsave = xgetmountlist(pm));
+
+  // Unmount all: loop through mounted filesystems, skip -t, unmount the rest
+  if (toys.optflags & FLAG_a) {
+    char *typestr = 0;
+    struct arg_list *tal;
+    
+    for (tal = TT.t; tal; tal = tal->next) comma_collate(&typestr, tal->arg);
+    for (ml = mlrev; ml; ml = ml->prev)
+      if (mountlist_istype(ml, typestr)) do_umount(ml->dir, ml->device, flags);
+    if (CFG_TOYBOX_FREE) {
+      free(typestr);
+      llist_traverse(mlsave, free);
+    }
+  // TODO: under what circumstances do we umount non-absolute path?
+  } else for (optargs = toys.optargs; *optargs; optargs++) {
+    char *abs = xabspath(*optargs, 0);
+
+    for (ml = abs ? mlrev : 0; ml; ml = ml->prev) {
+      if (!strcmp(ml->dir, abs)) break;
+      if (!strcmp(ml->device, abs)) {
+        free(abs);
+        abs = ml->dir;
+        break;
+      }
+    }
+
+    do_umount(abs ? abs : *optargs, ml ? ml->device : 0, flags);
+    if (ml && abs != ml->dir) free(abs);
+  }
+}
diff --git a/toybox/toys/net/README b/toybox/toys/net/README
new file mode 100644
index 0000000..8708e4b
--- /dev/null
+++ b/toybox/toys/net/README
@@ -0,0 +1 @@
+Networking
diff --git a/toybox/toys/net/ifconfig.c b/toybox/toys/net/ifconfig.c
new file mode 100644
index 0000000..1d2a41d
--- /dev/null
+++ b/toybox/toys/net/ifconfig.c
@@ -0,0 +1,517 @@
+/* ifconfig.c - Configure network interface.
+ *
+ * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2012 Kyungwan Han <asura321@gamil.com>
+ * Reviewed by Kyungsu Kim <kaspyx@gmail.com>
+ *
+ * Not in SUSv4.
+
+USE_IFCONFIG(NEWTOY(ifconfig, "^?a", TOYFLAG_SBIN))
+
+config IFCONFIG
+  bool "ifconfig"
+  default y
+  help
+    usage: ifconfig [-a] [INTERFACE [ACTION...]]
+
+    Display or configure network interface.
+
+    With no arguments, display active interfaces. First argument is interface
+    to operate on, one argument by itself displays that interface.
+
+    -a	Show all interfaces, not just active ones
+
+    Additional arguments are actions to perform on the interface:
+
+    ADDRESS[/NETMASK] - set IPv4 address (1.2.3.4/5)
+    default - unset ipv4 address
+    add|del ADDRESS[/PREFIXLEN] - add/remove IPv6 address (1111::8888/128)
+    up - enable interface
+    down - disable interface
+
+    netmask|broadcast|pointopoint ADDRESS - set more IPv4 characteristics
+    hw ether|infiniband ADDRESS - set LAN hardware address (AA:BB:CC...)
+    txqueuelen LEN - number of buffered packets before output blocks
+    mtu LEN - size of outgoing packets (Maximum Transmission Unit)
+
+    Flags you can set on an interface (or -remove by prefixing with -):
+    arp - don't use Address Resolution Protocol to map LAN routes
+    promisc - don't discard packets that aren't to this LAN hardware address
+    multicast - force interface into multicast mode if the driver doesn't
+    allmulti - promisc for multicast packets
+
+    Obsolete fields included for historical purposes:
+    irq|io_addr|mem_start ADDR - micromanage obsolete hardware
+    outfill|keepalive INTEGER - SLIP analog dialup line quality monitoring
+    metric INTEGER - added to Linux 0.9.10 with comment "never used", still true
+*/
+
+#define FOR_ifconfig
+#include "toys.h"
+
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+
+GLOBALS(
+  int sockfd;
+)
+
+// Convert hostname to binary address for AF_INET or AF_INET6
+// return /prefix (or range max if none)
+int get_addrinfo(char *host, sa_family_t af, void *addr)
+{
+  struct addrinfo hints, *result, *rp = 0;
+  int status, len;
+  char *from, *slash;
+
+  memset(&hints, 0 , sizeof(struct addrinfo));
+  hints.ai_family = af;
+  hints.ai_socktype = SOCK_STREAM;
+
+  slash = strchr(host, '/');
+  if (slash) *slash = 0;
+
+  status = getaddrinfo(host, NULL, &hints, &result);
+  if (!status)
+    for (rp = result; rp; rp = rp->ai_next)
+      if (rp->ai_family == af) break;
+  if (!rp) error_exit("bad address '%s' : %s", host, gai_strerror(status));
+
+  // ai_addr isn't struct in_addr or in6_addr, it's struct sockaddr. Of course.
+  // You'd think ipv4 and ipv6 would have some basic compatibility, but no.
+  from = ((char *)rp->ai_addr) + 4;
+  if (af == AF_INET6) {
+    len = 16;
+    from += 4;  // skip "flowinfo" field ipv6 puts before address
+  } else len = 4;
+  memcpy(addr, from, len);
+  freeaddrinfo(result);
+
+  len = -1;
+  if (slash) len = atolx_range(slash+1, 0, (af == AF_INET) ? 32 : 128);
+
+  return len;
+}
+
+static void display_ifconfig(char *name, int always, unsigned long long val[])
+{
+  struct ifreq ifre;
+  struct {
+    int type;
+    char *title;
+  } types[] = {
+    {ARPHRD_LOOPBACK, "Local Loopback"}, {ARPHRD_ETHER, "Ethernet"},
+    {ARPHRD_PPP, "Point-to-Point Protocol"}, {ARPHRD_INFINIBAND, "InfiniBand"},
+    {ARPHRD_SIT, "IPv6-in-IPv4"}, {-1, "UNSPEC"}
+  };
+  int i;
+  char *pp;
+  FILE *fp;
+  short flags;
+
+  xstrncpy(ifre.ifr_name, name, IFNAMSIZ);
+  if (ioctl(TT.sockfd, SIOCGIFFLAGS, &ifre)<0) perror_exit_raw(name);
+  flags = ifre.ifr_flags;
+  if (!always && !(flags & IFF_UP)) return;
+
+  // query hardware type and hardware address
+  i = ioctl(TT.sockfd, SIOCGIFHWADDR, &ifre);
+
+  for (i=0; i < (sizeof(types)/sizeof(*types))-1; i++)
+    if (ifre.ifr_hwaddr.sa_family == types[i].type) break;
+
+  xprintf("%-9s Link encap:%s  ", name, types[i].title);
+  if(i >= 0 && ifre.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
+    xprintf("HWaddr ");
+    for (i=0; i<6; i++) xprintf(":%02x"+!i, ifre.ifr_hwaddr.sa_data[i]);
+  }
+  xputc('\n');
+
+  // If an address is assigned record that.
+
+  ifre.ifr_addr.sa_family = AF_INET;
+  memset(&ifre.ifr_addr, 0, sizeof(ifre.ifr_addr));
+  ioctl(TT.sockfd, SIOCGIFADDR, &ifre);
+  pp = (char *)&ifre.ifr_addr;
+  for (i = 0; i<sizeof(ifre.ifr_addr); i++) if (pp[i]) break;
+
+  if (i != sizeof(ifre.ifr_addr)) {
+    struct sockaddr_in *si = (struct sockaddr_in *)&ifre.ifr_addr;
+    struct {
+      char *name;
+      int flag, ioctl;
+    } addr[] = {
+      {"addr", 0, 0},
+      {"P-t-P", IFF_POINTOPOINT, SIOCGIFDSTADDR},
+      {"Bcast", IFF_BROADCAST, SIOCGIFBRDADDR},
+      {"Mask", 0, SIOCGIFNETMASK}
+    };
+
+    xprintf("%10c%s", ' ', (si->sin_family == AF_INET) ? "inet" :
+        (si->sin_family == AF_INET6) ? "inet6" : "unspec");
+
+    for (i=0; i < sizeof(addr)/sizeof(*addr); i++) {
+      if (!addr[i].flag || (flags & addr[i].flag)) {
+        if (addr[i].ioctl && ioctl(TT.sockfd, addr[i].ioctl, &ifre))
+          si->sin_family = 0;
+        xprintf(" %s:%s ", addr[i].name,
+          (si->sin_family == 0xFFFF || !si->sin_family)
+            ? "[NOT SET]" : inet_ntoa(si->sin_addr));
+      }
+    }
+
+    xputc('\n');
+  }
+
+  fp = fopen(pp = "/proc/net/if_inet6", "r");
+  if (fp) {
+    char iface_name[IFNAMSIZ];
+    int plen, iscope;
+
+    while (fgets(toybuf, sizeof(toybuf), fp)) {
+      int nitems;
+      char ipv6_addr[40];
+
+      nitems = sscanf(toybuf, "%32s %*08x %02x %02x %*02x %15s\n",
+                      ipv6_addr, &plen, &iscope, iface_name);
+      if (nitems<0 && feof(fp)) break;
+      if (nitems != 4) perror_exit("bad %s", pp);
+
+      if (!strcmp(name, iface_name)) {
+        struct sockaddr_in6 s6;
+        char *ptr = ipv6_addr+sizeof(ipv6_addr)-1;
+
+        // convert giant hex string into colon-spearated ipv6 address by
+        // inserting ':' every 4 characters. 
+        for (i = 32; i; i--)
+          if ((*(ptr--) = ipv6_addr[i])) if (!(i&3)) *(ptr--) = ':';
+
+        // Convert to binary and back to get abbreviated :: version
+        if (inet_pton(AF_INET6, ipv6_addr, (void *)&s6.sin6_addr) > 0) {
+          if (inet_ntop(AF_INET6, &s6.sin6_addr, toybuf, sizeof(toybuf))) {
+            char *scopes[] = {"Global","Host","Link","Site","Compat"},
+                 *scope = "Unknown";
+
+            for (i=0; i < sizeof(scopes)/sizeof(*scopes); i++)
+              if (iscope == (!!i)<<(i+3)) scope = scopes[i];
+            xprintf("%10cinet6 addr: %s/%d Scope: %s\n",
+                    ' ', toybuf, plen, scope);
+          }
+        }
+      }
+    }
+    fclose(fp);
+  }
+
+  xprintf("%10c", ' ');
+
+  if (flags) {
+    unsigned short mask = 1;
+    char **s, *str[] = {
+      "UP", "BROADCAST", "DEBUG", "LOOPBACK", "POINTOPOINT", "NOTRAILERS",
+      "RUNNING", "NOARP", "PROMISC", "ALLMULTI", "MASTER", "SLAVE", "MULTICAST",
+      "PORTSEL", "AUTOMEDIA", "DYNAMIC", NULL
+    };
+
+    for (s = str; *s; s++) {
+      if (flags & mask) xprintf("%s ", *s);
+      mask = mask << 1;
+    }
+  } else xprintf("[NO FLAGS] ");
+
+  if (ioctl(TT.sockfd, SIOCGIFMTU, &ifre) < 0) ifre.ifr_mtu = 0;
+  xprintf(" MTU:%d", ifre.ifr_mtu);
+  if (ioctl(TT.sockfd, SIOCGIFMETRIC, &ifre) < 0) ifre.ifr_metric = 0;
+  if (!ifre.ifr_metric) ifre.ifr_metric = 1;
+  xprintf("  Metric:%d", ifre.ifr_metric);
+
+  // non-virtual interface
+
+  if (val) {
+    char *label[] = {"RX bytes", "RX packets", "errors", "dropped", "overruns",
+      "frame", 0, 0, "TX bytes", "TX packets", "errors", "dropped", "overruns",
+      "collisions", "carrier", 0, "txqueuelen"};
+    signed char order[] = {-1, 1, 2, 3, 4, 5, -1, 9, 10, 11, 12, 14, -1,
+      13, 16, -1, 0, 8};
+    int i;
+
+    // Query txqueuelen
+    if (ioctl(TT.sockfd, SIOCGIFTXQLEN, &ifre) >= 0) val[16] = ifre.ifr_qlen;
+    else val[16] = -1;
+
+    for (i = 0; i < sizeof(order); i++) {
+      int j = order[i];
+
+      if (j < 0) xprintf("\n%10c", ' ');
+      else xprintf("%s:%llu ", label[j], val[j]);
+    }
+  }
+  xputc('\n');
+
+  if(!ioctl(TT.sockfd, SIOCGIFMAP, &ifre) && (ifre.ifr_map.irq ||
+      ifre.ifr_map.mem_start || ifre.ifr_map.dma || ifre.ifr_map.base_addr))
+  {
+    xprintf("%10c", ' ');
+    if(ifre.ifr_map.irq) xprintf("Interrupt:%d ", ifre.ifr_map.irq);
+    if(ifre.ifr_map.base_addr >= 0x100) // IO_MAP_INDEX
+      xprintf("Base address:0x%x ", ifre.ifr_map.base_addr);
+    if(ifre.ifr_map.mem_start)
+      xprintf("Memory:%lx-%lx ", ifre.ifr_map.mem_start, ifre.ifr_map.mem_end);
+    if(ifre.ifr_map.dma) xprintf("DMA chan:%x ", ifre.ifr_map.dma);
+    xputc('\n');
+  }
+  xputc('\n');
+}
+
+static void show_iface(char *iface_name)
+{
+  char *name;
+  struct string_list *ifaces = 0, *sl;
+  int i, j;
+  FILE *fp;
+
+  fp = xfopen("/proc/net/dev", "r");
+
+  for (i=0; fgets(toybuf, sizeof(toybuf), fp); i++) {
+    char *buf = toybuf;
+    unsigned long long val[17];
+
+    if (i<2) continue;
+
+    while (isspace(*buf)) buf++;
+    name = strsep(&buf, ":");
+    if(!buf) error_exit("bad name %s", name);
+
+    errno = 0;
+    for (j=0; j<16 && !errno; j++) val[j] = strtoll(buf, &buf, 0);
+    if (errno) perror_exit("bad %s at %s", name, buf);
+
+    if (iface_name) {
+      if (!strcmp(iface_name, name)) {
+        display_ifconfig(iface_name, 1, val);
+
+        return;
+      }
+    } else {
+      sl = xmalloc(sizeof(*sl)+strlen(name)+1);
+      strcpy(sl->str, name);
+      sl->next = ifaces;
+      ifaces = sl;
+
+      display_ifconfig(sl->str, toys.optflags & FLAG_a, val);
+    }
+  }
+  fclose(fp);
+
+  if (iface_name) display_ifconfig(iface_name, 1, 0);
+  else {
+    struct ifconf ifcon;
+    struct ifreq *ifre;
+    int num;
+
+    // Loop until buffer's big enough
+    ifcon.ifc_buf = NULL;
+    for (num = 30;;num += 10) {
+      ifcon.ifc_len = sizeof(struct ifreq)*num;
+      ifcon.ifc_buf = xrealloc(ifcon.ifc_buf, ifcon.ifc_len);
+      xioctl(TT.sockfd, SIOCGIFCONF, &ifcon);
+      if (ifcon.ifc_len != sizeof(struct ifreq)*num) break;
+    }
+
+    ifre = ifcon.ifc_req;
+    for(num = 0; num < ifcon.ifc_len && ifre; num += sizeof(struct ifreq), ifre++)
+    {
+      // Skip duplicates
+      for(sl = ifaces; sl; sl = sl->next)
+        if(!strcmp(sl->str, ifre->ifr_name)) break;
+
+      if(!sl) display_ifconfig(ifre->ifr_name, toys.optflags & FLAG_a, 0);
+    }
+
+    free(ifcon.ifc_buf);
+  }
+
+  llist_traverse(ifaces, free);
+}
+
+// Encode offset and size of field into an int, and make result negative
+#define IFREQ_OFFSZ(x) -(int)((offsetof(struct ifreq, x)<<16) + sizeof(ifre.x))
+
+void ifconfig_main(void)
+{
+  char **argv = toys.optargs;
+  struct ifreq ifre;
+  int i;
+
+  TT.sockfd = xsocket(AF_INET, SOCK_DGRAM, 0);
+  if(toys.optc < 2) {
+    show_iface(*argv);
+    return;
+  }
+
+  // Open interface
+  memset(&ifre, 0, sizeof(struct ifreq));
+  xstrncpy(ifre.ifr_name, *argv, IFNAMSIZ);
+
+  // Perform operations on interface
+  while(*++argv) {
+    // Table of known operations
+    struct argh {
+      char *name;
+      int on, off; // set, clear
+    } try[] = {
+      {0, IFF_UP|IFF_RUNNING, SIOCSIFADDR},
+      {"up", IFF_UP|IFF_RUNNING, 0},
+      {"down", 0, IFF_UP},
+      {"arp", 0, IFF_NOARP},
+      {"promisc", IFF_PROMISC, 0},
+      {"allmulti", IFF_ALLMULTI, 0},
+      {"multicast", IFF_MULTICAST, 0},
+      {"pointopoint", IFF_POINTOPOINT, SIOCSIFDSTADDR},
+      {"broadcast", IFF_BROADCAST, SIOCSIFBRDADDR},
+      {"netmask", 0, SIOCSIFNETMASK},
+      {"dstaddr", 0, SIOCSIFDSTADDR},
+      {"mtu", IFREQ_OFFSZ(ifr_mtu), SIOCSIFMTU},
+      {"keepalive", IFREQ_OFFSZ(ifr_data), SIOCDEVPRIVATE}, // SIOCSKEEPALIVE
+      {"outfill", IFREQ_OFFSZ(ifr_data), SIOCDEVPRIVATE+2}, // SIOCSOUTFILL
+      {"metric", IFREQ_OFFSZ(ifr_metric), SIOCSIFMETRIC},
+      {"txqueuelen", IFREQ_OFFSZ(ifr_qlen), SIOCSIFTXQLEN},
+      {"mem_start", IFREQ_OFFSZ(ifr_map.mem_start), SIOCSIFMAP},
+      {"io_addr", IFREQ_OFFSZ(ifr_map.base_addr), SIOCSIFMAP},
+      {"irq", IFREQ_OFFSZ(ifr_map.irq), SIOCSIFMAP},
+      {"inet", 0, 0},
+      {"inet6", 0, 0}
+    };
+    char *s = *argv;
+    int rev = (*s == '-');
+
+    s += rev;
+
+    // "set hardware address" is oddball enough to special case
+    if (!strcmp(*argv, "hw")) {
+      char *hw_addr, *ptr, *p;
+      struct sockaddr *sock = &ifre.ifr_hwaddr;
+      int count = 6;
+
+      ptr = p = (char *)sock->sa_data;
+      memset(sock, 0, sizeof(struct sockaddr));
+      if (argv[1]) {
+        if (!strcmp("ether", *++argv)) sock->sa_family = ARPHRD_ETHER;
+        else if (!strcmp("infiniband", *argv)) {
+          sock->sa_family = ARPHRD_INFINIBAND;
+          count = 20;
+          p = ptr = toybuf;
+        }
+      }
+      if (!sock->sa_family || !argv[1]) help_exit("bad hw '%s'", *argv);
+      hw_addr = *++argv;
+
+      // Parse and verify address.
+      while (*hw_addr && (p-ptr) < count) {
+        int val, len = 0;
+
+        if (*hw_addr == ':') hw_addr++;
+        sscanf(hw_addr, "%2x%n", &val, &len);
+        if (!len || len > 2) break; // 1 nibble can be set e.g. C2:79:38:95:D:A 
+        hw_addr += len;
+        *p++ = val;
+      }
+
+      if ((p-ptr) != count || *hw_addr)
+        error_exit("bad hw-addr '%s'", *argv);
+
+      // the linux kernel's "struct sockaddr" (include/linux/socket.h in the
+      // kernel source) only has 14 bytes of sa_data, and an infiniband address
+      // is 20. So if we go through the ioctl, the kernel will truncate
+      // infiniband addresses, meaning we have to go through sysfs instead.
+      if (sock->sa_family == ARPHRD_INFINIBAND && !strchr(ifre.ifr_name, '/')) {
+        int fd;
+
+        sprintf(toybuf, "/sys/class/net/%s/address", ifre.ifr_name);
+        fd = xopen(toybuf, O_RDWR);
+        xwrite(fd, *argv, strlen(*argv));
+        close(fd);
+      } else xioctl(TT.sockfd, SIOCSIFHWADDR, &ifre);
+      continue;
+
+    // Add/remove ipv6 address to interface
+
+    } else if (!strcmp(*argv, "add") || !strcmp(*argv, "del")) {
+      struct ifreq_inet6 {
+        struct in6_addr addr;
+        unsigned prefix;
+        int index;
+      } ifre6;
+      int plen, fd6 = xsocket(AF_INET6, SOCK_DGRAM, 0);
+
+      if (!argv[1]) help_exit("%s", *argv);
+
+      plen = get_addrinfo(argv[1], AF_INET6, &ifre6.addr);
+      if (plen < 0) plen = 128;
+      xioctl(fd6, SIOCGIFINDEX, &ifre);
+      ifre6.index = ifre.ifr_ifindex;
+      ifre6.prefix = plen;
+      xioctl(fd6, **(argv++)=='a' ? SIOCSIFADDR : SIOCDIFADDR, &ifre6);
+
+      close(fd6);
+      continue;
+    // Iterate through table to find/perform operation
+    } else for (i = 0; i < ARRAY_LEN(try); i++) {
+      struct argh *t = try+i;
+      int on = t->on, off = t->off;
+
+      if (!t->name) {
+        if (isdigit(**argv) || !strcmp(*argv, "default")) argv--;
+        else continue;
+      } else if (strcmp(t->name, s)) continue;
+
+      // Is this an SIOCSI entry?
+      if ((off|0xff) == 0x89ff) {
+        if (!rev) {
+          if (!*++argv) error_exit("%s needs argument", t->name);
+
+          // Assign value to ifre field and call ioctl? (via IFREQ_OFFSZ.)
+          if (on < 0) {
+            long l = strtoul(*argv, 0, 0);
+
+            if (off == SIOCSIFMAP) xioctl(TT.sockfd, SIOCGIFMAP, &ifre);
+            on = -on;
+            poke((on>>16) + (char *)&ifre, l, on&15);
+            xioctl(TT.sockfd, off, &ifre);
+            break;
+          } else {
+            struct sockaddr_in *si = (struct sockaddr_in *)&ifre.ifr_addr;
+            int mask = -1;
+
+            si->sin_family = AF_INET;
+
+            if (!strcmp(*argv, "default")) si->sin_addr.s_addr = INADDR_ANY;
+            else mask = get_addrinfo(*argv, AF_INET, &si->sin_addr);
+            xioctl(TT.sockfd, off, &ifre);
+
+            // Handle /netmask
+            if (mask >= 0) {
+              // sin_addr probably isn't unaligned, but just in case...
+              mask = htonl((~0)<<(32-mask));
+              memcpy(&si->sin_addr, &mask, 4);
+              xioctl(TT.sockfd, SIOCSIFNETMASK, &ifre);
+            }
+          }
+        }
+        off = 0;
+      }
+
+      // Set flags
+      if (on || off) {
+        xioctl(TT.sockfd, SIOCGIFFLAGS, &ifre);
+        ifre.ifr_flags &= ~(rev ? on : off);
+        ifre.ifr_flags |= (rev ? off : on);
+        xioctl(TT.sockfd, SIOCSIFFLAGS, &ifre);
+      }
+
+      break;
+    }
+    if (i == sizeof(try)/sizeof(*try)) help_exit("bad argument '%s'", *argv);
+  }
+  close(TT.sockfd);
+}
diff --git a/toybox/toys/net/netcat.c b/toybox/toys/net/netcat.c
new file mode 100644
index 0000000..1c75eb2
--- /dev/null
+++ b/toybox/toys/net/netcat.c
@@ -0,0 +1,230 @@
+/* netcat.c - Forward stdin/stdout to a file or network connection.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * TODO: udp, ipv6, genericize for telnet/microcom/tail-f
+
+USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
+USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#p#s:q#f:", TOYFLAG_BIN))
+
+config NETCAT
+  bool "netcat"
+  default y
+  help
+    usage: netcat [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}
+
+    -f	use FILENAME (ala /dev/ttyS0) instead of network
+    -p	local port number
+    -q	SECONDS quit this many seconds after EOF on stdin.
+    -s	local ipv4 address
+    -w	SECONDS timeout for connection
+
+    Use "stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho" with
+    netcat -f to connect to a serial port.
+
+config NETCAT_LISTEN
+  bool "netcat server options (-let)"
+  default y
+  depends on NETCAT
+  depends on TOYBOX_FORK
+  help
+    usage: netcat [-lL COMMAND...]
+
+    -l	listen for one incoming connection.
+    -L	listen for multiple incoming connections (server mode).
+
+    The command line after -l or -L is executed to handle each incoming
+    connection. If none, the connection is forwarded to stdin/stdout.
+
+    For a quick-and-dirty server, try something like:
+    netcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l
+
+config NETCAT_LISTEN_TTY
+  bool
+  default y
+  depends on NETCAT_LISTEN
+  depends on TOYBOX_FORK
+  help
+    usage: netcat [-t]
+
+    -t	allocate tty (must come before -l or -L)
+*/
+
+#define FOR_netcat
+#include "toys.h"
+
+GLOBALS(
+  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.
+)
+
+static void timeout(int signum)
+{
+  if (TT.wait) error_exit("Timeout");
+  // This should be xexit() but would need siglongjmp()...
+  exit(0);
+}
+
+static void set_alarm(int seconds)
+{
+  xsignal(SIGALRM, seconds ? timeout : SIG_DFL);
+  alarm(seconds);
+}
+
+// Translate x.x.x.x numeric IPv4 address, or else DNS lookup an IPv4 name.
+static void lookup_name(char *name, uint32_t *result)
+{
+  struct hostent *hostbyname;
+
+  hostbyname = gethostbyname(name); // getaddrinfo
+  if (!hostbyname) error_exit("no host '%s'", name);
+  *result = *(uint32_t *)*hostbyname->h_addr_list;
+}
+
+// Worry about a fancy lookup later.
+static void lookup_port(char *str, uint16_t *port)
+{
+  *port = SWAP_BE16(atoi(str));
+}
+
+void netcat_main(void)
+{
+  int sockfd=-1, pollcount=2;
+  struct pollfd pollfds[2];
+
+  memset(pollfds, 0, 2*sizeof(struct pollfd));
+  pollfds[0].events = pollfds[1].events = POLLIN;
+  set_alarm(TT.wait);
+
+  // The argument parsing logic can't make "<2" conditional on other
+  // arguments like -f and -l, so we do it by hand here.
+  if ((toys.optflags&FLAG_f) ? toys.optc :
+      (!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2))
+        help_exit("Argument count wrong");
+
+  if (TT.filename) pollfds[0].fd = xopen(TT.filename, O_RDWR);
+  else {
+    int temp;
+    struct sockaddr_in address;
+
+    // Setup socket
+    sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
+    fcntl(sockfd, F_SETFD, FD_CLOEXEC);
+    temp = 1;
+    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp));
+    memset(&address, 0, sizeof(address));
+    address.sin_family = AF_INET;
+    if (TT.source_address || TT.port) {
+      address.sin_port = SWAP_BE16(TT.port);
+      if (TT.source_address)
+        lookup_name(TT.source_address, (uint32_t *)&address.sin_addr);
+      if (bind(sockfd, (struct sockaddr *)&address, sizeof(address)))
+        perror_exit("bind");
+    }
+
+    // Dial out
+
+    if (!CFG_NETCAT_LISTEN || !(toys.optflags&(FLAG_L|FLAG_l))) {
+      // Figure out where to dial out to.
+      lookup_name(*toys.optargs, (uint32_t *)&address.sin_addr);
+      lookup_port(toys.optargs[1], &address.sin_port);
+      temp = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
+      if (temp<0) perror_exit("connect");
+      pollfds[0].fd = sockfd;
+
+    // Listen for incoming connections
+
+    } else {
+      socklen_t len = sizeof(address);
+
+      if (listen(sockfd, 5)) error_exit("listen");
+      if (!TT.port) {
+        getsockname(sockfd, (struct sockaddr *)&address, &len);
+        printf("%d\n", SWAP_BE16(address.sin_port));
+        fflush(stdout);
+      }
+      // Do we need to return immediately because -l has arguments?
+
+      if ((toys.optflags & FLAG_l) && toys.optc) {
+        if (CFG_TOYBOX_FORK && xfork()) goto cleanup;
+        close(0);
+        close(1);
+        close(2);
+      }
+
+      for (;;) {
+        pid_t child = 0;
+
+        // For -l, call accept from the _new_ process.
+
+        pollfds[0].fd = accept(sockfd, (struct sockaddr *)&address, &len);
+        if (pollfds[0].fd<0) perror_exit("accept");
+
+        // Do we need a tty?
+
+        if (toys.optflags&FLAG_t)
+          child = forkpty(&(pollfds[1].fd), NULL, NULL, NULL);
+
+        // Do we need to fork and/or redirect for exec?
+
+        else {
+          if (toys.optflags&FLAG_L) {
+            toys.stacktop = 0;
+            child = vfork();
+          }
+          if (!child && toys.optc) {
+            int fd = pollfds[0].fd;
+
+            dup2(fd, 0);
+            dup2(fd, 1);
+            if (toys.optflags&FLAG_L) dup2(fd, 2);
+            if (fd>2) close(fd);
+          }
+        }
+
+        if (child<0) error_msg("Fork failed\n");
+        if (child<1) break;
+        close(pollfds[0].fd);
+      }
+    }
+  }
+
+  // We have a connection.  Disarm timeout.
+  // (Does not play well with -L, but what _should_ that do?)
+  set_alarm(0);
+
+  if (CFG_NETCAT_LISTEN && ((toys.optflags&(FLAG_L|FLAG_l)) && toys.optc))
+    xexec(toys.optargs);
+
+  // Poll loop copying stdin->socket and socket->stdout.
+  for (;;) {
+    int i;
+
+    if (0>poll(pollfds, pollcount, -1)) perror_exit("poll");
+
+    for (i=0; i<pollcount; i++) {
+      if (pollfds[i].revents & POLLIN) {
+        int len = read(pollfds[i].fd, toybuf, sizeof(toybuf));
+        if (len<1) goto dohupnow;
+        xwrite(i ? pollfds[0].fd : 1, toybuf, len);
+      } else if (pollfds[i].revents & POLLHUP) {
+dohupnow:
+        // Close half-connection.  This is needed for things like
+        // "echo GET / | netcat landley.net 80"
+        if (i) {
+          shutdown(pollfds[0].fd, SHUT_WR);
+          pollcount--;
+          set_alarm(TT.quit_delay);
+        } else goto cleanup;
+      }
+    }
+  }
+cleanup:
+  if (CFG_TOYBOX_FREE) {
+    close(pollfds[0].fd);
+    close(sockfd);
+  }
+}
diff --git a/toybox/toys/net/netstat.c b/toybox/toys/net/netstat.c
new file mode 100644
index 0000000..4e5c884
--- /dev/null
+++ b/toybox/toys/net/netstat.c
@@ -0,0 +1,383 @@
+/* netstat.c - Display Linux networking subsystem.
+ *
+ * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * Not in SUSv4.
+ *
+USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN))
+config NETSTAT
+  bool "netstat"
+  default y
+  help
+    usage: netstat [-pWrxwutneal]
+
+    Display networking information. Default is netsat -tuwx
+
+    -r  routing table
+    -a  all sockets (not just connected)
+    -l  listening server sockets
+    -t  TCP sockets
+    -u  UDP sockets
+    -w  raw sockets
+    -x  unix sockets
+    -e  extended info
+    -n  don't resolve names
+    -W  wide display
+    -p  PID/Program name of sockets
+*/
+
+#define FOR_netstat
+#include "toys.h"
+#include <net/route.h>
+
+GLOBALS(
+  struct num_cache *inodes;
+  int wpad;
+);
+
+// convert address into text format.
+static void addr2str(int af, void *addr, unsigned port, char *buf, int len,
+  char *proto)
+{
+  int pos, count;
+  struct servent *ser = 0;
+
+  // Convert to numeric address
+  if (!inet_ntop(af, addr, buf, 256)) {
+    *buf = 0;
+
+    return;
+  }
+  buf[len] = 0;
+  pos = strlen(buf);
+
+  // If there's no port number, it's a local :* binding, nothing to look up.
+  if (!port) {
+    if (len-pos<2) pos = len-2;
+    strcpy(buf+pos, ":*");
+
+    return;
+  }
+
+  if (!(toys.optflags & FLAG_n)) {
+    struct addrinfo hints, *result, *rp;
+    char cut[4];
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_family = af;
+
+    if (!getaddrinfo(buf, NULL, &hints, &result)) {
+      socklen_t sock_len = (af == AF_INET) ? sizeof(struct sockaddr_in)
+        : sizeof(struct sockaddr_in6);
+
+      // We assume that a failing getnameinfo dosn't stomp "buf" here.
+      for (rp = result; rp; rp = rp->ai_next)
+        if (!getnameinfo(rp->ai_addr, sock_len, buf, 256, 0, 0, 0)) break;
+      freeaddrinfo(result);
+      buf[len] = 0;
+      pos = strlen(buf);
+    }
+
+    // Doesn't understand proto "tcp6", so truncate
+    memcpy(cut, proto, 3);
+    cut[3] = 0;
+    ser = getservbyport(htons(port), cut);
+  }
+
+  // Append :service
+  count = snprintf(0, 0, ":%u", port);
+  if (ser) {
+    count = snprintf(0, 0, ":%s", ser->s_name);
+    // sheer paranoia
+    if (count>=len) {
+      count = len-1;
+      ser->s_name[count] = 0;
+    }
+  }
+  if (len-pos<count) pos = len-count;
+  if (ser) sprintf(buf+pos, ":%s", ser->s_name);
+  else sprintf(buf+pos, ":%u", port);
+}
+
+// Display info for tcp/udp/raw
+static void show_ip(char *fname)
+{
+  char *ss_state = "UNKNOWN", buf[12], *s, *label = strrchr(fname, '/')+1;
+  char *state_label[] = {"", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1",
+                         "FIN_WAIT2", "TIME_WAIT", "CLOSE", "CLOSE_WAIT",
+                         "LAST_ACK", "LISTEN", "CLOSING", "UNKNOWN"};
+  struct passwd *pw;
+  FILE *fp = fopen(fname, "r");
+
+  if (!fp) {
+     perror_msg("'%s'", fname);
+     return;
+  }
+
+  if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
+
+  while (fgets(toybuf, sizeof(toybuf), fp)) {
+    char lip[256], rip[256];
+    union {
+      struct {unsigned u; unsigned char b[4];} i4;
+      struct {struct {unsigned a, b, c, d;} u; unsigned char b[16];} i6;
+    } laddr, raddr;
+    unsigned lport, rport, state, txq, rxq, num, uid, nitems;
+    unsigned long inode;
+
+    // Try ipv6, then try ipv4
+    nitems = sscanf(toybuf,
+      " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x %*X:%*X %*X %d %*d %ld",
+      &num, &laddr.i6.u.a, &laddr.i6.u.b, &laddr.i6.u.c,
+      &laddr.i6.u.d, &lport, &raddr.i6.u.a, &raddr.i6.u.b,
+      &raddr.i6.u.c, &raddr.i6.u.d, &rport, &state, &txq, &rxq,
+      &uid, &inode);
+
+    if (nitems!=16) {
+      nitems = sscanf(toybuf,
+        " %d: %x:%x %x:%x %x %x:%x %*X:%*X %*X %d %*d %ld",
+        &num, &laddr.i4.u, &lport, &raddr.i4.u, &rport, &state, &txq,
+        &rxq, &uid, &inode);
+
+      if (nitems!=10) continue;
+      nitems = AF_INET;
+    } else nitems = AF_INET6;
+
+    // Should we display this? (listening or all or TCP/UDP/RAW)
+    if (!((toys.optflags & FLAG_l) && (!rport && (state & 0xA)))
+      && !(toys.optflags & FLAG_a) && !(rport & (0x10 | 0x20 | 0x40)))
+        continue;
+
+    addr2str(nitems, &laddr, lport, lip, TT.wpad, label);
+    addr2str(nitems, &raddr, rport, rip, TT.wpad, label);
+
+    // Display data
+    s = label;
+    if (strstart(&s, "tcp")) {
+      int sz = ARRAY_LEN(state_label);
+      if (!state || state >= sz) state = sz-1;
+      ss_state = state_label[state];
+    } else if (strstart(&s, "udp")) {
+      if (state == 1) ss_state = state_label[state];
+      else if (state == 7) ss_state = "";
+    } else if (strstart(&s, "raw")) sprintf(ss_state = buf, "%u", state);
+
+    if (!(toys.optflags & FLAG_n) && (pw = bufgetpwuid(uid)))
+      snprintf(toybuf, sizeof(toybuf), "%s", pw->pw_name);
+    else snprintf(toybuf, sizeof(toybuf), "%d", uid);
+
+    printf("%-6s%6d%7d ", label, rxq, txq);
+    printf("%*.*s %*.*s ", -TT.wpad, TT.wpad, lip, -TT.wpad, TT.wpad, rip);
+    printf("%-11s", ss_state);
+    if ((toys.optflags & FLAG_e)) printf(" %-10s %-11ld", toybuf, inode);
+    if ((toys.optflags & FLAG_p)) {
+      struct num_cache *nc = get_num_cache(TT.inodes, inode);
+
+      printf(" %s", nc ? nc->data : "-");
+    }
+    xputc('\n');
+  }
+  fclose(fp);
+}
+
+static void show_unix_sockets(void)
+{
+  char *types[] = {"","STREAM","DGRAM","RAW","RDM","SEQPACKET","DCCP","PACKET"},
+       *states[] = {"","LISTENING","CONNECTING","CONNECTED","DISCONNECTING"},
+       *s, *ss;
+  unsigned long refcount, flags, type, state, inode;
+  FILE *fp = xfopen("/proc/net/unix", "r");
+
+  if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
+
+  while (fgets(toybuf, sizeof(toybuf), fp)) {
+    unsigned offset = 0;
+
+    // count = 6 or 7 (first field ignored, sockets don't always have filenames)
+    if (6<sscanf(toybuf, "%*p: %lX %*X %lX %lX %lX %lu %n",
+      &refcount, &flags, &type, &state, &inode, &offset))
+        continue;
+
+    // Linux exports only SO_ACCEPTCON since 2.3.15pre3 in 1999, but let's
+    // filter in case they add more someday.
+    flags &= 1<<16;
+
+    // Only show unconnected listening sockets with -a
+    if (state==1 && flags && !(toys.optflags&FLAG_a)) continue;
+
+    if (type==10) type = 7; // move SOCK_PACKET into line
+    if (type>ARRAY_LEN(types)) type = 0;
+    if (state>ARRAY_LEN(states) || (state==1 && !flags)) state = 0;
+    sprintf(toybuf, "[ %s]", flags ? "ACC " : "");
+
+    printf("unix  %-6ld %-11s %-10s %-13s %8lu ",
+      refcount, toybuf, types[type], states[state], inode);
+    if (toys.optflags & FLAG_p) {
+      struct num_cache *nc = get_num_cache(TT.inodes, inode);
+
+      printf("%-19.19s", nc ? nc->data : "-");
+    }
+
+    if (offset) {
+      if ((ss = strrchr(s = toybuf+offset, '\n'))) *ss = 0;
+      printf("%s", s);
+    }
+    xputc('\n');
+  }
+
+  fclose(fp);
+}
+
+static int scan_pids(struct dirtree *node)
+{
+  char *s = toybuf+256;
+  struct dirent *entry;
+  DIR *dp;
+  int pid, dirfd;
+
+  if (!node->parent) return DIRTREE_RECURSE;
+  if (!(pid = atol(node->name))) return 0;
+
+  sprintf(toybuf, "/proc/%d/cmdline", pid);
+  if (!(readfile(toybuf, toybuf, 256))) return 0;
+
+  sprintf(s, "%d/fd", pid);
+  if (-1==(dirfd = openat(dirtree_parentfd(node), s, O_RDONLY))) return 0;
+  if (!(dp = fdopendir(dirfd))) {
+    close(dirfd);
+
+    return 0;
+  }
+
+  while ((entry = readdir(dp))) {
+    s = toybuf+256;
+    if (!readlinkat0(dirfd, entry->d_name, s, sizeof(toybuf)-256)) continue;
+    // Can the "[0000]:" happen in a modern kernel?
+    if (strstart(&s, "socket:[") || strstart(&s, "[0000]:")) {
+      long long ll = atoll(s);
+
+      sprintf(s, "%d/%s", pid, getbasename(toybuf));
+      add_num_cache(&TT.inodes, ll, s, strlen(s)+1);
+    }
+  }
+  closedir(dp);
+
+  return 0;
+}
+
+/*
+ * extract inet4 route info from /proc/net/route file and display it.
+ */
+static void display_routes(void)
+{
+  static const char flagchars[] = "GHRDMDAC";
+  static const unsigned flagarray[] = {
+    RTF_GATEWAY, RTF_HOST, RTF_REINSTATE, RTF_DYNAMIC, RTF_MODIFIED
+  };
+  unsigned long dest, gate, mask;
+  int flags, ref, use, metric, mss, win, irtt;
+  char *out = toybuf, *flag_val;
+  char iface[64]={0};
+  FILE *fp = xfopen("/proc/net/route", "r");
+
+  if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
+
+  printf("Kernel IP routing table\n"
+          "Destination\tGateway \tGenmask \tFlags %s Iface\n",
+          !(toys.optflags&FLAG_e) ? "  MSS Window  irtt" : "Metric Ref    Use");
+
+  while (fgets(toybuf, sizeof(toybuf), fp)) {
+     char *destip = 0, *gateip = 0, *maskip = 0;
+
+     if (11 != sscanf(toybuf, "%63s%lx%lx%X%d%d%d%lx%d%d%d", iface, &dest,
+       &gate, &flags, &ref, &use, &metric, &mask, &mss, &win, &irtt))
+         break;
+
+    // skip down interfaces.
+    if (!(flags & RTF_UP)) continue;
+
+// TODO /proc/net/ipv6_route
+
+    if (dest) {
+      if (inet_ntop(AF_INET, &dest, out, 16)) destip = out;
+    } else destip = (toys.optflags&FLAG_n) ? "0.0.0.0" : "default";
+    out += 16;
+
+    if (gate) {
+      if (inet_ntop(AF_INET, &gate, out, 16)) gateip = out;
+    } else gateip = (toys.optflags&FLAG_n) ? "0.0.0.0" : "*";
+    out += 16;
+
+// TODO /24
+    //For Mask
+    if (inet_ntop(AF_INET, &mask, out, 16)) maskip = out;
+    else maskip = "?";
+    out += 16;
+
+    //Get flag Values
+    flag_val = out;
+    *out++ = 'U';
+    for (dest = 0; dest < ARRAY_LEN(flagarray); dest++)
+      if (flags&flagarray[dest]) *out++ = flagchars[dest];
+    *out = 0;
+    if (flags & RTF_REJECT) *flag_val = '!';
+
+    printf("%-15.15s %-15.15s %-16s%-6s", destip, gateip, maskip, flag_val);
+    if (!(toys.optflags & FLAG_e))
+      printf("%5d %-5d %6d %s\n", mss, win, irtt, iface);
+    else printf("%-6d %-2d %7d %s\n", metric, ref, use, iface);
+  }
+
+  fclose(fp);
+}
+
+void netstat_main(void)
+{
+  int tuwx = FLAG_t|FLAG_u|FLAG_w|FLAG_x;
+  char *type = "w/o";
+
+  TT.wpad = (toys.optflags&FLAG_W) ? 51 : 23;
+  if (!(toys.optflags&(FLAG_r|tuwx))) toys.optflags |= tuwx;
+  if (toys.optflags & FLAG_r) display_routes();
+  if (!(toys.optflags&tuwx)) return;
+
+  if (toys.optflags & FLAG_a) type = "established and";
+  else if (toys.optflags & FLAG_l) type = "only";
+
+  if (toys.optflags & FLAG_p) dirtree_read("/proc", scan_pids);
+
+  if (toys.optflags&(FLAG_t|FLAG_u|FLAG_w)) {
+    printf("Active %s (%s servers)\n", "Internet connections", type);
+    printf("Proto Recv-Q Send-Q %*s %*s State      ", -TT.wpad, "Local Address",
+      -TT.wpad, "Foreign Address");
+    if (toys.optflags & FLAG_e) printf(" User       Inode      ");
+    if (toys.optflags & FLAG_p) printf(" PID/Program Name");
+    xputc('\n');
+
+    if (toys.optflags & FLAG_t) {
+      show_ip("/proc/net/tcp");
+      show_ip("/proc/net/tcp6");
+    }
+    if (toys.optflags & FLAG_u) {
+      show_ip("/proc/net/udp");
+      show_ip("/proc/net/udp6");
+    }
+    if (toys.optflags & FLAG_w) {
+      show_ip("/proc/net/raw");
+      show_ip("/proc/net/raw6");
+    }
+  }
+
+  if (toys.optflags & FLAG_x) {
+    printf("Active %s (%s servers)\n", "UNIX domain sockets", type);
+
+    printf("Proto RefCnt Flags\t Type\t    State\t    %s Path\n",
+      (toys.optflags&FLAG_p) ? "PID/Program Name" : "I-Node");
+    show_unix_sockets();
+  }
+
+  if ((toys.optflags & FLAG_p) && CFG_TOYBOX_FREE)
+    llist_traverse(TT.inodes, free);
+  toys.exitval = 0;
+}
diff --git a/toybox/toys/net/rfkill.c b/toybox/toys/net/rfkill.c
new file mode 100644
index 0000000..56e5768
--- /dev/null
+++ b/toybox/toys/net/rfkill.c
@@ -0,0 +1,102 @@
+/* rfkill.c - Enable/disable wireless devices.
+ *
+ * Copyright 2014 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+
+USE_RFKILL(NEWTOY(rfkill, "<1>2", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config RFKILL
+  bool "rfkill"
+  default y
+  help
+    Usage: rfkill COMMAND [DEVICE]
+
+    Enable/disable wireless devices.
+
+    Commands:
+    list [DEVICE]   List current state
+    block DEVICE    Disable device
+    unblock DEVICE  Enable device
+
+    DEVICE is an index number, or one of:
+    all, wlan(wifi), bluetooth, uwb(ultrawideband), wimax, wwan, gps, fm.
+*/
+
+#define FOR_rfkill
+#include "toys.h"
+#include <linux/rfkill.h>
+
+void rfkill_main(void)
+{
+  struct rfkill_event rfevent;
+  int fd, tvar, idx = -1, tid = RFKILL_TYPE_ALL;
+  char **optargs = toys.optargs;
+
+  // Parse command line options
+  for (tvar = 0; tvar < 3; tvar++)
+    if (!strcmp((char *[]){"list", "block", "unblock"}[tvar], *optargs)) break;
+  if (tvar == 3) error_exit("unknown cmd '%s'", *optargs);
+  if (tvar) {
+    int i;
+    struct arglist {
+      char *name;
+      int idx;
+    } rftypes[] = {{"all", RFKILL_TYPE_ALL}, {"wifi", RFKILL_TYPE_WLAN},
+      {"wlan", RFKILL_TYPE_WLAN}, {"bluetooth", RFKILL_TYPE_BLUETOOTH},
+      {"uwb", RFKILL_TYPE_UWB}, {"ultrawideband", RFKILL_TYPE_UWB},
+      {"wimax", RFKILL_TYPE_WIMAX}, {"wwan", RFKILL_TYPE_WWAN},
+      {"gps", RFKILL_TYPE_GPS}, {"fm", 7}}; // RFKILL_TYPE_FM = 7
+
+    if (!*++optargs) error_exit("'%s' needs IDENTIFIER", optargs[-1]);
+    for (i = 0; i < ARRAY_LEN(rftypes); i++)
+      if (!strcmp(rftypes[i].name, *optargs)) break;
+    if (i == ARRAY_LEN(rftypes)) idx = atolx_range(*optargs, 0, INT_MAX);
+    else tid = rftypes[i].idx;
+  }
+
+  // Perform requested action
+  fd = xopen("/dev/rfkill", (tvar ? O_RDWR : O_RDONLY)|O_NONBLOCK);
+  if (tvar) {
+    // block/unblock
+    memset(&rfevent, 0, sizeof(rfevent));
+    rfevent.soft = tvar == 1;
+    if (idx >= 0) {
+      rfevent.idx = idx;
+      rfevent.op = RFKILL_OP_CHANGE;
+    } else {
+      rfevent.type = tid;
+      rfevent.op = RFKILL_OP_CHANGE_ALL;
+    }
+    xwrite(fd, &rfevent, sizeof(rfevent));
+  } else {
+    // show list.
+    while (sizeof(rfevent) == readall(fd, &rfevent, sizeof(rfevent))) {
+      char *line, *name = 0, *type = 0;
+
+      // filter list items
+      if ((tid > 0 && tid != rfevent.type) || (idx != -1 && idx != rfevent.idx))
+        continue;
+
+      sprintf(toybuf, "/sys/class/rfkill/rfkill%u/uevent", rfevent.idx);
+      tvar = xopenro(toybuf);
+      while ((line = get_line(tvar))) {
+        char *s = line;
+
+        if (strstart(&s, "RFKILL_NAME=")) name = xstrdup(s);
+        else if (strstart(&s, "RFKILL_TYPE=")) type = xstrdup(s);
+
+        free(line);
+      }
+      xclose(tvar);
+
+      xprintf("%u: %s: %s\n", rfevent.idx, name, type);
+      xprintf("\tSoft blocked: %s\n", rfevent.soft ? "yes" : "no");
+      xprintf("\tHard blocked: %s\n", rfevent.hard ? "yes" : "no");
+      free(name);
+      free(type);
+    }
+  }
+  xclose(fd);
+}
diff --git a/toybox/toys/other/README b/toybox/toys/other/README
new file mode 100644
index 0000000..e16cd6f
--- /dev/null
+++ b/toybox/toys/other/README
@@ -0,0 +1,13 @@
+Other commands
+
+These are commands not present in Posix or LSB.
+
+Most of them are necessary to provide a development environment capable of
+booting a system image and building Linux From Scratch under it.
+
+Tested with Aboriginal Linux system image and the lfs-bootstrap.hdc automated
+build control image for Linux From Scratch 6.8):
+
+  http://landley.net/aboriginal
+
+  http://landley.net/aboriginal/control-images
diff --git a/toybox/toys/other/acpi.c b/toybox/toys/other/acpi.c
new file mode 100644
index 0000000..bca5381
--- /dev/null
+++ b/toybox/toys/other/acpi.c
@@ -0,0 +1,144 @@
+/* acpi.c - show power state
+ *
+ * Written by Isaac Dunham, 2013
+ *
+ * No standard.
+
+USE_ACPI(NEWTOY(acpi, "abctV", TOYFLAG_USR|TOYFLAG_BIN))
+
+config ACPI
+  bool "acpi"
+  default y
+  help
+    usage: acpi [-abctV]
+    
+    Show status of power sources and thermal devices.
+
+    -a	show power adapters
+    -b	show batteries
+    -c	show cooling device state
+    -t	show temperatures
+    -V	show everything
+*/
+
+#define FOR_acpi
+#include "toys.h"
+
+GLOBALS(
+  int ac, bat, therm, cool;
+  char *cpath;
+)
+
+int read_int_at(int dirfd, char *name)
+{
+  int fd, ret=0;
+  FILE *fil;
+
+  if ((fd = openat(dirfd, name, O_RDONLY)) < 0) return -1;
+  if (!fscanf(fil = xfdopen(fd, "r"), "%d", &ret)) perror_exit_raw(name);
+  fclose(fil);
+
+  return ret;
+}
+
+static int acpi_callback(struct dirtree *tree)
+{
+  int dfd, fd, len, on;
+
+  errno = 0;
+
+  if (tree->name[0]=='.') return 0;
+
+  if (!tree->parent)
+    return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
+
+  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
+    if ((fd = openat(dfd, "type", O_RDONLY)) < 0) goto done;
+    len = readall(fd, toybuf, sizeof(toybuf));
+    close(fd);
+    if (len < 1) goto done;
+
+    if (!strncmp(toybuf, "Battery", 7)) {
+      if ((toys.optflags & FLAG_b) || (!toys.optflags)) {
+        int cap = 0, curr = 0, max = 0;
+
+        if ((cap = read_int_at(dfd, "capacity")) < 0) {
+          if ((max = read_int_at(dfd, "charge_full")) > 0)
+            curr = read_int_at(dfd, "charge_now");
+          else if ((max = read_int_at(dfd, "energy_full")) > 0)
+            curr = read_int_at(dfd, "energy_now");
+          if (max > 0 && curr >= 0) cap = 100 * curr / max;
+        }
+        if (cap >= 0) printf("Battery %d: %d%%\n", TT.bat++, cap);
+      }
+    } else if (toys.optflags & FLAG_a) {
+      if ((on = read_int_at(dfd, "online")) >= 0)
+        printf("Adapter %d: %s-line\n", TT.ac++, (on ? "on" : "off"));
+    }
+done:
+    close(dfd);
+  }
+  free(TT.cpath);
+  return 0;
+}
+
+static int temp_callback(struct dirtree *tree)
+{
+  int dfd, temp;
+
+  if (*tree->name=='.') return 0;
+  if (!tree->parent || !tree->parent->parent)
+    return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
+  errno = 0;
+
+  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
+    if ((0 < (temp = read_int_at(dfd, "temp"))) || !errno) {
+      //some tempertures are in milli-C, some in deci-C
+      //reputedly some are in deci-K, but I have not seen them
+      if (((temp >= 1000) || (temp <= -1000)) && (temp%100 == 0)) temp /= 100;
+      printf("Thermal %d: %d.%d degrees C\n", TT.therm++, temp/10, temp%10);
+    }
+    close(dfd);
+  }
+  free(TT.cpath);
+
+  return 0;
+}
+
+static int cool_callback(struct dirtree *tree)
+{
+  int dfd=5, cur, max;
+
+  errno = 0;
+  memset(toybuf, 0, sizeof(toybuf));
+
+  if (*tree->name == '.') return 0;
+  if (!tree->parent) return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
+
+
+  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, &dfd)), O_RDONLY))) {
+    TT.cpath = strcat(TT.cpath, "/type");
+    if (readfile(TT.cpath, toybuf, 256) && !errno) {
+      toybuf[strlen(toybuf) -1] = 0;
+      cur=read_int_at(dfd, "cur_state");
+      max=read_int_at(dfd, "max_state");
+      if (errno)
+        printf("Cooling %d: %s no state information\n", TT.cool++, toybuf);
+      else printf("Cooling %d: %s %d of %d\n", TT.cool++, toybuf, cur, max);
+    }
+    close(dfd);
+  }
+  free(TT.cpath);
+  return 0;
+}
+
+void acpi_main(void)
+{
+  if (toys.optflags & FLAG_V) toys.optflags = FLAG_a|FLAG_b|FLAG_c|FLAG_t;
+  if (!toys.optflags) toys.optflags = FLAG_b;
+  if (toys.optflags & (FLAG_a|FLAG_b))
+    dirtree_read("/sys/class/power_supply", acpi_callback);
+  if (toys.optflags & FLAG_t) dirtree_read("/sys/class", temp_callback);
+  if (toys.optflags & FLAG_c) dirtree_read("/sys/class/thermal", cool_callback);
+
+}
diff --git a/toybox/toys/other/base64.c b/toybox/toys/other/base64.c
new file mode 100644
index 0000000..33155bc
--- /dev/null
+++ b/toybox/toys/other/base64.c
@@ -0,0 +1,94 @@
+/* base64.c - Encode and decode base64
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * No standard
+
+USE_BASE64(NEWTOY(base64, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config BASE64
+  bool "base64"
+  default y
+  help
+    usage: base64 [-di] [-w COLUMNS] [FILE...]
+
+    Encode or decode in base64.
+
+    -d	decode
+    -i	ignore non-alphabetic characters
+    -w	wrap output at COLUMNS (default 76 or 0 for no wrap)
+*/
+
+#define FOR_base64
+#include "toys.h"
+
+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) 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;
+
+        if ((x = stridx(toybuf, buf[i])) != -1) {
+          out = (out<<6) + x;
+          bits += 6;
+          if (bits >= 8) {
+            putchar(out >> (bits -= 8));
+            out &= (1<<bits)-1;
+            if (ferror(stdout)) perror_exit(0);
+          }
+
+          continue;
+        }
+        if (buf[i] == '\n' || (toys.optflags & FLAG_i)) continue;
+
+        break;
+      } else {
+        out = (out<<8) + buf[i];
+        bits += 8;
+        while (bits >= 6) {
+          wraputchar(toybuf[out >> (bits -= 6)], &x);
+          out &= (1<<bits)-1;
+        }
+      }
+    }
+  }
+}
+
+void base64_main(void)
+{
+  base64_init(toybuf);
+  loopfiles(toys.optargs, do_base64);
+}
diff --git a/toybox/toys/other/blkid.c b/toybox/toys/other/blkid.c
new file mode 100644
index 0000000..04c9b5f
--- /dev/null
+++ b/toybox/toys/other/blkid.c
@@ -0,0 +1,172 @@
+/* blkid.c - Prints type, label and UUID of filesystem(s).
+ *
+ * Copyright 2013 Brad Conroy <bconroy@uis.edu>
+ *
+ * See ftp://ftp.kernel.org/pub/linux/utils/util-linux/v2.24/libblkid-docs/api-index-full.html
+
+USE_BLKID(NEWTOY(blkid, 0, TOYFLAG_BIN))
+USE_FSTYPE(NEWTOY(fstype, "<1", TOYFLAG_BIN))
+
+config BLKID
+  bool "blkid"
+  default y
+  help
+    usage: blkid DEV...
+
+    Prints type, label and UUID of filesystem on a block device or image.
+
+config FSTYPE
+  bool "fstype"
+  default y
+  help
+    usage: fstype DEV...
+
+    Prints type of filesystem on a block device or image.
+*/
+
+#define FOR_blkid
+#include "toys.h"
+
+struct fstype {
+  char *name;
+  uint64_t magic;
+  int magic_len, magic_offset, uuid_off, label_len, label_off;
+};
+
+static const struct fstype fstypes[] = {
+  {"ext2", 0xEF53, 2, 1080, 1128, 16, 1144}, // keep this first for ext3/4 check
+  {"swap", 0x4341505350415753LL, 8, 4086, 1036, 15, 1052},
+  // NTFS label actually 8/16 0x4d80 but horrible: 16 bit wide characters via
+  // codepage, something called a uuid that's only 8 bytes long...
+  {"ntfs", 0x5346544e, 4, 3, 0x48+(8<<24), 0, 0},
+
+  {"adfs", 0xadf5, 2, 0xc00, 0,0,0},
+  {"bfs", 0x1badface, 4, 0, 0,0,0},
+  {"btrfs", 0x4D5F53665248425FULL, 8, 65600, 65803, 256, 65819},
+  {"cramfs", 0x28cd3d45, 4, 0, 0, 16, 48},
+  {"f2fs", 0xF2F52010, 4, 1024, 1132, 16, 1110},
+  {"jfs", 0x3153464a, 4, 32768, 32920, 16, 32904},
+  {"nilfs", 0x3434, 2, 1030, 1176, 80, 1192},
+  {"reiserfs", 0x724573496552ULL, 6, 8244, 8276, 16, 8292},
+  {"reiserfs", 0x724573496552ULL, 6, 65588, 65620, 16, 65636},
+  {"romfs", 0x2d6d6f72, 4, 0, 0,0,0},
+  {"squashfs", 0x73717368, 4, 0, 0,0,0},
+  {"xiafs", 0x012fd16d, 4, 572, 0,0,0},
+  {"xfs", 0x42534658, 4, 0, 32, 12, 108},
+  {"vfat", 0x3233544146ULL, 5, 82, 67+(4<<24), 11, 71},  // fat32
+  {"vfat", 0x31544146, 4, 54, 39+(4<<24), 11, 43}     // fat1
+};
+
+static void do_blkid(int fd, char *name)
+{
+  int off, i, j, len;
+  char *type;
+
+  off = i = 0;
+
+  for (;;) {
+    int pass = 0;
+
+    // Read next block of data
+    len = readall(fd, toybuf, sizeof(toybuf));
+    if (len != sizeof(toybuf)) return;
+
+    // Iterate through types in range
+    for (i=0; i < sizeof(fstypes)/sizeof(struct fstype); i++) {
+      uint64_t test;
+
+      // Skip tests not in this 4k block
+      if (fstypes[i].magic_offset > off+sizeof(toybuf)) {
+        pass++;
+        continue;
+      }
+      if (fstypes[i].magic_offset < off) continue;
+
+      // Populate 64 bit little endian magic value
+      test = 0;
+      for (j = 0; j < fstypes[i].magic_len; j++)
+        test += ((uint64_t)toybuf[j+fstypes[i].magic_offset-off])<<(8*j);
+      if (test == fstypes[i].magic) break;
+    }
+
+    if (i == ARRAY_LEN(fstypes)) {
+      off += len;
+      if (pass) continue;
+      return;
+    }
+    break;
+  }
+
+  // distinguish ext2/3/4
+  type = fstypes[i].name;
+  if (!i) {
+    if (toybuf[1116]&4) type = "ext3";
+    if (toybuf[1120]&64) type = "ext4";
+  }
+
+  // Could special case NTFS here...
+
+  // Output for fstype
+  if (*toys.which->name == 'f') {
+    puts(type);
+    return;
+  }
+
+  // output for blkid
+  printf("%s:",name);
+
+  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,
+        uoff = (fstypes[i].uuid_off & ((1<<24)-1))-off;
+
+    if (size) bits = 4*(size == 4);
+    else size = 16;
+
+    printf(" UUID=\"");
+    for (j = 0; j < size; j++) printf("-%02x"+!(bits & (1<<j)), toybuf[uoff+j]);
+    printf("\"");
+  }
+
+  printf(" TYPE=\"%s\"\n", type);
+}
+
+void blkid_main(void)
+{
+  if (*toys.optargs) loopfiles(toys.optargs, do_blkid);
+  else {
+    unsigned int ma, mi, sz, fd;
+    char *name = toybuf, *buffer = toybuf+1024, device[32];
+    FILE *fp = xfopen("/proc/partitions", "r");
+
+    while (fgets(buffer, 1024, fp)) {
+      *name = 0;
+      if (sscanf(buffer, " %u %u %u %[^\n ]", &ma, &mi, &sz, name) != 4)
+        continue;
+
+      sprintf(device, "/dev/%.20s", name);
+      if (-1 == (fd = open(device, O_RDONLY))) {
+        if (errno != ENOMEDIUM) perror_msg_raw(device);
+      } else {
+        do_blkid(fd, device);
+        close(fd);
+      }
+    }
+    if (CFG_TOYBOX_FREE) fclose(fp);
+  }
+}
+
+void fstype_main(void)
+{
+  loopfiles(toys.optargs, do_blkid);
+}
diff --git a/toybox/toys/other/blockdev.c b/toybox/toys/other/blockdev.c
new file mode 100644
index 0000000..38e0993
--- /dev/null
+++ b/toybox/toys/other/blockdev.c
@@ -0,0 +1,67 @@
+/* blockdev.c -show/set blockdev information.
+ *
+ * Copyright 2014 Sameer Prakash Pradhan <sameer.p.pradhan@gmail.com>
+ *
+ * No Standard.
+
+USE_BLOCKDEV(NEWTOY(blockdev, "<1>1(setro)(setrw)(getro)(getss)(getbsz)(setbsz)#<0(getsz)(getsize)(getsize64)(flushbufs)(rereadpt)",TOYFLAG_USR|TOYFLAG_BIN))
+
+config BLOCKDEV
+  bool "blockdev"
+  default y
+  help
+    usage: blockdev --OPTION... BLOCKDEV...
+
+    Call ioctl(s) on each listed block device
+
+    OPTIONs:
+    --setro		Set read only
+    --setrw		Set read write
+    --getro		Get read only
+    --getss		Get sector size
+    --getbsz	Get block size
+    --setbsz	BYTES	Set block size
+    --getsz		Get device size in 512-byte sectors
+    --getsize	Get device size in sectors (deprecated)
+    --getsize64	Get device size in bytes
+    --flushbufs	Flush buffers
+    --rereadpt	Reread partition table
+*/
+
+#define FOR_blockdev
+#include "toys.h"
+#include <linux/fs.h>
+
+GLOBALS(
+  long bsz;
+)
+
+void blockdev_main(void)
+{
+  int cmds[] = {BLKRRPART, BLKFLSBUF, BLKGETSIZE64, BLKGETSIZE, BLKGETSIZE64,
+                BLKBSZSET, BLKBSZGET, BLKSSZGET, BLKROGET, BLKROSET, BLKROSET};
+  char **ss;
+  long long val = 0;
+
+  if (!toys.optflags) help_exit("need --option");
+
+  for (ss = toys.optargs;  *ss; ss++) {
+    int fd = xopenro(*ss), i;
+
+    // Command line order discarded so perform multiple operations in flag order
+    for (i = 0; i < 32; i++) {
+      long flag = toys.optflags & (1<<i);
+
+      if (!flag) continue;
+
+      if (flag & FLAG_setbsz) val = TT.bsz;
+      else val = !!(flag & FLAG_setro);
+
+      xioctl(fd, cmds[i], &val);
+
+      flag &= FLAG_setbsz|FLAG_setro|FLAG_flushbufs|FLAG_rereadpt|FLAG_setrw;
+      if (!flag) printf("%lld\n", (toys.optflags & FLAG_getsz) ? val >> 9: val);
+    }
+    xclose(fd);
+  }
+}
diff --git a/toybox/toys/other/bzcat.c b/toybox/toys/other/bzcat.c
new file mode 100644
index 0000000..ff59849
--- /dev/null
+++ b/toybox/toys/other/bzcat.c
@@ -0,0 +1,723 @@
+/* bzcat.c - bzip2 decompression
+ *
+ * Copyright 2003, 2007 Rob Landley <rob@landley.net>
+ *
+ * Based on a close reading (but not the actual code) of the original bzip2
+ * decompression code by Julian R Seward (jseward@acm.org), which also
+ * acknowledges contributions by Mike Burrows, David Wheeler, Peter Fenwick,
+ * Alistair Moffat, Radford Neal, Ian H. Witten, Robert Sedgewick, and
+ * Jon L. Bentley.
+ *
+ * No standard.
+
+
+USE_BZCAT(NEWTOY(bzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_BUNZIP2(NEWTOY(bunzip2, "cftkv", TOYFLAG_USR|TOYFLAG_BIN))
+
+config BUNZIP2
+  bool "bunzip2"
+  default y
+  help
+    usage: bunzip2 [-cftkv] [FILE...]
+
+    Decompress listed files (file.bz becomes file) deleting archive file(s).
+    Read from stdin if no files listed.
+
+    -c	force output to stdout
+    -f	force decompression. (If FILE doesn't end in .bz, replace original.)
+    -k	keep input files (-c and -t imply this)
+    -t  test integrity
+    -v	verbose
+
+config BZCAT
+  bool "bzcat"
+  default y
+  help
+    usage: bzcat [FILE...]
+
+    Decompress listed files to stdout. Use stdin if no files listed.
+*/
+
+#define FOR_bunzip2
+#include "toys.h"
+
+#define THREADS 1
+
+// Constants for huffman coding
+#define MAX_GROUPS               6
+#define GROUP_SIZE               50     /* 64 would have been more efficient */
+#define MAX_HUFCODE_BITS         20     /* Longest huffman code allowed */
+#define MAX_SYMBOLS              258    /* 256 literals + RUNA + RUNB */
+#define SYMBOL_RUNA              0
+#define SYMBOL_RUNB              1
+
+// Other housekeeping constants
+#define IOBUF_SIZE               4096
+
+// Status return values
+#define RETVAL_LAST_BLOCK        (-100)
+#define RETVAL_NOT_BZIP_DATA     (-1)
+#define RETVAL_DATA_ERROR        (-2)
+#define RETVAL_OBSOLETE_INPUT    (-3)
+
+// This is what we know about each huffman coding group
+struct group_data {
+  int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS];
+  char minLen, maxLen;
+};
+
+// Data for burrows wheeler transform
+
+struct bwdata {
+  unsigned int origPtr;
+  int byteCount[256];
+  // State saved when interrupting output
+  int writePos, writeRun, writeCount, writeCurrent;
+  unsigned int dataCRC, headerCRC;
+  unsigned int *dbuf;
+};
+
+// Structure holding all the housekeeping data, including IO buffers and
+// memory that persists between calls to bunzip
+struct bunzip_data {
+  // Input stream, input buffer, input bit buffer
+  int in_fd, inbufCount, inbufPos;
+  char *inbuf;
+  unsigned int inbufBitCount, inbufBits;
+
+  // Output buffer
+  char outbuf[IOBUF_SIZE];
+  int outbufPos;
+
+  unsigned int totalCRC;
+
+  // First pass decompression data (Huffman and MTF decoding)
+  char selectors[32768];                  // nSelectors=15 bits
+  struct group_data groups[MAX_GROUPS];   // huffman coding tables
+  int symTotal, groupCount, nSelectors;
+  unsigned char symToByte[256], mtfSymbol[256];
+
+  // The CRC values stored in the block header and calculated from the data
+  unsigned int crc32Table[256];
+
+  // Second pass decompression data (burrows-wheeler transform)
+  unsigned int dbufSize;
+  struct bwdata bwdata[THREADS];
+};
+
+// Return the next nnn bits of input.  All reads from the compressed input
+// are done through this function.  All reads are big endian.
+static unsigned int get_bits(struct bunzip_data *bd, char bits_wanted)
+{
+  unsigned int bits = 0;
+
+  // If we need to get more data from the byte buffer, do so.  (Loop getting
+  // one byte at a time to enforce endianness and avoid unaligned access.)
+  while (bd->inbufBitCount < bits_wanted) {
+
+    // If we need to read more data from file into byte buffer, do so
+    if (bd->inbufPos == bd->inbufCount) {
+      if (0 >= (bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE)))
+        error_exit("input EOF");
+      bd->inbufPos = 0;
+    }
+
+    // Avoid 32-bit overflow (dump bit buffer to top of output)
+    if (bd->inbufBitCount>=24) {
+      bits = bd->inbufBits&((1<<bd->inbufBitCount)-1);
+      bits_wanted -= bd->inbufBitCount;
+      bits <<= bits_wanted;
+      bd->inbufBitCount = 0;
+    }
+
+    // Grab next 8 bits of input from buffer.
+    bd->inbufBits = (bd->inbufBits<<8) | bd->inbuf[bd->inbufPos++];
+    bd->inbufBitCount += 8;
+  }
+
+  // Calculate result
+  bd->inbufBitCount -= bits_wanted;
+  bits |= (bd->inbufBits>>bd->inbufBitCount) & ((1<<bits_wanted)-1);
+
+  return bits;
+}
+
+/* Read block header at start of a new compressed data block.  Consists of:
+ *
+ * 48 bits : Block signature, either pi (data block) or e (EOF block).
+ * 32 bits : bw->headerCRC
+ * 1  bit  : obsolete feature flag.
+ * 24 bits : origPtr (Burrows-wheeler unwind index, only 20 bits ever used)
+ * 16 bits : Mapping table index.
+ *[16 bits]: symToByte[symTotal] (Mapping table.  For each bit set in mapping
+ *           table index above, read another 16 bits of mapping table data.
+ *           If correspondig bit is unset, all bits in that mapping table
+ *           section are 0.)
+ *  3 bits : groupCount (how many huffman tables used to encode, anywhere
+ *           from 2 to MAX_GROUPS)
+ * variable: hufGroup[groupCount] (MTF encoded huffman table data.)
+ */
+
+static int read_block_header(struct bunzip_data *bd, struct bwdata *bw)
+{
+  struct group_data *hufGroup;
+  int hh, ii, jj, kk, symCount, *base, *limit;
+  unsigned char uc;
+
+  // Read in header signature and CRC (which is stored big endian)
+  ii = get_bits(bd, 24);
+  jj = get_bits(bd, 24);
+  bw->headerCRC = get_bits(bd,32);
+
+  // Is this the EOF block with CRC for whole file?  (Constant is "e")
+  if (ii==0x177245 && jj==0x385090) return RETVAL_LAST_BLOCK;
+
+  // Is this a valid data block?  (Constant is "pi".)
+  if (ii!=0x314159 || jj!=0x265359) return RETVAL_NOT_BZIP_DATA;
+
+  // We can add support for blockRandomised if anybody complains.
+  if (get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT;
+  if ((bw->origPtr = get_bits(bd,24)) > bd->dbufSize) return RETVAL_DATA_ERROR;
+
+  // mapping table: if some byte values are never used (encoding things
+  // like ascii text), the compression code removes the gaps to have fewer
+  // symbols to deal with, and writes a sparse bitfield indicating which
+  // values were present.  We make a translation table to convert the symbols
+  // back to the corresponding bytes.
+  hh = get_bits(bd, 16);
+  bd->symTotal = 0;
+  for (ii=0; ii<16; ii++) {
+    if (hh & (1 << (15 - ii))) {
+      kk = get_bits(bd, 16);
+      for (jj=0; jj<16; jj++)
+        if (kk & (1 << (15 - jj)))
+          bd->symToByte[bd->symTotal++] = (16 * ii) + jj;
+    }
+  }
+
+  // How many different huffman coding groups does this block use?
+  bd->groupCount = get_bits(bd,3);
+  if (bd->groupCount<2 || bd->groupCount>MAX_GROUPS) return RETVAL_DATA_ERROR;
+
+  // nSelectors: Every GROUP_SIZE many symbols we switch huffman coding
+  // tables.  Each group has a selector, which is an index into the huffman
+  // coding table arrays.
+  //
+  // Read in the group selector array, which is stored as MTF encoded
+  // bit runs.  (MTF = Move To Front.  Every time a symbol occurs it's moved
+  // to the front of the table, so it has a shorter encoding next time.)
+  if (!(bd->nSelectors = get_bits(bd, 15))) return RETVAL_DATA_ERROR;
+  for (ii=0; ii<bd->groupCount; ii++) bd->mtfSymbol[ii] = ii;
+  for (ii=0; ii<bd->nSelectors; ii++) {
+
+    // Get next value
+    for(jj=0;get_bits(bd,1);jj++)
+      if (jj>=bd->groupCount) return RETVAL_DATA_ERROR;
+
+    // Decode MTF to get the next selector, and move it to the front.
+    uc = bd->mtfSymbol[jj];
+    memmove(bd->mtfSymbol+1, bd->mtfSymbol, jj);
+    bd->mtfSymbol[0] = bd->selectors[ii] = uc;
+  }
+
+  // Read the huffman coding tables for each group, which code for symTotal
+  // literal symbols, plus two run symbols (RUNA, RUNB)
+  symCount = bd->symTotal+2;
+  for (jj=0; jj<bd->groupCount; jj++) {
+    unsigned char length[MAX_SYMBOLS];
+    unsigned temp[MAX_HUFCODE_BITS+1];
+    int minLen, maxLen, pp;
+
+    // Read lengths
+    hh = get_bits(bd, 5);
+    for (ii = 0; ii < symCount; ii++) {
+      for(;;) {
+        // !hh || hh > MAX_HUFCODE_BITS in one test.
+        if (MAX_HUFCODE_BITS-1 < (unsigned)hh-1) return RETVAL_DATA_ERROR;
+        // Grab 2 bits instead of 1 (slightly smaller/faster).  Stop if
+        // first bit is 0, otherwise second bit says whether to
+        // increment or decrement.
+        kk = get_bits(bd, 2);
+        if (kk & 2) hh += 1 - ((kk&1)<<1);
+        else {
+          bd->inbufBitCount++;
+          break;
+        }
+      }
+      length[ii] = hh;
+    }
+
+    // Find largest and smallest lengths in this group
+    minLen = maxLen = length[0];
+    for (ii = 1; ii < symCount; ii++) {
+      if(length[ii] > maxLen) maxLen = length[ii];
+      else if(length[ii] < minLen) minLen = length[ii];
+    }
+
+    /* Calculate permute[], base[], and limit[] tables from length[].
+     *
+     * permute[] is the lookup table for converting huffman coded symbols
+     * into decoded symbols.  It contains symbol values sorted by length.
+     *
+     * base[] is the amount to subtract from the value of a huffman symbol
+     * of a given length when using permute[].
+     *
+     * limit[] indicates the largest numerical value a symbol with a given
+     * number of bits can have.  It lets us know when to stop reading.
+     *
+     * To use these, keep reading bits until value <= limit[bitcount] or
+     * you've read over 20 bits (error).  Then the decoded symbol
+     * equals permute[hufcode_value - base[hufcode_bitcount]].
+     */
+    hufGroup = bd->groups+jj;
+    hufGroup->minLen = minLen;
+    hufGroup->maxLen = maxLen;
+
+    // Note that minLen can't be smaller than 1, so we adjust the base
+    // and limit array pointers so we're not always wasting the first
+    // entry.  We do this again when using them (during symbol decoding).
+    base = hufGroup->base-1;
+    limit = hufGroup->limit-1;
+
+    // zero temp[] and limit[], and calculate permute[]
+    pp = 0;
+    for (ii = minLen; ii <= maxLen; ii++) {
+      temp[ii] = limit[ii] = 0;
+      for (hh = 0; hh < symCount; hh++)
+        if (length[hh] == ii) hufGroup->permute[pp++] = hh;
+    }
+
+    // Count symbols coded for at each bit length
+    for (ii = 0; ii < symCount; ii++) temp[length[ii]]++;
+
+    /* Calculate limit[] (the largest symbol-coding value at each bit
+     * length, which is (previous limit<<1)+symbols at this level), and
+     * base[] (number of symbols to ignore at each bit length, which is
+     * limit minus the cumulative count of symbols coded for already). */
+    pp = hh = 0;
+    for (ii = minLen; ii < maxLen; ii++) {
+      pp += temp[ii];
+      limit[ii] = pp-1;
+      pp <<= 1;
+      base[ii+1] = pp-(hh+=temp[ii]);
+    }
+    limit[maxLen] = pp+temp[maxLen]-1;
+    limit[maxLen+1] = INT_MAX;
+    base[minLen] = 0;
+  }
+
+  return 0;
+}
+
+/* First pass, read block's symbols into dbuf[dbufCount].
+ *
+ * This undoes three types of compression: huffman coding, run length encoding,
+ * and move to front encoding.  We have to undo all those to know when we've
+ * read enough input.
+ */
+
+static int read_huffman_data(struct bunzip_data *bd, struct bwdata *bw)
+{
+  struct group_data *hufGroup;
+  int ii, jj, kk, runPos, dbufCount, symCount, selector, nextSym,
+    *byteCount, *base, *limit;
+  unsigned hh, *dbuf = bw->dbuf;
+  unsigned char uc;
+
+  // We've finished reading and digesting the block header.  Now read this
+  // block's huffman coded symbols from the file and undo the huffman coding
+  // and run length encoding, saving the result into dbuf[dbufCount++] = uc
+
+  // Initialize symbol occurrence counters and symbol mtf table
+  byteCount = bw->byteCount;
+  for(ii=0; ii<256; ii++) {
+    byteCount[ii] = 0;
+    bd->mtfSymbol[ii] = ii;
+  }
+
+  // Loop through compressed symbols.  This is the first "tight inner loop"
+  // that needs to be micro-optimized for speed.  (This one fills out dbuf[]
+  // linearly, staying in cache more, so isn't as limited by DRAM access.)
+  runPos = dbufCount = symCount = selector = 0;
+  // Some unnecessary initializations to shut gcc up.
+  base = limit = 0;
+  hufGroup = 0;
+  hh = 0;
+
+  for (;;) {
+    // Have we reached the end of this huffman group?
+    if (!(symCount--)) {
+      // Determine which huffman coding group to use.
+      symCount = GROUP_SIZE-1;
+      if (selector >= bd->nSelectors) return RETVAL_DATA_ERROR;
+      hufGroup = bd->groups + bd->selectors[selector++];
+      base = hufGroup->base-1;
+      limit = hufGroup->limit-1;
+    }
+
+    // Read next huffman-coded symbol (into jj).
+    ii = hufGroup->minLen;
+    jj = get_bits(bd, ii);
+    while (jj > limit[ii]) {
+      // if (ii > hufGroup->maxLen) return RETVAL_DATA_ERROR;
+      ii++;
+
+      // Unroll get_bits() to avoid a function call when the data's in
+      // the buffer already.
+      kk = bd->inbufBitCount
+        ? (bd->inbufBits >> --(bd->inbufBitCount)) & 1 : get_bits(bd, 1);
+      jj = (jj << 1) | kk;
+    }
+    // Huffman decode jj into nextSym (with bounds checking)
+    jj-=base[ii];
+
+    if (ii > hufGroup->maxLen || (unsigned)jj >= MAX_SYMBOLS)
+      return RETVAL_DATA_ERROR;
+    nextSym = hufGroup->permute[jj];
+
+    // If this is a repeated run, loop collecting data
+    if ((unsigned)nextSym <= SYMBOL_RUNB) {
+      // If this is the start of a new run, zero out counter
+      if(!runPos) {
+        runPos = 1;
+        hh = 0;
+      }
+
+      /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
+         each bit position, add 1 or 2 instead. For example,
+         1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
+         You can make any bit pattern that way using 1 less symbol than
+         the basic or 0/1 method (except all bits 0, which would use no
+         symbols, but a run of length 0 doesn't mean anything in this
+         context). Thus space is saved. */
+      hh += (runPos << nextSym); // +runPos if RUNA; +2*runPos if RUNB
+      runPos <<= 1;
+      continue;
+    }
+
+    /* When we hit the first non-run symbol after a run, we now know
+       how many times to repeat the last literal, so append that many
+       copies to our buffer of decoded symbols (dbuf) now. (The last
+       literal used is the one at the head of the mtfSymbol array.) */
+    if (runPos) {
+      runPos = 0;
+      // 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;
+      while (hh--) dbuf[dbufCount++] = uc;
+    }
+
+    // Is this the terminating symbol?
+    if (nextSym>bd->symTotal) break;
+
+    /* At this point, the symbol we just decoded indicates a new literal
+       character. Subtract one to get the position in the MTF array
+       at which this literal is currently to be found. (Note that the
+       result can't be -1 or 0, because 0 and 1 are RUNA and RUNB.
+       Another instance of the first symbol in the mtf array, position 0,
+       would have been handled as part of a run.) */
+    if (dbufCount>=bd->dbufSize) return RETVAL_DATA_ERROR;
+    ii = nextSym - 1;
+    uc = bd->mtfSymbol[ii];
+    // On my laptop, unrolling this memmove() into a loop shaves 3.5% off
+    // the total running time.
+    while(ii--) bd->mtfSymbol[ii+1] = bd->mtfSymbol[ii];
+    bd->mtfSymbol[0] = uc;
+    uc = bd->symToByte[uc];
+
+    // We have our literal byte.  Save it into dbuf.
+    byteCount[uc]++;
+    dbuf[dbufCount++] = (unsigned int)uc;
+  }
+
+  // Now we know what dbufCount is, do a better sanity check on origPtr.
+  if (bw->origPtr >= (bw->writeCount = dbufCount)) return RETVAL_DATA_ERROR;
+
+  return 0;
+}
+
+// Flush output buffer to disk
+static void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
+{
+  if (bd->outbufPos) {
+    if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos)
+      error_exit("output EOF");
+    bd->outbufPos = 0;
+  }
+}
+
+static void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
+{
+  int ii, jj;
+  unsigned int *dbuf = bw->dbuf;
+  int *byteCount = bw->byteCount;
+
+  // Turn byteCount into cumulative occurrence counts of 0 to n-1.
+  jj = 0;
+  for (ii=0; ii<256; ii++) {
+    int kk = jj + byteCount[ii];
+    byteCount[ii] = jj;
+    jj = kk;
+  }
+
+  // Use occurrence counts to quickly figure out what order dbuf would be in
+  // if we sorted it.
+  for (ii=0; ii < bw->writeCount; ii++) {
+    unsigned char uc = dbuf[ii];
+    dbuf[byteCount[uc]] |= (ii << 8);
+    byteCount[uc]++;
+  }
+
+  // blockRandomised support would go here.
+
+  // Using ii as position, jj as previous character, hh as current character,
+  // and uc as run count.
+  bw->dataCRC = 0xffffffffL;
+
+  /* Decode first byte by hand to initialize "previous" byte. Note that it
+     doesn't get output, and if the first three characters are identical
+     it doesn't qualify as a run (hence uc=255, which will either wrap
+     to 1 or get reset). */
+  if (bw->writeCount) {
+    bw->writePos = dbuf[bw->origPtr];
+    bw->writeCurrent = (unsigned char)bw->writePos;
+    bw->writePos >>= 8;
+    bw->writeRun = -1;
+  }
+}
+
+// Decompress a block of text to intermediate buffer
+static int read_bunzip_data(struct bunzip_data *bd)
+{
+  int rc = read_block_header(bd, bd->bwdata);
+  if (!rc) rc=read_huffman_data(bd, bd->bwdata);
+
+  // First thing that can be done by a background thread.
+  burrows_wheeler_prep(bd, bd->bwdata);
+
+  return rc;
+}
+
+// Undo burrows-wheeler transform on intermediate buffer to produce output.
+// If !len, write up to len bytes of data to buf.  Otherwise write to out_fd.
+// Returns len ? bytes written : 0.  Notice all errors are negative #'s.
+//
+// Burrows-wheeler transform is described at:
+// http://dogma.net/markn/articles/bwt/bwt.htm
+// http://marknelson.us/1996/09/01/bwt/
+
+static int write_bunzip_data(struct bunzip_data *bd, struct bwdata *bw,
+  int out_fd, char *outbuf, int len)
+{
+  unsigned int *dbuf = bw->dbuf;
+  int count, pos, current, run, copies, outbyte, previous, gotcount = 0;
+
+  for (;;) {
+    // If last read was short due to end of file, return last block now
+    if (bw->writeCount < 0) return bw->writeCount;
+
+    // If we need to refill dbuf, do it.
+    if (!bw->writeCount) {
+      int i = read_bunzip_data(bd);
+      if (i) {
+        if (i == RETVAL_LAST_BLOCK) {
+          bw->writeCount = i;
+          return gotcount;
+        } else return i;
+      }
+    }
+
+    // loop generating output
+    count = bw->writeCount;
+    pos = bw->writePos;
+    current = bw->writeCurrent;
+    run = bw->writeRun;
+    while (count) {
+
+      // If somebody (like tar) wants a certain number of bytes of
+      // data from memory instead of written to a file, humor them.
+      if (len && bd->outbufPos >= len) goto dataus_interruptus;
+      count--;
+
+      // Follow sequence vector to undo Burrows-Wheeler transform.
+      previous = current;
+      pos = dbuf[pos];
+      current = pos&0xff;
+      pos >>= 8;
+
+      // Whenever we see 3 consecutive copies of the same byte,
+      // the 4th is a repeat count
+      if (run++ == 3) {
+        copies = current;
+        outbyte = previous;
+        current = -1;
+      } else {
+        copies = 1;
+        outbyte = current;
+      }
+
+      // Output bytes to buffer, flushing to file if necessary
+      while (copies--) {
+        if (bd->outbufPos == IOBUF_SIZE) flush_bunzip_outbuf(bd, out_fd);
+        bd->outbuf[bd->outbufPos++] = outbyte;
+        bw->dataCRC = (bw->dataCRC << 8)
+                ^ bd->crc32Table[(bw->dataCRC >> 24) ^ outbyte];
+      }
+      if (current != previous) run=0;
+    }
+
+    // decompression of this block completed successfully
+    bw->dataCRC = ~(bw->dataCRC);
+    bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bw->dataCRC;
+
+    // if this block had a crc error, force file level crc error.
+    if (bw->dataCRC != bw->headerCRC) {
+      bd->totalCRC = bw->headerCRC+1;
+
+      return RETVAL_LAST_BLOCK;
+    }
+dataus_interruptus:
+    bw->writeCount = count;
+    if (len) {
+      gotcount += bd->outbufPos;
+      memcpy(outbuf, bd->outbuf, len);
+
+      // If we got enough data, checkpoint loop state and return
+      if ((len -= bd->outbufPos)<1) {
+        bd->outbufPos -= len;
+        if (bd->outbufPos) memmove(bd->outbuf, bd->outbuf+len, bd->outbufPos);
+        bw->writePos = pos;
+        bw->writeCurrent = current;
+        bw->writeRun = run;
+
+        return gotcount;
+      }
+    }
+  }
+}
+
+// Allocate the structure, read file header. If !len, src_fd contains
+// filehandle to read from. Else inbuf contains data.
+static int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf,
+  int len)
+{
+  struct bunzip_data *bd;
+  unsigned int i;
+
+  // Figure out how much data to allocate.
+  i = sizeof(struct bunzip_data);
+  if (!len) i += IOBUF_SIZE;
+
+  // Allocate bunzip_data. Most fields initialize to zero.
+  bd = *bdp = xzalloc(i);
+  if (len) {
+    bd->inbuf = inbuf;
+    bd->inbufCount = len;
+    bd->in_fd = -1;
+  } else {
+    bd->inbuf = (char *)(bd+1);
+    bd->in_fd = src_fd;
+  }
+
+  crc_init(bd->crc32Table, 0);
+
+  // Ensure that file starts with "BZh".
+  for (i=0;i<3;i++) if (get_bits(bd,8)!="BZh"[i]) return RETVAL_NOT_BZIP_DATA;
+
+  // Next byte ascii '1'-'9', indicates block size in units of 100k of
+  // uncompressed data. Allocate intermediate buffer for block.
+  i = get_bits(bd, 8);
+  if (i<'1' || i>'9') return RETVAL_NOT_BZIP_DATA;
+  bd->dbufSize = 100000*(i-'0')*THREADS;
+  for (i=0; i<THREADS; i++)
+    bd->bwdata[i].dbuf = xmalloc(bd->dbufSize * sizeof(int));
+
+  return 0;
+}
+
+// Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data,
+// not end of file.)
+static char *bunzipStream(int src_fd, int dst_fd)
+{
+  struct bunzip_data *bd;
+  char *bunzip_errors[] = {0, "not bzip", "bad data", "old format"};
+  int i, j;
+
+  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) {
+      if (bd->bwdata[0].headerCRC==bd->totalCRC) i = 0;
+      else i = RETVAL_DATA_ERROR;
+    }
+  }
+  flush_bunzip_outbuf(bd, dst_fd);
+
+  for (j=0; j<THREADS; j++) free(bd->bwdata[j].dbuf);
+  free(bd);
+
+  return bunzip_errors[-i];
+}
+
+static void do_bzcat(int fd, char *name)
+{
+  char *err = bunzipStream(fd, 1);
+
+  if (err) error_exit_raw(err);
+}
+
+void bzcat_main(void)
+{
+  loopfiles(toys.optargs, do_bzcat);
+}
+
+static void do_bunzip2(int fd, char *name)
+{
+  int outfd = 1, rename = 0, len = strlen(name);
+  char *tmp, *err, *dotbz = 0;
+
+  // Trim off .bz or .bz2 extension
+  dotbz = name+len-3;
+  if ((len>3 && !strcmp(dotbz, ".bz")) || (len>4 && !strcmp(--dotbz, ".bz2")))
+    dotbz = 0;
+
+  // For - no replace
+  if (toys.optflags&FLAG_t) outfd = xopen("/dev/null", O_WRONLY);
+  else if ((fd || strcmp(name, "-")) && !(toys.optflags&FLAG_c)) {
+    if (toys.optflags&FLAG_k) {
+      if (!dotbz || !access(name, X_OK)) {
+        error_msg("%s exists", name);
+
+        return;
+      }
+    }
+    outfd = copy_tempfile(fd, name, &tmp);
+    rename++;
+  }
+
+  if (toys.optflags&FLAG_v) printf("%s:", name);
+  err = bunzipStream(fd, outfd);
+  if (toys.optflags&FLAG_v) {
+    printf("%s\n", err ? err : "ok");
+    toys.exitval |= !!err;
+  } else if (err) error_msg_raw(err);
+
+  // can't test outfd==1 because may have been called with stdin+stdout closed
+  if (rename) {
+    if (toys.optflags&FLAG_k) {
+      free(tmp);
+      tmp = 0;
+    } else {
+      if (dotbz) *dotbz = '.';
+      if (!unlink(name)) perror_msg_raw(name);
+    }
+    (err ? delete_tempfile : replace_tempfile)(-1, outfd, &tmp);
+  }
+}
+
+void bunzip2_main(void)
+{
+  loopfiles(toys.optargs, do_bunzip2);
+}
diff --git a/toybox/toys/other/chcon.c b/toybox/toys/other/chcon.c
new file mode 100644
index 0000000..6dbdd13
--- /dev/null
+++ b/toybox/toys/other/chcon.c
@@ -0,0 +1,44 @@
+/* chcon.c - Change file security context
+ *
+ * Copyright 2014 The Android Open Source Project
+
+USE_CHCON(NEWTOY(chcon, "<2hvR", TOYFLAG_USR|TOYFLAG_BIN))
+
+config CHCON
+  bool "chcon"
+  depends on TOYBOX_SELINUX
+  default y
+  help
+    usage: chcon [-hRv] CONTEXT FILE...
+
+    Change the SELinux security context of listed file[s].
+
+    -h change symlinks instead of what they point to.
+    -R recurse into subdirectories.
+    -v verbose output.
+*/
+
+#define FOR_chcon
+#include "toys.h"
+
+static int do_chcon(struct dirtree *try)
+{
+  char *path, *con = *toys.optargs;
+
+  if (!dirtree_notdotdot(try)) return 0;
+
+  path = dirtree_path(try, 0);
+  if (toys.optflags & FLAG_v) printf("chcon '%s' to %s\n", path, con);
+  if (-1 == ((toys.optflags & FLAG_h) ? lsetfilecon : setfilecon)(path, con))
+    perror_msg("'%s' to %s", path, con);
+  free(path);
+
+  return (toys.optflags & FLAG_R)*DIRTREE_RECURSE;
+}
+
+void chcon_main(void)
+{
+  char **file;
+
+  for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chcon);
+}
diff --git a/toybox/toys/other/chroot.c b/toybox/toys/other/chroot.c
new file mode 100644
index 0000000..b6ef17d
--- /dev/null
+++ b/toybox/toys/other/chroot.c
@@ -0,0 +1,30 @@
+/* chroot.c - Run command in new root directory.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * TODO: The test for root is "==" so root can trivially escape a chroot by
+ * moving it below cwd, ala mkdir("sub"); chroot("sub"); chdir("../../../..")
+ * The container guys use pivot_root() to deal with this, which does actually
+ * edit mount tree. (New option? Kernel patch?)
+
+USE_CHROOT(NEWTOY(chroot, "^<1", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config CHROOT
+  bool "chroot"
+  default y
+  help
+    usage: chroot NEWPATH [commandline...]
+
+    Run command within a new root directory. If no command, run /bin/sh.
+*/
+
+#include "toys.h"
+
+void chroot_main(void)
+{
+  char *binsh[] = {"/bin/sh", "-i", 0};
+
+  if (chdir(*toys.optargs) || chroot(".")) perror_exit_raw(*toys.optargs);
+  if (toys.optargs[1]) xexec(toys.optargs+1);
+  else xexec(binsh);
+}
diff --git a/toybox/toys/other/chvt.c b/toybox/toys/other/chvt.c
new file mode 100644
index 0000000..a93327f
--- /dev/null
+++ b/toybox/toys/other/chvt.c
@@ -0,0 +1,34 @@
+/* chvt.c - switch virtual terminals
+ *
+ * Copyright (C) 2008 David Anders <danders@amltd.com>
+
+USE_CHVT(NEWTOY(chvt, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+
+config CHVT
+  bool "chvt"
+  default y
+  help
+    usage: chvt N
+
+    Change to virtual terminal number N. (This only works in text mode.)
+
+    Virtual terminals are the Linux VGA text mode displays, ordinarily
+    switched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch
+    from X to a virtual terminal, and alt-F6 (or F7, or F8) to get back.
+*/
+
+#include "toys.h"
+
+void chvt_main(void)
+{
+  int vtnum, fd = fd;
+  char *consoles[]={"/dev/console", "/dev/vc/0", "/dev/tty", NULL}, **cc;
+
+  vtnum=atoi(*toys.optargs);
+  for (cc = consoles; *cc; cc++)
+    if (-1 != (fd = open(*cc, O_RDWR))) break;
+
+  // These numbers are VT_ACTIVATE and VT_WAITACTIVE from linux/vt.h
+  if (!*cc || fd < 0 || ioctl(fd, 0x5606, vtnum) || ioctl(fd, 0x5607, vtnum))
+    perror_exit(0);
+}
diff --git a/toybox/toys/other/clear.c b/toybox/toys/other/clear.c
new file mode 100644
index 0000000..4061ea8
--- /dev/null
+++ b/toybox/toys/other/clear.c
@@ -0,0 +1,19 @@
+/* clear.c - clear the screen
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+
+USE_CLEAR(NEWTOY(clear, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config CLEAR
+  bool "clear"
+  default y
+  help
+    Clear the screen.
+*/
+
+#include "toys.h"
+
+void clear_main(void)
+{
+  xwrite(1, "\e[2J\e[H", 7);
+}
diff --git a/toybox/toys/other/count.c b/toybox/toys/other/count.c
new file mode 100644
index 0000000..f3b6f82
--- /dev/null
+++ b/toybox/toys/other/count.c
@@ -0,0 +1,32 @@
+/* count.c - Progress indicator from stdin to stdout
+ *
+ * Copyright 2002 Rob Landley <rob@landley.net>
+
+USE_COUNT(NEWTOY(count, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config COUNT
+  bool "count"
+  default y
+  help
+    usage: count
+
+    Copy stdin to stdout, displaying simple progress indicator to stderr.
+*/
+
+#include "toys.h"
+
+void count_main(void)
+{
+  uint64_t size = 0;
+  int len;
+  char buf[32];
+
+  for (;;) {
+    len = xread(0, toybuf, sizeof(toybuf));
+    if (!len) break;
+    size += len;
+    xwrite(1, toybuf, len);
+    xwrite(2, buf, sprintf(buf, "%"PRIu64" bytes\r", size));
+  }
+  xwrite(2, "\n", 1);
+}
diff --git a/toybox/toys/other/dos2unix.c b/toybox/toys/other/dos2unix.c
new file mode 100644
index 0000000..083a814
--- /dev/null
+++ b/toybox/toys/other/dos2unix.c
@@ -0,0 +1,76 @@
+/* dos2unix.c - convert newline format
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+
+USE_DOS2UNIX(NEWTOY(dos2unix, 0, TOYFLAG_BIN))
+USE_UNIX2DOS(NEWTOY(unix2dos, 0, TOYFLAG_BIN))
+
+config DOS2UNIX
+  bool "dos2unix/unix2dos"
+  default y
+  help
+    usage: dos2unix [FILE...]
+
+    Convert newline format from dos "\r\n" to unix "\n".
+    If no files listed copy from stdin, "-" is a synonym for stdin.
+
+config UNIX2DOS
+  bool "unix2dos"
+  default y
+  help
+    usage: unix2dos [FILE...]
+
+    Convert newline format from unix "\n" to dos "\r\n".
+    If no files listed copy from stdin, "-" is a synonym for stdin.
+*/
+
+#define FOR_dos2unix
+#include "toys.h"
+
+GLOBALS(
+  char *tempfile;
+)
+
+static void do_dos2unix(int fd, char *name)
+{
+  char c = toys.which->name[0];
+  int outfd = 1, catch = 0;
+
+  if (fd) outfd = copy_tempfile(fd, name, &TT.tempfile);
+
+  for (;;) {
+    int len, in, out;
+
+    len = read(fd, toybuf+(sizeof(toybuf)/2), sizeof(toybuf)/2);
+    if (len<0) perror_msg_raw(name);
+    if (len<1) break;
+
+    for (in = out = 0; in < len; in++) {
+      char x = toybuf[in+sizeof(toybuf)/2];
+
+      // Drop \r only if followed by \n in dos2unix mode
+      if (catch) {
+        if (c == 'u' || x != '\n') toybuf[out++] = '\r';
+        catch = 0;
+      // Add \r only if \n not after \r in unix2dos mode
+      } else if (c == 'u' && x == '\n') toybuf[out++] = '\r';
+
+      if (x == '\r') catch++;
+      else toybuf[out++] = x;
+    }
+    xwrite(outfd, toybuf, out);
+  }
+  if (catch) xwrite(outfd, "\r", 1);
+
+  if (fd) replace_tempfile(-1, outfd, &TT.tempfile);
+}
+
+void dos2unix_main(void)
+{
+  loopfiles(toys.optargs, do_dos2unix);
+}
+
+void unix2dos_main(void)
+{
+  dos2unix_main();
+}
diff --git a/toybox/toys/other/eject.c b/toybox/toys/other/eject.c
new file mode 100644
index 0000000..31eab14
--- /dev/null
+++ b/toybox/toys/other/eject.c
@@ -0,0 +1,78 @@
+/* eject.c - eject device.
+ *
+ * Copyright 2012 Harvind Singh <harvindsingh1981@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gamil.com>
+ *
+ * No standard.
+
+USE_EJECT(NEWTOY(eject, ">1stT[!tT]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config EJECT
+  bool "eject"
+  default y
+  help
+    usage: eject [-stT] [DEVICE]
+
+    Eject DEVICE or default /dev/cdrom
+
+    -s	SCSI device
+    -t	Close tray
+    -T	Open/close tray (toggle).
+*/
+
+#define FOR_eject
+#include "toys.h"
+#include <scsi/sg.h>
+#include <scsi/scsi.h>
+
+// The SCSI way of requesting eject
+static void remove_scsi(int fd)
+{
+  unsigned i;
+  sg_io_hdr_t *header = (sg_io_hdr_t *)(toybuf+64);
+  char sg_driver_cmd[3][6] = {
+    { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0 },
+    { START_STOP, 0, 0, 0, 1, 0 }, //start the motor
+    { START_STOP, 0, 0, 0, 2, 0 } //eject the media
+  };
+
+  header->interface_id = 'S';
+  header->cmd_len = 6;
+  header->mx_sb_len = 32;
+  header->dxfer_direction = SG_DXFER_NONE;
+  header->dxferp = toybuf + 32;
+  header->sbp = (void *)toybuf;
+  header->timeout = 2000;
+
+  for (i = 0; i < 3; i++) {
+    header->cmdp = (void *)sg_driver_cmd[i];
+    xioctl(fd, SG_IO, (void *)header);
+  }
+
+  // force kernel to reread partition table when new disc is inserted
+  ioctl(fd, BLKRRPART);
+}
+
+/*
+ * eject main function.
+ */
+void eject_main(void)
+{
+  int fd, out = 0;
+  char *device_name = "/dev/cdrom";
+
+  if (*toys.optargs) device_name = *toys.optargs;
+
+  fd = xopen(device_name, O_RDONLY | O_NONBLOCK);
+  if (!toys.optflags) xioctl(fd, 0x5309, &out);		// CDROM_EJECT
+  else if (toys.optflags & FLAG_s) remove_scsi(fd);
+  else {
+    if ((toys.optflags & FLAG_T) || (toys.optflags & FLAG_t)) {
+      int rc = ioctl(fd, 0x5326, &out);			// CDROM_DRIVE_STATUS
+      if ((toys.optflags & FLAG_t) || rc == 2)		// CDS_TRAY_OPEN
+        xioctl(fd, 0x5319, &out);			// CDROM_CLOSE_TRAY
+      else xioctl(fd, 0x5309, &out);			// CDROM_EJECT
+    }
+  }
+  if (CFG_TOYBOX_FREE) xclose(fd);
+}
diff --git a/toybox/toys/other/factor.c b/toybox/toys/other/factor.c
new file mode 100644
index 0000000..0e07d71
--- /dev/null
+++ b/toybox/toys/other/factor.c
@@ -0,0 +1,86 @@
+/* factor.c - Factor integers
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * No standard, but it's in coreutils
+
+USE_FACTOR(NEWTOY(factor, 0, TOYFLAG_USR|TOYFLAG_BIN))
+
+config FACTOR
+  bool "factor"
+  default y
+  help
+    usage: factor NUMBER...
+
+    Factor integers.
+*/
+
+#include "toys.h"
+
+static void factor(char *s)
+{
+  unsigned long long l, ll;
+
+  for (;;) {
+    char *err = s;
+    int dash = 0;
+
+    while(isspace(*s)) s++;
+    if (*s=='-') dash = *s++;
+    if (!*s) return;
+
+    l = strtoull(s, &s, 0);
+    if (*s && !isspace(*s)) {
+      error_msg("%s: not integer", err);
+      while (*s && !isspace(*s)) s++;
+      continue;
+    }
+
+    printf("-%llu:"+!dash, l);
+
+    // Negative numbers have -1 as a factor
+    if (dash) printf(" -1");
+
+    // Nothing below 4 has factors
+    if (l < 4) {
+      printf(" %llu\n", l);
+      continue;
+    }
+
+    // Special case factors of 2
+    while (l && !(l&1)) {
+      printf(" 2");
+      l >>= 1;
+    }
+
+    // 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(" %llu", l);
+        break;
+      }
+      while (!(l%ll)) {
+        printf(" %llu", ll);
+        l /= ll;
+      }
+    }
+    xputc('\n');
+  }
+}
+
+void factor_main(void)
+{
+  if (toys.optc) {
+    char **ss;
+
+    for (ss = toys.optargs; *ss; ss++) factor(*ss);
+  } else for (;;) {
+    char *s = 0;
+    size_t len = 0;
+
+    if (-1 == getline(&s, &len, stdin)) break;
+    factor(s);
+  }
+}
diff --git a/toybox/toys/other/fallocate.c b/toybox/toys/other/fallocate.c
new file mode 100644
index 0000000..7a22634
--- /dev/null
+++ b/toybox/toys/other/fallocate.c
@@ -0,0 +1,31 @@
+/* fallocate.c - Preallocate space to a file
+ *
+ * Copyright 2013 Felix Janda <felix.janda@posteo.de>
+ *
+ * No standard
+
+USE_FALLOCATE(NEWTOY(fallocate, ">1l#|", TOYFLAG_USR|TOYFLAG_BIN))
+
+config FALLOCATE
+  bool "fallocate"
+  depends on TOYBOX_FALLOCATE
+  default y
+  help
+    usage: fallocate [-l size] file
+
+    Tell the filesystem to allocate space for a file.
+*/
+
+#define FOR_fallocate
+#include "toys.h"
+
+GLOBALS(
+  long size;
+)
+
+void fallocate_main(void)
+{
+  int fd = xcreate(*toys.optargs, O_RDWR | O_CREAT, 0644);
+  if (posix_fallocate(fd, 0, TT.size)) error_exit("Not enough space");
+  if (CFG_TOYBOX_FREE) close(fd);
+}
diff --git a/toybox/toys/other/flock.c b/toybox/toys/other/flock.c
new file mode 100644
index 0000000..5f0190a
--- /dev/null
+++ b/toybox/toys/other/flock.c
@@ -0,0 +1,39 @@
+/* flock.c - manage advisory file locks
+ *
+ * Copyright 2015 The Android Open Source Project
+
+USE_FLOCK(NEWTOY(flock, "<1>1nsux[-sux]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config FLOCK
+  bool "flock"
+  default y
+  help
+    usage: flock [-sxun] fd
+
+    Manage advisory file locks.
+
+    -s	Shared lock.
+    -x	Exclusive lock (default).
+    -u	Unlock.
+    -n	Non-blocking: fail rather than wait for the lock.
+*/
+
+#define FOR_flock
+#include "toys.h"
+
+#include <sys/file.h>
+
+void flock_main(void)
+{
+  int fd = xstrtol(*toys.optargs, NULL, 10), op;
+
+  if (toys.optflags & FLAG_u) op = LOCK_UN;
+  else op = (toys.optflags & FLAG_s) ? LOCK_SH : LOCK_EX;
+
+  if (toys.optflags & FLAG_n) op |= LOCK_NB;
+
+  if (flock(fd, op)) {
+    if ((op & LOCK_NB) && errno == EAGAIN) toys.exitval = 1;
+    else perror_exit("flock");
+  }
+}
diff --git a/toybox/toys/other/free.c b/toybox/toys/other/free.c
new file mode 100644
index 0000000..0a4d69b
--- /dev/null
+++ b/toybox/toys/other/free.c
@@ -0,0 +1,58 @@
+/* free.c - Display amount of free and used memory in the system.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+// Flag order is signifcant: b-t are units in order, FLAG_h-1 is unit mask
+USE_FREE(NEWTOY(free, "htgmkb[!htgmkb]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config FREE
+  bool "free"
+  default y
+  help
+    usage: free [-bkmgt]
+
+    Display the total, free and used amount of physical memory and swap space.
+
+    -bkmgt	Output units (default is bytes)
+    -h	Human readable
+*/
+
+#define FOR_free
+#include "toys.h"
+
+GLOBALS(
+  unsigned bits;
+  unsigned long long units;
+  char *buf;
+)
+
+static char *convert(unsigned long d)
+{
+  long long ll = d*TT.units;
+  char *s = TT.buf;
+
+  if (toys.optflags & FLAG_h) human_readable(s, ll, 0);
+  else sprintf(s, "%llu",ll>>TT.bits);
+  TT.buf += strlen(TT.buf)+1;
+
+  return s;
+}
+
+void free_main(void)
+{
+  struct sysinfo in;
+
+  sysinfo(&in);
+  TT.units = in.mem_unit ? in.mem_unit : 1;
+  while ((toys.optflags&(FLAG_h-1)) && !(toys.optflags&(1<<TT.bits))) TT.bits++;
+  TT.bits *= 10;
+  TT.buf = toybuf;
+
+  xprintf("\t\ttotal        used        free      shared     buffers\n"
+    "Mem:%17s%12s%12s%12s%12s\n-/+ buffers/cache:%15s%12s\n"
+    "Swap:%16s%12s%12s\n", convert(in.totalram),
+    convert(in.totalram-in.freeram), convert(in.freeram), convert(in.sharedram),
+    convert(in.bufferram), convert(in.totalram - in.freeram - in.bufferram),
+    convert(in.freeram + in.bufferram), convert(in.totalswap),
+    convert(in.totalswap - in.freeswap), convert(in.freeswap));
+}
diff --git a/toybox/toys/other/freeramdisk.c b/toybox/toys/other/freeramdisk.c
new file mode 100644
index 0000000..cb0b7f8
--- /dev/null
+++ b/toybox/toys/other/freeramdisk.c
@@ -0,0 +1,27 @@
+/* freeramdisk.c - Free all memory allocated to ramdisk
+ *
+ * Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89@gmail.com>
+ *
+ * No Standard
+
+USE_FREERAMDISK(NEWTOY(freeramdisk, "<1>1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+
+config FREERAMDISK
+  bool "freeramdisk"
+  default y
+  help
+    usage: freeramdisk [RAM device]
+
+    Free all memory allocated to specified ramdisk
+*/
+
+#include "toys.h"
+
+void freeramdisk_main(void)
+{
+  int fd;
+
+  fd = xopen(toys.optargs[0], O_RDWR);
+  xioctl(fd, BLKFLSBUF, toys.optargs[0]);
+  if (CFG_TOYBOX_FREE) xclose(fd);
+}
diff --git a/toybox/toys/other/fsfreeze.c b/toybox/toys/other/fsfreeze.c
new file mode 100644
index 0000000..dfe17fb
--- /dev/null
+++ b/toybox/toys/other/fsfreeze.c
@@ -0,0 +1,31 @@
+/* fsfreeze.c - freeze or thaw filesystem
+ *
+ * No standard.
+
+USE_FSFREEZE(NEWTOY(fsfreeze, "<1>1f|u|[!fu]", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config FSFREEZE
+  bool "fsfreeze"
+  default y
+  depends on TOYBOX_FIFREEZE
+  help
+    usage: fsfreeze {-f | -u} MOUNTPOINT
+
+    Freeze or unfreeze a filesystem.
+
+    -f	freeze
+    -u	unfreeze
+*/
+
+#define FOR_fsfreeze
+#include "toys.h"
+#include <linux/fs.h>
+
+void fsfreeze_main(void)
+{
+  int fd = xopenro(*toys.optargs); 
+  long p = 1;
+
+  xioctl(fd, (toys.optflags & FLAG_f) ? FIFREEZE : FITHAW, &p);
+  xclose(fd);
+}
diff --git a/toybox/toys/other/fsync.c b/toybox/toys/other/fsync.c
new file mode 100644
index 0000000..e6f6c8d
--- /dev/null
+++ b/toybox/toys/other/fsync.c
@@ -0,0 +1,33 @@
+/* fsync.c - Synchronize a file's in-core state with storage device.
+ *
+ * Copyright 2015 Ranjan Kumar <ranjankumar.bth@gmail.comi>
+ *
+ * No Standard.
+
+USE_FSYNC(NEWTOY(fsync, "<1d", TOYFLAG_BIN))
+
+config FSYNC
+  bool "fsync"
+  default y
+  help
+    usage: fsync [-d] [FILE...]
+
+    Synchronize a file's in-core state with storage device.
+
+    -d	Avoid syncing metadata.
+*/
+
+#define FOR_fsync
+#include "toys.h"
+
+static void do_fsync(int fd, char *name)
+{
+  if (((toys.optflags & FLAG_d) ? fdatasync(fd) : fsync(fd)))
+    perror_msg("can't sync '%s'", name);
+}
+
+void fsync_main(void)
+{
+  loopfiles_rw(toys.optargs, O_RDONLY|O_NOATIME|O_NOCTTY|O_CLOEXEC,
+      0, 0, do_fsync);
+}
diff --git a/toybox/toys/other/help.c b/toybox/toys/other/help.c
new file mode 100644
index 0000000..4722528
--- /dev/null
+++ b/toybox/toys/other/help.c
@@ -0,0 +1,76 @@
+/* help.c - Show help for toybox commands
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * Often a shell builtin.
+
+USE_HELP(NEWTOY(help, ""USE_HELP_EXTRAS("ah"), TOYFLAG_BIN))
+
+config HELP
+  bool "help"
+  default y
+  depends on TOYBOX_HELP
+  help
+    usage: help [command]
+
+    Show usage information for toybox commands.
+    Run "toybox" with no arguments for a list of available commands.
+
+config HELP_EXTRAS
+  bool "help -ah"
+  default y
+  depends on TOYBOX
+  depends on HELP
+  help
+    usage: help [-ah]
+
+    -a	All commands
+    -h	HTML output
+*/
+
+#define FOR_help
+#include "toys.h"
+
+static void do_help(struct toy_list *t)
+{
+  if (toys.optflags & FLAG_h) 
+    xprintf("<a name=\"%s\"><h1>%s</h1><blockquote><pre>\n", t->name, t->name);
+
+  toys.which = t;
+  show_help(stdout);
+
+  if (toys.optflags & FLAG_h) xprintf("</blockquote></pre>\n");
+}
+
+// The simple help is just toys.which = toy_find("name"); show_help(stdout);
+// But iterating through html output and all commands is a big more 
+
+void help_main(void)
+{
+  int i;
+  
+  if (!(toys.optflags & FLAG_a)) {
+    struct toy_list *t = toys.which;
+
+    if (*toys.optargs && !(t = toy_find(*toys.optargs)))
+      error_exit("Unknown command '%s'", *toys.optargs);
+    do_help(t);
+    return;
+  }
+
+  if (toys.optflags & FLAG_h) {
+    xprintf("<html>\n<title>Toybox command list</title>\n<body>\n<p>\n");
+    for (i=0; i < toys.toycount; i++)
+      xprintf("<a href=\"#%s\">%s</a>\n", toy_list[i].name,
+              toy_list[i].name);
+    xprintf("</p>\n");
+  }
+
+  for (i = 0; i < toys.toycount; i++) {
+    if (toys.optflags & FLAG_h) xprintf("<hr>\n<pre>\n");
+    do_help(toy_list+i);
+    if (toys.optflags & FLAG_h) xprintf("</pre>\n");
+  }
+
+  if (toys.optflags & FLAG_h) xprintf("</html>");
+}
diff --git a/toybox/toys/other/hexedit.c b/toybox/toys/other/hexedit.c
new file mode 100644
index 0000000..ffa304c
--- /dev/null
+++ b/toybox/toys/other/hexedit.c
@@ -0,0 +1,242 @@
+/* hexedit.c - Hexadecimal file editor
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ *
+ * No standard
+
+USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+
+config HEXEDIT
+  bool "hexedit"
+  default y
+  help
+    usage: hexedit FILENAME
+
+    Hexadecimal file editor. All changes are written to disk immediately.
+
+    -r	Read only (display but don't edit)
+
+    Keys:
+    Arrows        Move left/right/up/down by one line/column
+    Pg Up/Pg Dn   Move up/down by one page
+    0-9, a-f      Change current half-byte to hexadecimal value
+    u             Undo
+    q/^c/^d/<esc> Quit
+*/
+
+#define FOR_hexedit
+#include "toys.h"
+
+GLOBALS(
+  char *data;
+  long long len, base;
+  int numlen, undo, undolen;
+  unsigned height;
+)
+
+#define UNDO_LEN (sizeof(toybuf)/(sizeof(long long)+1))
+
+// Render all characters printable, using color to distinguish.
+static int draw_char(FILE *fp, wchar_t broiled)
+{
+  if (fp) {
+    if (broiled<32 || broiled>=127) {
+      if (broiled>127) {
+        tty_esc("2m");
+        broiled &= 127;
+      }
+      if (broiled<32 || broiled==127) {
+        tty_esc("7m");
+        if (broiled==127) broiled = 32;
+        else broiled += 64;
+      }
+      printf("%c", (int)broiled);
+      tty_esc("0m");
+    } else printf("%c", (int)broiled);
+  }
+
+  return 1;
+}
+
+static void draw_tail(void)
+{
+  tty_jump(0, TT.height);
+  tty_esc("K");
+
+  draw_trim(*toys.optargs, -1, 71);
+}
+
+static void draw_line(long long yy)
+{
+  int x, xx = 16;
+
+  yy = (TT.base+yy)*16;
+  if (yy+xx>=TT.len) xx = TT.len-yy;
+
+  if (yy<TT.len) {
+    printf("\r%0*llX ", TT.numlen, yy);
+    for (x=0; x<xx; x++) printf(" %02X", TT.data[yy+x]);
+    printf("%*s", 2+3*(16-xx), "");
+    for (x=0; x<xx; x++) draw_char(stdout, TT.data[yy+x]);
+    printf("%*s", 16-xx, "");
+  }
+  tty_esc("K");
+}
+
+static void draw_page(void)
+{
+  int y;
+
+  tty_jump(0, 0);
+  for (y = 0; y<TT.height; y++) {
+    if (y) printf("\r\n");
+    draw_line(y);
+  }
+  draw_tail();
+}
+
+// side: 0 = editing left, 1 = editing right, 2 = clear, 3 = read only
+static void highlight(int xx, int yy, int side)
+{
+  char cc = TT.data[16*(TT.base+yy)+xx];
+  int i;
+
+  // Display cursor
+  tty_jump(2+TT.numlen+3*xx, yy);
+  tty_esc("0m");
+  if (side!=2) tty_esc("7m");
+  if (side>1) printf("%02X", cc);
+  else for (i=0; i<2;) {
+    if (side==i) tty_esc("32m");
+    printf("%X", (cc>>(4*(1&++i)))&15);
+  }
+  tty_esc("0m");
+  tty_jump(TT.numlen+17*3+xx, yy);
+  draw_char(stdout, cc);
+}
+
+void hexedit_main(void)
+{
+  long long pos = 0, y;
+  int x, i, side = 0, key, ro = toys.optflags&FLAG_r,
+      fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR);
+  char keybuf[16];
+
+  *keybuf = 0;
+
+  // Terminal setup
+  TT.height = 25;
+  terminal_size(0, &TT.height);
+  if (TT.height) TT.height--;
+  sigatexit(tty_sigreset);
+  tty_esc("0m");
+  tty_esc("?25l");
+  fflush(0);
+  xset_terminal(1, 1, 0);
+
+  if ((TT.len = fdlength(fd))<1) error_exit("bad length");
+  if (sizeof(long)==32 && TT.len>SIZE_MAX) TT.len = SIZE_MAX;
+  // count file length hex in digits, rounded up to multiple of 4
+  for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++);
+  TT.numlen += (4-TT.numlen)&3;
+
+  TT.data = mmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0);
+  draw_page();
+
+  for (;;) {
+    // Scroll display if necessary
+    if (pos<0) pos = 0;
+    if (pos>=TT.len) pos = TT.len-1;
+    x = pos&15;
+    y = pos/16;
+
+    i = 0;
+    while (y<TT.base) {
+      if (TT.base-y>(TT.height/2)) {
+        TT.base = y;
+        draw_page();
+      } else {
+        TT.base--;
+        i++;
+        tty_esc("1T");
+        tty_jump(0, 0);
+        draw_line(0);
+      }
+    }
+    while (y>=TT.base+TT.height) {
+      if (y-(TT.base+TT.height)>(TT.height/2)) {
+        TT.base = y-TT.height-1;
+        draw_page();
+      } else {
+        TT.base++;
+        i++;
+        tty_esc("1S");
+        tty_jump(0, TT.height-1);
+        draw_line(TT.height-1);
+      }
+    }
+    if (i) draw_tail();
+    y -= TT.base;
+
+    // Display cursor and flush output
+    highlight(x, y, ro ? 3 : side);
+    xflush();
+
+    // Wait for next key
+    key = scan_key(keybuf, -1);
+    // Exit for q, ctrl-c, ctrl-d, escape, or EOF
+    if (key==-1 || key==3 || key==4 || key==27 || key=='q') break;
+    highlight(x, y, 2);
+
+    // Hex digit?
+    if (key>='a' && key<='f') key-=32;
+    if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) {
+      if (!side) {
+        long long *ll = (long long *)toybuf;
+
+        ll[TT.undo] = pos;
+        toybuf[(sizeof(long long)*UNDO_LEN)+TT.undo++] = TT.data[pos];
+        if (TT.undolen < UNDO_LEN) TT.undolen++;
+        TT.undo %= UNDO_LEN;
+      }
+
+      i = key - '0';
+      if (i>9) i -= 7;
+      TT.data[pos] &= 15<<(4*side);
+      TT.data[pos] |= i<<(4*!side);
+
+      if (++side==2) {
+        highlight(x, y, side);
+        side = 0;
+        ++pos;
+      }
+    } else side = 0;
+    if (key=='u') {
+      if (TT.undolen) {
+        long long *ll = (long long *)toybuf;
+
+        TT.undolen--;
+        if (!TT.undo) TT.undo = UNDO_LEN;
+        pos = ll[--TT.undo];
+        TT.data[pos] = toybuf[sizeof(long long)*UNDO_LEN+TT.undo];
+      }
+    }
+    if (key>=256) {
+      key -= 256;
+
+      if (key==KEY_UP) pos -= 16;
+      else if (key==KEY_DOWN) pos += 16;
+      else if (key==KEY_RIGHT) {
+        if (x<15) pos++;
+      } else if (key==KEY_LEFT) {
+        if (x) pos--;
+      } else if (key==KEY_PGUP) pos -= 16*TT.height;
+      else if (key==KEY_PGDN) pos += 16*TT.height;
+      else if (key==KEY_HOME) pos = 0;
+      else if (key==KEY_END) pos = TT.len-1;
+    }
+  }
+  munmap(TT.data, TT.len);
+  close(fd);
+  tty_reset();
+}
diff --git a/toybox/toys/other/hostid.c b/toybox/toys/other/hostid.c
new file mode 100644
index 0000000..883ac3c
--- /dev/null
+++ b/toybox/toys/other/hostid.c
@@ -0,0 +1,23 @@
+/* hostid.c - Print the numeric identifier for the current host.
+ *
+ * Copyright 2015 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ *
+ * No Standard.
+
+USE_HOSTID(NEWTOY(hostid, ">0", TOYFLAG_USR|TOYFLAG_BIN))
+
+config HOSTID
+  bool "hostid"
+  default y
+  help
+    usage: hostid
+
+    Print the numeric identifier for the current host.
+*/
+#define FOR_hostid
+#include "toys.h"
+
+void hostid_main(void)
+{
+  xprintf("%08lx\n", gethostid());
+}
diff --git a/toybox/toys/other/hwclock.c b/toybox/toys/other/hwclock.c
new file mode 100644
index 0000000..75e0641
--- /dev/null
+++ b/toybox/toys/other/hwclock.c
@@ -0,0 +1,136 @@
+/* hwclock.c - get and set the hwclock
+ *
+ * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
+ *
+ * No standard, but see Documentation/rtc.txt in the linux kernel source..
+ *
+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))
+
+config HWCLOCK
+  bool "hwclock"
+  default y
+  help
+    usage: hwclock [-rswtluf]
+
+    -f FILE Use specified device file instead of /dev/rtc (--rtc)
+    -l      Hardware clock uses localtime (--localtime)
+    -r      Show hardware clock time (--show)
+    -s      Set system time from hardware clock (--hctosys)
+    -t      Set the system time based on the current timezone (--systz)
+    -u      Hardware clock uses UTC (--utc)
+    -w      Set hardware clock from system time (--systohc)
+*/
+
+#define FOR_hwclock
+#include "toys.h"
+#include <linux/rtc.h>
+
+GLOBALS(
+  char *fname;
+
+  int utc;
+)
+
+static int rtc_find(struct dirtree* node)
+{
+  FILE *fp;
+
+  if (!node->parent) return DIRTREE_RECURSE;
+
+  snprintf(toybuf, sizeof(toybuf), "/sys/class/rtc/%s/hctosys", node->name);
+  fp = fopen(toybuf, "r");
+  if (fp) {
+    int hctosys = 0, items = fscanf(fp, "%d", &hctosys);
+
+    fclose(fp);
+    if (items == 1 && hctosys == 1) {
+      snprintf(toybuf, sizeof(toybuf), "/dev/%s", node->name);
+      TT.fname = toybuf;
+
+      return DIRTREE_ABORT;
+    }
+  }
+
+  return 0;
+}
+
+void hwclock_main()
+{
+  struct timezone tzone;
+  struct timeval timeval;
+  struct tm tm;
+  time_t time;
+  int fd = -1;
+
+  // check for Grenich Mean Time
+  if (toys.optflags & FLAG_u) TT.utc = 1;
+  else {
+    FILE *fp;
+    char *s = 0;
+
+    for (fp = fopen("/etc/adjtime", "r");
+         fp && getline(&s, (void *)toybuf, fp)>0;
+         free(s), s = 0) TT.utc += !strncmp(s, "UTC", 3);
+    if (fp) fclose(fp);
+  }
+
+  if (!(toys.optflags&FLAG_t)) {
+    int w = toys.optflags & FLAG_w, flag = O_WRONLY*w;
+
+    // Open /dev/rtc (if your system has no /dev/rtc symlink, search for it).
+    if (!TT.fname && (fd = open("/dev/rtc", flag)) == -1) {
+      dirtree_read("/sys/class/rtc", rtc_find);
+      if (!TT.fname) TT.fname = "/dev/misc/rtc";
+    }
+    if (fd == -1) fd = xopen(TT.fname, flag);
+
+    // Get current time in seconds from rtc device. todo: get subsecond time
+    if (!w) {
+      char *s = s;
+
+      xioctl(fd, RTC_RD_TIME, &tm);
+      if (TT.utc) s = xtzset("UTC0");
+      if ((time = mktime(&tm)) < 0) error_exit("mktime failed");
+      if (TT.utc) {
+        free(xtzset(s));
+        free(s);
+      }
+    }
+  }
+
+  if (toys.optflags & (FLAG_w|FLAG_t)) {
+    if (gettimeofday(&timeval, 0)) perror_exit("gettimeofday failed");
+    if (!(TT.utc ? gmtime_r : localtime_r)(&timeval.tv_sec, &tm))
+      error_exit(TT.utc ? "gmtime_r failed" : "localtime_r failed");
+  }
+
+  if (toys.optflags & FLAG_w) {
+    /* The value of tm_isdst will positive if daylight saving time is in effect,
+     * zero if it is not and negative if the information is not available. 
+     * todo: so why isn't this negative...? */
+    tm.tm_isdst = 0;
+    xioctl(fd, RTC_SET_TIME, &tm);
+  } else if (toys.optflags & FLAG_s) {
+    tzone.tz_minuteswest = timezone / 60 - 60 * daylight;
+    timeval.tv_sec = time;
+    timeval.tv_usec = 0; // todo: fixit
+  } else if (toys.optflags & FLAG_t) {
+    // Adjust seconds for timezone and daylight saving time
+    // extern long timezone is defined in header sys/time.h
+    tzone.tz_minuteswest = timezone / 60;
+    if (tm.tm_isdst) tzone.tz_minuteswest -= 60;
+    if (!TT.utc) timeval.tv_sec += tzone.tz_minuteswest * 60;
+  } else {
+    char *c = ctime(&time), *s = strrchr(c, '\n');
+
+    if (s) *s = '\0';
+    // TODO: implement this.
+    xprintf("%s  0.000000 seconds\n", c);
+  }
+  if (toys.optflags & (FLAG_t|FLAG_s)) {
+    tzone.tz_dsttime = 0;
+    if (settimeofday(&timeval, &tzone)) perror_exit("settimeofday failed");
+  }
+
+  if (fd != -1) close(fd);
+}
diff --git a/toybox/toys/other/inotifyd.c b/toybox/toys/other/inotifyd.c
new file mode 100644
index 0000000..42d1d76
--- /dev/null
+++ b/toybox/toys/other/inotifyd.c
@@ -0,0 +1,126 @@
+/* inotifyd.c - inotify daemon. 
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
+
+config INOTIFYD
+  bool "inotifyd"
+  default y
+  help
+    usage: inotifyd PROG FILE[:MASK] ...
+
+    When a filesystem event matching MASK occurs to a FILE, run PROG as:
+
+      PROG EVENTS FILE [DIRFILE]
+
+    If PROG is "-" events are sent to stdout.
+
+    This file is:
+      a  accessed    c  modified    e  metadata change  w  closed (writable)
+      r  opened      D  deleted     M  moved            0  closed (unwritable)
+      u  unmounted   o  overflow    x  unwatchable
+
+    A file in this directory is:
+      m  moved in    y  moved out   n  created          d  deleted
+
+    When x event happens for all FILEs, inotifyd exits (after waiting for PROG).
+*/
+
+#define FOR_inotifyd
+#include "toys.h"
+#include <sys/inotify.h>
+
+void inotifyd_main(void)
+{
+  struct pollfd fds;
+  char *prog_args[5], **ss = toys.optargs;
+  char *masklist ="acew0rmyndDM uox";
+
+  fds.events = POLLIN;
+
+  *prog_args = *toys.optargs;
+  prog_args[4] = 0;
+  if ((fds.fd = inotify_init()) == -1) perror_exit(0);
+
+  // Track number of watched files. First one was program to run.
+  toys.optc--;
+
+  while (*++ss) {
+    char *path = *ss, *masks = strchr(*ss, ':');
+    int i, mask = 0;
+
+    if (!masks) mask = 0xfff; // default to all
+    else{
+      *masks++ = 0;
+      for (*masks++ = 0; *masks; masks++) {
+        i = stridx(masklist, *masks);;
+        if (i == -1) error_exit("bad mask '%c'", *masks);
+        mask |= 1<<i;
+      }
+    }
+
+    // This returns increasing numbers starting from 1, which coincidentally
+    // is the toys.optargs position of the file. (0 is program to run.)
+    if (inotify_add_watch(fds.fd, path, mask) < 0) perror_exit_raw(path);
+  }
+
+  for (;;) {
+    int ret = 0, len;
+    void *buf = 0;
+    struct inotify_event *event;
+
+    // Read next event(s)
+    ret = poll(&fds, 1, -1);
+    if (ret < 0 && errno == EINTR) continue;
+    if (ret <= 0) break;
+    xioctl(fds.fd, FIONREAD, &len);
+    event = buf = xmalloc(len);
+    len = readall(fds.fd, buf, len);
+
+    // Loop through set of events.
+    for (;;) {
+      int left = len - (((char *)event)-(char *)buf),
+          size = sizeof(struct inotify_event);
+
+      // Don't dereference event if ->len is off end of bufer
+      if (left >= size) size += event->len;
+      if (left < size) break;
+
+      if (event->mask) {
+        char *s = toybuf, *m;
+
+        for (m = masklist; *m; m++)
+          if (event->mask & (1<<(m-masklist))) *s++ = *m;
+        *s = 0;
+
+        if (**prog_args == '-' && !prog_args[0][1]) {
+          xprintf("%s\t%s\t%s\n" + 3*!event->len, toybuf,
+              toys.optargs[event->wd], event->name);
+        } else {
+          prog_args[1] = toybuf;
+          prog_args[2] = toys.optargs[event->wd];
+          prog_args[3] = event->len ? event->name : 0;
+          xrun(prog_args);
+        }
+
+        if (event->mask & IN_IGNORED) {
+          if (--toys.optc <= 0) {
+            free(buf);
+
+            goto done;
+          }
+          inotify_rm_watch(fds.fd, event->wd);
+        }
+      }
+      event = (void*)(size + (char*)event);
+    }
+    free(buf);
+  }
+
+done:
+  toys.exitval = !!toys.signal;
+}
diff --git a/toybox/toys/other/insmod.c b/toybox/toys/other/insmod.c
new file mode 100644
index 0000000..9a3f595
--- /dev/null
+++ b/toybox/toys/other/insmod.c
@@ -0,0 +1,54 @@
+/* insmod.c - Load a module into the Linux kernel.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_INSMOD(NEWTOY(insmod, "<1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+
+config INSMOD
+  bool "insmod"
+  default y
+  help
+    usage: insmod MODULE [MODULE_OPTIONS]
+
+    Load the module named MODULE passing options if given.
+*/
+
+#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 = xopenro(*toys.optargs);
+  int i, rc;
+
+  i = 1;
+  while (toys.optargs[i] &&
+    strlen(toybuf) + strlen(toys.optargs[i]) + 2 < sizeof(toybuf))
+  {
+    strcat(toybuf, toys.optargs[i++]);
+    strcat(toybuf, " ");
+  }
+
+  // finit_module was new in Linux 3.8, and doesn't work on stdin,
+  // so we fall back to init_module if necessary.
+  rc = finit_module(fd, toybuf, 0);
+  if (rc && (fd == 0 || errno == ENOSYS)) {
+    off_t len = 0;
+    char *path = !strcmp(*toys.optargs, "-") ? "/dev/stdin" : *toys.optargs;
+    char *buf = readfileat(AT_FDCWD, path, NULL, &len);
+
+    rc = init_module(buf, len, toybuf);
+    if (CFG_TOYBOX_FREE) free(buf);
+  }
+
+  if (rc) perror_exit("failed to load %s", toys.optargs[0]);
+
+  if (CFG_TOYBOX_FREE) close(fd);
+}
diff --git a/toybox/toys/other/ionice.c b/toybox/toys/other/ionice.c
new file mode 100644
index 0000000..37d3545
--- /dev/null
+++ b/toybox/toys/other/ionice.c
@@ -0,0 +1,97 @@
+/* ionice.c - set or get process I/O scheduling class and priority
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ *
+ * It would be really nice if there was a standard, but no. There is
+ * Documentation/block/ioprio.txt in the linux source.
+
+USE_IONICE(NEWTOY(ionice, "^tc#<0>3=2n#<0>7=5p#", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IORENICE(NEWTOY(iorenice, "?<1>3", TOYFLAG_USR|TOYFLAG_BIN))
+
+config IONICE
+  bool "ionice"
+  default y
+  help
+    usage: ionice [-t] [-c CLASS] [-n LEVEL] [COMMAND...|-p PID]
+
+    Change the I/O scheduling priority of a process. With no arguments
+    (or just -p), display process' existing I/O class/priority.
+
+    -c	CLASS = 1-3: 1(realtime), 2(best-effort, default), 3(when-idle)
+    -n	LEVEL = 0-7: (0 is highest priority, default = 5)
+    -p	Affect existing PID instead of spawning new child
+    -t	Ignore failure to set I/O priority
+
+    System default iopriority is generally -c 2 -n 4.
+
+config IORENICE
+  bool "iorenice"
+  default y
+  help
+    usage: iorenice PID [CLASS] [PRIORITY]
+
+    Display or change I/O priority of existing process. CLASS can be
+    "rt" for realtime, "be" for best effort, "idle" for only when idle, or
+    "none" to leave it alone. PRIORITY can be 0-7 (0 is highest, default 4).
+*/
+
+#define FOR_ionice
+#include "toys.h"
+#include <sys/syscall.h>
+
+GLOBALS(
+  long pid;
+  long level;
+  long class;
+)
+
+static int ioprio_get(void)
+{
+  return syscall(__NR_ioprio_get, 1, (int)TT.pid);
+}
+
+static int ioprio_set(void)
+{
+  int prio = ((int)TT.class << 13) | (int)TT.level;
+
+  return syscall(__NR_ioprio_set, 1, (int)TT.pid, prio);
+}
+
+void ionice_main(void)
+{
+  if (!TT.pid && !toys.optc) error_exit("Need -p or COMMAND");
+  if (toys.optflags == FLAG_p) {
+    int p = ioprio_get();
+    xprintf("%s: prio %d\n",
+      (char *[]){"unknown", "Realtime", "Best-effort", "Idle"}[(p>>13)&3],
+      p&7);
+  } else {
+    if (-1 == ioprio_set() && !(toys.optflags&FLAG_t)) perror_exit("set");
+    if (!TT.pid) xexec(toys.optargs);
+  }
+}
+
+void iorenice_main(void)
+{
+  char *classes[] = {"none", "rt", "be", "idle"};
+
+  TT.pid = atolx(*toys.optargs);
+  if (toys.optc == 1) {
+    int p = ioprio_get();
+
+    if (p == -1) perror_exit("read priority");
+    TT.class = (p>>13)&3;
+    p &= 7;
+    xprintf("Pid %ld, class %s (%ld), prio %d\n",
+            TT.pid, classes[TT.class], TT.class, p);
+    return;
+  }
+
+  for (TT.class = 0; TT.class<4; TT.class++)
+    if (!strcmp(toys.optargs[toys.optc-1], classes[TT.class])) break;
+  if (toys.optc == 3 || TT.class == 4) TT.level = atolx(toys.optargs[1]);
+  else TT.level = 4;
+  TT.class &= 3;
+
+  if (-1 == ioprio_set()) perror_exit("set");
+}
diff --git a/toybox/toys/other/login.c b/toybox/toys/other/login.c
new file mode 100644
index 0000000..7f9559a
--- /dev/null
+++ b/toybox/toys/other/login.c
@@ -0,0 +1,165 @@
+/* login.c - Start a session on the system.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+ *
+ * No support for PAM/securetty/selinux/login script/issue/utmp
+ * Relies on libcrypt for hash calculation.
+ *
+ * TODO: this command predates "pending" but needs cleanup. It #defines
+ * random stuff, calls exit() form a signal handler... yeah.
+
+USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+
+config LOGIN
+  bool "login"
+  default y
+  depends on TOYBOX_SHADOW
+  help
+    usage: login [-p] [-h host] [-f USERNAME] [USERNAME]
+
+    Log in as a user, prompting for username and password if necessary.
+
+    -p	Preserve environment
+    -h	The name of the remote host for this login
+    -f	login as USERNAME without authentication
+*/
+
+#define FOR_login
+#include "toys.h"
+
+GLOBALS(
+  char *hostname;
+  char *username;
+
+  int login_timeout, login_fail_timeout;
+)
+
+static void login_timeout_handler(int sig __attribute__((unused)))
+{
+  printf("\nLogin timed out after %d seconds.\n", TT.login_timeout);
+  exit(0);
+}
+
+void login_main(void)
+{
+  char *forbid[] = {
+    "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD",
+    "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH",
+    "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL"
+  };
+  int hh = toys.optflags&FLAG_h, count, tty;
+  char uu[33], *username, *pass = 0, *ss;
+  struct passwd *pwd = 0;
+
+  for (tty=0; tty<3; tty++) if (isatty(tty)) break;
+  if (tty == 3) error_exit("no tty");
+
+  for (count = 0; count < ARRAY_LEN(forbid); count++) unsetenv(forbid[count]);
+
+  openlog("login", LOG_PID | LOG_CONS, LOG_AUTH);
+  xsignal(SIGALRM, login_timeout_handler);
+
+  if (TT.username) username = TT.username;
+  else username = *toys.optargs;
+  for (count = 0; count < 3; count++) {
+    alarm(TT.login_timeout = 60);
+    tcflush(0, TCIFLUSH);
+
+    if (!username) {
+      int i;
+
+      memset(username = uu, 0, sizeof(uu));
+      gethostname(uu, sizeof(uu)-1);
+      printf("%s%slogin: ", *uu ? uu : "", *uu ? " " : "");
+      fflush(stdout);
+
+      if(!fgets(uu, sizeof(uu)-1, stdin)) _exit(1);
+
+      // Remove trailing \n and so on
+      for (i = 0; i<sizeof(uu); i++) if (uu[i]<=' ' || uu[i]==':') uu[i]=0;
+      if (!*uu) {
+        username = 0;
+        continue;
+      }
+    }
+
+    // If user exists and isn't locked
+    pwd = getpwnam(username);
+    if (pwd && *pwd->pw_passwd != '!' && *pwd->pw_passwd != '*') {
+
+      // Pre-authenticated or passwordless
+      if (TT.username || !*pwd->pw_passwd) break;
+
+      // fetch shadow password if necessary
+      if (*(pass = pwd->pw_passwd) == 'x') {
+        struct spwd *spwd = getspnam (username);
+
+        if (spwd) pass = spwd->sp_pwdp;
+      }
+    } else if (TT.username) error_exit("bad -f '%s'", TT.username);
+
+    // Verify password. (Prompt for password _before_ checking disable state.)
+    if (!read_password(toybuf, sizeof(toybuf), "Password: ")) {
+      int x = pass && (ss = crypt(toybuf, pass)) && !strcmp(pass, ss);
+
+      // password go bye-bye now.
+      memset(toybuf, 0, sizeof(toybuf));
+      if (x) break;
+    }
+
+    syslog(LOG_WARNING, "invalid password for '%s' on %s %s%s", pwd->pw_name,
+      ttyname(tty), hh ? "from " : "", hh ? TT.hostname : "");
+
+    sleep(3);
+    puts("Login incorrect");
+
+    username = 0;
+    pwd = 0;
+  }
+
+  alarm(0);
+  // This had password data in it, and we reuse for motd below
+  memset(toybuf, 0, sizeof(toybuf));
+
+  if (!pwd) error_exit("max retries (3)");
+
+  // Check twice because "this file exists" is a security test, and in
+  // theory filehandle exhaustion or other error could make open/read fail.
+  if (pwd->pw_uid && !access("/etc/nologin", R_OK)) {
+    ss = readfile("/etc/nologin", toybuf, sizeof(toybuf));
+    puts ((ss && *ss) ? ss : "nologin");
+    free(ss);
+    toys.exitval = 1;
+
+    return;
+  }
+
+  xsetuser(pwd);
+
+  if (chdir(pwd->pw_dir)) printf("bad $HOME: %s\n", pwd->pw_dir);
+
+  if (!(toys.optflags&FLAG_p)) {
+    char *term = getenv("TERM");
+
+    clearenv();
+    if (term) setenv("TERM", term, 1);
+  }
+
+  setenv("USER", pwd->pw_name, 1);
+  setenv("LOGNAME", pwd->pw_name, 1);
+  setenv("HOME", pwd->pw_dir, 1);
+  setenv("SHELL", pwd->pw_shell, 1);
+
+  // Message of the day
+  if ((ss = readfile("/etc/motd", 0, 0))) {
+    puts(ss);
+    free(ss);
+  }
+
+  syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name,
+    ttyname(tty), hh ? "from" : "", hh ? TT.hostname : "");
+
+  // not using xexec(), login calls absolute path from filesystem so must exec()
+  execl(pwd->pw_shell, xmprintf("-%s", pwd->pw_shell), (char *)0);
+  perror_exit("exec shell '%s'", pwd->pw_shell);
+}
diff --git a/toybox/toys/other/losetup.c b/toybox/toys/other/losetup.c
new file mode 100644
index 0000000..4e467a9
--- /dev/null
+++ b/toybox/toys/other/losetup.c
@@ -0,0 +1,190 @@
+/* losetup.c - Loopback setup
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * No standard. (Sigh.)
+
+USE_LOSETUP(NEWTOY(losetup, ">2S(sizelimit)#s(show)ro#j:fdca[!afj]", TOYFLAG_SBIN))
+
+config LOSETUP
+  bool "losetup"
+  default y
+  help
+    usage: losetup [-cdrs] [-o OFFSET] [-S SIZE] {-d DEVICE...|-j FILE|-af|{DEVICE FILE}}
+
+    Associate a loopback device with a file, or show current file (if any)
+    associated with a loop device.
+
+    Instead of a device:
+    -a	Iterate through all loopback devices
+    -f	Find first unused loop device (may create one)
+    -j	Iterate through all loopback devices associated with FILE
+
+    existing:
+    -c	Check capacity (file size changed)
+    -d	Detach loopback device
+
+    new:
+    -s	Show device name (alias --show)
+    -o	Start assocation at OFFSET into FILE
+    -r	Read only
+    -S	Limit SIZE of loopback association (alias --sizelimit)
+*/
+
+#define FOR_losetup
+#include "toys.h"
+#include <linux/loop.h>
+
+GLOBALS(
+  char *jfile;
+  long offset;
+  long size;
+
+  int openflags;
+  dev_t jdev;
+  ino_t jino;
+)
+
+/*
+todo: basic /dev file association
+  associate DEV FILE
+  #-a
+  cdfjosS
+  allocate new loop device:
+    /dev/loop-control
+    https://lkml.org/lkml/2011/7/26/148
+*/
+
+// -f: *device is NULL
+
+// Perform requested operation on one device. Returns 1 if handled, 0 if error
+static void loopback_setup(char *device, char *file)
+{
+  struct loop_info64 *loop = (void *)(toybuf+32);
+  int lfd = -1, ffd = ffd;
+  unsigned flags = toys.optflags;
+
+  // Open file (ffd) and loop device (lfd)
+
+  if (file) ffd = xopen(file, TT.openflags);
+  if (!device) {
+    int i, cfd = open("/dev/loop-control", O_RDWR);
+
+    // We assume /dev is devtmpfs so device creation has no lag. Otherwise
+    // just preallocate loop devices and stay within them.
+
+    // 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);
+      close(cfd);
+    }
+  }
+
+  if (device) lfd = open(device, TT.openflags);
+
+  // Stat the loop device to see if there's a current association.
+  memset(loop, 0, sizeof(struct loop_info64));
+  if (-1 == lfd || ioctl(lfd, LOOP_GET_STATUS64, loop)) {
+    if (errno == ENXIO && (flags & (FLAG_a|FLAG_j))) goto done;
+    if (errno != ENXIO || !file) {
+      perror_msg_raw(device ? device : "-f");
+      goto done;
+    }
+  }
+
+  // Skip -j filtered devices
+  if (TT.jfile && (loop->lo_device != TT.jdev || loop->lo_inode != TT.jino))
+    goto done;
+
+  // Check size of file or delete existing association
+  if (flags & (FLAG_c|FLAG_d)) {
+    // The constant is LOOP_SET_CAPACITY
+    if (ioctl(lfd, (flags & FLAG_c) ? 0x4C07 : LOOP_CLR_FD, 0)) {
+      perror_msg_raw(device);
+      goto done;
+    }
+  // Associate file with this device?
+  } else if (file) {
+    char *s = xabspath(file, 1);
+
+    if (!s) perror_exit("file"); // already opened, but if deleted since...
+    if (ioctl(lfd, LOOP_SET_FD, ffd)) perror_exit("%s=%s", device, file);
+    loop->lo_offset = TT.offset;
+    loop->lo_sizelimit = TT.size;
+    xstrncpy((char *)loop->lo_file_name, s, LO_NAME_SIZE);
+    s[LO_NAME_SIZE-1] = 0;
+    if (ioctl(lfd, LOOP_SET_STATUS64, loop)) perror_exit("%s=%s", device, file);
+    if (flags & FLAG_s) printf("%s", device);
+    free(s);
+  } else if (flags & FLAG_f) printf("%s", device);
+  else {
+    xprintf("%s: [%04llx]:%llu (%s)", device, loop->lo_device, loop->lo_inode,
+      loop->lo_file_name);
+    if (loop->lo_offset) xprintf(", offset %llu", loop->lo_offset);
+    if (loop->lo_sizelimit) xprintf(", sizelimit %llu", loop->lo_sizelimit);
+    xputc('\n');
+  }
+
+done:
+  if (file) close(ffd);
+  if (lfd != -1) close(lfd);
+}
+
+// Perform an action on all currently existing loop devices
+static int dash_a(struct dirtree *node)
+{
+  char *s = node->name;
+
+  // Initial /dev node needs to recurse down one level, then only loop[0-9]*
+  if (*s == '/') return DIRTREE_RECURSE;
+  if (strncmp(s, "loop", 4) || !isdigit(s[4])) return 0;
+
+  s = dirtree_path(node, 0);
+  loopback_setup(s, 0);
+  free(s);
+
+  return 0;
+}
+
+void losetup_main(void)
+{
+  char **s;
+
+  TT.openflags = (toys.optflags & FLAG_r) ? O_RDONLY : O_RDWR;
+
+  if (TT.jfile) {
+    struct stat st;
+
+    xstat(TT.jfile, &st);
+    TT.jdev = st.st_dev;
+    TT.jino = st.st_ino;
+  }
+
+  // With just device, display current association
+  // -a, -f substitute for device
+  // -j substitute for device
+
+  // new association: S size o offset rs - need a file
+  // existing association: cd
+
+  // -f(dc FILE)
+
+  if (toys.optflags & FLAG_f) {
+    if (toys.optc > 1) perror_exit("max 1 arg");
+    loopback_setup(NULL, *toys.optargs);
+  } else if (toys.optflags & (FLAG_a|FLAG_j)) {
+    if (toys.optc) error_exit("bad args");
+    dirtree_read("/dev", dash_a);
+  // Do we need one DEVICE argument?
+  } else {
+    char *file = (toys.optflags & (FLAG_d|FLAG_c)) ? NULL : toys.optargs[1];
+
+    if (!toys.optc || (file && toys.optc != 2)) 
+      help_exit("needs %d arg%s", 1+!!file, file ? "s" : "");
+    for (s = toys.optargs; *s; s++) {
+      loopback_setup(*s, file);
+      if (file) break;
+    }
+  }
+}
diff --git a/toybox/toys/other/lsattr.c b/toybox/toys/other/lsattr.c
new file mode 100644
index 0000000..ceb14bd
--- /dev/null
+++ b/toybox/toys/other/lsattr.c
@@ -0,0 +1,313 @@
+/* lsattr.c - List file attributes on a Linux second extended file system.
+ *
+ * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_LSATTR(NEWTOY(lsattr, "vldaR", TOYFLAG_BIN))
+USE_CHATTR(NEWTOY(chattr, NULL, TOYFLAG_BIN))
+
+config LSATTR
+  bool "lsattr"
+  default y
+  help
+    usage: lsattr [-Radlv] [Files...]
+
+    List file attributes on a Linux second extended file system.
+
+    -R Recursively list attributes of directories and their contents.
+    -a List all files in directories, including files that start with '.'.
+    -d List directories like other files, rather than listing their contents.
+    -l List long flag names.
+    -v List the file's version/generation number.
+
+config CHATTR
+  bool "chattr"
+  default y
+  help
+    usage: chattr [-R] [-+=AacDdijsStTu] [-v version] [File...]
+
+    Change file attributes on a Linux second extended file system.
+
+    Operators:
+      '-' Remove attributes.
+      '+' Add attributes.
+      '=' Set attributes.
+
+    Attributes:
+      A  Don't track atime.
+      a  Append mode only.
+      c  Enable compress.
+      D  Write dir contents synchronously.
+      d  Don't backup with dump.
+      i  Cannot be modified (immutable).
+      j  Write all data to journal first.
+      s  Zero disk storage when deleted.
+      S  Write file contents synchronously.
+      t  Disable tail-merging of partial blocks with other files.
+      u  Allow file to be undeleted.
+      -R Recurse.
+      -v Set the file's version/generation number.
+
+*/
+#define FOR_lsattr
+#include "toys.h"
+#include <linux/fs.h>
+
+static struct ext2_attr {
+  char *name;
+  unsigned long flag;
+  char opt;
+} e2attrs[] = {
+  {"Secure_Deletion",               FS_SECRM_FL,        's'}, // Secure deletion
+  {"Undelete",                      FS_UNRM_FL,         'u'}, // Undelete
+  {"Compression_Requested",         FS_COMPR_FL,        'c'}, // Compress file
+  {"Synchronous_Updates",           FS_SYNC_FL,         'S'}, // Synchronous updates
+  {"Immutable",                     FS_IMMUTABLE_FL,    'i'}, // Immutable file
+  {"Append_Only",                   FS_APPEND_FL,       'a'}, // writes to file may only append
+  {"No_Dump",                       FS_NODUMP_FL,       'd'}, // do not dump file
+  {"No_Atime",                      FS_NOATIME_FL,      'A'}, // do not update atime
+  {"Indexed_directory",             FS_INDEX_FL,        'I'}, // hash-indexed directory
+  {"Journaled_Data",                FS_JOURNAL_DATA_FL, 'j'}, // file data should be journaled
+  {"No_Tailmerging",                FS_NOTAIL_FL,       't'}, // file tail should not be merged
+  {"Synchronous_Directory_Updates", FS_DIRSYNC_FL,      'D'}, // dirsync behaviour (directories only)
+  {"Top_of_Directory_Hierarchies",  FS_TOPDIR_FL,       'T'}, // Top of directory hierarchies
+  {NULL,                            -1,                   0},
+};
+
+// Get file flags on a Linux second extended file system.
+static int ext2_getflag(int fd, struct stat *sb, unsigned long *flag)
+{
+  if(!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode)) {
+    errno = EOPNOTSUPP;
+    return -1;
+  }
+  return (ioctl(fd, FS_IOC_GETFLAGS, (void*)flag));
+}
+
+static void print_file_attr(char *path)
+{
+  unsigned long flag = 0, version = 0;
+  int fd;
+  struct stat sb;
+
+  if (!stat(path, &sb) && !S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode)) {
+    errno = EOPNOTSUPP;
+    goto LABEL1;
+  }
+  if (-1 == (fd=open(path, O_RDONLY | O_NONBLOCK))) goto LABEL1;
+
+  if (toys.optflags & FLAG_v) { 
+    if (ioctl(fd, FS_IOC_GETVERSION, (void*)&version) < 0) goto LABEL2;
+    xprintf("%5lu ", version);
+  }
+
+  if (ext2_getflag(fd, &sb, &flag) < 0) perror_msg("reading flags '%s'", path);
+  else {
+    struct ext2_attr *ptr = e2attrs;
+
+    if (toys.optflags & FLAG_l) {
+      int name_found = 0;
+
+      xprintf("%-50s ", path);
+      for (; ptr->name; ptr++) {
+        if (flag & ptr->flag) {
+          if (name_found) xprintf(", "); //for formatting.
+          xprintf("%s", ptr->name);
+          name_found = 1;
+        }
+      }
+      if (!name_found) xprintf("---");
+      xputc('\n');
+    } else {
+      int index = 0;
+
+      for (; ptr->name; ptr++)
+        toybuf[index++] = (flag & ptr->flag) ? ptr->opt : '-';
+      toybuf[index] = '\0';
+      xprintf("%s %s\n", toybuf, path);
+    }
+  }
+  xclose(fd);
+  return;
+LABEL2: xclose(fd);
+LABEL1: perror_msg("reading '%s'", path);
+}
+
+// Get directory information.
+static int retell_dir(struct dirtree *root)
+{
+  char *fpath = NULL;
+  
+  if (root->again) {
+    xputc('\n');
+    return 0;
+  }
+  if (S_ISDIR(root->st.st_mode) && !root->parent) 
+    return (DIRTREE_RECURSE | DIRTREE_COMEAGAIN);
+
+  fpath = dirtree_path(root, NULL);
+  //Special case: with '-a' option and '.'/'..' also included in printing list.
+  if ((root->name[0] != '.') || (toys.optflags & FLAG_a)) {
+    print_file_attr(fpath);
+    if (S_ISDIR(root->st.st_mode) && (toys.optflags & FLAG_R)
+        && dirtree_notdotdot(root)) {
+      xprintf("\n%s:\n", fpath);
+      free(fpath);
+      return (DIRTREE_RECURSE | DIRTREE_COMEAGAIN);
+    }
+  }
+  free(fpath);
+  return 0;
+}
+
+void lsattr_main(void)
+{
+  if (!*toys.optargs) dirtree_read(".", retell_dir);
+  else
+    for (; *toys.optargs;  toys.optargs++) {
+      struct stat sb;
+
+      if (lstat(*toys.optargs, &sb)) perror_msg("stat '%s'", *toys.optargs);
+      else if (S_ISDIR(sb.st_mode) && !(toys.optflags & FLAG_d))
+        dirtree_read(*toys.optargs, retell_dir);
+      else print_file_attr(*toys.optargs);// to handle "./Filename" or "./Dir"
+    }
+}
+
+// Switch gears from lsattr to chattr.
+#define CLEANUP_lsattr
+#define FOR_chattr
+#include "generated/flags.h"
+
+static struct _chattr {
+  unsigned long add, rm, set, version;
+  unsigned char vflag, recursive;
+} chattr;
+
+// Set file flags on a Linux second extended file system.
+static inline int ext2_setflag(int fd, struct stat *sb, unsigned long flag)
+{
+  if (!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode)) {
+    errno = EOPNOTSUPP;
+    return -1;
+  }
+  return (ioctl(fd, FS_IOC_SETFLAGS, (void*)&flag));
+}
+
+static unsigned long get_flag_val(char ch)
+{
+  struct ext2_attr *ptr = e2attrs;
+
+  for (; ptr->name; ptr++)
+    if (ptr->opt == ch) return ptr->flag;
+  help_exit("bad '%c'", ch);
+}
+
+// Parse command line argument and fill the chattr structure.
+static void parse_cmdline_arg(char ***argv)
+{
+  char *arg = **argv, *ptr = NULL;
+
+  while (arg) {
+    switch (arg[0]) {
+      case '-':
+        for (ptr = ++arg; *ptr; ptr++) {
+          if (*ptr == 'R') {
+            chattr.recursive = 1;
+            continue;
+          } else if (*ptr == 'v') {// get version from next argv.
+            char *endptr;
+
+            errno = 0;
+            arg = *(*argv += 1);
+            if (!arg) help_exit("bad -v");
+            if (*arg == '-') perror_exit("Invalid Number '%s'", arg);
+            chattr.version = strtoul(arg, &endptr, 0);
+            if (errno || *endptr) perror_exit("bad version '%s'", arg);
+            chattr.vflag = 1;
+            continue;
+          } else chattr.rm |= get_flag_val(*ptr);
+        }
+        break;
+      case '+':
+        for (ptr = ++arg; *ptr; ptr++)
+          chattr.add |= get_flag_val(*ptr);
+        break;
+      case '=':
+        for (ptr = ++arg; *ptr; ptr++)
+          chattr.set |= get_flag_val(*ptr);
+        break;
+      default: return;
+    }
+    arg = *(*argv += 1);
+  }
+}
+
+// Update attribute of given file.
+static int update_attr(struct dirtree *root)
+{
+  unsigned long fval = 0;
+  char *fpath = NULL;
+  int fd;
+
+  if (!dirtree_notdotdot(root)) return 0;
+
+  /*
+   * if file is a link and recursive is set or file is not regular+link+dir
+   * (like fifo or dev file) then escape the file.
+   */
+  if ((S_ISLNK(root->st.st_mode) && chattr.recursive)
+    || (!S_ISREG(root->st.st_mode) && !S_ISLNK(root->st.st_mode)
+      && !S_ISDIR(root->st.st_mode)))
+    return 0;
+
+  fpath = dirtree_path(root, NULL);
+  if (-1 == (fd=open(fpath, O_RDONLY | O_NONBLOCK))) {
+    free(fpath);
+    return DIRTREE_ABORT;
+  }
+  // Get current attr of file.
+  if (ext2_getflag(fd, &(root->st), &fval) < 0) {
+    perror_msg("read flags of '%s'", fpath);
+    free(fpath);
+    xclose(fd);
+    return DIRTREE_ABORT;
+  }
+  if (chattr.set) { // for '=' operator.
+    if (ext2_setflag(fd, &(root->st), chattr.set) < 0)
+      perror_msg("setting flags '%s'", fpath);
+  } else { // for '-' / '+' operator.
+    fval &= ~(chattr.rm);
+    fval |= chattr.add;
+    if (!S_ISDIR(root->st.st_mode)) fval &= ~FS_DIRSYNC_FL;
+    if (ext2_setflag(fd, &(root->st), fval) < 0)
+      perror_msg("setting flags '%s'", fpath);
+  }
+  if (chattr.vflag) { // set file version
+    if (ioctl(fd, FS_IOC_SETVERSION, (void*)&chattr.version) < 0)
+      perror_msg("while setting version on '%s'", fpath);
+  }
+  free(fpath);
+  xclose(fd);
+
+  if (S_ISDIR(root->st.st_mode) && chattr.recursive) return DIRTREE_RECURSE;
+  return 0;
+}
+
+void chattr_main(void)
+{
+  char **argv = toys.optargs;
+
+  memset(&chattr, 0, sizeof(struct _chattr));
+  parse_cmdline_arg(&argv);
+  if (!*argv) help_exit("no file");
+  if (chattr.set && (chattr.add || chattr.rm))
+    error_exit("no '=' with '-' or '+'");
+  if (chattr.rm & chattr.add) error_exit("set/unset same flag");
+  if (!(chattr.add || chattr.rm || chattr.set || chattr.vflag))
+    error_exit("need '-v', '=', '-' or '+'");
+  for (; *argv; argv++) dirtree_read(*argv, update_attr);
+  toys.exitval = 0; //always set success at this point.
+}
diff --git a/toybox/toys/other/lsmod.c b/toybox/toys/other/lsmod.c
new file mode 100644
index 0000000..4d16048
--- /dev/null
+++ b/toybox/toys/other/lsmod.c
@@ -0,0 +1,36 @@
+/* lsmod.c - Show the status of modules in the kernel
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_LSMOD(NEWTOY(lsmod, NULL, TOYFLAG_SBIN))
+
+config LSMOD
+  bool "lsmod"
+  default y
+  help
+    usage: lsmod
+
+    Display the currently loaded modules, their sizes and their dependencies.
+*/
+
+#include "toys.h"
+
+void lsmod_main(void)
+{
+  char *modfile = "/proc/modules";
+  FILE * file = xfopen(modfile, "r");
+
+  xprintf("%-23s Size  Used by\n", "Module");
+
+  while (fgets(toybuf, sizeof(toybuf), file)) {
+    char *name = strtok(toybuf, " "), *size = strtok(NULL, " "),
+         *refcnt = strtok(NULL, " "), *users = strtok(NULL, " ");
+
+    if(users) {
+      int len = strlen(users)-1;
+      if (users[len] == ',' || users[len] == '-') users[len] = 0;
+      xprintf("%-19s %8s  %s %s\n", name, size, refcnt, users);
+    } else perror_exit("bad %s", modfile);
+  }
+  fclose(file);
+}
diff --git a/toybox/toys/other/lspci.c b/toybox/toys/other/lspci.c
new file mode 100644
index 0000000..a067179
--- /dev/null
+++ b/toybox/toys/other/lspci.c
@@ -0,0 +1,128 @@
+/*
+ * lspci - written by Isaac Dunham
+
+USE_LSPCI(NEWTOY(lspci, "emkn"USE_LSPCI_TEXT("@i:"), TOYFLAG_USR|TOYFLAG_BIN))
+
+config LSPCI
+  bool "lspci"
+  default y
+  help
+    usage: lspci [-ekm]
+
+    List PCI devices.
+
+    -e	Print all 6 digits in class
+    -k	Print kernel driver
+    -m	Machine parseable format
+
+config LSPCI_TEXT
+  bool "lspci readable output"
+  depends on LSPCI
+  default y
+  help
+    usage: lspci [-n] [-i FILE ]
+
+    -n	Numeric output (repeat for readable and numeric)
+    -i	PCI ID database (default /usr/share/misc/pci.ids)
+
+*/
+
+#define FOR_lspci
+#include "toys.h"
+
+GLOBALS(
+  char *ids;
+  long numeric;
+
+  FILE *db;
+)
+
+static int do_lspci(struct dirtree *new)
+{
+  char *p = toybuf, *vendor = toybuf+9, *device = toybuf+18,
+       driver[256], *vbig = 0, *dbig = 0, **fields;
+  int dirfd;
+
+  if (!new->parent) return DIRTREE_RECURSE;
+
+  // Parse data out of /proc
+
+  if (-1 == (dirfd = openat(dirtree_parentfd(new), new->name, O_RDONLY)))
+    return 0;
+
+  *driver = 0;
+  if (toys.optflags & FLAG_k)
+    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);
+    *p = 0;
+
+    if (-1 == (fd = openat(dirfd, *fields, O_RDONLY))) {
+      close(dirfd);
+      return 0;
+    }
+    xreadall(fd, p, size);
+    memmove(p, p+2, size -= 2);
+    p[size] = 0;
+    close(fd);
+    p += 9;
+  }
+
+  close(dirfd);
+
+  // Lookup/display data from pci.ids?
+
+  if (CFG_LSPCI_TEXT && TT.db) {
+    if (TT.numeric != 1) {
+      char *s;
+
+      fseek(TT.db, 0, SEEK_SET);
+      while (!vbig || !dbig) {
+        s = p;
+        if (!fgets(s, sizeof(toybuf)-(p-toybuf)-1, TT.db)) break;
+        while (isspace(*s)) s++;
+        if (*s == '#') continue;
+        if (vbig && s == p) break;
+        if (strstart(&s, vbig ? device : vendor)) {
+          if (vbig) dbig = s+2;
+          else vbig = s+2;
+          s += strlen(s);
+          s[-1] = 0; // trim ending newline
+          p = s + 1;
+        }
+      }
+    }
+
+    if (TT.numeric > 1) {
+      printf((toys.optflags & FLAG_m)
+        ? "%s, \"%s\" \"%s [%s]\" \"%s [%s]\""
+        : "%s Class %s: %s [%s] %s [%s]",
+        new->name+5, toybuf, vbig ? vbig : "", vendor,
+        dbig ? dbig : "", device);
+
+      goto driver;
+    }
+  }
+
+  printf((toys.optflags & FLAG_m) ? "%s \"%s\" \"%s\" \"%s\""
+    : "%s Class %s: %s:%s", new->name+5, toybuf, 
+    vbig ? vbig : vendor, dbig ? dbig : device);
+
+driver:
+  if (*driver)
+    printf((toys.optflags & FLAG_m) ? " \"%s\"" : " %s", basename(driver));
+  xputc('\n');
+
+  return 0;
+}
+
+void lspci_main(void)
+{
+  if (CFG_LSPCI_TEXT && TT.numeric != 1) {
+    if (!TT.ids) TT.ids = "/usr/share/misc/pci.ids";
+    if (!(TT.db = fopen(TT.ids, "r"))) perror_msg("%s", TT.ids);
+  }
+
+  dirtree_read("/sys/bus/pci/devices", do_lspci);
+}
diff --git a/toybox/toys/other/lsusb.c b/toybox/toys/other/lsusb.c
new file mode 100644
index 0000000..07886e8
--- /dev/null
+++ b/toybox/toys/other/lsusb.c
@@ -0,0 +1,49 @@
+/* lsusb.c - list available USB devices
+ *
+ * Copyright 2013 Andre Renaud <andre@bluewatersys.com>
+
+USE_LSUSB(NEWTOY(lsusb, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config LSUSB
+  bool "lsusb"
+  default y
+  help
+    usage: lsusb
+
+    List USB hosts/devices.
+*/
+
+#include "toys.h"
+
+static int list_device(struct dirtree *new)
+{
+  FILE *file;
+  char *name;
+  int busnum = 0, devnum = 0, pid = 0, vid = 0;
+
+  if (!new->parent) return DIRTREE_RECURSE;
+  if (new->name[0] == '.') return 0;
+  name = dirtree_path(new, 0);
+  snprintf(toybuf, sizeof(toybuf), "%s/%s", name, "/uevent");
+  file = fopen(toybuf, "r");
+  if (file) {
+    int count = 0;
+
+    while (fgets(toybuf, sizeof(toybuf), file))
+      if (sscanf(toybuf, "BUSNUM=%u\n", &busnum)
+          || sscanf(toybuf, "DEVNUM=%u\n", &devnum)
+          || sscanf(toybuf, "PRODUCT=%x/%x/", &pid, &vid)) count++;
+
+    if (count == 3)
+      printf("Bus %03d Device %03d: ID %04x:%04x\n", busnum, devnum, pid, vid);
+    fclose(file);
+  }
+  free(name);
+
+  return 0;
+}
+
+void lsusb_main(void)
+{
+  dirtree_read("/sys/bus/usb/devices/", list_device);
+}
diff --git a/toybox/toys/other/makedevs.c b/toybox/toys/other/makedevs.c
new file mode 100644
index 0000000..5e6a982
--- /dev/null
+++ b/toybox/toys/other/makedevs.c
@@ -0,0 +1,112 @@
+/* makedevs.c - Make ranges of device files.
+ *
+ * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+ 
+USE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))
+
+config MAKEDEVS
+  bool "makedevs"
+  default y
+  help
+    usage: makedevs [-d device_table] rootdir
+
+    Create a range of special files as specified in a device table.
+
+    -d	file containing device table (default reads from stdin)
+
+    Each line of of the device table has the fields:
+    <name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count>
+    Where name is the file name, and type is one of the following:
+
+    b	Block device
+    c	Character device
+    d	Directory
+    f	Regular file
+    p	Named pipe (fifo)
+
+    Other fields specify permissions, user and group id owning the file,
+    and additional fields for device special files. Use '-' for blank entries,
+    unspecified fields are treated as '-'.
+*/
+
+#define FOR_makedevs
+#include "toys.h"
+
+GLOBALS(
+  char *fname;
+)
+
+void makedevs_main()
+{
+  int fd = 0, line_no, i;
+  char *line = NULL;
+
+  // Open file and chdir, verbosely
+  xprintf("rootdir = %s\n", *toys.optargs);
+  if (toys.optflags & FLAG_d && strcmp(TT.fname, "-")) {
+    fd = xopenro(TT.fname);
+    xprintf("table = %s\n", TT.fname);
+  } else xprintf("table = <stdin>\n");
+  xchdir(*toys.optargs);
+
+  for (line_no = 0; (line = get_line(fd)); free(line)) {
+    char type=0, user[64], group[64], *node, *ptr = line;
+    unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0, 
+                 st_val = 0;
+    uid_t uid;
+    gid_t gid;
+    struct stat st;
+
+    line_no++;
+    while (isspace(*ptr)) ptr++;
+    if (!*ptr || *ptr == '#') continue;
+    node = ptr;
+
+    while (*ptr && !isspace(*ptr)) ptr++;
+    if (*ptr) *(ptr++) = 0;
+    *user = *group = 0;
+    sscanf(ptr, "%c %o %63s %63s %u %u %u %u %u", &type, &mode,
+           user, group, &major, &minor, &st_val, &incr, &cnt);
+
+    // type order here needs to line up with actions[] order.
+    i = stridx("pcbdf", type);
+    if (i == -1) {
+      error_msg("line %d: bad type %c", line_no, type);
+      continue;
+    } else mode |= (mode_t[]){S_IFIFO, S_IFCHR, S_IFBLK, 0, 0}[i];
+
+    uid = *user ? xgetuid(user) : getuid();
+    gid = *group ? xgetgid(group) : getgid();
+
+    while (*node == '/') node++; // using relative path
+
+    for (i = 0; (!cnt && !i) || i < cnt; i++) {
+      if (cnt>1) {
+        snprintf(toybuf, sizeof(toybuf), "%.999s%u", node, st_val + i);
+        ptr = toybuf;
+      } else ptr = node;
+
+      if (type == 'd') {
+        if (mkpathat(AT_FDCWD, ptr, mode, 3))  {
+          perror_msg("can't create directory '%s'", ptr);
+          continue;
+        }
+      } else if (type == 'f') {
+        if (stat(ptr, &st) || !S_ISREG(st.st_mode)) {
+          perror_msg("line %d: file '%s' does not exist", line_no, ptr);
+          continue;
+        }
+      } 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 (chown(ptr, uid, gid) || chmod(ptr, mode)) 
+        perror_msg("line %d: can't chown/chmod '%s'", line_no, ptr);
+    }
+  }
+  xclose(fd);
+}
diff --git a/toybox/toys/other/mix.c b/toybox/toys/other/mix.c
new file mode 100644
index 0000000..845aac1
--- /dev/null
+++ b/toybox/toys/other/mix.c
@@ -0,0 +1,68 @@
+/* mix.c - A very basic mixer.
+ *
+ * Copyright 2014 Brad Conroy, dedicated to the Public Domain.
+ *
+
+USE_MIX(NEWTOY(mix, "c:d:l#r#", TOYFLAG_USR|TOYFLAG_BIN))
+
+config MIX
+  bool "mix"
+  default y
+  help
+   usage: mix [-d DEV] [-c CHANNEL] [-l VOL] [-r RIGHT]
+
+   List OSS sound channels (module snd-mixer-oss), or set volume(s).
+
+   -c CHANNEL	Set/show volume of CHANNEL (default first channel found)
+   -d DEV		Device node (default /dev/mixer)
+   -l VOL		Volume level
+   -r RIGHT	Volume of right stereo channel (with -r, -l sets left volume)
+*/
+
+#define FOR_mix
+#include "toys.h"
+#include <linux/soundcard.h>
+
+GLOBALS(
+   long right;
+   long level;
+   char *dev;
+   char *chan;
+)
+
+void mix_main(void)
+{
+  const char *channels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
+  int mask, channel = -1, level, fd;
+
+  if (!TT.dev) TT.dev = "/dev/mixer";
+  fd = xopen(TT.dev, O_RDWR|O_NONBLOCK);
+  xioctl(fd, SOUND_MIXER_READ_DEVMASK, &mask);
+
+  for (channel = 0; channel < SOUND_MIXER_NRDEVICES; channel++) {
+    if ((1<<channel) & mask) {
+      if (TT.chan) {
+        if (!strcmp(channels[channel], TT.chan)) break;
+      } else if (toys.optflags & FLAG_l) break;
+      else printf("%s\n", channels[channel]);
+    }
+  }
+
+  if (!(toys.optflags & (FLAG_c|FLAG_l))) return;
+  else if (channel == SOUND_MIXER_NRDEVICES) error_exit("bad -c '%s'", TT.chan);
+
+  if (!(toys.optflags & FLAG_l)) {
+    xioctl(fd, MIXER_READ(channel), &level);
+    if (level > 0xFF)
+      xprintf("%s:%s = left:%d\t right:%d\n",
+              TT.dev, channels[channel], level>>8, level & 0xFF);
+    else xprintf("%s:%s = %d\n", TT.dev, channels[channel], level);
+  } else {
+    level = TT.level;
+    if (!(toys.optflags & FLAG_r)) level = TT.right | (level<<8);
+
+    xioctl(fd, MIXER_WRITE(channel), &level);
+  }
+
+  if (CFG_TOYBOX_FREE) close(fd);
+}
diff --git a/toybox/toys/other/mkpasswd.c b/toybox/toys/other/mkpasswd.c
new file mode 100644
index 0000000..2e1c1a9
--- /dev/null
+++ b/toybox/toys/other/mkpasswd.c
@@ -0,0 +1,77 @@
+/* mkpasswd.c - encrypt the given passwd using salt
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+
+USE_MKPASSWD(NEWTOY(mkpasswd, ">2S:m:P#=0<0", TOYFLAG_USR|TOYFLAG_BIN))
+
+config MKPASSWD
+  bool "mkpasswd"
+  default y
+  help
+    usage: mkpasswd [-P FD] [-m TYPE] [-S SALT] [PASSWORD] [SALT]
+
+    Crypt PASSWORD using crypt(3)
+
+    -P FD   Read password from file descriptor FD
+    -m TYPE Encryption method (des, md5, sha256, or sha512; default is des)
+    -S SALT
+*/
+
+#define FOR_mkpasswd
+#include "toys.h"
+
+GLOBALS(
+  long pfd;
+  char *method;
+  char *salt;
+)
+
+void mkpasswd_main(void)
+{
+  char salt[MAX_SALT_LEN] = {0,};
+  int i;
+
+  if (!TT.method) TT.method = "des";
+  if (toys.optc == 2) {
+    if (TT.salt) error_exit("duplicate salt");
+    TT.salt = toys.optargs[1];
+  }
+
+  if (-1 == (i = get_salt(salt, TT.method))) error_exit("bad -m");
+  if (TT.salt) {
+    char *s = TT.salt;
+
+    // In C locale, isalnum() means [A-Za-Z0-0]
+    while (isalnum(*s) || *s == '.' || *s == '/') s++;
+    if (*s) error_exit("salt not in [./A-Za-z0-9]");
+
+    snprintf(salt+i, sizeof(salt)-i, "%s", TT.salt);
+  }
+
+  // Because read_password() doesn't have an fd argument
+  if (TT.pfd) {
+    if (dup2(TT.pfd, 0) == -1) perror_exit("fd");
+    close(TT.pfd);
+  }
+
+  // If we haven't got a password on the command line, read it from tty or FD
+  if (!*toys.optargs) {
+    // Prompt and read interactively?
+    if (isatty(0)) {
+      if (read_password(toybuf, sizeof(toybuf), "Password: ")) 
+        perror_exit("password read failed");
+    } else {
+      for (i = 0; i<sizeof(toybuf)-1; i++) {
+        if (!xread(0, toybuf+i, 1)) break;
+        if (toybuf[i] == '\n' || toybuf[i] == '\r') break;
+      }
+      toybuf[i] = 0;
+    }
+  }
+
+  // encrypt & print the password
+  xprintf("%s\n",crypt(*toys.optargs ? *toys.optargs : toybuf, salt));
+}
diff --git a/toybox/toys/other/mkswap.c b/toybox/toys/other/mkswap.c
new file mode 100644
index 0000000..49e0b94
--- /dev/null
+++ b/toybox/toys/other/mkswap.c
@@ -0,0 +1,50 @@
+/* mkswap.c - Format swap device.
+ *
+ * Copyright 2009 Rob Landley <rob@landley.net>
+
+USE_MKSWAP(NEWTOY(mkswap, "<1>1L:", TOYFLAG_SBIN))
+
+config MKSWAP
+  bool "mkswap"
+  default y
+  help
+    usage: mkswap [-L LABEL] DEVICE
+
+    Sets up a Linux swap area on a device or file.
+*/
+
+#define FOR_mkswap
+#include "toys.h"
+
+GLOBALS(
+  char *L;
+)
+
+void mkswap_main(void)
+{
+  int fd = xopen(*toys.optargs, O_RDWR), pagesize = sysconf(_SC_PAGE_SIZE);
+  off_t len = fdlength(fd);
+  unsigned int pages = (len/pagesize)-1, *swap = (unsigned int *)toybuf;
+  char *label = (char *)(swap+7), *uuid = (char *)(swap+3);
+
+  // Write header. Note that older kernel versions checked signature
+  // on disk (not in cache) during swapon, so sync after writing.
+
+  swap[0] = 1;
+  swap[1] = pages;
+  xlseek(fd, 1024, SEEK_SET);
+  create_uuid(uuid);
+  if (TT.L) strncpy(label, TT.L, 15);
+  xwrite(fd, swap, 129*sizeof(unsigned int));
+  xlseek(fd, pagesize-10, SEEK_SET);
+  xwrite(fd, "SWAPSPACE2", 10);
+  fsync(fd);
+
+  if (CFG_TOYBOX_FREE) close(fd);
+
+  if (TT.L) sprintf(toybuf, ", LABEL=%s", label);
+  else *toybuf = 0;
+  printf("Swapspace size: %luk%s, UUID=%s\n",
+    pages*(unsigned long)(pagesize/1024),
+    toybuf, show_uuid(uuid));
+}
diff --git a/toybox/toys/other/modinfo.c b/toybox/toys/other/modinfo.c
new file mode 100644
index 0000000..61155b4
--- /dev/null
+++ b/toybox/toys/other/modinfo.c
@@ -0,0 +1,118 @@
+/* modinfo.c - Display module info
+ *
+ * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
+ *
+ * TODO: cleanup
+
+USE_MODINFO(NEWTOY(modinfo, "<1b:k:F:0", TOYFLAG_BIN))
+
+config MODINFO
+  bool "modinfo"
+  default y
+  help
+    usage: modinfo [-0] [-b basedir] [-k kernrelease] [-F field] [modulename...]
+
+    Display module fields for all specified modules, looking in
+    <basedir>/lib/modules/<kernrelease>/ (kernrelease defaults to uname -r).
+*/
+
+#define FOR_modinfo
+#include "toys.h"
+
+GLOBALS(
+  char *field;
+  char *knam;
+  char *base;
+
+  long mod;
+)
+
+static void output_field(char *field, char *value)
+{
+  if (!TT.field) xprintf("%s:%*c", field, 15-(int)strlen(field), ' ');
+  else if (strcmp(TT.field, field)) return;
+  xprintf("%s", value);
+  xputc((toys.optflags & FLAG_0) ? 0 : '\n');
+}
+
+static void modinfo_file(char *full_name)
+{
+  int fd, len, i;
+  char *buf = 0, *pos, *modinfo_tags[] = {
+    "alias", "license", "description", "author", "firmware",
+    "vermagic", "srcversion", "intree", "depends", "parm",
+    "parmtype",
+  };
+
+  if (-1 != (fd = open(full_name, O_RDONLY))) {
+    len = fdlength(fd);
+    if (!(buf = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0))) close(fd);
+  }
+
+  if (!buf) {
+    perror_msg_raw(full_name);
+    return;
+  } 
+
+  output_field("filename", full_name);
+
+  for (pos = buf; pos < buf+len; pos++) {
+    if (*pos) continue;
+
+    for (i = 0; i < sizeof(modinfo_tags) / sizeof(*modinfo_tags); i++) {
+      char *str = modinfo_tags[i];
+      int len = strlen(str);
+
+      if (!strncmp(pos+1, str, len) && pos[len+1] == '=') 
+        output_field(str, pos+len+2);
+    }
+  }
+
+  munmap(buf, len);
+  close(fd);
+}
+
+static int check_module(struct dirtree *new)
+{
+  if (S_ISREG(new->st.st_mode)) {
+    char *s;
+
+    for (s = toys.optargs[TT.mod]; *s; s++) {
+      int len = 0;
+
+      // The kernel treats - and _ the same, so we should too.
+      for (len = 0; s[len]; len++) {
+        if (s[len] == '-' && new->name[len] == '_') continue;
+        if (s[len] == '_' && new->name[len] == '-') continue;
+        if (s[len] != new->name[len]) break;
+      }
+      if (s[len] || strcmp(new->name+len, ".ko")) break;
+
+      modinfo_file(s = dirtree_path(new, NULL));
+      free(s);
+
+      return DIRTREE_ABORT;
+    }
+  }
+
+  return dirtree_notdotdot(new);
+}
+
+void modinfo_main(void)
+{
+  for(TT.mod = 0; TT.mod<toys.optc; TT.mod++) {
+    char *s = strstr(toys.optargs[TT.mod], ".ko");
+
+    if (s && !s[3]) modinfo_file(toys.optargs[TT.mod]);
+    else {
+      struct utsname uts;
+
+      if (uname(&uts) < 0) perror_exit("bad uname");
+      if (snprintf(toybuf, sizeof(toybuf), "%s/lib/modules/%s",
+          (toys.optflags & FLAG_b) ? TT.base : "",
+          (toys.optflags & FLAG_k) ? TT.knam : uts.release) >= sizeof(toybuf))
+            perror_exit("basedir/kernrelease too long");
+      dirtree_read(toybuf, check_module);
+    }
+  }
+}
diff --git a/toybox/toys/other/mountpoint.c b/toybox/toys/other/mountpoint.c
new file mode 100644
index 0000000..98e1d30
--- /dev/null
+++ b/toybox/toys/other/mountpoint.c
@@ -0,0 +1,64 @@
+/* mountpoint.c - Check if a directory is a mountpoint.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_MOUNTPOINT(NEWTOY(mountpoint, "<1qdx[-dx]", TOYFLAG_BIN))
+
+config MOUNTPOINT
+  bool "mountpoint"
+  default y
+  help
+    usage: mountpoint [-q] [-d] directory
+           mountpoint [-q] [-x] device
+
+    -q	Be quiet, return zero if directory is a mountpoint
+    -d	Print major/minor device number of the directory
+    -x	Print major/minor device number of the block device
+*/
+
+#define FOR_mountpoint
+#include "toys.h"
+
+static void die(char *gripe)
+{
+  if (!(toys.optflags & FLAG_q)) printf("%s: not a %s\n", *toys.optargs, gripe);
+
+  toys.exitval++;
+  xexit();
+}
+
+void mountpoint_main(void)
+{
+  struct stat st1, st2;
+  char *arg = *toys.optargs;
+  int quiet = toys.optflags & FLAG_q;
+
+  if (lstat(arg, &st1)) perror_exit_raw(arg);
+
+  if (toys.optflags & FLAG_x) {
+    if (S_ISBLK(st1.st_mode)) {
+      if (!quiet)
+        printf("%u:%u\n", dev_major(st1.st_rdev), dev_minor(st1.st_rdev));
+
+      return;
+    }
+    die("block device");
+  }
+
+  // TODO: Ignore the fact a file can be a mountpoint for --bind mounts.
+  if (!S_ISDIR(st1.st_mode)) die("directory");
+
+  arg = xmprintf("%s/..", arg);
+  xstat(arg, &st2);
+  if (CFG_TOYBOX_FREE) free(arg);
+
+  // If the device is different, it's a mount point. If the device _and_
+  // inode are the same, it's probably "/". This misses --bind mounts from
+  // elsewhere in the same filesystem, but so does the other one and in the
+  // 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", dev_major(st1.st_dev), dev_minor(st1.st_dev));
+  else if (!quiet)
+    printf("%s is %sa mountpoint\n", *toys.optargs, toys.exitval ? "not " : "");
+}
diff --git a/toybox/toys/other/nbd_client.c b/toybox/toys/other/nbd_client.c
new file mode 100644
index 0000000..3ad366f
--- /dev/null
+++ b/toybox/toys/other/nbd_client.c
@@ -0,0 +1,114 @@
+/* nbd-client.c - network block device client
+ *
+ * Copyright 2010 Rob Landley <rob@landley.net>
+ *
+ * Not in SUSv4.
+
+// This little dance is because a NEWTOY with - in the name tries to do
+// things like prototype "nbd-client_main" which isn't a valid symbol. So
+// we hide the underscore name and OLDTOY the name we want.
+USE_NBD_CLIENT(NEWTOY(nbd_client, "<3>3ns", 0))
+USE_NBD_CLIENT(OLDTOY(nbd-client, nbd_client, TOYFLAG_USR|TOYFLAG_BIN))
+
+config NBD_CLIENT
+  bool "nbd-client"
+  depends on TOYBOX_FORK
+  default y
+  help
+    usage: nbd-client [-ns] HOST PORT DEVICE
+
+    -n	Do not fork into background
+    -s	nbd swap support (lock server into memory)
+*/
+
+/*  TODO:
+    usage: nbd-client [-sSpn] [-b BLKSZ] [-t SECS] [-N name] HOST PORT DEVICE
+
+    -b	block size
+    -t	timeout in seconds
+    -S	sdp
+    -p	persist
+    -n	nofork
+    -d	DEVICE
+    -c	DEVICE
+*/
+
+#define FOR_nbd_client
+#include "toys.h"
+#include <linux/nbd.h>
+
+void nbd_client_main(void)
+{
+  int sock = -1, nbd, flags;
+  unsigned long timeout = 0;
+  char *host=toys.optargs[0], *port=toys.optargs[1], *device=toys.optargs[2];
+  uint64_t devsize;
+
+  // Repeat until spanked
+
+  nbd = xopen(device, O_RDWR);
+  for (;;) {
+    int temp;
+
+    // Find and connect to server
+
+    sock = xconnect(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0);
+    temp = 1;
+    setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &temp, sizeof(int));
+
+    // Read login data
+
+    xreadall(sock, toybuf, 152);
+    if (memcmp(toybuf, "NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53", 16))
+      error_exit("bad login %s:%s", host, port);
+    devsize = SWAP_BE64(*(uint64_t *)(toybuf+16));
+    flags = SWAP_BE32(*(int *)(toybuf+24));
+
+    // Set 4k block size.  Everything uses that these days.
+    ioctl(nbd, NBD_SET_BLKSIZE, 4096);
+    ioctl(nbd, NBD_SET_SIZE_BLOCKS, devsize/4096);
+    ioctl(nbd, NBD_CLEAR_SOCK);
+
+    // If the sucker was exported read only, respect that locally.
+    temp = (flags & 2) ? 1 : 0;
+    xioctl(nbd, BLKROSET, &temp);
+
+    if (timeout && ioctl(nbd, NBD_SET_TIMEOUT, timeout)<0) break;
+    if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) break;
+
+    if (toys.optflags & FLAG_s) mlockall(MCL_CURRENT|MCL_FUTURE);
+
+    // Open the device to force reread of the partition table.
+    if ((toys.optflags & FLAG_n) || !xfork()) {
+      char *s = strrchr(device, '/');
+      int i;
+
+      sprintf(toybuf, "/sys/block/%.32s/pid", s ? s+1 : device);
+      // Is it up yet? (Give it 10 seconds.)
+      for (i=0; i<100; i++) {
+        temp = open(toybuf, O_RDONLY);
+        if (temp == -1) msleep(100);
+        else {
+          close(temp);
+          break;
+        }
+      }
+      close(open(device, O_RDONLY));
+      if (!(toys.optflags & FLAG_n)) exit(0);
+    }
+
+    // Daemonize here.
+
+    if (daemon(0,0)) perror_exit("daemonize");
+
+    // Process NBD requests until further notice.
+
+    if (ioctl(nbd, NBD_DO_IT)>=0 || errno==EBADR) break;
+    close(sock);
+  }
+
+  // Flush queue and exit.
+  ioctl(nbd, NBD_CLEAR_QUE);
+  ioctl(nbd, NBD_CLEAR_SOCK);
+  if (CFG_TOYBOX_FREE) close(nbd);
+}
diff --git a/toybox/toys/other/nsenter.c b/toybox/toys/other/nsenter.c
new file mode 100644
index 0000000..78a9d91
--- /dev/null
+++ b/toybox/toys/other/nsenter.c
@@ -0,0 +1,174 @@
+/* nsenter.c - Enter existing namespaces
+ *
+ * Copyright 2014 Andy Lutomirski <luto@amacapital.net>
+ *
+ * See http://man7.org/linux/man-pages/man1/nsenter.1.html
+ *
+ * unshare.c - run command in new context
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://man7.org/linux/man-pages/man1/unshare.1.html
+ *
+
+// Note: flags go in same order (right to left) for shared subset
+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_UNSHARE(NEWTOY(unshare, "<1^f(fork);r(map-root-user);i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
+
+config UNSHARE
+  bool "unshare"
+  default y
+  depends on TOYBOX_CONTAINER
+  help
+    usage: unshare [-imnpuUr] COMMAND...
+
+    Create new container namespace(s) for this process and its children, so
+    some attribute is not shared with the parent process.
+
+    -f  Fork command in the background (--fork)
+    -i	SysV IPC (message queues, semaphores, shared memory) (--ipc)
+    -m	Mount/unmount tree (--mount)
+    -n	Network address, sockets, routing, iptables (--net)
+    -p	Process IDs and init (--pid)
+    -r	Become root (map current euid/egid to 0/0, implies -U) (--map-root-user)
+    -u	Host and domain names (--uts)
+    -U	UIDs, GIDs, capabilities (--user)
+
+    A namespace allows a set of processes to have a different view of the
+    system than other sets of processes.
+
+config NSENTER
+  bool "nsenter"
+  default y
+  help
+    usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND...
+
+    Run COMMAND in an existing (set of) namespace(s).
+
+    -t  PID to take namespaces from    (--target)
+    -F  don't fork, even if -p is used (--no-fork)
+
+    The namespaces to switch are:
+
+    -i	SysV IPC: message queues, semaphores, shared memory (--ipc)
+    -m	Mount/unmount tree (--mount)
+    -n	Network address, sockets, routing, iptables (--net)
+    -p	Process IDs and init, will fork unless -F is used (--pid)
+    -u	Host and domain names (--uts)
+    -U	UIDs, GIDs, capabilities (--user)
+
+    If -t isn't specified, each namespace argument must provide a path
+    to a namespace file, ala "-i=/proc/$PID/ns/ipc"
+*/
+
+#define FOR_nsenter
+#include "toys.h"
+#include <linux/sched.h>
+int unshare(int flags);
+int setns(int fd, int nstype); 
+
+GLOBALS(
+  char *nsnames[6];
+  long targetpid;
+)
+
+// Code that must run in unshare's flag context
+#define CLEANUP_nsenter
+#define FOR_unshare
+#include <generated/flags.h>
+
+static void write_ugid_map(char *map, unsigned eugid)
+{
+  int bytes = sprintf(toybuf, "0 %u 1", eugid), fd = xopen(map, O_WRONLY);
+
+  xwrite(fd, toybuf, bytes);
+  xclose(fd);
+}
+
+static void handle_r(int euid, int egid)
+{
+  int fd;
+
+  if ((fd = open("/proc/self/setgroups", O_WRONLY)) >= 0) {
+    xwrite(fd, "deny", 4);
+    close(fd);
+  }
+
+  write_ugid_map("/proc/self/uid_map", euid);
+  write_ugid_map("/proc/self/gid_map", egid);
+}
+
+static int test_r()
+{
+  return toys.optflags & FLAG_r;
+}
+
+static int test_f()
+{
+  return toys.optflags & FLAG_f;
+}
+
+// Shift back to the context GLOBALS lives in (I.E. matching the filename).
+#define CLEANUP_unshare
+#define FOR_nsenter
+#include <generated/flags.h>
+
+void unshare_main(void)
+{
+  unsigned flags[]={CLONE_NEWUSER, CLONE_NEWUTS, CLONE_NEWPID, CLONE_NEWNET,
+                    CLONE_NEWNS, CLONE_NEWIPC}, f = 0;
+  int i, fd;
+
+  // Create new namespace(s)?
+  if (CFG_UNSHARE && *toys.which->name=='u') {
+    // For -r, we have to save our original [ug]id before calling unshare()
+    int euid = geteuid(), egid = getegid();
+
+    // unshare -U does not imply -r, so we cannot use [+rU]
+    if (test_r()) toys.optflags |= FLAG_U;
+
+    for (i = 0; i<ARRAY_LEN(flags); i++)
+      if (toys.optflags & (1<<i)) f |= flags[i];
+
+    if (unshare(f)) perror_exit(0);
+    if (test_r()) handle_r(euid, egid);
+
+    if (test_f()) {
+      toys.exitval = xrun(toys.optargs);
+
+      return;
+    }
+  // Bind to existing namespace(s)?
+  } else if (CFG_NSENTER) {
+    char *nsnames = "user\0uts\0pid\0net\0mnt\0ipc";
+
+    for (i = 0; i<ARRAY_LEN(flags); i++) {
+      char *filename = TT.nsnames[i];
+
+      if (toys.optflags & (1<<i)) {
+        if (!filename || !*filename) {
+          if (!(toys.optflags & FLAG_t)) error_exit("need -t or =filename");
+          sprintf(toybuf, "/proc/%ld/ns/%s", TT.targetpid, nsnames);
+          filename = toybuf;
+        }
+
+        if (setns(fd = xopenro(filename), flags[i])) perror_exit("setns");
+        close(fd);
+      }
+      nsnames += strlen(nsnames)+1;
+    }
+
+    if ((toys.optflags & FLAG_p) && !(toys.optflags & FLAG_F)) {
+      toys.exitval = xrun(toys.optargs);
+
+      return;
+    }
+  }
+
+  xexec(toys.optargs);
+}
+
+void nsenter_main(void)
+{
+  unshare_main();
+}
diff --git a/toybox/toys/other/oneit.c b/toybox/toys/other/oneit.c
new file mode 100644
index 0000000..9be67c0
--- /dev/null
+++ b/toybox/toys/other/oneit.c
@@ -0,0 +1,114 @@
+/* oneit.c - tiny init replacement to launch a single child process.
+ *
+ * Copyright 2005, 2007 by Rob Landley <rob@landley.net>.
+
+USE_ONEIT(NEWTOY(oneit, "^<1nc:p3[!pn]", TOYFLAG_SBIN))
+
+config ONEIT
+  bool "oneit"
+  default y
+  help
+    usage: oneit [-p] [-c /dev/tty0] command [...]
+
+    Simple init program that runs a single supplied command line with a
+    controlling tty (so CTRL-C can kill it).
+
+    -c	Which console device to use (/dev/console doesn't do CTRL-C, etc).
+    -p	Power off instead of rebooting when command exits.
+    -r	Restart child when it exits.
+    -3	Write 32 bit PID of each exiting reparented process to fd 3 of child.
+    	(Blocking writes, child must read to avoid eventual deadlock.)
+
+    Spawns a single child process (because PID 1 has signals blocked)
+    in its own session, reaps zombies until the child exits, then
+    reboots the system (or powers off with -p, or restarts the child with -r).
+
+    Responds to SIGUSR1 by halting the system, SIGUSR2 by powering off,
+    and SIGTERM or SIGINT reboot.
+*/
+
+#define FOR_oneit
+#include "toys.h"
+#include <sys/reboot.h>
+
+GLOBALS(
+  char *console;
+)
+
+// The minimum amount of work necessary to get ctrl-c and such to work is:
+//
+// - Fork a child (PID 1 is special: can't exit, has various signals blocked).
+// - Do a setsid() (so we have our own session).
+// - In the child, attach stdio to /dev/tty0 (/dev/console is special)
+// - Exec the rest of the command line.
+//
+// PID 1 then reaps zombies until the child process it spawned exits, at which
+// point it calls sync() and reboot().  I could stick a kill -1 in there.
+
+// Perform actions in response to signals. (Only root can send us signals.)
+static void oneit_signaled(int signal)
+{
+  int action = RB_AUTOBOOT;
+
+  toys.signal = signal;
+  if (signal == SIGUSR1) action = RB_HALT_SYSTEM;
+  if (signal == SIGUSR2) action = RB_POWER_OFF;
+
+  // PID 1 can't call reboot() because it kills the task that calls it,
+  // which causes the kernel to panic before the actual reboot happens.
+  sync();
+  if (!vfork()) reboot(action);
+}
+
+void oneit_main(void)
+{
+  int i, pid, pipes[] = {SIGUSR1, SIGUSR2, SIGTERM, SIGINT};
+
+  // Setup signal handlers for signals of interest
+  for (i = 0; i<ARRAY_LEN(pipes); i++) xsignal(pipes[i], oneit_signaled);
+
+  if (toys.optflags & FLAG_3) {
+    // Ensure next available filehandles are #3 and #4
+    while (xopen_stdio("/", 0) < 3);
+    close(3);
+    close(4);
+    xpipe(pipes);
+    fcntl(4, F_SETFD, FD_CLOEXEC);
+  }
+
+  while (!toys.signal) {
+
+    // Create a new child process.
+    pid = vfork();
+    if (pid) {
+
+      // pid 1 reaps zombies until it gets its child, then halts system.
+      // We ignore the return value of write (what would we do with it?)
+      // but save it in a variable we never read to make fortify shut up.
+      // (Real problem is if pid2 never reads, write() fills pipe and blocks.)
+      while (pid != wait(&i)) if (toys.optflags & FLAG_3) i = write(4, &pid, 4);
+      if (toys.optflags & FLAG_n) continue;
+
+      oneit_signaled((toys.optflags & FLAG_p) ? SIGUSR2 : SIGTERM);
+    } else {
+      // Redirect stdio to /dev/tty0, with new session ID, so ctrl-c works.
+      setsid();
+      for (i=0; i<3; i++) {
+        close(i);
+        // Remember, O_CLOEXEC is backwards for xopen()
+        xopen(TT.console ? TT.console : "/dev/tty0", O_RDWR|O_CLOEXEC);
+      }
+
+      // Can't xexec() here, we vforked so we don't want to error_exit().
+      toy_exec(toys.optargs);
+      execvp(*toys.optargs, toys.optargs);
+      perror_msg("%s not in PATH=%s", *toys.optargs, getenv("PATH"));
+
+      break;
+    }
+  }
+
+  // Give reboot() time to kick in, or avoid rapid spinning if exec failed
+  sleep(5);
+  _exit(127);
+}
diff --git a/toybox/toys/other/partprobe.c b/toybox/toys/other/partprobe.c
new file mode 100644
index 0000000..5c44cb3
--- /dev/null
+++ b/toybox/toys/other/partprobe.c
@@ -0,0 +1,30 @@
+/* partprobe.c - Tell the kernel about partition table changes
+ *
+ * Copyright 2014 Bertold Van den Bergh <vandenbergh@bertold.org>
+ *
+ * see http://man7.org/linux/man-pages/man8/partprobe.8.html
+
+USE_PARTPROBE(NEWTOY(partprobe, "<1", TOYFLAG_SBIN))
+
+config PARTPROBE
+  bool "partprobe"
+  default y
+  help
+    usage: partprobe DEVICE...
+
+    Tell the kernel about partition table changes
+
+    Ask the kernel to re-read the partition table on the specified devices.
+*/
+
+#include "toys.h"
+
+static void do_partprobe(int fd, char *name)
+{
+  if (ioctl(fd, BLKRRPART, 0)) perror_msg("ioctl failed");
+}
+
+void partprobe_main(void)
+{
+  loopfiles(toys.optargs, do_partprobe); 
+}
diff --git a/toybox/toys/other/pivot_root.c b/toybox/toys/other/pivot_root.c
new file mode 100644
index 0000000..7748032
--- /dev/null
+++ b/toybox/toys/other/pivot_root.c
@@ -0,0 +1,32 @@
+/* pivot_root.c - edit system mount tree
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+
+USE_PIVOT_ROOT(NEWTOY(pivot_root, "<2>2", TOYFLAG_SBIN))
+
+config PIVOT_ROOT
+  bool "pivot_root"
+  default y
+  help
+    usage: pivot_root OLD NEW
+
+    Swap OLD and NEW filesystems (as if by simultaneous mount --move), and
+    move all processes with chdir or chroot under OLD into NEW (including
+    kernel threads) so OLD may be unmounted.
+
+    The directory NEW must exist under OLD. This doesn't work on initramfs,
+    which can't be moved (about the same way PID 1 can't be killed; see
+    switch_root instead).
+*/
+
+#define FOR_pivot_root
+#include "toys.h"
+
+#include <sys/syscall.h>
+#include <unistd.h>
+
+void pivot_root_main(void)
+{
+  if (syscall(__NR_pivot_root, toys.optargs[0], toys.optargs[1]))
+    perror_exit("'%s' -> '%s'", toys.optargs[0], toys.optargs[1]);
+}
diff --git a/toybox/toys/other/pmap.c b/toybox/toys/other/pmap.c
new file mode 100644
index 0000000..a93ea3e
--- /dev/null
+++ b/toybox/toys/other/pmap.c
@@ -0,0 +1,113 @@
+/* pmap.c - Reports the memory map of a process or processes.
+ *
+ * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_PMAP(NEWTOY(pmap, "<1xq", TOYFLAG_BIN))
+
+config PMAP
+  bool "pmap"
+  default y
+  help
+    usage: pmap [-xq] [pids...]
+
+    Reports the memory map of a process or processes.
+
+    -x Show the extended format.
+    -q Do not display some header/footer lines.
+*/
+
+#define FOR_pmap
+#include "toys.h"
+
+void pmap_main(void)
+{
+  char **optargs;
+
+  for (optargs = toys.optargs; *optargs; optargs++) {
+    pid_t pid = atolx(*optargs);
+    FILE *fp;
+    char *line, *oldline = 0, *name = 0,
+         *k = (toys.optflags & FLAG_x) ? "" : "K";
+    size_t len;
+    long long start, end, pss, tpss = 0, dirty, tdirty = 0, swap, tswap = 0,
+              total = 0;
+    int xx = 0;
+
+    snprintf(toybuf, sizeof(toybuf), "/proc/%u/cmdline", pid);
+    line = readfile(toybuf, 0, 0);
+    if (!line) error_msg("No %lu", (long)pid);
+    xprintf("%u: %s\n", (int)pid, line);
+    free(line);
+
+    // Header
+    // Only use the more verbose file in -x mode
+    sprintf(toybuf, "/proc/%u/%smaps", pid,
+      (toys.optflags & FLAG_x) ? "s" : "");
+    if (!(fp = fopen(toybuf, "r"))) {
+      error_msg("No %ld\n", (long)pid);
+      return;
+    }
+
+    if ((toys.optflags & (FLAG_q|FLAG_x)) == FLAG_x)
+      xprintf("Address%*cKbytes     PSS   Dirty    Swap  Mode  Mapping\n",
+        (int)(sizeof(long)*2)-4, ' ');
+
+    // Loop through mappings
+    for (;;) {
+      int off, count;
+
+      line = 0;
+      if (0 >= getline(&line, &len, fp)) break;
+      count = sscanf(line, "%llx-%llx %s %*s %*s %*s %n",
+        &start, &end, toybuf, &off);
+
+      if (count == 3) {
+        name = line[off] ? line+off : "  [anon]\n";
+        if (toybuf[3] == 'p') toybuf[3] = '-';
+        total += end = (end-start)/1024;
+        printf("%0*llx % *lld%s ", (int)(2*sizeof(long)), start,
+          6+!!(toys.optflags & FLAG_x), end, k);
+        if (toys.optflags & FLAG_x) {
+          oldline = line;
+          continue;
+        }
+      } else {
+        if (0<sscanf(line, "Pss: %lld", &pss)
+            || 0<sscanf(line, "Private_Dirty: %lld", &dirty)
+            || 0<sscanf(line, "Swap: %lld", &swap)) xx++;
+        free(line);
+        if (xx<3) continue;
+        line = oldline;
+        name = basename(name);
+        xx = 0;
+        printf("% 7lld %7lld %7lld ", pss, dirty, swap);
+        tpss += pss;
+        tdirty += dirty;
+        tswap += swap;
+      }
+
+      xprintf("%s-  %s%s", toybuf, line[off]=='[' ? "  " : "", name);
+
+      free(line);
+      line = 0;
+    }
+
+    // Trailer
+    if (!(toys.optflags & FLAG_q)) {
+      int x = !!(toys.optflags & FLAG_x);
+      if (x) {
+        memset(toybuf, '-', 16);
+        xprintf("%.*s  ------  ------  ------  ------\n", (int)(sizeof(long)*2),
+          toybuf);
+      }
+      printf("total% *lld%s", 2*(int)(sizeof(long)+1)+x, total, k);
+      if (x) printf("% 8lld% 8lld% 8lld", tpss, tdirty, tswap);
+      xputc('\n');
+    }
+ 
+    fclose(fp);
+  }
+}
diff --git a/toybox/toys/other/printenv.c b/toybox/toys/other/printenv.c
new file mode 100644
index 0000000..e8bcf29
--- /dev/null
+++ b/toybox/toys/other/printenv.c
@@ -0,0 +1,43 @@
+/* printenv.c - Print environment variables.
+ *
+ * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
+
+USE_PRINTENV(NEWTOY(printenv, "0(null)", TOYFLAG_USR|TOYFLAG_BIN))
+
+config PRINTENV
+  bool "printenv"
+  default y
+  help
+    usage: printenv [-0] [env_var...]
+
+    Print environment variables.
+
+    -0	Use \0 as delimiter instead of \n
+*/
+
+#include "toys.h"
+
+extern char **environ;
+
+void printenv_main(void)
+{
+  char **env, **var = toys.optargs;
+  char delim = '\n';
+
+  if (toys.optflags) delim = 0;
+
+  do {
+    int catch = 0, len = *var ? strlen(*var) : 0;
+
+    for (env = environ; *env; env++) {
+      char *out = *env;
+      if (*var) {
+        if (!strncmp(out, *var, len) && out[len] == '=') out += len +1;
+        else continue;
+      }
+      xprintf("%s%c", out, delim);
+      catch++;
+    }
+    if (*var && !catch) toys.exitval = 1;
+  } while (*var && *(++var));
+}
diff --git a/toybox/toys/other/pwdx.c b/toybox/toys/other/pwdx.c
new file mode 100644
index 0000000..2a72dba
--- /dev/null
+++ b/toybox/toys/other/pwdx.c
@@ -0,0 +1,33 @@
+/* pwdx.c - report current directory of a process. 
+ *
+ * Copyright 2013 Lukasz Skalski <l.skalski@partner.samsung.com>
+
+USE_PWDX(NEWTOY(pwdx, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
+
+config PWDX
+  bool "pwdx"
+  default y
+  help
+    usage: pwdx PID...
+
+    Print working directory of processes listed on command line.
+*/
+
+#include "toys.h"
+
+void pwdx_main(void)
+{
+  char **optargs;
+
+  for (optargs = toys.optargs; *optargs; optargs++) {
+    char *path = toybuf;
+
+    sprintf(toybuf, "/proc/%d/cwd", atoi(*optargs));
+    if (!readlink0(path, toybuf, sizeof(toybuf))) {
+      path = strerror(errno);
+      toys.exitval = 1;
+    }
+
+    xprintf("%s: %s\n", *optargs, path);
+  }
+}
diff --git a/toybox/toys/other/readahead.c b/toybox/toys/other/readahead.c
new file mode 100644
index 0000000..4edd651
--- /dev/null
+++ b/toybox/toys/other/readahead.c
@@ -0,0 +1,37 @@
+/* readahead.c - preload files into disk cache.
+ *
+ * Copyright 2013 Rob Landley <rob@landley.net>
+ *
+ * No standard.
+
+USE_READAHEAD(NEWTOY(readahead, NULL, TOYFLAG_BIN))
+
+config READAHEAD
+  bool "readahead"
+  default y
+  help
+    usage: readahead FILE...
+
+    Preload files into disk cache.
+*/
+
+#include "toys.h"
+
+#include <sys/syscall.h>
+
+static void do_readahead(int fd, char *name)
+{
+  int rc;
+
+  // Since including fcntl.h doesn't give us the wrapper, use the syscall.
+  // 32 bits takes LO/HI offset (we don't care about endianness of 0).
+  if (sizeof(long) == 4) rc = syscall(__NR_readahead, fd, 0, 0, INT_MAX);
+  else rc = syscall(__NR_readahead, fd, 0, INT_MAX);
+
+  if (rc) perror_msg("readahead: %s", name);
+}
+
+void readahead_main(void)
+{
+  loopfiles(toys.optargs, do_readahead);
+}
diff --git a/toybox/toys/other/readlink.c b/toybox/toys/other/readlink.c
new file mode 100644
index 0000000..fecd1ef
--- /dev/null
+++ b/toybox/toys/other/readlink.c
@@ -0,0 +1,41 @@
+/* readlink.c - Return string representation of a symbolic link.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+
+USE_READLINK(NEWTOY(readlink, "<1>1fenq[-fe]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config READLINK
+  bool "readlink"
+  default y
+  help
+    usage: readlink FILE
+
+    With no options, show what symlink points to, return error if not symlink.
+
+    Options for producing cannonical paths (all symlinks/./.. resolved):
+
+    -e	cannonical path to existing entry (fail if missing)
+    -f	full path (fail if directory missing)
+    -n	no trailing newline
+    -q	quiet (no output, just error code)
+*/
+
+#define FOR_readlink
+#include "toys.h"
+
+void readlink_main(void)
+{
+  char *s;
+
+  // Calculating full cannonical path?
+
+  if (toys.optflags & (FLAG_f|FLAG_e))
+    s = xabspath(*toys.optargs, toys.optflags & FLAG_e);
+  else s = xreadlink(*toys.optargs);
+
+  if (s) {
+    if (!(toys.optflags & FLAG_q))
+      xprintf((toys.optflags & FLAG_n) ? "%s" : "%s\n", s);
+    if (CFG_TOYBOX_FREE) free(s);
+  } else toys.exitval = 1;
+}
diff --git a/toybox/toys/other/realpath.c b/toybox/toys/other/realpath.c
new file mode 100644
index 0000000..8f75d3f
--- /dev/null
+++ b/toybox/toys/other/realpath.c
@@ -0,0 +1,26 @@
+/* realpath.c - Return the canonical version of a pathname
+ *
+ * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
+
+USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+
+config REALPATH
+  bool "realpath"
+  default y
+  help
+    usage: realpath FILE...
+
+    Display the canonical absolute pathname
+*/
+
+#include "toys.h"
+
+void realpath_main(void)
+{
+  char **s = toys.optargs;
+
+  for (s = toys.optargs; *s; s++) {
+    if (!realpath(*s, toybuf)) perror_msg_raw(*s);
+    else xputs(toybuf);
+  }
+}
diff --git a/toybox/toys/other/reboot.c b/toybox/toys/other/reboot.c
new file mode 100644
index 0000000..15eea28
--- /dev/null
+++ b/toybox/toys/other/reboot.c
@@ -0,0 +1,35 @@
+/* reboot.c - Restart, halt or powerdown the system.
+ *
+ * Copyright 2013 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_REBOOT(NEWTOY(reboot, "fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_REBOOT(OLDTOY(halt, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+USE_REBOOT(OLDTOY(poweroff, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+
+config REBOOT
+  bool "reboot"
+  default y
+  help
+    usage: reboot/halt/poweroff [-fn]
+
+    Restart, halt or powerdown the system.
+
+    -f	Don't signal init
+    -n	Don't sync before stopping the system.
+*/
+
+#define FOR_reboot
+#include "toys.h"
+#include <sys/reboot.h>
+
+void reboot_main(void)
+{
+  int types[] = {RB_AUTOBOOT, RB_HALT_SYSTEM, RB_POWER_OFF},
+      sigs[] = {SIGTERM, SIGUSR1, SIGUSR2}, idx;
+
+  if (!(toys.optflags & FLAG_n)) sync();
+
+  idx = stridx("hp", *toys.which->name)+1;
+  if (toys.optflags & FLAG_f) toys.exitval = reboot(types[idx]);
+  else toys.exitval = kill(1, sigs[idx]);
+}
diff --git a/toybox/toys/other/reset.c b/toybox/toys/other/reset.c
new file mode 100644
index 0000000..0c2089c
--- /dev/null
+++ b/toybox/toys/other/reset.c
@@ -0,0 +1,23 @@
+/* reset.c - reset the terminal.
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ *
+ * No standard.
+
+USE_RESET(NEWTOY(reset, 0, TOYFLAG_USR|TOYFLAG_BIN))
+
+config RESET
+  bool "reset"
+  default y
+  help
+    usage: reset
+
+    reset the terminal
+*/
+#include "toys.h"
+
+void reset_main(void)
+{
+  // man 4 console codes: reset terminal is ESC (no left bracket) c
+  xwrite(xgettty(), "\033c", 2);
+}
diff --git a/toybox/toys/other/rev.c b/toybox/toys/other/rev.c
new file mode 100644
index 0000000..1506631
--- /dev/null
+++ b/toybox/toys/other/rev.c
@@ -0,0 +1,41 @@
+/* rev.c - reverse lines of a set of given input files
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_REV(NEWTOY(rev, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config REV
+  bool "rev"
+  default y
+  help
+    usage: rev [FILE...]
+
+    Output each line reversed, when no files are given stdin is used.
+*/
+
+#include "toys.h"
+
+static void do_rev(int fd, char *name)
+{
+  char *c;
+
+  for (;;) {
+    unsigned len, i;
+
+    if (!(c = get_line(fd))) break;
+    len = strlen(c);
+    if (len--) for (i = 0; i <= len/2; i++) {
+      char tmp = c[i];
+
+      c[i] = c[len-i];
+      c[len-i] = tmp;
+    }
+    xputs(c);
+    free(c);
+  }
+}
+
+void rev_main(void)
+{
+  loopfiles(toys.optargs, do_rev);
+}
diff --git a/toybox/toys/other/rmmod.c b/toybox/toys/other/rmmod.c
new file mode 100644
index 0000000..10c134c
--- /dev/null
+++ b/toybox/toys/other/rmmod.c
@@ -0,0 +1,43 @@
+/* rmmod.c - Remove a module from the Linux kernel.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_RMMOD(NEWTOY(rmmod, "<1wf", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+
+config RMMOD
+  bool "rmmod"
+  default y
+  help
+    usage: rmmod [-wf] [MODULE]
+
+    Unload the module named MODULE from the Linux kernel.
+    -f	Force unload of a module
+    -w	Wait until the module is no longer used.
+
+*/
+
+#define FOR_rmmod
+#include "toys.h"
+
+#include <sys/syscall.h>
+#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
+
+void rmmod_main(void)
+{
+  unsigned int flags = O_NONBLOCK|O_EXCL;
+  char * mod_name;
+  int len;
+
+  // Basename
+  mod_name = basename(*toys.optargs);
+
+  // Remove .ko if present
+  len = strlen(mod_name);
+  if (len > 3 && !strcmp(&mod_name[len-3], ".ko" )) mod_name[len-3] = 0;
+
+  if (toys.optflags & FLAG_f) flags |= O_TRUNC;
+  if (toys.optflags & FLAG_w) flags &= ~O_NONBLOCK;
+
+  if (delete_module(mod_name, flags))
+    perror_exit("failed to unload %s", mod_name);
+}
diff --git a/toybox/toys/other/setfattr.c b/toybox/toys/other/setfattr.c
new file mode 100644
index 0000000..080991f
--- /dev/null
+++ b/toybox/toys/other/setfattr.c
@@ -0,0 +1,47 @@
+/* setfattr.c - Write POSIX extended attributes.
+ *
+ * Copyright 2016 Android Open Source Project.
+ *
+ * No standard
+
+USE_SETFATTR(NEWTOY(setfattr, "hn:|v:x:|[!xv]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SETFATTR
+  bool "setfattr"
+  default y
+  help
+    usage: setfattr [-h] [-x|-n NAME] [-v VALUE] FILE...
+
+    Write POSIX extended attributes.
+
+    -h	Do not dereference symlink.
+    -n	Set given attribute.
+    -x	Remove given attribute.
+    -v	Set value for attribute -n (default is empty).
+*/
+
+#define FOR_setfattr
+#include "toys.h"
+
+GLOBALS(
+  char *x, *v, *n;
+)
+
+static void do_setfattr(char *file)
+{
+  int h = toys.optflags & FLAG_h;
+
+  if (toys.optflags&FLAG_x) {
+    if ((h ? lremovexattr : removexattr)(file, TT.x))
+      perror_msg("removexattr failed");
+  } else 
+    if ((h ? lsetxattr : setxattr)(file, TT.n, TT.v, TT.v?strlen(TT.v):0, 0))
+      perror_msg("setxattr failed");
+}
+
+void setfattr_main(void)
+{
+  char **s;
+
+  for (s=toys.optargs; *s; s++) do_setfattr(*s);
+}
diff --git a/toybox/toys/other/setsid.c b/toybox/toys/other/setsid.c
new file mode 100644
index 0000000..9569826
--- /dev/null
+++ b/toybox/toys/other/setsid.c
@@ -0,0 +1,28 @@
+/* setsid.c - Run program in a new session ID.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+
+USE_SETSID(NEWTOY(setsid, "^<1t", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SETSID
+  bool "setsid"
+  default y
+  help
+    usage: setsid [-t] command [args...]
+
+    Run process in a new session.
+
+    -t	Grab tty (become foreground process, receiving keyboard signals)
+*/
+
+#include "toys.h"
+
+void setsid_main(void)
+{
+  while (setsid()<0) if (XVFORK()) _exit(0);
+  if (toys.optflags) {
+    setpgid(0, 0);
+    tcsetpgrp(0, getpid());
+  }
+  xexec(toys.optargs);
+}
diff --git a/toybox/toys/other/shred.c b/toybox/toys/other/shred.c
new file mode 100644
index 0000000..30b5e7d
--- /dev/null
+++ b/toybox/toys/other/shred.c
@@ -0,0 +1,106 @@
+/* shred.c - Overwrite a file to securely delete
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * No standard
+
+USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SHRED
+  bool "shred"
+  default y
+  help
+    usage: shred [-fuz] [-n COUNT] [-s SIZE] FILE...
+
+    Securely delete a file by overwriting its contents with random data.
+
+    -f        Force (chmod if necessary)
+    -n COUNT  Random overwrite iterations (default 1)
+    -o OFFSET Start at OFFSET
+    -s SIZE   Use SIZE instead of detecting file size
+    -u        unlink (actually delete file when done)
+    -x        Use exact size (default without -s rounds up to next 4k)
+    -z        zero at end
+
+    Note: data journaling filesystems render this command useless, you must
+    overwrite all free space (fill up disk) to erase old data on those.
+*/
+
+#define FOR_shred
+#include "toys.h"
+
+GLOBALS(
+  long offset;
+  long iterations;
+  long size;
+
+  int ufd;
+)
+
+void shred_main(void)
+{
+  char **try;
+
+  if (!(toys.optflags & FLAG_n)) TT.iterations++;
+  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.
+
+  for (try = toys.optargs; *try; try++) {
+    off_t pos = 0, len = TT.size;
+    int fd = open(*try, O_RDWR), iter = 0, throw;
+
+    // do -f chmod if necessary
+    if (fd == -1 && (toys.optflags & FLAG_f)) {
+      chmod(*try, 0600);
+      fd = open(*try, O_RDWR);
+    }
+    if (fd == -1) {
+      perror_msg_raw(*try);
+      continue;
+    }
+
+    // determine length
+    if (!len) len = fdlength(fd);
+    if (len<1) {
+      error_msg("%s: needs -s", *try);
+      close(fd);
+      continue;
+    }
+
+    // Loop through, writing to this file
+    for (;;) {
+      // Advance to next -n or -z?
+
+      if (pos >= len) {
+        pos = -1;
+        if (++iter == TT.iterations && (toys.optargs && FLAG_z)) {
+          memset(toybuf, 0, sizeof(toybuf));
+          continue;
+        }
+        if (iter >= TT.iterations) break;
+      }
+
+      if (pos < TT.offset) {
+        if (TT.offset != lseek(fd, TT.offset, SEEK_SET)) {
+          perror_msg_raw(*try);
+          break;
+        }
+        pos = TT.offset;
+      }
+
+      // Determine length, read random data if not zeroing, write.
+
+      throw = sizeof(toybuf);
+      if (toys.optflags & FLAG_x)
+        if (len-pos < throw) throw = len-pos;
+
+      if (iter != TT.iterations) xread(TT.ufd, toybuf, throw);
+      if (throw != writeall(fd, toybuf, throw)) perror_msg_raw(*try);
+      pos += throw;
+    }
+    if (toys.optflags & FLAG_u)
+      if (unlink(*try)) perror_msg("unlink '%s'", *try);
+  }
+}
diff --git a/toybox/toys/other/stat.c b/toybox/toys/other/stat.c
new file mode 100644
index 0000000..b998a0e
--- /dev/null
+++ b/toybox/toys/other/stat.c
@@ -0,0 +1,218 @@
+/* stat.c : display file or file system status
+ * Copyright 2012 <warior.linux@gmail.com>
+ * Copyright 2013 <anand.sinha85@gmail.com>
+
+USE_STAT(NEWTOY(stat, "<1c:fLt", TOYFLAG_BIN)) 
+
+config STAT
+  bool stat
+  default y
+  help
+    usage: stat [-tfL] [-c FORMAT] FILE...
+
+    Display status of files or filesystems.
+
+    -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  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
+    %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
+
+    The valid format escape sequences for filesystems:
+    %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  FS type (hex)      |%T  FS type (driver name)
+*/
+
+#define FOR_stat
+#include "toys.h"
+
+GLOBALS(
+  char *fmt;
+
+  union {
+    struct stat st;
+    struct statfs sf;
+  } stat;
+  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
+// struct definition for legacy/namespace reasons.
+
+static void date_stat_format(struct timespec *ts)
+{
+  char *s = toybuf+128;
+  strftime(s, sizeof(toybuf), "%Y-%m-%d %H:%M:%S",
+    localtime(&(ts->tv_sec)));
+  sprintf(s+strlen(s), ".%09ld", ts->tv_nsec);
+  strout(s);
+}
+
+static void print_stat(char type)
+{
+  struct stat *stat = (struct stat *)&TT.stat;
+
+  if (type == 'a') out('o', stat->st_mode&~S_IFMT);
+  else if (type == 'A') {
+    char str[11];
+
+    mode_to_string(stat->st_mode, str);
+    strout(str);
+  } else if (type == 'b') out('u', stat->st_blocks);
+  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);
+  else if (type == 'F') {
+    char *t = "character device\0directory\0block device\0" \
+              "regular file\0symbolic link\0socket\0FIFO (named pipe)";
+    int i, filetype = stat->st_mode & S_IFMT;
+
+    for (i = 1; filetype != (i*8192) && i < 7; i++) t += strlen(t)+1;
+    if (!stat->st_size && filetype == S_IFREG) t = "regular empty file";
+    strout(t);
+  } else if (type == 'g') out('u', stat->st_gid);
+  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 == '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 (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') 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);
+  else if (type == 'Y') out('u', stat->st_mtime);
+  else if (type == 'z') date_stat_format((void *)&stat->st_ctime);
+  else if (type == 'Z') out('u', stat->st_ctime);
+  else xprintf("?");
+}
+
+static void print_statfs(char type) {
+  struct statfs *statfs = (struct statfs *)&TT.stat;
+
+  if (type == 'a') out('u', statfs->f_bavail);
+  else if (type == 'b') out('u', statfs->f_blocks);
+  else if (type == 'c') out('u', statfs->f_files);
+  else if (type == 'd') out('u', statfs->f_ffree);
+  else if (type == 'f') out('u', statfs->f_bfree);
+  else if (type == 'l') out('d', statfs->f_namelen);
+  else if (type == 't') out('x', statfs->f_type);
+  else if (type == 'T') {
+    char *s = "unknown";
+    struct {unsigned num; char *name;} nn[] = {
+      {0xADFF, "affs"}, {0x5346544e, "ntfs"}, {0x1Cd1, "devpts"},
+      {0x137D, "ext"}, {0xEF51, "ext2"}, {0xEF53, "ext3"},
+      {0x1BADFACE, "bfs"}, {0x9123683E, "btrfs"}, {0x28cd3d45, "cramfs"},
+      {0x3153464a, "jfs"}, {0x7275, "romfs"}, {0x01021994, "tmpfs"},
+      {0x3434, "nilfs"}, {0x6969, "nfs"}, {0x9fa0, "proc"},
+      {0x534F434B, "sockfs"}, {0x62656572, "sysfs"}, {0x517B, "smb"},
+      {0x4d44, "msdos"}, {0x4006, "fat"}, {0x43415d53, "smackfs"},
+      {0x73717368, "squashfs"}
+    };
+    int i;
+
+    for (i=0; i<ARRAY_LEN(nn); i++)
+      if (nn[i].num == statfs->f_type) s = nn[i].name;
+    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 strout("?");
+}
+
+void stat_main(void)
+{
+  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: (%5u/%8U)\tGid: (%5g/%8G)\n"
+      "Access: %x\nModify: %y\nChange: %z";
+
+  if (toys.optflags & FLAG_c) format = TT.fmt;
+
+  for (i = 0; toys.optargs[i]; i++) {
+    int L = toys.optflags & FLAG_L;
+
+    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 {
+        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);
+      }
+    }
+    xputc('\n');
+  }
+}
diff --git a/toybox/toys/other/swapoff.c b/toybox/toys/other/swapoff.c
new file mode 100644
index 0000000..fb17130
--- /dev/null
+++ b/toybox/toys/other/swapoff.c
@@ -0,0 +1,21 @@
+/* swapoff.c - Disable region for swapping
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_SWAPOFF(NEWTOY(swapoff, "<1>1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+
+config SWAPOFF
+  bool "swapoff"
+  default y
+  help
+    usage: swapoff swapregion
+
+    Disable swapping on a given swapregion.
+*/
+
+#include "toys.h"
+
+void swapoff_main(void)
+{
+  if (swapoff(toys.optargs[0])) perror_exit("failed to remove swaparea");
+}
diff --git a/toybox/toys/other/swapon.c b/toybox/toys/other/swapon.c
new file mode 100644
index 0000000..0d65040
--- /dev/null
+++ b/toybox/toys/other/swapon.c
@@ -0,0 +1,35 @@
+/* swapon.c - Enable region for swapping
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_SWAPON(NEWTOY(swapon, "<1>1p#<0>32767d", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+
+config SWAPON
+  bool "swapon"
+  default y
+  help
+    usage: swapon [-d] [-p priority] filename
+
+    Enable swapping on a given device/file.
+
+    -d	Discard freed SSD pages
+*/
+
+#define FOR_swapon
+#include "toys.h"
+
+GLOBALS(
+  long priority;
+)
+
+void swapon_main(void)
+{
+  // 0x70000 = SWAP_FLAG_DISCARD|SWAP_FLAG_DISCARD_ONCE|SWAP_FLAG_DISCARD_PAGES
+  int flags = (toys.optflags&FLAG_d)*0x70000;
+
+  if (toys.optflags)
+    flags |= SWAP_FLAG_PREFER | (TT.priority << SWAP_FLAG_PRIO_SHIFT);
+
+  if (swapon(*toys.optargs, flags))
+    perror_exit("Couldn't swapon '%s'", *toys.optargs);
+}
diff --git a/toybox/toys/other/switch_root.c b/toybox/toys/other/switch_root.c
new file mode 100644
index 0000000..acbae2b
--- /dev/null
+++ b/toybox/toys/other/switch_root.c
@@ -0,0 +1,116 @@
+/* switch_root.c - Switch from rootfs/initramfs to another filesystem
+ *
+ * Copyright 2005 Rob Landley <rob@landley.net>
+
+USE_SWITCH_ROOT(NEWTOY(switch_root, "<2c:h", TOYFLAG_SBIN))
+
+config SWITCH_ROOT
+  bool "switch_root"
+  default y
+  help
+    usage: switch_root [-c /dev/console] NEW_ROOT NEW_INIT...
+
+    Use from PID 1 under initramfs to free initramfs, chroot to NEW_ROOT,
+    and exec NEW_INIT.
+
+    -c	Redirect console to device in NEW_ROOT
+    -h	Hang instead of exiting on failure (avoids kernel panic)
+*/
+
+#define FOR_switch_root
+#include "toys.h"
+#include <sys/vfs.h>
+
+GLOBALS(
+  char *console;
+
+  dev_t rootdev;
+)
+
+static int del_node(struct dirtree *node)
+{
+  if (node->st.st_dev == TT.rootdev && dirtree_notdotdot(node)) {
+    int flag = 0;
+    if (S_ISDIR(node->st.st_mode)) {
+      if (!node->again) return DIRTREE_COMEAGAIN;
+      flag = AT_REMOVEDIR;
+    }
+    unlinkat(dirtree_parentfd(node), node->name, flag);
+  }
+
+  return 0;
+}
+
+void switch_root_main(void)
+{
+  char *newroot = *toys.optargs, **cmdline = toys.optargs+1;
+  struct stat st1, st2;
+  struct statfs stfs;
+  int console = console; // gcc's "may be used" warnings are broken.
+
+  if (getpid() != 1) error_exit("not pid 1");
+
+  // Root filesystem we're leaving must be ramfs or tmpfs
+  if (statfs("/", &stfs) ||
+    (stfs.f_type != 0x858458f6 && stfs.f_type != 0x01021994))
+  {
+    error_msg("not ramfs");
+    goto panic;
+  }
+
+  // New directory must be different filesystem instance
+  if (chdir(newroot) || stat(".", &st1) || stat("/", &st2) ||
+    st1.st_dev == st2.st_dev)
+  {
+    error_msg("bad newroot '%s'", newroot);
+    goto panic;
+  }
+  TT.rootdev=st2.st_dev;
+
+  // trim any / characters from the init cmdline, as we want to test it with
+  // stat(), relative to newroot. *cmdline is also used below, but by that
+  // point we are in the chroot, so a relative path is still OK.
+  while (**cmdline == '/') (*cmdline)++;
+
+  // init program must exist and be an executable file
+  if (stat(*cmdline, &st1) || !S_ISREG(st1.st_mode) || !(st1.st_mode&0100)) {
+    error_msg("bad init");
+    goto panic;
+  }
+
+  if (TT.console && -1 == (console = open(TT.console, O_RDWR))) {
+    perror_msg("bad console '%s'", TT.console);
+    goto panic;
+  }
+ 
+  // Ok, enough safety checks: wipe root partition.
+  dirtree_read("/", del_node);
+
+  // Fix the appearance of the mount table in the newroot chroot
+  if (mount(".", "/", NULL, MS_MOVE, NULL)) {
+    perror_msg("mount");
+    goto panic;
+  }
+
+  // Enter the new root before starting init
+  if (chroot(".")) {
+    perror_msg("chroot");
+    goto panic;
+  }
+
+  // Make sure cwd does not point outside of the chroot
+  if (chdir("/")) {
+    perror_msg("chdir");
+    goto panic;
+  }
+
+  if (TT.console) {
+    int i;
+    for (i=0; i<3; i++) if (console != i) dup2(console, i);
+    if (console>2) close(console);
+  }
+  execv(*cmdline, cmdline);
+  perror_msg("Failed to exec '%s'", *cmdline);
+panic:
+  if (toys.optflags & FLAG_h) for (;;) wait(NULL);
+}
diff --git a/toybox/toys/other/sysctl.c b/toybox/toys/other/sysctl.c
new file mode 100644
index 0000000..ad643c9
--- /dev/null
+++ b/toybox/toys/other/sysctl.c
@@ -0,0 +1,155 @@
+/* sysctl.c - A utility to read and manipulate the sysctl parameters.
+ *
+ * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+ 
+USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_SBIN))
+
+config SYSCTL
+  bool "sysctl"
+  default y
+  help
+    usage: sysctl [-aAeNnqw] [-p [FILE] | KEY[=VALUE]...]
+
+    Read/write system control data (under /proc/sys).
+
+    -a,A	Show all values
+    -e	Don't warn about unknown keys
+    -N	Don't print key values
+    -n	Don't print key names
+    -p	Read values from FILE (default /etc/sysctl.conf)
+    -q	Don't show value after write
+    -w	Only write values (object to reading)
+*/
+#define FOR_sysctl
+#include "toys.h"
+
+// Null terminate at =, return value
+static char *split_key(char *key)
+{
+  char *value = strchr(key, '=');
+
+  if (value) *(value++)=0;
+
+  return value;
+}
+
+static void replace_char(char *str, char old, char new)
+{
+  for (; *str; str++) if (*str == old) *str = new;
+}
+
+static void key_error(char *key)
+{
+  if (errno == ENOENT) {
+    if (!(toys.optflags & FLAG_e)) error_msg("unknown key '%s'", key);
+  } else perror_msg("key '%s'", key);
+}
+
+static int write_key(char *path, char *key, char *value)
+{
+  int fd = open(path, O_WRONLY);
+
+  if (fd < 0) {
+    key_error(key);
+
+    return 0;
+  }
+  xwrite(fd, value, strlen(value));
+  xclose(fd);
+
+  return 1;
+}
+
+// Display all keys under a path
+static int do_show_keys(struct dirtree *dt)
+{
+  char *path, *data, *key;
+
+  if (!dirtree_notdotdot(dt)) return 0; // Skip . and ..
+  if (S_ISDIR(dt->st.st_mode)) return DIRTREE_RECURSE;
+
+  path = dirtree_path(dt, 0);
+  data = readfile(path, 0, 0);
+  replace_char(key = path + 10, '/', '.'); // skip "/proc/sys/"
+  if (!data) key_error(key);
+  else {
+    // Print the parts that aren't switched off by flags.
+    if (!(toys.optflags & FLAG_n)) xprintf("%s", key);
+    if (!(toys.optflags & (FLAG_N|FLAG_n))) xprintf(" = ");
+    for (key = data+strlen(data); key > data && isspace(*--key); *key = 0);
+    if (!(toys.optflags & FLAG_N)) xprintf("%s", data);
+    if ((toys.optflags & (FLAG_N|FLAG_n)) != (FLAG_N|FLAG_n)) xputc('\n');
+  }
+
+  free(data);
+  free(path);
+
+  return 0;
+}
+
+// Read/write entries under a key. Accepts "key=value" in key if !value
+static void process_key(char *key, char *value)
+{
+  char *path;
+
+  if (!value) value = split_key(key);
+  if ((toys.optflags & FLAG_w) && !value) {
+    error_msg("'%s' not key=value", key);
+
+    return;
+  }
+
+  path = xmprintf("/proc/sys/%s", key);
+  replace_char(path, '.', '/');
+  // Note: failure to assign to a non-leaf node suppresses the display.
+  if (!(value && (!write_key(path, key, value) || (toys.optflags & FLAG_q)))) {
+    if (!access(path, R_OK)) dirtree_read(path, do_show_keys);
+    else key_error(key);
+  }
+  free(path);
+}
+
+void sysctl_main()
+{
+  char **args = 0;
+
+  // Display all keys
+  if (toys.optflags & FLAG_a) dirtree_read("/proc/sys", do_show_keys);
+
+  // read file
+  else if (toys.optflags & FLAG_p) {
+    FILE *fp = xfopen(*toys.optargs ? *toys.optargs : "/etc/sysctl.conf", "r");
+    size_t len;
+
+    for (;;) {
+      char *line = 0, *key, *val;
+
+      if (-1 == (len = getline(&line, &len, fp))) break;
+      key = line;
+      while (isspace(*key)) key++;
+      if (*key == '#' || *key == ';' || !*key) continue;
+      while (len && isspace(line[len-1])) line[--len] = 0;
+      if (!(val = split_key(line))) {
+        error_msg("'%s' not key=value", line);
+        continue;
+      }
+
+      // Trim whitespace around =
+      len = (val-line)-1;
+      while (len && isspace(line[len-1])) line[--len] = 0;
+      while (isspace(*val)) val++;;
+
+      process_key(key, val);
+      free(line);
+    }
+    fclose(fp);
+
+  // Loop through arguments, displaying or assigning as appropriate
+  } else {
+    if (!*toys.optargs) help_exit(0);
+    for (args = toys.optargs; *args; args++) process_key(*args, 0);
+  }
+}
diff --git a/toybox/toys/other/tac.c b/toybox/toys/other/tac.c
new file mode 100644
index 0000000..d5f72fd
--- /dev/null
+++ b/toybox/toys/other/tac.c
@@ -0,0 +1,49 @@
+/* tac.c - output lines in reverse order
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+
+USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config TAC
+  bool "tac"
+  default y
+  help
+    usage: tac [FILE...]
+
+    Output lines in reverse order.
+*/
+
+#include "toys.h"
+
+static void do_tac(int fd, char *name)
+{
+  struct arg_list *list = NULL;
+  char *c;
+
+  // Read in lines
+  for (;;) {
+    struct arg_list *temp;
+    long len;
+
+    if (!(c = get_rawline(fd, &len, '\n'))) break;
+
+    temp = xmalloc(sizeof(struct arg_list));
+    temp->next = list;
+    temp->arg = c;
+    list = temp;
+  }
+
+  // Play them back.
+  while (list) {
+    struct arg_list *temp = list->next;
+    xprintf("%s", list->arg);
+    free(list->arg);
+    free(list);
+    list = temp;
+  }
+}
+
+void tac_main(void)
+{
+  loopfiles(toys.optargs, do_tac);
+}
diff --git a/toybox/toys/other/taskset.c b/toybox/toys/other/taskset.c
new file mode 100644
index 0000000..abc3872
--- /dev/null
+++ b/toybox/toys/other/taskset.c
@@ -0,0 +1,133 @@
+/* taskset.c - Retrieve or set the CPU affinity of a process.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_BIN|TOYFLAG_STAYROOT))
+USE_NPROC(NEWTOY(nproc, "(all)", TOYFLAG_USR|TOYFLAG_BIN))
+
+config NPROC
+  bool "nproc"
+  default y
+  help
+    usage: nproc [--all]
+
+    Print number of processors.
+
+    --all	Show all processors, not just ones this task can run on.
+
+config TASKSET
+  bool "taskset"
+  default y
+  help
+    usage: taskset [-ap] [mask] [PID | cmd [args...]]
+
+    Launch a new task which may only run on certain processors, or change
+    the processor affinity of an exisitng PID.
+
+    Mask is a hex string where each bit represents a processor the process
+    is allowed to run on. PID without a mask displays existing affinity.
+
+    -p	Set/get the affinity of given PID instead of a new command.
+    -a	Set/get the affinity of all threads of the PID.
+*/
+
+#define FOR_taskset
+#include "toys.h"
+
+#include <sys/syscall.h>
+#define sched_setaffinity(pid, size, cpuset) \
+  syscall(__NR_sched_setaffinity, (pid_t)pid, (size_t)size, (void *)cpuset)
+#define sched_getaffinity(pid, size, cpuset) \
+  syscall(__NR_sched_getaffinity, (pid_t)pid, (size_t)size, (void *)cpuset)
+
+// mask is an array of long, which makes the layout a bit weird on big
+// endian systems but as long as it's consistent...
+
+static void do_taskset(pid_t pid, int quiet)
+{
+  unsigned long *mask = (unsigned long *)toybuf;
+  char *s = *toys.optargs, *failed = "failed to %s %d's affinity";
+  int i, j, k;
+
+  for (i=0; ; i++) {
+    if (!quiet) {
+      int j = sizeof(toybuf), flag = 0;
+
+      if (-1 == sched_getaffinity(pid, sizeof(toybuf), (void *)mask))
+        perror_exit(failed, "get", pid);
+
+      printf("pid %d's %s affinity mask: ", pid, i ? "new" : "current");
+
+      while (j--) {
+        int x = 255 & (mask[j/sizeof(long)] >> (8*(j&(sizeof(long)-1))));
+
+        if (flag) printf("%02x", x);
+        else if (x) {
+          flag++;
+          printf("%x", x);
+        }
+      }
+      putchar('\n');
+    }
+
+    if (i || toys.optc < 2) return;
+
+    memset(toybuf, 0, sizeof(toybuf));
+    k = strlen(s = *toys.optargs);
+    s += k;
+    for (j = 0; j<k; j++) {
+      unsigned long digit = *(--s) - '0';
+
+      if (digit > 9) digit = 10 + tolower(*s)-'a';
+      if (digit > 15) error_exit("bad mask '%s'", *toys.optargs);
+      mask[j/(2*sizeof(long))] |= digit << 4*(j&((2*sizeof(long))-1));
+    }
+
+    if (-1 == sched_setaffinity(pid, sizeof(toybuf), (void *)mask))
+      perror_exit(failed, "set", pid);
+  }
+}
+
+static int task_callback(struct dirtree *new)
+{
+  if (!new->parent) return DIRTREE_RECURSE;
+  if (isdigit(*new->name)) do_taskset(atoi(new->name), 0);
+
+  return 0;
+}
+
+void taskset_main(void)
+{
+  if (!(toys.optflags & FLAG_p)) {
+    if (toys.optc < 2) error_exit("Needs 2 args");
+    do_taskset(getpid(), 1);
+    xexec(toys.optargs+1);
+  } else {
+    char *c;
+    pid_t pid = strtol(toys.optargs[toys.optc-1], &c, 10);
+
+    if (*c) error_exit("Not int %s", toys.optargs[1]);
+
+    if (toys.optflags & FLAG_a) {
+      char buf[33];
+      sprintf(buf, "/proc/%ld/task/", (long)pid);
+      dirtree_read(buf, task_callback);
+    } else do_taskset(pid, 0);
+  }
+}
+
+void nproc_main(void)
+{
+  unsigned i, j, nproc = 0;
+
+  // This can only detect 32768 processors. Call getaffinity and count bits.
+  if (!toys.optflags && -1!=sched_getaffinity(getpid(), 4096, toybuf)) {
+    for (i = 0; i<4096; i++)
+      if (toybuf[i]) for (j=0; j<8; j++) if (toybuf[i]&(1<<j)) nproc++;
+  }
+
+  // If getaffinity failed or --all, count cpu entries in proc
+  if (!nproc) nproc = sysconf(_SC_NPROCESSORS_CONF);
+
+  xprintf("%u\n", nproc);
+}
diff --git a/toybox/toys/other/timeout.c b/toybox/toys/other/timeout.c
new file mode 100644
index 0000000..e39dc7a
--- /dev/null
+++ b/toybox/toys/other/timeout.c
@@ -0,0 +1,72 @@
+/* timeout.c - Run command line with a timeout
+ *
+ * Copyright 2013 Rob Landley <rob@landley.net>
+ *
+ * No standard
+
+USE_TIMEOUT(NEWTOY(timeout, "<2^vk:s: ", TOYFLAG_BIN))
+
+config TIMEOUT
+  bool "timeout"
+  default y
+  depends on TOYBOX_FLOAT
+  help
+    usage: timeout [-k LENGTH] [-s SIGNAL] LENGTH COMMAND...
+
+    Run command line as a child process, sending child a signal if the
+    command doesn't exit soon enough.
+
+    Length can be a decimal fraction. An optional suffix can be "m"
+    (minutes), "h" (hours), "d" (days), or "s" (seconds, the default).
+
+    -s	Send specified signal (default TERM)
+    -k	Send KILL signal if child still running this long after first signal.
+    -v	Verbose
+*/
+
+#define FOR_timeout
+#include "toys.h"
+
+GLOBALS(
+  char *s_signal;
+  char *k_timeout;
+
+  int nextsig;
+  pid_t pid;
+  struct timeval ktv;
+  struct itimerval itv;
+)
+
+static void handler(int i)
+{
+  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) {
+    TT.k_timeout = 0;
+    TT.nextsig = SIGKILL;
+    xsignal(SIGALRM, handler);
+    TT.itv.it_value = TT.ktv;
+    setitimer(ITIMER_REAL, &TT.itv, (void *)toybuf);
+  }
+}
+
+void timeout_main(void)
+{
+  // Parse early to get any errors out of the way.
+  TT.itv.it_value.tv_sec = xparsetime(*toys.optargs, 1000000, &TT.itv.it_value.tv_usec);
+
+  if (TT.k_timeout)
+    TT.ktv.tv_sec = xparsetime(TT.k_timeout, 1000000, &TT.ktv.tv_usec);
+  TT.nextsig = SIGTERM;
+  if (TT.s_signal && -1 == (TT.nextsig = sig_to_num(TT.s_signal)))
+    error_exit("bad -s: '%s'", TT.s_signal);
+
+  if (!(TT.pid = XVFORK())) xexec(toys.optargs+1);
+  else {
+    xsignal(SIGALRM, handler);
+    setitimer(ITIMER_REAL, &TT.itv, (void *)toybuf);
+    toys.exitval = xwaitpid(TT.pid);
+  }
+}
diff --git a/toybox/toys/other/truncate.c b/toybox/toys/other/truncate.c
new file mode 100644
index 0000000..bfe1f10
--- /dev/null
+++ b/toybox/toys/other/truncate.c
@@ -0,0 +1,65 @@
+/* truncate.c - set file length, extending sparsely if necessary
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+
+USE_TRUNCATE(NEWTOY(truncate, "<1s:|c", TOYFLAG_BIN))
+
+config TRUNCATE
+  bool "truncate"
+  default y
+  help
+    usage: truncate [-c] -s SIZE file...
+
+    Set length of file(s), extending sparsely if necessary.
+
+    -c	Don't create file if it doesn't exist.
+    -s	New size (with optional prefix and suffix)
+
+    SIZE prefix: + add, - subtract, < shrink to, > expand to,
+                 / multiple rounding down, % multiple rounding up
+    SIZE suffix: k=1024, m=1024^2, g=1024^3, t=1024^4, p=1024^5, e=1024^6
+*/
+
+#define FOR_truncate
+#include "toys.h"
+
+GLOBALS(
+  char *s;
+
+  long size;
+  int type;
+)
+
+static void do_truncate(int fd, char *name)
+{
+  long long size;
+
+  if (fd<0) return;
+
+  if (TT.type == -1) size = TT.size;
+  else {
+    size = fdlength(fd);
+    if (TT.type<2) size += TT.size*(1-(2*TT.type));
+    else if (TT.type<4) {
+      if ((TT.type==2) ? (size <= TT.size) : (size >= TT.size)) return;
+      size = TT.size;
+    } else {
+      size = (size+(TT.type-4)*(TT.size-1))/TT.size;
+      size *= TT.size;
+    }
+  }
+  if (ftruncate(fd, size)) perror_msg("'%s' to '%lld'", name, size);
+}
+
+void truncate_main(void)
+{
+  int cr = !(toys.optflags&1);
+
+  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);
+}
diff --git a/toybox/toys/other/uptime.c b/toybox/toys/other/uptime.c
new file mode 100644
index 0000000..91887df
--- /dev/null
+++ b/toybox/toys/other/uptime.c
@@ -0,0 +1,56 @@
+/* uptime.c - Tell how long the system has been running.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+ * Copyright 2012 Luis Felipe Strano Moraes <lfelipe@profusion.mobi>
+ * Copyright 2013 Jeroen van Rijn <jvrnix@gmail.com>
+
+
+USE_UPTIME(NEWTOY(uptime, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config UPTIME
+  bool "uptime"
+  default y
+  depends on TOYBOX_UTMPX
+  help
+    usage: uptime
+
+    Tell how long the system has been running and the system load
+    averages for the past 1, 5 and 15 minutes.
+*/
+
+#include "toys.h"
+
+void uptime_main(void)
+{
+  struct sysinfo info;
+  time_t tmptime;
+  struct tm * now;
+  unsigned int days, hours, minutes;
+  struct utmpx *entry;
+  int users = 0;
+
+  // Obtain the data we need.
+  sysinfo(&info);
+  time(&tmptime);
+  now = localtime(&tmptime);
+
+  // Obtain info about logged on users
+  setutxent();
+  while ((entry = getutxent())) if (entry->ut_type == USER_PROCESS) users++;
+  endutxent();
+
+  // Time
+  xprintf(" %02d:%02d:%02d up ", now->tm_hour, now->tm_min, now->tm_sec);
+  // Uptime
+  info.uptime /= 60;
+  minutes = info.uptime%60;
+  info.uptime /= 60;
+  hours = info.uptime%24;
+  days = info.uptime/24;
+  if (days) xprintf("%d day%s, ", days, (days!=1)?"s":"");
+  if (hours) xprintf("%2d:%02d, ", hours, minutes);
+  else printf("%d min, ", minutes);
+  printf(" %d user%s, ", users, (users!=1) ? "s" : "");
+  printf(" load average: %.02f, %.02f, %.02f\n", info.loads[0]/65536.0,
+    info.loads[1]/65536.0, info.loads[2]/65536.0);
+}
diff --git a/toybox/toys/other/usleep.c b/toybox/toys/other/usleep.c
new file mode 100644
index 0000000..6040cc0
--- /dev/null
+++ b/toybox/toys/other/usleep.c
@@ -0,0 +1,26 @@
+/* usleep.c - Wait for a number of microseconds.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+
+USE_USLEEP(NEWTOY(usleep, "<1", TOYFLAG_BIN))
+
+config USLEEP
+  bool "usleep"
+  default y
+  help
+    usage: usleep MICROSECONDS
+
+    Pause for MICROSECONDS microseconds.
+*/
+
+#include "toys.h"
+
+void usleep_main(void)
+{
+  struct timespec tv;
+  long delay = atol(*toys.optargs);
+
+  tv.tv_sec = delay/1000000;
+  tv.tv_nsec = (delay%1000000) * 1000;
+  toys.exitval = !!nanosleep(&tv, NULL);
+}
diff --git a/toybox/toys/other/vconfig.c b/toybox/toys/other/vconfig.c
new file mode 100644
index 0000000..fd78527
--- /dev/null
+++ b/toybox/toys/other/vconfig.c
@@ -0,0 +1,90 @@
+/* vconfig.c - Creates virtual ethernet devices.
+ *
+ * Copyright 2012 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2012 Kyungwan Han <asura321@gmail.com>
+ *
+ * No standard
+ *
+ * TODO: cleanup
+
+USE_VCONFIG(NEWTOY(vconfig, "<2>4", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+
+config VCONFIG
+  bool "vconfig"
+  default y
+  help
+    usage: vconfig COMMAND [OPTIONS]
+
+    Create and remove virtual ethernet devices
+
+    add             [interface-name] [vlan_id]
+    rem             [vlan-name]
+    set_flag        [interface-name] [flag-num]       [0 | 1]
+    set_egress_map  [vlan-name]      [skb_priority]   [vlan_qos]
+    set_ingress_map [vlan-name]      [skb_priority]   [vlan_qos]
+    set_name_type   [name-type]
+*/
+
+#include "toys.h"
+#include <linux/if_vlan.h>
+#include <linux/sockios.h>
+
+void vconfig_main(void)
+{
+  struct vlan_ioctl_args request;
+  char *cmd;
+  int fd;
+
+  fd = xsocket(AF_INET, SOCK_STREAM, 0);
+  memset(&request, 0, sizeof(struct vlan_ioctl_args));
+  cmd = toys.optargs[0];
+
+  if (!strcmp(cmd, "set_name_type")) {
+    char *types[] = {"VLAN_PLUS_VID", "DEV_PLUS_VID", "VLAN_PLUS_VID_NO_PAD",
+                     "DEV_PLUS_VID_NO_PAD"};
+    int i, j = sizeof(types)/sizeof(*types);
+
+    for (i=0; i<j; i++) if (!strcmp(toys.optargs[1], types[i])) break;
+    if (i == j) {
+      for (i=0; i<j; i++) puts(types[i]);
+      error_exit("%s: unknown '%s'", cmd, toys.optargs[1]);
+    }
+
+    request.u.name_type = i;
+    request.cmd = SET_VLAN_NAME_TYPE_CMD;
+    xioctl(fd, SIOCSIFVLAN, &request);
+    return;
+  }
+
+  // Store interface name
+  xstrncpy(request.device1, toys.optargs[1], 16);
+
+  if (!strcmp(cmd, "add")) {
+    request.cmd = ADD_VLAN_CMD;
+    if (toys.optargs[2]) request.u.VID = atolx_range(toys.optargs[2], 0, 4094);
+    if (request.u.VID == 1)
+      xprintf("WARNING: VLAN 1 does not work with many switches.\n");
+  } else if (!strcmp(cmd, "rem")) request.cmd = DEL_VLAN_CMD;
+  else if (!strcmp(cmd, "set_flag")) {
+    request.cmd = SET_VLAN_FLAG_CMD;
+    if (toys.optargs[2]) request.u.flag = atolx_range(toys.optargs[2], 0, 1);
+    if (toys.optargs[3]) request.vlan_qos = atolx_range(toys.optargs[3], 0, 7);
+  } else if(strcmp(cmd, "set_egress_map") == 0) {
+    request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
+    if (toys.optargs[2])
+      request.u.skb_priority = atolx_range(toys.optargs[2], 0, INT_MAX);
+    if (toys.optargs[3]) request.vlan_qos = atolx_range(toys.optargs[3], 0, 7);
+  } else if(strcmp(cmd, "set_ingress_map") == 0) {
+    request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;
+    if (toys.optargs[2])
+      request.u.skb_priority = atolx_range(toys.optargs[2], 0, INT_MAX);
+    //To set flag we must have to set vlan_qos
+    if (toys.optargs[3]) request.vlan_qos = atolx_range(toys.optargs[3], 0, 7);
+  } else {
+    xclose(fd);
+    perror_exit("Unknown command %s", cmd);
+  }
+
+  xioctl(fd, SIOCSIFVLAN, &request);
+  xprintf("Successful %s on device %s\n", cmd, toys.optargs[1]);
+}
diff --git a/toybox/toys/other/vmstat.c b/toybox/toys/other/vmstat.c
new file mode 100644
index 0000000..ae856cf
--- /dev/null
+++ b/toybox/toys/other/vmstat.c
@@ -0,0 +1,158 @@
+/* vmstat.c - Report virtual memory statistics.
+ *
+ * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com>
+ *
+ * TODO: I have no idea how "system" category is calculated.
+ * whatever we're doing isn't matching what other implementations are doing.
+
+USE_VMSTAT(NEWTOY(vmstat, ">2n", TOYFLAG_BIN))
+
+config VMSTAT
+  bool "vmstat"
+  default y
+  help
+    usage: vmstat [-n] [DELAY [COUNT]]
+
+    Print virtual memory statistics, repeating each DELAY seconds, COUNT times.
+    (With no DELAY, prints one line. With no COUNT, repeats until killed.)
+
+    Show processes running and blocked, kilobytes swapped, free, buffered, and
+    cached, kilobytes swapped in and out per second, file disk blocks input and
+    output per second, interrupts and context switches per second, percent
+    of CPU time spent running user code, system code, idle, and awaiting I/O.
+    First line is since system started, later lines are since last line.
+
+    -n	Display the header only once
+*/
+
+#define FOR_vmstat
+#include "toys.h"
+
+struct vmstat_proc {
+  // From /proc/stat (jiffies)
+  uint64_t user, nice, sys, idle, wait, irq, sirq, intr, ctxt, running, blocked;
+  // From /proc/meminfo (units are kb)
+  uint64_t memfree, buffers, cached, swapfree, swaptotal;
+  // From /proc/vmstat (units are kb)
+  uint64_t io_in, io_out;
+  // From /proc/vmstat (units are pages)
+  uint64_t swap_in, swap_out;
+};
+
+// All the elements of vmstat_proc are the same size, so we can populate it as
+// a big array, then read the elements back out by name
+static void get_vmstat_proc(struct vmstat_proc *vmstat_proc)
+{
+  char *vmstuff[] = { "/proc/stat", "cpu ", 0, 0, 0, 0, 0, 0,
+    "intr ", "ctxt ", "procs_running ", "procs_blocked ", "/proc/meminfo",
+    "MemFree: ", "Buffers: ", "Cached: ", "SwapFree: ", "SwapTotal: ",
+    "/proc/vmstat", "pgpgin ", "pgpgout ", "pswpin ", "pswpout " };
+  uint64_t *new = (uint64_t *)vmstat_proc;
+  char *p = p, *name = name;
+  int i, j;
+
+  // We use vmstuff to fill out vmstat_proc as an array of uint64_t:
+  //   Strings starting with / are the file to find next entries in
+  //   Any other string is a key to search for, with decimal value right after
+  //   0 means parse another value on same line as last key
+
+  for (i = 0; i<sizeof(vmstuff)/sizeof(char *); i++) {
+    if (!vmstuff[i]) p++;
+    else if (*vmstuff[i] == '/') {
+      xreadfile(name = vmstuff[i], toybuf, sizeof(toybuf));
+
+      continue;
+    } else if (!(p = strafter(toybuf, vmstuff[i]))) goto error;
+    if (1 != sscanf(p, "%"PRIu64"%n", new++, &j)) goto error;
+    p += j;
+  }
+
+  return;
+
+error:
+  error_exit("No %sin %s\n", vmstuff[i], name);
+}
+
+void vmstat_main(void)
+{
+  struct vmstat_proc top[2];
+  int i, loop_delay = 0, loop_max = 0;
+  unsigned loop, rows = (toys.optflags & FLAG_n) ? 0 : 25,
+           page_kb = sysconf(_SC_PAGESIZE)/1024;
+  char *headers="r\0b\0swpd\0free\0buff\0cache\0si\0so\0bi\0bo\0in\0cs\0us\0"
+                "sy\0id\0wa", lengths[] = {2,2,6,6,6,6,4,4,5,5,4,4,2,2,2,2};
+
+  memset(top, 0, sizeof(top));
+  if (toys.optc) loop_delay = atolx_range(toys.optargs[0], 0, INT_MAX);
+  if (toys.optc > 1) loop_max = atolx_range(toys.optargs[1], 1, INT_MAX) - 1;
+
+  for (loop = 0; !loop_max || loop <= loop_max; loop++) {
+    unsigned idx = loop&1, offset = 0, expected = 0;
+    uint64_t units, total_hz, *ptr = (uint64_t *)(top+idx),
+             *oldptr = (uint64_t *)(top+!idx);
+
+    if (loop && loop_delay) sleep(loop_delay);
+
+    // Print headers
+    if (rows>3 && !(loop % (rows-3))) {
+      char *header = headers;
+
+      if (isatty(1)) terminal_size(0, &rows);
+      else rows = 0;
+
+      printf("procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----\n");
+      for (i=0; i<sizeof(lengths); i++) {
+        printf(" %*s"+!i, lengths[i], header);
+        header += strlen(header)+1;
+      }
+      xputc('\n');
+    }
+
+    // Read data and combine some fields we display as aggregates
+    get_vmstat_proc(top+idx);
+    top[idx].running--; // Don't include ourselves
+    top[idx].user += top[idx].nice;
+    top[idx].sys += top[idx].irq + top[idx].sirq;
+    top[idx].swaptotal -= top[idx].swapfree;
+
+    // Collect unit adjustments (outside the inner loop to save time)
+
+    if (!loop) {
+      char *s = toybuf;
+
+      xreadfile("/proc/uptime", toybuf, sizeof(toybuf));
+      while (*(s++) > ' ');
+      sscanf(s, "%"PRIu64, &units);
+    } else units = loop_delay;
+
+    // add up user, sys, idle, and wait time used since last time
+    // (Already appended nice to user)
+    total_hz = 0;
+    for (i=0; i<4; i++) total_hz += ptr[i+!!i] - oldptr[i+!!i];
+
+    // Output values in order[]: running, blocked, swaptotal, memfree, buffers,
+    // cache, swap_in, swap_out, io_in, io_out, sirq, ctxt, user, sys, idle,wait
+
+    for (i=0; i<sizeof(lengths); i++) {
+      char order[] = {9, 10, 15, 11, 12, 13, 18, 19, 16, 17, 6, 8, 0, 2, 3, 4};
+      uint64_t out = ptr[order[i]];
+      int len;
+
+      // Adjust rate and units
+      if (i>5) out -= oldptr[order[i]];
+      if (order[i]<7) out = ((out*100) + (total_hz/2)) / total_hz;
+      else if (order[i]>17) out = ((out * page_kb)+(units-1))/units;
+      else if (order[i]>15) out = ((out)+(units-1))/units;
+      else if (order[i]<9) out = (out+(units-1)) / units;
+
+      // If a field was too big to fit in its slot, try to compensate later
+      expected += lengths[i] + !!i;
+      len = expected - offset - !!i;
+      if (len < 0) len = 0;
+      offset += printf(" %*"PRIu64+!i, len, out);
+    }
+    xputc('\n');
+
+    if (!loop_delay) break;
+  }
+}
diff --git a/toybox/toys/other/w.c b/toybox/toys/other/w.c
new file mode 100644
index 0000000..a76c82f
--- /dev/null
+++ b/toybox/toys/other/w.c
@@ -0,0 +1,34 @@
+/* w.c - shows logged in users
+ *
+ * Copyright 2012 Gaurang Shastri <gmshastri@gmail.com>
+
+USE_W(NEWTOY(w, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config W
+  bool "w"
+  default y
+  depends on TOYBOX_UTMPX
+  help
+    usage: w
+
+    Show who is logged on and since how long they logged in.
+*/
+
+#include "toys.h"
+
+void w_main(void)
+{
+  struct utmpx *x;
+
+  xprintf("USER     TTY             LOGIN@              FROM");
+  setutxent();
+  while ((x=getutxent()) != NULL) {
+    if (x->ut_type==7) {
+      time_t tt = x->ut_tv.tv_sec;
+
+      xprintf("\n%-9.8s%-9.8s %-4.24s (%-1.12s)", x->ut_user, x->ut_line,
+        ctime(&tt), x->ut_host);
+    }
+  }
+  xputc('\n');
+}
diff --git a/toybox/toys/other/which.c b/toybox/toys/other/which.c
new file mode 100644
index 0000000..fc65fe8
--- /dev/null
+++ b/toybox/toys/other/which.c
@@ -0,0 +1,68 @@
+/* which.c - Find executable files in $PATH.
+ *
+ * Copyright 2006 Rob landley <rob@landley.net>
+
+USE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
+
+config WHICH
+  bool "which"
+  default y
+  help
+    usage: which [-a] filename ...
+
+    Search $PATH for executable files matching filename(s).
+
+    -a	Show all matches
+*/
+#include "toys.h"
+
+// Find an exectuable file either at a path with a slash in it (absolute or
+// relative to current directory), or in $PATH.  Returns absolute path to file,
+// or NULL if not found.
+
+static int which_in_path(char *filename)
+{
+  struct string_list *list;
+
+  // If they gave us a path, don't worry about $PATH or -a
+
+  if (strchr(filename, '/')) {
+    // Confirm it has the executable bit set, and it's not a directory.
+    if (!access(filename, X_OK)) {
+      struct stat st;
+
+      if (!stat(filename, &st) && S_ISREG(st.st_mode)) {
+        puts(filename);
+        return 0;
+      }
+      return 1;
+    }
+  }
+
+  // Search $PATH for matches.
+  list = find_in_path(getenv("PATH"), filename);
+  if (!list) return 1;
+
+  // Print out matches
+  while (list) {
+    if (!access(list->str, X_OK)) {
+      puts(list->str);
+      // If we should stop at one match, do so
+      if (!toys.optflags) {
+        llist_traverse(list, free);
+        break;
+      }
+    }
+    free(llist_pop(&list));
+  }
+
+  return 0;
+}
+
+void which_main(void)
+{
+  int i;
+
+  for (i=0; toys.optargs[i]; i++)
+    toys.exitval |= which_in_path(toys.optargs[i]);
+}
diff --git a/toybox/toys/other/xxd.c b/toybox/toys/other/xxd.c
new file mode 100644
index 0000000..99de2ee
--- /dev/null
+++ b/toybox/toys/other/xxd.c
@@ -0,0 +1,138 @@
+/* xxd.c - hexdump.
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * No obvious standard, output looks like:
+ * 0000000: 4c69 6e75 7820 7665 7273 696f 6e20 332e  Linux version 3.
+
+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] [-s n] [file]
+
+    Hexdump a file to stdout.  If no file is listed, copy from stdin.
+    Filename "-" is a synonym for stdin.
+
+    -c n	Show n bytes per line (default 16).
+    -g n	Group bytes by adding a ' ' every n bytes (default 2).
+    -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;
+
+  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;
+
+    for (i=0; i<len;) {
+      space -= printf("%02x", toybuf[i]);
+      if (!(++i%TT.g)) {
+        putchar(' ');
+        space--;
+      }
+    }
+
+    if (!(toys.optflags&FLAG_p)) {
+      printf("%*s", space, "");
+      for (i=0; i<len; i++)
+        putchar((toybuf[i]>=' ' && toybuf[i]<='~') ? toybuf[i] : '.');
+    }
+    putchar('\n');
+  }
+  if (len<0) perror_exit("read");
+}
+
+static int dehex(char ch)
+{
+  if (ch >= '0' && ch <= '9') return ch - '0';
+  if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
+  if (ch >= 'A' && ch <= 'F') return ch - 'a' + 10;
+  return (ch == '\n') ? -2 : -1;
+}
+
+static void do_xxd_reverse(int fd, char *name)
+{
+  FILE *fp = xfdopen(fd, "r");
+
+  while (!feof(fp)) {
+    int col = 0;
+    int tmp;
+
+    // Each line of a non-plain hexdump starts with an offset/address.
+    if (!(toys.optflags&FLAG_p)) {
+      long long pos;
+
+      if (fscanf(fp, "%llx: ", &pos) == 1) {
+        if (fseek(stdout, pos, SEEK_SET) != 0) {
+          // TODO: just write out zeros if non-seekable?
+          perror_exit("%s: seek failed", name);
+        }
+      }
+    }
+
+    // A plain hexdump can have as many bytes per line as you like,
+    // but a non-plain hexdump assumes garbage after it's seen the
+    // specified number of bytes.
+    while (toys.optflags&FLAG_p || col < TT.c) {
+      int n1, n2;
+
+      // If we're at EOF or EOL or we read some non-hex...
+      if ((n1 = n2 = dehex(fgetc(fp))) < 0 || (n2 = dehex(fgetc(fp))) < 0) {
+        // If we're at EOL, start on that line.
+        if (n1 == -2 || n2 == -2) continue;
+        // Otherwise, skip to the next line.
+        break;
+      }
+
+      fputc((n1 << 4) | (n2 & 0xf), stdout);
+      col++;
+
+      // Is there any grouping going on? Ignore a single space.
+      tmp = fgetc(fp);
+      if (tmp != ' ') ungetc(tmp, fp);
+    }
+
+    // Skip anything else on this line (such as the ASCII dump).
+    while ((tmp = fgetc(fp)) != EOF && tmp != '\n')
+      ;
+  }
+  if (ferror(fp)) perror_msg_raw(name);
+
+  fclose(fp);
+}
+
+void xxd_main(void)
+{
+  // Plain style is 30 bytes/line, no grouping.
+  if (toys.optflags&FLAG_p) TT.c = TT.g = 30;
+
+  loopfiles(toys.optargs, toys.optflags&FLAG_r ? do_xxd_reverse : do_xxd);
+}
diff --git a/toybox/toys/other/yes.c b/toybox/toys/other/yes.c
new file mode 100644
index 0000000..773a5a8
--- /dev/null
+++ b/toybox/toys/other/yes.c
@@ -0,0 +1,29 @@
+/* yes.c - Repeatedly output a string.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+
+USE_YES(NEWTOY(yes, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config YES
+  bool "yes"
+  default y
+  help
+    usage: yes [args...]
+
+    Repeatedly output line until killed. If no args, output 'y'.
+*/
+
+#include "toys.h"
+
+void yes_main(void)
+{
+  for (;;) {
+    int i;
+    for (i=0; toys.optargs[i]; i++) {
+      if (i) xputc(' ');
+      xprintf("%s", toys.optargs[i]);
+    }
+    if (!i) xputc('y');
+    xputc('\n');
+  }
+}
diff --git a/toybox/toys/pending/README b/toybox/toys/pending/README
new file mode 100644
index 0000000..2eb83e1
--- /dev/null
+++ b/toybox/toys/pending/README
@@ -0,0 +1,15 @@
+pending (see toys/pending/README)
+
+Commands in this directory are external submissions awaiting review and/or
+cleanup before being "promoted" to one of the other directories.
+
+Code in this directory may or may not work, some of the commands here are
+unfinished stubs, others just need a more thorough inspection than we've had
+time for yet. Everything in here defaults to "n" in defconfig.
+
+Outside of this directory, several commands (and some library code) have
+TODO annotations.
+
+This directory should go away before the 1.0 release. It's just a staging
+area so code submissions don't get lost while awaiting more thorough (and
+very time consuming) scrutiny as described in www/cleanup.html.
diff --git a/toybox/toys/pending/arp.c b/toybox/toys/pending/arp.c
new file mode 100644
index 0000000..6b57c3c
--- /dev/null
+++ b/toybox/toys/pending/arp.c
@@ -0,0 +1,307 @@
+/* arp.c - manipulate the system ARP cache
+ *
+ * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gamil.com>
+ * No Standard 
+
+USE_ARP(NEWTOY(arp, "vi:nDsdap:A:H:[+Ap][!sd]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config ARP
+  bool "arp"
+  default n
+  help
+    Usage: arp 
+    [-vn] [-H HWTYPE] [-i IF] -a [HOSTNAME]
+    [-v]              [-i IF] -d HOSTNAME [pub]
+    [-v]  [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [temp]
+    [-v]  [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [netmask MASK] pub
+    [-v]  [-H HWTYPE] [-i IF] -Ds HOSTNAME IFACE [netmask MASK] pub
+
+    Manipulate ARP cache
+
+    -a    Display (all) hosts
+    -s    Set new ARP entry
+    -d    Delete a specified entry
+    -v    Verbose
+    -n    Don't resolve names
+    -i IF Network interface
+    -D    Read <hwaddr> from given device
+    -A,-p AF  Protocol family
+    -H    HWTYPE Hardware address type
+
+*/
+
+#define FOR_arp
+#include "toys.h"
+#include <net/if_arp.h>
+
+GLOBALS(
+    char *hw_type;
+    char *af_type_A;
+    char *af_type_p;
+    char *interface;
+    
+    int sockfd;
+    char *device;
+)
+
+struct arpreq req; //Global request structure 
+
+struct type {
+  char *name;
+  int val;
+};
+
+struct type hwtype[] = {
+  {"ether", ARPHRD_ETHER }, 
+  {"loop" ,ARPHRD_LOOPBACK},
+  {"ppp" ,ARPHRD_PPP},
+  {"infiniband" ,ARPHRD_INFINIBAND},
+  {NULL, -1},
+};
+
+struct type aftype[] = {
+  {"inet", AF_INET }, 
+  {"inet6" ,AF_INET6},
+  {"unspec" ,AF_UNSPEC},
+  {NULL, -1},
+};
+
+struct type flag_type[] = {
+  {"PERM", ATF_PERM }, 
+  {"PUB" ,ATF_PUBL},
+  {"DONTPUB" ,ATF_DONTPUB},
+  {"TRAIL" ,ATF_USETRAILERS},
+  {NULL, -1},
+};
+
+static int get_index(struct type arr[], char *name)
+{
+  int i;
+  
+  for (i = 0; arr[i].name; i++) 
+    if (!strcmp(arr[i].name, name)) break;
+  return arr[i].val;
+}
+
+
+void get_hw_add(char *hw_addr, char *ptr) 
+{
+  char *p = ptr, *hw = hw_addr;
+
+  while (*hw_addr && (p-ptr) < 6) {
+    int val, len = 0;
+
+    if (*hw_addr == ':') hw_addr++;
+    sscanf(hw_addr, "%2x%n", &val, &len);
+    if (!len || len > 2) break;
+    hw_addr += len;
+    *p++ = val;
+  }
+
+  if ((p-ptr) != 6 || *hw_addr)
+    error_exit("bad hw addr '%s'", hw);
+}
+
+static void resolve_host(char *host, struct sockaddr *sa)
+{
+  struct addrinfo hints, *res = NULL;
+  int ret;
+
+  memset(&hints, 0, sizeof hints);
+  hints.ai_family = AF_INET;
+  hints.ai_socktype = SOCK_STREAM;
+  if ((ret = getaddrinfo(host, NULL, &hints, &res))) 
+    perror_exit("%s", gai_strerror(ret));
+
+  memcpy(sa, res->ai_addr, res->ai_addrlen);
+  freeaddrinfo(res);
+}
+
+static void check_flags(int *i, char** argv)
+{
+  struct sockaddr sa;
+  int flag = *i, j;
+  struct flags {
+    char *name;
+    int or, flag;
+  } f[] = {
+    {"pub",  1 ,ATF_PUBL},
+    {"priv", 0 ,~ATF_PUBL},
+    {"trail", 1, ATF_USETRAILERS},
+    {"temp", 0, ~ATF_PERM},
+    {"dontpub",1, ATF_DONTPUB},
+  };
+  
+  for (;*argv; argv++) {
+    for (j = 0;  j < ARRAY_LEN(f); j++) { 
+      if (!strcmp(*argv, f[j].name)) {
+        (f[j].or) ?(flag |= f[j].flag):(flag &= f[j].flag);
+        break;
+      }
+    }
+    if (j > 4 && !strcmp(*argv, "netmask")) {
+      if (!*++argv) error_exit("NULL netmask");
+      if (strcmp(*argv, "255.255.255.255")) {
+        resolve_host(toys.optargs[0], &sa);
+        memcpy(&req.arp_netmask, &sa, sizeof(sa));
+        flag |= ATF_NETMASK;
+      } else argv++; 
+    } else if (j > 4 && !strcmp(*argv, "dev")) {
+      if (!*++argv) error_exit("NULL dev");
+      TT.device = *argv;
+    } else if (j > 4) error_exit("invalid arg");
+  }
+  *i = flag;
+}
+
+static int set_entry(void) 
+{
+  int flags = 0;
+  
+  if (!toys.optargs[1]) error_exit("bad syntax");
+
+  if (!(toys.optflags & FLAG_D)) get_hw_add(toys.optargs[1], (char*)&req.arp_ha.sa_data);
+  else {
+    struct ifreq ifre;
+
+    xstrncpy(ifre.ifr_name, toys.optargs[1], IFNAMSIZ);
+    xioctl(TT.sockfd, SIOCGIFHWADDR, &ifre);
+    if ((toys.optflags & FLAG_H) && (ifre.ifr_hwaddr.sa_family != ARPHRD_ETHER)) 
+      error_exit("protocol type mismatch");
+    memcpy(&req.arp_ha, &(ifre.ifr_hwaddr), sizeof(req.arp_ha));
+  }
+
+  flags = ATF_PERM | ATF_COM;
+  if (toys.optargs[2]) check_flags(&flags, (toys.optargs+2));
+  req.arp_flags = flags;
+  xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
+  xioctl(TT.sockfd, SIOCSARP, &req);
+  
+  if (toys.optflags & FLAG_v) xprintf("Entry set for %s\n", toys.optargs[0]);
+  return 0;
+}
+
+static int ip_to_host(struct sockaddr *sa, int flag) 
+{
+  int status = 0;
+  char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,}; 
+  socklen_t len = sizeof(struct sockaddr_in6);
+  
+  *toybuf = 0;
+  if (!(status = getnameinfo(sa, len, hbuf, sizeof(hbuf), sbuf, 
+          sizeof(sbuf), flag))) {
+    strcpy(toybuf, hbuf);
+    return 0;
+  }
+  return 1;
+}
+
+static int delete_entry(void)
+{
+  int flags;
+  
+  flags = ATF_PERM;
+  if (toys.optargs[1]) check_flags(&flags, (toys.optargs+1));
+  req.arp_flags = flags;
+  xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
+  xioctl(TT.sockfd, SIOCDARP, &req);
+  
+  if (toys.optflags & FLAG_v) xprintf("Delete entry for  %s\n", toys.optargs[0]);
+  return 0;
+}
+
+void arp_main(void)
+{
+  struct sockaddr sa;
+  char ip[128], hw_addr[128], mask[12], dev[128], *host_ip = NULL, *buf;
+  int h_type, type, flag, i, fd, entries = 0, disp = 0;
+
+  TT.device = "";
+  memset(&sa, 0, sizeof(sa));
+  memset(&req, 0, sizeof(req));
+  TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
+
+  if ((toys.optflags & FLAG_A) || (toys.optflags & FLAG_p)) {
+    if ((type = get_index(aftype, 
+            (TT.af_type_A)?TT.af_type_A:TT.af_type_p)) != AF_INET) 
+      error_exit((type != -1)?"only inet supported by kernel":"unknown family");
+  } 
+
+  req.arp_ha.sa_family = ARPHRD_ETHER;
+  if (toys.optflags & FLAG_H) {
+    if ((type = get_index(hwtype, TT.hw_type)) != ARPHRD_ETHER) 
+      error_exit((type != -1)?"h/w type not supported":"unknown h/w type");
+    req.arp_ha.sa_family = type;
+  }
+
+  if (((toys.optflags & FLAG_s) || toys.optflags & FLAG_d)) { 
+    if (!toys.optargs[0]) error_exit("host name req");
+    resolve_host(toys.optargs[0], &sa);
+    memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
+  }
+
+  if ((toys.optflags & FLAG_s) && !set_entry()) return;
+  if ((toys.optflags & FLAG_d) && !delete_entry()) return; 
+
+  //show arp chache
+  fd = xopenro("/proc/net/arp");
+  buf = get_line(fd);
+  free(buf); //skip first line
+
+  if (toys.optargs[0]) {
+    resolve_host(toys.optargs[0], &sa);
+    ip_to_host(&sa, NI_NUMERICHOST);
+    host_ip = xstrdup(toybuf);
+  }
+
+  while ((buf = get_line(fd))) {
+    char *host_name = "?";
+    
+    if ((sscanf(buf, "%s 0x%x 0x%x %s %s %s\n", ip,
+        &h_type, &flag, hw_addr, mask, dev )) != 6) break;
+    entries++;
+    if (((toys.optflags & FLAG_H) && (get_index(hwtype, TT.hw_type) != h_type))
+     || ((toys.optflags & FLAG_i) && strcmp(TT.interface, dev))
+     || (toys.optargs[0] && strcmp(host_ip, ip))) {
+      free(buf);
+      continue;
+    }
+
+    resolve_host(buf, &sa);
+    if (!(toys.optflags & FLAG_n)) { 
+      if (!ip_to_host(&sa, NI_NAMEREQD)) host_name = toybuf;
+    } else ip_to_host(&sa, NI_NUMERICHOST);
+    
+    disp++;
+    printf("%s (%s) at" , host_name, ip);
+
+    for (i = 0; hwtype[i].name; i++) 
+      if (hwtype[i].val & h_type) break;
+    if (!hwtype[i].name) error_exit("unknown h/w type");
+
+    if (!(flag & ATF_COM)) {
+      if ((flag & ATF_PUBL)) printf(" *");
+      else printf(" <incomplete>");
+    } else printf(" %s [%s]", hw_addr, hwtype[i].name);
+
+    if (flag & ATF_NETMASK) printf("netmask %s ", mask);
+
+    for (i = 0; flag_type[i].name; i++) 
+      if (flag_type[i].val & flag) printf(" %s", flag_type[i].name);
+
+    printf(" on %s\n", dev);
+    free(buf);
+  }
+  
+  if (toys.optflags & FLAG_v) 
+    xprintf("Entries: %d\tSkipped: %d\tFound: %d\n",
+        entries, entries - disp, disp);
+  if (!disp) xprintf("No Match found in %d entries\n", entries);
+  
+  if (CFG_TOYBOX_FREE) {
+    free(host_ip);
+    free(buf);
+    xclose(fd);
+  }
+}
diff --git a/toybox/toys/pending/arping.c b/toybox/toys/pending/arping.c
new file mode 100644
index 0000000..be43cab
--- /dev/null
+++ b/toybox/toys/pending/arping.c
@@ -0,0 +1,292 @@
+/* arping - send ARP REQUEST to a neighbour host.
+ *
+ * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_ARPING(NEWTOY(arping, "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config ARPING
+  bool "arping"
+  default n
+  help
+    usage: arping [-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP
+
+    Send ARP requests/replies
+
+    -f         Quit on first ARP reply
+    -q         Quiet
+    -b         Keep broadcasting, don't go unicast
+    -D         Duplicated address detection mode
+    -U         Unsolicited ARP mode, update your neighbors
+    -A         ARP answer mode, update your neighbors
+    -c N       Stop after sending N ARP requests
+    -w TIMEOUT Time to wait for ARP reply, seconds
+    -I IFACE   Interface to use (default eth0)
+    -s SRC_IP  Sender IP address
+    DST_IP     Target IP address
+*/
+#define FOR_arping
+#include "toys.h"
+#include <netinet/ether.h>
+#include <netpacket/packet.h>
+
+GLOBALS(
+    long count;
+    unsigned long time_out;
+    char *iface;
+    char *src_ip;
+
+    int sockfd;
+    unsigned long start, end;
+    unsigned sent_at, sent_nr, rcvd_nr, brd_sent, rcvd_req, brd_rcv,
+             unicast_flag;
+)
+
+struct sockaddr_ll src_pk, dst_pk; 
+struct in_addr src_addr, dest_addr;
+extern void *mempcpy(void *dest, const void *src, size_t n);
+
+// Gets information of INTERFACE and updates IFINDEX, MAC and IP.
+static void get_interface(char *interface, int *ifindex, uint32_t *oip, 
+    uint8_t *mac)
+{
+  struct ifreq req;
+  struct sockaddr_in *ip;
+  int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+
+  req.ifr_addr.sa_family = AF_INET;
+  xstrncpy(req.ifr_name, interface, IFNAMSIZ);
+  req.ifr_name[IFNAMSIZ-1] = '\0';
+
+  xioctl(fd, SIOCGIFFLAGS, &req);
+  if (!(req.ifr_flags & IFF_UP)) return;
+
+  if (oip) {
+    xioctl(fd, SIOCGIFADDR, &req);
+    ip = (struct sockaddr_in*) &req.ifr_addr;
+    *oip = ntohl(ip->sin_addr.s_addr);
+  }
+  if (ifindex) {
+    xioctl(fd, SIOCGIFINDEX, &req);
+    *ifindex = req.ifr_ifindex;
+  }
+  if (mac) {
+    xioctl(fd, SIOCGIFHWADDR, &req);
+    memcpy(mac, req.ifr_hwaddr.sa_data, 6);
+  }
+  xclose(fd);
+}
+
+// SIGINT handler, Print Number of Packets send or receive details.
+static void done(int sig)
+{
+  if (!(toys.optflags & FLAG_q)) {
+    xprintf("Sent %u probe(s) (%u broadcast(s))\n", TT.sent_nr, TT.brd_sent);
+    xprintf("Received %u repl%s (%u request(s), %u broadcast(s))\n", 
+        TT.rcvd_nr, TT.rcvd_nr == 1 ? "y":"ies", TT.rcvd_req, TT.brd_rcv);
+  }
+  if (toys.optflags & FLAG_D) exit(!!TT.rcvd_nr);
+  //In -U mode, No reply is expected.
+  if (toys.optflags & FLAG_U) exit(EXIT_SUCCESS); 
+  exit(!TT.rcvd_nr);
+}
+
+// Create and Send Packet 
+static void send_packet()
+{
+  int ret;
+  unsigned char sbuf[256] = {0,};
+  struct arphdr *arp_h = (struct arphdr *) sbuf;
+  unsigned char *ptr = (unsigned char *)(arp_h + 1);
+
+  arp_h->ar_hrd = htons(ARPHRD_ETHER);
+  arp_h->ar_pro = htons(ETH_P_IP);
+  arp_h->ar_hln = src_pk.sll_halen;
+  arp_h->ar_pln = 4;  
+  arp_h->ar_op = (toys.optflags & FLAG_A) ? htons(ARPOP_REPLY) 
+    : htons(ARPOP_REQUEST);
+
+  ptr = mempcpy(ptr, &src_pk.sll_addr, src_pk.sll_halen);
+  ptr = mempcpy(ptr, &src_addr, 4);
+  ptr = mempcpy(ptr,
+                (toys.optflags & FLAG_A) ? &src_pk.sll_addr : &dst_pk.sll_addr,
+                src_pk.sll_halen);
+  ptr = mempcpy(ptr, &dest_addr, 4);
+
+  ret = sendto(TT.sockfd, sbuf, ptr - sbuf, 0, 
+      (struct sockaddr *)&dst_pk, sizeof(dst_pk));
+  if (ret == ptr - sbuf) {
+    struct timeval tval;
+
+    gettimeofday(&tval, NULL);
+    TT.sent_at = tval.tv_sec * 1000000ULL + tval.tv_usec;
+    TT.sent_nr++;
+    if (!TT.unicast_flag) TT.brd_sent++;
+  }
+}
+
+// Receive Packet and filter with valid checks.
+static void recv_from(struct sockaddr_ll *from, int *recv_len)
+{
+  struct in_addr s_ip, d_ip;
+  struct arphdr *arp_hdr = (struct arphdr *)toybuf;
+  unsigned char *p = (unsigned char *)(arp_hdr + 1);
+
+  if (arp_hdr->ar_op != htons(ARPOP_REQUEST) && 
+      arp_hdr->ar_op != htons(ARPOP_REPLY)) return; 
+
+  if (from->sll_pkttype != PACKET_HOST && from->sll_pkttype != PACKET_BROADCAST
+      && from->sll_pkttype != PACKET_MULTICAST) return; 
+
+  if (arp_hdr->ar_pro != htons(ETH_P_IP) || (arp_hdr->ar_pln != 4) 
+      || (arp_hdr->ar_hln != src_pk.sll_halen) 
+      || (*recv_len < (int)(sizeof(*arp_hdr) + 2 * (4 + arp_hdr->ar_hln))))
+    return; 
+
+  memcpy(&s_ip.s_addr, p + arp_hdr->ar_hln, 4);
+  memcpy(&d_ip.s_addr, p + arp_hdr->ar_hln + 4 + arp_hdr->ar_hln, 4); 
+
+  if (dest_addr.s_addr != s_ip.s_addr) return;
+  if (toys.optflags & FLAG_D) {
+    if (src_addr.s_addr && src_addr.s_addr != d_ip.s_addr) return;
+    if (!memcmp(p, &src_pk.sll_addr, src_pk.sll_halen)) return;
+  } else if (src_addr.s_addr != d_ip.s_addr ) return;
+
+  if (!(toys.optflags & FLAG_q)) {
+    printf("%scast re%s from %s [%s]",
+        from->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
+        arp_hdr->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
+        inet_ntoa(s_ip), ether_ntoa((struct ether_addr *) p));
+    if (TT.sent_at) {  
+      unsigned delta;
+      struct timeval tval;
+
+      gettimeofday(&tval, NULL);
+      delta = (tval.tv_sec * 1000000ULL + (tval.tv_usec)) - TT.sent_at;
+      xprintf(" %u.%03ums\n", delta / 1000, delta % 1000);
+      xflush();
+    }
+  }
+  TT.rcvd_nr++;
+  if (from->sll_pkttype != PACKET_HOST) TT.brd_rcv++;
+  if (arp_hdr->ar_op == htons(ARPOP_REQUEST)) TT.rcvd_req++;
+  if (toys.optflags & FLAG_f) done(0);
+  if (!(toys.optflags & FLAG_b)) {
+    memcpy(dst_pk.sll_addr, p, src_pk.sll_halen);
+    TT.unicast_flag = 1;
+  }
+}
+
+// Alarm signal Handle, send packets in one second interval.
+static void send_signal(int sig)
+{
+  struct timeval start;
+
+  gettimeofday(&start, NULL);
+  if (!TT.start) 
+    TT.end = TT.start = start.tv_sec * 1000 + start.tv_usec / 1000;
+  else TT.end = start.tv_sec*1000 + start.tv_usec / 1000;
+  if (toys.optflags & FLAG_c) {
+    if (!TT.count) done(0);
+    TT.count--; 
+  }
+  if ((toys.optflags & FLAG_w) && ((TT.end - TT.start) > 
+        ((TT.time_out)*1000))) done(0);
+  send_packet();
+  alarm(1);
+}
+
+void arping_main(void)
+{
+  struct ifreq ifr;
+  struct sockaddr_ll from;
+  socklen_t len;
+  int if_index, recv_len;
+
+  if (!(toys.optflags & FLAG_I)) TT.iface = "eth0";
+  TT.sockfd = xsocket(AF_PACKET, SOCK_DGRAM, 0);
+
+  memset(&ifr, 0, sizeof(ifr));
+  xstrncpy(ifr.ifr_name, TT.iface, IFNAMSIZ);
+  get_interface(TT.iface, &if_index, NULL, NULL);
+  src_pk.sll_ifindex = if_index;
+
+  xioctl(TT.sockfd, SIOCGIFFLAGS, (char*)&ifr);
+  if (!(ifr.ifr_flags & IFF_UP) && !(toys.optflags & FLAG_q))
+    error_exit("Interface \"%s\" is down", TT.iface);
+  if ((ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK))
+      && !(toys.optflags & FLAG_q)) {
+    xprintf("Interface \"%s\" is not ARPable\n", TT.iface);
+    toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2;
+    return;
+  }
+  if (!inet_aton(*toys.optargs, &dest_addr)) {
+    struct hostent *hp = gethostbyname2(*toys.optargs, AF_INET);
+
+    if (!hp) perror_exit("bad address '%s'", *toys.optargs);
+    memcpy(&dest_addr, hp->h_addr, 4);
+  }
+  if ((toys.optflags & FLAG_s) && !(inet_aton(TT.src_ip, &src_addr))) 
+    perror_exit("invalid source address '%s'",TT.src_ip);
+  if (!(toys.optflags & FLAG_D) && (toys.optflags & FLAG_U) 
+      && !src_addr.s_addr) src_addr = dest_addr;
+  if (!(toys.optflags & FLAG_D) || src_addr.s_addr) {
+    struct sockaddr_in saddr;
+    int p_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
+
+    if (setsockopt(p_fd, SOL_SOCKET, SO_BINDTODEVICE, TT.iface,
+          strlen(TT.iface))) perror_exit("setsockopt");
+
+    memset(&saddr, 0, sizeof(saddr));
+    saddr.sin_family = AF_INET;
+    if (src_addr.s_addr) {
+      saddr.sin_addr = src_addr;
+      if (bind(p_fd, (struct sockaddr*)&saddr, sizeof(saddr))) 
+        perror_exit("bind");
+    } else {
+      uint32_t oip;
+
+      saddr.sin_port = htons(1025);
+      saddr.sin_addr = dest_addr;
+      if (connect(p_fd, (struct sockaddr *) &saddr, sizeof(saddr)))
+        perror_exit("cannot connect to remote host");
+      get_interface(TT.iface, NULL, &oip, NULL);
+      src_addr.s_addr = htonl(oip);
+    }
+    xclose(p_fd);
+  }
+
+  src_pk.sll_family = AF_PACKET;
+  src_pk.sll_protocol = htons(ETH_P_ARP);
+  if (bind(TT.sockfd, (struct sockaddr *)&src_pk, sizeof(src_pk))) 
+    perror_exit("bind");
+
+  socklen_t alen = sizeof(src_pk);
+  getsockname(TT.sockfd, (struct sockaddr *)&src_pk, &alen);
+  if (!src_pk.sll_halen) {
+    perror_msg("src is not arpable");
+    toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2;
+    return;
+  }
+  if (!(toys.optflags & FLAG_q)) {
+    xprintf("ARPING to %s", inet_ntoa(dest_addr));
+    xprintf(" from %s via %s\n", inet_ntoa(src_addr), TT.iface);
+  }
+
+  dst_pk = src_pk;
+  //First packet always broadcasts.
+  memset(dst_pk.sll_addr, -1, dst_pk.sll_halen);
+  signal(SIGINT, done);
+  signal(SIGALRM, send_signal);
+
+  send_signal(0); // Send first Broadcast message.
+  while (1) {
+    len = sizeof(from);
+    recv_len = recvfrom(TT.sockfd, toybuf, 4096, 0,
+        (struct sockaddr *)&from, &len);
+    if (recv_len < 0) continue;
+    recv_from(&from, &recv_len);
+  }
+}
diff --git a/toybox/toys/pending/bootchartd.c b/toybox/toys/pending/bootchartd.c
new file mode 100644
index 0000000..7e5a136
--- /dev/null
+++ b/toybox/toys/pending/bootchartd.c
@@ -0,0 +1,317 @@
+/* bootchartd.c - bootchartd is commonly used to profile the boot process.
+ *
+ * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gmail.com> 
+ *
+ * No Standard
+ 
+USE_BOOTCHARTD(NEWTOY(bootchartd, 0, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
+
+config BOOTCHARTD
+  bool "bootchartd"
+  default n
+  depends on TOYBOX_FORK
+  help
+    usage: bootchartd {start [PROG ARGS]}|stop|init
+
+    Create /var/log/bootlog.tgz with boot chart data
+
+    start: start background logging; with PROG, run PROG,
+           then kill logging with USR1
+    stop:  send USR1 to all bootchartd processes
+    init:  start background logging; stop when getty/xdm is seen
+          (for init scripts)
+
+    Under PID 1: as init, then exec $bootchart_init, /init, /sbin/init
+*/
+
+#define FOR_bootchartd
+#include "toys.h"
+
+GLOBALS(
+  char buf[32];
+  long smpl_period_usec;
+  int proc_accounting;
+  int is_login;
+
+  void *head;
+)
+
+struct pid_list {
+  struct pid_list *next, *prev;
+  int pid;
+};
+
+static int push_pids_in_list(pid_t pid, char *name)
+{
+  struct pid_list *new = xzalloc(sizeof(struct pid_list));
+
+  new->pid = pid;
+  dlist_add_nomalloc((void *)&TT.head, (void *)new);
+
+  return 0;
+}
+
+static void dump_data_in_file(char *fname, int wfd)
+{
+  int rfd = open(fname, O_RDONLY);
+
+  if (rfd != -1) {
+    xwrite(wfd, TT.buf, strlen(TT.buf));
+    xsendfile(rfd, wfd);
+    close(rfd);
+    xwrite(wfd, "\n", 1);
+  }
+}
+
+static int dump_proc_data(FILE *fp)
+{
+  struct dirent *pid_dir;
+  int login_flag = 0;
+  pid_t pid;
+  DIR *proc_dir = opendir("/proc");
+
+  fputs(TT.buf, fp);
+  while ((pid_dir = readdir(proc_dir))) {
+    char filename[64];
+    int fd;
+
+    if (!isdigit(pid_dir->d_name[0])) continue;
+    sscanf(pid_dir->d_name, "%d", &pid);
+    sprintf(filename, "/proc/%d/stat", pid);
+    if ((fd = open(filename, O_RDONLY)) != -1 ) {
+      char *ptr;
+      ssize_t len;
+
+      if ((len = readall(fd, toybuf, sizeof(toybuf)-1)) < 0) {
+        xclose(fd);
+        continue;
+      }
+      toybuf[len] = '\0';
+      close(fd);
+      fputs(toybuf, fp);
+      if (!TT.is_login) continue;
+      if ((ptr = strchr(toybuf, '('))) {
+        char *tmp = strchr(++ptr, ')');
+
+        if (tmp) *tmp = '\0';
+      }
+      // Checks for gdm, kdm or getty
+      if (((ptr[0] == 'g' || ptr[0] == 'k' || ptr[0] == 'x') && ptr[1] == 'd'
+            && ptr[2] == 'm') || strstr(ptr, "getty")) login_flag = 1;
+    }
+  }
+  closedir(proc_dir);
+  fputc('\n', fp);
+  return login_flag;
+}
+
+static int parse_config_file(char *fname)
+{
+  size_t len = 0;
+  char  *line = NULL;
+  FILE *fp = fopen(fname, "r");
+
+  if (!fp) return 0;
+  for (;getline(&line, &len, fp) != -1; line = NULL) {
+    char *ptr = line;
+
+    while (*ptr == ' ' || *ptr == '\t') ptr++;
+    if (!*ptr || *ptr == '#' || *ptr == '\n') continue;
+    if (!strncmp(ptr, "SAMPLE_PERIOD", strlen("SAMPLE_PERIOD"))) {
+      double smpl_val;
+
+      if ((ptr = strchr(ptr, '='))) ptr += 1;
+      else continue;
+      sscanf(ptr, "%lf", &smpl_val);
+      TT.smpl_period_usec = smpl_val * 1000000;
+      if (TT.smpl_period_usec <= 0) TT.smpl_period_usec = 1;
+    }
+    if (!strncmp(ptr, "PROCESS_ACCOUNTING", strlen("PROCESS_ACCOUNTING"))) {
+      if ((ptr = strchr(ptr, '='))) ptr += 1;
+      else continue;
+      sscanf(ptr, "%s", toybuf);  // string will come with double quotes.
+      if (!(strncmp(toybuf+1, "on", strlen("on"))) ||
+          !(strncmp(toybuf+1, "yes", strlen("yes")))) TT.proc_accounting = 1;
+    }
+    free(line);
+  }
+  fclose(fp);
+  return 1;
+}
+
+static char *create_tmp_dir()
+{
+  char *dir_list[] = {"/tmp", "/mnt", "/boot", "/proc"}, **target = dir_list;
+  char *dir, dir_path[] = "/tmp/bootchart.XXXXXX";
+
+  if ((dir = mkdtemp(dir_path))) {
+    xchdir((dir = xstrdup(dir)));
+    return dir;
+  }
+  while (mount("none", *target, "tmpfs", (1<<15), "size=16m")) //MS_SILENT
+    if (!++target) perror_exit("can't mount tmpfs");
+  xchdir(*target);
+  if (umount2(*target, MNT_DETACH)) perror_exit("Can't unmount tmpfs");
+  return *target;
+}
+
+static void start_logging()
+{
+  int proc_stat_fd = xcreate("proc_stat.log",  
+      O_WRONLY | O_CREAT | O_TRUNC, 0644);
+  int proc_diskstats_fd = xcreate("proc_diskstats.log",  
+      O_WRONLY | O_CREAT | O_TRUNC, 0644);
+  FILE *proc_ps_fp = xfopen("proc_ps.log", "w");
+  long tcnt = 60 * 1000 * 1000 / TT.smpl_period_usec;
+
+  if (tcnt <= 0) tcnt = 1;
+  if (TT.proc_accounting) {
+    int kp_fd = xcreate("kernel_procs_acct", O_WRONLY | O_CREAT | O_TRUNC,0666);
+
+    xclose(kp_fd);
+    acct("kernel_procs_acct");
+  }
+  memset(TT.buf, 0, sizeof(TT.buf));
+  while (--tcnt && !toys.signal) {
+    int i = 0, j = 0, fd = open("/proc/uptime", O_RDONLY);
+    if (fd < 0) goto wait_usec;
+    char *line = get_line(fd);
+
+    if (!line)  goto wait_usec;
+    while (line[i] != ' ') {
+      if (line[i] == '.') {
+        i++;
+        continue;
+      }
+      TT.buf[j++] = line[i++];
+    }
+    TT.buf[j++] = '\n';
+    TT.buf[j] = '\0';
+    free(line);
+    close(fd);
+    dump_data_in_file("/proc/stat", proc_stat_fd);
+    dump_data_in_file("/proc/diskstats", proc_diskstats_fd);
+    // stop proc dumping in 2 secs if getty or gdm, kdm, xdm found 
+    if (dump_proc_data(proc_ps_fp))
+      if (tcnt > 2 * 1000 * 1000 / TT.smpl_period_usec)
+        tcnt = 2 * 1000 * 1000 / TT.smpl_period_usec;
+    fflush(NULL);
+wait_usec:
+    usleep(TT.smpl_period_usec);
+  }
+  xclose(proc_stat_fd);
+  xclose(proc_diskstats_fd);
+  fclose(proc_ps_fp);
+}
+
+static void stop_logging(char *tmp_dir, char *prog)
+{
+  char host_name[32];
+  int kcmd_line_fd;
+  time_t t;
+  struct tm st;
+  struct utsname uts;
+  FILE *hdr_fp = xfopen("header", "w");
+
+  if (TT.proc_accounting) acct(NULL);
+  if (prog) fprintf(hdr_fp, "profile.process = %s\n", prog);
+  gethostname(host_name, sizeof(host_name));
+  time(&t);
+  localtime_r(&t, &st);
+  memset(toybuf, 0, sizeof(toybuf));
+  strftime(toybuf, sizeof(toybuf), "%a %b %e %H:%M:%S %Z %Y", &st);
+  fprintf(hdr_fp, "version = TBX_BCHARTD_VER 1.0.0\n");
+  fprintf(hdr_fp, "title = Boot chart for %s (%s)\n", host_name, toybuf);
+  if (uname(&uts) < 0) perror_exit("uname");
+  fprintf(hdr_fp, "system.uname = %s %s %s %s\n", uts.sysname, uts.release,
+      uts.version, uts.machine);
+  memset(toybuf, 0, sizeof(toybuf));
+  if ((kcmd_line_fd = open("/proc/cmdline", O_RDONLY)) != -1) {
+    ssize_t len;
+
+    if ((len = readall(kcmd_line_fd, toybuf, sizeof(toybuf)-1)) > 0) {
+      toybuf[len] = 0;
+      while (--len >= 0 && !toybuf[len]) continue;
+      for (; len > 0; len--) if (toybuf[len] < ' ') toybuf[len] = ' ';
+    } else *toybuf = 0;
+  }
+  fprintf(hdr_fp, "system.kernel.options = %s", toybuf);
+  close(kcmd_line_fd);
+  fclose(hdr_fp);
+  memset(toybuf, 0, sizeof(toybuf));
+  snprintf(toybuf, sizeof(toybuf), "tar -zcf /var/log/bootlog.tgz header %s *.log", 
+      TT.proc_accounting ? "kernel_procs_acct" : "");
+  system(toybuf);
+  if (tmp_dir) {
+    unlink("header");
+    unlink("proc_stat.log");
+    unlink("proc_diskstats.log");
+    unlink("proc_ps.log");
+    if (TT.proc_accounting) unlink("kernel_procs_acct");
+    rmdir(tmp_dir);
+  }
+}
+
+void bootchartd_main()
+{
+  pid_t lgr_pid, self_pid = getpid();
+  int bchartd_opt = 0; // 0=PID1, 1=start, 2=stop, 3=init
+  TT.smpl_period_usec = 200 * 1000;
+
+  TT.is_login = (self_pid == 1);
+  if (*toys.optargs) {
+    if (!strcmp("start", *toys.optargs)) bchartd_opt = 1;
+    else if (!strcmp("stop", *toys.optargs)) bchartd_opt = 2;
+    else if (!strcmp("init", *toys.optargs)) bchartd_opt = 3;
+    else error_exit("Unknown option '%s'", *toys.optargs);
+
+    if (bchartd_opt == 2) {
+      struct pid_list *temp;
+      char *process_name[] = {"bootchartd", NULL};
+
+      names_to_pid(process_name, push_pids_in_list);
+      temp = TT.head;
+      if (temp) temp->prev->next = 0;
+      for (; temp; temp = temp->next) 
+        if (temp->pid != self_pid) kill(temp->pid, SIGUSR1);
+      llist_traverse(TT.head, free);
+
+      return;
+    }
+  } else if (!TT.is_login) error_exit("not PID 1");
+
+  // Execute the code below for start or init or PID1 
+  if (!parse_config_file("bootchartd.conf"))
+    parse_config_file("/etc/bootchartd.conf");
+
+  memset(toybuf, 0, sizeof(toybuf));
+  if (!(lgr_pid = xfork())) {
+    char *tmp_dir = create_tmp_dir();
+
+    sigatexit(generic_signal);
+    raise(SIGSTOP);
+    if (!bchartd_opt && !getenv("PATH")) 
+      putenv("PATH=/sbin:/usr/sbin:/bin:/usr/bin");
+    start_logging();
+    stop_logging(tmp_dir, bchartd_opt == 1 ? toys.optargs[1] : NULL);
+    return;
+  } 
+  waitpid(lgr_pid, NULL, WUNTRACED);
+  kill(lgr_pid, SIGCONT);
+
+  if (!bchartd_opt) { 
+    char *pbchart_init = getenv("bootchart_init");
+
+    if (pbchart_init) execl(pbchart_init, pbchart_init, NULL);
+    execl("/init", "init", (void *)0);
+    execl("/sbin/init", "init", (void *)0);
+  }
+  if (bchartd_opt == 1 && toys.optargs[1]) { 
+    pid_t prog_pid;
+
+    if (!(prog_pid = xfork())) xexec(toys.optargs+1);
+    waitpid(prog_pid, NULL, 0);
+    kill(lgr_pid, SIGUSR1);
+  }
+}
diff --git a/toybox/toys/pending/brctl.c b/toybox/toys/pending/brctl.c
new file mode 100644
index 0000000..6017851
--- /dev/null
+++ b/toybox/toys/pending/brctl.c
@@ -0,0 +1,333 @@
+/* brctl.c - ethernet bridge control
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+
+USE_BRCTL(NEWTOY(brctl, "<1", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config BRCTL
+  bool "brctl"
+  default n
+  help
+    usage: brctl COMMAND [BRIDGE [INTERFACE]]
+
+    Manage ethernet bridges
+
+    Commands:
+    show                  Show a list of bridges
+    addbr BRIDGE          Create BRIDGE
+    delbr BRIDGE          Delete BRIDGE
+    addif BRIDGE IFACE    Add IFACE to BRIDGE
+    delif BRIDGE IFACE    Delete IFACE from BRIDGE
+    setageing BRIDGE TIME Set ageing time
+    setfd BRIDGE TIME     Set bridge forward delay
+    sethello BRIDGE TIME  Set hello time
+    setmaxage BRIDGE TIME Set max message age
+    setpathcost BRIDGE PORT COST   Set path cost
+    setportprio BRIDGE PORT PRIO   Set port priority
+    setbridgeprio BRIDGE PRIO      Set bridge priority
+    stp BRIDGE [1/yes/on|0/no/off] STP on/off
+*/
+
+#define FOR_brctl
+#include "toys.h"
+#include <linux/if_bridge.h>
+
+GLOBALS(
+    int sockfd;
+)
+#define MAX_BRIDGES 1024 //same is no of ports supported
+
+static void get_ports(char *bridge, int *indices)
+{
+  struct ifreq ifr;                              
+  int ifindices[MAX_BRIDGES];
+  unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+    (unsigned long) ifindices, MAX_BRIDGES, 0 };
+
+  memset(ifindices, 0, MAX_BRIDGES);
+  args[1] = (unsigned long)ifindices;
+  xstrncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+  if (indices) memcpy(indices, ifindices, sizeof(ifindices));
+}
+
+void get_br_info(char *bridge, struct __bridge_info *info)
+{
+  struct ifreq ifr;
+  unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
+    (unsigned long) info, 0, 0 };
+
+  memset(info, 0, sizeof(*info));
+  xstrncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+
+  if (ioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr) < 0) {
+    perror_msg("%s: can't get info %s\n", bridge, strerror(errno));
+    return;
+  }
+}
+
+void br_show(char **argv)
+{
+  struct __bridge_info info;
+  int num, cnt, i, j, ifindices[MAX_BRIDGES], pindices[MAX_BRIDGES];
+  unsigned long args[4] = { BRCTL_GET_BRIDGES,
+    (unsigned long)ifindices, MAX_BRIDGES,0 };
+  char br[IF_NAMESIZE], ifn[IF_NAMESIZE];
+
+  num = ioctl(TT.sockfd, SIOCGIFBR, args); //ret is num of bridges found
+  if (num < 0) error_exit("get bridges fail");
+  printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
+
+  for (i = 0; i < num; i++) {
+    unsigned char *id;
+
+    if (!if_indextoname(ifindices[i], br)) perror_exit("interface not found");
+    get_br_info(br, &info);
+    id = (unsigned char*)&(info.bridge_id);
+    printf("%s\t\t",br);
+    printf("%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x", id[0], id[1], 
+        id[2], id[3], id[4], id[5], id[6], id[7]);
+    printf("\t%s\t\t",(info.stp_enabled)?"yes" : "no");
+
+    memset(pindices, 0, sizeof(pindices));
+    get_ports(br, pindices);
+    for (j = 0, cnt = 0; j < MAX_BRIDGES; j++) {
+      if (!pindices[j]) continue;
+      if (!if_indextoname(pindices[j], ifn)) {
+        error_msg("no name for index :%d", pindices[j]);
+        continue;
+      }
+      if (cnt) printf("\n\t\t\t\t\t\t\t");
+      printf("%s", ifn);
+      cnt++;
+    }
+    xputc('\n');
+  }
+}
+
+void br_addbr(char **argv)
+{
+  char br[IFNAMSIZ];                
+  unsigned long args[4] = {BRCTL_ADD_BRIDGE, (unsigned long) br, 0, 0};
+
+#ifdef SIOCBRADDBR
+  xioctl(TT.sockfd, SIOCBRADDBR, argv[0]);
+#else            
+  xstrncpy(br, argv[0], IFNAMSIZ);   
+  xioctl(TT.sockfd, SIOCSIFBR, args);
+#endif
+}
+
+void br_delbr(char **argv)
+{
+  char br[IFNAMSIZ];
+  unsigned long args[4] = {BRCTL_DEL_BRIDGE, (unsigned long) br, 0, 0};
+
+#ifdef SIOCBRDELBR
+  xioctl(TT.sockfd, SIOCBRDELBR, argv[0]);
+#else
+  xstrncpy(br, argv[0], IFNAMSIZ);
+  xioctl(TT.sockfd, SIOCSIFBR, args);
+#endif
+}
+
+void br_addif(char **argv)
+{
+  int index;
+  struct ifreq ifr;
+  unsigned long args[4] = {BRCTL_ADD_IF, 0, 0, 0};
+
+  if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s", argv[1]);
+#ifdef SIOCBRADDIF
+  ifr.ifr_ifindex = index;
+  xioctl(TT.sockfd, SIOCBRADDIF, &ifr);
+#else
+  args[1] = index;
+  xstrncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+#endif
+}
+
+void br_delif(char **argv)
+{
+  int index;                             
+  struct ifreq ifr;                      
+  unsigned long args[4] = {BRCTL_DEL_IF, 0, 0, 0};
+
+  if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s",argv[1]);
+#ifdef SIOCBRDELIF
+  ifr.ifr_ifindex = ifindex;
+  xioctl(TT.sockfd, SIOCBRDELIF, &ifr);
+#else
+  args[1] = index;     
+  xstrncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
+  ifr.ifr_data = (char *)args;  
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+#endif
+}
+
+static void strtotimeval(struct timeval *tv, char *time)
+{
+  double secs;
+
+  if (sscanf(time, "%lf", &secs) != 1) error_exit("time format not proper");
+  tv->tv_sec = secs;
+  tv->tv_usec = 1000000 * (secs - tv->tv_sec);
+}
+
+static unsigned long tv_to_jify(struct timeval *tv)
+{                       
+  unsigned long long jify;
+
+  jify = 1000000ULL * tv->tv_sec + tv->tv_usec;
+  return (jify/10000);
+}                  
+
+void set_time(char *br, unsigned long cmd, unsigned long val)
+{
+  struct ifreq ifr;
+  unsigned long args[4] = {cmd, val, 0, 0};
+
+  xstrncpy(ifr.ifr_name, br, IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+}
+
+void br_set_ageing_time(char **argv)     
+{
+  struct timeval tv;
+
+  strtotimeval(&tv, argv[1]);
+  set_time(argv[0], BRCTL_SET_AGEING_TIME, tv_to_jify(&tv));
+}
+
+void br_set_fwd_delay(char **argv)
+{
+  struct timeval tv;
+
+  strtotimeval(&tv, argv[1]);
+  set_time(argv[0], BRCTL_SET_BRIDGE_FORWARD_DELAY, tv_to_jify(&tv));
+}
+
+void br_set_hello_time(char **argv)
+{
+  struct timeval tv;                        
+
+  strtotimeval(&tv, argv[1]);               
+  set_time(argv[0], BRCTL_SET_BRIDGE_HELLO_TIME, tv_to_jify(&tv));
+}
+
+void br_set_max_age(char **argv)
+{
+  struct timeval tv;                        
+
+  strtotimeval(&tv, argv[1]);               
+  set_time(argv[0], BRCTL_SET_BRIDGE_MAX_AGE, tv_to_jify(&tv));
+}
+
+void br_set_bridge_prio(char **argv)
+{
+  int prio;
+
+  if (sscanf(argv[1], "%i", &prio) != 1) error_exit("prio not proper");
+  set_time(argv[0], BRCTL_SET_BRIDGE_PRIORITY, prio);
+}
+
+void br_set_stp(char **argv)
+{
+  int i;
+  struct stp {
+    char *n;
+    int set;
+  } ss[] = {{"1", 1}, {"yes", 1},{"on", 1},
+    {"0", 0}, {"no", 0},{"off", 0}};
+
+  for (i = 0; i < ARRAY_LEN(ss); i++) {
+    if (!strcmp(ss[i].n, argv[1])) break;
+  }
+  if (i >= ARRAY_LEN(ss)) error_exit("invalid stp state");
+  set_time(argv[0], BRCTL_SET_BRIDGE_STP_STATE, ss[i].set);
+}
+
+void set_cost_prio(char *br, char *port, unsigned long cmd, unsigned long val)
+{
+  struct ifreq ifr;
+  int i, index, pindices[MAX_BRIDGES];
+  unsigned long args[4] = {cmd, 0, val, 0};
+  
+  if (!(index = if_nametoindex(port))) error_exit("invalid port");
+  
+  memset(pindices, 0, sizeof(pindices));
+  get_ports(br, pindices);
+  for (i = 0; i < MAX_BRIDGES; i++) {
+    if (index == pindices[i]) break;
+  }
+  if (i >= MAX_BRIDGES) error_exit("%s not in bridge", port);
+  args[1] = i;
+  xstrncpy(ifr.ifr_name, br, IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+}
+
+void br_set_path_cost(char **argv)
+{
+  int cost;
+
+  cost = atolx_range(argv[2], 0, INT_MAX);
+  set_cost_prio(argv[0], argv[1], BRCTL_SET_PATH_COST, cost);
+}
+
+void br_set_port_prio(char **argv)
+{ 
+  int prio;
+
+  prio = atolx_range(argv[2], 0, INT_MAX);
+  set_cost_prio(argv[0], argv[1], BRCTL_SET_PORT_PRIORITY, prio);
+
+}
+
+void brctl_main(void)
+{
+  int i;
+  struct cmds {
+    char *cmd;
+    int nargs;
+    void (*f)(char **argv);
+  } cc[] = {{"show", 0, br_show},
+    {"addbr", 1, br_addbr}, {"delbr", 1, br_delbr},
+    {"addif", 2, br_addif}, {"delif", 2, br_delif},
+    {"setageing", 2, br_set_ageing_time},
+    {"setfd", 2, br_set_fwd_delay},
+    {"sethello", 2, br_set_hello_time},
+    {"setmaxage", 2, br_set_max_age},
+    {"setpathcost", 3, br_set_path_cost},
+    {"setportprio", 3, br_set_port_prio},
+    {"setbridgeprio", 2, br_set_bridge_prio},
+    {"stp", 2, br_set_stp},
+  };
+
+  TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
+  while (*toys.optargs) {
+    for (i = 0; i < ARRAY_LEN(cc); i++) {
+      struct cmds *t = cc + i;
+
+      if (strcmp(t->cmd, *toys.optargs)) continue;
+
+      toys.optargs++, toys.optc--;
+      if (toys.optc < t->nargs) help_exit("check args");
+      t->f(toys.optargs);
+      toys.optargs += t->nargs;
+      toys.optc -= t->nargs;
+      break;
+    }
+
+    if (i == ARRAY_LEN(cc)) help_exit("invalid option '%s'", *toys.optargs);
+  }
+  xclose(TT.sockfd);
+}
diff --git a/toybox/toys/pending/compress.c b/toybox/toys/pending/compress.c
new file mode 100644
index 0000000..1749ee4
--- /dev/null
+++ b/toybox/toys/pending/compress.c
@@ -0,0 +1,606 @@
+/* compress.c - deflate/inflate code for zip, gzip, zlib, and raw
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * The inflate/deflate code lives here, so the various things that use it
+ * either live here or call these commands to pipe data through them.
+ *
+ * Divergence from posix: replace obsolete/patented "compress" with mutiplexer.
+ * (gzip already replaces "uncompress".)
+ *
+ * See RFCs 1950 (zlib), 1951 (deflate), and 1952 (gzip)
+ * LSB 4.1 has gzip, gunzip, and zcat
+ * TODO: zip -d DIR -x LIST -list -quiet -no overwrite -overwrite -p to stdout
+
+// Accept many different kinds of command line argument.
+// Leave Lrg at end so flag values line up.
+
+USE_COMPRESS(NEWTOY(compress, "zcd9lrg[-cd][!zgLr]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_GZIP(NEWTOY(gzip, USE_GZIP_D("d")"19dcflqStvgLRz[!gLRz]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_ZCAT(NEWTOY(zcat, 0, TOYFLAG_USR|TOYFLAG_BIN))
+USE_GUNZIP(NEWTOY(gunzip, "cflqStv", TOYFLAG_USR|TOYFLAG_BIN))
+
+//zip unzip gzip gunzip zcat
+
+config COMPRESS
+  bool "compress"
+  default n
+  help
+    usage: compress [-zgLR19] [FILE]
+
+    Compress or decompress file (or stdin) using "deflate" algorithm.
+
+    -1	min compression
+    -9	max compression (default)
+    -g	gzip (default)
+    -L	zlib
+    -R	raw
+    -z	zip
+
+config GZIP
+  bool "gzip"
+  default y
+  depends on COMPRESS
+  help
+    usage: gzip [-19cfqStvzgLR] [FILE...]
+
+    Compess (deflate) file(s). With no files, compress stdin to stdout.
+
+    On successful decompression, compressed files are replaced with the
+    uncompressed version. The input file is removed and replaced with
+    a new file without the .gz extension (with same ownership/permissions).
+
+    -1	Minimal compression (fastest)
+    -9	Max compression (default)
+    -c	cat to stdout (act as zcat)
+    -f	force (if output file exists, input is tty, unrecognized extension)
+    -q	quiet (no warnings)
+    -S	specify exension (default .*)
+    -t	test compressed file(s)
+    -v	verbose (like -l, but compress files)
+
+    Compression type:
+    -g gzip (default)    -L zlib    -R raw    -z zip
+
+config GZIP_D
+  bool
+  default y
+  depends on GZIP && DECOMPRESS
+  help
+    usage: gzip [-d]
+
+    -d	decompress (act as gunzip)
+
+config DECOMPRESS
+  bool "decompress"
+  default n
+  help
+    usage: compress [-zglrcd9] [FILE]
+
+    Compress or decompress file (or stdin) using "deflate" algorithm.
+
+    -c	compress with -g gzip (default)  -l zlib  -r raw  -z zip
+    -d	decompress (autodetects type)
+
+
+config ZCAT
+  bool "zcat"
+  default y
+  depends on DECOMPRESS
+  help
+    usage: zcat [FILE...]
+
+    Decompress deflated file(s) to stdout
+
+config GUNZIP
+  bool "gunzip"
+  default y
+  depends on DECOMPRESS
+  help
+    usage: gunzip [-cflqStv] [FILE...]
+
+    Decompess (deflate) file(s). With no files, compress stdin to stdout.
+
+    On successful decompression, compressed files are replaced with the
+    uncompressed version. The input file is removed and replaced with
+    a new file without the .gz extension (with same ownership/permissions).
+
+    -c	cat to stdout (act as zcat)
+    -f	force (output file exists, input is tty, unrecognized extension)
+    -l	list compressed/uncompressed/ratio/name for each input file.
+    -q	quiet (no warnings)
+    -S	specify exension (default .*)
+    -t	test compressed file(s)
+    -v	verbose (like -l, but decompress files)
+*/
+
+#define FOR_compress
+#include "toys.h"
+
+GLOBALS(
+  // Huffman codes: base offset and extra bits tables (length and distance)
+  char lenbits[29], distbits[30];
+  unsigned short lenbase[29], distbase[30];
+  void *fixdisthuff, *fixlithuff;
+
+  // CRC
+  void (*crcfunc)(char *data, int len);
+  unsigned crc;
+
+  // Compressed data buffer
+  char *data;
+  unsigned pos, len;
+  int infd, outfd;
+
+  // Tables only used for deflation
+  unsigned short *hashhead, *hashchain;
+)
+
+// little endian bit buffer
+struct bitbuf {
+  int fd, bitpos, len, max;
+  char buf[];
+};
+
+// malloc a struct bitbuf
+struct bitbuf *bitbuf_init(int fd, int size)
+{
+  struct bitbuf *bb = xzalloc(sizeof(struct bitbuf)+size);
+
+  bb->max = size;
+  bb->fd = fd;
+
+  return bb;
+}
+
+// Advance bitpos without the overhead of recording bits
+void bitbuf_skip(struct bitbuf *bb, int bits)
+{
+  int pos = bb->bitpos + bits, len = bb->len << 3;
+
+  while (pos >= len) {
+    pos -= len;
+    len = (bb->len = read(bb->fd, bb->buf, bb->max)) << 3;
+    if (bb->len < 1) perror_exit("inflate EOF");
+  }
+  bb->bitpos = pos;
+}
+
+// Optimized single bit inlined version
+static inline int bitbuf_bit(struct bitbuf *bb)
+{
+  int bufpos = bb->bitpos>>3;
+
+  if (bufpos == bb->len) {
+    bitbuf_skip(bb, 0);
+    bufpos = 0;
+  }
+
+  return (bb->buf[bufpos]>>(bb->bitpos++&7))&1;
+}
+
+// Fetch the next X bits from the bitbuf, little endian
+unsigned bitbuf_get(struct bitbuf *bb, int bits)
+{
+  int result = 0, offset = 0;
+
+  while (bits) {
+    int click = bb->bitpos >> 3, blow, blen;
+
+    // Load more data if buffer empty
+    if (click == bb->len) bitbuf_skip(bb, click = 0);
+
+    // grab bits from next byte
+    blow = bb->bitpos & 7;
+    blen = 8-blow;
+    if (blen > bits) blen = bits;
+    result |= ((bb->buf[click] >> blow) & ((1<<blen)-1)) << offset;
+    offset += blen;
+    bits -= blen;
+    bb->bitpos += blen;
+  }
+
+  return result;
+}
+
+void bitbuf_flush(struct bitbuf *bb)
+{
+  if (!bb->bitpos) return;
+
+  xwrite(bb->fd, bb->buf, (bb->bitpos+7)/8);
+  memset(bb->buf, 0, bb->max);
+  bb->bitpos = 0;
+}
+
+void bitbuf_put(struct bitbuf *bb, int data, int len)
+{
+  while (len) {
+    int click = bb->bitpos >> 3, blow, blen;
+
+    // Flush buffer if necessary
+    if (click == bb->max) {
+      bitbuf_flush(bb);
+      click = 0;
+    }
+    blow = bb->bitpos & 7;
+    blen = 8-blow;
+    if (blen > len) blen = len;
+    bb->buf[click] |= data << blow;
+    bb->bitpos += blen;
+    data >>= blen;
+    len -= blen;
+  }
+}
+
+static void output_byte(char sym)
+{
+  int pos = TT.pos++ & 32767;
+
+  TT.data[pos] = sym;
+
+  if (!pos) {
+    xwrite(TT.outfd, TT.data, 32768);
+    if (TT.crcfunc) TT.crcfunc(TT.data, 32768);
+  }
+}
+
+// Huffman coding uses bits to traverse a binary tree to a leaf node,
+// By placing frequently occurring symbols at shorter paths, frequently
+// used symbols may be represented in fewer bits than uncommon symbols.
+
+struct huff {
+  unsigned short length[16];
+  unsigned short symbol[288];
+};
+
+// Create simple huffman tree from array of bit lengths.
+
+// The symbols in the huffman trees are sorted (first by bit length
+// of the code to reach them, then by symbol number). This means that given
+// the bit length of each symbol, we can construct a unique tree.
+static void len2huff(struct huff *huff, char bitlen[], int len)
+{
+  int offset[16];
+  int i;
+
+  // Count number of codes at each bit length
+  memset(huff, 0, sizeof(struct huff));
+  for (i = 0; i<len; i++) huff->length[bitlen[i]]++;
+
+  // Sort symbols by bit length. (They'll remain sorted by symbol within that.)
+  *huff->length = *offset = 0;
+  for (i = 1; i<16; i++) offset[i] = offset[i-1] + huff->length[i-1];
+
+  for (i = 0; i<len; i++) if (bitlen[i]) huff->symbol[offset[bitlen[i]]++] = i;
+}
+
+// Fetch and decode next huffman coded symbol from bitbuf.
+// This takes advantage of the sorting to navigate the tree as an array:
+// each time we fetch a bit we have all the codes at that bit level in
+// order with no gaps.
+static unsigned huff_and_puff(struct bitbuf *bb, struct huff *huff)
+{
+  unsigned short *length = huff->length;
+  int start = 0, offset = 0;
+
+  // Traverse through the bit lengths until our code is in this range
+  for (;;) {
+    offset = (offset << 1) | bitbuf_bit(bb);
+    start += *++length;
+    if ((offset -= *length) < 0) break;
+    if ((length - huff->length) & 16) error_exit("bad symbol");
+  }
+
+  return huff->symbol[start + offset];
+}
+
+// Decompress deflated data from bitbuf to TT.outfd.
+static void inflate(struct bitbuf *bb)
+{
+  TT.crc = ~0;
+  // repeat until spanked
+  for (;;) {
+    int final, type;
+
+    final = bitbuf_get(bb, 1);
+    type = bitbuf_get(bb, 2);
+
+    if (type == 3) error_exit("bad type");
+
+    // Uncompressed block?
+    if (!type) {
+      int len, nlen;
+
+      // Align to byte, read length
+      bitbuf_skip(bb, (8-bb->bitpos)&7);
+      len = bitbuf_get(bb, 16);
+      nlen = bitbuf_get(bb, 16);
+      if (len != (0xffff & ~nlen)) error_exit("bad len");
+
+      // Dump literal output data
+      while (len) {
+        int pos = bb->bitpos >> 3, bblen = bb->len - pos;
+        char *p = bb->buf+pos;
+
+        // dump bytes until done or end of current bitbuf contents
+        if (bblen > len) bblen = len;
+        pos = bblen;
+        while (pos--) output_byte(*(p++));
+        bitbuf_skip(bb, bblen << 3);
+        len -= bblen;
+      }
+
+    // Compressed block
+    } else {
+      struct huff *disthuff, *lithuff;
+
+      // Dynamic huffman codes?
+      if (type == 2) {
+        struct huff *h2 = ((struct huff *)toybuf)+1;
+        int i, litlen, distlen, hufflen;
+        char *hufflen_order = "\x10\x11\x12\0\x08\x07\x09\x06\x0a\x05\x0b"
+                              "\x04\x0c\x03\x0d\x02\x0e\x01\x0f", *bits;
+
+        // The huffman trees are stored as a series of bit lengths
+        litlen = bitbuf_get(bb, 5)+257;  // max 288
+        distlen = bitbuf_get(bb, 5)+1;   // max 32
+        hufflen = bitbuf_get(bb, 4)+4;   // max 19
+
+        // The literal and distance codes are themselves compressed, in
+        // a complicated way: an array of bit lengths (hufflen many
+        // entries, each 3 bits) is used to fill out an array of 19 entries
+        // in a magic order, leaving the rest 0. Then make a tree out of it:
+        memset(bits = toybuf+1, 0, 19);
+        for (i=0; i<hufflen; i++) bits[hufflen_order[i]] = bitbuf_get(bb, 3);
+        len2huff(h2, bits, 19);
+
+        // Use that tree to read in the literal and distance bit lengths
+        for (i = 0; i < litlen + distlen;) {
+          int sym = huff_and_puff(bb, h2);
+
+          // 0-15 are literals, 16 = repeat previous code 3-6 times,
+          // 17 = 3-10 zeroes (3 bit), 18 = 11-138 zeroes (7 bit)
+          if (sym < 16) bits[i++] = sym;
+          else {
+            int len = sym & 2;
+
+            len = bitbuf_get(bb, sym-14+len+(len>>1)) + 3 + (len<<2);
+            memset(bits+i, bits[i-1] * !(sym&3), len);
+            i += len;
+          }
+        }
+        if (i > litlen+distlen) error_exit("bad tree");
+
+        len2huff(lithuff = h2, bits, litlen);
+        len2huff(disthuff = ((struct huff *)toybuf)+2, bits+litlen, distlen);
+
+      // Static huffman codes
+      } else {
+        lithuff = TT.fixlithuff;
+        disthuff = TT.fixdisthuff;
+      }
+
+      // Use huffman tables to decode block of compressed symbols
+      for (;;) {
+        int sym = huff_and_puff(bb, lithuff);
+
+        // Literal?
+        if (sym < 256) output_byte(sym);
+
+        // Copy range?
+        else if (sym > 256) {
+          int len, dist;
+
+          sym -= 257;
+          len = TT.lenbase[sym] + bitbuf_get(bb, TT.lenbits[sym]);
+          sym = huff_and_puff(bb, disthuff);
+          dist = TT.distbase[sym] + bitbuf_get(bb, TT.distbits[sym]);
+          sym = TT.pos & 32767;
+
+          while (len--) output_byte(TT.data[(TT.pos-dist) & 32767]);
+
+        // End of block
+        } else break;
+      }
+    }
+
+    // Was that the last block?
+    if (final) break;
+  }
+
+  if (TT.pos & 32767) {
+    xwrite(TT.outfd, TT.data, TT.pos & 32767);
+    if (TT.crcfunc) TT.crcfunc(TT.data, TT.pos & 32767);
+  }
+}
+
+// Deflate from TT.infd to bitbuf
+// For deflate, TT.len = input read, TT.pos = input consumed
+static void deflate(struct bitbuf *bb)
+{
+  char *data = TT.data;
+  int len, final = 0;
+
+  TT.crc = ~0;
+
+  while (!final) {
+    // Read next half-window of data if we haven't hit EOF yet.
+    len = readall(TT.infd, data+(TT.len&32768), 32768);
+    if (len < 0) perror_exit("read"); // todo: add filename
+    if (len != 32768) final++;
+    if (TT.crcfunc) TT.crcfunc(data+(TT.len&32768), len);
+    // TT.len += len;  crcfunc advances len
+
+    // store block as literal
+    bitbuf_put(bb, final, 1);
+    bitbuf_put(bb, 0, 1);
+
+    bitbuf_put(bb, 0, (8-bb->bitpos)&7);
+    bitbuf_put(bb, len, 16);
+    bitbuf_put(bb, 0xffff & ~len, 16);
+
+    // repeat until spanked
+    while (TT.pos != TT.len) {
+      unsigned pos = TT.pos & 65535;
+
+      bitbuf_put(bb, data[pos], 8);
+
+      // need to refill buffer?
+      if (!(32767 & ++TT.pos) && !final) break;
+    }
+  }
+  bitbuf_flush(bb);
+}
+
+// Allocate memory for deflate/inflate.
+static void init_deflate(int compress)
+{
+  int i, n = 1;
+
+  // compress needs 64k data and 32k each for hashhead and hashchain.
+  // decompress just needs 32k data.
+  TT.data = xmalloc(32768*(compress ? 4 : 1));
+  if (compress) {
+    TT.hashhead = (unsigned short *)(TT.data + 65536);
+    TT.hashchain = (unsigned short *)(TT.data + 65536 + 32768);
+  }
+
+  // Calculate lenbits, lenbase, distbits, distbase
+  *TT.lenbase = 3;
+  for (i = 0; i<sizeof(TT.lenbits)-1; i++) {
+    if (i>4) {
+      if (!(i&3)) {
+        TT.lenbits[i]++;
+        n <<= 1;
+      }
+      if (i == 27) n--;
+      else TT.lenbits[i+1] = TT.lenbits[i];
+    }
+    TT.lenbase[i+1] = n + TT.lenbase[i];
+  }
+  n = 0;
+  for (i = 0; i<sizeof(TT.distbits); i++) {
+    TT.distbase[i] = 1<<n;
+    if (i) TT.distbase[i] += TT.distbase[i-1];
+    if (i>3 && !(i&1)) n++;
+    TT.distbits[i] = n;
+  }
+
+  // Init fixed huffman tables
+  for (i=0; i<288; i++) toybuf[i] = 8 + (i>143) - ((i>255)<<1) + (i>279);
+  len2huff(TT.fixlithuff = ((struct huff *)toybuf)+3, toybuf, 288);
+  memset(toybuf, 5, 30);
+  len2huff(TT.fixdisthuff = ((struct huff *)toybuf)+4, toybuf, 30);
+}
+
+// Return true/false whether we consumed a gzip header.
+static int is_gzip(struct bitbuf *bb)
+{
+  int flags;
+
+  // Confirm signature
+  if (bitbuf_get(bb, 24) != 0x088b1f || (flags = bitbuf_get(bb, 8)) > 31)
+    return 0;
+  bitbuf_skip(bb, 6*8);
+
+  // Skip extra, name, comment, header CRC fields
+  if (flags & 4) bitbuf_skip(bb, 16);
+  if (flags & 8) while (bitbuf_get(bb, 8));
+  if (flags & 16) while (bitbuf_get(bb, 8));
+  if (flags & 2) bitbuf_skip(bb, 16);
+
+  return 1;
+}
+
+void gzip_crc(char *data, int len)
+{
+  int i;
+  unsigned crc, *crc_table = (unsigned *)(toybuf+sizeof(toybuf)-1024);
+
+  crc = TT.crc;
+  for (i=0; i<len; i++) crc = crc_table[(crc^data[i])&0xff] ^ (crc>>8);
+  TT.crc = crc;
+  TT.len += len;
+}
+
+static void do_gzip(int fd, char *name)
+{
+  struct bitbuf *bb = bitbuf_init(1, sizeof(toybuf));
+
+  // Header from RFC 1952 section 2.2:
+  // 2 ID bytes (1F, 8b), gzip method byte (8=deflate), FLAG byte (none),
+  // 4 byte MTIME (zeroed), Extra Flags (2=maximum compression),
+  // Operating System (FF=unknown)
+ 
+  TT.infd = fd;
+  xwrite(bb->fd, "\x1f\x8b\x08\0\0\0\0\0\x02\xff", 10);
+
+  // Use last 1k of toybuf for little endian crc table
+  crc_init((unsigned *)(toybuf+sizeof(toybuf)-1024), 1);
+  TT.crcfunc = gzip_crc;
+
+  deflate(bb);
+
+  // tail: crc32, len32
+
+  bitbuf_put(bb, 0, (8-bb->bitpos)&7);
+  bitbuf_put(bb, ~TT.crc, 32);
+  bitbuf_put(bb, TT.len, 32);
+
+  bitbuf_flush(bb);
+  free(bb);
+}
+
+static void do_zcat(int fd, char *name)
+{
+  struct bitbuf *bb = bitbuf_init(fd, sizeof(toybuf));
+
+  if (!is_gzip(bb)) error_exit("not gzip");
+  TT.outfd = 1;
+
+  // Use last 1k of toybuf for little endian crc table
+  crc_init((unsigned *)(toybuf+sizeof(toybuf)-1024), 1);
+  TT.crcfunc = gzip_crc;
+
+  inflate(bb);
+
+  // tail: crc32, len32
+
+  bitbuf_skip(bb, (8-bb->bitpos)&7);
+  if (~TT.crc != bitbuf_get(bb, 32) || TT.len != bitbuf_get(bb, 32))
+    error_exit("bad crc");
+  free(bb);
+}
+
+// Parse many different kinds of command line argument:
+
+void compress_main(void)
+{
+  // todo: this
+  printf("hello world");
+}
+
+//#define CLEANUP_compress
+//#define FOR_zcat
+//#include "generated/flags.h"
+
+void zcat_main(void)
+{
+  init_deflate(0);
+
+  loopfiles(toys.optargs, do_zcat);
+}
+
+void gunzip_main(void)
+{
+  init_deflate(0);
+
+  loopfiles(toys.optargs, do_zcat);
+}
+
+void gzip_main(void)
+{
+  init_deflate(1);
+
+  loopfiles(toys.optargs, do_gzip);
+}
diff --git a/toybox/toys/pending/crond.c b/toybox/toys/pending/crond.c
new file mode 100644
index 0000000..df8b5f1
--- /dev/null
+++ b/toybox/toys/pending/crond.c
@@ -0,0 +1,682 @@
+/* crond.c - daemon to execute scheduled commands.
+ *
+ * Copyright 2014 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ *
+ * No Standard
+
+USE_CROND(NEWTOY(crond, "fbSl#<0=8d#<0L:c:[-bf][-LS][-ld]", TOYFLAG_USR|TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+
+config CROND
+  bool "crond"
+  default n
+  help
+    usage: crond [-fbS] [-l N] [-d N] [-L LOGFILE] [-c DIR]
+
+    A daemon to execute scheduled commands.
+
+    -b Background (default)
+    -c crontab dir
+    -d Set log level, log to stderr
+    -f Foreground
+    -l Set log level. 0 is the most verbose, default 8
+    -S Log to syslog (default)
+    -L Log to file
+*/
+
+#define FOR_crond
+#include "toys.h"
+
+GLOBALS(
+  char *crontabs_dir;
+  char *logfile;
+  int loglevel_d;
+  int loglevel;
+
+  time_t crontabs_dir_mtime;
+  uint8_t flagd;
+)
+
+typedef struct _var {
+  struct _var *next, *prev;
+  char *name, *val;
+} VAR;
+
+typedef struct _job {
+  struct _job *next, *prev;
+  char min[60], hour[24], dom[31], mon[12], dow[7], *cmd;
+  int isrunning, needstart, mailsize;
+  pid_t pid;
+} JOB;
+
+typedef struct _cronfile {
+  struct _cronfile *next, *prev;
+  struct double_list *job, *var;
+  char *username, *mailto;
+  int invalid;
+} CRONFILE;
+
+static char days[]={"sun""mon""tue""wed""thu""fri""sat"};
+static char months[]={"jan""feb""mar""apr""may""jun""jul"
+  "aug""sep""oct""nov""dec"};
+CRONFILE *gclist;
+
+#define LOG_EXIT 0
+#define LOG_LEVEL5 5
+#define LOG_LEVEL7 7
+#define LOG_LEVEL8 8
+#define LOG_LEVEL9 9 // warning
+#define LOG_ERROR 20
+
+static void loginfo(uint8_t loglevel, char *msg, ...)
+{
+  va_list s, d;
+
+  va_start(s, msg);
+  va_copy(d, s);
+  if (loglevel >= TT.loglevel) {
+    int used;
+    char *smsg;
+
+    if (!TT.flagd && TT.logfile) {
+      int fd = open(TT.logfile, O_WRONLY | O_CREAT | O_APPEND, 0666);
+      if (fd==-1) perror_msg("'%s", TT.logfile);
+      else {
+        dup2(fd, 2);
+        close(fd);
+      }
+    }
+    used = vsnprintf(NULL, 0, msg, d);
+    smsg = xzalloc(++used);
+    vsnprintf(smsg, used, msg, s);
+    if (TT.flagd || TT.logfile) {
+      fflush(NULL);
+      smsg[used-1] = '\n';
+      writeall((loglevel > 8) ? 2 : 1, smsg, used);
+    } else syslog((loglevel > 8) ? LOG_ERR : LOG_INFO, "%s", smsg);
+    free(smsg);
+  }
+  va_end(d);
+  va_end(s);
+  if (!loglevel) exit(20);
+}
+
+/*
+ * Names can also be used for the 'month' and 'day of week' fields
+ * (First three letters of the particular day or month).
+ */
+static int getindex(char *src, int size)
+{
+  int i;
+  char *field = (size == 12) ? months : days;
+
+  // strings are not allowed for min, hour and dom fields.
+  if (!(size == 7 || size == 12)) return -1;
+
+  for (i = 0; field[i]; i += 3) {
+    if (!strncasecmp(src, &field[i], 3))
+      return (i/3);
+  }
+  return -1;
+}
+
+// set elements of minute, hour, day of month, month and day of week arrays.
+static void fillarray(char *dst, int start, int end, int skip)
+{
+  int sk = 1;
+
+  if (end < 0) {
+    dst[start] = 1;
+    return;
+  }
+  if (!skip) skip = 1;
+  do {
+    if (!--sk) {
+      dst[start] = 1;
+      sk = skip;
+    }
+  } while (start++ != end);
+}
+
+static long getval(char *num, long low, long high)
+{
+  long val = strtol(num, &num, 10);
+
+  if (*num || (val < low) || (val > high)) return -1;
+  return val;
+}
+
+//static int parse_and_fillarray(char *dst, int size, char *src)
+static int parse_and_fillarray(char *dst, int min, int max, char *src)
+{
+  int start, end, skip = 0;
+  char *ptr = strchr(src, '/');
+
+  if (ptr) {
+    *ptr++ = 0;
+    if ((skip = getval(ptr, min, (min ? max: max-1))) < 0) goto ERROR;
+  }
+
+  if (*src == '-' || *src == ',') goto ERROR;
+  if (*src == '*') {
+    if (*(src+1)) goto ERROR;
+    fillarray(dst, 0, max-1, skip);
+  } else {
+    for (;;) {
+      char *ctoken = strsep(&src, ","), *dtoken;
+
+      if (!ctoken) break;
+      if (!*ctoken) goto ERROR;
+
+      // Get start position.
+      dtoken = strsep(&ctoken, "-");
+      if (isdigit(*dtoken)) {
+        if ((start = getval(dtoken, min, (min ? max : max-1))) < 0) goto ERROR;
+        start = min ? (start-1) : start;
+      } else if ((start = getindex(dtoken, max)) < 0) goto ERROR;
+
+      // Get end position.
+      if (!ctoken) end = -1; // e.g. N1,N2,N3
+      else if (*ctoken) {// e.g. N-M
+        if (isdigit(*ctoken)) {
+          if ((end = getval(ctoken, min, (min ? max : max-1))) < 0) goto ERROR;
+          end = min ? (end-1) : end;
+        } else if ((end = getindex(ctoken, max)) < 0) goto ERROR;
+        if (end == start) end = -1;
+      } else goto ERROR; // error condition 'N-'
+      fillarray(dst, start, end, skip);
+    }
+  }
+
+  if (TT.flagd && (TT.loglevel <= 5)) {
+    for (start = 0; start < max; start++)
+      fprintf(stderr, "%d", (unsigned char)dst[start]);
+    fputc('\n', stderr);
+  }
+  return 0;
+ERROR:
+  loginfo(LOG_LEVEL9, "parse error at %s", src);
+  return -1;
+}
+
+static char *omitspace(char *line)
+{
+  while (*line == ' ' || *line == '\t') line++;
+  return line;
+}
+
+static void parse_line(char *line, CRONFILE *cfile)
+{
+  int count = 0;
+  char *name, *val, *tokens[5] = {0,};
+  VAR *v;
+  JOB *j;
+
+  line = omitspace(line);
+  if (!*line || *line == '#') return;
+
+  /*
+   * TODO: Enhancement to support 8 special strings
+   * @reboot -> Run once at startup.
+   * @yearly -> Run once a year (0 0 1 1 *).
+   * @annually -> Same as above.
+   * @monthly -> Run once a month (0 0 1 * *).
+   * @weekly -> Run once a week (0 0 * * 0).
+   * @daily -> Run once a day (0 0 * * *).
+   * @midnight -> same as above.
+   * @hourly -> Run once an hour (0 * * * *).
+   */
+  if (*line == '@') return;
+  if (TT.flagd) loginfo(LOG_LEVEL5, "user:%s entry:%s", cfile->username, line);
+  while (count<5) {
+    int len = strcspn(line, " \t");
+
+    if (line[len]) line[len++] = '\0';
+    tokens[count++] = line;
+    line += len;
+    line = omitspace(line);
+    if (!*line) break;
+  }
+
+  switch (count) {
+    case 1: // form SHELL=/bin/sh
+      name = tokens[0];
+      if ((val = strchr(name, '='))) *val++ = 0;
+      if (!val || !*val) return;
+      break;
+    case 2: // form SHELL =/bin/sh or SHELL= /bin/sh
+      name = tokens[0];
+      if ((val = strchr(name, '='))) {
+        *val = 0;
+        val = tokens[1];
+      } else {
+        if (*(tokens[1]) != '=') return;
+        val = tokens[1] + 1;
+      }
+      if (!*val) return;
+      break;
+    case 3: // NAME = VAL
+      name = tokens[0];
+      val = tokens[2];
+      if (*(tokens[1]) != '=') return;
+      break;
+    case 5:
+      // don't have any cmd to execute.
+      if (!*line) return;
+      j = xzalloc(sizeof(JOB));
+
+      if (parse_and_fillarray(j->min, 0, sizeof(j->min), tokens[0]))
+        goto STOP_PARSING;
+      if (parse_and_fillarray(j->hour, 0, sizeof(j->hour), tokens[1]))
+        goto STOP_PARSING;
+      if (parse_and_fillarray(j->dom, 1, sizeof(j->dom), tokens[2]))
+        goto STOP_PARSING;
+      if (parse_and_fillarray(j->mon, 1, sizeof(j->mon), tokens[3]))
+        goto STOP_PARSING;
+      if (parse_and_fillarray(j->dow, 0, sizeof(j->dow), tokens[4]))
+        goto STOP_PARSING;
+      j->cmd = xstrdup(line);
+
+      if (TT.flagd) loginfo(LOG_LEVEL5, " command:%s", j->cmd);
+      dlist_add_nomalloc((struct double_list **)&cfile->job, (struct double_list *)j);
+      return;
+STOP_PARSING:
+      free(j);
+      return;
+    default: return;
+  }
+  if (!strcmp(name, "MAILTO")) cfile->mailto = xstrdup(val);
+  else {
+    v = xzalloc(sizeof(VAR));
+    v->name = xstrdup(name);
+    v->val = xstrdup(val);
+    dlist_add_nomalloc((struct double_list **)&cfile->var, (struct double_list *)v);
+  }
+}
+
+static void free_jobs(JOB **jlist)
+{
+  JOB *j = dlist_pop(jlist);
+  free(j->cmd);
+  free(j);
+}
+
+static void free_cronfile(CRONFILE **list)
+{
+  CRONFILE *l = dlist_pop(list);
+  VAR *v, *vnode = (VAR *)l->var;
+
+  if (l->username != l->mailto) free(l->mailto);
+  free(l->username);
+  while (vnode && (v = dlist_pop(&vnode))) {
+    free(v->name);
+    free(v->val);
+    free(v);
+  }
+  free(l);
+}
+
+/*
+ * Iterate all cronfiles to identify the completed jobs and freed them.
+ * If all jobs got completed for a cronfile, freed cronfile too.
+ */
+static void remove_completed_jobs()
+{
+  CRONFILE *lstart, *list = gclist;
+
+  lstart = list;
+  while (list) {
+    int delete = 1;
+    JOB *jstart, *jlist = (JOB *)list->job;
+
+    list->invalid = 1;
+    jstart = jlist;
+    while (jlist) {
+      jlist->isrunning = 0;
+      if (jlist->pid > 0) {
+        jlist->isrunning = 1;
+        delete = 0;
+        jlist = jlist->next;
+      } else {
+        if (jlist == jstart) { // if 1st node has to delete.
+          jstart = jstart->next;
+          free_jobs(&jlist);
+          continue;
+        } else free_jobs(&jlist);
+      }
+      if (jlist == jstart) break;
+    }
+    list->job = (struct double_list *)jlist;
+
+    if (delete) {
+      if (lstart == list) {
+        lstart = lstart->next;
+        free_cronfile(&list);
+        continue;
+      } else free_cronfile(&list);
+    }
+    list = list->next;
+    if (lstart == list) break;
+  }
+  gclist = list;
+}
+
+// Scan cronfiles and prepare the list of cronfiles with their jobs.
+static void scan_cronfiles()
+{
+  DIR *dp;
+  struct dirent *entry;
+
+  remove_completed_jobs();
+  if (chdir(TT.crontabs_dir)) loginfo(LOG_EXIT, "chdir(%s)", TT.crontabs_dir);
+  if (!(dp = opendir("."))) loginfo(LOG_EXIT, "chdir(%s)", ".");
+
+  while ((entry = readdir(dp))) {
+    int fd;
+    char *line;
+    CRONFILE *cfile;
+
+    if (entry->d_name[0] == '.' && (!entry->d_name[1] ||
+          (entry->d_name[1] == '.' && !entry->d_name[2]))) 
+      continue;
+
+    if (!getpwnam(entry->d_name)) {
+      loginfo(LOG_LEVEL7, "ignoring file '%s' (no such user)", entry->d_name);
+      continue;
+    }
+    if ((fd = open(entry->d_name, O_RDONLY)) < 0) continue;
+
+    // one node for each user
+    cfile = xzalloc(sizeof(CRONFILE));
+    cfile->username = xstrdup(entry->d_name);
+
+    for (; (line = get_line(fd)); free(line))
+      parse_line(line, cfile);
+
+    // If there is no job for a cron, remove the VAR list.
+    if (!cfile->job) {
+      VAR *v, *vnode = (VAR *)cfile->var;
+
+      free(cfile->username);
+      if (cfile->mailto) free(cfile->mailto);
+
+      while (vnode && (v = dlist_pop(&vnode))) {
+        free(v->name);
+        free(v->val);
+        free(v);
+      }
+      free(cfile);
+    } else {
+      if (!cfile->mailto) cfile->mailto = cfile->username;
+      dlist_add_nomalloc((struct double_list **)&gclist,
+          (struct double_list *)cfile);
+    }
+    close(fd);
+  }
+  closedir(dp);
+}
+
+/*
+ * Set env variables, if any in the cronfile. Execute given job with the given
+ * SHELL or Default SHELL and send an e-mail with respect to every successfully
+ * completed job (as per the given param 'prog').
+ */
+static void do_fork(CRONFILE *cfile, JOB *job, int fd, char *prog)
+{
+  pid_t pid = vfork();
+
+  if (pid == 0) {
+    VAR *v, *vstart = (VAR *)cfile->var;
+    struct passwd *pwd = getpwnam(cfile->username);
+
+    if (!pwd) loginfo(LOG_LEVEL9, "can't get uid for %s", cfile->username);
+    else {
+      char *file = "/bin/sh";
+
+      if (setenv("USER", pwd->pw_name, 1)) _exit(1);
+      for (v = vstart; v;) {
+        if (!strcmp("SHELL", v->name)) file = v->val;
+        if (setenv(v->name, v->val, 1)) _exit(1);
+        if ((v=v->next) == vstart) break;
+      }
+      if (!getenv("HOME")) {
+        if (setenv("HOME", pwd->pw_dir, 1))
+          _exit(1);
+      }
+      xsetuser(pwd);
+      if (chdir(pwd->pw_dir)) loginfo(LOG_LEVEL9, "chdir(%s)", pwd->pw_dir);
+      if (prog) file = prog;
+      if (TT.flagd) loginfo(LOG_LEVEL5, "child running %s", file);
+
+      if (fd >= 0) {
+        int newfd = prog ? 0 : 1;
+        if (fd != newfd) {
+          dup2(fd, newfd);
+          close(fd);
+        }
+        dup2(1, 2);
+      }
+      setpgrp();
+      execlp(file, file, (prog ? "-ti" : "-c"), (prog ? NULL : job->cmd), (char *) NULL);
+      loginfo(LOG_ERROR, "can't execute '%s' for user %s", file, cfile->username);
+
+      if (!prog) dprintf(1, "Exec failed: %s -c %s\n", file, job->cmd);
+      _exit(EXIT_SUCCESS);
+    }
+  }
+  if (pid < 0) {
+    loginfo(LOG_ERROR, "can't vfork");
+    pid = 0;
+  }
+  if (fd >=0) close(fd);
+  job->pid = pid;
+}
+
+// Send an e-mail for each successfully completed jobs.
+static void sendmail(CRONFILE *cfile, JOB *job)
+{
+  pid_t pid = job->pid;
+  int mailfd;
+  struct stat sb;
+
+  job->pid = 0;
+  if (pid <=0 || job->mailsize <=0) {
+    job->isrunning = 0;
+    job->needstart = 1;
+    return;
+  }
+  snprintf(toybuf, sizeof(toybuf), "/var/spool/cron/cron.%s.%d",
+      cfile->username, (int)pid);
+
+  mailfd = open(toybuf, O_RDONLY);
+  unlink(toybuf);
+  if (mailfd < 0) return;
+
+  if (fstat(mailfd, &sb) == -1 || sb.st_uid != 0 || sb.st_nlink != 0
+      || sb.st_size == job->mailsize || !S_ISREG(sb.st_mode)) {
+    xclose(mailfd);
+    return;
+  }
+  job->mailsize = 0;
+  do_fork(cfile, job, mailfd, "sendmail");
+}
+
+// Count the number of jobs, which are not completed.
+static int count_running_jobs()
+{
+  CRONFILE *cfile = gclist;
+  JOB *job, *jstart;
+  int count = 0;
+
+  while (cfile) {
+    job = jstart = (JOB *)cfile->job;
+    while (job) {
+      int ret;
+
+      if (!job->isrunning || job->pid<=0) goto NEXT_JOB;
+      job->isrunning = 0;
+      ret = waitpid(job->pid, NULL, WNOHANG);
+      if (ret < 0 || ret == job->pid) {
+        sendmail(cfile, job);
+        if (job->pid) count += (job->isrunning=1);
+        else {
+          job->isrunning = 0;
+          job->needstart = 1;
+        }
+      }
+      else count += (job->isrunning=1);
+
+NEXT_JOB:
+      if ((job = job->next) == jstart) break;
+    }
+    if ((cfile = cfile->next) == gclist) break;
+  }
+  return count;
+}
+
+// Execute jobs one by one and prepare for the e-mail sending.
+static void execute_jobs(void)
+{
+  CRONFILE *cfile = gclist;
+  JOB *job, *jstart;
+
+  while (cfile) {
+    job = jstart = (JOB *)cfile->job;
+    while (job) {
+      if (job->needstart) {
+        job->needstart = 0;
+        if (job->pid < 0) {
+          int mailfd = -1;
+
+          job->mailsize = job->pid = 0;
+          snprintf(toybuf, sizeof(toybuf), "/var/spool/cron/cron.%s.%d",
+              cfile->username, getpid());
+          if ((mailfd = open(toybuf, O_CREAT|O_TRUNC|O_WRONLY|O_EXCL|O_APPEND,
+                  0600)) < 0) {
+            loginfo(LOG_ERROR, "can't create mail file %s for user %s, "
+                "discarding output", toybuf, cfile->username);
+          } else {
+            dprintf(mailfd, "To: %s\nSubject: cron: %s\n\n", cfile->mailto, job->cmd);
+            job->mailsize = lseek(mailfd, 0, SEEK_CUR);
+          }
+          do_fork(cfile, job, mailfd, NULL);
+          if (mailfd >= 0) {
+            if (job->pid <= 0) unlink(toybuf);
+            else {
+              char *mailfile = xmprintf("/var/spool/cron/cron.%s.%d",
+                  cfile->username, (int)job->pid);
+              rename(toybuf, mailfile);
+              free(mailfile);
+            }
+          }
+          loginfo(LOG_LEVEL8, "USER %s pid %3d cmd %s", 
+              cfile->username, job->pid, job->cmd);
+          if (job->pid < 0) job->needstart = 1;
+          else job->isrunning = 1;
+        }
+      }
+      if ((job = job->next) == jstart) break;
+    }
+    if ((cfile = cfile->next) == gclist) break;
+  }
+}
+
+// Identify jobs, which needs to be started at the given time interval.
+static void schedule_jobs(time_t ctime, time_t ptime)
+{
+  time_t tm = ptime-ptime%60;
+
+  for (; tm <= ctime; tm += 60) {
+    struct tm *lt;
+    CRONFILE *cfile = gclist;
+    JOB *job, *jstart;
+
+    if (tm <= ptime) continue;
+    lt = localtime(&tm);
+
+    while (cfile) {
+      if (TT.flagd) loginfo(LOG_LEVEL5, "file %s:", cfile->username);
+      if (cfile->invalid) goto NEXT_CRONFILE;
+      job = jstart = (JOB *)cfile->job;
+
+      while (job) {
+        if (TT.flagd) loginfo(LOG_LEVEL5, " line %s", job->cmd);
+
+        if (job->min[lt->tm_min] && job->hour[lt->tm_hour]
+            && (job->dom[lt->tm_mday] || job->dow[lt->tm_wday])
+            && job->mon[lt->tm_mon-1]) {
+          if (TT.flagd)
+            loginfo(LOG_LEVEL5, " job: %d %s\n", (int)job->pid, job->cmd);
+          if (job->pid > 0) {
+            loginfo(LOG_LEVEL8, "user %s: process already running: %s",
+                cfile->username, job->cmd);
+          } else if (!job->pid) {
+            job->pid = -1;
+            job->needstart = 1;
+            job->isrunning = 0;
+          }
+        }
+        if ((job = job->next) == jstart) break;
+      }
+NEXT_CRONFILE:
+      if ((cfile = cfile->next) == gclist) break;
+    }
+  }
+}
+
+void crond_main(void)
+{
+  time_t ctime, ptime;
+  int sleepfor = 60;
+  struct stat sb;
+
+  TT.flagd = (toys.optflags & FLAG_d);
+
+  // Setting default params.
+  if (TT.flagd) TT.loglevel = TT.loglevel_d;
+  if (!(toys.optflags & (FLAG_f | FLAG_b))) toys.optflags |= FLAG_b;
+  if (!(toys.optflags & (FLAG_S | FLAG_L))) toys.optflags |= FLAG_S;
+
+  if ((toys.optflags & FLAG_c)
+      && (TT.crontabs_dir[strlen(TT.crontabs_dir)-1] != '/'))
+    TT.crontabs_dir = xmprintf("%s/", TT.crontabs_dir);
+
+  if (!TT.crontabs_dir) TT.crontabs_dir = xstrdup("/var/spool/cron/crontabs/");
+  if (toys.optflags & FLAG_b) daemon(0,0);
+
+  if (!TT.flagd && !TT.logfile)
+    openlog(toys.which->name, LOG_CONS | LOG_PID, LOG_CRON);
+
+  // Set default shell once.
+  if (setenv("SHELL", "/bin/sh", 1)) error_exit("Can't set default shell");
+  xchdir(TT.crontabs_dir);
+  loginfo(LOG_LEVEL8, "crond started, log level %d", TT.loglevel);
+
+  if (stat(TT.crontabs_dir, &sb)) sb.st_mtime = 0;
+  TT.crontabs_dir_mtime = sb.st_mtime;
+  scan_cronfiles();
+  ctime = time(NULL);
+
+  while (1) {
+    long tdiff;
+
+    ptime = ctime;
+    sleep(sleepfor - (ptime%sleepfor) +1);
+    tdiff =(long) ((ctime = time(NULL)) - ptime);
+
+    if (stat(TT.crontabs_dir, &sb)) sb.st_mtime = 0;
+    if (TT.crontabs_dir_mtime != sb.st_mtime) {
+      TT.crontabs_dir_mtime = sb.st_mtime;
+      scan_cronfiles();
+    }
+
+    if (TT.flagd) loginfo(LOG_LEVEL5, "wakeup diff=%ld\n", tdiff);
+    if (tdiff < -60 * 60 || tdiff > 60 * 60)
+      loginfo(LOG_LEVEL9, "time disparity of %ld minutes detected", tdiff / 60);
+    else if (tdiff > 0) {
+      schedule_jobs(ctime, ptime);
+      execute_jobs();
+      if (count_running_jobs()) sleepfor = 10;
+      else sleepfor = 60;
+    }
+  }
+}
diff --git a/toybox/toys/pending/crontab.c b/toybox/toys/pending/crontab.c
new file mode 100644
index 0000000..0b1c47d
--- /dev/null
+++ b/toybox/toys/pending/crontab.c
@@ -0,0 +1,361 @@
+/* crontab.c - files used to schedule the execution of programs.
+ *
+ * Copyright 2014 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ *
+ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html
+
+USE_CRONTAB(NEWTOY(crontab, "c:u:elr[!elr]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
+
+config CRONTAB
+  bool "crontab"
+  default n
+  depends on TOYBOX_FORK
+  help
+    usage: crontab [-u user] FILE
+                   [-u user] [-e | -l | -r]
+                   [-c dir]
+
+    Files used to schedule the execution of programs.
+
+    -c crontab dir
+    -e edit user's crontab
+    -l list user's crontab
+    -r delete user's crontab
+    -u user
+    FILE Replace crontab by FILE ('-': stdin)
+*/
+#define FOR_crontab
+#include "toys.h"
+
+GLOBALS(
+  char *user;
+  char *cdir;
+)
+
+static char *omitspace(char *line)
+{
+  while (*line == ' ' || *line == '\t') line++;
+  return line;
+}
+
+/*
+ * Names can also be used for the 'month' and 'day of week' fields
+ * (First three letters of the particular day or month).
+ */
+static int getindex(char *src, int size)
+{
+  int i;
+  char days[]={"sun""mon""tue""wed""thu""fri""sat"};
+  char months[]={"jan""feb""mar""apr""may""jun""jul"
+    "aug""sep""oct""nov""dec"};
+  char *field = (size == 12) ? months : days;
+
+  // strings are not allowed for min, hour and dom fields.
+  if (!(size == 7 || size == 12)) return -1;
+
+  for (i = 0; field[i]; i += 3) {
+    if (!strncasecmp(src, &field[i], 3))
+      return (i/3);
+  }
+  return -1;
+}
+
+static long getval(char *num, long low, long high)
+{
+  long val = strtol(num, &num, 10);
+
+  if (*num || (val < low) || (val > high)) return -1;
+  return val;
+}
+
+// Validate minute, hour, day of month, month and day of week fields.
+static int validate_component(int min, int max, char *src)
+{
+  int skip = 0;
+  char *ptr;
+
+  if (!src) return 1;
+  if ((ptr = strchr(src, '/'))) {
+    *ptr++ = 0;
+    if ((skip = getval(ptr, min, (min ? max: max-1))) < 0) return 1;
+  }
+
+  if (*src == '-' || *src == ',') return 1;
+  if (*src == '*') {
+    if (*(src+1)) return 1;
+  }
+  else {
+    for (;;) {
+      char *ctoken = strsep(&src, ","), *dtoken;
+
+      if (!ctoken) break;
+      if (!*ctoken) return 1;
+
+      // validate start position.
+      dtoken = strsep(&ctoken, "-");
+      if (isdigit(*dtoken)) {
+        if (getval(dtoken, min, (min ? max : max-1)) < 0) return 1;
+      } else if (getindex(dtoken, max) < 0) return 1;
+
+      // validate end position.
+      if (!ctoken) {
+        if (skip) return 1; // case 10/20 or 1,2,4/3
+      }
+      else if (*ctoken) {// e.g. N-M
+        if (isdigit(*ctoken)) {
+          if (getval(ctoken, min, (min ? max : max-1)) < 0) return 1;
+        } else if (getindex(ctoken, max) < 0) return 1;
+      } else return 1; // error condition 'N-'
+    }
+  }
+  return 0;
+}
+
+static int parse_crontab(char *fname)
+{
+  char *line;
+  int lno, fd = xopenro(fname);
+  long plen = 0;
+
+  for (lno = 1; (line = get_rawline(fd, &plen, '\n')); lno++,free(line)) {
+    char *name, *val, *tokens[5] = {0,}, *ptr = line;
+    int count = 0;
+
+    if (line[plen - 1] == '\n') line[--plen] = '\0';
+    else {
+      snprintf(toybuf, sizeof(toybuf), "'%d': premature EOF\n", lno);
+      goto OUT;
+    }
+
+    ptr = omitspace(ptr);
+    if (!*ptr || *ptr == '#' || *ptr == '@') continue;
+    while (count<5) {
+      int len = strcspn(ptr, " \t");
+
+      if (ptr[len]) ptr[len++] = '\0';
+      tokens[count++] = ptr;
+      ptr += len;
+      ptr = omitspace(ptr);
+      if (!*ptr) break;
+    }
+    switch (count) {
+      case 1: // form SHELL=/bin/sh
+        name = tokens[0];
+        if ((val = strchr(name, '='))) *val++ = 0;
+        if (!val || !*val) {
+          snprintf(toybuf, sizeof(toybuf), "'%d': %s\n", lno, line);
+          goto OUT;
+        }
+        break;
+      case 2: // form SHELL =/bin/sh or SHELL= /bin/sh
+        name = tokens[0];
+        if ((val = strchr(name, '='))) {
+          *val = 0;
+          val = tokens[1];
+        } else {
+          if (*(tokens[1]) != '=') {
+            snprintf(toybuf, sizeof(toybuf), "'%d': %s\n", lno, line);
+            goto OUT;
+          }
+          val = tokens[1] + 1;
+        }
+        if (!*val) {
+          snprintf(toybuf, sizeof(toybuf), "'%d': %s\n", lno, line);
+          goto OUT;
+        }
+        break;
+      case 3: // NAME = VAL
+        name = tokens[0];
+        val = tokens[2];
+        if (*(tokens[1]) != '=') {
+          snprintf(toybuf, sizeof(toybuf), "'%d': %s\n", lno, line);
+          goto OUT;
+        }
+        break;
+      default:
+        if (validate_component(0, 60, tokens[0])) {
+          snprintf(toybuf, sizeof(toybuf), "'%d': bad minute\n", lno);
+          goto OUT;
+        }
+        if (validate_component(0, 24, tokens[1])) {
+          snprintf(toybuf, sizeof(toybuf), "'%d': bad hour\n", lno);
+          goto OUT;
+        }
+        if (validate_component(1, 31, tokens[2])) {
+          snprintf(toybuf, sizeof(toybuf), "'%d': bad day-of-month\n", lno);
+          goto OUT;
+        }
+        if (validate_component(1, 12, tokens[3])) {
+          snprintf(toybuf, sizeof(toybuf), "'%d': bad month\n", lno);
+          goto OUT;
+        }
+        if (validate_component(0, 7, tokens[4])) {
+          snprintf(toybuf, sizeof(toybuf), "'%d': bad day-of-week\n", lno);
+          goto OUT;
+        }
+        if (!*ptr) { // don't have any cmd to execute.
+          snprintf(toybuf, sizeof(toybuf), "'%d': bad command\n", lno);
+          goto OUT;
+        }
+        break;
+    }
+  }
+  xclose(fd);
+  return 0;
+OUT:
+  free(line);
+  printf("Error at line no %s", toybuf);
+  xclose(fd);
+  return 1;
+}
+
+static void do_list(char *name)
+{
+  int fdin;
+
+  snprintf(toybuf, sizeof(toybuf), "%s%s", TT.cdir, name);
+  fdin = xopenro(toybuf);
+  xsendfile(fdin, 1);
+  xclose(fdin);
+}
+
+static void do_remove(char *name)
+{
+  snprintf(toybuf, sizeof(toybuf), "%s%s", TT.cdir, name);
+  if (unlink(toybuf))
+    error_exit("No crontab for '%s'", name);
+}
+
+static void update_crontab(char *src, char *dest)
+{
+  int fdin, fdout;
+
+  snprintf(toybuf, sizeof(toybuf), "%s%s", TT.cdir, dest);
+  fdout = xcreate(toybuf, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+  fdin = xopenro(src);
+  xsendfile(fdin, fdout);
+  xclose(fdin);
+
+  fchown(fdout, getuid(), geteuid());
+  xclose(fdout);
+}
+
+static void do_replace(char *name)
+{
+  char *fname = *toys.optargs ? *toys.optargs : "-";
+  char tname[] = "/tmp/crontab.XXXXXX";
+
+  if ((*fname == '-') && !*(fname+1)) {
+    int tfd = mkstemp(tname);
+
+    if (tfd < 0) perror_exit("mkstemp");
+    xsendfile(0, tfd);
+    xclose(tfd);
+    fname = tname;
+  }
+
+  if (parse_crontab(fname))
+    error_exit("errors in crontab file '%s', can't install.", fname);
+  update_crontab(fname, name);
+  unlink(tname);
+}
+
+static void do_edit(struct passwd *pwd)
+{
+  struct stat sb;
+  time_t mtime = 0;
+  int srcfd, destfd, status;
+  pid_t pid, cpid;
+  char tname[] = "/tmp/crontab.XXXXXX";
+
+  if ((destfd = mkstemp(tname)) < 0)
+    perror_exit("Can't open tmp file");
+
+  fchmod(destfd, 0666);
+  snprintf(toybuf, sizeof(toybuf), "%s%s", TT.cdir, pwd->pw_name);
+
+  if (!stat(toybuf, &sb)) { // file exists and have some content.
+    if (sb.st_size) {
+      srcfd = xopenro(toybuf);
+      xsendfile(srcfd, destfd);
+      xclose(srcfd);
+    }
+  } else printf("No crontab for '%s'- using an empty one\n", pwd->pw_name);
+  xclose(destfd);
+
+  if (!stat(tname, &sb)) mtime = sb.st_mtime;
+
+RETRY:
+  if (!(pid = xfork())) {
+    char *prog = pwd->pw_shell;
+
+    xsetuser(pwd);
+    if (pwd->pw_uid) {
+      if (setenv("USER", pwd->pw_name, 1)) _exit(1);
+      if (setenv("LOGNAME", pwd->pw_name, 1)) _exit(1);
+    }
+    if (setenv("HOME", pwd->pw_dir, 1)) _exit(1);
+    if (setenv("SHELL",((!prog || !*prog) ? "/bin/sh" : prog), 1)) _exit(1);
+
+    if (!(prog = getenv("VISUAL"))) {
+      if (!(prog = getenv("EDITOR")))
+        prog = "vi";
+    }
+    execlp(prog, prog, tname, (char *) NULL);
+    perror_exit("can't execute '%s'", prog);
+  }
+
+  // Parent Process.
+  do {
+    cpid = waitpid(pid, &status, 0);
+  } while ((cpid == -1) && (errno == EINTR));
+
+  if (!stat(tname, &sb) && (mtime == sb.st_mtime)) {
+    printf("%s: no changes made to crontab\n", toys.which->name);
+    unlink(tname);
+    return;
+  }
+  printf("%s: installing new crontab\n", toys.which->name);
+  if (parse_crontab(tname)) {
+    fprintf(stderr, "errors in crontab file, can't install.\n"
+        "Do you want to retry the same edit? ");
+    if (!yesno(0)) {
+      error_msg("edits left in '%s'", tname);
+      return;
+    }
+    goto RETRY;
+  }
+  // parsing of crontab success; update the crontab.
+  update_crontab(tname, pwd->pw_name);
+  unlink(tname);
+}
+
+void crontab_main(void)
+{
+  struct passwd *pwd = NULL;
+  long FLAG_elr = toys.optflags & (FLAG_e|FLAG_l|FLAG_r);
+
+  if (TT.cdir && (TT.cdir[strlen(TT.cdir)-1] != '/'))
+    TT.cdir = xmprintf("%s/", TT.cdir);
+  if (!TT.cdir) TT.cdir = xstrdup("/var/spool/cron/crontabs/");
+
+  if (toys.optflags & FLAG_u) {
+    if (getuid()) error_exit("must be privileged to use -u");
+    pwd = xgetpwnam(TT.user);
+  } else pwd = xgetpwuid(getuid());
+
+  if (!toys.optc) {
+    if (!FLAG_elr) {
+      if (toys.optflags & FLAG_u) 
+        help_exit("file name must be specified for replace");
+      do_replace(pwd->pw_name);
+    }
+    else if (toys.optflags & FLAG_e) do_edit(pwd);
+    else if (toys.optflags & FLAG_l) do_list(pwd->pw_name);
+    else if (toys.optflags & FLAG_r) do_remove(pwd->pw_name);
+  } else {
+    if (FLAG_elr) help_exit("no arguments permitted after this option");
+    do_replace(pwd->pw_name);
+  }
+  if (!(toys.optflags & FLAG_c)) free(TT.cdir);
+}
diff --git a/toybox/toys/pending/dd.c b/toybox/toys/pending/dd.c
new file mode 100644
index 0000000..c3e51cf
--- /dev/null
+++ b/toybox/toys/pending/dd.c
@@ -0,0 +1,333 @@
+/* dd.c - program to convert and copy a file.
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * See  http://opengroup.org/onlinepubs/9699919799/utilities/dd.html
+
+USE_DD(NEWTOY(dd, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config DD
+  bool "dd"
+  default n
+  help
+    usage: dd [if=FILE] [of=FILE] [ibs=N] [obs=N] [bs=N] [count=N] [skip=N]
+            [seek=N] [conv=notrunc|noerror|sync|fsync] [status=noxfer|none]
+
+    Options:
+    if=FILE   Read from FILE instead of stdin
+    of=FILE   Write to FILE instead of stdout
+    bs=N      Read and write N bytes at a time
+    ibs=N     Read N bytes at a time
+    obs=N     Write N bytes at a time
+    count=N   Copy only N input blocks
+    skip=N    Skip N input blocks
+    seek=N    Skip N output blocks
+    conv=notrunc  Don't truncate output file
+    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 (*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 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_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
+#define C_SYNC    0x0100
+#define C_FSYNC   0x0200
+#define C_NOERROR 0x0400
+#define C_NOTRUNC 0x0800
+#define C_STATUS  0x1000
+
+struct pair {
+  char *name;
+  unsigned val;
+};
+
+static struct pair suffixes[] = {
+  { "c", 1 }, { "w", 2 }, { "b", 512 },
+  { "kD", 1000 }, { "k", 1024 }, { "K", 1024 },
+  { "MD", 1000000 }, { "M", 1048576 },
+  { "GD", 1000000000 }, { "G", 1073741824 }
+};
+
+static struct pair clist[] = {
+  { "fsync",    C_FSYNC },
+  { "noerror",  C_NOERROR },
+  { "notrunc",  C_NOTRUNC },
+  { "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  },
+  { "status",  C_STATUS},
+};
+
+static unsigned long long strsuftoll(char *arg, int def, unsigned long long max)
+{
+  unsigned long long result;
+  char *p = arg;
+  int i, idx = -1;
+
+  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 (*p != '\0') {
+    for (i = 0; i < ARRAY_LEN(suffixes); i++)
+      if (!strcmp(p, suffixes[i].name)) idx = i;
+    if (idx == -1 || (max/suffixes[idx].val < result)) 
+      error_exit("invalid number '%s'", arg);
+    result *= suffixes[idx].val;
+  }
+  return result;
+}
+
+static void status()
+{
+  double seconds;
+  struct timeval now;
+
+  gettimeofday(&now, NULL);
+  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 write_out(int all)
+{
+  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 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()
+{
+  struct pair *res, key;
+  char *arg;
+  long sz;
+
+  TT.show_xfer = TT.show_records = 1;
+
+  TT.in.sz = TT.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:
+        TT.in.sz = TT.out.sz = strsuftoll(arg, 1, LONG_MAX);
+        break;
+      case C_IBS:
+        sz = strsuftoll(arg, 1, LONG_MAX);
+        if (!(toys.optflags & C_BS)) TT.in.sz = sz;
+        break;
+      case C_OBS:
+        sz = strsuftoll(arg, 1, LONG_MAX);
+        if (!(toys.optflags & C_BS)) TT.out.sz = sz;
+        break;
+      case C_COUNT:
+        TT.c_count = strsuftoll(arg, 0, ULLONG_MAX);
+        break;
+      case C_IF:
+        TT.in.name = arg;
+        break;
+      case C_OF:
+        TT.out.name = arg;
+        break;
+      case C_SEEK:
+        TT.out.offset = strsuftoll(arg, 0, ULLONG_MAX);
+        break;
+      case C_SKIP:
+        TT.in.offset = strsuftoll(arg, 0, ULLONG_MAX);
+        break;
+      case C_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);
+        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++;
+  }
+
+  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.
+   * With Single buffer there will be overflow in a read following partial read
+   */
+  TT.in.buff = TT.out.buff = xmalloc(TT.in.sz
+    + ((toys.optflags & C_BS) ? 0 : TT.out.sz));
+  TT.in.bp = TT.out.bp = TT.in.buff;
+  //setup input
+  if (!TT.in.name) TT.in.name = "stdin";
+  else TT.in.fd = xopenro(TT.in.name);
+
+  //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|(O_TRUNC*!(toys.optflags&C_NOTRUNC)), 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", TT.in.name);
+          return;
+        }
+      }
+    }
+  }
+
+  if (TT.out.offset)
+    xlseek(TT.out.fd, TT.out.offset * (off_t)TT.out.sz, SEEK_CUR);
+
+  if ((toys.optflags&C_SEEK) && !(toys.optflags & C_NOTRUNC))
+    if (ftruncate(TT.out.fd, TT.out.offset * TT.out.sz))
+      perror_exit("ftruncate");
+
+  while (!(toys.optflags & C_COUNT) || (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", TT.in.name);
+      if (!(toys.optflags & C_NOERROR)) exit(1);
+      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 = TT.in.sz;
+    }
+    if (n == TT.in.sz) {
+      TT.in_full++;
+      TT.in.count += n;
+    } else {
+      TT.in_part++;
+      if (toys.optflags & C_SYNC) TT.in.count += TT.in.sz;
+      else TT.in.count += n;
+    }
+
+    TT.out.count = TT.in.count;
+    if (toys.optflags & C_BS) {
+      write_out(1);
+      TT.in.count = 0;
+      continue;
+    }
+
+    if (TT.in.count >= TT.out.sz) {
+      write_out(0);
+      TT.in.count = TT.out.count;
+    }
+  }
+  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);
+
+  close(TT.in.fd);
+  close(TT.out.fd);
+  if (TT.in.buff) free(TT.in.buff);
+
+  status();
+}
diff --git a/toybox/toys/pending/dhcp.c b/toybox/toys/pending/dhcp.c
new file mode 100644
index 0000000..b99bb4c
--- /dev/null
+++ b/toybox/toys/pending/dhcp.c
@@ -0,0 +1,1524 @@
+/* dhcp.c - DHCP client for dynamic network configuration.
+ *
+ * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * Not in SUSv4.
+USE_DHCP(NEWTOY(dhcp, "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
+
+config DHCP
+  bool "dhcp"
+  default n
+  help
+   usage: dhcp [-fbnqvoCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]
+               [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL] [-O OPT]
+
+        Configure network dynamicaly using DHCP.
+
+      -i Interface to use (default eth0)
+      -p Create pidfile
+      -s Run PROG at DHCP events (default /usr/share/dhcp/default.script)
+      -B Request broadcast replies
+      -t Send up to N discover packets
+      -T Pause between packets (default 3 seconds)
+      -A Wait N seconds after failure (default 20)
+      -f Run in foreground
+      -b Background if lease is not obtained
+      -n Exit if lease is not obtained
+      -q Exit after obtaining lease
+      -R Release IP on exit
+      -S Log to syslog too
+      -a Use arping to validate offered address
+      -O Request option OPT from server (cumulative)
+      -o Don't request any options (unless -O is given)
+      -r Request this IP address
+      -x OPT:VAL  Include option OPT in sent packets (cumulative)
+      -F Ask server to update DNS mapping for NAME
+      -H Send NAME as client hostname (default none)
+      -V VENDOR Vendor identifier (default 'toybox VERSION')
+      -C Don't send MAC as client identifier
+      -v Verbose
+
+      Signals:
+      USR1  Renew current lease
+      USR2  Release current lease
+
+*/
+
+#define FOR_dhcp
+#include "toys.h"
+
+// TODO: headers not in posix:
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netpacket/packet.h>
+
+#include <linux/filter.h> //FIXME: linux specific. fix for other OS ports
+#include <linux/if_ether.h>
+
+GLOBALS(
+    char *iface;
+    char *pidfile;
+    char *script;
+    long retries;
+    long timeout;
+    long tryagain;
+    struct arg_list *req_opt;
+    char *req_ip;
+    struct arg_list *pkt_opt;
+    char *fdn_name;
+    char *hostname;
+    char *vendor_cls;
+)
+
+#define STATE_INIT            0
+#define STATE_REQUESTING      1
+#define STATE_BOUND           2
+#define STATE_RENEWING        3
+#define STATE_REBINDING       4
+#define STATE_RENEW_REQUESTED 5
+#define STATE_RELEASED        6
+
+#define BOOTP_BROADCAST   0x8000
+#define DHCP_MAGIC        0x63825363
+
+#define DHCP_REQUEST          1
+#define DHCP_REPLY            2
+#define DHCP_HTYPE_ETHERNET   1
+
+#define DHCPC_SERVER_PORT     67
+#define DHCPC_CLIENT_PORT     68
+
+#define DHCPDISCOVER      1
+#define DHCPOFFER         2
+#define DHCPREQUEST       3
+#define DHCPACK           5
+#define DHCPNAK           6
+#define DHCPRELEASE       7
+
+#define DHCP_OPTION_PADDING     0x00
+#define DHCP_OPTION_SUBNET_MASK 0x01
+#define DHCP_OPTION_ROUTER      0x03
+#define DHCP_OPTION_DNS_SERVER  0x06
+#define DHCP_OPTION_HOST_NAME   0x0c
+#define DHCP_OPTION_BROADCAST   0x1c
+#define DHCP_OPTION_REQ_IPADDR  0x32
+#define DHCP_OPTION_LEASE_TIME  0x33
+#define DHCP_OPTION_OVERLOAD    0x34
+#define DHCP_OPTION_MSG_TYPE    0x35
+#define DHCP_OPTION_SERVER_ID   0x36
+#define DHCP_OPTION_REQ_LIST    0x37
+#define DHCP_OPTION_MAX_SIZE    0x39
+#define DHCP_OPTION_CLIENTID    0x3D
+#define DHCP_OPTION_VENDOR      0x3C
+#define DHCP_OPTION_FQDN        0x51
+#define DHCP_OPTION_END         0xFF
+
+#define DHCP_NUM8           (1<<8)
+#define DHCP_NUM16          (1<<9)
+#define DHCP_NUM32          DHCP_NUM16 | DHCP_NUM8
+#define DHCP_STRING         (1<<10)
+#define DHCP_STRLST         (1<<11)
+#define DHCP_IP             (1<<12)
+#define DHCP_IPLIST         (1<<13)
+#define DHCP_IPPLST         (1<<14)
+#define DHCP_STCRTS         (1<<15)
+
+#define LOG_SILENT          0x0
+#define LOG_CONSOLE         0x1
+#define LOG_SYSTEM          0x2
+
+#define MODE_OFF        0
+#define MODE_RAW        1
+#define MODE_APP        2
+
+static void (*dbg)(char *format, ...);
+static void dummy(char *format, ...){
+	return;
+}
+
+typedef struct dhcpc_result_s {
+  struct in_addr serverid;
+  struct in_addr ipaddr;
+  struct in_addr netmask;
+  struct in_addr dnsaddr;
+  struct in_addr default_router;
+  uint32_t lease_time;
+} dhcpc_result_t;
+
+typedef struct __attribute__((packed)) dhcp_msg_s {
+  uint8_t op;
+  uint8_t htype;
+  uint8_t hlen;
+  uint8_t hops;
+  uint32_t xid;
+  uint16_t secs;
+  uint16_t flags;
+  uint32_t ciaddr;
+  uint32_t yiaddr;
+  uint32_t nsiaddr;
+  uint32_t ngiaddr;
+  uint8_t chaddr[16];
+  uint8_t sname[64];
+  uint8_t file[128];
+  uint32_t cookie;
+  uint8_t options[308];
+} dhcp_msg_t;
+
+typedef struct __attribute__((packed)) dhcp_raw_s {
+  struct iphdr iph;
+  struct udphdr udph;
+  dhcp_msg_t dhcp;
+} dhcp_raw_t;
+
+typedef struct dhcpc_state_s {
+  uint8_t macaddr[6];
+   char *iface;
+  int ifindex;
+  int sockfd;
+  int status;
+  int mode;
+  uint32_t mask;
+  struct in_addr ipaddr;
+  struct in_addr serverid;
+  dhcp_msg_t pdhcp;
+} dhcpc_state_t;
+
+typedef struct option_val_s {
+  char *key;
+  uint16_t code;
+  void *val;
+  size_t len;
+} option_val_t;
+
+struct fd_pair { int rd; int wr; };
+static uint32_t xid;
+static dhcpc_state_t *state;
+static struct fd_pair sigfd;
+uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ int set = 1;
+uint8_t infomode = LOG_CONSOLE;
+uint8_t raw_opt[29];
+int raw_optcount = 0;
+struct arg_list *x_opt;
+in_addr_t server = 0;
+
+static option_val_t *msgopt_list = NULL;
+static option_val_t options_list[] = {
+    {"lease"          , DHCP_NUM32  | 0x33, NULL, 0},
+    {"subnet"         , DHCP_IP     | 0x01, NULL, 0},
+    {"broadcast"      , DHCP_IP     | 0x1c, NULL, 0},
+    {"router"         , DHCP_IP     | 0x03, NULL, 0},
+    {"ipttl"          , DHCP_NUM8   | 0x17, NULL, 0},
+    {"mtu"            , DHCP_NUM16  | 0x1a, NULL, 0},
+    {"hostname"       , DHCP_STRING | 0x0c, NULL, 0},
+    {"domain"         , DHCP_STRING | 0x0f, NULL, 0},
+    {"search"         , DHCP_STRLST | 0x77, NULL, 0},
+    {"nisdomain"      , DHCP_STRING | 0x28, NULL, 0},
+    {"timezone"       , DHCP_NUM32  | 0x02, NULL, 0},
+    {"tftp"           , DHCP_STRING | 0x42, NULL, 0},
+    {"bootfile"       , DHCP_STRING | 0x43, NULL, 0},
+    {"bootsize"       , DHCP_NUM16  | 0x0d, NULL, 0},
+    {"rootpath"       , DHCP_STRING | 0x11, NULL, 0},
+    {"wpad"           , DHCP_STRING | 0xfc, NULL, 0},
+    {"serverid"       , DHCP_IP     | 0x36, NULL, 0},
+    {"message"        , DHCP_STRING | 0x38, NULL, 0},
+    {"vlanid"         , DHCP_NUM32  | 0x84, NULL, 0},
+    {"vlanpriority"   , DHCP_NUM32  | 0x85, NULL, 0},
+    {"dns"            , DHCP_IPLIST | 0x06, NULL, 0},
+    {"wins"           , DHCP_IPLIST | 0x2c, NULL, 0},
+    {"nissrv"         , DHCP_IPLIST | 0x29, NULL, 0},
+    {"ntpsrv"         , DHCP_IPLIST | 0x2a, NULL, 0},
+    {"lprsrv"         , DHCP_IPLIST | 0x09, NULL, 0},
+    {"swapsrv"        , DHCP_IP     | 0x10, NULL, 0},
+    {"routes"         , DHCP_STCRTS | 0x21, NULL, 0},
+    {"staticroutes"   , DHCP_STCRTS | 0x79, NULL, 0},
+    {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0},
+};
+
+static  struct sock_filter filter_instr[] = {
+    BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
+    BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
+    BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
+    BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
+    BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
+    BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
+    BPF_STMT(BPF_RET|BPF_K, 0xffffffff), BPF_STMT(BPF_RET|BPF_K, 0),
+};
+
+static  struct sock_fprog filter_prog = {
+    .len = ARRAY_LEN(filter_instr), 
+    .filter = (struct sock_filter *) filter_instr,
+};
+
+// calculate options size.
+static int dhcp_opt_size(uint8_t *optionptr)
+{
+  int i = 0;
+  for(;optionptr[i] != 0xff; i++) if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1;
+  return i;
+}
+
+// calculates checksum for dhcp messages.
+static uint16_t dhcp_checksum(void *addr, int count)
+{
+  int32_t sum = 0;
+  uint16_t tmp = 0, *source = (uint16_t *)addr;
+
+  while (count > 1)  {
+    sum += *source++;
+    count -= 2;
+  }
+  if (count > 0) {
+    *(uint8_t*)&tmp = *(uint8_t*)source;
+    sum += tmp;
+  }
+  while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
+  return ~sum;
+}
+
+// gets information of INTERFACE and updates IFINDEX, MAC and IP
+static int get_interface( char *interface, int *ifindex, uint32_t *oip, uint8_t *mac)
+{
+  struct ifreq req;
+  struct sockaddr_in *ip;
+  int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+
+  req.ifr_addr.sa_family = AF_INET;
+  xstrncpy(req.ifr_name, interface, IFNAMSIZ);
+  req.ifr_name[IFNAMSIZ-1] = '\0';
+
+  xioctl(fd, SIOCGIFFLAGS, &req);
+  if (!(req.ifr_flags & IFF_UP)) return -1;
+
+  if (oip) {
+    xioctl(fd, SIOCGIFADDR, &req);
+    ip = (struct sockaddr_in*) &req.ifr_addr;
+    dbg("IP %s\n", inet_ntoa(ip->sin_addr));
+    *oip = ntohl(ip->sin_addr.s_addr);
+  }
+  if (ifindex) {
+    xioctl(fd, SIOCGIFINDEX, &req);
+    dbg("Adapter index %d\n", req.ifr_ifindex);
+    *ifindex = req.ifr_ifindex;
+  }
+  if (mac) {
+    xioctl(fd, SIOCGIFHWADDR, &req);
+    memcpy(mac, req.ifr_hwaddr.sa_data, 6);
+    dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+  }
+  close(fd);
+  return 0;
+}
+
+/*
+ *logs messeges to syslog or console
+ *opening the log is still left with applet.
+ *FIXME: move to more relevent lib. probably libc.c
+ */
+static void infomsg(uint8_t infomode,  char *s, ...)
+{
+  int used;
+  char *msg;
+  va_list p, t;
+
+  if (infomode == LOG_SILENT) return;
+  va_start(p, s);
+  va_copy(t, p);
+  used = vsnprintf(NULL, 0, s, t);
+  used++;
+  va_end(t);
+
+  msg = xmalloc(used);
+  vsnprintf(msg, used, s, p);
+  va_end(p);
+
+  if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
+  if (infomode & LOG_CONSOLE) printf("%s\n", msg);
+  free(msg);
+}
+
+/*
+ * Writes self PID in file PATH
+ * FIXME: libc implementation only writes in /var/run
+ * this is more generic as some implemenation may provide
+ * arguments to write in specific file. as dhcpd does.
+ */
+static void write_pid(char *path)
+{
+  int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+  if (pidfile > 0) {
+    char pidbuf[12];
+
+    sprintf(pidbuf, "%u", (unsigned)getpid());
+    write(pidfile, pidbuf, strlen(pidbuf));
+    close(pidfile);
+  }
+}
+
+// String STR to UINT32 conversion strored in VAR
+static long strtou32( char *str)
+{
+  char *endptr = NULL;
+  int base = 10;
+  errno=0;
+  if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
+    base = 16;
+    str+=2;
+  }
+  long ret_val = strtol(str, &endptr, base);
+  if (errno) return -1;
+  else if (endptr && (*endptr!='\0'||endptr == str)) return -1;
+  return ret_val;
+}
+
+// IP String STR to binary data.
+static int striptovar( char *str, void *var)
+{
+  in_addr_t addr;
+  if(!str) error_exit("NULL address string.");
+  addr = inet_addr(str);
+  if(addr == -1) error_exit("Wrong address %s.",str );
+  *((uint32_t*)(var)) = (uint32_t)addr;
+  return 0;
+}
+
+// String to dhcp option conversion
+static int strtoopt( char *str, uint8_t optonly)
+{
+  char *option, *valstr, *grp, *tp;
+  long optcode = 0, convtmp;
+  uint16_t flag = 0;
+  uint32_t mask, nip, router;
+  int count, size = ARRAY_LEN(options_list);
+
+  if (!*str) return 0;
+  option = strtok((char*)str, ":");
+  if (!option) return -1;
+
+  dbg("-x option : %s ", option);
+  optcode = strtou32(option);
+
+  if (optcode > 0 && optcode < 256) {         // raw option
+    for (count = 0; count < size; count++) {
+      if ((options_list[count].code & 0X00FF) == optcode) {
+        flag = (options_list[count].code & 0XFF00);
+        break;
+      }
+    }
+    if (count == size) error_exit("Obsolete OR Unknown Option : %s", option);
+  } else {    // string option
+    for (count = 0; count < size; count++) {
+      if (!strcmp(options_list[count].key, option)) {
+        flag = (options_list[count].code & 0XFF00);
+        optcode = (options_list[count].code & 0X00FF);
+        break;
+      }
+    }
+    if (count == size) error_exit("Obsolete OR Unknown Option : %s", option);
+  }
+  if (!flag || !optcode) return -1;
+  if (optonly) return optcode;
+
+  valstr = strtok(NULL, "\n");
+  if (!valstr) error_exit("option %s has no value defined.\n", option);
+  dbg(" value : %-20s \n ", valstr);
+  switch (flag) {
+  case DHCP_NUM32:
+    options_list[count].len = sizeof(uint32_t);
+    options_list[count].val = xmalloc(sizeof(uint32_t));
+    convtmp = strtou32(valstr);
+    if (convtmp < 0) error_exit("Invalid/wrong formated number %s", valstr);
+    convtmp = htonl(convtmp);
+    memcpy(options_list[count].val, &convtmp, sizeof(uint32_t));
+    break;
+  case DHCP_NUM16:
+    options_list[count].len = sizeof(uint16_t);
+    options_list[count].val = xmalloc(sizeof(uint16_t));
+    convtmp = strtou32(valstr);
+    if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr);
+    convtmp = htons(convtmp);
+    memcpy(options_list[count].val, &convtmp, sizeof(uint16_t));
+    break;
+  case DHCP_NUM8:
+    options_list[count].len = sizeof(uint8_t);
+    options_list[count].val = xmalloc(sizeof(uint8_t));
+    convtmp = strtou32(valstr);
+    if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr);
+    memcpy(options_list[count].val, &convtmp, sizeof(uint8_t));
+    break;
+  case DHCP_IP:
+    options_list[count].len = sizeof(uint32_t);
+    options_list[count].val = xmalloc(sizeof(uint32_t));
+    striptovar(valstr, options_list[count].val);
+    break;
+  case DHCP_STRING:
+    options_list[count].len = strlen(valstr);
+    options_list[count].val = strdup(valstr);
+    break;
+  case DHCP_IPLIST:
+    while(valstr){
+      options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t));
+      striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len);
+      options_list[count].len += sizeof(uint32_t);
+      valstr = strtok(NULL," \t");
+    }
+    break;
+  case DHCP_STRLST: 
+  case DHCP_IPPLST:
+    break;
+  case DHCP_STCRTS:
+    /* Option binary format:
+     * mask [one byte, 0..32]
+     * ip [0..4 bytes depending on mask]
+     * router [4 bytes]
+     * may be repeated
+     * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
+     */
+    grp = strtok(valstr, ",");;
+    while(grp){
+      while(*grp == ' ' || *grp == '\t') grp++;
+      tp = strchr(grp, '/');
+      if (!tp) error_exit("malformed static route option");
+      *tp = '\0';
+      mask = strtol(++tp, &tp, 10);
+      if (striptovar(grp, (uint8_t*)&nip) < 0) error_exit("malformed static route option");
+      while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++;
+      if (striptovar(tp, (uint8_t*)&router) < 0) error_exit("malformed static route option");
+      options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4);
+      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1);
+      options_list[count].len += 1;
+      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8);
+      options_list[count].len += mask/8;
+      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4);
+      options_list[count].len += 4;
+      tp = NULL;
+      grp = strtok(NULL, ",");
+    }
+    break;
+  }
+  return 0;
+}
+
+// Creates environment pointers from RES to use in script
+static int fill_envp(dhcpc_result_t *res)
+{
+  struct in_addr temp;
+  int size = ARRAY_LEN(options_list), count, ret = -1;
+
+  ret = setenv("interface", state->iface, 1);
+  if (!res) return ret;
+  if (res->ipaddr.s_addr) {
+      temp.s_addr = htonl(res->ipaddr.s_addr);
+      ret = setenv("ip", inet_ntoa(temp), 1);
+      if (ret) return ret;
+  }
+  if (msgopt_list) {
+    for (count = 0; count < size; count++) {
+        if ((msgopt_list[count].len == 0) || (msgopt_list[count].val == NULL)) continue;
+        ret = setenv(msgopt_list[count].key, (char*)msgopt_list[count].val, 1);
+        if (ret) return ret;
+      }
+  }
+  return ret;
+}
+
+// Executes Script NAME.
+static void run_script(dhcpc_result_t *res,  char *name)
+{
+  volatile int error = 0;
+  pid_t pid;
+  char *argv[3];
+  struct stat sts;
+  char *script = (toys.optflags & FLAG_s) ? TT.script
+    : "/usr/share/dhcp/default.script";
+
+  if (stat(script, &sts) == -1 && errno == ENOENT) return;
+  if (fill_envp(res)) {
+    dbg("Failed to create environment variables.");
+    return;
+  }
+  dbg("Executing %s %s\n", script, name);
+  argv[0] = (char*) script;
+  argv[1] = (char*) name;
+  argv[2] = NULL;
+  fflush(NULL);
+
+  pid = vfork();
+  if (pid < 0) {
+    dbg("Fork failed.\n");
+    return;
+  }
+  if (!pid) {
+    execvp(argv[0], argv);
+    error = errno;
+    _exit(111);
+  }
+  if (error) {
+    waitpid(pid, NULL,0);
+    errno = error;
+    perror_msg("script exec failed");
+  }
+  dbg("script complete.\n");
+}
+
+// returns a randome ID
+static uint32_t getxid(void)
+{
+  uint32_t randnum;
+  int fd = xopenro("/dev/urandom");
+
+// TODO xreadfile
+  xreadall(fd, &randnum, sizeof(randnum));
+  xclose(fd);
+  return randnum;
+}
+
+// opens socket in raw mode.
+static int mode_raw(void)
+{
+  state->mode = MODE_OFF;
+  struct sockaddr_ll sock;
+
+  if (state->sockfd > 0) close(state->sockfd);
+  dbg("Opening raw socket on ifindex %d\n", state->ifindex);
+
+  state->sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+  if (state->sockfd < 0) {
+    dbg("MODE RAW : socket fail ERROR : %d\n", state->sockfd);
+    return -1;
+  }
+  dbg("Got raw socket fd %d\n", state->sockfd);
+  memset(&sock, 0, sizeof(sock));
+  sock.sll_family = AF_PACKET;
+  sock.sll_protocol = htons(ETH_P_IP);
+  sock.sll_ifindex = state->ifindex;
+
+  if (bind(state->sockfd, (struct sockaddr *) &sock, sizeof(sock))) {
+    dbg("MODE RAW : bind fail.\n");
+    close(state->sockfd);
+    return -1;
+  }
+  state->mode = MODE_RAW;
+  if (setsockopt(state->sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) < 0)
+    dbg("MODE RAW : filter attach fail.\n");
+
+  dbg("MODE RAW : success\n");
+  return 0;
+}
+
+// opens UDP socket
+static int mode_app(void)
+{
+  struct sockaddr_in addr;
+  struct ifreq ifr;
+
+  state->mode = MODE_OFF;
+  if (state->sockfd > 0) close(state->sockfd);
+
+  dbg("Opening listen socket on *:%d %s\n", DHCPC_CLIENT_PORT, state->iface);
+  state->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  if (state->sockfd < 0) {
+    dbg("MODE APP : socket fail ERROR: %d\n", state->sockfd);
+    return -1;
+  }
+  setsockopt(state->sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
+  if (setsockopt(state->sockfd, SOL_SOCKET, SO_BROADCAST, &set, sizeof(set)) == -1) {
+    dbg("MODE APP : brodcast failed.\n");
+    close(state->sockfd);
+    return -1;
+  }
+  xstrncpy(ifr.ifr_name, state->iface, IFNAMSIZ);
+  ifr.ifr_name[IFNAMSIZ -1] = '\0';
+  setsockopt(state->sockfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons(DHCPC_CLIENT_PORT);
+  addr.sin_addr.s_addr = INADDR_ANY ;
+
+  if (bind(state->sockfd, (struct sockaddr *) &addr, sizeof(addr))) {
+    close(state->sockfd);
+    dbg("MODE APP : bind failed.\n");
+    return -1;
+  }
+  state->mode = MODE_APP;
+  dbg("MODE APP : success\n");
+  return 0;
+}
+
+static int read_raw(void)
+{
+  dhcp_raw_t packet;
+  uint16_t check;
+  int bytes = 0;
+
+  memset(&packet, 0, sizeof(packet));
+  if ((bytes = read(state->sockfd, &packet, sizeof(packet))) < 0) {
+    dbg("\tPacket read error, ignoring\n");
+    return bytes;
+  }
+  if (bytes < (int) (sizeof(packet.iph) + sizeof(packet.udph))) {
+    dbg("\tPacket is too short, ignoring\n");
+    return -2;
+  }
+  if (bytes < ntohs(packet.iph.tot_len)) {
+    dbg("\tOversized packet, ignoring\n");
+    return -2;
+  }
+  // ignore any extra garbage bytes
+  bytes = ntohs(packet.iph.tot_len);
+  // make sure its the right packet for us, and that it passes sanity checks 
+  if (packet.iph.protocol != IPPROTO_UDP || packet.iph.version != IPVERSION
+   || packet.iph.ihl != (sizeof(packet.iph) >> 2)
+   || packet.udph.dest != htons(DHCPC_CLIENT_PORT)
+   || ntohs(packet.udph.len) != (uint16_t)(bytes - sizeof(packet.iph))) {
+    dbg("\tUnrelated/bogus packet, ignoring\n");
+    return -2;
+  }
+  // verify IP checksum
+  check = packet.iph.check;
+  packet.iph.check = 0;
+  if (check != dhcp_checksum(&packet.iph, sizeof(packet.iph))) {
+    dbg("\tBad IP header checksum, ignoring\n");
+    return -2;
+  }
+  memset(&packet.iph, 0, ((size_t) &((struct iphdr *)0)->protocol));
+  packet.iph.tot_len = packet.udph.len;
+  check = packet.udph.check;
+  packet.udph.check = 0;
+  if (check && check != dhcp_checksum(&packet, bytes)) {
+    dbg("\tPacket with bad UDP checksum received, ignoring\n");
+    return -2;
+  }
+  memcpy(&state->pdhcp, &packet.dhcp, bytes - (sizeof(packet.iph) + sizeof(packet.udph)));
+  if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) {
+    dbg("\tPacket with bad magic, ignoring\n");
+    return -2;
+  }
+  return bytes - sizeof(packet.iph) - sizeof(packet.udph);
+}
+
+static int read_app(void)
+{
+  int ret;
+
+  memset(&state->pdhcp, 0, sizeof(dhcp_msg_t));
+  if ((ret = read(state->sockfd, &state->pdhcp, sizeof(dhcp_msg_t))) < 0) {
+    dbg("Packet read error, ignoring\n");
+    return ret; /* returns -1 */
+  }
+  if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) {
+    dbg("Packet with bad magic, ignoring\n");
+    return -2;
+  }
+  return ret;
+}
+
+// Sends data through raw socket.
+static int send_raw(void)
+{
+  struct sockaddr_ll dest_sll;
+  dhcp_raw_t packet;
+  unsigned padding;
+  int fd, result = -1;
+
+  memset(&packet, 0, sizeof(dhcp_raw_t));
+  memcpy(&packet.dhcp, &state->pdhcp, sizeof(dhcp_msg_t));
+
+  if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
+    dbg("SEND RAW: socket failed\n");
+    return result;
+  }
+  memset(&dest_sll, 0, sizeof(dest_sll));
+  dest_sll.sll_family = AF_PACKET;
+  dest_sll.sll_protocol = htons(ETH_P_IP);
+  dest_sll.sll_ifindex = state->ifindex;
+  dest_sll.sll_halen = 6;
+  memcpy(dest_sll.sll_addr, bmacaddr , 6);
+
+  if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
+    dbg("SEND RAW: bind failed\n");
+    close(fd);
+    return result;
+  }
+  padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options);
+  packet.iph.protocol = IPPROTO_UDP;
+  packet.iph.saddr = INADDR_ANY;
+  packet.iph.daddr = INADDR_BROADCAST;
+  packet.udph.source = htons(DHCPC_CLIENT_PORT);
+  packet.udph.dest = htons(DHCPC_SERVER_PORT);
+  packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding);
+  packet.iph.tot_len = packet.udph.len;
+  packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding);
+  packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding);
+  packet.iph.ihl = sizeof(packet.iph) >> 2;
+  packet.iph.version = IPVERSION;
+  packet.iph.ttl = IPDEFTTL;
+  packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph));
+
+  result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0,
+      (struct sockaddr *) &dest_sll, sizeof(dest_sll));
+
+  close(fd);
+  if (result < 0) dbg("SEND RAW: PACKET send error\n");
+  return result;
+}
+
+// Sends data through UDP socket.
+static int send_app(void)
+{
+  struct sockaddr_in cli;
+  int fd, ret = -1;
+
+  if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+    dbg("SEND APP: sock failed.\n");
+    return ret;
+  }
+  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
+
+  memset(&cli, 0, sizeof(cli));
+  cli.sin_family = AF_INET;
+  cli.sin_port = htons(DHCPC_CLIENT_PORT);
+  cli.sin_addr.s_addr = state->pdhcp.ciaddr;
+  if (bind(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) {
+    dbg("SEND APP: bind failed.\n");
+    goto error_fd;
+  }
+  memset(&cli, 0, sizeof(cli));
+  cli.sin_family = AF_INET;
+  cli.sin_port = htons(DHCPC_SERVER_PORT);
+  cli.sin_addr.s_addr = state->serverid.s_addr;
+  if (connect(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) {
+    dbg("SEND APP: connect failed.\n");
+    goto error_fd;
+  }
+  int padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options);
+  if((ret = write(fd, &state->pdhcp, sizeof(dhcp_msg_t) - padding)) < 0) {
+    dbg("SEND APP: write failed error %d\n", ret);
+    goto error_fd;
+  }
+  dbg("SEND APP: write success wrote %d\n", ret);
+error_fd:
+  close(fd);
+  return ret;
+}
+
+// Generic signal handler real handling is done in main funcrion.
+static void signal_handler(int sig)
+{
+  unsigned char ch = sig;
+  if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n");
+}
+
+// signal setup for SIGUSR1 SIGUSR2 SIGTERM
+static int setup_signal()
+{
+  if (pipe((int *)&sigfd) < 0) {
+    dbg("signal pipe failed\n");
+    return -1;
+  }
+  fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC);
+  fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC);
+  int flags = fcntl(sigfd.wr, F_GETFL);
+  fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK);
+  signal(SIGUSR1, signal_handler);
+  signal(SIGUSR2, signal_handler);
+  signal(SIGTERM, signal_handler);
+
+  return 0;
+}
+
+// adds client id to dhcp packet
+static uint8_t *dhcpc_addclientid(uint8_t *optptr)
+{
+  *optptr++ = DHCP_OPTION_CLIENTID;
+  *optptr++ = 7;
+  *optptr++ = 1;
+  memcpy(optptr, &state->macaddr, 6);
+  return optptr + 6;
+}
+
+// adds messege type to dhcp packet
+static uint8_t *dhcpc_addmsgtype(uint8_t *optptr, uint8_t type)
+{
+  *optptr++ = DHCP_OPTION_MSG_TYPE;
+  *optptr++ = 1;
+  *optptr++ = type;
+  return optptr;
+}
+
+// adds max size to dhcp packet
+static uint8_t *dhcpc_addmaxsize(uint8_t *optptr, uint16_t size)
+{
+  *optptr++ = DHCP_OPTION_MAX_SIZE;
+  *optptr++ = 2;
+  memcpy(optptr, &size, 2);
+  return optptr + 2;
+}
+
+static uint8_t *dhcpc_addstropt(uint8_t *optptr, uint8_t opcode, char* str, int len)
+{
+  *optptr++ = opcode;
+  *optptr++ = len;
+  memcpy(optptr, str, len);
+  return optptr + len;
+}
+
+// adds server id to dhcp packet.
+static uint8_t *dhcpc_addserverid(struct in_addr *serverid, uint8_t *optptr)
+{
+  *optptr++ = DHCP_OPTION_SERVER_ID;
+  *optptr++ = 4;
+  memcpy(optptr, &serverid->s_addr, 4);
+  return optptr + 4;
+}
+
+// adds requested ip address to dhcp packet.
+static uint8_t *dhcpc_addreqipaddr(struct in_addr *ipaddr, uint8_t *optptr)
+{
+  *optptr++ = DHCP_OPTION_REQ_IPADDR;
+  *optptr++ = 4;
+  memcpy(optptr, &ipaddr->s_addr, 4);
+  return optptr + 4;
+}
+
+// adds hostname to dhcp packet.
+static uint8_t *dhcpc_addfdnname(uint8_t *optptr, char *hname)
+{
+  int size = strlen(hname);
+
+  *optptr++ = DHCP_OPTION_FQDN;
+  *optptr++ = size + 3;
+  *optptr++ = 0x1;  //flags
+  optptr += 2;      // two blank bytes
+  strcpy((char*)optptr, hname); // name
+
+  return optptr + size;
+}
+
+// adds request options using -o,-O flag to dhcp packet
+static uint8_t *dhcpc_addreqoptions(uint8_t *optptr)
+{
+  uint8_t *len;
+
+  *optptr++ = DHCP_OPTION_REQ_LIST;
+  len = optptr;
+  *len = 0;
+  optptr++;
+
+  if (!(toys.optflags & FLAG_o)) {
+    *len = 4;
+    *optptr++ = DHCP_OPTION_SUBNET_MASK;
+    *optptr++ = DHCP_OPTION_ROUTER;
+    *optptr++ = DHCP_OPTION_DNS_SERVER;
+    *optptr++ = DHCP_OPTION_BROADCAST;
+  }
+  if (toys.optflags & FLAG_O) {
+    memcpy(optptr++, raw_opt, raw_optcount);
+    *len += raw_optcount;
+  }
+  return optptr;
+}
+
+static uint8_t *dhcpc_addend(uint8_t *optptr)
+{
+  *optptr++ = DHCP_OPTION_END;
+  return optptr;
+}
+
+// Sets values of -x options in dhcp discover and request packet.
+static uint8_t* set_xopt(uint8_t *optptr)
+{
+  int count;
+  int size = ARRAY_LEN(options_list);
+  for (count = 0; count < size; count++) {
+    if ((options_list[count].len == 0) || (options_list[count].val == NULL)) continue;
+    *optptr++ = (uint8_t) (options_list[count].code & 0x00FF);
+    *optptr++ = (uint8_t) options_list[count].len;
+    memcpy(optptr, options_list[count].val, options_list[count].len);
+    optptr += options_list[count].len;
+  }
+  return optptr;
+}
+
+static uint32_t get_option_serverid (uint8_t *opt, dhcpc_result_t *presult)
+{
+  uint32_t var = 0;
+  while (*opt != DHCP_OPTION_SERVER_ID) {
+    if (*opt == DHCP_OPTION_END) return var;
+    opt += opt[1] + 2;
+  }
+  memcpy(&var, opt+2, sizeof(uint32_t));
+  state->serverid.s_addr = var;
+  presult->serverid.s_addr = state->serverid.s_addr;
+  presult->serverid.s_addr = ntohl(presult->serverid.s_addr);
+  return var;
+}
+
+static uint8_t get_option_msgtype(uint8_t *opt)
+{
+  uint32_t var = 0;
+  while (*opt != DHCP_OPTION_MSG_TYPE) {
+    if (*opt == DHCP_OPTION_END) return var;
+    opt += opt[1] + 2;
+  }
+  memcpy(&var, opt+2, sizeof(uint8_t));
+  return var;
+}
+
+static uint8_t get_option_lease(uint8_t *opt, dhcpc_result_t *presult)
+{
+  uint32_t var = 0;
+  while (*opt != DHCP_OPTION_LEASE_TIME) {
+    if (*opt == DHCP_OPTION_END) return var;
+    opt += opt[1] + 2;
+  }
+  memcpy(&var, opt+2, sizeof(uint32_t));
+  var = htonl(var);
+  presult->lease_time = var;
+  return var;
+}
+
+
+// sends dhcp msg of MSGTYPE
+static int dhcpc_sendmsg(int msgtype)
+{
+  uint8_t *pend;
+  struct in_addr rqsd;
+  char *vendor;
+
+  // Create the common message header settings
+  memset(&state->pdhcp, 0, sizeof(dhcp_msg_t));
+  state->pdhcp.op = DHCP_REQUEST;
+  state->pdhcp.htype = DHCP_HTYPE_ETHERNET;
+  state->pdhcp.hlen = 6;
+  state->pdhcp.xid = xid;
+  memcpy(state->pdhcp.chaddr, state->macaddr, 6);
+  memset(&state->pdhcp.chaddr[6], 0, 10);
+  state->pdhcp.cookie = htonl(DHCP_MAGIC);;
+
+  // Add the common header options
+  pend = state->pdhcp.options;
+  pend = dhcpc_addmsgtype(pend, msgtype);
+
+  if (!(toys.optflags & FLAG_C)) pend = dhcpc_addclientid(pend);
+  // Handle the message specific settings
+  switch (msgtype) {
+  case DHCPDISCOVER: // Broadcast DISCOVER message to all servers
+    state->pdhcp.flags = htons(BOOTP_BROADCAST); //  Broadcast bit.
+    if (toys.optflags & FLAG_r) {
+      inet_aton(TT.req_ip, &rqsd);
+      pend = dhcpc_addreqipaddr(&rqsd, pend);
+    }
+    pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t)));
+    vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0";
+    pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor));
+    if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname));
+    if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name);
+    if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O))
+      pend = dhcpc_addreqoptions(pend);
+    if (toys.optflags & FLAG_x) pend = set_xopt(pend);
+    break;
+  case DHCPREQUEST: // Send REQUEST message to the server that sent the *first* OFFER
+    state->pdhcp.flags = htons(BOOTP_BROADCAST); //  Broadcast bit.
+    if (state->status == STATE_RENEWING) memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4);
+    pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t)));
+    rqsd.s_addr = htonl(server);
+    pend = dhcpc_addserverid(&rqsd, pend);
+    pend = dhcpc_addreqipaddr(&state->ipaddr, pend);
+    vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0";
+    pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor));
+    if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname));
+    if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name);
+    if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O))
+      pend = dhcpc_addreqoptions(pend);
+    if (toys.optflags & FLAG_x) pend = set_xopt(pend);
+    break;
+  case DHCPRELEASE: // Send RELEASE message to the server.
+    memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4);
+    rqsd.s_addr = htonl(server);
+    pend = dhcpc_addserverid(&rqsd, pend);
+    break;
+  default:
+    return -1;
+  }
+  pend = dhcpc_addend(pend);
+
+  if (state->mode == MODE_APP) return send_app();
+  return send_raw();
+}
+
+/*
+ * parses options from received dhcp packet at OPTPTR and
+ * stores result in PRESULT or MSGOPT_LIST
+ */
+static uint8_t dhcpc_parseoptions(dhcpc_result_t *presult, uint8_t *optptr)
+{
+  uint8_t type = 0, *options, overloaded = 0;;
+  uint16_t flag = 0;
+  uint32_t convtmp = 0;
+  char *dest, *pfx;
+  struct in_addr addr;
+  int count, optlen, size = ARRAY_LEN(options_list);
+
+  if (toys.optflags & FLAG_x) {
+    if(msgopt_list){
+      for (count = 0; count < size; count++){
+        if(msgopt_list[count].val) free(msgopt_list[count].val);
+        msgopt_list[count].val = NULL;
+        msgopt_list[count].len = 0;
+      }
+    } else {
+     msgopt_list = xmalloc(sizeof(options_list));
+     memcpy(msgopt_list, options_list, sizeof(options_list));
+     for (count = 0; count < size; count++) {
+         msgopt_list[count].len = 0;
+         msgopt_list[count].val = NULL;
+     }
+    }
+  } else {
+    msgopt_list = options_list;
+    for (count = 0; count < size; count++) {
+      msgopt_list[count].len = 0;
+      if(msgopt_list[count].val) free(msgopt_list[count].val);
+      msgopt_list[count].val = NULL;
+    }
+  }
+
+  while (*optptr != DHCP_OPTION_END) {
+    if (*optptr == DHCP_OPTION_PADDING) {
+      optptr++;
+      continue;
+    }
+    if (*optptr == DHCP_OPTION_OVERLOAD) {
+      overloaded = optptr[2];
+      optptr += optptr[1] + 2;
+      continue;
+    }
+    for (count = 0, flag = 0; count < size; count++) {
+      if ((msgopt_list[count].code & 0X00FF) == *optptr) {
+        flag = (msgopt_list[count].code & 0XFF00);
+        break;
+      }
+    }
+    switch (flag) {
+    case DHCP_NUM32:
+      memcpy(&convtmp, &optptr[2], sizeof(uint32_t));
+      convtmp = htonl(convtmp);
+      sprintf(toybuf, "%u", convtmp);
+      msgopt_list[count].val = strdup(toybuf);
+      msgopt_list[count].len = strlen(toybuf);
+      break;
+    case DHCP_NUM16:
+      memcpy(&convtmp, &optptr[2], sizeof(uint16_t));
+      convtmp = htons(convtmp);
+      sprintf(toybuf, "%u", convtmp);
+      msgopt_list[count].val = strdup(toybuf);
+      msgopt_list[count].len = strlen(toybuf);
+      break;
+    case DHCP_NUM8:
+      memcpy(&convtmp, &optptr[2], sizeof(uint8_t));
+      sprintf(toybuf, "%u", convtmp);
+      msgopt_list[count].val = strdup(toybuf);
+      msgopt_list[count].len = strlen(toybuf);
+      break;
+    case DHCP_IP:
+      memcpy(&convtmp, &optptr[2], sizeof(uint32_t));
+      addr.s_addr = convtmp;
+      sprintf(toybuf, "%s", inet_ntoa(addr));
+      msgopt_list[count].val = strdup(toybuf);
+      msgopt_list[count].len = strlen(toybuf);
+      break;
+    case DHCP_STRING:
+      sprintf(toybuf, "%.*s", optptr[1], &optptr[2]);
+      msgopt_list[count].val = strdup(toybuf);
+      msgopt_list[count].len = strlen(toybuf);
+      break;
+    case DHCP_IPLIST:
+      optlen = optptr[1];
+      dest = toybuf;
+      while (optlen) {
+        memcpy(&convtmp, &optptr[2], sizeof(uint32_t));
+        addr.s_addr = convtmp;
+        dest += sprintf(dest, "%s ", inet_ntoa(addr));
+        optlen -= 4;
+      }
+      *(dest - 1) = '\0';
+      msgopt_list[count].val = strdup(toybuf);
+      msgopt_list[count].len = strlen(toybuf);
+      break;
+    case DHCP_STRLST: //FIXME: do smthing.
+    case DHCP_IPPLST:
+      break;
+    case DHCP_STCRTS:
+      pfx = "";
+      dest = toybuf;
+      options = &optptr[2];
+      optlen = optptr[1];
+
+      while (optlen >= 1 + 4) {
+        uint32_t nip = 0;
+        int bytes;
+        uint8_t *p_tmp;
+        unsigned mask = *options;
+
+        if (mask > 32) break;
+        optlen--;
+        p_tmp = (void*) &nip;
+        bytes = (mask + 7) / 8;
+        while (--bytes >= 0) {
+          *p_tmp++ = *options++;
+          optlen--;
+        }
+        if (optlen < 4) break;
+        dest += sprintf(dest, "%s%u.%u.%u.%u", pfx, ((uint8_t*) &nip)[0],
+            ((uint8_t*) &nip)[1], ((uint8_t*) &nip)[2], ((uint8_t*) &nip)[3]);
+        pfx = " ";
+        dest += sprintf(dest, "/%u ", mask);
+        dest += sprintf(dest, "%u.%u.%u.%u", options[0], options[1], options[2], options[3]);
+        options += 4;
+        optlen -= 4;
+      }
+      msgopt_list[count].val = strdup(toybuf);
+      msgopt_list[count].len = strlen(toybuf);
+      break;
+    default: break;
+    }
+    optptr += optptr[1] + 2;
+  }
+  if ((overloaded == 1) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
+  if ((overloaded == 2) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
+  return type;
+}
+
+// parses recvd messege to check that it was for us.
+static uint8_t dhcpc_parsemsg(dhcpc_result_t *presult)
+{
+  if (state->pdhcp.op == DHCP_REPLY
+      && !memcmp(state->pdhcp.chaddr, state->macaddr, 6)
+      && !memcmp(&state->pdhcp.xid, &xid, sizeof(xid))) {
+    memcpy(&presult->ipaddr.s_addr, &state->pdhcp.yiaddr, 4);
+    presult->ipaddr.s_addr = ntohl(presult->ipaddr.s_addr);
+    return get_option_msgtype(state->pdhcp.options);
+  }
+  return 0;
+}
+
+// Sends a IP renew request.
+static void renew(void)
+{
+  infomsg(infomode, "Performing a DHCP renew");
+  switch (state->status) {
+  case STATE_INIT:
+    break;
+  case STATE_BOUND:
+    mode_raw();
+  case STATE_RENEWING:    // FALLTHROUGH 
+  case STATE_REBINDING:   // FALLTHROUGH 
+    state->status = STATE_RENEW_REQUESTED;
+    break;
+  case STATE_RENEW_REQUESTED:
+    run_script(NULL, "deconfig");
+  case STATE_REQUESTING:           // FALLTHROUGH 
+  case STATE_RELEASED:             // FALLTHROUGH 
+    mode_raw();
+    state->status = STATE_INIT;
+    break;
+  default: break;
+  }
+}
+
+// Sends a IP release request.
+static void release(void)
+{
+  char buffer[sizeof("255.255.255.255\0")];
+  struct in_addr temp_addr;
+
+  mode_app();
+  // send release packet
+  if (state->status == STATE_BOUND || state->status == STATE_RENEWING || state->status == STATE_REBINDING) {
+    temp_addr.s_addr = htonl(server);
+    xstrncpy(buffer, inet_ntoa(temp_addr), sizeof(buffer));
+    temp_addr.s_addr = state->ipaddr.s_addr;
+    infomsg( infomode, "Unicasting a release of %s to %s", inet_ntoa(temp_addr), buffer);
+    dhcpc_sendmsg(DHCPRELEASE);
+    run_script(NULL, "deconfig");
+  }
+  infomsg(infomode, "Entering released state");
+  close(state->sockfd);
+  state->sockfd = -1;
+  state->mode = MODE_OFF;
+  state->status = STATE_RELEASED;
+}
+
+static void free_option_stores(void)
+{
+  int count, size = ARRAY_LEN(options_list);
+  for (count = 0; count < size; count++)
+    if (options_list[count].val) free(options_list[count].val);
+  if (toys.optflags & FLAG_x) {
+    for (count = 0; count < size; count++)
+        if (msgopt_list[count].val) free(msgopt_list[count].val);
+    free(msgopt_list);
+  }
+}
+
+void dhcp_main(void)
+{
+  struct timeval tv;
+  int retval, bufflen = 0;
+  dhcpc_result_t result;
+  uint8_t packets = 0, retries = 0;
+  uint32_t timeout = 0, waited = 0;
+  fd_set rfds;
+
+  xid = 0;
+  setlinebuf(stdout);
+  dbg = dummy;
+  if (toys.optflags & FLAG_v) dbg = xprintf;
+  if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
+  retries = TT.retries;
+  if (toys.optflags & FLAG_S) {
+      openlog("UDHCPC :", LOG_PID, LOG_DAEMON);
+      infomode |= LOG_SYSTEM;
+  }
+  infomsg(infomode, "dhcp started");
+  if (toys.optflags & FLAG_O) {
+    while (TT.req_opt) {
+      raw_opt[raw_optcount] = (uint8_t) strtoopt(TT.req_opt->arg, 1);
+      raw_optcount++;
+      TT.req_opt = TT.req_opt->next;
+    }
+  }
+  if (toys.optflags & FLAG_x) {
+    while (TT.pkt_opt) {
+      (void) strtoopt(TT.pkt_opt->arg, 0);
+      TT.pkt_opt = TT.pkt_opt->next;
+    }
+  }
+  memset(&result, 0, sizeof(dhcpc_result_t));
+  state = (dhcpc_state_t*) xmalloc(sizeof(dhcpc_state_t));
+  memset(state, 0, sizeof(dhcpc_state_t));
+  state->iface = (toys.optflags & FLAG_i) ? TT.iface : "eth0";
+
+  if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
+    perror_exit("Failed to get interface %s", state->iface);
+
+  run_script(NULL, "deconfig");
+  setup_signal();
+  state->status = STATE_INIT;
+  mode_raw();
+  fcntl(state->sockfd, F_SETFD, FD_CLOEXEC);
+
+  for (;;) {
+    FD_ZERO(&rfds);
+    if (state->sockfd >= 0) FD_SET(state->sockfd, &rfds);
+    FD_SET(sigfd.rd, &rfds);
+    tv.tv_sec = timeout - waited;
+    tv.tv_usec = 0;
+    retval = 0;
+
+    int maxfd = (sigfd.rd > state->sockfd)? sigfd.rd : state->sockfd;
+    dbg("select wait ....\n");
+    uint32_t timestmp = time(NULL);
+    if((retval = select(maxfd + 1, &rfds, NULL, NULL, &tv)) < 0) {
+      if (errno == EINTR) {
+        waited += (unsigned) time(NULL) - timestmp;
+        continue;
+      }
+      perror_exit("Error in select");
+    }
+    if (!retval) { // Timed out
+      if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
+        error_exit("Interface lost %s\n", state->iface);
+
+      switch (state->status) {
+      case STATE_INIT:
+        if (packets < retries) {
+          if (!packets) xid = getxid();
+          run_script(NULL, "deconfig");
+          infomsg(infomode, "Sending discover...");
+          dhcpc_sendmsg(DHCPDISCOVER);
+          server = 0;
+          timeout = TT.timeout;
+          waited = 0;
+          packets++;
+          continue;
+        }
+lease_fail:
+        run_script(NULL,"leasefail");
+        if (toys.optflags & FLAG_n) {
+          infomsg(infomode, "Lease failed. Exiting");
+          goto ret_with_sockfd;
+        }
+        if (toys.optflags & FLAG_b) {
+          infomsg(infomode, "Lease failed. Going Daemon mode");
+          daemon(0, 0);
+          if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
+          toys.optflags &= ~FLAG_b;
+          toys.optflags |= FLAG_f;
+        }
+        timeout = TT.tryagain;
+        waited = 0;
+        packets = 0;
+        continue;
+      case STATE_REQUESTING:
+        if (packets < retries) {
+          memcpy(&state->ipaddr.s_addr,&state->pdhcp.yiaddr, 4);
+          dhcpc_sendmsg(DHCPREQUEST);
+          infomsg(infomode, "Sending select for %d.%d.%d.%d...",
+              (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff);
+          timeout = TT.timeout;
+          waited = 0;
+          packets++;
+          continue;
+        }
+        mode_raw();
+        state->status = STATE_INIT;
+        goto lease_fail;
+      case STATE_BOUND:
+        state->status = STATE_RENEWING;
+        dbg("Entering renew state\n");
+        // FALLTHROUGH
+      case STATE_RENEW_REQUESTED:   // FALLTHROUGH
+      case STATE_RENEWING:
+renew_requested:
+        if (timeout > 60) {
+          dhcpc_sendmsg(DHCPREQUEST);
+          timeout >>= 1;
+          waited = 0;
+          continue;
+        }
+        dbg("Entering rebinding state\n");
+        state->status = STATE_REBINDING;
+        // FALLTHROUGH
+      case STATE_REBINDING:
+        mode_raw();
+        if (timeout > 0) {
+          dhcpc_sendmsg(DHCPREQUEST);
+          timeout >>= 1;
+          waited = 0;
+          continue;
+        }
+        infomsg(infomode, "Lease lost, entering INIT state");
+        run_script(NULL, "deconfig");
+        state->status = STATE_INIT;
+        timeout = 0;
+        waited = 0;
+        packets = 0;
+        continue;
+      default: break;
+      }
+      timeout = INT_MAX;
+      waited = 0;
+      continue;
+    }
+    if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal
+      unsigned char sig;
+      if (read(sigfd.rd, &sig, 1) != 1) {
+        dbg("signal read failed.\n");
+        continue;
+      }
+      switch (sig) {
+      case SIGUSR1:
+        infomsg(infomode, "Received SIGUSR1");
+        renew();
+        packets = 0;
+        waited = 0;
+        if (state->status == STATE_RENEW_REQUESTED) goto renew_requested;
+        if (state->status == STATE_INIT) timeout = 0;
+        continue;
+      case SIGUSR2:
+        infomsg(infomode, "Received SIGUSR2");
+        release();
+        timeout = INT_MAX;
+        waited = 0;
+        packets = 0;
+        continue;
+      case SIGTERM:
+        infomsg(infomode, "Received SIGTERM");
+        if (toys.optflags & FLAG_R) release();
+        goto ret_with_sockfd;
+      default: break;
+      }
+    }
+    if (FD_ISSET(state->sockfd, &rfds)) { // Some Activity on RDFDs : is socket
+      dbg("main sock read\n");
+      uint8_t msgType;
+      if (state->mode == MODE_RAW) bufflen = read_raw();
+      if (state->mode == MODE_APP) bufflen = read_app();
+      if (bufflen < 0) {
+        if (state->mode == MODE_RAW) mode_raw();
+        if (state->mode == MODE_APP) mode_app();
+        continue;
+      }
+      waited += time(NULL) - timestmp;
+      memset(&result, 0, sizeof(dhcpc_result_t));
+      msgType = dhcpc_parsemsg(&result);
+      if (msgType != DHCPNAK && result.ipaddr.s_addr == 0 ) continue;       // no ip for me ignore
+      if (!msgType || !get_option_serverid(state->pdhcp.options, &result)) continue; //no server id ignore
+      if (msgType == DHCPOFFER && server == 0) server = result.serverid.s_addr; // select the server
+      if (result.serverid.s_addr != server) continue; // not from the server we requested ignore
+      dhcpc_parseoptions(&result, state->pdhcp.options);
+      get_option_lease(state->pdhcp.options, &result);
+
+      switch (state->status) {
+      case STATE_INIT:
+        if (msgType == DHCPOFFER) {
+          state->status = STATE_REQUESTING;
+          mode_raw();
+          timeout = 0;
+          waited = 0;
+          packets = 0;
+        }
+        continue;
+      case STATE_REQUESTING:         // FALLTHROUGH
+      case STATE_RENEWING:           // FALLTHROUGH
+      case STATE_RENEW_REQUESTED:    // FALLTHROUGH
+      case STATE_REBINDING:
+        if (msgType == DHCPACK) {
+          timeout = result.lease_time / 2;
+          run_script(&result, state->status == STATE_REQUESTING ? "bound" : "renew");
+          state->status = STATE_BOUND;
+          infomsg(infomode, "Lease of %d.%d.%d.%d obtained, lease time %d from server %d.%d.%d.%d",
+              (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff,
+              result.lease_time,
+              (result.serverid.s_addr >> 24) & 0xff, (result.serverid.s_addr >> 16) & 0xff, (result.serverid.s_addr >> 8) & 0xff, (result.serverid.s_addr) & 0xff);
+          if (toys.optflags & FLAG_q) {
+            if (toys.optflags & FLAG_R) release();
+            goto ret_with_sockfd;
+          }
+          toys.optflags &= ~FLAG_n;
+          if (!(toys.optflags & FLAG_f)) {
+            daemon(0, 0);
+            toys.optflags |= FLAG_f;
+            if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
+          }
+          waited = 0;
+          continue;
+        } else if (msgType == DHCPNAK) {
+          dbg("NACK received.\n");
+          run_script(&result, "nak");
+          if (state->status != STATE_REQUESTING) run_script(NULL, "deconfig");
+          mode_raw();
+          sleep(3);
+          state->status = STATE_INIT;
+          state->ipaddr.s_addr = 0;
+          server = 0;
+          timeout = 0;
+          packets = 0;
+          waited = 0;
+        }
+        continue;
+      default: break;
+      }
+    }
+  }
+ret_with_sockfd:
+  if (CFG_TOYBOX_FREE) {
+    free_option_stores();
+    if (state->sockfd > 0) close(state->sockfd);
+    free(state);
+  }
+}
diff --git a/toybox/toys/pending/dhcp6.c b/toybox/toys/pending/dhcp6.c
new file mode 100644
index 0000000..755c151
--- /dev/null
+++ b/toybox/toys/pending/dhcp6.c
@@ -0,0 +1,692 @@
+/* dhcp6.c - DHCP6 client for dynamic network configuration.
+ *
+ * Copyright 2015 Rajni Kant <rajnikant12345@gmail.com>
+ *
+ * Not in SUSv4.
+USE_DHCP6(NEWTOY(dhcp6, "r:A#<0T#<0t#<0s:p:i:SRvqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
+
+config DHCP6
+  bool "dhcp6"
+  default n
+  help
+  usage: dhcp6 [-fbnqvR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]
+
+        Configure network dynamicaly using DHCP.
+
+      -i Interface to use (default eth0)
+      -p Create pidfile
+      -s Run PROG at DHCP events 
+      -t Send up to N Solicit packets
+      -T Pause between packets (default 3 seconds)
+      -A Wait N seconds after failure (default 20)
+      -f Run in foreground
+      -b Background if lease is not obtained
+      -n Exit if lease is not obtained
+      -q Exit after obtaining lease
+      -R Release IP on exit
+      -S Log to syslog too
+      -r Request this IP address
+      -v Verbose
+
+      Signals:
+      USR1  Renew current lease
+      USR2  Release current lease
+*/
+#define FOR_dhcp6
+#include "toys.h"
+#include <linux/sockios.h> 
+#include <linux/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <linux/if_packet.h>
+#include <syslog.h>
+
+GLOBALS(
+  char *interface_name, *pidfile, *script;
+  long retry, timeout, errortimeout;
+  char *req_ip;
+  int length, state, request_length, sock, sock1, status, retval, retries;
+  struct timeval tv;
+  uint8_t transction_id[3];
+  struct sockaddr_in6 input_socket6;
+)
+
+#define DHCP6SOLICIT        1
+#define DHCP6ADVERTISE      2   // server -> client
+#define DHCP6REQUEST        3
+#define DHCP6CONFIRM        4
+#define DHCP6RENEW          5
+#define DHCP6REBIND         6
+#define DHCP6REPLY          7   // server -> client
+#define DHCP6RELEASE        8
+#define DHCP6DECLINE        9
+#define DHCP6RECONFIGURE    10  // server -> client
+#define DHCP6INFOREQUEST    11
+#define DHCP6RELAYFLOW      12  // relay -> relay/server
+#define DHCP6RELAYREPLY     13  // server/relay -> relay
+
+// DHCPv6 option codes (partial). See RFC 3315
+#define DHCP6_OPT_CLIENTID      1
+#define DHCP6_OPT_SERVERID      2
+#define DHCP6_OPT_IA_NA         3
+#define DHCP6_OPT_IA_ADDR       5
+#define DHCP6_OPT_ORO           6
+#define DHCP6_OPT_PREFERENCE    7
+#define DHCP6_OPT_ELAPSED_TIME  8
+#define DHCP6_OPT_RELAY_MSG     9
+#define DHCP6_OPT_STATUS_CODE   13
+#define DHCP6_OPT_IA_PD         25
+#define DHCP6_OPT_IA_PREFIX     26
+
+#define DHCP6_STATUS_SUCCESS        0
+#define DHCP6_STATUS_NOADDRSAVAIL   2
+
+#define DHCP6_DUID_LLT    1
+#define DHCP6_DUID_EN     2
+#define DHCP6_DUID_LL     3
+#define DHCP6_DUID_UUID   4
+
+#define DHCPC_SERVER_PORT     547
+#define DHCPC_CLIENT_PORT     546
+  
+#define LOG_SILENT          0x0
+#define LOG_CONSOLE         0x1
+#define LOG_SYSTEM          0x2
+  
+typedef struct __attribute__((packed)) dhcp6_msg_s {
+  uint8_t msgtype, transaction_id[3], options[524];
+} dhcp6_msg_t;
+
+typedef struct __attribute__((packed)) optval_duid_llt {
+  uint16_t type;
+  uint16_t hwtype;
+  uint32_t time;
+  uint8_t lladdr[6];
+} DUID;
+
+typedef struct __attribute__((packed)) optval_ia_na {
+  uint32_t iaid, t1, t2;
+} IA_NA;
+
+typedef struct __attribute__((packed)) dhcp6_raw_s {
+  struct ip6_hdr iph;
+  struct udphdr udph;
+  dhcp6_msg_t dhcp6;
+} dhcp6_raw_t;
+
+typedef struct __attribute__((packed)) dhcp_data_client {
+  uint16_t  status_code;
+  uint32_t iaid , t1,t2, pf_lf, va_lf;
+  uint8_t ipaddr[17] ;
+} DHCP_DATA;
+
+static DHCP_DATA dhcp_data;
+static dhcp6_raw_t *mymsg;
+static dhcp6_msg_t mesg;
+static DUID *duid;
+
+static void (*dbg)(char *format, ...);
+static void dummy(char *format, ...)
+{
+  return;
+}
+
+static void logit(char *format, ...)
+{
+  int used;
+  char *msg;
+  va_list p, t;
+  uint8_t infomode = LOG_SILENT;
+  
+  if (toys.optflags & FLAG_S) infomode |= LOG_SYSTEM;
+  if(toys.optflags & FLAG_v) infomode |= LOG_CONSOLE;
+  va_start(p, format);
+  va_copy(t, p);
+  used = vsnprintf(NULL, 0, format, t);
+  used++;
+  va_end(t);
+
+  msg = xmalloc(used);
+  vsnprintf(msg, used, format, p);
+  va_end(p);
+
+  if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
+  if (infomode & LOG_CONSOLE) printf("%s", msg);
+  free(msg);
+  return;
+}
+
+static void get_mac(uint8_t *mac, char *interface)
+{
+  int fd;
+  struct ifreq req;
+          
+  if (!mac) return;
+  fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
+  req.ifr_addr.sa_family = AF_INET6;
+  xstrncpy(req.ifr_name, interface, IFNAMSIZ);
+  xioctl(fd, SIOCGIFHWADDR, &req);
+  memcpy(mac, req.ifr_hwaddr.sa_data, 6);
+  xclose(fd);
+}
+
+static void fill_option(uint16_t option_id, uint16_t option_len, uint8_t **dhmesg)
+{
+  uint8_t *tmp = *dhmesg;
+  
+  *((uint16_t*)tmp) = htons(option_id);
+  *(uint16_t*)(tmp+2) = htons(option_len);
+  *dhmesg += 4;
+  TT.length += 4;
+}
+
+static void fill_clientID() 
+{  
+  uint8_t *tmp = &mesg.options[TT.length];
+  
+  if(!duid) {
+    uint8_t mac[7] = {0,};
+    duid = (DUID*)malloc(sizeof(DUID));
+    duid->type = htons(1);
+    duid->hwtype = htons(1);
+    duid->time = htonl((uint32_t)(time(NULL) - 946684800) & 0xffffffff);
+    fill_option(DHCP6_OPT_CLIENTID,14,&tmp);
+    get_mac(mac, TT.interface_name);
+    memcpy(duid->lladdr,mac, 6);
+    memcpy(tmp,(uint8_t*)duid,sizeof(DUID));
+  }
+  else {
+    fill_option(DHCP6_OPT_CLIENTID,14,&tmp);
+    memcpy(tmp,(uint8_t*)duid,sizeof(DUID));
+  }
+  TT.length += sizeof(DUID);
+}
+
+// TODO: make it generic for multiple options.
+static void fill_optionRequest() 
+{
+  uint8_t *tmp = &mesg.options[TT.length];
+  
+  fill_option(DHCP6_OPT_ORO,4,&tmp);
+  *(uint16_t*)(tmp+4) = htons(23);
+  *(uint16_t*)(tmp+6) = htons(24);
+  TT.length += 4;
+}
+
+static void fill_elapsedTime()
+{
+  uint8_t *tmp = &mesg.options[TT.length];
+  
+  fill_option(DHCP6_OPT_ELAPSED_TIME, 2, &tmp);
+  *(uint16_t*)(tmp+6) = htons(0);
+  TT.length += 2;
+}
+
+static void fill_iaid() 
+{
+  IA_NA iana;
+  uint8_t *tmp = &mesg.options[TT.length];
+  
+  fill_option(DHCP6_OPT_IA_NA, 12, &tmp);
+  iana.iaid = rand();
+  iana.t1 = 0xffffffff;
+  iana.t2 = 0xffffffff;
+  memcpy(tmp, (uint8_t*)&iana, sizeof(IA_NA));
+  TT.length += sizeof(IA_NA);
+}
+
+//static void mode_raw(int *sock_t)
+static void mode_raw()
+{
+  int constone = 1;
+  struct sockaddr_ll sockll;
+  
+  if (TT.sock > 0) xclose(TT.sock);
+  TT.sock = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
+  
+  memset(&sockll, 0, sizeof(sockll));
+  sockll.sll_family = AF_PACKET;
+  sockll.sll_protocol = htons(ETH_P_IPV6);
+  sockll.sll_ifindex = if_nametoindex(TT.interface_name);
+  if (bind(TT.sock, (struct sockaddr *) &sockll, sizeof(sockll))) {
+    xclose(TT.sock);
+    error_exit("MODE RAW : Bind fail.\n");
+  } 
+  if (setsockopt(TT.sock, SOL_PACKET, PACKET_HOST,&constone, sizeof(int)) < 0) {
+		if (errno != ENOPROTOOPT) error_exit("MODE RAW : Bind fail.\n");
+	}
+}
+
+static void generate_transection_id() 
+{
+  int i, r = rand() % 0xffffff;
+  
+  for (i=0; i<3; i++) {
+    TT.transction_id[i] = r%0xff;
+    r = r/10;
+  }  
+}
+
+static void set_timeout(int seconds) 
+{
+  TT.tv.tv_sec = seconds;
+  TT.tv.tv_usec = 100000;
+}
+
+static void  send_msg(int type)
+{
+  struct sockaddr_in6 addr6;
+  int sendlength = 0;
+  
+  memset(&addr6, 0, sizeof(addr6));
+  addr6.sin6_family = AF_INET6;
+  addr6.sin6_port = htons(DHCPC_SERVER_PORT); //SERVER_PORT
+  inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
+  mesg.msgtype = type;
+  generate_transection_id();
+  memcpy(mesg.transaction_id, TT.transction_id, 3);
+  
+  if (type  == DHCP6SOLICIT) {
+    TT.length = 0;
+    fill_clientID();
+    fill_optionRequest();
+    fill_elapsedTime();
+    fill_iaid();
+    sendlength = sizeof(dhcp6_msg_t) - 524 + TT.length;
+  } else if (type == DHCP6REQUEST || type == DHCP6RELEASE || type == DHCP6RENEW) 
+    sendlength = TT.request_length;
+  dbg("Sending message type: %d\n", type);
+  sendlength = sendto(TT.sock1, &mesg, sendlength , 0,(struct sockaddr *)&addr6,
+          sizeof(struct sockaddr_in6 ));
+  if (sendlength <= 0) dbg("Error in sending message type: %d\n", type);
+}
+
+uint8_t *get_msg_ptr(uint8_t *data, int data_length, int msgtype)
+{
+  uint16_t type =  *((uint16_t*)data), length = *((uint16_t*)(data+2));
+  
+  type = ntohs(type);
+  if (type == msgtype) return data;
+  length = ntohs(length);
+  while (type != msgtype) {
+    data_length -= (4 + length);
+    if (data_length <= 0) break;
+    data = data + 4 + length;
+    type = ntohs(*((uint16_t*)data));
+    length = ntohs(*((uint16_t*)(data+2)));
+    if (type == msgtype) return data;
+  }
+  return NULL;
+}
+
+static uint8_t *check_server_id(uint8_t *data, int data_length)
+{
+  return get_msg_ptr(data,  data_length, DHCP6_OPT_SERVERID);
+}
+
+static int check_client_id(uint8_t *data, int data_length)
+{
+  if ((data = get_msg_ptr(data,  data_length, DHCP6_OPT_CLIENTID))) {
+    DUID one = *((DUID*)(data+4));
+    DUID two = *((DUID*)&mesg.options[4]);
+    
+    if (!memcmp(&one, &two, sizeof(DUID))) return 1;
+  }
+  return 0;
+}
+
+static int validate_ids() 
+{
+  if (!check_server_id(mymsg->dhcp6.options, 
+    TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
+    dbg("Invalid server id: %d\n");
+    return 0;
+  }
+  if (!check_client_id(mymsg->dhcp6.options, 
+    TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
+    dbg("Invalid client id: %d\n");
+    return 0;
+  }
+  return 1;
+}
+
+static void parse_ia_na(uint8_t *data, int data_length) 
+{
+  uint8_t *t = get_msg_ptr(data, data_length, DHCP6_OPT_IA_NA);
+  uint16_t iana_len, content_len = 0;
+  
+  memset(&dhcp_data,0,sizeof(dhcp_data));
+  if (!t) return;
+  
+  iana_len = ntohs(*((uint16_t*)(t+2)));
+  dhcp_data.iaid = ntohl(*((uint32_t*)(t+4)));
+  dhcp_data.t1 = ntohl(*((uint32_t*)(t+8)));
+  dhcp_data.t2 = ntohl(*((uint32_t*)(t+12)));
+  t += 16;
+  iana_len -= 12;
+  
+  while(iana_len > 0) {
+    uint16_t sub_type = ntohs(*((uint16_t*)(t)));
+    
+    switch (sub_type) {
+      case DHCP6_OPT_IA_ADDR:
+        content_len = ntohs(*((uint16_t*)(t+2)));
+        memcpy(dhcp_data.ipaddr,t+4,16);
+        if (TT.state == DHCP6SOLICIT) {
+          if (TT.req_ip) {
+            struct addrinfo *res = NULL;
+            
+            if(!getaddrinfo(TT.req_ip, NULL, NULL,&res)) {
+              dbg("Requesting IP: %s\n", TT.req_ip);
+              memcpy (&TT.input_socket6, res->ai_addr, res->ai_addrlen);
+              memcpy(t+4, TT.input_socket6.sin6_addr.__in6_u.__u6_addr8, 16);
+            } else xprintf("Invalid IP: %s\n",TT.req_ip);
+            freeaddrinfo(res);
+          }
+        }
+        dhcp_data.pf_lf = ntohl(*((uint32_t*)(t+20)));
+        dhcp_data.va_lf = ntohl(*((uint32_t*)(t+24)));
+        iana_len -= (content_len + 4);
+        t += (content_len + 4);
+        break;
+      case DHCP6_OPT_STATUS_CODE:
+        content_len = ntohs(*((uint16_t*)(t+2)));
+        dhcp_data.status_code = ntohs(*((uint16_t*)(t+4)));
+        iana_len -= (content_len + 4);
+        t += (content_len + 4);
+        break;
+      default:
+        content_len = ntohs(*((uint16_t*)(t+2)));
+        iana_len -= (content_len + 4);
+        t += (content_len + 4);
+        break;
+    }
+  }
+}
+
+static void write_pid(char *path)
+{
+  int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+  
+  if (pidfile > 0) {
+    char pidbuf[12];
+
+    sprintf(pidbuf, "%u", (unsigned)getpid());
+    write(pidfile, pidbuf, strlen(pidbuf));
+    close(pidfile);
+  }
+}
+
+// Creates environment pointers from RES to use in script
+static int fill_envp(DHCP_DATA *res)
+{
+  int ret = setenv("interface", TT.interface_name, 1);
+  
+  if (ret) return ret;
+  inet_ntop(AF_INET6, res->ipaddr, toybuf, INET6_ADDRSTRLEN);
+  ret = setenv("ip",(const char*)toybuf , 1);
+  return ret;
+}
+
+// Executes Script NAME.
+static void run_script(DHCP_DATA *res,  char *name)
+{
+  volatile int error = 0;
+  struct stat sts;
+  pid_t pid;
+  char *argv[3];  
+  char *script = (toys.optflags & FLAG_s) ? TT.script
+    : "/usr/share/dhcp/default.script";
+
+  if (stat(script, &sts) == -1 && errno == ENOENT) return;
+  if (!res || fill_envp(res)) {
+    dbg("Failed to create environment variables.\n");
+    return;
+  }
+  dbg("Executing %s %s\n", script, name);
+  argv[0] = (char*)script;
+  argv[1] = (char*)name;
+  argv[2] = NULL;
+  fflush(NULL);
+
+  pid = vfork();
+  if (pid < 0) {
+    dbg("Fork failed.\n");
+    return;
+  }
+  if (!pid) {
+    execvp(argv[0], argv);
+    error = errno;
+    _exit(111);
+  }
+  if (error) {
+    waitpid(pid, NULL, 0);
+    errno = error;
+    perror_msg("script exec failed");
+  }
+  dbg("script complete.\n");
+}
+
+static void lease_fail()
+{
+  dbg("Lease failed.\n");
+  run_script(NULL, "leasefail");
+  if (toys.optflags & FLAG_n) {
+    xclose(TT.sock);
+    xclose(TT.sock1);
+    error_exit("Lease Failed, Exiting.");
+  }
+  if (toys.optflags & FLAG_b) {
+    dbg("Lease failed. Going to daemon mode.\n");
+    if (daemon(0,0)) perror_exit("daemonize");
+    if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
+    toys.optflags &= ~FLAG_b;
+    toys.optflags |= FLAG_f;
+  }
+}
+
+// Generic signal handler real handling is done in main funcrion.
+static void signal_handler(int sig)
+{
+    dbg("Caught signal: %d\n", sig);
+    switch (sig) {
+    case SIGUSR1:
+      dbg("SIGUSR1.\n");
+      if (TT.state == DHCP6RELEASE || TT.state == DHCP6REQUEST ) {
+        TT.state = DHCP6SOLICIT;
+        set_timeout(0);
+        return;
+      }
+      dbg("SIGUSR1 sending renew.\n");
+      send_msg(DHCP6RENEW);
+      TT.state = DHCP6RENEW;
+      TT.retries = 0;
+      set_timeout(0);
+      break;
+    case SIGUSR2:
+      dbg("SIGUSR2.\n");
+      if (TT.state == DHCP6RELEASE) return;
+      if (TT.state != DHCP6CONFIRM ) return;
+      dbg("SIGUSR2 sending release.\n");
+      send_msg(DHCP6RELEASE);
+      TT.state = DHCP6RELEASE;
+      TT.retries = 0;
+      set_timeout(0);
+      break;
+    case SIGTERM:
+    case SIGINT:
+      dbg((sig == SIGTERM)?"SIGTERM.\n":"SIGINT.\n");
+      if ((toys.optflags & FLAG_R) && TT.state == DHCP6CONFIRM)
+        send_msg(DHCP6RELEASE);
+      if(sig == SIGINT) exit(0);
+      break;
+    default: break;
+  }
+}
+
+// signal setup for SIGUSR1 SIGUSR2 SIGTERM
+static int setup_signal()
+{
+  signal(SIGUSR1, signal_handler);
+  signal(SIGUSR2, signal_handler);
+  signal(SIGTERM, signal_handler);
+  signal(SIGINT, signal_handler);
+  return 0;
+}
+
+void dhcp6_main(void)
+{
+  struct sockaddr_in6  sinaddr6;
+  int constone = 1;
+  fd_set rfds;
+  
+  srand(time(NULL));  
+  setlinebuf(stdout);
+  dbg = dummy;
+  TT.state = DHCP6SOLICIT;
+  
+  if (toys.optflags & FLAG_v) dbg = logit;
+  if (!TT.interface_name) TT.interface_name = "eth0";
+  if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
+  if (!TT.retry) TT.retry = 3;
+  if (!TT.timeout) TT.timeout = 3;
+  if (!TT.errortimeout) TT.errortimeout = 20;
+  if (toys.optflags & FLAG_S) {
+    openlog("DHCP6 :", LOG_PID, LOG_DAEMON);
+    dbg = logit;
+  }
+  
+  dbg("Interface: %s\n", TT.interface_name);
+  dbg("pid file: %s\n", TT.pidfile);
+  dbg("Retry count: %d\n", TT.retry);
+  dbg("Timeout : %d\n", TT.timeout);
+  dbg("Error timeout: %d\n", TT.errortimeout);
+  
+  
+  
+  setup_signal();
+  TT.sock1 = xsocket(PF_INET6, SOCK_DGRAM, 0);  
+  memset(&sinaddr6, 0, sizeof(sinaddr6));
+  sinaddr6.sin6_family = AF_INET6;
+  sinaddr6.sin6_port = htons(DHCPC_CLIENT_PORT);
+  sinaddr6.sin6_scope_id = if_nametoindex(TT.interface_name);
+  sinaddr6.sin6_addr = in6addr_any ;
+  
+  xsetsockopt(TT.sock1, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
+  
+  if (bind(TT.sock1, (struct sockaddr *)&sinaddr6, sizeof(sinaddr6))) {
+    xclose(TT.sock1);
+    error_exit("bind failed");
+  }
+  
+  mode_raw();
+  set_timeout(0);
+  for (;;) {
+    int maxfd = TT.sock;
+    
+    if (TT.sock >= 0) FD_SET(TT.sock, &rfds);
+    TT.retval = 0;    
+    if ((TT.retval = select(maxfd + 1, &rfds, NULL, NULL, &TT.tv)) < 0) {
+      if(errno == EINTR) continue;
+      perror_exit("Error in select");
+    }
+    if (!TT.retval) {
+      if (TT.state == DHCP6SOLICIT || TT.state == DHCP6CONFIRM) {
+        dbg("State is solicit, sending solicit packet\n");
+        run_script(NULL, "deconfig");
+        send_msg(DHCP6SOLICIT);
+        TT.state = DHCP6SOLICIT;
+        TT.retries++;
+        if(TT.retries > TT.retry) set_timeout(TT.errortimeout);
+        else if (TT.retries == TT.retry) {
+          dbg("State is solicit, retry count is max.\n");
+          lease_fail();
+          set_timeout(TT.errortimeout);
+        } else set_timeout(TT.timeout);
+        continue;
+      } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW || 
+              TT.state == DHCP6RELEASE) {
+        dbg("State is %d , sending packet\n", TT.state);
+        send_msg(TT.state);
+        TT.retries++;
+        if (TT.retries > TT.retry) set_timeout(TT.errortimeout);
+        else if (TT.retries == TT.retry) {
+          lease_fail();
+          set_timeout(TT.errortimeout);
+        } else set_timeout(TT.timeout);
+        continue;
+      }
+    } else if (FD_ISSET(TT.sock, &rfds)) {
+      if ((TT.status = read(TT.sock, toybuf, sizeof(toybuf))) <= 0) continue;
+      mymsg = (dhcp6_raw_t*)toybuf;
+      if (ntohs(mymsg->udph.dest) == 546 && 
+              !memcmp(mymsg->dhcp6.transaction_id, TT.transction_id, 3)) {
+        if (TT.state == DHCP6SOLICIT) {
+          if (mymsg->dhcp6.msgtype == DHCP6ADVERTISE ) {
+            if (!validate_ids()) {
+              dbg("Invalid id recieved, solicit.\n");
+              TT.state = DHCP6SOLICIT;
+              continue;
+            }
+            dbg("Got reply to request or solicit.\n");
+            TT.retries = 0;
+            set_timeout(0);
+            TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
+            memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
+            parse_ia_na(mesg.options, TT.request_length);
+            dbg("Status code:%d\n", dhcp_data.status_code);
+            inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
+            dbg("Advertiesed IP: %s\n", toybuf);
+            TT.state = DHCP6REQUEST;
+          } else {
+            dbg("Invalid solicit.\n");
+            continue;
+          }
+        } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ) {
+          if (mymsg->dhcp6.msgtype == DHCP6REPLY) {
+            if (!validate_ids()) {
+              dbg("Invalid id recieved, %d.\n", TT.state);
+              TT.state = DHCP6REQUEST;
+              continue;
+            }
+            dbg("Got reply to request or renew.\n");
+            TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
+            memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
+            parse_ia_na(mymsg->dhcp6.options, TT.request_length);
+            dbg("Status code:%d\n", dhcp_data.status_code);
+            inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
+            dbg("Got IP: %s\n", toybuf);
+            TT.retries = 0;
+            run_script(&dhcp_data, (TT.state == DHCP6REQUEST) ?
+              "request" : "renew");
+            if (toys.optflags & FLAG_q) {
+              if (toys.optflags & FLAG_R) send_msg(DHCP6RELEASE);
+              break;
+            }
+            TT.state = DHCP6CONFIRM;
+            set_timeout((dhcp_data.va_lf)?dhcp_data.va_lf:INT_MAX);
+            dbg("Setting timeout to intmax.");
+            if (TT.state == DHCP6REQUEST || !(toys.optflags & FLAG_f)) {
+              dbg("Making it a daemon\n");
+              if (daemon(0,0)) perror_exit("daemonize");
+              toys.optflags |= FLAG_f;
+              if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
+            }
+            dbg("Making it a foreground.\n");
+            continue;
+          } else {
+            dbg("Invalid reply.\n");
+            continue;
+          }          
+        } else if (TT.state == DHCP6RELEASE) {
+          dbg("Got reply to release.\n");
+          run_script(NULL, "release");
+          set_timeout(INT_MAX);
+        }
+      }
+    }
+  } 
+  xclose(TT.sock1);
+  xclose(TT.sock);
+}
diff --git a/toybox/toys/pending/dhcpd.c b/toybox/toys/pending/dhcpd.c
new file mode 100644
index 0000000..5d14316
--- /dev/null
+++ b/toybox/toys/pending/dhcpd.c
@@ -0,0 +1,2074 @@
+/* dhcpd.c - DHCP server for dynamic network configuration.
+ *
+ * Copyright 2013 Madhur Verma <mad.flexi@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gamil.com>
+ * Copyright 2015 Yeongdeok Suh <skyducks111@gmail.com>
+ *
+ * No Standard
+USE_DHCPD(NEWTOY(dhcpd, ">1P#<0>65535fi:S46[!46]", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
+
+config DHCPD
+  bool "dhcpd"
+  default n
+  help
+   usage: dhcpd [-46fS] [-i IFACE] [-P N] [CONFFILE]
+
+    -f    Run in foreground
+    -i Interface to use
+    -S    Log to syslog too
+    -P N  Use port N (default ipv4 67, ipv6 547)
+    -4, -6    Run as a DHCPv4 or DHCPv6 server
+
+config DEBUG_DHCP
+  bool "debugging messeges ON/OFF"
+  default n
+  depends on DHCPD
+*/
+
+/*
+ * TODO
+ * - Working as an relay agent
+ * - Rapid commit option support
+ * - Additional packet options (commented on the middle of sources)
+ * - Create common modules
+ */
+
+#define FOR_dhcpd
+
+#include "toys.h"
+#include <linux/sockios.h> 
+#include <linux/if_ether.h>
+
+// Todo: headers not in posix
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <netpacket/packet.h>
+
+#if CFG_DEBUG_DHCP==1
+# define dbg(fmt, arg...)   printf(fmt, ##arg)
+#else
+# define dbg(fmt, arg...)
+#endif
+
+#define LOG_SILENT          0x0
+#define LOG_CONSOLE         0x1
+#define LOG_SYSTEM          0x2
+
+#define DHCP_MAGIC          0x63825363
+
+#define DHCPDISCOVER        1
+#define DHCPOFFER           2
+#define DHCPREQUEST         3
+#define DHCPDECLINE         4
+#define DHCPACK             5
+#define DHCPNAK             6
+#define DHCPRELEASE         7
+#define DHCPINFORM          8
+
+#define DHCP6SOLICIT        1
+#define DHCP6ADVERTISE      2   // server -> client
+#define DHCP6REQUEST        3
+#define DHCP6CONFIRM        4
+#define DHCP6RENEW          5
+#define DHCP6REBIND         6
+#define DHCP6REPLY          7   // server -> client
+#define DHCP6RELEASE        8
+#define DHCP6DECLINE        9
+#define DHCP6RECONFIGURE    10  // server -> client
+#define DHCP6INFOREQUEST    11
+#define DHCP6RELAYFLOW      12  // relay -> relay/server
+#define DHCP6RELAYREPLY     13  // server/relay -> relay
+
+#define DHCP_NUM8           (1<<8)
+#define DHCP_NUM16          (1<<9)
+#define DHCP_NUM32          DHCP_NUM16 | DHCP_NUM8
+#define DHCP_STRING         (1<<10)
+#define DHCP_STRLST         (1<<11)
+#define DHCP_IP             (1<<12)
+#define DHCP_IPLIST         (1<<13)
+#define DHCP_IPPLST         (1<<14)
+#define DHCP_STCRTS         (1<<15)
+
+// DHCP option codes (partial list). See RFC 2132 and
+#define DHCP_OPT_PADDING                          0x00
+#define DHCP_OPT_HOST_NAME          DHCP_STRING | 0x0c // either client informs server or server gives name to client
+#define DHCP_OPT_REQUESTED_IP       DHCP_IP     | 0x32 // sent by client if specific IP is wanted
+#define DHCP_OPT_LEASE_TIME         DHCP_NUM32  | 0x33
+#define DHCP_OPT_OPTION_OVERLOAD                  0x34
+#define DHCP_OPT_MESSAGE_TYPE       DHCP_NUM8   | 0x35
+#define DHCP_OPT_SERVER_ID          DHCP_IP     | 0x36 // by default server's IP
+#define DHCP_OPT_PARAM_REQ          DHCP_STRING | 0x37 // list of options client wants
+#define DHCP_OPT_END                              0xff
+
+// DHCPv6 option codes (partial). See RFC 3315
+#define DHCP6_OPT_CLIENTID      1
+#define DHCP6_OPT_SERVERID      2
+#define DHCP6_OPT_IA_NA         3
+#define DHCP6_OPT_IA_ADDR       5
+#define DHCP6_OPT_ORO           6
+#define DHCP6_OPT_PREFERENCE    7
+#define DHCP6_OPT_ELAPSED_TIME  8
+#define DHCP6_OPT_RELAY_MSG     9
+#define DHCP6_OPT_STATUS_CODE   13
+#define DHCP6_OPT_IA_PD         25
+#define DHCP6_OPT_IA_PREFIX     26
+
+#define DHCP6_STATUS_SUCCESS        0
+#define DHCP6_STATUS_NOADDRSAVAIL   2
+
+#define DHCP6_DUID_LLT    1
+#define DHCP6_DUID_EN     2
+#define DHCP6_DUID_LL     3
+#define DHCP6_DUID_UUID   4
+
+GLOBALS(
+    char *iface;
+    long port;
+);
+
+struct config_keyword {
+  char *keyword;
+  int (*handler)(const char *str, void *var);
+  void *var;
+  char *def;
+};
+
+typedef struct __attribute__((packed)) dhcp_msg_s {
+  uint8_t op;
+  uint8_t htype;
+  uint8_t hlen;
+  uint8_t hops;
+  uint32_t xid;
+  uint16_t secs;
+  uint16_t flags;
+  uint32_t ciaddr;
+  uint32_t yiaddr;
+  uint32_t nsiaddr;
+  uint32_t ngiaddr;
+  uint8_t chaddr[16];
+  uint8_t sname[64];
+  uint8_t file[128];
+  uint32_t cookie;
+  uint8_t options[308];
+} dhcp_msg_t;
+
+typedef struct __attribute__((packed)) dhcp6_msg_s {
+  uint8_t msgtype;
+  uint8_t transaction_id[3];
+  uint8_t options[524];
+} dhcp6_msg_t;
+
+typedef struct __attribute__((packed)) dhcp_raw_s {
+  struct iphdr iph;
+  struct udphdr udph;
+  dhcp_msg_t dhcp;
+} dhcp_raw_t;
+
+typedef struct __attribute__((packed)) dhcp6_raw_s {
+  struct ip6_hdr iph;
+  struct udphdr udph;
+  dhcp6_msg_t dhcp6;
+} dhcp6_raw_t;
+
+typedef struct static_lease_s {
+  struct static_lease_s *next;
+  uint32_t nip;
+  int mac[6];
+} static_lease;
+
+typedef struct static_lease6_s {
+  struct static_lease6_s *next;
+  uint16_t duid_len;
+  uint16_t ia_type;
+  uint32_t iaid;
+  uint8_t nip6[16];
+  uint8_t duid[20];
+} static_lease6;
+
+typedef struct {
+  uint32_t expires;
+  uint32_t lease_nip;
+  uint8_t lease_mac[6];
+  char hostname[20];
+  uint8_t pad[2];
+} dyn_lease;
+
+typedef struct {
+  uint16_t duid_len;
+  uint16_t ia_type;
+  uint32_t expires;
+  uint32_t iaid;
+  uint8_t lease_nip6[16];
+  uint8_t duid[20];
+} dyn_lease6;
+
+typedef struct option_val_s {
+  char *key;
+  uint16_t code;
+  void *val;
+  size_t len;
+} option_val_t;
+
+struct __attribute__((packed)) optval_duid_llt {
+  uint16_t type;
+  uint16_t hwtype;
+  uint32_t time;
+  uint8_t lladdr[];   //flexible
+};
+
+struct __attribute__((packed)) optval_ia_na {
+  uint32_t iaid;
+  uint32_t t1, t2;
+  uint8_t optval[];   //flexible
+};
+struct __attribute__((packed)) optval_ia_addr {
+  uint8_t ipv6_addr[16];
+  uint32_t pref_lifetime;
+  uint32_t valid_lifetime;
+};
+struct __attribute__((packed)) optval_status_code {
+  uint16_t status_code;
+  uint8_t status_msg[]; //flexible
+};
+
+typedef struct __attribute__((__may_alias__)) server_config_s {
+  char *interface;                // interface to use
+  int ifindex;
+  uint8_t server_nip6[16];
+  uint32_t server_nip;
+  uint32_t port;
+  uint8_t server_mac[6];          // our MAC address (used only for ARP probing)
+  void *options[256];             // list of DHCP options loaded from the config file
+  /* start,end are in host order: we need to compare start <= ip <= end*/
+  uint32_t start_ip;              // start address of leases, in host order
+  uint32_t end_ip;                // end of leases, in host order
+  uint8_t start_ip6[16];          // start address of leases, in IPv6 mode
+  uint8_t end_ip6[16];            // end of leases, in IPv6 mode
+  uint32_t max_lease_sec;         // maximum lease time (host order)
+  uint32_t min_lease_sec;         // minimum lease time a client can request
+  uint32_t max_leases;            // maximum number of leases (including reserved addresses)
+  uint32_t auto_time;             // how long should dhcpd wait before writing a config file.
+                                  // if this is zero, it will only write one on SIGUSR1
+  uint32_t decline_time;          // how long an address is reserved if a client returns a
+                                  // decline message
+  uint32_t conflict_time;         // how long an arp conflict offender is leased for
+  uint32_t offer_time;            // how long an offered address is reserved
+  uint32_t siaddr_nip;            // "next server" bootp option
+  char *lease_file;
+  char *lease6_file;
+  char *pidfile;
+  char *notify_file;              // what to run whenever leases are written
+  char *sname;                    // bootp server name
+  char *boot_file;                // bootp boot file option
+  uint32_t pref_lifetime;
+  uint32_t valid_lifetime;
+  uint32_t t1,t2;
+  struct static_lease *static_leases; // List of ip/mac pairs to assign static leases
+} server_config_t;
+
+typedef struct __attribute__((__may_alias__)) server_state_s {
+  uint8_t client_nip6[16];
+  uint32_t client_port;
+  uint8_t rqcode;
+  int listensock;
+  union {
+    dhcp_msg_t rcvd_pkt;
+    dhcp6_msg_t rcvd_pkt6;
+  } rcvd;
+  uint8_t* rqopt;
+  union {
+    dhcp_msg_t send_pkt;
+    dhcp6_msg_t send_pkt6;
+  } send;
+  union {
+    static_lease *sleases;
+    static_lease6 *sleases6;
+  } leases;
+  struct arg_list *dleases;
+} server_state_t;
+
+static option_val_t options_list[] = {
+    {"lease"          , DHCP_NUM32  | 0x33, NULL, 0},
+    {"subnet"         , DHCP_IP     | 0x01, NULL, 0},
+    {"broadcast"      , DHCP_IP     | 0x1c, NULL, 0},
+    {"router"         , DHCP_IP     | 0x03, NULL, 0},
+    {"ipttl"          , DHCP_NUM8   | 0x17, NULL, 0},
+    {"mtu"            , DHCP_NUM16  | 0x1a, NULL, 0},
+    {"hostname"       , DHCP_STRING | 0x0c, NULL, 0},
+    {"domain"         , DHCP_STRING | 0x0f, NULL, 0},
+    {"search"         , DHCP_STRLST | 0x77, NULL, 0},
+    {"nisdomain"      , DHCP_STRING | 0x28, NULL, 0},
+    {"timezone"       , DHCP_NUM32  | 0x02, NULL, 0},
+    {"tftp"           , DHCP_STRING | 0x42, NULL, 0},
+    {"bootfile"       , DHCP_STRING | 0x43, NULL, 0},
+    {"bootsize"       , DHCP_NUM16  | 0x0d, NULL, 0},
+    {"rootpath"       , DHCP_STRING | 0x11, NULL, 0},
+    {"wpad"           , DHCP_STRING | 0xfc, NULL, 0},
+    {"serverid"       , DHCP_IP     | 0x36, NULL, 0},
+    {"message"        , DHCP_STRING | 0x38, NULL, 0},
+    {"vlanid"         , DHCP_NUM32  | 0x84, NULL, 0},
+    {"vlanpriority"   , DHCP_NUM32  | 0x85, NULL, 0},
+    {"dns"            , DHCP_IPLIST | 0x06, NULL, 0},
+    {"wins"           , DHCP_IPLIST | 0x2c, NULL, 0},
+    {"nissrv"         , DHCP_IPLIST | 0x29, NULL, 0},
+    {"ntpsrv"         , DHCP_IPLIST | 0x2a, NULL, 0},
+    {"lprsrv"         , DHCP_IPLIST | 0x09, NULL, 0},
+    {"swapsrv"        , DHCP_IP     | 0x10, NULL, 0},
+    {"routes"         , DHCP_STCRTS | 0x21, NULL, 0},
+    {"staticroutes"   , DHCP_STCRTS | 0x79, NULL, 0},
+    {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0},
+};
+
+struct fd_pair { int rd; int wr; };
+static server_config_t gconfig;
+static server_state_t gstate;
+static uint8_t infomode;
+static struct fd_pair sigfd;
+static int constone = 1;
+static sa_family_t addr_version = AF_INET;
+
+// calculate options size.
+static int dhcp_opt_size(uint8_t *optionptr)
+{
+  int i = 0;
+  for(;optionptr[i] != 0xff; i++)
+    if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1;
+  return i;
+}
+
+// calculates checksum for dhcp messeges.
+static uint16_t dhcp_checksum(void *addr, int count)
+{
+  int32_t sum = 0;
+  uint16_t tmp = 0, *source = (uint16_t *)addr;
+
+  while (count > 1)  {
+    sum += *source++;
+    count -= 2;
+  }
+  if (count > 0) {
+    *(uint8_t*)&tmp = *(uint8_t*)source;
+    sum += tmp;
+  }
+  while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
+  return ~sum;
+}
+
+// gets information of INTERFACE and updates IFINDEX, MAC and IP
+static int get_interface(const char *interface, int *ifindex, void *oip,
+    uint8_t *mac)
+{
+  struct ifreq req;
+  struct sockaddr_in *ip;
+  struct sockaddr_in6 ip6;
+  int fd = xsocket(addr_version, SOCK_RAW, IPPROTO_RAW);
+  char ipv6_addr[40] = {0,};
+
+  req.ifr_addr.sa_family = addr_version;
+  xstrncpy(req.ifr_name, (char *)interface, IFNAMSIZ);
+
+  xioctl(fd, SIOCGIFFLAGS, &req);
+
+  if (!(req.ifr_flags & IFF_UP)) return -1;
+
+  if (addr_version == AF_INET6) {
+
+    FILE *fd6 = fopen("/proc/net/if_inet6", "r");
+    uint8_t *oip6 = (uint8_t*)oip;
+    int i;
+
+    while(fgets(toybuf, sizeof(toybuf), fd6)) {
+      if (!strstr(toybuf, interface))
+        continue;
+
+      if (sscanf(toybuf, "%32s \n", ipv6_addr) == 1)
+        break;
+    }
+    fclose(fd6);
+
+    if (oip6) {
+      char *ptr = ipv6_addr+sizeof(ipv6_addr)-1;
+
+      // convert giant hex string into colon-spearated ipv6 address by
+      // inserting ':' every 4 characters.
+      for (i = 32; i; i--)
+        if ((*(ptr--) = ipv6_addr[i])) if (!(i&3)) *(ptr--) = ':';
+
+      dbg("ipv6 %s\n", ipv6_addr);
+      if(inet_pton(AF_INET6, ipv6_addr, &ip6.sin6_addr) <= 0)
+        error_msg("inet : the ipv6 address is not proper");
+      else
+        memcpy(oip6, ip6.sin6_addr.s6_addr32, sizeof(uint32_t)*4);
+    }
+  } else {
+    uint32_t *oip4 = (uint32_t*)oip;
+    if (oip4) {
+      xioctl(fd, SIOCGIFADDR, &req);
+      ip = (struct sockaddr_in*) &req.ifr_addr;
+      dbg("IP %s\n", inet_ntoa(ip->sin_addr));
+      *oip4 = ntohl(ip->sin_addr.s_addr);
+    }
+  }
+
+  if (ifindex) {
+    xioctl(fd, SIOCGIFINDEX, &req);
+    dbg("Adapter index %d\n", req.ifr_ifindex);
+    *ifindex = req.ifr_ifindex;
+  }
+  if (mac) {
+    xioctl(fd, SIOCGIFHWADDR, &req);
+    memcpy(mac, req.ifr_hwaddr.sa_data, 6);
+    dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+  }
+
+  close(fd);
+  return 0;
+}
+
+/*
+ *logs messeges to syslog or console
+ *opening the log is still left with applet.
+ *FIXME: move to more relevent lib. probably libc.c
+ */
+static void infomsg(uint8_t infomode, char *s, ...)
+{
+  int used;
+  char *msg;
+  va_list p, t;
+
+  if (infomode == LOG_SILENT) return;
+  va_start(p, s);
+  va_copy(t, p);
+  used = vsnprintf(NULL, 0, s, t);
+  used++;
+  va_end(t);
+
+  msg = xmalloc(used);
+  vsnprintf(msg, used, s, p);
+  va_end(p);
+
+  if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
+  if (infomode & LOG_CONSOLE) printf("%s\n", msg);
+  free(msg);
+}
+
+/*
+ * Writes self PID in file PATH
+ * FIXME: libc implementation only writes in /var/run
+ * this is more generic as some implemenation may provide
+ * arguments to write in specific file. as dhcpd does.
+ */
+static void write_pid(char *path)
+{
+  int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+  if (pidfile > 0) {
+    char pidbuf[12];
+
+    sprintf(pidbuf, "%u", (unsigned)getpid());
+    write(pidfile, pidbuf, strlen(pidbuf));
+    close(pidfile);
+  }
+}
+
+// Generic signal handler real handling is done in main funcrion.
+static void signal_handler(int sig)
+{
+  unsigned char ch = sig;
+  if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n");
+}
+
+// signal setup for SIGUSR1 SIGTERM
+static int setup_signal()
+{
+  if (pipe((int *)&sigfd) < 0) {
+    dbg("signal pipe failed\n");
+    return -1;
+  }
+  fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC);
+  fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC);
+  int flags = fcntl(sigfd.wr, F_GETFL);
+  fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK);
+  signal(SIGUSR1, signal_handler);
+  signal(SIGTERM, signal_handler);
+  return 0;
+}
+
+// String STR to UINT32 conversion strored in VAR
+static int strtou32(const char *str, void *var)
+{
+  char *endptr = NULL;
+  int base = 10;
+  errno=0;
+  *((uint32_t*)(var)) = 0;
+  if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
+    base = 16;
+    str+=2;
+  }
+
+  long ret_val = strtol(str, &endptr, base);
+  if (errno) infomsg(infomode, "config : Invalid num %s",str);
+  else if (endptr && (*endptr!='\0'||endptr == str))
+      infomsg(infomode, "config : Not a valid num %s",str);
+  else *((uint32_t*)(var)) = (uint32_t)ret_val;
+  return 0;
+}
+
+// copy string STR in variable VAR
+static int strinvar(const char *str, void *var)
+{
+  char **dest = var;
+  if (*dest) free(*dest);
+  *dest = strdup(str);
+  return 0;
+}
+
+// IP String STR to binary data.
+static int striptovar(const char *str, void *var)
+{
+  *((uint32_t*)(var)) = 0;
+  if(!str) {
+    error_msg("config : NULL address string \n");
+    return -1;
+  }
+  if((inet_pton(AF_INET6, str, var)<=0) && (inet_pton(AF_INET, str, var)<=0)) {
+    error_msg("config : wrong address %s \n", str);
+    return -1;
+  }
+  return 0;
+}
+
+// String to dhcp option conversion
+static int strtoopt(const char *str, void *var)
+{
+  char *option, *valstr, *grp, *tp;
+  uint32_t optcode = 0, inf = infomode, convtmp, mask, nip, router;
+  uint16_t flag = 0;
+  int count, size = ARRAY_LEN(options_list);
+
+  if (!*str) return 0;
+  if (!(option = strtok((char*)str, " \t="))) return -1;
+
+  infomode = LOG_SILENT;
+  strtou32(option, (uint32_t*)&optcode);
+  infomode = inf;
+
+  if (optcode > 0 && optcode < 256) { // raw option
+    for (count = 0; count < size; count++) {
+      if ((options_list[count].code & 0X00FF) == optcode) {
+        flag = (options_list[count].code & 0XFF00);
+        break;
+      }
+    }
+  } else { //string option
+    for (count = 0; count < size; count++) {
+      if (!strncmp(options_list[count].key, option, strlen(options_list[count].key))) {
+        flag = (options_list[count].code & 0XFF00);
+        optcode = (options_list[count].code & 0X00FF);
+        break;
+      }
+    }
+  }
+  if (count == size) {
+    infomsg(inf, "config : Obsolete OR Unknown Option : %s", option);
+    return -1;
+  }
+
+  if (!flag || !optcode) return -1;
+
+  if (!(valstr = strtok(NULL, " \t"))) {
+    dbg("config : option %s has no value defined.\n", option);
+    return -1;
+  }
+  dbg(" value : %-20s : ", valstr);
+  switch (flag) {
+  case DHCP_NUM32:
+    options_list[count].len = sizeof(uint32_t);
+    options_list[count].val = xmalloc(sizeof(uint32_t));
+    strtou32(valstr, &convtmp);
+    memcpy(options_list[count].val, &convtmp, sizeof(uint32_t));
+    break;
+  case DHCP_NUM16:
+    options_list[count].len = sizeof(uint16_t);
+    options_list[count].val = xmalloc(sizeof(uint16_t));
+    strtou32(valstr, &convtmp);
+    memcpy(options_list[count].val, &convtmp, sizeof(uint16_t));
+    break;
+  case DHCP_NUM8:
+    options_list[count].len = sizeof(uint8_t);
+    options_list[count].val = xmalloc(sizeof(uint8_t));
+    strtou32(valstr, &convtmp);
+    memcpy(options_list[count].val, &convtmp, sizeof(uint8_t));
+    break;
+  case DHCP_IP:
+    options_list[count].len = sizeof(uint32_t);
+    options_list[count].val = xmalloc(sizeof(uint32_t));
+    striptovar(valstr, options_list[count].val);
+    break;
+  case DHCP_STRING:
+    options_list[count].len = strlen(valstr);
+    options_list[count].val = strdup(valstr);
+    break;
+  case DHCP_IPLIST:
+    while(valstr){
+      options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t));
+      striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len);
+      options_list[count].len += sizeof(uint32_t);
+      valstr = strtok(NULL," \t");
+    }
+    break;
+  case DHCP_IPPLST:
+    break;
+  case DHCP_STCRTS:
+    /* Option binary format:
+     * mask [one byte, 0..32]
+     * ip [0..4 bytes depending on mask]
+     * router [4 bytes]
+     * may be repeated
+     * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
+     */
+    grp = strtok(valstr, ",");;
+    while(grp){
+      while(*grp == ' ' || *grp == '\t') grp++;
+      tp = strchr(grp, '/');
+      if (!tp) error_exit("wrong formated static route option");
+      *tp = '\0';
+      mask = strtol(++tp, &tp, 10);
+      if (striptovar(grp, (uint8_t*)&nip)<0) error_exit("wrong formated static route option");
+      while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++;
+      if (striptovar(tp, (uint8_t*)&router)<0) error_exit("wrong formated static route option");
+      options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4);
+      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1);
+      options_list[count].len += 1;
+      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8);
+      options_list[count].len += mask/8;
+      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4);
+      options_list[count].len += 4;
+      tp = NULL;
+      grp = strtok(NULL, ",");
+    }
+    break;
+  }
+  return 0;
+}
+
+// Reads Static leases from STR and updates inner structures.
+static int get_staticlease(const char *str, void *var)
+{
+  struct static_lease_s *sltmp;
+  char *tkmac, *tkip;
+  int count;
+
+  if (!*str) return 0;
+
+  if (!(tkmac = strtok((char*)str, " \t"))) {
+    infomsg(infomode, "config : static lease : mac not found");
+    return 0;
+  }
+  if (!(tkip = strtok(NULL, " \t"))) {
+    infomsg(infomode, "config : static lease : no ip bind to mac %s", tkmac);
+    return 0;
+  }
+  sltmp = xzalloc(sizeof(struct static_lease_s));
+  for (count = 0; count < 6; count++, tkmac++) {
+    errno = 0;
+    sltmp->mac[count] = strtol(tkmac, &tkmac, 16);
+    if (sltmp->mac[count]>255 || sltmp->mac[count]<0 || (*tkmac && *tkmac!=':') || errno) {
+      infomsg(infomode, "config : static lease : mac address wrong format");
+      free(sltmp);
+      return 0;
+    }
+  }
+  striptovar(tkip, &sltmp->nip);
+  sltmp->next = gstate.leases.sleases;
+  gstate.leases.sleases = sltmp;
+
+  return 0;
+}
+
+static struct config_keyword keywords[] = {
+// keyword          handler           variable address                default
+  {"start"        , striptovar      , (void*)&gconfig.start_ip     , "192.168.0.20"},
+  {"end"          , striptovar      , (void*)&gconfig.end_ip       , "192.168.0.254"},
+  {"interface"    , strinvar        , (void*)&gconfig.interface    , "eth0"},
+  {"port"         , strtou32        , (void*)&gconfig.port         , "67"},
+  {"min_lease"    , strtou32        , (void*)&gconfig.min_lease_sec, "60"},
+  {"max_leases"   , strtou32        , (void*)&gconfig.max_leases   , "235"},
+  {"auto_time"    , strtou32        , (void*)&gconfig.auto_time    , "7200"},
+  {"decline_time" , strtou32        , (void*)&gconfig.decline_time , "3600"},
+  {"conflict_time", strtou32        , (void*)&gconfig.conflict_time, "3600"},
+  {"offer_time"   , strtou32        , (void*)&gconfig.offer_time   , "60"},
+  {"lease_file"   , strinvar        , (void*)&gconfig.lease_file   , "/var/lib/misc/dhcpd.leases"}, //LEASES_FILE
+  {"lease6_file"  , strinvar        , (void*)&gconfig.lease6_file  , "/var/lib/misc/dhcpd6.leases"}, //LEASES_FILE
+  {"pidfile"      , strinvar        , (void*)&gconfig.pidfile      , "/var/run/dhcpd.pid"}, //DPID_FILE
+  {"siaddr"       , striptovar      , (void*)&gconfig.siaddr_nip   , "0.0.0.0"},
+  {"option"       , strtoopt        , (void*)&gconfig.options      , ""},
+  {"opt"          , strtoopt        , (void*)&gconfig.options      , ""},
+  {"notify_file"  , strinvar        , (void*)&gconfig.notify_file  , ""},
+  {"sname"        , strinvar        , (void*)&gconfig.sname        , ""},
+  {"boot_file"    , strinvar        , (void*)&gconfig.boot_file    , ""},
+  {"static_lease" , get_staticlease , (void*)&gconfig.static_leases, ""},
+  {"start6"       , striptovar      , (void*)&gconfig.start_ip6    , "2001:620:40b:555::100"},
+  {"end6"         , striptovar      , (void*)&gconfig.end_ip6      , "2001:620:40b:555::200"},
+  {"preferred_lifetime" , strtou32  , (void*)&gconfig.pref_lifetime, "3600"},
+  {"valid_lifetime"     , strtou32  , (void*)&gconfig.valid_lifetime, "7200"},
+  {"t1"           , strtou32        , (void*)&gconfig.t1           , "3600"},
+  {"t2"           , strtou32        , (void*)&gconfig.t2           , "5400"},
+};
+
+// Parses the server config file and updates the global server config accordingly.
+static int parse_server_config(char *config_file, struct config_keyword *confkey)
+{
+  FILE *fs = NULL;
+  char *confline_temp = NULL,*confline = NULL, *tk = NULL, *tokens[2] = {NULL, NULL};
+  int len, linelen, tcount, count, size = ARRAY_LEN(keywords);
+
+  for (count = 0; count < size; count++)
+    if (confkey[count].handler)
+      confkey[count].handler(confkey[count].def, confkey[count].var);
+
+  if (!(fs = fopen(config_file, "r"))) perror_msg("%s", config_file);
+  for (len = 0, linelen = 0; fs;) {
+    len = getline(&confline_temp, (size_t*) &linelen, fs);
+    confline = confline_temp;
+    if (len <= 0) break;
+    for (; *confline == ' '; confline++, len--);
+    if ((confline[0] == '#') || (confline[0] == '\n')) goto free_conf_continue;
+    tk = strchr(confline, '#');
+    if (tk) {
+      for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--);
+      *tk = '\0';
+    }
+    tk = strchr(confline, '\n');
+    if (tk) {
+      for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--);
+      *tk = '\0';
+    }
+    for (tcount=0, tk=strtok(confline, " \t"); tk && (tcount < 2);
+        tcount++, tk=strtok(NULL,(tcount==1)?"":" \t")) {
+      while ((*tk == '\t') || (*tk == ' ')) tk++;
+      tokens[tcount] = xstrdup(tk);
+    }
+    if (tcount<=1) goto free_tk0_continue;
+    for (count = 0; count < size; count++) {
+      if (!strcmp(confkey[count].keyword,tokens[0])) {
+        dbg("got config : %15s : ", confkey[count].keyword);
+        if (confkey[count].handler(tokens[1], confkey[count].var) == 0)
+          dbg("%s \n", tokens[1]);
+        break;
+      }
+    }
+    if (tokens[1]) { free(tokens[1]); tokens[1] = NULL; }
+free_tk0_continue:
+    if (tokens[0]) { free(tokens[0]); tokens[0] = NULL; }
+free_conf_continue:
+    free(confline_temp);
+    confline_temp = NULL;
+  }
+  if (fs) fclose(fs);
+  return 0;
+}
+
+// opens UDP socket for listen ipv6 packets
+static int open_listensock6(void)
+{
+  struct sockaddr_in6 addr6;
+  struct ipv6_mreq mreq;
+
+  if (gstate.listensock > 0) close(gstate.listensock);
+
+  dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface);
+
+  gstate.listensock = xsocket(PF_INET6, SOCK_DGRAM, 0);
+  setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
+  setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_CHECKSUM, &constone, sizeof(constone));
+
+  if (setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &constone,
+        sizeof(constone)) == -1) {
+    error_msg("failed to receive ipv6 packets.\n");
+    close(gstate.listensock);
+    return -1;
+  }
+
+  setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, gconfig.interface, strlen(gconfig.interface)+1);
+
+  memset(&addr6, 0, sizeof(addr6));
+  addr6.sin6_family = AF_INET6;
+  addr6.sin6_port = htons(gconfig.port); //SERVER_PORT
+  addr6.sin6_scope_id = if_nametoindex(gconfig.interface);
+  //Listening for multicast packet
+  inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
+
+  if (bind(gstate.listensock, (struct sockaddr *) &addr6, sizeof(addr6)) == -1) {
+    close(gstate.listensock);
+    perror_exit("bind failed");
+  }
+
+  memset(&mreq, 0, sizeof(mreq));
+  mreq.ipv6mr_interface = if_nametoindex(gconfig.interface);
+  memcpy(&mreq.ipv6mr_multiaddr, &addr6.sin6_addr, sizeof(addr6.sin6_addr));
+
+  if(setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) {
+    error_msg("failed to join a multicast group.\n");
+    close(gstate.listensock);
+    return -1;
+  }
+
+  dbg("OPEN : success\n");
+  return 0;
+}
+
+// opens UDP socket for listen
+static int open_listensock(void)
+{
+  struct sockaddr_in addr;
+  struct ifreq ifr;
+
+  if (gstate.listensock > 0) close(gstate.listensock);
+
+  dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface);
+  gstate.listensock = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
+  if (setsockopt(gstate.listensock, SOL_SOCKET, SO_BROADCAST, &constone, sizeof(constone)) == -1) {
+    error_msg("failed to receive brodcast packets.\n");
+    close(gstate.listensock);
+    return -1;
+  }
+  memset(&ifr, 0, sizeof(ifr));
+  xstrncpy(ifr.ifr_name, gconfig.interface, IFNAMSIZ);
+  setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons(gconfig.port); //SERVER_PORT
+  addr.sin_addr.s_addr = INADDR_ANY ;
+
+  if (bind(gstate.listensock, (struct sockaddr *) &addr, sizeof(addr))) {
+    close(gstate.listensock);
+    perror_exit("bind failed");
+  }
+  dbg("OPEN : success\n");
+  return 0;
+}
+
+static int send_packet6(uint8_t relay, uint8_t *client_lla, uint16_t optlen)
+{
+  struct sockaddr_ll dest_sll;
+  dhcp6_raw_t packet;
+  unsigned padding;
+  int fd, result = -1;
+
+  memset(&packet, 0, sizeof(dhcp6_raw_t));
+  memcpy(&packet.dhcp6, &gstate.send.send_pkt6, sizeof(dhcp6_msg_t));
+  padding = sizeof(packet.dhcp6.options) - optlen;
+
+  if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6))) < 0) {
+    dbg("SEND : ipv6 socket failed\n");
+    return -1;
+  }
+  memset(&dest_sll, 0, sizeof(dest_sll));
+  dest_sll.sll_family = AF_PACKET;
+  dest_sll.sll_protocol = htons(ETH_P_IPV6);
+  dest_sll.sll_ifindex = gconfig.ifindex;
+  dest_sll.sll_halen = ETH_ALEN;
+  memcpy(dest_sll.sll_addr, client_lla, sizeof(uint8_t)*6);
+
+  if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
+    dbg("SEND : bind failed\n");
+    close(fd);
+    return -1;
+  }
+  memcpy(&packet.iph.ip6_src, &gconfig.server_nip6, sizeof(uint32_t)*4);
+  memcpy(&packet.iph.ip6_dst, &gstate.client_nip6, sizeof(uint32_t)*4);
+
+  packet.udph.source = htons(gconfig.port); //SERVER_PORT
+  packet.udph.dest = gstate.client_port; //CLIENT_PORT
+  packet.udph.len = htons(sizeof(dhcp6_raw_t) - sizeof(struct ip6_hdr) - padding);
+  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ntohs(packet.udph.len) + 0x11);
+  packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp6_raw_t) - padding);
+  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
+  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = packet.udph.len;
+  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP;
+  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_hlim = 0x64;
+
+  result = sendto(fd, &packet, sizeof(dhcp6_raw_t)-padding,
+      0, (struct sockaddr *) &dest_sll, sizeof(dest_sll));
+
+  dbg("sendto %d\n", result);
+  close(fd);
+  if (result < 0) dbg("PACKET send error\n");
+  return result;
+}
+
+// Sends data through raw socket.
+static int send_packet(uint8_t broadcast)
+{
+  struct sockaddr_ll dest_sll;
+  dhcp_raw_t packet;
+  unsigned padding;
+  int fd, result = -1;
+  uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+  memset(&packet, 0, sizeof(dhcp_raw_t));
+  memcpy(&packet.dhcp, &gstate.send.send_pkt, sizeof(dhcp_msg_t));
+
+  if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
+    dbg("SEND : socket failed\n");
+    return -1;
+  }
+  memset(&dest_sll, 0, sizeof(dest_sll));
+  dest_sll.sll_family = AF_PACKET;
+  dest_sll.sll_protocol = htons(ETH_P_IP);
+  dest_sll.sll_ifindex = gconfig.ifindex;
+  dest_sll.sll_halen = 6;
+  memcpy(dest_sll.sll_addr, (broadcast)?bmacaddr:gstate.rcvd.rcvd_pkt.chaddr , 6);
+
+  if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
+    dbg("SEND : bind failed\n");
+    close(fd);
+    return -1;
+  }
+  padding = 308 - 1 - dhcp_opt_size(gstate.send.send_pkt.options);
+  packet.iph.protocol = IPPROTO_UDP;
+  packet.iph.saddr = gconfig.server_nip;
+  packet.iph.daddr = (broadcast || (gstate.rcvd.rcvd_pkt.ciaddr == 0))?
+    INADDR_BROADCAST : gstate.rcvd.rcvd_pkt.ciaddr;
+  packet.udph.source = htons(gconfig.port);//SERVER_PORT
+  packet.udph.dest = gstate.client_port; //CLIENT_PORT
+  packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding);
+  packet.iph.tot_len = packet.udph.len;
+  packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding);
+  packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding);
+  packet.iph.ihl = sizeof(packet.iph) >> 2;
+  packet.iph.version = IPVERSION;
+  packet.iph.ttl = IPDEFTTL;
+  packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph));
+
+  result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0,
+      (struct sockaddr *) &dest_sll, sizeof(dest_sll));
+
+  dbg("sendto %d\n", result);
+  close(fd);
+  if (result < 0) dbg("PACKET send error\n");
+  return result;
+}
+
+static int read_packet6(void)
+{
+  int ret;
+  struct sockaddr_in6 c_addr;
+  socklen_t c_addr_size = sizeof(c_addr);
+
+  memset(&gstate.rcvd.rcvd_pkt6, 0, sizeof(dhcp6_msg_t));
+  ret = recvfrom(gstate.listensock, &gstate.rcvd.rcvd_pkt6, sizeof(dhcp6_msg_t),
+      0, (struct sockaddr*) &c_addr, &c_addr_size);
+  memcpy(gstate.client_nip6, &c_addr.sin6_addr, sizeof(uint32_t)*4);
+  memcpy(&gstate.client_port, &c_addr.sin6_port, sizeof(uint32_t));
+  if (ret < 0) {
+    dbg("Packet read error, ignoring. \n");
+    return ret; // returns -1
+  }
+  if (gstate.rcvd.rcvd_pkt6.msgtype < 1) {
+    dbg("Bad message type, igroning. \n");
+    return -2;
+  }
+
+  dbg("Received an ipv6 packet. Size : %d \n", ret);
+  return ret;
+}
+
+// Reads from UDP socket
+static int read_packet(void)
+{
+  int ret;
+  struct sockaddr_in c_addr;
+  socklen_t c_addr_size = sizeof(c_addr);
+
+  memset(&gstate.rcvd.rcvd_pkt, 0, sizeof(dhcp_msg_t));
+  ret = recvfrom(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t),
+      0, (struct sockaddr*) &c_addr, &c_addr_size);
+  memcpy(&gstate.client_port, &c_addr.sin_port, sizeof(uint32_t));
+  /*ret = read(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t));*/
+  if (ret < 0) {
+    dbg("Packet read error, ignoring. \n");
+    return ret; // returns -1
+  }
+  if (gstate.rcvd.rcvd_pkt.cookie != htonl(DHCP_MAGIC)) {
+    dbg("Packet with bad magic, ignoring. \n");
+    return -2;
+  }
+  if (gstate.rcvd.rcvd_pkt.op != 1) { //BOOTPREQUEST
+    dbg("Not a BOOT REQUEST ignoring. \n");
+    return -2;
+  }
+  if (gstate.rcvd.rcvd_pkt.hlen != 6) {
+    dbg("hlen != 6 ignoring. \n");
+    return -2;
+  }
+  dbg("Received a packet. Size : %d \n", ret);
+  return ret;
+}
+
+// Preapres a dhcp packet with defaults and configs
+static uint8_t* prepare_send_pkt(void)
+{
+  memset((void*)&gstate.send.send_pkt, 0, sizeof(gstate.send.send_pkt));
+  gstate.send.send_pkt.op = 2; //BOOTPREPLY
+  gstate.send.send_pkt.htype = 1;
+  gstate.send.send_pkt.hlen = 6;
+  gstate.send.send_pkt.xid = gstate.rcvd.rcvd_pkt.xid;
+  gstate.send.send_pkt.cookie = htonl(DHCP_MAGIC);
+  gstate.send.send_pkt.nsiaddr = gconfig.server_nip;
+  memcpy(gstate.send.send_pkt.chaddr, gstate.rcvd.rcvd_pkt.chaddr, 16);
+  gstate.send.send_pkt.options[0] = DHCP_OPT_END;
+  return gstate.send.send_pkt.options;
+}
+
+static uint8_t* prepare_send_pkt6(uint16_t opt)
+{
+  memset((void*)&gstate.send.send_pkt6, 0, sizeof(gstate.send.send_pkt6));
+  gstate.send.send_pkt6.msgtype = opt;
+  memcpy(gstate.send.send_pkt6.transaction_id, gstate.rcvd.rcvd_pkt6.transaction_id, 3);
+  return gstate.send.send_pkt6.options;
+}
+
+// Sets a option value in dhcp packet's option field
+static uint8_t* set_optval(uint8_t *optptr, uint16_t opt, void *var, size_t len)
+{
+  while (*optptr != DHCP_OPT_END) optptr++;
+  *optptr++ = (uint8_t)(opt & 0x00FF);
+  *optptr++ = (uint8_t) len;
+  memcpy(optptr, var, len);
+  optptr += len;
+  *optptr = DHCP_OPT_END;
+  return optptr;
+}
+
+static uint8_t* set_optval6(uint8_t *optptr, uint16_t opt, void *var, size_t len)
+{
+  *((uint16_t*)optptr) = htons(opt);
+  *(uint16_t*)(optptr+2) = htons(len);
+  memcpy(optptr+4, var, len);
+  optptr += len+4;
+  return optptr;
+}
+
+// Gets a option value from dhcp packet's option field
+static uint8_t* get_optval(uint8_t *optptr, uint16_t opt, void *var)
+{
+  size_t len;
+  uint8_t overloaded = 0;
+
+  while (1) {
+    while (*optptr == DHCP_OPT_PADDING) optptr++;
+    if ((*optptr & 0x00FF) == DHCP_OPT_END) break;
+    if ((*optptr & 0x00FF) == DHCP_OPT_OPTION_OVERLOAD) {
+      overloaded = optptr[2];
+      optptr += optptr[1] + 2;
+    }
+    len = optptr[1];
+    if (*optptr == (opt & 0x00FF))
+      switch (opt & 0xFF00) {
+        case DHCP_NUM32: // FALLTHROUGH
+        case DHCP_IP:
+          memcpy(var, optptr+2, sizeof(uint32_t));
+          optptr += len + 2;
+          return optptr;
+          break;
+        case DHCP_NUM16:
+          memcpy(var, optptr+2, sizeof(uint16_t));
+          optptr += len + 2;
+          return optptr;
+          break;
+        case DHCP_NUM8:
+          memcpy(var, optptr+2, sizeof(uint8_t));
+          optptr += len + 2;
+          return optptr;
+          break;
+        case DHCP_STRING:
+          var = xstrndup((char*) optptr, len);
+          optptr += len + 2;
+          return optptr;
+          break;
+      }
+    optptr += len + 2;
+  }
+  if ((overloaded == 1) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.file, opt, var);
+  if ((overloaded == 2) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.sname, opt, var);
+  return optptr;
+}
+
+static uint8_t* get_optval6(uint8_t *optptr, uint16_t opt, uint16_t *datalen, void **var)
+{
+  uint16_t optcode;
+  uint16_t len;
+
+  memcpy(&optcode, optptr, sizeof(uint16_t));
+  memcpy(&len, optptr+2, sizeof(uint16_t));
+  if(!optcode) {
+    dbg("Option %d is not exist.\n", opt);
+    return optptr;
+  }
+  optcode = ntohs(optcode);
+  len = ntohs(len);
+
+  if (opt == optcode) {
+    *var = xmalloc(len);
+    memcpy(*var, optptr+4, len);
+    optptr = optptr + len + 4;
+    memcpy(datalen, &len, sizeof(uint16_t));
+  }
+  else {
+    optptr = get_optval6(optptr+len+4, opt, datalen, var);
+  }
+
+  return optptr;
+}
+
+// Retrives Requested Parameter list from dhcp req packet.
+static uint8_t get_reqparam(uint8_t **list)
+{
+  uint8_t len, *optptr;
+  if(*list) free(*list);
+  for (optptr = gstate.rcvd.rcvd_pkt.options;
+      *optptr && *optptr!=((DHCP_OPT_PARAM_REQ) & 0x00FF); optptr+=optptr[1]+2);
+  len = *++optptr;
+  *list = xzalloc(len+1);
+  memcpy(*list, ++optptr, len);
+  return len;
+}
+
+// Sets values of req param in dhcp offer packet.
+static uint8_t* set_reqparam(uint8_t *optptr, uint8_t *list)
+{
+  uint8_t reqcode;
+  int count, size = ARRAY_LEN(options_list);
+
+  while (*list) {
+    reqcode = *list++;
+    for (count = 0; count < size; count++) {
+      if ((options_list[count].code & 0X00FF)==reqcode) {
+        if (!(options_list[count].len) || !(options_list[count].val)) break;
+        for (; *optptr && *optptr!=DHCP_OPT_END; optptr+=optptr[1]+2);
+        *optptr++ = (uint8_t) (options_list[count].code & 0x00FF);
+        *optptr++ = (uint8_t) options_list[count].len;
+        memcpy(optptr, options_list[count].val, options_list[count].len);
+        optptr += options_list[count].len;
+        *optptr = DHCP_OPT_END;
+        break;
+      }
+    }
+  }
+  return optptr;
+}
+
+static void run_notify(char **argv)
+{
+  struct stat sts;
+  volatile int error = 0;
+  pid_t pid;
+
+  if (stat(argv[0], &sts) == -1 && errno == ENOENT) {
+    infomsg(infomode, "notify file: %s : not exist.", argv[0]);
+    return;
+  }
+  fflush(NULL);
+
+  pid = vfork();
+  if (pid < 0) {
+    dbg("Fork failed.\n");
+    return;
+  }
+  if (!pid) {
+    execvp(argv[0], argv);
+    error = errno;
+    _exit(111);
+  }
+  if (error) {
+    waitpid(pid, NULL, 0);
+    errno = error;
+  }
+  dbg("script complete.\n");
+}
+
+static void write_leasefile(void)
+{
+  int fd;
+  uint32_t curr, tmp_time;
+  int64_t timestamp;
+  struct arg_list *listdls = gstate.dleases;
+  dyn_lease *dls;
+
+  if ((fd = open(gconfig.lease_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
+    perror_msg("can't open %s ", gconfig.lease_file);
+  } else {
+    curr = timestamp = time(NULL);
+    timestamp = SWAP_BE64(timestamp);
+    writeall(fd, &timestamp, sizeof(timestamp));
+
+    while (listdls) {
+      dls = (dyn_lease*)listdls->arg;
+      tmp_time = dls->expires;
+      dls->expires -= curr;
+      if ((int32_t) dls->expires < 0) goto skip;
+      dls->expires = htonl(dls->expires);
+      writeall(fd, dls, sizeof(dyn_lease));
+skip:
+      dls->expires = tmp_time;
+      listdls = listdls->next;
+    }
+    close(fd);
+    if (gconfig.notify_file) {
+      char *argv[3];
+      argv[0] = gconfig.notify_file;
+      argv[1] = gconfig.lease_file;
+      argv[2] = NULL;
+      run_notify(argv);
+    }
+  }
+}
+
+static void write_lease6file(void)
+{
+  int fd;
+  uint32_t curr, tmp_time;
+  int64_t timestamp;
+  struct arg_list *listdls = gstate.dleases;
+  dyn_lease6 *dls6;
+
+  if ((fd = open(gconfig.lease6_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
+    perror_msg("can't open %s ", gconfig.lease6_file);
+  } else {
+    curr = timestamp = time(NULL);
+    timestamp = SWAP_BE64(timestamp);
+    writeall(fd, &timestamp, sizeof(timestamp));
+
+    while (listdls) {
+      dls6 = (dyn_lease6*)listdls->arg;
+      tmp_time = dls6->expires;
+      dls6->expires -= curr;
+      if ((int32_t) dls6->expires < 0) goto skip;
+      dls6->expires = htonl(dls6->expires);
+      writeall(fd, dls6, sizeof(dyn_lease6));
+skip:
+      dls6->expires = tmp_time;
+      listdls = listdls->next;
+    }
+    close(fd);
+    if (gconfig.notify_file) {
+      char *argv[3];
+      argv[0] = gconfig.notify_file;
+      argv[1] = gconfig.lease6_file;
+      argv[2] = NULL;
+      run_notify(argv);
+    }
+  }
+}
+
+// Update max lease time from options.
+static void set_maxlease(void)
+{
+  int count, size = ARRAY_LEN(options_list);
+  for (count = 0; count < size; count++)
+    if (options_list[count].val && options_list[count].code == (DHCP_OPT_LEASE_TIME)) {
+      gconfig.max_lease_sec = *((uint32_t*)options_list[count].val);
+      break;
+    }
+  if (!gconfig.max_lease_sec) gconfig.max_lease_sec = (60*60*24*10);// DEFAULT_LEASE_TIME;
+}
+
+// Returns lease time for client.
+static uint32_t get_lease(uint32_t req_exp)
+{
+  uint32_t now = time(NULL);
+  req_exp = req_exp - now;
+  if(addr_version == AF_INET6) {
+    if ((req_exp <= 0) || req_exp > gconfig.pref_lifetime ||
+        req_exp > gconfig.valid_lifetime) {
+      if ((gconfig.pref_lifetime > gconfig.valid_lifetime)) {
+        error_msg("The valid lifetime must be greater than the preferred lifetime, \
+            setting to valid lifetime", gconfig.valid_lifetime);
+        return gconfig.valid_lifetime;
+      }
+      return gconfig.pref_lifetime;
+    }
+  } else {
+    if ((req_exp <= 0) || (req_exp > gconfig.max_lease_sec))
+      return gconfig.max_lease_sec;
+
+    if (req_exp < gconfig.min_lease_sec)
+      return gconfig.min_lease_sec;
+  }
+
+  return req_exp;
+}
+
+static int verifyip6_in_lease(uint8_t *nip6, uint8_t *duid, uint16_t ia_type, uint32_t iaid)
+{
+  static_lease6 *sls6;
+  struct arg_list *listdls;
+
+  for (listdls = gstate.dleases; listdls; listdls = listdls->next) {
+    if (!memcmp(((dyn_lease6*) listdls->arg)->lease_nip6, nip6, sizeof(uint32_t)*4))
+      return -1;
+
+    if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)
+        && ((dyn_lease6*) listdls->arg)->ia_type == ia_type) 
+      return -1;
+  }
+  for (sls6 = gstate.leases.sleases6; sls6; sls6 = sls6->next)
+    if (memcmp(sls6->nip6, nip6, sizeof(uint32_t)*4)==0) return -2;
+
+  if (memcmp(nip6, gconfig.start_ip6, sizeof(uint32_t)*4) < 0 ||
+      memcmp(nip6, gconfig.end_ip6, sizeof(uint32_t)*4) > 0)
+    return -3;
+
+  return 0;
+}
+
+// Verify ip NIP in current leases ( assigned or not)
+static int verifyip_in_lease(uint32_t nip, uint8_t mac[6])
+{
+  static_lease *sls;
+  struct arg_list *listdls;
+
+  for (listdls = gstate.dleases; listdls; listdls = listdls->next) {
+    if (((dyn_lease*) listdls->arg)->lease_nip == nip) {
+      if (((int32_t)(((dyn_lease*) listdls->arg)->expires) - time(NULL)) < 0)
+        return 0;
+      return -1;
+    }
+    if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) return -1;
+  }
+  for (sls = gstate.leases.sleases; sls; sls = sls->next)
+    if (sls->nip == nip) return -2;
+
+  if ((ntohl(nip) < gconfig.start_ip) || (ntohl(nip) > gconfig.end_ip))
+    return -3;
+
+  return 0;
+}
+
+// add ip assigned_nip to dynamic lease.
+static int addip_to_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname, uint8_t update)
+{
+  dyn_lease *dls;
+  struct arg_list *listdls = gstate.dleases;
+  uint32_t now = time(NULL);
+
+  while (listdls) {
+    if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) {
+      if (update) *req_exp = get_lease(*req_exp + ((dyn_lease*) listdls->arg)->expires);
+      ((dyn_lease*) listdls->arg)->expires = *req_exp + now;
+      return 0;
+    }
+    listdls = listdls->next;
+  }
+
+  dls = xzalloc(sizeof(dyn_lease));
+  memcpy(dls->lease_mac, mac, 6);
+  dls->lease_nip = assigned_nip;
+  if (hostname) memcpy(dls->hostname, hostname, 20);
+
+  if (update) *req_exp = get_lease(*req_exp + now);
+  dls->expires = *req_exp + now;
+
+  listdls = xzalloc(sizeof(struct arg_list));
+  listdls->next = gstate.dleases;
+  listdls->arg = (char*)dls;
+  gstate.dleases = listdls;
+
+  return 0;
+}
+
+static int addip6_to_lease(uint8_t *assigned_nip, uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime, uint8_t update)
+{
+  dyn_lease6 *dls6;
+  struct arg_list *listdls = gstate.dleases;
+  uint32_t now = time(NULL);
+
+  while (listdls) {
+    if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)) {
+      if (update) *lifetime = get_lease(*lifetime + ((dyn_lease6*) listdls->arg)->expires);
+      ((dyn_lease6*) listdls->arg)->expires = *lifetime + now;
+      return 0;
+    }
+    listdls = listdls->next;
+  }
+
+  dls6 = xzalloc(sizeof(dyn_lease6));
+  dls6->duid_len = duid_len; 
+  memcpy(dls6->duid, duid, duid_len);
+  dls6->ia_type = ia_type;
+  dls6->iaid = iaid;
+  memcpy(dls6->lease_nip6, assigned_nip, sizeof(uint32_t)*4);
+  
+  if (update) *lifetime = get_lease(*lifetime + now);
+  dls6->expires = *lifetime + now;
+
+  listdls = xzalloc(sizeof(struct arg_list));
+  listdls->next = gstate.dleases;
+  listdls->arg = (char*)dls6;
+  gstate.dleases = listdls;
+
+  return 0;
+}
+
+// delete ip assigned_nip from dynamic lease.
+static int delip_from_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t del_time)
+{
+  struct arg_list *listdls = gstate.dleases;
+
+  while (listdls) {
+    if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) {
+      ((dyn_lease*) listdls->arg)->expires = del_time + time(NULL);
+      return 0;
+    }
+    listdls = listdls->next;
+  }
+  return -1;
+}
+
+// returns a IP from static, dynamic leases or free ip pool, 0 otherwise.
+static uint32_t getip_from_pool(uint32_t req_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname)
+{
+  uint32_t nip = 0;
+  static_lease *sls = gstate.leases.sleases;
+  struct arg_list *listdls = gstate.dleases, *tmp = NULL;
+
+  if (req_nip && (!verifyip_in_lease(req_nip, mac))) nip = req_nip;
+
+  if (!nip) {
+    while (listdls) {
+      if (!memcmp(((dyn_lease*)listdls->arg)->lease_mac, mac, 6)) {
+        nip = ((dyn_lease*)listdls->arg)->lease_nip;
+        if (tmp) tmp->next = listdls->next;
+        else gstate.dleases = listdls->next;
+        free(listdls->arg);
+        free(listdls);
+        if (verifyip_in_lease(nip, mac) < 0) nip = 0;
+        break;
+      }
+      tmp = listdls;
+      listdls = listdls->next;
+    }
+  }
+  if (!nip) {
+    while (sls) {
+      if (memcmp(sls->mac, mac, 6) == 0) {
+        nip = sls->nip;
+        break;
+      }
+      sls = sls->next;
+    }
+  }
+  if (!nip) {
+    for (nip = htonl(gconfig.start_ip); ntohl(nip) <= gconfig.end_ip; ) {
+      if (!verifyip_in_lease(nip, mac)) break;
+      nip = ntohl(nip);
+      nip = htonl(++nip);
+    }
+    if (ntohl(nip) > gconfig.end_ip) {
+      nip = 0;
+      infomsg(infomode, "can't find free IP in IP Pool.");
+    }
+  }
+  if (nip) addip_to_lease(nip, mac, req_exp, hostname, 1);
+  return nip;
+}
+
+static uint8_t *getip6_from_pool(uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime)
+{
+  static uint8_t nip6[16] = {0, };
+  static_lease6 *sls6 = gstate.leases.sleases6;
+  struct arg_list *listdls6 = gstate.dleases, *tmp = NULL;
+
+  while(listdls6) {
+    if (!memcmp(((dyn_lease6*)listdls6->arg)->duid, duid, duid_len)) {
+      memcpy(nip6, ((dyn_lease6*)listdls6->arg)->lease_nip6, sizeof(nip6));
+      if(tmp) tmp->next = listdls6->next;
+      else gstate.dleases = listdls6->next;
+      free(listdls6->arg);
+      free(listdls6);
+
+      if(verifyip6_in_lease(nip6, duid, ia_type, iaid) < 0)
+        memset(nip6, 0, sizeof(nip6));
+      break;
+    }
+    tmp = listdls6;
+    listdls6 = listdls6->next;
+  }
+
+  if(!memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
+    while(sls6) {
+      if(!memcmp(sls6->duid, duid, 6)) {
+        memcpy(nip6, sls6->nip6, sizeof(nip6));
+        break;
+      }
+      sls6 = sls6->next;
+    }
+  }
+
+  if(!memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
+    memcpy(nip6, gconfig.start_ip6, sizeof(nip6));
+    while(memcmp(nip6, gconfig.end_ip6, sizeof(nip6)) < 0) {
+      if(!verifyip6_in_lease(nip6, duid, ia_type, iaid)) break;
+      int i=sizeof(nip6);
+      while(i--) {
+        ++nip6[i];
+        if (!nip6[i]) {
+          if(i==(sizeof(nip6)-1)) ++nip6[i];
+          ++nip6[i-1];
+        } else
+          break;
+      }
+    }
+
+    if (memcmp(nip6, gconfig.end_ip6, sizeof(nip6)) > 0) {
+      memset(nip6, 0, sizeof(nip6));
+      infomsg(infomode, "can't find free IP in IPv6 Pool.");
+    }
+  }
+
+  if(memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
+    addip6_to_lease(nip6, duid, duid_len, ia_type, iaid, lifetime, 1);
+    infomsg(infomode, "Assigned IPv6 %02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+        nip6[0], nip6[1], nip6[2], nip6[3], nip6[4], nip6[5], nip6[6], nip6[7], nip6[8],
+        nip6[9], nip6[10], nip6[11], nip6[12], nip6[13], nip6[14], nip6[15]);
+  }
+  return nip6;
+}
+
+static void read_leasefile(void)
+{
+  uint32_t passed, ip;
+  int32_t tmp_time;
+  int64_t timestamp;
+  dyn_lease *dls;
+  int fd = open(gconfig.lease_file, O_RDONLY);
+
+  dls = xzalloc(sizeof(dyn_lease));
+
+  if (read(fd, &timestamp, sizeof(timestamp)) != sizeof(timestamp))
+    goto lease_error_exit;
+
+  timestamp = SWAP_BE64(timestamp);
+  passed = time(NULL) - timestamp;
+  if ((uint64_t)passed > 12 * 60 * 60) goto lease_error_exit;
+
+  while (read(fd, dls, sizeof(dyn_lease)) == sizeof(dyn_lease)) {
+    ip = ntohl(dls->lease_nip);
+    if (ip >= gconfig.start_ip && ip <= gconfig.end_ip) {
+      tmp_time = ntohl(dls->expires) - passed;
+      if (tmp_time < 0) continue;
+      addip_to_lease(dls->lease_nip, dls->lease_mac,
+          (uint32_t*)&tmp_time, dls->hostname, 0);
+    }
+  }
+lease_error_exit:
+  free(dls);
+  close(fd);
+}
+
+static void read_lease6file(void)
+{
+  uint32_t passed;
+  uint32_t tmp_time;
+  int64_t timestamp;
+  dyn_lease6 *dls6;
+  int fd = open(gconfig.lease6_file, O_RDONLY);
+
+  dls6 = xzalloc(sizeof(dyn_lease6));
+
+  if (read(fd, &timestamp, sizeof(timestamp)) != sizeof(timestamp))
+    goto lease6_error_exit;
+
+  timestamp = SWAP_BE64(timestamp);
+  passed = time(NULL) - timestamp;
+  if ((uint64_t)passed > 12 * 60 * 60) goto lease6_error_exit;
+
+  while (read(fd, dls6, sizeof(dyn_lease6)) == sizeof(dyn_lease6)) {
+    if (memcmp(dls6->lease_nip6, gconfig.start_ip6, sizeof(uint32_t)*4) > 0 &&
+        memcmp(dls6->lease_nip6, gconfig.end_ip6, sizeof(uint32_t)*4) < 0) {
+      tmp_time = ntohl(dls6->expires) - passed;
+      if (tmp_time < 0U) continue;
+      addip6_to_lease(dls6->lease_nip6, dls6->duid, dls6->duid_len, dls6->ia_type, dls6->iaid,
+          (uint32_t*)&tmp_time, 0);
+    }
+  }
+
+lease6_error_exit:
+  free(dls6);
+  close(fd);
+}
+
+void dhcpd_main(void)
+{
+  struct timeval tv;
+  int retval, i;
+  uint8_t *optptr, msgtype = 0;
+  uint16_t optlen = 0;
+  uint32_t waited = 0, serverid = 0, requested_nip = 0;
+  uint8_t transactionid[3] = {0,};
+  uint32_t reqested_lease = 0, ip_pool_size = 0;
+  char *hstname = NULL;
+  fd_set rfds;
+
+  infomode = LOG_CONSOLE;
+  if (!(toys.optflags & FLAG_f)) {
+    daemon(0,0);
+    infomode = LOG_SILENT;
+  }
+  if (toys.optflags & FLAG_S) {
+        openlog("UDHCPD :", LOG_PID, LOG_DAEMON);
+        infomode |= LOG_SYSTEM;
+  }
+  setlinebuf(stdout);
+  //DHCPD_CONF_FILE
+  parse_server_config((toys.optc==1)?toys.optargs[0]:"/etc/dhcpd.conf", keywords);
+  infomsg(infomode, "toybox dhcpd started");
+
+  if (toys.optflags & FLAG_6){
+    addr_version = AF_INET6;
+    gconfig.t1 = ntohl(gconfig.t1);
+    gconfig.t2 = ntohl(gconfig.t2);
+    gconfig.pref_lifetime = ntohl(gconfig.pref_lifetime);
+    gconfig.valid_lifetime = ntohl(gconfig.valid_lifetime);
+    gconfig.port = 547;
+    for(i=0;i<4;i++)
+      ip_pool_size += (gconfig.end_ip6[i]-gconfig.start_ip6[i])<<((3-i)*8);
+  } else {
+    gconfig.start_ip = ntohl(gconfig.start_ip);
+    gconfig.end_ip = ntohl(gconfig.end_ip);
+    ip_pool_size = gconfig.end_ip - gconfig.start_ip + 1;
+  }
+
+  if (gconfig.max_leases > ip_pool_size) {
+    error_msg("max_leases=%u is too big, setting to %u",
+        (unsigned) gconfig.max_leases, ip_pool_size);
+    gconfig.max_leases = ip_pool_size;
+  }
+  write_pid(gconfig.pidfile);
+  set_maxlease();
+  if(TT.iface) gconfig.interface = TT.iface;
+  if(TT.port) gconfig.port = TT.port;
+  (addr_version==AF_INET6) ? read_lease6file() : read_leasefile();
+
+
+  if (get_interface(gconfig.interface, &gconfig.ifindex,
+        (addr_version==AF_INET6)? (void*)gconfig.server_nip6 :
+        (void*)&gconfig.server_nip, gconfig.server_mac) < 0)
+    perror_exit("Failed to get interface %s", gconfig.interface);
+  setup_signal();
+  if (addr_version==AF_INET6) {
+    open_listensock6();
+  } else {
+    gconfig.server_nip = htonl(gconfig.server_nip);
+    open_listensock();
+  }
+
+  fcntl(gstate.listensock, F_SETFD, FD_CLOEXEC);
+
+  for (;;) {
+    uint32_t timestmp = time(NULL);
+    FD_ZERO(&rfds);
+    FD_SET(gstate.listensock, &rfds);
+    FD_SET(sigfd.rd, &rfds);
+    tv.tv_sec = gconfig.auto_time - waited;
+    tv.tv_usec = 0;
+    retval = 0;
+    serverid = 0;
+    msgtype = 0;
+
+    int maxfd = (sigfd.rd > gstate.listensock)? sigfd.rd : gstate.listensock;
+    dbg("select waiting ....\n");
+    retval = select(maxfd + 1, &rfds, NULL, NULL, (gconfig.auto_time?&tv:NULL));
+    if (retval < 0) {
+      if (errno == EINTR) {
+        waited += (unsigned) time(NULL) - timestmp;
+        continue;
+      }
+      dbg("Error in select wait again...\n");
+      continue;
+    }
+    if (!retval) { // Timed out 
+      dbg("select wait Timed Out...\n");
+      waited = 0;
+      (addr_version == AF_INET6)? write_lease6file() : write_leasefile();
+      if (get_interface(gconfig.interface, &gconfig.ifindex,
+            (addr_version==AF_INET6)? (void*)gconfig.server_nip6 :
+            (void*)&gconfig.server_nip, gconfig.server_mac)<0)
+        perror_exit("Failed to get interface %s", gconfig.interface);
+      if(addr_version != AF_INET6) {
+        gconfig.server_nip = htonl(gconfig.server_nip);
+      }
+      continue;
+    }
+    if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal 
+      unsigned char sig;
+      if (read(sigfd.rd, &sig, 1) != 1) {
+        dbg("signal read failed.\n");
+        continue;
+      }
+      switch (sig) {
+        case SIGUSR1:
+          infomsg(infomode, "Received SIGUSR1");
+          (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
+          continue;
+        case SIGTERM:
+          infomsg(infomode, "received sigterm");
+          (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
+          unlink(gconfig.pidfile);
+          exit(0);
+          break;
+        default: break;
+      }
+    }
+    if (FD_ISSET(gstate.listensock, &rfds)) { // Some Activity on RDFDs : is socket
+      dbg("select listen sock read\n");
+      if(addr_version==AF_INET6) {
+        void *client_duid, *server_duid, *client_ia_na, *server_ia_na,
+             *client_ia_pd;
+        uint8_t client_lla[6] = {0,};
+        uint16_t client_duid_len = 0, server_duid_len = 0, server_ia_na_len = 0,
+                 client_ia_na_len = 0, client_ia_pd_len = 0;
+
+        if(read_packet6() < 0) {
+          open_listensock6();
+          continue;
+        }
+        waited += time(NULL) - timestmp;
+
+        memcpy(&gstate.rqcode, &gstate.rcvd.rcvd_pkt6.msgtype, sizeof(uint8_t));
+        memcpy(&transactionid, &gstate.rcvd.rcvd_pkt6.transaction_id,
+            sizeof(transactionid));
+
+        if (!gstate.rqcode || gstate.rqcode < DHCP6SOLICIT ||
+            gstate.rqcode > DHCP6RELAYREPLY) {
+          dbg("no or bad message type option, ignoring packet.\n");
+          continue;
+        }
+        if (!gstate.rcvd.rcvd_pkt6.transaction_id || 
+            memcmp(gstate.rcvd.rcvd_pkt6.transaction_id, transactionid, 3)) {
+          dbg("no or bad transaction id, ignoring packet.\n");
+          continue;
+        }
+
+        waited += time(NULL) - timestmp;
+        switch (gstate.rqcode) {
+          case DHCP6SOLICIT:
+            dbg("Message Type: DHCP6SOLICIT\n");
+            optptr = prepare_send_pkt6(DHCP6ADVERTISE);
+            optlen = 0;
+
+            //TODO policy check
+            //TODO Receive: ORO check (e.g. DNS)
+
+            //Receive: Client Identifier (DUID)
+            get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
+                DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid);
+
+            //Receive: Identity Association for Non-temporary Address
+            if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
+                  DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) {
+              uint16_t ia_addr_len = sizeof(struct optval_ia_addr);
+              void *ia_addr, *status_code;
+              char *status_code_msg;
+              uint16_t status_code_len = 0;
+              server_ia_na_len = sizeof(struct optval_ia_na);
+
+              //IA Address
+              ia_addr = xzalloc(ia_addr_len);
+              struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr;
+              (*ia_addr_p).pref_lifetime = gconfig.pref_lifetime;
+              (*ia_addr_p).valid_lifetime = gconfig.valid_lifetime;
+              memcpy(&(*ia_addr_p).ipv6_addr,
+                  getip6_from_pool(client_duid, client_duid_len,
+                    DHCP6_OPT_IA_NA, (*(struct optval_ia_na*) client_ia_na).iaid,
+                    &(*ia_addr_p).pref_lifetime), sizeof(uint32_t)*4);
+              server_ia_na_len += (ia_addr_len+4);
+
+              //Status Code
+              if(memcmp((*ia_addr_p).ipv6_addr, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
+                status_code_msg = xstrdup("Assigned an address.");
+                status_code_len = strlen(status_code_msg)+1;
+                status_code = xzalloc(status_code_len);
+                struct optval_status_code *status_code_p =
+                  (struct optval_status_code*)status_code;
+                (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS);
+                memcpy((*status_code_p).status_msg, status_code_msg,
+                    status_code_len);
+                server_ia_na_len += (status_code_len+4);
+                free(status_code_msg);
+              } else {
+                status_code_msg = xstrdup("There's no available address.");
+                status_code_len = strlen(status_code_msg)+1;
+                status_code = xzalloc(status_code_len);
+                struct optval_status_code *status_code_p =
+                  (struct optval_status_code*)status_code;
+                (*status_code_p).status_code = htons(DHCP6_STATUS_NOADDRSAVAIL);
+                memcpy((*status_code_p).status_msg, status_code_msg,
+                    status_code_len);
+                server_ia_na_len += (status_code_len+4);
+                server_ia_na_len -= (ia_addr_len+4);
+                ia_addr_len = 0;
+                free(ia_addr);
+                free(status_code_msg);
+                //TODO send failed status code
+                break;
+              }
+
+              //combine options
+              server_ia_na = xzalloc(server_ia_na_len);
+              struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na;
+              (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid;
+              (*ia_na_p).t1 = gconfig.t1;
+              (*ia_na_p).t2 = gconfig.t2;
+
+              uint8_t* ia_na_optptr = (*ia_na_p).optval;
+              if(ia_addr_len) {
+                set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR, ia_addr, ia_addr_len);
+                ia_na_optptr += (ia_addr_len + 4);
+                free(ia_addr);
+              }
+              if(status_code_len) {
+                set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE, status_code,
+                    status_code_len);
+                ia_na_optptr += (status_code_len);
+                free(status_code);
+              }
+
+              //Response: Identity Association for Non-temporary Address
+              optptr = set_optval6(optptr, DHCP6_OPT_IA_NA, server_ia_na,
+                  server_ia_na_len);
+              optlen += (server_ia_na_len + 4);
+              free(client_ia_na);free(server_ia_na);
+            }
+            //Receive: Identity Association for Prefix Delegation
+            else if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
+                  DHCP6_OPT_IA_PD, &client_ia_pd_len, &client_ia_pd)) {
+
+              //TODO
+              //Response: Identity Association for Prefix Delegation
+            }
+
+            //DUID type: link-layer address plus time
+            if(ntohs((*(struct optval_duid_llt*)client_duid).type) ==
+                DHCP6_DUID_LLT) {
+              server_duid_len = 8+sizeof(gconfig.server_mac);
+              server_duid = xzalloc(server_duid_len);
+              struct optval_duid_llt *server_duid_p =
+                (struct optval_duid_llt*)server_duid;
+              (*server_duid_p).type = htons(1);
+              (*server_duid_p).hwtype = htons(1);
+              (*server_duid_p).time = htonl((uint32_t)
+                  (time(NULL) - 946684800) & 0xffffffff);
+              memcpy((*server_duid_p).lladdr, gconfig.server_mac,
+                  sizeof(gconfig.server_mac));
+              memcpy(&client_lla, (*(struct optval_duid_llt*)client_duid).lladdr,
+                  sizeof(client_lla));
+
+              //Response: Server Identifier (DUID)
+              optptr = set_optval6(optptr, DHCP6_OPT_SERVERID, server_duid,
+                  server_duid_len);
+              optlen += (server_duid_len + 4);
+              //Response: Client Identifier
+              optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid,
+                  client_duid_len);
+              optlen += (client_duid_len + 4);
+              free(client_duid);free(server_duid);
+            }
+
+            send_packet6(0, client_lla, optlen);
+            write_lease6file();
+            break;
+          case DHCP6REQUEST:
+            dbg("Message Type: DHCP6REQUEST\n");
+            optptr = prepare_send_pkt6(DHCP6REPLY);
+            optlen = 0;
+
+            //Receive: Client Identifier (DUID)
+            get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
+                DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid);
+            optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid,
+                client_duid_len);
+            optlen += (client_duid_len + 4);
+            memcpy(client_lla, (*(struct optval_duid_llt*)client_duid).lladdr,
+                sizeof(client_lla));
+
+            //Receive: Identity Association for Non-temporary Address
+            if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
+                  DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) {
+              uint16_t ia_addr_len = 0, status_code_len = 0;
+              void *ia_addr, *status_code;
+              uint16_t server_ia_na_len = sizeof(struct optval_ia_na);
+              char *status_code_msg;
+
+              //Check IA Address
+              get_optval6((uint8_t*)(*(struct optval_ia_na*)client_ia_na).optval,
+                  DHCP6_OPT_IA_ADDR, &ia_addr_len, &ia_addr);
+              struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr;
+              if(verifyip6_in_lease((*ia_addr_p).ipv6_addr, client_duid,
+                    DHCP6_OPT_IA_NA, (*(struct optval_ia_na*)client_ia_na).iaid)
+                  == -1) {
+                server_ia_na_len += (ia_addr_len + 4);
+                //Add Status Code
+                status_code_msg = xstrdup("Assigned an address.");
+                status_code_len = strlen(status_code_msg) + 1;
+                status_code = xzalloc(status_code_len);
+                struct optval_status_code *status_code_p =
+                  (struct optval_status_code*)status_code;
+                (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS);
+                memcpy((*status_code_p).status_msg, status_code_msg,
+                    status_code_len);
+                server_ia_na_len += (status_code_len+4);
+              } else {
+                //TODO send failed status code
+                break;
+              }
+
+              //combine options
+              server_ia_na = xzalloc(server_ia_na_len);
+              struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na;
+              (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid;
+              (*ia_na_p).t1 = gconfig.t1;
+              (*ia_na_p).t2 = gconfig.t2;
+
+              uint8_t* ia_na_optptr = (*ia_na_p).optval;
+              ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR,
+                  ia_addr, ia_addr_len);
+              free(ia_addr);
+
+              if(status_code_len) {
+                ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE,
+                    status_code, status_code_len);
+                free(status_code);
+              }
+
+              //Response: Identity Association for Non-temporary Address
+              //(Status Code added)
+              optptr = set_optval6(optptr, DHCP6_OPT_IA_NA,
+                  server_ia_na, server_ia_na_len);
+              optlen += (server_ia_na_len + 4);
+              free(client_ia_na);free(server_ia_na);
+            }
+
+            //Receive: Server Identifier (DUID)
+            get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
+                DHCP6_OPT_SERVERID, &server_duid_len, &server_duid);
+            optptr = set_optval6(optptr, DHCP6_OPT_SERVERID,
+                server_duid, server_duid_len);
+            optlen += (server_duid_len + 4);
+
+            free(client_duid); free(server_duid);
+
+            send_packet6(0, client_lla, optlen);
+            write_lease6file();
+            break;
+          case DHCP6DECLINE:  //TODO
+          case DHCP6RENEW:    //TODO
+          case DHCP6REBIND:   //TODO
+          case DHCP6RELEASE:
+            dbg("Message Type: DHCP6RELEASE\n");
+            optptr = prepare_send_pkt6(DHCP6REPLY);
+            break;
+          default:
+            dbg("Message Type : %u\n", gstate.rqcode);
+            break;
+        }
+        
+      } else {
+        if(read_packet() < 0) {
+          open_listensock();
+          continue;
+        }
+        waited += time(NULL) - timestmp;
+
+        get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.options,
+            DHCP_OPT_MESSAGE_TYPE, &gstate.rqcode);
+        if (gstate.rqcode == 0 || gstate.rqcode < DHCPDISCOVER 
+            || gstate.rqcode > DHCPINFORM) {
+          dbg("no or bad message type option, ignoring packet.\n");
+          continue;
+        }
+        get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+            DHCP_OPT_SERVER_ID, &serverid);
+        if (serverid && (serverid != gconfig.server_nip)) {
+          dbg("server ID doesn't match, ignoring packet.\n");
+          continue;
+        }
+
+        waited += time(NULL) - timestmp;
+        switch (gstate.rqcode) {
+          case DHCPDISCOVER:
+            msgtype = DHCPOFFER;
+            dbg("Message Type : DHCPDISCOVER\n");
+            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+                DHCP_OPT_REQUESTED_IP, &requested_nip);
+            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+                DHCP_OPT_HOST_NAME, &hstname);
+            reqested_lease = gconfig.offer_time;
+            get_reqparam(&gstate.rqopt);
+            optptr = prepare_send_pkt();
+            gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip,
+                gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname);
+            if(!gstate.send.send_pkt.yiaddr){
+              msgtype = DHCPNAK;
+              optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
+              send_packet(1);
+              break;
+            }
+            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+                DHCP_OPT_LEASE_TIME, &reqested_lease);
+            reqested_lease = htonl(get_lease(reqested_lease + time(NULL)));
+            optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
+            optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4);
+            optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4);
+            optptr = set_reqparam(optptr, gstate.rqopt);
+            send_packet(1);
+            break;
+          case DHCPREQUEST:
+            msgtype = DHCPACK;
+            dbg("Message Type : DHCPREQUEST\n");
+            optptr = prepare_send_pkt();
+            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+                DHCP_OPT_REQUESTED_IP, &requested_nip);
+            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+                DHCP_OPT_LEASE_TIME, &reqested_lease);
+            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+                DHCP_OPT_HOST_NAME, &hstname);
+            gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip,
+                gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname);
+            if (!serverid) reqested_lease = gconfig.max_lease_sec;
+            if (!gstate.send.send_pkt.yiaddr) {
+              msgtype = DHCPNAK;
+              optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
+              send_packet(1);
+              break;
+            }
+            optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
+            optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4);
+            reqested_lease = htonl(reqested_lease);
+            optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4);
+            send_packet(1);
+            write_leasefile();
+            break;
+          case DHCPDECLINE:// FALL THROUGH
+          case DHCPRELEASE:
+            dbg("Message Type : DHCPDECLINE or DHCPRELEASE \n");
+            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+                DHCP_OPT_SERVER_ID, &serverid);
+            if (serverid != gconfig.server_nip) break;
+            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
+                DHCP_OPT_REQUESTED_IP, &requested_nip);
+            delip_from_lease(requested_nip, gstate.rcvd.rcvd_pkt.chaddr,
+                (gstate.rqcode==DHCPRELEASE)?0:gconfig.decline_time);
+            break;
+          default:
+            dbg("Message Type : %u\n", gstate.rqcode);
+            break;
+        }
+      }
+    }
+  }
+}
diff --git a/toybox/toys/pending/diff.c b/toybox/toys/pending/diff.c
new file mode 100644
index 0000000..53bdbce
--- /dev/null
+++ b/toybox/toys/pending/diff.c
@@ -0,0 +1,837 @@
+/* diff.c - compare files line by line
+ *
+ * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2014 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ *
+ * See: http://cm.bell-labs.com/cm/cs/cstr/41.pdf
+
+USE_DIFF(NEWTOY(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", TOYFLAG_USR|TOYFLAG_BIN))
+
+config DIFF
+  bool "diff"
+  default n
+  help
+  usage: diff [-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2
+
+  -a  Treat all files as text
+  -b  Ignore changes in the amount of whitespace
+  -B  Ignore changes whose lines are all blank
+  -d  Try hard to find a smaller set of changes
+  -i  Ignore case differences
+  -L  Use LABEL instead of the filename in the unified header
+  -N  Treat absent files as empty
+  -q  Output only whether files differ
+  -r  Recurse
+  -S  Start with FILE when comparing directories
+  -T  Make tabs line up by prefixing a tab when necessary
+  -s  Report when two files are the same
+  -t  Expand tabs to spaces in output
+  -U  Output LINES lines of context
+  -w  Ignore all whitespace
+*/
+
+#define FOR_diff
+#include "toys.h"
+
+GLOBALS(
+  long ct;
+  char *start;
+  struct arg_list *L_list;
+
+  int dir_num, size, is_binary, status, change, len[2];
+  int *offset[2];
+)
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define IS_STDIN(s)     ((s)[0] == '-' && !(s)[1])
+
+struct v_vector {
+  unsigned serial:31;
+  unsigned last:1;
+  union {
+    unsigned hash;
+    unsigned p;
+  };
+};
+
+struct diff {
+  long a, b, c, d, prev, suff;
+};
+
+static struct dir_t {
+  char **list;
+  int nr_elm;
+} dir[2];
+
+struct candidate {
+  int a, b;
+  struct candidate *prev, *next;
+};
+
+static struct file_t {
+  FILE *fp;
+  int len;
+} file[2];
+
+enum {
+  SAME,
+  DIFFER,
+};
+
+enum {
+  empty = 1 << 9,
+  eol = 1 << 10,
+  eof = 1 << 11,
+  space = 1 << 12
+};
+
+static int comp(const void *a, const void* b)
+{
+  int i = ((struct v_vector *)a)->hash -
+    ((struct v_vector *)b)->hash;
+
+  if (!i) i = ((struct v_vector *)a)->serial -
+    ((struct v_vector *)b)->serial;
+  return i;
+}
+
+static int search (struct candidate **K, int r, int k, int j)
+{
+  int low = r, upper = k, mid;
+
+  mid = (low + upper) / 2;
+  while (low <= mid) {
+    if (((struct candidate*)(K[mid]))->b < j &&
+        ((struct candidate*)(K[mid + 1]))->b > j)
+      return mid;
+
+    if (((struct candidate*)(K[mid]))->b < j) low = mid + 1;
+    else if (((struct candidate*)(K[mid]))->b > j) upper = mid - 1;
+    else return -1;
+
+    mid = (low + upper) / 2;
+  }
+  return -1;
+}
+
+static struct candidate * new_candidate (int i, int j, struct candidate* prev)
+{
+  struct candidate *c = xzalloc(sizeof(struct candidate));
+
+  c->a = i;
+  c->b = j;
+  c->prev = prev;
+  return c;
+}
+
+
+static void free_candidates(struct candidate *c)
+{
+  struct candidate *t = c;
+  
+  while ((t = c)) {
+    c = c->next;
+    free(t);
+  }
+}
+/*
+ * 1. Search K[r: k] for an element K[s] such that K[s]-> b < j and K[s + 1]->b > j
+ * 2. if found do
+ *  2.a. If K[s + 1]->b > j do K[r] = c; r = s+1 and c = candidate(i, j, K[s]) //we have a candidate
+ *  2.b. if s = k (fence reached move it further) do K[k + 2] = K[k + 1], k++
+ * 3. if E[p].last true break i.e we have reached at the end of an equiv class
+ *    else p = p + 1 //keep traversing the equiv class.
+ * 4. K[r] = c //Save the sucessfully filled k-candidate.
+ */
+static void  do_merge(struct candidate **K, int *k, int i,
+    struct v_vector *E, int p)
+{
+  int r = 0, s, j;
+  struct candidate *pr = 0, *c = K[0];
+
+  while (1) {
+    j = E[p].serial;
+    s = search(K, r, *k, j);
+    if (s >= 0 && (((struct candidate*)(K[s]))->b < j &&
+          ((struct candidate*)(K[s + 1]))->b > j)) {
+
+      if (((struct candidate*)(K[s + 1]))->b > j) {
+        pr = K[s];
+        if (r && K[r]) c->next = K[r];
+        K[r] = c;
+        r = s + 1;
+        c = new_candidate(i , j, pr);
+      }
+      if (s == *k) {
+        K[*k + 2] = K[*k + 1];
+        *k = *k + 1;
+        break;
+      }
+    }
+    if (E[p].last) break;
+    else p = p + 1;
+  }
+  K[r] = c;
+}
+
+static FILE* read_stdin()
+{
+  char tmp_name[] = "/tmp/diffXXXXXX";
+  int rd, wr, tmpfd = mkstemp(tmp_name);
+
+  if (tmpfd == -1) perror_exit("mkstemp");
+  unlink(tmp_name);
+
+  while (1) {
+    rd = xread(STDIN_FILENO, toybuf, sizeof(toybuf));
+
+    if (!rd) break;
+    if (rd < 0) perror_exit("read error");
+    wr = writeall(tmpfd, toybuf, rd);
+    if (wr < 0) perror_exit("write");
+  }
+  return fdopen(tmpfd, "r");
+}
+
+static int read_tok(FILE *fp, off_t *off, int tok)
+{
+  int t = 0, is_space;
+
+  tok |= empty;
+  while (!(tok & eol)) {
+
+    t = fgetc(fp);
+    if (off && t != EOF) *off += 1;
+    is_space = isspace(t) || (t == EOF);
+    tok |= (t & (eof + eol)); //set tok eof+eol when t is eof
+
+    if (t == '\n') tok |= eol;
+    if (toys.optflags & FLAG_i)
+      if (t >= 'A' && t <= 'Z') t = tolower(t);
+
+    if (toys.optflags & FLAG_w && is_space) continue;
+
+    if (toys.optflags & FLAG_b) {
+      if (tok & space) {
+        if (is_space) continue;
+        tok &= ~space;
+      } else if (is_space) t = space + ' ';
+    }
+    tok &= ~(empty + 0xff);  //remove empty and char too.
+    tok |= t; //add most recent char
+    break;
+  }
+
+  return tok;
+}
+
+int bcomp(const void *a, const void *b) 
+{
+  struct v_vector *l = (struct v_vector*)a,
+                  *r = (struct v_vector*)b;
+  int ret = l->hash - r->hash;
+
+  if (!ret) {
+    if ((r -1)->last) return 0;
+    else return -1;
+  }
+  return ret;
+}
+/*  file[0] corresponds file 1 and file[1] correspond file 2.
+ * 1. calc hashes for both the files and store them in vector(v[0], v[1])
+ * 2. sort file[1] with hash as primary and serial as sec. key
+ * 3. Form the equivalance class of file[1] stored in e vector. It lists all the equivalence
+ *    classes of lines in file[1], with e.last = true on the last element of each class.
+ *    The elements are ordered by serial within classes.
+ * 4. Form the p vector stored in  p_vector. p_vector[i], if non-zero, now points in e vector
+ *    to the begining of the equiv class of lines in file[1] equivalent to line
+ *    i in file[0].
+ * 5. Form the k-candidates as discribed in do_merge.
+ * 6. Create a vector J[i] = j, such that i'th line in file[0] is j'th line of
+ *    file[1], i.e J comprises LCS
+ */
+static int * create_j_vector()
+{
+  int tok, i, j, size = 100, k;
+  off_t off;
+  long hash;
+  int *p_vector, *J;
+  struct v_vector *v[2], *e;
+  struct candidate **kcand, *pr;
+
+  for (i = 0; i < 2; i++) {
+    tok = off = 0;
+    hash = 5831;
+    v[i] = xzalloc(size * sizeof(struct v_vector));
+    TT.offset[i] = xzalloc(size * sizeof(int));
+    file[i].len = 0;
+    fseek(file[i].fp, 0, SEEK_SET);
+
+    while (1) {
+      tok  = read_tok(file[i].fp, &off, tok);
+      if (!(tok & empty)) {
+        hash = ((hash << 5) + hash) + (tok & 0xff);
+        continue;
+      }
+
+      if (size == ++file[i].len) {
+        size = size * 11 / 10;
+        v[i] = xrealloc(v[i], size*sizeof(struct v_vector));
+        TT.offset[i] = xrealloc(TT.offset[i], size*sizeof(int));
+      }
+
+      v[i][file[i].len].hash = hash & INT_MAX;
+      TT.offset[i][file[i].len] = off;
+      if ((tok & eof)) {
+        TT.offset[i][file[i].len] = ++off;
+        break;
+      }
+      hash = 5831;  //next line
+      tok = 0;
+    }
+    if (TT.offset[i][file[i].len] - TT.offset[i][file[i].len - 1] == 1)
+      file[i].len--;
+  }
+
+  for (i = 0; i <= file[1].len; i++) v[1][i].serial = i;
+  qsort(v[1] + 1, file[1].len, sizeof(struct v_vector), comp);
+
+  e = v[1];
+  e[0].serial = 0;
+  e[0].last = 1;
+  for ( i = 1; i <= file[1].len; i++) {
+    if ((i == file[1].len) || (v[1][i].hash != v[1][i+1].hash)) e[i].last = 1;
+    else e[i].last = 0;
+  }
+
+  p_vector = xzalloc((file[0].len + 2) * sizeof(int));
+  for (i = 1; i <= file[0].len; i++) {
+    void *r = bsearch(&v[0][i], (e + 1), file[1].len, sizeof(e[0]), bcomp);
+    if (r) p_vector[i] = (struct v_vector*)r - e;
+  }
+
+  for (i = 1; i <= file[0].len; i++)
+    e[i].p = p_vector[i];
+  free(p_vector);
+
+  size = 100;
+  kcand = xzalloc(size * sizeof(struct candidate*));
+
+  kcand[0] = new_candidate(0 , 0, NULL);
+  kcand[1] = new_candidate(file[0].len+1, file[1].len+1, NULL); //the fence
+
+  k = 0;  //last successfully filled k candidate.
+  for (i = 1; i <= file[0].len; i++) {
+
+    if (!e[i].p) continue;
+    if ((size - 2) == k) {
+      size = size * 11 / 10;
+      kcand = xrealloc(kcand, (size * sizeof(struct candidate*)));
+    }
+    do_merge(kcand, &k, i, e, e[i].p);
+  }
+  free(v[0]); //no need for v_vector now.
+  free(v[1]);
+
+  J = xzalloc((file[0].len + 2) * sizeof(int));
+
+  for (pr = kcand[k]; pr; pr = pr->prev)
+    J[pr->a] = pr->b;
+  J[file[0].len + 1] = file[1].len+1; //mark boundary
+
+  for (i = k + 1; i >= 0; i--) free_candidates(kcand[i]);
+  free(kcand);
+
+  for (i = 1; i <= file[0].len; i++) { // jackpot?
+    if (!J[i]) continue;
+
+    fseek(file[0].fp, TT.offset[0][i - 1], SEEK_SET);
+    fseek(file[1].fp, TT.offset[1][J[i] - 1], SEEK_SET);
+
+    for (j = J[i]; i <= file[0].len && J[i] == j; i++, j++) {
+      int tok0 = 0, tok1 = 0;
+
+      do {
+        tok0 = read_tok(file[0].fp, NULL, tok0);
+        tok1 = read_tok(file[1].fp, NULL, tok1);
+        if (((tok0 ^ tok1) & empty) || ((tok0 & 0xff) != (tok1 & 0xff)))
+          J[i] = 0;
+      } while (!(tok0 & tok1 & empty));
+    }
+  }
+  return J;
+}
+
+static int *diff(char **files)
+{
+  size_t i ,j;
+  int s, t;
+  char *bufi, *bufj;
+
+  TT.is_binary = 0; //loop calls to diff
+  TT.status = SAME;
+
+  for (i = 0; i < 2; i++) {
+    if (IS_STDIN(files[i])) file[i].fp = read_stdin();
+    else file[i].fp = fopen(files[i], "r");
+
+    if (!file[i].fp){
+      perror_msg("%s",files[i]);
+      TT.status = 2;
+      return NULL; //return SAME
+    }
+  }
+
+  s = sizeof(toybuf)/2;
+  bufi = toybuf;
+  bufj = (toybuf + s);
+
+  fseek(file[0].fp, 0, SEEK_SET);
+  fseek(file[1].fp, 0, SEEK_SET);
+
+  if (toys.optflags & FLAG_a) return create_j_vector();
+
+  while (1) {
+    i = fread(bufi, 1, s, file[0].fp);
+    j = fread(bufj, 1, s, file[1].fp);
+
+    if (i != j) TT.status = DIFFER;
+
+    for (t = 0; t < i && !TT.is_binary; t++)
+      if (!bufi[t]) TT.is_binary = 1;
+    for (t = 0; t < j && !TT.is_binary; t++)
+      if (!bufj[t]) TT.is_binary = 1;
+
+    i = MIN(i, j);
+    for (t = 0; t < i; t++)
+      if (bufi[t] != bufj[t]) TT.status = DIFFER;
+
+    if (!i || !j) break;
+  }
+  if (TT.is_binary || (TT.status == SAME)) return NULL;
+  return create_j_vector();
+}
+
+static void print_diff(int a, int b, char c, int *off_set, FILE *fp)
+{
+  int i, j, cc, cl;
+
+  for (i = a; i <= b; i++) {
+    fseek(fp, off_set[i - 1], SEEK_SET);
+    putchar(c);
+    if (toys.optflags & FLAG_T) putchar('\t');
+    for (j = 0, cl = 0; j <  (off_set[i] - off_set[i - 1]); j++) {
+      cc = fgetc(fp);
+      if (cc == EOF) {
+        printf("\n\\ No newline at end of file\n");
+        return;
+      }
+      if ((cc == '\t') && (toys.optflags & FLAG_t))
+        do putchar(' '); while (++cl & 7);
+      else {
+        putchar(cc); //xputc has calls to fflush, it hurts performance badly.
+        cl++;
+      }
+    }
+  }
+}
+
+static char *concat_file_path(char *path, char *default_path)
+{
+  char *final_path;
+
+  if ('/' == path[strlen(path) - 1]) {
+    while (*default_path == '/') ++default_path;
+    final_path = xmprintf("%s%s", path, default_path);
+  }
+  else if (*default_path != '/')
+    final_path = xmprintf("%s/%s", path, default_path);
+  else final_path = xmprintf("%s%s", path, default_path);
+  return final_path;
+}
+
+static int skip(struct dirtree *node)
+{
+  int len = strlen(toys.optargs[TT.dir_num]), ret = 0;
+  char *tmp = NULL, *ptr, *f_path = dirtree_path(node, NULL);
+  struct stat st;
+
+  ptr = f_path;
+  ptr += len;
+  if (ptr[0]) {
+    tmp = concat_file_path(toys.optargs[1 - TT.dir_num], ptr);
+    if (tmp && !stat(tmp, &st)) ret = 0; //it is there on other side
+    else ret = 1; //not present on other side.
+  }
+  free(f_path);
+  if (tmp) free(tmp);
+  return ret; //add otherwise
+}
+
+static void add_to_list(struct dirtree *node)
+{
+  char *full_path;
+
+  dir[TT.dir_num].list = xrealloc(dir[TT.dir_num].list,
+      (TT.size + 1)*sizeof(char*));
+  TT.size++;
+  full_path = dirtree_path(node, NULL);
+  dir[TT.dir_num].list[TT.size - 1] = full_path;
+}
+
+static int list_dir (struct dirtree *node)
+{
+  int ret = 0;
+
+  if (node->parent && !dirtree_notdotdot(node)) return 0;
+
+  if (S_ISDIR(node->st.st_mode) && !node->parent) { //add root dirs.
+    add_to_list(node);
+    return (DIRTREE_RECURSE|DIRTREE_SYMFOLLOW);
+  }
+
+  if (S_ISDIR(node->st.st_mode) && (toys.optflags & FLAG_r)) {
+    if (!(toys.optflags & FLAG_N)) ret = skip(node);
+    if (!ret) return (DIRTREE_RECURSE|DIRTREE_SYMFOLLOW);
+    else {
+      add_to_list(node); //only at one side.
+      return 0;
+    }
+  } else {
+    add_to_list(node);
+    return S_ISDIR(node->st.st_mode) ? 0 : (DIRTREE_RECURSE|DIRTREE_SYMFOLLOW);
+  }
+}
+
+static int cmp(const void *p1, const void *p2)
+{
+   return strcmp(* (char * const *)p1, * (char * const *)p2);
+}
+
+static void do_diff(char **files)
+{
+
+  long i = 1, size = 1, x = 0, change = 0, ignore_white,
+   start1, end1, start2, end2;
+  struct diff *d;
+  struct arg_list *llist = TT.L_list;
+  int *J;
+  
+  TT.offset[0] = TT.offset[1] = NULL;
+  J = diff(files);
+
+  if (!J) return; //No need to compare, have to status only
+
+  d = xzalloc(size *sizeof(struct diff));
+  do {
+    ignore_white = 0;
+    for (d[x].a = i; d[x].a <= file[0].len; d[x].a++) {
+      if (J[d[x].a] != (J[d[x].a - 1] + 1)) break;
+      else continue;
+    }
+    d[x].c = (J[d[x].a - 1] + 1);
+
+    for (d[x].b = (d[x].a - 1); d[x].b <= file[0].len; d[x].b++) {
+      if (J[d[x].b + 1]) break;
+      else continue;
+    }
+    d[x].d = (J[d[x].b + 1] - 1);
+
+    if ((toys.optflags & FLAG_B)) {
+      if (d[x].a <= d[x].b) {
+        if ((TT.offset[0][d[x].b] - TT.offset[0][d[x].a - 1])
+            == (d[x].b - d[x].a + 1))
+          ignore_white = 1;
+      } else if (d[x].c <= d[x].d){
+        if ((TT.offset[1][d[x].d] - TT.offset[1][d[x].c - 1])
+            == (d[x].d - d[x].c + 1))
+          ignore_white = 1;
+      }
+    }
+
+    if ((d[x].a <= d[x].b || d[x].c <= d[x].d) && !ignore_white)
+      change = 1; //is we have diff ?
+
+    if (!ignore_white) d = xrealloc(d, (x + 2) *sizeof(struct diff));
+    i = d[x].b + 1;
+    if (i > file[0].len) break;
+    J[d[x].b] = d[x].d;
+    if (!ignore_white) x++;
+  } while (i <= file[0].len);
+
+  i = x+1;
+  TT.status = change; //update status, may change bcoz of -w etc.
+
+  if (!(toys.optflags & FLAG_q) && change) {  //start of !FLAG_q
+
+      xprintf("--- %s\n", (toys.optflags & FLAG_L) ? llist->arg : files[0]);
+      if (((toys.optflags & FLAG_L) && !llist->next) || !(toys.optflags & FLAG_L))
+        xprintf("+++ %s\n", files[1]);
+      else {
+        while (llist->next) llist = llist->next;
+        xprintf("+++ %s\n", llist->arg);
+      }
+
+    struct diff *t, *ptr1 = d, *ptr2 = d;
+    while (i) {
+      long a,b;
+
+      if (TT.ct > file[0].len) TT.ct = file[0].len; //trim context to file len.
+      if (ptr1->b < ptr1->a && ptr1->d < ptr1->c) {
+        i--;
+        continue;
+      }
+      //Handle the context stuff
+      a =  ptr1->a;
+      b =  ptr1->b;
+
+      b  = MIN(file[0].len, b);
+      if (i == x + 1) ptr1->suff = MAX(1,a - TT.ct);
+      else {
+        if ((ptr1 - 1)->prev >= (ptr1->a - TT.ct))
+          ptr1->suff = (ptr1 - 1)->prev + 1;
+        else ptr1->suff =  ptr1->a - TT.ct;
+      }
+calc_ct:
+      if (i > 1) {
+        if ((ptr2->b + TT.ct) >= (ptr2  + 1)->a) {
+          ptr2++;
+          i--;
+          goto calc_ct;
+        } else ptr2->prev = ptr2->b + TT.ct;
+      } else ptr2->prev = ptr2->b;
+      start1 = (ptr2->prev - ptr1->suff + 1);
+      end1 = (start1 == 1) ? -1 : start1;
+      start2 = MAX(1, ptr1->c - (ptr1->a - ptr1->suff));
+      end2 = ptr2->prev - ptr2->b + ptr2->d;
+
+      printf("@@ -%ld", start1 ? ptr1->suff: (ptr1->suff -1));
+      if (end1 != -1) printf(",%ld ", ptr2->prev-ptr1->suff + 1);
+      else putchar(' ');
+
+      printf("+%ld", (end2 - start2 + 1) ? start2: (start2 -1));
+      if ((end2 - start2 +1) != 1) printf(",%ld ", (end2 - start2 +1));
+      else putchar(' ');
+      printf("@@\n");
+
+      for (t = ptr1; t <= ptr2; t++) {
+        if (t== ptr1) print_diff(t->suff, t->a-1, ' ', TT.offset[0], file[0].fp);
+        print_diff(t->a, t->b, '-', TT.offset[0], file[0].fp);
+        print_diff(t->c, t->d, '+', TT.offset[1], file[1].fp);
+        if (t == ptr2)
+          print_diff(t->b+1, (t)->prev, ' ', TT.offset[0], file[0].fp);
+        else print_diff(t->b+1, (t+1)->a-1, ' ', TT.offset[0], file[0].fp);
+      }
+      ptr2++;
+      ptr1 = ptr2;
+      i--;
+    } //end of while
+  } //End of !FLAG_q
+  free(d);
+  free(J);
+  free(TT.offset[0]);
+  free(TT.offset[1]);
+}
+
+static void show_status(char **files)
+{
+  switch (TT.status) {
+    case SAME:
+      if (toys.optflags & FLAG_s)
+        printf("Files %s and %s are identical\n",files[0], files[1]);
+      break;
+    case DIFFER:
+      if ((toys.optflags & FLAG_q) || TT.is_binary)
+        printf("Files %s and %s differ\n",files[0], files[1]);
+      break;
+  }
+}
+
+static void create_empty_entry(int l , int r, int j)
+{
+  struct stat st[2];
+  char *f[2], *path[2];
+  int i;
+
+  if (j > 0 && (toys.optflags & FLAG_N)) {
+    path[0] = concat_file_path(dir[0].list[0], dir[1].list[r] + TT.len[1]);
+    f[0] = "/dev/null";
+    path[1] = f[1] = dir[1].list[r];
+    stat(f[1], &st[0]);
+    st[1] = st[0];
+  }
+  else if (j < 0 && (toys.optflags & FLAG_N)) {
+    path[1] = concat_file_path(dir[1].list[0], dir[0].list[l] + TT.len[0]);
+    f[1] = "/dev/null";
+    path[0] = f[0] = dir[0].list[l];
+    stat(f[0], &st[0]);
+    st[1] = st[0];
+  }
+
+  if (!j) {
+    for (i = 0; i < 2; i++) {
+      path[i] = f[i] = dir[i].list[!i ? l: r];
+      stat(f[i], &st[i]);
+    }
+  }
+
+  if (S_ISDIR(st[0].st_mode) && S_ISDIR(st[1].st_mode))
+    printf("Common subdirectories: %s and %s\n", path[0], path[1]);
+  else if (!S_ISREG(st[0].st_mode) && !S_ISDIR(st[0].st_mode))
+    printf("File %s is not a regular file or directory "
+        "and was skipped\n", path[0]);
+  else if (!S_ISREG(st[1].st_mode) && !S_ISDIR(st[1].st_mode))
+    printf("File %s is not a regular file or directory "
+        "and was skipped\n", path[1]);
+  else if (S_ISDIR(st[0].st_mode) != S_ISDIR(st[1].st_mode)) {
+    if (S_ISDIR(st[0].st_mode))
+      printf("File %s is a %s while file %s is a"
+          " %s\n", path[0], "directory", path[1], "regular file");
+    else
+      printf("File %s is a %s while file %s is a"
+          " %s\n", path[0], "regular file", path[1], "directory");
+  } else {
+    do_diff(f);
+    show_status(path);
+    if (file[0].fp) fclose(file[0].fp);
+    if (file[1].fp) fclose(file[1].fp);
+  }
+
+  if ((toys.optflags & FLAG_N) && j) {
+    if (j > 0) free(path[0]);
+    else free(path[1]);
+  }
+}
+
+static void diff_dir(int *start)
+{
+  int l, r, j = 0;
+
+  l = start[0]; //left side file start
+  r = start[1]; //right side file start
+  while (l < dir[0].nr_elm && r < dir[1].nr_elm) {
+    if ((j = strcmp ((dir[0].list[l] + TT.len[0]),
+            (dir[1].list[r] + TT.len[1]))) && !(toys.optflags & FLAG_N)) {
+      if (j > 0) {
+        printf ("Only in %s: %s\n", dir[1].list[0], dir[1].list[r] + TT.len[1]);
+        free(dir[1].list[r]);
+        r++;
+      } else {
+        printf ("Only in %s: %s\n", dir[0].list[0], dir[0].list[l] + TT.len[0]);
+        free(dir[0].list[l]);
+        l++;
+      }
+      TT.status = DIFFER;
+    } else {
+      create_empty_entry(l, r, j); //create non empty dirs/files if -N.
+      if (j > 0) {
+        free(dir[1].list[r]);
+        r++;
+      } else if (j < 0) {
+        free(dir[0].list[l]);
+        l++;
+      } else {
+        free(dir[1].list[r]);
+        free(dir[0].list[l]);
+        l++;
+        r++;
+      }
+    }
+  }
+
+  if (l == dir[0].nr_elm) {
+    while (r < dir[1].nr_elm) {
+      if (!(toys.optflags & FLAG_N)) {
+        printf ("Only in %s: %s\n", dir[1].list[0], dir[1].list[r] + TT.len[1]);
+        TT.status = DIFFER;
+      } else create_empty_entry(l, r, 1);
+      free(dir[1].list[r]);
+      r++;
+    }
+  } else if (r == dir[1].nr_elm) {
+    while (l < dir[0].nr_elm) {
+      if (!(toys.optflags & FLAG_N)) {
+        printf ("Only in %s: %s\n", dir[0].list[0], dir[0].list[l] + TT.len[0]);
+        TT.status = DIFFER;
+      } else create_empty_entry(l, r, -1);
+      free(dir[0].list[l]);
+      l++;
+    }
+  }
+  free(dir[0].list[0]); //we are done, free root nodes too
+  free(dir[1].list[0]);
+}
+
+void diff_main(void)
+{
+  struct stat st[2];
+  int j = 0, k = 1, start[2] = {1, 1};
+  char *files[2];
+
+  for (j = 0; j < 2; j++) {
+    files[j] = toys.optargs[j];
+    if (IS_STDIN(files[j])) {
+      if (fstat(0, &st[j]) == -1)
+        perror_exit("can fstat %s", files[j]);
+    } else {
+      if (stat(files[j], &st[j]) == -1)
+        perror_exit("can't stat %s", files[j]);
+    }
+  }
+
+  if (IS_STDIN(files[0]) && IS_STDIN(files[1])) { //compat :(
+    show_status(files);  //check ASAP
+    return;
+  }
+
+  if ((IS_STDIN(files[0]) || IS_STDIN(files[1]))
+      && (S_ISDIR(st[0].st_mode) || S_ISDIR(st[1].st_mode)))
+    error_exit("can't compare stdin to directory");
+
+  if ((st[0].st_ino == st[1].st_ino) //physicaly same device
+      &&(st[0].st_dev == st[1].st_dev)) {
+    show_status(files);
+    return ;
+  }
+
+  if (S_ISDIR(st[0].st_mode) && S_ISDIR(st[1].st_mode)) {
+    for (j = 0; j < 2; j++) {
+      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);
+
+      TT.len[j] = strlen(dir[j].list[0]); //calc root node len
+      TT.len[j] += (dir[j].list[0][TT.len[j] -1] != '/');
+
+      if (toys.optflags & FLAG_S) {
+        while (k < TT.size && strcmp(dir[j].list[k] +
+              TT.len[j], TT.start) < 0) {
+          start[j] += 1;
+          k++;
+        }
+      }
+      TT.dir_num++;
+      TT.size = 0;
+      k = 1;
+    }
+    diff_dir(start);
+    free(dir[0].list); //free array
+    free(dir[1].list);
+  } else {
+    if (S_ISDIR(st[0].st_mode) || S_ISDIR(st[1].st_mode)) {
+      int d = S_ISDIR(st[0].st_mode);
+      char *slash = strrchr(files[d], '/');
+
+      files[1 - d] = concat_file_path(files[1 - d], slash ? slash + 1 : files[d]);
+      if ((stat(files[1 - d], &st[1 - d])) == -1)
+        perror_exit("%s", files[1 - d]);
+    }
+    do_diff(files);
+    show_status(files);
+    if (file[0].fp) fclose(file[0].fp);
+    if (file[1].fp) fclose(file[1].fp);
+  }
+  toys.exitval = TT.status; //exit status will be the status
+}
diff --git a/toybox/toys/pending/dumpleases.c b/toybox/toys/pending/dumpleases.c
new file mode 100644
index 0000000..ef17aab
--- /dev/null
+++ b/toybox/toys/pending/dumpleases.c
@@ -0,0 +1,77 @@
+/* dumpleases.c - Dump the leases granted by udhcpd.
+ *
+ * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+
+USE_DUMPLEASES(NEWTOY(dumpleases, ">0arf:[!ar]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config DUMPLEASES
+  bool "dumpleases"
+  default n
+  help
+    usage: dumpleases [-r|-a] [-f LEASEFILE]
+
+    Display DHCP leases granted by udhcpd
+    -f FILE,  Lease file
+    -r        Show remaining time
+    -a        Show expiration time
+*/
+
+#define FOR_dumpleases
+#include "toys.h"
+
+GLOBALS(
+    char *file;
+)
+
+//lease structure
+struct lease { 
+  uint32_t expires;
+  uint32_t lease_nip;
+  uint8_t lease_mac[6];
+  char hostname[20];
+  uint8_t pad[2]; //Padding
+};
+
+void dumpleases_main(void)
+{
+  struct in_addr addr;
+  struct lease lease_struct;
+  int64_t written_time , current_time, exp;
+  int i, fd; 
+  
+  if(!(toys.optflags & FLAG_f)) TT.file = "/var/lib/misc/dhcpd.leases"; //DEF_LEASE_FILE
+  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);
+  written_time = SWAP_BE64(written_time);
+  if(current_time < written_time) written_time = current_time;
+
+  while(sizeof(lease_struct) == 
+      (readall(fd, &lease_struct, sizeof(lease_struct)))) {
+    for (i = 0; i < 6; i++) printf(":%02x"+ !i, lease_struct.lease_mac[i]);
+    
+    addr.s_addr = lease_struct.lease_nip;
+    lease_struct.hostname[19] = '\0';
+    xprintf(" %-16s%-20s", inet_ntoa(addr), lease_struct.hostname );
+    exp = ntohl(lease_struct.expires) + written_time;
+    if (exp <= current_time) {
+      xputs("expired");
+      continue;
+    }
+    if (!(toys.optflags & FLAG_a)) { 
+      unsigned dt, hr, m;
+      unsigned expires = exp - current_time;
+      dt = expires / (24*60*60); expires %= (24*60*60);
+      hr = expires / (60*60); expires %= (60*60);
+      m = expires / 60; expires %= 60;
+      if (dt) xprintf("%u days ", dt);
+      xprintf("%02u:%02u:%02u\n", hr, m, (unsigned)expires);
+    } else {
+      fputs(ctime((const time_t*)&exp), stdout);
+    }
+  }
+  xclose(fd);
+}
diff --git a/toybox/toys/pending/expr.c b/toybox/toys/pending/expr.c
new file mode 100644
index 0000000..743a953
--- /dev/null
+++ b/toybox/toys/pending/expr.c
@@ -0,0 +1,260 @@
+/* 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))
+
+config EXPR
+  bool "expr"
+  default n
+  help
+    usage: expr ARG1 OPERATOR ARG2...
+
+    Evaluate expression and print result. For example, "expr 1 + 2".
+
+    The supported operators are (grouped from highest to lowest priority):
+
+      ( )    :    * / %    + -    != <= < >= > =    &    |
+
+    Each constant and operator must be a separate command line argument.
+    All operators are infix, meaning they expect a constant (or expression
+    that resolves to a constant) on each side of the operator. Operators of
+    the same priority (within each group above) are evaluated left to right.
+    Parentheses may be used (as separate arguments) to elevate the priority
+    of expressions.
+
+    Calling expr from a command shell requires a lot of \( or '*' escaping
+    to avoid interpreting shell control characters.
+
+    The & and | operators are logical (not bitwise) and may operate on
+    strings (a blank string is "false"). Comparison operators may also
+    operate on strings (alphabetical sort).
+
+    Constants may be strings or integers. Comparison, logical, and regex
+    operators may operate on strings (a blank string is "false"), other
+    operators require integers.
+*/
+
+// TODO: int overflow checking
+
+#define FOR_expr
+#include "toys.h"
+
+GLOBALS(
+  char **tok; // current token, not on the stack since recursive calls mutate it
+
+  char *refree;
+)
+
+// Scalar value.  If s != NULL, it's a string, otherwise it's an int.
+struct value {
+  char *s;
+  long long i;
+};
+
+// Get the value as a string.
+char *get_str(struct value *v)
+{
+  if (v->s) return v->s;
+  else return xmprintf("%lld", v->i);
+}
+
+// Get the value as an integer and return 1, or return 0 on error.
+int get_int(struct value *v, long long *ret)
+{
+  if (v->s) {
+    char *endp;
+
+    *ret = strtoll(v->s, &endp, 10);
+
+    if (*endp) return 0; // If endp points to NUL, all chars were converted
+  } else *ret = v->i;
+
+  return 1;
+}
+
+// Preserve the invariant that v.s is NULL when the value is an integer.
+void assign_int(struct value *v, long long i)
+{
+  v->i = i;
+  v->s = NULL;
+}
+
+// Check if v is 0 or the empty string.
+static int is_false(struct value *v)
+{
+  return get_int(v, &v->i) && !v->i;
+}
+
+// 'ret' is filled with a string capture or int match position.
+static void re(char *target, char *pattern, struct value *ret)
+{
+  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);
+}
+
+// 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 };
+
+enum { OR = 1, AND, EQ, NE, GT, GTE, LT, LTE, ADD, SUB, MUL, DIVI, MOD, RE };
+
+// 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
+};
+
+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;
+
+  switch (o->sig) {
+
+  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;
+  }
+}
+
+// Evalute a compound expression using recursive "Precedence Climbing"
+// algorithm, setting 'ret'.
+static void eval_expr(struct value *ret, int min_prec)
+{
+  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++;
+
+    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 ret = {0};
+
+  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);
+
+  toys.exitval = is_false(&ret);
+
+  if (TT.refree) free(TT.refree);
+}
diff --git a/toybox/toys/pending/fdisk.c b/toybox/toys/pending/fdisk.c
new file mode 100644
index 0000000..d000c05
--- /dev/null
+++ b/toybox/toys/pending/fdisk.c
@@ -0,0 +1,1557 @@
+/* fdisk.c -  fdisk program to modify partitions on disk.
+ *
+ * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_FDISK(NEWTOY(fdisk, "C#<0H#<0S#<0b#<512ul", TOYFLAG_SBIN))
+
+config FDISK
+  bool "fdisk"
+  default n
+  help
+    usage: fdisk [-lu] [-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SECTSZ] DISK
+
+    Change partition table
+
+    -u            Start and End are in sectors (instead of cylinders)
+    -l            Show partition table for each DISK, then exit
+    -b size       sector size (512, 1024, 2048 or 4096)
+    -C CYLINDERS  Set number of cylinders/heads/sectors
+    -H HEADS
+    -S SECTORS
+*/
+
+#define FOR_fdisk
+#include "toys.h"
+#include <linux/hdreg.h>
+
+GLOBALS(
+  long sect_sz;
+  long sectors;
+  long heads;
+  long cylinders;
+)
+
+#define EXTENDED        0x05                                                                      
+#define WIN98_EXTENDED  0x0f
+#define LINUX_NATIVE    0x83
+#define LINUX_EXTENDED  0x85
+
+#define SECTOR_SIZE 512
+#define ONE_K       1024
+#define PARTITION_MAX  60  //partition max is modifiable
+#define IS_EXTENDED(i) ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
+#define sector(s) ((s) & 0x3f)
+#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
+
+typedef off_t sector_t;
+
+struct partition {
+  unsigned char boot_ind, head, sector, cyl, sys_ind, end_head,
+                end_sector, end_cyl, start4[4], size4[4];
+};
+
+struct part_entry {
+  struct partition *part;
+  char *sec_buffer;
+  sector_t  start_offset;
+  int modified;
+};
+
+struct part_types {
+  int id;
+  char type[24];
+} sys_types[] = {
+  {0x00, "Empty"}, {0x01, "FAT12"}, {0x04, "FAT16 <32M"}, {0x05, "Extended"},
+  {0x06, "FAT16"}, {0x07, "HPFS/NTFS"}, {0x0a, "OS/2 Boot Manager"},
+  {0x0b, "Win95 FAT32"}, {0x0c, "Win95 FAT32 (LBA)"}, {0x0e, "Win95 FAT16 (LBA)"},
+  {0x0f, "Win95 Ext'd (LBA)"}, {0x11, "Hidden FAT12"}, {0x12, "Compaq diagnostics"},
+  {0x14, "Hidden FAT16 <32M"}, {0x16, "Hidden FAT16"}, {0x17, "Hidden HPFS/NTFS"},
+  {0x1b, "Hidden Win95 FAT32"}, {0x1c, "Hidden W95 FAT32 (LBA)"}, {0x1e, "Hidden W95 FAT16 (LBA)"},
+  {0x3c, "Part.Magic recovery"}, {0x41, "PPC PReP Boot"}, {0x42, "SFS"},
+  {0x63, "GNU HURD or SysV"}, {0x80, "Old Minix"}, {0x81, "Minix / old Linux"},
+  {0x82, "Linux swap"}, {0x83, "Linux"}, {0x84, "OS/2 hidden C: drive"},
+  {0x85, "Linux extended"}, {0x86, "NTFS volume set"}, {0x87, "NTFS volume set"},
+  {0x8e, "Linux LVM"}, {0x9f, "BSD/OS"}, {0xa0, "Thinkpad hibernation"},
+  {0xa5, "FreeBSD"}, {0xa6, "OpenBSD"}, {0xa8, "Darwin UFS"}, {0xa9, "NetBSD"},
+  {0xab, "Darwin boot"}, {0xb7, "BSDI fs"}, {0xb8, "BSDI swap"},
+  {0xbe, "Solaris boot"}, {0xeb, "BeOS fs"}, {0xee, "EFI GPT"},
+  {0xef, "EFI (FAT-12/16/32)"}, {0xf0, "Linux/PA-RISC boot"},
+  {0xf2, "DOS secondary"}, {0xfd, "Linux raid autodetect"},
+};
+
+static int num_parts, disp_unit_cyl, dos_flag, dev_fd = 3;
+static long g_cylinders, g_heads, g_sectors, g_sect_size;
+static sector_t total_number_sectors, extended_offset;
+static char MBRbuf[2048], *disk_device;
+struct part_entry partitions[PARTITION_MAX];
+
+static struct partition* part_offset(char *secbuf, int i)
+{
+  return (struct partition*)(secbuf + 0x1be + i*(sizeof(struct partition)));
+}
+
+static void set_levalue(unsigned char *cp, sector_t value )
+{
+  uint32_t val = SWAP_LE32(value);
+  memcpy(cp, (void*)&val, 4);
+}
+
+static void set_hsc(struct partition *p, sector_t start, sector_t end)
+{
+  if (dos_flag && (start / (g_sectors * g_heads) > 1023))
+    start = g_heads * g_sectors * ONE_K - 1;
+  p->sector = (start % g_sectors) + 1;
+  start /= g_sectors;
+  p->head = start % g_heads;
+  start /= g_heads;
+  p->cyl = start & 0xFF;
+  p->sector |= (start >> 2) & 0xc0;
+
+  if (dos_flag && (end / (g_sectors * g_heads) > 1023))
+    end = g_heads * g_sectors * ONE_K - 1;
+  p->end_sector = (end % g_sectors) + 1;
+  end /= g_sectors;
+  p->end_head = end % g_heads;
+  end /= g_heads;
+  p->end_cyl = end & 0xFF;
+  p->end_sector |= (end >> 2) & 0xc0;
+}
+
+static int chs_warn(void)
+{
+  if (g_heads && g_sectors && g_cylinders)
+    return 0;
+
+  printf("Unknown value(s) for:");
+  if (!g_heads) printf(" heads");
+  if (!g_sectors) printf(" sectors");
+  if (!g_cylinders) printf(" cylinders");
+  printf(". can set in the expert menu.\n");
+  return 1;
+}
+
+static void list_types(void)
+{
+  int i, adjust = 0, size = ARRAY_LEN(sys_types);
+ 
+  if(size % 2) adjust = 1;
+  for (i = 0; i < (size - adjust); i+=2)
+    xprintf("%2x %-22s\t\t%2x %-22.22s\n", sys_types[i].id, sys_types[i].type,
+        sys_types[i+1].id, sys_types[i+1].type);
+  if (adjust) xprintf("%2x %-22s\n",sys_types[size-1].id, sys_types[size-1].type);
+  xputc('\n');
+}
+
+static void read_sec_sz()
+{
+  int arg;       
+  if (ioctl(dev_fd, BLKSSZGET, &arg) == 0) g_sect_size = arg;
+  if (toys.optflags & FLAG_b) {
+    if (TT.sect_sz !=  512 && TT.sect_sz != 1024 && TT.sect_sz != 2048 &&
+        TT.sect_sz != 4096)
+    {
+      help_exit("bad sector size");
+    }
+    g_sect_size = TT.sect_sz;
+  }
+}
+
+static sector_t read_size()
+{
+  uint64_t sec64 = 0;
+  unsigned long sectors = 0;
+  if (ioctl(dev_fd, BLKGETSIZE64, &sec64) == 0) {
+    sec64 = sec64 >> 9; //convert to 512 block size.
+    if (sec64 != (uint32_t) sec64) {
+      perror_msg("device has more than 2^32 sectors, can't use all of them");
+      sec64 = (uint32_t) - 1L;
+    }
+    return sec64;
+  }
+  if (ioctl(dev_fd, BLKGETSIZE, &sectors) == 0)
+    if (sizeof(long) > sizeof(sector_t) && sectors != (sector_t)sectors)
+      sectors = (uint32_t) - 1L;
+  return sectors;
+}
+
+static int validate_part_buff(char *buffer)
+{
+  if ((buffer[510] != 0x55) || (buffer[511] != 0xAA)) return 0;
+  return 1;
+}
+
+static int is_partition_clear(struct partition* p)
+{
+  int i = 0;
+  unsigned char res = 0;
+  const char *ptr = (const char*)p;
+
+  for (i = 0; i < sizeof(struct partition); i++) res |= (unsigned char)ptr[i];
+  return (res == 0x00);
+}
+
+static uint32_t swap_le32toh(unsigned char *cp)
+{
+  uint32_t val;
+  memcpy((void*)&val, cp, 4);
+  return le32toh(val);
+}
+
+static int check_order(void)    
+{                              
+  sector_t first[num_parts], last_seen_val = 0;
+  int i;
+  struct part_entry *pe;       
+  struct partition *px;
+
+  for (i = 0; i < num_parts; i++) {
+    if (i == 4) last_seen_val = 0;
+    pe = &partitions[i];       
+    px = pe->part;             
+    if (px->sys_ind) {
+      first[i] = swap_le32toh(px->start4) + pe->start_offset;
+      if (last_seen_val > first[i]) return 1;
+      last_seen_val = first[i];
+    }
+  }
+  return 0;
+}
+
+static void read_geometry(struct hd_geometry *disk)
+{
+  struct hd_geometry geometry;
+
+  if (ioctl(dev_fd, HDIO_GETGEO, &geometry)) return;
+  disk->heads = geometry.heads;
+  disk->sectors = geometry.sectors;
+}
+
+/* Read the extended boot record for the 
+ * logical partion details.
+ */
+static void read_ebr(int idx)
+{
+  char *sec_buf = NULL;
+  sector_t offset = 0, local_start_off = 0;
+  struct partition *p, *q;
+
+  q = p = partitions[idx].part;
+  local_start_off = swap_le32toh(p->start4);
+
+  if (!extended_offset) extended_offset = local_start_off;
+  do {
+    if (num_parts >= 60) {
+      xprintf("Warning: deleting partitions after 60\n");
+      memset(q, 0, sizeof(struct partition)); //clear_partition
+      partitions[num_parts-1].modified = 1;
+      break;
+    }
+
+    sec_buf = xzalloc(g_sect_size);
+    partitions[num_parts].part = part_offset(sec_buf, 0);
+    partitions[num_parts].sec_buffer = sec_buf;
+    offset = swap_le32toh(q->start4);
+
+    if (num_parts > 4) offset += local_start_off;
+    partitions[num_parts].start_offset = offset;
+    xlseek(dev_fd, (off_t)(offset * g_sect_size), SEEK_SET);
+
+    if (g_sect_size != readall(dev_fd, sec_buf, g_sect_size)) {
+      close(dev_fd);
+      error_exit("Couldn't read sector zero\n");
+    }
+    num_parts++; //extended partions present.
+    q = part_offset(sec_buf, 1);
+  } while (!is_partition_clear(q) && IS_EXTENDED(q->sys_ind));
+}
+
+static void physical_HS(int* h, int *s)
+{  
+  struct partition *p;
+  int i, end_h, end_s, e_hh = 0, e_ss = 0, ini = 1, dirty = 0;
+  const unsigned char *bufp = (const unsigned char *)MBRbuf;
+
+  if (!(validate_part_buff((char*)bufp))) return;
+
+  for (i = 0; i < 4; i++) {
+    p = part_offset((char*)bufp, i);
+    if (p->sys_ind) {
+      end_h = p->end_head + 1;
+      end_s = (p->end_sector & 077);
+      if (ini) {
+        e_hh = end_h;
+        e_ss = end_s;
+        ini = 0;
+      } else if (e_hh !=end_h || e_ss != end_s)
+        dirty = 1;
+    }
+  }
+  if (!dirty && !ini) {
+    *h = e_hh;
+    *s = e_ss;
+  }
+}
+
+//Reset the primary partition table
+static void reset_boot(int change)
+{
+  int i;
+  for(i = 0; i < 4; i++) {
+    struct part_entry *pe = &partitions[i];
+    pe->part = part_offset(MBRbuf, i);
+    pe->start_offset = 0;
+    pe->sec_buffer = MBRbuf;
+    pe->modified = change;
+  }
+}
+
+static inline void write_table_flag(char *buf)
+{
+  buf[510] = 0x55;
+  buf[511] = 0xaa;
+}
+
+/* free the buffers used for holding details of
+ * extended logical partions
+*/
+static void free_bufs(void)
+{
+  int i = 4;
+  for (; i < num_parts; i++) free(partitions[i].sec_buffer);
+}
+
+static void create_empty_doslabel(void)
+{
+  xprintf("Building a new DOS Disklabel. The changes will\n"
+      "remain in memory only, until you write it.\n");
+
+  num_parts = 4;
+  extended_offset = 0;
+  memset(&MBRbuf[510 - 4*16], 0, 4*16);
+  write_table_flag(MBRbuf);
+  partitions[0].modified = 1;
+  reset_boot(1);
+}
+
+/* Read the Master Boot sector of the device for the 
+ * partition table entries/details.
+ * If any extended partition is found then read the EBR
+ * for logical partition details
+ */
+static int read_mbr(char *device, int validate)
+{
+  int fd, sector_fac, i, h = 0, s = 0;
+  struct hd_geometry disk;
+  fd = open(device, O_RDWR);
+  if(fd < 0) {
+    perror_msg("can't open '%s'",device);
+    return 1;
+  }
+
+  disk_device = strdup(device);
+  if(fd != dev_fd) {
+    if(dup2(fd, dev_fd) != dev_fd) perror_exit("Can't dup2");
+    close(fd);
+  }
+
+  //read partition table - MBR
+  if (SECTOR_SIZE != readall(dev_fd, MBRbuf, SECTOR_SIZE)) {
+    close(dev_fd);
+    perror_exit("Couldn't read sector zero\n");
+  }
+  if (validate && !validate_part_buff(MBRbuf)) {
+    xprintf("Device contains neither a valid DOS "
+        "partition table, nor Sun, SGI, OSF or GPT "
+        "disklabel\n");
+    create_empty_doslabel();
+  }
+
+  disk.heads = disk.sectors = 0;
+  read_geometry(&disk); //CHS values
+  total_number_sectors = read_size(); //Device size
+  read_sec_sz();
+  sector_fac = g_sect_size/SECTOR_SIZE; //512 is hardware sector size.
+  physical_HS(&h, &s); //physical dimensions may be diferent from HDIO_GETGEO
+  g_sectors = (toys.optflags & FLAG_S && TT.sectors)? TT.sectors :  s? s : disk.sectors?disk.sectors : 63;
+  g_heads = (toys.optflags & FLAG_H && TT.heads)? TT.heads : h? h : disk.heads? disk.heads : 255;
+  g_cylinders = total_number_sectors/(g_heads * g_sectors * sector_fac);
+
+  if (!g_cylinders) g_cylinders = toys.optflags & FLAG_C? TT.cylinders : 0;
+  if ((g_cylinders > ONE_K) && !(toys.optflags & (FLAG_l | FLAG_S)))
+    xprintf("\nThe number of cylinders for this disk is set to %lu.\n"
+        "There is nothing wrong with that, but this is larger than 1024,\n"
+        "and could in certain setups cause problems.\n", g_cylinders);
+  for (i = 0; i < num_parts; i++) {
+    if (IS_EXTENDED(partitions[i].part->sys_ind)) {
+      read_ebr(i);
+      break;
+    }
+  }
+  chs_warn();
+
+  return 0;
+}
+
+static char* get_type(int sys_ind)
+{
+  int i, size = ARRAY_LEN(sys_types);
+  for (i = 0; i < size; i++)
+    if (sys_ind == sys_types[i].id)
+      return sys_types[i].type;
+  return "Unknown";
+}
+
+static void consistency_check(const struct partition *p, int partition)
+{        
+  unsigned physbc, physbh, physbs, physec, physeh, physes;
+  unsigned lbc, lbh, lbs, lec, leh, les;
+  sector_t start, end;
+
+  if (!g_heads || !g_sectors || (partition >= 4)) return;
+  // physical beginning c, h, s 
+  physbc = cylinder(p->sector,p->cyl);
+  physbh = p->head;
+  physbs = sector(p->sector);
+  // physical ending c, h, s 
+  physec = cylinder(p->end_sector, p->end_cyl);
+  physeh = p->end_head;
+  physes = sector(p->end_sector);
+  // logical begin and end CHS values 
+  start = swap_le32toh((unsigned char*)(p->start4));
+  end = start + swap_le32toh((unsigned char*)(p->size4)) -1;
+
+  lbc = start/(g_sectors * g_heads);
+  lbh = (start/g_sectors) % g_heads;
+  lbs = (start % g_sectors) + 1;
+
+  lec = end/(g_sectors * g_heads);
+  leh = (end/g_sectors) % g_heads;
+  les = (end % g_sectors) + 1;
+
+  //Logical and Physical diff 
+  if (g_cylinders <= ONE_K && (physbc != lbc || physbh != lbh || physbs != lbs)) {
+    xprintf("Partition %u has different physical/logical beginings (Non-Linux?): \n", partition+1);
+    xprintf("phys = (%u %u %u) ",physbc, physbh, physbs);
+    xprintf("logical = (%u %u %u)\n", lbc, lbh, lbs);
+  }
+  if (g_cylinders <= ONE_K && (physec != lec || physeh != leh || physes != les)) {
+    xprintf("Partition %u has different physical/logical endings: \n", partition+1);
+    xprintf("phys = (%u %u %u) ",physec, physeh, physes);
+    xprintf("logical = (%u %u %u)\n", lec, leh, les);
+  }
+  // Ending on cylinder boundary? 
+  if (physeh != (g_heads - 1) || physes != g_sectors)
+    xprintf("Partition %u does not end on cylinder boundary\n", partition + 1);
+}
+
+// List the partition details
+static void list_partitions(int validate)
+{
+  struct partition *p;
+  uint32_t start_cyl, end_cyl, start_sec, end_sec, blocks, secs;
+  char boot, lastchar = '\0', *dev = disk_device;
+  int i = 0, len = strlen(disk_device), odds = 0;
+
+  if (validate && !validate_part_buff(MBRbuf)) {
+    close(dev_fd);
+    toys.exitval = 1;
+    xprintf("Device %s: doesn't contain a valid partition table\n", disk_device);
+    return;
+  }
+  if (isdigit(dev[len - 1])) lastchar = 'p';
+
+  xprintf("%*s Boot      Start         End      Blocks  Id System\n", len+1, "Device");
+  for (i = 0; i < num_parts; i++) {
+    p = partitions[i].part;
+    if (is_partition_clear(p)) continue;
+
+    boot = ((p->boot_ind == 0x80)?'*':(!p->boot_ind)?' ':'?');
+    start_sec = swap_le32toh(p->start4) + partitions[i].start_offset;
+    secs = swap_le32toh(p->size4);
+
+    if ((start_sec + secs) == 0) end_sec = 0;
+    else end_sec = start_sec + secs -1;
+    start_cyl = start_sec/(g_heads * g_sectors) + 1;
+    end_cyl = end_sec/(g_heads * g_sectors) + 1;
+    blocks = secs;
+    if (g_sect_size < ONE_K) {
+      blocks /= (ONE_K/g_sect_size);
+      odds = secs %(ONE_K/g_sect_size);
+    } else if (g_sect_size > ONE_K) blocks *= (g_sect_size/ONE_K);
+
+    if (lastchar) xprintf("%s%c%d",dev, lastchar, i+1);
+    else xprintf("%s%d",dev, i+1);
+
+    xprintf("   %c %11u %11u %11u%c %2x %s\n",
+        boot,
+        disp_unit_cyl == 0? start_sec: start_cyl,
+        disp_unit_cyl == 0? end_sec: end_cyl,
+        blocks,odds?'+':' ', p->sys_ind, get_type(p->sys_ind));
+
+    consistency_check(p, i);
+  }
+  if (check_order()) xprintf("\nPartition table entries are not in disk order");
+}
+
+//Print device details
+static void print_mbr(int validate)
+{
+  unsigned long long bytes = ((unsigned long long)total_number_sectors << 9);
+  long mbytes = bytes/1000000;
+
+  if (mbytes < 10000) xprintf("Disk %s: %lu MB, %llu bytes\n", disk_device, mbytes, bytes);
+  else xprintf("Disk %s: %lu.%lu GB, %llu bytes\n", disk_device, mbytes/1000, (mbytes/100)%10, bytes);
+  xprintf("%ld heads, %ld sectors/track, %ld cylinders", g_heads, g_sectors, g_cylinders);
+  if (!disp_unit_cyl) {
+    xprintf(", total %lld sectors\n", total_number_sectors/(g_sect_size/SECTOR_SIZE));
+    xprintf("Units = sectors of 1 * %ld = %ld bytes\n",g_sect_size, g_sect_size);
+  } else xprintf("\nUnits = cylinders of %ld * %ld = %ld bytes\n\n",
+      g_heads * g_sectors, g_sect_size, g_heads * g_sectors * g_sect_size);
+  list_partitions(validate);
+  xputc('\n');
+}
+
+static void init_members(void)
+{
+  int i = 0;
+  num_parts = 4; //max of primaries in a part table
+  disp_unit_cyl = dos_flag = 1;
+  extended_offset = 0;
+  g_sect_size = SECTOR_SIZE;
+  for (i = 0; i < num_parts; i++) {
+    partitions[i].part = part_offset(MBRbuf, i);
+    partitions[i].sec_buffer = MBRbuf;
+    partitions[i].modified = 0;
+    partitions[i].start_offset = 0;
+  }
+}
+
+static int read_input(char *mesg, char *outp)
+{
+  char *p;
+  int size = 0;
+  do {
+    xprintf("%s", mesg);
+    p = fgets(toybuf, 80, stdin);
+  
+    if (!p || !(size = strlen(p))) exit(0);
+    if (p[size-1] == '\n') p[--size] = '\0';
+  } while (!size);
+
+  while (*p != '\0' && *p <= ' ') p++;
+  if (outp) memcpy(outp, p, strlen(p) + 1); //1 for nul
+  return *p;
+}
+
+static int read_hex(char *mesg)
+{
+  int val;
+  char input[80], *endp;
+  while (1) {
+    read_input(mesg, input);
+    if ((*input | 0x20) == 'l') {
+      list_types();
+      memset(input, 0, 80);
+      continue;
+    }
+    val = strtoul(input, &endp, 16);
+    if (endp && *endp) continue;
+    if (val <= 0xff) return val;
+  }
+}
+
+/* Delete an exiting partition,
+ * if its primary, then just clear the partition details
+ * if extended, then clear the partition details, also for logical
+ * if only logical, then move the later partitions backwards 1 step
+ */
+void delete_partition(int i)
+{
+  int sys_id, looper = 0;
+  struct partition *p, *q, *ext_p, *ext_q;
+  sector_t new_start;
+  struct part_entry *pe = &partitions[i];
+  
+  if (chs_warn()) return;
+  p = pe->part;
+  sys_id = p->sys_ind;
+  if (!sys_id) xprintf("Partition %u is empty\n", i+1);
+
+  if (i < 4 && !IS_EXTENDED(sys_id)) {
+    memset(p, 0, sizeof(struct partition)); //clear_partition
+    pe->modified = 1;
+  } else if (i < 4 && IS_EXTENDED(sys_id)) {
+    memset(p, 0, sizeof(struct partition)); //clear_partition
+    pe->modified = 1;
+    for (looper = 4; looper < num_parts; looper++) {
+      pe = &partitions[looper];
+      p = pe->part; 
+      if (is_partition_clear(p)) break;
+      else {
+        memset(p, 0, sizeof(struct partition)); //clear_partition
+        pe->modified = 1;
+        free(pe->sec_buffer);
+      }
+    }
+    extended_offset = 0;
+    num_parts = 4;
+  } else {
+    //only logical is delete, need to move the rest of them backwards
+    if (i == 4) { //move partiton# 6 to 5.
+      partitions[i].modified = 1;
+      if (num_parts > i+1) {
+        q = partitions[i + 1].part;
+        *p = *q; //copy the part table
+        ext_p = part_offset(partitions[i].sec_buffer, 1);
+        ext_q = part_offset(partitions[i + 1].sec_buffer, 1);
+        *ext_p = *ext_q; //copy the extended info pointer
+        // change the start of the 4th partiton. 
+        new_start = partitions[i + 1].start_offset + swap_le32toh(q->start4) - extended_offset;
+        new_start = SWAP_LE32(new_start);
+        memcpy(p->start4, (void *)&new_start, 4);
+      } else {
+        memset(partitions[i].part, 0, sizeof(struct partition));
+        return; //only logical
+      }
+    } else if (i > 4) {
+      ext_p = part_offset(partitions[i-1].sec_buffer, 1);
+      ext_q = part_offset(partitions[i].sec_buffer, 1);
+      memcpy((void*)ext_p, (void *)ext_q, sizeof(struct partition));
+      partitions[i-1].modified = 1;
+    }
+    if (i == 4) looper = i+2;
+    else if (i > 4) looper = i+1;
+    for (; looper < num_parts; looper++)
+      partitions[looper-1] = partitions[looper];
+    num_parts--;
+  }
+}
+
+static int ask_partition(int num_parts)
+{
+  int val;
+  while (1) {
+    do {
+      xprintf("Partition (%u - %u):", 1, num_parts);
+      fgets(toybuf, 80, stdin);
+    } while (!isdigit(*toybuf));
+    val = atoi(toybuf);
+    if (val > 0 && val <= num_parts) return val;
+    else xprintf("Invalid number entered\n");
+  }
+}
+
+static void toggle_active_flag(int i)
+{
+  struct partition *p = partitions[i].part;
+  if (is_partition_clear(p)) xprintf("Partition %u is empty\n", i+1);
+  
+  if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
+    xprintf("WARNING: Partition %u is an extended partition\n", i + 1);
+  p->boot_ind = p->boot_ind == 0x80?0 : 0x80;
+  partitions[i].modified = 1;
+}
+
+//Write the partition details from Buffer to Disk.
+void write_table(void)
+{
+  int i =0;
+  struct part_entry *pe;
+  sector_t offset;
+
+  for (i = 0; i < 4; i++)
+    if (partitions[i].modified) partitions[3].modified = 1;
+
+  for (i = 3; i < num_parts; i++) {
+    pe = &partitions[i];
+    write_table_flag(pe->sec_buffer);
+    offset = pe->start_offset;
+    if (pe->modified == 1) {
+      xlseek(dev_fd, offset * g_sect_size, SEEK_SET);
+      xwrite(dev_fd, pe->sec_buffer, g_sect_size);
+    }
+  }
+  xprintf("The partition table has been altered.\n");
+  xprintf("Calling ioctl() to re-read partition table\n");
+  sync();
+  for (i = 4; i < num_parts; i++) free(partitions[i].sec_buffer);
+  if(ioctl(dev_fd, BLKRRPART, NULL) < 0)
+    perror_exit("WARNING: rereading partition table failed, kernel still uses old table");
+
+}
+
+/* try to find a partition for deletion, if only
+ * one, then select the same, else ask from USER
+ */
+static int get_non_free_partition(int max)
+{       
+  int num = -1, i = 0;
+
+  for (i = 0; i < max; i++) {
+    if (!is_partition_clear(partitions[i].part)) {
+      if (num >= 0)
+        return ask_partition(num_parts)-1;
+      num = i;
+    }
+  }
+  (num >= 0) ? xprintf("Selected partition %d\n",num+1):
+    xprintf("No partition is defined yet!\n");
+  return num;
+}
+
+/* a try at autodetecting an empty partition table entry,
+ * if multiple options then get USER's choce.
+ */
+static int get_free_partition(int max)
+{
+  int num = -1, i = 0;
+
+  for (i = 0; i < max; i++) {
+    if (is_partition_clear(partitions[i].part)) {
+      if (num >= 0)
+        return ask_partition(4)-1;
+      num = i;
+    }
+  }
+  (num >= 0) ? xprintf("Selected partition %d\n",num+1):
+    xprintf("All primary partitions have been defined already!\n");
+  return num;
+}
+
+//taking user input for partition start/end sectors/cyinders
+static uint32_t ask_value(char *mesg, sector_t left, sector_t right, sector_t defalt)
+{ 
+  char *str = toybuf;
+  uint32_t val;
+  int use_default = 1;
+
+  while (1) {
+    use_default = 1;
+    do {
+      xprintf("%s",mesg);
+      fgets(str, 80, stdin);
+    } while (!isdigit(*str) && (*str != '\n')
+        && (*str != '-') && (*str != '+') && (!isblank(*str)));
+    while (isblank(*str)) str++; //remove leading white spaces
+    if (*str == '+' || *str == '-') {
+      int minus = (*str == '-');
+      int absolute = 0;
+
+      val = atoi(str + 1);
+      while (isdigit(*++str)) use_default = 0;
+
+      switch (*str) {
+        case 'c':
+        case 'C':
+          if (!disp_unit_cyl) val *= g_heads * g_sectors;
+          break;
+        case 'K':
+          absolute = ONE_K;
+          break;
+        case 'k':
+          absolute = 1000;
+          break;
+        case 'm':
+        case 'M':
+          absolute = 1000000;
+          break;
+        case 'g':
+        case 'G':
+          absolute = 1000000000;
+          break;
+        default:
+          break;
+      }
+      if (absolute) {
+        unsigned long long bytes = (unsigned long long) val * absolute;
+        unsigned long unit = (disp_unit_cyl && (g_heads * g_sectors))? g_heads * g_sectors : 1;
+
+        unit = unit * g_sect_size;
+        bytes += unit/2; // rounding
+        bytes /= unit;
+        val = bytes;
+      }
+      if (minus)
+        val = -val;
+      val += left;
+    } else {
+      val = atoi(str);
+      while (isdigit(*str)) {
+        str++;
+        use_default = 0;
+      }
+    }
+    if(use_default) {
+      val = defalt;
+      xprintf("Using default value %lld\n", defalt);
+    }
+    if (val >= left && val <= right) return val;
+    else xprintf("Value out of range\n");
+  }
+}
+
+//validating if the start given falls in a limit or not
+static int validate(int start_index, sector_t* begin,sector_t* end, sector_t start
+    , int asked)
+{
+  int i, valid = 0;
+  for (i = start_index; i < num_parts; i++) {
+    if (start >= begin[i] && start <= end[i]) {
+      if (asked) xprintf("Sector %lld is already allocated\n",start);
+      valid = 0;
+      break;
+    } else valid = 1;
+  }
+  return valid;
+}
+
+//get the start sector/cylinder of a new partition
+static sector_t ask_start_sector(int idx, sector_t* begin, sector_t* end, int ext_idx)
+{
+  sector_t start, limit, temp = 0, start_cyl, limit_cyl, offset = 1;
+  char mesg[256];
+  int i, asked = 0, valid = 0, start_index = 0;
+
+  if (dos_flag) offset = g_sectors;
+  start = offset;
+  if (disp_unit_cyl) limit = (sector_t)g_sectors * g_heads * g_cylinders - 1;
+  else limit = total_number_sectors - 1;
+
+  if (disp_unit_cyl) //make the begin of every partition to cylnder boundary 
+    for (i = 0; i < num_parts; i++)
+      begin[i] = (begin[i]/(g_heads* g_sectors)) * (g_heads* g_sectors);
+
+  if (idx >= 4) {
+    if (!begin[ext_idx] && extended_offset) begin[ext_idx] = extended_offset;
+    start = begin[ext_idx] + offset;
+    limit = end[ext_idx];
+    start_index = 4;
+  }
+  do {
+    if (asked) valid = validate(start_index, begin, end, start, asked);
+    if (valid) break;
+
+    do {
+      for (i = start_index; i < num_parts; i++) 
+        if (start >= begin[i] && start <= end[i])
+          start = end[i] + 1 + ((idx >= 4)? offset : 0);
+    } while (!validate(start_index, begin, end, start, 0));
+
+    start_cyl = start/(g_sectors * g_heads) + 1;
+    limit_cyl = limit/(g_sectors * g_heads) + 1;
+
+    if (start > limit) break;
+    sprintf(mesg, "First %s (%lld - %lld, default %lld): ", disp_unit_cyl? "cylinder" : "sector",
+        (long long int)(disp_unit_cyl? start_cyl : start), 
+        (long long int)(disp_unit_cyl? limit_cyl : limit),
+        (long long int)(disp_unit_cyl? start_cyl : start));
+    temp = ask_value(mesg, disp_unit_cyl? start_cyl : start, 
+        disp_unit_cyl? limit_cyl : limit, disp_unit_cyl? start_cyl : start);
+    asked = 1;
+
+    if (disp_unit_cyl) {
+      // point to the cylinder start sector
+      temp = (temp-1) * g_heads * g_sectors;
+      if (temp < start) //the boundary is falling in the already used sectors.
+        temp = start;
+    }
+    start = temp;
+  } while (asked && !valid);
+  return start;
+}
+
+//get the end sector/cylinder of a new partition
+static sector_t ask_end_sector(int idx, sector_t* begin, sector_t* end, int ext_idx, sector_t start_sec)
+{
+  sector_t limit, temp = 0, start_cyl, limit_cyl, start = start_sec;
+  char mesg[256];
+  int i;
+
+  if (disp_unit_cyl) limit = (sector_t)g_sectors * g_heads * g_cylinders - 1;
+  else limit = total_number_sectors - 1;
+
+  if (disp_unit_cyl) //make the begin of every partition to cylnder boundary
+    for (i = 0; i < num_parts; i++)
+      begin[i] = (begin[i]/(g_heads* g_sectors)) * (g_heads* g_sectors);
+
+  if (idx >= 4) limit = end[ext_idx];
+
+  for (i = 0; i < num_parts; i++) {
+    struct part_entry *pe = &partitions[i];
+    if (start < pe->start_offset && limit >= pe->start_offset) limit = pe->start_offset - 1;
+    if (start < begin[i] && limit >= begin[i]) limit = begin[i] - 1;
+  }
+
+  start_cyl = start/(g_sectors * g_heads) + 1;
+  limit_cyl = limit/(g_sectors * g_heads) + 1;
+  if (limit < start) { //the boundary is falling in the already used sectors.
+    xprintf("No Free sectors available\n");
+    return 0;
+  }
+  sprintf(mesg, "Last %s or +size or +sizeM or +sizeK (%lld - %lld, default %lld): ",
+      disp_unit_cyl? "cylinder" : "sector",
+      (long long int)(disp_unit_cyl? start_cyl : start), 
+      (long long int)(disp_unit_cyl? limit_cyl : limit),
+      (long long int)(disp_unit_cyl? limit_cyl : limit));
+  temp = ask_value(mesg, disp_unit_cyl? start_cyl : start, 
+      disp_unit_cyl? limit_cyl : limit, disp_unit_cyl? limit_cyl : limit);
+
+  if (disp_unit_cyl) { // point to the cylinder start sector
+    temp = temp * g_heads * g_sectors - 1;
+    if (temp > limit) temp = limit;
+  }
+  if (temp < start) { //the boundary is falling in the already used sectors.
+    xprintf("No Free sectors available\n");
+    return 0;
+  }
+  return temp;
+}
+
+// add a new partition to the partition table
+static int add_partition(int idx, int sys_id)
+{
+  int i, ext_idx = -1;
+  sector_t start, end, begin_sec[num_parts], end_sec[num_parts];
+  struct part_entry *pe = &partitions[idx];
+  struct partition *p = pe->part;
+
+  if (p && !is_partition_clear(p)) {
+    xprintf("Partition %u is already defined, delete it to re-add\n", idx+1);
+    return 0;
+  }
+  for (i = 0; i < num_parts; i++) {
+    pe = &partitions[i];
+    p = pe->part;
+    if (is_partition_clear(p)) {
+      begin_sec[i] = 0xffffffff;
+      end_sec[i] = 0;
+    } else {
+      begin_sec[i] = swap_le32toh(p->start4) + pe->start_offset;
+      end_sec[i] = begin_sec[i] + swap_le32toh(p->size4) - 1;
+    }
+    if (IS_EXTENDED(p->sys_ind)) ext_idx = i;
+  }
+  start = ask_start_sector(idx, begin_sec, end_sec, ext_idx);
+  end = ask_end_sector(idx, begin_sec, end_sec, ext_idx, start);
+  if (!end) return 0;
+  //Populate partition table entry  - 16 bytes
+  pe = &partitions[idx];
+  p = pe->part;
+
+  if (idx > 4) {
+    if (dos_flag) pe->start_offset = start - (sector_t)g_sectors;
+    else pe->start_offset = start - 1;
+    if (pe->start_offset == extended_offset) pe->start_offset++;
+    if (!dos_flag) start++;
+  }
+ 
+  set_levalue(p->start4, start - pe->start_offset);
+  set_levalue(p->size4, end - start + 1);
+  set_hsc(p, start, end);
+  p->boot_ind = 0;
+  p->sys_ind = sys_id;
+  pe->modified = 1;
+
+  if (idx > 4) {
+    p = partitions[idx-1].part + 1; //extended pointer for logical partitions
+    set_levalue(p->start4, pe->start_offset - extended_offset);
+    set_levalue(p->size4, end - start + 1 + (dos_flag? g_sectors: 1));
+    set_hsc(p, pe->start_offset, end);
+    p->boot_ind = 0;  
+    p->sys_ind = EXTENDED;
+    partitions[idx-1].modified = 1;   
+  }
+  if (IS_EXTENDED(sys_id)) {
+    pe = &partitions[4];
+    pe->modified = 1; 
+    pe->sec_buffer = xzalloc(g_sect_size);
+    pe->part = part_offset(pe->sec_buffer, 0);
+    pe->start_offset = extended_offset = start;
+    num_parts = 5;
+  }
+  return 1;
+}
+
+static void add_logical_partition(void)
+{
+  struct part_entry *pe;
+  if (num_parts > 5 || !is_partition_clear(partitions[4].part)) {
+    pe = &partitions[num_parts];
+    pe->modified = 1;
+    pe->sec_buffer = xzalloc(g_sect_size);
+    pe->part = part_offset(pe->sec_buffer, 0);
+    pe->start_offset = 0;
+    num_parts++;
+    if (!add_partition(num_parts - 1, LINUX_NATIVE)) {
+      num_parts--;
+      free(pe->sec_buffer);
+    }
+  } 
+  else add_partition(num_parts -1, LINUX_NATIVE);
+}
+
+/* Add a new partiton to the partition table.
+ * MAX partitions limit is taken to be 60, can be changed
+ */
+static void add_new_partition(void)
+{
+  int choice, idx, i, free_part = 0;
+  char *msg = NULL;
+  
+  if (chs_warn()) return;
+  for (i = 0; i < 4; i++) if(is_partition_clear(partitions[i].part)) free_part++;
+
+  if (!free_part && num_parts >= 60) {
+    xprintf("The maximum number of partitions has been created\n");
+    return;       
+  }
+  if (!free_part) {
+    if (extended_offset) add_logical_partition();
+    else xprintf("You must delete some partition and add "
+          "an extended partition first\n");
+    return;
+  }
+
+  msg = xmprintf("  %s\n  p  primary partition(1-4)\n",
+          extended_offset? "l  logical (5 or over)" : "e  extended");
+
+  choice = 0x20 | read_input(msg, NULL);
+  free(msg);
+  if (choice == 'p') {
+    idx = get_free_partition(4);
+    if (idx >= 0) add_partition(idx, LINUX_NATIVE);
+    return;
+  }
+  if (choice =='l' && extended_offset) {
+    add_logical_partition();
+    return;
+  }
+  if (choice == 'e' && !extended_offset) {
+    idx = get_free_partition(4);   
+    if (idx >= 0) add_partition(idx, EXTENDED);
+    return;
+  }
+}
+
+static void change_systype(void )
+{
+  int i, sys_id;
+  struct partition *p;
+  struct part_entry *pe;
+
+  i = ask_partition(num_parts);
+  pe = &partitions[i-1];
+  p = pe->part;
+  if (is_partition_clear(p)) {
+    xprintf("Partition %d doesn't exist yet!\n", i);
+    return;
+  }
+  sys_id = read_hex("Hex code (L to list codes): ");
+  if ((IS_EXTENDED(p->sys_ind) && !IS_EXTENDED(sys_id)) ||
+      (!IS_EXTENDED(p->sys_ind) && IS_EXTENDED(sys_id))) {
+    xprintf("you can't change a  partition to an extended or vice-versa\n");
+    return;
+  }
+
+  xprintf("Changed system type of partition %u to %0x (%s)\n",i, sys_id, get_type(sys_id));
+  p->sys_ind = sys_id;
+  pe->modified = 1;
+}
+
+static void check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
+{   
+  sector_t total, real_s, real_c;
+
+  real_s = sector(s) - 1;
+  real_c = cylinder(s, c);
+  total = (real_c * g_sectors + real_s) * g_heads + h;
+  if (!total) xprintf("Partition %u contains sector 0\n", n);
+  if (h >= g_heads)
+    xprintf("Partition %u: head %u greater than maximum %lu\n", n, h + 1, g_heads);
+  if (real_s >= g_sectors)
+    xprintf("Partition %u: sector %u greater than maximum %lu\n", n, s, g_sectors);
+  if (real_c >= g_cylinders)
+    xprintf("Partition %u: cylinder %lld greater than maximum %lu\n", n, real_c + 1, g_cylinders);
+  if (g_cylinders <= ONE_K && start != total)
+    xprintf("Partition %u: previous sectors %lld disagrees with total %lld\n", n, start, total);
+}
+
+static void verify_table(void)
+{
+  int i, j, ext_idx = -1;
+  sector_t begin_sec[num_parts], end_sec[num_parts], total = 1;
+  struct part_entry *pe;
+  struct partition *p;
+
+  for (i = 0; i < num_parts; i++) {
+    pe = &partitions[i];
+    p = pe->part;
+    if (is_partition_clear(p) || IS_EXTENDED(p->sys_ind)) {
+      begin_sec[i] = 0xffffffff;
+      end_sec[i] = 0;
+    } else {
+      begin_sec[i] = swap_le32toh(p->start4) + pe->start_offset;
+      end_sec[i] = begin_sec[i] + swap_le32toh(p->size4) - 1;
+    }
+    if (IS_EXTENDED(p->sys_ind)) ext_idx = i;
+  }
+  for (i = 0; i < num_parts; i++) {
+    pe = &partitions[i];
+    p = pe->part;
+    if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
+      consistency_check(p, i);
+      if ((swap_le32toh(p->start4) + pe->start_offset) < begin_sec[i])
+        xprintf("Warning: bad start-of-data in partition %u\n", i + 1);
+      check(i + 1, p->end_head, p->end_sector, p->end_cyl, end_sec[i]);
+      total += end_sec[i] + 1 - begin_sec[i];
+      for (j = 0; j < i; j++) {
+        if ((begin_sec[i] >= begin_sec[j] && begin_sec[i] <= end_sec[j])
+            || ((end_sec[i] <= end_sec[j] && end_sec[i] >= begin_sec[j]))) {
+          xprintf("Warning: partition %u overlaps partition %u\n", j + 1, i + 1);
+          total += begin_sec[i] >= begin_sec[j] ? begin_sec[i] : begin_sec[j];
+          total -= end_sec[i] <= end_sec[j] ? end_sec[i] : end_sec[j];
+        }
+      }
+    }
+  }  
+  if (extended_offset) {
+    struct part_entry *pex = &partitions[ext_idx];
+    sector_t e_last = swap_le32toh(pex->part->start4) +
+      swap_le32toh(pex->part->size4) - 1;
+
+    for (i = 4; i < num_parts; i++) {
+      total++;
+      p = partitions[i].part;
+      if (!p->sys_ind) {
+        if (i != 4 || i + 1 < num_parts)
+          xprintf("Warning: partition %u is empty\n", i + 1);
+      } else if (begin_sec[i] < extended_offset || end_sec[i] > e_last)
+        xprintf("Logical partition %u not entirely in partition %u\n", i + 1, ext_idx + 1);
+    }
+  }
+  if (total > g_heads * g_sectors * g_cylinders)
+    xprintf("Total allocated sectors %lld greater than the maximum "
+        "%lu\n", total, g_heads * g_sectors * g_cylinders);
+  else {
+    total = g_heads * g_sectors * g_cylinders - total;
+    if (total) xprintf("%lld unallocated sectors\n", total);
+  }
+}
+
+static void move_begning(int idx)
+{
+  sector_t start, num, new_start, end;
+  char mesg[256];
+  struct part_entry *pe = &partitions[idx];
+  struct partition *p = pe->part;
+
+  if (chs_warn()) return;
+  start = swap_le32toh(p->start4) + pe->start_offset;
+  num = swap_le32toh(p->size4);
+  end = start + num -1;
+
+  if (!num || IS_EXTENDED(p->sys_ind)) {
+    xprintf("Partition %u doesn't have data area\n", idx+1);
+    return;
+  }
+  sprintf(mesg, "New begining of data (0 - %lld, default %lld): ", 
+      (long long int)(end), (long long int)(start));
+  new_start = ask_value(mesg, 0, end, start);
+  if (new_start != start) {
+    set_levalue(p->start4, new_start - pe->start_offset);
+    set_levalue(p->size4, end - new_start +1);
+    if ((read_input("Recalculate C/H/S (Y/n): ", NULL) | 0x20) == 'y')
+      set_hsc(p, new_start, end);
+    pe->modified = 1;
+  }
+}
+
+static void print_raw_sectors()
+{
+  int i, j;
+  struct part_entry *pe;
+
+  xprintf("Device: %s\n", disk_device);
+  for (i = 3; i < num_parts; i++) {
+    pe = &partitions[i];
+    for (j = 0; j < g_sect_size; j++) {
+      if (!(j % 16)) xprintf("\n0x%03X: ",j);
+      xprintf("%02X ",pe->sec_buffer[j]);
+    }
+    xputc('\n');
+  }
+}
+
+static void print_partitions_list(int ext)
+{
+  int i;                                                                                    
+  struct part_entry *pe;
+  struct partition *p;
+
+  xprintf("Disk %s: %lu heads, %lu sectors, %lu cylinders\n\n", disk_device, g_heads, g_sectors, g_cylinders);
+  xprintf("Nr AF  Hd Sec  Cyl  Hd Sec  Cyl      Start       Size ID\n");
+
+  for (i = 0; i < num_parts; i++) {
+    pe = &partitions[i];
+    p = pe->part;
+    if (p) {
+      if (ext && (i >= 4)) p = pe->part + 1;
+      if(ext && i < 4 && !IS_EXTENDED(p->sys_ind)) continue;
+
+      xprintf("%2u %02x%4u%4u%5u%4u%4u%5u%11u%11u %02x\n",
+          i+1, p->boot_ind, p->head,
+          sector(p->sector), cylinder(p->sector, p->cyl),
+          p->end_head,           
+          sector(p->end_sector), cylinder(p->end_sector, p->end_cyl),
+          swap_le32toh(p->start4),
+          swap_le32toh(p->size4),
+          p->sys_ind);
+      if (p->sys_ind) consistency_check(p, i);
+    }
+  }
+}
+
+//fix the partition table order to ascending
+static void fix_order(void)
+{
+  sector_t first[num_parts], min;
+  int i, j, oj, ojj, sj, sjj;
+  struct part_entry *pe;
+  struct partition *px, *py, temp, *pj, *pjj, tmp;
+
+  for (i = 0; i < num_parts; i++) {
+    pe = &partitions[i];
+    px = pe->part;
+    if (is_partition_clear(px)) first[i] = 0xffffffff;
+    else first[i] = swap_le32toh(px->start4) + pe->start_offset;
+  }
+  
+  if (!check_order()) {
+    xprintf("Ordering is already correct\n\n");
+    return;
+  }
+  for (i = 0; i < 4; i++) {
+    for (j = 0; j < 3; j++) {
+      if (first[j] > first[j+1]) {
+        py = partitions[j+1].part;
+        px = partitions[j].part;
+        memcpy(&temp, py, sizeof(struct partition));
+        memcpy(py, px, sizeof(struct partition));
+        memcpy(px, &temp, sizeof(struct partition));
+        min = first[j+1];
+        first[j+1] = first[j];
+        first[j] = min;
+        partitions[j].modified = 1;
+      }
+    }
+  }
+  for (i = 5; i < num_parts; i++) {
+    for (j = 5; j < num_parts - 1; j++) {
+      oj = partitions[j].start_offset;
+      ojj = partitions[j+1].start_offset;
+      if (oj > ojj) {
+        partitions[j].start_offset = ojj;
+        partitions[j+1].start_offset = oj;
+        pj = partitions[j].part;
+        set_levalue(pj->start4, swap_le32toh(pj->start4)+oj-ojj);
+        pjj = partitions[j+1].part;
+        set_levalue(pjj->start4, swap_le32toh(pjj->start4)+ojj-oj);
+        set_levalue((partitions[j-1].part+1)->start4, ojj-extended_offset);
+        set_levalue((partitions[j].part+1)->start4, oj-extended_offset);
+      }
+    }
+  }
+  for (i = 4; i < num_parts; i++) {
+    for (j = 4; j < num_parts - 1; j++) {
+      pj = partitions[j].part;
+      pjj = partitions[j+1].part;
+      sj = swap_le32toh(pj->start4);
+      sjj = swap_le32toh(pjj->start4);
+      oj = partitions[j].start_offset;
+      ojj = partitions[j+1].start_offset;
+      if (oj+sj > ojj+sjj) {
+        tmp = *pj;
+        *pj = *pjj;
+        *pjj = tmp;
+        set_levalue(pj->start4, ojj+sjj-oj);
+        set_levalue(pjj->start4, oj+sj-ojj);
+      }  
+    }    
+  }
+  // If anything changed 
+  for (j = 4; j < num_parts; j++) partitions[j].modified = 1;
+  xprintf("Done!\n");
+}
+
+static void print_menu(void)
+{
+  xprintf("a\ttoggle a bootable flag\n"
+  "b\tedit bsd disklabel\n"
+  "c\ttoggle the dos compatibility flag\n"
+  "d\tdelete a partition\n"
+  "l\tlist known partition types\n"
+  "n\tadd a new partition\n"
+  "o\tcreate a new empty DOS partition table\n"
+  "p\tprint the partition table\n"
+  "q\tquit without saving changes\n"
+  "s\tcreate a new empty Sun disklabel\n"
+  "t\tchange a partition's system id\n"
+  "u\tchange display/entry units\n"
+  "v\tverify the partition table\n"
+  "w\twrite table to disk and exit\n"
+  "x\textra functionality (experts only)\n");
+}
+
+static void print_xmenu(void)
+{
+  xprintf("b\tmove beginning of data in a partition\n"
+  "c\tchange number of cylinders\n"
+  "d\tprint the raw data in the partition table\n"
+  "e\tlist extended partitions\n"
+  "f\tfix partition order\n"  
+  "h\tchange number of heads\n"
+  "p\tprint the partition table\n"
+  "q\tquit without saving changes\n"
+  "r\treturn to main menu\n"
+  "s\tchange number of sectors/track\n"
+  "v\tverify the partition table\n"
+  "w\twrite table to disk and exit\n");
+}
+
+static void expert_menu(void)
+{
+  int choice, idx;
+  sector_t value;
+  char mesg[256];
+
+  while (1) {
+    xputc('\n');
+    char *msg = "Expert Command ('m' for help): ";
+    choice = 0x20 | read_input(msg, NULL);
+    switch (choice) {
+      case 'b': //move data begining in partition
+        idx = ask_partition(num_parts);
+        move_begning(idx - 1);
+        break;
+      case 'c': //change cylinders
+          sprintf(mesg, "Number of cylinders (1 - 1048576, default %lu): ", g_cylinders);
+          value = ask_value(mesg, 1, 1048576, g_cylinders);
+          g_cylinders = TT.cylinders = value;
+          toys.optflags |= FLAG_C;
+          if(g_cylinders > ONE_K)
+            xprintf("\nThe number of cylinders for this disk is set to %lu.\n"
+                "There is nothing wrong with that, but this is larger than 1024,\n"
+                "and could in certain setups cause problems.\n", g_cylinders);
+        break;
+      case 'd': //print raw data in part tables
+        print_raw_sectors();
+        break;
+      case 'e': //list extended partitions
+        print_partitions_list(1);
+        break;
+      case 'f': //fix part order
+        fix_order();
+        break;
+      case 'h': //change number of heads
+          sprintf(mesg, "Number of heads (1 - 256, default %lu): ", g_heads);
+          value = ask_value(mesg, 1, 256, g_heads);
+          g_heads = TT.heads = value;
+          toys.optflags |= FLAG_H;
+        break;
+      case 'p': //print partition table
+        print_partitions_list(0);
+        break;
+      case 'q':
+        free_bufs();
+        close(dev_fd);
+        xputc('\n');
+        exit(0);
+        break;
+      case 'r':
+        return;
+        break;
+      case 's': //change sector/track
+          sprintf(mesg, "Number of sectors (1 - 63, default %lu): ", g_sectors);
+          value = ask_value(mesg, 1, 63, g_sectors);
+          g_sectors = TT.sectors = value;
+          toys.optflags |= FLAG_H;
+        break;
+      case 'v':
+        verify_table();
+        break;
+      case 'w':
+        write_table();
+        toys.exitval = 0;
+        exit(0);
+        break;
+      case 'm':
+        print_xmenu();
+        break;
+      default:
+        xprintf("Unknown command '%c'\n",choice);
+        print_xmenu();
+        break;
+    }
+  } //while(1)
+}
+
+static int disk_proper(const char *device)
+{
+  unsigned length;
+  int fd = open(device, O_RDONLY);
+
+  if (fd != -1) {
+    struct hd_geometry dev_geo;
+    dev_geo.heads = 0;
+    dev_geo.sectors = 0;
+    int err = ioctl(fd, HDIO_GETGEO, &dev_geo);
+    close(fd);
+    if (!err) return (dev_geo.start == 0);
+  }
+  length = strlen(device);
+  if (length != 0 && isdigit(device[length - 1])) return 0;
+  return 1;
+}
+
+static void reset_entries()
+{
+  int i;
+
+  memset(MBRbuf, 0, sizeof(MBRbuf));
+  for (i = 4; i < num_parts; i++)
+    memset(&partitions[i], 0, sizeof(struct part_entry));
+}
+
+//this will keep dev_fd = 3 always alive
+static void move_fd()
+{
+  int fd = xopen("/dev/null", O_RDONLY);
+  if(fd != dev_fd) {
+    if(dup2(fd, dev_fd) != dev_fd) perror_exit("Can't dup2");
+    close(fd);
+  }
+}
+
+/* Read proc/partitions and then print the details
+ * for partitions on each device
+ */
+static void read_and_print_parts()
+{
+  unsigned int ma, mi, sz;
+  char *name = toybuf, *buffer = toybuf + ONE_K, *device = toybuf + 2048;
+  FILE* fp = xfopen("/proc/partitions", "r");
+
+  while (fgets(buffer, ONE_K, fp)) {
+    reset_entries();
+    num_parts = 4;
+    memset(name, 0, sizeof(name));
+    if (sscanf(buffer, " %u %u %u %[^\n ]", &ma, &mi, &sz, name) != 4)
+      continue;
+      
+    sprintf(device,"/dev/%s",name);
+    if (disk_proper(device)) {
+      if (read_mbr(device, 0)) continue;
+      print_mbr(1);
+      move_fd();
+    }
+  }
+  fclose(fp);
+}
+
+void fdisk_main(void)
+{
+  int choice, p;
+
+  init_members();
+  move_fd();
+  if (TT.heads >= 256) TT.heads = 0;
+  if (TT.sectors >= 64) TT.sectors = 0;
+  if (toys.optflags & FLAG_u) disp_unit_cyl = 0;
+  if (toys.optflags & FLAG_l) {
+    if (!toys.optc) read_and_print_parts();
+    else {
+      while(*toys.optargs){
+        if (read_mbr(*toys.optargs, 0)) {
+          toys.optargs++;
+          continue;
+        }
+        print_mbr(1);
+        move_fd();
+        toys.optargs++;
+      }
+    }
+    toys.exitval = 0;
+    return;
+  } else {
+    if (toys.optc != 1) help_exit(stdout);
+    if (read_mbr(toys.optargs[0], 1)) return;
+    while (1) {
+      xputc('\n');
+      char *msg = "Command ('m' for help): ";
+      choice = 0x20 | read_input(msg, NULL);
+      switch (choice) {
+        case 'a':
+          p = ask_partition(num_parts);
+          toggle_active_flag(p - 1); //partition table index start from 0.
+          break;
+        case 'b':
+          break;
+        case 'c':
+          dos_flag = !dos_flag;
+          xprintf("Dos compatible flag is %s\n", dos_flag?"Set" : "Not set");
+          break;
+        case 'd':
+          p = get_non_free_partition(num_parts); //4 was here
+          if(p >= 0) delete_partition(p);
+          break;
+        case 'l':
+          list_types();
+          break;
+        case 'n': //add new partition
+          add_new_partition();
+          break;
+        case 'o':
+          create_empty_doslabel();
+          break;
+        case 'p':
+          print_mbr(0);
+          break;
+        case 'q':
+          free_bufs();
+          close(dev_fd);
+          xputc('\n');
+          exit(0);
+          break;
+        case 's':
+          break;
+        case 't':
+          change_systype();
+          break;
+        case 'u':
+          disp_unit_cyl = !disp_unit_cyl;
+          xprintf("Changing Display/Entry units to %s\n",disp_unit_cyl?"cylinders" : "sectors");
+          break;
+        case 'v':
+          verify_table();
+          break;
+        case 'w':
+          write_table();
+          toys.exitval = 0;
+          return;
+          break;
+        case 'x':
+          expert_menu();
+          break;
+        case 'm':
+          print_menu();
+          break;
+        default:
+          xprintf("%c: Unknown command\n",choice);
+          break;
+      }
+    } //while(1)
+  }
+}
diff --git a/toybox/toys/pending/fold.c b/toybox/toys/pending/fold.c
new file mode 100644
index 0000000..0face64
--- /dev/null
+++ b/toybox/toys/pending/fold.c
@@ -0,0 +1,97 @@
+/* fold.c - fold text
+ *
+ * Copyright 2014 Samuel Holland <samuel@sholland.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/fold.html
+
+USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN))
+
+config FOLD
+  bool "fold"
+  default n
+  help
+    usage: fold [-bsu] [-w WIDTH] [FILE...]
+
+    Folds (wraps) or unfolds ascii text by adding or removing newlines.
+    Default line width is 80 columns for folding and infinite for unfolding.
+
+    -b	Fold based on bytes instead of columns
+    -s	Fold/unfold at whitespace boundaries if possible
+    -u	Unfold text (and refold if -w is given)
+    -w	Set lines to WIDTH columns or bytes
+*/
+
+#define FOR_fold
+#include "toys.h"
+
+GLOBALS(
+  int width;
+)
+
+// wcwidth mbrtowc
+void do_fold(int fd, char *name)
+{
+  int bufsz, len = 0, maxlen;
+
+  if (toys.optflags & FLAG_w) maxlen = TT.width;
+  else if (toys.optflags & FLAG_u) maxlen = 0;
+  else maxlen = 80;
+
+  while ((bufsz = read(fd, toybuf, sizeof(toybuf))) > 0) {
+    char *buf = toybuf;
+    int pos = 0, split = -1;
+
+    while (pos < bufsz) {
+      switch (buf[pos]) {
+        case '\n':
+          // print everything but the \n, then move on to the next buffer
+          if ((toys.optflags & FLAG_u) && buf[pos-1] != '\n'
+                                       && buf[pos+1] != '\n') {
+              xwrite(1, buf, pos);
+              bufsz -= pos + 1;
+              buf += pos + 1;
+              pos = 0;
+              split = -1;
+          // reset len, FLAG_b or not; just print multiple lines at once
+          } else len = 0;
+          break;
+        case '\b':
+          // len cannot be negative; not allowed to wrap after backspace
+          if (toys.optflags & FLAG_b) len++;
+          else if (len > 0) len--;
+          break;
+        case '\r':
+          // not allowed to wrap after carriage return
+          if (toys.optflags & FLAG_b) len++;
+          else len = 0;
+          break;
+        case '\t':
+          // round to 8, but we add one after falling through
+          // (because of whitespace, but it also takes care of FLAG_b)
+          if (!(toys.optflags & FLAG_b)) len = (len & ~7) + 7;
+        case ' ':
+          split = pos;
+        default:
+          len++;
+      }
+
+      // we don't want to double up \n; not allowed to wrap before \b
+      if (maxlen > 0 && len >= maxlen && buf[pos+1] != '\n' && buf[pos+1] != '\b') {
+        if (!(toys.optflags & FLAG_s) || split < 0) split = pos;
+        xwrite(1, buf, split + 1);
+        xputc('\n');
+        bufsz -= split + 1;
+        buf += split + 1;
+        len = pos = 0;
+        split = -1;
+      } else pos++;
+    }
+    xwrite(1, buf, bufsz);
+  }
+  xputc('\n');
+}
+
+void fold_main(void)
+{
+  loopfiles(toys.optargs, do_fold);
+}
diff --git a/toybox/toys/pending/fsck.c b/toybox/toys/pending/fsck.c
new file mode 100644
index 0000000..723f77d
--- /dev/null
+++ b/toybox/toys/pending/fsck.c
@@ -0,0 +1,434 @@
+/* fsck.c -  check and repair a Linux filesystem
+ *
+ * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+
+USE_FSCK(NEWTOY(fsck, "?t:ANPRTVsC#", TOYFLAG_USR|TOYFLAG_BIN))
+
+config FSCK
+  bool "fsck"
+  default n
+  help
+    usage: fsck [-ANPRTV] [-C FD] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]... 
+    
+    Check and repair filesystems
+
+    -A      Walk /etc/fstab and check all filesystems
+    -N      Don't execute, just show what would be done
+    -P      With -A, check filesystems in parallel
+    -R      With -A, skip the root filesystem
+    -T      Don't show title on startup
+    -V      Verbose
+    -C n    Write status information to specified filedescriptor
+    -t TYPE List of filesystem types to check
+
+*/
+
+#define FOR_fsck
+#include "toys.h"
+#include <mntent.h>
+
+#define FLAG_WITHOUT_NO_PRFX 1
+#define FLAG_WITH_NO_PRFX 2
+#define FLAG_DONE 1
+
+GLOBALS(
+  int fd_num;
+  char *t_list;
+
+  struct double_list *devices;
+  char *arr_flag;
+  char **arr_type;
+  int negate;
+  int sum_status;
+  int nr_run;
+  int sig_num;
+  long max_nr_run;
+)
+
+struct f_sys_info {
+  char *device, *mountpt, *type, *opts;
+  int passno, flag;
+  struct f_sys_info *next;
+};
+
+struct child_list {
+  struct child_list *next;
+  pid_t pid;
+  char *prog_name, *dev_name;
+};
+
+static struct f_sys_info *filesys_info = NULL; //fstab entry list
+static struct child_list *c_list = NULL; //fsck.type child list.
+
+static void kill_all(void) 
+{
+  struct child_list *child;
+
+  for (child = c_list; child; child = child->next) 
+    kill(child->pid, SIGTERM);
+  _exit(0);
+}
+
+static long strtol_range(char *str, int min, int max)
+{
+  char *endptr = NULL;
+  errno = 0;
+  long ret_value = strtol(str, &endptr, 10);
+
+  if(errno) perror_exit("Invalid num %s", str);
+  else if(endptr && (*endptr != '\0' || endptr == str))
+    perror_exit("Not a valid num %s", str);
+  if(ret_value >= min && ret_value <= max) return ret_value;
+  else perror_exit("Number %s is not in valid [%d-%d] Range", str, min, max);
+}
+
+//create fstab entries list.
+static struct f_sys_info* create_db(struct mntent *f_info)
+{
+  struct f_sys_info *temp = filesys_info;
+  if (temp) {
+    while (temp->next) temp = temp->next;
+    temp->next = xzalloc(sizeof(struct f_sys_info));
+    temp = temp->next;
+  } else filesys_info = temp = xzalloc(sizeof(struct f_sys_info));
+
+  temp->device = xstrdup(f_info->mnt_fsname);
+  temp->mountpt = xstrdup(f_info->mnt_dir);
+  if (strchr(f_info->mnt_type, ',')) temp->type = xstrdup("auto");
+  else  temp->type = xstrdup(f_info->mnt_type);
+  temp->opts = xstrdup(f_info->mnt_opts);
+  temp->passno = f_info->mnt_passno;
+  return temp;
+}
+
+//is we have 'no' or ! before type.
+static int is_no_prefix(char **p)
+{
+  int no = 0;
+
+  if ((*p[0] == 'n' && *(*p + 1) == 'o')) no = 2; 
+  else if (*p[0] == '!') no = 1;
+  *p += no;
+  return ((no) ? 1 :0);
+}
+
+static void fix_tlist(void)
+{
+  char *p, *s = TT.t_list;
+  int n = 1, no;
+
+  while ((s = strchr(s, ','))) {
+    s++;
+    n++;
+  }
+
+  TT.arr_flag = xzalloc(n + 1);
+  TT.arr_type = xzalloc((n + 1) * sizeof(char *));
+  s = TT.t_list;
+  n = 0;
+  while ((p = strsep(&s, ","))) {
+    no = is_no_prefix(&p);
+    if (!strcmp(p, "loop")) {
+      TT.arr_flag[n] = no ? FLAG_WITH_NO_PRFX :FLAG_WITHOUT_NO_PRFX;
+      TT.negate = no;
+    } else if (!strncmp(p, "opts=", 5)) {
+      p+=5;
+      TT.arr_flag[n] = is_no_prefix(&p) ?FLAG_WITH_NO_PRFX :FLAG_WITHOUT_NO_PRFX;
+      TT.negate = no;
+    } else {
+      if (!n) TT.negate = no;
+      if (n && TT.negate != no) error_exit("either all or none of the filesystem"
+          " types passed to -t must be prefixed with 'no' or '!'");
+    }
+    TT.arr_type[n++] = p;
+  }
+}
+
+//ignore these types...
+static int ignore_type(char *type)
+{
+  int i = 0;
+  char *str;
+  char *ignored_types[] = {
+    "ignore","iso9660", "nfs","proc",
+    "sw","swap", "tmpfs","devpts",NULL
+  };
+  while ((str = ignored_types[i++])) {
+    if (!strcmp(str, type)) return 1;
+  }
+  return 0;
+}
+
+// return true if has to ignore the filesystem.
+static int to_be_ignored(struct f_sys_info *finfo) 
+{
+  int i, ret = 0, type_present = 0;
+
+  if (!finfo->passno) return 1; //Ignore with pass num = 0
+  if (TT.arr_type) {
+    for (i = 0; TT.arr_type[i]; i++) {
+      if (!TT.arr_flag[i]) { //it is type of filesys.
+        type_present = 2;
+        if (!strcmp(TT.arr_type[i], finfo->type)) ret = 0;
+        else ret = 1;
+      } else if (TT.arr_flag[i] == FLAG_WITH_NO_PRFX) { //it is option of filesys
+        if (hasmntopt((const struct mntent *)finfo, TT.arr_type[i])) return 1;
+      } else { //FLAG_WITHOUT_NO_PRFX
+        if (!hasmntopt((const struct mntent *)finfo, TT.arr_type[i])) return 1;
+      }
+    }
+  }
+  if (ignore_type(finfo->type)) return 1;
+  if (TT.arr_type && type_present != 2) return 0;
+  return ((TT.negate) ? !ret : ret);
+}
+
+// find type and execute corresponding fsck.type prog.
+static void do_fsck(struct f_sys_info *finfo) 
+{
+  struct child_list *child;
+  char **args;
+  char *type;
+  pid_t pid;
+  int i = 1, j = 0;
+
+  if (strcmp(finfo->type, "auto")) type = finfo->type;
+  else if (TT.t_list && (TT.t_list[0] != 'n' || TT.t_list[1] != 'o' || TT.t_list[0] != '!')
+      && strncmp(TT.t_list, "opts=", 5) && strncmp(TT.t_list , "loop", 4)
+      && !TT.arr_type[1]) type = TT.t_list; //one file sys at cmdline
+  else type = "auto";
+
+  args = xzalloc((toys.optc + 2 + 1 + 1) * sizeof(char*)); //+1, for NULL, +1 if -C
+  args[0] = xmprintf("fsck.%s", type);
+  
+  if(toys.optflags & FLAG_C) args[i++] = xmprintf("%s %d","-C", TT.fd_num);
+  while(toys.optargs[j]) {
+    if(*toys.optargs[j]) args[i++] = xstrdup(toys.optargs[j]);
+    j++;
+  }
+  args[i] = finfo->device;
+
+  TT.nr_run++;
+  if ((toys.optflags & FLAG_V) || (toys.optflags & FLAG_N)) {
+    printf("[%s (%d) -- %s]", args[0], TT.nr_run,
+        finfo->mountpt ? finfo->mountpt : finfo->device);
+    for (i = 0; args[i]; i++) xprintf(" %s", args[i]);
+    xputc('\n');
+  }
+
+  if (toys.optflags & FLAG_N) {
+    for (j=0;j<i;j++) free(args[i]);
+    free(args);
+    return;
+  } else { 
+    if ((pid = fork()) < 0) {
+      perror_msg(args[0]);
+      for (j=0;j<i;j++) free(args[i]);
+      free(args);
+      return; 
+    }
+    if (!pid) xexec(args); //child, executes fsck.type
+  } 
+
+  child = xzalloc(sizeof(struct child_list)); //Parent, add to child list.
+  child->dev_name = xstrdup(finfo->device);
+  child->prog_name = args[0];
+  child->pid = pid;
+
+  if (c_list) {
+    child->next = c_list;
+    c_list = child;
+  } else {
+    c_list = child;
+    child->next =NULL;
+  }
+}
+
+// for_all = 1; wait for all child to exit
+// for_all = 0; wait for any one to exit
+static int wait_for(int for_all)
+{
+  pid_t pid;
+  int status = 0, child_exited;
+  struct child_list *prev, *temp;
+
+  errno = 0;
+  if (!c_list) return 0;
+  while ((pid = wait(&status))) {
+    temp = c_list;
+    prev = temp;
+    if (TT.sig_num) kill_all();
+    child_exited = 0;
+    if (pid < 0) {
+      if (errno == EINTR) continue;
+      else if (errno == ECHILD) break; //No child to wait, break and return status.
+      else perror_exit("option arg Invalid\n"); //paranoid.
+    }
+    while (temp) {
+      if (temp->pid == pid) {
+        child_exited = 1;
+        break;
+      }
+      prev = temp;
+      temp = temp->next;
+    }
+    if (child_exited) {
+      if (WIFEXITED(status)) TT.sum_status |= WEXITSTATUS(status);
+      else if (WIFSIGNALED(status)) { 
+        TT.sum_status |= 4; //Uncorrected.
+        if (WTERMSIG(status) != SIGINT)
+          perror_msg("child Term. by sig: %d\n",(WTERMSIG(status)));
+        TT.sum_status |= 8; //Operatinal error
+      } else { 
+        TT.sum_status |= 4; //Uncorrected.
+        perror_msg("%s %s: status is %x, should never happen\n", 
+            temp->prog_name, temp->dev_name, status);
+      }
+      TT.nr_run--;
+      if (prev == temp) c_list = c_list->next; //first node 
+      else prev->next = temp->next;
+      free(temp->prog_name);
+      free(temp->dev_name);
+      free(temp);
+      if (!for_all) break;
+    }
+  }
+  return TT.sum_status;
+}
+
+//scan all the fstab entries or -t matches with fstab.
+static int scan_all(void)
+{
+  struct f_sys_info *finfo = filesys_info;
+  int ret = 0, passno;
+
+  if (toys.optflags & FLAG_V) xprintf("Checking all filesystem\n");
+  while (finfo) {
+    if (to_be_ignored(finfo)) finfo->flag |= FLAG_DONE;
+    finfo = finfo->next;
+  }
+  finfo = filesys_info;
+
+  if (!(toys.optflags & FLAG_P)) {
+    while (finfo) {
+      if (!strcmp(finfo->mountpt, "/")) { // man says: check / in parallel with others if -P is absent.
+        if ((toys.optflags & FLAG_R) || to_be_ignored(finfo)) {
+          finfo->flag |= FLAG_DONE;
+          break;
+        } else {
+          do_fsck(finfo);
+          finfo->flag |= FLAG_DONE;
+          if (TT.sig_num) kill_all();
+          if ((ret |= wait_for(1)) > 4) return ret; //destruction in filesys.
+          break;
+        }
+      }
+      finfo = finfo->next;
+    }
+  }
+  if (toys.optflags & FLAG_R) { // with -PR we choose to skip root.
+    for (finfo = filesys_info; finfo; finfo = finfo->next) {
+      if(!strcmp(finfo->mountpt, "/")) finfo->flag |= FLAG_DONE;
+    }
+  }
+  passno = 1;
+  while (1) {
+    for (finfo = filesys_info; finfo; finfo = finfo->next) 
+      if (!finfo->flag) break;
+    if (!finfo) break;
+
+    for (finfo = filesys_info; finfo; finfo = finfo->next) {
+      if (finfo->flag) continue;
+      if (finfo->passno == passno) {
+        do_fsck(finfo);
+        finfo->flag |= FLAG_DONE;
+        if ((toys.optflags & FLAG_s) || (TT.nr_run 
+              && (TT.nr_run >= TT.max_nr_run))) ret |= wait_for(0);
+      }
+    }
+    if (TT.sig_num) kill_all();
+    ret |= wait_for(1);
+    passno++;
+  }
+  return ret;
+}
+
+void record_sig_num(int sig) 
+{
+  TT.sig_num = sig;
+}
+
+void fsck_main(void)
+{
+  struct mntent mt;
+  struct double_list *dev;
+  struct f_sys_info *finfo;
+  FILE *fp;
+  char *tmp, **arg = toys.optargs;
+
+  sigatexit(record_sig_num);
+  while (*arg) {
+    if ((**arg == '/') || strchr(*arg, '=')) {
+      dlist_add(&TT.devices, xstrdup(*arg));
+      **arg = '\0';
+    }
+    arg++;
+  }
+  if (toys.optflags & FLAG_t) fix_tlist();
+  if (!(tmp = getenv("FSTAB_FILE"))) tmp = "/etc/fstab";
+  if (!(fp = setmntent(tmp, "r"))) perror_exit("setmntent failed:");
+  while (getmntent_r(fp, &mt, toybuf, 4096)) create_db(&mt);
+  endmntent(fp);
+
+  if (!(toys.optflags & FLAG_T)) xprintf("fsck ----- (Toybox)\n");
+
+  if ((tmp = getenv("FSCK_MAX_INST")))
+    TT.max_nr_run = strtol_range(tmp, 0, INT_MAX);
+  if (!TT.devices || (toys.optflags & FLAG_A)) {
+    toys.exitval = scan_all();
+    if (CFG_TOYBOX_FREE) goto free_all;
+    return; //if CFG_TOYBOX_FREE is not set, exit.
+  }
+
+  dev = TT.devices;
+  dev->prev->next = NULL; //break double list to traverse.
+  for (; dev; dev = dev->next) {
+    for (finfo = filesys_info; finfo; finfo = finfo->next)
+      if (!strcmp(finfo->device, dev->data) 
+          || !strcmp(finfo->mountpt, dev->data)) break;
+    if (!finfo) { //if not present, fill def values.
+      mt.mnt_fsname = dev->data;
+      mt.mnt_dir = "";
+      mt.mnt_type = "auto";
+      mt.mnt_opts = "";
+      mt.mnt_passno = -1;
+      finfo = create_db(&mt);
+    }
+    do_fsck(finfo);
+    finfo->flag |= FLAG_DONE;
+    if ((toys.optflags & FLAG_s) || (TT.nr_run && (TT.nr_run >= TT.max_nr_run))) 
+      toys.exitval |= wait_for(0);
+  }
+  if (TT.sig_num) kill_all();
+  toys.exitval |= wait_for(1);
+  finfo = filesys_info;
+
+free_all:
+  if (CFG_TOYBOX_FREE) {
+    struct f_sys_info *finfo, *temp;
+
+    llist_traverse(TT.devices, llist_free_double);
+    free(TT.arr_type);
+    free(TT.arr_flag);
+    for (finfo = filesys_info; finfo;) {
+      temp = finfo->next;
+      free(finfo->device);
+      free(finfo->mountpt);
+      free(finfo->type);
+      free(finfo->opts);
+      free(finfo);
+      finfo = temp;
+    }
+  }
+}
diff --git a/toybox/toys/pending/ftpget.c b/toybox/toys/pending/ftpget.c
new file mode 100644
index 0000000..a144713
--- /dev/null
+++ b/toybox/toys/pending/ftpget.c
@@ -0,0 +1,293 @@
+/* ftpget.c - Get a remote file from FTP.
+ *
+ * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+ * 
+USE_FTPGET(NEWTOY(ftpget, "<2cvu:p:P#<0=21>65535", TOYFLAG_BIN))
+USE_FTPGET(OLDTOY(ftpput, ftpget, TOYFLAG_BIN))
+
+config FTPGET
+  bool "ftpget/ftpput"
+  default n
+  help
+    usage: ftpget [-cv] [-u USER -p PASSWORD -P PORT] HOST_NAME [LOCAL_FILENAME] REMOTE_FILENAME
+    usage: ftpput [-v] [-u USER -p PASSWORD -P PORT] HOST_NAME [REMOTE_FILENAME] LOCAL_FILENAME
+
+    ftpget - Get a remote file from FTP.
+    ftpput - Upload a local file on remote machine through FTP.
+
+    -c Continue previous transfer.
+    -v Verbose.
+    -u User name.
+    -p Password.
+    -P Port Number (default 21).
+*/
+#define FOR_ftpget
+#include "toys.h"
+
+GLOBALS(
+  long port; //  char *port;
+  char *password;
+  char *username;
+
+  FILE *sockfp;
+  int c;
+  int isget;
+  char buf[sizeof(struct sockaddr_storage)];
+)
+
+#define DATACONNECTION_OPENED   125
+#define FTPFILE_STATUSOKAY      150
+#define FTP_COMMAND_OKAY        200
+#define FTPFILE_STATUS          213
+#define FTPSERVER_READY         220
+#define CLOSE_DATACONECTION     226
+#define PASSIVE_MODE            227
+#define USERLOGGED_SUCCESS      230
+#define PASSWORD_REQUEST        331
+#define REQUESTED_PENDINGACTION 350
+
+
+static void setport(unsigned port_num)
+{
+  int af = ((struct sockaddr *)TT.buf)->sa_family;
+
+  if (af == AF_INET) ((struct sockaddr_in*)TT.buf)->sin_port = port_num;
+  else if (af == AF_INET6) ((struct sockaddr_in6*)TT.buf)->sin6_port = port_num;
+}
+
+static int connect_to_stream()
+{
+  int sockfd, af = ((struct sockaddr *)TT.buf)->sa_family;
+
+  sockfd = xsocket(af, SOCK_STREAM, 0);
+  if (connect(sockfd, (struct sockaddr*)TT.buf,((af == AF_INET)? 
+          sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6))) < 0) {
+    close(sockfd);
+    perror_exit("can't connect to remote host");
+  }
+  return sockfd;
+}
+
+//close ftp connection and print the message.
+static void close_stream(char *msg_str)
+{
+  char *str = toybuf; //toybuf holds response data.
+
+  //Remove garbage chars (from ' ' space to '\x7f') DEL remote server response.
+  while ((*str >= 0x20) && (*str < 0x7f)) str++; 
+  *str = '\0';
+  if (TT.sockfp) fclose(TT.sockfp);
+  error_exit("%s server response: %s", (msg_str) ? msg_str:"", toybuf);
+}
+
+//send command to ftp and get return status.
+static int get_ftp_response(char *command, char *param)
+{
+  unsigned cmd_status = 0;
+  char *fmt = "%s %s\r\n";
+
+  if (command) {
+    if (!param) fmt += 3;
+    fprintf(TT.sockfp, fmt, command, param);
+    fflush(TT.sockfp);
+    if (toys.optflags & FLAG_v) 
+      fprintf(stderr, "FTP Request: %s %s\r\n", command, param);
+  }
+
+  do {
+    if (!fgets(toybuf, sizeof(toybuf)-1, TT.sockfp)) close_stream(NULL);
+  } while (!isdigit(toybuf[0]) || toybuf[3] != ' ');
+
+  toybuf[3] = '\0';
+  cmd_status = atolx_range(toybuf, 0, INT_MAX);
+  toybuf[3] = ' ';
+  return cmd_status;
+}
+
+static void send_requests(void)
+{
+  int cmd_status = 0;
+
+  //FTP connection request.
+  if (get_ftp_response(NULL, NULL) != FTPSERVER_READY) close_stream(NULL);
+
+  //230 User authenticated, password please; 331 Password request.
+  cmd_status = get_ftp_response("USER", TT.username);
+  if (cmd_status == PASSWORD_REQUEST) { //user logged in. Need Password.
+    if (get_ftp_response("PASS", TT.password) != USERLOGGED_SUCCESS) 
+      close_stream("PASS");
+  } else if (cmd_status == USERLOGGED_SUCCESS); //do nothing
+  else close_stream("USER");
+  //200 Type Binary. Command okay.
+  if (get_ftp_response("TYPE I", NULL) != FTP_COMMAND_OKAY) 
+    close_stream("TYPE I");
+}
+
+static void get_sockaddr(char *host)
+{  
+  struct addrinfo hints, *result;
+  char port[6];
+  int status;
+  
+  errno = 0;
+  snprintf(port, 6, "%ld", TT.port);
+
+  memset(&hints, 0 , sizeof(struct addrinfo));
+  hints.ai_family = AF_UNSPEC;
+  hints.ai_socktype = SOCK_STREAM;
+
+  status = getaddrinfo(host, port, &hints, &result); 
+  if (status) error_exit("bad address '%s' : %s", host, gai_strerror(status));
+
+  memcpy(TT.buf, result->ai_addr, result->ai_addrlen);
+  freeaddrinfo(result);
+} 
+
+// send commands to ftp fo PASV mode.
+static void verify_pasv_mode(char *r_filename)
+{
+  char *pch;
+  unsigned portnum;
+
+  //vsftpd reply like:- "227 Entering Passive Mode (125,19,39,117,43,39)".
+  if (get_ftp_response("PASV", NULL) != PASSIVE_MODE) goto close_stream;
+
+  //Response is "NNN <some text> (N1,N2,N3,N4,P1,P2) garbage.
+  //Server's IP is N1.N2.N3.N4
+  //Server's port for data connection is P1*256+P2.
+  if (!(pch = strrchr(toybuf, ')'))) goto close_stream;
+  *pch = '\0';
+  if (!(pch = strrchr(toybuf, ','))) goto close_stream;
+  *pch = '\0';
+
+  portnum = atolx_range(pch + 1, 0, 255);
+
+  if (!(pch = strrchr(toybuf, ','))) goto close_stream;
+  *pch = '\0';
+  portnum = portnum + (atolx_range(pch + 1, 0, 255) * 256);
+  setport(htons(portnum));
+
+  if (TT.isget && get_ftp_response("SIZE", r_filename) != FTPFILE_STATUS)
+    TT.c = 0;
+  return;
+
+close_stream:
+  close_stream("PASV");
+}
+
+/*
+ * verify the local file presence.
+ * if present, get the size of the file.
+ */
+static void is_localfile_present(char *l_filename)
+{
+  struct stat sb;
+
+  if (stat(l_filename, &sb) < 0) perror_exit("stat");
+  //if local file present, then request for pending file action.
+  if (sb.st_size > 0) {
+    sprintf(toybuf, "REST %lu", (unsigned long) sb.st_size);
+    if (get_ftp_response(toybuf, NULL) != REQUESTED_PENDINGACTION) TT.c = 0;
+  } else TT.c = 0;
+}
+
+static void transfer_file(int local_fd, int remote_fd)
+{
+  int len, rfd = (TT.isget)?remote_fd:local_fd,
+      wfd = (TT.isget)?local_fd:remote_fd;
+
+  if (rfd < 0 || wfd < 0) error_exit("Error in file creation:");
+  while ((len = xread(rfd, toybuf, sizeof(toybuf)))) xwrite(wfd, toybuf, len);
+}
+
+static void get_file(char *l_filename, char *r_filename)
+{
+  int local_fd = -1, remote_fd;
+
+  verify_pasv_mode(r_filename);
+  remote_fd = connect_to_stream(); //Connect to data socket.
+
+  //if local file name will be '-' then local fd will be stdout.
+  if ((l_filename[0] == '-') && !l_filename[1]) {
+    local_fd = 1; //file descriptor will become stdout.
+    TT.c = 0;
+  }
+
+  //if continue, check for local file existance.
+  if (TT.c) is_localfile_present(l_filename);
+
+  //verify the remote file presence.
+  if (get_ftp_response("RETR", r_filename) > FTPFILE_STATUSOKAY) 
+    close_stream("RETR");
+
+  //if local fd is not stdout, create a file descriptor.
+  if (local_fd == -1) {
+    int flags = O_WRONLY;
+
+    flags |= (TT.c)? O_APPEND : (O_CREAT | O_TRUNC);
+    local_fd = xcreate((char *)l_filename, flags, 0666);
+  }
+  transfer_file(local_fd, remote_fd);
+  xclose(remote_fd);
+  xclose(local_fd);
+  if (get_ftp_response(NULL, NULL) != CLOSE_DATACONECTION) close_stream(NULL);
+  get_ftp_response("QUIT", NULL);
+  toys.exitval = EXIT_SUCCESS;
+}
+
+static void put_file(char *r_filename, char *l_filename)
+{
+  int local_fd = 0, remote_fd;
+  unsigned cmd_status = 0;
+
+  verify_pasv_mode(r_filename);
+  remote_fd = connect_to_stream(); //Connect to data socket.
+
+  //open the local file for transfer.
+  if ((l_filename[0] != '-') || l_filename[1]) 
+    local_fd = xcreate((char *)l_filename, O_RDONLY, 0666);
+
+  //verify for the remote file status, Ok or Open: transfer File.
+  cmd_status = get_ftp_response("STOR", r_filename);
+  if ( (cmd_status == DATACONNECTION_OPENED) || 
+      (cmd_status == FTPFILE_STATUSOKAY)) {
+    transfer_file(local_fd, remote_fd);
+    if (get_ftp_response(NULL, NULL) != CLOSE_DATACONECTION) close_stream(NULL);
+    get_ftp_response("QUIT", NULL);
+    toys.exitval = EXIT_SUCCESS;
+  } else {
+    toys.exitval = EXIT_FAILURE;
+    close_stream("STOR");
+  }
+  xclose(remote_fd);
+  xclose(local_fd);
+}
+
+void ftpget_main(void)
+{
+  char **argv = toys.optargs; //host name + file name.
+
+  TT.isget = toys.which->name[3] == 'g';
+  TT.c = 1;
+  //if user name is not specified.
+  if (!(toys.optflags & FLAG_u) && (toys.optflags & FLAG_p)) 
+    error_exit("Missing username:");
+  //if user name and password is not specified in command line.
+  if (!(toys.optflags & FLAG_u) && !(toys.optflags & FLAG_p))
+    TT.username = TT.password ="anonymous";
+
+  //if continue is not in the command line argument.
+  if (TT.isget && !(toys.optflags & FLAG_c)) TT.c = 0;
+
+  if (toys.optflags & FLAG_v) fprintf(stderr, "Connecting to %s\n", argv[0]);
+  get_sockaddr(argv[0]);
+
+  TT.sockfp = xfdopen(connect_to_stream(), "r+");
+  send_requests();
+
+  if (TT.isget) get_file(argv[1], argv[2] ? argv[2] : argv[1]); 
+  else put_file(argv[1], argv[2] ? argv[2] : argv[1]);
+}
diff --git a/toybox/toys/pending/getfattr.c b/toybox/toys/pending/getfattr.c
new file mode 100644
index 0000000..efec53a
--- /dev/null
+++ b/toybox/toys/pending/getfattr.c
@@ -0,0 +1,95 @@
+/* getfattr.c - Read POSIX extended attributes.
+ *
+ * Copyright 2016 Android Open Source Project.
+ *
+ * No standard
+
+USE_GETFATTR(NEWTOY(getfattr, "dhn:", TOYFLAG_USR|TOYFLAG_BIN))
+
+config GETFATTR
+  bool "getfattr"
+  default y
+  help
+    usage: getfattr [-d] [-h] [-n NAME] FILE...
+
+    Read POSIX extended attributes.
+
+    -d	Show values as well as names.
+    -h	Do not dereference symbolic links.
+    -n	Show only attributes with the given name.
+*/
+
+#define FOR_getfattr
+#include "toys.h"
+
+GLOBALS(
+  char *n;
+)
+
+// TODO: factor out the lister and getter loops and use them in cp too.
+static void do_getfattr(char *file)
+{
+  ssize_t (*getter)(const char *, const char *, void *, size_t) = getxattr;
+  ssize_t (*lister)(const char *, char *, size_t) = listxattr;
+  char **sorted_keys;
+  ssize_t keys_len;
+  char *keys, *key;
+  int i, key_count;
+
+  if (toys.optflags&FLAG_h) {
+    getter = lgetxattr;
+    lister = llistxattr;
+  }
+
+  // Collect the keys.
+  while ((keys_len = lister(file, NULL, 0))) {
+    if (keys_len == -1) perror_msg("listxattr failed");
+    keys = xmalloc(keys_len);
+    if (lister(file, keys, keys_len) == keys_len) break;
+    free(keys);
+  }
+
+  if (keys_len == 0) return;
+
+  // Sort the keys.
+  for (key = keys, key_count = 0; key-keys < keys_len; key += strlen(key)+1)
+    key_count++;
+  sorted_keys = xmalloc(key_count * sizeof(char *));
+  for (key = keys, i = 0; key-keys < keys_len; key += strlen(key)+1)
+    sorted_keys[i++] = key;
+  qsort(sorted_keys, key_count, sizeof(char *), qstrcmp);
+
+  printf("# file: %s\n", file);
+
+  for (i = 0; i < key_count; i++) {
+    key = sorted_keys[i];
+
+    if (TT.n && strcmp(TT.n, key)) continue;
+
+    if (toys.optflags&FLAG_d) {
+      ssize_t value_len;
+      char *value = NULL;
+
+      while ((value_len = getter(file, key, NULL, 0))) {
+        if (value_len == -1) perror_msg("getxattr failed");
+        value = xzalloc(value_len+1);
+        if (getter(file, key, value, value_len) == value_len) break;
+        free(value);
+      }
+
+      if (!value) puts(key);
+      else printf("%s=\"%s\"\n", key, value);
+      free(value);
+    } else puts(key); // Just list names.
+  }
+
+  xputc('\n');
+  free(sorted_keys);
+}
+
+void getfattr_main(void)
+{
+  char **s;
+
+  for (s=toys.optargs; *s; s++) do_getfattr(*s);
+}
diff --git a/toybox/toys/pending/getty.c b/toybox/toys/pending/getty.c
new file mode 100644
index 0000000..25d04ea
--- /dev/null
+++ b/toybox/toys/pending/getty.c
@@ -0,0 +1,336 @@
+/* getty.c - A getty program to get controlling terminal.
+ *
+ * Copyright 2012 Sandeep Sharma <sandeep.jack2756@gamil.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_GETTY(NEWTOY(getty, "<2t#<0H:I:l:f:iwnmLh",TOYFLAG_SBIN))
+
+config GETTY
+  bool "getty"
+  default n
+  help
+    usage: getty [OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]
+
+    -h    Enable hardware RTS/CTS flow control
+    -L    Set CLOCAL (ignore Carrier Detect state)
+    -m    Get baud rate from modem's CONNECT status message
+    -n    Don't prompt for login name
+    -w    Wait for CR or LF before sending /etc/issue
+    -i    Don't display /etc/issue
+    -f ISSUE_FILE  Display ISSUE_FILE instead of /etc/issue
+    -l LOGIN  Invoke LOGIN instead of /bin/login
+    -t SEC    Terminate after SEC if no login name is read
+    -I INITSTR  Send INITSTR before anything else
+    -H HOST    Log HOST into the utmp file as the hostname
+*/
+#define FOR_getty
+#include "toys.h"
+#include <utmp.h>
+
+GLOBALS(
+  char *issue_str;
+  char *login_str;
+  char *init_str;
+  char *host_str; 
+  long timeout;
+  
+  char *tty_name;  
+  int  speeds[20];
+  int  sc;              
+  struct termios termios;
+  char buff[128];
+)
+
+#define CTL(x)        ((x) ^ 0100) 
+#define HOSTNAME_SIZE 32
+
+typedef void (*sighandler_t)(int);
+struct speed_mapper {
+  long speed;
+  speed_t code;
+};
+
+struct speed_mapper speedtab[] = {
+  {50, B50}, {75, B75}, {110, B110}, {134, B134}, {150, B150}, {200, B200},
+  {300, B300}, {600, B600}, {1200, B1200}, {1800, B1800}, {2400, B2400},
+  {4800, B4800}, {9600, B9600},
+#ifdef  B19200
+  {19200, B19200},
+#endif
+#ifdef  B38400
+  {38400, B38400},
+#endif
+#ifdef  EXTA
+  {19200, EXTA},
+#endif
+#ifdef  EXTB
+  {38400, B38400},
+#endif
+#ifdef B57600
+  {57600, B57600},
+#endif
+#ifdef B115200
+  {115200, B115200},
+#endif
+#ifdef B230400
+  {230400, B230400},
+#endif
+  {0, 0},
+};
+
+// Find speed from mapper array 
+static speed_t encode(char *s)
+{
+  struct speed_mapper *sp;
+  long speed = atolx(s);
+
+  if (!speed) return 0;
+  for (sp = speedtab; sp->speed; sp++) if (sp->speed == speed) return sp->code;
+  return (speed_t) -1;
+}
+
+static void get_speed(char *sp)
+{
+  char *ptr;
+
+  TT.sc = 0;
+  while ((ptr = strsep(&sp, ","))) {
+    TT.speeds[TT.sc] = encode(ptr);
+    if (TT.speeds[TT.sc] < 0) perror_exit("bad speed");
+    if (++TT.sc > 10) perror_exit("too many speeds, max is 10");
+  }
+}
+
+// Parse args and set TERM env. variable
+static void parse_arguments(void)
+{
+  if (isdigit(**toys.optargs)) {
+    get_speed(*toys.optargs);
+    if (*++toys.optargs) TT.tty_name = xmprintf("%s", *toys.optargs);
+  } else {
+    TT.tty_name = xmprintf("%s", *toys.optargs);
+    if (*++toys.optargs) get_speed(*toys.optargs);
+  } 
+  if (*++toys.optargs) setenv("TERM", *toys.optargs, 1);
+}
+
+// Get controlling terminal and redirect stdio 
+static void open_tty(void)
+{
+  if (strcmp(TT.tty_name, "-")) {
+    if (*(TT.tty_name) != '/') TT.tty_name = xmprintf("/dev/%s", TT.tty_name);
+    // Sends SIGHUP to all foreground process if Session leader don't die,Ignore
+    sighandler_t sig = signal(SIGHUP, SIG_IGN); 
+    ioctl(0, TIOCNOTTY, 0); // Giveup if there is any controlling terminal
+    signal(SIGHUP, sig);
+    if ((setsid() < 0) && (getpid() != getsid(0))) 
+      perror_exit("setsid");
+    xclose(0);
+    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);
+    if (ioctl(0, TIOCSCTTY, 1) < 0) perror_msg("ioctl(TIOCSCTTY)");
+    if (!isatty(0)) perror_exit("/dev/%s: not a tty", TT.tty_name);
+    chown(TT.tty_name, 0, 0); // change ownership, Hope login will change this
+    chmod(TT.tty_name, 0620);
+  } else { // We already have opened TTY
+    if (setsid() < 0) perror_msg("setsid failed");
+    if ((fcntl(0, F_GETFL) & (O_RDWR|O_RDONLY|O_WRONLY)) != O_RDWR)
+      perror_exit("no read/write permission");
+  }
+}
+
+// Intialise terminal settings
+static void termios_init(void)
+{
+  if (tcgetattr(STDIN_FILENO, &TT.termios) < 0) perror_exit("tcgetattr");
+  // Flush input and output queues, important for modems!
+  tcflush(STDIN_FILENO, TCIOFLUSH); 
+  TT.termios.c_cflag &= (0|CSTOPB|PARENB|PARODD);
+#ifdef CRTSCTS
+  if (toys.optflags & FLAG_h) TT.termios.c_cflag |= CRTSCTS;
+#endif
+  if (toys.optflags & FLAG_L) TT.termios.c_cflag |= CLOCAL;
+  TT.termios.c_cc[VTIME] = 0;
+  TT.termios.c_cc[VMIN] = 1;
+  TT.termios.c_oflag = OPOST|ONLCR;
+  TT.termios.c_cflag |= CS8|CREAD|HUPCL|CBAUDEX;
+  // login will disable echo for passwd.
+  TT.termios.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOKE;
+  TT.termios.c_cc[VINTR] = CTL('C');
+  TT.termios.c_cc[VQUIT] = CTL('\\');
+  TT.termios.c_cc[VEOF] = CTL('D');
+  TT.termios.c_cc[VEOL] = '\n';
+  TT.termios.c_cc[VKILL] = CTL('U');
+  TT.termios.c_cc[VERASE] = 127; // CERASE
+  TT.termios.c_iflag = ICRNL|IXON|IXOFF;
+  // set non-zero baud rate. Zero baud rate left it unchanged.
+  if (TT.speeds[0] != B0) cfsetspeed(&TT.termios, TT.speeds[0]); 
+  if (tcsetattr(STDIN_FILENO, TCSANOW, &TT.termios) < 0) 
+    perror_exit("tcsetattr");
+}
+
+// Get the baud rate from modems CONNECT mesage, Its of form <junk><BAUD><Junk>
+static void sense_baud(void)
+{
+  int vmin;
+  ssize_t size;
+  char *ptr;
+  speed_t speed;
+
+  vmin = TT.termios.c_cc[VMIN]; // Store old
+  TT.termios.c_cc[VMIN] = 0; // No block even queue is empty.
+  if (tcsetattr(STDIN_FILENO, TCSANOW, &TT.termios) < 0) 
+    perror_exit("tcsetattr");
+  size = readall(STDIN_FILENO, TT.buff, sizeof(TT.buff)-1);
+  if (size > 0) {
+    for (ptr = TT.buff; ptr < TT.buff+size; ptr++) {
+      if (isdigit(*ptr)) {
+        speed = encode(ptr);
+        if (speed > 0) cfsetspeed(&TT.termios,speed);
+        break;
+      }
+    } 
+  }
+  TT.termios.c_cc[VMIN] = vmin; //restore old value
+  if (tcsetattr(STDIN_FILENO, TCSANOW, &TT.termios) < 0)
+    perror_exit("tcsetattr");
+}
+
+// Just prompt for login name 
+void print_prompt(void)
+{
+  char *hostname;
+  struct utsname uts;
+
+  uname(&uts);
+  hostname = xstrdup(uts.nodename);
+  fputs(hostname, stdout);
+  fputs(" login: ", stdout);
+  fflush(NULL);
+  free(hostname);
+  hostname = NULL;
+}
+
+// Print /etc/isuue with taking care of each escape sequence
+void write_issue(char *file)
+{
+  char buff[20] = {0,};
+  struct utsname u;
+  uname(&u);
+  int size, fd = open(TT.issue_str, O_RDONLY);
+
+  if (fd < 0) return;
+  while ((size = readall(fd, buff, 1)) > 0) {
+    char *ch = buff;
+
+    if (*ch == '\\' || *ch == '%') {
+      if (readall(fd, buff, 1) <= 0) perror_exit("readall");
+      if (*ch == 's') fputs(u.sysname, stdout);
+      if (*ch == 'n'|| *ch == 'h') fputs(u.nodename, stdout);
+      if (*ch == 'r') fputs(u.release, stdout);
+      if (*ch == 'm') fputs(u.machine, stdout);
+      if (*ch == 'l') fputs(TT.tty_name, stdout);
+    } else xputc(*ch);
+  }
+}
+
+// Read login name and print prompt and Issue file. 
+static int read_login_name(void)
+{
+  tcflush(STDIN_FILENO, TCIFLUSH); // Flush pending speed switches
+  int i = 0;
+
+  while (1) { // Option -i will overide -f
+    if (!(toys.optflags & FLAG_i)) write_issue(TT.issue_str); 
+    print_prompt();
+    TT.buff[0] = getchar();
+    if (!TT.buff[0] && TT.sc > 1) return 0; // Switch speed
+    if (TT.buff[0] == '\n') continue;
+    if (TT.buff[0] != '\n')
+      if (!fgets(&TT.buff[1], HOSTNAME_SIZE-1, stdin)) _exit(1);
+    while (i < HOSTNAME_SIZE-1 && isgraph(TT.buff[i])) i++;
+    TT.buff[i] = 0;
+    break;
+  }
+  return 1;
+}
+
+// Put hostname entry in utmp file
+static void utmp_entry(void)
+{
+  struct utmp entry;
+  struct utmp *utp_ptr;
+  pid_t pid = getpid();
+  char *utmperr = "can't make utmp entry, host length greater than UT_HOSTSIZE(256)";
+
+  utmpname(_PATH_UTMP);
+  setutent(); // Starts from start
+  while ((utp_ptr = getutent())) 
+    if (utp_ptr->ut_pid == pid && utp_ptr->ut_type >= INIT_PROCESS) break;
+  if (!utp_ptr) { 
+    entry.ut_type = LOGIN_PROCESS;
+    entry.ut_pid = getpid();
+    xstrncpy(entry.ut_line, ttyname(STDIN_FILENO) + 
+        strlen("/dev/"), UT_LINESIZE);
+    time((time_t *)&entry.ut_time);
+    xstrncpy(entry.ut_user, "LOGIN", UT_NAMESIZE);
+    if (strlen(TT.host_str) > UT_HOSTSIZE) 
+      perror_msg(utmperr);
+    else xstrncpy(entry.ut_host, TT.host_str, UT_HOSTSIZE);
+    setutent();
+    pututline(&entry);
+    return;
+  }
+  xstrncpy(entry.ut_line, ttyname(STDIN_FILENO) + strlen("/dev/"), UT_LINESIZE);
+  xstrncpy(entry.ut_user, "LOGIN", UT_NAMESIZE);
+  if (strlen(TT.host_str) > UT_HOSTSIZE) 
+    perror_msg(utmperr);
+  else xstrncpy(entry.ut_host, TT.host_str, UT_HOSTSIZE);
+  time((time_t *)&entry.ut_time);
+  setutent();
+  pututline(&entry);
+}
+
+void getty_main(void)
+{
+  pid_t pid = getpid();
+  char *ptr[3] = {"/bin/login", NULL, NULL}; //2 NULLs so we can add username
+
+  if (!(toys.optflags & FLAG_f)) TT.issue_str = "/etc/issue";
+  if (toys.optflags & FLAG_l) ptr[0] = TT.login_str;
+  parse_arguments();
+  open_tty();
+  termios_init();
+  tcsetpgrp(STDIN_FILENO, pid);
+  if (toys.optflags & FLAG_H) utmp_entry();
+  if (toys.optflags & FLAG_I) 
+    writeall(STDOUT_FILENO,TT.init_str,strlen(TT.init_str));
+  if (toys.optflags & FLAG_m) sense_baud();
+  if (toys.optflags & FLAG_t) alarm(TT.timeout);
+  if (toys.optflags & FLAG_w) {
+    char ch;
+
+    while (readall(STDIN_FILENO, &ch, 1) != 1)  
+      if (ch == '\n' || ch == '\r') break;
+  }
+  if (!(toys.optflags & FLAG_n)) {
+    int index = 1; // 0th we already set.
+
+    while (1) {
+      int l = read_login_name();
+
+      if (l) break;
+      index = index % TT.sc;
+      cfsetspeed(&TT.termios, TT.speeds[index]); // Select from multiple speeds
+      //Necessary after cfsetspeed
+      if (tcsetattr(STDIN_FILENO, TCSANOW, &TT.termios) < 0) 
+        perror_exit("tcsetattr"); 
+    }
+    ptr[1]=TT.buff; //put the username in the login command line
+  }
+  xexec(ptr);
+}
diff --git a/toybox/toys/pending/groupadd.c b/toybox/toys/pending/groupadd.c
new file mode 100644
index 0000000..30468c9
--- /dev/null
+++ b/toybox/toys/pending/groupadd.c
@@ -0,0 +1,101 @@
+/* groupadd.c - create a new group
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/groupadd.html
+
+USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_GROUPADD(OLDTOY(addgroup, groupadd, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+
+config GROUPADD
+  bool "groupadd"
+  default n
+  help
+    usage: groupadd [-S] [-g GID] [USER] GROUP
+
+    Add a group or add a user to a group
+    
+      -g GID Group id
+      -S     Create a system group
+*/
+
+#define FOR_groupadd
+#include "toys.h"
+
+#define GROUP_PATH        "/etc/group"
+#define SECURE_GROUP_PATH "/etc/gshadow"
+
+GLOBALS(
+  long gid;
+)
+
+/* Add a new group to the system, if GID is given then that is validated
+ * to be free, else a free GID is choosen by self.
+ * SYSTEM IDs are considered in the range 100 ... 999
+ * update_group(), updates the entries in /etc/group, /etc/gshadow files
+ */
+static void new_group()
+{
+  char *entry = NULL;
+
+  if (toys.optflags & FLAG_g) {
+    if (TT.gid > INT_MAX) error_exit("gid should be less than  '%d' ", INT_MAX);
+    if (getgrgid(TT.gid)) error_exit("group '%ld' is in use", TT.gid);
+  } else {
+    if (toys.optflags & FLAG_S) TT.gid = CFG_TOYBOX_UID_SYS;
+    else TT.gid = CFG_TOYBOX_UID_USR;
+    //find unused gid
+    while (getgrgid(TT.gid)) TT.gid++;
+  }
+
+  entry = xmprintf("%s:%s:%d:", *toys.optargs, "x", TT.gid);
+  update_password(GROUP_PATH, *toys.optargs, entry);
+  free(entry);
+  entry = xmprintf("%s:%s::", *toys.optargs, "!");
+  update_password(SECURE_GROUP_PATH, *toys.optargs, entry);
+  free(entry);
+}
+
+void groupadd_main(void)
+{
+  struct group *grp = NULL;
+  char *entry = NULL;
+
+  if (toys.optflags && toys.optc == 2)
+    help_exit("options, user and group can't be together");
+
+  if (toys.optc == 2) {  //add user to group
+    //toys.optargs[0]- user, toys.optargs[1] - group
+    xgetpwnam(*toys.optargs);
+    if (!(grp = getgrnam(toys.optargs[1]))) 
+      error_exit("group '%s' does not exist", toys.optargs[1]);
+    if (!grp->gr_mem) entry = xmprintf("%s", *toys.optargs);
+    else {
+      int i;
+
+      for (i = 0; grp->gr_mem[i]; i++)
+        if (!strcmp(grp->gr_mem[i], *toys.optargs)) return;
+
+      entry = xstrdup("");
+      for (i=0; grp->gr_mem[i]; i++) {
+        entry = xrealloc(entry, strlen(entry) + strlen(grp->gr_mem[i]) + 2);
+        strcat(entry, grp->gr_mem[i]);
+        strcat(entry, ",");
+      }
+      entry = xrealloc(entry, strlen(entry) + strlen(*toys.optargs) + 1);
+      strcat(entry, *toys.optargs);
+    }
+    update_password(GROUP_PATH, grp->gr_name, entry);
+    update_password(SECURE_GROUP_PATH, grp->gr_name, entry);
+    free(entry);
+  } else {    //new group to be created
+    char *s = *toys.optargs;
+
+    /* investigate the group to be created */
+    if (getgrnam(s)) error_exit("'%s' in use", s);
+    if (s[strcspn(s, ":/\n")] || strlen(s) > LOGIN_NAME_MAX)
+      error_exit("bad name");
+    new_group();
+  }
+}
diff --git a/toybox/toys/pending/groupdel.c b/toybox/toys/pending/groupdel.c
new file mode 100644
index 0000000..483ac59
--- /dev/null
+++ b/toybox/toys/pending/groupdel.c
@@ -0,0 +1,61 @@
+/* groupdel.c - delete a group
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/groupdel.html
+
+USE_GROUPDEL(NEWTOY(groupdel, "<1>2", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_GROUPDEL(OLDTOY(delgroup, groupdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+
+config GROUPDEL
+  bool "groupdel"
+  default n
+  help
+    usage: groupdel [USER] GROUP
+
+    Delete a group or remove a user from a group
+*/
+
+#define FOR_groupdel
+#include "toys.h"
+
+void groupdel_main(void)
+{
+  struct group *grp = xgetgrnam(toys.optargs[toys.optc-1]);
+  char *entry = 0;
+
+  // delete user from group
+  if (toys.optc == 2) {
+    int i, len = 0, found = 0;
+    char *s;
+
+    xgetpwnam(*toys.optargs);
+    if (grp->gr_mem) for (i = 0; grp->gr_mem[i]; i++) {
+      if (!found && !strcmp(*toys.optargs, grp->gr_mem[i])) found++;
+      else len += strlen(grp->gr_mem[i]) + 1;
+    }
+    if (!found)
+      error_exit("user '%s' not in group '%s'", *toys.optargs, toys.optargs[1]);
+
+    entry = s = xmalloc(len);
+    for (i = 0; grp->gr_mem[i]; ) {
+      if (i) *(s++) = ',';
+      s = stpcpy(s, grp->gr_mem[i]);
+    }
+
+  // delete group
+  } else {
+    struct passwd *pw;
+
+    for (endpwent(); (pw = getpwent());)
+      if (pw->pw_gid == grp->gr_gid) break;
+
+    if (pw) error_exit("can't remove primary group of user '%s'", pw->pw_name);
+    if (CFG_TOYBOX_FREE) endpwent();
+  }
+
+  update_password("/etc/group", grp->gr_name, entry);
+  update_password("/etc/gshadow", grp->gr_name, entry);
+  if (CFG_TOYBOX_FREE) free(entry);
+}
diff --git a/toybox/toys/pending/host.c b/toybox/toys/pending/host.c
new file mode 100644
index 0000000..50de1d3
--- /dev/null
+++ b/toybox/toys/pending/host.c
@@ -0,0 +1,214 @@
+/* host.c - DNS lookup utility
+ *
+ * Copyright 2014 Rich Felker <dalias@aerifal.cx>
+ *
+ * No standard, but there's a version in bind9
+
+USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN))
+
+config HOST
+  bool "host"
+  default n
+  help
+    usage: host [-av] [-t TYPE] NAME [SERVER]
+
+    Perform DNS lookup on NAME, which can be a domain name to lookup,
+    or an ipv4 dotted or ipv6 colon seprated address to reverse lookup.
+    SERVER (if present) is the DNS server to use.
+
+    -a	no idea
+    -t	not a clue
+    -v	verbose
+*/
+
+#define FOR_host
+#include "toys.h"
+
+GLOBALS(
+  char *type_str;
+)
+
+#include <resolv.h>
+
+#define PL_IP 1
+#define PL_NAME 2
+#define PL_DATA 3
+#define PL_TEXT 4
+#define PL_SOA 5
+#define PL_MX 6
+#define PL_SRV 7
+
+static const struct rrt {
+  const char *name;
+  const char *msg;
+  int pl;
+  int af;
+} rrt[] = {
+  [1] = { "A", "has address", PL_IP, AF_INET },
+  [28] = { "AAAA", "has address", PL_IP, AF_INET6 },
+  [2] = { "NS", "name server", PL_NAME },
+  [5] = { "CNAME", "is a nickname for", PL_NAME },
+  [16] = { "TXT", "descriptive text", PL_TEXT },
+  [6] = { "SOA", "start of authority", PL_SOA },
+  [12] = { "PTR", "domain name pointer", PL_NAME },
+  [15] = { "MX", "mail is handled", PL_MX },
+  [33] = { "SRV", "mail is handled", PL_SRV },
+  [255] = { "*", 0, 0 },
+};
+
+static const char rct[16][32] = {
+  "Success",
+  "Format error",
+  "Server failure",
+  "Non-existant domain",
+  "Not implemented",
+  "Refused",
+};
+
+void host_main(void)
+{
+  int verbose=(toys.optflags & (FLAG_a|FLAG_v)), type,
+      i, j, ret, sec, count, rcode, qlen, alen, pllen = 0;
+  unsigned ttl, pri, v[5];
+  unsigned char qbuf[280], abuf[512], *p;
+  char *name, *nsname, rrname[256], plname[640], ptrbuf[64];
+  struct addrinfo *ai, iplit_hints = { .ai_flags = AI_NUMERICHOST };
+
+  name = *toys.optargs;
+  nsname = toys.optargs[1];
+
+  if (!TT.type_str && (toys.optflags & FLAG_a)) TT.type_str = "255";
+  if (!getaddrinfo(name, 0, &iplit_hints, &ai)) {
+    unsigned char *a;
+    static const char xdigits[] = "0123456789abcdef";
+
+    if (ai->ai_family == AF_INET) {
+      a = (void *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
+      snprintf(ptrbuf, sizeof(ptrbuf), "%d.%d.%d.%d.in-addr.arpa",
+        a[3], a[2], a[1], a[0]);
+    } else if (ai->ai_family == AF_INET6) {
+      a = (void *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
+      for (j=0, i=15; i>=0; i--) {
+        ptrbuf[j++] = xdigits[a[i]&15];
+        ptrbuf[j++] = '.';
+        ptrbuf[j++] = xdigits[a[i]>>4];
+        ptrbuf[j++] = '.';
+      }
+      strcpy(ptrbuf+j, "ip6.arpa");
+    }
+    name = ptrbuf;
+    if (!TT.type_str) TT.type_str="12";
+  } else if (!TT.type_str) TT.type_str="1";
+
+  if (TT.type_str[0]-'0' < 10u) type = atoi(TT.type_str);
+  else {
+    type = -1;
+    for (i=0; i < sizeof rrt / sizeof *rrt; i++) {
+      if (rrt[i].name && !strcasecmp(TT.type_str, rrt[i].name)) {
+        type = i;
+        break;
+      }
+    }
+    if (!strcasecmp(TT.type_str, "any")) type = 255;
+    if (type < 0) error_exit("Invalid query type: %s", TT.type_str);
+  }
+
+  qlen = res_mkquery(0, name, 1, type, 0, 0, 0, qbuf, sizeof qbuf);
+  if (qlen < 0) error_exit("Invalid query parameters: %s", name);
+
+  if (nsname) {
+    struct addrinfo ns_hints = { .ai_socktype = SOCK_DGRAM };
+
+    if ((ret = getaddrinfo(nsname, "53", &ns_hints, &ai)) < 0)
+      error_exit("Error looking up server name: %s", gai_strerror(ret));
+    int s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+    if (s < 0 || connect(s, ai->ai_addr, ai->ai_addrlen) < 0)
+      perror_exit("Socket error");
+    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &(struct timeval){ .tv_sec = 5 },
+      sizeof(struct timeval));
+    printf("Using domain server %s:\n", nsname);
+    send(s, qbuf, qlen, 0);
+    alen = recv(s, abuf, sizeof abuf, 0);
+  } else alen = res_send(qbuf, qlen, abuf, sizeof abuf);
+
+  if (alen < 12) error_exit("Host not found.");
+
+  rcode = abuf[3] & 15;
+
+  if (verbose) {
+    printf("rcode = %d (%s), ancount = %d\n",
+      rcode, rct[rcode], 256*abuf[6] + abuf[7]);
+    if (!(abuf[2] & 4)) printf("The following answer is not authoritative:\n");
+  }
+
+  if (rcode) error_exit("Host not found.");
+
+  p = abuf + 12;
+  for (sec=0; sec<4; sec++) {
+    count = 256*abuf[4+2*sec] + abuf[5+2*sec];
+    if (verbose && count>0 && sec>1) 
+      puts(sec==2 ? "For authoritative answers, see:"
+        : "Additional information:");
+
+    for (; count--; p += pllen) {
+      p += dn_expand(abuf, abuf+alen, p, rrname, sizeof(rrname));
+      type = (p[0]<<8) + p[1];
+      p += 4;
+      if (!sec) continue;
+      ttl = (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
+      p += 4;
+      pllen = (p[0]<<8) + p[1];
+      p += 2;
+
+      switch (type<sizeof(rrt)/sizeof(*rrt) ? rrt[type].pl : 0) {
+      case PL_IP:
+        inet_ntop(rrt[type].af, p, plname, sizeof plname);
+        break;
+      case PL_NAME:
+        dn_expand(abuf, abuf+alen, p, plname, sizeof plname);
+        break;
+      case PL_TEXT:
+        snprintf(plname, sizeof plname, "\"%.*s\"", pllen, p);
+        break;
+      case PL_SOA:
+        i = dn_expand(abuf, abuf+alen, p, plname, sizeof plname - 1);
+        strcat(plname, " ");
+        i += dn_expand(abuf, abuf+alen, p+i, plname+strlen(plname),
+          sizeof(plname)-strlen(plname));
+        for (j=0; j<5; j++)
+          v[j] = (p[i+4*j]<<24)+(p[1+i+4*j]<<16)+(p[2+i+4*j]<<8)+p[3+i+4*j];
+        snprintf(plname+strlen(plname), sizeof(plname)-strlen(plname),
+          "(\n\t\t%u\t;serial (version)\n"
+          "\t\t%u\t;refresh period\n"
+          "\t\t%u\t;retry interval\n"
+          "\t\t%u\t;expire time\n"
+          "\t\t%u\t;default ttl\n"
+          "\t\t)", v[0], v[1], v[2], v[3], v[4]);
+        break;
+      case PL_MX:
+        pri = (p[0]<<8)+p[1];
+        snprintf(plname, sizeof(plname), verbose ? "%d " : "(pri=%d) by ", pri);
+        dn_expand(abuf, abuf+alen, p+2, plname+strlen(plname),
+          sizeof plname - strlen(plname));
+        break;
+      case PL_SRV:
+        for (j=0; j<3; j++) v[j] = (p[2*j]<<8) + p[1+2*j];
+        snprintf(plname, sizeof(plname), "%u %u %u ", v[0], v[1], v[2]);
+        dn_expand(abuf, abuf+alen, p+6, plname+strlen(plname),
+          sizeof plname - strlen(plname));
+        break;
+      default:
+        printf("%s unsupported RR type %u\n", rrname, type);
+        continue;
+      }
+
+      if (verbose)
+        printf("%s\t%u\tIN %s\t%s\n", rrname, ttl, rrt[type].name, plname);
+      else if (rrt[type].msg)
+        printf("%s %s %s\n", rrname, rrt[type].msg, plname);
+    }
+    if (!verbose && sec==1) break;
+  }
+
+  toys.exitval = rcode;
+}
diff --git a/toybox/toys/pending/iconv.c b/toybox/toys/pending/iconv.c
new file mode 100644
index 0000000..77b8038
--- /dev/null
+++ b/toybox/toys/pending/iconv.c
@@ -0,0 +1,74 @@
+/* iconv.c - Convert character encoding
+ *
+ * Copyright 2014 Felix Janda <felix.janda@posteo.de>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/iconv.html
+
+USE_ICONV(NEWTOY(iconv, "cst:f:", TOYFLAG_USR|TOYFLAG_BIN))
+
+config ICONV
+  bool "iconv"
+  default n
+  depends on TOYBOX_ICONV
+  help
+    usage: iconv [-f FROM] [-t TO] [FILE...]
+
+    Convert character encoding of files.
+
+    -f  convert from (default utf8)
+    -t  convert to   (default utf8)
+*/
+
+#define FOR_iconv
+#include "toys.h"
+#include <iconv.h>
+
+GLOBALS(
+  char *from;
+  char *to;
+
+  void *ic;
+)
+
+static void do_iconv(int fd, char *name)
+{
+  char *outstart = toybuf+2048;
+  size_t inleft = 0;
+  int len = 1;
+
+  do {
+    size_t outleft = 2048;
+    char *in = toybuf+inleft, *out = outstart;
+
+    len = read(fd, in, 2048-inleft);
+
+    if (len < 0) {
+      perror_msg("read '%s'");
+      return;
+    }
+    inleft += len;
+
+    do {
+      if (iconv(TT.ic, &in, &inleft, &out, &outleft) == -1
+          && (errno == EILSEQ || (in == toybuf+inleft-len && errno == EINVAL)))
+      {
+        if (outleft) {
+          // Skip first byte of illegal sequence to avoid endless loops
+          *(out++) = *(in++);
+          inleft--;
+        }
+      }
+      xwrite(1, outstart, out-outstart);
+      // Top off input buffer
+      memmove(in, toybuf, inleft);
+    } while (len < 1 && inleft);
+  } while (len > 0);
+}
+
+void iconv_main(void)
+{
+  TT.ic = iconv_open(TT.to ? TT.to : "utf8", TT.from ? TT.from : "utf8");
+  if (TT.ic == (iconv_t)-1) error_exit("bad encoding");
+  loopfiles(toys.optargs, do_iconv);
+  if (CFG_TOYBOX_FREE) iconv_close(TT.ic);
+}
diff --git a/toybox/toys/pending/init.c b/toybox/toys/pending/init.c
new file mode 100644
index 0000000..64b6148
--- /dev/null
+++ b/toybox/toys/pending/init.c
@@ -0,0 +1,498 @@
+/* init.c - init program.
+ *
+ * Copyright 2012 Harvind Singh <harvindsingh1981@gmail.com>
+ * Copyright 2013 Kyungwan Han  <asura321@gmail.com>
+ *
+ * No Standard
+
+USE_INIT(NEWTOY(init, "", TOYFLAG_SBIN))
+
+config INIT
+  bool "init"
+  default n
+  help
+    usage: init
+
+    System V style init.
+
+    First program to run (as PID 1) when the system comes up, reading
+    /etc/inittab to determine actions.
+*/
+
+#include "toys.h"
+#include <sys/reboot.h>
+
+struct action_list_seed {
+  struct action_list_seed *next;
+  pid_t pid;
+  uint8_t action;
+  char *terminal_name;
+  char *command;
+} *action_list_pointer = NULL;
+int caught_signal;
+
+//INITTAB action defination
+#define SYSINIT     0x01
+#define WAIT        0x02
+#define ONCE        0x04
+#define RESPAWN     0x08
+#define ASKFIRST    0x10
+#define CTRLALTDEL  0x20
+#define SHUTDOWN    0x40
+#define RESTART     0x80
+
+static void initialize_console(void)
+{
+  int fd;
+  char *p = getenv("CONSOLE");
+
+  if (!p) p = getenv("console");
+  if (!p) {
+    fd = open("/dev/null", O_RDWR);
+    if (fd >= 0) {
+      while (fd < 2) fd = dup(fd);
+      while (fd > 2) close(fd--);
+    }
+  } else {
+    fd = open(p, O_RDWR | O_NONBLOCK | O_NOCTTY);
+    if (fd < 0) printf("Unable to open console %s\n",p);
+    else {
+      dup2(fd,0);
+      dup2(fd,1);
+      dup2(fd,2);
+    }
+  }
+
+  if (!getenv("TERM")) putenv("TERM=linux");
+}
+
+static void reset_term(int fd)
+{
+  struct termios terminal;
+ 
+  tcgetattr(fd, &terminal);
+  terminal.c_cc[VINTR] = 3;    //ctrl-c
+  terminal.c_cc[VQUIT] = 28;   /*ctrl-\*/
+  terminal.c_cc[VERASE] = 127; //ctrl-?
+  terminal.c_cc[VKILL] = 21;   //ctrl-u
+  terminal.c_cc[VEOF] = 4;     //ctrl-d
+  terminal.c_cc[VSTART] = 17;  //ctrl-q
+  terminal.c_cc[VSTOP] = 19;   //ctrl-s
+  terminal.c_cc[VSUSP] = 26;   //ctrl-z
+
+  terminal.c_line = 0;
+  terminal.c_cflag &= CRTSCTS|PARODD|PARENB|CSTOPB|CSIZE|CBAUDEX|CBAUD;
+  terminal.c_cflag |= CLOCAL|HUPCL|CREAD;
+
+  //enable start/stop input and output control + map CR to NL on input
+  terminal.c_iflag = IXON|IXOFF|ICRNL;
+
+  //Map NL to CR-NL on output
+  terminal.c_oflag = ONLCR|OPOST;
+  terminal.c_lflag = IEXTEN|ECHOKE|ECHOCTL|ECHOK|ECHOE|ECHO|ICANON|ISIG;
+  tcsetattr(fd, TCSANOW, &terminal);
+}
+
+static void add_new_action(uint8_t action,char *command,char *term)
+{
+  struct action_list_seed *x,**y;
+
+  y = &action_list_pointer;
+  x = *y;
+  while (x) {
+    if (!(strcmp(x->command, command)) && !(strcmp(x->terminal_name, term))) {
+      *y = x->next; //remove from the list
+      while(*y) y = &(*y)->next; //traverse through list till end
+      x->next = NULL;
+      break;
+    }
+    y = &(x)->next;
+    x = *y;
+  }
+
+  //create a new node
+  if (!x) {
+    x = xzalloc(sizeof(*x));
+    x->command = xstrdup(command);
+    x->terminal_name = xstrdup(term);
+  }
+  x->action = action;
+  *y = x;
+}
+
+static void inittab_parsing(void)
+{
+  int i, fd, line_number = 0, token_count = 0;
+  char *p, *q, *extracted_token, *tty_name = NULL, *command = NULL, *tmp;
+  uint8_t action = 0;
+  char *act_name = "sysinit\0wait\0once\0respawn\0askfirst\0ctrlaltdel\0"
+                    "shutdown\0restart\0";
+
+  fd = open("/etc/inittab", O_RDONLY);
+  if (fd < 0) {
+    error_msg("Unable to open /etc/inittab. Using Default inittab");
+    add_new_action(SYSINIT, "/etc/init.d/rcS", "");
+    add_new_action(RESPAWN, "/sbin/getty -n -l /bin/sh -L 115200 tty1 vt100", "");
+  } else {
+    while((q = p = get_line(fd))) { //read single line from /etc/inittab
+      char *x;
+
+      if ((x = strchr(p, '#'))) *x = '\0';
+      line_number++;
+      token_count = 0;
+      action = 0;
+      tty_name = command = NULL;
+
+      while ((extracted_token = strsep(&p,":"))) {
+        token_count++;
+        switch (token_count) {
+          case 1:
+            if (*extracted_token) {
+              if (!strncmp(extracted_token, "/dev/", 5))
+                tty_name = xmprintf("%s",extracted_token);
+              else tty_name = xmprintf("/dev/%s",extracted_token);
+            } else tty_name = xstrdup("");
+            break;
+          case 2:
+            break;
+          case 3:
+            for (tmp = act_name, i = 0; *tmp; i++, tmp += strlen(tmp) +1) {
+              if (!strcmp(tmp, extracted_token)) {
+                action = 1 << i;
+                break;
+              }
+            }
+            if (!*tmp) error_msg("Invalid action at line number %d ---- ignoring",line_number);
+            break;
+          case 4:
+            command = xstrdup(extracted_token);
+            break;
+          default:
+            error_msg("Bad inittab entry at line %d", line_number);
+            break;
+        }
+      }  //while token
+
+      if (q) free(q);
+      if (token_count != 4) {
+        free(tty_name);
+        free(command);
+        continue;
+      }
+      if (action) add_new_action(action, command, tty_name);
+      free(tty_name);
+      free(command);
+    } //while line
+
+    close(fd);
+  }
+}
+
+static void run_command(char *command)
+{
+  char *final_command[128];
+  int hyphen = (command[0]=='-');
+
+  command = command + hyphen;
+  if (!strpbrk(command, "?<>'\";[]{}\\|=()*&^$!`~")) {
+    char *next_command;
+    char *extracted_command;
+    int x = 0;
+
+    next_command = strncpy(toybuf, command - hyphen, sizeof(toybuf));
+    next_command[sizeof(toybuf) - 1] = toybuf[sizeof(toybuf) - 1 ] = '\0';
+    command = next_command + hyphen;
+    while ((extracted_command = strsep(&next_command," \t"))) {
+      if (*extracted_command) {
+        final_command[x] = extracted_command;
+        x++;
+      }
+    }
+    final_command[x] = NULL;
+  } else {
+    snprintf(toybuf, sizeof(toybuf), "exec %s", command);
+    command = "-/bin/sh"+1;
+    final_command[0] = ("-/bin/sh"+!hyphen);
+    final_command[1] = "-c";
+    final_command[2] = toybuf;
+    final_command[3] = NULL;
+  }
+  if (hyphen) ioctl(0, TIOCSCTTY, 0);
+  execvp(command, final_command);
+  error_msg("unable to run %s",command);
+}
+
+//runs all same type of actions
+static pid_t final_run(struct action_list_seed *x)
+{
+  pid_t pid;
+  int fd;
+  sigset_t signal_set;
+
+  sigfillset(&signal_set);
+  sigprocmask(SIG_BLOCK, &signal_set, NULL);
+  if (x->action & ASKFIRST) pid = fork();
+  else pid = vfork();
+
+  if (pid > 0) {
+    //parent process or error
+    //unblock the signals
+    sigfillset(&signal_set);
+    sigprocmask(SIG_UNBLOCK, &signal_set, NULL);
+
+    return pid;      
+  } else if (pid < 0) {
+    perror_msg("fork fail");
+    sleep(1);
+    return 0;
+  }
+
+  //new born child process
+  sigset_t signal_set_c;
+  sigfillset(&signal_set_c);
+  sigprocmask(SIG_UNBLOCK, &signal_set_c, NULL);
+  setsid(); //new session
+
+  if (x->terminal_name[0]) {
+    close(0);
+    fd = open(x->terminal_name, (O_RDWR|O_NONBLOCK),0600);
+    if (fd != 0) {
+      error_msg("Unable to open %s,%s\n", x->terminal_name, strerror(errno));
+      _exit(EXIT_FAILURE);
+    } else {
+      dup2(0, 1);
+      dup2(0, 2);
+    }
+  }
+  reset_term(0);
+  run_command(x->command);
+  _exit(-1);
+}
+
+static struct action_list_seed* mark_as_terminated_process(pid_t pid)
+{
+  struct action_list_seed *x;
+
+  if (pid > 0) {
+    for (x = action_list_pointer; x; x = x->next) {
+      if (x->pid == pid) {
+        x->pid = 0;
+        return x;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+static void waitforpid(pid_t pid)
+{
+  if (pid <= 0) return;
+
+  for(;;) {
+    pid_t y = wait(NULL);
+    mark_as_terminated_process(y);
+    if (kill(y, 0)) break;
+  }
+}
+
+static void run_action_from_list(int action)
+{
+  pid_t pid;
+  struct action_list_seed *x = action_list_pointer;
+
+  for (; x; x = x->next) {
+    if (!(x->action & action)) continue;
+    if (x->action & (SHUTDOWN|ONCE|SYSINIT|CTRLALTDEL|WAIT)) {
+      pid = final_run(x);
+      if (!pid) return;
+      if (x->action & (SHUTDOWN|SYSINIT|CTRLALTDEL|WAIT)) waitforpid(pid);
+    }
+    if (x->action & (ASKFIRST|RESPAWN))
+      if (!(x->pid)) x->pid = final_run(x);
+  }
+ }
+
+static void set_default(void)
+{
+  sigset_t signal_set_c;
+
+  sigatexit(SIG_DFL);
+  sigfillset(&signal_set_c);
+  sigprocmask(SIG_UNBLOCK,&signal_set_c, NULL);
+
+  run_action_from_list(SHUTDOWN);
+  error_msg("The system is going down NOW!");
+  kill(-1, SIGTERM);
+  error_msg("Sent SIGTERM to all processes");
+  sync();
+  sleep(1);
+  kill(-1,SIGKILL);
+  sync();
+}
+
+static void halt_poweroff_reboot_handler(int sig_no)
+{
+  unsigned int reboot_magic_no = 0;
+  pid_t pid;
+
+  set_default();
+
+  switch (sig_no) {
+    case SIGUSR1:
+      error_msg("Requesting system halt");
+      reboot_magic_no=RB_HALT_SYSTEM;
+      break;
+    case SIGUSR2:
+      error_msg("Requesting system poweroff");
+      reboot_magic_no=RB_POWER_OFF;
+      break;
+    case SIGTERM:  
+      error_msg("Requesting system reboot");
+      reboot_magic_no=RB_AUTOBOOT;
+      break;
+    default:
+      break;
+  }
+
+  sleep(1);
+  pid = vfork();
+
+  if (pid == 0) {
+    reboot(reboot_magic_no);
+    _exit(EXIT_SUCCESS);
+  }
+
+  while(1) sleep(1);
+}
+
+static void restart_init_handler(int sig_no)
+{
+  struct action_list_seed *x;
+  pid_t pid;
+  int fd;
+
+  for (x = action_list_pointer; x; x = x->next) {
+    if (!(x->action & RESTART)) continue;
+
+    set_default();
+
+    if (x->terminal_name[0]) {
+      close(0);
+      fd = open(x->terminal_name, (O_RDWR|O_NONBLOCK),0600);
+
+      if (fd != 0) {
+        error_msg("Unable to open %s,%s\n", x->terminal_name, strerror(errno));
+        sleep(1);
+        pid = vfork();
+
+        if (pid == 0) {
+          reboot(RB_HALT_SYSTEM);
+          _exit(EXIT_SUCCESS);
+        }
+
+        while(1) sleep(1);
+      } else {
+        dup2(0, 1);
+        dup2(0, 2);
+        reset_term(0);
+        run_command(x->command);
+      }
+    }
+  }
+}
+
+static void catch_signal(int sig_no)
+{
+  caught_signal = sig_no;
+  error_msg("signal seen");
+}
+
+static void pause_handler(int sig_no)
+{
+  int signal_backup,errno_backup;
+  pid_t pid;
+
+  errno_backup = errno;
+  signal_backup = caught_signal;
+  xsignal(SIGCONT, catch_signal);
+
+  while(1) {
+    if (caught_signal == SIGCONT) break;
+    do pid = waitpid(-1,NULL,WNOHANG); while((pid==-1) && (errno=EINTR));
+    mark_as_terminated_process(pid);
+    sleep(1);
+  }
+
+  signal(SIGCONT, SIG_DFL);
+  errno = errno_backup;
+  caught_signal = signal_backup;
+}
+
+static int check_if_pending_signals(void)
+{
+  int signal_caught = 0;
+
+  while(1) {
+    int sig = caught_signal;
+    if (!sig) return signal_caught;
+    caught_signal = 0;
+    signal_caught = 1;
+    if (sig == SIGINT) run_action_from_list(CTRLALTDEL);
+  }
+}
+
+void init_main(void)
+{
+  struct sigaction sig_act;
+
+  if (getpid() != 1) error_exit("Already running"); 
+  printf("Started init\n"); 
+  initialize_console();
+  reset_term(0);
+
+  if (chdir("/")) perror_exit("Can't cd to /");
+  setsid();
+
+  putenv("HOME=/");
+  putenv("PATH=/sbin:/usr/sbin:/bin:/usr/bin");
+  putenv("SHELL=/bin/sh");
+  putenv("USER=root");
+
+  inittab_parsing();  
+  xsignal(SIGUSR1, halt_poweroff_reboot_handler);//halt
+  xsignal(SIGUSR2, halt_poweroff_reboot_handler);//poweroff
+  xsignal(SIGTERM, halt_poweroff_reboot_handler);//reboot
+  xsignal(SIGQUIT, restart_init_handler);//restart init
+  memset(&sig_act, 0, sizeof(sig_act));
+  sigfillset(&sig_act.sa_mask);
+  sigdelset(&sig_act.sa_mask, SIGCONT);
+  sig_act.sa_handler = pause_handler;
+  sigaction(SIGTSTP, &sig_act, NULL);
+  memset(&sig_act, 0, sizeof(sig_act));
+  sig_act.sa_handler = catch_signal;
+  sigaction(SIGINT, &sig_act, NULL);  
+  sigaction(SIGHUP, &sig_act, NULL);  
+  run_action_from_list(SYSINIT);
+  check_if_pending_signals();
+  run_action_from_list(WAIT);
+  check_if_pending_signals();
+  run_action_from_list(ONCE);
+  while (1) {
+    int suspected_WNOHANG = check_if_pending_signals();
+
+    run_action_from_list(RESPAWN | ASKFIRST);
+    suspected_WNOHANG = suspected_WNOHANG|check_if_pending_signals();
+    sleep(1);//let cpu breath
+    suspected_WNOHANG = suspected_WNOHANG|check_if_pending_signals();
+    if (suspected_WNOHANG) suspected_WNOHANG=WNOHANG;
+
+    while(1) {
+      pid_t pid = waitpid(-1, NULL, suspected_WNOHANG);
+
+      if (pid <= 0) break;
+      mark_as_terminated_process(pid);
+      suspected_WNOHANG = WNOHANG;
+    }
+  }
+}
diff --git a/toybox/toys/pending/ip.c b/toybox/toys/pending/ip.c
new file mode 100644
index 0000000..90f7330
--- /dev/null
+++ b/toybox/toys/pending/ip.c
@@ -0,0 +1,2795 @@
+/* ip.c - Show / manipulate routing, devices, policy routing and tunnels.
+ *
+ * Copyright 2014 Sameer Prakash Pradhan <sameer.p.pradhan@gmail.com>
+ * Copyright 2014 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2014 Rajni Kant <rajnikant12345@gmail.com>
+ * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
+ *
+ * No Standard.
+ *
+USE_IP(NEWTOY(ip, NULL, TOYFLAG_SBIN))
+USE_IP(OLDTOY(ipaddr, ip, TOYFLAG_SBIN))
+USE_IP(OLDTOY(iplink, ip, TOYFLAG_SBIN))
+USE_IP(OLDTOY(iproute, ip, TOYFLAG_SBIN))
+USE_IP(OLDTOY(iprule, ip, TOYFLAG_SBIN))
+USE_IP(OLDTOY(iptunnel, ip, TOYFLAG_SBIN))
+
+config IP
+  bool "ip"
+  default n
+  help
+    usage: ip [ OPTIONS ] OBJECT { COMMAND }
+
+    Show / manipulate routing, devices, policy routing and tunnels.
+
+    where OBJECT := {address | link | route | rule | tunnel}
+    OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }
+*/
+#define FOR_ip
+#include "toys.h"
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_ether.h>
+#include <linux/if_addr.h>
+#include <net/if_arp.h>
+#include <ifaddrs.h>
+#include <fnmatch.h>
+#include <netinet/ip.h>
+#include <linux/if_tunnel.h>
+
+GLOBALS(
+  char stats, singleline, flush, *filter_dev, gbuf[8192];
+  int sockfd, connected, from_ok, route_cmd;
+  int8_t addressfamily, is_addr;
+)
+
+struct arglist {
+  char *name;
+  int idx;
+};
+
+static struct 
+{
+  int ifindex, scope, scopemask, up, to;
+  char *label, *addr;
+} addrinfo;
+
+struct linkdata  {
+  struct linkdata *next, *prev;
+  int flags, iface_idx, mtu, txqueuelen, parent,iface_type;
+  char qdiscpline[IFNAMSIZ+1], state[IFNAMSIZ+1], type[IFNAMSIZ+1],
+       iface[IFNAMSIZ+1], laddr[64], bcast[64];
+  struct  rtnl_link_stats rt_stat;
+}*linfo;
+
+typedef int (*cmdobj)(char **argv);
+
+#define MESG_LEN 8192
+
+// For "/etc/iproute2/RPDB_tables"
+enum {
+  RPDB_rtdsfield = 1,
+  RPDB_rtprotos = 2,
+  RPDB_rtrealms = 3,
+  RPDB_rtscopes = 4,
+  RPDB_rttables = 5
+};
+
+#define RPDB_ENTRIES 256
+static int8_t rttable_init;
+static int8_t rtprotos_init;
+static int8_t rtdsfield_init;
+static int8_t rtscope_init;
+static int8_t rtrealms_init;
+
+static struct arglist *rt_dsfield[RPDB_ENTRIES];
+static struct arglist *rt_protos[RPDB_ENTRIES];
+static struct arglist *rt_tables[RPDB_ENTRIES];
+static struct arglist *rt_realms[RPDB_ENTRIES];
+static struct arglist *rt_scope[RPDB_ENTRIES];
+
+static struct arglist rtmtypes[] = { {"none", RTN_UNSPEC},
+  {"unicast", RTN_UNICAST}, {"local", RTN_LOCAL},
+  {"broadcast", RTN_BROADCAST}, {"anycast", RTN_ANYCAST},
+  {"multicast", RTN_MULTICAST}, {"blackhole", RTN_BLACKHOLE},
+  {"unreachable", RTN_UNREACHABLE}, {"prohibit", RTN_PROHIBIT},
+  {"throw", RTN_THROW}, {"nat", RTN_NAT},
+  {"xresolve", RTN_XRESOLVE}, {NULL, -1}
+};
+
+static int filter_nlmesg(int (*fun)(struct nlmsghdr *mhdr, char **), char **);
+static int  ipaddr_print(struct linkdata *, int flg);
+
+
+// ===========================================================================
+// Common Code for IP Options (like: addr, link, route etc.)
+// ===========================================================================
+static int substring_to_idx(char *str, struct arglist *list)
+{
+  struct arglist *alist;
+  int len;
+
+  if (!str) return -1;
+  len = strlen(str);
+
+  for (alist = list; alist->name; alist++)
+    if (!memcmp(str, alist->name, len)) return alist->idx;
+  return -1;
+}
+
+static int string_to_idx(char *str, struct arglist *list)
+{
+  struct arglist *alist;
+
+  if (!str) return -1;
+  for (alist = list; alist->name; alist++)
+    if (!strcmp(str, alist->name)) return alist->idx;
+  return -1;
+}
+
+static char *idx_to_string(int idx, struct arglist *list)
+{
+  struct arglist *alist;
+
+  if (idx < 0) return NULL;
+  for (alist = list; alist->name; alist++)
+    if (idx == alist->idx) return alist->name;
+  return NULL;
+}
+
+static void send_nlmesg(int type, int flags, int family,
+    void *buf, int blen)
+{
+  struct {
+    struct nlmsghdr nlh;
+    struct rtgenmsg g;
+  } req;
+
+  if (!buf) {
+    memset(&req, 0, sizeof(req));
+    req.nlh.nlmsg_len = sizeof(req);
+    req.nlh.nlmsg_type = type;
+    req.nlh.nlmsg_flags = flags;
+    req.g.rtgen_family = family;
+    buf = &req;
+    blen = sizeof(req);
+  }
+  if (send(TT.sockfd , (void*)buf, blen, 0) < 0)
+    perror_exit("Unable to send data on socket.");
+}
+
+// Parse /etc/iproute2/RPDB_tables and prepare list.
+static void parseRPDB(char *fname, struct arglist **list, int32_t size)
+{
+  char *line;
+  int fd = open(fname, O_RDONLY);
+
+  if (fd < 0) return;
+  for (; (line = get_line(fd)); free(line)) {
+    char *ptr = line;
+    int32_t idx;
+
+    while (*ptr == ' ' || *ptr == '\t') ptr++;
+    if (*ptr == 0 || *ptr == '#' || *ptr == '\n') continue;
+    if ((sscanf(ptr, "0x%x %s\n", &idx, toybuf) != 2) &&
+        (sscanf(ptr, "0x%x %s #", &idx, toybuf) != 2) &&
+        (sscanf(ptr, "%d %s\n", &idx, toybuf) != 2) &&
+        (sscanf(ptr, "%d %s #", &idx, toybuf) != 2)) {
+      error_msg("Corrupted '%s' file", fname);
+      xclose(fd);
+      free(line);
+      return;
+    }
+    if (idx >= 0 && idx < size) {
+      int index = idx & (size-1);
+      if (list[index]) free(list[index]->name);
+      else list[index] = xzalloc(sizeof(struct arglist));
+      list[index]->idx = idx;
+      list[index]->name = xstrdup(toybuf);
+    }
+  }
+  xclose(fd);
+}
+
+static void free_alist(struct arglist **list)
+{
+  int i;
+  for (i = 0;i<RPDB_ENTRIES;i++) {
+    if (list[i]) {
+      free(list[i]->name);
+      free(list[i]);
+    }
+  }
+}
+
+static void init_arglist(struct arglist **list,int value, char* name)
+{
+  if (!list[value]) list[value] =  xzalloc(sizeof(struct arglist));
+  list[value]->idx = value;
+  list[value]->name = xstrdup(name);
+}
+
+static struct arglist **getlist(u_int8_t whichDB)
+{
+  struct arglist **alist;
+
+  switch (whichDB) {
+    case RPDB_rtdsfield:
+      alist = rt_dsfield;
+      if (!rtdsfield_init) {
+        rtdsfield_init = 1;
+        parseRPDB("/etc/iproute2/rt_dsfield", alist, ARRAY_LEN(rt_dsfield));
+      }
+      break;
+    case RPDB_rtprotos:
+      alist = rt_protos;
+      if (!rttable_init) {
+        rtprotos_init = 1;
+        init_arglist(rt_protos,0,"none");
+        init_arglist(rt_protos,1,"redirect");
+        init_arglist(rt_protos,2,"kernel");
+        init_arglist(rt_protos,3,"boot");
+        init_arglist(rt_protos,4,"static");
+        init_arglist(rt_protos,8,"gated");
+        init_arglist(rt_protos,9,"ra");
+        init_arglist(rt_protos,10,"mrt");
+        init_arglist(rt_protos,11,"zebra");
+        init_arglist(rt_protos,12,"bird");
+        parseRPDB("/etc/iproute2/rt_protos", alist, ARRAY_LEN(rt_protos));
+      }
+      break;
+    case RPDB_rtrealms:
+      alist = rt_realms;
+      if (!rtrealms_init) {
+        rtrealms_init = 1;
+        init_arglist(rt_realms,0,"unspec");
+        parseRPDB("/etc/iproute2/rt_realms", alist, ARRAY_LEN(rt_realms));
+      }
+      break;
+    case RPDB_rtscopes:
+      alist = rt_scope;
+      if (!rtscope_init) {
+        rtscope_init = 1;
+        init_arglist(rt_scope,0,"global");
+        init_arglist(rt_scope,200,"site");
+        init_arglist(rt_scope,253,"link");
+        init_arglist(rt_scope,254,"host");
+        init_arglist(rt_scope,255,"nowhere");
+        parseRPDB("/etc/iproute2/rt_scopes", alist, ARRAY_LEN(rt_scope));
+      }
+      break;
+    case RPDB_rttables:
+      alist = rt_tables;
+      if (!rttable_init) {
+        rttable_init = 1;
+        init_arglist(rt_tables,RT_TABLE_DEFAULT,"default");
+        init_arglist(rt_tables,RT_TABLE_MAIN,"main");
+        init_arglist(rt_tables,RT_TABLE_LOCAL,"local");
+        parseRPDB("/etc/iproute2/rt_tables", alist, ARRAY_LEN(rt_tables));
+      }
+      break;
+    default: 
+      error_exit("wrong database");
+      break; // Unreachable code.
+  }
+  return alist;
+}
+
+/*
+ * Parse RPBD tables (if not parsed already).
+ * return RPDB table name as per idx.
+ */
+static char *namefromRPDB(int idx, u_int8_t whichDB)
+{
+  struct arglist **alist;
+
+  if (idx < 0 || idx >= RPDB_ENTRIES) {
+    snprintf(toybuf, RPDB_ENTRIES, "%u", idx);
+    return toybuf;
+  }
+
+  alist = getlist(whichDB);
+
+  if (alist[idx] && alist[idx]->name) return alist[idx]->name;
+
+  if (whichDB == RPDB_rtdsfield) snprintf(toybuf, RPDB_ENTRIES, "0x%02x", idx);
+  else snprintf(toybuf, RPDB_ENTRIES, "%u", idx);
+
+  return toybuf;
+}
+
+static int idxfromRPDB(char *name, u_int8_t whichDB)
+{
+  struct arglist **alist;
+  long i = 0;
+  char *ptr = NULL;
+
+  for (alist = getlist(whichDB); i < RPDB_ENTRIES; i++) {
+    if (!alist[i] || !alist[i]->name) continue;
+    if (!strcmp(alist[i]->name, name)) return i;
+  }
+  i = strtol(name, &ptr, 0);
+  if (errno || (ptr && *ptr) || i < 0 || i > 255)
+    return -1;
+  return i;
+}
+
+static char *rtmtype_idx2str(u_int8_t idx)
+{
+  char *name = idx_to_string(idx, rtmtypes);
+
+  if (!name) snprintf(toybuf, RPDB_ENTRIES, "%u", idx);
+  else snprintf(toybuf, sizeof(toybuf), "%s", name);
+  return toybuf;
+}
+
+static int rtmtype_str2idx(char *name)
+{
+  int idx = string_to_idx(name, rtmtypes);
+
+  if (idx < 0) return atolx_range(name, 0, 255);
+  return idx;
+}
+
+/*
+ * Used to get the prefix value in binary form.
+ * For IPv4: non-standard parsing used; as 10.10 will be treated as 10.10.0.0
+ * unlike inet_aton which is 10.0.0.10
+ */
+static int get_prefix(uint32_t *addr, uint8_t *af, char *name, int family)
+{
+  if (family == AF_PACKET) error_exit("'%s' may be inet prefix", name);
+  if (!memcmp(name, "default", strlen(name))
+      || !memcmp(name, "all", strlen(name))
+      || !memcmp(name, "any", strlen(name))) {
+    *af = family;
+    return 0;
+  }
+  if (strchr(name, ':')) {
+    *af = AF_INET6;
+    if (family != AF_UNSPEC && family != AF_INET6) return 1;
+    if (inet_pton(AF_INET6, name, (void *)addr) != 1) 
+      return 1;
+  } else { // for IPv4.
+    char *ptr = name;
+    uint8_t count = 0;
+
+    *af = AF_INET;
+    if (family != AF_UNSPEC && family != AF_INET) return 1;
+    while (*ptr) {
+      int val, len = 0;
+
+      if (*ptr == '.') ptr++;
+      sscanf(ptr, "%d%n", &val, &len);
+      if (!len || len > 3 || val < 0 || val > 255 || count > 3) return 1;
+      ptr += len;
+      ((uint8_t*)addr)[count++] = val;
+    }
+  }
+  return 0;
+}
+
+/*
+ * Used to calculate netmask, which can be in the form of
+ * either 255.255.255.0 or 24 or default or any or all strings.
+ */
+static int get_nmask_prefix(uint32_t *netmask, uint8_t af,
+    char *name, uint8_t family)
+{
+  char *ptr;
+  uint32_t naddr[4] = {0,};
+  uint64_t plen;
+  uint8_t naf = AF_UNSPEC;
+
+  *netmask = (af == AF_INET6) ? 128 : 32; // set default netmask
+  plen = strtoul(name, &ptr, 0);
+
+  if (!ptr || ptr == name || *ptr || !plen || plen > *netmask) {
+    if (get_prefix(naddr, &naf, name, family)) return -1;
+    if (naf == AF_INET) {
+      uint32_t mask = htonl(*naddr), host = ~mask;
+      if (host & (host + 1)) return -1;
+      for (plen = 0; mask; mask <<= 1) ++plen;
+      if (plen > 32) return -1;
+    }
+  }
+  *netmask = plen;
+  return 0;
+}
+
+/*
+ * Parse prefix, which will be in form of
+ * either default or default/default or default/24 or default/255.255.255.0
+ * or 10.20.30.40 or 10.20.30.40/default or 10.20.30.40/24
+ * or 10.20.30.40/255.255.255.0
+ */
+static void parse_prefix(uint32_t *addr, uint32_t *netmask, uint8_t *len,
+    char *name, int family)
+{
+  uint8_t af = AF_UNSPEC;
+  char *slash = strchr(name, '/');
+
+  if (slash) *slash = 0;
+  if (get_prefix(addr, &af, name, family)) error_exit("Invalid prefix");
+
+  if (slash) { // grab netmask.
+    if (get_nmask_prefix(netmask, af, slash+1, family))
+      error_exit("Invalid prefix");
+    *slash ='/';
+  }
+  else if (af == AF_INET && *addr) *netmask = 32;
+  else if (af == AF_INET6 && (*addr || *(addr+3))) *netmask = 128;
+
+  if (!*addr && !slash && !af) *len = 0;
+  else *len = (af == AF_INET6) ? 16 : 4;
+}
+
+static void add_string_to_rtattr(struct nlmsghdr *n, int maxlen,
+    int type, void *data, int alen)
+{
+  int len = RTA_LENGTH(alen);
+  struct rtattr *rta;
+
+  if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) return;
+  rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
+  rta->rta_type = type;
+  rta->rta_len = len;
+  memcpy(RTA_DATA(rta), data, alen);
+  n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
+}
+
+
+
+// ===========================================================================
+// Code for ip link.
+// ===========================================================================
+#ifndef NLMSG_TAIL
+#define NLMSG_TAIL(nmsg) \
+  ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+#endif
+
+static uint32_t get_ifaceindex(char *name, int ext)
+{
+  struct if_nameindex *if_ni, *i;
+  int index = -1;
+
+  if_ni = if_nameindex();
+  if (!if_ni) perror_exit("if_nameindex");
+
+  for (i = if_ni; i->if_index && i->if_name; i++)
+    if (!strcmp(name, i->if_name)) { 
+      index = i->if_index; 
+      break;
+    }
+  if_freenameindex(if_ni);
+  if (index == -1 && ext) perror_exit("can't find device '%s'", name);
+  return index;
+}
+
+static void fill_hwaddr(char *arg, int len, unsigned char *address)
+{
+  int count = 0, val, length;
+
+  while (count < len) {
+    val = length = 0;
+    if (!arg) error_exit("bad hw-addr '%s'", "");
+    if (*arg == ':') arg++, count++;
+    sscanf(arg, "%2x%n", &val, &length);
+    if (!length || length > 2)
+      error_exit("bad hw-addr '%s'", arg);
+    arg += length;
+    count += length;
+    *address++ = val;
+  }
+}
+
+// Multimach = 1, single match = 0
+static char *get_flag_string(struct arglist *aflags, int flags, int ismulti)
+{
+  struct arglist *p = aflags;
+  char *out = NULL, *tmp = NULL;
+
+  for (; p->name; p++) {
+    int test = (ismulti ? p->idx & flags : 0) || p->idx == flags;
+    if (test) { // flags can be zero
+      tmp = out ? xmprintf("%s,%s", out, p->name) : xmprintf("%s", p->name);
+      if (out) free(out);
+      out = tmp;
+    }
+  }
+  return out;
+}
+
+static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
+{
+  struct arglist vlan_optlist[] = {{"id", 0}, {"protocol", 1}, 
+    {"reorder_hdr", 2}, {"gvrp", 3}, {NULL,-1}};
+  struct arglist vlan_protolist[] = {{"802.1q", 0}, {"802.1ad", 1}, {NULL,-1}};
+  struct arglist on_off[] = { {"on", 0}, {"off", 1}, {NULL,-1}};
+  int idx;
+  struct ifla_vlan_flags flags;
+
+  memset(&flags, 0, sizeof(flags));
+  for (; *argv; argv++) {
+    int param, proto;
+
+    if ((idx = substring_to_idx(*argv++, vlan_optlist)) == -1) help_exit(0);
+    switch (idx) {
+      case 0: // ARG_id
+        if (!*argv) help_exit(0);
+        param = atolx(*argv);
+        add_string_to_rtattr(n, size, IFLA_VLAN_ID, &param, sizeof(param));
+        break;
+      case 1: // ARG_protocol
+        if (!*argv) error_exit("Invalid vlan id.");
+        if ((idx = substring_to_idx(*argv, vlan_protolist)) == -1) help_exit(0);
+        if (!idx) proto = ETH_P_8021Q; // PROTO_8021Q - 0
+        else if (idx == 1) proto = 0x88A8; // ETH Protocol - 8021AD
+        // IFLA VLAN PROTOCOL - 5
+        add_string_to_rtattr(n, size, 5, &proto, sizeof(proto));
+        break;
+      case 2: // ARG_reorder_hdr
+      case 3: // ARG_gvrp
+        if ((param = substring_to_idx(*argv, on_off)) == -1) help_exit(0);
+
+        flags.mask |= (idx -1); // VLAN FLAG REORDER Header              
+        flags.flags &= ~(idx -1); // VLAN FLAG REORDER Header            
+        if (!param) flags.flags |= (idx -1); // VLAN FLAG REORDER Header
+        break;
+    }
+  }
+  if (flags.mask) 
+    add_string_to_rtattr(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
+}
+
+static int linkupdate(char **argv)
+{
+  struct {
+    struct nlmsghdr mhdr;
+    struct ifinfomsg info;
+    char buf[1024];
+  } request;  
+  char *name, *dev, *type, *link, *addr;
+  struct rtattr *attr = NULL;
+  int len = 0, add = (*argv[-1] == 'a') ? 1 : 0;
+
+  name = dev = type = link = addr = NULL;
+  for (; *argv; argv++) {
+    struct arglist objectlist[] = { {"type", 0}, {"name", 1}, {"link", 2}, 
+      {"address", 3}, {NULL,-1}};
+    uint8_t idx = substring_to_idx(*argv, objectlist);
+
+    if (!idx) {
+      type = *++argv;
+      break;
+    }
+    else if (idx == 1) dev = name = *++argv;
+    else if (idx == 2) link = *++argv;
+    else if (idx == 3) addr = *++argv;
+    else if (!dev) name = dev = *argv;
+  }
+
+  if (!name && !add)
+    error_exit("Not enough information: \"dev\" argument is required.\n");
+  else if (!type  && add)
+    error_exit("Not enough information: \"type\" argument is required.\n");
+
+  memset(&request, 0, sizeof(request));
+  request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+  request.mhdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+  if (add) {
+    request.mhdr.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
+    request.mhdr.nlmsg_type = RTM_NEWLINK;
+  } else {
+    request.mhdr.nlmsg_type = RTM_DELLINK;
+    request.info.ifi_index = get_ifaceindex(name, 1);
+  }
+  request.info.ifi_family = AF_UNSPEC;
+  attr = NLMSG_TAIL(&request.mhdr);
+  if (type) {
+    add_string_to_rtattr(&request.mhdr, sizeof(request),
+        IFLA_LINKINFO, NULL, 0);
+    add_string_to_rtattr(&request.mhdr, sizeof(request),
+        IFLA_INFO_KIND, type, strlen(type));
+    if (!strcmp(type, "vlan")) {
+      struct rtattr *data = NLMSG_TAIL(&request.mhdr);
+      add_string_to_rtattr(&request.mhdr, sizeof(request), 
+          IFLA_INFO_DATA, NULL, 0);
+      vlan_parse_opt(++argv, &request.mhdr, sizeof(request));
+      data->rta_len = (void *)NLMSG_TAIL(&request.mhdr) - (void *)data;
+    }
+    attr->rta_len = (void *)NLMSG_TAIL(&request.mhdr) - (void *)attr;
+  }
+
+  if (link) {
+    uint32_t idx = get_ifaceindex(link, 1);
+    add_string_to_rtattr(&request.mhdr, sizeof(request), 
+        IFLA_LINK, &idx, sizeof(uint32_t));
+  }
+  if (addr) {
+    char abuf[IF_NAMESIZE] = {0,};
+
+    fill_hwaddr(addr, IF_NAMESIZE, (unsigned char *)abuf);
+    add_string_to_rtattr(&request.mhdr, sizeof(request), 
+        IFLA_ADDRESS, abuf, strlen(abuf));
+  }
+  if (!name) {
+    snprintf(toybuf, IFNAMSIZ, "%s%d", type, 0);
+    for (len = 1; ; len++) {
+      if (!get_ifaceindex(toybuf, 0)) break;
+      snprintf(toybuf, IFNAMSIZ, "%s%d", type, len);
+    }
+    name = toybuf;
+  }
+  len = strlen(name) + 1;
+  if (len < 2 || len > IFNAMSIZ) error_exit("Invalid device name.");
+  add_string_to_rtattr(&request.mhdr, sizeof(request), IFLA_IFNAME, name, len);
+
+  send_nlmesg(0, 0, 0, (void *)&request, request.mhdr.nlmsg_len);
+  return (filter_nlmesg(NULL,NULL));
+}
+
+static int link_set(char **argv)
+{
+  struct arglist cmd_objectlist[] = {{"up", 0}, {"down", 1}, {"arp", 2}, 
+    {"multicast", 3}, {"dynamic", 4}, {"name", 5}, {"txqueuelen", 6}, 
+    {"mtu", 7},{"address", 8}, {"broadcast", 9}, {NULL,-1}};
+  int case_flags[] = {IFF_NOARP,IFF_MULTICAST,IFF_DYNAMIC};
+  struct ifreq req;
+  int idx, flags = 0, masks = 0xffff, fd;
+
+  memset(&req, 0, sizeof(req));
+  if (!*argv) error_exit("\"dev\" missing");
+  xstrncpy(req.ifr_name, *argv, IF_NAMESIZE);
+  fd = xsocket(AF_INET, SOCK_DGRAM, 0);
+  xioctl(fd, SIOCGIFINDEX, &req);
+  for (++argv; *argv;) {
+    if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1) help_exit(0);
+    switch(idx) {
+      case 0:
+        flags |= IFF_UP; break;
+      case 1:
+        masks &= ~IFF_UP; break;
+      case 2:
+      case 3:
+      case 4:
+        if (!*argv) help_exit(0);
+        else if (!strcmp(*argv, "on")) {
+          if (idx == 2) {
+            masks &= ~case_flags[idx-2];
+            flags &= ~case_flags[idx-2];
+          } else flags |= case_flags[idx-2];
+        } else if (!strcmp(*argv,"off")) {
+          if (idx == 2) {
+            masks |= case_flags[idx-2];
+            flags |= case_flags[idx-2];
+          } else masks &= ~case_flags[idx-2];
+        } else help_exit(0);
+        ++argv;
+        break;
+      case 5:
+        xstrncpy(req.ifr_ifru.ifru_newname, *argv, IF_NAMESIZE);
+        xioctl(fd, SIOCSIFNAME, &req);
+        xstrncpy(req.ifr_name, *argv++, IF_NAMESIZE);
+        xioctl(fd, SIOCGIFINDEX, &req);
+        break;
+      case 6:
+        req.ifr_ifru.ifru_ivalue = atolx(*argv++);
+        xioctl(fd, SIOCSIFTXQLEN, &req);
+        break;
+      case 7:
+        req.ifr_ifru.ifru_mtu = atolx(*argv++);
+        xioctl(fd, SIOCSIFMTU, &req);
+        break;
+      case 8:
+        xioctl(fd, SIOCGIFHWADDR, &req);
+        fill_hwaddr(*argv++, IF_NAMESIZE, 
+            (unsigned char *)(req.ifr_hwaddr.sa_data));
+        xioctl(fd, SIOCSIFHWADDR, &req);
+        break;
+      case 9:
+        xioctl(fd, SIOCGIFHWADDR, &req);
+        fill_hwaddr(*argv++, IF_NAMESIZE,
+            (unsigned char *)(req.ifr_hwaddr.sa_data));
+        xioctl(fd, SIOCSIFHWBROADCAST, &req);
+        break;
+    }
+  }
+  xioctl(fd, SIOCGIFFLAGS, &req);
+  req.ifr_ifru.ifru_flags |= flags;
+  req.ifr_ifru.ifru_flags &= masks;
+  xioctl(fd, SIOCSIFFLAGS, &req);
+  xclose(fd);
+  return 0;
+}
+
+static void print_stats(struct  rtnl_link_stats *rtstat)
+{
+  char *line_feed = (!TT.singleline ? "\n    " : " ");
+
+  if (TT.stats > 0) {
+    xprintf("    RX: bytes  packets  errors  "
+        "dropped  overrun  mcast%s%-10u %-8u %-7u %-8u %-8u %-8u\n",
+        line_feed, rtstat->rx_bytes, rtstat->rx_packets, rtstat->rx_errors,
+        rtstat->rx_dropped, rtstat->rx_over_errors, rtstat->multicast);
+    if (TT.stats > 1) {
+      xprintf("    RX: errors  length  crc  "
+          "frame  fifo  missed%s%-10u %-8u %-7u %-8u %-8u %-8u\n",
+          line_feed, rtstat->rx_errors, rtstat->rx_length_errors,
+          rtstat->rx_crc_errors, rtstat->rx_frame_errors,
+          rtstat->rx_fifo_errors, rtstat->rx_missed_errors);
+    }
+    xprintf("    TX: bytes  packets  errors  "
+        "dropped  carrier  collsns%s%-10u %-8u %-7u %-8u %-8u %-8u\n",
+        line_feed, rtstat->tx_bytes, rtstat->tx_packets, rtstat->tx_errors,
+        rtstat->tx_dropped, rtstat->tx_carrier_errors, rtstat->collisions);
+    if (TT.stats > 1) {
+      xprintf("    TX: errors  aborted  fifo  window  "
+          "heartbeat%s%-10u %-8u %-7u %-8u %-8u\n",
+          line_feed, rtstat->tx_errors, rtstat->tx_aborted_errors,
+          rtstat->tx_fifo_errors, rtstat->tx_window_errors, 
+          rtstat->tx_heartbeat_errors);
+    }
+  }
+}
+
+static int print_link_output(struct linkdata *link)
+{
+  char *line_feed = " ", *flags,*peer = "brd";
+  struct arglist iface_flags[] = {{"",0},{"UP", IFF_UP}, 
+    {"BROADCAST", IFF_BROADCAST}, {"DEBUG", IFF_DEBUG},
+    {"LOOPBACK", IFF_LOOPBACK}, {"POINTOPOINT", IFF_POINTOPOINT},
+    {"NOTRAILERS", IFF_NOTRAILERS}, {"RUNNING", IFF_RUNNING},
+    {"NOARP", IFF_NOARP}, {"PROMISC",IFF_PROMISC},
+    {"ALLMULTI", IFF_ALLMULTI}, {"MASTER", IFF_MASTER}, {"SLAVE", IFF_SLAVE},
+    {"MULTICAST", IFF_MULTICAST}, {"PORTSEL", IFF_PORTSEL},
+    {"AUTOMEDIA", IFF_AUTOMEDIA}, {"DYNAMIC", IFF_DYNAMIC}, {NULL,-1}};
+
+  if (link->parent != -1) {
+    int fd = 0;
+    struct ifreq req;
+
+    memset(&req, 0, sizeof(req));
+    if_indextoname( link->parent,req.ifr_ifrn.ifrn_name);
+    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
+    if (ioctl(fd, SIOCGIFTXQLEN, &req)) perror("");
+    else link->txqueuelen = req.ifr_ifru.ifru_ivalue;
+    xclose(fd);
+  }
+
+  if (TT.is_addr && addrinfo.label && fnmatch(addrinfo.label, link->iface, 0))
+    return 0;
+
+
+  if (!(flags = get_flag_string(iface_flags, link->flags, 1)))
+    error_exit("Invalid data.");    
+  if (!TT.singleline) line_feed="\n    ";
+  if (link->parent != -1) {
+    char iface[IF_NAMESIZE];
+
+    if (!if_indextoname(link->parent, iface)) perror_exit(NULL);
+    sprintf(toybuf,"%s@%s", link->iface, iface);
+  }
+  if (link->flags & IFF_POINTOPOINT) peer = "peer";
+  if (TT.is_addr && TT.singleline && TT.addressfamily)
+    xprintf("%d: %s", link->iface_idx,
+        ((link->parent == -1) ? link->iface : toybuf));
+  else xprintf("%d: %s: <%s> mtu %d qdisc %s state %s qlen %d",
+      link->iface_idx, ((link->parent == -1) ? link->iface : toybuf), flags,
+      link->mtu, link->qdiscpline, link->state, link->txqueuelen);
+
+  if (!TT.addressfamily || TT.addressfamily == AF_PACKET)
+    xprintf("%slink/%s %s %s %s",
+        line_feed, link->type, link->laddr, peer ,link->bcast);
+
+  xputc('\n');
+
+  //user can specify stats flag two times
+  //one for stats and other for erros e.g. -s and -s -s
+  print_stats(&link->rt_stat);
+  free(flags);
+
+  return 0;
+}
+
+static void fill_address(void *p, char *ip)
+{
+  unsigned char *ptr = (unsigned char*)p;
+  snprintf(ip, 64, " %02x:%02x:%02x:%02x:%02x:%02x",
+      ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
+}
+
+static int get_link_info(struct nlmsghdr* h,struct linkdata* link,char **argv)
+{
+  struct ifinfomsg *iface = NLMSG_DATA(h);
+  struct rtattr *attr = IFLA_RTA(iface);
+  int len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*iface));
+  struct arglist hwtypes[]={{"generic",0},{"ether",ARPHRD_ETHER},
+    {"loopback", ARPHRD_LOOPBACK},{"sit",ARPHRD_SIT},
+#ifdef ARPHRD_INFINIBAND
+    {"infiniband",ARPHRD_INFINIBAND},
+#endif
+#ifdef ARPHRD_IEEE802_TR
+    {"ieee802",ARPHRD_IEEE802}, {"tr",ARPHRD_IEEE802_TR},
+#else
+    {"tr",ARPHRD_IEEE802},
+#endif
+#ifdef ARPHRD_IEEE80211
+    {"ieee802.11",ARPHRD_IEEE80211},
+#endif
+#ifdef ARPHRD_IEEE1394
+    {"ieee1394",ARPHRD_IEEE1394},
+#endif
+    {"irda",ARPHRD_IRDA},{"slip",ARPHRD_SLIP},{"cslip",ARPHRD_CSLIP},
+    {"slip6",ARPHRD_SLIP6}, {"cslip6",ARPHRD_CSLIP6}, {"ppp",ARPHRD_PPP},
+    {"ipip",ARPHRD_TUNNEL}, {"tunnel6",ARPHRD_TUNNEL6},
+    {"gre",ARPHRD_IPGRE},
+#ifdef ARPHRD_VOID
+    {"void",ARPHRD_VOID},
+#endif
+    {NULL,-1}};
+  char *lname = get_flag_string(hwtypes, iface->ifi_type, 0);
+
+  link->next = link->prev = 0;
+  link->iface_type = iface->ifi_type;
+  if (!lname) error_exit("Invalid link.");
+  xstrncpy(link->type, lname, IFNAMSIZ);
+  free(lname);
+  link->iface_idx = iface->ifi_index;
+  link->flags = iface->ifi_flags;
+  if (*argv && !strcasecmp("up",*argv) && !(link->flags & IFF_UP)) return 1;
+  link->parent =  -1;
+  for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
+    switch(attr->rta_type) {
+      case IFLA_IFNAME:
+        snprintf(link->iface, IFNAMSIZ, "%s",(char *) RTA_DATA(attr));
+        break;
+      case IFLA_ADDRESS:
+        if ( iface->ifi_type== ARPHRD_TUNNEL ||
+            iface->ifi_type == ARPHRD_SIT ||
+            iface->ifi_type == ARPHRD_IPGRE)
+          inet_ntop(AF_INET, RTA_DATA(attr), link->laddr, 64);
+        else fill_address(RTA_DATA(attr), link->laddr);
+        break;
+      case IFLA_BROADCAST:
+        if (iface->ifi_type== ARPHRD_TUNNEL ||
+            iface->ifi_type == ARPHRD_SIT ||
+            iface->ifi_type == ARPHRD_IPGRE)
+          inet_ntop(AF_INET, RTA_DATA(attr), link->bcast, 64);
+        else  fill_address(RTA_DATA(attr), link->bcast);
+        break;
+      case IFLA_MTU:
+        link->mtu = *((int*)(RTA_DATA(attr)));
+        break;
+      case IFLA_QDISC:
+        snprintf(link->qdiscpline, IFNAMSIZ, "%s", (char *) RTA_DATA(attr));
+        break;
+      case IFLA_STATS  :
+        link->rt_stat = *((struct rtnl_link_stats*) RTA_DATA(attr));
+        break;
+      case IFLA_LINK:
+        link->parent = *((int*)(RTA_DATA(attr)));
+        break;
+      case IFLA_TXQLEN:
+        link->txqueuelen = *((int*)(RTA_DATA(attr)));
+        break;
+      case IFLA_OPERSTATE: 
+        {
+          struct arglist flags[]={{"UNKNOWN", 0}, {"NOTPRESENT", 1}, 
+            {"DOWN", 2}, {"LOWERLAYERDOWN", 3}, {"TESTING", 4}, 
+            {"DORMANT", 5}, {"UP", 6}, {NULL, -1}};
+          if (!(lname = get_flag_string(flags, *((int*)(RTA_DATA(attr))), 0)))
+            error_exit("Invalid state.");
+          xstrncpy(link->state, lname,IFNAMSIZ);
+          free(lname);
+        }
+        break;
+      default: break;
+    }
+  }
+  return 0;
+}
+
+static int display_link_info(struct nlmsghdr *mhdr, char **argv)
+{
+  struct linkdata link;
+
+  if (!get_link_info(mhdr, &link, argv)) {
+    if (TT.is_addr) {
+      struct linkdata *lnk = xzalloc(sizeof(struct linkdata));
+      memcpy(lnk, &link, sizeof(struct linkdata));
+      dlist_add_nomalloc((struct double_list **)&linfo,
+          (struct double_list *)lnk);
+    }
+    else print_link_output(&link);
+  }
+  return 0;
+}
+
+static int link_show(char **argv)
+{
+  struct {
+    struct nlmsghdr mhdr;
+    struct ifinfomsg info;
+  } request;
+  uint32_t index = 0;
+
+  if (*argv && strcasecmp("up",*argv)) index = get_ifaceindex(*argv, 1);
+  memset(&request, 0, sizeof(request));
+  request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+  request.mhdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+  if (!index) request.mhdr.nlmsg_flags |= NLM_F_ROOT|NLM_F_MATCH;
+  else request.info.ifi_change =  0xffffffff; // used in single operation
+  request.mhdr.nlmsg_type = RTM_GETLINK;
+  request.info.ifi_index = index;
+  request.info.ifi_family = AF_UNSPEC;
+  send_nlmesg(0, 0, 0, (void*)&request, sizeof(request));
+  return (filter_nlmesg(display_link_info, argv));
+}
+
+static int iplink(char **argv)
+{
+  int idx;
+  cmdobj ipcmd, cmdobjlist[] = {linkupdate, link_set, link_show};
+  struct arglist cmd_objectlist[] = {{"add", 0}, {"delete", 0},
+    {"set", 1}, {"show", 2}, {"list", 2}, {"lst", 2}, {NULL,-1}};
+
+  if (!*argv) idx = 2;
+  else if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1)
+    help_exit(0);
+  ipcmd = cmdobjlist[idx];
+  return ipcmd(argv);
+}
+
+// ===========================================================================
+// Code for ip addr.
+// ===========================================================================
+
+static int print_addrinfo(struct nlmsghdr *h, int flag_l)
+{
+  struct rtattr *rta, *rta_tb[IFA_MAX+1] = {0,};
+  char *family = toybuf, *scope = toybuf+256, *label = toybuf+512,
+       *brd = toybuf+768, *peer = toybuf+1024, *any = toybuf+1280,
+       lbuf[INET6_ADDRSTRLEN] = {0,}, lbuf_ifa[INET6_ADDRSTRLEN] = {0,};
+  struct ifaddrmsg *ifa = NLMSG_DATA(h);
+  int len;
+
+  if ((len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))) < 0) {
+    error_msg("wrong nlmsg len %d", len);
+    return 0;
+  }
+
+  for (rta = IFA_RTA(ifa); RTA_OK(rta, len); rta=RTA_NEXT(rta, len))
+    if (rta->rta_type <= IFA_MAX) rta_tb[rta->rta_type] = rta;
+
+  if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
+  if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
+  if ((addrinfo.scope ^ ifa->ifa_scope)&addrinfo.scopemask) return 0;
+  if (addrinfo.ifindex && addrinfo.ifindex != ifa->ifa_index) return 0;
+
+  if (flag_l && addrinfo.label && ifa->ifa_family == AF_INET6) return 0;
+  if ((rta_tb[IFA_LABEL])) {
+    xstrncpy(label, RTA_DATA(rta_tb[IFA_LABEL]), 256);
+    label[255] = '\0';
+    if (addrinfo.label && fnmatch(addrinfo.label, label, 0))
+      return 0;
+  }
+
+  if (TT.flush) {
+    if (ifa->ifa_index == addrinfo.ifindex) {
+      h->nlmsg_type = RTM_DELADDR;
+      h->nlmsg_flags = NLM_F_REQUEST;
+      send_nlmesg(RTM_DELADDR, 0, 0, h, h->nlmsg_len);
+      return 0;
+    }
+  }
+
+  if (h->nlmsg_type == RTM_DELADDR) printf("Deleted ");
+
+  if (TT.singleline) {
+    if (!if_indextoname(ifa->ifa_index, lbuf)) perror_exit(NULL);
+    printf("%u: %s",ifa->ifa_index, lbuf);
+  }
+
+  sprintf(scope, " scope %s ", namefromRPDB(ifa->ifa_scope, RPDB_rtscopes));
+
+  if (ifa->ifa_family == AF_INET) strcpy(family, "    inet ");
+  else if (ifa->ifa_family == AF_INET6) strcpy(family, "    inet6 ");
+  else sprintf(family, "    family %d", ifa->ifa_family);
+
+  if (rta_tb[IFA_LOCAL]) {
+    if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_LOCAL]),
+          lbuf, sizeof(lbuf))) perror_exit("inet");
+
+    sprintf(family+strlen(family), lbuf, strlen(lbuf));
+    if (!rta_tb[IFA_ADDRESS] || !memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]),
+          RTA_DATA(rta_tb[IFA_LOCAL]), 4))
+      sprintf(family+strlen(family), "/%d ", ifa->ifa_prefixlen);
+    else {
+      if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_ADDRESS]),
+            lbuf_ifa, sizeof(lbuf_ifa))) perror_exit("inet");
+      sprintf(peer, " peer %s/%d ", lbuf_ifa, ifa->ifa_prefixlen);
+    }
+  }
+
+  if (addrinfo.to && strcmp(addrinfo.addr, lbuf))
+    return 0;
+
+  if (rta_tb[IFA_BROADCAST]) {
+    if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_BROADCAST]),
+          lbuf, sizeof(lbuf))) perror_exit("inet");
+    sprintf(brd, " brd %s", lbuf);
+  }else brd = "";
+
+  if (rta_tb[IFA_ANYCAST]) {
+    if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_ANYCAST]),
+          lbuf, sizeof(lbuf))) perror_exit("inet");
+    sprintf(any, " any %s", lbuf);
+  }
+
+  if (ifa->ifa_family == AF_INET)
+    printf("%s%s%s%s%s %c", family, brd, peer, scope, label,
+        (TT.singleline? '\0' : '\n'));
+  else printf("%s%s %c", family, scope, (TT.singleline? '\0' : '\n'));
+  if (TT.singleline && (ifa->ifa_family == AF_INET)) xputc('\n');
+
+  if (rta_tb[IFA_CACHEINFO]) {
+    struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
+
+    printf("%c      valid_lft ", (TT.singleline? '\\' : '\0'));
+    if (ci->ifa_valid ==  0xFFFFFFFFU) printf("forever");
+    else printf("%usec", ci->ifa_valid);
+    printf(" preferred_lft ");
+    if (ci->ifa_prefered ==  0xFFFFFFFFU) printf("forever");
+    else printf("%dsec", ci->ifa_prefered);
+    xputc('\n');
+  }
+  return 0;
+}
+
+static int ipaddrupdate(char **argv)
+{
+  int length, cmd = !memcmp("add", argv[-1], strlen(argv[-1]))
+    ? RTM_NEWADDR: RTM_DELADDR;
+  int idx = 0,length_brd = 0, length_peer = 0,length_any = 0,length_local = 0,
+      scoped = 0;
+  char *dev = NULL,*label = NULL, reply[8192];
+
+  struct nlmsghdr *addr_ptr = NULL;
+  struct nlmsgerr *err = NULL;
+  struct arglist cmd_objectlist[] = {{"dev",0}, {"peer", 1},
+    {"remote", 2}, {"broadcast", 3}, {"brd", 4}, {"label", 5},
+    {"anycast", 6},{"scope", 7}, {"local", 8}, {NULL, -1}};
+  struct {
+    struct nlmsghdr nlm;
+    struct ifaddrmsg ifadd;
+    char buf[256];
+  } req;
+  typedef struct {
+    int family, bytelen, bitlen;
+    __u32  data[8];
+  } option_data;
+  option_data local;
+
+  memset(&req, 0, sizeof(req));
+  req.nlm.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+  req.nlm.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+  req.nlm.nlmsg_type = cmd;
+  req.ifadd.ifa_family = TT.addressfamily;
+
+  while (*argv) {
+    idx = substring_to_idx(*argv, cmd_objectlist);
+    if (idx >= 0)
+      if (!*++argv)
+        error_exit("Incomplete Command line");
+    switch(idx) {
+      case 0:
+        dev = *argv;
+        break;
+      case 1:
+      case 2:
+        {
+          uint32_t addr[4] = {0,}, netmask = 0;
+          uint8_t len = 0;
+          parse_prefix(addr, &netmask, &len, *argv,
+              req.ifadd.ifa_family);
+          if (len)
+            req.ifadd.ifa_family = ((len == 4) ? AF_INET : AF_INET6);
+          length_peer = len;
+          add_string_to_rtattr(&req.nlm, sizeof(req),
+              IFA_ADDRESS, addr, len);
+          req.ifadd.ifa_prefixlen = netmask;
+        }
+        break;
+      case 3:
+      case 4:
+        if (*argv[0] == '+') {
+          length_brd = -1;
+        } else if (*argv[0] == '-') {
+          length_brd = -2;
+        } else {
+          uint32_t addr[4] = {0,};
+          uint8_t af = AF_UNSPEC;
+
+          if (get_prefix(addr, &af, *argv, req.ifadd.ifa_family))
+            error_exit("Invalid prefix");
+
+          length_brd = ((af == AF_INET6) ? 16 : 4);
+          if (req.ifadd.ifa_family == AF_UNSPEC)
+            req.ifadd.ifa_family = af;
+          add_string_to_rtattr(&req.nlm, sizeof(req),
+              IFA_BROADCAST, &addr, length_brd);
+        }
+        break;
+      case 5:
+        label = *argv;
+        add_string_to_rtattr(&req.nlm, sizeof(req),
+            IFA_LABEL, label, strlen(label) + 1);
+        break;
+      case 6:
+        {
+          uint32_t addr[4] = {0,};
+          uint8_t af = AF_UNSPEC;
+
+          if (get_prefix(addr, &af, *argv, req.ifadd.ifa_family))
+            error_exit("Invalid prefix");
+          length_any = ((af == AF_INET6) ? 16 : 4);
+          if (req.ifadd.ifa_family == AF_UNSPEC)
+            req.ifadd.ifa_family = af;
+          add_string_to_rtattr(&req.nlm, sizeof(req),
+              IFA_ANYCAST, &addr, length_any);
+        }
+        break;
+      case 7:
+        {
+          int scope = idxfromRPDB(*argv, RPDB_rtscopes);
+          if (scope < 0) error_exit("wrong scope '%s'", *argv);
+          req.ifadd.ifa_scope = scope;
+          scoped = 1;
+        }
+        break;
+      default:
+        {
+          //local is by default
+          uint32_t addr[8] = {0,}, netmask = 0;
+          uint8_t len = 0;
+
+          parse_prefix(addr, &netmask, &len, *argv,
+              req.ifadd.ifa_family);
+          if (len)
+            req.ifadd.ifa_family = ((len == 4) ? AF_INET : AF_INET6);
+          length_local = len;
+          local.bitlen = netmask;
+          local.bytelen = len;
+          memcpy(local.data, addr, sizeof(local.data));
+          local.family = req.ifadd.ifa_family;
+          add_string_to_rtattr(&req.nlm, sizeof(req),
+              IFA_LOCAL, &local.data, local.bytelen);
+        }
+        break;
+    }
+    argv++;
+  }
+  if (!dev) error_exit("need \"dev \" argument");
+  if (label && strncmp(dev, label, strlen(dev)) != 0)
+    error_exit("\"dev\" (%s) must match \"label\" (%s)", dev, label);
+
+  if (length_peer == 0 && length_local && cmd != RTM_DELADDR){
+    add_string_to_rtattr(&req.nlm, sizeof(req),
+        IFA_ADDRESS, &local.data, local.bytelen);
+  }
+
+  if (length_brd < 0 && cmd != RTM_DELADDR){
+    int i;
+
+    if (req.ifadd.ifa_family != AF_INET)
+      error_exit("broadcast can be set only for IPv4 addresses");
+
+    if (local.bitlen <= 30) {
+      for (i = 31; i >= local.bitlen; i--) {
+        if (length_brd == -1)
+          local.data[0] |= htonl(1<<(31-i));
+        else
+          local.data[0] &= ~htonl(1<<(31-i));
+      }
+      add_string_to_rtattr(&req.nlm, sizeof(req),
+          IFA_BROADCAST, &local.data, local.bytelen);
+      length_brd = local.bytelen;
+    }
+  }
+  if (req.ifadd.ifa_prefixlen == 0)
+    req.ifadd.ifa_prefixlen = local.bitlen;
+  if (!scoped && (cmd != RTM_DELADDR) && (local.family == AF_INET)
+      && (local.bytelen >= 1 && *(uint8_t*)&local.data == 127))
+    req.ifadd.ifa_scope = RT_SCOPE_HOST;
+  req.ifadd.ifa_index = get_ifaceindex(dev, 1);
+
+  send_nlmesg(RTM_NEWADDR, 0, AF_UNSPEC, (void *)&req, req.nlm.nlmsg_len);
+  length = recv(TT.sockfd, reply, sizeof(reply), 0);
+  addr_ptr = (struct nlmsghdr *) reply;
+  for (; NLMSG_OK(addr_ptr, length); addr_ptr = NLMSG_NEXT(addr_ptr, length)) {
+    if (addr_ptr->nlmsg_type == NLMSG_DONE)
+      return 1;
+    if (addr_ptr->nlmsg_type == NLMSG_ERROR)
+      err = (struct nlmsgerr*) NLMSG_DATA(addr_ptr);
+    if (err && err->error) {
+      errno = -err->error;
+      perror_exit("RTNETLINK answers:");
+    }
+  }
+  return 0;
+}
+
+static int ipaddr_listflush(char **argv)
+{
+  int idx; uint32_t netmask = 0, found = 0;
+  char *tmp = NULL, *name = NULL;
+  struct double_list *dlist;
+  struct arglist cmd_objectlist[] = {{"to", 0}, {"scope", 1}, {"up", 2},
+    {"label", 3}, {"dev", 4}, {NULL, -1}};
+
+  TT.flush = *argv[-1] == 'f' ? 1 : 0;
+  memset(&addrinfo, 0, sizeof(addrinfo));
+
+  if (TT.flush) {
+    if (!*argv)
+      error_exit("Incomplete command for \"flush\"");
+    if (TT.addressfamily == AF_PACKET)
+      error_exit("Can't flush link Addressess");
+  }
+  addrinfo.scope = -1;
+  while (*argv) {
+    switch (idx = substring_to_idx(*argv, cmd_objectlist)) {
+      case 0: 
+        {// ADDR_TO
+          if (!*++argv) error_exit("Incomplete Command line");
+          else if (!strcmp(*argv, "0")) return 0;
+          uint32_t addr[4] = {0,};
+          uint8_t len = 0;
+
+          addrinfo.to = 1;
+          parse_prefix(addr, &netmask, &len, *argv, TT.addressfamily);
+          if (len)
+            TT.addressfamily = ((len == 4) ? AF_INET : AF_INET6);
+          addrinfo.addr  = strtok(*argv, "/");
+        }
+        break;
+      case 1: // ADDR_SCOPE
+        {
+          int scope = 0;
+          if (!*++argv) error_exit("Incomplete Command line");
+          name = *argv;
+
+          addrinfo.scopemask = -1;
+          if (isdigit(**argv)) {
+            int idx = atolx(*argv);
+
+            name = xstrdup(namefromRPDB(idx, RPDB_rtscopes));
+          }
+          if ((scope = idxfromRPDB(name, RPDB_rtscopes)) < 0) {
+            if (strcmp(name, "all"))
+              error_exit("wrong scope '%s'", name);
+            scope = RT_SCOPE_NOWHERE;
+            addrinfo.scopemask = 0;
+          }
+
+          if (isdigit(**argv))
+            free(name);
+          addrinfo.scope = scope;
+        }
+        break;       
+      case 2: // ADDR_UP
+        addrinfo.up = 1;
+        break;            
+      case 3: // ADDR_LABEL
+        if (!*++argv) error_exit("Incomplete Command line");
+        addrinfo.label = *argv;
+        break;
+      case 4: // ADDR_DEV
+        if (!*++argv) error_exit("Incomplete Command line");
+
+      default:                               
+        if (TT.filter_dev)
+          error_exit("Either \"dev\" is duplicate or %s is garbage",
+              *argv);
+        TT.filter_dev = *argv;
+        break;
+    }
+    argv++;
+  }
+
+  link_show(&tmp);
+  while ( linfo && (dlist = dlist_pop(&linfo))){    
+    struct linkdata *tmp  = (struct linkdata*) dlist;
+    char *temp = &tmp->iface[0];
+
+    if (TT.filter_dev && strcmp(TT.filter_dev, temp))
+      continue;
+    found = 1;
+    if (TT.flush && addrinfo.label) ipaddr_print( tmp, 0);
+    if (addrinfo.up && !(tmp->flags & IFF_UP)){
+      ipaddr_print(tmp, 0);
+      continue;
+    }
+    if (addrinfo.label){
+      if ( fnmatch(addrinfo.label, temp, 0)) {
+        ipaddr_print(tmp, 1);
+        continue;
+      }      
+    }
+    if (!TT.addressfamily && ! TT.flush ) print_link_output(tmp);
+
+    ipaddr_print(tmp, 0);
+    free(tmp);
+  }
+  if (TT.filter_dev && !found)
+    error_exit("Device \"%s\" doesn't exist. \n", TT.filter_dev);
+  return 0;
+}
+
+static int ipaddr_print( struct linkdata *link, int flag_l)
+{
+  struct nlmsghdr *addr_ptr;
+  int ip_match = 0;
+
+  addrinfo.ifindex = link->iface_idx;
+  send_nlmesg(RTM_GETADDR, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST,
+      AF_UNSPEC, NULL, 0);
+  if (TT.addressfamily == AF_PACKET) print_link_output(link);
+
+  if (addrinfo.label){
+    char *col = strchr(addrinfo.label, ':');
+    if (!col && (fnmatch(addrinfo.label, &link->iface[0], 0)))
+      return 0;
+  }
+
+  while (1){
+    int len = recv(TT.sockfd, TT.gbuf, sizeof(TT.gbuf), 0);
+    addr_ptr = (struct nlmsghdr *)TT.gbuf;
+    struct ifaddrmsg *addressInfo = NLMSG_DATA(addr_ptr);
+    char lbuf[INET6_ADDRSTRLEN];
+    struct rtattr *rta, *rta_tb[IFA_MAX+1] = {0,};
+
+    int len1 = addr_ptr->nlmsg_len - NLMSG_LENGTH(sizeof(*addressInfo));
+    if (len1 > 0) {
+      for (; NLMSG_OK(addr_ptr, len); addr_ptr = NLMSG_NEXT(addr_ptr, len)) {
+        addressInfo = NLMSG_DATA(addr_ptr);
+        if (TT.addressfamily && TT.addressfamily != addressInfo->ifa_family)
+          continue;
+        if (addrinfo.ifindex && addrinfo.ifindex != addressInfo->ifa_index)
+          continue;
+
+        if (addrinfo.to) {        
+          memset(rta_tb, 0, sizeof(rta_tb));
+          int rt_len = IFA_PAYLOAD(addr_ptr);
+          for (rta = IFA_RTA(addressInfo); RTA_OK(rta, rt_len); rta=RTA_NEXT(rta, rt_len)) {
+            if (rta->rta_type <= IFA_MAX) rta_tb[rta->rta_type] = rta;
+          }
+          if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
+          if (rta_tb[IFA_LOCAL]) {
+            if (!inet_ntop(TT.addressfamily, RTA_DATA(rta_tb[IFA_LOCAL]),
+                  lbuf, sizeof(lbuf))) perror_exit("inet");
+            if (strcmp(addrinfo.addr, lbuf))
+              continue;
+            ip_match=1;
+          }
+          if (!ip_match)
+            continue;
+        }
+
+        if (!TT.flush){
+          if (addrinfo.scope != -1 && TT.addressfamily && TT.addressfamily ==
+              addressInfo->ifa_family &&
+              (addrinfo.ifindex == addressInfo->ifa_index)) {
+            if ((addrinfo.scope ^ addressInfo->ifa_scope) & addrinfo.scopemask)
+              continue;
+            else if (addrinfo.up && (link->flags & IFF_UP))
+              print_link_output(link);
+            else if (!addrinfo.up) print_link_output(link);
+          }
+          if (TT.addressfamily &&
+              (addrinfo.ifindex == addressInfo->ifa_index) &&
+              (addrinfo.scope == -1)){
+            if (addrinfo.up && (link->flags & IFF_UP))
+              print_link_output(link);
+            else if (!addrinfo.up) print_link_output(link);
+          }
+        }
+
+        for (; NLMSG_OK(addr_ptr, len); addr_ptr = NLMSG_NEXT(addr_ptr, len)) {
+          if ((addr_ptr->nlmsg_type == RTM_NEWADDR))
+            print_addrinfo(addr_ptr, flag_l);
+          if ((addr_ptr->nlmsg_type == NLMSG_DONE) ||
+              (addr_ptr->nlmsg_type == NLMSG_ERROR) ||
+              (TT.flush && addrinfo.to))
+            goto ret_stop;          
+        }
+        if ((addr_ptr->nlmsg_type == NLMSG_DONE) ||
+            (addr_ptr->nlmsg_type == NLMSG_ERROR))
+          break;
+      }
+    }
+    else
+      return 0;
+  }
+
+ret_stop:
+  return 0;
+}
+
+static int ipaddr(char **argv)
+{
+  int    idx;
+  cmdobj ipcmd, cmdobjlist[] = {ipaddrupdate, ipaddr_listflush};
+  struct arglist cmd_objectlist[] = { {"add", 0}, {"delete", 0},
+    {"list", 1},{"show", 1},{"lst", 1}, {"flush", 1}, {NULL,-1}};
+
+  TT.is_addr++;
+  if (!*argv) idx = 1;
+  else if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1)
+    help_exit(0);
+
+  ipcmd = cmdobjlist[idx];
+  return ipcmd(argv);
+}
+
+// ===========================================================================
+// code for ip route
+// ===========================================================================
+struct I_data {
+  unsigned char family;
+  uint32_t addr[8] , netmask ;
+  uint8_t len ;
+};
+
+struct {
+  int tb,idev,odev,proto;
+  struct I_data rvia, rdst, mdst, rsrc, msrc;
+} gfilter;
+
+static void show_iproute_help(void)
+{
+  char *errmsg = "\n\n" \
+       "iproute { list | flush } SELECTOR\n" \
+       "iproute get ADDRESS [from ADDRESS iif STRING]\n" \
+       "	[oif STRING]\n" \
+       "iproute { add | del | change | append | replace | test } ROUTE\n" \
+       "	SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" \
+       "	ROUTE := [TYPE] PREFIX [proto RTPROTO] [metric METRIC]";
+
+  error_exit(errmsg);
+}
+
+static int display_route_info(struct nlmsghdr *mhdr, char **argv)
+{
+  char *inetval = NULL, out[1024] = {0};
+  struct rtmsg *msg = NLMSG_DATA(mhdr);
+  struct rtattr *rta, *attr[RTA_MAX+1] = {0,};
+  int32_t tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
+  int hlen = ((msg->rtm_family == AF_INET) ? 32
+      : ((msg->rtm_family == AF_INET6) ? 128 : -1));
+
+  if (mhdr->nlmsg_type != RTM_NEWROUTE) return 0;
+  if (msglen < 0) return 1;
+
+  if (msg->rtm_family == AF_INET6) {
+    if (gfilter.tb) {
+      if (gfilter.tb < 0) {
+        if (!(msg->rtm_flags & RTM_F_CLONED)) return 0;
+      } else {
+        if (msg->rtm_flags & RTM_F_CLONED) return 0;
+        if (gfilter.tb == RT_TABLE_LOCAL && msg->rtm_type != RTN_LOCAL)
+          return 0;
+        else if (gfilter.tb == RT_TABLE_MAIN && msg->rtm_type == RTN_LOCAL)
+          return 0;
+      }
+    }
+  }
+  else if (gfilter.tb > 0 && gfilter.tb != msg->rtm_table) return 0;
+
+  if (gfilter.proto && (msg->rtm_protocol != gfilter.proto)) return 0;
+
+
+  if (gfilter.rdst.family && (msg->rtm_family != gfilter.rdst.family ||
+        gfilter.rdst.netmask > msg->rtm_dst_len)) return 0;
+  if (gfilter.mdst.family && (msg->rtm_family != gfilter.mdst.family
+        || (gfilter.mdst.netmask < msg->rtm_dst_len))) return 0;
+  if (gfilter.rsrc.family && (msg->rtm_family != gfilter.rsrc.family
+        || gfilter.rsrc.netmask > msg->rtm_src_len)) return 0;
+  if (gfilter.msrc.family && (msg->rtm_family != gfilter.msrc.family
+        || (gfilter.msrc.netmask < msg->rtm_src_len))) return 0;
+  tvar = msglen;
+
+  for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar))
+    if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta;
+
+  if (msg->rtm_type != RTN_UNICAST)
+    sprintf(out,"%s%s ", out,rtmtype_idx2str(msg->rtm_type));
+  if (attr[RTA_DST]) {
+    inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_DST]),
+        toybuf, sizeof(toybuf));
+    if (gfilter.rdst.family &&
+        memcmp(RTA_DATA(attr[RTA_DST]), &gfilter.rdst.addr, gfilter.rdst.len))
+      return 0;
+    if (gfilter.mdst.family &&
+        memcmp(RTA_DATA(attr[RTA_DST]), &gfilter.mdst.addr, gfilter.mdst.len))
+      return 0;
+    sprintf(out,"%s%s",out,inetval);
+  }
+  if (msg->rtm_dst_len) sprintf(out,"%s/%d ", out,msg->rtm_dst_len);
+  else sprintf(out,"%s%s",out,"default ");
+
+  if (attr[RTA_SRC]) {
+    inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_SRC]),
+        toybuf, sizeof(toybuf));
+    if (gfilter.rsrc.family &&
+        memcmp(RTA_DATA(attr[RTA_SRC]), &gfilter.rsrc.addr, gfilter.rsrc.len))
+      return 0;
+    if (gfilter.msrc.family &&
+        memcmp(RTA_DATA(attr[RTA_SRC]), &gfilter.msrc.addr, gfilter.msrc.len))
+      return 0;
+    sprintf(out, "%s from %s", out, inetval);
+  }
+  if (msg->rtm_src_len) sprintf(out, "%s/%d ", out, msg->rtm_src_len);
+
+  if (attr[RTA_GATEWAY]) {
+    inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_GATEWAY]),
+        toybuf, sizeof(toybuf));
+    sprintf(out, "%s via %s ", out, inetval);
+  }
+  if (gfilter.rvia.family) {
+    char tmp[256];
+
+    if (!attr[RTA_GATEWAY]) return 0;
+    if (strcmp((char *)inet_ntop(msg->rtm_family, gfilter.rvia.addr,
+            tmp, sizeof(tmp)), inetval)) return 0;
+  }
+
+  if (gfilter.odev != 0) if (!attr[RTA_OIF]) return 0;
+  if (attr[RTA_OIF]) {
+    if (gfilter.odev !=0 && gfilter.odev != *(int*)RTA_DATA(attr[RTA_OIF]))
+      return 0;
+    sprintf(out, "%s dev %s ", out, 
+        if_indextoname(*(int*)RTA_DATA(attr[RTA_OIF]), toybuf));
+  }
+
+  if (attr[RTA_PREFSRC] && hlen) {
+    inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_PREFSRC]),
+        toybuf, sizeof(toybuf));
+    sprintf(out, "%s src %s ", out, inetval);
+  }
+  if (attr[RTA_PRIORITY])
+    sprintf(out, "%s metric %d ", out, *(uint32_t*)RTA_DATA(attr[RTA_PRIORITY]));
+  if (msg->rtm_family == AF_INET6) {
+    struct rta_cacheinfo *ci = NULL;
+    if (attr[RTA_CACHEINFO]) ci = RTA_DATA(attr[RTA_CACHEINFO]);
+    if ((msg->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
+      if (msg->rtm_flags & RTM_F_CLONED) sprintf(out, "%s%s    cache ",
+          out, (!TT.singleline ? "\n" : " "));
+      if (ci && ci->rta_expires) {
+        int hz = 0;
+        FILE *fp = xfopen("/proc/net/psched","r");
+
+        if (fp) {
+          unsigned int nom, denom;
+
+          if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
+            if (nom == 1000000)
+              hz = denom;
+          fclose(fp);
+        }
+        if (!hz) hz = sysconf(_SC_CLK_TCK);
+        sprintf(out, "%s expires %dsec", out, ci->rta_expires /hz);
+      }
+      if (ci && ci->rta_error) sprintf(out, "%s error %d", out, ci->rta_error);
+    }
+    else if (ci && ci->rta_error)
+      sprintf(out, "%s error %d", out, ci->rta_error);
+  }
+  if (attr[RTA_IIF] && !gfilter.idev)
+    sprintf(out, "%s iif %s", out, 
+        if_indextoname(*(int*)RTA_DATA(attr[RTA_IIF]), toybuf));
+  if (TT.flush || (TT.connected && !TT.from_ok)) 
+    memcpy(toybuf, (void*)mhdr,mhdr->nlmsg_len);
+
+  if (TT.flush) {
+    int sockfd = 0;
+    struct nlmsghdr* mhdr = (struct nlmsghdr*)toybuf;
+    struct rtmsg *msg = NLMSG_DATA(mhdr);
+    int tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
+    struct rtattr *rta, *attr[RTA_MAX+1] = {0,};
+
+    tvar = msglen;
+    for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar))
+      if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta;
+
+    if (msg->rtm_family == AF_INET6
+        && !msg->rtm_dst_len
+        && msg->rtm_type == RTN_UNREACHABLE
+        && attr[RTA_PRIORITY]
+        && *(int*)RTA_DATA(attr[RTA_PRIORITY]) == -1)
+      return 0;
+
+    mhdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+    mhdr->nlmsg_type  = RTM_DELROUTE;
+    mhdr->nlmsg_pid = 0;
+    sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    if (send(sockfd , (void*)mhdr, mhdr->nlmsg_len, 0) < 0)
+      perror_exit("Unable to send data on socket.");
+
+    while (1) {
+      struct nlmsghdr *mhdr;
+      int msglen = recv(sockfd, toybuf, sizeof(toybuf), 0);
+
+      if ((msglen < 0) && (errno == EINTR || errno == EAGAIN)) continue;
+      else if (msglen < 0) {
+        error_msg("netlink receive error %s", strerror(errno));
+        xclose(sockfd);
+        return 1;
+      } else if (!msglen) {
+        error_msg("EOF on netlink");
+        xclose(sockfd);
+        return 1;
+      }
+
+      for (mhdr = (struct nlmsghdr*)toybuf; NLMSG_OK(mhdr, msglen);
+          mhdr = NLMSG_NEXT(mhdr, msglen)) {
+        switch (mhdr->nlmsg_type) {
+          case NLMSG_DONE:
+            xclose(sockfd);
+            return 0;
+          case NLMSG_ERROR:
+            {
+              struct nlmsgerr *merr = (struct nlmsgerr*)NLMSG_DATA(mhdr);
+
+              if (merr->error == 0)  { xclose(sockfd); return 0; }
+              if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+                error_msg("ERROR truncated");
+              else {
+                errno = -merr->error;
+                perror_msg("RTNETLINK answers");
+              }
+              xclose(sockfd);
+              return 1;
+            }
+          default:
+            break;
+        }
+      } // End of for loop.
+    } // End of while loop.
+
+    xclose(sockfd);
+  } else printf("%s\n",out);
+  return 0;
+}
+
+static int route_get(char **argv)
+{
+  int idx, flag;
+  struct arglist cmd_objectlist[] = {{"from", 0}, {"iif", 1}, {"oif", 2}, 
+    {"dev", 3}, {"notify", 4}, {"connected", 5}, {"to", 6}, {NULL, -1}};
+  char *idev = NULL, *odev = NULL;
+  struct {
+    struct nlmsghdr mhdr;
+    struct rtmsg msg;
+    char buf[1024];
+  } request;
+
+  memset(&request, 0, sizeof(request));
+  request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+  request.mhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+  request.mhdr.nlmsg_type = RTM_GETROUTE;
+  request.msg.rtm_family = AF_UNSPEC;
+
+  for (; *argv; argv++) {
+    switch(idx = substring_to_idx(*argv, cmd_objectlist)) {
+      case 0: TT.from_ok = 1; // dst address
+      case 6: argv++; //fallthrough
+      default: 
+              {
+                uint32_t addr[8] = {0,}, netmask = 0;
+                uint8_t len = 0;
+
+                if (!*argv) error_exit("'%s': Missing Prefix", argv[-1]);
+                parse_prefix(addr, &netmask, &len, *argv, request.msg.rtm_family);
+                if (len) request.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6);
+                netmask = (request.msg.rtm_family == AF_INET6) ? 128 : 32;
+                if (!idx) request.msg.rtm_src_len = netmask;
+                else request.msg.rtm_dst_len = netmask;
+                add_string_to_rtattr(&request.mhdr, sizeof(request),
+                    (!idx ? RTA_SRC : RTA_DST), addr, len);
+                break;
+              }
+      case 1:
+      case 2:
+      case 3:
+              if (!*++argv) show_iproute_help();
+              if (idx == 1) idev = *argv, flag = RTA_IIF;
+              else odev = *argv, flag = RTA_OIF;
+              idx = get_ifaceindex(*argv, 1);
+              add_string_to_rtattr(&request.mhdr, sizeof(request),
+                  flag, (char*)&idx, sizeof(idx));
+              break;
+      case 4:
+              request.msg.rtm_flags |= RTM_F_NOTIFY;
+              break;
+      case 5:
+              TT.connected = 1;
+              break;
+    }
+  }
+  if (!request.msg.rtm_dst_len) 
+    error_exit("need at least destination address");
+
+  send_nlmesg(0, 0, 0, &request, sizeof(request));
+  filter_nlmesg(display_route_info, NULL);
+
+  if (TT.connected && !TT.from_ok) {
+    struct nlmsghdr *mhdr = (struct nlmsghdr*)toybuf;
+    struct rtmsg *msg = NLMSG_DATA(mhdr);
+    int tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
+    struct rtattr *rta, *attr[RTA_MAX+1] = {0,};
+
+    if (mhdr->nlmsg_type != RTM_NEWROUTE) error_exit("not a route?");
+    if (msglen < 0) error_exit("wrong len %d", msglen);
+
+    tvar = msglen;
+    for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar))
+      if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta;
+
+    if (attr[RTA_PREFSRC]) {
+      attr[RTA_PREFSRC]->rta_type = RTA_SRC;
+      msg->rtm_src_len = 8*RTA_PAYLOAD(attr[RTA_PREFSRC]);
+    } else if (!attr[RTA_SRC]) error_exit("can't connect the route");
+
+    if (!odev && attr[RTA_OIF]) attr[RTA_OIF]->rta_type = 0;
+    if (attr[RTA_GATEWAY]) attr[RTA_GATEWAY]->rta_type = 0;
+    if (!idev && attr[RTA_IIF]) attr[RTA_IIF]->rta_type = 0;
+    mhdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+    mhdr->nlmsg_type  = RTM_GETROUTE;
+    mhdr->nlmsg_pid = 0;
+    xclose(TT.sockfd);
+    TT.sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    send_nlmesg(0, 0, 0, mhdr, mhdr->nlmsg_len);
+    filter_nlmesg(display_route_info, NULL);
+  }
+  return 0;
+}
+
+static int route_show_flush(char **argv)
+{
+  struct arglist cmd_objectlist[] = {{"protocol", 0}, {"dev", 1}, {"oif", 2},
+    {"iif", 3}, {"via", 4}, {"table", 5}, {"cache", 6}, {"from", 7}, 
+    {"to", 8}, {"all", 9}, {"root", 10}, {"match", 11}, {"exact", 12}, 
+    {"main", 13}, {NULL,-1}};
+  int family = TT.addressfamily, idx;
+  struct {
+    struct nlmsghdr mhdr;
+    struct rtmsg msg;
+  } request;
+
+  if (*argv[-1] == 'f') TT.flush = 1;
+  if (TT.flush && !*argv) show_iproute_help();
+
+  gfilter.tb = RT_TABLE_MAIN;
+  for (; *argv; argv++) {
+    switch (idx = substring_to_idx(*argv, cmd_objectlist)) {
+      case 0:
+        if (!*++argv) show_iproute_help();
+        if ((idx = idxfromRPDB(*argv,RPDB_rtprotos)) < 0)
+          error_exit("Invalid argument protocol.");
+        gfilter.proto = idx;
+        break;
+      case 1:
+      case 2:
+      case 3:
+        {
+          if (!*++argv) show_iproute_help();
+          int dev = get_ifaceindex(*argv, 1);
+
+          if (idx == 3) gfilter.idev = dev;
+          else gfilter.odev = dev;        
+        }
+        break;
+      case 4:
+        if (!*++argv) show_iproute_help();
+        parse_prefix(gfilter.rvia.addr, &gfilter.rvia.netmask,
+            &gfilter.rvia.len, *argv, gfilter.rvia.family);
+        if (gfilter.rvia.len)
+          gfilter.rvia.family = ((gfilter.rvia.len == 4) ?
+              AF_INET : AF_INET6);
+        break;
+      case 5:
+        if (!*++argv) show_iproute_help();
+        idx = substring_to_idx(*argv, cmd_objectlist);
+        if (idx == 6) gfilter.tb = -1;
+        else if (idx == 9) gfilter.tb = 0;
+        else if (idx != 13) {
+          if ((gfilter.tb = idxfromRPDB(*argv, RPDB_rttables)) < 0)
+            error_exit("table %s is invalid.", *argv);
+        }
+        break;
+      case 6:
+        gfilter.tb = -1;
+        break;
+      case 7:
+        if (!*++argv) show_iproute_help();
+        idx = substring_to_idx(*argv, cmd_objectlist);
+        if (idx < 0)  if (!*++argv) show_iproute_help();
+        if (idx == 10)
+           if (!*++argv) show_iproute_help();
+          parse_prefix(gfilter.rsrc.addr, &gfilter.rsrc.netmask,
+              &gfilter.rsrc.len, *argv, gfilter.rsrc.family);
+        if (gfilter.rsrc.len)
+          gfilter.rsrc.family = ((gfilter.rsrc.len == 4) ?
+              AF_INET : AF_INET6);
+        else {
+          if ((idx == 12 ||idx == 11) && !*++argv) show_iproute_help();
+          parse_prefix(gfilter.msrc.addr, &gfilter.msrc.netmask,
+              &gfilter.msrc.len, *argv, gfilter.msrc.family);
+          if (gfilter.msrc.len)
+            gfilter.msrc.family = ((gfilter.msrc.len == 4) ?
+                AF_INET : AF_INET6);
+          if (idx != 11) gfilter.rsrc = gfilter.msrc;
+        }
+        break;
+      case 8:
+        idx = substring_to_idx(*argv, cmd_objectlist);
+        if (idx != -1 && !*++argv) show_iproute_help();
+      default: // fallthrough
+        if (idx == 10) {
+          if (!*++argv) show_iproute_help();
+          parse_prefix(gfilter.rdst.addr, &gfilter.rdst.netmask,
+              &gfilter.rdst.len, *argv, gfilter.rdst.family);
+        if (gfilter.rdst.len)
+          gfilter.rdst.family = ((gfilter.rdst.len == 4) ?
+              AF_INET : AF_INET6);
+        }
+        else {
+          if ((idx == 12 ||idx == 11) && !*++argv) show_iproute_help();
+          parse_prefix(gfilter.mdst.addr, &gfilter.mdst.netmask,
+              &gfilter.mdst.len, *argv, gfilter.mdst.family);
+          if (gfilter.mdst.len)
+            gfilter.mdst.family = ((gfilter.mdst.len == 4) ?
+                AF_INET : AF_INET6);
+          if (idx != 11) gfilter.rdst = gfilter.mdst;
+        }
+        break;
+    }
+  }
+  if (family == AF_UNSPEC && gfilter.tb) family = AF_INET;
+
+  if (TT.flush) {
+    if (gfilter.tb < 0) { // flush table cache
+      if (family != AF_INET6) {
+        FILE *fp = xfopen("/proc/sys/net/ipv4/route/flush", "w");
+
+        if (fwrite("-1",1,2,fp) < 2) error_exit("can't flush routing cache");
+        fclose(fp);
+      }
+      if (family == AF_INET) return 0;
+    }
+  }
+
+  memset(&request, 0, sizeof (request));
+  request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof (struct rtmsg));
+  request.mhdr.nlmsg_flags = NLM_F_REQUEST;
+  request.mhdr.nlmsg_flags |= NLM_F_ROOT | NLM_F_MATCH;
+  request.mhdr.nlmsg_type = RTM_GETROUTE;
+  request.msg.rtm_family = family;
+  if (gfilter.tb < 0) request.msg.rtm_flags = RTM_F_CLONED;
+  send_nlmesg(0, 0, 0, (void*)&request, sizeof (request));
+  return (filter_nlmesg(display_route_info, NULL));
+}
+
+static int route_update(char **argv, unsigned int route_flags)
+{
+  char mxbuf[256], *d = NULL;
+  struct rtattr *mxrta = (void*)mxbuf;
+  unsigned mxlock = 0, ok = 0;
+  int idx;
+  uint32_t addr[8] = {0,}, netmask = 0;
+  uint8_t len = 0;
+
+  struct arglist cmd_objectlist[] = {{"src", 0}, {"via", 1}, {"mtu", 2},
+    {"lock", 3}, {"protocol", 4}, {"table", 5}, {"dev", 6}, {"oif", 7},
+    {"to", 8}, {"metric", 9}, {NULL,-1}
+  };
+  enum {
+    gtwy_ok = 1,
+    dst_ok = 2,
+    proto_ok = 4,
+    type_ok = 8
+  };
+  struct {
+    struct nlmsghdr hdr;
+    struct rtmsg msg;
+    char buf[1024];
+  } req;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+  req.hdr.nlmsg_flags = NLM_F_ACK| NLM_F_REQUEST | route_flags;
+  req.hdr.nlmsg_type = TT.route_cmd;
+  req.msg.rtm_family = AF_UNSPEC;
+  req.msg.rtm_table = RT_TABLE_MAIN;
+  req.msg.rtm_scope = RT_SCOPE_NOWHERE;
+
+  if (TT.route_cmd != RTM_DELROUTE) {
+    req.msg.rtm_protocol = RTPROT_BOOT;
+    req.msg.rtm_scope = RT_SCOPE_UNIVERSE;
+    req.msg.rtm_type = RTN_UNICAST;
+  }
+
+  mxrta->rta_type = RTA_METRICS;
+  mxrta->rta_len = RTA_LENGTH(0);
+
+  for (; *argv; argv++) {
+    idx = substring_to_idx(*argv, cmd_objectlist);
+    if (!idx) {
+      if (!*++argv) show_iproute_help();
+      parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family);
+      if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6);
+      add_string_to_rtattr(&req.hdr, sizeof(req), RTA_PREFSRC, addr, len);
+    } else if (idx == 1) {
+      ok |= gtwy_ok;
+      if (!*++argv) show_iproute_help();
+      parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family);
+      if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6);
+      add_string_to_rtattr(&req.hdr, sizeof(req),RTA_GATEWAY, addr, len);
+    } else if (idx == 2) {
+      if (!*++argv) show_iproute_help();
+      if (substring_to_idx(*argv, cmd_objectlist ) == 3) {
+        mxlock |= (1 << RTAX_MTU);
+        if (!*++argv) show_iproute_help();
+      }
+      idx = atolx(*argv);
+      add_string_to_rtattr(&req.hdr, sizeof(req),
+          RTAX_MTU, (char*)&idx, sizeof(idx));
+    } else if (idx == 4) {
+      if (!*++argv) show_iproute_help();
+      if ((idx = idxfromRPDB(*argv,RPDB_rtprotos)) < 0)
+      error_exit("Invalid argument protocol %s.",*argv);
+      req.msg.rtm_protocol = idx;
+      ok |= proto_ok;
+    } else if (idx == 5) {
+      if (!*++argv) show_iproute_help();
+      req.msg.rtm_table = idxfromRPDB(*argv, RPDB_rttables);
+    } else if (idx == 6 || idx == 7) {
+      if (!*++argv) show_iproute_help();
+      d = *argv;
+    } else if (idx == 9) {
+      unsigned long metric;
+      unsigned int res;
+      char* ptr;
+      if (!*++argv) show_iproute_help();
+      metric = strtoul(*argv, &ptr, 0);
+		  if (!(!*ptr && metric <= 0xFFFFFFFFUL)) 
+        error_exit("Invalid argument metric %s.",*argv);
+      else
+        res = metric;
+      add_string_to_rtattr(&req.hdr, sizeof(req),
+          RTA_PRIORITY, (char*)&res, sizeof(res));
+    } else {
+      if (idx == 8)
+        if (!*++argv) show_iproute_help();
+      idx = substring_to_idx(*argv,rtmtypes);
+      if (idx != -1) {
+        if (!*++argv) show_iproute_help();
+        req.msg.rtm_type = idx;
+        ok |= type_ok;
+      }
+      if (ok & dst_ok) error_exit("Duplicate argument 'to'");
+      parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family);
+      if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6);
+      req.msg.rtm_dst_len = netmask;
+      ok |= dst_ok;
+      if (len) add_string_to_rtattr(&req.hdr, sizeof(req),RTA_DST, addr, len);
+    }
+  }
+
+  if (d) {
+    idx = get_ifaceindex(d,1);
+    add_string_to_rtattr(&req.hdr, sizeof(req),
+        RTA_OIF, (char*)&idx, sizeof(idx));
+  }
+  if (mxrta->rta_len > RTA_LENGTH(0)) {
+    if (mxlock)
+      add_string_to_rtattr(&req.hdr, sizeof(req),
+          RTAX_LOCK, (char*)&mxlock, sizeof(mxlock));
+    add_string_to_rtattr(&req.hdr, sizeof(req),
+        RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
+  }
+
+  if (req.msg.rtm_type == RTN_LOCAL || req.msg.rtm_type == RTN_NAT)
+    req.msg.rtm_scope = RT_SCOPE_HOST;
+  else if (req.msg.rtm_type == RTN_BROADCAST||req.msg.rtm_type == RTN_MULTICAST
+      || req.msg.rtm_type == RTN_ANYCAST)
+    req.msg.rtm_scope = RT_SCOPE_LINK;
+  else if (req.msg.rtm_type == RTN_UNICAST || req.msg.rtm_type == RTN_UNSPEC) {
+    if (TT.route_cmd == RTM_DELROUTE)
+      req.msg.rtm_scope = RT_SCOPE_NOWHERE;
+    else if (!(ok & gtwy_ok))
+      req.msg.rtm_scope = RT_SCOPE_LINK;
+  }
+  if (req.msg.rtm_family == AF_UNSPEC) req.msg.rtm_family = AF_INET;
+  send_nlmesg(0, 0, 0, &req, sizeof(req));
+  filter_nlmesg(NULL, NULL);
+  return 0;
+}
+
+static int iproute(char **argv)
+{
+  int idx = 1;
+  struct arglist cmd_objectlist1[] = {{"add", 0}, {"append", 1},{"change", 2},
+    {"chg", 3},{"delete",4}, {"get", 5}, {"list", 6}, {"show", 7},
+    {"prepend", 8},{"replace", 9},{"test", 10}, {"flush", 11},{NULL,-1}};
+
+  TT.route_cmd = RTM_NEWROUTE;
+  switch (idx = substring_to_idx(*argv , cmd_objectlist1)) {
+    case 0: // add
+      return route_update(++argv , NLM_F_CREATE|NLM_F_EXCL);
+    case 1: // append
+      return route_update(++argv , NLM_F_CREATE|NLM_F_APPEND);
+    case 2: // change
+    case 3: // chg
+      return route_update(++argv , NLM_F_REPLACE);
+    case 4: // delete
+      TT.route_cmd = RTM_DELROUTE;
+      return route_update(++argv , RTM_DELROUTE);
+    case 5:
+      return route_get(++argv);
+    case 6:
+    case 7:
+      return route_show_flush(++argv);
+    case 8: // prepend
+      return route_update(++argv , NLM_F_CREATE);
+    case 9: // replace
+      return route_update(++argv ,  NLM_F_CREATE|NLM_F_REPLACE);
+    case 10: // test
+      return route_update(++argv , NLM_F_EXCL);
+    case 11: // flush
+      return route_show_flush(++argv);
+    default:
+      if (!*argv) return route_show_flush(argv);
+      else show_iproute_help();
+  }
+  return 0; // non reachable code.
+}
+
+
+// ===========================================================================
+// code for ip rule.
+// ===========================================================================
+static void show_iprule_help(void)
+{
+  char *errmsg = "Usage: ip rule [ list | add | del ] SELECTOR ACTION\n"
+    "SELECTOR := [ from PREFIX ] [ to PREFIX ] [pref NUMBER] [ tos TOS ]\n"
+    "            [ fwmark FWMARK] [ dev/iif STRING ] [type TYPE]\n"
+    "ACTION := [ table TABLE_ID ] [ realms [SRCREALM/]DSTREALM ]";
+
+  error_exit(errmsg);
+}
+
+static int ruleupdate(char **argv)
+{
+  int8_t idx, tflag = 0, opt = (*argv[-1] == 'a') ? RTM_NEWRULE : RTM_DELRULE;
+  struct arglist options[] = {{"from", 0}, {"to", 1}, {"preference", 2},
+    {"order", 2}, {"priority", 2}, {"tos", 3}, {"dsfield", 3}, {"fwmark", 4},
+    {"realms", 5}, {"table", 6}, {"lookup", 6}, {"dev", 7}, {"iif", 7},
+    {"nat", 8}, {"map-to", 8}, {"type", 9}, {"help", 10}, {NULL, -1}};
+  struct {
+    struct nlmsghdr mhdr;
+    struct rtmsg    msg;
+    char buf[1024];
+  } request;
+
+  memset(&request, 0, sizeof(request));
+  request.mhdr.nlmsg_type = opt;
+  request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+  request.mhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK |
+    ((opt == RTM_DELRULE) ? 0 : NLM_F_CREATE | NLM_F_EXCL);
+  request.msg.rtm_family = TT.addressfamily;
+  request.msg.rtm_protocol = RTPROT_BOOT;
+  request.msg.rtm_scope = RT_SCOPE_UNIVERSE;
+  request.msg.rtm_table = 0;
+  request.msg.rtm_type = ((opt == RTM_DELRULE) ? RTN_UNSPEC : RTN_UNICAST);
+
+  for (; *argv; argv++) {
+    switch ((idx = substring_to_idx(*argv, options))) {
+      case 0:
+      case 1: 
+        { // e.g. from IP/Netmask and to IP/Netmask.
+          uint32_t addr[4] = {0,}, netmask = 0;
+          uint8_t len = 0, *tmp;
+
+          if (!*++argv) error_exit("'%s': Missing Prefix", argv[-1]);
+          parse_prefix(addr, &netmask, &len, *argv, request.msg.rtm_family);
+
+          tmp = idx ? &request.msg.rtm_dst_len : &request.msg.rtm_src_len;
+          if (!netmask) *tmp = 0;
+          else *tmp = netmask;
+
+          add_string_to_rtattr(&request.mhdr, sizeof(request),
+              (idx ? RTA_DST : RTA_SRC), addr, len);
+        }
+        break;
+      case 2:
+      case 4: 
+        { // e.g. Preference p# and fwmark MARK
+          uint32_t pref;
+          char *ptr;
+
+          if (!*++argv)
+            error_exit("Missing %s", (idx == 2) ? "Preference" : "fwmark");
+          pref = strtoul(*argv, &ptr, 0);
+          if (!ptr || (ptr == *argv) || *ptr  || pref > 0xFFFFFFFFUL)
+            error_exit("Invalid %s",  (idx == 2) ? "Preference" : "fwmark");
+          add_string_to_rtattr(&request.mhdr, sizeof(request),
+              ((idx == 2) ? RTA_PRIORITY : RTA_PROTOINFO),
+              (void *)&pref, sizeof(uint32_t));
+        }
+        break;
+      case 3:
+        {
+          uint32_t tos;
+          if (!*++argv) error_exit("Missing TOS key");
+          if ((tos = idxfromRPDB(*argv, RPDB_rtdsfield)) < 0)
+            error_exit("Invalid TOS");
+          request.msg.rtm_tos = tos;
+        }
+        break;
+      case 5:
+        { // e.g. realms FROM_realm/TO_realm
+          uint32_t realms = 0;
+          int ret;
+          char *ptr;
+
+          if (!*++argv) error_exit("Missing REALMSID");
+          if ((ptr = strchr(*argv, '/'))) {
+            *ptr = 0;
+            if ((ret = idxfromRPDB(*argv, RPDB_rtrealms)) < 0)
+              error_exit("Invalid realms");
+            realms = ret;
+            realms <<= 16;
+            *ptr++ = '/';
+          } else ptr = *argv;
+          if ((ret = idxfromRPDB(ptr, RPDB_rtrealms)) < 0)
+            error_exit("Invalid realms");
+          realms |= ret;
+          add_string_to_rtattr(&request.mhdr, sizeof(request),
+              RTA_FLOW, (void *)&realms, sizeof(uint32_t));
+        }
+        break;
+      case 6:
+        { // e.g. table tid/tableName
+          int tid;
+          if (!*++argv) error_exit("Missing TableID");
+          if ((tid = idxfromRPDB(*argv, RPDB_rttables)) < 0)
+            error_exit("Invalid TID");
+          request.msg.rtm_table = tid;
+          tflag = 1;
+        }
+        break;
+      case 7:
+        {
+          if (!*++argv) error_exit("Missing dev/iif NAME");
+          add_string_to_rtattr(&request.mhdr, sizeof(request),
+              RTA_IIF, *argv, strlen(*argv)+1);
+        }
+        break;
+      case 8:
+        {
+          uint32_t addr[4] = {0,};
+          uint8_t af = AF_UNSPEC;
+
+          if (!*++argv) error_exit("Missing nat/map-to ADDRESS");
+          if (get_prefix(addr, &af /* Un-used variable */, *argv, AF_INET))
+            error_exit("Invalid mapping Address");
+
+          add_string_to_rtattr(&request.mhdr, sizeof(request),
+              RTA_GATEWAY, addr, sizeof(uint32_t));
+          request.msg.rtm_type = RTN_NAT;
+        }
+        break;
+      case 9:
+        {
+          if (!*++argv) error_exit("TYPE Missing");
+          request.msg.rtm_type = rtmtype_str2idx(*argv);
+        }
+        break;
+      case 10: 
+        show_iprule_help();
+        break; // Unreachable code.
+      default: 
+        error_exit("Invalid argument '%s'", *argv);
+        break; // Unreachable code.
+    }
+  }
+
+  if (!request.msg.rtm_family) request.msg.rtm_family = AF_INET;
+  if (!tflag && opt == RTM_NEWRULE) request.msg.rtm_table = RT_TABLE_MAIN;
+
+  send_nlmesg(0, 0, 0, &request, sizeof(request));
+  return (filter_nlmesg(NULL, NULL));
+}
+
+static int show_rules(struct nlmsghdr *mhdr,
+    char **argv __attribute__ ((__unused__)))
+{
+  struct rtmsg *msg = NLMSG_DATA(mhdr);
+  struct rtattr *rta, *attr[RTA_MAX+1] = {0,};
+  int32_t tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
+  int hlen = ((msg->rtm_family == AF_INET) ? 32
+      : ((msg->rtm_family == AF_INET6) ? 128 : -1));
+
+  if (mhdr->nlmsg_type != RTM_NEWRULE) return 0;
+  if (msglen < 0) return 1;
+
+  tvar = msglen;
+  for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar))
+    if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta;
+
+  if (tvar) error_msg("deficit %d, rtalen = %d!", tvar, rta->rta_len);
+
+  printf("%u:\tfrom ", attr[RTA_PRIORITY] ?
+      *(unsigned *)RTA_DATA(attr[RTA_PRIORITY]) : 0);
+
+  if (attr[RTA_SRC]) {
+    printf("%s", (msg->rtm_family == AF_INET || msg->rtm_family == AF_INET6)
+        ? inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_SRC]),
+          toybuf, sizeof(toybuf))
+        : "???");
+    (msg->rtm_src_len != hlen) ? printf("/%u", msg->rtm_src_len) : 0;
+  } else msg->rtm_src_len ? printf("0/%d", msg->rtm_src_len) : printf("all");
+
+  xputc(' ');
+  if (attr[RTA_DST]) {
+    printf("to %s", (msg->rtm_family == AF_INET || msg->rtm_family == AF_INET6)
+        ? inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_DST]),
+          toybuf, sizeof(toybuf))  : "???");
+    (msg->rtm_dst_len != hlen) ? printf("/%u", msg->rtm_dst_len) : xputc(' ');
+  } else if (msg->rtm_dst_len)
+    printf("to 0/%d ", msg->rtm_dst_len);
+
+  if (msg->rtm_tos)
+    printf("tos %s ", namefromRPDB(msg->rtm_tos, RPDB_rtdsfield));
+
+  if (attr[RTA_PROTOINFO])
+    printf("fwmark %#x ", *(uint32_t*)RTA_DATA(attr[RTA_PROTOINFO]));
+
+  if (attr[RTA_IIF]) printf("iif %s ", (char*)RTA_DATA(attr[RTA_IIF]));
+
+  if (msg->rtm_table)
+    printf("lookup %s ", namefromRPDB(msg->rtm_table, RPDB_rttables));
+
+  if (attr[RTA_FLOW]) {
+    u_int32_t from, to = *(u_int32_t *)RTA_DATA(attr[RTA_FLOW]);
+    char *format = "realms %s/";
+
+    to = (from = (to >> 16)) & 0xFFFF;
+    format = (from ? format: "%s");
+    printf(format, namefromRPDB((from ? from : to), RPDB_rtrealms));
+  }
+
+  if (msg->rtm_type == RTN_NAT) {
+    if (!attr[RTA_GATEWAY]) printf("masquerade");
+    else printf("map-to %s ", inet_ntop(msg->rtm_family,
+          RTA_DATA(attr[RTA_GATEWAY]), toybuf, sizeof(toybuf)));
+  } else if (msg->rtm_type != RTN_UNICAST)
+    printf("%s", rtmtype_idx2str(msg->rtm_type));
+
+  xputc('\n');
+  return 0;
+}
+
+static int rulelist(char **argv)
+{
+  if (*argv) {
+    error_msg("'ip rule show' does not take any arguments.");
+    return 1;
+  }
+  send_nlmesg(RTM_GETRULE, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
+      ((TT.addressfamily != AF_UNSPEC) ? TT.addressfamily : AF_INET), NULL, 0);
+  return filter_nlmesg(show_rules, argv);
+}
+
+static int iprule(char **argv)
+{
+  int idx;
+  struct arglist options[] = {{"add", 0}, {"delete", 0}, {"list", 1},
+    {"show", 1}, {NULL, -1}};
+  cmdobj ipcmd, cmdobjlist[] = {ruleupdate, rulelist};
+
+  if (!*argv) idx = 1;
+  else if ((idx = substring_to_idx(*argv++, options)) == -1)
+    show_iprule_help();
+  ipcmd = cmdobjlist[idx];
+  return ipcmd(argv);
+}
+//============================================================================
+// code for ip tunnel.
+//============================================================================
+static void show_iptunnel_help(void)
+{
+  char *errmsg = "Usage: iptunnel { add | change | del | show } [NAME]\n"
+    "           [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n"
+    "           [[i|o]seq] [[i|o]key KEY] [[i|o]csum] [ttl TTL]\n"
+    "           [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]";
+
+  error_exit(errmsg);
+}
+
+static int tnl_ioctl(char *dev, int rtype, struct ip_tunnel_parm *ptnl)
+{
+  struct ifreq req;
+  int fd, ret = 0;
+
+  if ((rtype == SIOCCHGTUNNEL || rtype == SIOCDELTUNNEL) && *ptnl->name)
+    xstrncpy(req.ifr_name, ptnl->name, IF_NAMESIZE);
+  else xstrncpy(req.ifr_name, dev, IF_NAMESIZE);
+
+  if (rtype != SIOCGIFHWADDR) req.ifr_ifru.ifru_data = (void*)ptnl;
+  fd = xsocket(AF_INET, SOCK_DGRAM, 0);
+
+  if (rtype == SIOCGETTUNNEL) ret = ioctl(fd, rtype, &req);
+  else if (rtype == SIOCGIFHWADDR)
+    ret = (ioctl(fd, rtype, &req) < 0) ? -1 : req.ifr_addr.sa_family;
+  else xioctl(fd, rtype, &req);
+
+  close(fd);
+  return ret;
+}
+
+static int display_tunnel(struct ip_tunnel_parm *ptnl)
+{
+  char rmt_addr[64], lcl_addr[64], ikey_str[64], okey_str[64];
+
+  printf("%s: %s/ip", ptnl->name, ptnl->iph.protocol == IPPROTO_IPIP ? "ip" :
+      (ptnl->iph.protocol == IPPROTO_GRE ? "gre" :
+       (ptnl->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown")));
+  printf("  remote %s  local %s ", ptnl->iph.daddr ?
+      inet_ntop(AF_INET, &ptnl->iph.daddr, rmt_addr, sizeof(rmt_addr)) : "any",
+      ptnl->iph.saddr ? inet_ntop(AF_INET, &ptnl->iph.saddr, lcl_addr,
+        sizeof(lcl_addr)) : "any");
+  if (ptnl->link) {
+    struct ifreq req;
+    int fd;
+
+    req.ifr_ifindex = ptnl->link;
+    fd = xsocket(AF_INET, SOCK_DGRAM, 0);
+    if (ioctl(fd, SIOCGIFNAME, &req) < 0) perror_msg("SIOCGIFNAME");
+    else printf(" dev %s ", req.ifr_name);
+    close(fd);
+  }
+  if (ptnl->iph.ttl) printf(" ttl %d ", ptnl->iph.ttl);
+  else printf(" ttl inherit ");
+
+  if (ptnl->iph.tos) {
+    printf(" tos");
+    if (ptnl->iph.tos & 1) printf(" inherit");
+    if (ptnl->iph.tos & ~1) printf("%c%s ", ptnl->iph.tos & 1 ? '/' : ' ',
+        namefromRPDB((ptnl->iph.tos & ~1), RPDB_rtdsfield));
+  }
+  if (!(ptnl->iph.frag_off & htons(IP_DF))) printf(" nopmtudisc");
+  inet_ntop(AF_INET, &ptnl->i_key, ikey_str, sizeof(ikey_str));
+  if ((ptnl->i_flags & GRE_KEY) && (ptnl->o_flags & GRE_KEY)
+      && ptnl->o_key == ptnl->i_key) printf(" key %s", ikey_str);
+  else if ((ptnl->i_flags | ptnl->o_flags) & GRE_KEY) {
+    inet_ntop(AF_INET, &ptnl->o_key, okey_str, sizeof(okey_str));
+    if (ptnl->i_flags & GRE_KEY) printf(" ikey %s ", ikey_str);
+    if (ptnl->o_flags & GRE_KEY) printf(" okey %s ", okey_str);
+  }
+  if (ptnl->i_flags & GRE_SEQ) printf("\n  Drop packets out of sequence.\n");
+  if (ptnl->i_flags & GRE_CSUM)
+    printf("\n  Checksum in received packet is required.");
+  if (ptnl->o_flags & GRE_SEQ) printf("\n  Sequence packets on output.");
+  if (ptnl->o_flags & GRE_CSUM) printf("\n  Checksum output packets.");
+  xputc('\n');
+  return 0;
+}
+
+static int read_tunnel(struct ip_tunnel_parm *ptnl)
+{
+  int count = 0;
+  char iface[IF_NAMESIZE];
+  struct ip_tunnel_parm iptnl;
+  FILE *fp = xfopen("/proc/net/dev", "r");
+
+  while (fgets(toybuf, sizeof(toybuf), fp)) {
+    char *ptr;
+    int ret;
+
+    if (count++ < 2) continue; // 1st two lines are header.
+
+    ptr = strchr(toybuf, ':');
+    if (!ptr || (*ptr++ = 0, sscanf(toybuf, "%s", iface) != 1))
+      error_exit("invalid format of '/proc/net/dev'");
+    if (*ptnl->name && strcmp(ptnl->name, iface)) continue;
+    if ((ret = tnl_ioctl(iface, SIOCGIFHWADDR, &iptnl)) < 0) {
+      error_msg("failed to get type of '%s'", iface);
+      continue;
+    }
+    if (ret != ARPHRD_TUNNEL && ret !=  ARPHRD_SIT &&
+        ret != ARPHRD_IPGRE) continue;
+
+    memset(&iptnl, 0, sizeof(iptnl));
+    if (tnl_ioctl(iface, SIOCGETTUNNEL, &iptnl) < 0) continue;
+    if ((ptnl->link && iptnl.link != ptnl->link) || (*ptnl->name &&
+          strcmp(iptnl.name, ptnl->name)) || (ptnl->iph.daddr &&
+          iptnl.iph.daddr != ptnl->iph.daddr) || (ptnl->iph.saddr &&
+            iptnl.iph.saddr != ptnl->iph.saddr) || (ptnl->i_key &&
+              iptnl.i_key != ptnl->i_key)) continue;
+    display_tunnel(&iptnl);
+  }
+  fclose(fp);
+  return 0;
+}
+
+static void parse_iptunnel_args(struct ip_tunnel_parm *ptnl, char **argv, 
+    int ipt_opt_idx)
+{
+  int idx;
+  uint8_t af = AF_INET;
+  uint32_t addr = 0;
+  struct arglist opts[] = { {"mode", 0}, {"key", 1}, {"ikey", 2},
+    {"okey", 3}, {"seq", 4}, {"iseq", 5}, {"oseq", 6}, {"csum", 7},
+    {"icsum", 8}, {"ocsum", 9}, {"nopmtudisc", 10}, {"pmtudisc", 11},
+    {"remote", 12}, {"local", 13},{"dev", 14}, {"ttl", 15}, {"tos", 16},
+    {"dsfield", 17}, {"name", 18}, {NULL, -1} 
+  };
+
+  ptnl->iph.version = 4; // The value indicates the version of IP (4 or 6)
+  ptnl->iph.ihl = 5; // Minimum Internet Header Length
+  // frag_off is measured in units of 8 octets (64 bits)
+  ptnl->iph.frag_off = htons(IP_DF);
+  if (*argv && ipt_opt_idx <= 2 && string_to_idx(*argv, opts) == -1) {
+    xstrncpy(ptnl->name, *argv, IF_NAMESIZE);
+    if (ipt_opt_idx == 1) {
+      struct ip_tunnel_parm iptnl_old;
+
+      memset(&iptnl_old, 0, sizeof(iptnl_old));
+      tnl_ioctl(ptnl->name, SIOCGETTUNNEL, &iptnl_old);
+      *ptnl = iptnl_old;
+    }
+    argv++;
+  }
+  for (; *argv; argv++, addr = 0) {
+    switch (idx = string_to_idx(*argv, opts)) {
+      case 0:
+        if (!*++argv) error_exit("mode is missing");
+        if ((!strcmp("ipip", *argv) || !strcmp("ip/ip", *argv)))
+          ptnl->iph.protocol = IPPROTO_IPIP;
+        else if ((!strcmp("gre", *argv) || !strcmp("gre/ip", *argv)))
+          ptnl->iph.protocol = IPPROTO_GRE;
+        else if ((!strcmp("sit", *argv) || !strcmp("ipv6/ip", *argv)))
+          ptnl->iph.protocol = IPPROTO_IPV6;
+        else show_iptunnel_help();
+        break;
+      case 1:
+      case 2:
+      case 3:
+        {
+          struct addrinfo *info, hint;
+          int ret;
+
+          if (!*++argv) error_exit("key value is missing");
+          memset(&hint, 0, sizeof(hint));
+          hint.ai_family = AF_INET;
+          ret = getaddrinfo(*argv, NULL, &hint, &info);
+          if (ret || !info) error_exit("invalid argument to key");
+          freeaddrinfo(info);
+
+          if (strchr(*argv, '.')) {
+            if (get_prefix(&addr, &af, *argv, AF_INET))
+              error_exit("invalid key '%s'", *argv);
+          } else {
+            unsigned key_val;
+
+            sscanf(*argv, "%u", &key_val);
+            addr = htonl(key_val);
+          }
+          if (idx == 1) {
+            ptnl->i_flags |= GRE_KEY;
+            ptnl->o_flags |= GRE_KEY;
+            ptnl->i_key = ptnl->o_key = addr;
+          } else if (idx == 2) {
+            ptnl->i_flags |= GRE_KEY;
+            ptnl->i_key = addr;
+          } else {
+            ptnl->o_flags |= GRE_KEY;
+            ptnl->o_key = addr;
+          }
+        }
+        break;
+      case 4:
+        ptnl->i_flags |= GRE_SEQ;
+        ptnl->o_flags |= GRE_SEQ;
+        break;
+      case 5:
+        ptnl->i_flags |= GRE_SEQ;
+        break;
+      case 6:
+        ptnl->o_flags |= GRE_SEQ;
+        break;
+      case 7:
+        ptnl->i_flags |= GRE_CSUM;
+        ptnl->o_flags |= GRE_CSUM;
+        break;
+      case 8:
+        ptnl->i_flags |= GRE_CSUM;
+        break;
+      case 9:
+        ptnl->o_flags |= GRE_CSUM;
+        break;
+      case 10:
+        ptnl->iph.frag_off = 0;
+        break;
+      case 11:
+        ptnl->iph.frag_off = htons(IP_DF);
+        break;
+      case 12:
+      case 13:
+        if (!*++argv) error_exit("remote/local address is missing");
+        if (get_prefix(&addr, &af, *argv, AF_INET))
+          error_exit("invalid remote/local address '%s'", *argv);
+        (idx == 12) ? (ptnl->iph.daddr = addr) : (ptnl->iph.saddr = addr);
+        break;
+      case 14:
+        if (!*++argv) error_exit("device name is missing");
+        else {
+          struct ifreq req;
+          int fd;
+
+          xstrncpy(req.ifr_name, *argv, IFNAMSIZ);
+          fd = xsocket(AF_INET, SOCK_DGRAM, 0);
+          xioctl(fd, SIOCGIFINDEX, &req);
+          close(fd);
+          ptnl->link = req.ifr_ifindex;
+        }
+        break;
+      case 15:
+        if (!*++argv) error_exit("ttl value is missing");
+        if (strcmp(*argv, "inherit"))
+          ptnl->iph.ttl = atolx_range(*argv, 0, 255);
+        break;
+      case 16:
+      case 17:
+        if (!*++argv) error_exit("tos value is missing");
+        if (strcmp(*argv, "inherit")) {
+          char *ptr;
+          unsigned long tval = strtoul(*argv, &ptr, 16);
+
+          if (tval > 255) error_exit("invalid tos value '%s'", *argv);
+          if (*ptr) {
+            int ret;
+
+            if ((ret = idxfromRPDB(*argv, RPDB_rtdsfield)) < 0)
+              error_exit("invalid tos value");
+            ptnl->iph.tos = ret;
+          } else ptnl->iph.tos = tval;
+        } else ptnl->iph.tos = 1;
+        break;
+      case 18:
+        if (*ptnl->name) error_exit("invalid tunnel");
+        else {
+          if (!*++argv) error_exit("name is missing");
+          xstrncpy(ptnl->name, *argv, IF_NAMESIZE);
+        }
+        break;
+      default:
+        if (*ptnl->name) error_exit("invalid tunnel");
+        xstrncpy(ptnl->name, *argv, IF_NAMESIZE);
+        break;
+    }
+  }
+  if (ptnl->iph.protocol == IPPROTO_IPIP ||
+      ptnl->iph.protocol == IPPROTO_IPV6) {
+    if ((ptnl->i_flags & GRE_KEY) || (ptnl->o_flags & GRE_KEY))
+      error_exit("[i|o]key is allowed with gre only");
+    if ((ptnl->i_flags & GRE_SEQ) || (ptnl->o_flags & GRE_SEQ))
+      error_exit("[i|o]seq is allowed with gre only");
+    if ((ptnl->i_flags & GRE_CSUM) || (ptnl->o_flags & GRE_CSUM))
+      error_exit("[i|o]csum is allowed with gre only");
+  }
+  if (!ptnl->i_key && IN_MULTICAST(ntohl(ptnl->iph.daddr))) {
+    ptnl->i_key = ptnl->iph.daddr;
+    ptnl->i_flags |= GRE_KEY;
+  }
+  if (!ptnl->o_key && IN_MULTICAST(ntohl(ptnl->iph.daddr))) {
+    ptnl->o_key = ptnl->iph.daddr;
+    ptnl->o_flags |= GRE_KEY;
+  }
+  if (IN_MULTICAST(ntohl(ptnl->iph.daddr)) && !ptnl->iph.saddr)
+    error_exit("broadcast tunnel requires a source address");
+}
+
+static int tunnellist(char **argv)
+{
+  struct ip_tunnel_parm iptnl;
+  int ret = 0;
+
+  memset(&iptnl, 0, sizeof(iptnl));
+  parse_iptunnel_args(&iptnl, argv, 3);
+
+  if (iptnl.iph.protocol == IPPROTO_IPIP) 
+    ret = tnl_ioctl(*iptnl.name ? iptnl.name : "tunl0", SIOCGETTUNNEL, &iptnl);
+  else if (iptnl.iph.protocol == IPPROTO_GRE) 
+    ret = tnl_ioctl(*iptnl.name ? iptnl.name : "gre0", SIOCGETTUNNEL, &iptnl);
+  else if (iptnl.iph.protocol == IPPROTO_IPV6) 
+    ret = tnl_ioctl(*iptnl.name ? iptnl.name : "sit0", SIOCGETTUNNEL, &iptnl);
+  else return read_tunnel(&iptnl);
+
+  if (ret < 0) {
+    perror_msg("SIOCGETTUNNEL");
+    return ret;
+  } else return display_tunnel(&iptnl);
+}
+
+// Performing add, change, & delete tunnel action, according to passed req_type
+static int tunnelupdate(char **argv)
+{
+  struct ip_tunnel_parm iptnl;
+  int idx = 2, rtype = SIOCDELTUNNEL;
+
+  if (*argv[-1] == 'a') {
+    idx = 0;
+    rtype = SIOCADDTUNNEL;
+  } else if (*argv[-1] == 'c') {
+    idx = 1;
+    rtype = SIOCCHGTUNNEL;
+  }
+
+  memset(&iptnl, 0, sizeof(iptnl));
+  parse_iptunnel_args(&iptnl, argv, idx);
+  if (idx != 2 && iptnl.iph.ttl && !(iptnl.iph.frag_off))
+    error_exit("ttl > 0 and nopmtudisc are incompatible");
+  if (iptnl.iph.protocol == IPPROTO_IPIP)
+    return (tnl_ioctl("tunl0", rtype, &iptnl) < 0) ? 1 : 0;
+  else if (iptnl.iph.protocol == IPPROTO_GRE)
+    return (tnl_ioctl("gre0", rtype, &iptnl) < 0) ? 1 : 0;
+  else if (iptnl.iph.protocol == IPPROTO_IPV6)
+    return (tnl_ioctl("sit0", rtype, &iptnl) < 0) ? 1 : 0;
+  else {
+    if (idx != 2) error_exit("invalid tunnel mode");
+    return (tnl_ioctl(iptnl.name, rtype, &iptnl) < 0) ? 1 : 0;
+  }
+}
+
+static int iptunnel(char **argv)
+{
+  int idx;
+  struct arglist opts[] = {{"add", 0}, {"change", 0}, {"del", 0},
+    {"delete", 0}, {"show", 1}, {"list", 1}, {"lst", 1}, {NULL, -1}
+  };
+  cmdobj ipcmd, cmdobjlist[] = {tunnelupdate, tunnellist};
+
+  if (!*argv) idx = 1;
+  else if ((idx = substring_to_idx(*argv++, opts)) == -1)
+    show_iptunnel_help();
+  ipcmd = cmdobjlist[idx];
+  return ipcmd(argv);
+}
+
+// ===========================================================================
+// Common code, which is used for all ip options.
+// ===========================================================================
+
+// Parse netlink messages and call input callback handler for action
+static int filter_nlmesg(int (*fun)(struct nlmsghdr *mhdr, char **argv),
+    char **argv)
+{
+  while (1) {
+    struct nlmsghdr *mhdr;
+    int msglen = recv(TT.sockfd, TT.gbuf, MESG_LEN, 0);
+
+    if ((msglen < 0) && (errno == EINTR || errno == EAGAIN)) continue;
+    else if (msglen < 0) {
+      error_msg("netlink receive error %s", strerror(errno));
+      return 1;
+    } else if (!msglen) {
+      error_msg("EOF on netlink");
+      return 1;
+    }
+
+    for (mhdr = (struct nlmsghdr*)TT.gbuf; NLMSG_OK(mhdr, msglen);
+        mhdr = NLMSG_NEXT(mhdr, msglen)) {
+      int err;
+      if (mhdr->nlmsg_pid != getpid())
+        continue;
+      switch (mhdr->nlmsg_type) {
+        case NLMSG_DONE:
+          return 0;
+        case NLMSG_ERROR:
+          {
+            struct nlmsgerr *merr = (struct nlmsgerr*)NLMSG_DATA(mhdr);
+
+            if (merr->error == 0) return 0;
+            if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+              error_msg("ERROR truncated");
+            else {
+              errno = -merr->error;
+              perror_msg("RTNETLINK answers");
+            }
+            return 1;
+          }
+        default:
+          if (fun && (err = fun(mhdr, argv))) return err;
+          break;
+      }
+    } // End of for loop.
+  } // End of while loop.
+  return 0;
+}
+
+void ip_main(void)
+{
+  char **optargv = toys.argv;
+  int idx, isip = !(toys.which->name[2]); //1 -> if only ip
+  cmdobj ipcmd, cmdobjlist[] = {ipaddr, iplink, iproute, iprule, iptunnel};
+
+  for (++optargv; *optargv; ++optargv) {
+    char *ptr = *optargv;
+    struct arglist ip_options[] = {{"oneline", 0}, {"family",  1},
+      {"4", 1}, {"6", 1}, {"0", 1}, {"stats", 2}, {NULL, -1}};
+
+    if (*ptr != '-') break;
+    else if ((*(ptr+1) == '-') && (*(ptr+2))) ptr +=2;
+    //escape "--" and stop ip arg parsing.
+    else if ((*(ptr+1) == '-') && (!*(ptr+2))) {
+      *ptr +=1;
+      break;
+    } else ptr +=1;
+    switch (substring_to_idx(ptr, ip_options)) {
+      case 0: TT.singleline = 1;
+              break;
+      case 1: {
+                if (isdigit(*ptr)) {
+                  long num = atolx(ptr);
+                  if (num == 4) TT.addressfamily  = AF_INET;
+                  else if (num == 6) TT.addressfamily  = AF_INET6;
+                  else TT.addressfamily = AF_PACKET;
+                } else {
+                  struct arglist ip_aflist[] = {{"inet", AF_INET},
+                    {"inet6", AF_INET6}, {"link", AF_PACKET}, {NULL, -1}};
+
+                  if (!*++optargv) help_exit(0);
+                  if ((TT.addressfamily = string_to_idx(*optargv, ip_aflist)) == -1)
+                    error_exit("wrong family '%s'", *optargv);
+                }
+              }
+              break;
+      case 2:
+              TT.stats++;
+              break;
+      default: help_exit(0);
+               break; // unreachable code.
+    }
+  }
+
+  TT.sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+
+  if (isip) {// only for ip
+    if (*optargv) {
+      struct arglist ip_objectlist[] = { {"address", 0}, {"link", 1},
+        {"route", 2}, {"rule", 3}, {"tunnel", 4}, {"tunl", 4}, {NULL, -1}};
+
+      if ((idx = substring_to_idx(*optargv, ip_objectlist)) == -1) help_exit(0);
+      ipcmd = cmdobjlist[idx];
+      toys.exitval = ipcmd(++optargv);
+    } else help_exit(0);
+  } else {
+    struct arglist ip_objectlist[] = { {"ipaddr", 0}, {"iplink", 1},
+      {"iproute", 2}, {"iprule", 3}, {"iptunnel", 4}, {NULL, -1}};
+    if ((idx = string_to_idx(toys.which->name, ip_objectlist)) == -1)
+      help_exit(0);
+    ipcmd = cmdobjlist[idx];
+    toys.exitval = ipcmd(optargv);
+  }
+  xclose(TT.sockfd);
+  if (rtdsfield_init) free_alist(rt_dsfield);
+  if (rtrealms_init) free_alist(rt_realms);
+  if (rtscope_init) free_alist(rt_scope);
+  if (rttable_init) free_alist(rt_tables);
+  if (rtprotos_init) free_alist(rt_protos);
+}
diff --git a/toybox/toys/pending/ipcrm.c b/toybox/toys/pending/ipcrm.c
new file mode 100644
index 0000000..cec1b12
--- /dev/null
+++ b/toybox/toys/pending/ipcrm.c
@@ -0,0 +1,88 @@
+/* ipcrm.c - remove msg que, sem or shared memory
+ *
+ * Copyright 2014 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ipcrm.html
+
+
+USE_IPCRM(NEWTOY(ipcrm, "m*M*s*S*q*Q*", TOYFLAG_USR|TOYFLAG_BIN))
+
+config IPCRM
+  bool "ipcrm"
+  default n
+  help
+    usage: ipcrm [ [-q msqid] [-m shmid] [-s semid]
+              [-Q msgkey] [-M shmkey] [-S semkey] ... ]
+
+    -mM Remove memory segment after last detach
+    -qQ Remove message queue
+    -sS Remove semaphore
+*/
+
+#define FOR_ipcrm
+#include "toys.h"
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/msg.h>
+
+GLOBALS(
+  struct arg_list *qkey;
+  struct arg_list *qid;
+  struct arg_list *skey;
+  struct arg_list *sid;
+  struct arg_list *mkey;
+  struct arg_list *mid;
+)
+
+static void do_ipcrm(int key, int ipc, char *name)
+{
+  char *c;
+  int id, ret = 0;
+
+  id = strtol(name, &c, 0);
+  if (*c) {
+    error_msg("invalid number :%s", name);
+    return;
+  }
+
+  if (key) {
+    if (id == IPC_PRIVATE) {
+      error_msg("illegal key (%s)", name);
+      return;
+    }
+    id = ((ipc == 1)?shmget(id, 0, 0) :
+         (ipc == 2)? msgget(id, 0): semget(id, 0, 0));
+    if (id < 0) {
+      perror_msg("key (%s)", name);
+      return;
+    }
+  }
+
+  if (ipc == 1) ret = shmctl(id, IPC_RMID, NULL);
+  else if (ipc == 2) ret = msgctl(id, IPC_RMID, NULL);
+  else if (ipc == 3) ret = semctl(id, 0, IPC_RMID, NULL);
+
+  if (ret < 0) perror_msg("%s (%s)", ((key)? "key": "id"), name);
+}
+
+void ipcrm_main(void)
+{
+  ++toys.argv;
+  if (toys.optc && (!strcmp(*toys.argv, "shm") ||
+        !strcmp(*toys.argv, "sem") || !strcmp(*toys.argv, "msg"))) {
+    int t = (toys.argv[0][1] == 'h')? 1 : (toys.argv[0][1] == 's')? 2:3;
+
+    while (*(++toys.argv)) do_ipcrm(0, t, *toys.argv); 
+  } else {
+    struct arg_list *tmp;
+
+    for (tmp = TT.mkey; tmp; tmp = tmp->next) do_ipcrm(1, 1, tmp->arg);
+    for (tmp = TT.mid; tmp; tmp = tmp->next) do_ipcrm(0, 1, tmp->arg);
+    for (tmp = TT.qkey; tmp; tmp = tmp->next) do_ipcrm(1, 2, tmp->arg);
+    for (tmp = TT.qid; tmp; tmp = tmp->next) do_ipcrm(0, 2, tmp->arg);
+    for (tmp = TT.skey; tmp; tmp = tmp->next) do_ipcrm(1, 3, tmp->arg);
+    for (tmp = TT.sid; tmp; tmp = tmp->next) do_ipcrm(0, 3, tmp->arg);
+    if (toys.optc) help_exit("unknown argument: %s", *toys.optargs);
+  }
+}
diff --git a/toybox/toys/pending/ipcs.c b/toybox/toys/pending/ipcs.c
new file mode 100644
index 0000000..b5986af
--- /dev/null
+++ b/toybox/toys/pending/ipcs.c
@@ -0,0 +1,447 @@
+/* ipcs.c - provide information on ipc facilities
+ *
+ * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ *
+ * see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ipcs.html
+
+USE_IPCS(NEWTOY(ipcs, "acptulsqmi#", TOYFLAG_USR|TOYFLAG_BIN))
+
+config IPCS
+  bool "ipcs"
+  default n
+  help
+    usage: ipcs [[-smq] -i shmid] | [[-asmq] [-tcplu]]
+
+    -i Show specific resource
+    Resource specification:
+    -a All (default)
+    -m Shared memory segments
+    -q Message queues
+    -s Semaphore arrays
+    Output format:
+    -c Creator
+    -l Limits
+    -p Pid
+    -t Time
+    -u Summary
+*/
+
+#define FOR_ipcs
+#include "toys.h"
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/msg.h>
+
+GLOBALS(
+  int id;
+)
+
+//used many times, so good to paste it
+#define flag(x) (toys.optflags & FLAG_ ## x)
+
+union semun { //man says declare it yourself
+  int              val;
+  struct semid_ds *buf;
+  unsigned short  *array;
+  struct seminfo  *__buf;
+};
+
+static void show_msg_id(void)
+{
+  struct msqid_ds buf;
+  int ret;
+
+  if ((ret = msgctl(TT.id, IPC_STAT, &buf)) < 0) {
+    perror_msg("msgctl");
+    return;
+  }
+
+#define ipcperm buf.msg_perm
+
+  printf("\nMessage Queue msqid=%d\n"
+      "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\tmode=%#o\n",
+      TT.id, ipcperm.uid, ipcperm.gid, ipcperm.cuid, ipcperm.cgid,ipcperm.mode);
+  printf ("cbytes=%ld\tqbytes=%ld\tqnum=%ld\tlspid=%d\tlrpid=%d\n",
+      (long) buf.msg_cbytes, (long) buf.msg_qbytes,
+      (long) buf.msg_qnum, buf.msg_lspid, buf.msg_lrpid);
+
+  printf("send_time=%-26.24s\nrcv_time=%-26.24s\nchange_time=%-26.24s\n\n",
+      buf.msg_stime ? ctime(&buf.msg_stime) : "Not set",
+      buf.msg_rtime ? ctime(&buf.msg_rtime) : "Not set",
+      buf.msg_ctime ? ctime(&buf.msg_ctime) : "Not set");
+#undef ipcperm
+}
+
+static void show_sem_id(void)
+{
+  struct semid_ds buf;
+  union semun n;
+  int ret, i;
+
+  n.buf = &buf;
+  if ((ret = semctl(TT.id, 0, IPC_STAT, n)) < 0) {
+    perror_msg("semctl");
+    return;
+  }
+
+#define ipcperm buf.sem_perm
+  printf("\nSemaphore Array semid=%d\n"
+      "uid=%d\t gid=%d\t cuid=%d\t cgid=%d\n"
+      "mode=%#o, access_perms=%#o\n"
+      "nsems = %ld\n"
+      "otime = %-26.24s\n",
+      TT.id,
+      ipcperm.uid, ipcperm.gid, ipcperm.cuid, ipcperm.cgid,
+      ipcperm.mode, ipcperm.mode & 0777,
+      (long) buf.sem_nsems,
+      buf.sem_otime ? ctime(&buf.sem_otime) : "Not set");
+  printf("ctime = %-26.24s\n"
+      "%-10s %-10s %-10s %-10s %-10s\n",
+      ctime(&buf.sem_ctime),
+      "semnum", "value", "ncount", "zcount", "pid");
+#undef ipcperm
+
+  for (i = 0; i < buf.sem_nsems; i++) {
+    int val, nc, zc, pid;
+    val = semctl(TT.id, i, GETVAL, n);
+    nc = semctl(TT.id, i, GETNCNT, n);
+    zc = semctl(TT.id, i, GETZCNT, n);
+    pid = semctl(TT.id, i, GETPID, n);
+    if (val < 0 || nc < 0 || zc < 0 || pid < 0)
+      perror_exit("semctl");
+    printf("%-10d %-10d %-10d %-10d %-10d\n", i, val, nc, zc, pid);
+  }
+  xputc('\n');
+}
+
+static void show_shm_id(void)
+{
+  struct shmid_ds buf;
+  int ret;
+
+  if ((ret = shmctl(TT.id, IPC_STAT, &buf)) < 0) {
+    perror_msg("shmctl");
+    return;
+  }
+
+#define ipcperm buf.shm_perm
+
+  printf("\nShared memory Segment shmid=%d\n"
+      "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\n"
+      "mode=%#o\taccess_perms=%#o\n"
+      "bytes=%ld\tlpid=%d\tcpid=%d\tnattch=%ld\n",
+      TT.id,
+      ipcperm.uid, ipcperm.gid, ipcperm.cuid, ipcperm.cgid,
+      ipcperm.mode, (ipcperm.mode & 0777),
+      (long) buf.shm_segsz, buf.shm_lpid, buf.shm_cpid,
+      (long) buf.shm_nattch);
+  printf("att_time=%-26.24s\n",
+      buf.shm_atime ? ctime(&buf.shm_atime) : "Not set");
+  printf("det_time=%-26.24s\n",
+      buf.shm_dtime ? ctime(&buf.shm_dtime) : "Not set");
+  printf("change_time=%-26.24s\n\n", ctime(&buf.shm_ctime));
+#undef ipcperm
+}
+
+static void shm_array(void)
+{
+  struct shm_info shm_buf;
+  struct shminfo ipc_buf;
+  struct shmid_ds buf;
+  int max_nr, i, shmid;
+  struct passwd *pw;
+  struct group *gr;
+
+  if ((max_nr = shmctl(0, SHM_INFO, (struct shmid_ds*)&shm_buf)) < 0) {
+    perror_msg("kernel not configured for shared memory");
+    return;
+  }
+
+  if (flag(u)) {
+    printf("------ Shared Memory Status --------\n");
+    printf("segments allocated %d\n"
+        "pages allocated %ld\n"
+        "pages resident  %ld\n"
+        "pages swapped   %ld\n"
+        "Swap performance: %ld attempts\t%ld successes\n",
+        shm_buf.used_ids,
+        shm_buf.shm_tot,
+        shm_buf.shm_rss,
+        shm_buf.shm_swp,
+        shm_buf.swap_attempts, shm_buf.swap_successes);
+    return;
+  }
+  if (flag(l)) {
+    if ((shmctl(0, 3, (struct shmid_ds*)&ipc_buf)) < 0) return; //IPC_INFO
+    printf("------ Shared Memory Limits --------\n");
+    printf("max number of segments = %lu\n"
+        "max seg size (kbytes) = %lu\n"
+        "max total shared memory (pages) = %lu\n"
+        "min seg size (bytes) = %lu\n",
+        (unsigned long) ipc_buf.shmmni,
+        (unsigned long) (ipc_buf.shmmax >> 10),
+        (unsigned long) ipc_buf.shmall,
+        (unsigned long) ipc_buf.shmmin);
+    return;
+  }
+
+  if (flag(t)) {
+    printf("------ Shared Memory Attach/Detach/Change Times --------\n");
+    printf("%-10s %-10s %-20s %-20s %-20s\n",
+        "shmid", "owner", "attached", "detached", "changed");
+  } else if (flag(p)) {
+    printf("------ Shared Memory Creator/Last-op --------\n");
+    printf("%-10s %-10s %-10s %-10s\n",
+        "shmid", "owner", "cpid", "lpid");
+  } else if (flag(c)) {
+    printf("------ Shared Memory Segment Creators/Owners --------\n");
+    printf("%-10s %-10s %-10s %-10s %-10s %-10s\n",
+        "shmid", "perms", "cuid", "cgid", "uid", "gid");
+  } else {
+    printf("------ Shared Memory Segments --------\n");
+    printf("%-10s %-10s %-10s %-10s %-10s %-10s %-12s\n",
+        "key", "shmid", "owner", "perms", "bytes", "nattch",
+        "status");
+  }
+
+  for (i = 0; i <= max_nr; i++) {
+    if ((shmid = shmctl(i, SHM_STAT, &buf)) < 0 ) continue;
+    if (flag(t)) {
+      if ((pw = getpwuid(buf.shm_perm.uid)))
+        printf("%-10d %-10.10s", shmid, pw->pw_name);
+      else printf("%-10d %-10.10d", shmid, buf.shm_perm.uid);
+      printf(" %-20.16s", buf.shm_atime
+          ? ctime(&buf.shm_atime) + 4 : "Not set");
+      printf(" %-20.16s", buf.shm_dtime
+          ? ctime(&buf.shm_dtime) + 4 : "Not set");
+      printf(" %-20.16s\n", buf.shm_ctime
+          ? ctime(&buf.shm_ctime) + 4 : "Not set");
+    } else if (flag(p)) {
+      if ((pw = getpwuid(buf.shm_perm.uid)))
+        printf("%-10d %-10.10s", shmid, pw->pw_name);
+      else printf("%-10d %-10.10d", shmid, buf.shm_perm.uid);
+      printf(" %-10d %-10d\n", buf.shm_cpid, buf.shm_lpid);
+    } else if (flag(c)) {
+      printf("%-10d %-10o", shmid, buf.shm_perm.mode & 0777);
+      if ((pw = getpwuid(buf.shm_perm.cuid))) printf(" %-10s", pw->pw_name);
+      else printf(" %-10d", buf.shm_perm.cuid);
+      if ((gr = getgrgid(buf.shm_perm.cgid))) printf(" %-10s", gr->gr_name);
+      else printf(" %-10d", buf.shm_perm.cgid);
+      if ((pw = getpwuid(buf.shm_perm.uid))) printf(" %-10s", pw->pw_name);
+      else printf(" %-10d", buf.shm_perm.uid);
+      if ((gr = getgrgid(buf.shm_perm.gid))) printf(" %-10s\n", gr->gr_name);
+      else printf(" %-10d\n", buf.shm_perm.gid);
+    } else {
+      printf("0x%08x ", buf.shm_perm.__key);
+      if ((pw = getpwuid(buf.shm_perm.uid)))
+        printf("%-10d %-10.10s", shmid, pw->pw_name);
+      else printf("%-10d %-10.10d", shmid, buf.shm_perm.uid);
+      printf(" %-10o %-10lu %-10ld %-6s %-6s\n", buf.shm_perm.mode & 0777,
+          (unsigned long) buf.shm_segsz,
+          (long) buf.shm_nattch,
+          buf.shm_perm.mode & SHM_DEST ? "dest" : " ",
+          buf.shm_perm.mode & SHM_LOCKED ? "locked" : " ");
+    }
+  }
+}
+
+static void sem_array(void)
+{
+  struct seminfo info_buf;
+  struct semid_ds buf;
+  union semun u;
+  int max_nr, i,semid;
+  struct passwd *pw;
+  struct group *gr;
+
+  u.array = (unsigned short *)&info_buf;
+  if ((max_nr = semctl(0, 0, SEM_INFO, u)) < 0) {
+    perror_msg("kernel is not configured for semaphores");
+    return;
+  }
+
+
+  if (flag(u)) {
+    printf("------ Semaphore Status --------\n");
+    printf("used arrays = %d\n"
+        "allocated semaphores = %d\n",
+        info_buf.semusz, info_buf.semaem);
+    return;
+  } 
+  if (flag(l)) {
+    printf("------ Semaphore Limits --------\n");
+    u.array = (unsigned short *)&info_buf;
+    if ((semctl(0, 0, 3, u)) < 0) //IPC_INFO
+      return;
+    printf("max number of arrays = %d\n"
+        "max semaphores per array = %d\n"
+        "max semaphores system wide = %d\n"
+        "max ops per semop call = %d\n"
+        "semaphore max value = %d\n",
+        info_buf.semmni,
+        info_buf.semmsl,
+        info_buf.semmns, info_buf.semopm, info_buf.semvmx);
+    return;
+  }
+
+  if (flag(t)) {
+    printf("------ Semaphore Operation/Change Times --------\n");
+    printf("%-8s %-10s %-26.24s %-26.24s\n",
+        "shmid", "owner", "last-op", "last-changed");
+  } else if (flag(c)) {
+    printf("------ Semaphore %s --------\n", "Arrays Creators/Owners");
+    printf("%-10s %-10s %-10s %-10s %-10s %-10s\n",
+        "semid", "perms", "cuid", "cgid", "uid", "gid");
+
+  } else if (flag(p)){
+    return;
+  } else {
+    printf("------ Semaphore %s --------\n", "Arrays");
+    printf("%-10s %-10s %-10s %-10s %-10s\n",
+        "key", "semid", "owner", "perms", "nsems");
+  }
+
+  for (i = 0; i <= max_nr; i++) {
+    u.buf = &buf;
+    if ((semid = semctl(i, 0, SEM_STAT, u)) < 0) continue;
+    pw = getpwuid(buf.sem_perm.uid);
+    if (flag(t)) {
+      if (pw) printf("%-8d %-10.10s", semid, pw->pw_name);
+      else printf("%-8d %-10d", semid, buf.sem_perm.uid);
+
+      printf("  %-26.24s", buf.sem_otime
+          ? ctime(&buf.sem_otime) : "Not set");
+      printf(" %-26.24s\n", buf.sem_ctime
+          ? ctime(&buf.sem_ctime) : "Not set");
+    } else if (flag(c)) {
+      printf("%-10d %-10o", semid, buf.sem_perm.mode & 0777);
+      if ((pw = getpwuid(buf.sem_perm.cuid))) printf(" %-10s", pw->pw_name);
+      else printf(" %-10d", buf.sem_perm.cuid);
+      if ((gr = getgrgid(buf.sem_perm.cgid))) printf(" %-10s", gr->gr_name);
+      else printf(" %-10d", buf.sem_perm.cgid);
+      if ((pw = getpwuid(buf.sem_perm.uid))) printf(" %-10s", pw->pw_name);
+      else printf(" %-10d", buf.sem_perm.uid);
+      if ((gr = getgrgid(buf.sem_perm.gid))) printf(" %-10s\n", gr->gr_name);
+      else printf(" %-10d\n", buf.sem_perm.gid);
+    } else {
+      printf("0x%08x ", buf.sem_perm.__key);
+      if (pw) printf("%-10d %-10.9s", semid, pw->pw_name);
+      else printf("%-10d %-9d", semid, buf.sem_perm.uid);
+      printf(" %-10o %-10ld\n", buf.sem_perm.mode & 0777,
+          (long) buf.sem_nsems);
+    }
+  }
+}
+
+static void msg_array(void)
+{
+  struct msginfo info_buf;
+  struct msqid_ds buf;
+  int max_nr, i, msqid;
+  struct passwd *pw;
+  struct group *gr;
+
+  if ((max_nr = msgctl(0, MSG_INFO, (struct msqid_ds*)&info_buf)) < 0) {
+    perror_msg("kernel not configured for message queue");
+    return;
+  }
+
+  if (flag(u)) {
+    printf("------ Message%s --------\n", "s: Status");
+    printf("allocated queues = %d\n"
+        "used headers = %d\n"
+        "used space = %d bytes\n",
+        info_buf.msgpool, info_buf.msgmap, info_buf.msgtql);
+    return;
+  }
+  if (flag(l)) {
+    if ((msgctl(0, 3, (struct msqid_ds*)&info_buf)) < 0) return; //IPC_INFO
+    printf("------ Messages: Limits --------\n");
+    printf("max queues system wide = %d\n"
+        "max size of message (bytes) = %d\n"
+        "default max size of queue (bytes) = %d\n",
+        info_buf.msgmni, info_buf.msgmax, info_buf.msgmnb);
+    return;
+  }
+
+  if (flag(t)) {
+    printf("------ Message%s --------\n", " Queues Send/Recv/Change Times");
+    printf("%-8s %-10s %-20s %-20s %-20s\n",
+        "msqid", "owner", "send", "recv", "change");
+  } else if (flag(p)) {
+    printf("------ Message%s --------\n", " Queues PIDs");
+    printf("%-10s %-10s %-10s %-10s\n",
+        "msqid", "owner", "lspid", "lrpid");
+  } else if (flag(c)) {
+    printf("------ Message%s --------\n", " Queues: Creators/Owners");
+    printf("%-10s %-10s %-10s %-10s %-10s %-10s\n",
+        "msqid", "perms", "cuid", "cgid", "uid", "gid");
+  } else {
+    printf("------ Message%s --------\n", " Queues");
+    printf("%-10s %-10s %-10s %-10s %-12s %-12s\n",
+        "key", "msqid", "owner", "perms", "used-bytes", "messages");
+  }
+
+  for (i = 0; i <= max_nr; i++) {
+    if ((msqid = msgctl(i, MSG_STAT, &buf)) < 0 ) continue;
+    pw = getpwuid(buf.msg_perm.uid);
+    if (flag(t)) {
+      if (pw) printf("%-8d %-10.10s", msqid, pw->pw_name);
+      else printf("%-8d %-10d", msqid, buf.msg_perm.uid);
+      printf(" %-20.16s", buf.msg_stime
+          ? ctime(&buf.msg_stime) + 4 : "Not set");
+      printf(" %-20.16s", buf.msg_rtime
+          ? ctime(&buf.msg_rtime) + 4 : "Not set");
+      printf(" %-20.16s\n", buf.msg_ctime
+          ? ctime(&buf.msg_ctime) + 4 : "Not set");
+    } else if (flag(p)) {
+      if (pw) printf("%-8d %-10.10s", msqid, pw->pw_name);
+      else printf("%-8d %-10d", msqid, buf.msg_perm.uid);
+      printf("  %5d     %5d\n", buf.msg_lspid, buf.msg_lrpid);
+    } else if (flag(c)) {
+      printf("%-10d %-10o", msqid, buf.msg_perm.mode & 0777);
+      if ((pw = getpwuid(buf.msg_perm.cuid))) printf(" %-10s", pw->pw_name);
+      else printf(" %-10d", buf.msg_perm.cuid);
+      if ((gr = getgrgid(buf.msg_perm.cgid))) printf(" %-10s", gr->gr_name);
+      else printf(" %-10d", buf.msg_perm.cgid);
+      if ((pw = getpwuid(buf.msg_perm.uid))) printf(" %-10s", pw->pw_name);
+      else printf(" %-10d", buf.msg_perm.uid);
+      if ((gr = getgrgid(buf.msg_perm.gid))) printf(" %-10s\n", gr->gr_name);
+      else printf(" %-10d\n", buf.msg_perm.gid);
+    } else {
+      printf("0x%08x ", buf.msg_perm.__key);
+      if (pw) printf("%-10d %-10.10s", msqid, pw->pw_name);
+      else printf("%-10d %-10d", msqid, buf.msg_perm.uid);
+      printf(" %-10o %-12ld %-12ld\n", buf.msg_perm.mode & 0777,
+          (long) buf.msg_cbytes, (long) buf.msg_qnum);
+    }
+  }
+}
+
+void ipcs_main(void)
+{
+  if (flag(i)) {
+    if (flag(m)) show_shm_id();
+    else if (flag(s)) show_sem_id();
+    else if (flag(q)) show_msg_id();
+    else help_exit(0);
+    return;
+  }
+
+  if (!(flag(m) || flag(s) || flag(q)) || flag(a)) toys.optflags |= (FLAG_m|FLAG_s|FLAG_q);
+
+  xputc('\n');
+  if (flag(m)) {
+    shm_array();
+    xputc('\n');
+  }
+  if (flag(s)) {
+    sem_array();
+    xputc('\n');
+  }
+  if (flag(q)) {
+    msg_array();
+    xputc('\n');
+  }
+}
diff --git a/toybox/toys/pending/klogd.c b/toybox/toys/pending/klogd.c
new file mode 100644
index 0000000..d950981
--- /dev/null
+++ b/toybox/toys/pending/klogd.c
@@ -0,0 +1,109 @@
+/* klogd.c - Klogd, The kernel log Dameon.
+ *
+ * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No standard
+
+USE_KLOGD(NEWTOY(klogd, "c#<1>8n", TOYFLAG_SBIN))
+
+config KLOGD
+    bool "klogd"
+    default n
+    help
+    usage: klogd [-n] [-c N]
+
+    -c  N   Print to console messages more urgent than prio N (1-8)"
+    -n    Run in foreground.
+
+config KLOGD_SOURCE_RING_BUFFER
+    bool "enable kernel ring buffer as log source."
+    default n
+    depends on KLOGD
+*/
+
+#define FOR_klogd
+#include "toys.h"
+#include <signal.h>
+#include <sys/klog.h>
+GLOBALS(
+  long level;
+
+  int fd;
+)
+
+static void set_log_level(int level)
+{   
+  if (CFG_KLOGD_SOURCE_RING_BUFFER)
+    klogctl(8, NULL, level);
+  else {
+    FILE *fptr = xfopen("/proc/sys/kernel/printk", "w");
+    fprintf(fptr, "%u\n", level);
+    fclose(fptr);
+    fptr = NULL;
+  }
+}
+
+static void handle_signal(int sig)
+{
+  if (CFG_KLOGD_SOURCE_RING_BUFFER) {
+    klogctl(7, NULL, 0); 
+    klogctl(0, NULL, 0);
+  } else {
+    set_log_level(7);
+    xclose(TT.fd);
+  }
+  syslog(LOG_NOTICE,"KLOGD: Daemon exiting......");
+  exit(1);
+}
+
+/*
+ * Read kernel ring buffer in local buff and keep track of
+ * "used" amount to track next read to start.
+ */
+void klogd_main(void)
+{
+  int prio, size, used = 0;
+  char *start, *line_start, msg_buffer[16348]; //LOG_LINE_LENGTH - Ring buffer size
+
+  sigatexit(handle_signal);
+  if (toys.optflags & FLAG_c) set_log_level(TT.level);    //set log level
+  if (!(toys.optflags & FLAG_n)) daemon(0, 0);            //Make it daemon
+
+  if (CFG_KLOGD_SOURCE_RING_BUFFER) {
+    syslog(LOG_NOTICE, "KLOGD: started with Kernel ring buffer as log source\n");
+    klogctl(1, NULL, 0);
+  } else {
+    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..
+
+  while(1) {
+    start = msg_buffer + used; //start updated for re-read.
+    if (CFG_KLOGD_SOURCE_RING_BUFFER) {
+      size = klogctl(2, start, sizeof(msg_buffer) - used - 1);
+    } else {
+      size = xread(TT.fd, start, sizeof(msg_buffer) - used - 1);
+    }
+    if (size < 0) perror_exit("error reading file:");
+    start[size] = '\0';  //Ensure last line to be NUL terminated.
+    if (used) start = msg_buffer;
+    while(start) {
+      if ((line_start = strsep(&start, "\n")) != NULL && start != NULL) used = 0;
+      else {                            //Incomplete line, copy it to start of buff.
+        used = strlen(line_start);
+        strcpy(msg_buffer, line_start);
+        if (used < (sizeof(msg_buffer) - 1)) break;
+        used = 0; //we have buffer full, log it as it is.
+      }
+      prio = LOG_INFO;  //we dont know priority, mark it INFO
+      if (*line_start == '<') {  //we have new line to syslog
+        line_start++;
+        if (line_start) prio = (int)strtoul(line_start, &line_start, 10);
+        if (*line_start == '>') line_start++;
+      }
+      if (*line_start) syslog(prio, "%s", line_start);
+    }
+  }
+}
diff --git a/toybox/toys/pending/last.c b/toybox/toys/pending/last.c
new file mode 100644
index 0000000..4b7b472
--- /dev/null
+++ b/toybox/toys/pending/last.c
@@ -0,0 +1,196 @@
+/* last.c - Show listing of last logged in users.
+ *
+ * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_LAST(NEWTOY(last, "f:W", TOYFLAG_BIN))
+
+config LAST
+  bool "last"
+  default n
+  help
+    usage: last [-W] [-f FILE]
+
+    Show listing of last logged in users.
+
+    -W      Display the information without host-column truncation.
+    -f FILE Read from file FILE instead of /var/log/wtmp.
+*/
+
+#define FOR_last
+#include "toys.h"
+#include <utmp.h>
+
+#ifndef SHUTDOWN_TIME
+#define SHUTDOWN_TIME 254
+#endif
+
+GLOBALS(
+  char *file;
+
+  struct arg_list *list;
+)
+
+static void free_list()
+{
+  if (TT.list) {
+    llist_traverse(TT.list, llist_free_arg);
+    TT.list = NULL;
+  }
+}
+
+static void llist_add_node(struct arg_list **old, void *data)
+{
+  struct arg_list *new = xmalloc(sizeof(struct arg_list));
+  
+  new->arg = (char*)data;
+  new->next = *old;
+  *old = new;
+}
+
+// Find a node and dlink it from the list.
+static struct arg_list *find_and_dlink(struct arg_list **list, char *devname)
+{
+  struct arg_list *l = *list;
+  
+  while (*list) {
+    struct utmp *ut = (struct utmp *)l->arg;
+
+    if (!strncmp(ut->ut_line, devname, UT_LINESIZE)) {
+      *list = (*list)->next;
+      return l;
+    }
+    list = &(*list)->next;
+    l = *list;
+  }
+  return NULL;
+}
+
+// Compute login, logout and duration of login.
+static void seize_duration(time_t tm0, time_t tm1)
+{
+  unsigned days, hours, mins;
+  double diff = difftime(tm1, tm0);
+  
+  diff = (diff > 0) ? (tm1 - tm0) : 0;
+  toybuf[0] = toybuf[18] = toybuf[28] = '\0';
+  strncpy(toybuf, ctime(&tm0), 16); // Login Time.
+  snprintf(toybuf+18, 8, "- %s", ctime(&tm1) + 11); // Logout Time.
+  days = (mins = diff/60)/(24*60);
+  hours = (mins = (mins%(24*60)))/60;
+  mins = mins%60;
+  sprintf(toybuf+28, "(%u+%02u:%02u)", days, hours, mins); // Duration.
+}
+
+void last_main(void)
+{
+  struct utmp ut;
+  time_t tm[3] = {0,}; //array for time avlues, previous, current
+  char *file = "/var/log/wtmp";
+  int fd, pwidth, curlog_type = EMPTY;
+  off_t loc;
+
+  if (toys.optflags & FLAG_f) file = TT.file;
+
+  pwidth = (toys.optflags & FLAG_W) ? 46 : 16;
+  *tm = time(tm+1);
+  fd = xopenro(file);
+  loc = xlseek(fd, 0, SEEK_END);
+
+  // Loop through file structures in reverse order.
+  for (;;) {
+    loc -= sizeof(ut);
+    if(loc < 0) break;
+    xlseek(fd, loc, SEEK_SET);
+
+    // Read next structure, determine type
+    xreadall(fd, &ut, sizeof(ut));
+    *tm = ut.ut_tv.tv_sec;
+    if (*ut.ut_line == '~') {
+      if (!strcmp(ut.ut_user, "runlevel")) ut.ut_type = RUN_LVL;
+      else if (!strcmp(ut.ut_user, "reboot")) ut.ut_type = BOOT_TIME;
+      else if (!strcmp(ut.ut_user, "shutdown")) ut.ut_type = SHUTDOWN_TIME;
+    } else if (!*ut.ut_user) ut.ut_type = DEAD_PROCESS;
+    else if (*ut.ut_user && *ut.ut_line && ut.ut_type != DEAD_PROCESS
+        && strcmp(ut.ut_user, "LOGIN")) ut.ut_type = USER_PROCESS;
+    /* The pair of terminal names '|' / '}' logs the
+     * old/new system time when date changes it.
+     */ 
+    if (!strcmp(ut.ut_user, "date")) {
+      if (ut.ut_line[0] == '|') ut.ut_type = OLD_TIME;
+      if (ut.ut_line[0] == '{') ut.ut_type = NEW_TIME;
+    }
+
+    if ((ut.ut_type == SHUTDOWN_TIME) || ((ut.ut_type == RUN_LVL) && 
+        (((ut.ut_pid & 255) == '0') || ((ut.ut_pid & 255) == '6'))))
+    {
+      tm[1] = tm[2] = (time_t)ut.ut_tv.tv_sec;
+      free_list();
+      curlog_type = RUN_LVL;
+    } else if (ut.ut_type == BOOT_TIME) {
+      seize_duration(tm[0], tm[1]);
+      strcpy(ut.ut_line, "system boot");
+      free_list();
+      printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user, 
+          ut.ut_line, pwidth, pwidth, ut.ut_host, 
+          toybuf, toybuf+18, toybuf+28);
+      curlog_type = BOOT_TIME;
+      tm[2] = (time_t)ut.ut_tv.tv_sec;
+    } else if (ut.ut_type == USER_PROCESS && *ut.ut_line) {
+      struct arg_list *l = find_and_dlink(&TT.list, ut.ut_line);
+
+      if (l) {
+        struct utmp *u = (struct utmp *)l->arg;
+        seize_duration(tm[0], u->ut_tv.tv_sec);
+        printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user, 
+            ut.ut_line, pwidth, pwidth, ut.ut_host, 
+            toybuf, toybuf+18, toybuf+28);
+        free(l->arg);
+        free(l);
+      } else {
+        int type = !tm[2] ? EMPTY : curlog_type;
+        if (!tm[2]) { //check process's current status (alive or dead).
+          if ((ut.ut_pid > 0) && (kill(ut.ut_pid, 0)!=0) && (errno == ESRCH))
+            type = INIT_PROCESS;
+        }
+        seize_duration(tm[0], tm[2]);
+        switch (type) {
+          case EMPTY:
+            strcpy(toybuf+18, "  still");
+            strcpy(toybuf+28, "logged in"); 
+            break;
+          case RUN_LVL:
+            strcpy(toybuf+18, "- down ");
+            break;
+          case BOOT_TIME:
+            strcpy(toybuf+18, "- crash");
+            break;
+          case INIT_PROCESS:
+            strcpy(toybuf+18, "   gone");
+            strcpy(toybuf+28, "- no logout");
+            break;
+          default:
+            break;
+        }
+        printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user, 
+            ut.ut_line, pwidth, pwidth, ut.ut_host, 
+            toybuf, toybuf+18, toybuf+28);
+      }
+      llist_add_node(&TT.list, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut)));
+    } else if (ut.ut_type == DEAD_PROCESS && *ut.ut_line)
+      llist_add_node(&TT.list, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut)));
+
+    loc -= sizeof(ut);
+    if(loc < 0) break;
+    xlseek(fd, loc, SEEK_SET);
+  }
+
+  if (CFG_TOYBOX_FREE) {
+    xclose(fd);
+    free_list();
+  }
+
+  xprintf("\n%s begins %-24.24s\n", basename(file), ctime(tm));
+}
diff --git a/toybox/toys/pending/logger.c b/toybox/toys/pending/logger.c
new file mode 100644
index 0000000..d94e6f8
--- /dev/null
+++ b/toybox/toys/pending/logger.c
@@ -0,0 +1,73 @@
+/* logger.c - Log messages.
+ *
+ * Copyright 2013 Ilya Kuzmich <ilya.kuzmich@gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/logger.html
+
+USE_LOGGER(NEWTOY(logger, "st:p:", TOYFLAG_USR|TOYFLAG_BIN))
+
+config LOGGER
+  bool "logger"
+  depends on SYSLOGD
+  default n
+  help
+    usage: logger [-s] [-t tag] [-p [facility.]priority] [message]
+
+    Log message (or stdin) to syslog.
+*/
+
+#define FOR_logger
+#include "toys.h"
+
+GLOBALS(
+  char *priority_arg;
+  char *ident;
+)
+
+extern int logger_lookup(int where, char *key);
+
+void logger_main(void)
+{
+  int facility = LOG_USER, priority = LOG_NOTICE;
+  char *message = NULL;
+
+  if (toys.optflags & FLAG_p) {
+    char *sep = strchr(TT.priority_arg, '.');
+
+    if (sep) {
+      *sep = '\0';
+      if ((facility = logger_lookup(0, TT.priority_arg)) == -1)
+        error_exit("bad facility: %s", TT.priority_arg);
+      TT.priority_arg = sep+1;
+    }
+
+    if ((priority = logger_lookup(1, TT.priority_arg)) == -1)
+      error_exit("bad priority: %s", TT.priority_arg);
+  }
+
+  if (!(toys.optflags & FLAG_t)) {
+    struct passwd *pw = getpwuid(geteuid());
+
+    if (!pw) perror_exit("getpwuid");
+    TT.ident = xstrdup(pw->pw_name);
+  }
+
+  if (toys.optc) {
+    int length = 0, pos = 0;
+
+    for (;*toys.optargs; toys.optargs++) {
+      length += strlen(*(toys.optargs)) + 1; // plus one for the args spacing
+      message = xrealloc(message, length + 1); // another one for the null byte
+
+      sprintf(message + pos, "%s ", *toys.optargs);
+      pos = length;
+    }
+  } else {
+    toybuf[readall(0, toybuf, 4096-1)] = '\0';
+    message = toybuf;
+  }
+
+  openlog(TT.ident, (toys.optflags & FLAG_s ? LOG_PERROR : 0) , facility);
+  syslog(priority, "%s", message);
+  closelog();
+}
diff --git a/toybox/toys/pending/lsof.c b/toybox/toys/pending/lsof.c
new file mode 100644
index 0000000..436fdd2
--- /dev/null
+++ b/toybox/toys/pending/lsof.c
@@ -0,0 +1,471 @@
+/* lsof.c - list open files.
+ *
+ * Copyright 2015 The Android Open Source Project
+
+USE_LSOF(NEWTOY(lsof, "lp*t", TOYFLAG_USR|TOYFLAG_BIN))
+
+config LSOF
+  bool "lsof"
+  default n
+  help
+    usage: lsof [-lt] [-p PID1,PID2,...] [NAME]...
+
+    Lists open files. If names are given on the command line, only
+    those files will be shown.
+
+    -l	list uids numerically
+    -p	for given comma-separated pids only (default all pids)
+    -t	terse (pid only) output
+*/
+
+#define FOR_lsof
+#include "toys.h"
+
+GLOBALS(
+  struct arg_list *p;
+
+  struct stat *sought_files;
+
+  struct double_list *all_sockets;
+  struct double_list *files;
+  int last_shown_pid;
+  int shown_header;
+)
+
+struct proc_info {
+  char cmd[10];
+  int pid;
+  char user[12];
+};
+
+struct file_info {
+  char *next, *prev;
+
+  // For output.
+  struct proc_info pi;
+  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 void print_info(void *data)
+{
+  struct file_info *fi = data;
+
+  // 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);
+  } else {
+    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);
+  }
+}
+
+static void free_info(void *data)
+{
+  free(((struct file_info *)data)->name);
+  free(data);
+}
+
+static void fill_flags(struct file_info *fi)
+{
+  FILE* fp;
+  long long pos;
+  unsigned flags;
+
+  snprintf(toybuf, sizeof(toybuf), "/proc/%d/fdinfo/%s", fi->pi.pid, fi->fd);
+  fp = fopen(toybuf, "r");
+  if (!fp) return;
+
+  if (fscanf(fp, "pos: %lld flags: %o", &pos, &flags) == 2) {
+    flags &= O_ACCMODE;
+    if (flags == O_RDONLY) fi->rw = 'r';
+    else if (flags == O_WRONLY) fi->rw = 'w';
+    else fi->rw = 'u';
+
+    snprintf(fi->size_off, sizeof(fi->size_off), "0t%lld", pos);
+  }
+  fclose(fp);
+}
+
+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;
+
+  if (!getline(&line, &line_length, fp)) return; // Skip header.
+
+  while (getline(&line, &line_length, fp) > 0) {
+    fn(line, family, type);
+  }
+
+  free(line);
+  fclose(fp);
+}
+
+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 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) {
+    struct file_info *fi = add_socket(inode, "unix");
+    char *name = chomp(line + path_pos);
+
+    fi->name = strdup(*name ? name : "socket");
+  }
+}
+
+static void scan_netlink(char *line, int af, char type)
+{
+  unsigned state;
+  long inode;
+  char *netlink_states[] = {
+    "ROUTE", "UNUSED", "USERSOCK", "FIREWALL", "SOCK_DIAG", "NFLOG", "XFRM",
+    "SELINUX", "ISCSI", "AUDIT", "FIB_LOOKUP", "CONNECTOR", "NETFILTER",
+    "IP6_FW", "DNRTMSG", "KOBJECT_UEVENT", "GENERIC", "DM", "SCSITRANSPORT",
+    "ENCRYPTFS", "RDMA", "CRYPTO"
+  };
+
+  if (sscanf(line, "%*p %u %*u %*x %*u %*u %*u %*u %*u %lu", &state, &inode)
+      < 2) {
+    return;
+  }
+
+  struct file_info *fi = add_socket(inode, "netlink");
+  fi->name =
+      strdup(state < ARRAY_LEN(netlink_states) ? netlink_states[state] : "?");
+}
+
+static void scan_ip(char *line, int af, char type)
+{
+  char *tcp_states[] = {
+    "UNKNOWN", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2",
+    "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING"
+  };
+  char local_ip[INET6_ADDRSTRLEN] = {0};
+  char remote_ip[INET6_ADDRSTRLEN] = {0};
+  struct in6_addr local, remote;
+  int local_port, remote_port, state;
+  long inode;
+  int ok;
+
+  if (af == 4) {
+    ok = sscanf(line, " %*d: %x:%x %x:%x %x %*x:%*x %*X:%*X %*X %*d %*d %ld",
+                &(local.s6_addr32[0]), &local_port,
+                &(remote.s6_addr32[0]), &remote_port,
+                &state, &inode) == 6;
+  } else {
+    ok = sscanf(line, " %*d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x "
+                "%*x:%*x %*X:%*X %*X %*d %*d %ld",
+                &(local.s6_addr32[0]), &(local.s6_addr32[1]),
+                &(local.s6_addr32[2]), &(local.s6_addr32[3]),
+                &local_port,
+                &(remote.s6_addr32[0]), &(remote.s6_addr32[1]),
+                &(remote.s6_addr32[2]), &(remote.s6_addr32[3]),
+                &remote_port, &state, &inode) == 12;
+  }
+  if (!ok) return;
+
+  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') {
+    if (state < 0 || state > TCP_CLOSING) state = 0;
+    fi->name = xmprintf(af == 4 ?
+                        "TCP %s:%d->%s:%d (%s)" :
+                        "TCP [%s]:%d->[%s]:%d (%s)",
+                        local_ip, local_port, remote_ip, remote_port,
+                        tcp_states[state]);
+  } else {
+    fi->name = xmprintf(af == 4 ? "%s %s:%d->%s:%d" : "%s [%s]:%d->[%s]:%d",
+                        type == 'u' ? "UDP" : "RAW",
+                        local_ip, local_port, remote_ip, remote_port);
+  }
+}
+
+static int find_socket(struct file_info *fi, long 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)
+{
+  struct stat sb;
+  long dev;
+
+  if (stat(path, &sb)) return;
+
+  // Fill TYPE.
+  switch ((sb.st_mode & S_IFMT)) {
+    case S_IFBLK: strcpy(fi->type, "BLK"); break;
+    case S_IFCHR: strcpy(fi->type, "CHR"); break;
+    case S_IFDIR: strcpy(fi->type, "DIR"); break;
+    case S_IFIFO: strcpy(fi->type, "FIFO"); break;
+    case S_IFLNK: strcpy(fi->type, "LINK"); break;
+    case S_IFREG: strcpy(fi->type, "REG"); break;
+    case S_IFSOCK: strcpy(fi->type, "sock"); break;
+    default:
+      snprintf(fi->type, sizeof(fi->type), "0%03o", sb.st_mode & S_IFMT);
+      break;
+  }
+
+  if (S_ISSOCK(sb.st_mode)) find_socket(fi, sb.st_ino);
+
+  // 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), "%d,%d",
+             dev_major(dev), dev_minor(dev));
+
+  // Fill SIZE/OFF.
+  if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
+    snprintf(fi->size_off, sizeof(fi->size_off), "%lld",
+             (long long)sb.st_size);
+
+  // Fill NODE.
+  snprintf(fi->node, sizeof(fi->node), "%ld", (long)sb.st_ino);
+
+  // Stash st_dev and st_ino for filtering.
+  fi->st_dev = sb.st_dev;
+  fi->st_ino = sb.st_ino;
+}
+
+struct file_info *new_file_info(struct proc_info *pi, const char *fd)
+{
+  struct file_info *fi = xzalloc(sizeof(struct file_info));
+
+  dlist_add_nomalloc(&TT.files, (struct double_list *)fi);
+
+  fi->pi = *pi;
+
+  // Defaults.
+  strcpy(fi->fd, fd);
+  strcpy(fi->type, "unknown");
+  fi->rw = fi->locks = ' ';
+
+  return fi;
+}
+
+static void visit_symlink(struct proc_info *pi, char *name, char *path)
+{
+  struct file_info *fi = new_file_info(pi, "");
+
+  // Get NAME.
+  if (name) { // "/proc/pid/[cwd]".
+    snprintf(fi->fd, sizeof(fi->fd), "%s", name);
+    snprintf(toybuf, sizeof(toybuf), "/proc/%d/%s", pi->pid, path);
+  } else { // "/proc/pid/fd/[3]"
+    snprintf(fi->fd, sizeof(fi->fd), "%s", path);
+    fill_flags(fi); // Clobbers toybuf.
+    snprintf(toybuf, sizeof(toybuf), "/proc/%d/fd/%s", pi->pid, path);
+  }
+  // TODO: code called by fill_stat would be easier to write if we didn't
+  // rely on toybuf being preserved here.
+  fill_stat(fi, toybuf);
+  if (!fi->name) { // We already have a name for things like sockets.
+    fi->name = xreadlink(toybuf);
+    if (!fi->name) {
+      fi->name = xmprintf("%s (readlink: %s)", toybuf, strerror(errno));
+    }
+  }
+}
+
+static void visit_maps(struct proc_info *pi)
+{
+  FILE *fp;
+  unsigned long long offset;
+  char device[10];
+  long inode;
+  char *line = NULL;
+  size_t line_length = 0;
+
+  snprintf(toybuf, sizeof(toybuf), "/proc/%d/maps", pi->pid);
+  fp = fopen(toybuf, "r");
+  if (!fp) return;
+
+  while (getline(&line, &line_length, fp) > 0) {
+    int name_pos;
+
+    if (sscanf(line, "%*x-%*x %*s %llx %s %ld %n",
+               &offset, device, &inode, &name_pos) >= 3) {
+      struct file_info *fi;
+
+      // Ignore non-file maps.
+      if (inode == 0 || !strcmp(device, "00:00")) continue;
+      // TODO: show unique maps even if they have a non-zero offset?
+      if (offset != 0) continue;
+
+      fi = new_file_info(pi, "mem");
+      fi->name = strdup(chomp(line + name_pos));
+      fill_stat(fi, fi->name);
+    }
+  }
+  free(line);
+  fclose(fp);
+}
+
+static void visit_fds(struct proc_info *pi)
+{
+  DIR *dir;
+  struct dirent *de;
+
+  snprintf(toybuf, sizeof(toybuf), "/proc/%d/fd", pi->pid);
+  if (!(dir = opendir(toybuf))) {
+    struct file_info *fi = new_file_info(pi, "NOFD");
+
+    fi->name = xmprintf("%s (opendir: %s)", toybuf, strerror(errno));
+    return;
+  }
+
+  while ((de = readdir(dir))) {
+    if (*de->d_name == '.') continue;
+    visit_symlink(pi, NULL, de->d_name);
+  }
+
+  closedir(dir);
+}
+
+static void lsof_pid(int pid)
+{
+  struct proc_info pi;
+  char *line;
+  struct stat sb;
+
+  // Skip nonexistent pids
+  sprintf(toybuf, "/proc/%d/stat", pid);
+  if (!(line = readfile(toybuf, toybuf, sizeof(toybuf)))) return;
+
+  // Get COMMAND.
+  strcpy(pi.cmd, "?");
+  if (line) {
+    char *open_paren = strchr(toybuf, '(');
+    char *close_paren = strrchr(toybuf, ')');
+
+    if (open_paren && close_paren) {
+      *close_paren = 0;
+      snprintf(pi.cmd, sizeof(pi.cmd), "%s", open_paren + 1);
+    }
+  }
+
+  // We already know PID.
+  pi.pid = pid;
+
+  // Get USER.
+  snprintf(toybuf, sizeof(toybuf), "/proc/%d", pid);
+  if (!stat(toybuf, &sb)) {
+    struct passwd *pw;
+
+    if (!(toys.optflags&FLAG_l) && (pw = getpwuid(sb.st_uid))) {
+      snprintf(pi.user, sizeof(pi.user), "%s", pw->pw_name);
+    } else snprintf(pi.user, sizeof(pi.user), "%u", (unsigned)sb.st_uid);
+  }
+
+  visit_symlink(&pi, "cwd", "cwd");
+  visit_symlink(&pi, "rtd", "root");
+  visit_symlink(&pi, "txt", "exe");
+  visit_maps(&pi);
+  visit_fds(&pi);
+}
+
+static int scan_proc(struct dirtree *node)
+{
+  int pid;
+
+  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);
+
+  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 ((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);
+    }
+  }
+
+  llist_traverse(TT.files, print_info);
+
+  if (CFG_TOYBOX_FREE) {
+    llist_traverse(TT.files, free_info);
+    llist_traverse(TT.all_sockets, free_info);
+  }
+}
diff --git a/toybox/toys/pending/mdev.c b/toybox/toys/pending/mdev.c
new file mode 100644
index 0000000..2688cf3
--- /dev/null
+++ b/toybox/toys/pending/mdev.c
@@ -0,0 +1,234 @@
+/* mdev.c - Populate /dev directory and handle hotplug events
+ *
+ * Copyright 2005, 2008 Rob Landley <rob@landley.net>
+ * Copyright 2005 Frank Sorenson <frank@tuxrocks.com>
+
+USE_MDEV(NEWTOY(mdev, "s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK))
+
+config MDEV
+  bool "mdev"
+  default n
+  help
+    usage: mdev [-s]
+
+    Create devices in /dev using information from /sys.
+
+    -s	Scan all entries in /sys to populate /dev.
+
+config MDEV_CONF
+  bool "Configuration file for mdev"
+  default y
+  depends on MDEV
+  help
+    The mdev config file (/etc/mdev.conf) contains lines that look like:
+    hd[a-z][0-9]* 0:3 660
+
+    Each line must contain three whitespace separated fields. The first
+    field is a regular expression matching one or more device names,
+    the second and third fields are uid:gid and file permissions for
+    matching devies.
+*/
+
+#include "toys.h"
+
+// mknod in /dev based on a path like "/sys/block/hda/hda1"
+static void make_device(char *path)
+{
+  char *device_name = 0, *s, *temp;
+  int major = 0, minor = 0, type, len, fd, mode = 0660;
+  uid_t uid = 0;
+  gid_t gid = 0;
+
+  if (path) {
+
+    // Try to read major/minor string, returning if we can't
+    temp = strrchr(path, '/');
+    fd = open(path, O_RDONLY);
+    *temp = 0;
+    len = read(fd, toybuf, 64);
+    close(fd);
+    if (len<1) return;
+    toybuf[len] = 0;
+
+    // Determine device type, major and minor
+
+    type = path[5]=='c' ? S_IFCHR : S_IFBLK;
+    sscanf(toybuf, "%u:%u", &major, &minor);
+  } else {
+    // if (!path), do hotplug
+
+    if (!(temp = getenv("MODALIAS"))) xrun((char *[]){"modprobe", temp, 0});
+    if (!(temp = getenv("SUBSYSTEM"))) return;
+    type = strcmp(temp, "block") ? S_IFCHR : S_IFBLK;
+    if (!(temp = getenv("MAJOR"))) return;
+    sscanf(temp, "%u", &major);
+    if (!(temp = getenv("MINOR"))) return;
+    sscanf(temp, "%u", &minor);
+    if (!(path = getenv("DEVPATH"))) return;
+    device_name = getenv("DEVNAME");
+  }
+  if (!device_name)
+    device_name = strrchr(path, '/') + 1;
+
+  // as in linux/drivers/base/core.c, device_get_devnode()
+  while ((temp = strchr(device_name, '!'))) {
+    *temp = '/';
+  }
+
+  // If we have a config file, look up permissions for this device
+
+  if (CFG_MDEV_CONF) {
+    char *conf, *pos, *end;
+
+    // mmap the config file
+    if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) {
+      len = fdlength(fd);
+      conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+      if (conf) {
+        int line = 0;
+
+        // Loop through lines in mmaped file
+        for (pos = conf; pos-conf<len;) {
+          int field;
+          char *end2;
+
+          line++;
+          // find end of this line
+          for(end = pos; end-conf<len && *end!='\n'; end++);
+
+          // Three fields: regex, uid:gid, mode
+          for (field = 3; field; field--) {
+            // Skip whitespace
+            while (pos<end && isspace(*pos)) pos++;
+            if (pos==end || *pos=='#') break;
+            for (end2 = pos;
+              end2<end && !isspace(*end2) && *end2!='#'; end2++);
+            switch(field) {
+              // Regex to match this device
+              case 3:
+              {
+                char *regex = strndup(pos, end2-pos);
+                regex_t match;
+                regmatch_t off;
+                int result;
+
+                // Is this it?
+                xregcomp(&match, regex, REG_EXTENDED);
+                result=regexec(&match, device_name, 1, &off, 0);
+                regfree(&match);
+                free(regex);
+
+                // If not this device, skip rest of line
+                if (result || off.rm_so
+                  || off.rm_eo!=strlen(device_name))
+                    goto end_line;
+
+                break;
+              }
+              // uid:gid
+              case 2:
+              {
+                char *s2;
+
+                // Find :
+                for(s = pos; s<end2 && *s!=':'; s++);
+                if (s==end2) goto end_line;
+
+                // Parse UID
+                uid = strtoul(pos,&s2,10);
+                if (s!=s2) {
+                  struct passwd *pass;
+                  char *str = strndup(pos, s-pos);
+                  pass = getpwnam(str);
+                  free(str);
+                  if (!pass) goto end_line;
+                  uid = pass->pw_uid;
+                }
+                s++;
+                // parse GID
+                gid = strtoul(s,&s2,10);
+                if (end2!=s2) {
+                  struct group *grp;
+                  char *str = strndup(s, end2-s);
+                  grp = getgrnam(str);
+                  free(str);
+                  if (!grp) goto end_line;
+                  gid = grp->gr_gid;
+                }
+                break;
+              }
+              // mode
+              case 1:
+              {
+                mode = strtoul(pos, &pos, 8);
+                if (pos!=end2) goto end_line;
+                goto found_device;
+              }
+            }
+            pos=end2;
+          }
+end_line:
+          // Did everything parse happily?
+          if (field && field!=3) error_exit("Bad line %d", line);
+
+          // Next line
+          pos = ++end;
+        }
+found_device:
+        munmap(conf, len);
+      }
+      close(fd);
+    }
+  }
+
+  sprintf(toybuf, "/dev/%s", device_name);
+
+  if ((temp=getenv("ACTION")) && !strcmp(temp, "remove")) {
+    unlink(toybuf);
+    return;
+  }
+
+  if (strchr(device_name, '/'))
+    mkpathat(AT_FDCWD, toybuf, 0, 2);
+  if (mknod(toybuf, mode | type, dev_makedev(major, minor)) && errno != EEXIST)
+    perror_exit("mknod %s failed", toybuf);
+
+ 
+  if (type == S_IFBLK) close(open(toybuf, O_RDONLY)); // scan for partitions
+
+  if (CFG_MDEV_CONF) mode=chown(toybuf, uid, gid);
+}
+
+static int callback(struct dirtree *node)
+{
+  // Entries in /sys/class/block aren't char devices, so skip 'em.  (We'll
+  // get block devices out of /sys/block.)
+  if(!strcmp(node->name, "block")) return 0;
+
+  // Does this directory have a "dev" entry in it?
+  // This is path based because the hotplug callbacks are
+  if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) {
+    int len=4;
+    char *dev = dirtree_path(node, &len);
+    strcpy(dev+len, "/dev");
+    if (!access(dev, R_OK)) make_device(dev);
+    free(dev);
+  }
+
+  // Circa 2.6.25 the entries more than 2 deep are all either redundant
+  // (mouse#, event#) or unnamed (every usb_* entry is called "device").
+
+  return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE;
+}
+
+void mdev_main(void)
+{
+  // Handle -s
+
+  if (toys.optflags) {
+    dirtree_read("/sys/class", callback);
+    dirtree_read("/sys/block", callback);
+  } else { // hotplug support
+    make_device(NULL);
+  }
+}
diff --git a/toybox/toys/pending/mke2fs.c b/toybox/toys/pending/mke2fs.c
new file mode 100644
index 0000000..b4c841a
--- /dev/null
+++ b/toybox/toys/pending/mke2fs.c
@@ -0,0 +1,631 @@
+/* mke2fs.c - Create an ext2 filesystem image.
+ *
+ * Copyright 2006, 2007 Rob Landley <rob@landley.net>
+
+// Still to go: "E:jJ:L:m:O:"
+USE_MKE2FS(NEWTOY(mke2fs, "<1>2g:Fnqm#N#i#b#", TOYFLAG_SBIN))
+
+config MKE2FS
+  bool "mke2fs"
+  default n
+  help
+    usage: mke2fs [-Fnq] [-b ###] [-N|i ###] [-m ###] device
+
+    Create an ext2 filesystem on a block device or filesystem image.
+
+    -F         Force to run on a mounted device
+    -n         Don't write to device
+    -q         Quiet (no output)
+    -b size    Block size (1024, 2048, or 4096)
+    -N inodes  Allocate this many inodes
+    -i bytes   Allocate one inode for every XXX bytes of device
+    -m percent Reserve this percent of filesystem space for root user
+
+config MKE2FS_JOURNAL
+  bool "Journaling support (ext3)"
+  default n
+  depends on MKE2FS
+  help
+    usage: mke2fs [-j] [-J size=###,device=XXX]
+
+    -j         Create journal (ext3)
+    -J         Journal options
+               size: Number of blocks (1024-102400)
+               device: Specify an external journal
+
+config MKE2FS_GEN
+  bool "Generate (gene2fs)"
+  default n
+  depends on MKE2FS
+  help
+    usage: gene2fs [options] device filename
+
+    The [options] are the same as mke2fs.
+
+config MKE2FS_LABEL
+  bool "Label support"
+  default n
+  depends on MKE2FS
+  help
+    usage: mke2fs [-L label] [-M path] [-o string]
+
+    -L         Volume label
+    -M         Path to mount point
+    -o         Created by
+
+config MKE2FS_EXTENDED
+  bool "Extended options"
+  default n
+  depends on MKE2FS
+  help
+    usage: mke2fs [-E stride=###] [-O option[,option]]
+
+    -E stride= Set RAID stripe size (in blocks)
+    -O [opts]  Specify fewer ext2 option flags (for old kernels)
+               All of these are on by default (as appropriate)
+       none         Clear default options (all but journaling)
+       dir_index    Use htree indexes for large directories
+       filetype     Store file type info in directory entry
+       has_journal  Set by -j
+       journal_dev  Set by -J device=XXX
+       sparse_super Don't allocate huge numbers of redundant superblocks
+*/
+
+#define FOR_mke2fs
+#include "toys.h"
+
+GLOBALS(
+  // Command line arguments.
+  long blocksize;
+  long bytes_per_inode;
+  long inodes;           // Total inodes in filesystem.
+  long reserved_percent; // Integer precent of space to reserve for root.
+  char *gendir;          // Where to read dirtree from.
+
+  // Internal data.
+  struct dirtree *dt;    // Tree of files to copy into the new filesystem.
+  unsigned treeblocks;   // Blocks used by dt
+  unsigned treeinodes;   // Inodes used by dt
+
+  unsigned blocks;       // Total blocks in the filesystem.
+  unsigned freeblocks;   // Free blocks in the filesystem.
+  unsigned inodespg;     // Inodes per group
+  unsigned groups;       // Total number of block groups.
+  unsigned blockbits;    // Bits per block.  (Also blocks per group.)
+
+  // For gene2fs
+  unsigned nextblock;    // Next data block to allocate
+  unsigned nextgroup;    // Next group we'll be allocating from
+  int fsfd;              // File descriptor of filesystem (to output to).
+
+  struct ext2_superblock sb;
+)
+
+#define INODES_RESERVED 10
+
+static uint32_t div_round_up(uint32_t a, uint32_t b)
+{
+  uint32_t c = a/b;
+
+  if (a%b) c++;
+  return c;
+}
+
+// Calculate data blocks plus index blocks needed to hold a file.
+
+static uint32_t file_blocks_used(uint64_t size, uint32_t *blocklist)
+{
+  uint32_t dblocks = (uint32_t)((size+(TT.blocksize-1))/TT.blocksize);
+  uint32_t idx=TT.blocksize/4, iblocks=0, diblocks=0, tiblocks=0;
+
+  // Fill out index blocks in inode.
+
+  if (blocklist) {
+    int i;
+
+    // Direct index blocks
+    for (i=0; i<13 && i<dblocks; i++) blocklist[i] = i;
+    // Singly indirect index blocks
+    if (dblocks > 13+idx) blocklist[13] = 13+idx;
+    // Doubly indirect index blocks
+    idx = 13 + idx + (idx*idx);
+    if (dblocks > idx) blocklist[14] = idx;
+
+    return 0;
+  }
+
+  // Account for direct, singly, doubly, and triply indirect index blocks
+
+  if (dblocks > 12) {
+    iblocks = ((dblocks-13)/idx)+1;
+    if (iblocks > 1) {
+      diblocks = ((iblocks-2)/idx)+1;
+      if (diblocks > 1)
+        tiblocks = ((diblocks-2)/idx)+1;
+    }
+  }
+
+  return dblocks + iblocks + diblocks + tiblocks;
+}
+
+// Use the parent pointer to iterate through the tree non-recursively.
+static struct dirtree *treenext(struct dirtree *this)
+{
+  while (this && !this->next) this = this->parent;
+  if (this) this = this->next;
+
+  return this;
+}
+
+// Recursively calculate the number of blocks used by each inode in the tree.
+// Returns blocks used by this directory, assigns bytes used to *size.
+// Writes total block count to TT.treeblocks and inode count to TT.treeinodes.
+
+static long check_treesize(struct dirtree *that, off_t *size)
+{
+  long blocks;
+
+  while (that) {
+    *size += sizeof(struct ext2_dentry) + strlen(that->name);
+
+    if (that->child)
+      that->st.st_blocks = check_treesize(that->child, &that->st.st_size);
+    else if (S_ISREG(that->st.st_mode)) {
+       that->st.st_blocks = file_blocks_used(that->st.st_size, 0);
+       TT.treeblocks += that->st.st_blocks;
+    }
+    that = that->next;
+  }
+  TT.treeblocks += blocks = file_blocks_used(*size, 0);
+  TT.treeinodes++;
+
+  return blocks;
+}
+
+// Calculate inode numbers and link counts.
+//
+// To do this right I need to copy the tree and sort it, but here's a really
+// ugly n^2 way of dealing with the problem that doesn't scale well to large
+// numbers of files (> 100,000) but can be done in very little code.
+// This rewrites inode numbers to their final values, allocating depth first.
+
+static void check_treelinks(struct dirtree *tree)
+{
+  struct dirtree *current=tree, *that;
+  long inode = INODES_RESERVED;
+
+  while (current) {
+    ++inode;
+    // Since we can't hardlink to directories, we know their link count.
+    if (S_ISDIR(current->st.st_mode)) current->st.st_nlink = 2;
+    else {
+      dev_t new = current->st.st_dev;
+
+      if (!new) continue;
+
+      // Look for other copies of current node
+      current->st.st_nlink = 0;
+      for (that = tree; that; that = treenext(that)) {
+        if (current->st.st_ino == that->st.st_ino &&
+          current->st.st_dev == that->st.st_dev)
+        {
+          current->st.st_nlink++;
+          current->st.st_ino = inode;
+        }
+      }
+    }
+    current->st.st_ino = inode;
+    current = treenext(current);
+  }
+}
+
+// Calculate inodes per group from total inodes.
+static uint32_t get_inodespg(uint32_t inodes)
+{
+  uint32_t temp;
+
+  // Round up to fill complete inode blocks.
+  temp = (inodes + TT.groups - 1) / TT.groups;
+  inodes = TT.blocksize/sizeof(struct ext2_inode);
+  return ((temp + inodes - 1)/inodes)*inodes;
+}
+
+// Fill out superblock and TT structures.
+
+static void init_superblock(struct ext2_superblock *sb)
+{
+  uint32_t temp;
+
+  // Set log_block_size and log_frag_size.
+
+  for (temp = 0; temp < 4; temp++) if (TT.blocksize == 1024<<temp) break;
+  if (temp==4) error_exit("bad blocksize");
+  sb->log_block_size = sb->log_frag_size = SWAP_LE32(temp);
+
+  // Fill out blocks_count, r_blocks_count, first_data_block
+
+  sb->blocks_count = SWAP_LE32(TT.blocks);
+  sb->free_blocks_count = SWAP_LE32(TT.freeblocks);
+  temp = (TT.blocks * (uint64_t)TT.reserved_percent) / 100;
+  sb->r_blocks_count = SWAP_LE32(temp);
+
+  sb->first_data_block = SWAP_LE32(TT.blocksize == 1024 ? 1 : 0);
+
+  // Set blocks_per_group and frags_per_group, which is the size of an
+  // allocation bitmap that fits in one block (I.E. how many bits per block)?
+
+  sb->blocks_per_group = sb->frags_per_group = SWAP_LE32(TT.blockbits);
+
+  // Set inodes_per_group and total inodes_count
+  sb->inodes_per_group = SWAP_LE32(TT.inodespg);
+  sb->inodes_count = SWAP_LE32(TT.inodespg * TT.groups);
+
+  // Determine free inodes.
+  temp = TT.inodespg*TT.groups - INODES_RESERVED;
+  if (temp < TT.treeinodes) error_exit("Not enough inodes.\n");
+  sb->free_inodes_count = SWAP_LE32(temp - TT.treeinodes);
+
+  // Fill out the rest of the superblock.
+  sb->max_mnt_count=0xFFFF;
+  sb->wtime = sb->lastcheck = sb->mkfs_time = SWAP_LE32(time(NULL));
+  sb->magic = SWAP_LE32(0xEF53);
+  sb->state = sb->errors = SWAP_LE16(1);
+
+  sb->rev_level = SWAP_LE32(1);
+  sb->first_ino = SWAP_LE32(INODES_RESERVED+1);
+  sb->inode_size = SWAP_LE16(sizeof(struct ext2_inode));
+  sb->feature_incompat = SWAP_LE32(EXT2_FEATURE_INCOMPAT_FILETYPE);
+  sb->feature_ro_compat = SWAP_LE32(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER);
+
+  create_uuid(sb->uuid);
+
+  // TODO If we're called as mke3fs or mkfs.ext3, do a journal.
+
+  //if (strchr(toys.which->name,'3'))
+  //	sb->feature_compat |= SWAP_LE32(EXT3_FEATURE_COMPAT_HAS_JOURNAL);
+}
+
+// Does this group contain a superblock backup (and group descriptor table)?
+static int is_sb_group(uint32_t group)
+{
+  int i;
+
+  // Superblock backups are on groups 0, 1, and powers of 3, 5, and 7.
+  if(!group || group==1) return 1;
+  for (i=3; i<9; i+=2) {
+    int j = i;
+    while (j<group) j*=i;
+    if (j==group) return 1;
+  }
+  return 0;
+}
+
+
+// Number of blocks used in group by optional superblock/group list backup.
+static int group_superblock_overhead(uint32_t group)
+{
+  int used;
+
+  if (!is_sb_group(group)) return 0;
+
+  // How many blocks does the group descriptor table take up?
+  used = TT.groups * sizeof(struct ext2_group);
+  used += TT.blocksize - 1;
+  used /= TT.blocksize;
+  // Plus the superblock itself.
+  used++;
+  // And a corner case.
+  if (!group && TT.blocksize == 1024) used++;
+
+  return used;
+}
+
+// Number of blocks used in group to store superblock/group/inode list
+static int group_overhead(uint32_t group)
+{
+  // Return superblock backup overhead (if any), plus block/inode
+  // allocation bitmaps, plus inode tables.
+  return group_superblock_overhead(group) + 2 + get_inodespg(TT.inodespg)
+        / (TT.blocksize/sizeof(struct ext2_inode));
+}
+
+// In bitmap "array" set "len" bits starting at position "start" (from 0).
+static void bits_set(char *array, int start, int len)
+{
+  while(len) {
+    if ((start&7) || len<8) {
+      array[start/8]|=(1<<(start&7));
+      start++;
+      len--;
+    } else {
+      array[start/8]=255;
+      start+=8;
+      len-=8;
+    }
+  }
+}
+
+// Seek past len bytes (to maintain sparse file), or write zeroes if output
+// not seekable
+static void put_zeroes(int len)
+{
+  if(-1 == lseek(TT.fsfd, len, SEEK_SET)) {
+    memset(toybuf, 0, sizeof(toybuf));
+    while (len) {
+      int out = len > sizeof(toybuf) ? sizeof(toybuf) : len;
+      xwrite(TT.fsfd, toybuf, out);
+      len -= out;
+    }
+  }
+}
+
+// Fill out an inode structure from struct stat info in dirtree.
+static void fill_inode(struct ext2_inode *in, struct dirtree *that)
+{
+  uint32_t fbu[15];
+  int temp;
+
+  file_blocks_used(that->st.st_size, fbu);
+
+  // If that inode needs data blocks allocated to it.
+  if (that->st.st_size) {
+    int i, group = TT.nextblock/TT.blockbits;
+
+    // TODO: teach this about indirect blocks.
+    for (i=0; i<15; i++) {
+      // If we just jumped into a new group, skip group overhead blocks.
+      while (group >= TT.nextgroup)
+        TT.nextblock += group_overhead(TT.nextgroup++);
+    }
+  }
+  // TODO :  S_ISREG/DIR/CHR/BLK/FIFO/LNK/SOCK(m)
+  in->mode = SWAP_LE32(that->st.st_mode);
+
+  in->uid = SWAP_LE16(that->st.st_uid & 0xFFFF);
+  in->uid_high = SWAP_LE16(that->st.st_uid >> 16);
+  in->gid = SWAP_LE16(that->st.st_gid & 0xFFFF);
+  in->gid_high = SWAP_LE16(that->st.st_gid >> 16);
+  in->size = SWAP_LE32(that->st.st_size & 0xFFFFFFFF);
+
+  // Contortions to make the compiler not generate a warning for x>>32
+  // when x is 32 bits.  The optimizer should clean this up.
+  if (sizeof(that->st.st_size) > 4) temp = 32;
+  else temp = 0;
+  if (temp) in->dir_acl = SWAP_LE32(that->st.st_size >> temp);
+
+  in->atime = SWAP_LE32(that->st.st_atime);
+  in->ctime = SWAP_LE32(that->st.st_ctime);
+  in->mtime = SWAP_LE32(that->st.st_mtime);
+
+  in->links_count = SWAP_LE16(that->st.st_nlink);
+  in->blocks = SWAP_LE32(that->st.st_blocks);
+  // in->faddr
+}
+
+// Works like an archiver.
+// The first argument is the name of the file to create.  If it already
+// exists, that size will be used.
+
+void mke2fs_main(void)
+{
+  int i, temp;
+  off_t length;
+  uint32_t usedblocks, usedinodes, dtiblk, dtbblk;
+  struct dirtree *dti, *dtb;
+
+  // Handle command line arguments.
+
+  if (toys.optargs[1]) {
+    sscanf(toys.optargs[1], "%u", &TT.blocks);
+    temp = O_RDWR|O_CREAT;
+  } else temp = O_RDWR;
+  if (!TT.reserved_percent) TT.reserved_percent = 5;
+
+  // TODO: Check if filesystem is mounted here
+
+  // For mke?fs, open file.  For gene?fs, create file.
+  TT.fsfd = xcreate(*toys.optargs, temp, 0777);
+
+  // Determine appropriate block size and block count from file length.
+  // (If no length, default to 4k.  They can override it on the cmdline.)
+
+  length = fdlength(TT.fsfd);
+  if (!TT.blocksize) TT.blocksize = (length && length < 1<<29) ? 1024 : 4096;
+  TT.blockbits = 8*TT.blocksize;
+  if (!TT.blocks) TT.blocks = length/TT.blocksize;
+
+  // Collect gene2fs list or lost+found, calculate requirements.
+
+  if (TT.gendir) {
+    strncpy(toybuf, TT.gendir, sizeof(toybuf));
+    dti = dirtree_read(toybuf, dirtree_notdotdot);
+  } else {
+    dti = xzalloc(sizeof(struct dirtree)+11);
+    strcpy(dti->name, "lost+found");
+    dti->st.st_mode = S_IFDIR|0755;
+    dti->st.st_ctime = dti->st.st_mtime = time(NULL);
+  }
+
+  // Add root directory inode.  This is iterated through for when finding
+  // blocks, but not when finding inodes.  The tree's parent pointers don't
+  // point back into this.
+
+  dtb = xzalloc(sizeof(struct dirtree)+1);
+  dtb->st.st_mode = S_IFDIR|0755;
+  dtb->st.st_ctime = dtb->st.st_mtime = time(NULL);
+  dtb->child = dti;
+
+  // Figure out how much space is used by preset files
+  length = check_treesize(dtb, &(dtb->st.st_size));
+  check_treelinks(dtb);
+
+  // Figure out how many total inodes we need.
+
+  if (!TT.inodes) {
+    if (!TT.bytes_per_inode) TT.bytes_per_inode = 8192;
+    TT.inodes = (TT.blocks * (uint64_t)TT.blocksize) / TT.bytes_per_inode;
+  }
+
+  // If we're generating a filesystem and have no idea how many blocks it
+  // needs, start with a minimal guess, find the overhead of that many
+  // groups, and loop until this is enough groups to store this many blocks.
+  if (!TT.blocks) TT.groups = (TT.treeblocks/TT.blockbits)+1;
+  else TT.groups = div_round_up(TT.blocks, TT.blockbits);
+
+  for (;;) {
+    temp = TT.treeblocks;
+
+    for (i = 0; i<TT.groups; i++) temp += group_overhead(i);
+
+    if (TT.blocks) {
+      if (TT.blocks < temp) error_exit("Not enough space.\n");
+      break;
+    }
+    if (temp <= TT.groups * TT.blockbits) {
+      TT.blocks = temp;
+      break;
+    }
+    TT.groups++;
+  }
+  TT.freeblocks = TT.blocks - temp;
+
+  // Now we know all the TT data, initialize superblock structure.
+
+  init_superblock(&TT.sb);
+
+  // Start writing.  Skip the first 1k to avoid the boot sector (if any).
+  put_zeroes(1024);
+
+  // Loop through block groups, write out each one.
+  dtiblk = dtbblk = usedblocks = usedinodes = 0;
+  for (i=0; i<TT.groups; i++) {
+    struct ext2_inode *in = (struct ext2_inode *)toybuf;
+    uint32_t start, itable, used, end;
+    int j, slot;
+
+    // Where does this group end?
+    end = TT.blockbits;
+    if ((i+1)*TT.blockbits > TT.blocks) end = TT.blocks & (TT.blockbits-1);
+
+    // Blocks used by inode table
+    itable = (TT.inodespg*sizeof(struct ext2_inode))/TT.blocksize;
+
+    // If a superblock goes here, write it out.
+    start = group_superblock_overhead(i);
+    if (start) {
+      struct ext2_group *bg = (struct ext2_group *)toybuf;
+      int treeblocks = TT.treeblocks, treeinodes = TT.treeinodes;
+
+      TT.sb.block_group_nr = SWAP_LE16(i);
+
+      // Write superblock and pad it up to block size
+      xwrite(TT.fsfd, &TT.sb, sizeof(struct ext2_superblock));
+      temp = TT.blocksize - sizeof(struct ext2_superblock);
+      if (!i && TT.blocksize > 1024) temp -= 1024;
+      memset(toybuf, 0, TT.blocksize);
+      xwrite(TT.fsfd, toybuf, temp);
+
+      // Loop through groups to write group descriptor table.
+      for(j=0; j<TT.groups; j++) {
+
+        // Figure out what sector this group starts in.
+        used = group_superblock_overhead(j);
+
+        // Find next array slot in this block (flush block if full).
+        slot = j % (TT.blocksize/sizeof(struct ext2_group));
+        if (!slot) {
+          if (j) xwrite(TT.fsfd, bg, TT.blocksize);
+          memset(bg, 0, TT.blocksize);
+        }
+
+        // How many free inodes in this group?
+        temp = TT.inodespg;
+        if (!i) temp -= INODES_RESERVED;
+        if (temp > treeinodes) {
+          treeinodes -= temp;
+          temp = 0;
+        } else {
+          temp -= treeinodes;
+          treeinodes = 0;
+        }
+        bg[slot].free_inodes_count = SWAP_LE16(temp);
+
+        // How many free blocks in this group?
+        temp = TT.inodespg/(TT.blocksize/sizeof(struct ext2_inode)) + 2;
+        temp = end-used-temp;
+        if (temp > treeblocks) {
+          treeblocks -= temp;
+          temp = 0;
+        } else {
+          temp -= treeblocks;
+          treeblocks = 0;
+        }
+        bg[slot].free_blocks_count = SWAP_LE32(temp);
+
+        // Fill out rest of group structure
+        used += j*TT.blockbits;
+        bg[slot].block_bitmap = SWAP_LE32(used++);
+        bg[slot].inode_bitmap = SWAP_LE32(used++);
+        bg[slot].inode_table = SWAP_LE32(used);
+        bg[slot].used_dirs_count = 0;  // (TODO)
+      }
+      xwrite(TT.fsfd, bg, TT.blocksize);
+    }
+
+    // Now write out stuff that every block group has.
+
+    // Write block usage bitmap
+
+    start += 2 + itable;
+    memset(toybuf, 0, TT.blocksize);
+    bits_set(toybuf, 0, start);
+    bits_set(toybuf, end, TT.blockbits-end);
+    temp = TT.treeblocks - usedblocks;
+    if (temp) {
+      if (end-start > temp) temp = end-start;
+      bits_set(toybuf, start, temp);
+    }
+    xwrite(TT.fsfd, toybuf, TT.blocksize);
+
+    // Write inode bitmap
+    memset(toybuf, 0, TT.blocksize);
+    j = 0;
+    if (!i) bits_set(toybuf, 0, j = INODES_RESERVED);
+    bits_set(toybuf, TT.inodespg, slot = TT.blockbits-TT.inodespg);
+    temp = TT.treeinodes - usedinodes;
+    if (temp) {
+      if (slot-j > temp) temp = slot-j;
+      bits_set(toybuf, j, temp);
+    }
+    xwrite(TT.fsfd, toybuf, TT.blocksize);
+
+    // Write inode table for this group (TODO)
+    for (j = 0; j<TT.inodespg; j++) {
+      slot = j % (TT.blocksize/sizeof(struct ext2_inode));
+      if (!slot) {
+        if (j) xwrite(TT.fsfd, in, TT.blocksize);
+        memset(in, 0, TT.blocksize);
+      }
+      if (!i && j<INODES_RESERVED) {
+        // Write root inode
+        if (j == 2) fill_inode(in+slot, dtb);
+      } else if (dti) {
+        fill_inode(in+slot, dti);
+        dti = treenext(dti);
+      }
+    }
+    xwrite(TT.fsfd, in, TT.blocksize);
+
+    while (dtb) {
+      // TODO write index data block
+      // TODO write root directory data block
+      // TODO write directory data block
+      // TODO write file data block
+      put_zeroes(TT.blocksize);
+      start++;
+      if (start == end) break;
+    }
+    // Write data blocks (TODO)
+    put_zeroes((end-start) * TT.blocksize);
+  }
+}
diff --git a/toybox/toys/pending/modprobe.c b/toybox/toys/pending/modprobe.c
new file mode 100644
index 0000000..ebf17a0
--- /dev/null
+++ b/toybox/toys/pending/modprobe.c
@@ -0,0 +1,567 @@
+/* modprobe.c - modprobe utility.
+ *
+ * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_MODPROBE(NEWTOY(modprobe, "alrqvsDb", TOYFLAG_SBIN))
+
+config MODPROBE
+  bool "modprobe"
+  default n
+  help
+    usage: modprobe [-alrqvsDb] MODULE [symbol=value][...]
+
+    modprobe utility - inserts modules and dependencies.
+
+    -a  Load multiple MODULEs
+    -l  List (MODULE is a pattern)
+    -r  Remove MODULE (stacks) or do autoclean
+    -q  Quiet
+    -v  Verbose
+    -s  Log to syslog
+    -D  Show dependencies
+    -b  Apply blacklist to module names too
+*/
+#define FOR_modprobe
+#include "toys.h"
+#include <sys/syscall.h>
+
+GLOBALS(
+  struct arg_list *probes;
+  struct arg_list *dbase[256];
+  char *cmdopts;
+  int nudeps;
+  uint8_t symreq;
+  void (*dbg)(char *format, ...);
+)
+
+/* Note: if "#define DBASE_SIZE" modified, 
+ * Please update GLOBALS dbase[256] accordingly.
+ */
+#define DBASE_SIZE  256
+#define MODNAME_LEN 256
+
+// Modules flag definations
+#define MOD_ALOADED   0x0001
+#define MOD_BLACKLIST 0x0002
+#define MOD_FNDDEPMOD 0x0004
+#define MOD_NDDEPS    0x0008
+
+// dummy interface for debugging.
+static void dummy(char *format, ...)
+{
+}
+
+// Current probing modules info
+struct module_s {
+  uint32_t flags;
+  char *cmdname, *name, *depent, *opts;
+  struct arg_list *rnames, *dep;
+};
+
+// Converts path name FILE to module name.
+static char *path2mod(char *file, char *mod)
+{
+  int i;
+  char *from;
+
+  if (!file) return NULL;
+  if (!mod) mod = xmalloc(MODNAME_LEN);
+	
+  from = getbasename(file);
+  
+  for (i = 0; i < (MODNAME_LEN-1) && from[i] && from[i] != '.'; i++)
+    mod[i] = (from[i] == '-') ? '_' : from[i];
+  mod[i] = '\0';
+  return mod;
+}
+
+// Add options in opts from toadd.
+static char *add_opts(char *opts, char *toadd)
+{
+  if (toadd) {
+    int optlen = 0;
+
+    if (opts) optlen = strlen(opts);
+    opts = xrealloc(opts, optlen + strlen(toadd) + 2);
+    sprintf(opts + optlen, " %s", toadd);
+  }
+  return opts;
+}
+
+// Remove first element from the list and return it.
+static void *llist_popme(struct arg_list **head)
+{
+  char *data = NULL;
+  struct arg_list *temp = *head;
+
+  if (temp) {
+    data = temp->arg;
+    *head = temp->next;
+    free(temp);
+  }
+  return data;
+}
+
+// Add new node at the beginning of the list.
+static void llist_add(struct arg_list **old, void *data)
+{
+  struct arg_list *new = xmalloc(sizeof(struct arg_list));
+
+  new->arg = (char*)data;
+  new->next = *old;
+  *old = new;
+}
+
+// Add new node at tail of list.
+static void llist_add_tail(struct arg_list **head, void *data)
+{
+  while (*head) head = &(*head)->next;
+  *head = xzalloc(sizeof(struct arg_list));
+  (*head)->arg = (char*)data;
+}
+
+// Reverse list order.
+static struct arg_list *llist_rev(struct arg_list *list)
+{
+  struct arg_list *rev = NULL;
+
+  while (list) {
+    struct arg_list *next = list->next;
+
+    list->next = rev;
+    rev = list;
+    list = next;
+  }
+  return rev;
+}
+
+/*
+ * Returns struct module_s from the data base if found, NULL otherwise.
+ * if add - create module entry, add it to data base and return the same mod.
+ */
+static struct module_s *get_mod(char *mod, uint8_t add)
+{
+  char name[MODNAME_LEN];
+  struct module_s *modentry;
+  struct arg_list *temp;
+  unsigned i, hash = 0;
+
+  path2mod(mod, name);
+  for (i = 0; name[i]; i++) hash = ((hash*31) + hash) + name[i];
+  hash %= DBASE_SIZE;
+  for (temp = TT.dbase[hash]; temp; temp = temp->next) {
+    modentry = (struct module_s *) temp->arg;
+    if (!strcmp(modentry->name, name)) return modentry;
+  }
+  if (!add) return NULL;
+  modentry = xzalloc(sizeof(*modentry));
+  modentry->name = xstrdup(name);
+  llist_add(&TT.dbase[hash], modentry);
+  return modentry;
+}
+
+/*
+ * Read a line from file with \ continuation and escape commented line.
+ * Return the line in allocated string (*li)
+ */
+static int read_line(FILE *fl, char **li)
+{
+  char *nxtline = NULL, *line;
+  int len, nxtlen, linelen, nxtlinelen;
+
+  while (1) {
+    line = NULL;
+    linelen = nxtlinelen = 0;
+    len = getline(&line, (size_t*)&linelen, fl);
+    if (len <= 0) {
+      free(line);
+      return len;
+    }
+    // checking for commented lines.
+    if (line[0] != '#') break;
+    free(line);
+  }
+  for (;;) {
+    if (line[len - 1] == '\n') len--;
+    if (!len) { 
+      free(line);
+      return len;
+    } else if (line[len - 1] != '\\') break;
+    
+    len--;
+    nxtlen = getline(&nxtline, (size_t*)&nxtlinelen, fl);
+    if (nxtlen <= 0) break;
+    if (linelen < len + nxtlen + 1) {
+      linelen = len + nxtlen + 1;
+      line = xrealloc(line, linelen);
+    }
+    memcpy(&line[len], nxtline, nxtlen);
+    len += nxtlen;
+  }
+  line[len] = '\0';
+  *li = xstrdup(line);
+  free(line);
+  if (nxtline) free(nxtline);
+  return len;
+}
+
+/*
+ * Action to be taken on all config files in default directories
+ * checks for aliases, options, install, remove and blacklist
+ */
+static int config_action(struct dirtree *node)
+{
+  FILE *fc;
+  char *filename, *tokens[3], *line, *linecp;
+  struct module_s *modent;
+  int tcount = 0;
+
+  if (!dirtree_notdotdot(node)) return 0;
+  if (S_ISDIR(node->st.st_mode)) return DIRTREE_RECURSE;
+
+  if (!S_ISREG(node->st.st_mode)) return 0; // process only regular file
+  filename = dirtree_path(node, NULL);
+  if (!(fc = fopen(filename, "r"))) {
+    free(filename);
+    return 0;
+  }
+  for (line = linecp = NULL; read_line(fc, &line) > 0; 
+      free(line), free(linecp), line = linecp = NULL) {
+    char *tk = NULL;
+
+    if (!strlen(line)) continue; 
+    linecp = xstrdup(line);
+    for (tk = strtok(linecp, "# \t"), tcount = 0; tk;
+        tk = strtok(NULL, "# \t"), tcount++) {
+      tokens[tcount] = tk;
+      if (tcount == 2) {
+        tokens[2] = line + strlen(tokens[0]) + strlen(tokens[1]) + 2;
+        break;
+      }
+    }
+    if (!tk) continue; 
+    // process the tokens[0] contains first word of config line.
+    if (!strcmp(tokens[0], "alias")) {
+      struct arg_list *temp;
+      char aliase[MODNAME_LEN], *realname;
+
+      if (!tokens[2]) continue;
+      path2mod(tokens[1], aliase);
+      for (temp = TT.probes; temp; temp = temp->next) {
+        modent = (struct module_s *) temp->arg;
+        if (fnmatch(aliase, modent->name, 0)) continue;
+        realname = path2mod(tokens[2], NULL);
+        llist_add(&modent->rnames, realname);
+        if (modent->flags & MOD_NDDEPS) {
+          modent->flags &= ~MOD_NDDEPS;
+          TT.nudeps--;
+        }
+        modent = get_mod(realname, 1);
+        if (!(modent->flags & MOD_NDDEPS)) {
+          modent->flags |= MOD_NDDEPS;
+          TT.nudeps++;
+        }
+      }
+    } else if (!strcmp(tokens[0], "options")) {
+      if (!tokens[2]) continue;
+      modent = get_mod(tokens[1], 1);
+      modent->opts = add_opts(modent->opts, tokens[2]);
+    } else if (!strcmp(tokens[0], "include"))
+      dirtree_read(tokens[1], config_action);
+    else if (!strcmp(tokens[0], "blacklist"))
+      get_mod(tokens[1], 1)->flags |= MOD_BLACKLIST;
+    else if (!strcmp(tokens[0], "install")) continue;
+    else if (!strcmp(tokens[0], "remove")) continue;
+    else if (toys.optflags & FLAG_q)
+      error_msg("Invalid option %s found in file %s", tokens[0], filename);
+  }
+  fclose(fc);
+  free(filename);
+  return 0;
+}
+
+// Show matched modules else return -1 on failure.
+static int depmode_read_entry(char *cmdname)
+{
+  char *line;
+  int ret = -1;
+  FILE *fe = xfopen("modules.dep", "r");
+
+  while (read_line(fe, &line) > 0) {
+    char *tmp = strchr(line, ':');
+
+    if (tmp) {
+      *tmp = '\0';
+     char *name = basename(line);
+
+      tmp = strchr(name, '.');
+      if (tmp) *tmp = '\0';
+      if (!cmdname || !fnmatch(cmdname, name, 0)) {
+        if (tmp) *tmp = '.';
+        TT.dbg("%s\n", line);
+        ret = 0;
+      }
+    }
+    free(line);
+  }
+  fclose(fe);
+  return ret;
+}
+
+// Finds dependencies for modules from the modules.dep file.
+static void find_dep(void)
+{
+  char *line = NULL;
+  struct module_s *mod;
+  FILE *fe = xfopen("modules.dep", "r");
+
+  for (; read_line(fe, &line) > 0; free(line)) {
+    char *tmp = strchr(line, ':');
+
+    if (tmp) {
+      *tmp = '\0';
+      mod = get_mod(line, 0);
+      if (!mod) continue;
+      if ((mod->flags & MOD_ALOADED) &&
+          !(toys.optflags & (FLAG_r | FLAG_D))) continue;
+      
+      mod->flags |= MOD_FNDDEPMOD;
+      if ((mod->flags & MOD_NDDEPS) && (!mod->dep)) {
+        TT.nudeps--;
+        llist_add(&mod->dep, xstrdup(line));
+        tmp++;
+        if (*tmp) {
+          char *tok;
+
+          while ((tok = strsep(&tmp, " \t"))) {
+            if (!*tok) continue;
+            llist_add_tail(&mod->dep, xstrdup(tok));
+          }
+        }
+      }
+    }
+  }
+  fclose(fe);
+}
+
+// Remove a module from the Linux Kernel. if !modules does auto remove.
+static int rm_mod(char *modules, uint32_t flags)
+{
+  if (modules) {
+    int len = strlen(modules);
+
+    if (len > 3 && !strcmp(modules+len-3, ".ko" )) modules[len-3] = 0;
+  }
+
+  errno = 0;
+  syscall(__NR_delete_module, modules, flags ? flags : O_NONBLOCK|O_EXCL);
+
+  return errno;
+}
+
+// Insert module same as insmod implementation.
+static int ins_mod(char *modules, char *flags)
+{
+  char *buf = NULL;
+  int len, res;
+  int fd = xopenro(modules);
+
+  // TODO xreadfile()
+
+  len = fdlength(fd);
+  buf = xmalloc(len);
+  xreadall(fd, buf, len);
+  xclose(fd);
+
+  while (flags && strlen(toybuf) + strlen(flags) + 2 < sizeof(toybuf)) {
+    strcat(toybuf, flags);
+    strcat(toybuf, " ");
+  }
+  res = syscall(__NR_init_module, buf, len, toybuf);
+  if (CFG_TOYBOX_FREE && buf != toybuf) free(buf);
+  return res;
+}
+
+// Add module in probes list, if not loaded.
+static void add_mod(char *name)
+{
+  struct module_s *mod = get_mod(name, 1);
+
+  if (!(toys.optflags & (FLAG_r | FLAG_D)) && (mod->flags & MOD_ALOADED)) {
+    TT.dbg("skipping %s, it is already loaded\n", name);
+    return;
+  }
+  TT.dbg("queuing %s\n", name);
+  mod->cmdname = name;
+  mod->flags |= MOD_NDDEPS;
+  llist_add_tail(&TT.probes, mod);
+  TT.nudeps++;
+  if (!strncmp(mod->name, "symbol:", 7)) TT.symreq = 1;
+}
+
+// Parse cmdline options suplied for module.
+static char *add_cmdopt(char **argv)
+{
+  char *opt = xzalloc(1);
+  int lopt = 0;
+
+  while (*++argv) {
+    char *fmt, *var, *val;
+
+    var = *argv;
+    opt = xrealloc(opt, lopt + 2 + strlen(var) + 2);
+    // check for key=val or key = val.
+    fmt = "%.*s%s ";
+    for (val = var; *val && *val != '='; val++);
+    if (*val && strchr(++val, ' ')) fmt = "%.*s\"%s\" ";
+    lopt += sprintf(opt + lopt, fmt, (int) (val - var), var, val);
+  }
+  return opt;
+}
+
+// Probes a single module and loads all its dependencies.
+static int go_probe(struct module_s *m)
+{
+  int rc = 0, first = 1;
+
+  if (!(m->flags & MOD_FNDDEPMOD)) {
+    if (!(toys.optflags & FLAG_q))
+      error_msg("module %s not found in modules.dep", m->name);
+    return -ENOENT;
+  }
+  TT.dbg("go_prob'ing %s\n", m->name);
+  if (!(toys.optflags & FLAG_r)) m->dep = llist_rev(m->dep);
+  
+  while (m->dep) {
+    struct module_s *m2;
+    char *fn, *options;
+
+    rc = 0;
+    fn = llist_popme(&m->dep);
+    m2 = get_mod(fn, 1);
+    // are we removing ?
+    if (toys.optflags & FLAG_r) {
+      if (m2->flags & MOD_ALOADED) {
+        if ((rc = rm_mod(m2->name, O_EXCL))) {
+          if (first) {
+            perror_msg("can't unload module %s", m2->name);
+            break;
+          }
+        } else m2->flags &= ~MOD_ALOADED;
+      }
+      first = 0;
+      continue;
+    }
+    options = m2->opts;
+    m2->opts = NULL;
+    if (m == m2) options = add_opts(options, TT.cmdopts);
+
+    // are we only checking dependencies ?
+    if (toys.optflags & FLAG_D) {
+      TT.dbg(options ? "insmod %s %s\n" : "insmod %s\n", fn, options);
+      if (options) free(options);
+      continue;
+    }
+    if (m2->flags & MOD_ALOADED) {
+      TT.dbg("%s is already loaded, skipping\n", fn);
+      if (options) free(options);
+      continue;
+    }
+    // none of above is true insert the module.
+    rc = ins_mod(fn, options);
+    TT.dbg("loaded %s '%s', rc:%d\n", fn, options, rc);
+    if (rc == EEXIST) rc = 0;
+    if (options) free(options);
+    if (rc) {
+      perror_msg("can't load module %s (%s)", m2->name, fn);
+      break;
+    }
+    m2->flags |= MOD_ALOADED;
+  }
+  return rc;
+}
+
+void modprobe_main(void)
+{
+  struct utsname uts;
+  char **argv = toys.optargs, *procline = NULL;
+  FILE *fs;
+  struct module_s *module;
+  unsigned flags = toys.optflags;
+
+  TT.dbg = (flags & FLAG_v) ? xprintf : dummy;
+
+  if ((toys.optc < 1) && (((flags & FLAG_r) && (flags & FLAG_l))
+        ||(!((flags & FLAG_r)||(flags & FLAG_l)))))
+  {
+	  help_exit("bad syntax");
+  }
+  // Check for -r flag without arg if yes then do auto remove.
+  if ((flags & FLAG_r) && !toys.optc) {
+    if (rm_mod(NULL, O_NONBLOCK | O_EXCL)) perror_exit("rmmod");
+    return;
+  }
+
+  // change directory to /lib/modules/<release>/ 
+  xchdir("/lib/modules");
+  uname(&uts);
+  xchdir(uts.release);
+
+  // modules.dep processing for dependency check.
+  if (flags & FLAG_l) {
+    if (depmode_read_entry(toys.optargs[0])) error_exit("no module found.");
+    return;
+  }
+  // Read /proc/modules to get loaded modules.
+  fs = xfopen("/proc/modules", "r");
+  
+  while (read_line(fs, &procline) > 0) {
+    *(strchr(procline, ' ')) = '\0';
+    get_mod(procline, 1)->flags = MOD_ALOADED;
+    free(procline);
+    procline = NULL;
+  }
+  fclose(fs);
+  if ((flags & FLAG_a) || (flags & FLAG_r)) {
+    do {
+      add_mod(*argv++);
+    } while (*argv);
+  } else {
+    add_mod(argv[0]);
+    TT.cmdopts = add_cmdopt(argv);
+  }
+  if (!TT.probes) {
+    TT.dbg("All modules loaded\n");
+    return;
+  }
+  dirtree_read("/etc/modprobe.conf", config_action);
+  dirtree_read("/etc/modprobe.d", config_action);
+  if (TT.symreq) dirtree_read("modules.symbols", config_action);
+  if (TT.nudeps) dirtree_read("modules.alias", config_action);
+  find_dep();
+  while ((module = llist_popme(&TT.probes))) {
+    if (!module->rnames) {
+      TT.dbg("probing by module name\n");
+      /* This is not an alias. Literal names are blacklisted
+       * only if '-b' is given.
+       */
+      if (!(flags & FLAG_b) || !(module->flags & MOD_BLACKLIST))
+        go_probe(module);
+      continue;
+    }
+    do { // Probe all real names for the alias.
+      char *real = ((struct arg_list*)llist_pop(&module->rnames))->arg;
+      struct module_s *m2 = get_mod(real, 0);
+      
+      TT.dbg("probing alias %s by realname %s\n", module->name, real);
+      if (!m2) continue;
+      if (!(m2->flags & MOD_BLACKLIST) 
+          && (!(m2->flags & MOD_ALOADED) || (flags & (FLAG_r | FLAG_D))))
+        go_probe(m2);
+      free(real);
+    } while (module->rnames);
+  }
+}
diff --git a/toybox/toys/pending/more.c b/toybox/toys/pending/more.c
new file mode 100644
index 0000000..7923ee4
--- /dev/null
+++ b/toybox/toys/pending/more.c
@@ -0,0 +1,153 @@
+/* more.c - View FILE (or stdin) one screenful at a time.
+ *
+ * Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com>
+ *
+ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html
+
+USE_MORE(NEWTOY(more, 0, TOYFLAG_USR|TOYFLAG_BIN))
+
+config MORE
+  bool "more"
+  default n
+  help
+    usage: more [FILE...]
+
+    View FILE(s) (or stdin) one screenful at a time.
+*/
+
+#define FOR_more
+#include "toys.h"
+
+GLOBALS(
+  struct termios inf;
+  int cin_fd;
+)
+
+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);
+  _exit(sig | 128);
+}
+
+static void show_file_header(const char *name)
+{
+  printf(":::::::::::::::::::::::\n%s\n:::::::::::::::::::::::\n", name);
+}
+
+static int prompt(FILE *cin, const char* fmt, ...)
+{
+  int input_key;
+  va_list ap;
+
+  printf("\33[7m"); // Reverse video before printing the prompt.
+
+  va_start(ap, fmt);
+  vfprintf(stdout, fmt, ap);
+  va_end(ap);
+
+  while (1) {
+    fflush(NULL);
+    input_key = tolower(getc(cin));
+    printf("\33[0m\33[1K\r"); // Reset all attributes, erase to start of line.
+    if (strchr(" \nrq", input_key)) {
+      fflush(NULL);
+      return input_key;
+    }
+    printf("\33[7m(Enter:Next line Space:Next page Q:Quit R:Show the rest)");
+  }
+}
+
+static void do_cat_operation(int fd, char *name)
+{
+  if (toys.optc > 1) show_file_header(name);
+  xsendfile(fd, 1);
+}
+
+void more_main()
+{
+  int ch, input_key = 0, show_prompt;
+  unsigned rows = 24, cols = 80, row = 0, col = 0;
+  struct stat st;  
+  struct termios newf;
+  FILE *fp, *cin;
+
+  if (!isatty(1) || !(cin = fopen("/dev/tty", "r"))) {
+    loopfiles(toys.optargs, do_cat_operation);
+    return;
+  }
+
+  TT.cin_fd = fileno(cin);
+  tcgetattr(TT.cin_fd, &TT.inf);
+
+  //Prepare terminal for input
+  memcpy(&newf, &TT.inf, sizeof(struct termios));
+  newf.c_lflag &= ~(ICANON | ECHO);
+  newf.c_cc[VMIN] = 1;
+  newf.c_cc[VTIME] = 0;
+  tcsetattr(TT.cin_fd, TCSANOW, &newf);
+
+  sigatexit(signal_handler);
+
+  do {
+    fp = stdin;
+    if (*toys.optargs && !(fp = fopen(*toys.optargs, "r"))) {
+        perror_msg("%s", *toys.optargs);
+        goto next_file;
+    }
+    st.st_size = show_prompt = col = row = 0;
+    fstat(fileno(fp), &st);
+    terminal_size(&cols, &rows);
+    rows--;
+
+    if (toys.optc > 1) {
+      show_file_header(*toys.optargs);
+      row += 3;
+    }
+
+    while ((ch = getc(fp)) != EOF) {
+      if (input_key != 'r' && show_prompt) {
+        if (st.st_size)
+          input_key = prompt(cin, "--More--(%d%% of %lld bytes)",
+              (int) (100 * ( (double) ftell(fp) / (double) st.st_size)),
+              (long long)st.st_size);
+        else
+          input_key = prompt(cin, "--More--");
+        if (input_key == 'q') goto stop; 
+
+        col = row = show_prompt = 0;
+        terminal_size(&cols, &rows);
+        rows--;
+      }
+
+      putchar(ch);
+      if (ch == '\t') col = (col | 0x7) + 1;
+      else col++;
+      if (col == cols) putchar(ch = '\n');
+      if (ch == '\n') {
+        col = 0;
+        if (++row >= rows || input_key == '\n') show_prompt = 1;
+      }
+    }
+    fclose(fp);
+
+next_file:
+    if (*toys.optargs && *++toys.optargs) {
+      input_key = prompt(cin, "--More--(Next file: %s)", *toys.optargs);
+      if (input_key == 'q') goto stop;
+    }
+  } while (*toys.optargs);
+
+stop:
+  tcsetattr(TT.cin_fd, TCSANOW, &TT.inf);
+  fclose(cin);
+  // Even if optarg not found, exit value still 0
+  toys.exitval = 0;
+}
diff --git a/toybox/toys/pending/openvt.c b/toybox/toys/pending/openvt.c
new file mode 100644
index 0000000..29f8a17
--- /dev/null
+++ b/toybox/toys/pending/openvt.c
@@ -0,0 +1,145 @@
+/* openvt.c - Run a program on a new VT
+ *
+ * Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89@gmail.com>
+ *
+ * No Standard
+
+USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+
+config OPENVT
+  bool "openvt"
+  default n
+  depends on TOYBOX_FORK
+  help
+    usage: openvt [-c N] [-sw] [command [command_options]]
+
+    start a program on a new virtual terminal (VT)
+
+    -c N  Use VT N
+    -s    Switch to new VT
+    -w    Wait for command to exit
+
+    if -sw used together, switch back to originating VT when command completes
+
+config DEALLOCVT
+  bool "deallocvt"
+  default n
+  help
+    usage: deallocvt [N]
+
+    Deallocate unused virtual terminal /dev/ttyN, or all unused consoles.
+*/
+
+#define FOR_openvt
+#include "toys.h"
+#include <linux/vt.h>
+#include <linux/kd.h>
+
+GLOBALS(
+  unsigned long vt_num;
+)
+
+int open_console(void)
+{
+  char arg, *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"};
+  int i, fd;
+
+  for (i = 0; i < ARRAY_LEN(console_name); i++) {
+    fd = open(console_name[i], O_RDWR);
+    if (fd >= 0) {
+      arg = 0;
+      if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
+      close(fd);
+    }
+  }
+
+  /* check std fd 0, 1 and 2 */
+  for (fd = 0; fd < 3; fd++) {
+    arg = 0;
+    if (0 == ioctl(fd, KDGKBTYPE, &arg)) return fd;
+  }
+
+  return -1;
+}
+
+int xvtnum(int fd)
+{
+  int ret;
+
+  ret = ioctl(fd, VT_OPENQRY, (int *)&TT.vt_num);
+  if (ret != 0 || TT.vt_num <= 0) perror_exit("can't find open VT");
+
+  return TT.vt_num;
+}
+
+void openvt_main(void)
+{
+  int fd, vt_fd, ret = 0;
+  struct vt_stat vstate;
+  pid_t pid;
+
+  if (!(toys.optflags & FLAG_c)) {
+    // check if fd 0,1 or 2 is already opened
+    for (fd = 0; fd < 3; fd++)
+      if (!ioctl(fd, VT_GETSTATE, &vstate)) {
+        ret = xvtnum(fd);
+        break;
+      }
+
+    // find VT number using /dev/console
+    if (!ret) {
+      fd = xopen("/dev/console", O_RDONLY | O_NONBLOCK);
+      xioctl(fd, VT_GETSTATE, &vstate);
+      xvtnum(fd);
+    }
+  }
+
+  sprintf(toybuf, "/dev/tty%lu", TT.vt_num);
+  fd = open_console();
+  xioctl(fd, VT_GETSTATE, &vstate);
+
+  close(0);  //new vt becomes stdin
+  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);
+  }
+
+  close(1);
+  close(2);
+  dup2(vt_fd, 1);
+  dup2(vt_fd, 2);
+  while (vt_fd > 2)
+    close(vt_fd--);
+
+  pid = xfork();
+  if (!pid) {
+    setsid();
+    ioctl(vt_fd, TIOCSCTTY, 0);
+    xexec(toys.optargs);
+  }
+
+  if (toys.optflags & FLAG_w) {
+    while (-1 == waitpid(pid, NULL, 0) && errno == EINTR)
+      ;
+    if (toys.optflags & FLAG_s) {
+      ioctl(fd, VT_ACTIVATE, vstate.v_active);
+      ioctl(fd, VT_WAITACTIVE, vstate.v_active);
+      //check why deallocate isn't working here
+      xioctl(fd, VT_DISALLOCATE, (void *)(ptrdiff_t)TT.vt_num); 
+    }
+  }
+}
+
+void deallocvt_main(void)
+{
+  long vt_num = 0; // 0 deallocates all unused consoles
+  int fd;
+
+  if (*toys.optargs) vt_num = atolx_range(*toys.optargs, 1, 63);
+
+  if ((fd = open_console()) < 0) error_exit("can't open console");
+  xioctl(fd, VT_DISALLOCATE, (void *)vt_num);
+  if (CFG_TOYBOX_FREE) close(fd);
+}
diff --git a/toybox/toys/pending/ping.c b/toybox/toys/pending/ping.c
new file mode 100644
index 0000000..629f98b
--- /dev/null
+++ b/toybox/toys/pending/ping.c
@@ -0,0 +1,110 @@
+/* ping.c - check network connectivity
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * Not in SUSv4.
+ 
+USE_PING(NEWTOY(ping, "<1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]", TOYFLAG_ROOTONLY|TOYFLAG_USR|TOYFLAG_BIN))
+ 
+config PING
+  bool "ping"
+  default n
+  help
+    usage: ping [OPTIONS] HOST
+
+    Check network connectivity by sending packets to a host and reporting
+    its response.
+
+    Send ICMP ECHO_REQUEST packets to ipv4 or ipv6 addresses and prints each
+    echo it receives back, with round trip time.
+
+    Options:
+    -4, -6      Force IPv4 or IPv6
+    -c CNT      Send CNT many packets
+    -I IFACE/IP Source interface or address
+    -q          Quiet, only displays output at start and when finished
+    -s SIZE     Packet SIZE in bytes (default 56)
+    -t TTL      Set Time (number of hops) To Live
+    -W SEC      Seconds to wait for response after all packets sent (default 10)
+    -w SEC      Exit after this many seconds
+*/
+
+#define FOR_ping 
+#include "toys.h"
+
+#include <ifaddrs.h>
+
+GLOBALS(
+  long wait_exit;
+  long wait_resp;
+  char *iface;
+  long size;
+  long count;
+  long ttl;
+
+  int sock;
+)
+
+void ping_main(void)
+{
+  int family, protocol;
+  union {
+    struct in_addr in;
+    struct in6_addr in6;
+  } src_addr;
+  char *host = 0;
+
+  // Determine IPv4 vs IPv6 type
+
+  if(!(toys.optflags & (FLAG_4|FLAG_6))) {
+// todo getaddrinfo instead?
+    if (inet_pton(AF_INET6, toys.optargs[0], (void*)&src_addr))
+      toys.optflags |= FLAG_6;
+  }
+
+  if (toys.optflags & FLAG_6) {
+    family = AF_INET6;
+    protocol = IPPROTO_ICMPV6;
+  } else {
+    family = AF_INET;
+    protocol = IPPROTO_ICMP;
+  }
+
+  if (!(toys.optflags & FLAG_s)) TT.size = 56; // 64-PHDR_LEN
+
+  if (TT.iface) {
+    memset(&src_addr, 0, sizeof(src_addr));
+
+    // IP address?
+    if (!inet_pton(family, TT.iface, &src_addr)) {
+      struct ifaddrs *ifsave, *ifa = 0;
+
+      // Interface name?
+      if (!getifaddrs(&ifsave)) {
+        for (ifa = ifsave; ifa; ifa = ifa->ifa_next) {
+          if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != family) continue;
+          if (!strcmp(ifa->ifa_name, TT.iface)) {
+            if (family == AF_INET)
+              memcpy(&src_addr,
+                &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
+                sizeof(struct in_addr));
+            else memcpy(&src_addr,
+                &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
+                sizeof(struct in6_addr));
+            break;
+          }
+        }
+        freeifaddrs(ifsave);
+      }
+      if (!ifa)
+        error_exit("no v%d addr for -I %s", 4+2*(family==AF_INET6), TT.iface);
+    }
+    inet_ntop(family, &src_addr, toybuf, sizeof(toybuf));
+    host = xstrdup(toybuf);
+  }
+
+printf("host=%s\n", host);
+
+  // Open raw socket
+  TT.sock = xsocket(family, SOCK_RAW, protocol);
+}
diff --git a/toybox/toys/pending/route.c b/toybox/toys/pending/route.c
new file mode 100644
index 0000000..0126dc9
--- /dev/null
+++ b/toybox/toys/pending/route.c
@@ -0,0 +1,442 @@
+/* route.c - Display/edit network routing table.
+ *
+ * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+ *
+USE_ROUTE(NEWTOY(route, "?neA:", TOYFLAG_BIN))
+config ROUTE
+  bool "route"
+  default n
+  help
+    usage: route [-ne] [-A inet[6]] / [add|del]
+
+    Display/Edit kernel routing tables.
+
+    -n	no name lookups
+    -e	display other/more information
+    -A	inet{6} Select Address Family
+
+    reject mod dyn reinstate metric netmask gw mss window irtt dev
+*/
+
+#define FOR_route
+#include "toys.h"
+#include <net/route.h>
+
+GLOBALS(
+  char *family;
+)
+
+#define DEFAULT_PREFIXLEN 128
+#define INVALID_ADDR 0xffffffffUL
+#define IPV6_ADDR_LEN 40 //32 + 7 (':') + 1 ('\0')
+
+struct _arglist {
+  char *arg;
+
+  int action;
+};
+
+static struct _arglist arglist1[] = {
+  { "add", 1 }, { "del", 2 },
+  { "delete", 2 }, { NULL, 0 }
+};
+
+static struct _arglist arglist2[] = {
+  { "-net", 1 }, { "-host", 2 },
+  { NULL, 0 }
+};
+
+// to get the host name from the given ip.
+static int get_hostname(char *ipstr, struct sockaddr_in *sockin)
+{
+  struct hostent *host;
+
+  sockin->sin_family = AF_INET;
+  sockin->sin_port = 0;
+
+  if (!strcmp(ipstr, "default")) {
+    sockin->sin_addr.s_addr = INADDR_ANY;
+    return 1;
+  }
+
+  if (inet_aton(ipstr, &sockin->sin_addr)) return 0;
+  if (!(host = gethostbyname(ipstr))) return -1;
+  memcpy(&sockin->sin_addr, host->h_addr_list[0], sizeof(struct in_addr));
+  return 0;
+}
+
+// used to extract the address info from the given ip.
+static int get_addrinfo(char *ip, struct sockaddr_in6 *sock_in6)
+{
+  struct addrinfo hints, *result;
+  int status = 0;
+
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = AF_INET6;
+  if ((status = getaddrinfo(ip, NULL, &hints, &result))) {
+    perror_msg("getaddrinfo: %s", gai_strerror(status));
+    return -1;
+  }
+  if (result) {
+    memcpy(sock_in6, result->ai_addr, sizeof(*sock_in6));
+    freeaddrinfo(result);
+  }
+  return 0;
+}
+
+static void get_flag_value(char *str, int flags)
+{
+  // RTF_* bits in order:
+  // UP, GATEWAY, HOST, REINSTATE, DYNAMIC, MODIFIED, DEFAULT, ADDRCONF, CACHE
+  int i = 0, mask = 0x105003f;
+
+  for (; mask; mask>>=1) if (mask&1) {
+    if (flags&(1<<i)) *str++ = "UGHRDMDAC"[i];
+    i++;
+  }
+  *str = 0;
+}
+
+// extract inet4 route info from /proc/net/route file and display it.
+static void display_routes(void)
+{
+  unsigned long dest, gate, mask;
+  int flags, ref, use, metric, mss, win, irtt, items;
+  char iface[64] = {0,}, flag_val[10]; //there are 9 flags "UGHRDMDAC" for route.
+
+  FILE *fp = xfopen("/proc/net/route", "r");
+
+  xprintf("Kernel IP routing table\n"
+      "Destination     Gateway         Genmask         Flags %s Iface\n",
+      (toys.optflags & FLAG_e)? "  MSS Window  irtt" : "Metric Ref    Use");
+
+  if (fscanf(fp, "%*[^\n]\n") < 0) perror_exit("fscanf"); //skip 1st line
+  while ((items = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n", iface, &dest, 
+          &gate, &flags, &ref, &use, &metric, &mask, &mss, &win, &irtt)) == 11)
+  {
+    char *destip = toybuf, *gateip = toybuf+32, *maskip = toybuf+64; //ip string 16
+
+    if (!(flags & RTF_UP)) continue; //skip down interfaces.
+
+    if (!dest && !(toys.optflags & FLAG_n)) strcpy( destip, "default");
+    else if (!inet_ntop(AF_INET, &dest, destip, 32)) perror_exit("inet");
+
+    if (!gate && !(toys.optflags & FLAG_n)) strcpy( gateip, "*");
+    else if (!inet_ntop(AF_INET, &gate, gateip, 32)) perror_exit("inet");
+
+    if (!inet_ntop(AF_INET, &mask, maskip, 32)) perror_exit("inet");
+
+    //Get flag Values
+    get_flag_value(flag_val, flags);
+    if (flags & RTF_REJECT) flag_val[0] = '!';
+    xprintf("%-15.15s %-15.15s %-16s%-6s", destip, gateip, maskip, flag_val);
+    if (toys.optflags & FLAG_e) xprintf("%5d %-5d %6d %s\n", mss, win, irtt, iface);
+    else xprintf("%-6d %-2d %7d %s\n", metric, ref, use, iface);
+  }
+
+  if (items > 0 && feof(fp)) perror_exit("fscanf %d", items);
+  fclose(fp);
+}
+
+/*
+ * find the given parameter in list like add/del/net/host.
+ * and if match found return the appropriate action.
+ */
+static int get_action(char ***argv, struct _arglist *list)
+{
+  struct _arglist *alist;
+
+  if (!**argv) return 0;
+  for (alist = list; alist->arg; alist++) { //find the given parameter in list
+    if (!strcmp(**argv, alist->arg)) {
+      *argv += 1;
+      return alist->action;
+    }
+  }
+  return 0;
+}
+
+/*
+ * get prefix len (if any) and remove the prefix from target ip.
+ * if no prefix then set netmask as default.
+ */
+static void is_prefix(char **tip, char **netmask, struct rtentry *rt)
+{
+  char *prefix = strchr(*tip, '/');
+  if (prefix) {
+    unsigned long plen;
+    plen = atolx_range(prefix + 1, 0, 32);
+    //used to verify the netmask and route conflict.
+    (((struct sockaddr_in *)&((rt)->rt_genmask))->sin_addr.s_addr)
+      = htonl( ~(INVALID_ADDR >> plen));
+    *prefix = '\0';
+    rt->rt_genmask.sa_family = AF_INET;
+  } else *netmask = "default"; //default netmask.
+}
+
+/*
+ * used to get the params like: metric, netmask, gw, mss, window, irtt, dev and their values.
+ * additionally set the flag values for reject, mod, dyn and reinstate.
+ */
+static void get_next_params(char **argv, struct rtentry *rt, char **netmask)
+{
+  for (;*argv;argv++) {
+    if (!strcmp(*argv, "reject")) rt->rt_flags |= RTF_REJECT;
+    else if (!strcmp(*argv, "mod")) rt->rt_flags |= RTF_MODIFIED;
+    else if (!strcmp(*argv, "dyn")) rt->rt_flags |= RTF_DYNAMIC;
+    else if (!strcmp(*argv, "reinstate")) rt->rt_flags |= RTF_REINSTATE;
+    else {
+      if (!argv[1]) help_exit(0);
+
+      //set the metric field in the routing table.
+      if (!strcmp(*argv, "metric"))
+        rt->rt_metric = atolx_range(*argv, 0, ULONG_MAX) + 1;
+      else if (!strcmp(*argv, "netmask")) {
+        //when adding a network route, the netmask to be used.
+        struct sockaddr sock;
+        unsigned int addr_mask = (((struct sockaddr_in *)&((rt)->rt_genmask))->sin_addr.s_addr);
+
+        if (addr_mask) help_exit("dup netmask");
+        *netmask = *argv;
+        if (get_hostname(*netmask, (struct sockaddr_in *) &sock) < 0)
+          perror_exit("resolving '%s'", *netmask);
+        rt->rt_genmask = sock;
+      } else if (!strcmp(*argv, "gw")) { 
+        //route packets via a gateway.
+        if (!(rt->rt_flags & RTF_GATEWAY)) {
+          int ishost;
+
+          if ((ishost = get_hostname(*argv, (struct sockaddr_in *) &rt->rt_gateway)) == 0) {
+            rt->rt_flags |= RTF_GATEWAY;
+          } else if (ishost < 0) perror_exit("resolving '%s'", *argv);
+          else perror_exit("gateway '%s' is a NETWORK", *argv);
+        } else help_exit("dup gw");
+      } else if (!strcmp(*argv, "mss")) {
+        //set the TCP Maximum Segment Size for connections over this route.
+        rt->rt_mss = atolx_range(*argv, 64, 32768); //MSS low and max
+        rt->rt_flags |= RTF_MSS;
+      } else if (!strcmp(*argv, "window")) {
+        //set the TCP window size for connections over this route to W bytes.
+        rt->rt_window = atolx_range(*argv, 128, INT_MAX); //win low
+        rt->rt_flags |= RTF_WINDOW;
+      } else if (!strcmp(*argv, "irtt")) {
+        rt->rt_irtt = atolx_range(*argv, 0, INT_MAX);
+        rt->rt_flags |= RTF_IRTT;
+      } else if (!strcmp(*argv, "dev") && !rt->rt_dev) rt->rt_dev = *argv;
+      else help_exit("no '%s'", *argv);
+    }
+  }
+
+  if (!rt->rt_dev && (rt->rt_flags & RTF_REJECT)) rt->rt_dev = (char *)"lo";
+}
+
+// verify the netmask and conflict in netmask and route address.
+static void verify_netmask(struct rtentry *rt, char *netmask)
+{
+  unsigned int addr_mask = (((struct sockaddr_in *)&((rt)->rt_genmask))->sin_addr.s_addr);
+  unsigned int router_addr = ~(unsigned int)(((struct sockaddr_in *)&((rt)->rt_dst))->sin_addr.s_addr);
+
+  if (addr_mask) {
+    addr_mask = ~ntohl(addr_mask);
+    if ((rt->rt_flags & RTF_HOST) && addr_mask != INVALID_ADDR)
+      perror_exit("conflicting netmask and host route");
+    if (addr_mask & (addr_mask + 1)) perror_exit("wrong netmask '%s'", netmask);
+    addr_mask = ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr;
+    if (addr_mask & router_addr) perror_exit("conflicting netmask and route address");
+  }
+}
+
+// add/del a route.
+static void setroute(char **argv)
+{
+  struct rtentry rt;
+  char *netmask = NULL, *targetip;
+  int is_net_or_host = 0, sokfd, arg2_action;
+  int action = get_action(&argv, arglist1); //verify the arg for add/del.
+
+  if (!action || !*argv) help_exit("setroute");
+
+  arg2_action = get_action(&argv, arglist2); //verify the arg for -net or -host
+  if (!*argv) help_exit("setroute");
+
+  memset(&rt, 0, sizeof(struct rtentry));
+  targetip = *argv++;
+
+  is_prefix((char **)&targetip, (char **)&netmask, &rt);
+  if ((is_net_or_host = get_hostname(targetip, 
+          (struct sockaddr_in *) &rt.rt_dst)) < 0)
+    perror_exit("resolving '%s'", targetip);
+
+  if (arg2_action) is_net_or_host = arg2_action & 1;
+  rt.rt_flags = ((is_net_or_host) ? RTF_UP : (RTF_UP | RTF_HOST));
+
+  get_next_params(argv, &rt, (char **)&netmask);
+  verify_netmask(&rt, (char *)netmask);
+
+  if ((action == 1) && (rt.rt_flags & RTF_HOST))
+    (((struct sockaddr_in *)&((rt).rt_genmask))->sin_addr.s_addr) = INVALID_ADDR;
+
+  sokfd = xsocket(AF_INET, SOCK_DGRAM, 0);
+  if (action == 1) xioctl(sokfd, SIOCADDRT, &rt);
+  else xioctl(sokfd, SIOCDELRT, &rt);
+  xclose(sokfd);
+}
+
+/*
+ * get prefix len (if any) and remove the prefix from target ip.
+ * if no prefix then set default prefix len.
+ */
+static void is_prefix_inet6(char **tip, struct in6_rtmsg *rt)
+{
+  unsigned long plen;
+  char *prefix = strchr(*tip, '/');
+
+  if (prefix) {
+    *prefix = '\0';
+    plen = atolx_range(prefix + 1, 0, 128); //DEFAULT_PREFIXLEN);
+  } else plen = DEFAULT_PREFIXLEN;
+
+  rt->rtmsg_flags = (plen == DEFAULT_PREFIXLEN) ? (RTF_UP | RTF_HOST) : RTF_UP;
+  rt->rtmsg_dst_len = plen;
+}
+
+/*
+ * used to get the params like: metric, gw, dev and their values.
+ * additionally set the flag values for mod and dyn.
+ */
+static void get_next_params_inet6(char **argv, struct sockaddr_in6 *sock_in6, struct in6_rtmsg *rt, char **dev_name)
+{
+  for (;*argv;argv++) {
+    if (!strcmp(*argv, "mod")) rt->rtmsg_flags |= RTF_MODIFIED;
+    else if (!strcmp(*argv, "dyn")) rt->rtmsg_flags |= RTF_DYNAMIC;
+    else {
+      if (!argv[1]) help_exit(0);
+
+      if (!strcmp(*argv, "metric")) 
+        rt->rtmsg_metric = atolx_range(*argv, 0, ULONG_MAX);
+      else if (!strcmp(*argv, "gw")) {
+        //route packets via a gateway.
+        if (!(rt->rtmsg_flags & RTF_GATEWAY)) {
+          if (!get_addrinfo(*argv, (struct sockaddr_in6 *) &sock_in6)) {
+            memcpy(&rt->rtmsg_gateway, sock_in6->sin6_addr.s6_addr, sizeof(struct in6_addr));
+            rt->rtmsg_flags |= RTF_GATEWAY;
+          } else perror_exit("resolving '%s'", *argv);
+        } else help_exit(0);
+      } else if (!strcmp(*argv, "dev")) {
+        if (!*dev_name) *dev_name = *argv;
+      } else help_exit(0);
+    }
+  }
+}
+
+// add/del a route.
+static void setroute_inet6(char **argv)
+{
+  struct sockaddr_in6 sock_in6;
+  struct in6_rtmsg rt;
+  char *targetip, *dev_name = 0;
+  int sockfd, action = get_action(&argv, arglist1);
+
+  if (!action || !*argv) help_exit(0);
+  memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
+  memset(&rt, 0, sizeof(struct in6_rtmsg));
+  targetip = *argv++;
+  if (!*argv) help_exit(0);
+
+  if (!strcmp(targetip, "default")) {
+    rt.rtmsg_flags = RTF_UP;
+    rt.rtmsg_dst_len = 0;
+  } else {
+    is_prefix_inet6((char **)&targetip, &rt);
+    if (get_addrinfo(targetip, (struct sockaddr_in6 *) &sock_in6))
+      perror_exit("resolving '%s'", targetip);
+  }
+  rt.rtmsg_metric = 1; //default metric.
+  memcpy(&rt.rtmsg_dst, sock_in6.sin6_addr.s6_addr, sizeof(struct in6_addr));
+  get_next_params_inet6(argv, &sock_in6, &rt, (char **)&dev_name);
+
+  sockfd = xsocket(AF_INET6, SOCK_DGRAM, 0);
+  if (dev_name) {
+    char ifre_buf[sizeof(struct ifreq)] = {0,};
+    struct ifreq *ifre = (struct ifreq*)ifre_buf;
+    xstrncpy(ifre->ifr_name, dev_name, IFNAMSIZ);
+    xioctl(sockfd, SIOGIFINDEX, ifre);
+    rt.rtmsg_ifindex = ifre->ifr_ifindex;
+  }          
+  if (action == 1) xioctl(sockfd, SIOCADDRT, &rt);
+  else xioctl(sockfd, SIOCDELRT, &rt);
+  xclose(sockfd);
+}
+
+/*
+ * format the dest and src address in ipv6 format.
+ * e.g. 2002:6b6d:26c8:d:ea03:9aff:fe65:9d62
+ */
+static void ipv6_addr_formating(char *ptr, char *addr)
+{
+  int i = 0;
+  while (i <= IPV6_ADDR_LEN) {
+    if (!*ptr) {
+      if (i == IPV6_ADDR_LEN) {
+        addr[IPV6_ADDR_LEN - 1] = 0; //NULL terminating the ':' seperated address.
+        break;
+      }
+      error_exit("IPv6 ip format error");
+    }
+    addr[i++] = *ptr++;
+    if (!((i+1) % 5)) addr[i++] = ':'; //put ':' after 4th bit
+  }
+}
+
+static void display_routes6(void)
+{
+  char iface[16] = {0,}, ipv6_dest_addr[41]; 
+  char ipv6_src_addr[41], flag_val[10], buf2[INET6_ADDRSTRLEN];
+  int prefixlen, metric, use, refcount, flag, items = 0;
+  unsigned char buf[sizeof(struct in6_addr)];
+
+  FILE *fp = xfopen("/proc/net/ipv6_route", "r");
+
+  xprintf("Kernel IPv6 routing table\n"
+      "%-43s%-40s Flags Metric Ref    Use Iface\n", "Destination", "Next Hop");
+
+  while ((items = fscanf(fp, "%32s%x%*s%*x%32s%x%x%x%x%10s\n", ipv6_dest_addr+8,
+          &prefixlen, ipv6_src_addr+8, &metric, &use, &refcount, &flag, 
+          iface)) == 8)
+  {
+    if (!(flag & RTF_UP)) continue; //skip down interfaces.
+
+    //ipv6_dest_addr+8: as the values are filled from the 8th location of the array.
+    ipv6_addr_formating(ipv6_dest_addr+8, ipv6_dest_addr);
+    ipv6_addr_formating(ipv6_src_addr+8, ipv6_src_addr);
+
+    get_flag_value(flag_val, flag);
+    if (inet_pton(AF_INET6, ipv6_dest_addr, buf) <= 0) perror_exit("inet");
+    if (inet_ntop(AF_INET6, buf, buf2, INET6_ADDRSTRLEN))
+      sprintf(toybuf, "%s/%d", buf2, prefixlen);
+
+    if (inet_pton(AF_INET6, ipv6_src_addr, buf) <= 0) perror_exit("inet");
+    if (inet_ntop(AF_INET6, buf, buf2, INET6_ADDRSTRLEN))
+      xprintf("%-43s %-39s %-5s %-6d %-4d %5d %-8s\n",
+          toybuf, buf2, flag_val, metric, refcount, use, iface);
+  }
+  if ((items > 0) && feof(fp)) perror_exit("fscanf");
+
+  fclose(fp);
+}
+
+void route_main(void)
+{
+  if (!TT.family) TT.family = "inet";
+  if (!*toys.optargs) {
+    if (!strcmp(TT.family, "inet")) display_routes();
+    else if (!strcmp(TT.family, "inet6")) display_routes6();
+    else help_exit(0);
+  } else {
+    if (!strcmp(TT.family, "inet6")) setroute_inet6(toys.optargs);
+    else setroute(toys.optargs);
+  }
+}
diff --git a/toybox/toys/pending/sh.c b/toybox/toys/pending/sh.c
new file mode 100644
index 0000000..76b4e13
--- /dev/null
+++ b/toybox/toys/pending/sh.c
@@ -0,0 +1,335 @@
+/* sh.c - toybox shell
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * The POSIX-2008/SUSv4 spec for this is at:
+ * http://opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
+ * and http://opengroup.org/onlinepubs/9699919799/utilities/sh.html
+ *
+ * The first link describes the following shell builtins:
+ *
+ *   break colon continue dot eval exec exit export readonly return set shift
+ *   times trap unset
+ *
+ * The second link (the utilities directory) also contains specs for the
+ * following shell builtins:
+ *
+ *   alias bg cd command fc fg getopts hash jobs kill read type ulimit
+ *   umask unalias wait
+ *
+ * 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))
+
+USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN))
+USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN))
+// Login lies in argv[0], so add some aliases to catch that
+USE_SH(OLDTOY(-sh, sh, 0))
+USE_SH(OLDTOY(-toysh, sh, 0))
+
+config SH
+  bool "sh (toysh)"
+  default n
+  help
+    usage: sh [-c command] [script]
+
+    Command shell.  Runs a shell script, or reads input interactively
+    and responds to it.
+
+    -c	command line to execute
+    -i	interactive mode (default when STDIN is a tty)
+
+config CD
+  bool
+  default n
+  depends on SH
+  help
+    usage: cd [-PL] [path]
+
+    Change current directory.  With no arguments, go $HOME.
+
+    -P	Physical path: resolve symlinks in path.
+    -L	Local path: .. trims directories off $PWD (default).
+
+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.
+*/
+
+#define FOR_sh
+#include "toys.h"
+
+GLOBALS(
+  char *command;
+
+  long lineno;
+)
+
+// What we know about a single process.
+struct command {
+  struct command *next;
+  int flags;              // exit, suspend, && ||
+  int pid;                // pid (or exit code)
+  int argc;
+  char *argv[0];
+};
+
+// A collection of processes piped into/waiting on each other.
+struct pipeline {
+  struct pipeline *next;
+  int job_id;
+  struct command *cmd;
+  char *cmdline;         // Unparsed line for display purposes
+  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
+// hit an ending token.
+static char *parse_word(char *start, struct command **cmd)
+{
+  char *end;
+
+  // Detect end of line (and truncate line at comment)
+  if (strchr("><&|(;", *start)) return 0;
+
+  // Grab next word.  (Add dequote and envvar logic here)
+  end = start;
+  while (*end && !isspace(*end)) end++;
+  (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start);
+
+  // Allocate more space if there's no room for NULL terminator.
+
+  if (!((*cmd)->argc & 7))
+    *cmd=xrealloc(*cmd,
+        sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *));
+  (*cmd)->argv[(*cmd)->argc] = 0;
+  return end;
+}
+
+// Parse a line of text into a pipeline.
+// Returns a pointer to the next line.
+
+static char *parse_pipeline(char *cmdline, struct pipeline *line)
+{
+  struct command **cmd = &(line->cmd);
+  char *start = line->cmdline = cmdline;
+
+  if (!cmdline) return 0;
+
+  line->cmdline = cmdline;
+
+  // Parse command into argv[]
+  for (;;) {
+    char *end;
+
+    // Skip leading whitespace and detect end of line.
+    while (isspace(*start)) start++;
+    if (!*start || *start=='#') {
+      line->cmdlinelen = start-cmdline;
+      return 0;
+    }
+
+    // Allocate next command structure if necessary
+    if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *));
+
+    // Parse next argument and add the results to argv[]
+    end = parse_word(start, cmd);
+
+    // If we hit the end of this command, how did it end?
+    if (!end) {
+      if (*start) {
+        if (*start==';') {
+          start++;
+          break;
+        }
+        // handle | & < > >> << || &&
+      }
+      break;
+    }
+    start = end;
+  }
+
+  line->cmdlinelen = start-cmdline;
+
+  return start;
+}
+
+// Execute the commands in a pipeline
+static void run_pipeline(struct pipeline *line)
+{
+  struct toy_list *tl;
+  struct command *cmd = line->cmd;
+  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;
+    jmp_buf rebound;
+
+    // This fakes lots of what toybox_main() does.
+    memcpy(&temp, &toys, sizeof(struct toy_context));
+    memset(&toys, 0, sizeof(struct toy_context));
+
+    if (!setjmp(rebound)) {
+      toys.rebound = &rebound;
+      toy_init(tl, cmd->argv);
+      tl->toy_main();
+    }
+    cmd->pid = toys.exitval;
+    if (toys.optargs != toys.argv+1) free(toys.optargs);
+    if (toys.old_umask) umask(toys.old_umask);
+    memcpy(&toys, &temp, sizeof(struct toy_context));
+  } else {
+    int status;
+
+    cmd->pid = vfork();
+    if (!cmd->pid) xexec(cmd->argv);
+    else waitpid(cmd->pid, &status, 0);
+
+    if (WIFEXITED(status)) cmd->pid = WEXITSTATUS(status);
+    if (WIFSIGNALED(status)) cmd->pid = WTERMSIG(status);
+  }
+
+  return;
+}
+
+// Free the contents of a command structure
+static void free_cmd(void *data)
+{
+  struct command *cmd=(struct command *)data;
+
+  while(cmd->argc) free(cmd->argv[--cmd->argc]);
+}
+
+
+// Parse a command line and do what it says to do.
+static void handle(char *command)
+{
+  struct pipeline line;
+  char *start = command;
+
+  // Loop through commands in this line
+
+  for (;;) {
+
+    // Parse a group of connected commands
+
+    memset(&line,0,sizeof(struct pipeline));
+    start = parse_pipeline(start, &line);
+    if (!line.cmd) break;
+
+    // Run those commands
+
+    run_pipeline(&line);
+    llist_traverse(line.cmd, free_cmd);
+  }
+}
+
+static void do_prompt(void)
+{
+  char *prompt = getenv("PS1"), *s, c, cc;
+
+  if (!prompt) prompt = "\\$ ";
+  while (*prompt) {
+    c = *(prompt++);
+
+    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 = 0;
+
+  // Set up signal handlers and grab control of this tty.
+  if (isatty(0)) toys.optflags |= FLAG_i;
+
+  if (*toys.optargs) f = xfopen(*toys.optargs, "r");
+  if (TT.command) handle(xstrdup(TT.command));
+  else {
+    size_t cmdlen = 0;
+    for (;;) {
+      char *command = 0;
+
+      // TODO: parse escapes in prompt
+      if (!f) do_prompt();
+      if (1 > getline(&command, &cmdlen, f ? f : stdin)) break;
+      handle(command);
+      free(command);
+    }
+  }
+
+  toys.exitval = 1;
+}
diff --git a/toybox/toys/pending/sulogin.c b/toybox/toys/pending/sulogin.c
new file mode 100644
index 0000000..bc3638e
--- /dev/null
+++ b/toybox/toys/pending/sulogin.c
@@ -0,0 +1,118 @@
+/* sulogin.c - Single User Login.
+ *
+ * Copyright 2014 Ashish Kumar Gupta <ashishkguptaiit.cse@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gmail.com>
+ *
+ * 
+ * Relies on libcrypt for hash calculation. 
+ * No support for PAM/securetty/selinux/login script/issue/utmp
+
+
+USE_SULOGIN(NEWTOY(sulogin, "t#<0=0", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
+
+config SULOGIN
+  bool "sulogin"
+  default n
+  depends on TOYBOX_SHADOW
+  help
+    usage: sulogin [-t time] [tty]
+
+    Single User Login.
+    -t	Default Time for Single User Login
+*/
+#define FOR_sulogin
+#include "toys.h"
+
+GLOBALS(
+  long timeout;
+  struct termios crntio;
+)
+
+static void timeout_handle(int signo) 
+{
+  tcsetattr(0, TCSANOW, &(TT.crntio));
+  fflush(stdout);
+  xprintf("\n Timed out - Normal startup\n");
+  exit(0);
+}
+
+static int validate_password(char *pwd)
+{
+  struct sigaction sa;
+  int ret;
+  char *s = "Give root password for system maintenance\n"
+    "(or type Control-D for normal startup):",
+    *pass;
+
+  tcgetattr(0, &(TT.crntio));
+  sa.sa_handler = timeout_handle;
+
+  if(TT.timeout) {
+    sigaction(SIGALRM, &sa, NULL);
+    alarm(TT.timeout);
+  }
+
+  ret = read_password(toybuf, sizeof(toybuf), s);
+  if(TT.timeout) alarm(0);
+
+  if ( ret && !toybuf[0]) {   
+    xprintf("Normal startup.\n");
+    return -1;
+  }
+
+  pass = crypt(toybuf, pwd);
+  ret = 1;
+  if( pass && !strcmp(pass, pwd)) ret = 0;
+
+  return ret;
+}
+
+static void run_shell(char *shell) 
+{
+  snprintf(toybuf,sizeof(toybuf), "-%s", shell);
+  execl(shell, toybuf, NULL);
+  error_exit("Failed to spawn shell");
+}
+
+void sulogin_main(void)
+{
+  struct passwd *pwd = NULL;
+  struct spwd * spwd = NULL;
+  char *forbid[] = {
+    "BASH_ENV", "ENV", "HOME", "IFS", "LD_LIBRARY_PATH", "LD_PRELOAD",
+    "LD_TRACE_LOADED_OBJECTS", "LD_BIND_NOW", "LD_AOUT_LIBRARY_PATH",
+    "LD_AOUT_PRELOAD", "LD_NOWARN", "LD_KEEPDIR", "SHELL", NULL
+  };
+  char *shell = NULL, *pass = NULL, **temp = forbid;
+
+  if (toys.optargs[0]) {
+    int fd;
+
+    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);
+    if (fd > 2) close(fd);
+  }  
+
+  for (temp = forbid; *temp; temp++) unsetenv(*temp);
+
+  if (!(pwd = getpwuid(0))) error_exit("invalid user");
+  pass = pwd->pw_passwd;
+
+  if ((pass[0] == 'x' || pass[0] == '*') && !pass[1]) {
+    if ((spwd = getspnam (pwd->pw_name))) pass = spwd->sp_pwdp;
+  }
+
+  while (1) {
+    int r = validate_password(pass);
+
+    if (r == 1) xprintf("Incorrect Login.\n");
+    else if (r == 0) break;
+    else if (r == -1) return;
+  }
+
+  if ((shell = getenv("SUSHELL")) || (shell = getenv("sushell"))
+      || (shell = pwd->pw_shell))
+    run_shell((shell && *shell)? shell: "/bin/sh");
+}
diff --git a/toybox/toys/pending/syslogd.c b/toybox/toys/pending/syslogd.c
new file mode 100644
index 0000000..73542ca
--- /dev/null
+++ b/toybox/toys/pending/syslogd.c
@@ -0,0 +1,546 @@
+/* syslogd.c - a system logging utility.
+ *
+ * Copyright 2013 Madhur Verma <mad.flexi@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+
+USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT))
+
+config SYSLOGD
+  bool "syslogd"
+  default n
+  help
+  usage: syslogd  [-a socket] [-O logfile] [-f config file] [-m interval]
+                  [-p socket] [-s SIZE] [-b N] [-R HOST] [-l N] [-nSLKD]
+
+  System logging utility
+
+  -a      Extra unix socket for listen
+  -O FILE Default log file <DEFAULT: /var/log/messages>
+  -f FILE Config file <DEFAULT: /etc/syslog.conf>
+  -p      Alternative unix domain socket <DEFAULT : /dev/log>
+  -n      Avoid auto-backgrounding.
+  -S      Smaller output
+  -m MARK interval <DEFAULT: 20 minutes> (RANGE: 0 to 71582787)
+  -R HOST Log to IP or hostname on PORT (default PORT=514/UDP)"
+  -L      Log locally and via network (default is network only if -R)"
+  -s SIZE Max size (KB) before rotation (default:200KB, 0=off)
+  -b N    rotated logs to keep (default:1, max=99, 0=purge)
+  -K      Log to kernel printk buffer (use dmesg to read it)
+  -l N    Log only messages more urgent than prio(default:8 max:8 min:1)
+  -D      Drop duplicates
+*/
+
+#define FOR_syslogd
+#define SYSLOG_NAMES
+#include "toys.h"
+
+// UNIX Sockets for listening
+struct unsocks {
+  struct unsocks *next;
+  char *path;
+  struct sockaddr_un sdu;
+  int sd;
+};
+
+// Log file entry to log into.
+struct logfile {
+  struct logfile *next;
+  char *filename;
+  uint32_t facility[8];
+  uint8_t level[LOG_NFACILITIES];
+  int logfd;
+  struct sockaddr_in saddr;
+};
+
+GLOBALS(
+  char *socket;
+  char *config_file;
+  char *unix_socket;
+  char *logfile;
+  long interval;
+  long rot_size;
+  long rot_count;
+  char *remote_log;
+  long log_prio;
+
+  struct unsocks *lsocks;  // list of listen sockets
+  struct logfile *lfiles;  // list of write logfiles
+  int sigfd[2];
+)
+
+// Lookup numerical code from name
+// Also used in logger
+int logger_lookup(int where, char *key)
+{
+  CODE *w = ((CODE *[]){facilitynames, prioritynames})[where];
+
+  for (; w->c_name; w++)
+    if (!strcasecmp(key, w->c_name)) return w->c_val;
+
+  return -1;
+}
+
+//search the given name and return its value
+static char *dec(int val, CODE *clist, char *buf)
+{
+  for (; clist->c_name; clist++) 
+    if (val == clist->c_val) return clist->c_name;
+  sprintf(buf, "%u", val);
+
+  return buf;
+}
+
+/*
+ * recurses the logfile list and resolves config
+ * for evry file and updates facilty and log level bits.
+ */
+static int resolve_config(struct logfile *file, char *config)
+{
+  char *tk;
+
+  for (tk = strtok(config, "; \0"); tk; tk = strtok(NULL, "; \0")) {
+    char *fac = tk, *lvl;
+    int i = 0;
+    unsigned facval = 0;
+    uint8_t set, levval, bits = 0;
+
+    tk = strchr(fac, '.');
+    if (!tk) return -1;
+    *tk = '\0';
+    lvl = tk + 1;
+
+    for (;;) {
+      char *nfac = strchr(fac, ',');
+
+      if (nfac) *nfac = '\0';
+      if (*fac == '*') {
+        facval = 0xFFFFFFFF;
+        if (fac[1]) return -1;
+      } else {
+        if ((i = logger_lookup(0, fac)) == -1) return -1;
+        facval |= (1 << LOG_FAC(i));
+      }
+      if (nfac) fac = nfac + 1;
+      else break;
+    }
+
+    levval = 0;
+    for (tk = "!=*"; *tk; tk++, bits <<= 1) {
+      if (*lvl == *tk) {
+        bits++;
+        lvl++;
+      }
+    }
+    if (bits & 2) levval = 0xff;
+    if (*lvl) {
+      if ((i = logger_lookup(1, lvl)) == -1) return -1;
+      levval |= (bits & 4) ? LOG_MASK(i) : LOG_UPTO(i);
+      if (bits & 8) levval = ~levval;
+    }
+
+    for (i = 0, set = levval; set; set >>= 1, i++)
+      if (set & 0x1) file->facility[i] |= ~facval;
+    for (i = 0; i < LOG_NFACILITIES; facval >>= 1, i++)
+      if (facval & 0x1) file->level[i] |= ~levval;
+  }
+
+  return 0;
+}
+
+// Parse config file and update the log file list.
+static int parse_config_file(void)
+{
+  struct logfile *file;
+  FILE *fp;
+  char *confline, *tk[2];
+  int len, lineno = 0;
+  size_t linelen;
+  /*
+   * if -K then open only /dev/kmsg
+   * all other log files are neglected
+   * thus no need to open config either.
+   */
+  if (toys.optflags & FLAG_K) {
+    file = xzalloc(sizeof(struct logfile));
+    file->filename = xstrdup("/dev/kmsg");
+    TT.lfiles = file;
+    return 0;
+  }
+  /*
+   * if -R then add remote host to log list
+   * if -L is not provided all other log
+   * files are neglected thus no need to
+   * open config either so just return.
+   */
+  if (toys.optflags & FLAG_R) {
+    file = xzalloc(sizeof(struct logfile));
+    file->filename = xmprintf("@%s",TT.remote_log);
+    TT.lfiles = file;
+    if (!(toys.optflags & FLAG_L)) return 0;
+  }
+  /*
+   * Read config file and add logfiles to the list
+   * with their configuration.
+   */
+  if (!(fp = fopen(TT.config_file, "r")) && (toys.optflags & FLAG_f))
+    perror_exit("can't open '%s'", TT.config_file);
+
+  for (linelen = 0; fp;) {
+    confline = NULL;
+    len = getline(&confline, &linelen, fp);
+    if (len <= 0) break;
+    lineno++;
+    for (; *confline == ' '; confline++, len--) ;
+    if ((confline[0] == '#') || (confline[0] == '\n')) continue;
+    tk[0] = confline;
+    for (; len && !(*tk[0]==' ' || *tk[0]=='\t'); tk[0]++, len--);
+    for (tk[1] = tk[0]; len && (*tk[1]==' ' || *tk[1]=='\t'); tk[1]++, len--);
+    if (!len || (len == 1 && *tk[1] == '\n')) {
+      error_msg("error in '%s' at line %d", TT.config_file, lineno);
+      return -1;
+    }
+    else if (*(tk[1] + len - 1) == '\n') *(tk[1] + len - 1) = '\0';
+    *tk[0] = '\0';
+    if (*tk[1] != '*') {
+      file = TT.lfiles;
+      while (file && strcmp(file->filename, tk[1])) file = file->next;
+      if (!file) {
+        file = xzalloc(sizeof(struct logfile));
+        file->filename = xstrdup(tk[1]);
+        file->next = TT.lfiles;
+        TT.lfiles = file;
+      }
+      if (resolve_config(file, confline) == -1) {
+        error_msg("error in '%s' at line %d", TT.config_file, lineno);
+        return -1;
+      }
+    }
+    free(confline);
+  }
+  /*
+   * Can't open config file or support is not enabled
+   * adding default logfile to the head of list.
+   */
+  if (!fp){
+    file = xzalloc(sizeof(struct logfile));
+    file->filename = xstrdup((toys.optflags & FLAG_O) ?
+                     TT.logfile : "/var/log/messages"); //DEFLOGFILE
+    file->next = TT.lfiles;
+    TT.lfiles = file;
+  } else fclose(fp);
+  return 0;
+}
+
+// open every log file in list.
+static void open_logfiles(void)
+{
+  struct logfile *tfd;
+
+  for (tfd = TT.lfiles; tfd; tfd = tfd->next) {
+    char *p, *tmpfile;
+    long port = 514;
+
+    if (*tfd->filename == '@') { // network
+      struct addrinfo *info, rp;
+
+      tmpfile = xstrdup(tfd->filename + 1);
+      if ((p = strchr(tmpfile, ':'))) {
+        char *endptr;
+
+        *p = '\0';
+        port = strtol(++p, &endptr, 10);
+        if (*endptr || endptr == p || port < 0 || port > 65535)
+          error_exit("bad port in %s", tfd->filename);
+      }
+      memset(&rp, 0, sizeof(rp));
+      rp.ai_family = AF_INET;
+      rp.ai_socktype = SOCK_DGRAM;
+      rp.ai_protocol = IPPROTO_UDP;
+
+      if (getaddrinfo(tmpfile, NULL, &rp, &info) || !info) 
+        perror_exit("BAD ADDRESS: can't find : %s ", tmpfile);
+      ((struct sockaddr_in*)info->ai_addr)->sin_port = htons(port);
+      memcpy(&tfd->saddr, info->ai_addr, info->ai_addrlen);
+      freeaddrinfo(info);
+
+      tfd->logfd = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+      free(tmpfile);
+    } else tfd->logfd = open(tfd->filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
+    if (tfd->logfd < 0) {
+      tfd->filename = "/dev/console";
+      tfd->logfd = open(tfd->filename, O_APPEND);
+    }
+  }
+}
+
+//write to file with rotation
+static int write_rotate(struct logfile *tf, int len)
+{
+  int size, isreg;
+  struct stat statf;
+  isreg = (!fstat(tf->logfd, &statf) && S_ISREG(statf.st_mode));
+  size = statf.st_size;
+
+  if ((toys.optflags & FLAG_s) || (toys.optflags & FLAG_b)) {
+    if (TT.rot_size && isreg && (size + len) > (TT.rot_size*1024)) {
+      if (TT.rot_count) { /* always 0..99 */
+        int i = strlen(tf->filename) + 3 + 1;
+        char old_file[i];
+        char new_file[i];
+        i = TT.rot_count - 1;
+        while (1) {
+          sprintf(new_file, "%s.%d", tf->filename, i);
+          if (!i) break;
+          sprintf(old_file, "%s.%d", tf->filename, --i);
+          rename(old_file, new_file);
+        }
+        rename(tf->filename, new_file);
+        unlink(tf->filename);
+        close(tf->logfd);
+        tf->logfd = open(tf->filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
+        if (tf->logfd < 0) {
+          perror_msg("can't open %s", tf->filename);
+          return -1;
+        }
+      }
+      ftruncate(tf->logfd, 0);
+    }
+  }
+  return write(tf->logfd, toybuf, len);
+}
+
+//Parse messege and write to file.
+static void logmsg(char *msg, int len)
+{
+  time_t now;
+  char *p, *ts, *lvlstr, *facstr;
+  struct utsname uts;
+  int pri = 0;
+  struct logfile *tf = TT.lfiles;
+
+  char *omsg = msg;
+  int olen = len, fac, lvl;
+  
+  if (*msg == '<') { // Extract the priority no.
+    pri = (int) strtoul(msg + 1, &p, 10);
+    if (*p == '>') msg = p + 1;
+  }
+  /* Jan 18 00:11:22 msg...
+   * 01234567890123456
+   */
+  if (len < 16 || msg[3] != ' ' || msg[6] != ' ' || msg[9] != ':'
+      || msg[12] != ':' || msg[15] != ' ') {
+    time(&now);
+    ts = ctime(&now) + 4; /* skip day of week */
+  } else {
+    now = 0;
+    ts = msg;
+    msg += 16;
+  }
+  ts[15] = '\0';
+  fac = LOG_FAC(pri);
+  lvl = LOG_PRI(pri);
+
+  if (toys.optflags & FLAG_K) len = sprintf(toybuf, "<%d> %s\n", pri, msg);
+  else {
+    char facbuf[12], pribuf[12];
+
+    facstr = dec(pri & LOG_FACMASK, facilitynames, facbuf);
+    lvlstr = dec(LOG_PRI(pri), prioritynames, pribuf);
+
+    p = "local";
+    if (!uname(&uts)) p = uts.nodename;
+    if (toys.optflags & FLAG_S) len = sprintf(toybuf, "%s %s\n", ts, msg);
+    else len = sprintf(toybuf, "%s %s %s.%s %s\n", ts, p, facstr, lvlstr, msg);
+  }
+  if (lvl >= TT.log_prio) return;
+
+  for (; tf; tf = tf->next) {
+    if (tf->logfd > 0) {
+      if (!((tf->facility[lvl] & (1 << fac)) || (tf->level[fac] & (1<<lvl)))) {
+        int wlen, isNetwork = *tf->filename == '@';
+        if (isNetwork)
+          wlen = sendto(tf->logfd, omsg, olen, 0, (struct sockaddr*)&tf->saddr, sizeof(tf->saddr));
+        else wlen = write_rotate(tf, len);
+        if (wlen < 0) perror_msg("write failed file : %s ", tf->filename + isNetwork);
+      }
+    }
+  }
+}
+
+/*
+ * closes all read and write fds
+ * and frees all nodes and lists
+ */
+static void cleanup(void)
+{
+  while (TT.lsocks) {
+    struct unsocks *fnode = TT.lsocks;
+
+    if (fnode->sd >= 0) {
+      close(fnode->sd);
+      unlink(fnode->path);
+    }
+    TT.lsocks = fnode->next;
+    free(fnode);
+  }
+
+  while (TT.lfiles) {
+    struct logfile *fnode = TT.lfiles;
+
+    free(fnode->filename);
+    if (fnode->logfd >= 0) close(fnode->logfd);
+    TT.lfiles = fnode->next;
+    free(fnode);
+  }
+}
+
+static void signal_handler(int sig)
+{
+  unsigned char ch = sig;
+  if (write(TT.sigfd[1], &ch, 1) != 1) error_msg("can't send signal");
+}
+
+void syslogd_main(void)
+{
+  struct unsocks *tsd;
+  int nfds, retval, last_len=0;
+  struct timeval tv;
+  fd_set rfds;        // fds for reading
+  char *temp, *buffer = (toybuf +2048), *last_buf = (toybuf + 3072); //these two buffs are of 1K each
+
+  if ((toys.optflags & FLAG_p) && (strlen(TT.unix_socket) > 108))
+    error_exit("Socket path should not be more than 108");
+
+  TT.config_file = (toys.optflags & FLAG_f) ?
+                   TT.config_file : "/etc/syslog.conf"; //DEFCONFFILE
+init_jumpin:
+  tsd = xzalloc(sizeof(struct unsocks));
+
+  tsd->path = (toys.optflags & FLAG_p) ? TT.unix_socket : "/dev/log"; // DEFLOGSOCK
+  TT.lsocks = tsd;
+
+  if (toys.optflags & FLAG_a) {
+    for (temp = strtok(TT.socket, ":"); temp; temp = strtok(NULL, ":")) {
+      if (strlen(temp) > 107) temp[108] = '\0';
+      tsd = xzalloc(sizeof(struct unsocks));
+      tsd->path = temp;
+      tsd->next = TT.lsocks;
+      TT.lsocks = tsd;
+    }
+  }
+  /*
+   * initializes unsock_t structure
+   * and opens socket for reading
+   * and adds to global lsock list.
+  */
+  nfds = 0;
+  for (tsd = TT.lsocks; tsd; tsd = tsd->next) {
+    tsd->sdu.sun_family = AF_UNIX;
+    strcpy(tsd->sdu.sun_path, tsd->path);
+    tsd->sd = socket(AF_UNIX, SOCK_DGRAM, 0);
+    if (tsd->sd < 0) {
+      perror_msg("OPEN SOCKS : failed");
+      continue;
+    }
+    unlink(tsd->sdu.sun_path);
+    if (bind(tsd->sd, (struct sockaddr *) &tsd->sdu, sizeof(tsd->sdu))) {
+      perror_msg("BIND SOCKS : failed sock : %s", tsd->sdu.sun_path);
+      close(tsd->sd);
+      continue;
+    }
+    chmod(tsd->path, 0777);
+    nfds++;
+  }
+  if (!nfds) {
+    error_msg("Can't open single socket for listenning.");
+    goto clean_and_exit;
+  }
+
+  // Setup signals
+  xpipe(TT.sigfd);
+
+  fcntl(TT.sigfd[1] , F_SETFD, FD_CLOEXEC);
+  fcntl(TT.sigfd[0] , F_SETFD, FD_CLOEXEC);
+  int flags = fcntl(TT.sigfd[1], F_GETFL);
+  fcntl(TT.sigfd[1], F_SETFL, flags | O_NONBLOCK);
+  signal(SIGHUP, signal_handler);
+  signal(SIGTERM, signal_handler);
+  signal(SIGINT, signal_handler);
+  signal(SIGQUIT, signal_handler);
+
+  if (parse_config_file() == -1) goto clean_and_exit;
+  open_logfiles();
+  if (!(toys.optflags & FLAG_n)) {
+    daemon(0, 0);
+    //don't daemonize again if SIGHUP received.
+    toys.optflags |= FLAG_n;
+  }
+  xpidfile("syslogd");
+
+  logmsg("<46>Toybox: syslogd started", 27); //27 : the length of message
+  for (;;) {
+    // Add opened socks to rfds for select()
+    FD_ZERO(&rfds);
+    for (tsd = TT.lsocks; tsd; tsd = tsd->next) FD_SET(tsd->sd, &rfds);
+    FD_SET(TT.sigfd[0], &rfds);
+    tv.tv_usec = 0;
+    tv.tv_sec = TT.interval*60;
+
+    retval = select(TT.sigfd[0] + 1, &rfds, NULL, NULL, (TT.interval)?&tv:NULL);
+    if (retval < 0) {
+      if (errno != EINTR) perror_msg("Error in select ");
+    }
+    else if (!retval) logmsg("<46>-- MARK --", 14);
+    else if (FD_ISSET(TT.sigfd[0], &rfds)) { /* May be a signal */
+      unsigned char sig;
+
+      if (read(TT.sigfd[0], &sig, 1) != 1) {
+        error_msg("signal read failed.\n");
+        continue;
+      }
+      switch(sig) {
+        case SIGTERM:    /* FALLTHROUGH */
+        case SIGINT:     /* FALLTHROUGH */
+        case SIGQUIT:
+          logmsg("<46>syslogd exiting", 19);
+          if (CFG_TOYBOX_FREE ) cleanup();
+          signal(sig, SIG_DFL);
+          sigset_t ss;
+          sigemptyset(&ss);
+          sigaddset(&ss, sig);
+          sigprocmask(SIG_UNBLOCK, &ss, NULL);
+          raise(sig);
+          _exit(1);  /* Should not reach it */
+          break;
+        case SIGHUP:
+          logmsg("<46>syslogd exiting", 19);
+          cleanup(); //cleanup is done, as we restart syslog.
+          goto init_jumpin;
+        default: break;
+      }
+    } else { /* Some activity on listen sockets. */
+      for (tsd = TT.lsocks; tsd; tsd = tsd->next) {
+        int sd = tsd->sd;
+        if (FD_ISSET(sd, &rfds)) {
+          int len = read(sd, buffer, 1023); //buffer is of 1K, hence readingonly 1023 bytes, 1 for NUL
+          if (len > 0) {
+            buffer[len] = '\0';
+            if((toys.optflags & FLAG_D) && (len == last_len))
+              if (!memcmp(last_buf, buffer, len)) break;
+
+            memcpy(last_buf, buffer, len);
+            last_len = len;
+            logmsg(buffer, len);
+          }
+          break;
+        }
+      }
+    }
+  }
+clean_and_exit:
+  logmsg("<46>syslogd exiting", 19);
+  if (CFG_TOYBOX_FREE ) cleanup();
+}
diff --git a/toybox/toys/pending/tar.c b/toybox/toys/pending/tar.c
new file mode 100644
index 0000000..384199e
--- /dev/null
+++ b/toybox/toys/pending/tar.c
@@ -0,0 +1,806 @@
+/* tar.c - create/extract archives
+ *
+ * Copyright 2014 Ashwini Kumar <ak.ashwini81@gmail.com>
+ *
+ * USTAR interchange format is of interest in
+ * See http://http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
+ * For writing to external program
+ * http://www.gnu.org/software/tar/manual/html_node/Writing-to-an-External-Program.html
+
+USE_TAR(NEWTOY(tar, "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config TAR
+  bool "tar"
+  default n
+  help
+    usage: tar -[cxtzhmvO] [-X FILE] [-T FILE] [-f TARFILE] [-C DIR]
+
+    Create, extract, or list files from a tar file
+
+    Operation:
+    c Create
+    f Name of TARFILE ('-' for stdin/out)
+    h Follow symlinks
+    m Don't restore mtime
+    t List
+    v Verbose
+    x Extract
+    z (De)compress using gzip
+    C Change to DIR before operation
+    O Extract to stdout
+    exclude=FILE File to exclude
+    X File with names to exclude
+    T File with names to include
+*/
+
+#define FOR_tar
+#include "toys.h"
+
+GLOBALS(
+  char *fname;
+  char *dir;
+  struct arg_list *inc_file;
+  struct arg_list *exc_file;
+  char *tocmd;
+  struct arg_list *exc;
+
+  struct arg_list *inc, *pass;
+  void *inodes, *handle;
+)
+
+struct tar_hdr {
+  char name[100], mode[8], uid[8], gid[8],size[12], mtime[12], chksum[8],
+       type, link[100], magic[8], uname[32], gname[32], major[8], minor[8],
+       prefix[155], padd[12];
+};
+
+struct file_header {
+  char *name, *link_target, *uname, *gname;
+  off_t size;
+  uid_t uid;
+  gid_t gid;
+  mode_t mode;
+  time_t mtime;
+  dev_t device;
+};
+
+struct archive_handler {
+  int src_fd;
+  struct file_header file_hdr;
+  off_t offset;
+  void (*extract_handler)(struct archive_handler*);
+};
+
+struct inode_list {
+  struct inode_list *next;
+  char *arg;
+  ino_t ino;
+  dev_t dev;
+};
+
+static void copy_in_out(int src, int dst, off_t size)
+{
+  int i, rd, rem = size%512, cnt;
+  
+  cnt = size/512 + (rem?1:0);
+
+  for (i = 0; i < cnt; i++) {
+    rd = (i == cnt-1 && rem) ? rem : 512;
+    xreadall(src, toybuf, rd);
+    writeall(dst, toybuf, rd);
+  }
+}
+
+//convert to octal
+static void itoo(char *str, int len, off_t val)
+{
+  char *t, tmp[sizeof(off_t)*3+1];
+  int cnt  = sprintf(tmp, "%0*llo", len, (unsigned long long)val);
+
+  t = tmp + cnt - len;
+  if (*t == '0') t++;
+  memcpy(str, t, len);
+}
+
+static struct inode_list *seen_inode(void **list, struct stat *st, char *name)
+{
+  if (!st) llist_traverse(*list, llist_free_arg);
+  else if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
+    struct inode_list *new;
+
+    for (new = *list; new; new = new->next)
+      if(new->ino == st->st_ino && new->dev == st->st_dev)
+        return new;
+
+    new = xzalloc(sizeof(*new));
+    new->ino = st->st_ino;
+    new->dev = st->st_dev;
+    new->arg = xstrdup(name);
+    new->next = *list;
+    *list = new;
+  }
+  return 0;
+}
+
+static void write_longname(struct archive_handler *tar, char *name, char type)
+{
+  struct tar_hdr tmp;
+  unsigned int sum = 0;
+  int i, sz = strlen(name) +1;
+  char buf[512] = {0,};
+
+  memset(&tmp, 0, sizeof(tmp));
+  strcpy(tmp.name, "././@LongLink");
+  sprintf(tmp.mode, "%0*d", (int)sizeof(tmp.mode)-1, 0);
+  sprintf(tmp.uid, "%0*d", (int)sizeof(tmp.uid)-1, 0);
+  sprintf(tmp.gid, "%0*d", (int)sizeof(tmp.gid)-1, 0);
+  sprintf(tmp.size, "%0*d", (int)sizeof(tmp.size)-1, 0);
+  sprintf(tmp.mtime, "%0*d", (int)sizeof(tmp.mtime)-1, 0);
+  itoo(tmp.size, sizeof(tmp.size), sz);
+  tmp.type = type;
+  memset(tmp.chksum, ' ', 8);
+  strcpy(tmp.magic, "ustar  ");
+  for (i= 0; i < 512; i++) sum += (unsigned int)((char*)&tmp)[i];
+  itoo(tmp.chksum, sizeof(tmp.chksum)-1, sum);
+
+  writeall(tar->src_fd, (void*) &tmp, sizeof(tmp));
+  //write name to archive
+  writeall(tar->src_fd, name, sz);
+  if (sz%512) writeall(tar->src_fd, buf, (512-(sz%512)));
+}
+
+static int filter(struct arg_list *lst, char *name)
+{
+  struct arg_list *cur;
+
+  for (cur = lst; cur; cur = cur->next)
+    if (!fnmatch(cur->arg, name, 1<<3)) return 1;
+  return 0;
+}
+
+static void add_file(struct archive_handler *tar, char **nam, struct stat *st)
+{
+  struct tar_hdr hdr;
+  struct passwd *pw;
+  struct group *gr;
+  struct inode_list *node;
+  int i, fd =-1;
+  char *c, *p, *name = *nam, *lnk, *hname, buf[512] = {0,};
+  unsigned int sum = 0;
+  static int warn = 1;
+
+  for (p = name; *p; p++)
+    if ((p == name || p[-1] == '/') && *p != '/'
+        && filter(TT.exc, p)) return;
+
+  if (S_ISDIR(st->st_mode) && name[strlen(name)-1] != '/') {
+    lnk = xmprintf("%s/",name);
+    free(name);
+    *nam = name = lnk;
+  }
+  hname = name;
+  //remove leading '/' or relative path '../' component
+  if (*hname == '/') hname++;
+  if (!*hname) return;
+  while ((c = strstr(hname, "../"))) hname = c + 3;
+  if (warn && hname != name) {
+    printf("removing leading '%.*s' "
+        "from member names\n", (int)(hname-name), name);
+    warn = 0;
+  }
+
+  memset(&hdr, 0, sizeof(hdr));
+  strncpy(hdr.name, hname, sizeof(hdr.name));
+  itoo(hdr.mode, sizeof(hdr.mode), st->st_mode &07777);
+  itoo(hdr.uid, sizeof(hdr.uid), st->st_uid);
+  itoo(hdr.gid, sizeof(hdr.gid), st->st_gid);
+  itoo(hdr.size, sizeof(hdr.size), 0); //set size later
+  itoo(hdr.mtime, sizeof(hdr.mtime), st->st_mtime);
+  for (i=0; i<sizeof(hdr.chksum); i++) hdr.chksum[i] = ' ';
+
+  if ((node = seen_inode(&TT.inodes, st, hname))) {
+    //this is a hard link
+    hdr.type = '1';
+    if (strlen(node->arg) > sizeof(hdr.link))
+      write_longname(tar, hname, 'K'); //write longname LINK
+    xstrncpy(hdr.link, node->arg, sizeof(hdr.link));
+  } else if (S_ISREG(st->st_mode)) {
+    hdr.type = '0';
+    if (st->st_size <= (off_t)0777777777777LL)
+      itoo(hdr.size, sizeof(hdr.size), st->st_size);
+    else {
+      error_msg("can't store file '%s' of size '%lld'\n",
+                hname, (unsigned long long)st->st_size);
+      return;
+    }
+  } else if (S_ISLNK(st->st_mode)) {
+    hdr.type = '2'; //'K' long link
+    if (!(lnk = xreadlink(name))) {
+      perror_msg("readlink");
+      return;
+    }
+    if (strlen(lnk) > sizeof(hdr.link))
+      write_longname(tar, hname, 'K'); //write longname LINK
+    xstrncpy(hdr.link, lnk, sizeof(hdr.link));
+    free(lnk);
+  }
+  else if (S_ISDIR(st->st_mode)) hdr.type = '5';
+  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), 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;
+  }
+  if (strlen(hname) > sizeof(hdr.name))
+          write_longname(tar, hname, 'L'); //write longname NAME
+  strcpy(hdr.magic, "ustar  ");
+  if ((pw = getpwuid(st->st_uid)))
+    snprintf(hdr.uname, sizeof(hdr.uname), "%s", pw->pw_name);
+  else snprintf(hdr.uname, sizeof(hdr.uname), "%d", st->st_uid);
+
+  if ((gr = getgrgid(st->st_gid)))
+    snprintf(hdr.gname, sizeof(hdr.gname), "%s", gr->gr_name);
+  else snprintf(hdr.gname, sizeof(hdr.gname), "%d", st->st_gid);
+
+  //calculate chksum.
+  for (i= 0; i < 512; i++) sum += (unsigned int)((char*)&hdr)[i];
+  itoo(hdr.chksum, sizeof(hdr.chksum)-1, sum);
+  if (toys.optflags & FLAG_v) printf("%s\n",hname);
+  writeall(tar->src_fd, (void*)&hdr, 512);
+
+  //write actual data to archive
+  if (hdr.type != '0') return; //nothing to write
+  if ((fd = open(name, O_RDONLY)) < 0) {
+    perror_msg("can't open '%s'", name);
+    return;
+  }
+  copy_in_out(fd, tar->src_fd, st->st_size);
+  if (st->st_size%512) writeall(tar->src_fd, buf, (512-(st->st_size%512)));
+  close(fd);
+}
+
+static int add_to_tar(struct dirtree *node)
+{
+  struct stat st;
+  char *path;
+  struct archive_handler *hdl = (struct archive_handler*)TT.handle;
+
+  if (!fstat(hdl->src_fd, &st) && st.st_dev == node->st.st_dev
+      && st.st_ino == node->st.st_ino) {
+    error_msg("'%s' file is the archive; not dumped", TT.fname);
+    return ((DIRTREE_RECURSE | ((toys.optflags & FLAG_h)?DIRTREE_SYMFOLLOW:0)));
+  }
+
+  if (node->parent && !dirtree_notdotdot(node)) return 0;
+  path = dirtree_path(node, 0);
+  add_file(hdl, &path, &(node->st)); //path may be modified
+  free(path);
+  if (toys.optflags & FLAG_no_recursion) return 0;
+  return ((DIRTREE_RECURSE | ((toys.optflags & FLAG_h)?DIRTREE_SYMFOLLOW:0)));
+}
+
+static void compress_stream(struct archive_handler *tar_hdl)
+{
+  int pipefd[2];
+  pid_t cpid;
+
+  xpipe(pipefd);
+
+  signal(SIGPIPE, SIG_IGN);
+  cpid = fork();
+  if (cpid == -1) perror_exit("fork");
+
+  if (!cpid) {    /* Child reads from pipe */
+    char *argv[] = {"gzip", "-f", NULL};
+    xclose(pipefd[1]); /* Close unused write*/
+    dup2(pipefd[0], 0);
+    dup2(tar_hdl->src_fd, 1); //write to tar fd
+    xexec(argv);
+  } else {
+    xclose(pipefd[0]);          /* Close unused read end */
+    dup2(pipefd[1], tar_hdl->src_fd); //write to pipe
+  }
+}
+
+static void extract_to_stdout(struct archive_handler *tar)
+{
+  struct file_header *file_hdr = &tar->file_hdr;
+
+  copy_in_out(tar->src_fd, 0, file_hdr->size);
+  tar->offset += file_hdr->size;
+}
+
+static void extract_to_command(struct archive_handler *tar)
+{
+  int pipefd[2], status = 0;
+  pid_t cpid;
+  struct file_header *file_hdr = &tar->file_hdr;
+
+  if (pipe(pipefd) == -1) error_exit("pipe");
+  if (!S_ISREG(file_hdr->mode)) return; //only regular files are supported.
+
+  cpid = fork();
+  if (cpid == -1) perror_exit("fork");
+
+  if (!cpid) {    // Child reads from pipe
+    char buf[64], *argv[4] = {"sh", "-c", TT.tocmd, NULL};
+
+    setenv("TAR_FILETYPE", "f", 1);
+    sprintf(buf, "%0o", file_hdr->mode);
+    setenv("TAR_MODE", buf, 1);
+    sprintf(buf, "%ld", (long)file_hdr->size);
+    setenv("TAR_SIZE", buf, 1);
+    setenv("TAR_FILENAME", file_hdr->name, 1);
+    setenv("TAR_UNAME", file_hdr->uname, 1);
+    setenv("TAR_GNAME", file_hdr->gname, 1);
+    sprintf(buf, "%0o", (int)file_hdr->mtime);
+    setenv("TAR_MTIME", buf, 1);
+    sprintf(buf, "%0o", file_hdr->uid);
+    setenv("TAR_UID", buf, 1);
+    sprintf(buf, "%0o", file_hdr->gid);
+    setenv("TAR_GID", buf, 1);
+
+    xclose(pipefd[1]); // Close unused write
+    dup2(pipefd[0], 0);
+    signal(SIGPIPE, SIG_DFL);
+    xexec(argv);
+  } else {
+    xclose(pipefd[0]);  // Close unused read end
+    copy_in_out(tar->src_fd, pipefd[1], file_hdr->size);
+    tar->offset += file_hdr->size;
+    xclose(pipefd[1]);
+    waitpid(cpid, &status, 0);
+    if (WIFSIGNALED(status))
+      xprintf("tar : %d: child returned %d\n", cpid, WTERMSIG(status));
+  }
+}
+
+static void extract_to_disk(struct archive_handler *tar)
+{
+  int flags, dst_fd = -1;
+  char *s;
+  struct stat ex;
+  struct file_header *file_hdr = &tar->file_hdr;
+
+  if (file_hdr->name[strlen(file_hdr->name)-1] == '/')
+    file_hdr->name[strlen(file_hdr->name)-1] = 0;
+  //Regular file with preceding path
+  if ((s = strrchr(file_hdr->name, '/'))) {
+    if (mkpathat(AT_FDCWD, file_hdr->name, 00, 2) && errno !=EEXIST) {
+      error_msg(":%s: not created", file_hdr->name);
+      return;
+    }
+  }
+
+  //remove old file, if exists
+  if (!(toys.optflags & FLAG_k) && !S_ISDIR(file_hdr->mode)
+      && !lstat( file_hdr->name, &ex)) {
+    if (unlink(file_hdr->name)) {
+      perror_msg("can't remove: %s",file_hdr->name);
+    }
+  }
+
+  //hard link
+  if (S_ISREG(file_hdr->mode) && file_hdr->link_target) {
+    if (link(file_hdr->link_target, file_hdr->name))
+      perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
+    goto COPY;
+  }
+
+  switch (file_hdr->mode & S_IFMT) {
+    case S_IFREG:
+      flags = O_WRONLY|O_CREAT|O_EXCL;
+      if (toys.optflags & FLAG_overwrite) flags = O_WRONLY|O_CREAT|O_TRUNC;
+      dst_fd = open(file_hdr->name, flags, file_hdr->mode & 07777);
+      if (dst_fd == -1) perror_msg("%s: can't open", file_hdr->name);
+      break;
+    case S_IFDIR:
+      if ((mkdir(file_hdr->name, file_hdr->mode) == -1) && errno != EEXIST)
+        perror_msg("%s: can't create", file_hdr->name);
+      break;
+    case S_IFLNK:
+      if (symlink(file_hdr->link_target, file_hdr->name))
+        perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
+      break;
+    case S_IFBLK:
+    case S_IFCHR:
+    case S_IFIFO:
+      if (mknod(file_hdr->name, file_hdr->mode, file_hdr->device))
+        perror_msg("can't create '%s'", file_hdr->name);
+      break;
+    default:
+      printf("type not yet supported\n");
+      break;
+  }
+
+  //copy file....
+COPY:
+  copy_in_out(tar->src_fd, dst_fd, file_hdr->size);
+  tar->offset += file_hdr->size;
+  close(dst_fd);
+
+  if (S_ISLNK(file_hdr->mode)) return;
+  if (!(toys.optflags & FLAG_o)) {
+    //set ownership..., --no-same-owner, --numeric-owner
+    uid_t u = file_hdr->uid;
+    gid_t g = file_hdr->gid;
+
+    if (!(toys.optflags & FLAG_numeric_owner)) {
+      struct group *gr = getgrnam(file_hdr->gname);
+      struct passwd *pw = getpwnam(file_hdr->uname);
+      if (pw) u = pw->pw_uid;
+      if (gr) g = gr->gr_gid;
+    }
+    if (chown(file_hdr->name, u, g))
+      perror_msg("chown %d:%d '%s'", u, g, file_hdr->name);;
+  }
+
+  if (toys.optflags & FLAG_p) // || !(toys.optflags & FLAG_no_same_permissions))
+    chmod(file_hdr->name, file_hdr->mode);
+
+  //apply mtime
+  if (!(toys.optflags & FLAG_m)) {
+    struct timeval times[2] = {{file_hdr->mtime, 0},{file_hdr->mtime, 0}};
+    utimes(file_hdr->name, times);
+  }
+}
+
+static void add_to_list(struct arg_list **llist, char *name)
+{
+  struct arg_list **list = llist;
+
+  while (*list) list=&((*list)->next);
+  *list = xzalloc(sizeof(struct arg_list));
+  (*list)->arg = name;
+  if ((name[strlen(name)-1] == '/') && strlen(name) != 1)
+    name[strlen(name)-1] = '\0';
+}
+
+static void add_from_file(struct arg_list **llist, struct arg_list *flist)
+{
+  char *line = NULL;
+
+  while (flist) {
+    int fd = 0;
+
+    if (strcmp((char *)flist->arg, "-"))
+      fd = xopen((char *)flist->arg, O_RDONLY);
+
+    while ((line = get_line(fd))) {
+      add_to_list(llist, line);
+    }
+    if (fd) close(fd);
+    flist = flist->next;
+  }
+}
+
+static struct archive_handler *init_handler()
+{
+  struct archive_handler *tar_hdl = xzalloc(sizeof(struct archive_handler));
+  tar_hdl->extract_handler = extract_to_disk;
+  return tar_hdl;
+}
+
+//convert octal to int
+static int otoi(char *str, int len)
+{
+  long val;
+  char *endp, inp[len+1]; //1 for NUL termination
+
+  memcpy(inp, str, len);
+  inp[len] = '\0'; //nul-termination made sure
+  val = strtol(inp, &endp, 8);
+  if (*endp && *endp != ' ') error_exit("invalid param");
+  return (int)val;
+}
+
+static void extract_stream(struct archive_handler *tar_hdl)
+{
+  int pipefd[2];              
+  pid_t cpid;                 
+
+  if (pipe(pipefd) == -1) error_exit("pipe");
+
+  cpid = fork();
+  if (cpid == -1) perror_exit("fork");
+
+  if (!cpid) {    /* Child reads from pipe */
+    char *argv[] = {"gunzip", "-cf", "-", NULL};
+    xclose(pipefd[0]); /* Close unused read*/
+    dup2(tar_hdl->src_fd, 0);
+    dup2(pipefd[1], 1); //write to pipe
+    xexec(argv);
+  } else {
+    xclose(pipefd[1]);          /* Close unused read end */
+    dup2(pipefd[0], tar_hdl->src_fd); //read from pipe
+  }
+}
+
+static char *process_extended_hdr(struct archive_handler *tar, int size)
+{
+  char *value = NULL, *p, *buf = xzalloc(size+1);
+
+  if (readall(tar->src_fd, buf, size) != size) error_exit("short read");
+  buf[size] = 0;
+  tar->offset += size;
+  p = buf;
+
+  while (size) {
+    char *key;
+    int len, n;
+
+    // extended records are of the format: "LEN NAME=VALUE\n"
+    sscanf(p, "%d %n", &len, &n);
+    key = p + n;
+    p += len;
+    size -= len;
+    p[-1] = 0;
+    if (size < 0) {
+      error_msg("corrupted extended header");
+      break;
+    }
+
+    len = strlen("path=");
+    if (!strncmp(key, "path=", len)) {
+      value = key + strlen("path=");
+      break;
+    }
+  }
+  if (value) value = xstrdup(value);
+  free(buf);
+  return value;
+}
+
+static void tar_skip(struct archive_handler *tar, int sz)
+{
+  int x;
+
+  while ((x = lskip(tar->src_fd, sz))) {
+    tar->offset += sz - x;
+    sz = x;
+  }
+  tar->offset += sz;
+}
+
+static void unpack_tar(struct archive_handler *tar_hdl)
+{
+  struct tar_hdr tar;
+  struct file_header *file_hdr;
+  int i, j, maj, min, sz, e = 0;
+  unsigned int cksum;
+  unsigned char *gzMagic;
+  char *longname = NULL, *longlink = NULL;
+
+  while (1) {
+    cksum = 0;
+    if (tar_hdl->offset % 512) {
+      sz = 512 - tar_hdl->offset % 512;
+      tar_skip(tar_hdl, sz);
+    }
+    i = readall(tar_hdl->src_fd, &tar, 512);
+    tar_hdl->offset += i;
+    if (i != 512) {
+      if (i >= 2) goto CHECK_MAGIC; //may be a small (<512 byte)zipped file
+      error_exit("read error");
+    }
+
+    if (!tar.name[0]) {
+      if (e) return; //end of tar 2 empty blocks
+      e = 1;//empty jump to next block
+      continue;
+    }
+    if (strncmp(tar.magic, "ustar", 5)) {
+      //try detecting by reading magic
+CHECK_MAGIC:
+      gzMagic = (unsigned char*)&tar;
+      if ((gzMagic[0] == 0x1f) && (gzMagic[1] == 0x8b) 
+          && !lseek(tar_hdl->src_fd, -i, SEEK_CUR)) {
+        tar_hdl->offset -= i;
+        extract_stream(tar_hdl);
+        continue;
+      }
+      error_exit("invalid tar format");
+    }
+
+    for (j = 0; j<148; j++) cksum += (unsigned int)((char*)&tar)[j];
+    for (j = 156; j<500; j++) cksum += (unsigned int)((char*)&tar)[j];
+    //cksum field itself treated as ' '
+    for ( j= 0; j<8; j++) cksum += (unsigned int)' ';
+
+    if (cksum != otoi(tar.chksum, sizeof(tar.chksum))) error_exit("wrong cksum");
+
+    file_hdr = &tar_hdl->file_hdr;
+    memset(file_hdr, 0, sizeof(struct file_header));
+    file_hdr->mode = otoi(tar.mode, sizeof(tar.mode));
+    file_hdr->uid = otoi(tar.uid, sizeof(tar.uid));
+    file_hdr->gid = otoi(tar.gid, sizeof(tar.gid));
+    file_hdr->size = otoi(tar.size, sizeof(tar.size));
+    file_hdr->mtime = otoi(tar.mtime, sizeof(tar.mtime));
+    file_hdr->uname = xstrdup(tar.uname);
+    file_hdr->gname = xstrdup(tar.gname);
+    maj = otoi(tar.major, sizeof(tar.major));
+    min = otoi(tar.minor, sizeof(tar.minor));
+    file_hdr->device = dev_makedev(maj, min);
+
+    if (tar.type <= '7') {
+      if (tar.link[0]) {
+        sz = sizeof(tar.link);
+        file_hdr->link_target = xmalloc(sz + 1);
+        memcpy(file_hdr->link_target, tar.link, sz);
+        file_hdr->link_target[sz] = '\0';
+      }
+
+      file_hdr->name = xzalloc(256);// pathname supported size
+      if (tar.prefix[0]) {
+        memcpy(file_hdr->name, tar.prefix, sizeof(tar.prefix));
+        sz = strlen(file_hdr->name);
+        if (file_hdr->name[sz-1] != '/') file_hdr->name[sz] = '/';
+      }
+      sz = strlen(file_hdr->name);
+      memcpy(file_hdr->name + sz, tar.name, sizeof(tar.name));
+      if (file_hdr->name[255]) error_exit("filename too long");
+    }
+
+    switch (tar.type) {
+      //    case '\0':
+      case '0':
+      case '7':
+      case '1': //Hard Link
+        file_hdr->mode |= S_IFREG;
+        break;
+      case '2':
+        file_hdr->mode |= S_IFLNK;
+        break;
+      case '3':
+        file_hdr->mode |= S_IFCHR;
+        break;
+      case '4':
+        file_hdr->mode |= S_IFBLK;
+        break;
+      case '5':
+        file_hdr->mode |= S_IFDIR;
+        break;
+      case '6':
+        file_hdr->mode |= S_IFIFO;
+        break;
+      case 'K':
+        longlink = xzalloc(file_hdr->size +1);
+        xread(tar_hdl->src_fd, longlink, file_hdr->size);
+        tar_hdl->offset += file_hdr->size;
+        continue;
+      case 'L':
+        free(longname);
+        longname = xzalloc(file_hdr->size +1);           
+        xread(tar_hdl->src_fd, longname, file_hdr->size);
+        tar_hdl->offset += file_hdr->size;
+        continue;
+      case 'D':
+      case 'M':
+      case 'N':
+      case 'S':
+      case 'V':
+      case 'g':  // pax global header
+        tar_skip(tar_hdl, file_hdr->size);
+        continue;
+      case 'x':  // pax extended header
+        free(longname);
+        longname = process_extended_hdr(tar_hdl, file_hdr->size);
+        continue;
+      default: break;
+    }
+
+    if (longname) {
+      free(file_hdr->name);
+      file_hdr->name = longname;
+      longname = NULL;
+    }
+    if (longlink) {
+      free(file_hdr->link_target);
+      file_hdr->link_target = longlink;
+      longlink = NULL;
+    }
+
+    if ((file_hdr->mode & S_IFREG) && 
+        file_hdr->name[strlen(file_hdr->name)-1] == '/') {
+      file_hdr->name[strlen(file_hdr->name)-1] = '\0';
+      file_hdr->mode &= ~S_IFREG;
+      file_hdr->mode |= S_IFDIR;
+    }
+
+    if ((file_hdr->link_target && *(file_hdr->link_target)) 
+        || S_ISLNK(file_hdr->mode) || S_ISDIR(file_hdr->mode))
+      file_hdr->size = 0;
+
+    if (filter(TT.exc, file_hdr->name) ||
+        (TT.inc && !filter(TT.inc, file_hdr->name))) goto SKIP;
+    add_to_list(&TT.pass, xstrdup(file_hdr->name));
+
+    if (toys.optflags & FLAG_t) {
+      if (toys.optflags & FLAG_v) {
+        char perm[11];
+        struct tm *lc = localtime((const time_t*)&(file_hdr->mtime));
+
+        mode_to_string(file_hdr->mode, perm);
+        printf("%s %s/%s %9ld %d-%02d-%02d %02d:%02d:%02d ",perm,file_hdr->uname,
+            file_hdr->gname, (long)file_hdr->size, 1900+lc->tm_year,
+            1+lc->tm_mon, lc->tm_mday, lc->tm_hour, lc->tm_min, lc->tm_sec);
+      }
+      printf("%s",file_hdr->name);
+      if (file_hdr->link_target) printf(" -> %s",file_hdr->link_target);
+      xputc('\n');
+SKIP:
+      tar_skip(tar_hdl, file_hdr->size);
+    } else {
+      if (toys.optflags & FLAG_v) printf("%s\n",file_hdr->name);
+      tar_hdl->extract_handler(tar_hdl);
+    }
+    free(file_hdr->name);
+    free(file_hdr->link_target);
+    free(file_hdr->uname);
+    free(file_hdr->gname);
+  }
+}
+
+void tar_main(void)
+{
+  struct archive_handler *tar_hdl;
+  int fd = 0;
+  struct arg_list *tmp;
+  char **args = toys.optargs;
+
+  if (!geteuid()) toys.optflags |= FLAG_p;
+
+  for (tmp = TT.exc; tmp; tmp = tmp->next)
+    tmp->arg = xstrdup(tmp->arg); //freeing at the end fails otherwise
+
+  while(*args) add_to_list(&TT.inc, xstrdup(*args++));
+  if (toys.optflags & FLAG_X) add_from_file(&TT.exc, TT.exc_file);
+  if (toys.optflags & FLAG_T) add_from_file(&TT.inc, TT.inc_file);
+
+  if (toys.optflags & FLAG_c) {
+    if (!TT.inc) error_exit("empty archive");
+    fd = 1;
+  }
+  if ((toys.optflags & FLAG_f) && strcmp(TT.fname, "-")) 
+    fd = xcreate(TT.fname, fd*(O_WRONLY|O_CREAT|O_TRUNC), 0666);
+  if (toys.optflags & FLAG_C) xchdir(TT.dir);
+
+  tar_hdl = init_handler();
+  tar_hdl->src_fd = fd;
+
+  if ((toys.optflags & FLAG_x) || (toys.optflags & FLAG_t)) {
+    if (toys.optflags & FLAG_O) tar_hdl->extract_handler = extract_to_stdout;
+    if (toys.optflags & FLAG_to_command) {
+      signal(SIGPIPE, SIG_IGN); //will be using pipe between child & parent
+      tar_hdl->extract_handler = extract_to_command;
+    }
+    if (toys.optflags & FLAG_z) extract_stream(tar_hdl);
+    unpack_tar(tar_hdl);
+    for (tmp = TT.inc; tmp; tmp = tmp->next)
+      if (!filter(TT.exc, tmp->arg) && !filter(TT.pass, tmp->arg))
+        error_msg("'%s' not in archive", tmp->arg);
+  } else if (toys.optflags & FLAG_c) {
+    //create the tar here.
+    if (toys.optflags & FLAG_z) compress_stream(tar_hdl);
+    for (tmp = TT.inc; tmp; tmp = tmp->next) {
+      TT.handle = tar_hdl;
+      //recurse thru dir and add files to archive
+      dirtree_flagread(tmp->arg, DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_h),
+        add_to_tar);
+    }
+    memset(toybuf, 0, 1024);
+    writeall(tar_hdl->src_fd, toybuf, 1024);
+    seen_inode(&TT.inodes, 0, 0);
+  }
+
+  if (CFG_TOYBOX_FREE) {
+    close(tar_hdl->src_fd);
+    free(tar_hdl);
+    llist_traverse(TT.exc, llist_free_arg);
+    llist_traverse(TT.inc, llist_free_arg);
+    llist_traverse(TT.pass, llist_free_arg);
+  }
+}
diff --git a/toybox/toys/pending/tcpsvd.c b/toybox/toys/pending/tcpsvd.c
new file mode 100644
index 0000000..31c2761
--- /dev/null
+++ b/toybox/toys/pending/tcpsvd.c
@@ -0,0 +1,404 @@
+/* tcpsvd.c - TCP(UDP)/IP service daemon 
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com>
+ * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ * 
+ * No Standard.
+
+USE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1C:b#=20<0u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TCPSVD(OLDTOY(udpsvd, tcpsvd, TOYFLAG_USR|TOYFLAG_BIN))
+
+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
+    
+    Create TCP/UDP socket, bind to IP:PORT and listen for incoming connection. 
+    Run PROG for each connection.
+
+    IP            IP to listen on, 0 = all
+    PORT          Port to listen on
+    PROG ARGS     Program to run
+    -l NAME       Local hostname (else looks up local hostname in DNS)
+    -u USER[:GRP] Change to user/group after bind
+    -c N          Handle up to N (> 0) connections simultaneously
+    -b N          (TCP Only) Allow a backlog of approximately N TCP SYNs
+    -C N[:MSG]    (TCP Only) Allow only up to N (> 0) connections from the same IP
+                  New connections from this IP address are closed
+                  immediately. MSG is written to the peer before close
+    -h            Look up peer's hostname
+    -E            Don't set up environment variables
+    -v            Verbose
+*/
+
+#define FOR_tcpsvd
+#include "toys.h"
+
+GLOBALS(
+  char *name;
+  char *user;
+  long bn;
+  char *nmsg;
+  long cn;
+
+  int maxc;
+  int count_all;
+  int udp;
+)
+
+struct list_pid {
+  struct list_pid *next;
+  char *ip;  
+  int pid;
+};
+
+struct list {
+  struct list* next;
+  char *d;
+  int count;
+};
+
+struct hashed {
+  struct list *head;
+};
+
+#define HASH_NR 256
+struct hashed h[HASH_NR];
+struct list_pid *pids = NULL;
+
+// convert IP address to string.
+static char *sock_to_address(struct sockaddr *sock, int flags)
+{
+  char hbuf[NI_MAXHOST] = {0,};
+  char sbuf[NI_MAXSERV] = {0,}; 
+  int status = 0;
+  socklen_t len = sizeof(struct sockaddr_in6);
+
+  if (!(status = getnameinfo(sock, len, hbuf, sizeof(hbuf), sbuf, 
+          sizeof(sbuf), flags))) {
+    if (flags & NI_NUMERICSERV) return xmprintf("%s:%s",hbuf, sbuf);
+    return xmprintf("%s",hbuf);
+  }
+  error_exit("getnameinfo: %s", gai_strerror(status));
+}
+
+// Insert pid, ip and fd in the list.
+static void insert(struct list_pid **l, int pid, char *addr)
+{
+  struct list_pid *newnode = xmalloc(sizeof(struct list_pid));
+  newnode->pid = pid;
+  newnode->ip = addr;
+  newnode->next = NULL;
+  if (!*l) *l = newnode;
+  else {
+    newnode->next = (*l);
+   *l = newnode;
+  }
+}
+
+// Hashing of IP address.
+static int haship( char *addr)
+{
+  uint32_t ip[8] = {0,};
+  int count = 0, i = 0;
+
+  if (!addr) error_exit("NULL ip");
+  while (i < strlen(addr)) {
+    while (addr[i] && (addr[i] != ':') && (addr[i] != '.')) {
+      ip[count] = ip[count]*10 + (addr[i]-'0');
+      i++;
+    }
+    if (i >= strlen(addr)) break;
+    count++;
+    i++;
+  }
+  return (ip[0]^ip[1]^ip[2]^ip[3]^ip[4]^ip[5]^ip[6]^ip[7])%HASH_NR;
+}
+
+// Remove a node from the list.
+static char *delete(struct list_pid **pids, int pid)
+{
+  struct list_pid *prev, *free_node, *head = *pids; 
+  char *ip = NULL;
+ 
+  if (!head) return NULL;
+  prev = free_node = NULL;
+  while (head) {
+    if (head->pid == pid) {
+      ip = head->ip;
+      free_node = head;
+      if (!prev) *pids = head->next;
+      else prev->next = head->next;
+      free(free_node);
+      return ip;
+    }
+    prev = head;
+    head = head->next;
+  }
+  return NULL;
+}
+
+// decrement the ref count fora connection, if count reches ZERO then remove the node
+static void remove_connection(char *ip)
+{
+  struct list *head, *prev = NULL, *free_node = NULL;
+  int hash = haship(ip);
+
+  head = h[hash].head;
+  while (head) {
+    if (!strcmp(ip, head->d)) {
+      head->count--;
+      free_node = head;
+      if (!head->count) {
+        if (!prev) h[hash].head = head->next;
+        else prev->next = head->next;
+        free(free_node);
+      }
+      break;
+    }
+    prev = head;
+    head = head->next;
+  }
+  free(ip);
+}
+
+// Handler function.
+static void handle_exit(int sig)
+{
+  int status;
+  pid_t pid_n = wait(&status);
+
+  if (pid_n <= 0) return;
+  char *ip = delete(&pids, pid_n);
+  if (!ip) return;
+  remove_connection(ip);
+  TT.count_all--;
+  if (toys.optflags & FLAG_v) {
+    if (WIFEXITED(status))
+      xprintf("%s: end %d exit %d\n",toys.which->name, pid_n, WEXITSTATUS(status));
+    else if (WIFSIGNALED(status))
+      xprintf("%s: end %d signaled %d\n",toys.which->name, pid_n, WTERMSIG(status));
+    if (TT.cn > 1) xprintf("%s: status %d/%d\n",toys.which->name, TT.count_all, TT.cn);
+  }
+}
+
+// Grab uid and gid 
+static void get_uidgid(uid_t *uid, gid_t *gid, char *ug)
+{
+  struct passwd *pass = NULL;
+  struct group *grp = NULL;
+  char *user = NULL, *group = NULL;
+  unsigned int n;
+
+  user = ug;
+  group = strchr(ug,':');
+  if (group) {
+    *group = '\0';
+    group++;
+  }
+  if (!(pass = getpwnam(user))) {
+    n = atolx_range(user, 0, INT_MAX);
+    if (!(pass = getpwuid(n))) perror_exit("Invalid user '%s'", user);
+  }
+  *uid = pass->pw_uid;
+  *gid = pass->pw_gid;
+
+  if (group) {
+    if (!(grp = getgrnam(group))) {
+      n = atolx_range(group, 0, INT_MAX);
+      if (!(grp = getgrgid(n))) perror_exit("Invalid group '%s'",group);
+    }    
+  }
+  if (grp) *gid = grp->gr_gid;
+}
+
+// Bind socket.
+static int create_bind_sock(char *host, struct sockaddr *haddr)
+{
+  struct addrinfo hints, *res = NULL, *rp;
+  int sockfd, ret, set = 1;
+  char *ptr;
+  unsigned long port;
+
+  errno = 0;
+  port = strtoul(toys.optargs[1], &ptr, 10);  
+  if (errno || port > 65535) 
+    error_exit("Invalid port, Range is [0-65535]");
+  if (*ptr) ptr = toys.optargs[1];
+  else {
+    sprintf(toybuf, "%lu", port);
+    ptr = toybuf;
+  }
+
+  memset(&hints, 0, sizeof hints);
+  hints.ai_family = AF_UNSPEC;  
+  hints.ai_socktype = ((TT.udp) ?SOCK_DGRAM : SOCK_STREAM);
+  if ((ret = getaddrinfo(host, ptr, &hints, &res))) 
+    perror_exit("%s", gai_strerror(ret));
+
+  for (rp = res; rp; rp = rp->ai_next) 
+    if ( (rp->ai_family == AF_INET) || (rp->ai_family == AF_INET6)) break;
+
+  if (!rp) error_exit("Invalid IP %s", host);
+
+  sockfd = xsocket(rp->ai_family, TT.udp ?SOCK_DGRAM :SOCK_STREAM, 0);
+  setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
+  if (TT.udp) setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &set, sizeof(set));
+  if ((bind(sockfd, rp->ai_addr, rp->ai_addrlen)) < 0) perror_exit("Bind failed");
+  if(haddr) memcpy(haddr, rp->ai_addr, rp->ai_addrlen);
+  freeaddrinfo(res);
+  return sockfd;
+}
+
+static void handle_signal(int sig)
+{
+  if (toys.optflags & FLAG_v) xprintf("got signal %d, exit\n", sig);
+  raise(sig);
+  _exit(sig + 128); //should not reach here
+} 
+
+void tcpsvd_main(void)
+{
+  uid_t uid = 0;
+  gid_t gid = 0;
+  pid_t pid;
+  char haddr[sizeof(struct sockaddr_in6)];
+  struct list *head, *newnode;
+  int hash, fd, newfd, j;
+  char *ptr = NULL, *addr, *server, buf[sizeof(struct sockaddr_in6)];
+  socklen_t len = sizeof(buf);
+
+  TT.udp = (*toys.which->name == 'u');
+  if (TT.udp) toys.optflags &= ~FLAG_C;
+  memset(buf, 0, len);
+  if (toys.optflags & FLAG_C) {
+    if ((ptr = strchr(TT.nmsg, ':'))) {
+      *ptr = '\0';
+      ptr++;
+    }
+    TT.maxc = atolx_range(TT.nmsg, 1, INT_MAX);
+  }
+  
+  fd = create_bind_sock(toys.optargs[0], (struct sockaddr*)&haddr);
+  if(toys.optflags & FLAG_u) {
+    get_uidgid(&uid, &gid, TT.user);
+    setuid(uid);
+    setgid(gid);
+  }
+
+  if (!TT.udp && (listen(fd, TT.bn) < 0)) perror_exit("Listen failed");
+  server = sock_to_address((struct sockaddr*)&haddr, NI_NUMERICHOST|NI_NUMERICSERV);
+  if (toys.optflags & FLAG_v) {
+    if (toys.optflags & FLAG_u)
+      xprintf("%s: listening on %s, starting, uid %u, gid %u\n"
+          ,toys.which->name, server, uid, gid);
+    else 
+      xprintf("%s: listening on %s, starting\n", toys.which->name, server);
+  }
+  for (j = 0; j < HASH_NR; j++) h[j].head = NULL;
+  sigatexit(handle_signal);  
+  signal(SIGCHLD, handle_exit);
+
+  while (1) {
+    if (TT.count_all  < TT.cn) {
+      if (TT.udp) {
+        if(recvfrom(fd, NULL, 0, MSG_PEEK, (struct sockaddr *)buf, &len) < 0)
+          perror_exit("recvfrom");
+        newfd = fd;
+      } else {
+        newfd = accept(fd, (struct sockaddr *)buf, &len);
+        if (newfd < 0) perror_exit("Error on accept");
+      }
+    } else {
+      sigset_t ss;
+      sigemptyset(&ss);
+      sigsuspend(&ss);
+      continue;
+    }
+    TT.count_all++;
+    addr = sock_to_address((struct sockaddr*)buf, NI_NUMERICHOST);
+
+    hash = haship(addr);
+    if (toys.optflags & FLAG_C) {
+      for (head = h[hash].head; head; head = head->next)
+        if (!strcmp(head->d, addr)) break;
+
+      if (head && head->count >= TT.maxc) {
+        if (ptr) write(newfd, ptr, strlen(ptr)+1);
+        close(newfd);
+        TT.count_all--;
+        continue;
+      }
+    }
+
+    newnode = (struct list*)xzalloc(sizeof(struct list));
+    newnode->d = addr;
+    for (head = h[hash].head; head; head = head->next) {
+      if (!strcmp(addr, head->d)) {
+        head->count++;
+        free(newnode);
+        break;
+      }
+    }
+
+    if (!head) {
+      newnode->next = h[hash].head;
+      h[hash].head = newnode;
+      h[hash].head->count++;
+    }
+
+    if (!(pid = xfork())) {
+      char *serv = NULL, *clie = NULL;
+      char *client = sock_to_address((struct sockaddr*)buf, NI_NUMERICHOST | NI_NUMERICSERV);
+      if (toys.optflags & FLAG_h) { //lookup name
+        if (toys.optflags & FLAG_l) serv = xstrdup(TT.name);
+        else serv = sock_to_address((struct sockaddr*)&haddr, 0);
+        clie = sock_to_address((struct sockaddr*)buf, 0);
+      }
+
+      if (!(toys.optflags & FLAG_E)) {
+        setenv("PROTO", TT.udp ?"UDP" :"TCP", 1);
+        setenv("PROTOLOCALADDR", server, 1);
+        setenv("PROTOREMOTEADDR", client, 1);
+        if (toys.optflags & FLAG_h) {
+          setenv("PROTOLOCALHOST", serv, 1);
+          setenv("PROTOREMOTEHOST", clie, 1);
+        }
+        if (!TT.udp) {
+          char max_c[32];
+          sprintf(max_c, "%d", TT.maxc);
+          setenv("TCPCONCURRENCY", max_c, 1); //Not valid for udp
+        }
+      }
+      if (toys.optflags & FLAG_v) {
+        xprintf("%s: start %d %s-%s",toys.which->name, getpid(), server, client);
+        if (toys.optflags & FLAG_h) xprintf(" (%s-%s)", serv, clie);
+        xputc('\n');
+        if (TT.cn > 1) 
+          xprintf("%s: status %d/%d\n",toys.which->name, TT.count_all, TT.cn);
+      }
+      free(client);
+      if (toys.optflags & FLAG_h) {
+        free(serv);
+        free(clie);
+      }
+      if (TT.udp && (connect(newfd, (struct sockaddr *)buf, sizeof(buf)) < 0))
+          perror_exit("connect");
+
+      close(0);
+      close(1);
+      dup2(newfd, 0);
+      dup2(newfd, 1);
+      xexec(toys.optargs+2); //skip IP PORT
+    } else {
+      insert(&pids, pid, addr);
+      xclose(newfd); //close and reopen for next client.
+      if (TT.udp) fd = create_bind_sock(toys.optargs[0],
+          (struct sockaddr*)&haddr);
+    }
+  } //while(1)
+}
diff --git a/toybox/toys/pending/telnet.c b/toybox/toys/pending/telnet.c
new file mode 100644
index 0000000..dc3487a
--- /dev/null
+++ b/toybox/toys/pending/telnet.c
@@ -0,0 +1,342 @@
+/* telnet.c - Telnet client.
+ *
+ * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ * Modified by Ashwini Kumar <ak.ashwini1981@gmail.com>
+ *
+ * Not in SUSv4.
+
+USE_TELNET(NEWTOY(telnet, "<1>2", TOYFLAG_BIN))
+
+config TELNET
+  bool "telnet"
+  default n
+  help
+    usage: telnet HOST [PORT]
+
+    Connect to telnet server
+*/
+
+#define FOR_telnet
+#include "toys.h"
+#include <arpa/telnet.h>
+#include <netinet/in.h>
+#include  <sys/poll.h>
+
+GLOBALS(
+  int port;
+  int sfd;
+  char buff[128];
+  int pbuff;
+  char iac[256];
+  int piac;
+  char *ttype;
+  struct termios def_term;
+  struct termios raw_term;
+  uint8_t term_ok;
+  uint8_t term_mode;
+  uint8_t flags;
+  unsigned win_width;
+  unsigned win_height;
+)
+
+#define DATABUFSIZE 128
+#define IACBUFSIZE  256
+#define CM_TRY      0
+#define CM_ON       1
+#define CM_OFF      2
+#define UF_ECHO     0x01
+#define UF_SGA      0x02
+
+// sets terminal mode: LINE or CHARACTER based om internal stat.
+static char const es[] = "\r\nEscape character is ";
+static void set_mode(void)
+{
+  if (TT.flags & UF_ECHO) {
+    if (TT.term_mode == CM_TRY) {
+      TT.term_mode = CM_ON;
+      printf("\r\nEntering character mode%s'^]'.\r\n", es);
+      if (TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.raw_term);
+    }
+  } else {
+    if (TT.term_mode != CM_OFF) {
+      TT.term_mode = CM_OFF;
+      printf("\r\nEntering line mode%s'^C'.\r\n", es);
+      if (TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.def_term);
+    }
+  }
+}
+
+// flushes all data in IAC buff to server.
+static void flush_iac(void)
+{
+  int wlen = write(TT.sfd, TT.iac, TT.piac);
+
+  if(wlen <= 0) error_msg("IAC : send failed.");
+  TT.piac = 0;
+}
+
+// puts DATA in iac buff of length LEN and updates iac buff pointer.
+static void put_iac(int len, ...)
+{
+  va_list va; 
+
+  if(TT.piac + len >= IACBUFSIZE) flush_iac();
+  va_start(va, len);
+  for(;len > 0; TT.iac[TT.piac++] = (uint8_t)va_arg(va, int), len--);
+  va_end(va);
+}
+
+// puts string STR in iac buff and updates iac buff pointer.
+static void str_iac(char *str)
+{
+  int len = strlen(str);
+
+  if(TT.piac + len + 1 >= IACBUFSIZE) flush_iac();
+  strcpy(&TT.iac[TT.piac], str);
+  TT.piac += len+1;
+}
+
+static void handle_esc(void)
+{
+  char input;
+
+  if(toys.signal && TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.raw_term);
+  xwrite(1,"\r\nConsole escape. Commands are:\r\n\n"
+      " l  go to line mode\r\n"
+      " c  go to character mode\r\n"
+      " z  suspend telnet\r\n"
+      " e  exit telnet\r\n", 114);
+
+  if (read(STDIN_FILENO, &input, 1) <= 0) {
+    if(TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.def_term);
+    exit(0);
+  }
+
+  switch (input) {
+  case 'l':
+    if (!toys.signal) {
+      TT.term_mode = CM_TRY;
+      TT.flags &= ~(UF_ECHO | UF_SGA);
+      set_mode();
+      put_iac(6, IAC,DONT,TELOPT_ECHO,IAC,DONT, TELOPT_SGA);
+      flush_iac();
+      goto ret;
+    }
+    break;
+  case 'c':
+    if (toys.signal) {
+      TT.term_mode = CM_TRY;
+      TT.flags |= (UF_ECHO | UF_SGA);
+      set_mode();
+      put_iac(6, IAC,DO,TELOPT_ECHO,IAC,DO,TELOPT_SGA);
+      flush_iac();
+      goto ret;
+    }
+    break;
+  case 'z':
+    if(TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.def_term);
+    kill(0, SIGTSTP);
+    if(TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.raw_term);
+    break;
+  case 'e':
+    if(TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.def_term);
+    exit(0);
+  default: break;
+  }
+
+  xwrite(1, "continuing...\r\n", 15);
+  if (toys.signal && TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.def_term);
+
+ret:
+  toys.signal = 0;
+}
+
+/*
+ * handles telnet SUB NEGOTIATIONS
+ * only terminal type is supported.
+ */
+static void handle_negotiations(void)
+{
+  char opt = TT.buff[TT.pbuff++];
+
+  switch(opt) {
+  case TELOPT_TTYPE:
+    opt =  TT.buff[TT.pbuff++];
+    if(opt == TELQUAL_SEND) {
+      put_iac(4, IAC,SB,TELOPT_TTYPE,TELQUAL_IS);
+      str_iac(TT.ttype);
+      put_iac(2, IAC,SE);
+    }
+    break;
+  default: break;
+  }
+}
+
+/*
+ * handles server's DO DONT WILL WONT requests.
+ * supports ECHO, SGA, TTYPE, NAWS
+ */
+static void handle_ddww(char ddww)
+{
+  char opt = TT.buff[TT.pbuff++];
+
+  switch (opt) {
+  case TELOPT_ECHO: /* ECHO */
+    if (ddww == DO) put_iac(3, IAC,WONT,TELOPT_ECHO);
+    if(ddww == DONT) break;
+    if (TT.flags & UF_ECHO) {
+        if (ddww == WILL) return;
+      } else if (ddww == WONT) return;
+    if (TT.term_mode != CM_OFF) TT.flags ^= UF_ECHO;
+    (TT.flags & UF_ECHO)? put_iac(3, IAC,DO,TELOPT_ECHO) : 
+      put_iac(3, IAC,DONT,TELOPT_ECHO);
+    set_mode();
+    printf("\r\n");
+    break;
+
+  case TELOPT_SGA: /* Supress GO Ahead */
+    if (TT.flags & UF_SGA){ if (ddww == WILL) return;
+    } else if (ddww == WONT) return;
+
+    TT.flags ^= UF_SGA;
+    (TT.flags & UF_SGA)? put_iac(3, IAC,DO,TELOPT_SGA) :
+      put_iac(3, IAC,DONT,TELOPT_SGA);
+    break;
+
+  case TELOPT_TTYPE: /* Terminal Type */
+    (TT.ttype)? put_iac(3, IAC,WILL,TELOPT_TTYPE):
+      put_iac(3, IAC,WONT,TELOPT_TTYPE);
+    break;
+
+  case TELOPT_NAWS: /* Window Size */
+    put_iac(3, IAC,WILL,TELOPT_NAWS);
+    put_iac(9, IAC,SB,TELOPT_NAWS,(TT.win_width >> 8) & 0xff,
+        TT.win_width & 0xff,(TT.win_height >> 8) & 0xff,
+        TT.win_height & 0xff,IAC,SE);
+    break;
+
+  default: /* Default behaviour is to say NO */
+    if(ddww == WILL) put_iac(3, IAC,DONT,opt);
+    if(ddww == DO) put_iac(3, IAC,WONT,opt);
+    break;
+  }
+}
+
+/*
+ * parses data which is read from server of length LEN.
+ * and passes it to console.
+ */
+static int read_server(int len)
+{
+  int i = 0;
+  char curr;
+  TT.pbuff = 0;
+
+  do {
+    curr = TT.buff[TT.pbuff++];
+    if (curr == IAC) {
+      curr = TT.buff[TT.pbuff++];
+      switch (curr) {
+      case DO:    /* FALLTHROUGH */
+      case DONT:    /* FALLTHROUGH */
+      case WILL:    /* FALLTHROUGH */
+      case WONT:
+        handle_ddww(curr);
+        break;
+      case SB:
+        handle_negotiations();
+        break;
+      case SE:
+        break;
+      default: break;
+      }
+    } else {
+      toybuf[i++] = curr;
+      if (curr == '\r') { curr = TT.buff[TT.pbuff++];
+        if (curr != '\0') TT.pbuff--;
+      }
+    }
+  } while (TT.pbuff < len);
+
+  if (i) xwrite(STDIN_FILENO, toybuf, i);
+  return 0;
+}
+
+/*
+ * parses data which is read from console of length LEN
+ * and passes it to server.
+ */
+static void write_server(int len)
+{
+  char *c = (char*)TT.buff;
+  int i = 0;
+
+  for (; len > 0; len--, c++) {
+    if (*c == 0x1d) {
+      handle_esc();
+      return;
+    }
+    toybuf[i++] = *c;
+    if (*c == IAC) toybuf[i++] = *c; /* IAC -> IAC IAC */
+    else if (*c == '\r') toybuf[i++] = '\0'; /* CR -> CR NUL */
+  }
+  if(i) xwrite(TT.sfd, toybuf, i);
+}
+
+void telnet_main(void)
+{
+  char *port = "23";
+  int set = 1, len;
+  struct pollfd pfds[2];
+
+  TT.win_width = 80; //columns
+  TT.win_height = 24; //rows
+
+  if (toys.optc == 2) port = toys.optargs[1];
+
+  TT.ttype = getenv("TERM");
+  if(!TT.ttype) TT.ttype = "";
+  if(strlen(TT.ttype) > IACBUFSIZE-1) TT.ttype[IACBUFSIZE - 1] = '\0';
+
+  if (!tcgetattr(0, &TT.def_term)) {
+    TT.term_ok = 1;
+    TT.raw_term = TT.def_term;
+    cfmakeraw(&TT.raw_term);
+  }
+  terminal_size(&TT.win_width, &TT.win_height);
+
+  TT.sfd = xconnect(*toys.optargs, port, 0, SOCK_STREAM, IPPROTO_TCP, 0);
+  setsockopt(TT.sfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
+  setsockopt(TT.sfd, SOL_SOCKET, SO_KEEPALIVE, &set, sizeof(set));
+
+  pfds[0].fd = STDIN_FILENO;
+  pfds[0].events = POLLIN;
+  pfds[1].fd = TT.sfd;
+  pfds[1].events = POLLIN;
+
+  signal(SIGINT, generic_signal);
+  while(1) {
+    if(TT.piac) flush_iac();
+    if(poll(pfds, 2, -1) < 0) {
+      if (toys.signal) handle_esc();
+      else sleep(1);
+
+      continue;
+    }
+    if(pfds[0].revents) {
+      len = read(STDIN_FILENO, TT.buff, DATABUFSIZE);
+      if(len > 0) write_server(len);
+      else return;
+    }
+    if(pfds[1].revents) {
+      len = read(TT.sfd, TT.buff, DATABUFSIZE);
+      if(len > 0) read_server(len);
+      else {
+        printf("Connection closed by foreign host\r\n");
+        if(TT.term_ok) tcsetattr(0, TCSADRAIN, &TT.def_term);
+        exit(1);
+      }
+    }
+  }
+}
diff --git a/toybox/toys/pending/telnetd.c b/toybox/toys/pending/telnetd.c
new file mode 100644
index 0000000..4198e63
--- /dev/null
+++ b/toybox/toys/pending/telnetd.c
@@ -0,0 +1,446 @@
+/* telnetd.c - Telnet Server 
+ *
+ * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+USE_TELNETD(NEWTOY(telnetd, "w#<0b:p#<0>65535=23f:l:FSKi[!wi]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config TELNETD
+  bool "telnetd"
+  default n
+  help
+    Handle incoming telnet connections
+
+    -l LOGIN  Exec LOGIN on connect
+    -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue
+    -K Close connection as soon as login exits
+    -p PORT   Port to listen on
+    -b ADDR[:PORT]  Address to bind to
+    -F Run in foreground
+    -i Inetd mode
+    -w SEC    Inetd 'wait' mode, linger time SEC
+    -S Log to syslog (implied by -i or without -F and -w)
+*/
+
+#define FOR_telnetd
+#include "toys.h"
+#include <utmp.h>
+GLOBALS(
+    char *login_path;
+    char *issue_path;
+    int port;
+    char *host_addr;
+    long w_sec;
+
+    int gmax_fd;
+    pid_t fork_pid;
+)
+
+
+# define IAC         255  /* interpret as command: */
+# define DONT        254  /* you are not to use option */
+# define DO          253  /* please, you use option */
+# define WONT        252  /* I won't use option */
+# define WILL        251  /* I will use option */
+# define SB          250  /* interpret as subnegotiation */
+# define SE          240  /* end sub negotiation */
+# define NOP         241  /* No Operation */
+# define TELOPT_ECHO   1  /* echo */
+# define TELOPT_SGA    3  /* suppress go ahead */
+# define TELOPT_TTYPE 24  /* terminal type */
+# define TELOPT_NAWS  31  /* window size */
+
+#define BUFSIZE 4*1024
+struct term_session {
+  int new_fd, pty_fd;
+  pid_t child_pid;
+  int buff1_avail, buff2_avail;
+  int buff1_written, buff2_written;
+  int rem;  //unprocessed data from socket
+  char buff1[BUFSIZE], buff2[BUFSIZE];
+  struct term_session *next;
+};
+
+struct term_session *session_list = NULL;
+
+static void get_sockaddr(char *host, void *buf)
+{
+  in_port_t port_num = htons(TT.port);
+  struct addrinfo hints, *result;
+  int status, af = AF_UNSPEC;
+  char *s;
+
+  // [ipv6]:port or exactly one :
+  if (*host == '[') {
+    host++;
+    s = strchr(host, ']');
+    if (s) *s++ = 0;
+    else error_exit("bad address '%s'", host-1);
+    af = AF_INET6;
+  } else {
+    s = strrchr(host, ':');
+    if (s && strchr(host, ':') == s) {
+      *s = 0;
+      af = AF_INET;
+    } else if (s && strchr(host, ':') != s) {
+      af = AF_INET6;
+      s = 0;
+    }
+  }
+
+  if (s++) {
+    char *ss;
+    unsigned long p = strtoul(s, &ss, 0);
+    if (!*s || *ss || p > 65535) error_exit("bad port '%s'", s);
+    port_num = htons(p);
+  }
+
+  memset(&hints, 0 , sizeof(struct addrinfo));
+  hints.ai_family = af;
+  hints.ai_socktype = SOCK_STREAM;
+
+  status = getaddrinfo(host, NULL, &hints, &result);
+  if (status) error_exit("bad address '%s' : %s", host, gai_strerror(status));
+
+  memcpy(buf, result->ai_addr, result->ai_addrlen);
+  freeaddrinfo(result);
+
+  if (af == AF_INET) ((struct sockaddr_in*)buf)->sin_port = port_num;
+  else ((struct sockaddr_in6*)buf)->sin6_port = port_num;
+}
+
+static void utmp_entry(void)
+{               
+  struct utmp entry;
+  struct utmp *utp_ptr;
+  pid_t pid = getpid();
+
+  utmpname(_PATH_UTMP);
+  setutent(); //start from start
+  while ((utp_ptr = getutent()) != NULL) {
+    if (utp_ptr->ut_pid == pid && utp_ptr->ut_type >= INIT_PROCESS) break;
+  }             
+  if (!utp_ptr) entry.ut_type = DEAD_PROCESS;
+  time(&entry.ut_time);  
+  setutent();   
+  pututline(&entry);     
+}
+
+static int listen_socket(void)
+{
+  int s, af = AF_INET, yes = 1;
+  char buf[sizeof(struct sockaddr_storage)];
+
+  memset(buf, 0, sizeof(buf));
+  if (toys.optflags & FLAG_b) {
+    get_sockaddr(TT.host_addr, buf);
+    af = ((struct sockaddr *)buf)->sa_family;
+  } else {
+    ((struct sockaddr_in*)buf)->sin_port = htons(TT.port);
+    ((struct sockaddr_in*)buf)->sin_family = af;
+  }
+  s = xsocket(af, SOCK_STREAM, 0);
+  if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) == -1) 
+    perror_exit("setsockopt");
+
+  if (bind(s, (struct sockaddr *)buf, ((af == AF_INET)?
+          (sizeof(struct sockaddr_in)):(sizeof(struct sockaddr_in6)))) == -1) {
+    close(s);
+    perror_exit("bind");
+  }
+
+  if (listen(s, 1) < 0) perror_exit("listen");
+  return s;
+}
+
+static void write_issue(char *tty)
+{
+  int size;
+  char ch = 0;
+  struct utsname u;
+  int fd = open(TT.issue_path, O_RDONLY);
+
+  if (fd < 0) return ;
+  uname(&u);
+  while ((size = readall(fd, &ch, 1)) > 0) {
+    if (ch == '\\' || ch == '%') {
+      if (readall(fd, &ch, 1) <= 0) perror_exit("readall!");
+      if (ch == 's') fputs(u.sysname, stdout);
+      if (ch == 'n'|| ch == 'h') fputs(u.nodename, stdout);
+      if (ch == 'r') fputs(u.release, stdout);
+      if (ch == 'm') fputs(u.machine, stdout);
+      if (ch == 'l') fputs(tty, stdout);
+    }
+    else if (ch == '\n') {
+      fputs("\n\r\0", stdout);
+    } else fputc(ch, stdout);
+  }
+  fflush(NULL);
+  close(fd);
+}
+
+static int new_session(int sockfd)
+{
+  char *argv_login[2]; //arguments for execvp cmd, NULL
+  char tty_name[30]; //tty name length.
+  int fd, flags, i = 1;
+  char intial_iacs[] = {IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_NAWS,
+    IAC, WILL, TELOPT_ECHO, IAC, WILL, TELOPT_SGA };
+
+  setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i));
+  flags = fcntl(sockfd, F_GETFL);
+  fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+  if (toys.optflags & FLAG_i) fcntl((sockfd + 1), F_SETFL, flags | O_NONBLOCK);
+
+  writeall((toys.optflags & FLAG_i)?1:sockfd, intial_iacs, sizeof(intial_iacs));
+  if ((TT.fork_pid = forkpty(&fd, tty_name, NULL, NULL)) > 0) {
+    flags = fcntl(fd, F_GETFL);
+    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+    return fd;
+  }
+  if (TT.fork_pid < 0) perror_exit("fork");
+  write_issue(tty_name);
+  argv_login[0] = strdup(TT.login_path);
+  argv_login[1] = NULL;
+  execvp(argv_login[0], argv_login);
+  exit(EXIT_FAILURE);
+}
+
+static int handle_iacs(struct term_session *tm, int c, int fd)
+{
+  char *curr ,*start,*end;
+  int i = 0;
+
+  curr = start = tm->buff2+tm->buff2_avail; 
+  end = tm->buff2 + c -1;
+  tm->rem = 0;
+  while (curr <= end) {
+    if (*curr != IAC){
+
+      if (*curr != '\r') {
+        toybuf[i++] = *curr++;
+        continue;
+      } else {
+        toybuf[i++] = *curr++;
+        curr++;
+        if (curr < end && (*curr == '\n' || *curr == '\0')) 
+          curr++;
+        continue;
+      }
+    }
+
+    if ((curr + 1) > end) {
+      tm->rem = 1;
+      break; 
+    }
+    if (*(curr+1) == IAC) { //IAC as data --> IAC IAC
+      toybuf[i++] = *(curr+1);
+      curr += 2; //IAC IAC --> 2 bytes
+      continue;
+    }
+    if (*(curr + 1) == NOP || *(curr + 1) == SE) {
+      curr += 2;
+      continue;
+    }
+
+    if (*(curr + 1) == SB ) {
+      if (*(curr+2) == TELOPT_NAWS) {
+        struct winsize ws;
+        if ((curr+8) >= end) {  //ensure we have data to process.
+          tm->rem = end - curr; 
+          break;  
+        }
+        ws.ws_col = (curr[3] << 8) | curr[4];
+        ws.ws_row = (curr[5] << 8) | curr[6];
+        ioctl(fd, TIOCSWINSZ, (char *)&ws);
+        curr += 9;
+        continue;
+      } else { //eat non-supported sub neg. options.
+        curr++, tm->rem++;
+        while (*curr != IAC && curr <= end) {
+          curr++;
+          tm->rem++;
+        } 
+        if (*curr == IAC) {
+          tm->rem = 0;
+          continue;
+        } else break;
+      }
+    }
+    curr += 3; //skip non-supported 3 bytes.
+  }
+  memcpy(start, toybuf, i);
+  memcpy(start + i, end - tm->rem, tm->rem); //put remaining if we break;
+  return i;
+}
+
+static int dup_iacs(char *start, int fd, int len)
+{
+  char arr[] = {IAC, IAC};
+  char *needle = NULL;
+  int ret = 0, c, count = 0;
+
+  while (len) {
+    if (*start == IAC) {
+      count = writeall(fd, arr, sizeof(arr));
+      if (count != 2) break; //short write
+      start++;
+      ret++;
+      len--;
+      continue;
+    }
+    needle = memchr(start, IAC, len);
+    if (needle) c = needle - start;
+    else c = len;
+    count = writeall(fd, start, c);
+    if (count < 0) break; 
+    len -= count;
+    ret += count;
+    start += count;
+  }
+  return ret;
+}
+
+void telnetd_main(void)
+{
+  errno = 0;
+  fd_set rd, wr;
+  struct term_session *tm = NULL;
+  struct timeval tv, *tv_ptr = NULL;
+  int pty_fd, new_fd, c = 0, w, master_fd = 0;
+  int inetd_m = toys.optflags & FLAG_i;
+
+  if (!(toys.optflags & FLAG_l)) TT.login_path = "/bin/login";
+  if (!(toys.optflags & FLAG_f)) TT.issue_path = "/etc/issue.net";
+  if (toys.optflags & FLAG_w) toys.optflags |= FLAG_F;
+  if (!inetd_m) {
+    master_fd = listen_socket();
+    fcntl(master_fd, F_SETFD, FD_CLOEXEC);
+    if (master_fd > TT.gmax_fd) TT.gmax_fd = master_fd;
+    if (!(toys.optflags & FLAG_F)) daemon(0, 0); 
+  } else {
+    pty_fd = new_session(master_fd); //master_fd = 0
+    if (pty_fd > TT.gmax_fd) TT.gmax_fd = pty_fd;
+    tm = xzalloc(sizeof(struct term_session));
+    tm->child_pid = TT.fork_pid;
+    tm->new_fd = 0;    
+    tm->pty_fd = pty_fd;    
+    if (session_list) {     
+      tm->next = session_list;
+      session_list = tm;    
+    } else session_list = tm;
+  }
+
+  if ((toys.optflags & FLAG_w) && !session_list) {
+    tv.tv_sec = TT.w_sec;
+    tv.tv_usec = 0;
+    tv_ptr = &tv;
+  }                
+  signal(SIGCHLD, generic_signal);
+
+  for (;;) {
+    FD_ZERO(&rd);
+    FD_ZERO(&wr);
+    if (!inetd_m) FD_SET(master_fd, &rd);
+
+    tm = session_list;
+    while (tm) {
+
+      if (tm->pty_fd > 0 && tm->buff1_avail < BUFSIZE) FD_SET(tm->pty_fd, &rd);
+      if (tm->new_fd >= 0 && tm->buff2_avail < BUFSIZE) FD_SET(tm->new_fd, &rd);
+      if (tm->pty_fd > 0 && (tm->buff2_avail - tm->buff2_written) > 0)  
+        FD_SET(tm->pty_fd, &wr);
+      if (tm->new_fd >= 0 && (tm->buff1_avail - tm->buff1_written) > 0)  
+        FD_SET(tm->new_fd, &wr);
+      tm = tm->next;
+    }
+
+
+    int r = select(TT.gmax_fd + 1, &rd, &wr, NULL, tv_ptr);
+    if (!r) return; //timeout
+    if (r < -1) continue;
+
+    if (!inetd_m && FD_ISSET(master_fd, &rd)) { //accept new connection
+      new_fd = accept(master_fd, NULL, NULL);
+      if (new_fd < 0) continue;
+      tv_ptr = NULL;
+      fcntl(new_fd, F_SETFD, FD_CLOEXEC);
+      if (new_fd > TT.gmax_fd) TT.gmax_fd = new_fd;
+      pty_fd = new_session(new_fd);
+      if (pty_fd > TT.gmax_fd) TT.gmax_fd = pty_fd;
+
+      tm = xzalloc(sizeof(struct term_session));
+      tm->child_pid = TT.fork_pid;
+      tm->new_fd = new_fd;
+      tm->pty_fd = pty_fd;
+      if (session_list) {
+        tm->next = session_list;
+        session_list = tm;
+      } else session_list = tm;
+    }
+
+    tm = session_list;
+    for (;tm;tm=tm->next) {
+      if (FD_ISSET(tm->pty_fd, &rd)) {
+        if ((c = read(tm->pty_fd, tm->buff1 + tm->buff1_avail,
+                BUFSIZE-tm->buff1_avail)) <= 0) break;
+        tm->buff1_avail += c;
+        if ((w = dup_iacs(tm->buff1 + tm->buff1_written, tm->new_fd + inetd_m,
+                tm->buff1_avail - tm->buff1_written)) < 0) break;
+        tm->buff1_written += w;
+      }
+      if (FD_ISSET(tm->new_fd, &rd)) {
+        if ((c = read(tm->new_fd, tm->buff2+tm->buff2_avail,
+                BUFSIZE-tm->buff2_avail)) <= 0) break;
+        c = handle_iacs(tm, c, tm->pty_fd);
+        tm->buff2_avail += c;
+        if ((w = write(tm->pty_fd, tm->buff2+ tm->buff2_written, 
+                tm->buff2_avail - tm->buff2_written)) < 0) break;
+        tm->buff2_written += w;
+      }
+      if (FD_ISSET(tm->pty_fd, &wr)) {
+        if ((w = write(tm->pty_fd,  tm->buff2 + tm->buff2_written, 
+                tm->buff2_avail - tm->buff2_written)) < 0) break;
+        tm->buff2_written += w;
+      }
+      if (FD_ISSET(tm->new_fd, &wr)) {
+        if ((w = dup_iacs(tm->buff1 + tm->buff1_written, tm->new_fd + inetd_m,
+                tm->buff1_avail - tm->buff1_written)) < 0) break;
+        tm->buff1_written += w;
+      }
+      if (tm->buff1_written == tm->buff1_avail)
+        tm->buff1_written = tm->buff1_avail = 0;
+      if (tm->buff2_written == tm->buff2_avail)
+        tm->buff2_written = tm->buff2_avail = 0;
+      fflush(NULL);
+    }
+
+    // Loop to handle (unknown number of) SIGCHLD notifications
+    while (toys.signal) {
+      int status;
+      struct term_session *prev = NULL;
+      pid_t pid;
+
+      // funny little dance to avoid race conditions.
+      toys.signal = 0;
+      pid = waitpid(-1, &status, WNOHANG);
+      if (pid < 0) break;
+      toys.signal++;
+
+
+      for (tm = session_list; tm; tm = tm->next) {
+        if (tm->child_pid == pid) break;
+        prev = tm;
+      }
+      if (!tm) return; // reparented child we don't care about
+
+      if (toys.optflags & FLAG_i) exit(EXIT_SUCCESS);
+      if (!prev) session_list = session_list->next;
+      else prev->next = tm->next;
+      utmp_entry();
+      xclose(tm->pty_fd);
+      xclose(tm->new_fd);
+      free(tm);
+    }
+  }
+}
diff --git a/toybox/toys/pending/test.c b/toybox/toys/pending/test.c
new file mode 100644
index 0000000..c03e450
--- /dev/null
+++ b/toybox/toys/pending/test.c
@@ -0,0 +1,114 @@
+/* test.c - evaluate expression
+ *
+ * Copyright 2013 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
+
+USE_TEST(NEWTOY(test, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config TEST
+  bool "test"
+  default n
+  help
+    usage: test [-bcdefghLPrSsuwx PATH] [-nz STRING] [-t FD] [X ?? Y]
+
+    Return true or false by performing tests. (With no arguments return false.)
+
+    --- Tests with a single argument (after the option):
+    PATH is/has:
+      -b  block device   -f  regular file   -p  fifo           -u  setuid bit
+      -c  char device    -g  setgid         -r  read bit       -w  write bit
+      -d  directory      -h  symlink        -S  socket         -x  execute bit
+      -e  exists         -L  symlink        -s  nonzero size
+    STRING is:
+      -n  nonzero size   -z  zero size      (STRING by itself implies -n)
+    FD (integer file descriptor) is:
+      -t  a TTY
+
+    --- Tests with one argument on each side of an operator:
+    Two strings:
+      =  are identical	 !=  differ
+    Two integers:
+      -eq  equal         -gt  first > second    -lt  first < second
+      -ne  not equal     -ge  first >= second   -le  first <= second
+
+    --- Modify or combine tests:
+      ! EXPR     not (swap true/false)   EXPR -a EXPR    and (are both true)
+      ( EXPR )   evaluate this first     EXPR -o EXPR    or (is either true)
+*/
+
+#include "toys.h"
+
+void test_main(void)
+{
+  int id, not;
+  char *s, *err_fmt = "Bad flag '%s'";
+
+  toys.exitval = 2;
+  if (!strcmp("[", toys.which->name))
+    if (!strcmp("]", toys.optargs[--toys.optc])) error_exit("Missing ']'");
+  if (!strcmp("!", toys.optargs[0])) {
+    not = 1;
+    toys.optargs++;
+    toys.optc--;
+  }
+  if (!toys.optc) toys.exitval = 0;
+  else if (toys.optargs[0][0] == '-') {
+    id = stridx("bcdefghLpSsurwxznt", toys.optargs[0][1]);
+    if (id == -1 || toys.optargs[0][2]) error_exit(err_fmt, toys.optargs[0]);
+    if (id < 12) {
+      struct stat st;
+      int nolink;
+
+      toys.exitval = 1;
+      if (lstat(toys.optargs[1], &st) == -1) return;
+      nolink = !S_ISLNK(st.st_mode);
+      if (!nolink && (stat(toys.optargs[1], &st) == -1)) return;
+
+      if (id == 0) toys.exitval = !S_ISBLK(st.st_mode); // b
+      else if (id == 1) toys.exitval = !S_ISCHR(st.st_mode); // c
+      else if (id == 2) toys.exitval = !S_ISDIR(st.st_mode); // d
+      else if (id == 3) toys.exitval = 0; // e
+      else if (id == 4) toys.exitval = !S_ISREG(st.st_mode); // f
+      else if (id == 5) toys.exitval = !(st.st_mode & S_ISGID); // g
+      else if ((id == 6) || (id == 7)) toys.exitval = nolink; // hL
+      else if (id == 8) toys.exitval = !S_ISFIFO(st.st_mode); // p
+      else if (id == 9) toys.exitval = !S_ISSOCK(st.st_mode); // S
+      else if (id == 10) toys.exitval = st.st_size == 0; // s
+      else toys.exitval = !(st.st_mode & S_ISUID); // u
+    }
+    else if (id < 15) // rwx
+      toys.exitval = access(toys.optargs[1], 1 << (id - 12)) == -1;
+    else if (id < 17) // zn
+      toys.exitval = toys.optargs[1] && !*toys.optargs[1] ^ (id - 15);
+    else { // t
+      struct termios termios;
+      toys.exitval = tcgetattr(atoi(toys.optargs[1]), &termios) == -1;
+    }
+  }
+  else if (toys.optc == 1) toys.exitval = *toys.optargs[0] == 0;
+  else if (toys.optc == 3) {
+    if (*toys.optargs[1] == '-') {
+      long a = atol(toys.optargs[0]), b = atol(toys.optargs[2]);
+      
+      s = toys.optargs[1] + 1;
+      if (!strcmp("eq", s)) toys.exitval = a != b;
+      else if (!strcmp("ne", s)) toys.exitval = a == b;
+      else if (!strcmp("gt", s)) toys.exitval = a < b;
+      else if (!strcmp("ge", s)) toys.exitval = a <= b;
+      else if (!strcmp("lt", s)) toys.exitval = a > b;
+      else if (!strcmp("le", s)) toys.exitval = a >= b;
+      else error_exit(err_fmt, toys.optargs[1]);
+    }
+    else {
+      int result = strcmp(toys.optargs[0], toys.optargs[2]);
+
+      s = toys.optargs[1];
+      if (!strcmp("=", s)) toys.exitval = !!result;
+      else if (!strcmp("!=", s)) toys.exitval = !result;
+      else error_exit(err_fmt, toys.optargs[1]);
+    }
+  }
+  toys.exitval ^= not;
+  return;
+}
diff --git a/toybox/toys/pending/tftp.c b/toybox/toys/pending/tftp.c
new file mode 100644
index 0000000..1c6fe9e
--- /dev/null
+++ b/toybox/toys/pending/tftp.c
@@ -0,0 +1,454 @@
+/* tftp.c - TFTP client.
+ *
+ * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
+ * Copyright 2015 Sameer Prakash Pradhan <sameer.p.pradhan@gmail.com>
+ *
+ * No Standard.
+
+USE_TFTP(NEWTOY(tftp, "<1b#<8>65464r:l:g|p|[!gp]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config TFTP
+  bool "tftp"
+  default n
+  help
+    usage: tftp [OPTIONS] HOST [PORT]
+
+    Transfer file from/to tftp server.
+
+    -l FILE Local FILE
+    -r FILE Remote FILE
+    -g    Get file
+    -p    Put file
+    -b SIZE Transfer blocks of SIZE octets(8 <= SIZE <= 65464)
+*/
+#define FOR_tftp
+#include "toys.h"
+
+GLOBALS(
+  char *local_file;
+  char *remote_file;
+  long block_size;
+
+  struct sockaddr_storage inaddr;
+  int af;
+)
+
+#define TFTP_BLKSIZE    512
+#define TFTP_RETRIES    3
+#define TFTP_DATAHEADERSIZE 4
+#define TFTP_MAXPACKETSIZE  (TFTP_DATAHEADERSIZE + TFTP_BLKSIZE)
+#define TFTP_PACKETSIZE    TFTP_MAXPACKETSIZE
+#define TFTP_DATASIZE    (TFTP_PACKETSIZE-TFTP_DATAHEADERSIZE)
+#define TFTP_IOBUFSIZE    (TFTP_PACKETSIZE+8)
+
+#define TFTP_OP_RRQ      1  /* Read Request      RFC 1350, RFC 2090 */
+#define TFTP_OP_WRQ      2  /* Write Request     RFC 1350 */
+#define TFTP_OP_DATA    3  /* Data chunk      RFC 1350 */
+#define TFTP_OP_ACK      4  /* Acknowledgement     RFC 1350 */
+#define TFTP_OP_ERR      5  /* Error Message     RFC 1350 */
+#define TFTP_OP_OACK    6  /* Option acknowledgment RFC 2347 */
+
+#define TFTP_ER_ILLEGALOP  4  /* Illegal TFTP operation */
+#define TFTP_ER_UNKID    5  /* Unknown transfer ID */
+
+#define TFTP_ES_NOSUCHFILE  "File not found"
+#define TFTP_ES_ACCESS    "Access violation"
+#define TFTP_ES_FULL    "Disk full or allocation exceeded"
+#define TFTP_ES_ILLEGALOP  "Illegal TFTP operation"
+#define TFTP_ES_UNKID    "Unknown transfer ID"
+#define TFTP_ES_EXISTS    "File already exists"
+#define TFTP_ES_UNKUSER    "No such user"
+#define TFTP_ES_NEGOTIATE  "Terminate transfer due to option negotiation"
+
+// Initializes SERVER with ADDR and returns socket.
+static int init_tftp(struct sockaddr_storage *server)
+{
+  struct timeval to = { .tv_sec = 10, //Time out
+                        .tv_usec = 0 };
+  const int set = 1;
+  int port = 69, sd = xsocket(TT.af, SOCK_DGRAM, IPPROTO_UDP);
+
+  xsetsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (void *)&to, sizeof(struct timeval));
+  xsetsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *)&set, sizeof(set));
+
+  if(toys.optc == 2) port = atolx_range(toys.optargs[1], 1, 65535);
+  memset(server, 0, sizeof(struct sockaddr_storage));
+  if (TT.af == AF_INET6) {
+      ((struct sockaddr_in6 *)server)->sin6_family = AF_INET6;
+      ((struct sockaddr_in6 *)server)->sin6_addr =
+        ((struct sockaddr_in6 *)&TT.inaddr)->sin6_addr;
+      ((struct sockaddr_in6 *)server)->sin6_port = htons(port);
+  }
+  else {
+      ((struct sockaddr_in *)server)->sin_family = AF_INET;
+      ((struct sockaddr_in *)server)->sin_addr.s_addr =
+        ((struct sockaddr_in *)&TT.inaddr)->sin_addr.s_addr;
+      ((struct sockaddr_in *)server)->sin_port = htons(port);
+  }
+  return sd;
+}
+
+/*
+ * Makes a request packet in BUFFER with OPCODE and file PATH of MODE
+ * and returns length of packet.
+ */
+static int mkpkt_request(uint8_t *buffer, int opcode, char *path, int mode)
+{
+  buffer[0] = opcode >> 8;
+  buffer[1] = opcode & 0xff;
+  if(strlen(path) > TFTP_BLKSIZE) error_exit("path too long");
+  return sprintf((char*) &buffer[2], "%s%c%s", path, 0, 
+    (mode ? "octet" : "netascii")) + 3;
+}
+
+/*
+ * Makes an acknowledgement packet in BUFFER of BLOCNO
+ * and returns packet length.
+ */
+static int mkpkt_ack(uint8_t *buffer, uint16_t blockno)
+{
+  buffer[0] = TFTP_OP_ACK >> 8;
+  buffer[1] = TFTP_OP_ACK & 0xff;
+  buffer[2] = blockno >> 8;
+  buffer[3] = blockno & 0xff;
+  return 4;
+}
+
+/*
+ * Makes an error packet in BUFFER with ERRORCODE and ERRORMSG.
+ * and returns packet length.
+ */
+static int mkpkt_err(uint8_t *buffer, uint16_t errorcode, char *errormsg)
+{
+  buffer[0] = TFTP_OP_ERR >> 8;
+  buffer[1] = TFTP_OP_ERR & 0xff;
+  buffer[2] = errorcode >> 8;
+  buffer[3] = errorcode & 0xff;
+  strcpy((char*) &buffer[4], errormsg);
+  return strlen(errormsg) + 5;
+}
+
+/*
+ * Recieves data from server in BUFF with socket SD and updates FROM
+ * and returns read length.
+ */
+static ssize_t read_server(int sd, void *buf, size_t len,
+  struct sockaddr_storage *from)
+{
+  socklen_t alen;
+  ssize_t nb;
+  
+  for (;;) {
+    memset(buf, 0, len);
+    alen = sizeof(struct sockaddr_storage);
+    nb = recvfrom(sd, buf, len, 0, (struct sockaddr *) from, &alen);
+    if (nb < 0) {
+      if (errno == EAGAIN) {
+        perror_msg("server read timed out");
+        return nb;
+      }else if (errno != EINTR) {
+        perror_msg("server read failed");
+        return nb;
+      }
+    }else return nb;
+  }
+  return nb;
+}
+
+/*
+ * sends data to server TO from BUFF of length LEN through socket SD
+ * and returns successfully send bytes number.
+ */
+static ssize_t write_server(int sd, void *buf, size_t len,
+  struct sockaddr_storage *to)
+{
+  ssize_t nb;
+  
+  for (;;) {
+    nb = sendto(sd, buf, len, 0, (struct sockaddr *)to,
+            sizeof(struct sockaddr_storage));
+    if (nb < 0) {
+      if (errno != EINTR) {
+        perror_msg("server write failed");
+        return nb;
+      }
+    } else return nb;
+  }
+  return nb;
+}
+
+// checks packet for data and updates block no
+static inline int check_data( uint8_t *packet, uint16_t *opcode, 
+  uint16_t *blockno)
+{
+  *opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1];
+  if (*opcode == TFTP_OP_DATA) {
+    *blockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3];
+    return 0;
+  }
+  return -1;
+}
+
+// Makes data packet through FD from file OFFSET in buffer PACKET of BLOCKNO
+static int mkpkt_data(int fd, off_t offset, uint8_t *packet, uint16_t blockno)
+{
+  off_t tmp;
+  int nbytesread;
+
+  packet[0] = TFTP_OP_DATA >> 8;
+  packet[1] = TFTP_OP_DATA & 0xff;
+  packet[2] = blockno >> 8;
+  packet[3] = blockno & 0xff;
+  tmp = lseek(fd, offset, SEEK_SET);
+  if (tmp == (off_t) -1) {
+    perror_msg("lseek failed");
+    return -1;
+  }
+  nbytesread = readall(fd, &packet[TFTP_DATAHEADERSIZE], TFTP_DATASIZE);
+  if (nbytesread < 0) return -1;
+  return nbytesread + TFTP_DATAHEADERSIZE;
+}
+
+// Receives ACK responses from server and updates blockno
+static int read_ack(int sd, uint8_t *packet, struct sockaddr_storage *server,
+  uint16_t *port, uint16_t *blockno)
+{
+  struct sockaddr_storage from;
+  ssize_t nbytes;
+  uint16_t opcode, rblockno;
+  int packetlen, retry;
+
+  for (retry = 0; retry < TFTP_RETRIES; retry++) {
+    for (;;) {
+      nbytes = read_server(sd, packet, TFTP_IOBUFSIZE, &from);
+      if (nbytes < 4) { // Ack headersize = 4
+        if (nbytes == 0) error_msg("Connection lost.");
+        else if (nbytes > 0) error_msg("Short packet: %d bytes", nbytes);
+        else error_msg("Server read ACK failure.");
+        break;
+      } else {
+        if (!*port) {
+          *port = ((struct sockaddr_in *)&from)->sin_port;
+          ((struct sockaddr_in *)server)->sin_port =
+                  ((struct sockaddr_in *)&from)->sin_port;
+        }
+        if (((struct sockaddr_in *)server)->sin_addr.s_addr !=
+                ((struct sockaddr_in *)&from)->sin_addr.s_addr) {
+          error_msg("Invalid address in DATA.");
+          continue;
+        }
+        if (*port != ((struct sockaddr_in *)server)->sin_port) {
+          error_msg("Invalid port in DATA.");
+          packetlen = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID);
+          (void) write_server(sd, packet, packetlen, server);
+          continue;
+        }
+        opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1];
+        rblockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3];
+
+        if (opcode != TFTP_OP_ACK) {
+          error_msg("Bad opcode.");
+          if (opcode > 5) {
+            packetlen = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP);
+            (void) write_server(sd, packet, packetlen, server);
+          }
+          break;
+        }
+        if (blockno) *blockno = rblockno;
+        return 0;
+      }
+    }
+  }
+  error_msg("Timeout, Waiting for ACK.");
+  return -1;
+}
+
+// receives file from server.
+static int file_get(void)
+{
+  struct sockaddr_storage server, from;
+  uint8_t *packet;
+  uint16_t blockno = 0, opcode, rblockno = 0;
+  int len, sd, fd, retry, nbytesrecvd = 0, ndatabytes, ret, result = -1;
+
+  sd = init_tftp(&server);
+
+  packet = (uint8_t*) xzalloc(TFTP_IOBUFSIZE);
+  fd = xcreate(TT.local_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+  len = mkpkt_request(packet, TFTP_OP_RRQ, TT.remote_file, 1);
+  ret = write_server(sd, packet, len, &server);
+  if (ret != len){
+    unlink(TT.local_file);
+    goto errout_with_sd;
+  }
+  if (TT.af == AF_INET6) ((struct sockaddr_in6 *)&server)->sin6_port = 0;
+  else ((struct sockaddr_in *)&server)->sin_port = 0;
+
+  do {
+    blockno++;
+    for (retry = 0 ; retry < TFTP_RETRIES; retry++) {
+      nbytesrecvd = read_server(sd, packet, TFTP_IOBUFSIZE, &from);
+      if (nbytesrecvd > 0) {
+        if ( ((TT.af == AF_INET) &&
+                memcmp(&((struct sockaddr_in *)&server)->sin_addr,
+                &((struct sockaddr_in *)&from)->sin_addr,
+                sizeof(struct in_addr))) ||
+             ((TT.af == AF_INET6) &&
+                memcmp(&((struct sockaddr_in6 *)&server)->sin6_addr,
+                &((struct sockaddr_in6 *)&from)->sin6_addr,
+                sizeof(struct in6_addr)))) {
+          error_msg("Invalid address in DATA.");
+          retry--;
+          continue;
+        }
+        if ( ((TT.af == AF_INET) && ((struct sockaddr_in *)&server)->sin_port
+                && (((struct sockaddr_in *)&server)->sin_port !=
+                ((struct sockaddr_in *)&from)->sin_port)) ||
+             ((TT.af == AF_INET6) && ((struct sockaddr_in6 *)&server)->sin6_port
+                && (((struct sockaddr_in6 *)&server)->sin6_port !=
+                ((struct sockaddr_in6 *)&from)->sin6_port))) {
+          error_msg("Invalid port in DATA.");
+          len = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID);
+          ret = write_server(sd, packet, len, &from);
+          retry--;
+          continue;
+        }
+        if (nbytesrecvd < TFTP_DATAHEADERSIZE) {
+          error_msg("Tiny data packet ignored.");
+          continue;
+        }
+        if (check_data(packet, &opcode, &rblockno) != 0
+            || blockno != rblockno) {
+
+        if (opcode == TFTP_OP_ERR) {
+          char *message = "DATA Check failure.";
+            char *arr[] = {TFTP_ES_NOSUCHFILE, TFTP_ES_ACCESS,
+              TFTP_ES_FULL, TFTP_ES_ILLEGALOP,
+              TFTP_ES_UNKID, TFTP_ES_EXISTS,
+              TFTP_ES_UNKUSER, TFTP_ES_NEGOTIATE};
+            if (rblockno && (rblockno < 9)) message = arr[rblockno - 1];
+            error_msg(message);
+        }
+        if (opcode > 5) {
+          len = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP);
+          ret = write_server(sd, packet, len, &from);
+        }
+        continue;
+        }
+        if ((TT.af == AF_INET6) && !((struct sockaddr_in6 *)&server)->sin6_port)
+          ((struct sockaddr_in6 *)&server)->sin6_port =
+            ((struct sockaddr_in6 *)&from)->sin6_port;
+        else if ((TT.af == AF_INET) && !((struct sockaddr_in *)&server)->sin_port)
+          ((struct sockaddr_in *)&server)->sin_port =
+            ((struct sockaddr_in *)&from)->sin_port;
+        break;
+      }
+    }
+    if (retry == TFTP_RETRIES) {
+      error_msg("Retry limit exceeded.");
+      unlink(TT.local_file);
+      goto errout_with_sd;
+    }
+    ndatabytes = nbytesrecvd - TFTP_DATAHEADERSIZE;
+    if (writeall(fd, packet + TFTP_DATAHEADERSIZE, ndatabytes) < 0){
+      unlink(TT.local_file);
+      goto errout_with_sd;
+    }
+    len = mkpkt_ack(packet, blockno);
+    ret = write_server(sd, packet, len, &server);
+    if (ret != len){
+      unlink(TT.local_file);
+      goto errout_with_sd;
+    }
+  } while (ndatabytes >= TFTP_DATASIZE);
+
+  result = 0;
+
+errout_with_sd: xclose(sd);
+  free(packet);
+  return result;
+}
+
+// Sends file to server.
+int file_put(void)
+{
+  struct sockaddr_storage server;
+  uint8_t *packet;
+  off_t offset = 0;
+  uint16_t blockno = 1, rblockno, port = 0;
+  int packetlen, sd, fd, retry = 0, ret, result = -1;
+
+  sd = init_tftp(&server);
+  packet = (uint8_t*)xzalloc(TFTP_IOBUFSIZE);
+  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);
+    ret = write_server(sd, packet, packetlen, &server);
+    if (ret != packetlen) goto errout_with_sd;
+    if (read_ack(sd, packet, &server, &port, NULL) == 0) break;
+    if (++retry > TFTP_RETRIES) {
+      error_msg("Retry count exceeded.");
+      goto errout_with_sd;
+    }
+  }
+  for (;;) {  // loop for data sending and receving ack from server.
+    packetlen = mkpkt_data(fd, offset, packet, blockno);
+    if (packetlen < 0) goto errout_with_sd;
+
+    ret = write_server(sd, packet, packetlen, &server);
+    if (ret != packetlen) goto errout_with_sd;
+
+    if (read_ack(sd, packet, &server, &port, &rblockno) == 0) {
+      if (rblockno == blockno) {
+        if (packetlen < TFTP_PACKETSIZE) break;
+        blockno++;
+        offset += TFTP_DATASIZE;
+        retry = 0;
+        continue;
+      }
+    }
+    if (++retry > TFTP_RETRIES) {
+      error_msg("Retry count exceeded.");
+      goto errout_with_sd;
+    }
+  }
+  result = 0;
+
+errout_with_sd: close(sd);
+  free(packet);
+  return result;
+}
+
+void tftp_main(void)
+{
+  struct addrinfo *info, rp, *res=0;
+  int ret;
+
+  if (toys.optflags & FLAG_r) {
+    if (!(toys.optflags & FLAG_l)) {
+      char *slash = strrchr(TT.remote_file, '/');
+      TT.local_file = (slash) ? slash + 1 : TT.remote_file;
+    }
+  } else if (toys.optflags & FLAG_l) TT.remote_file = TT.local_file;
+  else error_exit("Please provide some files.");
+
+  memset(&rp, 0, sizeof(rp));
+  rp.ai_family = AF_UNSPEC;
+  rp.ai_socktype = SOCK_STREAM;
+  ret = getaddrinfo(toys.optargs[0], toys.optargs[1], &rp, &info);
+  if (!ret) {
+    for (res = info; res; res = res->ai_next)
+    if ( (res->ai_family == AF_INET) || (res->ai_family == AF_INET6)) break;
+  }
+  if (!res)
+    error_exit("bad address '%s' : %s", toys.optargs[0], gai_strerror(ret));
+  TT.af = info->ai_family;
+
+  memcpy((void *)&TT.inaddr, info->ai_addr, info->ai_addrlen);
+  freeaddrinfo(info);
+
+  if (toys.optflags & FLAG_g) file_get();
+  if (toys.optflags & FLAG_p) file_put();
+}
diff --git a/toybox/toys/pending/tftpd.c b/toybox/toys/pending/tftpd.c
new file mode 100644
index 0000000..806326e
--- /dev/null
+++ b/toybox/toys/pending/tftpd.c
@@ -0,0 +1,309 @@
+/* tftpd.c - TFTP server.
+ *
+ * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_TFTPD(NEWTOY(tftpd, "rcu:l", TOYFLAG_BIN))
+
+config TFTPD
+  bool "tftpd"
+  default n
+  help
+    usage: tftpd [-cr] [-u USER] [DIR]
+
+    Transfer file from/to tftp server.
+
+    -r	read only
+    -c	Allow file creation via upload
+    -u	run as USER
+    -l	Log to syslog (inetd mode requires this)
+*/
+
+#define FOR_tftpd
+#include "toys.h"
+
+GLOBALS(
+  char *user;
+
+  long sfd;
+  struct passwd *pw;
+)
+
+#define TFTPD_BLKSIZE 512  // as per RFC 1350.
+
+// opcodes
+#define TFTPD_OP_RRQ  1  // Read Request          RFC 1350, RFC 2090
+#define TFTPD_OP_WRQ  2  // Write Request         RFC 1350
+#define TFTPD_OP_DATA 3  // Data chunk            RFC 1350
+#define TFTPD_OP_ACK  4  // Acknowledgement       RFC 1350
+#define TFTPD_OP_ERR  5  // Error Message         RFC 1350
+#define TFTPD_OP_OACK 6  // Option acknowledgment RFC 2347
+
+// Error Codes:
+#define TFTPD_ER_NOSUCHFILE  1 // File not found
+#define TFTPD_ER_ACCESS      2 // Access violation
+#define TFTPD_ER_FULL        3 // Disk full or allocation exceeded
+#define TFTPD_ER_ILLEGALOP   4 // Illegal TFTP operation
+#define TFTPD_ER_UNKID       5 // Unknown transfer ID
+#define TFTPD_ER_EXISTS      6 // File already exists
+#define TFTPD_ER_UNKUSER     7 // No such user
+#define TFTPD_ER_NEGOTIATE   8 // Terminate transfer due to option negotiation
+
+/* TFTP Packet Formats
+ *  Type   Op #     Format without header
+ *         2 bytes    string    1 byte    string    1 byte
+ *         -----------------------------------------------
+ *  RRQ/  | 01/02 |  Filename  |   0  |    Mode    |   0  |
+ *  WRQ    -----------------------------------------------
+ *         2 bytes    2 bytes      n bytes
+ *         ---------------------------------
+ *  DATA  | 03    |   Block #  |    Data    |
+ *         ---------------------------------
+ *         2 bytes    2 bytes
+ *         -------------------
+ *  ACK   | 04    |   Block #  |
+ *         --------------------
+ *         2 bytes  2 bytes       string     1 byte
+ *         ----------------------------------------
+ *  ERROR | 05    |  ErrorCode |   ErrMsg   |   0  |
+ *         ----------------------------------------
+ */
+
+static char *g_errpkt = toybuf + TFTPD_BLKSIZE;
+
+// Create and send error packet.
+static void send_errpkt(struct sockaddr *dstaddr,
+    socklen_t socklen, char *errmsg)
+{
+  error_msg(errmsg);
+  g_errpkt[1] = TFTPD_OP_ERR;
+  strcpy(g_errpkt + 4, errmsg);
+  if (sendto(TT.sfd, g_errpkt, strlen(errmsg)+5, 0, dstaddr, socklen) < 0)
+    perror_exit("sendto failed");
+}
+
+// Used to send / receive packets.
+static void do_action(struct sockaddr *srcaddr, struct sockaddr *dstaddr,
+    socklen_t socklen, char *file, int opcode, int tsize, int blksize)
+{
+  int fd, done = 0, retry_count = 12, timeout = 100, len;
+  uint16_t blockno = 1, pktopcode, rblockno;
+  char *ptr, *spkt, *rpkt;
+  struct pollfd pollfds[1];
+
+  spkt = xzalloc(blksize + 4);
+  rpkt = xzalloc(blksize + 4);
+  ptr = spkt+2; //point after opcode.
+
+  pollfds[0].fd = TT.sfd;
+  // initialize groups, setgid and setuid
+  if (TT.pw) xsetuser(TT.pw);
+
+  if (opcode == TFTPD_OP_RRQ) fd = open(file, O_RDONLY, 0666);
+  else fd = open(file, ((toys.optflags & FLAG_c) ?
+        (O_WRONLY|O_TRUNC|O_CREAT) : (O_WRONLY|O_TRUNC)) , 0666);
+  if (fd < 0) {
+    g_errpkt[3] = TFTPD_ER_NOSUCHFILE;
+    send_errpkt(dstaddr, socklen, "can't open file");
+    goto CLEAN_APP;
+  }
+  // For download -> blockno will be 1.
+  // 1st ACK will be from dst,which will have blockno-=1
+  // Create and send ACK packet.
+  if (blksize != TFTPD_BLKSIZE || tsize) {
+    pktopcode = TFTPD_OP_OACK;
+    // add "blksize\000blksize_val\000" in send buffer.
+    if (blksize != TFTPD_BLKSIZE) {
+      strcpy(ptr, "blksize");
+      ptr += strlen("blksize") + 1;
+      ptr += snprintf(ptr, 6, "%d", blksize) + 1;
+    }
+    if (tsize) {// add "tsize\000tsize_val\000" in send buffer.
+      struct stat sb;
+
+      sb.st_size = 0;
+      fstat(fd, &sb);
+      strcpy(ptr, "tsize");
+      ptr += strlen("tsize") + 1;
+      ptr += sprintf(ptr, "%lu", (unsigned long)sb.st_size)+1;
+    }
+    goto SEND_PKT;
+  }
+  // upload ->  ACK 1st packet with filename, as it has blockno 0.
+  if (opcode == TFTPD_OP_WRQ) blockno = 0;
+
+  // Prepare DATA and/or ACK pkt and send it.
+  for (;;) {
+    int poll_ret;
+
+    retry_count = 12, timeout = 100, pktopcode = TFTPD_OP_ACK;
+    ptr = spkt+2;
+    *((uint16_t*)ptr) = htons(blockno);
+    blockno++;
+    ptr += 2;
+    if (opcode == TFTPD_OP_RRQ) {
+      pktopcode = TFTPD_OP_DATA;
+      len = readall(fd, ptr, blksize);
+      if (len < 0) {
+        send_errpkt(dstaddr, socklen, "read-error");
+        break;
+      }
+      if (len != blksize) done = 1; //last pkt.
+      ptr += len;
+    }
+SEND_PKT:
+    // 1st ACK will be from dst, which will have blockno-=1
+    *((uint16_t*)spkt) = htons(pktopcode); //append send pkt's opcode.
+RETRY_SEND:
+    if (sendto(TT.sfd, spkt, (ptr - spkt), 0, dstaddr, socklen) <0)
+      perror_exit("sendto failed");
+    // if "block size < 512", send ACK and exit.
+    if ((pktopcode == TFTPD_OP_ACK) && done) break;
+
+POLL_INPUT:
+    pollfds[0].events = POLLIN;
+    pollfds[0].fd = TT.sfd;
+    poll_ret = poll(pollfds, 1, timeout);
+    if (poll_ret < 0 && (errno == EINTR || errno == ENOMEM)) goto POLL_INPUT;
+    if (!poll_ret) {
+      if (!--retry_count) {
+        error_msg("timeout");
+        break;
+      }
+      timeout += 150;
+      goto RETRY_SEND;
+    } else if (poll_ret == 1) {
+      len = read(pollfds[0].fd, rpkt, blksize + 4);
+      if (len < 0) {
+        send_errpkt(dstaddr, socklen, "read-error");
+        break;
+      }
+      if (len < 4) goto POLL_INPUT;
+    } else {
+      perror_msg("poll");
+      break;
+    }
+    // Validate receive packet.
+    pktopcode = ntohs(((uint16_t*)rpkt)[0]);
+    rblockno = ntohs(((uint16_t*)rpkt)[1]);
+    if (pktopcode == TFTPD_OP_ERR) {
+      char *message = "DATA Check failure.";
+      char *arr[] = {"File not found", "Access violation",
+        "Disk full or allocation exceeded", "Illegal TFTP operation",
+        "Unknown transfer ID", "File already exists",
+        "No such user", "Terminate transfer due to option negotiation"};
+
+      if (rblockno && (rblockno < 9)) message = arr[rblockno - 1];
+      error_msg(message);
+      break; // Break the for loop.
+    }
+
+    // if download requested by client,
+    // server will send data pkt and will receive ACK pkt from client.
+    if ((opcode == TFTPD_OP_RRQ) && (pktopcode == TFTPD_OP_ACK)) {
+      if (rblockno == (uint16_t) (blockno - 1)) {
+        if (!done) continue; // Send next chunk of data.
+        break;
+      }
+    }
+    
+    // server will receive DATA pkt and write the data.
+    if ((opcode == TFTPD_OP_WRQ) && (pktopcode == TFTPD_OP_DATA)) {
+      if (rblockno == blockno) {
+        int nw = writeall(fd, &rpkt[4], len-4);
+        if (nw != len-4) {
+          g_errpkt[3] = TFTPD_ER_FULL;
+          send_errpkt(dstaddr, socklen, "write error");
+          break;
+        }
+      
+        if (nw != blksize) done = 1;
+      }
+      continue;
+    }
+    goto POLL_INPUT;
+  } // end of loop
+
+CLEAN_APP:
+  if (CFG_TOYBOX_FREE) {
+    free(spkt);
+    free(rpkt);
+    close(fd);
+  }
+}
+
+void tftpd_main(void)
+{
+  int fd = 0, recvmsg_len, rbuflen, opcode, blksize = TFTPD_BLKSIZE, tsize = 0, set =1;
+  struct sockaddr_storage srcaddr, dstaddr;
+  socklen_t socklen = sizeof(struct sockaddr_storage);
+  char *buf = toybuf;
+
+  memset(&srcaddr, 0, sizeof(srcaddr));
+  if (getsockname(0, (struct sockaddr *)&srcaddr, &socklen)) help_exit(0);
+
+  if (TT.user) TT.pw = xgetpwnam(TT.user);
+  if (*toys.optargs) xchroot(*toys.optargs);
+
+  recvmsg_len = recvfrom(fd, toybuf, blksize, 0, (void *)&dstaddr, &socklen);
+
+  TT.sfd = xsocket(dstaddr.ss_family, SOCK_DGRAM, 0);
+  if (setsockopt(TT.sfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&set,
+        sizeof(set)) < 0) perror_exit("setsockopt failed");
+  if (bind(TT.sfd, (void *)&srcaddr, socklen)) perror_exit("bind");
+  if (connect(TT.sfd, (void *)&dstaddr, socklen) < 0)
+    perror_exit("can't connect to remote host");
+  // Error condition.
+  if (recvmsg_len<4 || recvmsg_len>TFTPD_BLKSIZE || toybuf[recvmsg_len-1]) {
+    send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error");
+    return;
+  }
+
+  // request is either upload or Download.
+  opcode = buf[1];
+  if (((opcode != TFTPD_OP_RRQ) && (opcode != TFTPD_OP_WRQ))
+      || ((opcode == TFTPD_OP_WRQ) && (toys.optflags & FLAG_r))) {
+    send_errpkt((struct sockaddr*)&dstaddr, socklen,
+    	(opcode == TFTPD_OP_WRQ) ? "write error" : "packet format error");
+    return;
+  }
+
+  buf += 2;
+  if (*buf == '.' || strstr(buf, "/.")) {
+    send_errpkt((struct sockaddr*)&dstaddr, socklen, "dot in filename");
+    return;
+  }
+
+  buf += strlen(buf) + 1; //1 '\0'.
+  // As per RFC 1350, mode is case in-sensitive.
+  if (buf >= toybuf+recvmsg_len || strcasecmp(buf, "octet")) {
+    send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error");
+    return;
+  }
+
+  //RFC2348. e.g. of size type: "ttype1\0ttype1_val\0...ttypeN\0ttypeN_val\0"
+  buf += strlen(buf) + 1;
+  rbuflen = toybuf + recvmsg_len - buf;
+  if (rbuflen) {
+    int jump = 0, bflag = 0;
+
+    for (; rbuflen; rbuflen -= jump, buf += jump) {
+      if (!bflag && !strcasecmp(buf, "blksize")) { //get blksize
+        errno = 0;
+        blksize = strtoul(buf, NULL, 10);
+        if (errno || blksize > 65564 || blksize < 8) blksize = TFTPD_BLKSIZE;
+        bflag ^= 1;
+      } else if (!tsize && !strcasecmp(buf, "tsize")) tsize ^= 1;
+      
+      jump += strlen(buf) + 1;
+    }
+    tsize &= (opcode == TFTPD_OP_RRQ);
+  }
+
+  //do send / receive file.
+  do_action((struct sockaddr*)&srcaddr, (struct sockaddr*)&dstaddr,
+      socklen, toybuf + 2, opcode, tsize, blksize);
+  if (CFG_TOYBOX_FREE) close(STDIN_FILENO);
+}
diff --git a/toybox/toys/pending/tr.c b/toybox/toys/pending/tr.c
new file mode 100644
index 0000000..9a823f6
--- /dev/null
+++ b/toybox/toys/pending/tr.c
@@ -0,0 +1,268 @@
+/* tr.c - translate or delete characters
+ *
+ * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tr.html
+
+USE_TR(NEWTOY(tr, "^>2<1Ccsd[+cC]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config TR
+  bool "tr"
+  default n
+  help
+    usage: tr [-cds] SET1 [SET2]
+
+    Translate, squeeze, or delete characters from stdin, writing to stdout
+
+    -c/-C  Take complement of SET1
+    -d     Delete input characters coded SET1
+    -s     Squeeze multiple output characters of SET2 into one character
+*/
+
+#define FOR_tr
+#include "toys.h"
+
+GLOBALS(
+  short map[256]; //map of chars
+  int len1, len2;
+)
+
+enum {
+  class_alpha, class_alnum, class_digit,
+  class_lower,class_upper,class_space,class_blank,
+  class_punct,class_cntrl,class_xdigit,class_invalid
+};
+
+static void map_translation(char *set1 , char *set2)
+{
+  int i = TT.len1, k = 0;
+
+  if (toys.optflags & FLAG_d)
+    for (; i; i--, k++) TT.map[set1[k]] = set1[k]|0x100; //set delete bit
+
+  if (toys.optflags & FLAG_s) {
+    for (i = TT.len1, k = 0; i; i--, k++)
+      TT.map[set1[k]] = TT.map[set1[k]]|0x200;
+    for (i = TT.len2, k = 0; i; i--, k++)
+      TT.map[set2[k]] = TT.map[set2[k]]|0x200;
+  }
+  i = k = 0;
+  while (!(toys.optflags & FLAG_d) && set2 && TT.len1--) { //ignore set2 if -d present
+    TT.map[set1[i]] = ((TT.map[set1[i]] & 0xFF00) | set2[k]);
+    if (set2[k + 1]) k++;
+    i++;
+  }
+}
+
+static int handle_escape_char(char **esc_val) //taken from printf
+{
+  char *ptr = *esc_val;
+  int esc_length = 0;
+  unsigned  base = 0, num = 0, result = 0, count = 0;
+
+  if (*ptr == 'x') {
+    ptr++;
+    esc_length++;
+    base = 16;
+  } else if (isdigit(*ptr)) base = 8;
+
+  while (esc_length < 3 && base) {
+    num = tolower(*ptr) - '0';
+    if (num > 10) num += ('0' - 'a' + 10);
+    if (num >= base) {
+      if (base == 16) {
+        esc_length--;
+        if (!esc_length) {// Invalid hex value eg. /xvd, print as it is /xvd
+          result = '\\';
+          ptr--;
+        }
+      }
+      break;
+    }
+    esc_length++;
+    count = result = (count * base) + num;
+    ptr++;
+  }
+  if (base) {
+    ptr--;
+    *esc_val = ptr;
+    return (char)result;
+  } else {
+    switch (*ptr) {
+      case 'n':  result = '\n'; break;
+      case 't':  result = '\t'; break;
+      case 'e':  result = (char)27; break;
+      case 'b':  result = '\b'; break;
+      case 'a':  result = '\a'; break;
+      case 'f':  result = '\f'; break;
+      case 'v':  result = '\v'; break;
+      case 'r':  result = '\r'; break;
+      case '\\': result = '\\'; break;
+      default :
+        result = '\\';
+        ptr--; // Let pointer pointing to / we will increment after returning.
+        break;
+    }
+  }
+  *esc_val = ptr;
+  return (char)result;
+}
+
+static int find_class(char *class_name)
+{
+  int i;
+  static char *class[] = {
+    "[:alpha:]","[:alnum:]","[:digit:]",
+    "[:lower:]","[:upper:]","[:space:]",
+    "[:blank:]","[:punct:]","[:cntrl:]",
+    "[:xdigit:]","NULL"
+  };
+
+  for (i = 0; i != class_invalid; i++) {
+    if (!memcmp(class_name, class[i], (class_name[0] == 'x')?10:9)) break;
+  }
+  return i;
+}
+
+static char *expand_set(char *arg, int *len)
+{
+  int i = 0, j, k, size = 256;
+  char *set = xzalloc(size*sizeof(char));
+
+  while (*arg) {
+
+    if (i >= size) {
+      size += 256;
+      set = xrealloc(set, size);
+    }
+    if (*arg == '\\') {
+      arg++;
+      set[i++] = (int)handle_escape_char(&arg);
+      arg++;
+      continue;
+    }
+    if (arg[1] == '-') {
+      if (arg[2] == '\0') goto save;
+      j = arg[0];
+      k = arg[2];
+      if (j > k) perror_exit("reverse colating order");
+      while (j <= k) set[i++] = j++;
+      arg += 3;
+      continue;
+    }
+    if (arg[0] == '[' && arg[1] == ':') {
+
+      if ((j = find_class(arg)) == class_invalid) goto save;
+
+      if ((j == class_alpha) || (j == class_upper) || (j == class_alnum)) {
+      for (k = 'A'; k <= 'Z'; k++) set[i++] = k;
+      }
+      if ((j == class_alpha) || (j == class_lower) || (j == class_alnum)) {
+        for (k = 'a'; k <= 'z'; k++) set[i++] = k;
+      }
+      if ((j == class_alnum) || (j == class_digit) || (j == class_xdigit)) {
+        for (k = '0'; k <= '9'; k++) set[i++] = k;
+      }
+      if (j == class_space || j == class_blank) {
+        set[i++] = '\t';
+        if (j == class_space) {
+          set[i++] = '\n';
+          set[i++] = '\f';
+          set[i++] = '\r';
+          set[i++] = '\v';
+        }
+        set[i++] = ' ';
+      }
+      if (j == class_punct) {
+        for (k = 0; k <= 255; k++)
+          if (ispunct(k)) set[i++] = k;
+      }
+      if (j == class_cntrl) {
+        for (k = 0; k <= 255; k++)
+          if (iscntrl(k)) set[i++] = k;
+      }
+      if (j == class_xdigit) {
+        for (k = 'A'; k <= 'F'; k++) {
+          set[i + 6] = k | 0x20;
+          set[i++] = k;
+        }
+        i += 6;
+        arg += 10;
+        continue;
+      }
+
+      arg += 9; //never here for class_xdigit.
+      continue;
+    }
+    if (arg[0] == '[' && arg[1] == '=') { //[=char=] only
+      arg += 2;
+      if (*arg) set[i++] = *arg;
+      if (!arg[1] || arg[1] != '=' || arg[2] != ']')
+        error_exit("bad equiv class");
+      continue;
+    }
+save:
+    set[i++] = *arg++;
+  }
+  *len = i;
+  return set;
+}
+
+static void print_map(char *set1, char *set2)
+{
+  int r = 0, i, prev_char = -1;
+
+  while (1)
+  {
+    i = 0;
+    r = read(STDIN_FILENO, (toybuf), sizeof(toybuf));
+    if (!r) break;
+    for (;r > i;i++) {
+
+      if ((toys.optflags & FLAG_d) && (TT.map[(int)toybuf[i]] & 0x100)) continue;
+      if (toys.optflags & FLAG_s) {
+        if ((TT.map[(int)toybuf[i]] & 0x200) &&
+            (prev_char == TT.map[(int)toybuf[i]])) {
+          continue;
+        }
+      }
+      xputc(TT.map[(int)toybuf[i]] & 0xFF);
+      prev_char = TT.map[(int)toybuf[i]];
+      fflush(stdout);
+    }
+  }
+}
+
+static void do_complement(char **set)
+{
+  int i, j;
+  char *comp = xmalloc(256);
+
+  for (i = 0, j = 0;i < 256; i++) {
+    if (memchr(*set, i, TT.len1)) continue;
+    else comp[j++] = (char)i;
+  }
+  free(*set);
+  TT.len1 = j;
+  *set = comp;
+}
+
+void tr_main(void)
+{
+  char *set1, *set2 = NULL;
+  int i;
+
+  for (i = 0; i < 256; i++) TT.map[i] = i; //init map
+
+  set1 = expand_set(toys.optargs[0], &TT.len1);
+  if (toys.optflags & FLAG_c) do_complement(&set1);
+  if (toys.optargs[1]) {
+    if (toys.optargs[1][0] == '\0') error_exit("set2 can't be empty string");
+    set2 = expand_set(toys.optargs[1], &TT.len2);
+  }
+  map_translation(set1, set2);
+
+  print_map(set1, set2);
+  free(set1);
+  free(set2);
+}
diff --git a/toybox/toys/pending/traceroute.c b/toybox/toys/pending/traceroute.c
new file mode 100644
index 0000000..9a818eb
--- /dev/null
+++ b/toybox/toys/pending/traceroute.c
@@ -0,0 +1,641 @@
+/* traceroute - trace the route to "host".
+ *
+ * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ * Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com>
+ * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ *
+ * No Standard
+
+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))
+config TRACEROUTE
+  bool "traceroute"
+  default n
+  help
+    usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]
+    [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES]
+    
+    traceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC] 
+      [-i IFACE] HOST [BYTES]
+
+    Trace the route to HOST
+
+    -4,-6 Force IP or IPv6 name resolution 
+    -F    Set the don't fragment bit (supports IPV4 only)
+    -U    Use UDP datagrams instead of ICMP ECHO (supports IPV4 only)
+    -I    Use ICMP ECHO instead of UDP datagrams (supports IPV4 only)
+    -l    Display the TTL value of the returned packet (supports IPV4 only)
+    -d    Set SO_DEBUG options to socket
+    -n    Print numeric addresses
+    -v    verbose
+    -r    Bypass routing tables, send directly to HOST
+    -m    Max time-to-live (max number of hops)(RANGE 1 to 255)
+    -p    Base UDP port number used in probes(default 33434)(RANGE 1 to 65535)
+    -q    Number of probes per TTL (default 3)(RANGE 1 to 255)
+    -s    IP address to use as the source address
+    -t    Type-of-service in probe packets (default 0)(RANGE 0 to 255)
+    -w    Time in seconds to wait for a response (default 3)(RANGE 0 to 86400)
+    -g    Loose source route gateway (8 max) (supports IPV4 only)
+    -z    Pause Time in milisec (default 0)(RANGE 0 to 86400) (supports IPV4 only)
+    -f    Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only)
+    -i    Specify a network interface to operate with
+*/
+#define FOR_traceroute
+#include "toys.h"
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+GLOBALS(
+  long max_ttl;
+  long port;
+  long ttl_probes;
+  char *src_ip;
+  long tos;
+  long wait_time;
+  struct arg_list *loose_source;
+  long pause_time;
+  long first_ttl;
+  char *iface;
+
+  uint32_t gw_list[9];
+  int recv_sock;
+  int snd_sock;
+  unsigned msg_len;
+  char *packet;
+  uint32_t ident;
+  int istraceroute6;
+)
+
+#ifndef SOL_IPV6
+# define SOL_IPV6 IPPROTO_IPV6
+#endif
+
+#define ICMP_HD_SIZE4  8
+#define USEC           1000000ULL
+
+struct payload_s {
+  uint32_t seq;
+  uint32_t ident;
+};
+
+char addr_str[INET6_ADDRSTRLEN];
+struct sockaddr_storage dest;
+
+//Compute checksum SUM of buffer P of length LEN
+static u_int16_t in_cksum(u_int16_t *p, u_int len)
+{
+  u_int32_t sum = 0;
+  int nwords = len >> 1;
+
+  while (nwords-- != 0) sum += *p++;
+  if (len & 1) {
+    union {
+      u_int16_t w;
+      u_int8_t c[2];
+    } u;
+    u.c[0] = *(u_char *) p;
+    u.c[1] = 0;
+    sum += u.w;
+  }
+  // end-around-carry 
+  sum = (sum >> 16) + (sum & 0xffff);
+  sum += (sum >> 16);
+  return (~sum);
+}
+
+//sends a single probe packet with sequence(SEQ) and time-to-live(TTL)
+static void send_probe4(int seq, int ttl)
+{
+  int res, len;
+  void *out;
+  struct payload_s *send_data4 = (struct payload_s *)(TT.packet);
+  struct icmp *send_icmp4 = (struct icmp *)(TT.packet);
+
+  if (toys.optflags & FLAG_U) {
+    send_data4->seq = seq;
+    send_data4->ident = TT.ident;
+    ((struct sockaddr_in *)&dest)->sin_port = TT.port + seq;
+    out = send_data4;
+  } else {
+    send_icmp4->icmp_type = ICMP_ECHO;
+    send_icmp4->icmp_id = htons(TT.ident);
+    send_icmp4->icmp_seq = htons(seq);
+    send_icmp4->icmp_cksum = 0;
+    send_icmp4->icmp_cksum = in_cksum((uint16_t *) send_icmp4, TT.msg_len);
+    if (send_icmp4->icmp_cksum == 0) send_icmp4->icmp_cksum = 0xffff;
+    out = send_icmp4;
+  }
+
+  res = setsockopt(TT.snd_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
+  if (res < 0) perror_exit("setsockopt ttl %d", ttl);
+
+  len = TT.msg_len;
+  res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest, 
+      sizeof(struct sockaddr_in));
+  if (res != len) perror_exit(" sendto");
+}
+
+//sends a single probe packet with sequence(SEQ) and time-to-live(TTL)
+static void send_probe6(int seq, int ttl)
+{
+  void *out;
+  struct payload_s *send_data6 = (struct payload_s *) (TT.packet);
+
+  send_data6->seq = seq;
+  send_data6->ident = TT.ident;
+  ((struct sockaddr_in6 *)&dest)->sin6_port = TT.port;
+
+  if (setsockopt(TT.snd_sock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, 
+        sizeof(ttl)) < 0) error_exit("setsockopt ttl %d", ttl);
+
+  out = send_data6;
+
+  if (sendto(TT.snd_sock, out, TT.msg_len, 0,
+        (struct sockaddr *) &dest, sizeof(struct sockaddr_in6)) < 0)
+    perror_exit("sendto");
+}
+
+static void set_flag_dr(int sock)
+{
+  int set = 1;
+  if ((toys.optflags & FLAG_d) && (setsockopt(sock,SOL_SOCKET, SO_DEBUG,
+          &set, sizeof(set)) < 0)) perror_exit("SO_DEBUG failed ");
+
+  if ((toys.optflags & FLAG_r) && (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE,
+          &set, sizeof(set)) < 0)) perror_exit("SO_DONTROUTE failed ");
+}
+
+static void bind_to_interface(int sock)
+{
+  struct ifreq ifr;
+
+  snprintf(ifr.ifr_name, IFNAMSIZ, "%s", TT.iface);
+  if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)))
+      perror_msg("can't bind to interface %s", TT.iface);
+}
+
+static void resolve_addr(char *host, int family, int type, int proto, void *sock)
+{
+  struct addrinfo *info, hint;
+  int ret;
+
+  memset(&hint, 0, sizeof(hint));
+  hint.ai_family = family;
+  hint.ai_socktype = type;
+  hint.ai_protocol = proto;
+
+  ret = getaddrinfo(host, NULL, &hint, &info);
+  if (ret || !info) error_exit("bad address:  %s ", host);
+
+  memcpy(sock, info->ai_addr, info->ai_addrlen);
+  freeaddrinfo(info);
+}
+
+static void do_trace()
+{
+  int seq, fexit, ttl, tv = TT.wait_time * 1000;
+  struct pollfd pfd[1];
+  struct sockaddr_storage from;
+
+  memset(&from, 0, sizeof(from));
+  pfd[0].fd = TT.recv_sock;
+  pfd[0].events = POLLIN;
+
+  for (ttl = TT.first_ttl; ttl <= TT.max_ttl; ++ttl) {
+    int probe, dest_reach = 0, print_verbose = 1;
+    struct timeval t1, t2;
+    struct sockaddr_storage last_addr;
+
+    memset(&last_addr, 0, sizeof(last_addr));
+    fexit = 0;
+    xprintf("%2d", ttl);
+
+    for (probe = 0, seq = 0; probe < TT.ttl_probes; ++probe) {
+      int res = 0, tleft;
+
+      fflush(NULL);
+      if (!TT.istraceroute6)
+        if (probe && (toys.optflags & FLAG_z)) usleep(TT.pause_time * 1000);
+
+      if (!TT.istraceroute6) send_probe4(++seq, ttl);
+      else send_probe6(++seq, ttl);
+      gettimeofday(&t1, NULL);
+      t2 = t1;
+
+      while ((tleft = (int)(tv - ((unsigned long long)(t2.tv_sec * 1000ULL 
+                  + t2.tv_usec/1000) - (unsigned long long)(t1.tv_sec * 1000ULL
+                    + t1.tv_usec/1000)))) >= 0) {
+        unsigned delta = 0;
+        if (!(res = poll(pfd, 1, tleft))) { 
+          xprintf("  *"); 
+          break;
+        }
+        gettimeofday(&t2, NULL);
+        if (res < 0) {
+          if (errno != EINTR) perror_exit("poll");
+          continue;
+        }
+        delta = (t2.tv_sec * USEC + t2.tv_usec)
+          - (t1.tv_sec * USEC + t1.tv_usec);
+
+        if (pfd[0].revents) {
+          socklen_t addrlen = sizeof(struct sockaddr_storage);
+          int rcv_len, icmp_res = 0;
+
+          rcv_len = recvfrom(TT.recv_sock, toybuf, sizeof(toybuf),
+              MSG_DONTWAIT, (struct sockaddr *) &from, &addrlen);
+          if (rcv_len <= 0) continue;
+
+          if (!TT.istraceroute6) {
+            int pmtu = 0;
+            struct ip *rcv_pkt = (struct ip*) toybuf;
+            struct icmp *ricmp;
+
+            ricmp = (struct icmp *) ((char*)rcv_pkt + (rcv_pkt->ip_hl << 2));
+            if (ricmp->icmp_code == ICMP_UNREACH_NEEDFRAG)
+              pmtu = ntohs(ricmp->icmp_nextmtu);
+
+            if ((ricmp->icmp_type == ICMP_TIMXCEED
+                  && ricmp->icmp_code == ICMP_TIMXCEED_INTRANS)
+                || ricmp->icmp_type == ICMP_UNREACH
+                || ricmp->icmp_type == ICMP_ECHOREPLY) {
+
+              struct udphdr *hudp;
+              struct icmp *hicmp;
+              struct ip *hip = &ricmp->icmp_ip;
+
+              if (toys.optflags & FLAG_U) {
+                hudp = (struct udphdr*) ((char*)hip + (hip->ip_hl << 2));
+                if ((hip->ip_hl << 2) + 12 <=(rcv_len - (rcv_pkt->ip_hl << 2))
+                    && hip->ip_p == IPPROTO_UDP
+                    && hudp->dest == (TT.port + seq))
+                  icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 :
+                      ricmp->icmp_code);
+              } else {
+                hicmp = (struct icmp *) ((char*)hip + (hip->ip_hl << 2));
+                if (ricmp->icmp_type == ICMP_ECHOREPLY 
+                    && ricmp->icmp_id == ntohs(TT.ident)
+                    && ricmp->icmp_seq == ntohs(seq))
+                  icmp_res = ICMP_UNREACH_PORT;
+                else if ((hip->ip_hl << 2) + ICMP_HD_SIZE4 
+                    <= (rcv_len - (rcv_pkt->ip_hl << 2))
+                    && hip->ip_p == IPPROTO_ICMP
+                    && hicmp->icmp_id == htons(TT.ident)
+                    && hicmp->icmp_seq == htons(seq))
+                  icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : 
+                      ricmp->icmp_code);
+              }
+            }
+            if (!icmp_res) continue;
+
+            if (addrlen > 0) {
+              if (memcmp(&((struct sockaddr_in *)&last_addr)->sin_addr, 
+                    &((struct sockaddr_in *)&from)->sin_addr, 
+                    sizeof(struct in_addr))) {
+                if (!(toys.optflags & FLAG_n)) {
+                  char host[NI_MAXHOST];
+                  if (!getnameinfo((struct sockaddr *) &from, 
+                        sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, 0))
+                    xprintf("  %s (", host);
+                  else xprintf(" %s (", inet_ntoa(
+                          ((struct sockaddr_in *)&from)->sin_addr));
+                }
+                xprintf(" %s", inet_ntoa(
+                      ((struct sockaddr_in *)&from)->sin_addr));
+                if (!(toys.optflags & FLAG_n)) xprintf(")");
+                memcpy(&last_addr, &from, sizeof(from));
+              }
+              xprintf("  %u.%03u ms", delta / 1000, delta % 1000);
+              if (toys.optflags & FLAG_l) xprintf(" (%d)", rcv_pkt->ip_ttl);
+              if (toys.optflags & FLAG_v) {
+                xprintf(" %d bytes from %s : icmp type %d code %d\t",
+                    rcv_len, inet_ntoa(((struct sockaddr_in *)&from)->sin_addr),
+                    ricmp->icmp_type, ricmp->icmp_code);
+              }
+            } else xprintf("\t!H");
+
+            switch (icmp_res) {
+              case ICMP_UNREACH_PORT:
+                if (rcv_pkt->ip_ttl <= 1) xprintf(" !");
+                dest_reach = 1;
+                break;
+              case ICMP_UNREACH_NET:
+                xprintf(" !N");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_HOST:
+                xprintf(" !H");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_PROTOCOL:
+                xprintf(" !P");
+                dest_reach = 1;
+                break;
+              case ICMP_UNREACH_NEEDFRAG:
+                xprintf(" !F-%d", pmtu);
+                ++fexit;
+                break;
+              case ICMP_UNREACH_SRCFAIL:
+                xprintf(" !S");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_FILTER_PROHIB:
+              case ICMP_UNREACH_NET_PROHIB:
+                xprintf(" !A");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_HOST_PROHIB:
+                xprintf(" !C");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_HOST_PRECEDENCE:
+                xprintf(" !V");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_PRECEDENCE_CUTOFF:
+                xprintf(" !C");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_NET_UNKNOWN:  
+              case ICMP_UNREACH_HOST_UNKNOWN:
+                xprintf(" !U");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_ISOLATED:
+                xprintf(" !I");
+                ++fexit;
+                break;
+              case ICMP_UNREACH_TOSNET:
+              case ICMP_UNREACH_TOSHOST:
+                xprintf(" !T");
+                ++fexit;
+                break;
+              default:
+                break;
+            }
+            break;
+          } else {
+            struct icmp6_hdr *ricmp  = (struct icmp6_hdr *) toybuf;
+
+            if ((ricmp->icmp6_type == ICMP6_TIME_EXCEEDED
+                  && ricmp->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT)
+                || ricmp->icmp6_type == ICMP6_DST_UNREACH
+                || ricmp->icmp6_type == ICMP6_ECHO_REPLY) {
+
+              struct ip6_hdr *hip;
+              struct udphdr *hudp;
+              int hdr_next;
+
+              hip = (struct ip6_hdr *)(ricmp + 1);
+              hudp = (struct udphdr*) (hip + 1);
+              hdr_next = hip->ip6_nxt;
+              if (hdr_next == IPPROTO_FRAGMENT) {
+                hdr_next = *(unsigned char*)hudp;
+                hudp++;
+              }
+
+              if (hdr_next == IPPROTO_UDP) {
+                struct payload_s *pkt = (struct payload_s*)(hudp + 1);
+                if ((pkt->ident == TT.ident) && (pkt->seq == seq))
+                  icmp_res = (ricmp->icmp6_type == ICMP6_TIME_EXCEEDED) ? -1 :
+                    ricmp->icmp6_code;
+              }
+            }
+
+            if (!icmp_res) continue;
+            if (addrlen > 0) {
+              if (memcmp(&((struct sockaddr_in6 *)&last_addr)->sin6_addr, 
+                    &((struct sockaddr_in6 *)&from)->sin6_addr, 
+                    sizeof(struct in6_addr))) {
+                if (!(toys.optflags & FLAG_n)) {
+                  char host[NI_MAXHOST];
+                  if (!getnameinfo((struct sockaddr *) &from,
+                        sizeof(from), host, sizeof(host), NULL, 0, 0))
+                    xprintf("  %s (", host);
+                }
+                memset(addr_str, '\0', INET6_ADDRSTRLEN);
+                inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr,
+                    addr_str, INET6_ADDRSTRLEN);
+                xprintf(" %s", addr_str);
+
+                if (!(toys.optflags & FLAG_n)) xprintf(")");
+                memcpy(&last_addr,&from,sizeof(from));
+              }
+
+              if (toys.optflags & FLAG_v) {
+                if(print_verbose){
+                  memset(addr_str, '\0', INET6_ADDRSTRLEN);
+                  inet_ntop(AF_INET6, &((struct sockaddr_in6 *)
+                        &from)->sin6_addr, addr_str, INET6_ADDRSTRLEN);
+                  rcv_len -= sizeof(struct ip6_hdr);
+                  xprintf(" %d bytes to %s ", rcv_len, addr_str);
+                }
+              }
+              xprintf("  %u.%03u ms", delta / 1000, delta % 1000);
+              delta = 0;
+
+            } else xprintf("\t!H");
+
+            switch (icmp_res) {
+              case ICMP6_DST_UNREACH_NOPORT:
+                ++fexit;
+                dest_reach = 1;
+                break;
+              case ICMP6_DST_UNREACH_NOROUTE:
+                xprintf(" !N");
+                ++fexit;
+                break;
+              case ICMP6_DST_UNREACH_ADDR:
+                xprintf(" !H");
+                ++fexit;
+                break;
+              case ICMP6_DST_UNREACH_ADMIN:
+                xprintf(" !S");
+                ++fexit;
+                break;
+              default:
+                break;
+            }
+            break;
+          }
+        } //revents
+      }
+      print_verbose = 0;
+    }
+    xputc('\n');
+    if(!TT.istraceroute6) {
+      if (!memcmp(&((struct sockaddr_in *)&from)->sin_addr, 
+            &((struct sockaddr_in *)&dest)->sin_addr, sizeof(struct in_addr))
+          || dest_reach || (fexit && fexit >= TT.ttl_probes -1))
+        break;
+    } else if (dest_reach || (fexit > 0 && fexit >= TT.ttl_probes -1)) break;
+  }
+}
+
+void traceroute_main(void)
+{
+  unsigned opt_len = 0, pack_size = 0, tyser = 0;
+  int lsrr = 0, set = 1;
+  
+  if(!(toys.optflags & FLAG_4) && 
+      (inet_pton(AF_INET6, toys.optargs[0], &dest)))
+    toys.optflags |= FLAG_6;
+
+  memset(&dest, 0, sizeof(dest));
+  if (toys.optflags & FLAG_6) TT.istraceroute6 = 1;
+  else TT.istraceroute6 = toys.which->name[10] == '6';
+
+  if(!TT.istraceroute6 && (toys.optflags & FLAG_g)) {
+      struct arg_list *node;
+
+      for (node = TT.loose_source; node; node = node->next, lsrr++) {
+        struct sockaddr_in sin;
+
+        memset( &sin, 0, sizeof(sin));
+        if (lsrr >= 8) error_exit("no more than 8 gateways"); // NGATEWAYS
+        resolve_addr(node->arg, AF_INET, SOCK_STREAM, 0, &sin);
+        TT.gw_list[lsrr] = sin.sin_addr.s_addr;
+      }
+      opt_len = (lsrr + 1) * sizeof(TT.gw_list[0]);
+  } else TT.first_ttl = 1;
+
+  TT.msg_len = pack_size = ICMP_HD_SIZE4; //udp payload is also 8bytes
+  if (toys.optargs[1])
+    TT.msg_len = atolx_range(toys.optargs[1], pack_size, 32768);//max packet size
+
+  TT.recv_sock = xsocket((TT.istraceroute6 ? AF_INET6 : AF_INET), SOCK_RAW,
+      (TT.istraceroute6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP));
+
+  if (TT.istraceroute6) {
+    int two = 2;
+#ifdef IPV6_RECVPKTINFO
+    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set, 
+        sizeof(set));
+    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set, 
+        sizeof(set));
+#else
+    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_PKTINFO, &set, sizeof(set));
+#endif
+
+    if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two, 
+          sizeof(two)) < 0)  perror_exit("setsockopt RAW_CHECKSUM");
+  }
+
+  set_flag_dr(TT.recv_sock);
+
+  if (!TT.istraceroute6) {
+    if (toys.optflags & FLAG_U) 
+      TT.snd_sock = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    else TT.snd_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+
+    if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
+
+    resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ? 
+          SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP : 
+            IPPROTO_ICMP), &dest);
+    if (lsrr > 0) {
+      unsigned char optlist[MAX_IPOPTLEN];
+      unsigned size;
+
+      TT.gw_list[lsrr] = ((struct sockaddr_in *)&dest)->sin_addr.s_addr;
+      ++lsrr;
+
+      optlist[0] = IPOPT_NOP;
+      optlist[1] = IPOPT_LSRR;// loose source route option 
+      size = lsrr * sizeof(TT.gw_list[0]);
+      optlist[2] = size + 3;
+      optlist[3] = IPOPT_MINOFF;
+      memcpy(optlist + 4, TT.gw_list, size);
+
+      if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_OPTIONS,
+            (char *)optlist, size + sizeof(TT.gw_list[0])) < 0)
+        perror_exit("LSRR IP_OPTIONS");
+    }
+  } else TT.snd_sock = xsocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+
+  if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len, 
+        sizeof(TT.msg_len)) < 0) perror_exit("SO_SNDBUF failed ");
+
+  if (!TT.istraceroute6) {
+    if ((toys.optflags & FLAG_t) && 
+        setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0)
+      perror_exit("IP_TOS %ld failed ", TT.tos);
+
+#ifdef IP_DONTFRAG
+    if ((toys.optflags & FLAG_F) &&
+        (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set, 
+                    sizeof(set)) < 0)) perror_exit("IP_DONTFRAG failed ");
+#endif
+  } else if (setsockopt(TT.snd_sock, IPPROTO_IPV6, IPV6_TCLASS, &TT.tos,
+        sizeof(TT.tos)) < 0) perror_exit("IPV6_TCLASS %ld failed ", TT.tos);
+
+  set_flag_dr(TT.snd_sock);
+  TT.packet = xzalloc(TT.msg_len);
+  TT.ident = getpid();
+
+  if (!TT.istraceroute6) {
+    if (!(toys.optflags & FLAG_U)) TT.ident |= 0x8000;
+    if (toys.optflags & FLAG_s) {
+      struct sockaddr_in source;
+
+      memset(&source, 0, sizeof(source));
+      if (!inet_aton(TT.src_ip, &(source.sin_addr)))
+        error_exit("bad address: %s", TT.src_ip);
+      if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_MULTICAST_IF,
+            (struct sockaddr*)&source, sizeof(struct sockaddr_in)))
+        perror_exit("can't set multicast source interface");
+      if (bind(TT.snd_sock,(struct sockaddr*)&source, 
+            sizeof(struct sockaddr_in)) < 0) perror_exit("bind");
+    }
+
+    if(TT.first_ttl > TT.max_ttl) 
+      error_exit("ERROR :Range for -f is 1 to %ld (max ttl)", TT.max_ttl);
+
+    xprintf("traceroute to %s(%s)", toys.optargs[0], 
+           inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr));
+  } else {
+    if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
+
+    resolve_addr(toys.optargs[0], AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dest);
+    if (toys.optflags & FLAG_s) {
+      struct sockaddr_in6 source;
+
+      memset(&source, 0, sizeof(source));
+      if(inet_pton(AF_INET6, TT.src_ip, &(source.sin6_addr)) <= 0)
+        error_exit("bad address: %s", TT.src_ip);
+
+      if (bind(TT.snd_sock,(struct sockaddr*)&source, 
+            sizeof(struct sockaddr_in6)) < 0)
+        error_exit("bind: Cannot assign requested address");
+    } else {
+      struct sockaddr_in6 prb;
+      socklen_t len = sizeof(prb);
+      int p_fd = xsocket(AF_INET6, SOCK_DGRAM, 0);
+      if (toys.optflags & FLAG_i) bind_to_interface(p_fd);
+
+      ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025);
+      if (connect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6)) < 0)
+        perror_exit("can't connect to remote host");
+      if(getsockname(p_fd, (struct sockaddr *)&prb, &len)) 
+        error_exit("probe addr failed");
+      close(p_fd);
+      prb.sin6_port = 0;
+      if (bind(TT.snd_sock, (struct sockaddr*)&prb, 
+            sizeof(struct sockaddr_in6))) perror_exit("bind");
+      if (bind(TT.recv_sock, (struct sockaddr*)&prb, 
+            sizeof(struct sockaddr_in6))) perror_exit("bind");
+    }
+
+    inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr, 
+              addr_str, INET6_ADDRSTRLEN);
+    xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str);
+  }
+
+  if (toys.optflags & FLAG_s) xprintf(" from %s",TT.src_ip);
+  xprintf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len);
+
+  do_trace();
+}
diff --git a/toybox/toys/pending/useradd.c b/toybox/toys/pending/useradd.c
new file mode 100644
index 0000000..d0ad03a
--- /dev/null
+++ b/toybox/toys/pending/useradd.c
@@ -0,0 +1,158 @@
+/* useradd.c - add a new user
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/useradd.html
+
+USE_USERADD(NEWTOY(useradd, "<1>2u#<0G:s:g:h:SDH", TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
+USE_USERADD(OLDTOY(adduser, useradd, TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
+
+config USERADD
+  bool "useradd"
+  default n
+  help
+    usage: useradd [-SDH] [-h DIR] [-s SHELL] [-G GRP] [-g NAME] [-u UID] USER [GROUP]
+
+    Create new user, or add USER to GROUP
+
+    -D       Don't assign a password
+    -g NAME  Real name
+    -G GRP   Add user to existing group
+    -h DIR   Home directory
+    -H       Don't create home directory
+    -s SHELL Login shell
+    -S       Create a system user
+    -u UID   User id
+*/
+
+#define FOR_useradd
+#include "toys.h"
+
+GLOBALS(
+  char *dir;
+  char *gecos;
+  char *shell;
+  char *u_grp;
+  long uid;
+
+  long gid;
+)
+
+void useradd_main(void)
+{
+  char *s = *toys.optargs, *entry;
+  struct passwd pwd;
+
+  // Act like groupadd?
+  if (toys.optc == 2) {
+    if (toys.optflags) help_exit("options with USER GROUP");
+    xexec((char *[]){"groupadd", toys.optargs[0], toys.optargs[1], 0});
+  }
+
+  // Sanity check user to add
+  if (s[strcspn(s, ":/\n")] || strlen(s) > LOGIN_NAME_MAX)
+    error_exit("bad username");
+  // race condition: two adds at same time?
+  if (getpwnam(s)) error_exit("'%s' in use", s);
+
+  // Add a new group to the system, if UID is given then that is validated
+  // to be free, else a free UID is choosen by self.
+  // SYSTEM IDs are considered in the range 100 ... 999
+  // add_user(), add a new entry in /etc/passwd, /etc/shadow files
+
+  pwd.pw_name = s;
+  pwd.pw_passwd = "x";
+  pwd.pw_gecos = TT.gecos ? TT.gecos : "Linux User,";
+  pwd.pw_dir = TT.dir ? TT.dir : xmprintf("/home/%s", *toys.optargs);
+
+  if (!TT.shell) {
+    TT.shell = getenv("SHELL");
+
+    if (!TT.shell) {
+      struct passwd *pw = getpwuid(getuid());
+
+      if (pw && pw->pw_shell && *pw->pw_shell) TT.shell = xstrdup(pw->pw_shell);
+      else TT.shell = "/bin/sh";
+    }
+  }
+  pwd.pw_shell = TT.shell;
+
+  if (toys.optflags & FLAG_u) {
+    if (TT.uid > INT_MAX) error_exit("bad uid");
+    if (getpwuid(TT.uid)) error_exit("uid '%ld' in use", TT.uid);
+  } else {
+    if (toys.optflags & FLAG_S) TT.uid = CFG_TOYBOX_UID_SYS;
+    else TT.uid = CFG_TOYBOX_UID_USR;
+    //find unused uid
+    while (getpwuid(TT.uid)) TT.uid++;
+  }
+  pwd.pw_uid = TT.uid;
+
+  if (toys.optflags & FLAG_G) TT.gid = xgetgrnam(TT.u_grp)->gr_gid;
+  else {
+    // Set the GID for the user, if not specified
+    if (toys.optflags & FLAG_S) TT.gid = CFG_TOYBOX_UID_SYS;
+    else TT.gid = CFG_TOYBOX_UID_USR;
+    if (getgrnam(pwd.pw_name)) error_exit("group '%s' in use", pwd.pw_name);
+    //find unused gid
+    while (getgrgid(TT.gid)) TT.gid++;
+  }
+  pwd.pw_gid = TT.gid;
+
+  // Create a new group for user
+  if (!(toys.optflags & FLAG_G)) {
+    char *s = xmprintf("-g%ld", (long)pwd.pw_gid);
+
+    if (xrun((char *[]){"groupadd", *toys.optargs, s, 0}))
+      error_msg("addgroup -g%ld fail", (long)pwd.pw_gid);
+    free(s);
+  }
+
+  /*add user to system 
+   * 1. add an entry to /etc/passwd and /etcshadow file
+   * 2. Copy /etc/skel dir contents to use home dir
+   * 3. update the user passwd by running 'passwd' utility
+   */
+
+  // 1. add an entry to /etc/passwd and /etc/shadow file
+  entry = xmprintf("%s:%s:%ld:%ld:%s:%s:%s", pwd.pw_name, pwd.pw_passwd,
+      (long)pwd.pw_uid, (long)pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
+      pwd.pw_shell);
+  if (update_password("/etc/passwd", pwd.pw_name, entry)) error_exit("updating passwd file failed");
+  free(entry);
+
+  if (toys.optflags & FLAG_S) 
+  entry = xmprintf("%s:!!:%u::::::", pwd.pw_name, 
+      (unsigned)(time(NULL))/(24*60*60)); //passwd is not set initially
+  else entry = xmprintf("%s:!!:%u:0:99999:7:::", pwd.pw_name, 
+            (unsigned)(time(0))/(24*60*60)); //passwd is not set initially
+  update_password("/etc/shadow", pwd.pw_name, entry);
+  free(entry);
+
+  // create home dir & copy skel dir to home
+  if (!(toys.optflags & (FLAG_S|FLAG_H))) {
+    char *skel = "/etc/skel", *p = pwd.pw_dir;
+
+    // Copy and change ownership
+    if (access(p, F_OK)) {
+      if (!access(skel, R_OK))
+        toys.exitval = xrun((char *[]){"cp", "-R", skel, p, 0});
+      else toys.exitval = xrun((char *[]){"mkdir", "-p", p, 0});
+      if (!toys.exitval)
+        toys.exitval |= xrun((char *[]){"chown", "-R",
+          xmprintf("%lu:%lu", TT.uid, TT.gid), p, 0});
+      wfchmodat(AT_FDCWD, p, 0700);
+    } else fprintf(stderr, "'%s' exists, not copying '%s'", p, skel);
+  }
+
+  //3. update the user passwd by running 'passwd' utility
+  if (!(toys.optflags & FLAG_D))
+    if (xrun((char *[]){"passwd", pwd.pw_name, 0})) error_exit("passwd");
+
+  if (toys.optflags & FLAG_G) {
+    /*add user to the existing group, invoke addgroup command */
+    if (xrun((char *[]){"groupadd", *toys.optargs, TT.u_grp, 0}))
+      error_exit("groupadd");
+  }
+}
diff --git a/toybox/toys/pending/userdel.c b/toybox/toys/pending/userdel.c
new file mode 100644
index 0000000..9c93a21
--- /dev/null
+++ b/toybox/toys/pending/userdel.c
@@ -0,0 +1,116 @@
+/* userdel.c - delete a user
+ *
+ * Copyright 2014 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/userdel.html
+
+USE_USERDEL(NEWTOY(userdel, "<1>1r", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+USE_USERDEL(OLDTOY(deluser, userdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
+
+config USERDEL
+  bool "userdel"
+  default n
+  help
+    usage: userdel [-r] USER
+    usage: deluser [-r] USER
+  
+    Options:
+    -r remove home directory
+    Delete USER from the SYSTEM
+*/
+
+#define FOR_userdel
+#include "toys.h"
+
+static void update_groupfiles(char *filename, char* username)
+{
+  char *filenamesfx = NULL, *sfx = NULL, *line = NULL;
+  FILE *exfp, *newfp;
+  int ulen = strlen(username);
+  struct flock lock;
+
+  filenamesfx = xmprintf("%s+", filename);
+  sfx = strchr(filenamesfx, '+');
+  exfp = xfopen(filename, "r+");
+
+  *sfx = '-';
+  unlink(filenamesfx);
+  if (link(filename, filenamesfx)) error_msg("Can't create backup file");
+
+  *sfx = '+';
+  lock.l_type = F_WRLCK;
+  lock.l_whence = SEEK_SET;
+  lock.l_start = lock.l_len = 0;
+
+  if (fcntl(fileno(exfp), F_SETLK, &lock) < 0)
+    perror_msg("Couldn't lock file %s",filename);
+
+  lock.l_type = F_UNLCK; //unlocking at a later stage
+
+  newfp = xfopen(filenamesfx, "w+");
+
+  while ((line = get_line(fileno(exfp))) != NULL){
+    sprintf(toybuf, "%s:",username);
+    if (!strncmp(line, toybuf, ulen+1)) goto LOOP;
+    else {
+      char *n, *p = strrchr(line, ':');
+
+      if (p && *++p && (n = strstr(p, username))) {
+        do {
+          if (n[ulen] == ',') {
+            *n = '\0';
+            n += ulen + 1;
+            fprintf(newfp, "%s%s\n", line, n);
+            break;
+          } else if (!n[ulen]) {
+            if (n[-1] == ',') n[-1] = *n = '\0';
+            if (n[-1] == ':') *n = '\0';
+            fprintf(newfp, "%s%s\n", line, n);
+            break;
+          } else n += ulen;
+        } while (*n && (n=strstr(n, username)));
+        if (!n) fprintf(newfp, "%s\n", line);
+      } else fprintf(newfp, "%s\n", line);
+    }
+LOOP:
+    free(line);
+  }
+  fcntl(fileno(exfp), F_SETLK, &lock);
+  fclose(exfp);
+  errno = 0;
+  fflush(newfp);
+  fsync(fileno(newfp));
+  fclose(newfp);
+  rename(filenamesfx, filename);
+  if (errno){
+    perror_msg("File Writing/Saving failed: ");
+    unlink(filenamesfx);
+  }
+  free(filenamesfx);
+}
+
+void userdel_main(void)
+{
+  struct passwd *pwd = NULL;
+
+  pwd = xgetpwnam(*toys.optargs);
+  update_password("/etc/passwd", pwd->pw_name, NULL);
+  update_password("/etc/shadow", pwd->pw_name, NULL);
+
+  // delete the group named USER, and remove user from group.
+  // could update_password() be used for this? 
+  // not a good idea, as update_passwd() updates one entry at a time
+  // in this case it will be modifying the files as many times the 
+  // USER appears in group database files. So the customized version
+  // of update_passwd() is here.
+  update_groupfiles("/etc/group", *toys.optargs);
+  update_groupfiles("/etc/gshadow", *toys.optargs);
+
+  if (toys.optflags & FLAG_r) {
+    char *arg[] = {"rm", "-fr", pwd->pw_dir, NULL, NULL};
+
+    sprintf(toybuf, "/var/spool/mail/%s",pwd->pw_name);
+    arg[3] = toybuf;
+    xexec(arg);
+  }
+}
diff --git a/toybox/toys/pending/vi.c b/toybox/toys/pending/vi.c
new file mode 100644
index 0000000..bf8db84
--- /dev/null
+++ b/toybox/toys/pending/vi.c
@@ -0,0 +1,48 @@
+/* vi.c - You can't spell "evil" without "vi".
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html
+
+USE_VI(NEWTOY(vi, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
+
+config VI
+  bool "vi"
+  default n
+  help
+    usage: vi FILE
+
+    Visual text editor. Predates the existence of standardized cursor keys,
+    so the controls are weird and historical.
+*/
+
+#define FOR_vi
+#include "toys.h"
+
+GLOBALS(
+  struct linestack *ls;
+  char *statline;
+)
+
+struct linestack_show {
+  struct linestack_show *next;
+  long top, left;
+  int x, width, y, height;
+};
+
+// linestack, what to show, where to show it
+void linestack_show(struct linestack *ls, struct linestack_show *lss)
+{
+  return;
+}
+
+void vi_main(void)
+{
+  int i;
+
+  if (!(TT.ls = linestack_load(*toys.optargs)))
+    TT.ls = xzalloc(sizeof(struct linestack));
+ 
+  for (i=0; i<TT.ls->len; i++)
+    printf("%.*s\n", (int)TT.ls->idx[i].len, (char *)TT.ls->idx[i].ptr);  
+}
diff --git a/toybox/toys/pending/watch.c b/toybox/toys/pending/watch.c
new file mode 100644
index 0000000..d81a079
--- /dev/null
+++ b/toybox/toys/pending/watch.c
@@ -0,0 +1,70 @@
+/* watch.c - Execute a program periodically
+ *
+ * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+USE_WATCH(NEWTOY(watch, "^<1n#<0=2te", TOYFLAG_USR|TOYFLAG_BIN))
+
+config WATCH
+  bool "watch"
+  default n
+  help
+    usage: watch [-n SEC] [-t] PROG ARGS
+
+    Run PROG periodically
+
+    -n  Loop period in seconds (default 2)
+    -t  Don't print header
+    -e  Freeze updates on command error, and exit after enter.
+*/
+#define FOR_watch
+#include "toys.h"
+
+GLOBALS(
+  int interval;
+)
+
+void watch_main(void)
+{
+  int i = 0, hlen;
+  time_t t;
+  unsigned width = 80, len = sizeof("Www Mmm dd hh:mm:ss yyyy") - 1 ;
+  char *header, *cmd = *toys.optargs;
+  int retval;
+
+  while(toys.optargs[++i])
+  {
+    char * oldcmd = cmd;
+    cmd = xmprintf("%s %s", oldcmd, toys.optargs[i]);
+    if (CFG_TOYBOX_FREE) free(oldcmd);
+  }
+  header = xmprintf("Every %us: %s", TT.interval, cmd);
+  hlen = strlen(header);
+
+  while(1) {
+    xprintf("\033[H\033[J");
+    if(!(toys.optflags & FLAG_t)) {
+      terminal_size(&width, NULL);
+      if (!width) width = 80; //on serial it may return 0.
+      time(&t);
+      if (width > (hlen + len)) xprintf("%s", header);
+      if(width >= len)
+        xprintf("%*s\n",width + ((width > (hlen + len))?-hlen:0) + 1, ctime(&t));
+      else
+        xprintf("\n\n");
+    }
+    fflush(NULL); //making sure the screen is clear
+    retval = system(cmd);
+    if ((toys.optflags & FLAG_e) && retval){
+      xprintf("command exit with non-zero status, press enter to exit\n");
+      getchar();
+      break;
+    }
+    sleep(TT.interval);
+  }
+
+  if (CFG_TOYBOX_FREE){
+    free(header);
+    if (cmd != *toys.optargs) free(cmd);
+  }
+}
diff --git a/toybox/toys/pending/wget.c b/toybox/toys/pending/wget.c
new file mode 100644
index 0000000..4283fe4
--- /dev/null
+++ b/toybox/toys/pending/wget.c
@@ -0,0 +1,178 @@
+/* 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");
+}
diff --git a/toybox/toys/pending/xzcat.c b/toybox/toys/pending/xzcat.c
new file mode 100644
index 0000000..951ead0
--- /dev/null
+++ b/toybox/toys/pending/xzcat.c
@@ -0,0 +1,3143 @@
+/*
+ * Simple XZ decoder command line tool
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ * Modified for toybox by Isaac Dunham
+USE_XZCAT(NEWTOY(xzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+
+config XZCAT
+  bool "xzcat"
+  default n
+  help
+    usage: xzcat [filename...]
+    
+    Decompress listed files to stdout. Use stdin if no files listed.
+
+*/
+#define FOR_xzcat
+#include "toys.h"
+
+// BEGIN xz.h
+
+/**
+ * enum xz_ret - Return codes
+ * @XZ_OK:                  Everything is OK so far. More input or more
+ *                          output space is required to continue.
+ * @XZ_STREAM_END:          Operation finished successfully.
+ * @XZ_UNSUPPORTED_CHECK:   Integrity check type is not supported. Decoding
+ *                          is still possible in multi-call mode by simply
+ *                          calling xz_dec_run() again.
+ *                          Note that this return value is used only if
+ *                          XZ_DEC_ANY_CHECK was defined at build time,
+ *                          which is not used in the kernel. Unsupported
+ *                          check types return XZ_OPTIONS_ERROR if
+ *                          XZ_DEC_ANY_CHECK was not defined at build time.
+ * @XZ_MEM_ERROR:           Allocating memory failed. The amount of memory 
+ *                          that was tried to be allocated was no more than the
+ *                          dict_max argument given to xz_dec_init().
+ * @XZ_MEMLIMIT_ERROR:      A bigger LZMA2 dictionary would be needed than
+ *                          allowed by the dict_max argument given to
+ *                          xz_dec_init().
+ * @XZ_FORMAT_ERROR:        File format was not recognized (wrong magic
+ *                          bytes).
+ * @XZ_OPTIONS_ERROR:       This implementation doesn't support the requested
+ *                          compression options. In the decoder this means
+ *                          that the header CRC32 matches, but the header
+ *                          itself specifies something that we don't support.
+ * @XZ_DATA_ERROR:          Compressed data is corrupt.
+ * @XZ_BUF_ERROR:           Cannot make any progress. Details are slightly
+ *                          different between multi-call and single-call
+ *                          mode; more information below.
+ *
+ * XZ_BUF_ERROR is returned when two consecutive calls to XZ code cannot 
+ * consume any input and cannot produce any new output. This happens when
+ * there is no new input available, or the output buffer is full while at
+ * least one output byte is still pending. Assuming your code is not buggy,
+ * you can get this error only when decoding a compressed stream that is 
+ * truncated or otherwise corrupt.
+ */
+enum xz_ret {
+  XZ_OK,
+  XZ_STREAM_END,
+  XZ_UNSUPPORTED_CHECK,
+  XZ_MEM_ERROR,
+  XZ_MEMLIMIT_ERROR,
+  XZ_FORMAT_ERROR,
+  XZ_OPTIONS_ERROR,
+  XZ_DATA_ERROR,
+  XZ_BUF_ERROR
+};
+
+/**
+ * struct xz_buf - Passing input and output buffers to XZ code
+ * @in:         Beginning of the input buffer. This may be NULL if and only
+ *              if in_pos is equal to in_size.
+ * @in_pos:     Current position in the input buffer. This must not exceed
+ *              in_size.
+ * @in_size:    Size of the input buffer
+ * @out:        Beginning of the output buffer. This may be NULL if and only
+ *              if out_pos is equal to out_size.
+ * @out_pos:    Current position in the output buffer. This must not exceed
+ *              out_size.
+ * @out_size:   Size of the output buffer
+ *
+ * Only the contents of the output buffer from out[out_pos] onward, and
+ * the variables in_pos and out_pos are modified by the XZ code.
+ */
+struct xz_buf {
+  const uint8_t *in;
+  size_t in_pos;
+  size_t in_size;
+
+  uint8_t *out;
+  size_t out_pos;
+  size_t out_size;
+};
+
+/**
+ * struct xz_dec - Opaque type to hold the XZ decoder state
+ */
+struct xz_dec;
+
+/**
+ * xz_dec_init() - Allocate and initialize a XZ decoder state
+ * @mode:       Operation mode
+ * @dict_max:   Maximum size of the LZMA2 dictionary (history buffer) for
+ *              multi-call decoding. LZMA2 dictionary is always 2^n bytes
+ *              or 2^n + 2^(n-1) bytes (the latter sizes are less common
+ *              in practice), so other values for dict_max don't make sense.
+ *              In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
+ *              512 KiB, and 1 MiB are probably the only reasonable values,
+ *              except for kernel and initramfs images where a bigger
+ *              dictionary can be fine and useful.
+ *
+ * dict_max specifies the maximum allowed dictionary size that xz_dec_run()
+ * may allocate once it has parsed the dictionary size from the stream
+ * headers. This way excessive allocations can be avoided while still
+ * limiting the maximum memory usage to a sane value to prevent running the
+ * system out of memory when decompressing streams from untrusted sources.
+ *
+ * On success, xz_dec_init() returns a pointer to struct xz_dec, which is
+ * ready to be used with xz_dec_run(). If memory allocation fails,
+ * xz_dec_init() returns NULL.
+ */
+struct xz_dec *xz_dec_init(uint32_t dict_max);
+
+/**
+ * xz_dec_run() - Run the XZ decoder
+ * @s:          Decoder state allocated using xz_dec_init()
+ * @b:          Input and output buffers
+ *
+ * The possible return values depend on build options and operation mode.
+ * See enum xz_ret for details.
+ *
+ * Note that if an error occurs in single-call mode (return value is not
+ * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
+ * contents of the output buffer from b->out[b->out_pos] onward are
+ * undefined. This is true even after XZ_BUF_ERROR, because with some filter
+ * chains, there may be a second pass over the output buffer, and this pass
+ * cannot be properly done if the output buffer is truncated. Thus, you
+ * cannot give the single-call decoder a too small buffer and then expect to
+ * get that amount valid data from the beginning of the stream. You must use
+ * the multi-call decoder if you don't want to uncompress the whole stream.
+ */
+enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
+
+/**
+ * xz_dec_reset() - Reset an already allocated decoder state
+ * @s:          Decoder state allocated using xz_dec_init()
+ *
+ * This function can be used to reset the multi-call decoder state without
+ * freeing and reallocating memory with xz_dec_end() and xz_dec_init().
+ *
+ * In single-call mode, xz_dec_reset() is always called in the beginning of
+ * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
+ * multi-call mode.
+ */
+void xz_dec_reset(struct xz_dec *s);
+
+/**
+ * xz_dec_end() - Free the memory allocated for the decoder state
+ * @s:          Decoder state allocated using xz_dec_init(). If s is NULL,
+ *              this function does nothing.
+ */
+void xz_dec_end(struct xz_dec *s);
+
+/*
+ * Update CRC32 value using the polynomial from IEEE-802.3. To start a new
+ * calculation, the third argument must be zero. To continue the calculation,
+ * the previously returned value is passed as the third argument.
+ */
+static uint32_t xz_crc32_table[256];
+
+uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
+{
+  crc = ~crc;
+
+  while (size != 0) {
+    crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+    --size;
+  }
+
+  return ~crc;
+}
+
+static uint64_t xz_crc64_table[256];
+
+
+// END xz.h
+
+static uint8_t in[BUFSIZ];
+static uint8_t out[BUFSIZ];
+
+void do_xzcat(int fd, char *name)
+{
+  struct xz_buf b;
+  struct xz_dec *s;
+  enum xz_ret ret;
+  const char *msg;
+
+  crc_init(xz_crc32_table, 1);
+  const uint64_t poly = 0xC96C5795D7870F42ULL;
+  uint32_t i;
+  uint32_t j;
+  uint64_t r;
+
+  /* initialize CRC64 table*/
+  for (i = 0; i < 256; ++i) {
+    r = i;
+    for (j = 0; j < 8; ++j)
+      r = (r >> 1) ^ (poly & ~((r & 1) - 1));
+
+    xz_crc64_table[i] = r;
+  }
+
+  /*
+   * Support up to 64 MiB dictionary. The actually needed memory
+   * is allocated once the headers have been parsed.
+   */
+  s = xz_dec_init(1 << 26);
+  if (s == NULL) {
+    msg = "Memory allocation failed\n";
+    goto error;
+  }
+
+  b.in = in;
+  b.in_pos = 0;
+  b.in_size = 0;
+  b.out = out;
+  b.out_pos = 0;
+  b.out_size = BUFSIZ;
+
+  for (;;) {
+    if (b.in_pos == b.in_size) {
+      b.in_size = read(fd, in, sizeof(in));
+      b.in_pos = 0;
+    }
+
+    ret = xz_dec_run(s, &b);
+
+    if (b.out_pos == sizeof(out)) {
+      if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
+        msg = "Write error\n";
+        goto error;
+      }
+
+      b.out_pos = 0;
+    }
+
+    if (ret == XZ_OK)
+      continue;
+
+    if (ret == XZ_UNSUPPORTED_CHECK)
+      continue;
+
+    if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
+      msg = "Write error\n";
+      goto error;
+    }
+
+    switch (ret) {
+    case XZ_STREAM_END:
+      xz_dec_end(s);
+      return;
+
+    case XZ_MEM_ERROR:
+      msg = "Memory allocation failed\n";
+      goto error;
+
+    case XZ_MEMLIMIT_ERROR:
+      msg = "Memory usage limit reached\n";
+      goto error;
+
+    case XZ_FORMAT_ERROR:
+      msg = "Not a .xz file\n";
+      goto error;
+
+    case XZ_OPTIONS_ERROR:
+      msg = "Unsupported options in the .xz headers\n";
+      goto error;
+
+    case XZ_DATA_ERROR:
+    case XZ_BUF_ERROR:
+      msg = "File is corrupt\n";
+      goto error;
+
+    default:
+      msg = "Bug!\n";
+      goto error;
+    }
+  }
+
+error:
+  xz_dec_end(s);
+  error_exit("%s", msg);
+}
+
+void xzcat_main(void)
+{
+  loopfiles(toys.optargs, do_xzcat);
+}
+
+// BEGIN xz_private.h
+
+
+/* Uncomment as needed to enable BCJ filter decoders. 
+ * These cost about 2.5 k when all are enabled; SPARC and IA64 make 0.7 k
+ * */
+
+#define XZ_DEC_X86
+#define XZ_DEC_POWERPC
+#define XZ_DEC_IA64
+#define XZ_DEC_ARM
+#define XZ_DEC_ARMTHUMB
+#define XZ_DEC_SPARC
+
+
+#define memeq(a, b, size) (memcmp(a, b, size) == 0)
+
+#ifndef min
+#	define min(x, y) ((x) < (y) ? (x) : (y))
+#endif
+#define min_t(type, x, y) min(x, y)
+
+
+/* Inline functions to access unaligned unsigned 32-bit integers */
+#ifndef get_unaligned_le32
+static inline uint32_t get_unaligned_le32(const uint8_t *buf)
+{
+  return (uint32_t)buf[0]
+      | ((uint32_t)buf[1] << 8)
+      | ((uint32_t)buf[2] << 16)
+      | ((uint32_t)buf[3] << 24);
+}
+#endif
+
+#ifndef get_unaligned_be32
+static inline uint32_t get_unaligned_be32(const uint8_t *buf)
+{
+  return (uint32_t)(buf[0] << 24)
+      | ((uint32_t)buf[1] << 16)
+      | ((uint32_t)buf[2] << 8)
+      | (uint32_t)buf[3];
+}
+#endif
+
+#ifndef put_unaligned_le32
+static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
+{
+  buf[0] = (uint8_t)val;
+  buf[1] = (uint8_t)(val >> 8);
+  buf[2] = (uint8_t)(val >> 16);
+  buf[3] = (uint8_t)(val >> 24);
+}
+#endif
+
+#ifndef put_unaligned_be32
+static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
+{
+  buf[0] = (uint8_t)(val >> 24);
+  buf[1] = (uint8_t)(val >> 16);
+  buf[2] = (uint8_t)(val >> 8);
+  buf[3] = (uint8_t)val;
+}
+#endif
+
+/*
+ * Use get_unaligned_le32() also for aligned access for simplicity. On
+ * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
+ * could save a few bytes in code size.
+ */
+#ifndef get_le32
+#	define get_le32 get_unaligned_le32
+#endif
+
+/*
+ * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
+ * XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
+ */
+#ifndef XZ_DEC_BCJ
+#	if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
+      || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
+      || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
+      || defined(XZ_DEC_SPARC)
+#		define XZ_DEC_BCJ
+#	endif
+#endif
+
+/*
+ * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
+ * before calling xz_dec_lzma2_run().
+ */
+struct xz_dec_lzma2 *xz_dec_lzma2_create(uint32_t dict_max);
+
+/*
+ * Decode the LZMA2 properties (one byte) and reset the decoder. Return
+ * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
+ * big enough, and XZ_OPTIONS_ERROR if props indicates something that this
+ * decoder doesn't support.
+ */
+enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s,
+           uint8_t props);
+
+/* Decode raw LZMA2 stream from b->in to b->out. */
+enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
+               struct xz_buf *b);
+
+// END "xz_private.h"
+
+
+
+
+/*
+ * Branch/Call/Jump (BCJ) filter decoders
+ * The rest of the code is inside this ifdef. It makes things a little more
+ * convenient when building without support for any BCJ filters.
+ */
+#ifdef XZ_DEC_BCJ
+
+struct xz_dec_bcj {
+  /* Type of the BCJ filter being used */
+  enum {
+    BCJ_X86 = 4,        /* x86 or x86-64 */
+    BCJ_POWERPC = 5,    /* Big endian only */
+    BCJ_IA64 = 6,       /* Big or little endian */
+    BCJ_ARM = 7,        /* Little endian only */
+    BCJ_ARMTHUMB = 8,   /* Little endian only */
+    BCJ_SPARC = 9       /* Big or little endian */
+  } type;
+
+  /*
+   * Return value of the next filter in the chain. We need to preserve
+   * this information across calls, because we must not call the next
+   * filter anymore once it has returned XZ_STREAM_END.
+   */
+  enum xz_ret ret;
+
+  /*
+   * Absolute position relative to the beginning of the uncompressed
+   * data (in a single .xz Block). We care only about the lowest 32
+   * bits so this doesn't need to be uint64_t even with big files.
+   */
+  uint32_t pos;
+
+  /* x86 filter state */
+  uint32_t x86_prev_mask;
+
+  /* Temporary space to hold the variables from struct xz_buf */
+  uint8_t *out;
+  size_t out_pos;
+  size_t out_size;
+
+  struct {
+    /* Amount of already filtered data in the beginning of buf */
+    size_t filtered;
+
+    /* Total amount of data currently stored in buf  */
+    size_t size;
+
+    /*
+     * Buffer to hold a mix of filtered and unfiltered data. This
+     * needs to be big enough to hold Alignment + 2 * Look-ahead:
+     *
+     * Type         Alignment   Look-ahead
+     * x86              1           4
+     * PowerPC          4           0
+     * IA-64           16           0
+     * ARM              4           0
+     * ARM-Thumb        2           2
+     * SPARC            4           0
+     */
+    uint8_t buf[16];
+  } temp;
+};
+
+/*
+ * Decode the Filter ID of a BCJ filter. This implementation doesn't
+ * support custom start offsets, so no decoding of Filter Properties
+ * is needed. Returns XZ_OK if the given Filter ID is supported.
+ * Otherwise XZ_OPTIONS_ERROR is returned.
+ */
+enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id);
+
+/*
+ * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
+ * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
+ * must be called directly.
+ */
+enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
+             struct xz_dec_lzma2 *lzma2,
+             struct xz_buf *b);
+
+#ifdef XZ_DEC_X86
+/*
+ * This is used to test the most significant byte of a memory address
+ * in an x86 instruction.
+ */
+static inline int bcj_x86_test_msbyte(uint8_t b)
+{
+  return b == 0x00 || b == 0xFF;
+}
+
+static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+  static const int mask_to_allowed_status[8]
+    = { 1,1,1,0,1,0,0,0 };
+
+  static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
+
+  size_t i;
+  size_t prev_pos = (size_t)-1;
+  uint32_t prev_mask = s->x86_prev_mask;
+  uint32_t src;
+  uint32_t dest;
+  uint32_t j;
+  uint8_t b;
+
+  if (size <= 4)
+    return 0;
+
+  size -= 4;
+  for (i = 0; i < size; ++i) {
+    if ((buf[i] & 0xFE) != 0xE8)
+      continue;
+
+    prev_pos = i - prev_pos;
+    if (prev_pos > 3) {
+      prev_mask = 0;
+    } else {
+      prev_mask = (prev_mask << (prev_pos - 1)) & 7;
+      if (prev_mask != 0) {
+        b = buf[i + 4 - mask_to_bit_num[prev_mask]];
+        if (!mask_to_allowed_status[prev_mask]
+            || bcj_x86_test_msbyte(b)) {
+          prev_pos = i;
+          prev_mask = (prev_mask << 1) | 1;
+          continue;
+        }
+      }
+    }
+
+    prev_pos = i;
+
+    if (bcj_x86_test_msbyte(buf[i + 4])) {
+      src = get_unaligned_le32(buf + i + 1);
+      for (;;) {
+        dest = src - (s->pos + (uint32_t)i + 5);
+        if (prev_mask == 0)
+          break;
+
+        j = mask_to_bit_num[prev_mask] * 8;
+        b = (uint8_t)(dest >> (24 - j));
+        if (!bcj_x86_test_msbyte(b))
+          break;
+
+        src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
+      }
+
+      dest &= 0x01FFFFFF;
+      dest |= (uint32_t)0 - (dest & 0x01000000);
+      put_unaligned_le32(dest, buf + i + 1);
+      i += 4;
+    } else {
+      prev_mask = (prev_mask << 1) | 1;
+    }
+  }
+
+  prev_pos = i - prev_pos;
+  s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
+  return i;
+}
+#endif
+
+#ifdef XZ_DEC_POWERPC
+static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+  size_t i;
+  uint32_t instr;
+
+  for (i = 0; i + 4 <= size; i += 4) {
+    instr = get_unaligned_be32(buf + i);
+    if ((instr & 0xFC000003) == 0x48000001) {
+      instr &= 0x03FFFFFC;
+      instr -= s->pos + (uint32_t)i;
+      instr &= 0x03FFFFFC;
+      instr |= 0x48000001;
+      put_unaligned_be32(instr, buf + i);
+    }
+  }
+
+  return i;
+}
+#endif
+
+#ifdef XZ_DEC_IA64
+static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+  static const uint8_t branch_table[32] = {
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    4, 4, 6, 6, 0, 0, 7, 7,
+    4, 4, 0, 0, 4, 4, 0, 0
+  };
+
+  /*
+   * The local variables take a little bit stack space, but it's less
+   * than what LZMA2 decoder takes, so it doesn't make sense to reduce
+   * stack usage here without doing that for the LZMA2 decoder too.
+   */
+
+  /* Loop counters */
+  size_t i;
+  size_t j;
+
+  /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
+  uint32_t slot;
+
+  /* Bitwise offset of the instruction indicated by slot */
+  uint32_t bit_pos;
+
+  /* bit_pos split into byte and bit parts */
+  uint32_t byte_pos;
+  uint32_t bit_res;
+
+  /* Address part of an instruction */
+  uint32_t addr;
+
+  /* Mask used to detect which instructions to convert */
+  uint32_t mask;
+
+  /* 41-bit instruction stored somewhere in the lowest 48 bits */
+  uint64_t instr;
+
+  /* Instruction normalized with bit_res for easier manipulation */
+  uint64_t norm;
+
+  for (i = 0; i + 16 <= size; i += 16) {
+    mask = branch_table[buf[i] & 0x1F];
+    for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
+      if (((mask >> slot) & 1) == 0)
+        continue;
+
+      byte_pos = bit_pos >> 3;
+      bit_res = bit_pos & 7;
+      instr = 0;
+      for (j = 0; j < 6; ++j)
+        instr |= (uint64_t)(buf[i + j + byte_pos])
+            << (8 * j);
+
+      norm = instr >> bit_res;
+
+      if (((norm >> 37) & 0x0F) == 0x05
+          && ((norm >> 9) & 0x07) == 0) {
+        addr = (norm >> 13) & 0x0FFFFF;
+        addr |= ((uint32_t)(norm >> 36) & 1) << 20;
+        addr <<= 4;
+        addr -= s->pos + (uint32_t)i;
+        addr >>= 4;
+
+        norm &= ~((uint64_t)0x8FFFFF << 13);
+        norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
+        norm |= (uint64_t)(addr & 0x100000)
+            << (36 - 20);
+
+        instr &= (1 << bit_res) - 1;
+        instr |= norm << bit_res;
+
+        for (j = 0; j < 6; j++)
+          buf[i + j + byte_pos]
+            = (uint8_t)(instr >> (8 * j));
+      }
+    }
+  }
+
+  return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARM
+static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+  size_t i;
+  uint32_t addr;
+
+  for (i = 0; i + 4 <= size; i += 4) {
+    if (buf[i + 3] == 0xEB) {
+      addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
+          | ((uint32_t)buf[i + 2] << 16);
+      addr <<= 2;
+      addr -= s->pos + (uint32_t)i + 8;
+      addr >>= 2;
+      buf[i] = (uint8_t)addr;
+      buf[i + 1] = (uint8_t)(addr >> 8);
+      buf[i + 2] = (uint8_t)(addr >> 16);
+    }
+  }
+
+  return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARMTHUMB
+static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+  size_t i;
+  uint32_t addr;
+
+  for (i = 0; i + 4 <= size; i += 2) {
+    if ((buf[i + 1] & 0xF8) == 0xF0
+        && (buf[i + 3] & 0xF8) == 0xF8) {
+      addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
+          | ((uint32_t)buf[i] << 11)
+          | (((uint32_t)buf[i + 3] & 0x07) << 8)
+          | (uint32_t)buf[i + 2];
+      addr <<= 1;
+      addr -= s->pos + (uint32_t)i + 4;
+      addr >>= 1;
+      buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
+      buf[i] = (uint8_t)(addr >> 11);
+      buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
+      buf[i + 2] = (uint8_t)addr;
+      i += 2;
+    }
+  }
+
+  return i;
+}
+#endif
+
+#ifdef XZ_DEC_SPARC
+static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+  size_t i;
+  uint32_t instr;
+
+  for (i = 0; i + 4 <= size; i += 4) {
+    instr = get_unaligned_be32(buf + i);
+    if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
+      instr <<= 2;
+      instr -= s->pos + (uint32_t)i;
+      instr >>= 2;
+      instr = ((uint32_t)0x40000000 - (instr & 0x400000))
+          | 0x40000000 | (instr & 0x3FFFFF);
+      put_unaligned_be32(instr, buf + i);
+    }
+  }
+
+  return i;
+}
+#endif
+
+/*
+ * Apply the selected BCJ filter. Update *pos and s->pos to match the amount
+ * of data that got filtered.
+ *
+ * NOTE: This is implemented as a switch statement to avoid using function
+ * pointers, which could be problematic in the kernel boot code, which must
+ * avoid pointers to static data (at least on x86).
+ */
+static void bcj_apply(struct xz_dec_bcj *s,
+          uint8_t *buf, size_t *pos, size_t size)
+{
+  size_t filtered;
+
+  buf += *pos;
+  size -= *pos;
+
+  switch (s->type) {
+#ifdef XZ_DEC_X86
+  case BCJ_X86:
+    filtered = bcj_x86(s, buf, size);
+    break;
+#endif
+#ifdef XZ_DEC_POWERPC
+  case BCJ_POWERPC:
+    filtered = bcj_powerpc(s, buf, size);
+    break;
+#endif
+#ifdef XZ_DEC_IA64
+  case BCJ_IA64:
+    filtered = bcj_ia64(s, buf, size);
+    break;
+#endif
+#ifdef XZ_DEC_ARM
+  case BCJ_ARM:
+    filtered = bcj_arm(s, buf, size);
+    break;
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+  case BCJ_ARMTHUMB:
+    filtered = bcj_armthumb(s, buf, size);
+    break;
+#endif
+#ifdef XZ_DEC_SPARC
+  case BCJ_SPARC:
+    filtered = bcj_sparc(s, buf, size);
+    break;
+#endif
+  default:
+    /* Never reached but silence compiler warnings. */
+    filtered = 0;
+    break;
+  }
+
+  *pos += filtered;
+  s->pos += filtered;
+}
+
+/*
+ * Flush pending filtered data from temp to the output buffer.
+ * Move the remaining mixture of possibly filtered and unfiltered
+ * data to the beginning of temp.
+ */
+static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
+{
+  size_t copy_size;
+
+  copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
+  memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
+  b->out_pos += copy_size;
+
+  s->temp.filtered -= copy_size;
+  s->temp.size -= copy_size;
+  memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
+}
+
+/*
+ * The BCJ filter functions are primitive in sense that they process the
+ * data in chunks of 1-16 bytes. To hide this issue, this function does
+ * some buffering.
+ */
+enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
+             struct xz_dec_lzma2 *lzma2,
+             struct xz_buf *b)
+{
+  size_t out_start;
+
+  /*
+   * Flush pending already filtered data to the output buffer. Return
+   * immediatelly if we couldn't flush everything, or if the next
+   * filter in the chain had already returned XZ_STREAM_END.
+   */
+  if (s->temp.filtered > 0) {
+    bcj_flush(s, b);
+    if (s->temp.filtered > 0)
+      return XZ_OK;
+
+    if (s->ret == XZ_STREAM_END)
+      return XZ_STREAM_END;
+  }
+
+  /*
+   * If we have more output space than what is currently pending in
+   * temp, copy the unfiltered data from temp to the output buffer
+   * and try to fill the output buffer by decoding more data from the
+   * next filter in the chain. Apply the BCJ filter on the new data
+   * in the output buffer. If everything cannot be filtered, copy it
+   * to temp and rewind the output buffer position accordingly.
+   *
+   * This needs to be always run when temp.size == 0 to handle a special
+   * case where the output buffer is full and the next filter has no
+   * more output coming but hasn't returned XZ_STREAM_END yet.
+   */
+  if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
+    out_start = b->out_pos;
+    memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
+    b->out_pos += s->temp.size;
+
+    s->ret = xz_dec_lzma2_run(lzma2, b);
+    if (s->ret != XZ_STREAM_END
+        && (s->ret != XZ_OK ))
+      return s->ret;
+
+    bcj_apply(s, b->out, &out_start, b->out_pos);
+
+    /*
+     * As an exception, if the next filter returned XZ_STREAM_END,
+     * we can do that too, since the last few bytes that remain
+     * unfiltered are meant to remain unfiltered.
+     */
+    if (s->ret == XZ_STREAM_END)
+      return XZ_STREAM_END;
+
+    s->temp.size = b->out_pos - out_start;
+    b->out_pos -= s->temp.size;
+    memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
+
+    /*
+     * If there wasn't enough input to the next filter to fill
+     * the output buffer with unfiltered data, there's no point
+     * to try decoding more data to temp.
+     */
+    if (b->out_pos + s->temp.size < b->out_size)
+      return XZ_OK;
+  }
+
+  /*
+   * We have unfiltered data in temp. If the output buffer isn't full
+   * yet, try to fill the temp buffer by decoding more data from the
+   * next filter. Apply the BCJ filter on temp. Then we hopefully can
+   * fill the actual output buffer by copying filtered data from temp.
+   * A mix of filtered and unfiltered data may be left in temp; it will
+   * be taken care on the next call to this function.
+   */
+  if (b->out_pos < b->out_size) {
+    /* Make b->out{,_pos,_size} temporarily point to s->temp. */
+    s->out = b->out;
+    s->out_pos = b->out_pos;
+    s->out_size = b->out_size;
+    b->out = s->temp.buf;
+    b->out_pos = s->temp.size;
+    b->out_size = sizeof(s->temp.buf);
+
+    s->ret = xz_dec_lzma2_run(lzma2, b);
+
+    s->temp.size = b->out_pos;
+    b->out = s->out;
+    b->out_pos = s->out_pos;
+    b->out_size = s->out_size;
+
+    if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
+      return s->ret;
+
+    bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
+
+    /*
+     * If the next filter returned XZ_STREAM_END, we mark that
+     * everything is filtered, since the last unfiltered bytes
+     * of the stream are meant to be left as is.
+     */
+    if (s->ret == XZ_STREAM_END)
+      s->temp.filtered = s->temp.size;
+
+    bcj_flush(s, b);
+    if (s->temp.filtered > 0)
+      return XZ_OK;
+  }
+
+  return s->ret;
+}
+
+enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id)
+{
+  switch (id) {
+#ifdef XZ_DEC_X86
+  case BCJ_X86:
+#endif
+#ifdef XZ_DEC_POWERPC
+  case BCJ_POWERPC:
+#endif
+#ifdef XZ_DEC_IA64
+  case BCJ_IA64:
+#endif
+#ifdef XZ_DEC_ARM
+  case BCJ_ARM:
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+  case BCJ_ARMTHUMB:
+#endif
+#ifdef XZ_DEC_SPARC
+  case BCJ_SPARC:
+#endif
+    break;
+
+  default:
+    /* Unsupported Filter ID */
+    return XZ_OPTIONS_ERROR;
+  }
+
+  s->type = id;
+  s->ret = XZ_OK;
+  s->pos = 0;
+  s->x86_prev_mask = 0;
+  s->temp.filtered = 0;
+  s->temp.size = 0;
+
+  return XZ_OK;
+}
+
+#endif
+/*
+ * LZMA2 decoder
+ */
+
+
+// BEGIN xz_lzma2.h
+/*
+ * LZMA2 definitions
+ *
+ */
+
+
+/* Range coder constants */
+#define RC_SHIFT_BITS 8
+#define RC_TOP_BITS 24
+#define RC_TOP_VALUE (1 << RC_TOP_BITS)
+#define RC_BIT_MODEL_TOTAL_BITS 11
+#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
+#define RC_MOVE_BITS 5
+
+/*
+ * Maximum number of position states. A position state is the lowest pb
+ * number of bits of the current uncompressed offset. In some places there
+ * are different sets of probabilities for different position states.
+ */
+#define POS_STATES_MAX (1 << 4)
+
+/*
+ * This enum is used to track which LZMA symbols have occurred most recently
+ * and in which order. This information is used to predict the next symbol.
+ *
+ * Symbols:
+ *  - Literal: One 8-bit byte
+ *  - Match: Repeat a chunk of data at some distance
+ *  - Long repeat: Multi-byte match at a recently seen distance
+ *  - Short repeat: One-byte repeat at a recently seen distance
+ *
+ * The symbol names are in from STATE_oldest_older_previous. REP means
+ * either short or long repeated match, and NONLIT means any non-literal.
+ */
+enum lzma_state {
+  STATE_LIT_LIT,
+  STATE_MATCH_LIT_LIT,
+  STATE_REP_LIT_LIT,
+  STATE_SHORTREP_LIT_LIT,
+  STATE_MATCH_LIT,
+  STATE_REP_LIT,
+  STATE_SHORTREP_LIT,
+  STATE_LIT_MATCH,
+  STATE_LIT_LONGREP,
+  STATE_LIT_SHORTREP,
+  STATE_NONLIT_MATCH,
+  STATE_NONLIT_REP
+};
+
+/* Total number of states */
+#define STATES 12
+
+/* The lowest 7 states indicate that the previous state was a literal. */
+#define LIT_STATES 7
+
+/* Indicate that the latest symbol was a literal. */
+static inline void lzma_state_literal(enum lzma_state *state)
+{
+  if (*state <= STATE_SHORTREP_LIT_LIT)
+    *state = STATE_LIT_LIT;
+  else if (*state <= STATE_LIT_SHORTREP)
+    *state -= 3;
+  else
+    *state -= 6;
+}
+
+/* Indicate that the latest symbol was a match. */
+static inline void lzma_state_match(enum lzma_state *state)
+{
+  *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
+}
+
+/* Indicate that the latest state was a long repeated match. */
+static inline void lzma_state_long_rep(enum lzma_state *state)
+{
+  *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
+}
+
+/* Indicate that the latest symbol was a short match. */
+static inline void lzma_state_short_rep(enum lzma_state *state)
+{
+  *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
+}
+
+/* Test if the previous symbol was a literal. */
+static inline int lzma_state_is_literal(enum lzma_state state)
+{
+  return state < LIT_STATES;
+}
+
+/* Each literal coder is divided in three sections:
+ *   - 0x001-0x0FF: Without match byte
+ *   - 0x101-0x1FF: With match byte; match bit is 0
+ *   - 0x201-0x2FF: With match byte; match bit is 1
+ *
+ * Match byte is used when the previous LZMA symbol was something else than
+ * a literal (that is, it was some kind of match).
+ */
+#define LITERAL_CODER_SIZE 0x300
+
+/* Maximum number of literal coders */
+#define LITERAL_CODERS_MAX (1 << 4)
+
+/* Minimum length of a match is two bytes. */
+#define MATCH_LEN_MIN 2
+
+/* Match length is encoded with 4, 5, or 10 bits.
+ *
+ * Length   Bits
+ *  2-9      4 = Choice=0 + 3 bits
+ * 10-17     5 = Choice=1 + Choice2=0 + 3 bits
+ * 18-273   10 = Choice=1 + Choice2=1 + 8 bits
+ */
+#define LEN_LOW_BITS 3
+#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
+#define LEN_MID_BITS 3
+#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
+#define LEN_HIGH_BITS 8
+#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
+#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
+
+/*
+ * Maximum length of a match is 273 which is a result of the encoding
+ * described above.
+ */
+#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
+
+/*
+ * Different sets of probabilities are used for match distances that have
+ * very short match length: Lengths of 2, 3, and 4 bytes have a separate
+ * set of probabilities for each length. The matches with longer length
+ * use a shared set of probabilities.
+ */
+#define DIST_STATES 4
+
+/*
+ * Get the index of the appropriate probability array for decoding
+ * the distance slot.
+ */
+static inline uint32_t lzma_get_dist_state(uint32_t len)
+{
+  return len < DIST_STATES + MATCH_LEN_MIN
+      ? len - MATCH_LEN_MIN : DIST_STATES - 1;
+}
+
+/*
+ * The highest two bits of a 32-bit match distance are encoded using six bits.
+ * This six-bit value is called a distance slot. This way encoding a 32-bit
+ * value takes 6-36 bits, larger values taking more bits.
+ */
+#define DIST_SLOT_BITS 6
+#define DIST_SLOTS (1 << DIST_SLOT_BITS)
+
+/* Match distances up to 127 are fully encoded using probabilities. Since
+ * the highest two bits (distance slot) are always encoded using six bits,
+ * the distances 0-3 don't need any additional bits to encode, since the
+ * distance slot itself is the same as the actual distance. DIST_MODEL_START
+ * indicates the first distance slot where at least one additional bit is
+ * needed.
+ */
+#define DIST_MODEL_START 4
+
+/*
+ * Match distances greater than 127 are encoded in three pieces:
+ *   - distance slot: the highest two bits
+ *   - direct bits: 2-26 bits below the highest two bits
+ *   - alignment bits: four lowest bits
+ *
+ * Direct bits don't use any probabilities.
+ *
+ * The distance slot value of 14 is for distances 128-191.
+ */
+#define DIST_MODEL_END 14
+
+/* Distance slots that indicate a distance <= 127. */
+#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
+#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
+
+/*
+ * For match distances greater than 127, only the highest two bits and the
+ * lowest four bits (alignment) is encoded using probabilities.
+ */
+#define ALIGN_BITS 4
+#define ALIGN_SIZE (1 << ALIGN_BITS)
+#define ALIGN_MASK (ALIGN_SIZE - 1)
+
+/* Total number of all probability variables */
+#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
+
+/*
+ * LZMA remembers the four most recent match distances. Reusing these
+ * distances tends to take less space than re-encoding the actual
+ * distance value.
+ */
+#define REPS 4
+
+
+// END xz_lzma2.h
+
+/*
+ * Range decoder initialization eats the first five bytes of each LZMA chunk.
+ */
+#define RC_INIT_BYTES 5
+
+/*
+ * Minimum number of usable input buffer to safely decode one LZMA symbol.
+ * The worst case is that we decode 22 bits using probabilities and 26
+ * direct bits. This may decode at maximum of 20 bytes of input. However,
+ * lzma_main() does an extra normalization before returning, thus we
+ * need to put 21 here.
+ */
+#define LZMA_IN_REQUIRED 21
+
+/*
+ * Dictionary (history buffer)
+ *
+ * These are always true:
+ *    start <= pos <= full <= end
+ *    pos <= limit <= end
+ *    end == size
+ *    size <= size_max
+ *    allocated <= size
+ *
+ * Most of these variables are size_t as a relic of single-call mode,
+ * in which the dictionary variables address the actual output
+ * buffer directly.
+ */
+struct dictionary {
+  /* Beginning of the history buffer */
+  uint8_t *buf;
+
+  /* Old position in buf (before decoding more data) */
+  size_t start;
+
+  /* Position in buf */
+  size_t pos;
+
+  /*
+   * How full dictionary is. This is used to detect corrupt input that
+   * would read beyond the beginning of the uncompressed stream.
+   */
+  size_t full;
+
+  /* Write limit; we don't write to buf[limit] or later bytes. */
+  size_t limit;
+
+  /* End of the dictionary buffer. This is the same as the dictionary size. */
+  size_t end;
+
+  /*
+   * Size of the dictionary as specified in Block Header. This is used
+   * together with "full" to detect corrupt input that would make us
+   * read beyond the beginning of the uncompressed stream.
+   */
+  uint32_t size;
+
+  /*
+   * Maximum allowed dictionary size.
+   */
+  uint32_t size_max;
+
+  /*
+   * Amount of memory currently allocated for the dictionary.
+   */
+  uint32_t allocated;
+};
+
+/* Range decoder */
+struct rc_dec {
+  uint32_t range;
+  uint32_t code;
+
+  /*
+   * Number of initializing bytes remaining to be read
+   * by rc_read_init().
+   */
+  uint32_t init_bytes_left;
+
+  /*
+   * Buffer from which we read our input. It can be either
+   * temp.buf or the caller-provided input buffer.
+   */
+  const uint8_t *in;
+  size_t in_pos;
+  size_t in_limit;
+};
+
+/* Probabilities for a length decoder. */
+struct lzma_len_dec {
+  /* Probability of match length being at least 10 */
+  uint16_t choice;
+
+  /* Probability of match length being at least 18 */
+  uint16_t choice2;
+
+  /* Probabilities for match lengths 2-9 */
+  uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+
+  /* Probabilities for match lengths 10-17 */
+  uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+
+  /* Probabilities for match lengths 18-273 */
+  uint16_t high[LEN_HIGH_SYMBOLS];
+};
+
+struct lzma_dec {
+  /* Distances of latest four matches */
+  uint32_t rep0;
+  uint32_t rep1;
+  uint32_t rep2;
+  uint32_t rep3;
+
+  /* Types of the most recently seen LZMA symbols */
+  enum lzma_state state;
+
+  /*
+   * Length of a match. This is updated so that dict_repeat can
+   * be called again to finish repeating the whole match.
+   */
+  uint32_t len;
+
+  /*
+   * LZMA properties or related bit masks (number of literal
+   * context bits, a mask dervied from the number of literal
+   * position bits, and a mask dervied from the number
+   * position bits)
+   */
+  uint32_t lc;
+  uint32_t literal_pos_mask; /* (1 << lp) - 1 */
+  uint32_t pos_mask;         /* (1 << pb) - 1 */
+
+  /* If 1, it's a match. Otherwise it's a single 8-bit literal. */
+  uint16_t is_match[STATES][POS_STATES_MAX];
+
+  /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */
+  uint16_t is_rep[STATES];
+
+  /*
+   * If 0, distance of a repeated match is rep0.
+   * Otherwise check is_rep1.
+   */
+  uint16_t is_rep0[STATES];
+
+  /*
+   * If 0, distance of a repeated match is rep1.
+   * Otherwise check is_rep2.
+   */
+  uint16_t is_rep1[STATES];
+
+  /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */
+  uint16_t is_rep2[STATES];
+
+  /*
+   * If 1, the repeated match has length of one byte. Otherwise
+   * the length is decoded from rep_len_decoder.
+   */
+  uint16_t is_rep0_long[STATES][POS_STATES_MAX];
+
+  /*
+   * Probability tree for the highest two bits of the match
+   * distance. There is a separate probability tree for match
+   * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+   */
+  uint16_t dist_slot[DIST_STATES][DIST_SLOTS];
+
+  /*
+   * Probility trees for additional bits for match distance
+   * when the distance is in the range [4, 127].
+   */
+  uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END];
+
+  /*
+   * Probability tree for the lowest four bits of a match
+   * distance that is equal to or greater than 128.
+   */
+  uint16_t dist_align[ALIGN_SIZE];
+
+  /* Length of a normal match */
+  struct lzma_len_dec match_len_dec;
+
+  /* Length of a repeated match */
+  struct lzma_len_dec rep_len_dec;
+
+  /* Probabilities of literals */
+  uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
+};
+
+struct lzma2_dec {
+  /* Position in xz_dec_lzma2_run(). */
+  enum lzma2_seq {
+    SEQ_CONTROL,
+    SEQ_UNCOMPRESSED_1,
+    SEQ_UNCOMPRESSED_2,
+    SEQ_COMPRESSED_0,
+    SEQ_COMPRESSED_1,
+    SEQ_PROPERTIES,
+    SEQ_LZMA_PREPARE,
+    SEQ_LZMA_RUN,
+    SEQ_COPY
+  } sequence;
+
+  /* Next position after decoding the compressed size of the chunk. */
+  enum lzma2_seq next_sequence;
+
+  /* Uncompressed size of LZMA chunk (2 MiB at maximum) */
+  uint32_t uncompressed;
+
+  /*
+   * Compressed size of LZMA chunk or compressed/uncompressed
+   * size of uncompressed chunk (64 KiB at maximum)
+   */
+  uint32_t compressed;
+
+  /*
+   * True if dictionary reset is needed. This is false before
+   * the first chunk (LZMA or uncompressed).
+   */
+  int need_dict_reset;
+
+  /*
+   * True if new LZMA properties are needed. This is false
+   * before the first LZMA chunk.
+   */
+  int need_props;
+};
+
+struct xz_dec_lzma2 {
+  /*
+   * The order below is important on x86 to reduce code size and
+   * it shouldn't hurt on other platforms. Everything up to and
+   * including lzma.pos_mask are in the first 128 bytes on x86-32,
+   * which allows using smaller instructions to access those
+   * variables. On x86-64, fewer variables fit into the first 128
+   * bytes, but this is still the best order without sacrificing
+   * the readability by splitting the structures.
+   */
+  struct rc_dec rc;
+  struct dictionary dict;
+  struct lzma2_dec lzma2;
+  struct lzma_dec lzma;
+
+  /*
+   * Temporary buffer which holds small number of input bytes between
+   * decoder calls. See lzma2_lzma() for details.
+   */
+  struct {
+    uint32_t size;
+    uint8_t buf[3 * LZMA_IN_REQUIRED];
+  } temp;
+};
+
+/**************
+ * Dictionary *
+ **************/
+
+/* Reset the dictionary state. */
+static void dict_reset(struct dictionary *dict)
+{
+  dict->start = 0;
+  dict->pos = 0;
+  dict->limit = 0;
+  dict->full = 0;
+}
+
+/* Set dictionary write limit */
+static void dict_limit(struct dictionary *dict, size_t out_max)
+{
+  if (dict->end - dict->pos <= out_max)
+    dict->limit = dict->end;
+  else
+    dict->limit = dict->pos + out_max;
+}
+
+/* Return true if at least one byte can be written into the dictionary. */
+static inline int dict_has_space(const struct dictionary *dict)
+{
+  return dict->pos < dict->limit;
+}
+
+/*
+ * Get a byte from the dictionary at the given distance. The distance is
+ * assumed to valid, or as a special case, zero when the dictionary is
+ * still empty. This special case is needed for single-call decoding to
+ * avoid writing a '\0' to the end of the destination buffer.
+ */
+static inline uint32_t dict_get(const struct dictionary *dict, uint32_t dist)
+{
+  size_t offset = dict->pos - dist - 1;
+
+  if (dist >= dict->pos)
+    offset += dict->end;
+
+  return dict->full > 0 ? dict->buf[offset] : 0;
+}
+
+/*
+ * Put one byte into the dictionary. It is assumed that there is space for it.
+ */
+static inline void dict_put(struct dictionary *dict, uint8_t byte)
+{
+  dict->buf[dict->pos++] = byte;
+
+  if (dict->full < dict->pos)
+    dict->full = dict->pos;
+}
+
+/*
+ * Repeat given number of bytes from the given distance. If the distance is
+ * invalid, false is returned. On success, true is returned and *len is
+ * updated to indicate how many bytes were left to be repeated.
+ */
+static int dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t dist)
+{
+  size_t back;
+  uint32_t left;
+
+  if (dist >= dict->full || dist >= dict->size) return 0;
+
+  left = min_t(size_t, dict->limit - dict->pos, *len);
+  *len -= left;
+
+  back = dict->pos - dist - 1;
+  if (dist >= dict->pos)
+    back += dict->end;
+
+  do {
+    dict->buf[dict->pos++] = dict->buf[back++];
+    if (back == dict->end)
+      back = 0;
+  } while (--left > 0);
+
+  if (dict->full < dict->pos)
+    dict->full = dict->pos;
+
+  return 1;
+}
+
+/* Copy uncompressed data as is from input to dictionary and output buffers. */
+static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
+            uint32_t *left)
+{
+  size_t copy_size;
+
+  while (*left > 0 && b->in_pos < b->in_size
+      && b->out_pos < b->out_size) {
+    copy_size = min(b->in_size - b->in_pos,
+        b->out_size - b->out_pos);
+    if (copy_size > dict->end - dict->pos)
+      copy_size = dict->end - dict->pos;
+    if (copy_size > *left)
+      copy_size = *left;
+
+    *left -= copy_size;
+
+    memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
+    dict->pos += copy_size;
+
+    if (dict->full < dict->pos)
+      dict->full = dict->pos;
+
+    if (dict->pos == dict->end)
+      dict->pos = 0;
+
+    memcpy(b->out + b->out_pos, b->in + b->in_pos,
+        copy_size);
+
+    dict->start = dict->pos;
+
+    b->out_pos += copy_size;
+    b->in_pos += copy_size;
+  }
+}
+
+/*
+ * Flush pending data from dictionary to b->out. It is assumed that there is
+ * enough space in b->out. This is guaranteed because caller uses dict_limit()
+ * before decoding data into the dictionary.
+ */
+static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b)
+{
+  size_t copy_size = dict->pos - dict->start;
+
+  if (dict->pos == dict->end)
+    dict->pos = 0;
+
+  memcpy(b->out + b->out_pos, dict->buf + dict->start,
+      copy_size);
+
+  dict->start = dict->pos;
+  b->out_pos += copy_size;
+  return copy_size;
+}
+
+/*****************
+ * Range decoder *
+ *****************/
+
+/* Reset the range decoder. */
+static void rc_reset(struct rc_dec *rc)
+{
+  rc->range = (uint32_t)-1;
+  rc->code = 0;
+  rc->init_bytes_left = RC_INIT_BYTES;
+}
+
+/*
+ * Read the first five initial bytes into rc->code if they haven't been
+ * read already. (Yes, the first byte gets completely ignored.)
+ */
+static int rc_read_init(struct rc_dec *rc, struct xz_buf *b)
+{
+  while (rc->init_bytes_left > 0) {
+    if (b->in_pos == b->in_size) return 0;
+
+    rc->code = (rc->code << 8) + b->in[b->in_pos++];
+    --rc->init_bytes_left;
+  }
+
+  return 1;
+}
+
+/* Return true if there may not be enough input for the next decoding loop. */
+static inline int rc_limit_exceeded(const struct rc_dec *rc)
+{
+  return rc->in_pos > rc->in_limit;
+}
+
+/*
+ * Return true if it is possible (from point of view of range decoder) that
+ * we have reached the end of the LZMA chunk.
+ */
+static inline int rc_is_finished(const struct rc_dec *rc)
+{
+  return rc->code == 0;
+}
+
+/* Read the next input byte if needed. */
+static inline void rc_normalize(struct rc_dec *rc)
+{
+  if (rc->range < RC_TOP_VALUE) {
+    rc->range <<= RC_SHIFT_BITS;
+    rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++];
+  }
+}
+
+/*
+ * Decode one bit. In some versions, this function has been splitted in three
+ * functions so that the compiler is supposed to be able to more easily avoid
+ * an extra branch. In this particular version of the LZMA decoder, this
+ * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3
+ * on x86). Using a non-splitted version results in nicer looking code too.
+ *
+ * NOTE: This must return an int. Do not make it return a bool or the speed
+ * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care,
+ * and it generates 10-20 % faster code than GCC 3.x from this file anyway.)
+ */
+static inline int rc_bit(struct rc_dec *rc, uint16_t *prob)
+{
+  uint32_t bound;
+  int bit;
+
+  rc_normalize(rc);
+  bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob;
+  if (rc->code < bound) {
+    rc->range = bound;
+    *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS;
+    bit = 0;
+  } else {
+    rc->range -= bound;
+    rc->code -= bound;
+    *prob -= *prob >> RC_MOVE_BITS;
+    bit = 1;
+  }
+
+  return bit;
+}
+
+/* Decode a bittree starting from the most significant bit. */
+static inline uint32_t rc_bittree(struct rc_dec *rc,
+             uint16_t *probs, uint32_t limit)
+{
+  uint32_t symbol = 1;
+
+  do {
+    if (rc_bit(rc, &probs[symbol]))
+      symbol = (symbol << 1) + 1;
+    else
+      symbol <<= 1;
+  } while (symbol < limit);
+
+  return symbol;
+}
+
+/* Decode a bittree starting from the least significant bit. */
+static inline void rc_bittree_reverse(struct rc_dec *rc,
+                 uint16_t *probs,
+                 uint32_t *dest, uint32_t limit)
+{
+  uint32_t symbol = 1;
+  uint32_t i = 0;
+
+  do {
+    if (rc_bit(rc, &probs[symbol])) {
+      symbol = (symbol << 1) + 1;
+      *dest += 1 << i;
+    } else {
+      symbol <<= 1;
+    }
+  } while (++i < limit);
+}
+
+/* Decode direct bits (fixed fifty-fifty probability) */
+static inline void rc_direct(struct rc_dec *rc, uint32_t *dest, uint32_t limit)
+{
+  uint32_t mask;
+
+  do {
+    rc_normalize(rc);
+    rc->range >>= 1;
+    rc->code -= rc->range;
+    mask = (uint32_t)0 - (rc->code >> 31);
+    rc->code += rc->range & mask;
+    *dest = (*dest << 1) + (mask + 1);
+  } while (--limit > 0);
+}
+
+/********
+ * LZMA *
+ ********/
+
+/* Get pointer to literal coder probability array. */
+static uint16_t *lzma_literal_probs(struct xz_dec_lzma2 *s)
+{
+  uint32_t prev_byte = dict_get(&s->dict, 0);
+  uint32_t low = prev_byte >> (8 - s->lzma.lc);
+  uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc;
+  return s->lzma.literal[low + high];
+}
+
+/* Decode a literal (one 8-bit byte) */
+static void lzma_literal(struct xz_dec_lzma2 *s)
+{
+  uint16_t *probs;
+  uint32_t symbol;
+  uint32_t match_byte;
+  uint32_t match_bit;
+  uint32_t offset;
+  uint32_t i;
+
+  probs = lzma_literal_probs(s);
+
+  if (lzma_state_is_literal(s->lzma.state)) {
+    symbol = rc_bittree(&s->rc, probs, 0x100);
+  } else {
+    symbol = 1;
+    match_byte = dict_get(&s->dict, s->lzma.rep0) << 1;
+    offset = 0x100;
+
+    do {
+      match_bit = match_byte & offset;
+      match_byte <<= 1;
+      i = offset + match_bit + symbol;
+
+      if (rc_bit(&s->rc, &probs[i])) {
+        symbol = (symbol << 1) + 1;
+        offset &= match_bit;
+      } else {
+        symbol <<= 1;
+        offset &= ~match_bit;
+      }
+    } while (symbol < 0x100);
+  }
+
+  dict_put(&s->dict, (uint8_t)symbol);
+  lzma_state_literal(&s->lzma.state);
+}
+
+/* Decode the length of the match into s->lzma.len. */
+static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l,
+         uint32_t pos_state)
+{
+  uint16_t *probs;
+  uint32_t limit;
+
+  if (!rc_bit(&s->rc, &l->choice)) {
+    probs = l->low[pos_state];
+    limit = LEN_LOW_SYMBOLS;
+    s->lzma.len = MATCH_LEN_MIN;
+  } else {
+    if (!rc_bit(&s->rc, &l->choice2)) {
+      probs = l->mid[pos_state];
+      limit = LEN_MID_SYMBOLS;
+      s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS;
+    } else {
+      probs = l->high;
+      limit = LEN_HIGH_SYMBOLS;
+      s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS
+          + LEN_MID_SYMBOLS;
+    }
+  }
+
+  s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit;
+}
+
+/* Decode a match. The distance will be stored in s->lzma.rep0. */
+static void lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+  uint16_t *probs;
+  uint32_t dist_slot;
+  uint32_t limit;
+
+  lzma_state_match(&s->lzma.state);
+
+  s->lzma.rep3 = s->lzma.rep2;
+  s->lzma.rep2 = s->lzma.rep1;
+  s->lzma.rep1 = s->lzma.rep0;
+
+  lzma_len(s, &s->lzma.match_len_dec, pos_state);
+
+  probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)];
+  dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS;
+
+  if (dist_slot < DIST_MODEL_START) {
+    s->lzma.rep0 = dist_slot;
+  } else {
+    limit = (dist_slot >> 1) - 1;
+    s->lzma.rep0 = 2 + (dist_slot & 1);
+
+    if (dist_slot < DIST_MODEL_END) {
+      s->lzma.rep0 <<= limit;
+      probs = s->lzma.dist_special + s->lzma.rep0
+          - dist_slot - 1;
+      rc_bittree_reverse(&s->rc, probs,
+          &s->lzma.rep0, limit);
+    } else {
+      rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS);
+      s->lzma.rep0 <<= ALIGN_BITS;
+      rc_bittree_reverse(&s->rc, s->lzma.dist_align,
+          &s->lzma.rep0, ALIGN_BITS);
+    }
+  }
+}
+
+/*
+ * Decode a repeated match. The distance is one of the four most recently
+ * seen matches. The distance will be stored in s->lzma.rep0.
+ */
+static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+  uint32_t tmp;
+
+  if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) {
+    if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[
+        s->lzma.state][pos_state])) {
+      lzma_state_short_rep(&s->lzma.state);
+      s->lzma.len = 1;
+      return;
+    }
+  } else {
+    if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) {
+      tmp = s->lzma.rep1;
+    } else {
+      if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) {
+        tmp = s->lzma.rep2;
+      } else {
+        tmp = s->lzma.rep3;
+        s->lzma.rep3 = s->lzma.rep2;
+      }
+
+      s->lzma.rep2 = s->lzma.rep1;
+    }
+
+    s->lzma.rep1 = s->lzma.rep0;
+    s->lzma.rep0 = tmp;
+  }
+
+  lzma_state_long_rep(&s->lzma.state);
+  lzma_len(s, &s->lzma.rep_len_dec, pos_state);
+}
+
+/* LZMA decoder core */
+static int lzma_main(struct xz_dec_lzma2 *s)
+{
+  uint32_t pos_state;
+
+  /*
+   * If the dictionary was reached during the previous call, try to
+   * finish the possibly pending repeat in the dictionary.
+   */
+  if (dict_has_space(&s->dict) && s->lzma.len > 0)
+    dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0);
+
+  /*
+   * Decode more LZMA symbols. One iteration may consume up to
+   * LZMA_IN_REQUIRED - 1 bytes.
+   */
+  while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) {
+    pos_state = s->dict.pos & s->lzma.pos_mask;
+
+    if (!rc_bit(&s->rc, &s->lzma.is_match[
+        s->lzma.state][pos_state])) {
+      lzma_literal(s);
+    } else {
+      if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state]))
+        lzma_rep_match(s, pos_state);
+      else
+        lzma_match(s, pos_state);
+
+      if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0))
+        return 0;
+    }
+  }
+
+  /*
+   * Having the range decoder always normalized when we are outside
+   * this function makes it easier to correctly handle end of the chunk.
+   */
+  rc_normalize(&s->rc);
+
+  return 1;
+}
+
+/*
+ * Reset the LZMA decoder and range decoder state. Dictionary is nore reset
+ * here, because LZMA state may be reset without resetting the dictionary.
+ */
+static void lzma_reset(struct xz_dec_lzma2 *s)
+{
+  uint16_t *probs;
+  size_t i;
+
+  s->lzma.state = STATE_LIT_LIT;
+  s->lzma.rep0 = 0;
+  s->lzma.rep1 = 0;
+  s->lzma.rep2 = 0;
+  s->lzma.rep3 = 0;
+
+  /*
+   * All probabilities are initialized to the same value. This hack
+   * makes the code smaller by avoiding a separate loop for each
+   * probability array.
+   *
+   * This could be optimized so that only that part of literal
+   * probabilities that are actually required. In the common case
+   * we would write 12 KiB less.
+   */
+  probs = s->lzma.is_match[0];
+  for (i = 0; i < PROBS_TOTAL; ++i)
+    probs[i] = RC_BIT_MODEL_TOTAL / 2;
+
+  rc_reset(&s->rc);
+}
+
+/*
+ * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks
+ * from the decoded lp and pb values. On success, the LZMA decoder state is
+ * reset and true is returned.
+ */
+static int lzma_props(struct xz_dec_lzma2 *s, uint8_t props)
+{
+  if (props > (4 * 5 + 4) * 9 + 8)
+    return 0;
+
+  s->lzma.pos_mask = 0;
+  while (props >= 9 * 5) {
+    props -= 9 * 5;
+    ++s->lzma.pos_mask;
+  }
+
+  s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1;
+
+  s->lzma.literal_pos_mask = 0;
+  while (props >= 9) {
+    props -= 9;
+    ++s->lzma.literal_pos_mask;
+  }
+
+  s->lzma.lc = props;
+
+  if (s->lzma.lc + s->lzma.literal_pos_mask > 4)
+    return 0;
+
+  s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1;
+
+  lzma_reset(s);
+
+  return 1;
+}
+
+/*********
+ * LZMA2 *
+ *********/
+
+/*
+ * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't
+ * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This
+ * wrapper function takes care of making the LZMA decoder's assumption safe.
+ *
+ * As long as there is plenty of input left to be decoded in the current LZMA
+ * chunk, we decode directly from the caller-supplied input buffer until
+ * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into
+ * s->temp.buf, which (hopefully) gets filled on the next call to this
+ * function. We decode a few bytes from the temporary buffer so that we can
+ * continue decoding from the caller-supplied input buffer again.
+ */
+static int lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b)
+{
+  size_t in_avail;
+  uint32_t tmp;
+
+  in_avail = b->in_size - b->in_pos;
+  if (s->temp.size > 0 || s->lzma2.compressed == 0) {
+    tmp = 2 * LZMA_IN_REQUIRED - s->temp.size;
+    if (tmp > s->lzma2.compressed - s->temp.size)
+      tmp = s->lzma2.compressed - s->temp.size;
+    if (tmp > in_avail)
+      tmp = in_avail;
+
+    memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp);
+
+    if (s->temp.size + tmp == s->lzma2.compressed) {
+      memset(s->temp.buf + s->temp.size + tmp, 0,
+          sizeof(s->temp.buf)
+            - s->temp.size - tmp);
+      s->rc.in_limit = s->temp.size + tmp;
+    } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) {
+      s->temp.size += tmp;
+      b->in_pos += tmp;
+      return 1;
+    } else {
+      s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED;
+    }
+
+    s->rc.in = s->temp.buf;
+    s->rc.in_pos = 0;
+
+    if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp)
+      return 0;
+
+    s->lzma2.compressed -= s->rc.in_pos;
+
+    if (s->rc.in_pos < s->temp.size) {
+      s->temp.size -= s->rc.in_pos;
+      memmove(s->temp.buf, s->temp.buf + s->rc.in_pos,
+          s->temp.size);
+      return 1;
+    }
+
+    b->in_pos += s->rc.in_pos - s->temp.size;
+    s->temp.size = 0;
+  }
+
+  in_avail = b->in_size - b->in_pos;
+  if (in_avail >= LZMA_IN_REQUIRED) {
+    s->rc.in = b->in;
+    s->rc.in_pos = b->in_pos;
+
+    if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED)
+      s->rc.in_limit = b->in_pos + s->lzma2.compressed;
+    else
+      s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED;
+
+    if (!lzma_main(s))
+      return 0;
+
+    in_avail = s->rc.in_pos - b->in_pos;
+    if (in_avail > s->lzma2.compressed) return 0;
+
+    s->lzma2.compressed -= in_avail;
+    b->in_pos = s->rc.in_pos;
+  }
+
+  in_avail = b->in_size - b->in_pos;
+  if (in_avail < LZMA_IN_REQUIRED) {
+    if (in_avail > s->lzma2.compressed)
+      in_avail = s->lzma2.compressed;
+
+    memcpy(s->temp.buf, b->in + b->in_pos, in_avail);
+    s->temp.size = in_avail;
+    b->in_pos += in_avail;
+  }
+
+  return 1;
+}
+
+/*
+ * Take care of the LZMA2 control layer, and forward the job of actual LZMA
+ * decoding or copying of uncompressed chunks to other functions.
+ */
+enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
+               struct xz_buf *b)
+{
+  uint32_t tmp;
+
+  while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) {
+    switch (s->lzma2.sequence) {
+    case SEQ_CONTROL:
+      /*
+       * LZMA2 control byte
+       *
+       * Exact values:
+       *   0x00   End marker
+       *   0x01   Dictionary reset followed by
+       *          an uncompressed chunk
+       *   0x02   Uncompressed chunk (no dictionary reset)
+       *
+       * Highest three bits (s->control & 0xE0):
+       *   0xE0   Dictionary reset, new properties and state
+       *          reset, followed by LZMA compressed chunk
+       *   0xC0   New properties and state reset, followed
+       *          by LZMA compressed chunk (no dictionary
+       *          reset)
+       *   0xA0   State reset using old properties,
+       *          followed by LZMA compressed chunk (no
+       *          dictionary reset)
+       *   0x80   LZMA chunk (no dictionary or state reset)
+       *
+       * For LZMA compressed chunks, the lowest five bits
+       * (s->control & 1F) are the highest bits of the
+       * uncompressed size (bits 16-20).
+       *
+       * A new LZMA2 stream must begin with a dictionary
+       * reset. The first LZMA chunk must set new
+       * properties and reset the LZMA state.
+       *
+       * Values that don't match anything described above
+       * are invalid and we return XZ_DATA_ERROR.
+       */
+      tmp = b->in[b->in_pos++];
+
+      if (tmp == 0x00)
+        return XZ_STREAM_END;
+
+      if (tmp >= 0xE0 || tmp == 0x01) {
+        s->lzma2.need_props = 1;
+        s->lzma2.need_dict_reset = 0;
+        dict_reset(&s->dict);
+      } else if (s->lzma2.need_dict_reset) {
+        return XZ_DATA_ERROR;
+      }
+
+      if (tmp >= 0x80) {
+        s->lzma2.uncompressed = (tmp & 0x1F) << 16;
+        s->lzma2.sequence = SEQ_UNCOMPRESSED_1;
+
+        if (tmp >= 0xC0) {
+          /*
+           * When there are new properties,
+           * state reset is done at
+           * SEQ_PROPERTIES.
+           */
+          s->lzma2.need_props = 0;
+          s->lzma2.next_sequence
+              = SEQ_PROPERTIES;
+
+        } else if (s->lzma2.need_props) {
+          return XZ_DATA_ERROR;
+
+        } else {
+          s->lzma2.next_sequence
+              = SEQ_LZMA_PREPARE;
+          if (tmp >= 0xA0)
+            lzma_reset(s);
+        }
+      } else {
+        if (tmp > 0x02)
+          return XZ_DATA_ERROR;
+
+        s->lzma2.sequence = SEQ_COMPRESSED_0;
+        s->lzma2.next_sequence = SEQ_COPY;
+      }
+
+      break;
+
+    case SEQ_UNCOMPRESSED_1:
+      s->lzma2.uncompressed
+          += (uint32_t)b->in[b->in_pos++] << 8;
+      s->lzma2.sequence = SEQ_UNCOMPRESSED_2;
+      break;
+
+    case SEQ_UNCOMPRESSED_2:
+      s->lzma2.uncompressed
+          += (uint32_t)b->in[b->in_pos++] + 1;
+      s->lzma2.sequence = SEQ_COMPRESSED_0;
+      break;
+
+    case SEQ_COMPRESSED_0:
+      s->lzma2.compressed
+          = (uint32_t)b->in[b->in_pos++] << 8;
+      s->lzma2.sequence = SEQ_COMPRESSED_1;
+      break;
+
+    case SEQ_COMPRESSED_1:
+      s->lzma2.compressed
+          += (uint32_t)b->in[b->in_pos++] + 1;
+      s->lzma2.sequence = s->lzma2.next_sequence;
+      break;
+
+    case SEQ_PROPERTIES:
+      if (!lzma_props(s, b->in[b->in_pos++]))
+        return XZ_DATA_ERROR;
+
+      s->lzma2.sequence = SEQ_LZMA_PREPARE;
+
+    case SEQ_LZMA_PREPARE:
+      if (s->lzma2.compressed < RC_INIT_BYTES)
+        return XZ_DATA_ERROR;
+
+      if (!rc_read_init(&s->rc, b))
+        return XZ_OK;
+
+      s->lzma2.compressed -= RC_INIT_BYTES;
+      s->lzma2.sequence = SEQ_LZMA_RUN;
+
+    case SEQ_LZMA_RUN:
+      /*
+       * Set dictionary limit to indicate how much we want
+       * to be encoded at maximum. Decode new data into the
+       * dictionary. Flush the new data from dictionary to
+       * b->out. Check if we finished decoding this chunk.
+       * In case the dictionary got full but we didn't fill
+       * the output buffer yet, we may run this loop
+       * multiple times without changing s->lzma2.sequence.
+       */
+      dict_limit(&s->dict, min_t(size_t,
+          b->out_size - b->out_pos,
+          s->lzma2.uncompressed));
+      if (!lzma2_lzma(s, b))
+        return XZ_DATA_ERROR;
+
+      s->lzma2.uncompressed -= dict_flush(&s->dict, b);
+
+      if (s->lzma2.uncompressed == 0) {
+        if (s->lzma2.compressed > 0 || s->lzma.len > 0
+            || !rc_is_finished(&s->rc))
+          return XZ_DATA_ERROR;
+
+        rc_reset(&s->rc);
+        s->lzma2.sequence = SEQ_CONTROL;
+
+      } else if (b->out_pos == b->out_size
+          || (b->in_pos == b->in_size
+            && s->temp.size
+            < s->lzma2.compressed)) {
+        return XZ_OK;
+      }
+
+      break;
+
+    case SEQ_COPY:
+      dict_uncompressed(&s->dict, b, &s->lzma2.compressed);
+      if (s->lzma2.compressed > 0)
+        return XZ_OK;
+
+      s->lzma2.sequence = SEQ_CONTROL;
+      break;
+    }
+  }
+
+  return XZ_OK;
+}
+
+struct xz_dec_lzma2 *xz_dec_lzma2_create(uint32_t dict_max)
+{
+  struct xz_dec_lzma2 *s = malloc(sizeof(*s));
+  if (s == NULL)
+    return NULL;
+
+  s->dict.size_max = dict_max;
+  s->dict.buf = NULL;
+  s->dict.allocated = 0;
+
+  return s;
+}
+
+enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props)
+{
+  /* This limits dictionary size to 3 GiB to keep parsing simpler. */
+  if (props > 39)
+    return XZ_OPTIONS_ERROR;
+
+  s->dict.size = 2 + (props & 1);
+  s->dict.size <<= (props >> 1) + 11;
+
+  if (s->dict.size > s->dict.size_max)
+    return XZ_MEMLIMIT_ERROR;
+
+  s->dict.end = s->dict.size;
+
+  if (s->dict.allocated < s->dict.size) {
+    free(s->dict.buf);
+    s->dict.buf = malloc(s->dict.size);
+    if (s->dict.buf == NULL) {
+      s->dict.allocated = 0;
+      return XZ_MEM_ERROR;
+    }
+  }
+
+  s->lzma.len = 0;
+
+  s->lzma2.sequence = SEQ_CONTROL;
+  s->lzma2.need_dict_reset = 1;
+
+  s->temp.size = 0;
+
+  return XZ_OK;
+}
+
+/*
+ * .xz Stream decoder
+ */
+
+
+// BEGIN xz_stream.h
+/*
+ * Definitions for handling the .xz file format
+ */
+
+/*
+ * See the .xz file format specification at
+ * http://tukaani.org/xz/xz-file-format.txt
+ * to understand the container format.
+ */
+
+#define STREAM_HEADER_SIZE 12
+
+#define HEADER_MAGIC "\3757zXZ"
+#define HEADER_MAGIC_SIZE 6
+
+#define FOOTER_MAGIC "YZ"
+#define FOOTER_MAGIC_SIZE 2
+
+/*
+ * Variable-length integer can hold a 63-bit unsigned integer or a special
+ * value indicating that the value is unknown.
+ *
+ * Experimental: vli_type can be defined to uint32_t to save a few bytes
+ * in code size (no effect on speed). Doing so limits the uncompressed and
+ * compressed size of the file to less than 256 MiB and may also weaken
+ * error detection slightly.
+ */
+typedef uint64_t vli_type;
+
+#define VLI_MAX ((vli_type)-1 / 2)
+#define VLI_UNKNOWN ((vli_type)-1)
+
+/* Maximum encoded size of a VLI */
+#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
+
+/* Integrity Check types */
+enum xz_check {
+  XZ_CHECK_NONE = 0,
+  XZ_CHECK_CRC32 = 1,
+  XZ_CHECK_CRC64 = 4,
+  XZ_CHECK_SHA256 = 10
+};
+
+/* Maximum possible Check ID */
+#define XZ_CHECK_MAX 15
+// END xz_stream.h
+
+#define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64)
+
+/* Hash used to validate the Index field */
+struct xz_dec_hash {
+  vli_type unpadded;
+  vli_type uncompressed;
+  uint32_t crc32;
+};
+
+struct xz_dec {
+  /* Position in dec_main() */
+  enum {
+    SEQ_STREAM_HEADER,
+    SEQ_BLOCK_START,
+    SEQ_BLOCK_HEADER,
+    SEQ_BLOCK_UNCOMPRESS,
+    SEQ_BLOCK_PADDING,
+    SEQ_BLOCK_CHECK,
+    SEQ_INDEX,
+    SEQ_INDEX_PADDING,
+    SEQ_INDEX_CRC32,
+    SEQ_STREAM_FOOTER
+  } sequence;
+
+  /* Position in variable-length integers and Check fields */
+  uint32_t pos;
+
+  /* Variable-length integer decoded by dec_vli() */
+  vli_type vli;
+
+  /* Saved in_pos and out_pos */
+  size_t in_start;
+  size_t out_start;
+
+  /* CRC32 or CRC64 value in Block or CRC32 value in Index */
+  uint64_t crc;
+
+  /* Type of the integrity check calculated from uncompressed data */
+  enum xz_check check_type;
+
+  /*
+   * True if the next call to xz_dec_run() is allowed to return
+   * XZ_BUF_ERROR.
+   */
+  int allow_buf_error;
+
+  /* Information stored in Block Header */
+  struct {
+    /*
+     * Value stored in the Compressed Size field, or
+     * VLI_UNKNOWN if Compressed Size is not present.
+     */
+    vli_type compressed;
+
+    /*
+     * Value stored in the Uncompressed Size field, or
+     * VLI_UNKNOWN if Uncompressed Size is not present.
+     */
+    vli_type uncompressed;
+
+    /* Size of the Block Header field */
+    uint32_t size;
+  } block_header;
+
+  /* Information collected when decoding Blocks */
+  struct {
+    /* Observed compressed size of the current Block */
+    vli_type compressed;
+
+    /* Observed uncompressed size of the current Block */
+    vli_type uncompressed;
+
+    /* Number of Blocks decoded so far */
+    vli_type count;
+
+    /*
+     * Hash calculated from the Block sizes. This is used to
+     * validate the Index field.
+     */
+    struct xz_dec_hash hash;
+  } block;
+
+  /* Variables needed when verifying the Index field */
+  struct {
+    /* Position in dec_index() */
+    enum {
+      SEQ_INDEX_COUNT,
+      SEQ_INDEX_UNPADDED,
+      SEQ_INDEX_UNCOMPRESSED
+    } sequence;
+
+    /* Size of the Index in bytes */
+    vli_type size;
+
+    /* Number of Records (matches block.count in valid files) */
+    vli_type count;
+
+    /*
+     * Hash calculated from the Records (matches block.hash in
+     * valid files).
+     */
+    struct xz_dec_hash hash;
+  } index;
+
+  /*
+   * Temporary buffer needed to hold Stream Header, Block Header,
+   * and Stream Footer. The Block Header is the biggest (1 KiB)
+   * so we reserve space according to that. buf[] has to be aligned
+   * to a multiple of four bytes; the size_t variables before it
+   * should guarantee this.
+   */
+  struct {
+    size_t pos;
+    size_t size;
+    uint8_t buf[1024];
+  } temp;
+
+  struct xz_dec_lzma2 *lzma2;
+
+#ifdef XZ_DEC_BCJ
+  struct xz_dec_bcj *bcj;
+  int bcj_active;
+#endif
+};
+
+/* Sizes of the Check field with different Check IDs */
+static const uint8_t check_sizes[16] = {
+  0,
+  4, 4, 4,
+  8, 8, 8,
+  16, 16, 16,
+  32, 32, 32,
+  64, 64, 64
+};
+
+/*
+ * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
+ * must have set s->temp.pos to indicate how much data we are supposed
+ * to copy into s->temp.buf. Return true once s->temp.pos has reached
+ * s->temp.size.
+ */
+static int fill_temp(struct xz_dec *s, struct xz_buf *b)
+{
+  size_t copy_size = min_t(size_t,
+      b->in_size - b->in_pos, s->temp.size - s->temp.pos);
+
+  memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
+  b->in_pos += copy_size;
+  s->temp.pos += copy_size;
+
+  if (s->temp.pos == s->temp.size) {
+    s->temp.pos = 0;
+    return 1;
+  }
+
+  return 0;
+}
+
+/* Decode a variable-length integer (little-endian base-128 encoding) */
+static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
+         size_t *in_pos, size_t in_size)
+{
+  uint8_t byte;
+
+  if (s->pos == 0)
+    s->vli = 0;
+
+  while (*in_pos < in_size) {
+    byte = in[*in_pos];
+    ++*in_pos;
+
+    s->vli |= (vli_type)(byte & 0x7F) << s->pos;
+
+    if ((byte & 0x80) == 0) {
+      /* Don't allow non-minimal encodings. */
+      if (byte == 0 && s->pos != 0)
+        return XZ_DATA_ERROR;
+
+      s->pos = 0;
+      return XZ_STREAM_END;
+    }
+
+    s->pos += 7;
+    if (s->pos == 7 * VLI_BYTES_MAX)
+      return XZ_DATA_ERROR;
+  }
+
+  return XZ_OK;
+}
+
+/*
+ * Decode the Compressed Data field from a Block. Update and validate
+ * the observed compressed and uncompressed sizes of the Block so that
+ * they don't exceed the values possibly stored in the Block Header
+ * (validation assumes that no integer overflow occurs, since vli_type
+ * is normally uint64_t). Update the CRC32 or CRC64 value if presence of
+ * the CRC32 or CRC64 field was indicated in Stream Header.
+ *
+ * Once the decoding is finished, validate that the observed sizes match
+ * the sizes possibly stored in the Block Header. Update the hash and
+ * Block count, which are later used to validate the Index field.
+ */
+static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
+{
+  enum xz_ret ret;
+
+  s->in_start = b->in_pos;
+  s->out_start = b->out_pos;
+
+#ifdef XZ_DEC_BCJ
+  if (s->bcj_active)
+    ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
+  else
+#endif
+    ret = xz_dec_lzma2_run(s->lzma2, b);
+
+  s->block.compressed += b->in_pos - s->in_start;
+  s->block.uncompressed += b->out_pos - s->out_start;
+
+  /*
+   * There is no need to separately check for VLI_UNKNOWN, since
+   * the observed sizes are always smaller than VLI_UNKNOWN.
+   */
+  if (s->block.compressed > s->block_header.compressed
+      || s->block.uncompressed
+        > s->block_header.uncompressed)
+    return XZ_DATA_ERROR;
+
+  if (s->check_type == XZ_CHECK_CRC32)
+    s->crc = xz_crc32(b->out + s->out_start,
+        b->out_pos - s->out_start, s->crc);
+  else if (s->check_type == XZ_CHECK_CRC64)
+    s->crc = ~(s->crc);
+    size_t size = b->out_pos - s->out_start;
+    uint8_t *buf = b->out + s->out_start;
+    while (size) {
+      s->crc = xz_crc64_table[*buf++ ^ (s->crc & 0xFF)] ^ (s->crc >> 8);
+      --size;
+    }
+    s->crc=~(s->crc);
+
+  if (ret == XZ_STREAM_END) {
+    if (s->block_header.compressed != VLI_UNKNOWN
+        && s->block_header.compressed
+          != s->block.compressed)
+      return XZ_DATA_ERROR;
+
+    if (s->block_header.uncompressed != VLI_UNKNOWN
+        && s->block_header.uncompressed
+          != s->block.uncompressed)
+      return XZ_DATA_ERROR;
+
+    s->block.hash.unpadded += s->block_header.size
+        + s->block.compressed;
+
+    s->block.hash.unpadded += check_sizes[s->check_type];
+
+    s->block.hash.uncompressed += s->block.uncompressed;
+    s->block.hash.crc32 = xz_crc32(
+        (const uint8_t *)&s->block.hash,
+        sizeof(s->block.hash), s->block.hash.crc32);
+
+    ++s->block.count;
+  }
+
+  return ret;
+}
+
+/* Update the Index size and the CRC32 value. */
+static void index_update(struct xz_dec *s, const struct xz_buf *b)
+{
+  size_t in_used = b->in_pos - s->in_start;
+  s->index.size += in_used;
+  s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc);
+}
+
+/*
+ * Decode the Number of Records, Unpadded Size, and Uncompressed Size
+ * fields from the Index field. That is, Index Padding and CRC32 are not
+ * decoded by this function.
+ *
+ * This can return XZ_OK (more input needed), XZ_STREAM_END (everything
+ * successfully decoded), or XZ_DATA_ERROR (input is corrupt).
+ */
+static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
+{
+  enum xz_ret ret;
+
+  do {
+    ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
+    if (ret != XZ_STREAM_END) {
+      index_update(s, b);
+      return ret;
+    }
+
+    switch (s->index.sequence) {
+    case SEQ_INDEX_COUNT:
+      s->index.count = s->vli;
+
+      /*
+       * Validate that the Number of Records field
+       * indicates the same number of Records as
+       * there were Blocks in the Stream.
+       */
+      if (s->index.count != s->block.count)
+        return XZ_DATA_ERROR;
+
+      s->index.sequence = SEQ_INDEX_UNPADDED;
+      break;
+
+    case SEQ_INDEX_UNPADDED:
+      s->index.hash.unpadded += s->vli;
+      s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
+      break;
+
+    case SEQ_INDEX_UNCOMPRESSED:
+      s->index.hash.uncompressed += s->vli;
+      s->index.hash.crc32 = xz_crc32(
+          (const uint8_t *)&s->index.hash,
+          sizeof(s->index.hash),
+          s->index.hash.crc32);
+      --s->index.count;
+      s->index.sequence = SEQ_INDEX_UNPADDED;
+      break;
+    }
+  } while (s->index.count > 0);
+
+  return XZ_STREAM_END;
+}
+
+/*
+ * Validate that the next four or eight input bytes match the value
+ * of s->crc. s->pos must be zero when starting to validate the first byte.
+ * The "bits" argument allows using the same code for both CRC32 and CRC64.
+ */
+static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
+        uint32_t bits)
+{
+  do {
+    if (b->in_pos == b->in_size)
+      return XZ_OK;
+
+    if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++])
+      return XZ_DATA_ERROR;
+
+    s->pos += 8;
+
+  } while (s->pos < bits);
+
+  s->crc = 0;
+  s->pos = 0;
+
+  return XZ_STREAM_END;
+}
+
+/*
+ * Skip over the Check field when the Check ID is not supported.
+ * Returns true once the whole Check field has been skipped over.
+ */
+static int check_skip(struct xz_dec *s, struct xz_buf *b)
+{
+  while (s->pos < check_sizes[s->check_type]) {
+    if (b->in_pos == b->in_size) return 0;
+
+    ++b->in_pos;
+    ++s->pos;
+  }
+
+  s->pos = 0;
+
+  return 1;
+}
+
+/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
+static enum xz_ret dec_stream_header(struct xz_dec *s)
+{
+  if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
+    return XZ_FORMAT_ERROR;
+
+  if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
+      != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
+    return XZ_DATA_ERROR;
+
+  if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
+    return XZ_OPTIONS_ERROR;
+
+  /*
+   * Of integrity checks, we support none (Check ID = 0),
+   * CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4).
+   * However, if XZ_DEC_ANY_CHECK is defined, we will accept other
+   * check types too, but then the check won't be verified and
+   * a warning (XZ_UNSUPPORTED_CHECK) will be given.
+   */
+  s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+
+  if (s->check_type > XZ_CHECK_MAX)
+    return XZ_OPTIONS_ERROR;
+
+  if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
+    return XZ_UNSUPPORTED_CHECK;
+
+  return XZ_OK;
+}
+
+/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
+static enum xz_ret dec_stream_footer(struct xz_dec *s)
+{
+  if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
+    return XZ_DATA_ERROR;
+
+  if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
+    return XZ_DATA_ERROR;
+
+  /*
+   * Validate Backward Size. Note that we never added the size of the
+   * Index CRC32 field to s->index.size, thus we use s->index.size / 4
+   * instead of s->index.size / 4 - 1.
+   */
+  if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
+    return XZ_DATA_ERROR;
+
+  if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
+    return XZ_DATA_ERROR;
+
+  /*
+   * Use XZ_STREAM_END instead of XZ_OK to be more convenient
+   * for the caller.
+   */
+  return XZ_STREAM_END;
+}
+
+/* Decode the Block Header and initialize the filter chain. */
+static enum xz_ret dec_block_header(struct xz_dec *s)
+{
+  enum xz_ret ret;
+
+  /*
+   * Validate the CRC32. We know that the temp buffer is at least
+   * eight bytes so this is safe.
+   */
+  s->temp.size -= 4;
+  if (xz_crc32(s->temp.buf, s->temp.size, 0)
+      != get_le32(s->temp.buf + s->temp.size))
+    return XZ_DATA_ERROR;
+
+  s->temp.pos = 2;
+
+  /*
+   * Catch unsupported Block Flags. We support only one or two filters
+   * in the chain, so we catch that with the same test.
+   */
+#ifdef XZ_DEC_BCJ
+  if (s->temp.buf[1] & 0x3E)
+#else
+  if (s->temp.buf[1] & 0x3F)
+#endif
+    return XZ_OPTIONS_ERROR;
+
+  /* Compressed Size */
+  if (s->temp.buf[1] & 0x40) {
+    if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+          != XZ_STREAM_END)
+      return XZ_DATA_ERROR;
+
+    s->block_header.compressed = s->vli;
+  } else {
+    s->block_header.compressed = VLI_UNKNOWN;
+  }
+
+  /* Uncompressed Size */
+  if (s->temp.buf[1] & 0x80) {
+    if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+        != XZ_STREAM_END)
+      return XZ_DATA_ERROR;
+
+    s->block_header.uncompressed = s->vli;
+  } else {
+    s->block_header.uncompressed = VLI_UNKNOWN;
+  }
+
+#ifdef XZ_DEC_BCJ
+  /* If there are two filters, the first one must be a BCJ filter. */
+  s->bcj_active = s->temp.buf[1] & 0x01;
+  if (s->bcj_active) {
+    if (s->temp.size - s->temp.pos < 2)
+      return XZ_OPTIONS_ERROR;
+
+    ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
+    if (ret != XZ_OK)
+      return ret;
+
+    /*
+     * We don't support custom start offset,
+     * so Size of Properties must be zero.
+     */
+    if (s->temp.buf[s->temp.pos++] != 0x00)
+      return XZ_OPTIONS_ERROR;
+  }
+#endif
+
+  /* Valid Filter Flags always take at least two bytes. */
+  if (s->temp.size - s->temp.pos < 2)
+    return XZ_DATA_ERROR;
+
+  /* Filter ID = LZMA2 */
+  if (s->temp.buf[s->temp.pos++] != 0x21)
+    return XZ_OPTIONS_ERROR;
+
+  /* Size of Properties = 1-byte Filter Properties */
+  if (s->temp.buf[s->temp.pos++] != 0x01)
+    return XZ_OPTIONS_ERROR;
+
+  /* Filter Properties contains LZMA2 dictionary size. */
+  if (s->temp.size - s->temp.pos < 1)
+    return XZ_DATA_ERROR;
+
+  ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
+  if (ret != XZ_OK)
+    return ret;
+
+  /* The rest must be Header Padding. */
+  while (s->temp.pos < s->temp.size)
+    if (s->temp.buf[s->temp.pos++] != 0x00)
+      return XZ_OPTIONS_ERROR;
+
+  s->temp.pos = 0;
+  s->block.compressed = 0;
+  s->block.uncompressed = 0;
+
+  return XZ_OK;
+}
+
+static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
+{
+  enum xz_ret ret;
+
+  /*
+   * Store the start position for the case when we are in the middle
+   * of the Index field.
+   */
+  s->in_start = b->in_pos;
+
+  for (;;) {
+    switch (s->sequence) {
+    case SEQ_STREAM_HEADER:
+      /*
+       * Stream Header is copied to s->temp, and then
+       * decoded from there. This way if the caller
+       * gives us only little input at a time, we can
+       * still keep the Stream Header decoding code
+       * simple. Similar approach is used in many places
+       * in this file.
+       */
+      if (!fill_temp(s, b))
+        return XZ_OK;
+
+      /*
+       * If dec_stream_header() returns
+       * XZ_UNSUPPORTED_CHECK, it is still possible
+       * to continue decoding if working in multi-call
+       * mode. Thus, update s->sequence before calling
+       * dec_stream_header().
+       */
+      s->sequence = SEQ_BLOCK_START;
+
+      ret = dec_stream_header(s);
+      if (ret != XZ_OK)
+        return ret;
+
+    case SEQ_BLOCK_START:
+      /* We need one byte of input to continue. */
+      if (b->in_pos == b->in_size)
+        return XZ_OK;
+
+      /* See if this is the beginning of the Index field. */
+      if (b->in[b->in_pos] == 0) {
+        s->in_start = b->in_pos++;
+        s->sequence = SEQ_INDEX;
+        break;
+      }
+
+      /*
+       * Calculate the size of the Block Header and
+       * prepare to decode it.
+       */
+      s->block_header.size
+        = ((uint32_t)b->in[b->in_pos] + 1) * 4;
+
+      s->temp.size = s->block_header.size;
+      s->temp.pos = 0;
+      s->sequence = SEQ_BLOCK_HEADER;
+
+    case SEQ_BLOCK_HEADER:
+      if (!fill_temp(s, b))
+        return XZ_OK;
+
+      ret = dec_block_header(s);
+      if (ret != XZ_OK)
+        return ret;
+
+      s->sequence = SEQ_BLOCK_UNCOMPRESS;
+
+    case SEQ_BLOCK_UNCOMPRESS:
+      ret = dec_block(s, b);
+      if (ret != XZ_STREAM_END)
+        return ret;
+
+      s->sequence = SEQ_BLOCK_PADDING;
+
+    case SEQ_BLOCK_PADDING:
+      /*
+       * Size of Compressed Data + Block Padding
+       * must be a multiple of four. We don't need
+       * s->block.compressed for anything else
+       * anymore, so we use it here to test the size
+       * of the Block Padding field.
+       */
+      while (s->block.compressed & 3) {
+        if (b->in_pos == b->in_size)
+          return XZ_OK;
+
+        if (b->in[b->in_pos++] != 0)
+          return XZ_DATA_ERROR;
+
+        ++s->block.compressed;
+      }
+
+      s->sequence = SEQ_BLOCK_CHECK;
+
+    case SEQ_BLOCK_CHECK:
+      if (s->check_type == XZ_CHECK_CRC32) {
+        ret = crc_validate(s, b, 32);
+        if (ret != XZ_STREAM_END)
+          return ret;
+      }
+      else if (IS_CRC64(s->check_type)) {
+        ret = crc_validate(s, b, 64);
+        if (ret != XZ_STREAM_END)
+          return ret;
+      }
+      else if (!check_skip(s, b)) {
+        return XZ_OK;
+      }
+
+      s->sequence = SEQ_BLOCK_START;
+      break;
+
+    case SEQ_INDEX:
+      ret = dec_index(s, b);
+      if (ret != XZ_STREAM_END)
+        return ret;
+
+      s->sequence = SEQ_INDEX_PADDING;
+
+    case SEQ_INDEX_PADDING:
+      while ((s->index.size + (b->in_pos - s->in_start))
+          & 3) {
+        if (b->in_pos == b->in_size) {
+          index_update(s, b);
+          return XZ_OK;
+        }
+
+        if (b->in[b->in_pos++] != 0)
+          return XZ_DATA_ERROR;
+      }
+
+      /* Finish the CRC32 value and Index size. */
+      index_update(s, b);
+
+      /* Compare the hashes to validate the Index field. */
+      if (!memeq(&s->block.hash, &s->index.hash,
+          sizeof(s->block.hash)))
+        return XZ_DATA_ERROR;
+
+      s->sequence = SEQ_INDEX_CRC32;
+
+    case SEQ_INDEX_CRC32:
+      ret = crc_validate(s, b, 32);
+      if (ret != XZ_STREAM_END)
+        return ret;
+
+      s->temp.size = STREAM_HEADER_SIZE;
+      s->sequence = SEQ_STREAM_FOOTER;
+
+    case SEQ_STREAM_FOOTER:
+      if (!fill_temp(s, b))
+        return XZ_OK;
+
+      return dec_stream_footer(s);
+    }
+  }
+
+  /* Never reached */
+}
+
+/*
+ * xz_dec_run() is a wrapper for dec_main() to handle some special cases in
+ * multi-call and single-call decoding.
+ *
+ * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
+ * are not going to make any progress anymore. This is to prevent the caller
+ * from calling us infinitely when the input file is truncated or otherwise
+ * corrupt. Since zlib-style API allows that the caller fills the input buffer
+ * only when the decoder doesn't produce any new output, we have to be careful
+ * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
+ * after the second consecutive call to xz_dec_run() that makes no progress.
+ *
+ * In single-call mode, if we couldn't decode everything and no error
+ * occurred, either the input is truncated or the output buffer is too small.
+ * Since we know that the last input byte never produces any output, we know
+ * that if all the input was consumed and decoding wasn't finished, the file
+ * must be corrupt. Otherwise the output buffer has to be too small or the
+ * file is corrupt in a way that decoding it produces too big output.
+ *
+ * If single-call decoding fails, we reset b->in_pos and b->out_pos back to
+ * their original values. This is because with some filter chains there won't
+ * be any valid uncompressed data in the output buffer unless the decoding
+ * actually succeeds (that's the price to pay of using the output buffer as
+ * the workspace).
+ */
+enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
+{
+  size_t in_start;
+  size_t out_start;
+  enum xz_ret ret;
+
+  in_start = b->in_pos;
+  out_start = b->out_pos;
+  ret = dec_main(s, b);
+
+  if (ret == XZ_OK && in_start == b->in_pos && out_start == b->out_pos) {
+    if (s->allow_buf_error)
+      ret = XZ_BUF_ERROR;
+
+    s->allow_buf_error = 1;
+  } else {
+    s->allow_buf_error = 0;
+  }
+
+  return ret;
+}
+
+struct xz_dec *xz_dec_init(uint32_t dict_max)
+{
+  struct xz_dec *s = malloc(sizeof(*s));
+  if (!s)
+    return NULL;
+
+#ifdef XZ_DEC_BCJ
+  s->bcj = malloc(sizeof(*s->bcj));
+  if (!s->bcj)
+    goto error_bcj;
+#endif
+
+  s->lzma2 = xz_dec_lzma2_create(dict_max);
+  if (s->lzma2 == NULL)
+    goto error_lzma2;
+
+  xz_dec_reset(s);
+  return s;
+
+error_lzma2:
+#ifdef XZ_DEC_BCJ
+  free(s->bcj);
+error_bcj:
+#endif
+  free(s);
+  return NULL;
+}
+
+void xz_dec_reset(struct xz_dec *s)
+{
+  s->sequence = SEQ_STREAM_HEADER;
+  s->allow_buf_error = 0;
+  s->pos = 0;
+  s->crc = 0;
+  memset(&s->block, 0, sizeof(s->block));
+  memset(&s->index, 0, sizeof(s->index));
+  s->temp.pos = 0;
+  s->temp.size = STREAM_HEADER_SIZE;
+}
+
+void xz_dec_end(struct xz_dec *s)
+{
+  if (s != NULL) {
+    free((s->lzma2)->dict.buf);
+    free(s->lzma2);
+
+#ifdef XZ_DEC_BCJ
+    free(s->bcj);
+#endif
+    free(s);
+  }
+}
diff --git a/toybox/toys/posix/README b/toybox/toys/posix/README
new file mode 100644
index 0000000..b0d6007
--- /dev/null
+++ b/toybox/toys/posix/README
@@ -0,0 +1,5 @@
+Posix commands
+
+Commands defined in POSIX-2008, also known as the Single Unix
+Specification version 4, available online at
+http://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html
diff --git a/toybox/toys/posix/basename.c b/toybox/toys/posix/basename.c
new file mode 100644
index 0000000..c123cc7
--- /dev/null
+++ b/toybox/toys/posix/basename.c
@@ -0,0 +1,34 @@
+/* basename.c - Return non-directory portion of a pathname
+ *
+ * Copyright 2012 Tryn Mirell <tryn@mirell.org>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/basename.html
+
+
+USE_BASENAME(NEWTOY(basename, "<1>2", TOYFLAG_USR|TOYFLAG_BIN))
+
+config BASENAME
+  bool "basename"
+  default y
+  help
+    usage: basename string [suffix]
+
+    Return non-directory portion of a pathname removing suffix
+*/
+
+#include "toys.h"
+
+void basename_main(void)
+{
+  char *base = basename(*toys.optargs), *suffix = toys.optargs[1];
+
+  // chop off the suffix if provided
+  if (suffix && *suffix) {
+    long bl = strlen(base), sl = strlen(suffix);
+    char *s = base + bl - sl;
+
+    if (bl > sl && !strcmp(s, suffix)) *s = 0;
+  }
+
+  puts(base);
+}
diff --git a/toybox/toys/posix/cal.c b/toybox/toys/posix/cal.c
new file mode 100644
index 0000000..bd3afad
--- /dev/null
+++ b/toybox/toys/posix/cal.c
@@ -0,0 +1,125 @@
+/* cal.c - show calendar.
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/cal.html
+
+USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN))
+
+config CAL
+  bool "cal"
+  default y
+  help
+    usage: cal [[month] year]
+
+    Print a calendar.
+
+    With one argument, prints all months of the specified year.
+    With two arguments, prints calendar for month and year.
+*/
+
+#include "toys.h"
+
+// Write calendar into buffer: each line is 20 chars wide, end indicated
+// by empty string.
+
+static char *calstrings(char *buf, struct tm *tm)
+{
+  char temp[21];
+  int wday, mday, start, len, line;
+
+  // header
+  len = strftime(temp, 21, "%B %Y", tm);
+  len += (20-len)/2;
+  buf += sprintf(buf, "%*s%*s ", len, temp, 20-len, "");
+  buf++;
+  buf += sprintf(buf, "Su Mo Tu We Th Fr Sa ");
+  buf++;
+
+  // What day of the week does this month start on?
+  if (tm->tm_mday>1)
+    start = (36+tm->tm_wday-tm->tm_mday)%7;
+  else start = tm->tm_wday;
+
+  // What day does this month end on?  Alas, libc doesn't tell us...
+  len = 31;
+  if (tm->tm_mon == 1) {
+    int year = tm->tm_year;
+    len = 28;
+    if (!(year & 3) && !((year&100) && !(year&400))) len++;
+  } else if ((tm->tm_mon+(tm->tm_mon>6 ? 1 : 0)) & 1) len = 30;
+
+  for (mday=line=0;line<6;line++) {
+    for (wday=0; wday<7; wday++) {
+      char *pat = "   ";
+      if (!mday ? wday==start : mday<len) {
+        pat = "%2d ";
+        mday++;
+      }
+      buf += sprintf(buf, pat, mday);
+    }
+    buf++;
+  }
+
+  return buf;
+}
+
+// Worst case scenario toybuf usage: sizeof(struct tm) plus 21 bytes/line
+// plus 8 lines/month plus 12 months, comes to a bit over 2k of our 4k buffer.
+
+void cal_main(void)
+{
+  struct tm *tm;
+  char *buf = toybuf;
+
+  if (toys.optc) {
+    // Conveniently starts zeroed
+    tm = (struct tm *)toybuf;
+    buf += sizeof(struct tm);
+
+    // Last argument is year, one before that (if any) is month.
+    tm->tm_year = atolx_range(toys.optargs[--toys.optc], 1, 9999);
+    tm->tm_year -= 1900;
+    tm->tm_mday = 1;
+    tm->tm_hour = 12;  // noon to avoid timezone weirdness
+    if (toys.optc) {
+      tm->tm_mon = atolx_range(toys.optargs[--toys.optc], 1, 12);
+      tm->tm_mon--;
+
+    // Print 12 months of the year
+
+    } else {
+      char *bufs[12];
+      int i, j, k;
+
+      for (i=0; i<12; i++) {
+        tm->tm_mon=i;
+        mktime(tm);
+        buf = calstrings(bufs[i]=buf, tm);
+      }
+
+      // 4 rows, 6 lines each, 3 columns
+      for (i=0; i<4; i++) {
+        for (j=0; j<8; j++) {
+          for(k=0; k<3; k++) {
+            char **b = bufs+(k+i*3);
+            *b += printf("%s ", *b);
+          }
+          puts("");
+        }
+      }
+      return;
+    }
+
+    // What day of the week does that start on?
+    mktime(tm);
+
+  } else {
+    time_t now;
+    time(&now);
+    tm = localtime(&now);
+  }
+
+  calstrings(buf, tm);
+  while (*buf) buf += printf("%s\n", buf);
+}
diff --git a/toybox/toys/posix/cat.c b/toybox/toys/posix/cat.c
new file mode 100644
index 0000000..4da2ec2
--- /dev/null
+++ b/toybox/toys/posix/cat.c
@@ -0,0 +1,102 @@
+/* cat.c - copy inputs to stdout.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/cat.html
+ *
+ * And "Cat -v considered harmful" at
+ *   http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz
+
+USE_CAT(NEWTOY(cat, "u"USE_CAT_V("vte"), TOYFLAG_BIN))
+USE_CATV(NEWTOY(catv, USE_CATV("vte"), TOYFLAG_USR|TOYFLAG_BIN))
+
+config CAT
+  bool "cat"
+  default y
+  help
+    usage: cat [-u] [file...]
+
+    Copy (concatenate) files to stdout.  If no files listed, copy from stdin.
+    Filename "-" is a synonym for stdin.
+
+    -u	Copy one byte at a time (slow).
+
+config CAT_V
+  bool "cat -etv"
+  default n
+  depends on CAT
+  help
+    usage: cat [-evt]
+
+    -e	Mark each newline with $
+    -t	Show tabs as ^I
+    -v	Display nonprinting characters as escape sequences. Use M-x for
+    	high ascii characters (>127), and ^x for other nonprinting chars.
+
+config CATV
+  bool "catv"
+  default y
+  help
+    usage: catv [-evt] [filename...]
+
+    Display nonprinting characters as escape sequences. Use M-x for
+    high ascii characters (>127), and ^x for other nonprinting chars.
+
+    -e  Mark each newline with $
+    -t  Show tabs as ^I
+    -v  Don't use ^x or M-x escapes.
+*/
+
+#define FOR_cat
+#define FORCE_FLAGS
+#include "toys.h"
+
+static void do_cat(int fd, char *name)
+{
+  int i, len, size=(toys.optflags & FLAG_u) ? 1 : sizeof(toybuf);
+
+  for(;;) {
+    len = read(fd, toybuf, size);
+    if (len < 0) {
+      toys.exitval = EXIT_FAILURE;
+      perror_msg_raw(name);
+    }
+    if (len < 1) break;
+    if ((CFG_CAT_V || CFG_CATV) && (toys.optflags&~FLAG_u)) {
+      for (i=0; i<len; i++) {
+        char c=toybuf[i];
+
+        if (c > 126 && (toys.optflags & FLAG_v)) {
+          if (c > 127) {
+            printf("M-");
+            c -= 128;
+          }
+          if (c == 127) {
+            printf("^?");
+            continue;
+          }
+        }
+        if (c < 32) {
+          if (c == 10) {
+            if (toys.optflags & FLAG_e) xputc('$');
+          } else if (toys.optflags & (c==9 ? FLAG_t : FLAG_v)) {
+            printf("^%c", c+'@');
+            continue;
+          }
+        }
+        xputc(c);
+      }
+    } else xwrite(1, toybuf, len);
+  }
+}
+
+void cat_main(void)
+{
+  loopfiles(toys.optargs, do_cat);
+}
+
+void catv_main(void)
+{
+  toys.optflags ^= FLAG_v;
+  loopfiles(toys.optargs, do_cat);
+}
diff --git a/toybox/toys/posix/chgrp.c b/toybox/toys/posix/chgrp.c
new file mode 100644
index 0000000..62e9eb1
--- /dev/null
+++ b/toybox/toys/posix/chgrp.c
@@ -0,0 +1,106 @@
+/* chgrp.c - Change user and group ownership
+ *
+ * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/chown.html
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/chgrp.html
+
+USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv[-HLP]", TOYFLAG_BIN))
+USE_CHOWN(OLDTOY(chown, chgrp, TOYFLAG_BIN))
+
+config CHGRP
+  bool "chgrp"
+  default y
+  help
+    usage: chgrp/chown [-RHLP] [-fvh] group file...
+
+    Change group of one or more files.
+
+    -f	suppress most error messages.
+    -h	change symlinks instead of what they point to
+    -R	recurse into subdirectories (implies -h).
+    -H	with -R change target of symlink, follow command line symlinks
+    -L	with -R change target of symlink, follow all symlinks
+    -P	with -R change symlink, do not follow symlinks (default)
+    -v	verbose output.
+
+config CHOWN
+  bool "chown"
+  default y
+  help
+    see: chgrp
+*/
+
+#define FOR_chgrp
+#define FORCE_FLAGS
+#include "toys.h"
+
+GLOBALS(
+  uid_t owner;
+  gid_t group;
+  char *owner_name, *group_name;
+  int symfollow;
+)
+
+static int do_chgrp(struct dirtree *node)
+{
+  int fd, ret, flags = toys.optflags;
+
+  // Depth first search
+  if (!dirtree_notdotdot(node)) return 0;
+  if ((flags & FLAG_R) && !node->again && S_ISDIR(node->st.st_mode))
+    return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(flags&FLAG_L));
+
+  fd = dirtree_parentfd(node);
+  ret = fchownat(fd, node->name, TT.owner, TT.group,
+    AT_SYMLINK_NOFOLLOW*(!(flags&(FLAG_L|FLAG_H)) && (flags&(FLAG_h|FLAG_R))));
+
+  if (ret || (flags & FLAG_v)) {
+    char *path = dirtree_path(node, 0);
+    if (flags & FLAG_v)
+      xprintf("%s %s%s%s %s\n", toys.which->name,
+        TT.owner_name ? TT.owner_name : "",
+        toys.which->name[2]=='o' && TT.group_name ? ":" : "",
+        TT.group_name ? TT.group_name : "", path);
+    if (ret == -1 && !(toys.optflags & FLAG_f))
+      perror_msg("'%s' to '%s:%s'", path, TT.owner_name, TT.group_name);
+    free(path);
+  }
+  toys.exitval |= ret;
+
+  return 0;
+}
+
+void chgrp_main(void)
+{
+  int ischown = toys.which->name[2] == 'o';
+  char **s, *own;
+
+  TT.owner = TT.group = -1;
+
+  // Distinguish chown from chgrp
+  if (ischown) {
+    char *grp;
+
+    own = xstrdup(*toys.optargs);
+    if ((grp = strchr(own, ':')) || (grp = strchr(own, '.'))) {
+      *(grp++) = 0;
+      TT.group_name = grp;
+    }
+    if (*own) TT.owner = xgetuid(TT.owner_name = own);
+  } else TT.group_name = *toys.optargs;
+
+  if (TT.group_name && *TT.group_name)
+    TT.group = xgetgid(TT.group_name);
+
+  for (s=toys.optargs+1; *s; s++)
+    dirtree_flagread(*s, DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)),
+      do_chgrp);
+
+  if (CFG_TOYBOX_FREE && ischown) free(own);
+}
+
+void chown_main()
+{
+  chgrp_main();
+}
diff --git a/toybox/toys/posix/chmod.c b/toybox/toys/posix/chmod.c
new file mode 100644
index 0000000..4292439
--- /dev/null
+++ b/toybox/toys/posix/chmod.c
@@ -0,0 +1,65 @@
+/* chmod.c - Change file mode bits
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/chmod.html
+
+USE_CHMOD(NEWTOY(chmod, "<2?vRf[-vf]", TOYFLAG_BIN))
+
+config CHMOD
+  bool "chmod"
+  default y
+  help
+    usage: chmod [-R] MODE FILE...
+
+    Change mode of listed file[s] (recursively with -R).
+
+    MODE can be (comma-separated) stanzas: [ugoa][+-=][rwxstXugo]
+
+    Stanzas are applied in order: For each category (u = user,
+    g = group, o = other, a = all three, if none specified default is a),
+    set (+), clear (-), or copy (=), r = read, w = write, x = execute.
+    s = u+s = suid, g+s = sgid, o+s = sticky. (+t is an alias for o+s).
+    suid/sgid: execute as the user/group who owns the file.
+    sticky: can't delete files you don't own out of this directory
+    X = x for directories or if any category already has x set.
+
+    Or MODE can be an octal value up to 7777	ug uuugggooo	top +
+    bit 1 = o+x, bit 1<<8 = u+w, 1<<11 = g+1	sstrwxrwxrwx	bottom
+
+    Examples:
+    chmod u+w file - allow owner of "file" to write to it.
+    chmod 744 file - user can read/write/execute, everyone else read only
+*/
+
+#define FOR_chmod
+#include "toys.h"
+
+GLOBALS(
+  char *mode;
+)
+
+static int do_chmod(struct dirtree *try)
+{
+  mode_t mode;
+
+  if (!dirtree_notdotdot(try)) return 0;
+
+  mode = string_to_mode(TT.mode, try->st.st_mode);
+  if (toys.optflags & FLAG_v) {
+    char *s = dirtree_path(try, 0);
+    printf("chmod '%s' to %04o\n", s, mode);
+    free(s);
+  }
+  wfchmodat(dirtree_parentfd(try), try->name, mode);
+
+  return (toys.optflags & FLAG_R) ? DIRTREE_RECURSE : 0;
+}
+
+void chmod_main(void)
+{
+  TT.mode = *toys.optargs;
+  char **file;
+
+  for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chmod);
+}
diff --git a/toybox/toys/posix/cksum.c b/toybox/toys/posix/cksum.c
new file mode 100644
index 0000000..bcb2843
--- /dev/null
+++ b/toybox/toys/posix/cksum.c
@@ -0,0 +1,83 @@
+/* cksum.c - produce crc32 checksum value for each input
+ *
+ * Copyright 2008 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/cksum.html
+
+USE_CKSUM(NEWTOY(cksum, "HIPLN", TOYFLAG_BIN))
+
+config CKSUM
+  bool "cksum"
+  default y
+  help
+    usage: cksum [-IPLN] [file...]
+
+    For each file, output crc32 checksum value, length and name of file.
+    If no files listed, copy from stdin.  Filename "-" is a synonym for stdin.
+
+    -H	Hexadecimal checksum (defaults to decimal)
+    -L	Little endian (defaults to big endian)
+    -P	Pre-inversion
+    -I	Skip post-inversion
+    -N	Do not include length in CRC calculation
+*/
+
+#define FOR_cksum
+#include "toys.h"
+
+GLOBALS(
+  unsigned crc_table[256];
+)
+
+static unsigned cksum_be(unsigned crc, unsigned char c)
+{
+  return (crc<<8)^TT.crc_table[(crc>>24)^c];
+}
+
+static unsigned cksum_le(unsigned crc, unsigned char c)
+{
+  return TT.crc_table[(crc^c)&0xff] ^ (crc>>8);
+}
+
+static void do_cksum(int fd, char *name)
+{
+  unsigned crc = (toys.optflags & FLAG_P) ? 0xffffffff : 0;
+  uint64_t llen = 0, llen2;
+  unsigned (*cksum)(unsigned crc, unsigned char c);
+
+  cksum = (toys.optflags & FLAG_L) ? cksum_le : cksum_be;
+  // CRC the data
+
+  for (;;) {
+    int len, i;
+
+    len = read(fd, toybuf, sizeof(toybuf));
+    if (len<0) perror_msg_raw(name);
+    if (len<1) break;
+
+    llen += len;
+    for (i=0; i<len; i++) crc=cksum(crc, toybuf[i]);
+  }
+
+  // CRC the length
+
+  llen2 = llen;
+  if (!(toys.optflags & FLAG_N)) {
+    while (llen) {
+      crc = cksum(crc, llen);
+      llen >>= 8;
+    }
+  }
+
+  printf((toys.optflags & FLAG_H) ? "%x" : "%u",
+    (toys.optflags & FLAG_I) ? crc : ~crc);
+  printf(" %"PRIu64, llen2);
+  if (strcmp("-", name)) printf(" %s", name);
+  xputc('\n');
+}
+
+void cksum_main(void)
+{
+  crc_init(TT.crc_table, toys.optflags & FLAG_L);
+  loopfiles(toys.optargs, do_cksum);
+}
diff --git a/toybox/toys/posix/cmp.c b/toybox/toys/posix/cmp.c
new file mode 100644
index 0000000..527fbfd
--- /dev/null
+++ b/toybox/toys/posix/cmp.c
@@ -0,0 +1,84 @@
+/* cmp.c - Compare two files.
+ *
+ * Copyright 2012 Timothy Elliott <tle@holymonkey.com>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/cmp.html
+
+USE_CMP(NEWTOY(cmp, "<2>2ls[!ls]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config CMP
+  bool "cmp"
+  default y
+  help
+    usage: cmp [-l] [-s] FILE1 FILE2
+
+    Compare the contents of two files.
+
+    -l	show all differing bytes
+    -s	silent
+*/
+
+#define FOR_cmp
+#include "toys.h"
+
+GLOBALS(
+  int fd;
+  char *name;
+)
+
+// This handles opening the file and
+
+static void do_cmp(int fd, char *name)
+{
+  int i, len1, len2, min_len, size = sizeof(toybuf)/2;
+  long byte_no = 1, line_no = 1;
+  char *buf2 = toybuf+size;
+
+  // First time through, cache the data and return.
+  if (!TT.fd) {
+    TT.name = name;
+    // On return the old filehandle is closed, and this assures that even
+    // if we were called with stdin closed, the new filehandle != 0.
+    TT.fd = dup(fd);
+    return;
+  }
+
+  for (;;) {
+    len1 = readall(TT.fd, toybuf, size);
+    len2 = readall(fd, buf2, size);
+
+    min_len = len1 < len2 ? len1 : len2;
+    for (i=0; i<min_len; i++) {
+      if (toybuf[i] != buf2[i]) {
+        toys.exitval = 1;
+        if (toys.optflags & FLAG_l)
+          printf("%ld %o %o\n", byte_no, toybuf[i], buf2[i]);
+        else {
+          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;
+        }
+      }
+      byte_no++;
+      if (toybuf[i] == '\n') line_no++;
+    }
+    if (len1 != len2) {
+      if (!(toys.optflags & FLAG_s))
+        fprintf(stderr, "cmp: EOF on %s\n", len1 < len2 ? TT.name : name);
+      toys.exitval = 1;
+      break;
+    }
+    if (len1 < 1) break;
+  }
+out:
+  if (CFG_TOYBOX_FREE) close(TT.fd);
+}
+
+void cmp_main(void)
+{
+  loopfiles_rw(toys.optargs, O_CLOEXEC, 0, toys.optflags&FLAG_s, do_cmp);
+}
+
diff --git a/toybox/toys/posix/comm.c b/toybox/toys/posix/comm.c
new file mode 100644
index 0000000..ded262f
--- /dev/null
+++ b/toybox/toys/posix/comm.c
@@ -0,0 +1,80 @@
+/* comm.c - select or reject lines common to two files
+ *
+ * Copyright 2012 Ilya Kuzmich <ikv@safe-mail.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/comm.html
+
+// <# and ># take single digit, so 321 define flags
+USE_COMM(NEWTOY(comm, "<2>2321", TOYFLAG_USR|TOYFLAG_BIN))
+
+config COMM
+  bool "comm"
+  default y
+  help
+    usage: comm [-123] FILE1 FILE2
+
+    Reads FILE1 and FILE2, which should be ordered, and produces three text
+    columns as output: lines only in FILE1; lines only in FILE2; and lines
+    in both files. Filename "-" is a synonym for stdin.
+
+    -1 suppress the output column of lines unique to FILE1
+    -2 suppress the output column of lines unique to FILE2
+    -3 suppress the output column of lines duplicated in FILE1 and FILE2
+*/
+
+#define FOR_comm
+#include "toys.h"
+
+static void writeline(const char *line, int col)
+{
+  if (col == 0 && toys.optflags & FLAG_1) return;
+  else if (col == 1) {
+    if (toys.optflags & FLAG_2) return;
+    if (!(toys.optflags & FLAG_1)) putchar('\t');
+  } else if (col == 2) {
+    if (toys.optflags & FLAG_3) return;
+    if (!(toys.optflags & FLAG_1)) putchar('\t');
+    if (!(toys.optflags & FLAG_2)) putchar('\t');
+  }
+  puts(line);
+}
+
+void comm_main(void)
+{
+  int file[2];
+  char *line[2];
+  int i;
+
+  if (toys.optflags == 7) return;
+
+  for (i = 0; i < 2; i++) {
+    file[i] = xopenro(toys.optargs[i]);
+    line[i] = get_line(file[i]);
+  }
+
+  while (line[0] && line[1]) {
+    int order = strcmp(line[0], line[1]);
+
+    if (order == 0) {
+      writeline(line[0], 2);
+      for (i = 0; i < 2; i++) {
+        free(line[i]);
+        line[i] = get_line(file[i]);
+      }
+    } else {
+      i = order < 0 ? 0 : 1;
+      writeline(line[i], i);
+      free(line[i]);
+      line[i] = get_line(file[i]);
+    }
+  }
+
+  /* print rest of the longer file */
+  for (i = line[0] ? 0 : 1; line[i];) {
+    writeline(line[i], i);
+    free(line[i]);
+    line[i] = get_line(file[i]);
+  }
+
+  if (CFG_TOYBOX_FREE) for (i = 0; i < 2; i++) xclose(file[i]);
+}
diff --git a/toybox/toys/posix/cp.c b/toybox/toys/posix/cp.c
new file mode 100644
index 0000000..0dd63a7
--- /dev/null
+++ b/toybox/toys/posix/cp.c
@@ -0,0 +1,507 @@
+/* Copyright 2008 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/cp.html
+ * And http://opengroup.org/onlinepubs/9699919799/utilities/mv.html
+ * And http://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic.html#INSTALL
+ *
+ * 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):;")"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 [-adlnrsvfipRHLP] SOURCE... DEST
+
+    Copy files from SOURCE to DEST.  If more than one SOURCE, DEST must
+    be a directory.
+
+    -f	delete destination files we can't write to
+    -F	delete any existing destination file first (--remove-destination)
+    -i	interactive, prompt before overwriting existing DEST
+    -p	preserve timestamps, ownership, and mode
+    -R	recurse into subdirectories (DEST must be a directory)
+    -H	Follow symlinks listed on command line
+    -L	Follow all symlinks
+    -P	Do not follow symlinks [default]
+    -a	same as -dpr
+    -d	don't dereference symlinks
+    -l	hard link instead of copy
+    -n	no clobber (don't overwrite DEST)
+    -r	synonym for -R
+    -s	symlink instead of copy
+    -v	verbose
+
+config CP_PRESERVE
+  bool "cp --preserve support"
+  default y
+  depends on CP
+  help
+    usage: cp [--preserve=motcxa]
+
+    --preserve takes either a comma separated list of attributes, or the first
+    letter(s) of:
+
+            mode - permissions (ignore umask for rwx, copy suid and sticky bit)
+       ownership - user and group
+      timestamps - file creation, modification, and access times.
+         context - security context
+           xattr - extended attributes
+             all - all of the above
+
+config MV
+  bool "mv"
+  default y
+  help
+    usage: mv [-fivn] SOURCE... DEST"
+
+    -f	force copy by deleting destination file
+    -i	interactive, prompt before overwriting existing DEST
+    -v	verbose
+    -n	no clobber (don't overwrite DEST)
+
+config INSTALL
+  bool "install"
+  default y
+  help
+    usage: install [-dDpsv] [-o USER] [-g GROUP] [-m MODE] [SOURCE...] DEST
+
+    Copy files and set attributes.
+
+    -d	Act like mkdir -p
+    -D	Create leading directories for DEST
+    -g	Make copy belong to GROUP
+    -m	Set permissions to MODE
+    -o	Make copy belong to USER
+    -p	Preserve timestamps
+    -s	Call "strip -p"
+    -v	Verbose
+*/
+
+#define FORCE_FLAGS
+#define FOR_cp
+#include "toys.h"
+
+GLOBALS(
+  union {
+    struct {
+      // install's options
+      char *group;
+      char *user;
+      char *mode;
+    } i;
+    struct {
+      char *preserve;
+    } c;
+  };
+
+  char *destname;
+  struct stat top;
+  int (*callback)(struct dirtree *try);
+  uid_t uid;
+  gid_t gid;
+  int pflags;
+)
+
+struct cp_preserve {
+  char *name;
+} static const cp_preserve[] = TAGGED_ARRAY(CP,
+  {"mode"}, {"ownership"}, {"timestamps"}, {"context"}, {"xattr"},
+);
+
+// Callback from dirtree_read() for each file/directory under a source dir.
+
+int cp_node(struct dirtree *try)
+{
+  int fdout = -1, cfd = try->parent ? try->parent->extra : AT_FDCWD,
+      tfd = dirtree_parentfd(try);
+  unsigned flags = toys.optflags;
+  char *catch = try->parent ? try->name : TT.destname, *err = "%s";
+  struct stat cst;
+
+  if (!dirtree_notdotdot(try)) return 0;
+
+  // If returning from COMEAGAIN, jump straight to -p logic at end.
+  if (S_ISDIR(try->st.st_mode) && try->again) {
+    fdout = try->extra;
+    err = 0;
+  } else {
+
+    // -d is only the same as -r for symlinks, not for directories
+    if (S_ISLNK(try->st.st_mode) && (flags & FLAG_d)) flags |= FLAG_r;
+
+    // Detect recursive copies via repeated top node (cp -R .. .) or
+    // identical source/target (fun with hardlinks).
+    if ((TT.top.st_dev == try->st.st_dev && TT.top.st_ino == try->st.st_ino
+         && (catch = TT.destname))
+        || (!fstatat(cfd, catch, &cst, 0) && cst.st_dev == try->st.st_dev
+         && cst.st_ino == try->st.st_ino))
+    {
+      error_msg("'%s' is '%s'", catch, err = dirtree_path(try, 0));
+      free(err);
+
+      return 0;
+    }
+
+    // Handle -invF
+
+    if (!faccessat(cfd, catch, F_OK, 0) && !S_ISDIR(cst.st_mode)) {
+      char *s;
+
+      if (S_ISDIR(try->st.st_mode)) {
+        error_msg("dir at '%s'", s = dirtree_path(try, 0));
+        free(s);
+        return 0;
+      } else if ((flags & FLAG_F) && unlinkat(cfd, catch, 0)) {
+        error_msg("unlink '%s'", catch);
+        return 0;
+      } else if (flags & FLAG_n) return 0;
+      else if (flags & FLAG_i) {
+        fprintf(stderr, "%s: overwrite '%s'", toys.which->name,
+          s = dirtree_path(try, 0));
+        free(s);
+        if (!yesno(1)) return 0;
+      }
+    }
+
+    if (flags & FLAG_v) {
+      char *s = dirtree_path(try, 0);
+      printf("%s '%s'\n", toys.which->name, s);
+      free(s);
+    }
+
+    // Loop for -f retry after unlink
+    do {
+
+      // directory, hardlink, symlink, mknod (char, block, fifo, socket), file
+
+      // Copy directory
+
+      if (S_ISDIR(try->st.st_mode)) {
+        struct stat st2;
+
+        if (!(flags & (FLAG_a|FLAG_r|FLAG_R))) {
+          err = "Skipped dir '%s'";
+          catch = try->name;
+          break;
+        }
+
+        // Always make directory writeable to us, so we can create files in it.
+        //
+        // Yes, there's a race window between mkdir() and open() so it's
+        // possible that -p can be made to chown a directory other than the one
+        // we created. The closest we can do to closing this is make sure
+        // that what we open _is_ a directory rather than something else.
+
+        if (!mkdirat(cfd, catch, try->st.st_mode | 0200) || errno == EEXIST)
+          if (-1 != (try->extra = openat(cfd, catch, O_NOFOLLOW)))
+            if (!fstat(try->extra, &st2) && S_ISDIR(st2.st_mode))
+              return DIRTREE_COMEAGAIN
+                     | (DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_L));
+
+      // Hardlink
+
+      } else if (flags & FLAG_l) {
+        if (!linkat(tfd, try->name, cfd, catch, 0)) err = 0;
+
+      // Copy tree as symlinks. For non-absolute paths this involves
+      // appending the right number of .. entries as you go down the tree.
+
+      } else if (flags & FLAG_s) {
+        char *s;
+        struct dirtree *or;
+        int dotdots = 0;
+
+        s = dirtree_path(try, 0);
+        for (or = try; or->parent; or = or->parent) dotdots++;
+
+        if (*or->name == '/') dotdots = 0;
+        if (dotdots) {
+          char *s2 = xmprintf("%*c%s", 3*dotdots, ' ', s);
+          free(s);
+          s = s2;
+          while(dotdots--) {
+            memcpy(s2, "../", 3);
+            s2 += 3;
+          }
+        }
+        if (!symlinkat(s, cfd, catch)) {
+          err = 0;
+          fdout = AT_FDCWD;
+        }
+        free(s);
+
+      // Do something _other_ than copy contents of a file?
+      } else if (!S_ISREG(try->st.st_mode)
+                 && (try->parent || (flags & (FLAG_a|FLAG_r))))
+      {
+        int i;
+
+        // make symlink, or make block/char/fifo/socket
+        if (S_ISLNK(try->st.st_mode)
+            ? ((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;
+          fdout = AT_FDCWD;
+        }
+
+      // Copy contents of file.
+      } else {
+        int fdin;
+
+        fdin = openat(tfd, try->name, O_RDONLY);
+        if (fdin < 0) {
+          catch = try->name;
+          break;
+        }
+        fdout = openat(cfd, catch, O_RDWR|O_CREAT|O_TRUNC, try->st.st_mode);
+        if (fdout >= 0) {
+          xsendfile(fdin, fdout);
+          err = 0;
+        }
+
+        // We only copy xattrs for files because there's no flistxattrat()
+        if (TT.pflags&(_CP_xattr|_CP_context)) {
+          ssize_t listlen = flistxattr(fdin, 0, 0), len;
+          char *name, *value, *list;
+
+          if (listlen>0) {
+            list = xmalloc(listlen);
+            flistxattr(fdin, list, listlen);
+            list[listlen-1] = 0; // I do not trust this API.
+            for (name = list; name-list < listlen; name += strlen(name)+1) {
+              if (!(TT.pflags&_CP_xattr) && strncmp(name, "security.", 9))
+                continue;
+              if ((len = fgetxattr(fdin, name, 0, 0))>0) {
+                value = xmalloc(len);
+                if (len == fgetxattr(fdin, name, value, len))
+                  if (fsetxattr(fdout, name, value, len, 0))
+                    perror_msg("%s setxattr(%s=%s)", catch, name, value);
+                free(value);
+              }
+            }
+            free(list);
+          }
+        }
+
+        close(fdin);
+      }
+    } while (err && (flags & (FLAG_f|FLAG_n)) && !unlinkat(cfd, catch, 0));
+  }
+
+  // Did we make a thing?
+  if (fdout != -1) {
+    int rc;
+
+    // Inability to set --preserve isn't fatal, some require root access.
+
+    // ownership
+    if (TT.pflags & _CP_ownership) {
+
+      // permission bits already correct for mknod and don't apply to symlink
+      // If we can't get a filehandle to the actual object, use racy functions
+      if (fdout == AT_FDCWD)
+        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 && !geteuid()) {
+        char *pp;
+
+        perror_msg("chown '%s'", pp = dirtree_path(try, 0));
+        free(pp);
+      }
+    }
+
+    // timestamp
+    if (TT.pflags & _CP_timestamps) {
+      struct timespec times[] = {try->st.st_atim, try->st.st_mtim};
+
+      if (fdout == AT_FDCWD) utimensat(cfd, catch, times, AT_SYMLINK_NOFOLLOW);
+      else futimens(fdout, times);
+    }
+
+    // mode comes last because other syscalls can strip suid bit
+    if (fdout != AT_FDCWD) {
+      if (TT.pflags & _CP_mode) fchmod(fdout, try->st.st_mode);
+      xclose(fdout);
+    }
+
+    if (CFG_MV && toys.which->name[0] == 'm')
+      if (unlinkat(tfd, try->name, S_ISDIR(try->st.st_mode) ? AT_REMOVEDIR :0))
+        err = "%s";
+  }
+
+  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;
+}
+
+void cp_main(void)
+{
+  char *destname = toys.optargs[--toys.optc];
+  int i, destdir = !stat(destname, &TT.top) && S_ISDIR(TT.top.st_mode);
+
+  if (toys.optc>1 && !destdir) error_exit("'%s' not directory", destname);
+
+  if (toys.optflags & (FLAG_a|FLAG_p)) {
+    TT.pflags = CP_mode|CP_ownership|CP_timestamps;
+    umask(0);
+  }
+  // Not using comma_args() (yet?) because interpeting as letters.
+  if (CFG_CP_PRESERVE && (toys.optflags & FLAG_preserve)) {
+    char *pre = xstrdup(TT.c.preserve), *s;
+
+    if (comma_scan(pre, "all", 1)) TT.pflags = ~0;
+    for (i=0; i<ARRAY_LEN(cp_preserve); i++)
+      if (comma_scan(pre, cp_preserve[i].name, 1)) TT.pflags |= 1<<i;
+    if (*pre) {
+
+      // Try to interpret as letters, commas won't set anything this doesn't.
+      for (s = TT.c.preserve; *s; s++) {
+        for (i=0; i<ARRAY_LEN(cp_preserve); i++)
+          if (*s == *cp_preserve[i].name) break;
+        if (i == ARRAY_LEN(cp_preserve)) {
+          if (*s == 'a') TT.pflags = ~0;
+          else break;
+        } else TT.pflags |= 1<<i;
+      }
+
+      if (*s) error_exit("bad --preserve=%s", pre);
+    }
+    free(pre);
+  }
+  if (!TT.callback) TT.callback = cp_node;
+
+  // Loop through sources
+  for (i=0; i<toys.optc; i++) {
+    char *src = toys.optargs[i];
+    int rc = 1;
+
+    if (destdir) TT.destname = xmprintf("%s/%s", destname, basename(src));
+    else TT.destname = destname;
+
+    errno = EXDEV;
+    if (CFG_MV && toys.which->name[0] == 'm') {
+      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);
+
+        // 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);
+    }
+
+    // Copy if we didn't mv, skipping nonexistent sources
+    if (rc) {
+      if (errno!=EXDEV || dirtree_flagread(src, DIRTREE_SHUTUP+
+        DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)), TT.callback))
+          perror_msg("bad '%s'", src);
+    }
+    if (destdir) free(TT.destname);
+  }
+}
+
+void mv_main(void)
+{
+  toys.optflags |= FLAG_d|FLAG_p|FLAG_R;
+
+  cp_main();
+}
+
+// Export cp flags into install's flag context.
+
+static inline int cp_flag_F(void) { return FLAG_F; };
+static inline int cp_flag_p(void) { return FLAG_p; };
+static inline int cp_flag_v(void) { return FLAG_v; };
+
+// Switch to install's flag context
+#define CLEANUP_cp
+#define FOR_install
+#include <generated/flags.h>
+
+static int install_node(struct dirtree *try)
+{
+  try->st.st_mode = (TT.i.mode)
+    ? string_to_mode(TT.i.mode, try->st.st_mode) : 0755;
+  if (TT.i.group) try->st.st_gid = TT.gid;
+  if (TT.i.user) try->st.st_uid = TT.uid;
+
+  // Always returns 0 because no -r
+  cp_node(try);
+
+  // No -r so always one level deep, so destname as set by cp_node() is correct
+  if (toys.optflags & FLAG_s)
+    if (xrun((char *[]){"strip", "-p", TT.destname, 0})) toys.exitval = 1;
+
+  return 0;
+}
+
+void install_main(void)
+{
+  char **ss;
+  int flags = toys.optflags;
+
+  if (flags & FLAG_d) {
+    for (ss = toys.optargs; *ss; ss++) {
+      if (mkpathat(AT_FDCWD, *ss, 0777, 3)) perror_msg_raw(*ss);
+      if (flags & FLAG_v) printf("%s\n", *ss);
+    }
+
+    return;
+  }
+
+  if (toys.optflags & FLAG_D) {
+    TT.destname = toys.optargs[toys.optc-1];
+    if (mkpathat(AT_FDCWD, TT.destname, 0, 2))
+      perror_exit("-D '%s'", TT.destname);
+    if (toys.optc == 1) return;
+  }
+  if (toys.optc < 2) error_exit("needs 2 args");
+
+  // Translate flags from install to cp
+  toys.optflags = cp_flag_F();
+  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 = xgetuid(TT.i.user);
+  if (TT.i.group) TT.gid = xgetgid(TT.i.group);
+
+  TT.callback = install_node;
+  cp_main();
+}
diff --git a/toybox/toys/posix/cpio.c b/toybox/toys/posix/cpio.c
new file mode 100644
index 0000000..3bd40f4
--- /dev/null
+++ b/toybox/toys/posix/cpio.c
@@ -0,0 +1,285 @@
+/* cpio.c - a basic cpio
+ *
+ * Written 2013 AD by Isaac Dunham; this code is placed under the
+ * same license as toybox or as CC0, at your option.
+ *
+ * Portions Copyright 2015 by Frontier Silicon Ltd.
+ *
+ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cpio.html
+ * and http://pubs.opengroup.org/onlinepubs/7908799/xcu/cpio.html
+ *
+ * Yes, that's SUSv2, the newer standards removed it around the time RPM
+ * and initramfs started heavily using this archive format.
+ *
+ * Modern cpio expanded header to 110 bytes (first field 6 bytes, rest are 8).
+ * In order: magic ino mode uid gid nlink mtime filesize devmajor devminor
+ * rdevmajor rdevminor namesize check
+ * This is the equiavlent of mode -H newc when using GNU CPIO.
+
+USE_CPIO(NEWTOY(cpio, "(no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]", TOYFLAG_BIN))
+
+config CPIO
+  bool "cpio"
+  default y
+  help
+    usage: cpio -{o|t|i|p DEST} [-v] [--verbose] [-F FILE] [--no-preserve-owner]
+           [ignored: -mdu -H newc]
+
+    copy files into and out of a "newc" format cpio archive
+
+    -F FILE	use archive FILE instead of stdin/stdout
+    -p DEST	copy-pass mode, copy stdin file list to directory DEST
+    -i	extract from archive into file system (stdin=archive)
+    -o	create archive (stdin=list of files, stdout=archive)
+    -t	test files (list only, stdin=archive, stdout=list of files)
+    -v	verbose (list files during create/extract)
+    --no-preserve-owner (don't set ownership during extract)
+*/
+
+#define FOR_cpio
+#include "toys.h"
+
+GLOBALS(
+  char *archive;
+  char *pass;
+  char *fmt;
+)
+
+// Read strings, tail padded to 4 byte alignment. Argument "align" is amount
+// by which start of string isn't aligned (usually 0, but header is 110 bytes
+// which is 2 bytes off because the first field wasn't expanded from 6 to 8).
+static char *strpad(int fd, unsigned len, unsigned align)
+{
+  char *str;
+
+  align = (align + len) & 3;
+  if (align) len += (4-align);
+  xreadall(fd, str = xmalloc(len+1), len);
+  str[len]=0; // redundant, in case archive is bad
+
+  return str;
+}
+
+//convert hex to uint; mostly to allow using bits of non-terminated strings
+unsigned x8u(char *hex)
+{
+  unsigned val, inpos = 8, outpos;
+  char pattern[6];
+
+  while (*hex == '0') {
+    hex++;
+    if (!--inpos) return 0;
+  }
+  // Because scanf gratuitously treats %*X differently than printf does.
+  sprintf(pattern, "%%%dX%%n", inpos);
+  sscanf(hex, pattern, &val, &outpos);
+  if (inpos != outpos) error_exit("bad header");
+
+  return val;
+}
+
+void cpio_main(void)
+{
+  // Subtle bit: FLAG_o is 1 so we can just use it to select stdin/stdout.
+  int pipe, afd = toys.optflags & FLAG_o;
+  pid_t pid = 0;
+
+  // In passthrough mode, parent stays in original dir and generates archive
+  // to pipe, child does chdir to new dir and reads archive from stdin (pipe).
+  if (TT.pass) {
+    if (toys.stacktop) {
+      // xpopen() doesn't return from child due to vfork(), instead restarts
+      // with !toys.stacktop
+      pid = xpopen(0, &pipe, 0);
+      afd = pipe;
+    } else {
+      // child
+      toys.optflags |= FLAG_i;
+      xchdir(TT.pass);
+    }
+  }
+
+  if (TT.archive) {
+    int perm = (toys.optflags & FLAG_o) ? O_CREAT|O_WRONLY|O_TRUNC : O_RDONLY;
+
+    afd = xcreate(TT.archive, perm, 0644);
+  }
+
+  // read cpio archive
+
+  if (toys.optflags & (FLAG_i|FLAG_t)) for (;;) {
+    char *name, *tofree, *data;
+    unsigned size, mode, uid, gid, timestamp;
+    int test = toys.optflags & FLAG_t, err = 0;
+
+    // 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);
+      break;
+    }
+
+    // If you want to extract absolute paths, "cd /" and run cpio.
+    while (*name == '/') name++;
+    // TODO: remove .. entries
+
+    size = x8u(toybuf+54);
+    mode = x8u(toybuf+14);
+    uid = x8u(toybuf+22);
+    gid = x8u(toybuf+30);
+    timestamp = x8u(toybuf+46); // unsigned 32 bit, so year 2100 problem
+
+    if (toys.optflags & (FLAG_t|FLAG_v)) puts(name);
+
+    if (!test && strrchr(name, '/') && mkpathat(AT_FDCWD, name, 0, 2)) {
+      perror_msg("mkpath '%s'", name);
+      test++;
+    }
+
+    // Consume entire record even if it couldn't create file, so we're
+    // properly aligned with next file.
+
+    if (S_ISDIR(mode)) {
+      if (!test) err = mkdir(name, mode);
+    } else if (S_ISLNK(mode)) {
+      data = strpad(afd, size, 0);
+      if (!test) err = symlink(data, name);
+      free(data);
+      // Can't get a filehandle to a symlink, so do special chown
+      if (!err && !geteuid() && !(toys.optflags & FLAG_no_preserve_owner))
+        err = lchown(name, uid, gid);
+    } else if (S_ISREG(mode)) {
+      int fd = test ? 0 : open(name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, mode);
+
+      // If write fails, we still need to read/discard data to continue with
+      // archive. Since doing so overwrites errno, report error now
+      if (fd < 0) {
+        perror_msg("create %s", name);
+        test++;
+      }
+
+      data = toybuf;
+      while (size) {
+        if (size < sizeof(toybuf)) data = strpad(afd, size, 0);
+        else xreadall(afd, toybuf, sizeof(toybuf));
+        if (!test) xwrite(fd, data, data == toybuf ? sizeof(toybuf) : size);
+        if (data != toybuf) {
+          free(data);
+          break;
+        }
+        size -= sizeof(toybuf);
+      }
+
+      if (!test) {
+        // set owner, restore dropped suid bit
+        if (!geteuid() && !(toys.optflags & FLAG_no_preserve_owner)) {
+          err = fchown(fd, uid, gid);
+          if (!err) err = fchmod(fd, mode);
+        }
+        close(fd);
+      }
+    } else if (!test)
+      err = mknod(name, mode, dev_makedev(x8u(toybuf+78), x8u(toybuf+86)));
+
+    // Set ownership and timestamp.
+    if (!test && !err) {
+      // Creading dir/dev doesn't give us a filehandle, we have to refer to it
+      // by name to chown/utime, but how do we know it's the same item?
+      // Check that we at least have the right type of entity open, and do
+      // NOT restore dropped suid bit in this case.
+      if (!S_ISREG(mode) && !S_ISLNK(mode) && !geteuid()
+          && !(toys.optflags & FLAG_no_preserve_owner))
+      {
+        int fd = open(name, O_RDONLY|O_NOFOLLOW);
+        struct stat st;
+
+        if (fd != -1 && !fstat(fd, &st) && (st.st_mode&S_IFMT) == (mode&S_IFMT))
+          err = fchown(fd, uid, gid);
+        else err = 1;
+
+        close(fd);
+      }
+
+      // set timestamp
+      if (!err) {
+        struct timespec times[2];
+
+        memset(times, 0, sizeof(struct timespec)*2);
+        times[0].tv_sec = times[1].tv_sec = timestamp;
+        err = utimensat(AT_FDCWD, name, times, AT_SYMLINK_NOFOLLOW);
+      }
+    }
+
+    if (err) perror_msg_raw(name);
+    free(tofree);
+
+  // Output cpio archive
+
+  } else {
+    char *name = 0;
+    size_t size = 0;
+
+    for (;;) {
+      struct stat st;
+      unsigned nlen, error = 0, zero = 0;
+      int len, fd = -1;
+      ssize_t llen;
+
+      len = getline(&name, &size, stdin);
+      if (len<1) break;
+      if (name[len-1] == '\n') name[--len] = 0;
+      nlen = len+1;
+      if (lstat(name, &st) || (S_ISREG(st.st_mode)
+          && st.st_size && (fd = open(name, O_RDONLY))<0))
+      {
+        perror_msg_raw(name);
+        continue;
+      }
+
+      if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) st.st_size = 0;
+      if (st.st_size >> 32) perror_msg("skipping >2G file '%s'", name);
+      else {
+        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, 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);
+
+        // NUL Pad header up to 4 multiple bytes.
+        llen = (llen + nlen) & 3;
+        if (llen) xwrite(afd, &zero, 4-llen);
+
+        // Write out body for symlink or regular file
+        llen = st.st_size;
+        if (S_ISLNK(st.st_mode)) {
+          if (readlink(name, toybuf, sizeof(toybuf)-1) == llen)
+            xwrite(afd, toybuf, llen);
+          else perror_msg("readlink '%s'", name);
+        } else while (llen) {
+          nlen = llen > sizeof(toybuf) ? sizeof(toybuf) : llen;
+          llen -= nlen;
+          // If read fails, write anyway (already wrote size in header)
+          if (nlen != readall(fd, toybuf, nlen))
+            if (!error++) perror_msg("bad read from file '%s'", name);
+          xwrite(afd, toybuf, nlen);
+        }
+        llen = st.st_size & 3;
+        if (llen) xwrite(afd, &zero, 4-llen);
+      }
+      close(fd);
+    }
+    free(name);
+
+    memset(toybuf, 0, sizeof(toybuf));
+    xwrite(afd, toybuf,
+      sprintf(toybuf, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0)+4);
+  }
+  if (TT.archive) xclose(afd);
+
+  if (TT.pass) toys.exitval |= xpclose(pid, pipe);
+}
diff --git a/toybox/toys/posix/cut.c b/toybox/toys/posix/cut.c
new file mode 100644
index 0000000..13be5e7
--- /dev/null
+++ b/toybox/toys/posix/cut.c
@@ -0,0 +1,276 @@
+/* cut.c - Cut from a file.
+ *
+ * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2012 Kyungwan Han <asura321@gmail.com>
+ *
+ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cut.html
+ *
+ * TODO: cleanup
+
+USE_CUT(NEWTOY(cut, "b:|c:|f:|d:sn[!cbf]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config CUT
+  bool "cut"
+  default y
+  help
+    usage: cut OPTION... [FILE]...
+
+    Print selected parts of lines from each FILE to standard output.
+
+    -b LIST	select only these bytes from LIST.
+    -c LIST	select only these characters from LIST.
+    -f LIST	select only these fields.
+    -d DELIM	use DELIM instead of TAB for field delimiter.
+    -s	do not print lines not containing delimiters.
+    -n	don't split multibyte characters (Ignored).
+*/
+#define FOR_cut
+#include "toys.h"
+
+GLOBALS(
+  char *delim;
+  char *flist;
+  char *clist;
+  char *blist;
+
+  void *slist_head;
+  unsigned nelem;
+  void (*do_cut)(int fd);
+)
+
+struct slist {
+  struct slist *next;
+  int start, end;
+};
+
+static void add_to_list(int start, int end)
+{
+  struct slist *current, *head_ref, *temp1_node;
+
+  head_ref = TT.slist_head;
+  temp1_node = xzalloc(sizeof(struct slist));
+  temp1_node->start = start;
+  temp1_node->end = end;
+
+  /* Special case for the head end */
+  if (!head_ref || head_ref->start >= start) { 
+      temp1_node->next = head_ref; 
+      head_ref = temp1_node;
+  } else { 
+    /* Locate the node before the point of insertion */   
+    current = head_ref;   
+    while (current->next && current->next->start < temp1_node->start)
+        current = current->next;
+    temp1_node->next = current->next;   
+    current->next = temp1_node;
+  }
+  TT.slist_head = head_ref;
+}
+
+// parse list and add to slist.
+static void parse_list(char *list)
+{
+  for (;;) {
+    char *ctoken = strsep(&list, ","), *dtoken;
+    int start = 0, end = INT_MAX;
+
+    if (!ctoken) break;
+    if (!*ctoken) continue;
+
+    // Get start position.
+    if (*(dtoken = strsep(&ctoken, "-"))) {
+      start = atolx_range(dtoken, 0, INT_MAX);
+      start = (start?(start-1):start);
+    }
+
+    // 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);
+      if (!end) end = INT_MAX;
+      end--;
+      if(end == start) end = -1;
+    }
+    add_to_list(start, end);
+    TT.nelem++;
+  }
+  // if list is missing in command line.
+  if (!TT.nelem) error_exit("missing positions list");
+}
+
+/*
+ * retrive data from the file/s.
+ */
+static void get_data(void)
+{
+  char **argv = toys.optargs; //file name.
+  toys.exitval = EXIT_SUCCESS;
+
+  if(!*argv) TT.do_cut(0); //for stdin
+  else {
+    for(; *argv; ++argv) {
+      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.
+          perror_msg_raw(*argv);
+          continue;
+        }
+        TT.do_cut(fd);
+        xclose(fd);
+      }
+    }
+  }
+}
+
+// perform cut operation on the given delimiter.
+static void do_fcut(int fd)
+{
+  char *buff, *pfield = 0, *delimiter = TT.delim;
+
+  for (;;) {
+    unsigned cpos = 0;
+    int start, ndelimiters = -1;
+    int  nprinted_fields = 0;
+    struct slist *temp_node = TT.slist_head;
+
+    free(pfield);
+    pfield = 0;
+
+    if (!(buff = get_line(fd))) break;
+
+    //does line have any delimiter?.
+    if (strrchr(buff, (int)delimiter[0]) == NULL) {
+      //if not then print whole line and move to next line.
+      if (!(toys.optflags & FLAG_s)) xputs(buff);
+      continue;
+    }
+
+    pfield = xzalloc(strlen(buff) + 1);
+
+    if (temp_node) {
+      //process list on each line.
+      while (cpos < TT.nelem && buff) {
+        if (!temp_node) break;
+        start = temp_node->start;
+        do {
+          char *field = 0;
+
+          //count number of delimeters per line.
+          while (buff) {
+            if (ndelimiters < start) {
+              ndelimiters++;
+              field = strsep(&buff, delimiter);
+            } else break;
+          }
+          //print field (if not yet printed).
+          if (!pfield[ndelimiters]) {
+            if (ndelimiters == start) {
+              //put delimiter.
+              if (nprinted_fields++ > 0) xputc(delimiter[0]);
+              if (field) fputs(field, stdout);
+              //make sure this field won't print again.
+              pfield[ndelimiters] = (char) 0x23; //put some char at this position.
+            }
+          }
+          start++;
+          if ((temp_node->end < 0) || !buff) break;          
+        } while(start <= temp_node->end);
+        temp_node = temp_node->next;
+        cpos++;
+      }
+    }
+    xputc('\n');
+  }
+}
+
+// perform cut operation char or byte.
+static void do_bccut(int fd)
+{
+  char *buff;
+
+  while ((buff = get_line(fd)) != NULL) {
+    unsigned cpos = 0;
+    int buffln = strlen(buff);
+    char *pfield = xzalloc(buffln + 1);
+    struct slist *temp_node = TT.slist_head;
+
+    if (temp_node != NULL) {
+      while (cpos < TT.nelem) {
+        int start;
+
+        if (!temp_node) break;
+        start = temp_node->start;
+        while (start < buffln) {
+          //to avoid duplicate field printing.
+          if (pfield[start]) {
+              if (++start <= temp_node->end) continue;
+              temp_node = temp_node->next;
+              break;
+          } else {
+            //make sure this field won't print again.
+            pfield[start] = (char) 0x23; //put some char at this position.
+            xputc(buff[start]);
+          }
+          if (++start > temp_node->end) {
+            temp_node = temp_node->next;
+            break;
+          }
+        }
+        cpos++;
+      }
+      xputc('\n');
+    }
+    free(pfield);
+    pfield = NULL;
+  }
+}
+
+void cut_main(void)
+{
+  char delimiter = '\t'; //default delimiter.
+  char *list;
+
+  TT.nelem = 0;
+  TT.slist_head = NULL;
+
+  //Get list and assign the function.
+  if (toys.optflags & FLAG_f) {
+    list = TT.flist;
+    TT.do_cut = do_fcut;
+  } else if (toys.optflags & FLAG_c) {
+    list = TT.clist;
+    TT.do_cut = do_bccut;
+  } else {
+    list = TT.blist;
+    TT.do_cut = do_bccut;
+  }
+
+  if (toys.optflags & FLAG_d) {
+    //delimiter must be 1 char.
+    if(TT.delim[0] && TT.delim[1])
+      perror_exit("the delimiter must be a single character");
+    delimiter = TT.delim[0];
+  }
+
+  if(!(toys.optflags & FLAG_d) && (toys.optflags & FLAG_f)) {
+    TT.delim = xzalloc(2);
+    TT.delim[0] = delimiter;
+  }
+  
+  //when field is not specified, cutting has some special handling.
+  if (!(toys.optflags & FLAG_f)) {
+    if (toys.optflags & FLAG_s)
+      perror_exit("suppressing non-delimited lines operating on fields");
+    if (delimiter != '\t')
+      perror_exit("an input delimiter may be specified only when operating on fields");
+  }
+
+  parse_list(list);
+  get_data();
+  if (!(toys.optflags & FLAG_d) && (toys.optflags & FLAG_f)) {
+    free(TT.delim);
+    TT.delim = NULL;
+  }
+  llist_traverse(TT.slist_head, free);
+}
diff --git a/toybox/toys/posix/date.c b/toybox/toys/posix/date.c
new file mode 100644
index 0000000..ca0ca53
--- /dev/null
+++ b/toybox/toys/posix/date.c
@@ -0,0 +1,227 @@
+/* date.c - set/get the date
+ *
+ * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/date.html
+ *
+ * Note: setting a 2 year date is 50 years back/forward from today,
+ * not posix's hardwired magic dates.
+
+USE_DATE(NEWTOY(date, "d:D:r:u[!dr]", TOYFLAG_BIN))
+
+config DATE
+  bool "date"
+  default y
+  help
+    usage: date [-u] [-r FILE] [-d DATE] [+DISPLAY_FORMAT] [-D SET_FORMAT] [SET]
+
+    Set/get the current date/time. With no SET shows the current date.
+
+    Default SET format is "MMDDhhmm[[CC]YY][.ss]", that's (2 digits each)
+    month, day, hour (0-23), and minute. Optionally century, year, and second.
+    Also accepts "@UNIXTIME[.FRACTION]" as seconds since midnight Jan 1 1970.
+
+    -d	Show DATE instead of current time (convert date format)
+    -D	+FORMAT for SET or -d (instead of MMDDhhmm[[CC]YY][.ss])
+    -r	Use modification time of FILE instead of current date
+    -u	Use UTC instead of current timezone
+
+    +FORMAT specifies display format string using these escapes:
+
+    %% literal %             %n newline              %t tab
+    %S seconds (00-60)       %M minute (00-59)       %m month (01-12)
+    %H hour (0-23)           %I hour (01-12)         %p AM/PM
+    %y short year (00-99)    %Y year                 %C century
+    %a short weekday name    %A weekday name         %u day of week (1-7, 1=mon)
+    %b short month name      %B month name           %Z timezone name
+    %j day of year (001-366) %d day of month (01-31) %e day of month ( 1-31)
+    %s seconds past the Epoch
+
+    %U Week of year (0-53 start sunday)   %W Week of year (0-53 start monday)
+    %V Week of year (1-53 start monday, week < 4 days not part of this year) 
+
+    %D = "%m/%d/%y"    %r = "%I : %M : %S %p"   %T = "%H:%M:%S"   %h = "%b"
+    %x locale date     %X locale time           %c locale date/time
+*/
+
+#define FOR_date
+#include "toys.h"
+
+GLOBALS(
+  char *file;
+  char *setfmt;
+  char *showdate;
+
+  char *tz;
+  unsigned nano;
+)
+
+// mktime(3) normalizes the struct tm fields, but date(1) shouldn't.
+static time_t chkmktime(struct tm *tm, const char *str, const char* fmt)
+{
+  struct tm tm0 = *tm;
+  struct tm tm1;
+  time_t t = mktime(tm);
+
+  if (t == -1 || !localtime_r(&t, &tm1) ||
+      tm0.tm_sec != tm1.tm_sec || tm0.tm_min != tm1.tm_min ||
+      tm0.tm_hour != tm1.tm_hour || tm0.tm_mday != tm1.tm_mday ||
+      tm0.tm_mon != tm1.tm_mon) {
+    int len;
+
+    strftime(toybuf, sizeof(toybuf), fmt, &tm0);
+    len = strlen(toybuf) + 1;
+    strftime(toybuf + len, sizeof(toybuf) - len, fmt, &tm1);
+    error_exit("bad date '%s'; %s != %s", str, toybuf, toybuf + len);
+  }
+  return t;
+}
+
+static void utzset(void)
+{
+  if (!(TT.tz = getenv("TZ"))) TT.tz = (char *)1;
+  setenv("TZ", "UTC", 1);
+  tzset();
+}
+
+static void utzreset(void)
+{
+  if (TT.tz) {
+    if (TT.tz != (char *)1) setenv("TZ", TT.tz, 1);
+    else unsetenv("TZ");
+    tzset();
+  }
+}
+
+// Handle default posix date format (mmddhhmm[[cc]yy]) or @UNIX[.FRAC]
+// returns 0 success, nonzero for error
+static int parse_default(char *str, struct tm *tm)
+{
+  int len = 0;
+
+  // Parse @UNIXTIME[.FRACTION]
+  if (*str == '@') {
+    long long ll;
+    time_t tt;
+
+    // Collect seconds and nanoseconds
+    // Note: struct tm hasn't got a fractional seconds field, thus strptime()
+    // doesn't support it, so store nanoseconds out of band (in globals).
+    // tt and ll are separate because we can't guarantee time_t is 64 bit (yet).
+    sscanf(str, "@%lld%n", &ll, &len);
+    if (str[len]=='.') {
+      str += len+1;
+      for (len = 0; len<9; len++) {
+        TT.nano *= 10;
+        if (isdigit(str[len])) TT.nano += str[len]-'0';
+      }
+    }
+    if (str[len]) return 1;
+    tt = ll;
+    gmtime_r(&tt, tm);
+
+    return 0;
+  }
+
+  // Posix format
+  sscanf(str, "%2u%2u%2u%2u%n", &tm->tm_mon, &tm->tm_mday, &tm->tm_hour,
+    &tm->tm_min, &len);
+  if (len != 8) return 1;
+  str += len;
+  tm->tm_mon--;
+
+  // If year specified, overwrite one we fetched earlier
+  if (*str && *str != '.') {
+    unsigned year;
+
+    len = 0;
+    sscanf(str, "%u%n", &year, &len);
+    if (len == 4) tm->tm_year = year - 1900;
+    else if (len != 2) return 1;
+    str += len;
+
+    // 2 digit years, next 50 years are "future", last 50 years are "past".
+    // A "future" date in past is a century ahead.
+    // A non-future date in the future is a century behind.
+    if (len == 2) {
+      unsigned r1 = tm->tm_year % 100, r2 = (tm->tm_year + 50) % 100,
+        century = tm->tm_year - r1;
+
+      if ((r1 < r2) ? (r1 < year && year < r2) : (year < r1 || year > r2)) {
+        if (year < r1) year += 100;
+      } else if (year > r1) year -= 100;
+      tm->tm_year = year + century;
+    }
+  }
+  if (*str == '.') {
+    len = 0;
+    sscanf(str, ".%u%n", &tm->tm_sec, &len);
+    str += len;
+  } else tm->tm_sec = 0;
+
+  return *str;
+}
+
+void date_main(void)
+{
+  char *setdate = *toys.optargs, *format_string = "%a %b %e %H:%M:%S %Z %Y";
+  struct tm tm;
+
+  memset(&tm, 0, sizeof(struct tm));
+
+  // We can't just pass a timezone to mktime because posix.
+  if (toys.optflags & FLAG_u) utzset();
+
+  if (TT.showdate) {
+    if (TT.setfmt) {
+      char *s = strptime(TT.showdate, TT.setfmt+(*TT.setfmt=='+'), &tm);
+
+      if (!s || *s) goto bad_showdate;
+    } else if (parse_default(TT.showdate, &tm)) goto bad_showdate;
+  } else {
+    time_t now;
+
+    if (TT.file) {
+      struct stat st;
+
+      xstat(TT.file, &st);
+      now = st.st_mtim.tv_sec;
+    } else now = time(0);
+
+    ((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&now, &tm);
+  }
+
+  // Fall through if no arguments
+  if (!setdate);
+  // Display the date?
+  else if (*setdate == '+') {
+    format_string = toys.optargs[0]+1;
+    setdate = toys.optargs[1];
+
+  // Set the date
+  } else if (setdate) {
+    struct timeval tv;
+
+    if (parse_default(setdate, &tm)) error_exit("bad date '%s'", setdate);
+
+    if (toys.optflags & FLAG_u) {
+      // We can't just pass a timezone to mktime because posix.
+      utzset();
+      tv.tv_sec = chkmktime(&tm, setdate, format_string);
+      utzreset();
+    } else tv.tv_sec = chkmktime(&tm, setdate, format_string);
+
+    tv.tv_usec = TT.nano/1000;
+    if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date");
+  }
+
+  utzreset();
+  if (!strftime(toybuf, sizeof(toybuf), format_string, &tm))
+    perror_exit("bad format '%s'", format_string);
+  puts(toybuf);
+
+  return;
+
+bad_showdate:
+  error_exit("bad date '%s'", TT.showdate);
+}
diff --git a/toybox/toys/posix/df.c b/toybox/toys/posix/df.c
new file mode 100644
index 0000000..3b6e6d4
--- /dev/null
+++ b/toybox/toys/posix/df.c
@@ -0,0 +1,222 @@
+/* df.c - report free disk space.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/df.html
+
+USE_DF(NEWTOY(df, "HPkht*a[-HPkh]", TOYFLAG_SBIN))
+
+config DF
+  bool "df"
+  default y
+  help
+    usage: df [-HPkh] [-t type] [FILESYSTEM ...]
+
+    The "disk free" command shows total/used/available disk space for
+    each filesystem listed on the command line, or all currently mounted
+    filesystems.
+
+    -P	The SUSv3 "Pedantic" option
+    -k	Sets units back to 1024 bytes (the default without -P)
+    -h	Human readable output (K=1024)
+    -H	Human readable output (k=1000)
+    -t type	Display only filesystems of this type.
+
+    Pedantic provides a slightly less useful output format dictated by Posix,
+    and sets the units to 512 bytes instead of the default 1024 bytes.
+*/
+
+#define FOR_df
+#include "toys.h"
+
+GLOBALS(
+  struct arg_list *fstype;
+
+  long units;
+  int column_widths[5];
+  int header_shown;
+)
+
+static void measure_column(int col, const char *s)
+{
+  size_t len = strlen(s);
+
+  if (TT.column_widths[col] < len) TT.column_widths[col] = len;
+}
+
+static void measure_numeric_column(int col, long long n)
+{
+  snprintf(toybuf, sizeof(toybuf), "%lld", n);
+  return measure_column(col, toybuf);
+}
+
+static void show_header()
+{
+  TT.header_shown = 1;
+
+  // The filesystem column is always at least this wide.
+  if (TT.column_widths[0] < 14) TT.column_widths[0] = 14;
+
+  if (toys.optflags & (FLAG_H|FLAG_h)) {
+    xprintf("%-*s Size  Used Avail Use%% Mounted on\n",
+            TT.column_widths[0], "Filesystem");
+  } else {
+    const char *blocks_label = TT.units == 512 ? "512-blocks" : "1K-blocks";
+    const char *use_label = toys.optflags & FLAG_P ? "Capacity" : "Use%";
+
+    measure_column(1, blocks_label);
+    measure_column(2, "Used");
+    measure_column(3, "Available");
+    measure_column(4, use_label);
+    xprintf("%-*s %*s %*s %*s %*s Mounted on\n",
+            TT.column_widths[0], "Filesystem",
+            TT.column_widths[1], blocks_label,
+            TT.column_widths[2], "Used",
+            TT.column_widths[3], "Available",
+            TT.column_widths[4], use_label);
+
+    // For the "Use%" column, the trailing % should be inside the column.
+    TT.column_widths[4]--;
+  }
+}
+
+static void show_mt(struct mtab_list *mt, int measuring)
+{
+  long long size, used, avail, percent, block;
+  char *device;
+
+  // Return if it wasn't found (should never happen, but with /etc/mtab...)
+  if (!mt) return;
+
+  // If we have -t, skip other filesystem types
+  if (TT.fstype) {
+    struct arg_list *al;
+
+    for (al = TT.fstype; al; al = al->next) 
+      if (!strcmp(mt->type, al->arg)) break;
+
+    if (!al) return;
+  }
+
+  // If we don't have -a, skip synthetic filesystems
+  if (!(toys.optflags & FLAG_a) && !mt->statvfs.f_blocks) return;
+
+  // Figure out how much total/used/free space this filesystem has,
+  // forcing 64-bit math because filesystems are big now.
+  block = mt->statvfs.f_bsize ? mt->statvfs.f_bsize : 1;
+  size = (block * mt->statvfs.f_blocks) / TT.units;
+  used = (block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree)) / TT.units;
+  avail = (block*(getuid()?mt->statvfs.f_bavail:mt->statvfs.f_bfree))/TT.units;
+  if (!(used+avail)) percent = 0;
+  else {
+    percent = (used*100)/(used+avail);
+    if (used*100 != percent*(used+avail)) percent++;
+  }
+
+  device = *mt->device == '/' ? realpath(mt->device, NULL) : NULL;
+  if (!device) device = mt->device;
+
+  if (measuring) {
+    measure_column(0, device);
+    measure_numeric_column(1, size);
+    measure_numeric_column(2, used);
+    measure_numeric_column(3, avail);
+  } else {
+    if (!TT.header_shown) show_header();
+
+    if (toys.optflags & (FLAG_H|FLAG_h)) {
+      char *size_str = toybuf, *used_str = toybuf+64, *avail_str = toybuf+128;
+      int hr_flags = (toys.optflags & FLAG_H) ? HR_1000 : 0;
+
+      human_readable(size_str, size, hr_flags);
+      human_readable(used_str, used, hr_flags);
+      human_readable(avail_str, avail, hr_flags);
+      xprintf("%-*s %4s  %4s  %4s % 3lld%% %s\n",
+        TT.column_widths[0], device,
+        size_str, used_str, avail_str, percent, mt->dir);
+    } else xprintf("%-*s %*lld %*lld %*lld %*lld%% %s\n",
+        TT.column_widths[0], device,
+        TT.column_widths[1], size,
+        TT.column_widths[2], used,
+        TT.column_widths[3], avail,
+        TT.column_widths[4], percent,
+        mt->dir);
+  }
+
+  if (device != mt->device) free(device);
+}
+
+void df_main(void)
+{
+  struct mtab_list *mt, *mtstart, *mtend;
+  int measuring;
+
+  if (toys.optflags & (FLAG_H|FLAG_h)) {
+    TT.units = 1;
+  } else {
+    // Units are 512 bytes if you select "pedantic" without "kilobytes".
+    TT.units = toys.optflags & FLAG_P ? 512 : 1024;
+  }
+
+  if (!(mtstart = xgetmountlist(0))) return;
+  mtend = dlist_terminate(mtstart);
+
+  // If we have a list of filesystems on the command line, loop through them.
+  if (*toys.optargs) {
+    // Measure the names then output the table.
+    for (measuring = 1; measuring >= 0; --measuring) {
+      char **next;
+
+      for (next = toys.optargs; *next; next++) {
+        struct stat st;
+
+        // Stat it (complain if we can't).
+        if (stat(*next, &st)) {
+          perror_msg("'%s'", *next);
+          continue;
+        }
+
+        // Find and display this filesystem.  Use _last_ hit in case of
+        // overmounts (which is first hit in the reversed list).
+        for (mt = mtend; mt; mt = mt->prev) {
+          if (st.st_dev == mt->stat.st_dev
+              || (st.st_rdev && (st.st_rdev == mt->stat.st_dev)))
+          {
+            show_mt(mt, measuring);
+            break;
+          }
+        }
+      }
+    }
+  } else {
+    // Loop through mount list to filter out overmounts.
+    for (mt = mtend; mt; mt = mt->prev) {
+      struct mtab_list *mt2, *mt3;
+
+      // 0:0 is LANANA null device
+      if (!mt->stat.st_dev) continue;
+
+      // Filter out overmounts.
+      mt3 = mt;
+      for (mt2 = mt->prev; mt2; mt2 = mt2->prev) {
+        if (mt->stat.st_dev == mt2->stat.st_dev) {
+          // For --bind mounts, show earliest mount
+          if (!strcmp(mt->device, mt2->device)) {
+            if (!toys.optflags & FLAG_a) mt3->stat.st_dev = 0;
+            mt3 = mt2;
+          } else mt2->stat.st_dev = 0;
+        }
+      }
+    }
+
+    // Measure the names then output the table.
+    for (measuring = 1; measuring >= 0; --measuring) {
+      // Cosmetic: show filesystems in creation order.
+      for (mt = mtstart; mt; mt = mt->next) {
+        if (mt->stat.st_dev) show_mt(mt, measuring);
+      }
+    }
+  }
+
+  if (CFG_TOYBOX_FREE) llist_traverse(mtstart, free);
+}
diff --git a/toybox/toys/posix/dirname.c b/toybox/toys/posix/dirname.c
new file mode 100644
index 0000000..06470ad
--- /dev/null
+++ b/toybox/toys/posix/dirname.c
@@ -0,0 +1,23 @@
+/* dirname.c - show directory portion of path
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/dirname.html
+
+USE_DIRNAME(NEWTOY(dirname, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+
+config DIRNAME
+  bool "dirname"
+  default y
+  help
+    usage: dirname PATH
+
+    Show directory portion of path.
+*/
+
+#include "toys.h"
+
+void dirname_main(void)
+{
+  puts(dirname(*toys.optargs));
+}
diff --git a/toybox/toys/posix/du.c b/toybox/toys/posix/du.c
new file mode 100644
index 0000000..2797b3f
--- /dev/null
+++ b/toybox/toys/posix/du.c
@@ -0,0 +1,161 @@
+/* du.c - disk usage program.
+ *
+ * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/du.html
+ *
+ * TODO: cleanup
+
+USE_DU(NEWTOY(du, "d#<0hmlcaHkKLsx[-HL][-kKmh]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config DU
+  bool "du"
+  default y
+  help
+    usage: du [-d N] [-askxHLlmc] [file...]
+
+    Show disk usage, space consumed by files and directories.
+
+    Size in:
+    -k    1024 byte blocks (default)
+    -K    512 byte blocks (posix)
+    -m    megabytes
+    -h    human readable format (e.g., 1K 243M 2G )
+
+    What to show:
+    -a    all files, not just directories
+    -H    follow symlinks on cmdline
+    -L    follow all symlinks
+    -s    only total size of each argument
+    -x    don't leave this filesystem
+    -c    cumulative total
+    -d N  only depth < N
+    -l    disable hardlink filter
+*/
+
+#define FOR_du
+#include "toys.h"
+
+GLOBALS(
+  long maxdepth;
+
+  long depth, total;
+  dev_t st_dev;
+  void *inodes;
+)
+
+typedef struct node_size {
+  struct dirtree *node;
+  long size;
+} node_size;
+
+// Print the size and name, given size in bytes
+static void print(long long size, struct dirtree *node)
+{
+  char *name = "total";
+
+  if (TT.maxdepth && TT.depth > TT.maxdepth) return;
+
+  if (toys.optflags & FLAG_h) {
+    human_readable(toybuf, size, 0);
+    printf("%s", toybuf);
+  } else {
+    int bits = 10;
+
+    if (toys.optflags & FLAG_K) bits = 9;
+    else if (toys.optflags & FLAG_m) bits = 20;
+
+    printf("%llu", (size>>bits)+!!(size&((1<<bits)-1)));
+  }
+  if (node) name = dirtree_path(node, NULL);
+  xprintf("\t%s\n", name);
+  if (node) free(name);
+}
+
+// Return whether or not we've seen this inode+dev, adding it to the list if
+// we haven't.
+static int seen_inode(void **list, struct stat *st)
+{
+  if (!st) llist_traverse(st, free);
+
+  // Skipping dir nodes isn't _quite_ right. They're not hardlinked, but could
+  // be bind mounted. Still, it's more efficient and the archivers can't use
+  // hardlinked directory info anyway. (Note that we don't catch bind mounted
+  // _files_ because it doesn't change st_nlink.)
+  else if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
+    struct inode_list {
+      struct inode_list *next;
+      ino_t ino;
+      dev_t dev;
+    } *new;
+
+    for (new = *list; new; new = new->next)
+      if(new->ino == st->st_ino && new->dev == st->st_dev)
+        return 1;
+
+    new = xzalloc(sizeof(*new));
+    new->ino = st->st_ino;
+    new->dev = st->st_dev;
+    new->next = *list;
+    *list = new;
+  }
+
+  return 0;
+}
+
+// dirtree callback, comput/display size of node
+static int do_du(struct dirtree *node)
+{
+  if (!node->parent) TT.st_dev = node->st.st_dev;
+  else if (!dirtree_notdotdot(node)) return 0;
+
+  // detect swiching filesystems
+  if ((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev))
+    return 0;
+
+  // Don't loop endlessly on recursive directory symlink
+  if (toys.optflags & FLAG_L) {
+    struct dirtree *try = node;
+
+    while ((try = try->parent))
+      if (node->st.st_dev==try->st.st_dev && node->st.st_ino==try->st.st_ino)
+        return 0;
+  }
+
+  // Don't count hard links twice
+  if (!(toys.optflags & FLAG_l) && !node->again)
+    if (seen_inode(&TT.inodes, &node->st)) return 0;
+
+  // Collect child info before printing directory size
+  if (S_ISDIR(node->st.st_mode)) {
+    if (!node->again) {
+      TT.depth++;
+      return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_L));
+    } else TT.depth--;
+  }
+
+  node->extra += node->st.st_blocks;
+  if (node->parent) node->parent->extra += node->extra;
+  else TT.total += node->extra;
+
+  if ((toys.optflags & FLAG_a) || !node->parent
+      || (S_ISDIR(node->st.st_mode) && !(toys.optflags & FLAG_s)))
+  {
+    print(node->extra*512, node);
+  }
+
+  return 0;
+}
+
+void du_main(void)
+{
+  char *noargs[] = {".", 0}, **args;
+
+  // Loop over command line arguments, recursing through children
+  for (args = toys.optc ? toys.optargs : noargs; *args; args++)
+    dirtree_flagread(*args, DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)),
+      do_du);
+  if (toys.optflags & FLAG_c) print(TT.total*512, 0);
+
+  if (CFG_TOYBOX_FREE) seen_inode(TT.inodes, 0);
+}
diff --git a/toybox/toys/posix/echo.c b/toybox/toys/posix/echo.c
new file mode 100644
index 0000000..33de678
--- /dev/null
+++ b/toybox/toys/posix/echo.c
@@ -0,0 +1,95 @@
+/* echo.c - echo supporting -n and -e.
+ *
+ * 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))
+
+config ECHO
+  bool "echo"
+  default y
+  help
+    usage: echo [-ne] [args...]
+
+    Write each argument to stdout, with one space between each, followed
+    by a newline.
+
+    -n	No trailing newline.
+    -e	Process the following escape sequences:
+    	\\	backslash
+    	\0NNN	octal values (1 to 3 digits)
+    	\a	alert (beep/flash)
+    	\b	backspace
+    	\c	stop output here (avoids trailing newline)
+    	\f	form feed
+    	\n	newline
+    	\r	carriage return
+    	\t	horizontal tab
+    	\v	vertical tab
+    	\xHH	hexadecimal values (1 to 2 digits)
+*/
+
+#define FOR_echo
+#include "toys.h"
+
+void echo_main(void)
+{
+  int i = 0, out;
+  char *arg, *c;
+
+  for (;;) {
+    arg = toys.optargs[i];
+    if (!arg) break;
+    if (i++) putchar(' ');
+
+    // Should we output arg verbatim?
+
+    if (!(toys.optflags & FLAG_e)) {
+      xprintf("%s", arg);
+      continue;
+    }
+
+    // Handle -e
+
+    for (c = arg;;) {
+      if (!(out = *(c++))) break;
+
+      // handle \escapes
+      if (out == '\\' && *c) {
+        int slash = *(c++), n = unescape(slash);
+
+        if (n) out = n;
+        else if (slash=='c') goto done;
+        else if (slash=='0') {
+          out = 0;
+          while (*c>='0' && *c<='7' && n++<3) out = (out*8)+*(c++)-'0';
+        } else if (slash=='x') {
+          out = 0;
+          while (n++<2) {
+            if (*c>='0' && *c<='9') out = (out*16)+*(c++)-'0';
+            else {
+              int temp = tolower(*c);
+              if (temp>='a' && temp<='f') {
+                out = (out*16)+temp-'a'+10;
+                c++;
+              } else break;
+            }
+          }
+        // Slash in front of unknown character, print literal.
+        } else c--;
+      }
+      putchar(out);
+    }
+  }
+
+  // Output "\n" if no -n
+  if (!(toys.optflags&FLAG_n)) putchar('\n');
+done:
+  xflush();
+}
diff --git a/toybox/toys/posix/env.c b/toybox/toys/posix/env.c
new file mode 100644
index 0000000..c2fc5cf
--- /dev/null
+++ b/toybox/toys/posix/env.c
@@ -0,0 +1,50 @@
+/* env.c - Set the environment for command invocation.
+ *
+ * Copyright 2012 Tryn Mirell <tryn@mirell.org>
+ *
+ * http://opengroup.org/onlinepubs/9699919799/utilities/env.html
+
+USE_ENV(NEWTOY(env, "^iu*", TOYFLAG_USR|TOYFLAG_BIN))
+
+config ENV
+  bool "env"
+  default y
+  help
+    usage: env [-i] [-u NAME] [NAME=VALUE...] [command [option...]]
+
+    Set the environment for command invocation.
+
+    -i	Clear existing environment.
+    -u NAME	Remove NAME from the environment
+*/
+
+#define FOR_env
+#include "toys.h"
+
+GLOBALS(
+  struct arg_list *u;
+);
+
+extern char **environ;
+
+void env_main(void)
+{
+  char **ev;
+
+  if (toys.optflags & FLAG_i) clearenv();
+  while (TT.u) {
+    unsetenv(TT.u->arg);
+    TT.u = TT.u->next;
+  }
+
+  for (ev = toys.optargs; *ev; ev++) {
+    char *name = *ev, *val = strchr(name, '=');
+
+    if (val) {
+      *(val++) = 0;
+      setenv(name, val, 1);
+    } else xexec(ev);
+  }
+
+  if (environ) for (ev = environ; *ev; ev++) xputs(*ev);
+}
diff --git a/toybox/toys/posix/expand.c b/toybox/toys/posix/expand.c
new file mode 100644
index 0000000..a25848a
--- /dev/null
+++ b/toybox/toys/posix/expand.c
@@ -0,0 +1,128 @@
+/* expand.c - expands tabs to space
+ *
+ * Copyright 2012 Jonathan Clairembault <jonathan at clairembault dot fr>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expand.html
+
+USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+
+config EXPAND
+  bool "expand"
+  default y
+  help
+    usage: expand [-t TABLIST] [FILE...]
+
+    Expand tabs to spaces according to tabstops.
+
+    -t	TABLIST
+
+    Specify tab stops, either a single number instead of the default 8,
+    or a comma separated list of increasing numbers representing tabstop
+    positions (absolute, not increments) with each additional tab beyound
+    that becoming one space.
+*/
+
+#define FOR_expand
+#include "toys.h"
+
+GLOBALS(
+  struct arg_list *tabs;
+
+  unsigned tabcount, *tab;
+)
+
+static void do_expand(int fd, char *name)
+{
+  int i, len, x=0, stop = 0;
+
+  for (;;) {
+    len = readall(fd, toybuf, sizeof(toybuf));
+    if (len<0) {
+      perror_msg_raw(name);
+      return;
+    }
+    if (!len) break;
+    for (i=0; i<len; i++) {
+      int width = 1;
+      char c;
+
+      if (CFG_TOYBOX_I18N) {
+        wchar_t blah;
+
+        width = mbrtowc(&blah, toybuf+i, len-i, 0);
+        if (width > 1) {
+          if (width != fwrite(toybuf+i, width, 1, stdout))
+            perror_exit("stdout");
+          i += width-1;
+          x++;
+          continue;
+        } else if (width == -2) break;
+        else if (width == -1) continue;
+      }
+      c = toybuf[i];
+
+      if (c != '\t') {
+        if (EOF == putc(c, stdout)) perror_exit(0);
+
+        if (c == '\b' && x) width = -1;
+        if (c == '\n') {
+          x = stop = 0;
+          continue;
+        }
+      } else {
+        if (TT.tabcount < 2) {
+          width = TT.tabcount ? *TT.tab : 8;
+          width -= x%width;
+        } else while (stop < TT.tabcount) {
+          if (TT.tab[stop] > x) {
+            width = TT.tab[stop] - x;
+            break;
+          } else stop++;
+        }
+        xprintf("%*c", width, ' ');
+      }
+      x += width;
+    }
+  }
+}
+
+// Parse -t options to fill out unsigned array in tablist (if not NULL)
+// return number of entries in tablist
+static int parse_tablist(unsigned *tablist)
+{
+  struct arg_list *tabs;
+  int tabcount = 0;
+
+  for (tabs = TT.tabs; tabs; tabs = tabs->next) {
+    char *s = tabs->arg;
+
+    while (*s) {
+      int count;
+      unsigned x, *t = tablist ? tablist+tabcount : &x;
+
+      if (tabcount >= sizeof(toybuf)/sizeof(unsigned)) break;
+      if (sscanf(s, "%u%n", t, &count) != 1) break;
+      if (tabcount++ && tablist && *(t-1) >= *t) break;
+      s += count;
+      if (*s==' ' || *s==',') s++;
+      else break;
+    }
+    if (*s) error_exit("bad tablist");
+  }
+
+  return tabcount;
+}
+
+void expand_main(void)
+{
+  TT.tabcount = parse_tablist(NULL);
+
+  // Determine size of tablist, allocate memory, fill out tablist
+  if (TT.tabcount) {
+    TT.tab = xmalloc(sizeof(unsigned)*TT.tabcount);
+    parse_tablist(TT.tab);
+  }
+
+  loopfiles(toys.optargs, do_expand);
+  if (CFG_TOYBOX_FREE) free(TT.tab);
+}
diff --git a/toybox/toys/posix/false.c b/toybox/toys/posix/false.c
new file mode 100644
index 0000000..0853b01
--- /dev/null
+++ b/toybox/toys/posix/false.c
@@ -0,0 +1,21 @@
+/* false.c - Return nonzero.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/false.html
+
+USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
+
+config FALSE
+  bool "false"
+  default y
+  help
+    Return nonzero.
+*/
+
+#include "toys.h"
+
+void false_main(void)
+{
+  toys.exitval = 1;
+}
diff --git a/toybox/toys/posix/file.c b/toybox/toys/posix/file.c
new file mode 100644
index 0000000..0cd9047
--- /dev/null
+++ b/toybox/toys/posix/file.c
@@ -0,0 +1,308 @@
+/* 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 y
+  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, 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>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++) {
+    struct stat sb;
+    char *name = *arg, *what = "cannot open";
+
+    xprintf("%s: %*s", name, (int)(TT.max_name_len - strlen(name)), "");
+
+    if (!lstat(name, &sb)) {
+      if (S_ISFIFO(sb.st_mode)) what = "fifo";
+      else if (S_ISREG(sb.st_mode)) {
+        int fd = !strcmp(name, "-") ? 0 : open(name, O_RDONLY);
+
+        if (fd!=-1) {
+          if (!sb.st_size) what = "empty";
+          else do_regular_file(fd, name, &sb);
+          if (fd) close(fd);
+          if (sb.st_size) continue;
+        }
+      } 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);
+  }
+}
diff --git a/toybox/toys/posix/find.c b/toybox/toys/posix/find.c
new file mode 100644
index 0000000..86fc141
--- /dev/null
+++ b/toybox/toys/posix/find.c
@@ -0,0 +1,564 @@
+/* find.c - Search directories for matching files.
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.c
+ *
+ * Our "unspecified" behavior for no paths is to use "."
+ * Parentheses can only stack 4096 deep
+ * Not treating two {} as an error, but only using last
+ *
+ * TODO: -empty (dirs too!)
+
+USE_FIND(NEWTOY(find, "?^HL[-HL]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config FIND
+  bool "find"
+  default y
+  help
+    usage: find [-HL] [DIR...] [<options>]
+
+    Search directories for matching files.
+    Default: search "." match all -print all matches.
+
+    -H  Follow command line symlinks         -L  Follow all symlinks
+
+    Match filters:
+    -name  PATTERN  filename with wildcards   -iname      case insensitive -name
+    -path  PATTERN  path name with wildcards  -ipath      case insensitive -path
+    -user  UNAME    belongs to user UNAME     -nouser     user ID not known
+    -group GROUP    belongs to group GROUP    -nogroup    group ID not known
+    -perm  [-/]MODE permissions (-=min /=any) -prune      ignore contents of dir
+    -size  N[c]     512 byte blocks (c=bytes) -xdev       only this filesystem
+    -links N        hardlink count            -atime N    accessed N days ago
+    -ctime N        created N days ago        -mtime N    modified N days ago
+    -newer FILE     newer mtime than FILE     -mindepth # at least # dirs down
+    -depth          ignore contents of dir    -maxdepth # at most # dirs down
+    -inum  N        inode number N            -empty      empty files and dirs
+    -type [bcdflps] (block, char, dir, file, symlink, pipe, socket)
+
+    Numbers N may be prefixed by a - (less than) or + (greater than):
+
+    Combine matches with:
+    !, -a, -o, ( )    not, and, or, group expressions
+
+    Actions:
+    -print   Print match with newline  -print0    Print match with null
+    -exec    Run command with path     -execdir   Run command in file's dir
+    -ok      Ask before exec           -okdir     Ask before execdir
+    -delete  Remove matching file/dir
+
+    Commands substitute "{}" with matched file. End with ";" to run each file,
+    or "+" (next argument after "{}") to collect and run with multiple files.
+*/
+
+#define FOR_find
+#include "toys.h"
+
+GLOBALS(
+  char **filter;
+  struct double_list *argdata;
+  int topdir, xdev, depth;
+  time_t now;
+)
+
+struct execdir_data {
+  struct execdir_data *next;
+
+  int namecount;
+  struct double_list *names;
+};
+
+// None of this can go in TT because you can have more than one -exec
+struct exec_range {
+  char *next, *prev;  // layout compatible with struct double_list
+
+  int dir, plus, arglen, argsize, curly;
+  char **argstart;
+  struct execdir_data exec, *execdir;
+};
+
+// Perform pending -exec (if any)
+static int flush_exec(struct dirtree *new, struct exec_range *aa)
+{
+  struct execdir_data *bb = aa->execdir ? aa->execdir : &aa->exec;
+  char **newargs;
+  int rc, revert = 0;
+
+  if (!bb->namecount) return 0;
+
+  dlist_terminate(bb->names);
+
+  // switch to directory for -execdir, or back to top if we have an -execdir
+  // _and_ a normal -exec, or are at top of tree in -execdir
+  if (TT.topdir != -1) {
+    if (aa->dir && new && new->parent) {
+      revert++;
+      rc = fchdir(new->parent->dirfd);
+    } else rc = fchdir(TT.topdir);
+    if (rc) {
+      perror_msg_raw(revert ? new->name : ".");
+
+      return rc;
+    }
+  }
+
+  // execdir: accumulated execs in this directory's children.
+  newargs = xmalloc(sizeof(char *)*(aa->arglen+bb->namecount+1));
+  if (aa->curly < 0) {
+    memcpy(newargs, aa->argstart, sizeof(char *)*aa->arglen);
+    newargs[aa->arglen] = 0;
+  } else {
+    int pos = aa->curly, rest = aa->arglen - aa->curly;
+    struct double_list *dl;
+
+    // Collate argument list
+    memcpy(newargs, aa->argstart, sizeof(char *)*pos);
+    for (dl = bb->names; dl; dl = dl->next) newargs[pos++] = dl->data;
+    rest = aa->arglen - aa->curly - 1;
+    memcpy(newargs+pos, aa->argstart+aa->curly+1, sizeof(char *)*rest);
+    newargs[pos+rest] = 0;
+  }
+
+  rc = xrun(newargs);
+
+  llist_traverse(bb->names, llist_free_double);
+  bb->names = 0;
+  bb->namecount = 0;
+
+  if (revert) revert = fchdir(TT.topdir);
+
+  return rc;
+}
+
+// Return numeric value with explicit sign
+static int compare_numsign(long val, long units, char *str)
+{
+  char sign = 0;
+  long myval;
+
+  if (*str == '+' || *str == '-') sign = *(str++);
+  else if (!isdigit(*str)) error_exit("%s not [+-]N", str);
+  myval = atolx(str);
+  if (units && isdigit(str[strlen(str)-1])) myval *= units;
+
+  if (sign == '+') return val > myval;
+  if (sign == '-') return val < myval;
+  return val == myval;
+}
+
+static void do_print(struct dirtree *new, char c)
+{
+  char *s=dirtree_path(new, 0);
+
+  xprintf("%s%c", s, c);
+  free(s);
+}
+
+// Descend or ascend -execdir + directory level
+static void execdir(struct dirtree *new, int flush)
+{
+  struct double_list *dl;
+  struct exec_range *aa;
+  struct execdir_data *bb;
+
+  if (new && TT.topdir == -1) return;
+
+  for (dl = TT.argdata; dl; dl = dl->next) {
+    if (dl->prev != (void *)1) continue;
+    aa = (void *)dl;
+    if (!aa->plus || (new && !aa->dir)) continue;
+
+    if (flush) {
+
+      // Flush pending "-execdir +" instances for this dir
+      // or flush everything for -exec at top
+      toys.exitval |= flush_exec(new, aa);
+
+      // pop per-directory struct
+      if ((bb = aa->execdir)) {
+        aa->execdir = bb->next;
+        free(bb);
+      }
+    } else if (aa->dir) {
+
+      // Push new per-directory struct for -execdir/okdir + codepath. (Can't
+      // use new->extra because command line may have multiple -execdir)
+      bb = xzalloc(sizeof(struct execdir_data));
+      bb->next = aa->execdir;
+      aa->execdir = bb;
+    }
+  }
+} 
+
+// Call this with 0 for first pass argument parsing and syntax checking (which
+// populates argdata). Later commands traverse argdata (in order) when they
+// need "do once" results.
+static int do_find(struct dirtree *new)
+{
+  int pcount = 0, print = 0, not = 0, active = !!new, test = active, recurse;
+  struct double_list *argdata = TT.argdata;
+  char *s, **ss;
+
+  recurse = DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_L));
+
+  // skip . and .. below topdir, handle -xdev and -depth
+  if (new) {
+    if (new->parent) {
+      if (!dirtree_notdotdot(new)) return 0;
+      if (TT.xdev && new->st.st_dev != new->parent->st.st_dev) recurse = 0;
+    }
+
+    if (S_ISDIR(new->st.st_mode)) {
+      // Descending into new directory
+      if (!new->again) {
+        struct dirtree *n;
+
+        for (n = new->parent; n; n = n->parent) {
+          if (n->st.st_ino==new->st.st_ino && n->st.st_dev==new->st.st_dev) {
+            error_msg("'%s': loop detected", s = dirtree_path(new, 0));
+            free(s);
+
+            return 0;
+          }
+        }
+
+        if (TT.depth) {
+          execdir(new, 0);
+
+          return recurse;
+        }
+      // Done with directory (COMEAGAIN call)
+      } else {
+        execdir(new, 1);
+        recurse = 0;
+        if (!TT.depth) return 0;
+      }
+    }
+  }
+
+  // pcount: parentheses stack depth (using toybuf bytes, 4096 max depth)
+  // test: result of most recent test
+  // active: if 0 don't perform tests
+  // not: a pending ! applies to this test (only set if performing tests)
+  // print: saw one of print/ok/exec, no need for default -print
+
+  if (TT.filter) for (ss = TT.filter; *ss; ss++) {
+    int check = active && test;
+
+    s = *ss;
+
+    // handle ! ( ) using toybuf as a stack
+    if (*s != '-') {
+      if (s[1]) goto error;
+
+      if (*s == '!') {
+        // Don't invert if we're not making a decision
+        if (check) not = !not;
+
+      // Save old "not" and "active" on toybuf stack.
+      // Deactivate this parenthetical if !test
+      // Note: test value should never change while !active
+      } else if (*s == '(') {
+        if (pcount == sizeof(toybuf)) goto error;
+        toybuf[pcount++] = not+(active<<1);
+        if (!check) active = 0;
+        not = 0;
+
+      // Pop status, apply deferred not to test
+      } else if (*s == ')') {
+        if (--pcount < 0) goto error;
+        // Pop active state, apply deferred not (which was only set if checking)
+        active = (toybuf[pcount]>>1)&1;
+        if (active && (toybuf[pcount]&1)) test = !test;
+        not = 0;
+      } else goto error;
+
+      continue;
+    } else s++;
+
+    if (!strcmp(s, "xdev")) TT.xdev = 1;
+    else if (!strcmp(s, "delete")) {
+      // Delete forces depth first
+      TT.depth = 1;
+      if (new && check)
+        test = !unlinkat(dirtree_parentfd(new), new->name,
+          S_ISDIR(new->st.st_mode) ? AT_REMOVEDIR : 0);
+    } else if (!strcmp(s, "depth")) TT.depth = 1;
+    else if (!strcmp(s, "o") || !strcmp(s, "or")) {
+      if (not) goto error;
+      if (active) {
+        if (!test) test = 1;
+        else active = 0;     // decision has been made until next ")"
+      }
+    } else if (!strcmp(s, "not")) {
+      if (check) not = !not;
+      continue;
+    // Mostly ignore NOP argument
+    } else if (!strcmp(s, "a") || !strcmp(s, "and") || !strcmp(s, "noleaf")) {
+      if (not) goto error;
+
+    } else if (!strcmp(s, "print") || !strcmp("print0", s)) {
+      print++;
+      if (check) do_print(new, s[5] ? 0 : '\n');
+
+    } else if (!strcmp(s, "nouser")) {
+      if (check) if (bufgetpwuid(new->st.st_uid)) test = 0;
+    } else if (!strcmp(s, "nogroup")) {
+      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;
+
+    // Remaining filters take an argument
+    } else {
+      if (!strcmp(s, "name") || !strcmp(s, "iname")
+        || !strcmp(s, "path") || !strcmp(s, "ipath"))
+      {
+        int i = (*s == 'i');
+        char *arg = ss[1], *path = 0, *name = new ? new->name : arg;
+
+        // Handle path expansion and case flattening
+        if (new && s[i] == 'p') name = path = dirtree_path(new, 0);
+        if (i) {
+          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'));
+          if (i) free(name);
+        }
+        free(path);
+      } else if (!strcmp(s, "perm")) {
+        if (check) {
+          char *m = ss[1];
+          int match_min = *m == '-',
+              match_any = *m == '/';
+          mode_t m1 = string_to_mode(m+(match_min || match_any), 0),
+                 m2 = new->st.st_mode & 07777;
+
+          if (match_min || match_any) m2 &= m1;
+          test = match_any ? !m1 || m2 : m1 == m2;
+        }
+      } else if (!strcmp(s, "type")) {
+        if (check) {
+          int types[] = {S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFIFO,
+                         S_IFREG, S_IFSOCK}, i = stridx("bcdlpfs", *ss[1]);
+
+          if (i<0) error_exit("bad -type '%c'", *ss[1]);
+          if ((new->st.st_mode & S_IFMT) != types[i]) test = 0;
+        }
+
+      } else if (!strcmp(s, "atime")) {
+        if (check)
+          test = compare_numsign(TT.now - new->st.st_atime, 86400, ss[1]);
+      } else if (!strcmp(s, "ctime")) {
+        if (check)
+          test = compare_numsign(TT.now - new->st.st_ctime, 86400, ss[1]);
+      } else if (!strcmp(s, "mtime")) {
+        if (check)
+          test = compare_numsign(TT.now - new->st.st_mtime, 86400, ss[1]);
+      } else if (!strcmp(s, "size")) {
+        if (check)
+          test = compare_numsign(new->st.st_size, 512, ss[1]);
+      } else if (!strcmp(s, "links")) {
+        if (check) test = compare_numsign(new->st.st_nlink, 0, ss[1]);
+      } else if (!strcmp(s, "inum")) {
+        if (check)
+          test = compare_numsign(new->st.st_ino, 0, ss[1]);
+      } else if (!strcmp(s, "mindepth") || !strcmp(s, "maxdepth")) {
+        if (check) {
+          struct dirtree *dt = new;
+          int i = 0, d = atolx(ss[1]);
+
+          while ((dt = dt->parent)) i++;
+          if (s[1] == 'i') {
+            test = i >= d;
+            if (i == d && not) recurse = 0;
+          } else {
+            test = i <= d;
+            if (i == d && !not) recurse = 0;
+          }
+        }
+      } else if (!strcmp(s, "user") || !strcmp(s, "group")
+              || !strcmp(s, "newer"))
+      {
+        struct {
+          void *next, *prev;
+          union {
+            uid_t uid;
+            gid_t gid;
+            struct timespec tm;
+          } u;
+        } *udl;
+
+        if (!new) {
+          if (ss[1]) {
+            udl = xmalloc(sizeof(*udl));
+            dlist_add_nomalloc(&TT.argdata, (void *)udl);
+
+            if (*s == 'u') udl->u.uid = xgetuid(ss[1]);
+            else if (*s == 'g') udl->u.gid = xgetgid(ss[1]);
+            else {
+              struct stat st;
+
+              xstat(ss[1], &st);
+              udl->u.tm = st.st_mtim;
+            }
+          }
+        } else {
+          udl = (void *)llist_pop(&argdata);
+          if (check) {
+            if (*s == 'u') test = new->st.st_uid == udl->u.uid;
+            else if (*s == 'g') test = new->st.st_gid == udl->u.gid;
+            else {
+              test = new->st.st_mtim.tv_sec > udl->u.tm.tv_sec;
+              if (new->st.st_mtim.tv_sec == udl->u.tm.tv_sec)
+                test = new->st.st_mtim.tv_nsec > udl->u.tm.tv_nsec;
+            }
+          }
+        }
+      } else if (!strcmp(s, "exec") || !strcmp("ok", s)
+              || !strcmp(s, "execdir") || !strcmp(s, "okdir"))
+      {
+        struct exec_range *aa;
+
+        print++;
+
+        // Initial argument parsing pass
+        if (!new) {
+          int len;
+
+          // catch "-exec" with no args and "-exec \;"
+          if (!ss[1] || !strcmp(ss[1], ";")) error_exit("'%s' needs 1 arg", s);
+
+          dlist_add_nomalloc(&TT.argdata, (void *)(aa = xzalloc(sizeof(*aa))));
+          aa->argstart = ++ss;
+          aa->curly = -1;
+
+          // Record command line arguments to -exec
+          for (len = 0; ss[len]; len++) {
+            if (!strcmp(ss[len], ";")) break;
+            else if (!strcmp(ss[len], "{}")) {
+              aa->curly = len;
+              if (ss[len+1] && !strcmp(ss[len+1], "+")) {
+                aa->plus++;
+                len++;
+                break;
+              }
+            } else aa->argsize += sizeof(char *) + strlen(ss[len]) + 1;
+          }
+          if (!ss[len]) error_exit("-exec without %s",
+            aa->curly!=-1 ? "\\;" : "{}");
+          ss += len;
+          aa->arglen = len;
+          aa->dir = !!strchr(s, 'd');
+          if (TT.topdir == -1) TT.topdir = xopenro(".");
+
+        // collect names and execute commands
+        } else {
+          char *name, *ss1 = ss[1];
+          struct execdir_data *bb;
+
+          // Grab command line exec argument list
+          aa = (void *)llist_pop(&argdata);
+          ss += aa->arglen + 1;
+
+          if (!check) goto cont;
+          // name is always a new malloc, so we can always free it.
+          name = aa->dir ? xstrdup(new->name) : dirtree_path(new, 0);
+
+          if (*s == 'o') {
+            fprintf(stderr, "[%s] %s", ss1, name);
+            if (!(test = yesno(0))) {
+              free(name);
+              goto cont;
+            }
+          }
+
+          // Add next name to list (global list without -dir, local with)
+          bb = aa->execdir ? aa->execdir : &aa->exec;
+          dlist_add(&bb->names, name);
+          bb->namecount++;
+
+          // -exec + collates and saves result in exitval
+          if (aa->plus) {
+            // Mark entry so COMEAGAIN can call flush_exec() in parent.
+            // This is never a valid pointer value for prev to have otherwise
+            // Done here vs argument parsing pass so it's after dlist_terminate
+            aa->prev = (void *)1;
+
+            // Flush if we pass 16 megs of environment space.
+            // An insanely long path (>2 gigs) could wrap the counter and
+            // defeat this test, which could potentially trigger OOM killer.
+            if ((aa->plus += sizeof(char *)+strlen(name)+1) > 1<<24) {
+              aa->plus = 1;
+              toys.exitval |= flush_exec(new, aa);
+            }
+          } else test = flush_exec(new, aa);
+        }
+
+        // Argument consumed, skip the check.
+        goto cont;
+      } else goto error;
+
+      // This test can go at the end because we do a syntax checking
+      // pass first. Putting it here gets the error message (-unknown
+      // vs -known noarg) right.
+      if (!*++ss) error_exit("'%s' needs 1 arg", --s);
+    }
+cont:
+    // Apply pending "!" to result
+    if (active && not) test = !test;
+    not = 0;
+  }
+
+  if (new) {
+    // If there was no action, print
+    if (!print && test) do_print(new, '\n');
+
+    if (S_ISDIR(new->st.st_mode)) execdir(new, 0);
+ 
+  } else dlist_terminate(TT.argdata);
+
+  return recurse;
+
+error:
+  error_exit("bad arg '%s'", *ss);
+}
+
+void find_main(void)
+{
+  int i, len;
+  char **ss = toys.optargs;
+
+  TT.topdir = -1;
+
+  // Distinguish paths from filters
+  for (len = 0; toys.optargs[len]; len++)
+    if (strchr("-!(", *toys.optargs[len])) break;
+  TT.filter = toys.optargs+len;
+
+  // use "." if no paths
+  if (!len) {
+    ss = (char *[]){"."};
+    len = 1;
+  }
+
+  // first pass argument parsing, verify args match up, handle "evaluate once"
+  TT.now = time(0);
+  do_find(0);
+
+  // Loop through paths
+  for (i = 0; i < len; i++)
+    dirtree_flagread(ss[i], DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)),
+      do_find);
+
+  execdir(0, 1);
+
+  if (CFG_TOYBOX_FREE) {
+    close(TT.topdir);
+    llist_traverse(TT.argdata, free);
+  }
+}
diff --git a/toybox/toys/posix/grep.c b/toybox/toys/posix/grep.c
new file mode 100644
index 0000000..6423ea6
--- /dev/null
+++ b/toybox/toys/posix/grep.c
@@ -0,0 +1,372 @@
+/* grep.c - print lines what match given regular expression
+ *
+ * Copyright 2013 CE Strake <strake888 at gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html
+ *
+ * TODO: -ABC
+
+USE_GREP(NEWTOY(grep, "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
+USE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
+USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
+
+config GREP
+  bool "grep"
+  default y
+  help
+    usage: grep [-EFivwcloqsHbhn] [-A NUM] [-m MAX] [-e REGEX]... [-f REGFILE] [FILE]...
+
+    Show lines matching regular expressions. If no -e, first argument is
+    regular expression to match. With no files (or "-" filename) read stdin.
+    Returns 0 if matched, 1 if no match found.
+
+    -e  Regex to match. (May be repeated.)
+    -f  File containing regular expressions to match.
+
+    match type:
+    -A  Show NUM lines after     -B  Show NUM lines before match
+    -C  NUM lines context (A+B)  -E  extended regex syntax
+    -F  fixed (literal match)    -i  case insensitive
+    -m  match MAX many lines     -r  recursive (on dir)
+    -v  invert match             -w  whole word (implies -E)
+    -x  whole line               -z  input NUL terminated
+
+    display modes: (default: matched line)
+    -c  count of matching lines  -l  show matching filenames
+    -o  only matching part       -q  quiet (errors only)
+    -s  silent (no error msg)    -Z  output NUL terminated
+
+    output prefix (default: filename if checking more than 1 file)
+    -H  force filename           -b  byte offset of match
+    -h  hide filename            -n  line number of match
+
+config EGREP
+  bool
+  default y
+  depends on GREP
+
+config FGREP
+  bool
+  default y
+  depends on GREP
+*/
+
+#define FOR_grep
+#include "toys.h"
+#include <regex.h>
+
+GLOBALS(
+  long m;
+  struct arg_list *f;
+  struct arg_list *e;
+  long a;
+  long b;
+  long c;
+
+  char indelim, outdelim;
+)
+
+// Emit line with various potential prefixes and delimiter
+static void outline(char *line, char dash, char *name, long lcount, long bcount,
+  int trim)
+{
+  if (name && (toys.optflags&FLAG_H)) printf("%s%c", name, dash);
+  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, 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");
+  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;
+    regmatch_t matches;
+    size_t unused;
+    long len;
+    int mmatch = 0;
+
+    lcount++;
+    if (0 > (len = getdelim(&line, &unused, TT.indelim, file))) break;
+    if (line[len-1] == TT.indelim) line[len-1] = 0;
+
+    start = line;
+
+    // Loop through matches in this line
+    do {
+      int rc = 0, skip = 0;
+
+      // Handle non-regex matches
+      if (toys.optflags & FLAG_F) {
+        struct arg_list *seek, fseek;
+        char *s = 0;
+
+        for (seek = TT.e; seek; seek = seek->next) {
+          if (toys.optflags & FLAG_x) {
+            int i = (toys.optflags & FLAG_i);
+
+            if ((i ? strcasecmp : strcmp)(seek->arg, line)) s = line;
+          } else if (!*seek->arg) {
+            seek = &fseek;
+            fseek.arg = s = line;
+            break;
+          }
+          if (toys.optflags & FLAG_i) s = strnstr(line, seek->arg);
+          else s = strstr(line, seek->arg);
+          if (s) break;
+        }
+
+        if (s) {
+          matches.rm_so = (s-line);
+          skip = matches.rm_eo = (s-line)+strlen(seek->arg);
+        } else rc = 1;
+      } else {
+        rc = regexec((regex_t *)toybuf, start, 1, &matches,
+                     start==line ? 0 : REG_NOTBOL);
+        skip = matches.rm_eo;
+      }
+
+      if (toys.optflags & FLAG_x)
+        if (matches.rm_so || line[matches.rm_eo]) rc = 1;
+
+      if (!rc && (toys.optflags & FLAG_w)) {
+        char c = 0;
+
+        if ((start+matches.rm_so)!=line) {
+          c = start[matches.rm_so-1];
+          if (!isalnum(c) && c != '_') c = 0;
+        }
+        if (!c) {
+          c = start[matches.rm_eo];
+          if (!isalnum(c) && c != '_') c = 0;
+        }
+        if (c) {
+          start += matches.rm_so+1;
+
+          continue;
+        }
+      }
+
+      if (toys.optflags & FLAG_v) {
+        if (toys.optflags & FLAG_o) {
+          if (rc) skip = matches.rm_eo = strlen(start);
+          else if (!matches.rm_so) {
+            start += skip;
+            continue;
+          } else matches.rm_eo = matches.rm_so;
+        } else {
+          if (!rc) break;
+          matches.rm_eo = strlen(start);
+        }
+        matches.rm_so = 0;
+      } else if (rc) break;
+
+      // At least one line we didn't print since match while -ABC active
+      if (bars) {
+        xputs(bars);
+        bars = 0;
+      }
+      mmatch++;
+      toys.exitval = 0;
+      if (toys.optflags & FLAG_q) xexit();
+      if (toys.optflags & FLAG_l) {
+        xprintf("%s%c", name, TT.outdelim);
+        free(line);
+        fclose(file);
+        return;
+      }
+      if (toys.optflags & FLAG_o)
+        if (matches.rm_eo == matches.rm_so)
+          break;
+
+      if (!(toys.optflags & FLAG_c)) {
+        long bcount = 1 + offset + (start-line) +
+          ((toys.optflags & FLAG_o) ? matches.rm_so : 0);
+ 
+        if (!(toys.optflags & FLAG_o)) {
+          while (dlb) {
+            struct double_list *dl = dlist_pop(&dlb);
+
+            outline(dl->data, '-', name, lcount-before, 0, -1);
+            free(dl->data);
+            free(dl);
+            before--;
+          }
+
+          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);
+      }
+
+      start += skip;
+      if (!(toys.optflags & FLAG_o)) break;
+    } while (*start);
+    offset += len;
+
+    if (mmatch) mcount++;
+    else {
+      int discard = (after || TT.b);
+
+      if (after && --after) {
+        outline(line, '-', name, lcount, 0, -1);
+        discard = 0;
+      }
+      if (discard && TT.b) {
+        dlist_add(&dlb, line);
+        line = 0;
+        if (++before>TT.b) {
+          struct double_list *dl;
+
+          dl = dlist_pop(&dlb);
+          free(dl->data);
+          free(dl);
+          before--;
+        } else discard = 0;
+      }
+      // If we discarded a line while displaying context, show bars before next
+      // line (but don't show them now in case that was last match in file)
+      if (discard && mcount) bars = "--";
+    }
+    free(line);
+
+    if ((toys.optflags & FLAG_m) && mcount >= TT.m) break;
+  }
+
+  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);
+}
+
+static void parse_regex(void)
+{
+  struct arg_list *al, *new, *list = NULL;
+  long len = 0;
+  char *s, *ss;
+
+  // Add all -f lines to -e list. (Yes, this is leaking allocation context for
+  // exit to free. Not supporting nofork for this command any time soon.)
+  al = TT.f ? TT.f : TT.e;
+  while (al) {
+    if (TT.f) s = ss = xreadfile(al->arg, 0, 0);
+    else s = ss = al->arg;
+
+    // Split lines at \n, add individual lines to new list.
+    do {
+      ss = strchr(s, '\n');
+      if (ss) *(ss++) = 0;
+      new = xmalloc(sizeof(struct arg_list));
+      new->next = list;
+      new->arg = s;
+      list = new;
+      s = ss;
+    } while (ss && *s);
+
+    // Advance, when we run out of -f switch to -e.
+    al = al->next;
+    if (!al && TT.f) {
+      TT.f = 0;
+      al = TT.e;
+    }
+  }
+  TT.e = list;
+
+  if (!(toys.optflags & FLAG_F)) {
+    char *regstr;
+    int i;
+
+    // Convert strings to one big regex
+    for (al = TT.e; al; al = al->next)
+      len += strlen(al->arg)+1+!(toys.optflags & FLAG_E);
+
+    regstr = s = xmalloc(len);
+    for (al = TT.e; al; al = al->next) {
+      s = stpcpy(s, al->arg);
+      if (!(toys.optflags & FLAG_E)) *(s++) = '\\';
+      *(s++) = '|';
+    }
+    *(s-=(1+!(toys.optflags & FLAG_E))) = 0;
+
+    i = regcomp((regex_t *)toybuf, regstr,
+                ((toys.optflags & FLAG_E) ? REG_EXTENDED : 0) |
+                ((toys.optflags & FLAG_i) ? REG_ICASE    : 0));
+
+    if (i) {
+      regerror(i, (regex_t *)toybuf, toybuf+sizeof(regex_t),
+               sizeof(toybuf)-sizeof(regex_t));
+      error_exit("bad REGEX: %s", toybuf);
+    }
+  }
+}
+
+static int do_grep_r(struct dirtree *new)
+{
+  char *name;
+
+  if (new->parent && !dirtree_notdotdot(new)) return 0;
+  if (S_ISDIR(new->st.st_mode)) return DIRTREE_RECURSE;
+
+  // "grep -r onefile" doesn't show filenames, but "grep -r onedir" should.
+  if (new->parent && !(toys.optflags & FLAG_h)) toys.optflags |= FLAG_H;
+
+  name = dirtree_path(new, 0);
+  do_grep(openat(dirtree_parentfd(new), new->name, 0), name);
+  free(name);
+
+  return 0;
+}
+
+void grep_main(void)
+{
+  char **ss = toys.optargs;
+
+  if (!TT.a) TT.a = TT.c;
+  if (!TT.b) TT.b = TT.c;
+
+  TT.indelim = '\n' * !(toys.optflags&FLAG_z);
+  TT.outdelim = '\n' * !(toys.optflags&FLAG_Z);
+
+  // Handle egrep and fgrep
+  if (*toys.which->name == 'e') toys.optflags |= FLAG_E;
+  if (*toys.which->name == 'f') toys.optflags |= FLAG_F;
+
+  if (!TT.e && !TT.f) {
+    if (!*ss) error_exit("no REGEX");
+    TT.e = xzalloc(sizeof(struct arg_list));
+    TT.e->arg = *(ss++);
+    toys.optc--;
+  }
+
+  parse_regex();
+
+  if (!(toys.optflags & FLAG_h) && toys.optc>1) toys.optflags |= FLAG_H;
+
+  toys.exitval = 1;
+  if (toys.optflags & FLAG_s) {
+    close(2);
+    xopen_stdio("/dev/null", O_RDWR);
+  }
+
+  if (toys.optflags & FLAG_r) {
+    // Iterate through -r arguments. Use "." as default if none provided.
+    for (ss = *ss ? ss : (char *[]){".", 0}; *ss; ss++) {
+      if (!strcmp(*ss, "-")) do_grep(0, *ss);
+      else dirtree_read(*ss, do_grep_r);
+    }
+  } else loopfiles_rw(ss, O_RDONLY, 0, 1, do_grep);
+}
diff --git a/toybox/toys/posix/head.c b/toybox/toys/posix/head.c
new file mode 100644
index 0000000..f300760
--- /dev/null
+++ b/toybox/toys/posix/head.c
@@ -0,0 +1,61 @@
+/* head.c - copy first lines from input to stdout.
+ *
+ * Copyright 2006 Timothy Elliott <tle@holymonkey.com>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/head.html
+
+USE_HEAD(NEWTOY(head, "?n#<0=10", TOYFLAG_USR|TOYFLAG_BIN))
+
+config HEAD
+  bool "head"
+  default y
+  help
+    usage: head [-n number] [file...]
+
+    Copy first lines from files to stdout. If no files listed, copy from
+    stdin. Filename "-" is a synonym for stdin.
+
+    -n	Number of lines to copy.
+*/
+
+#define FOR_head
+#include "toys.h"
+
+GLOBALS(
+  long lines;
+  int file_no;
+)
+
+static void do_head(int fd, char *name)
+{
+  int i, len, lines=TT.lines, size=sizeof(toybuf);
+
+  if (toys.optc > 1) {
+    // Print an extra newline for all but the first file
+    if (TT.file_no++) xprintf("\n");
+    xprintf("==> %s <==\n", name);
+    xflush();
+  }
+
+  while (lines) {
+    len = read(fd, toybuf, size);
+    if (len<0) perror_msg_raw(name);
+    if (len<1) break;
+
+    for(i=0; i<len;) if (toybuf[i++] == '\n' && !--lines) break;
+
+    xwrite(1, toybuf, i);
+  }
+}
+
+void head_main(void)
+{
+  char *arg = *toys.optargs;
+
+  // handle old "-42" style arguments
+  if (arg && *arg == '-' && arg[1]) {
+    TT.lines = atolx(arg+1);
+    toys.optc--;
+  } else arg = 0;
+  loopfiles(toys.optargs+!!arg, do_head);
+}
diff --git a/toybox/toys/posix/id.c b/toybox/toys/posix/id.c
new file mode 100644
index 0000000..4b732b1
--- /dev/null
+++ b/toybox/toys/posix/id.c
@@ -0,0 +1,179 @@
+/* id.c - print real and effective user and group IDs
+ *
+ * Copyright 2012 Sony Network Entertainment, Inc.
+ *
+ * by Tim Bird <tim.bird@am.sony.com>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/id.html
+
+USE_ID(NEWTOY(id, ">1"USE_ID_Z("Z")"nGgru[!"USE_ID_Z("Z")"Ggu]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_GROUPS(NEWTOY(groups, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_LOGNAME(NEWTOY(logname, ">0", TOYFLAG_USR|TOYFLAG_BIN))
+USE_WHOAMI(OLDTOY(whoami, logname, TOYFLAG_USR|TOYFLAG_BIN))
+
+config ID
+  bool "id"
+  default y
+  help
+    usage: id [-nGgru]
+
+    Print user and group ID.
+
+    -n	print names instead of numeric IDs (to be used with -Ggu)
+    -G	Show only the group IDs
+    -g	Show only the effective group ID
+    -r	Show real ID instead of effective ID
+    -u	Show only the effective user ID
+
+config ID_Z
+  bool
+  default y
+  depends on ID && !TOYBOX_LSM_NONE
+  help
+    usage: id [-Z]
+
+    -Z	Show only security context
+
+config GROUPS
+  bool "groups"
+  default y
+  help
+    usage: groups [user]
+
+    Print the groups a user is in.
+
+config LOGNAME
+  bool "logname"
+  default y
+  help
+    usage: logname
+
+    Print the current user name.
+
+config WHOAMI
+  bool "whoami"
+  default y
+  help
+    usage: whoami
+
+    Print the current user name.
+*/
+
+#define FOR_id
+#define FORCE_FLAGS
+#include "toys.h"
+
+GLOBALS(
+  int is_groups;
+)
+
+static void s_or_u(char *s, unsigned u, int done)
+{
+  if (toys.optflags&FLAG_n) printf("%s", s);
+  else printf("%u", u);
+  if (done) {
+    xputc('\n');
+    xexit();
+  }
+}
+
+static void showid(char *header, unsigned u, char *s)
+{
+  printf("%s%u(%s)", header, u, s);
+}
+
+static void do_id(char *username)
+{
+  int flags, i, ngroups;
+  struct passwd *pw;
+  struct group *grp;
+  uid_t uid = getuid(), euid = geteuid();
+  gid_t gid = getgid(), egid = getegid(), *groups;
+
+  flags = toys.optflags;
+
+  // check if a username is given
+  if (username) {
+    pw = xgetpwnam(username);
+    uid = euid = pw->pw_uid;
+    gid = egid = pw->pw_gid;
+    if (TT.is_groups) printf("%s : ", pw->pw_name);
+  }
+
+  i = flags & FLAG_r;
+  pw = xgetpwuid(i ? uid : euid);
+  if (toys.optflags&FLAG_u) s_or_u(pw->pw_name, pw->pw_uid, 1);
+
+  grp = xgetgrgid(i ? gid : egid);
+  if (flags & FLAG_g) s_or_u(grp->gr_name, grp->gr_gid, 1);
+
+  if (!(toys.optflags&(FLAG_g|FLAG_Z))) {
+    showid("uid=", pw->pw_uid, pw->pw_name);
+    showid(" gid=", grp->gr_gid, grp->gr_name);
+
+    if (!i) {
+      if (uid != euid) {
+        pw = xgetpwuid(euid);
+        showid(" euid=", pw->pw_uid, pw->pw_name);
+      }
+      if (gid != egid) {
+        grp = xgetgrgid(egid);
+        showid(" egid=", grp->gr_gid, grp->gr_name);
+      }
+    }
+
+    showid(" groups=", grp->gr_gid, grp->gr_name);
+  }
+
+  if (!(toys.optflags&FLAG_Z)) {
+    groups = (gid_t *)toybuf;
+    i = sizeof(toybuf)/sizeof(gid_t);
+    ngroups = username ? getgrouplist(username, gid, groups, &i)
+      : getgroups(i, groups);
+    if (ngroups<0) perror_exit(0);
+
+    int show_separator = !(toys.optflags&FLAG_G);
+    for (i = 0; i<ngroups; i++) {
+      if (show_separator) xputc((toys.optflags&FLAG_G) ? ' ' : ',');
+      show_separator = 1;
+      if (!(grp = getgrgid(groups[i]))) perror_msg(0);
+      else if (toys.optflags&FLAG_G) s_or_u(grp->gr_name, grp->gr_gid, 0);
+      else if (grp->gr_gid != egid) showid("", grp->gr_gid, grp->gr_name);
+      else show_separator = 0; // Because we didn't show anything this time.
+    }
+    if (toys.optflags&FLAG_G) {
+      xputc('\n');
+      xexit();
+    }
+  }
+
+  if (!CFG_TOYBOX_LSM_NONE) {
+    if (lsm_enabled()) {
+      char *context = lsm_context();
+
+      printf(" context=%s"+!!(toys.optflags&FLAG_Z), context);
+      if (CFG_TOYBOX_FREE) free(context);
+    } else if (toys.optflags&FLAG_Z) error_exit("%s disabled", lsm_name());
+  }
+
+  xputc('\n');
+}
+
+void id_main(void)
+{
+  if (toys.optc) while(*toys.optargs) do_id(*toys.optargs++);
+  else do_id(NULL);
+}
+
+void groups_main(void)
+{
+  TT.is_groups = 1;
+  toys.optflags = FLAG_G|FLAG_n;
+  id_main();
+}
+
+void logname_main(void)
+{
+  toys.optflags = FLAG_u|FLAG_n;
+  id_main();
+}
diff --git a/toybox/toys/posix/kill.c b/toybox/toys/posix/kill.c
new file mode 100644
index 0000000..3fcd36a
--- /dev/null
+++ b/toybox/toys/posix/kill.c
@@ -0,0 +1,153 @@
+/* kill.c - a program to send signals to processes
+ *
+ * Copyright 2012 Daniel Walter <d.walter@0x90.at>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/kill.html
+ *
+ * killall5.c - Send signal to all processes outside current session.
+ *
+ * Copyright 2014 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gamil.com>
+ *
+ * No Standard
+
+USE_KILL(NEWTOY(kill, "?ls: ", TOYFLAG_BIN))
+USE_KILLALL5(NEWTOY(killall5, "?o*ls: [!lo][!ls]", TOYFLAG_SBIN))
+
+config KILL
+  bool "kill"
+  default y
+  help
+    usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] pid...
+
+    Send signal to process(es).
+
+    -l	List signal name(s) and number(s)
+    -s	Send SIGNAL (default SIGTERM)
+
+config KILLALL5
+  bool "killall5"
+  default y
+  depends on KILL
+  help
+    usage: killall5 [-l [SIGNAL]] [-SIGNAL|-s SIGNAL] [-o PID]...
+
+    Send a signal to all processes outside current session.
+
+    -l     List signal name(s) and number(s)
+    -o PID Omit PID
+    -s     send SIGNAL (default SIGTERM)
+*/
+
+// This has to match the filename:
+#define FOR_kill
+#include "toys.h"
+
+GLOBALS(
+  char *signame;
+  struct arg_list *olist;
+)
+
+// But kill's flags are a subset of killall5's
+
+#define CLEANUP_kill
+#define FOR_killall5
+#include "generated/flags.h"
+
+void kill_main(void)
+{
+  int signum;
+  char *tmp, **args = toys.optargs;
+  pid_t pid;
+
+  // list signal(s)
+  if (toys.optflags & FLAG_l) {
+    if (*args) {
+      int signum = sig_to_num(*args);
+      char *s = NULL;
+
+      if (signum>=0) s = num_to_sig(signum&127);
+      puts(s ? s : "UNKNOWN");
+    } else sig_to_num(NULL);
+    return;
+  }
+
+  // signal must come before pids, so "kill -9 -1" isn't confusing.
+
+  if (!TT.signame && *args && **args=='-') TT.signame=*(args++)+1;
+  if (TT.signame) {
+    char *arg;
+    int i = strtol(TT.signame, &arg, 10);
+    if (!*arg) arg = num_to_sig(i);
+    else arg = TT.signame;
+
+    if (!arg || -1 == (signum = sig_to_num(arg)))
+      error_exit("Unknown signal '%s'", arg);
+  } else signum = SIGTERM;
+
+  // is it killall5?
+  if (CFG_KILLALL5 && toys.which->name[4]=='a') {
+    DIR *dp;
+    struct dirent *entry;
+    int pid, sid;
+    long *olist = 0, ocount = 0;
+
+    // parse omit list
+    if (toys.optflags & FLAG_o) {
+      struct arg_list *ptr;
+
+      for (ptr = TT.olist; ptr; ptr = ptr->next) ocount++;
+      olist = xmalloc(ocount*sizeof(long));
+      ocount = 0;
+      for (ptr = TT.olist; ptr; ptr=ptr->next)
+        olist[ocount++] = atolx(ptr->arg);
+    }
+
+    sid = getsid(pid = getpid());
+
+    if (!(dp = opendir("/proc"))) perror_exit("/proc");
+    while ((entry = readdir(dp))) {
+      int count, procpid, procsid;
+
+      if (!(procpid = atoi(entry->d_name))) continue;
+
+      snprintf(toybuf, sizeof(toybuf), "/proc/%d/stat", procpid);
+      if (!readfile(toybuf, toybuf, sizeof(toybuf))) continue;
+      if (sscanf(toybuf, "%*d %*s %*c %*d %*d %d", &procsid) != 1) continue;
+      if (pid == procpid || sid == procsid || procpid == 1) continue;
+
+      // Check for kernel threads.
+      snprintf(toybuf, sizeof(toybuf), "/proc/%d/cmdline", procpid);
+      if (!readfile(toybuf, toybuf, sizeof(toybuf)) || !*toybuf) continue;
+
+      // Check with omit list.
+      for (count = 0; count < ocount; count++) 
+        if (procpid == olist[count]) break;
+      if (count != ocount) continue;
+
+      kill(procpid, signum);
+    }
+    if (CFG_TOYBOX_FREE) {
+      closedir(dp);
+      free(olist);
+    }
+
+  // is it kill?
+  } else {
+
+    // "<1" in optstr wouldn't cover this because "-SIGNAL"
+    if (!*args) help_exit("missing argument");
+
+    while (*args) {
+      char *arg = *(args++);
+
+      pid = strtol(arg, &tmp, 10);
+      if (*tmp || kill(pid, signum) < 0) error_msg("unknown pid '%s'", arg);
+    }
+  }
+}
+
+void killall5_main(void)
+{
+  kill_main();
+}
diff --git a/toybox/toys/posix/link.c b/toybox/toys/posix/link.c
new file mode 100644
index 0000000..38d2cf0
--- /dev/null
+++ b/toybox/toys/posix/link.c
@@ -0,0 +1,25 @@
+/* link.c - hardlink a file
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/link.html
+
+USE_LINK(NEWTOY(link, "<2>2", TOYFLAG_USR|TOYFLAG_BIN))
+
+config LINK
+  bool "link"
+  default y
+  help
+    usage: link FILE NEWLINK
+
+    Create hardlink to a file.
+*/
+
+#include "toys.h"
+
+void link_main(void)
+{
+  if (link(toys.optargs[0], toys.optargs[1]))
+    perror_exit("couldn't link '%s' to '%s'", toys.optargs[1],
+      toys.optargs[0]);
+}
diff --git a/toybox/toys/posix/ln.c b/toybox/toys/posix/ln.c
new file mode 100644
index 0000000..06700dd
--- /dev/null
+++ b/toybox/toys/posix/ln.c
@@ -0,0 +1,88 @@
+/* ln.c - Create filesystem links
+ *
+ * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/ln.html
+
+USE_LN(NEWTOY(ln, "<1vnfs", TOYFLAG_BIN))
+
+config LN
+  bool "ln"
+  default y
+  help
+    usage: ln [-sfnv] [FROM...] TO
+
+    Create a link between FROM and TO.
+    With only one argument, create link in current directory.
+
+    -s	Create a symbolic link
+    -f	Force the creation of the link, even if TO already exists
+    -n	Symlink at destination treated as file
+    -v	Verbose
+*/
+
+#define FOR_ln
+#include "toys.h"
+
+void ln_main(void)
+{
+  char *dest = toys.optargs[--toys.optc], *new;
+  struct stat buf;
+  int i;
+
+  // With one argument, create link in current directory.
+  if (!toys.optc) {
+    toys.optc++;
+    dest=".";
+  }
+
+  // Is destination a directory?
+  if (((toys.optflags&FLAG_n) ? lstat : stat)(dest, &buf)
+    || !S_ISDIR(buf.st_mode))
+  {
+    if (toys.optc>1) error_exit("'%s' not a directory", dest);
+    buf.st_mode = 0;
+  }
+
+  for (i=0; i<toys.optc; i++) {
+    int rc;
+    char *oldnew, *try = toys.optargs[i];
+
+    if (S_ISDIR(buf.st_mode)) new = xmprintf("%s/%s", dest, basename(try));
+    else new = dest;
+
+    // Force needs to unlink the existing target (if any). Do that by creating
+    // a temp version and renaming it over the old one, so we can retain the
+    // old file in cases we can't replace it (such as hardlink between mounts).
+    oldnew = new;
+    if (toys.optflags & FLAG_f) {
+      new = xmprintf("%s_XXXXXX", new);
+      rc = mkstemp(new);
+      if (rc >= 0) {
+        close(rc);
+        if (unlink(new)) perror_msg("unlink '%s'", new);
+      }
+    }
+
+    rc = (toys.optflags & FLAG_s) ? symlink(try, new) : link(try, new);
+    if (toys.optflags & FLAG_f) {
+      if (!rc) {
+        int temp;
+
+        rc = rename(new, oldnew);
+        temp = errno;
+        if (rc && unlink(new)) perror_msg("unlink '%s'", new);
+        errno = temp;
+      }
+      free(new);
+      new = oldnew;
+    }
+    if (rc)
+      perror_msg("cannot create %s link from '%s' to '%s'",
+        (toys.optflags & FLAG_s) ? "symbolic" : "hard", try, new);
+    else
+      if (toys.optflags & FLAG_v) fprintf(stderr, "'%s' -> '%s'\n", new, try);
+
+    if (new != dest) free(new);
+  }
+}
diff --git a/toybox/toys/posix/ls.c b/toybox/toys/posix/ls.c
new file mode 100644
index 0000000..6b181c0
--- /dev/null
+++ b/toybox/toys/posix/ls.c
@@ -0,0 +1,569 @@
+/* ls.c - list files
+ *
+ * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html
+
+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"
+  default y
+  help
+    usage: ls [-ACFHLRSZacdfhiklmnpqrstux1] [directory...]
+
+    list files
+
+    what to show:
+    -a  all files including .hidden    -b  escape nongraphic chars
+    -c  use ctime for timestamps       -d  directory, not contents
+    -i  inode number                   -k  block sizes in kilobytes
+    -p  put a '/' after dir names      -q  unprintable chars as '?'
+    -s  size (in blocks)               -u  use access time for timestamps
+    -A  list all files but . and ..    -H  follow command line symlinks
+    -L  follow symlinks                -R  recursively list files in subdirs
+    -F  append /dir *exe @sym |FIFO    -Z  security context
+
+    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)
+
+    sorting (default is alphabetical):
+    -f  unsorted    -r  reverse    -t  timestamp    -S  size
+
+config LS_COLOR
+  bool "ls --color"
+  default y
+  depends on LS
+  help
+    usage: ls --color[=auto]
+
+    --color  device=yellow  symlink=turquoise/red  dir=blue  socket=purple
+             files: exe=green  suid=red  suidfile=redback  stickydir=greenback
+             =auto means detect if output is a tty.
+*/
+
+#define FOR_ls
+#include "toys.h"
+
+// test sst output (suid/sticky in ls flaglist)
+
+// ls -lR starts .: then ./subdir:
+
+GLOBALS(
+  char *color;
+
+  struct dirtree *files, *singledir;
+
+  unsigned screen_width;
+  int nl_title;
+  char *escmore;
+)
+
+// Callback from crunch_str to represent unprintable chars
+int crunch_qb(FILE *out, int cols, int wc)
+{
+  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;
+    }
+  }
+
+  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;
+  if ((toys.optflags&(FLAG_F|FLAG_p)) && S_ISDIR(mode)) return '/';
+  if (toys.optflags & FLAG_F) {
+    if (S_ISLNK(mode)) return '@';
+    if (S_ISREG(mode) && (mode&0111)) return '*';
+    if (S_ISFIFO(mode)) return '|';
+    if (S_ISSOCK(mode)) return '=';
+  }
+  return 0;
+}
+
+static int numlen(long long ll)
+{
+  return snprintf(0, 0, "%llu", ll);
+}
+
+// Figure out size of printable entry fields for display indent/wrap
+
+static void entrylen(struct dirtree *dt, unsigned *len)
+{
+  struct stat *st = &(dt->st);
+  unsigned flags = toys.optflags;
+  char tmp[64];
+
+  *len = strwidth(dt->name);
+  if (endtype(st)) ++*len;
+  if (flags & FLAG_m) ++*len;
+
+  len[1] = (flags & FLAG_i) ? numlen(st->st_ino) : 0;
+  if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) {
+    unsigned fn = flags & FLAG_n;
+    len[2] = numlen(st->st_nlink);
+    len[3] = fn ? numlen(st->st_uid) : strwidth(getusername(st->st_uid));
+    len[4] = fn ? numlen(st->st_gid) : strwidth(getgroupname(st->st_gid));
+    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(dev_major(st->st_rdev))+5;
+    } else if (flags & FLAG_h) {
+        human_readable(tmp, st->st_size, 0);
+        len[5] = strwidth(tmp);
+    } else len[5] = numlen(st->st_size);
+  }
+
+  len[6] = (flags & FLAG_s) ? numlen(st->st_blocks) : 0;
+  len[7] = (flags & FLAG_Z) ? strwidth((char *)dt->extra) : 0;
+}
+
+static int compare(void *a, void *b)
+{
+  struct dirtree *dta = *(struct dirtree **)a;
+  struct dirtree *dtb = *(struct dirtree **)b;
+  int ret = 0, reverse = (toys.optflags & FLAG_r) ? -1 : 1;
+
+  if (toys.optflags & FLAG_S) {
+    if (dta->st.st_size > dtb->st.st_size) ret = -1;
+    else if (dta->st.st_size < dtb->st.st_size) ret = 1;
+  }
+  if (toys.optflags & FLAG_t) {
+    if (dta->st.st_mtime > dtb->st.st_mtime) ret = -1;
+    else if (dta->st.st_mtime < dtb->st.st_mtime) ret = 1;
+  }
+  if (!ret) ret = strcmp(dta->name, dtb->name);
+  return ret * reverse;
+}
+
+// callback from dirtree_recurse() determining how to handle this entry.
+
+static int filter(struct dirtree *new)
+{
+  int flags = toys.optflags;
+
+  // Special case to handle enormous dirs without running out of memory.
+  if (flags == (FLAG_1|FLAG_f)) {
+    xprintf("%s\n", new->name);
+    return 0;
+  }
+
+  if (flags & FLAG_Z) {
+    if (!CFG_TOYBOX_LSM_NONE) {
+
+      // (Wouldn't it be nice if the lsm functions worked like openat(),
+      // fchmodat(), mknodat(), readlinkat() so we could do this without
+      // even O_PATH? But no, this is 1990's tech.)
+      int fd = openat(dirtree_parentfd(new), new->name,
+        O_PATH|(O_NOFOLLOW*!(toys.optflags&FLAG_L)));
+
+      if (fd != -1) {
+        if (-1 == lsm_fget_context(fd, (char **)&new->extra) && errno == EBADF)
+        {
+          char hack[32];
+
+          // Work around kernel bug that won't let us read this "metadata" from
+          // the filehandle unless we have permission to read the data. (We can
+          // query the same data in by path, but can't do it through an O_PATH
+          // filehandle, because reasons. But for some reason, THIS is ok? If
+          // they ever fix the kernel, this should stop triggering.)
+
+          sprintf(hack, "/proc/self/fd/%d", fd);
+          lsm_lget_context(hack, (char **)&new->extra);
+        }
+        close(fd);
+      }
+    }
+    if (CFG_TOYBOX_LSM_NONE || !new->extra) new->extra = (long)xstrdup("?");
+  }
+
+  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;
+
+  if (flags & (FLAG_a|FLAG_f)) return DIRTREE_SAVE;
+  if (!(flags & FLAG_A) && new->name[0]=='.') return 0;
+
+  return dirtree_notdotdot(new) & DIRTREE_SAVE;
+}
+
+// For column view, calculate horizontal position (for padding) and return
+// index of next entry to display.
+
+static unsigned long next_column(unsigned long ul, unsigned long dtlen,
+  unsigned columns, unsigned *xpos)
+{
+  unsigned long transition;
+  unsigned height, widecols;
+
+  // Horizontal sort is easy
+  if (!(toys.optflags & FLAG_C)) {
+    *xpos = ul % columns;
+    return ul;
+  }
+
+  // vertical sort
+
+  // For -x, calculate height of display, rounded up
+  height = (dtlen+columns-1)/columns;
+
+  // Sanity check: does wrapping render this column count impossible
+  // due to the right edge wrapping eating a whole row?
+  if (height*columns - dtlen >= height) {
+    *xpos = columns;
+    return 0;
+  }
+
+  // Uneven rounding goes along right edge
+  widecols = dtlen % height;
+  if (!widecols) widecols = height;
+  transition = widecols * columns;
+  if (ul < transition) {
+    *xpos =  ul % columns;
+    return (*xpos*height) + (ul/columns);
+  }
+
+  ul -= transition;
+  *xpos = ul % (columns-1);
+
+  return (*xpos*height) + widecols + (ul/(columns-1));
+}
+
+int color_from_mode(mode_t mode)
+{
+  int color = 0;
+
+  if (S_ISDIR(mode)) color = 256+34;
+  else if (S_ISLNK(mode)) color = 256+36;
+  else if (S_ISBLK(mode) || S_ISCHR(mode)) color = 256+33;
+  else if (S_ISREG(mode) && (mode&0111)) color = 256+32;
+  else if (S_ISFIFO(mode)) color = 33;
+  else if (S_ISSOCK(mode)) color = 256+35;
+
+  return color;
+}
+
+// Display a list of dirtree entries, according to current format
+// Output types -1, -l, -C, or stream
+
+static void listfiles(int dirfd, struct dirtree *indir)
+{
+  struct dirtree *dt, **sort;
+  unsigned long dtlen, ul = 0;
+  unsigned width, flags = toys.optflags, totals[8], len[8], totpad = 0,
+    *colsizes = (unsigned *)(toybuf+260), columns = (sizeof(toybuf)-260)/4;
+  char tmp[64];
+
+  if (-1 == dirfd) {
+    perror_msg_raw(indir->name);
+
+    return;
+  }
+
+  memset(totals, 0, sizeof(totals));
+  if (CFG_TOYBOX_ON_ANDROID || CFG_TOYBOX_DEBUG) memset(len, 0, sizeof(len));
+
+  // Top level directory was already populated by main()
+  if (!indir->parent) {
+    // Silently descend into single directory listed by itself on command line.
+    // In this case only show dirname/total header when given -R.
+    dt = indir->child;
+    if (dt && S_ISDIR(dt->st.st_mode) && !dt->next && !(flags&(FLAG_d|FLAG_R)))
+    {
+      listfiles(open(dt->name, 0), TT.singledir = dt);
+
+      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;
+  // 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
+  // fill with the same inner loop.)
+  for (sort = 0;;sort = xmalloc(dtlen*sizeof(void *))) {
+    for (dtlen = 0, dt = indir->child; dt; dt = dt->next, dtlen++)
+      if (sort) sort[dtlen] = dt;
+    if (sort || !dtlen) break;
+  }
+
+  // Label directory if not top of tree, or if -R
+  if (indir->parent && (TT.singledir!=indir || (flags&FLAG_R)))
+  {
+    char *path = dirtree_path(indir, 0);
+
+    if (TT.nl_title++) xputc('\n');
+    xprintf("%s:\n", path);
+    free(path);
+  }
+
+  // Measure each entry to work out whitespace padding and total blocks
+  if (!(flags & FLAG_f)) {
+    unsigned long long blocks = 0;
+
+    qsort(sort, dtlen, sizeof(void *), (void *)compare);
+    for (ul = 0; ul<dtlen; ul++) {
+      entrylen(sort[ul], len);
+      for (width = 0; width<8; width++)
+        if (len[width]>totals[width]) totals[width] = len[width];
+      blocks += sort[ul]->st.st_blocks;
+    }
+    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);
+    }
+  }
+
+  // Find largest entry in each field for display alignment
+  if (flags & (FLAG_C|FLAG_x)) {
+
+    // columns can't be more than toybuf can hold, or more than files,
+    // or > 1/2 screen width (one char filename, one space).
+    if (columns > TT.screen_width/2) columns = TT.screen_width/2;
+    if (columns > dtlen) columns = dtlen;
+
+    // Try to fit as many columns as we can, dropping down by one each time
+    for (;columns > 1; columns--) {
+      unsigned c, totlen = columns;
+
+      memset(colsizes, 0, columns*sizeof(unsigned));
+      for (ul=0; ul<dtlen; ul++) {
+        entrylen(sort[next_column(ul, dtlen, columns, &c)], len);
+        *len += totpad;
+        if (c == columns) break;
+        // Expand this column if necessary, break if that puts us over budget
+        if (*len > colsizes[c]) {
+          totlen += (*len)-colsizes[c];
+          colsizes[c] = *len;
+          if (totlen > TT.screen_width) break;
+        }
+      }
+      // If everything fit, stop here
+      if (ul == dtlen) break;
+    }
+  }
+
+  // Loop through again to produce output.
+  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), *ss;
+
+    // Skip directories at the top of the tree when -d isn't set
+    if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue;
+    TT.nl_title=1;
+
+    // Handle padding and wrapping for display purposes
+    entrylen(sort[next], len);
+    if (ul) {
+      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) {
+        xputc('\n');
+        width = 0;
+      } else {
+        xputc(' ');
+        width++;
+      }
+    }
+    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_l|FLAG_o|FLAG_n|FLAG_g)) {
+      struct tm *tm;
+
+      // (long) is to coerce the st types into something we know we can print.
+      mode_to_string(mode, tmp);
+      printf("%s% *ld", tmp, totals[2]+1, (long)st->st_nlink);
+
+      // print user
+      if (!(flags&FLAG_g)) {
+        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)) {
+        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)
+        printf(" %-*s", -(int)totals[7], (char *)sort[next]->extra);
+
+      // print major/minor, or size
+      if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
+        printf("% *d,% 4d", totals[5]-4, dev_major(st->st_rdev),
+          dev_minor(st->st_rdev));
+      else if (flags&FLAG_h) {
+        human_readable(tmp, st->st_size, 0);
+        xprintf("%*s", totals[5]+1, tmp);
+      } else printf("% *lld", totals[5]+1, (long long)st->st_size);
+
+      // print time, always in --time-style=long-iso
+      tm = localtime(&(st->st_mtime));
+      strftime(tmp, sizeof(tmp), "%F %H:%M", tm);
+      xprintf(" %s ", tmp);
+    } else if (flags & FLAG_Z)
+      printf("%-*s ", (int)totals[7], (char *)sort[next]->extra);
+
+    if (flags & FLAG_color) {
+      color = color_from_mode(st->st_mode);
+      if (color) printf("\033[%d;%dm", color>>8, color&255);
+    }
+
+    ss = sort[next]->name;
+    crunch_str(&ss, INT_MAX, stdout, TT.escmore, crunch_qb);
+    if (color) xprintf("\033[0m");
+
+    if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) {
+      printf(" -> ");
+      if (flags & FLAG_color) {
+        struct stat st2;
+
+        if (fstatat(dirfd, sort[next]->symlink, &st2, 0)) color = 256+31;
+        else color = color_from_mode(st2.st_mode);
+
+        if (color) printf("\033[%d;%dm", color>>8, color&255);
+      }
+
+      printf("%s", sort[next]->symlink);
+      if (color) printf("\033[0m");
+    }
+
+    if (et) xputc(et);
+
+    // Pad columns
+    if (flags & (FLAG_C|FLAG_x)) {
+      curcol = colsizes[curcol]-(*len)-totpad;
+      if (curcol < 255) xprintf("%s", toybuf+255-curcol);
+    }
+  }
+
+  if (width) xputc('\n');
+
+  // Free directory entries, recursing first if necessary.
+
+  for (ul = 0; ul<dtlen; free(sort[ul++])) {
+    if ((flags & FLAG_d) || !S_ISDIR(sort[ul]->st.st_mode)) continue;
+
+    // Recurse into dirs if at top of the tree or given -R
+    if (!indir->parent || ((flags&FLAG_R) && dirtree_notdotdot(sort[ul])))
+      listfiles(openat(dirfd, sort[ul]->name, 0), sort[ul]);
+    free((void *)sort[ul]->extra);
+  }
+  free(sort);
+  if (dirfd != AT_FDCWD) close(dirfd);
+}
+
+void ls_main(void)
+{
+  char **s, *noargs[] = {".", 0};
+  struct dirtree *dt;
+
+  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_m)) toys.optflags |= FLAG_1;
+    if (TT.color) toys.optflags ^= FLAG_color;
+  } else if (toys.optflags&(FLAG_l|FLAG_o|FLAG_n|FLAG_g))
+    toys.optflags |= FLAG_1;
+  else if (!(toys.optflags&(FLAG_1|FLAG_x|FLAG_m))) toys.optflags |= FLAG_C;
+  // The optflags parsing infrastructure should really do this for us,
+  // but currently it has "switch off when this is set", so "-dR" and "-Rd"
+  // behave differently
+  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. 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++) {
+    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);
+    else toys.exitval = 1;
+  }
+
+  // Convert double_list into dirtree.
+  dlist_terminate(TT.files->child);
+  for (dt = TT.files->child; dt; dt = dt->next) dt->parent = TT.files;
+
+  // Display the files we collected
+  listfiles(AT_FDCWD, TT.files);
+
+  if (CFG_TOYBOX_FREE) free(TT.files);
+}
diff --git a/toybox/toys/posix/mkdir.c b/toybox/toys/posix/mkdir.c
new file mode 100644
index 0000000..95bdf33
--- /dev/null
+++ b/toybox/toys/posix/mkdir.c
@@ -0,0 +1,55 @@
+/* mkdir.c - Make directories
+ *
+ * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/mkdir.html
+
+USE_MKDIR(NEWTOY(mkdir, "<1"USE_MKDIR_Z("Z:")"vpm:", TOYFLAG_BIN|TOYFLAG_UMASK))
+
+config MKDIR
+  bool "mkdir"
+  default y
+  help
+    usage: mkdir [-vp] [-m mode] [dirname...]
+
+    Create one or more directories.
+
+    -m	set permissions of directory to mode.
+    -p	make parent directories as needed.
+    -v	verbose
+
+config MKDIR_Z
+  bool
+  default y
+  depends on MKDIR && !TOYBOX_LSM_NONE
+  help
+    usage: [-Z context]
+
+    -Z	set security context
+*/
+
+#define FOR_mkdir
+#include "toys.h"
+
+GLOBALS(
+  char *arg_mode;
+  char *arg_context;
+)
+
+void mkdir_main(void)
+{
+  char **s;
+  mode_t mode = (0777&~toys.old_umask);
+
+  if (CFG_MKDIR_Z && (toys.optflags&FLAG_Z))
+    if (0>lsm_set_create(TT.arg_context))
+      perror_exit("-Z '%s' failed", TT.arg_context);
+
+  if (TT.arg_mode) mode = string_to_mode(TT.arg_mode, 0777);
+
+  // Note, -p and -v flags line up with mkpathat() flags
+  for (s=toys.optargs; *s; s++) {
+    if (mkpathat(AT_FDCWD, *s, mode, toys.optflags|1))
+      perror_msg("'%s'", *s);
+  }
+}
diff --git a/toybox/toys/posix/mkfifo.c b/toybox/toys/posix/mkfifo.c
new file mode 100644
index 0000000..942dfdc
--- /dev/null
+++ b/toybox/toys/posix/mkfifo.c
@@ -0,0 +1,50 @@
+/* mkfifo.c - Create FIFOs (named pipes)
+ *
+ * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/mkfifo.html
+
+USE_MKFIFO(NEWTOY(mkfifo, "<1"USE_MKFIFO_Z("Z:")"m:", TOYFLAG_USR|TOYFLAG_BIN))
+
+config MKFIFO
+  bool "mkfifo"
+  default y
+  help
+    usage: mkfifo [NAME...]
+
+    Create FIFOs (named pipes).
+
+config MKFIFO_Z
+  bool
+  default y
+  depends on MKFIFO && !TOYBOX_LSM_NONE
+  help
+    usage: mkfifo [-Z CONTEXT]
+
+    -Z	Security context
+*/
+
+#define FOR_mkfifo
+#include "toys.h"
+
+GLOBALS(
+  char *m_string;
+  char *Z;
+
+  mode_t mode;
+)
+
+void mkfifo_main(void)
+{
+  char **s;
+
+  TT.mode = 0666;
+  if (toys.optflags & FLAG_m) TT.mode = string_to_mode(TT.m_string, 0);
+
+  if (CFG_MKFIFO_Z && (toys.optflags&FLAG_Z))
+    if (0>lsm_set_create(TT.Z))
+      perror_exit("-Z '%s' failed", TT.Z);
+
+  for (s = toys.optargs; *s; s++)
+    if (mknod(*s, S_IFIFO | TT.mode, 0) < 0) perror_msg_raw(*s);
+}
diff --git a/toybox/toys/posix/nice.c b/toybox/toys/posix/nice.c
new file mode 100644
index 0000000..4b587ee
--- /dev/null
+++ b/toybox/toys/posix/nice.c
@@ -0,0 +1,38 @@
+/* nice.c - Run a program at a different niceness level.
+ *
+ * Copyright 2010 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/nice.html
+
+USE_NICE(NEWTOY(nice, "^<1n#", TOYFLAG_USR|TOYFLAG_BIN))
+
+config NICE
+  bool "nice"
+  default y
+  help
+    usage: nice [-n PRIORITY] command [args...]
+
+    Run a command line at an increased or decreased scheduling priority.
+
+    Higher numbers make a program yield more CPU time, from -20 (highest
+    priority) to 19 (lowest).  By default processes inherit their parent's
+    niceness (usually 0).  By default this command adds 10 to the parent's
+    priority.  Only root can set a negative niceness level.
+*/
+
+#define FOR_nice
+#include "toys.h"
+
+GLOBALS(
+  long priority;
+)
+
+void nice_main(void)
+{
+  if (!toys.optflags) TT.priority = 10;
+
+  errno = 0;
+  if (nice(TT.priority)==-1 && errno) perror_exit("Can't set priority");
+
+  xexec(toys.optargs);
+}
diff --git a/toybox/toys/posix/nl.c b/toybox/toys/posix/nl.c
new file mode 100644
index 0000000..9b02bfa
--- /dev/null
+++ b/toybox/toys/posix/nl.c
@@ -0,0 +1,93 @@
+/* nl.c - print line numbers
+ *
+ * Copyright 2013 CE Strake <strake888@gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/nl.html
+ *
+ * This implements a subset: only one logical page (-ip), no sections (-dfh).
+ * todo: -lv
+
+USE_NL(NEWTOY(nl, "v#<1=1l#b:n:s:w#<0=6E", TOYFLAG_BIN))
+
+config NL
+  bool "nl"
+  default y
+  help
+    usage: nl [-E] [-l #] [-b MODE] [-n STYLE] [-s SEPARATOR] [-w WIDTH] [FILE...]
+
+    Number lines of input.
+
+    -E	Use extended regex syntax (when doing -b pREGEX)
+    -b	which lines to number: a (all) t (non-empty, default) pREGEX (pattern)
+    -l	Only count last of this many consecutive blank lines
+    -n	number STYLE: ln (left justified) rn (right justified) rz (zero pad)
+    -s	Separator to use between number and line (instead of TAB)
+    -w	Width of line numbers (default 6)
+*/
+
+#define FOR_nl
+#include "toys.h"
+
+GLOBALS(
+  long w;
+  char *s;
+  char *n;
+  char *b;
+  long l;
+  long v;
+
+  // Count of consecutive blank lines for -l has to persist between files
+  long lcount;
+)
+
+static void do_nl(int fd, char *name)
+{
+  FILE *f = xfdopen(fd, "r");
+  int w = TT.w, slen = strlen(TT.s);
+
+  for (;;) {
+    char *line = 0;
+    size_t temp;
+    int match = *TT.b != 'n';
+
+    if (getline(&line, &temp, f) < 1) {
+      if (ferror(f)) perror_msg_raw(name);
+      break;
+    }
+
+    if (*TT.b == 'p') match = !regexec((void *)(toybuf+16), line, 0, 0, 0);
+    if (TT.l || *TT.b == 't')
+      if (*line == '\n') match = TT.l && ++TT.lcount >= TT.l;
+    if (match) {
+      TT.lcount = 0;
+      printf(toybuf, w, TT.v++, TT.s);
+    } else printf("%*c", (int)w+slen, ' ');
+    xprintf("%s", line);
+
+    free(line);
+  }
+
+  fclose(f);
+}
+
+void nl_main(void)
+{
+  char *clip = "";
+
+  if (!TT.s) TT.s = "\t";
+
+  if (!TT.n || !strcmp(TT.n, "rn")); // default
+  else if (!strcmp(TT.n, "ln")) clip = "-";
+  else if (!strcmp(TT.n, "rz")) clip = "0";
+  else error_exit("bad -n '%s'", TT.n);
+
+  sprintf(toybuf, "%%%s%s", clip, "*ld%s");
+
+  if (!TT.b) TT.b = "t";
+  if (*TT.b == 'p' && TT.b[1])
+    xregcomp((void *)(toybuf+16), TT.b+1,
+      REG_NOSUB | (toys.optflags&FLAG_E)*REG_EXTENDED);
+  else if (!strchr("atn", *TT.b)) error_exit("bad -b '%s'", TT.b);
+
+  loopfiles (toys.optargs, do_nl);
+}
diff --git a/toybox/toys/posix/nohup.c b/toybox/toys/posix/nohup.c
new file mode 100644
index 0000000..b302cbe
--- /dev/null
+++ b/toybox/toys/posix/nohup.c
@@ -0,0 +1,42 @@
+/* nohup.c - run commandline with SIGHUP blocked.
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/nohup.html
+
+USE_NOHUP(NEWTOY(nohup, "<1^", TOYFLAG_USR|TOYFLAG_BIN))
+
+config NOHUP
+  bool "nohup"
+  default y
+  help
+    usage: nohup COMMAND [ARGS...]
+
+    Run a command that survives the end of its terminal.
+
+    Redirect tty on stdin to /dev/null, tty on stdout to "nohup.out".
+*/
+
+#include "toys.h"
+
+void nohup_main(void)
+{
+  xsignal(SIGHUP, SIG_IGN);
+  if (isatty(1)) {
+    close(1);
+    if (-1 == open("nohup.out", O_CREAT|O_APPEND|O_WRONLY,
+        S_IRUSR|S_IWUSR ))
+    {
+      char *temp = getenv("HOME");
+
+      temp = xmprintf("%s/%s", temp ? temp : "", "nohup.out");
+      xcreate(temp, O_CREAT|O_APPEND|O_WRONLY, 0600);
+      free(temp);
+    }
+  }
+  if (isatty(0)) {
+    close(0);
+    xopen_stdio("/dev/null", O_RDONLY);
+  }
+  xexec(toys.optargs);
+}
diff --git a/toybox/toys/posix/od.c b/toybox/toys/posix/od.c
new file mode 100644
index 0000000..5ccea58
--- /dev/null
+++ b/toybox/toys/posix/od.c
@@ -0,0 +1,296 @@
+/* od.c - Provide octal/hex dumps of data
+ *
+ * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/od.html
+
+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 #] [-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
+    	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
+#include "toys.h"
+
+GLOBALS(
+  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; // Points to buffers[0] or buffers[1].
+  char *bufs[2]; // Used to detect duplicate lines.
+  off_t pos;
+)
+
+static char *ascii = "nulsohstxetxeotenqackbel bs ht nl vt ff cr so si"
+  "dledc1dc2dc3dc4naksynetbcan emsubesc fs gs rs us sp";
+
+struct odtype {
+  int type;
+  int size;
+};
+
+static int od_out_t(struct odtype *t, char *buf, int *offset)
+{
+  unsigned k;
+  int throw = 0, pad = 0;
+
+  // Handle ascii
+  if (t->type < 2) {
+    char c = TT.buf[(*offset)++];
+    pad += 4;
+
+    if (!t->type) {
+      c &= 127;
+      if (c<=32) sprintf(buf, "%.3s", ascii+(3*c));
+      else if (c==127) strcpy(buf, "del");
+      else sprintf(buf, "%c", c);
+    } else {
+      char *bfnrtav = "\b\f\n\r\t\a\v", *s = strchr(bfnrtav, c);
+      if (s) sprintf(buf, "\\%c", "bfnrtav0"[s-bfnrtav]);
+      else if (c < 32 || c >= 127) sprintf(buf, "%03o", c);
+      else {
+        // TODO: this should be UTF8 aware.
+        sprintf(buf, "%c", c);
+      }
+    }
+  } else if (CFG_TOYBOX_FLOAT && t->type == 6) {
+    long double ld;
+    union {float f; double d; long double ld;} fdl;
+
+    memcpy(&fdl, TT.buf+*offset, t->size);
+    *offset += t->size;
+    if (sizeof(float) == t->size) {
+      ld = fdl.f;
+      pad += (throw = 8)+7;
+    } else if (sizeof(double) == t->size) {
+      ld = fdl.d;
+      pad += (throw = 17)+8;
+    } else if (sizeof(long double) == t->size) {
+      ld = fdl.ld;
+      pad += (throw = 21)+9;
+    } else error_exit("bad -tf '%d'", t->size);
+
+    sprintf(buf, "%.*Le", throw, ld);
+  // Integer types
+  } else {
+    unsigned long long ll = 0, or;
+    char *c[] = {"%*lld", "%*llu", "%0*llo", "%0*llx"},
+      *class = c[t->type-2];
+
+    // Work out width of field
+    if (t->size == 8) {
+      or = -1LL;
+      if (t->type == 2) or >>= 1;
+    } else or = (1LL<<(8*t->size))-1;
+    throw = sprintf(buf, class, 0, or);
+
+    // Accumulate integer based on size argument
+    for (k=0; k < t->size; k++) {
+      or = TT.buf[(*offset)++];
+      ll |= or << (8*(IS_BIG_ENDIAN ? t->size-k-1 : k));
+    }
+
+    // Handle negative values
+    if (t->type == 2) {
+      or = sizeof(or) - t->size;
+      throw++;
+      if (or && (ll & (1l<<((8*t->size)-1))))
+        ll |= ((or<<(8*or))-1) << (8*t->size);
+    }
+
+    sprintf(buf, class, throw, ll);
+    pad += throw+1;
+  }
+
+  return pad;
+}
+
+static void od_outline(void)
+{
+  unsigned flags = toys.optflags;
+  char buf[128], *abases[] = {"", "%07lld", "%07llo", "%06llx"};
+  struct odtype *types = (struct odtype *)toybuf;
+  int i, j, len, pad;
+
+  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[0], TT.bufs[1], TT.width))
+  {
+    if (!TT.star) {
+      xputs("*");
+      TT.star++;
+    }
+
+  // Print line position
+  } else {
+    TT.star = 0;
+
+    // off_t varies so expand it to largest possible size
+    xprintf(abases[TT.address_idx], (long long)TT.pos);
+    if (!TT.leftover) {
+      if (TT.address_idx) xputc('\n');
+      return;
+    }
+  }
+
+  TT.pos += len = TT.leftover;
+  TT.leftover = 0;
+  if (TT.star) return;
+
+  // Find largest "pad" of the output types.
+  for (i = pad = 0; i<TT.types; i++) {
+    int bytes = 0;
+
+    // If more than one byte of input consumed, average rounding up.
+    j = od_out_t(types+i, buf, &bytes);
+    j = (j+bytes-1)/bytes;
+   
+    if (j > pad) pad = j;
+  }
+
+  // For each output type, print one line
+  for (i=0; i<TT.types; i++) {
+    for (j = 0; j<len;) {
+      int bytes = j;
+
+      // pad for as many bytes as were consumed, and indent non-numbered lines
+      od_out_t(types+i, buf, &bytes);
+      xprintf("%*s", pad*(bytes-j) + 7*(!!i)*!j, buf);
+      j = bytes;
+    }
+    xputc('\n');
+  }
+
+  // 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
+static void do_od(int fd, char *name)
+{
+  // Skip input, possibly more than one entire file.
+  if (TT.jump_bytes > TT.pos) {
+    off_t pos = TT.jump_bytes-TT.pos, off = lskip(fd, pos);
+
+    if (off >= 0) TT.pos += pos-off;
+    if (TT.jump_bytes > TT.pos) return;
+  }
+
+  for(;;) {
+    char *buf = TT.buf + TT.leftover;
+    int len = TT.width - TT.leftover;
+
+    if (toys.optflags & FLAG_N) {
+      if (!TT.max_count) break;
+      if (TT.max_count < len) len = TT.max_count;
+    }
+
+    len = readall(fd, buf, len);
+    if (len < 0) {
+      perror_msg_raw(name);
+      break;
+    }
+    if (TT.max_count) TT.max_count -= len;
+    TT.leftover += len;
+    if (TT.leftover < TT.width) break;
+
+    od_outline();
+  }
+}
+
+// Handle one -t argument (including implicit ones)
+static void append_base(char *base)
+{
+  char *s = base;
+  struct odtype *types = (struct odtype *)toybuf;
+  int type;
+
+  for (;;) {
+    int size = 1;
+
+    if (!*s) return;
+    if (TT.types >= sizeof(toybuf)/sizeof(struct odtype)) break;
+    if (-1 == (type = stridx("acduox"USE_TOYBOX_FLOAT("f"), *(s++)))) break;
+
+    if (isdigit(*s)) {
+      size = strtol(s, &s, 10);
+      if (type < 2 && size != 1) break;
+      if (CFG_TOYBOX_FLOAT && type == 6 && size == sizeof(long double));
+      else if (size < 1 || size > 8) break;
+    } else if (CFG_TOYBOX_FLOAT && type == 6) {
+      int sizes[] = {sizeof(float), sizeof(double), sizeof(long double)};
+      if (-1 == (size = stridx("FDL", *s))) size = sizeof(double);
+      else {
+        s++;
+        size = sizes[size];
+      }
+    } else if (type > 1) {
+      if (-1 == (size = stridx("CSIL", *s))) size = 4;
+      else {
+        s++;
+        size = 1 << size;
+      }
+    }
+
+    types[TT.types].type = type;
+    types[TT.types].size = size;
+    TT.types++;
+  }
+
+  error_exit("bad -t %s", base);
+}
+
+void od_main(void)
+{
+  struct arg_list *arg;
+
+  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)))
+    error_exit("bad -A '%c'", *TT.address_base);
+
+  // Collect -t entries
+
+  for (arg = TT.output_base; arg; arg = arg->next) append_base(arg->arg);
+  if (toys.optflags & FLAG_b) append_base("o1");
+  if (toys.optflags & FLAG_c) append_base("c");
+  if (toys.optflags & FLAG_d) append_base("u2");
+  if (toys.optflags & FLAG_o) append_base("o2");
+  if (toys.optflags & FLAG_s) append_base("d2");
+  if (toys.optflags & FLAG_x) append_base("x2");
+  if (!TT.types) append_base("o2");
+
+  loopfiles(toys.optargs, do_od);
+
+  if (TT.leftover) od_outline();
+  od_outline();
+
+  if (CFG_TOYBOX_FREE) {
+    free(TT.bufs[0]);
+    free(TT.bufs[1]);
+  }
+}
diff --git a/toybox/toys/posix/paste.c b/toybox/toys/posix/paste.c
new file mode 100644
index 0000000..5ab3448
--- /dev/null
+++ b/toybox/toys/posix/paste.c
@@ -0,0 +1,99 @@
+/* paste.c - Replace newlines
+ *
+ * Copyright 2012 Felix Janda <felix.janda@posteo.de>
+ *
+ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/paste.html 
+ *
+USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_BIN))
+
+config PASTE
+  bool "paste"
+  default y
+  help
+    usage: paste [-s] [-d list] [file...]
+
+    Replace newlines in files.
+
+    -d list    list of delimiters to separate lines
+    -s         process files sequentially instead of in parallel
+
+    By default print corresponding lines separated by <tab>.
+*/
+#define FOR_paste
+#include "toys.h"
+
+GLOBALS(
+  char *delim;
+)
+
+void paste_main(void)
+{
+  char *p, *buf = toybuf, **args = toys.optargs;
+  size_t ndelim = 0;
+  int i, j, c;
+
+  // Process delimiter list
+  // TODO: Handle multibyte characters
+  if (!(toys.optflags & FLAG_d)) TT.delim = "\t";
+  for (p = TT.delim; *p; p++, buf++, ndelim++) {
+    if (*p == '\\') {
+      p++;
+      if (-1 == (i = stridx("nt\\0", *p)))
+        error_exit("bad delimiter: \\%c", *p);
+      *buf = "\n\t\\\0"[i];
+    } else *buf = *p;
+  }
+  *buf = 0;
+
+  if (toys.optflags & FLAG_s) { // Sequential
+    FILE *f;
+
+    for (; *args; args++) {
+      if ((*args)[0] == '-' && !(*args)[1]) f = stdin;
+      else if (!(f = fopen(*args, "r"))) perror_exit_raw(*args);
+      for (i = 0, c = 0; c != EOF;) {
+        switch(c = getc(f)) {
+        case '\n':
+          putchar(toybuf[i++ % ndelim]);
+        case EOF:
+          break;
+        default:
+          putchar(c);
+        }
+      }
+      if (f != stdin) fclose(f);
+      putchar('\n');
+    }
+  } else { // Parallel
+    // Need to be careful not to print an extra line at the end
+    FILE **files;
+    int anyopen = 1;
+
+    files = (FILE**)(buf + 1);
+    for (; *args; args++, files++) {
+      if ((*args)[0] == '-' && !(*args)[1]) *files = stdin;
+      else if (!(*files = fopen(*args, "r"))) perror_exit_raw(*args);
+    }
+    while (anyopen) {
+      anyopen = 0;
+      for (i = 0; i < toys.optc; i++) {
+        FILE **f = (FILE**)(buf + 1) + i;
+
+        if (*f) for (;;) {
+          c = getc(*f);
+          if (c != EOF) {
+            if (!anyopen++) for (j = 0; j < i; j++) putchar(toybuf[j % ndelim]);
+            if (c != '\n') putchar(c);
+            else break;
+          }
+          else {
+            if (*f != stdin) fclose(*f);
+            *f = 0;
+            break;
+          }
+        }
+        if (anyopen) putchar((i + 1 == toys.optc) ? toybuf[i % ndelim] : '\n');
+      }
+    }
+  }
+}
diff --git a/toybox/toys/posix/patch.c b/toybox/toys/posix/patch.c
new file mode 100644
index 0000000..fbad1fb
--- /dev/null
+++ b/toybox/toys/posix/patch.c
@@ -0,0 +1,431 @@
+/* patch.c - Apply a "universal" diff.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * see http://opengroup.org/onlinepubs/9699919799/utilities/patch.html
+ * (But only does -u, because who still cares about "ed"?)
+ *
+ * TODO:
+ * -b backup
+ * -N ignore already applied
+ * -d chdir first
+ * -D define wrap #ifdef and #ifndef around changes
+ * -o outfile output here instead of in place
+ * -r rejectfile write rejected hunks to this file
+ *
+ * -E remove empty files --remove-empty-files
+ * -f force (no questions asked)
+ * -F fuzz (number, default 2)
+ * [file] which file to patch
+
+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 [-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
+    hunks to stderr, and exits with nonzero status if any hunks fail.
+
+    A file compared against /dev/null (or with a date <= the epoch) is
+    created/deleted as appropriate.
+*/
+
+#define FOR_patch
+#include "toys.h"
+
+GLOBALS(
+  char *infile;
+  long prefix;
+  char *dir;
+
+  struct double_list *current_hunk;
+  long oldline, oldlen, newline, newlen;
+  long linenum;
+  int context, state, filein, fileout, filepatch, hunknum;
+  char *tempname;
+)
+
+// Dispose of a line of input, either by writing it out or discarding it.
+
+// state < 2: just free
+// state = 2: write whole line to stderr
+// state = 3: write whole line to fileout
+// state > 3: write line+1 to fileout when *line != state
+
+static void do_line(void *data)
+{
+  struct double_list *dlist = (struct double_list *)data;
+
+  if (TT.state>1 && *dlist->data != TT.state) {
+    char *s = dlist->data+(TT.state>3 ? 1 : 0);
+    int i = TT.state == 2 ? 2 : TT.fileout;
+
+    xwrite(i, s, strlen(s));
+    xwrite(i, "\n", 1);
+  }
+
+  if (toys.optflags & FLAG_x)
+    fprintf(stderr, "DO %d: %s\n", TT.state, dlist->data);
+
+  free(dlist->data);
+  free(data);
+}
+
+static void finish_oldfile(void)
+{
+  if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname);
+  TT.fileout = TT.filein = -1;
+}
+
+static void fail_hunk(void)
+{
+  if (!TT.current_hunk) return;
+
+  fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n",
+      TT.hunknum, TT.oldline, TT.newline);
+  toys.exitval = 1;
+
+  // If we got to this point, we've seeked to the end.  Discard changes to
+  // this file and advance to next file.
+
+  TT.state = 2;
+  llist_traverse(TT.current_hunk, do_line);
+  TT.current_hunk = NULL;
+  if (!(toys.optflags & FLAG_dry_run))
+    delete_tempfile(TT.filein, TT.fileout, &TT.tempname);
+  TT.state = 0;
+}
+
+// Compare ignoring whitespace. Just returns 0/1, no > or <
+static int loosecmp(char *aa, char *bb)
+{
+  int a = 0, b = 0;
+
+  for (;;) {
+    while (isspace(aa[a])) a++;
+    while (isspace(bb[b])) b++;
+    if (aa[a] != bb[b]) return 1;
+    if (!aa[a]) return 0;
+    a++, b++;
+  }
+}
+
+// Given a hunk of a unified diff, make the appropriate change to the file.
+// This does not use the location information, but instead treats a hunk
+// as a sort of regex.  Copies data from input to output until it finds
+// the change to be made, then outputs the changed data and returns.
+// (Finding EOF first is an error.)  This is a single pass operation, so
+// multiple hunks must occur in order in the file.
+
+static int apply_one_hunk(void)
+{
+  struct double_list *plist, *buf = NULL, *check;
+  int matcheof, trailing = 0, reverse = toys.optflags & FLAG_R, backwarn = 0;
+  int (*lcmp)(char *aa, char *bb);
+
+  lcmp = (toys.optflags & FLAG_l) ? (void *)loosecmp : (void *)strcmp;
+  dlist_terminate(TT.current_hunk);
+
+  // Match EOF if there aren't as many ending context lines as beginning
+  for (plist = TT.current_hunk; plist; plist = plist->next) {
+    if (plist->data[0]==' ') trailing++;
+    else trailing = 0;
+    if (toys.optflags & FLAG_x) fprintf(stderr, "HUNK:%s\n", plist->data);
+  }
+  matcheof = !trailing || trailing < TT.context;
+
+  if (toys.optflags & FLAG_x)
+    fprintf(stderr,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N');
+
+  // Loop through input data searching for this hunk.  Match all context
+  // lines and all lines to be removed until we've found the end of a
+  // complete hunk.
+  plist = TT.current_hunk;
+  buf = NULL;
+
+  for (;;) {
+    char *data = get_line(TT.filein);
+
+    TT.linenum++;
+    // Figure out which line of hunk to compare with next.  (Skip lines
+    // of the hunk we'd be adding.)
+    while (plist && *plist->data == "+-"[reverse]) {
+      if (data && !lcmp(data, plist->data+1)) {
+        if (!backwarn) backwarn = TT.linenum;
+      }
+      plist = plist->next;
+    }
+
+    // Is this EOF?
+    if (!data) {
+      if (toys.optflags & FLAG_x) fprintf(stderr, "INEOF\n");
+
+      // Does this hunk need to match EOF?
+      if (!plist && matcheof) break;
+
+      if (backwarn)
+        fprintf(stderr, "Possibly reversed hunk %d at %ld\n",
+            TT.hunknum, TT.linenum);
+
+      // File ended before we found a place for this hunk.
+      fail_hunk();
+      goto done;
+    } else if (toys.optflags & FLAG_x) fprintf(stderr, "IN: %s\n", data);
+    check = dlist_add(&buf, data);
+
+    // Compare this line with next expected line of hunk.
+
+    // A match can fail because the next line doesn't match, or because
+    // we hit the end of a hunk that needed EOF, and this isn't EOF.
+
+    // If match failed, flush first line of buffered data and
+    // recheck buffered data for a new match until we find one or run
+    // out of buffer.
+
+    for (;;) {
+      if (!plist || lcmp(check->data, plist->data+1)) {
+        // Match failed.  Write out first line of buffered data and
+        // recheck remaining buffered data for a new match.
+
+        if (toys.optflags & FLAG_x) {
+          int bug = 0;
+
+          if (!plist) fprintf(stderr, "NULL plist\n");
+          else {
+            while (plist->data[bug] == check->data[bug]) bug++;
+            fprintf(stderr, "NOT(%d:%d!=%d): %s\n", bug, plist->data[bug],
+              check->data[bug], plist->data);
+          }
+        }
+
+        // If this hunk must match start of file, fail if it didn't.
+        if (!TT.context || trailing>TT.context) {
+          fail_hunk();
+          goto done;
+        }
+
+        TT.state = 3;
+        do_line(check = dlist_pop(&buf));
+        plist = TT.current_hunk;
+
+        // If we've reached the end of the buffer without confirming a
+        // match, read more lines.
+        if (!buf) break;
+        check = buf;
+      } else {
+        if (toys.optflags & FLAG_x) fprintf(stderr, "MAYBE: %s\n", plist->data);
+        // This line matches.  Advance plist, detect successful match.
+        plist = plist->next;
+        if (!plist && !matcheof) goto out;
+        check = check->next;
+        if (check == buf) break;
+      }
+    }
+  }
+out:
+  // We have a match.  Emit changed data.
+  TT.state = "-+"[reverse];
+  llist_traverse(TT.current_hunk, do_line);
+  TT.current_hunk = NULL;
+  TT.state = 1;
+done:
+  if (buf) {
+    dlist_terminate(buf);
+    llist_traverse(buf, do_line);
+  }
+
+  return TT.state;
+}
+
+// Read a patch file and find hunks, opening/creating/deleting files.
+// Call apply_one_hunk() on each hunk.
+
+// state 0: Not in a hunk, look for +++.
+// state 1: Found +++ file indicator, look for @@
+// state 2: In hunk: counting initial context lines
+// state 3: In hunk: getting body
+
+void patch_main(void)
+{
+  int reverse = toys.optflags&FLAG_R, state = 0, patchlinenum = 0,
+    strip = 0;
+  char *oldname = NULL, *newname = NULL;
+
+  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;
+
+    patchline = get_line(TT.filepatch);
+    if (!patchline) break;
+
+    // Other versions of patch accept damaged patches,
+    // so we need to also.
+    if (strip || !patchlinenum++) {
+      int len = strlen(patchline);
+      if (patchline[len-1] == '\r') {
+        if (!strip) fprintf(stderr, "Removing DOS newlines\n");
+        strip = 1;
+        patchline[len-1]=0;
+      }
+    }
+    if (!*patchline) {
+      free(patchline);
+      patchline = xstrdup(" ");
+    }
+
+    // Are we assembling a hunk?
+    if (state >= 2) {
+      if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
+        dlist_add(&TT.current_hunk, patchline);
+
+        if (*patchline != '+') TT.oldlen--;
+        if (*patchline != '-') TT.newlen--;
+
+        // Context line?
+        if (*patchline==' ' && state==2) TT.context++;
+        else state=3;
+
+        // If we've consumed all expected hunk lines, apply the hunk.
+
+        if (!TT.oldlen && !TT.newlen) state = apply_one_hunk();
+        continue;
+      }
+      dlist_terminate(TT.current_hunk);
+      fail_hunk();
+      state = 0;
+      continue;
+    }
+
+    // Open a new file?
+    if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) {
+      char *s, **name = &oldname;
+      int i;
+
+      if (*patchline == '+') {
+        name = &newname;
+        state = 1;
+      }
+
+      free(*name);
+      finish_oldfile();
+
+      // Trim date from end of filename (if any).  We don't care.
+      for (s = patchline+4; *s && *s!='\t'; s++)
+        if (*s=='\\' && s[1]) s++;
+      i = atoi(s);
+      if (i>1900 && i<=1970) *name = xstrdup("/dev/null");
+      else {
+        *s = 0;
+        *name = xstrdup(patchline+4);
+      }
+
+      // We defer actually opening the file because svn produces broken
+      // patches that don't signal they want to create a new file the
+      // way the patch man page says, so you have to read the first hunk
+      // and _guess_.
+
+    // Start a new hunk?  Usually @@ -oldline,oldlen +newline,newlen @@
+    // but a missing ,value means the value is 1.
+    } else if (state == 1 && !strncmp("@@ -", patchline, 4)) {
+      int i;
+      char *s = patchline+4;
+
+      // Read oldline[,oldlen] +newline[,newlen]
+
+      TT.oldlen = TT.newlen = 1;
+      TT.oldline = strtol(s, &s, 10);
+      if (*s == ',') TT.oldlen=strtol(s+1, &s, 10);
+      TT.newline = strtol(s+2, &s, 10);
+      if (*s == ',') TT.newlen = strtol(s+1, &s, 10);
+
+      TT.context = 0;
+      state = 2;
+
+      // If this is the first hunk, open the file.
+      if (TT.filein == -1) {
+        int oldsum, newsum, del = 0;
+        char *name;
+
+        oldsum = TT.oldline + TT.oldlen;
+        newsum = TT.newline + TT.newlen;
+
+        name = reverse ? oldname : newname;
+
+        // We're deleting oldname if new file is /dev/null (before -p)
+        // or if new hunk is empty (zero context) after patching
+        if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum))
+        {
+          name = reverse ? newname : oldname;
+          del++;
+        }
+
+        // handle -p path truncation.
+        for (i = 0, s = name; *s;) {
+          if ((toys.optflags & FLAG_p) && TT.prefix == i) break;
+          if (*s++ != '/') continue;
+          while (*s == '/') s++;
+          name = s;
+          i++;
+        }
+
+        if (del) {
+          printf("removing %s\n", name);
+          xunlink(name);
+          state = 0;
+        // If we've got a file to open, do so.
+        } else if (!(toys.optflags & FLAG_p) || i <= TT.prefix) {
+          // If the old file was null, we're creating a new one.
+          if ((!strcmp(oldname, "/dev/null") || !oldsum) && access(name, F_OK))
+          {
+            printf("creating %s\n", name);
+            if (mkpathat(AT_FDCWD, name, 0, 2))
+              perror_exit("mkpath %s", name);
+            TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666);
+          } else {
+            printf("patching %s\n", name);
+            TT.filein = xopenro(name);
+          }
+          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;
+        }
+      }
+
+      TT.hunknum++;
+
+      continue;
+    }
+
+    // If we didn't continue above, discard this line.
+    free(patchline);
+  }
+
+  finish_oldfile();
+
+  if (CFG_TOYBOX_FREE) {
+    close(TT.filepatch);
+    free(oldname);
+    free(newname);
+  }
+}
diff --git a/toybox/toys/posix/printf.c b/toybox/toys/posix/printf.c
new file mode 100644
index 0000000..2dd1e2f
--- /dev/null
+++ b/toybox/toys/posix/printf.c
@@ -0,0 +1,144 @@
+/* printf.c - Format and Print the data.
+ *
+ * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
+ *
+ * todo: *m$ ala printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);
+
+USE_PRINTF(NEWTOY(printf, "<1?^", TOYFLAG_USR|TOYFLAG_BIN))
+
+config PRINTF 
+  bool "printf"
+  default y
+  help
+    usage: printf FORMAT [ARGUMENT...]
+    
+    Format and print ARGUMENT(s) according to FORMAT, using C printf syntax
+    (% escapes for cdeEfgGiosuxX, \ escapes for abefnrtv0 or \OCTAL or \xHEX).
+*/
+
+#define FOR_printf
+#include "toys.h"
+
+// Detect matching character (return true/false) and advance pointer if match.
+static int eat(char **s, char c)
+{
+  int x = (**s == c);
+
+  if (x) ++*s;
+
+  return x;
+}
+
+// Parse escape sequences.
+static int handle_slash(char **esc_val, int posix)
+{
+  char *ptr = *esc_val;
+  int len, base = 0;
+  unsigned result = 0, num;
+
+  if (*ptr == 'c') xexit();
+
+  // 0x12 hex escapes have 1-2 digits, \123 octal escapes have 1-3 digits.
+  if (eat(&ptr, 'x')) base = 16;
+  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 \)
+  if (!len) {
+    if (!(result = unescape(*ptr))) result = '\\';
+    else ++*esc_val;
+
+    return result;
+  }
+
+  while (len) {
+    num = tolower(*ptr) - '0';
+    if (num >= 'a'-'0') num += '0'-'a'+10;
+    if (num >= base) {
+      // Don't parse invalid hex value ala "\xvd", print it verbatim
+      if (base == 16 && len == 2) {
+        ptr--;
+        result = '\\';
+      }
+      break;
+    }
+    result = (result*base)+num;
+    ptr++;
+    len--;
+  }
+  *esc_val = ptr;
+
+  return result;
+}
+
+void printf_main(void)
+{
+  char **arg = toys.optargs+1;
+
+  // Repeat format until arguments consumed
+  for (;;) {
+    int seen = 0;
+    char *f = *toys.optargs;
+
+    // Loop through characters in format
+    while (*f) {
+      if (eat(&f, '\\')) putchar(handle_slash(&f, 0));
+      else if (!eat(&f, '%') || *f == '%') putchar(*f++);
+
+      // Handle %escape
+      else {
+        char c, *end = 0, *aa, *to = toybuf;
+        int wp[] = {0,-1}, i = 0;
+
+        // Parse width.precision between % and type indicator.
+        *to++ = '%';
+        while (strchr("-+# '0", *f) && (to-toybuf)<10) *to++ = *f++;
+        for (;;) {
+          if (eat(&f, '*')) {
+            if (*arg) wp[i] = atolx(*arg++);
+          } else while (*f >= '0' && *f <= '9') wp[i] = (wp[i]*10)+(*f++)-'0';
+          if (i++ || !eat(&f, '.')) break;
+          wp[1] = 0;
+        }
+        c = *f++;
+        seen = sprintf(to, "*.*%c", c);;
+        errno = 0;
+        aa = *arg ? *arg++ : "";
+
+        // Output %esc using parsed format string
+        if (c == 'b') {
+          while (*aa) putchar(eat(&aa, '\\') ? handle_slash(&aa, 1) : *aa++);
+
+          continue;
+        } else if (c == 'c') printf(toybuf, wp[0], wp[1], *aa);
+        else if (c == 's') printf(toybuf, wp[0], wp[1], aa);
+        else if (strchr("diouxX", c)) {
+          long ll;
+
+          if (*aa == '\'' || *aa == '"') ll = aa[1];
+          else ll = strtoll(aa, &end, 0);
+
+          sprintf(to, "*.*ll%c", c);
+          printf(toybuf, wp[0], wp[1], ll);
+        } else if (strchr("feEgG", c)) {
+          long double ld = strtold(aa, &end);
+
+          sprintf(to, "*.*L%c", c);
+          printf(toybuf, wp[0], wp[1], ld);
+        } else error_exit("bad %%%c@%ld", c, (long)(f-*toys.optargs));
+
+        if (end && (errno || *end)) perror_msg("bad %%%c %s", c, aa);
+      }
+    }
+
+    // Posix says to keep looping through format until we consume all args.
+    // This only works if the format actually consumed at least one arg.
+    if (!seen || !*arg) break;
+  }
+}
diff --git a/toybox/toys/posix/ps.c b/toybox/toys/posix/ps.c
new file mode 100644
index 0000000..6a128bd
--- /dev/null
+++ b/toybox/toys/posix/ps.c
@@ -0,0 +1,1765 @@
+/* ps.c - show process list
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
+ * And http://kernel.org/doc/Documentation/filesystems/proc.txt Table 1-4
+ * And linux kernel source fs/proc/array.c function do_task_stat()
+ *
+ * Deviations from posix: no -n because /proc/self/wchan exists; we use -n to
+ * mean "show numeric users and groups" instead.
+ * Posix says default output should have field named "TTY" but if you "-o tty"
+ * the same field should be called "TT" which is _INSANE_ and I'm not doing it.
+ * Similarly -f outputs USER but calls it UID (we call it USER).
+ * It also says that -o "args" and "comm" should behave differently but use
+ * the same title, which is not the same title as the default output. (No.)
+ * Select by session id is -s not -g.
+ *
+ * Posix defines -o ADDR as "The address of the process" but the process
+ * start address is a constant on any elf system with mmu. The procps ADDR
+ * field always prints "-" with an alignment of 1, which is why it has 11
+ * characters left for "cmd" in in 80 column "ps -l" mode. On x86-64 you
+ * need 12 chars, leaving nothing for cmd: I.E. posix 2008 ps -l mode can't
+ * be sanely implemented on 64 bit Linux systems. In procps there's ps -y
+ * which changes -l by removing the "F" column and swapping RSS for ADDR,
+ * leaving 9 chars for cmd, so we're using that as our -l output.
+ *
+ * Added a bunch of new -o fields posix doesn't mention, and we don't
+ * label "ps -o command,args,comm" as "COMMAND COMMAND COMMAND". We don't
+ * output argv[0] unmodified for -o comm or -o args (but procps violates
+ * posix for -o comm anyway, it's stat[2] not argv[0]).
+ *
+ * Note: iotop is STAYROOT so it can read other process's /proc/$PID/io
+ *       files (why they're not globally readable when the rest of proc
+ *       data is...?) and get a global I/O picture. Normal top is NOT,
+ *       even though you can -o AIO there, to give sysadmins the option
+ *       to reduce security exposure.)
+ *
+ * TODO: ps aux (att & bsd style "ps -ax" vs "ps ax" behavior difference)
+ * TODO: switch -fl to -y
+ * TODO: thread support /proc/$d/task/%d/stat (and -o stat has "l")
+ * TODO: iotop: Window size change: respond immediately. Why not padding
+ *       at right edge? (Not adjusting to screen size at all? Header wraps?)
+ * TODO: top: thread support and SMP
+ * TODO: pgrep -f only searches the amount of cmdline that fits in toybuf.
+
+USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+// stayroot because iotop needs root to read other process' proc/$$/io
+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))
+
+config PS
+  bool "ps"
+  default y
+  help
+    usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]
+
+    List processes.
+
+    Which processes to show (selections may be comma separated lists):
+
+    -A	All processes
+    -a	Processes with terminals that aren't session leaders
+    -d	All processes that aren't session leaders
+    -e	Same as -A
+    -g	Belonging to GROUPs
+    -G	Belonging to real GROUPs (before sgid)
+    -p	PIDs (--pid)
+    -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)
+
+    Output modifiers:
+
+    -k	Sort FIELDs in +increasing or -decreasting order (--sort)
+    -M	Measure field widths (expanding as necessary)
+    -n	Show numeric USER and GROUP
+    -w	Wide output (don't truncate at terminal width)
+
+    Which FIELDs to show. (Default = -o PID,TTY,TIME,CMD)
+
+    -f	Full listing (-o USER:8=UID,PID,PPID,C,STIME,TTY,TIME,ARGS=CMD)
+    -l	Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)
+    -o	Output FIELDs instead of defaults, each with optional :size and =title
+    -O	Add FIELDS to defaults
+    -Z	Include LABEL
+
+    Command line -o fields:
+
+      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
+      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
+      RSS   Resident Set Size (pages in use)  RTPRIO  Realtime priority
+      RUID  Real (before suid) user ID        RUSER   Real (before suid) user name
+      S     Process state:
+            R (running) S (sleeping) D (device I/O) T (stopped)  t (traced)
+            Z (zombie)  X (deader)   x (dead)       K (wakekill) W (waking)
+      SCHED Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)
+      STAT  Process state (S) plus:
+            < high priority          N low priority L locked memory
+            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 What are we waiting in kernel for
+
+config TOP
+  bool "top"
+  depends on TOP_COMMON
+  default y
+  help
+    usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]
+
+    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]
+
+    Rank processes by I/O.
+
+    -A	All I/O, not just disk
+    -a	Accumulated I/O (not percentage)
+    -K	Kilobytes
+    -k	Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)
+    -O	Only show processes doing I/O
+    -o	Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)
+    -s	Sort by field number (0-X, default 6)
+
+config TOP_COMMON
+  bool
+  default y
+  help
+    usage: * [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
+
+    -b	Batch mode (no tty)
+    -d	Delay SECONDS between each cycle (default 3)
+    -n	Exit after NUMBER iterations
+    -p	Show these PIDs
+    -u	Show these USERs
+    -q	Quiet (no header lines)
+
+    Cursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force
+    update, R to reverse sort, Q to exit.
+
+config PGREP
+  bool "pgrep"
+  default y
+  depends on PGKILL_COMMON
+  help
+    usage: pgrep [-cL] [-d DELIM] [-L SIGNAL] [PATTERN]
+
+    Search for process(es). PATTERN is an extended regular expression checked
+    against command names.
+
+    -c	Show only count of matches
+    -d	Use DELIM instead of newline
+    -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: * [-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)
+    -g	Match Process Group(s) (0 is current user)
+    -n	Newest match only
+    -o	Oldest match only
+    -P	Match Parent Process ID(s)
+    -s	Match Session ID(s) (0 for current)
+    -t	Match Terminal(s)
+    -U	Match real User ID(s)
+    -u	Match effective User ID(s)
+    -v	Negate the match
+    -x	Match whole command (not substring)
+*/
+
+#define FOR_ps
+#include "toys.h"
+
+GLOBALS(
+  union {
+    struct {
+      struct arg_list *G;
+      struct arg_list *g;
+      struct arg_list *U;
+      struct arg_list *u;
+      struct arg_list *t;
+      struct arg_list *s;
+      struct arg_list *p;
+      struct arg_list *O;
+      struct arg_list *o;
+      struct arg_list *P;
+      struct arg_list *k;
+    } ps;
+    struct {
+      long n;
+      long d;
+      long s;
+      struct arg_list *u;
+      struct arg_list *p;
+      struct arg_list *o;
+      struct arg_list *k;
+      struct arg_list *O;
+    } top;
+    struct {
+      char *L;
+      struct arg_list *G;
+      struct arg_list *g;
+      struct arg_list *P;
+      struct arg_list *s;
+      struct arg_list *t;
+      struct arg_list *U;
+      struct arg_list *u;
+      char *d;
+
+      void *regexes, *snapshot;
+      int signal;
+      pid_t self, match;
+    } pgrep;
+  };
+
+  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;
+  long long ticks, bits, time;
+  int kcount, forcek, sortpos;
+  int (*match_process)(long long *slot);
+  void (*show_process)(void *tb);
+)
+
+struct strawberry {
+  struct strawberry *next, *prev;
+  short which, len, reverse;
+  char *title;
+  char forever[];
+};
+
+/* The slot[] array is mostly populated from /proc/$PID/stat (kernel proc.txt
+ * table 1-4) but we shift and repurpose fields, with the result being: */
+
+enum {
+ SLOT_pid,      /*process id*/            SLOT_ppid,      // parent process id
+ SLOT_pgrp,     /*process group*/         SLOT_sid,       // session id
+ SLOT_ttynr,    /*tty the process uses*/  SLOT_ttypgrp,   // pgrp of the tty
+ SLOT_flags,    /*task flags*/            SLOT_minflt,    // minor faults
+ SLOT_cminflt,  /*minor faults+child*/    SLOT_majflt,    // major faults
+ SLOT_cmajflt,  /*major faults+child*/    SLOT_utime,     // user+kernel jiffies
+ SLOT_stime,    /*kernel mode jiffies*/   SLOT_cutime,    // utime+child
+ SLOT_cstime,   /*stime+child*/           SLOT_priority,  // priority level
+ SLOT_nice,     /*nice level*/            SLOT_numthreads,// thread count
+ SLOT_vmlck,    /*locked memory*/         SLOT_starttime, // jiffies after boot
+ SLOT_vsize,    /*virtual memory size*/   SLOT_rss,       // resident set size
+ SLOT_rsslim,   /*limit in bytes on rss*/ SLOT_startcode, // code segment addr
+ SLOT_endcode,  /*code segment address*/  SLOT_startstack,// stack address
+ SLOT_esp,      /*task stack pointer*/    SLOT_eip,       // instruction pointer
+ SLOT_iobytes,  /*All I/O bytes*/         SLOT_diobytes,  // disk I/O bytes
+ SLOT_utime2,   /*relative utime (top)*/  SLOT_uid,       // user id
+ SLOT_ruid,     /*real user id*/          SLOT_gid,       // group id
+ SLOT_rgid,     /*real group id*/         SLOT_exitsig,   // sent to parent
+ SLOT_taskcpu,  /*CPU running on*/        SLOT_rtprio,    // realtime priority
+ SLOT_policy,   /*man sched_setscheduler*/SLOT_blkioticks,// IO wait time
+ SLOT_gtime,    /*guest jiffies of task*/ SLOT_cgtime,    // gtime+child
+ SLOT_startbss, /*data/bss address*/      SLOT_endbss,    // end addr data+bss
+ SLOT_upticks,  /*46-19 (divisor for %)*/ SLOT_argv0len,  // argv[0] length
+ SLOT_uptime,   /*si.uptime @read time*/  SLOT_vsz,       // Virtual mem Size
+ 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_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[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
+};
+
+// TODO: Android uses -30 for LABEL, but ideally it would auto-size.
+// 64|slot means compare as string when sorting
+struct typography {
+  char *name;
+  signed char width, slot;
+} static const typos[] = TAGGED_ARRAY(PS,
+  // 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", 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
+  {"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},
+  {"RUSER", -8, 64|SLOT_ruid}, {"GID", 8, SLOT_gid}, {"GROUP", -8, 64|SLOT_gid},
+  {"RGID", 4, SLOT_rgid}, {"RGROUP", -8, 64|SLOT_rgid},
+
+  // clock displays
+  {"TIME", 8, SLOT_utime}, {"ELAPSED", 11, SLOT_starttime},
+  {"TIME+", 9, SLOT_utime},
+
+  // Percentage displays
+  {"C", 1, SLOT_utime2}, {"%VSZ", 5, SLOT_vsize}, {"%MEM", 5, SLOT_rss},
+  {"%CPU", 4, SLOT_utime2},
+
+  // human_readable
+  {"VIRT", 4, SLOT_vsz}, {"RES", 4, SLOT_rss2},
+  {"SHR", 4, SLOT_shr}, {"READ", 6, SLOT_rchar}, {"WRITE", 6, SLOT_wchar},
+  {"IO", 6, SLOT_iobytes}, {"DREAD", 6, SLOT_rbytes},
+  {"DWRITE", 6, SLOT_wbytes}, {"SWAP", 6, SLOT_swap}, {"DIO", 6, SLOT_diobytes},
+
+  // Misc
+  {"STIME", 5, SLOT_starttime}, {"F", 1, 64|SLOT_flags}, {"S", -1, 64},
+  {"STAT", -5, 64}, {"PCY", 3, 64|SLOT_pcy},
+);
+
+// Return 0 to discard, nonzero to keep
+static int shared_match_process(long long *slot)
+{
+  struct ptr_len match[] = {
+    {&TT.gg, SLOT_gid}, {&TT.GG, SLOT_rgid}, {&TT.pp, SLOT_pid},
+    {&TT.PP, SLOT_ppid}, {&TT.ss, SLOT_sid}, {&TT.tt, SLOT_ttynr},
+    {&TT.uu, SLOT_uid}, {&TT.UU, SLOT_ruid}
+  };
+  int i, j;
+  long *ll = 0;
+
+  // 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;
+    }
+  }
+
+  return ll ? 0 : -1;
+}
+
+
+// Return 0 to discard, nonzero to keep
+static int ps_match_process(long long *slot)
+{
+  int i = shared_match_process(slot);
+
+  if (i>0) return 1;
+  // If we had selections and didn't match them, don't display
+  if (!i) return 0;
+
+  // Filter implicit categories for other display types
+  if ((toys.optflags&(FLAG_a|FLAG_d)) && slot[SLOT_sid]==*slot) return 0;
+  if ((toys.optflags&FLAG_a) && !slot[SLOT_ttynr]) return 0;
+  if (!(toys.optflags&(FLAG_a|FLAG_d|FLAG_A|FLAG_e))
+      && TT.tty!=slot[SLOT_ttynr]) return 0;
+
+  return 1;
+}
+
+// Convert field to string representation
+static char *string_field(struct carveup *tb, struct strawberry *field)
+{
+  char *buf = toybuf+sizeof(toybuf)-260, *out = buf, *s;
+  int which = field->which, sl = typos[which].slot;
+  long long *slot = tb->slot, ll = (sl >= 0) ? slot[sl&63] : 0;
+
+  // numbers, mostly from /proc/$PID/stat
+  if (which <= PS_BIT) {
+    char *fmt = "%lld";
+
+    if (which==PS_PRI) ll = 39-ll;
+    if (which==PS_ADDR) fmt = "%llx";
+    else if (which==PS_SZ) ll >>= 12;
+    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 || which==PS_BIT) && ll == 0) fmt="-";
+    sprintf(out, fmt, ll);
+
+  // String fields
+  } else if (sl < 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 || 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 = bufgetgrgid(ll);
+
+        if (gr) out = gr->gr_name;
+      } else {
+        struct passwd *pw = bufgetpwuid(ll);
+
+        if (pw) out = pw->pw_name;
+      }
+    }
+
+  // Clock displays
+  } else if (which <= PS_TIME_) {
+    int unit = 60, pad = 2, j = TT.ticks; 
+    time_t seconds;
+
+    if (which!=PS_TIME_) unit *= 60*24;
+    else pad = 0;
+    // top adjusts slot[SLOT_upticks], we want original meaning.
+    if (which==PS_ELAPSED) ll = (slot[SLOT_uptime]*j)-slot[SLOT_starttime];
+    seconds = ll/j;
+
+    // Output days-hours:mins:secs, skipping non-required fields with zero
+    // TIME has 3 required fields, ETIME has 2. (Posix!) TIME+ is from top
+    for (s = 0, j = 2*(which==PS_TIME_); j<4; j++) {
+      if (!s && (seconds>unit || j == 1+(which!=PS_TIME))) s = out;
+      if (s) {
+        s += sprintf(s, j ? "%0*ld": "%*ld", pad, (long)(seconds/unit));
+        pad = 2;
+        if ((*s = "-::"[j])) s++;
+      }
+      seconds %= unit;
+      unit /= j ? 60 : 24;
+    }
+    if (which==PS_TIME_ && s-out<8)
+      sprintf(s, ".%02lld", (100*(ll%TT.ticks))/TT.ticks);
+
+  // Percentage displays
+  } else if (which <= PS__CPU) {
+    ll = slot[sl&63]*1000;
+    if (which==PS__VSZ || which==PS__MEM)
+      ll /= TT.si.totalram/((which==PS__VSZ) ? 1024 : 4096);
+    else if (slot[SLOT_upticks]) ll /= slot[SLOT_upticks];
+    sl = ll;
+    if (which==PS_C) sl += 5;
+    sprintf(out, "%d", sl/10);
+    if (which!=PS_C && sl<1000) sprintf(out+strlen(out), ".%d", sl%10);
+
+  // Human readable
+  } else if (which <= PS_DIO) {
+    ll = slot[typos[which].slot];
+    if (which <= PS_SHR) ll *= sysconf(_SC_PAGESIZE);
+    if (TT.forcek) sprintf(out, "%lldk", ll/1024);
+    else human_readable(out, ll, 0);
+
+  // Posix doesn't specify what flags should say. Man page says
+  // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h
+  } else if (which==PS_F) sprintf(out, "%llo", (slot[SLOT_flags]>>6)&5);
+  else if (which==PS_S || which==PS_STAT) {
+    s = out;
+    *s++ = tb->state;
+    if (which==PS_STAT) {
+      // TODO l = multithreaded
+      if (slot[SLOT_nice]<0) *s++ = '<';
+      else if (slot[SLOT_nice]>0) *s++ = 'N';
+      if (slot[SLOT_sid]==*slot) *s++ = 's';
+      if (slot[SLOT_vmlck]) *s++ = 'L';
+      if (slot[SLOT_ttypgrp]==*slot) *s++ = '+';
+    } 
+    *s = 0;
+  } else if (which==PS_STIME) {
+    time_t t = time(0)-slot[SLOT_uptime]+slot[SLOT_starttime]/TT.ticks;
+
+    // Padding behavior's a bit odd: default field size is just hh:mm.
+    // Increasing stime:size reveals more data at left until full,
+    // so move start address so yyyy-mm-dd hh:mm revealed on left at :16,
+    // then add :ss on right for :19.
+    strftime(out, 260, "%F %T", localtime(&t));
+    out = out+strlen(out)-3-abs(field->len);
+    if (out<buf) out = buf;
+
+  } 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;
+}
+
+// Display process data that get_ps() read from /proc, formatting with TT.fields
+static void show_ps(struct carveup *tb)
+{
+  struct strawberry *field;
+  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--;
+    }
+
+    // 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);
+    if (!width) break;
+  }
+  xputc(TT.time ? '\r' : '\n');
+}
+
+// dirtree callback: read data about process to display, store, or discard it.
+// Fills toybuf with struct carveup and either DIRTREE_SAVEs a copy to ->extra
+// (in -k mode) or calls show_ps on toybuf (no malloc/copy/free there).
+static int get_ps(struct dirtree *new)
+{
+  struct {
+    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|_PS_COMM}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME},
+    {"", _PS_NAME}
+  };
+  struct carveup *tb = (void *)toybuf;
+  long long *slot = tb->slot;
+  char *name, *s, *buf = tb->str, *end = 0;
+  int i, j, fd;
+  off_t len;
+
+  // Recurse one level into /proc children, skip non-numeric entries
+  if (!new->parent)
+    return DIRTREE_RECURSE|DIRTREE_SHUTUP
+      |(DIRTREE_SAVE*(TT.threadparent||!TT.show_process));
+
+  memset(slot, 0, sizeof(tb->slot));
+  if (!(tb->slot[SLOT_tid] = *slot = atol(new->name))) return 0;
+  if (TT.threadparent && TT.threadparent->extra)
+    if (*slot == *(((struct carveup *)TT.threadparent->extra)->slot)) return 0;
+  fd = dirtree_parentfd(new);
+
+  len = 2048;
+  sprintf(buf, "%lld/stat", *slot);
+  if (!readfileat(fd, buf, buf, &len)) return 0;
+
+  // parse oddball fields (name and state). Name can have embedded ')' so match
+  // _last_ ')' in stat (although VFS limits filenames to 255 bytes max).
+  // All remaining fields should be numeric.
+  if (!(name = strchr(buf, '('))) return 0;
+  for (s = ++name; *s; s++) if (*s == ')') end = s;
+  if (!end || end-name>255) return 0;
+
+  // 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<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.
+  for (i = 0; i<end-name; i++)
+    if ((tb->str[i] = name[i]) < ' ')
+      if (!TT.tty) tb->str[i] = '?';
+  buf = tb->str+i;
+  *buf++ = 0;
+  len = sizeof(toybuf)-(buf-toybuf);
+
+  // save uid, ruid, gid, gid, and rgid int slots 31-34 (we don't use sigcatch
+  // or numeric wchan, and the remaining two are always zero), and vmlck into
+  // 18 (which is "obsolete, always 0" from stat)
+  slot[SLOT_uid] = new->st.st_uid;
+  slot[SLOT_gid] = new->st.st_gid;
+
+  // TIME and TIME+ use combined value, ksort needs 'em added.
+  slot[SLOT_utime] += slot[SLOT_stime];
+  slot[SLOT_utime2] = slot[SLOT_utime];
+
+  // If RGROUP RUSER STAT RUID RGID SWAP happening, or -G or -U, parse "status"
+  // and save ruid, rgid, and vmlck.
+  if ((TT.bits&(_PS_RGROUP|_PS_RUSER|_PS_STAT|_PS_RUID|_PS_RGID|_PS_SWAP
+               |_PS_IO|_PS_DIO)) || TT.GG.len || TT.UU.len)
+  {
+    off_t temp = len;
+
+    sprintf(buf, "%lld/status", *slot);
+    if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
+    s = strafter(buf, "\nUid:");
+    slot[SLOT_ruid] = s ? atol(s) : new->st.st_uid;
+    s = strafter(buf, "\nGid:");
+    slot[SLOT_rgid] = s ? atol(s) : new->st.st_gid;
+    if ((s = strafter(buf, "\nVmLck:"))) slot[SLOT_vmlck] = atoll(s);
+    if ((s = strafter(buf, "\nVmSwap:"))) slot[SLOT_swap] = atoll(s);
+  }
+
+  // Do we need to read "io"?
+  if (TT.bits&(_PS_READ|_PS_WRITE|_PS_DREAD|_PS_DWRITE|_PS_IO|_PS_DIO)) {
+    off_t temp = len;
+
+    sprintf(buf, "%lld/io", *slot);
+    if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
+    if ((s = strafter(buf, "rchar:"))) slot[SLOT_rchar] = atoll(s);
+    if ((s = strafter(buf, "wchar:"))) slot[SLOT_wchar] = atoll(s);
+    if ((s = strafter(buf, "read_bytes:"))) slot[SLOT_rbytes] = atoll(s);
+    if ((s = strafter(buf, "write_bytes:"))) slot[SLOT_wbytes] = atoll(s);
+    slot[SLOT_iobytes] = slot[SLOT_rchar]+slot[SLOT_wchar]+slot[SLOT_swap];
+    slot[SLOT_diobytes] = slot[SLOT_rbytes]+slot[SLOT_wbytes]+slot[SLOT_swap];
+  }
+
+  // We now know enough to skip processes we don't care about.
+  if (TT.match_process && !TT.match_process(slot)) return 0;
+
+  // /proc data is generated as it's read, so for maximum accuracy on slow
+  // systems (or ps | more) we re-fetch uptime as we fetch each /proc line.
+  sysinfo(&TT.si);
+  slot[SLOT_uptime] = TT.si.uptime;
+  slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_starttime];
+
+  // Do we need to read "statm"?
+  if (TT.bits&(_PS_VIRT|_PS_RES|_PS_SHR)) {
+    off_t temp = len;
+
+    sprintf(buf, "%lld/statm", *slot);
+    if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
+    
+    for (s = buf, i=0; i<3; i++)
+      if (!sscanf(s, " %lld%n", slot+SLOT_vsz+i, &j)) slot[SLOT_vsz+i] = 0;
+      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++) {
+    tb->offset[j] = buf-(tb->str);
+    if (!(TT.bits&fetch[j].bits)) {
+      *buf++ = 0;
+      continue;
+    }
+
+    // Determine remaining space, reserving minimum of 256 bytes/field and
+    // 260 bytes scratch space at the end (for output conversion later).
+    len = sizeof(toybuf)-(buf-toybuf)-260-256*(ARRAY_LEN(fetch)-j);
+    sprintf(buf, "%lld/%s", *slot, fetch[j].name);
+
+    // 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)
+    } else if (!j) {
+      int rdev = slot[SLOT_ttynr];
+      struct stat st;
+
+      // Call no tty "?" rather than "0:0".
+      strcpy(buf, "?");
+      if (rdev) {
+        // Can we readlink() our way to a name?
+        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 && (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 = 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) {
+                len = strlen(buf);
+                len += sprintf(buf+len, "%d", min);
+                if (!stat(buf, &st) && S_ISCHR(st.st_mode) && st.st_rdev==rdev)
+                  break;
+              }
+              tty_major = 0;
+            }
+            fclose(fp);
+          }
+
+          // Really couldn't find it, so just show major:minor.
+          if (!tty_major) len = sprintf(buf, "%d:%d", maj, min);
+        }
+
+        s = buf;
+        if (strstart(&s, "/dev/")) memmove(buf, s, len -= 5);
+      }
+
+    // Data we want is in a file.
+    // Last length saved in slot[] is command line (which has embedded NULs)
+    } else {
+
+      // When command has no arguments, don't space over the NUL
+      if (readfileat(fd, buf, buf, &len) && len>0) {
+        int temp = 0;
+
+        // Trim trailing whitespace and NUL bytes
+        while (len)
+          if (!buf[len-1] || isspace(buf[len-1])) buf[--len] = 0;
+          else break;
+
+        // Turn NUL to space, other low ascii to ? (in non-tty mode)
+        // cmdline has a trailing NUL that we don't want to turn to space.
+        for (i=0; i<len-1; i++) {
+          char c = buf[i];
+
+          if (!c) {
+            if (!temp) temp = i;
+            c = ' ';
+          } else if (!TT.tty && c<' ') c = '?';
+          buf[i] = c;
+        }
+        // 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;
+    }
+
+    // Above calculated/retained len, so we don't need to re-strlen.
+    buf += len+1;
+  }
+
+  TT.kcount++;
+  if (TT.show_process && !TT.threadparent) {
+    TT.show_process(tb);
+
+    return 0;
+  }
+
+  // If we need to sort the output, add it to the list and return.
+  s = xmalloc(buf-toybuf);
+  new->extra = (long)s;
+  memcpy(s, toybuf, buf-toybuf);
+
+  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;
+  char *width, *title, *end, *s;
+  int i, j, k;
+
+  // Get title, length of title, type, end of type, and display width
+
+  // Chip off =name to display
+  if ((end = strchr(type, '=')) && length>(end-type)) {
+    title = end+1;
+    length -= (end-type)+1;
+  } else {
+    end = type+length;
+    title = 0;
+  }
+
+  // Chip off :width to display
+  if ((width = strchr(type, ':')) && width<end) {
+    if (!title) length = width-type;
+  } else width = 0;
+
+  // Allocate structure, copy title
+  field = xzalloc(sizeof(struct strawberry)+(length+1)*!!title);
+  if (title) {
+    memcpy(field->title = field->forever, title, length);
+    field->title[field->len = length] = 0;
+  }
+
+  if (width) {
+    field->len = strtol(++width, &title, 10);
+    if (!isdigit(*width) || title != end) return title;
+    end = --width;
+  }
+
+  // Find type
+  field->reverse = 1;
+  if (*type == '-') field->reverse = -1;
+  else if (*type != '+') type--;
+  type++;
+  for (i = 0; i<ARRAY_LEN(typos); i++) {
+    field->which = i;
+    for (j = 0; j<2; j++) {
+      if (!j) s = typos[i].name;
+      // posix requires alternate names for some fields
+      else if (-1==(k = stridx((char []){PS_NI, PS_SCH, PS_ELAPSED, PS__CPU,
+        PS_VSZ, PS_USER, 0}, i))) continue;
+      else
+        s = ((char *[]){"NICE", "SCHED", "ETIME", "PCPU", "VSIZE", "UNAME"})[k];
+
+      if (!strncasecmp(type, s, end-type) && strlen(s)==end-type) break;
+    }
+    if (j!=2) break;
+  }
+  if (i==ARRAY_LEN(typos)) return type;
+  if (!field->title) field->title = typos[field->which].name;
+  if (!field->len) field->len = typos[field->which].width;
+  else if (typos[field->which].width<0) field->len *= -1;
+  dlist_add_nomalloc(data, (void *)field);
+
+  return 0;
+}
+
+long long get_headers(struct strawberry *fields, char *buf, int blen)
+{
+  long long bits = 0;
+  int len = 0;
+
+  for (; fields; fields = fields->next) {
+    len += snprintf(buf+len, blen-len, " %*s"+!bits, fields->len,
+      fields->title);
+    bits |= 1LL<<fields->which;
+  }
+
+  return bits;
+}
+
+// Parse -p -s -t -u -U -g -G
+static char *parse_rest(void *data, char *str, int len)
+{
+  struct ptr_len *pl = (struct ptr_len *)data;
+  long *ll = pl->ptr;
+  char *end;
+  int num = 0;
+
+  // Allocate next chunk of data
+  if (!(15&pl->len))
+    ll = pl->ptr = xrealloc(pl->ptr, sizeof(long)*(pl->len+16));
+
+  // Parse numerical input
+  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) {
+    if (num && ll[pl->len]>0) {
+      pl->len++;
+
+      return 0;
+    }
+  } else if (pl==&TT.tt) {
+    // -t pts = 12,pts/12 tty = /dev/tty2,tty2,S0
+    if (!num) {
+      if (strstart(&str, strcpy(toybuf, "/dev/"))) len -= 5;
+      if (strstart(&str, "pts/")) {
+        len -= 4;
+        num++;
+      } else if (strstart(&str, "tty")) len -= 3;
+    }
+    if (len<256 && (!(end = strchr(str, '/')) || end-str>len)) {
+      struct stat st;
+
+      end = toybuf + sprintf(toybuf, "/dev/%s", num ? "pts/" : "tty");
+      memcpy(end, str, len);
+      end[len] = 0;
+      xstat(toybuf, &st);
+      ll[pl->len++] = st.st_rdev;
+
+      return 0;
+    }
+  } else if (len<255) {
+    char name[256];
+
+    if (num) {
+      pl->len++;
+
+      return 0;
+    }
+
+    memcpy(name, str, len);
+    name[len] = 0;
+    if (pl==&TT.gg || pl==&TT.GG) {
+      struct group *gr = getgrnam(name);
+      if (gr) {
+        ll[pl->len++] = gr->gr_gid;
+
+        return 0;
+      }
+    } else if (pl==&TT.uu || pl==&TT.UU) {
+      struct passwd *pw = getpwnam(name);
+      if (pw) {
+        ll[pl->len++] = pw->pw_uid;
+
+        return 0;
+      }
+    }
+  }
+
+  // Return error
+  return str;
+}
+
+// sort for -k
+static int ksort(void *aa, void *bb)
+{
+  struct strawberry *field;
+  struct carveup *ta = *(struct carveup **)aa, *tb = *(struct carveup **)bb;
+  int ret = 0, slot;
+
+  for (field = TT.kfields; field && !ret; field = field->next) {
+    slot = typos[field->which].slot;
+
+    // Can we do numeric sort?
+    if (!(slot&64)) {
+      if (ta->slot[slot]<tb->slot[slot]) ret = -1;
+      if (ta->slot[slot]>tb->slot[slot]) ret = 1;
+    }
+
+    // fallback to string sort
+    if (!ret) {
+      memccpy(toybuf, string_field(ta, field), 0, 2048);
+      toybuf[2048] = 0;
+      ret = strcmp(toybuf, string_field(tb, field));
+    }
+    ret *= field->reverse;
+  }
+
+  return ret;
+}
+
+static struct carveup **collate_leaves(struct carveup **tb, struct dirtree *dt) 
+{
+  while (dt) {
+    struct dirtree *next = dt->next;
+
+    if (dt->extra) *(tb++) = (void *)dt->extra;
+    if (dt->child) tb = collate_leaves(tb, dt->child);
+    free(dt);
+    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;
+} 
+
+static void default_ko(char *s, void *fields, char *err, struct arg_list *arg)
+{
+  struct arg_list def;
+
+  memset(&def, 0, sizeof(struct arg_list));
+  def.arg = s;
+  comma_args(arg ? arg : &def, fields, err, parse_ko);
+}
+
+static void shared_main(void)
+{
+  int i;
+
+  TT.ticks = sysconf(_SC_CLK_TCK);
+  if (!TT.width) {
+    TT.width = (toys.which->name[1] == 's') ? 99999 : 80;
+    TT.height = 25;
+    terminal_size(&TT.width, &TT.height);
+  }
+
+  // find controlling tty, falling back to /dev/tty if none
+  for (i = 0; !TT.tty && i<4; i++) {
+    struct stat st;
+    int fd = i;
+
+    if (i==3 && -1==(fd = open("/dev/tty", O_RDONLY))) break;
+
+    if (isatty(fd) && !fstat(fd, &st)) TT.tty = st.st_rdev;
+    if (i==3) close(fd);
+  }
+}
+
+void ps_main(void)
+{
+  struct dirtree *dt;
+  char *not_o;
+  int i;
+
+  if (toys.optflags&FLAG_w) TT.width = 99999;
+  shared_main();
+
+  // parse command line options other than -o
+  comma_args(TT.ps.P, &TT.PP, "bad -P", parse_rest);
+  comma_args(TT.ps.p, &TT.pp, "bad -p", parse_rest);
+  comma_args(TT.ps.t, &TT.tt, "bad -t", parse_rest);
+  comma_args(TT.ps.s, &TT.ss, "bad -s", parse_rest);
+  comma_args(TT.ps.u, &TT.uu, "bad -u", parse_rest);
+  comma_args(TT.ps.U, &TT.UU, "bad -U", parse_rest);
+  comma_args(TT.ps.g, &TT.gg, "bad -g", parse_rest);
+  comma_args(TT.ps.G, &TT.GG, "bad -G", parse_rest);
+  comma_args(TT.ps.k, &TT.kfields, "bad -k", parse_ko);
+  dlist_terminate(TT.kfields);
+
+  // 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)
+    not_o = "F,S,UID,%sPPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD";
+  else if (CFG_TOYBOX_ON_ANDROID)
+    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);
+    if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->next;
+  }
+  dlist_terminate(TT.fields);
+
+  // -f and -n change the meaning of some fields
+  if (toys.optflags&(FLAG_f|FLAG_n)) {
+    struct strawberry *ever;
+
+    for (ever = TT.fields; ever; ever = ever->next) {
+      if ((toys.optflags&FLAG_n) && ever->which>=PS_UID
+        && ever->which<=PS_RGROUP && (typos[ever->which].slot&64))
+          ever->which--;
+    }
+  }
+
+  // Calculate seen fields bit array, and if we aren't deferring printing
+  // print headers now (for low memory/nommu systems).
+  TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
+  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",
+    ((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);
+
+    if (toys.optflags&FLAG_M) {
+      for (i = 0; i<TT.kcount; i++) {
+        struct strawberry *field;
+
+        for (field = TT.fields; field; field = field->next) {
+          int len = strlen(string_field(tbsort[i], field));
+
+          if (abs(field->len)<len) field->len = (field->len<0) ? -len : len;
+        }
+      }
+
+      // Now that we've recalculated field widths, re-pad headers again
+      get_headers(TT.fields, toybuf, sizeof(toybuf));
+      printf("%.*s\n", TT.width, toybuf);
+    }
+
+    if (toys.optflags&FLAG_k)
+      qsort(tbsort, TT.kcount, sizeof(struct carveup *), (void *)ksort);
+    for (i = 0; i<TT.kcount; i++) {
+      show_ps(tbsort[i]);
+      free(tbsort[i]);
+    }
+    if (CFG_TOYBOX_FREE) free(tbsort);
+  }
+
+  if (CFG_TOYBOX_FREE) {
+    free(TT.gg.ptr);
+    free(TT.GG.ptr);
+    free(TT.pp.ptr);
+    free(TT.PP.ptr);
+    free(TT.ss.ptr);
+    free(TT.tt.ptr);
+    free(TT.uu.ptr);
+    free(TT.UU.ptr);
+    llist_traverse(TT.fields, free);
+  }
+}
+
+#define CLEANUP_ps
+#define FOR_top
+#include "generated/flags.h"
+
+// select which of the -o fields to sort by
+static void setsort(int pos)
+{
+  struct strawberry *field, *going2;
+  int i = 0;
+
+  if (pos<0) pos = 0;
+
+  for (field = TT.fields; field; field = field->next) {
+    if ((TT.sortpos = i++)<pos && field->next) continue;
+    going2 = TT.kfields;
+    going2->which = field->which;
+    going2->len = field->len;
+    break;
+  }
+}
+
+// If we have both, adjust slot[deltas[]] to be relative to previous
+// measurement rather than process start. Stomping old.data is fine
+// because we free it after displaying.
+static int merge_deltas(long long *oslot, long long *nslot, int milis)
+{
+  char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_rchar,
+                   SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
+  int i;
+
+  for (i = 0; i<ARRAY_LEN(deltas); i++)
+    oslot[deltas[i]] = nslot[deltas[i]] - oslot[deltas[i]];
+  oslot[SLOT_upticks] = (milis*TT.ticks)/1000;
+
+  return 1;
+}
+
+static int header_line(int line, int rev)
+{
+  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;
+}
+
+static long long millitime(void)
+{
+  struct timespec ts;
+
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+  return ts.tv_sec*1000+ts.tv_nsec/1000000;
+}
+
+static void top_common(
+  int (*filter)(long long *oslot, long long *nslot, int milis))
+{
+  long long timeout = 0, now, stats[16];
+  struct proclist {
+    struct carveup **tb;
+    int count;
+    long long whence;
+  } plist[2], *plold, *plnew, old, new, mix;
+  char scratch[16], *pos, *cpufields[] = {"user", "nice", "sys", "idle",
+    "iow", "irq", "sirq", "host"};
+ 
+  unsigned tock = 0;
+  int i, lines, topoff = 0, done = 0;
+
+  toys.signal = SIGWINCH;
+  TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
+  *scratch = 0;
+  memset(plist, 0, sizeof(plist));
+  memset(stats, 0, sizeof(stats));
+  do {
+    struct dirtree *dt;
+    int recalc = 1;
+
+    plold = plist+(tock++&1);
+    plnew = plist+(tock&1);
+    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))) {
+      long long *st = stats+8*(tock&1);
+
+      // user nice system idle iowait irq softirq host
+      sscanf(pos, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
+        st, st+1, st+2, st+3, st+4, st+5, st+6, st+7);
+    }
+
+    // First time, wait a quarter of a second to collect a little delta data.
+    if (!plold->tb) {
+      msleep(250);
+      continue;
+    }
+
+    // Collate old and new into "mix", depends on /proc read in pid sort order
+    old = *plold;
+    new = *plnew;
+    mix.tb = xmalloc((old.count+new.count)*sizeof(struct carveup));
+    mix.count = 0;
+
+    while (old.count || new.count) {
+      struct carveup *otb = *old.tb, *ntb = *new.tb;
+
+      // 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--;
+
+        continue;
+      }
+
+      // If we just have new, use it verbatim
+      if (!old.count || *otb->slot > *ntb->slot) mix.tb[mix.count] = ntb;
+      else {
+        // Keep or discard
+        if (filter(otb->slot, ntb->slot, new.whence-old.whence)) {
+          mix.tb[mix.count] = otb;
+          mix.count++;
+        }
+        old.tb++;
+        old.count--;
+      }
+      new.tb++;
+      new.count--;
+    }
+
+    // Don't re-fetch data if it's not time yet, just re-display existing data.
+    for (;;) {
+      char was, is;
+
+      if (recalc) {
+        qsort(mix.tb, mix.count, sizeof(struct carveup *), (void *)ksort);
+        if (!(toys.optflags&FLAG_b)) {
+          printf("\033[H\033[J");
+          if (toys.signal) {
+            toys.signal = 0;
+            terminal_probesize(&TT.width, &TT.height);
+          }
+        }
+        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]);
+          lines = header_line(lines, 0);
+
+          if (readfile("/proc/meminfo", toybuf, sizeof(toybuf))) {
+            for (i=0; i<6; i++) {
+              pos = strafter(toybuf, (char *[]){"MemTotal:","\nMemFree:",
+                    "\nBuffers:","\nCached:","\nSwapTotal:","\nSwapFree:"}[i]);
+              run[i] = pos ? atol(pos) : 0;
+            }
+            sprintf(toybuf,
+             "Mem:%10ldk total,%9ldk used,%9ldk free,%9ldk buffers",
+              run[0], run[0]-run[1], run[1], run[2]);
+            lines = header_line(lines, 0);
+            sprintf(toybuf,
+              "Swap:%9ldk total,%9ldk used,%9ldk free,%9ldk cached",
+              run[4], run[4]-run[5], run[5], run[3]);
+            lines = header_line(lines, 0);
+          }
+
+          pos = toybuf;
+          i = sysconf(_SC_NPROCESSORS_CONF);
+          pos += sprintf(pos, "%d%%cpu", i*100);
+          j = 4+(i>10);
+
+          // If a processor goes idle it's powered down and its idle ticks don't
+          // advance, so calculate idle time as potential time - used.
+          if (mix.count) up = mix.tb[0]->slot[SLOT_upticks];
+          if (!up) up = 1;
+          now = up*i;
+          ll = stats[3] = stats[11] = 0;
+          for (i = 0; i<8; i++) ll += stats[i]-stats[i+8];
+          stats[3] = now - llabs(ll);
+
+          for (i = 0; i<8; i++) {
+            ll = (llabs(stats[i]-stats[i+8])*1000)/up;
+            pos += sprintf(pos, "% *lld%%%s", j, (ll+5)/10, cpufields[i]);
+          }
+          lines = header_line(lines, 0);
+        } else {
+          struct strawberry *fields;
+          struct carveup tb;
+
+          memset(&tb, 0, sizeof(struct carveup));
+          pos = stpcpy(toybuf, "Totals:");
+          for (fields = TT.fields; fields; fields = fields->next) {
+            long long ll, bits = 0;
+            int slot = typos[fields->which].slot&63;
+
+            if (fields->which<PS_C || fields->which>PS_DIO) continue;
+            ll = 1LL<<fields->which;
+            if (bits&ll) continue;
+            bits |= ll;
+            for (i=0; i<mix.count; i++)
+              tb.slot[slot] += mix.tb[i]->slot[slot];
+            pos += snprintf(pos, sizeof(toybuf)/2-(pos-toybuf),
+              " %s: %*s,", typos[fields->which].name,
+              fields->len, string_field(&tb, fields));
+          }
+          *--pos = 0;
+          lines = header_line(lines, 0);
+        }
+
+        get_headers(TT.fields, pos = toybuf, sizeof(toybuf));
+        for (i = 0, is = ' '; *pos; pos++) {
+          was = is;
+          is = *pos;
+          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 && !(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 (!(toys.optflags&FLAG_b) && i) xputc('\n');
+        show_ps(mix.tb[i+topoff]);
+      }
+
+      if (TT.top.n && !--TT.top.n) {
+        done++;
+        break;
+      }
+
+      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++;
+        break;
+      }
+      if (i==-2) break;
+
+      // Flush unknown escape sequences.
+      if (i==27) while (0<scan_key_getsize(scratch, 0, &TT.width, &TT.height));
+      else if (i==' ') {
+        timeout = 0;
+        break;
+      } else if (toupper(i)=='R')
+        ((struct strawberry *)TT.kfields)->reverse *= -1;
+      else {
+        i -= 256;
+        if (i == KEY_LEFT) setsort(TT.sortpos-1);
+        else if (i == KEY_RIGHT) setsort(TT.sortpos+1);
+        // KEY_UP is 0, so at end of strchr
+        else if (strchr((char []){KEY_DOWN,KEY_PGUP,KEY_PGDN,KEY_UP}, i)) {
+          recalc = 0;
+
+          if (i == KEY_UP) topoff--;
+          else if (i == KEY_DOWN) topoff++;
+          else if (i == KEY_PGDN) topoff += lines;
+          else if (i == KEY_PGUP) topoff -= lines;
+          if (topoff<0) topoff = 0; 
+          if (topoff>mix.count) topoff = mix.count;
+        }
+      }
+      continue;
+    }
+
+    free(mix.tb);
+    for (i=0; i<plold->count; i++) free(plold->tb[i]);
+    free(plold->tb);
+  } while (!done);
+
+  if (!(toys.optflags&FLAG_b)) tty_reset();
+}
+
+static void top_setup(char *defo, char *defk)
+{
+  TT.top.d *= 1000;
+  if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
+  else {
+    TT.time = millitime();
+    set_terminal(0, 1, 0);
+    sigatexit(tty_sigreset);
+    xsignal(SIGWINCH, generic_signal);
+    printf("\033[?25l\033[0m");
+  }
+  shared_main();
+
+  comma_args(TT.top.u, &TT.uu, "bad -u", parse_rest);
+  comma_args(TT.top.p, &TT.pp, "bad -p", parse_rest);
+  TT.match_process = shared_match_process;
+
+  default_ko(defo, &TT.fields, "bad -o", TT.top.o);
+  dlist_terminate(TT.fields);
+
+  // First (dummy) sort field is overwritten by setsort()
+  default_ko("-S", &TT.kfields, 0, 0);
+  default_ko(defk, &TT.kfields, "bad -k", TT.top.k);
+  dlist_terminate(TT.kfields);
+  setsort(TT.top.s-1);
+}
+
+void top_main(void)
+{
+  // usage: [-h HEADER] -o OUTPUT -k SORT
+
+  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);
+}
+
+#define CLEANUP_top
+#define FOR_iotop
+#include "generated/flags.h"
+
+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] = ((millitime()-TT.time)*TT.ticks)/1000;
+
+  return !(toys.optflags&FLAG_o)||oslot[SLOT_iobytes+!(toys.optflags&FLAG_A)];
+}
+
+void iotop_main(void)
+{
+  char *s1 = 0, *s2 = 0, *d = "D"+!!(toys.optflags&FLAG_A);
+
+  if (toys.optflags&FLAG_K) TT.forcek++;
+
+  top_setup(s1 = xmprintf("PID,PR,USER,%sREAD,%sWRITE,SWAP,%sIO,COMM",d,d,d),
+    s2 = xmprintf("-%sIO,-ETIME,-PID",d));
+  free(s1);
+  free(s2);
+  top_common(iotop_filter);
+}
+
+// pkill's plumbing wraps pgrep's and thus mostly takes place in pgrep's flag
+// context, so force pgrep's flags on even when building pkill standalone.
+// (All the pgrep/pkill functions drop out when building ps standalone.)
+#define FORCE_FLAGS
+#define CLEANUP_iotop
+#define FOR_pgrep
+#include "generated/flags.h"
+
+struct regex_list {
+  struct regex_list *next;
+  regex_t reg;
+};
+
+static void do_pgk(struct carveup *tb)
+{
+  if (TT.pgrep.signal) {
+    if (kill(*tb->slot, TT.pgrep.signal)) {
+      char *s = num_to_sig(TT.pgrep.signal);
+
+      if (!s) sprintf(s = toybuf, "%d", TT.pgrep.signal);
+      perror_msg("%s->%lld", s, *tb->slot);
+    }
+  }
+  if (!(toys.optflags&FLAG_c) && (!TT.pgrep.signal || TT.tty)) {
+    printf("%lld", *tb->slot);
+    if (toys.optflags&FLAG_l)
+      printf(" %s", tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f));
+    
+    printf("%s", TT.pgrep.d ? TT.pgrep.d : "\n");
+  }
+}
+
+static void match_pgrep(struct carveup *tb)
+{
+  regmatch_t match;
+  struct regex_list *reg;
+  char *name = tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f);;
+
+  // Never match ourselves.
+  if (TT.pgrep.self == *tb->slot) return;
+
+  if (TT.pgrep.regexes) {
+    for (reg = TT.pgrep.regexes; reg; reg = reg->next) {
+      if (regexec(&reg->reg, name, 1, &match, 0)) continue;
+      if (toys.optflags&FLAG_x)
+        if (match.rm_so || match.rm_eo!=strlen(name)) continue;
+      break;
+    }
+    if ((toys.optflags&FLAG_v) ? !!reg : !reg) return;
+  }
+
+  // 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];
+
+    if (toys.optflags&FLAG_o) ll *= -1;
+    if (TT.time && TT.time>ll) return;
+    TT.time = ll;
+    free(TT.pgrep.snapshot);
+    TT.pgrep.snapshot = xmemdup(toybuf, (name+strlen(name)+1)-toybuf);
+  } else do_pgk(tb);
+}
+
+static int pgrep_match_process(long long *slot)
+{
+  int match = shared_match_process(slot);
+
+  return (toys.optflags&FLAG_v) ? !match : match;
+}
+
+void pgrep_main(void)
+{
+  char **arg;
+  struct regex_list *reg;
+
+  TT.pgrep.self = getpid();
+
+  // No signal names start with "L", so no need for "L: " parsing.
+  if (TT.pgrep.L && 1>(TT.pgrep.signal = sig_to_num(TT.pgrep.L)))
+    error_exit("bad -L '%s'", TT.pgrep.L);
+
+  comma_args(TT.pgrep.G, &TT.GG, "bad -G", parse_rest);
+  comma_args(TT.pgrep.g, &TT.gg, "bad -g", parse_rest);
+  comma_args(TT.pgrep.P, &TT.PP, "bad -P", parse_rest);
+  comma_args(TT.pgrep.s, &TT.ss, "bad -s", parse_rest);
+  comma_args(TT.pgrep.t, &TT.tt, "bad -t", parse_rest);
+  comma_args(TT.pgrep.U, &TT.UU, "bad -U", parse_rest);
+  comma_args(TT.pgrep.u, &TT.uu, "bad -u", parse_rest);
+
+  if ((toys.optflags&(FLAG_x|FLAG_f)) ||
+      !(toys.optflags&(FLAG_G|FLAG_g|FLAG_P|FLAG_s|FLAG_t|FLAG_U|FLAG_u)))
+    if (!toys.optc) help_exit("No PATTERN");
+
+  if (toys.optflags&FLAG_f) TT.bits |= _PS_CMDLINE;
+  for (arg = toys.optargs; *arg; arg++) {
+    reg = xmalloc(sizeof(struct regex_list));
+    xregcomp(&reg->reg, *arg, REG_EXTENDED);
+    reg->next = TT.pgrep.regexes;
+    TT.pgrep.regexes = reg;
+  }
+  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) {
+    do_pgk(TT.pgrep.snapshot);
+    if (CFG_TOYBOX_FREE) free(TT.pgrep.snapshot);
+  }
+  if (TT.pgrep.d) xputc('\n');
+}
+
+#define CLEANUP_pgrep
+#define FOR_pkill
+#include "generated/flags.h"
+
+void pkill_main(void)
+{
+  char **args = toys.optargs;
+
+  if (!(toys.optflags&FLAG_l) && *args && **args=='-') TT.pgrep.L = *(args++)+1;
+  if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
+  if (toys.optflags & FLAG_V) TT.tty = 1;
+  pgrep_main();
+}
diff --git a/toybox/toys/posix/pwd.c b/toybox/toys/posix/pwd.c
new file mode 100644
index 0000000..3203592
--- /dev/null
+++ b/toybox/toys/posix/pwd.c
@@ -0,0 +1,54 @@
+/* pwd.c - Print working directory.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/pwd.html
+
+USE_PWD(NEWTOY(pwd, ">0LP[-LP]", TOYFLAG_BIN))
+
+config PWD
+  bool "pwd"
+  default y
+  help
+    usage: pwd [-L|-P]
+
+    Print working (current) directory.
+
+    -L  Use shell's path from $PWD (when applicable)
+    -P  Print cannonical absolute path
+*/
+
+#define FOR_pwd
+#include "toys.h"
+
+void pwd_main(void)
+{
+  char *s, *pwd = getcwd(0, 0), *PWD;
+
+  // Only use $PWD if it's an absolute path alias for cwd with no "." or ".."
+  if (!(toys.optflags & FLAG_P) && (s = PWD = getenv("PWD"))) {
+    struct stat st1, st2;
+
+    while (*s == '/') {
+      if (*(++s) == '.') {
+        if (s[1] == '/' || !s[1]) break;
+        if (s[1] == '.' && (s[2] == '/' || !s[2])) break;
+      }
+      while (*s && *s != '/') s++;
+    }
+    if (!*s && s != PWD) s = PWD;
+    else s = NULL;
+
+    // If current directory exists, make sure it matches.
+    if (s && pwd)
+        if (stat(pwd, &st1) || stat(PWD, &st2) || st1.st_ino != st2.st_ino ||
+            st1.st_dev != st2.st_dev) s = NULL;
+  } else s = NULL;
+
+  // If -L didn't give us a valid path, use cwd.
+  if (!s && !(s = pwd)) perror_exit("xgetcwd");
+
+  xprintf("%s\n", s);
+
+  if (CFG_TOYBOX_FREE) free(pwd);
+}
diff --git a/toybox/toys/posix/renice.c b/toybox/toys/posix/renice.c
new file mode 100644
index 0000000..489eb13
--- /dev/null
+++ b/toybox/toys/posix/renice.c
@@ -0,0 +1,48 @@
+/* renice.c - renice process
+ *
+ * Copyright 2013 CE Strake <strake888 at gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/renice.html
+
+USE_RENICE(NEWTOY(renice, "<1gpun#|", TOYFLAG_USR|TOYFLAG_BIN))
+
+config RENICE
+  bool "renice"
+  default y
+  help
+    usage: renice [-gpu] -n increment ID ...
+*/
+
+#define FOR_renice
+#include "toys.h"
+
+GLOBALS(
+  long nArgu;
+)
+
+void renice_main(void) {
+  int which = (toys.optflags & FLAG_g) ? PRIO_PGRP :
+              ((toys.optflags & FLAG_u) ? PRIO_USER : PRIO_PROCESS);
+  char **arg;
+
+  for (arg = toys.optargs; *arg; arg++) {
+    char *s = *arg;
+    int id = -1;
+
+    if (toys.optflags & FLAG_u) {
+      struct passwd *p = getpwnam(s);
+      if (p) id = p->pw_uid;
+    } else {
+      id = strtol(s, &s, 10);
+      if (*s) id = -1;
+    }
+
+    if (id < 0) {
+      error_msg("bad '%s'", *arg);
+      continue;
+    }
+
+    if (setpriority(which, id, getpriority(which, id)+TT.nArgu) < 0)
+      perror_msg("setpriority %d", id);
+  }
+}
diff --git a/toybox/toys/posix/rm.c b/toybox/toys/posix/rm.c
new file mode 100644
index 0000000..99fa8ed
--- /dev/null
+++ b/toybox/toys/posix/rm.c
@@ -0,0 +1,104 @@
+/* rm.c - remove files
+ *
+ * Copyright 2012 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html
+
+USE_RM(NEWTOY(rm, "fiRr[-fi]", TOYFLAG_BIN))
+
+config RM
+  bool "rm"
+  default y
+  help
+    usage: rm [-fiRr] FILE...
+
+    Remove each argument from the filesystem.
+
+    -f	force: remove without confirmation, no error if it doesn't exist
+    -i	interactive: prompt for confirmation
+    -rR	recursive: remove directory contents
+*/
+
+#define FOR_rm
+#include "toys.h"
+
+static int do_rm(struct dirtree *try)
+{
+  int fd = dirtree_parentfd(try), flags = toys.optflags;
+  int dir = S_ISDIR(try->st.st_mode), or = 0, using = 0;
+
+  // Skip . and .. (yes, even explicitly on the command line: posix says to)
+  if (!dirtree_notdotdot(try)) return 0;
+
+  // Intentionally fail non-recursive attempts to remove even an empty dir
+  // (via wrong flags to unlinkat) because POSIX says to.
+  if (dir && !(flags & (FLAG_r|FLAG_R))) goto skip;
+
+  // This is either the posix section 2(b) prompt or the section 3 prompt.
+  if (!(flags & FLAG_f)
+    && (!S_ISLNK(try->st.st_mode) && faccessat(fd, try->name, W_OK, 0))) or++;
+  if (!(dir && try->again) && ((or && isatty(0)) || (flags & FLAG_i))) {
+    char *s = dirtree_path(try, 0);
+
+    fprintf(stderr, "rm %s%s%s", or ? "ro " : "", dir ? "dir " : "", s);
+    free(s);
+    or = yesno(0);
+    if (!or) goto nodelete;
+  }
+
+  // handle directory recursion
+  if (dir) {
+    using = AT_REMOVEDIR;
+    // Handle chmod 000 directories when -f
+    if (faccessat(fd, try->name, R_OK, 0)) {
+      if (toys.optflags & FLAG_f) wfchmodat(fd, try->name, 0700);
+      else goto skip;
+    }
+    if (!try->again) return DIRTREE_COMEAGAIN;
+    if (try->symlink) goto skip;
+    if (flags & FLAG_i) {
+      char *s = dirtree_path(try, 0);
+
+      // This is the section 2(d) prompt. (Yes, posix says to prompt twice.)
+      fprintf(stderr, "rmdir %s", s);
+      free(s);
+      or = yesno(0);
+      if (!or) goto nodelete;
+    }
+  }
+
+skip:
+  if (unlinkat(fd, try->name, using)) {
+    if (!dir || try->symlink != (char *)2) perror_msg_raw(try->name);
+nodelete:
+    if (try->parent) try->parent->symlink = (char *)2;
+  }
+
+  return 0;
+}
+
+void rm_main(void)
+{
+  char **s;
+
+  // Can't use <1 in optstring because zero arguments with -f isn't an error
+  if (!toys.optc && !(toys.optflags & FLAG_f)) error_exit("Needs 1 argument");
+
+  for (s = toys.optargs; *s; s++) {
+    if (!strcmp(*s, "/")) {
+      error_msg("rm /. if you mean it");
+      continue;
+    }
+
+    // Files that already don't exist aren't errors for -f, so try a quick
+    // unlink now to see if it succeeds or reports that it didn't exist.
+    if ((toys.optflags & FLAG_f) && (!unlink(*s) || errno == ENOENT))
+      continue;
+
+    // There's a race here where a file removed between the above check and
+    // dirtree's stat would report the nonexistence as an error, but that's
+    // not a normal "it didn't exist" so I'm ok with it.
+
+    dirtree_read(*s, do_rm);
+  }
+}
diff --git a/toybox/toys/posix/rmdir.c b/toybox/toys/posix/rmdir.c
new file mode 100644
index 0000000..7421bb3
--- /dev/null
+++ b/toybox/toys/posix/rmdir.c
@@ -0,0 +1,47 @@
+/* rmdir.c - remove directory/path
+ *
+ * Copyright 2008 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/rmdir.html
+
+USE_RMDIR(NEWTOY(rmdir, "<1p", TOYFLAG_BIN))
+
+config RMDIR
+  bool "rmdir"
+  default y
+  help
+    usage: rmdir [-p] [dirname...]
+
+    Remove one or more directories.
+
+    -p	Remove path.
+*/
+
+#include "toys.h"
+
+static void do_rmdir(char *name)
+{
+  char *temp;
+
+  for (;;) {
+    if (rmdir(name)) {
+      perror_msg_raw(name);
+      return;
+    }
+
+    // Each -p cycle back up one slash, ignoring trailing and repeated /.
+
+    if (!toys.optflags) return;
+    do {
+      if (!(temp = strrchr(name, '/'))) return;
+      *temp = 0;
+    } while (!temp[1]);
+  }
+}
+
+void rmdir_main(void)
+{
+  char **s;
+
+  for (s=toys.optargs; *s; s++) do_rmdir(*s);
+}
diff --git a/toybox/toys/posix/sed.c b/toybox/toys/posix/sed.c
new file mode 100644
index 0000000..7198824
--- /dev/null
+++ b/toybox/toys/posix/sed.c
@@ -0,0 +1,1043 @@
+/* sed.c - stream editor. Thing that does s/// and other stuff.
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
+ *
+ * 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))
+
+config SED
+  bool "sed"
+  default y
+  help
+    usage: sed [-inrE] [-e SCRIPT]...|SCRIPT [-f SCRIPT_FILE]... [FILE...]
+
+    Stream editor. Apply one or more editing SCRIPTs to each line of input
+    (from FILE or stdin) producing output (by default to stdout).
+
+    -e	add SCRIPT to list
+    -f	add contents of SCRIPT_FILE to list
+    -i	Edit each file in place.
+    -n	No default output. (Use the p command to output matched lines.)
+    -r	Use extended regular expression syntax.
+    -E	Alias for -r.
+    -s	Treat input files separately (implied by -i)
+
+    A SCRIPT is a series of one or more COMMANDs separated by newlines or
+    semicolons. All -e SCRIPTs are concatenated together as if separated
+    by newlines, followed by all lines from -f SCRIPT_FILEs, in order.
+    If no -e or -f SCRIPTs are specified, the first argument is the SCRIPT.
+
+    Each COMMAND may be preceded by an address which limits the command to
+    apply only to the specified line(s). Commands without an address apply to
+    every line. Addresses are of the form:
+
+      [ADDRESS[,ADDRESS]]COMMAND
+
+    The ADDRESS may be a decimal line number (starting at 1), a /regular
+    expression/ within a pair of forward slashes, or the character "$" which
+    matches the last line of input. (In -s or -i mode this matches the last
+    line of each file, otherwise just the last line of the last file.) A single
+    address matches one line, a pair of comma separated addresses match
+    everything from the first address to the second address (inclusive). If
+    both addresses are regular expressions, more than one range of lines in
+    each file can match.
+
+    REGULAR EXPRESSIONS in sed are started and ended by the same character
+    (traditionally / but anything except a backslash or a newline works).
+    Backslashes may be used to escape the delimiter if it occurs in the
+    regex, and for the usual printf escapes (\abcefnrtv and octal, hex,
+    and unicode). An empty regex repeats the previous one. ADDRESS regexes
+    (above) require the first delimeter to be escaped with a backslash when
+    it isn't a forward slash (to distinguish it from the COMMANDs below).
+
+    Sed mostly operates on individual lines one at a time. It reads each line,
+    processes it, and either writes it to the output or discards it before
+    reading the next line. Sed can remember one additional line in a separate
+    buffer (using the h, H, g, G, and x commands), and can read the next line
+    of input early (using the n and N command), but other than that command
+    scripts operate on individual lines of text.
+
+    Each COMMAND starts with a single character. The following commands take
+    no arguments:
+
+      {  Start a new command block, continuing until a corresponding "}".
+         Command blocks may nest. If the block has an address, commands within
+         the block are only run for lines within the block's address range.
+
+      }  End command block (this command cannot have an address)
+
+      d  Delete this line and move on to the next one
+         (ignores remaining COMMANDs)
+
+      D  Delete one line of input and restart command SCRIPT (same as "d"
+         unless you've glued lines together with "N" or similar)
+
+      g  Get remembered line (overwriting current line)
+
+      G  Get remembered line (appending to current line)
+
+      h  Remember this line (overwriting remembered line)
+
+      H  Remember this line (appending to remembered line, if any)
+
+      l  Print line, escaping \abfrtv (but not newline), octal escaping other
+         nonprintable characters, wrapping lines to terminal width with a
+         backslash, and appending $ to actual end of line.
+
+      n  Print default output and read next line, replacing current line
+         (If no next line available, quit processing script)
+
+      N  Append next line of input to this line, separated by a newline
+         (This advances the line counter for address matching and "=", if no
+         next line available quit processing script without default output)
+
+      p  Print this line
+
+      P  Print this line up to first newline (from "N")
+
+      q  Quit (print default output, no more commands processed or lines read)
+
+      x  Exchange this line with remembered line (overwrite in both directions)
+
+      =  Print the current line number (followed by a newline)
+
+    The following commands (may) take an argument. The "text" arguments (to
+    the "a", "b", and "c" commands) may end with an unescaped "\" to append
+    the next line (for which leading whitespace is not skipped), and also
+    treat ";" as a literal character (use "\;" instead).
+
+      a [text]   Append text to output before attempting to read next line
+
+      b [label]  Branch, jumps to :label (or with no label, to end of SCRIPT)
+
+      c [text]   Delete line, output text at end of matching address range
+                 (ignores remaining COMMANDs)
+
+      i [text]   Print text
+
+      r [file]   Append contents of file to output before attempting to read
+                 next line.
+
+      s/S/R/F    Search for regex S, replace matched text with R using flags F.
+                 The first character after the "s" (anything but newline or
+                 backslash) is the delimiter, escape with \ to use normally.
+
+                 The replacement text may contain "&" to substitute the matched
+                 text (escape it with backslash for a literal &), or \1 through
+                 \9 to substitute a parenthetical subexpression in the regex.
+                 You can also use the normal backslash escapes such as \n and
+                 a backslash at the end of the line appends the next line.
+
+                 The flags are:
+
+                 [0-9]    A number, substitute only that occurrence of pattern
+                 g        Global, substitute all occurrences of pattern
+                 i        Ignore case when matching
+                 p        Print the line if match was found and replaced
+                 w [file] Write (append) line to file if match replaced
+
+      t [label]  Test, jump to :label only if an "s" command found a match in
+                 this line since last test (replacing with same text counts)
+
+      T [label]  Test false, jump only if "s" hasn't found a match.
+
+      w [file]   Write (append) line to file
+
+      y/old/new/ Change each character in 'old' to corresponding character
+                 in 'new' (with standard backslash escapes, delimiter can be
+                 any repeated character except \ or \n)
+
+      : [label]  Labeled target for jump commands
+
+      #  Comment, ignore rest of this line of SCRIPT
+
+    Deviations from posix: allow extended regular expressions with -r,
+    editing in place with -i, separate with -s, printf escapes in text, line
+    continuations, semicolons after all commands, 2-address anywhere an
+    address is allowed, "T" command, multiline continuations for [abc],
+    \; to end [abc] argument before end of line.
+*/
+
+#define FOR_sed
+#include "toys.h"
+
+GLOBALS(
+  struct arg_list *f;
+  struct arg_list *e;
+
+  // processed pattern list
+  struct double_list *pattern;
+
+  char *nextline, *remember;
+  void *restart, *lastregex;
+  long nextlen, rememberlen, count;
+  int fdout, noeol;
+  unsigned xx;
+)
+
+// 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]; // 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
+};
+
+// Write out line with potential embedded NUL, handling eol/noeol
+static int emit(char *line, long len, int eol)
+{
+  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;
+  l = writeall(TT.fdout, line, len);
+  if (eol) line[len-1] = old;
+  if (l != len) {
+    perror_msg("short write");
+
+    return 1;
+  }
+
+  return 0;
+}
+
+// Extend allocation to include new string, with newline between if newlen<0
+
+static char *extend_string(char **old, char *new, int oldlen, int newlen)
+{
+  int newline = newlen < 0;
+  char *s;
+
+  if (newline) newlen = -newlen;
+  s = *old = xrealloc(*old, oldlen+newlen+newline+1);
+  if (newline) s[oldlen++] = '\n';
+  memcpy(s+oldlen, new, newlen);
+  s[oldlen+newlen] = 0;
+
+  return s+oldlen+newlen+1;
+}
+
+// An empty regex repeats the previous one
+static void *get_regex(void *trump, int offset)
+{
+  if (!offset) {
+    if (!TT.lastregex) error_exit("no previous regex");
+    return TT.lastregex;
+  }
+
+  return TT.lastregex = offset+(char *)trump;
+}
+
+// Apply pattern to line from input file
+static void process_line(char **pline, long plen)
+{
+  struct append {
+    struct append *next, *prev;
+    int file;
+    char *str;
+  } *append = 0;
+  char *line = TT.nextline;
+  long len = TT.nextlen;
+  struct sedcmd *command;
+  int eol = 0, tea = 0;
+
+  // Grab next line for deferred processing (EOF detection: we get a NULL
+  // pline at EOF to flush last line). Note that only end of _last_ input
+  // file matches $ (unless we're doing -i).
+  TT.nextline = 0;
+  TT.nextlen = 0;
+  if (pline) {
+    TT.nextline = *pline;
+    TT.nextlen = plen;
+    *pline = 0;
+  }
+
+  if (!line || !len) return;
+  if (line[len-1] == '\n') line[--len] = eol++;
+  TT.count++;
+
+  // The restart-1 is because we added one to make sure it wasn't NULL,
+  // otherwise N as last command would restart script
+  command = TT.restart ? ((struct sedcmd *)TT.restart)-1 : (void *)TT.pattern;
+  TT.restart = 0;
+
+  while (command) {
+    char *str, c = command->c;
+
+    // Have we got a line or regex matching range for this rule?
+    if (*command->lmatch || *command->rmatch) {
+      int miss = 0;
+      long lm;
+
+      // In a match that might end?
+      if (command->hit) {
+        if (!(lm = command->lmatch[1])) {
+          if (!command->rmatch[1]) command->hit = 0;
+          else {
+            void *rm = get_regex(command, command->rmatch[1]);
+
+            // regex match end includes matching line, so defer deactivation
+            if (line && !regexec0(rm, line, len, 0, 0, 0)) miss = 1;
+          }
+        } else if (lm > 0 && lm < TT.count) command->hit = 0;
+
+      // Start a new match?
+      } else {
+        if (!(lm = *command->lmatch)) {
+          void *rm = get_regex(command, *command->rmatch);
+
+          if (line && !regexec0(rm, line, len, 0, 0, 0)) command->hit++;
+        } else if (lm == TT.count || (lm == -1 && !pline)) command->hit++;
+
+        if (!command->lmatch[1] && !command->rmatch[1]) miss = 1;
+      } 
+
+      // Didn't match?
+      lm = !(command->hit ^ command->not);
+
+      // Deferred disable from regex end match
+      if (miss || command->lmatch[1] == TT.count) command->hit = 0;
+
+      if (lm) {
+        // Handle skipping curly bracket command group
+        if (c == '{') {
+          int curly = 1;
+
+          while (curly) {
+            command = command->next;
+            if (command->c == '{') curly++;
+            if (command->c == '}') curly--;
+          }
+        }
+        command = command->next;
+        continue;
+      }
+    }
+
+    // A deleted line can still update line match state for later commands
+    if (!line) {
+      command = command->next;
+      continue;
+    }
+
+    // Process command
+
+    if (c=='a' || c=='r') {
+      struct append *a = xzalloc(sizeof(struct append));
+      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') {
+      int t = tea;
+
+      if (c != 'b') tea = 0;
+      if (c=='b' || t^(c=='T')) {
+        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 (!command) error_exit("no :%s", str);
+      }
+    } else if (c=='c') {
+      str = command->arg1+(char *)command;
+      if (!command->hit) emit(str, strlen(str), 1);
+      free(line);
+      line = 0;
+      continue;
+    } else if (c=='d') {
+      free(line);
+      line = 0;
+      continue;
+    } else if (c=='D') {
+      // Delete up to \n or end of buffer
+      str = line;
+      while ((str-line)<len) if (*(str++) == '\n') break;
+      len -= str - line;
+      memmove(line, str, len);
+
+      // if "delete" blanks line, disable further processing
+      // otherwise trim and restart script
+      if (!len) {
+        free(line);
+        line = 0;
+      } else {
+        line[len] = 0;
+        command = (void *)TT.pattern;
+      }
+      continue;
+    } else if (c=='g') {
+      free(line);
+      line = xstrdup(TT.remember);
+      len = TT.rememberlen;
+    } else if (c=='G') {
+      line = xrealloc(line, len+TT.rememberlen+2);
+      line[len++] = '\n';
+      memcpy(line+len, TT.remember, TT.rememberlen);
+      line[len += TT.rememberlen] = 0;
+    } else if (c=='h') {
+      free(TT.remember);
+      TT.remember = xstrdup(line);
+      TT.rememberlen = len;
+    } else if (c=='H') {
+      TT.remember = xrealloc(TT.remember, TT.rememberlen+len+2);
+      TT.remember[TT.rememberlen++] = '\n';
+      memcpy(TT.remember+TT.rememberlen, line, len);
+      TT.remember[TT.rememberlen += len] = 0;
+    } else if (c=='i') {
+      str = command->arg1+(char *)command;
+      emit(str, strlen(str), 1);
+    } else if (c=='l') {
+      int i, x, off;
+
+      if (!TT.xx) {
+        terminal_size(&TT.xx, 0);
+        if (!TT.xx) TT.xx = 80;
+        if (TT.xx > sizeof(toybuf)-10) TT.xx = sizeof(toybuf)-10;
+        if (TT.xx > 4) TT.xx -= 4;
+      }
+
+      for (i = off = 0; i<len; i++) {
+        if (off >= TT.xx) {
+          toybuf[off++] = '\\';
+          emit(toybuf, off, 1);
+          off = 0;
+        }
+        x = stridx("\\\a\b\f\r\t\v", line[i]);
+        if (x != -1) {
+          toybuf[off++] = '\\';
+          toybuf[off++] = "\\abfrtv"[x];
+        } else if (line[i] >= ' ') toybuf[off++] = line[i];
+        else off += sprintf(toybuf+off, "\\%03o", line[i]);
+      }
+      toybuf[off++] = '$';
+      emit(toybuf, off, 1);
+    } else if (c=='n') {
+      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 = command->next+1;
+        extend_string(&line, TT.nextline, len, -TT.nextlen);
+        free(TT.nextline);
+        TT.nextline = line;
+        TT.nextlen += len + 1;
+        line = 0;
+      }
+
+      // Pending append goes out right after N
+      goto done; 
+    } else if (c=='p' || c=='P') {
+      char *l = (c=='P') ? strchr(line, '\n') : 0;
+
+      if (emit(line, l ? l-line : len, eol)) break;
+    } else if (c=='q') {
+      if (pline) *pline = (void *)1;
+      free(TT.nextline);
+      TT.nextline = 0;
+      TT.nextlen = 0;
+
+      break;
+    } else if (c=='s') {
+      char *rline = line, *new = command->arg2 + (char *)command, *swap, *rswap;
+      regmatch_t *match = (void *)toybuf;
+      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 (!regexec0(reg, rline, rlen, 10, match, mflags)) {
+        mflags = REG_NOTBOL;
+
+        // Zero length matches don't count immediately after a previous match
+        mlen = match[0].rm_eo-match[0].rm_so;
+        if (!mlen && !zmatch) {
+          if (!rlen--) break;
+          rline++;
+          zmatch++;
+          continue;
+        } else zmatch = 0;
+
+        // If we're replacing only a specific match, skip if this isn't it
+        off = command->sflags>>3;
+        if (off && off != ++count) {
+          rline += match[0].rm_eo;
+          rlen -= match[0].rm_eo;
+
+          continue;
+        }
+        // The fact getline() can allocate unbounded amounts of memory is
+        // a bigger issue, but while we're here check for integer overflow
+        if (match[0].rm_eo > INT_MAX) perror_exit(0);
+
+        // newlen = strlen(new) but with \1 and & and printf escapes
+        for (off = newlen = 0; new[off]; off++) {
+          int cc = -1;
+
+          if (new[off] == '&') cc = 0;
+          else if (new[off] == '\\') cc = new[++off] - '0';
+          if (cc < 0 || cc > 9) {
+            newlen++;
+            continue;
+          }
+          newlen += match[cc].rm_eo-match[cc].rm_so;
+        }
+
+        // Allocate new size, copy start/end around match. (Can't extend in
+        // place because backrefs may refer to text after it's overwritten.)
+        len += newlen-mlen;
+        swap = xmalloc(len+1);
+        rswap = swap+(rline-line)+match[0].rm_so;
+        memcpy(swap, line, (rline-line)+match[0].rm_so);
+        memcpy(rswap+newlen, rline+match[0].rm_eo, (rlen -= match[0].rm_eo)+1);
+
+        // copy in new replacement text
+        for (off = mlen = 0; new[off]; off++) {
+          int cc = 0, ll;
+
+          if (new[off] == '\\') {
+            cc = new[++off] - '0';
+            if (cc<0 || cc>9) {
+              if (!(rswap[mlen++] = unescape(new[off])))
+                rswap[mlen-1] = new[off];
+
+              continue;
+            } else if (match[cc].rm_so == -1) error_exit("no s//\\%d/", cc);
+          } else if (new[off] != '&') {
+            rswap[mlen++] = new[off];
+
+            continue;
+          }
+
+          ll = match[cc].rm_eo-match[cc].rm_so;
+          memcpy(rswap+mlen, rline+match[cc].rm_so, ll);
+          mlen += ll;
+        }
+
+        rline = rswap+newlen;
+        free(line);
+        line = swap;
+
+        // Stop after first substitution unless we have flag g
+        if (!(command->sflags & 2)) break;
+      }
+
+      if (mflags) {
+        // flag p
+        if (command->sflags & 4) emit(line, len, eol);
+
+        tea = 1;
+        if (command->w) goto writenow;
+      }
+    } else if (c=='w') {
+      int fd, noeol;
+      char *name;
+
+writenow:
+      // Swap out emit() context
+      fd = TT.fdout;
+      noeol = TT.noeol;
+
+      // We save filehandle and newline status before filename
+      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'", command->arg1+(char *)command);
+      *(--name) = TT.noeol;
+      TT.noeol = noeol;
+      TT.fdout = fd;
+    } else if (c=='x') {
+      long swap = TT.rememberlen;
+
+      str = TT.remember;
+      TT.remember = line;
+      line = str;
+      TT.rememberlen = len;
+      len = swap;
+    } else if (c=='y') {
+      char *from, *to = (char *)command;
+      int i, j;
+
+      from = to+command->arg1;
+      to += command->arg2;
+
+      for (i = 0; i < len; i++) {
+        j = stridx(from, line[i]);
+        if (j != -1) line[i] = to[j];
+      }
+    } else if (c=='=') {
+      sprintf(toybuf, "%ld", TT.count);
+      emit(toybuf, strlen(toybuf), 1);
+    }
+
+    command = command->next;
+  }
+
+  if (line && !(toys.optflags & FLAG_n)) emit(line, len, eol);
+
+done:
+  if (dlist_terminate(append)) while (append) {
+    struct append *a = append->next;
+
+    if (append->file) {
+      int fd = open(append->str, O_RDONLY);
+
+      // Force newline if noeol pending
+      if (fd != -1) {
+        if (TT.noeol) xwrite(TT.fdout, "\n", 1);
+        TT.noeol = 0;
+        xsendfile(fd, TT.fdout);
+        close(fd);
+      }
+    } else if (append->str) emit(append->str, strlen(append->str), 1);
+    else emit(line, 0, 0);
+    free(append);
+    append = a;
+  }
+  free(line);
+}
+
+// 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, 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);
+}
+
+// Callback called on each input file
+static void do_sed(int fd, char *name)
+{
+  int i = toys.optflags & FLAG_i;
+  char *tmp;
+
+  if (i) {
+    struct sedcmd *command;
+
+    if (!fd && !strcmp(name, "-")) {
+      error_msg("-i on stdin");
+      return;
+    }
+    TT.fdout = copy_tempfile(fd, name, &tmp);
+    TT.count = 0;
+    for (command = (void *)TT.pattern; command; command = command->next)
+      command->hit = 0;
+  }
+  do_lines(fd, process_line);
+  if (i) {
+    process_line(0, 0);
+    replace_tempfile(-1, TT.fdout, &tmp);
+    TT.fdout = 1;
+    TT.nextline = 0;
+    TT.nextlen = TT.noeol = 0;
+  }
+}
+
+// Copy chunk of string between two delimiters, converting printf escapes.
+// returns processed copy of string (0 if error), *pstr advances to next
+// unused char. if delim (or *delim) is 0 uses/saves starting char as delimiter
+// if regxex, ignore delimiter in [ranges]
+static char *unescape_delimited_string(char **pstr, char *delim)
+{
+  char *to, *from, mode = 0, d;
+
+  from = *pstr;
+  if (!delim || !*delim) {
+    if (!(d = *(from++))) return 0;
+    if (d == '\\') d = *(from++);
+    if (!d || d == '\\') return 0;
+    if (delim) *delim = d;
+  } else d = *delim;
+  to = delim = xmalloc(strlen(*pstr)+1);
+
+  while (mode || *from != d) {
+    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;
+    // 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]) {
+      from+=2;
+      continue;
+    } else if (*from == '\\') {
+      if (!from[1]) return 0;
+
+      // Check escaped end delimiter before printf style escapes.
+      if (from[1] == d) from++;
+      else if (from[1]=='\\') *(to++) = *(from++);
+      else {
+        char c = unescape(from[1]);
+
+        if (c) {
+          *(to++) = c;
+          from+=2;
+          continue;
+        } else if (!mode) *(to++) = *(from++);
+      }
+    }
+    *(to++) = *(from++);
+  }
+  *to = 0;
+  *pstr = from+1;
+
+  return delim;
+}
+
+// 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 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 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;
+    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 this line.
+
+  command = 0;
+  for (;;) {
+    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++;
+      else break;
+    }
+    if (!*line) return;
+
+    // We start by writing data into toybuf. Later we'll allocate the
+    // ex
+
+    errstart = line;
+    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)) command->lmatch[i] = strtol(line, &line, 0);
+      else if (*line == '$') {
+        command->lmatch[i] = -1;
+        line++;
+      } else if (*line == '/' || *line == '\\') {
+        char *s = line;
+
+        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);
+          command->rmatch[i] = reg-toybuf;
+          reg += sizeof(regex_t);
+        }
+        free(s);
+      } else break;
+    }
+
+    while (isspace(*line)) line++;
+    if (!*line) break;
+
+    while (*line == '!') {
+      command->not = 1;
+      line++;
+    }
+    while (isspace(*line)) line++;
+
+    c = command->c = *(line++);
+    if (strchr("}:", c) && i) break;
+    if (strchr("aiqr=", c) && i>1) break;
+
+    // Add step to pattern
+    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 *end, delim = 0;
+
+      // s/pattern/replacement/flags
+
+      // 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)
+      command->arg2 = reg - (char *)command;
+      if (!(TT.remember = unescape_delimited_string(&line, &delim)))
+        goto error;
+
+      reg += sizeof(regex_t);
+      command->arg1 = reg-(char *)command;
+      command->hit = delim;
+resume_s:
+      // get replacement - don't replace escapes yet because \1 and \& need
+      // processing later, after we replace \\ with \ we can't tell \\1 from \1
+      end = line;
+      while (*end != command->hit) {
+        if (!*end) goto error;
+        if (*end++ == '\\') {
+          if (!*end || *end == '\n') {
+            end[-1] = '\n';
+            break;
+          }
+          end++;
+        }
+      }
+
+      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 == command->hit) command->hit = 0;
+      else {
+        if (!*line) continue;
+        reg--;
+        line++;
+        goto resume_s;
+      }
+
+      // swap arg1/arg2 so they're back in order arguments occur.
+      i = command->arg1;
+      command->arg1 = command->arg2;
+      command->arg2 = i;
+
+      // get flags
+      for (line++; *line; line++) {
+        long l;
+
+        if (isspace(*line) && *line != '\n') continue;
+
+        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) 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') {
+        line++;
+        goto writenow;
+      }
+    } else if (c == 'w') {
+      int fd, delim;
+      char *cc;
+
+      // Since s/// uses arg1 and arg2, and w needs a persistent filehandle and
+      // eol status, and to retain the filename for error messages, we'd need
+      // to go up to arg5 just for this. Compromise: dynamically allocate the
+      // filehandle and eol status.
+
+writenow:
+      while (isspace(*line)) line++;
+      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;
+
+      command->w = reg - (char *)command;
+      command = xrealloc(command, command->w+(cc-line)+6);
+      reg = command->w + (char *)command;
+
+      memcpy(reg, &fd, 4);
+      reg += 4;
+      *(reg++) = 0;
+      memcpy(reg, line, delim);
+      reg += delim;
+      *(reg++) = 0;
+
+      line = cc;
+      if (delim) line += 2;
+    } else if (c == 'y') {
+      char *s, delim = 0;
+      int len;
+
+      if (!(s = unescape_delimited_string(&line, &delim))) goto error;
+      command->arg1 = reg-(char *)command;
+      len = strlen(s);
+      reg = extend_string((void *)&command, s, reg-(char *)command, len);
+      free(s);
+      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:
+      command->hit = 0;
+
+      // 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 (!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 (!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)) {
+        reg -= end+1;
+        for (i = end; i; i--) {
+          if ((*reg++ = *line++)=='\\') {
+
+            // escape at end of line: resume if -e escaped literal newline,
+            // else request callback and resume with next line
+            if (!--i) {
+              *--reg = 0;
+              if (*line) {
+                line++;
+                goto resume_a;
+              }
+              command->hit = 256;
+              break;
+            }
+            if (!(reg[-1] = unescape(*line))) reg[-1] = *line;
+            line++;
+          }
+        }
+        *reg = 0;
+      } else line += end;
+
+    // Commands that take no arguments
+    } else if (!strchr("{dDgGhHlnNpPqx=", c)) break;
+  }
+
+error:
+  error_exit("bad pattern '%s'@%ld (%c)", errstart, line-errstart+1L, *line);
+}
+
+void sed_main(void)
+{
+  struct arg_list *al;
+  char **args = toys.optargs;
+
+  // Lie to autoconf when it asks stupid questions, so configure regexes
+  // that look for "GNU sed version %f" greater than some old buggy number
+  // don't fail us for not matching their narrow expectations.
+  if (toys.optflags & FLAG_version) {
+    xprintf("This is not GNU sed version 9.0\n");
+    return;
+  }
+
+  // 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 (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);
+
+  if (!(toys.optflags & FLAG_i)) process_line(0, 0);
+
+  // todo: need to close fd when done for TOYBOX_FREE?
+}
diff --git a/toybox/toys/posix/sleep.c b/toybox/toys/posix/sleep.c
new file mode 100644
index 0000000..c7b8bbf
--- /dev/null
+++ b/toybox/toys/posix/sleep.c
@@ -0,0 +1,36 @@
+/* sleep.c - Wait for a number of seconds.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/sleep.html
+
+USE_SLEEP(NEWTOY(sleep, "<1", TOYFLAG_BIN))
+
+config SLEEP
+  bool "sleep"
+  default y
+  help
+    usage: sleep LENGTH
+
+    Wait before exiting. An optional suffix can be "m" (minutes), "h" (hours),
+    "d" (days), or "s" (seconds, the default).
+
+
+config SLEEP_FLOAT
+  bool
+  default y
+  depends on SLEEP && TOYBOX_FLOAT
+  help
+    Length can be a decimal fraction.
+*/
+
+#include "toys.h"
+
+void sleep_main(void)
+{
+  struct timespec tv;
+
+  tv.tv_sec = xparsetime(*toys.optargs, 1000000000, &tv.tv_nsec);
+  toys.exitval = !!nanosleep(&tv, NULL);
+}
diff --git a/toybox/toys/posix/sort.c b/toybox/toys/posix/sort.c
new file mode 100644
index 0000000..a1722fb
--- /dev/null
+++ b/toybox/toys/posix/sort.c
@@ -0,0 +1,400 @@
+/* sort.c - put input lines into order
+ *
+ * Copyright 2004, 2008 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/007904975/utilities/sort.html
+ *
+ * Deviations from POSIX: Lots.
+ * We invented -x
+
+USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")USE_SORT_BIG("S:T:m" "o:k*t:xbMcszdfi") "run", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SORT
+  bool "sort"
+  default y
+  help
+    usage: sort [-run] [FILE...]
+
+    Sort all lines of text from input files (or stdin) to stdout.
+
+    -r	reverse
+    -u	unique lines only
+    -n	numeric order (instead of alphabetical)
+
+config SORT_BIG
+  bool "SuSv3 options (Support -ktcsbdfiozM)"
+  default y
+  depends on SORT
+  help
+    usage: sort [-bcdfiMsz] [-k#[,#[x]] [-t X]] [-o FILE]
+
+    -b	ignore leading blanks (or trailing blanks in second part of key)
+    -c	check whether input is sorted
+    -d	dictionary order (use alphanumeric and whitespace chars only)
+    -f	force uppercase (case insensitive sort)
+    -i	ignore nonprinting characters
+    -M	month sort (jan, feb, etc).
+    -x	Hexadecimal numerical sort
+    -s	skip fallback sort (only sort with keys)
+    -z	zero (null) terminated lines
+    -k	sort by "key" (see below)
+    -t	use a key separator other than whitespace
+    -o	output to FILE instead of stdout
+
+    Sorting by key looks at a subset of the words on each line.  -k2
+    uses the second word to the end of the line, -k2,2 looks at only
+    the second word, -k2,4 looks from the start of the second to the end
+    of the fourth word.  Specifying multiple keys uses the later keys as
+    tie breakers, in order.  A type specifier appended to a sort key
+    (such as -2,2n) applies only to sorting that key.
+
+config SORT_FLOAT
+  bool
+  default y
+  depends on SORT_BIG && TOYBOX_FLOAT
+  help
+    usage: sort [-g]
+
+    -g	general numeric sort (double precision with nan and inf)
+*/
+
+#define FOR_sort
+#include "toys.h"
+
+GLOBALS(
+  char *key_separator;
+  struct arg_list *raw_keys;
+  char *outfile;
+  char *ignore1, ignore2;   // GNU compatability NOPs for -S and -T.
+
+  void *key_list;
+  int linecount;
+  char **lines;
+)
+
+// The sort types are n, g, and M.
+// u, c, s, and z apply to top level only, not to keys.
+// b at top level implies bb.
+// The remaining options can be applied to search keys.
+
+#define FLAG_bb (1<<31)  // Ignore trailing blanks
+
+struct sort_key
+{
+  struct sort_key *next_key;  // linked list
+  unsigned range[4];          // start word, start char, end word, end char
+  int flags;
+};
+
+// Copy of the part of this string corresponding to a key/flags.
+
+static char *get_key_data(char *str, struct sort_key *key, int flags)
+{
+  int start=0, end, len, i, j;
+
+  // Special case whole string, so we don't have to make a copy
+
+  if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3]
+    && !(flags&(FLAG_b|FLAG_d|FLAG_i|FLAG_bb))) return str;
+
+  // Find start of key on first pass, end on second pass
+
+  len = strlen(str);
+  for (j=0; j<2; j++) {
+    if (!key->range[2*j]) end=len;
+
+    // Loop through fields
+    else {
+      end=0;
+      for (i=1; i < key->range[2*j]+j; i++) {
+
+        // Skip leading blanks
+        if (str[end] && !TT.key_separator)
+          while (isspace(str[end])) end++;
+
+        // Skip body of key
+        for (; str[end]; end++) {
+          if (TT.key_separator) {
+            if (str[end]==*TT.key_separator) break;
+          } else if (isspace(str[end])) break;
+        }
+      }
+    }
+    if (!j) start=end;
+  }
+
+  // Key with explicit separator starts after the separator
+  if (TT.key_separator && str[start]==*TT.key_separator) start++;
+
+  // Strip leading and trailing whitespace if necessary
+  if (flags&FLAG_b) while (isspace(str[start])) start++;
+  if (flags&FLAG_bb) while (end>start && isspace(str[end-1])) end--;
+
+  // Handle offsets on start and end
+  if (key->range[3]) {
+    end += key->range[3]-1;
+    if (end>len) end=len;
+  }
+  if (key->range[1]) {
+    start += key->range[1]-1;
+    if (start>len) start=len;
+  }
+
+  // Make the copy
+  if (end<start) end=start;
+  str = xstrndup(str+start, end-start);
+
+  // Handle -d
+  if (flags&FLAG_d) {
+    for (start = end = 0; str[end]; end++)
+      if (isspace(str[end]) || isalnum(str[end])) str[start++] = str[end];
+    str[start] = 0;
+  }
+
+  // Handle -i
+  if (flags&FLAG_i) {
+    for (start = end = 0; str[end]; end++)
+      if (isprint(str[end])) str[start++] = str[end];
+    str[start] = 0;
+  }
+
+  return str;
+}
+
+// append a sort_key to key_list.
+
+static struct sort_key *add_key(void)
+{
+  void **stupid_compiler = &TT.key_list;
+  struct sort_key **pkey = (struct sort_key **)stupid_compiler;
+
+  while (*pkey) pkey = &((*pkey)->next_key);
+  return *pkey = xzalloc(sizeof(struct sort_key));
+}
+
+// Perform actual comparison
+static int compare_values(int flags, char *x, char *y)
+{
+  int ff = flags & (FLAG_n|FLAG_g|FLAG_M|FLAG_x);
+
+  // Ascii sort
+  if (!ff) return ((flags&FLAG_f) ? strcasecmp : strcmp)(x, y);
+
+  if (CFG_SORT_FLOAT && ff == FLAG_g) {
+    char *xx,*yy;
+    double dx = strtod(x,&xx), dy = strtod(y,&yy);
+    int xinf, yinf;
+
+    // not numbers < NaN < -infinity < numbers < +infinity
+
+    if (x==xx) return y==yy ? 0 : -1;
+    if (y==yy) return 1;
+
+    // Check for isnan
+    if (dx!=dx) return (dy!=dy) ? 0 : -1;
+    if (dy!=dy) return 1;
+
+    // Check for infinity.  (Could underflow, but avoids needing libm.)
+    xinf = (1.0/dx == 0.0);
+    yinf = (1.0/dy == 0.0);
+    if (xinf) {
+      if(dx<0) return (yinf && dy<0) ? 0 : -1;
+      return (yinf && dy>0) ? 0 : 1;
+    }
+    if (yinf) return dy<0 ? 1 : -1;
+
+    return dx>dy ? 1 : (dx<dy ? -1 : 0);
+  } else if (CFG_SORT_BIG && ff == FLAG_M) {
+    struct tm thyme;
+    int dx;
+    char *xx,*yy;
+
+    xx = strptime(x,"%b",&thyme);
+    dx = thyme.tm_mon;
+    yy = strptime(y,"%b",&thyme);
+    if (!xx) return !yy ? 0 : -1;
+    else if (!yy) return 1;
+    else return dx==thyme.tm_mon ? 0 : dx-thyme.tm_mon;
+
+  } else if (CFG_SORT_BIG && ff == FLAG_x) {
+    return strtol(x, NULL, 16)-strtol(y, NULL, 16);
+  // This has to be ff == FLAG_n
+  } else {
+    // Full floating point version of -n
+    if (CFG_SORT_FLOAT) {
+      double dx = atof(x), dy = atof(y);
+
+      return dx>dy ? 1 : (dx<dy ? -1 : 0);
+    // Integer version of -n for tiny systems
+    } else return atoi(x)-atoi(y);
+  }
+}
+
+// Callback from qsort(): Iterate through key_list and perform comparisons.
+static int compare_keys(const void *xarg, const void *yarg)
+{
+  int flags = toys.optflags, retval = 0;
+  char *x, *y, *xx = *(char **)xarg, *yy = *(char **)yarg;
+  struct sort_key *key;
+
+  if (CFG_SORT_BIG) {
+    for (key=(struct sort_key *)TT.key_list; !retval && key;
+       key = key->next_key)
+    {
+      flags = key->flags ? key->flags : toys.optflags;
+
+      // Chop out and modify key chunks, handling -dfib
+
+      x = get_key_data(xx, key, flags);
+      y = get_key_data(yy, key, flags);
+
+      retval = compare_values(flags, x, y);
+
+      // Free the copies get_key_data() made.
+
+      if (x != xx) free(x);
+      if (y != yy) free(y);
+
+      if (retval) break;
+    }
+  } else retval = compare_values(flags, xx, yy);
+
+  // Perform fallback sort if necessary (always case insensitive, no -f,
+  // the point is to get a stable order even for -f sorts)
+  if (!retval && !(CFG_SORT_BIG && (toys.optflags&FLAG_s))) {
+    flags = toys.optflags;
+    retval = strcmp(xx, yy);
+  }
+
+  return retval * ((flags&FLAG_r) ? -1 : 1);
+}
+
+// Callback from loopfiles to handle input files.
+static void sort_read(int fd, char *name)
+{
+  // Read each line from file, appending to a big array.
+
+  for (;;) {
+    char * line = (CFG_SORT_BIG && (toys.optflags&FLAG_z))
+             ? get_rawline(fd, NULL, 0) : get_line(fd);
+
+    if (!line) break;
+
+    // handle -c here so we don't allocate more memory than necessary.
+    if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) {
+      int j = (toys.optflags&FLAG_u) ? -1 : 0;
+
+      if (TT.lines && compare_keys((void *)&TT.lines, &line)>j)
+        error_exit("%s: Check line %d\n", name, TT.linecount);
+      free(TT.lines);
+      TT.lines = (char **)line;
+    } else {
+      if (!(TT.linecount&63))
+        TT.lines = xrealloc(TT.lines, sizeof(char *)*(TT.linecount+64));
+      TT.lines[TT.linecount] = line;
+    }
+    TT.linecount++;
+  }
+}
+
+void sort_main(void)
+{
+  int idx, fd = 1;
+
+  // Open output file if necessary.
+  if (CFG_SORT_BIG && TT.outfile)
+    fd = xcreate(TT.outfile, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+
+  // Parse -k sort keys.
+  if (CFG_SORT_BIG && TT.raw_keys) {
+    struct arg_list *arg;
+
+    for (arg = TT.raw_keys; arg; arg = arg->next) {
+      struct sort_key *key = add_key();
+      char *temp;
+      int flag;
+
+      idx = 0;
+      temp = arg->arg;
+      while (*temp) {
+        // Start of range
+        key->range[2*idx] = (unsigned)strtol(temp, &temp, 10);
+        if (*temp=='.')
+          key->range[(2*idx)+1] = (unsigned)strtol(temp+1, &temp, 10);
+
+        // Handle flags appended to a key type.
+        for (;*temp;temp++) {
+          char *temp2, *optlist;
+
+          // Note that a second comma becomes an "Unknown key" error.
+
+          if (*temp==',' && !idx++) {
+            temp++;
+            break;
+          }
+
+          // Which flag is this?
+
+          optlist = toys.which->options;
+          temp2 = strchr(optlist, *temp);
+          flag = (1<<(optlist-temp2+strlen(optlist)-1));
+
+          // Was it a flag that can apply to a key?
+
+          if (!temp2 || flag>FLAG_b
+            || (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z)))
+          {
+            error_exit("Unknown key option.");
+          }
+          // b after , means strip _trailing_ space, not leading.
+          if (idx && flag==FLAG_b) flag = FLAG_bb;
+          key->flags |= flag;
+        }
+      }
+    }
+  }
+
+  // global b flag strips both leading and trailing spaces
+  if (toys.optflags&FLAG_b) toys.optflags |= FLAG_bb;
+
+  // If no keys, perform alphabetic sort over the whole line.
+  if (CFG_SORT_BIG && !TT.key_list) add_key()->range[0] = 1;
+
+  // Open input files and read data, populating TT.lines[TT.linecount]
+  loopfiles(toys.optargs, sort_read);
+
+  // The compare (-c) logic was handled in sort_read(),
+  // so if we got here, we're done.
+  if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) goto exit_now;
+
+  // Perform the actual sort
+  qsort(TT.lines, TT.linecount, sizeof(char *), compare_keys);
+
+  // handle unique (-u)
+  if (toys.optflags&FLAG_u) {
+    int jdx;
+
+    for (jdx=0, idx=1; idx<TT.linecount; idx++) {
+      if (!compare_keys(&TT.lines[jdx], &TT.lines[idx]))
+        free(TT.lines[idx]);
+      else TT.lines[++jdx] = TT.lines[idx];
+    }
+    if (TT.linecount) TT.linecount = jdx+1;
+  }
+
+  // Output result
+  for (idx = 0; idx<TT.linecount; idx++) {
+    char *s = TT.lines[idx];
+    unsigned i = strlen(s);
+
+    if (!(toys.optflags&FLAG_z)) s[i] = '\n';
+    xwrite(fd, s, i+1);
+    if (CFG_TOYBOX_FREE) free(s);
+  }
+
+exit_now:
+  if (CFG_TOYBOX_FREE) {
+    if (fd != 1) close(fd);
+    free(TT.lines);
+  }
+}
diff --git a/toybox/toys/posix/split.c b/toybox/toys/posix/split.c
new file mode 100644
index 0000000..075a414
--- /dev/null
+++ b/toybox/toys/posix/split.c
@@ -0,0 +1,108 @@
+/* split.c - split a file into smaller files
+ *
+ * Copyright 2013 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/split.html
+ *
+ * Standard does not cover:
+ * - should splitting an empty file produce an empty outfile? (Went with "no".)
+ * - permissions on output file
+
+USE_SPLIT(NEWTOY(split, ">2a#<1=2>9b#<1l#<1", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SPLIT
+  bool "split"
+  default y
+  help
+    usage: split [-a SUFFIX_LEN] [-b BYTES] [-l LINES] [INPUT [OUTPUT]]
+
+    Copy INPUT (or stdin) data to a series of OUTPUT (or "x") files with
+    alphabetically increasing suffix (aa, ab, ac... az, ba, bb...).
+
+    -a	Suffix length (default 2)
+    -b	BYTES/file (10, 10k, 10m, 10g...)
+    -l	LINES/file (default 1000)
+*/
+
+#define FOR_split
+#include "toys.h"
+
+GLOBALS(
+  long lines;
+  long bytes;
+  long suflen;
+
+  char *outfile;
+)
+
+static void do_split(int infd, char *in)
+{
+  unsigned long bytesleft, linesleft, filenum, len, pos;
+  int outfd = -1;
+  struct stat st;
+
+  // posix doesn't cover permissions on output file, so copy input (or 0777)
+  st.st_mode = 0777;
+  fstat(infd, &st);
+
+  len = pos = filenum = bytesleft = linesleft = 0;
+  for (;;) {
+    int i, j;
+
+    // Refill toybuf?
+    if (len == pos) {
+      if (!(len = xread(infd, toybuf, sizeof(toybuf)))) break;
+      pos = 0;
+    }
+
+    // Start new output file?
+    if ((TT.bytes && !bytesleft) || (TT.lines && !linesleft)) {
+      char *s = TT.outfile + strlen(TT.outfile);
+
+      j = filenum++;
+      for (i = 0; i<TT.suflen; i++) {
+        *(--s) = 'a'+(j%26);
+        j /= 26;
+      }
+      if (j) error_exit("bad suffix");
+      bytesleft = TT.bytes;
+      linesleft = TT.lines;
+      if (outfd != -1) close(outfd);
+      outfd = xcreate(TT.outfile, O_RDWR|O_CREAT|O_TRUNC, st.st_mode & 0777);
+    }
+
+    // Write next chunk of output.
+    if (TT.lines) {
+      for (i = pos; i < len; ) {
+        if (toybuf[i++] == '\n' && !--linesleft) break;
+        if (!--bytesleft) break;
+      }
+      j = i - pos;
+    } else {
+      j = len - pos;
+      if (j > bytesleft) j = bytesleft;
+      bytesleft -= j;
+    }
+    xwrite(outfd, toybuf+pos, j);
+    pos += j;
+  }
+
+  if (CFG_TOYBOX_FREE) {
+    if (outfd != -1) close(outfd);
+    if (infd) close(infd);
+    free(TT.outfile);
+  }
+  xexit();
+}
+
+void split_main(void)
+{
+  if (!TT.bytes && !TT.lines) TT.lines = 1000;
+
+  // Allocate template for output filenames
+  TT.outfile = xmprintf("%s%*c", (toys.optc == 2) ? toys.optargs[1] : "x",
+    (int)TT.suflen, ' ');
+
+  // We only ever use one input, but this handles '-' or no input for us.
+  loopfiles(toys.optargs, do_split);
+}
diff --git a/toybox/toys/posix/strings.c b/toybox/toys/posix/strings.c
new file mode 100644
index 0000000..f3ce70c
--- /dev/null
+++ b/toybox/toys/posix/strings.c
@@ -0,0 +1,67 @@
+/*strings.c - print the strings of printable characters in files.
+ *
+ * Copyright 2014 Kyung-su Kim <kaspyx@gmail.com>
+ * Copyright 2014 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+ * TODO: utf8 strings
+ * TODO: posix -t
+
+USE_STRINGS(NEWTOY(strings, "an#=4<1fo", TOYFLAG_USR|TOYFLAG_BIN))
+
+config STRINGS
+  bool "strings"
+  default y
+  help
+    usage: strings [-fo] [-n LEN] [FILE...]
+
+    Display printable strings in a binary file
+
+    -f	Precede strings with filenames
+    -n	At least LEN characters form a string (default 4)
+    -o	Precede strings with decimal offsets
+*/
+
+#define FOR_strings
+#include "toys.h"
+
+GLOBALS(
+  long num;
+)
+
+static void do_strings(int fd, char *filename)
+{
+  int nread, i, wlen = TT.num, count = 0;
+  off_t offset = 0;
+  char *string = xzalloc(wlen + 1);
+
+  for (;;) {
+    nread = read(fd, toybuf, sizeof(toybuf));
+    if (nread < 0) perror_msg_raw(filename);
+    if (nread < 1) break;
+    for (i = 0; i < nread; i++, offset++) {
+      if (((toybuf[i] >= 32) && (toybuf[i] <= 126)) || (toybuf[i] == '\t')) {
+        if (count == wlen) fputc(toybuf[i], stdout);
+        else {
+          string[count++] = toybuf[i];
+          if (count == wlen) {
+            if (toys.optflags & FLAG_f) printf("%s: ", filename);
+            if (toys.optflags & FLAG_o)
+              printf("%7lld ",(long long)(offset - wlen));
+            printf("%s", string);
+          }
+        }
+      } else {
+        if (count == wlen) xputc('\n');
+        count = 0;
+      }
+    }
+  }
+  xclose(fd);
+  free(string);
+}
+
+void strings_main(void)
+{
+  loopfiles(toys.optargs, do_strings);
+}
diff --git a/toybox/toys/posix/tail.c b/toybox/toys/posix/tail.c
new file mode 100644
index 0000000..787e116
--- /dev/null
+++ b/toybox/toys/posix/tail.c
@@ -0,0 +1,270 @@
+/* tail.c - copy last lines from input to stdout.
+ *
+ * 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))
+
+config TAIL
+  bool "tail"
+  default y
+  help
+    usage: tail [-n|c NUMBER] [-f] [FILE...]
+
+    Copy last lines from files to stdout. If no files listed, copy from
+    stdin. Filename "-" is a synonym for stdin.
+
+    -n	output the last NUMBER lines (default 10), +X counts from start.
+    -c	output the last NUMBER bytes, +NUMBER counts from start
+    -f	follow FILE(s), waiting for more data to be appended
+
+config TAIL_SEEK
+  bool "tail seek support"
+  default y
+  depends on TAIL
+  help
+    This version uses lseek, which is faster on large files.
+*/
+
+#define FOR_tail
+#include "toys.h"
+#include <sys/inotify.h>
+
+GLOBALS(
+  long lines;
+  long bytes;
+
+  int file_no, ffd, *files;
+)
+
+struct line_list {
+  struct line_list *next, *prev;
+  char *data;
+  int len;
+};
+
+static struct line_list *get_chunk(int fd, int len)
+{
+  struct line_list *line = xmalloc(sizeof(struct line_list)+len);
+
+  memset(line, 0, sizeof(struct line_list));
+  line->data = ((char *)line) + sizeof(struct line_list);
+  line->len = readall(fd, line->data, len);
+
+  if (line->len < 1) {
+    free(line);
+    return 0;
+  }
+
+  return line;
+}
+
+static void dump_chunk(void *ptr)
+{
+  struct line_list *list = ptr;
+
+  xwrite(1, list->data, list->len);
+  free(list);
+}
+
+// Reading through very large files is slow.  Using lseek can speed things
+// up a lot, but isn't applicable to all input (cat | tail).
+// Note: bytes and lines are negative here.
+static int try_lseek(int fd, long bytes, long lines)
+{
+  struct line_list *list = 0, *temp;
+  int flag = 0, chunk = sizeof(toybuf);
+  off_t pos = lseek(fd, 0, SEEK_END);
+
+  // If lseek() doesn't work on this stream, return now.
+  if (pos<0) return 0;
+
+  // Seek to the right spot, output data from there.
+  if (bytes) {
+    if (lseek(fd, bytes, SEEK_END)<0) lseek(fd, 0, SEEK_SET);
+    xsendfile(fd, 1);
+    return 1;
+  }
+
+  // Read from end to find enough lines, then output them.
+
+  bytes = pos;
+  while (lines && pos) {
+    int offset;
+
+    // Read in next chunk from end of file
+    if (chunk>pos) chunk = pos;
+    pos -= chunk;
+    if (pos != lseek(fd, pos, SEEK_SET)) {
+      perror_msg("seek failed");
+      break;
+    }
+    if (!(temp = get_chunk(fd, chunk))) break;
+    temp->next = list;
+    list = temp;
+
+    // Count newlines in this chunk.
+    offset = list->len;
+    while (offset--) {
+      // If the last line ends with a newline, that one doesn't count.
+      if (!flag) flag++;
+
+      // Start outputting data right after newline
+      else if (list->data[offset] == '\n' && !++lines) {
+        offset++;
+        list->data += offset;
+        list->len -= offset;
+
+        break;
+      }
+    }
+  }
+
+  // Output stored data
+  llist_traverse(list, dump_chunk);
+
+  // In case of -f
+  lseek(fd, bytes, SEEK_SET);
+  return 1;
+}
+
+// Called for each file listed on command line, and/or stdin
+static void do_tail(int fd, char *name)
+{
+  long bytes = TT.bytes, lines = TT.lines;
+  int linepop = 1;
+
+  if (toys.optflags & FLAG_f) {
+    int f = TT.file_no*2;
+    char *s = name;
+
+    if (!fd) sprintf(s = toybuf, "/proc/self/fd/%d", fd);
+    TT.files[f++] = fd;
+    if (0 > (TT.files[f] = inotify_add_watch(TT.ffd, s, IN_MODIFY)))
+      perror_msg("bad -f on '%s'", 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 (bytes<0 || lines<0) {
+    struct line_list *list = 0, *new;
+
+    // The slow codepath is always needed, and can handle all input,
+    // so make lseek support optional.
+    if (CFG_TAIL_SEEK && try_lseek(fd, bytes, lines)) return;
+
+    // Read data until we run out, keep a trailing buffer
+    for (;;) {
+      // Read next page of data, appending to linked list in order
+      if (!(new = get_chunk(fd, sizeof(toybuf)))) break;
+      dlist_add_nomalloc((void *)&list, (void *)new);
+
+      // If tracing bytes, add until we have enough, discarding overflow.
+      if (TT.bytes) {
+        bytes += new->len;
+        if (bytes > 0) {
+          while (list->len <= bytes) {
+            bytes -= list->len;
+            free(dlist_pop(&list));
+          }
+          list->data += bytes;
+          list->len -= bytes;
+          bytes = 0;
+        }
+      } else {
+        int len = new->len, count;
+        char *try = new->data;
+
+        // First character _after_ a newline starts a new line, which
+        // works even if file doesn't end with a newline
+        for (count=0; count<len; count++) {
+          if (linepop) lines++;
+          linepop = try[count] == '\n';
+
+          if (lines > 0) {
+            char c;
+
+            do {
+              c = *list->data;
+              if (!--(list->len)) free(dlist_pop(&list));
+              else list->data++;
+            } while (c != '\n');
+            lines--;
+          }
+        }
+      }
+    }
+
+    // Output/free the buffer.
+    llist_traverse(list, dump_chunk);
+
+  // Measuring from the beginning of the file.
+  } else for (;;) {
+    int len, offset = 0;
+
+    // Error while reading does not exit.  Error writing does.
+    len = read(fd, toybuf, sizeof(toybuf));
+    if (len<1) break;
+    while (bytes > 1 || lines > 1) {
+      bytes--;
+      if (toybuf[offset++] == '\n') lines--;
+      if (offset >= len) break;
+    }
+    if (offset<len) xwrite(1, toybuf+offset, len-offset);
+  }
+}
+
+void tail_main(void)
+{
+  char **args = toys.optargs;
+
+  if (!(toys.optflags&(FLAG_n|FLAG_c))) {
+    char *arg = *args;
+
+    // handle old "-42" style arguments
+    if (arg && *arg == '-' && arg[1]) {
+      TT.lines = atolx(*(args++));
+      toys.optc--;
+    } else {
+      // if nothing specified, default -n to -10
+      TT.lines = -10;
+    }
+  }
+
+  // Allocate 2 ints per optarg for -f
+  if (toys.optflags&FLAG_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);
+
+  if ((toys.optflags & FLAG_f) && TT.file_no) {
+    int len, last_fd = TT.files[(TT.file_no-1)*2], i, fd;
+    struct inotify_event ev;
+
+    for (;;) {
+      if (sizeof(ev)!=read(TT.ffd, &ev, sizeof(ev))) perror_exit("inotify");
+
+      for (i = 0; i<TT.file_no && ev.wd!=TT.files[(i*2)+1]; i++);
+      if (i==TT.file_no) continue;
+      fd = TT.files[i*2];
+
+      // Read new data.
+      while ((len = read(fd, toybuf, sizeof(toybuf)))>0) {
+        if (last_fd != fd) {
+          last_fd = fd;
+          xprintf("\n==> %s <==\n", args[i]);
+        }
+
+        xwrite(1, toybuf, len);
+      }
+    }
+  }
+}
diff --git a/toybox/toys/posix/tee.c b/toybox/toys/posix/tee.c
new file mode 100644
index 0000000..d5591b6
--- /dev/null
+++ b/toybox/toys/posix/tee.c
@@ -0,0 +1,71 @@
+/* tee.c - cat to multiple outputs.
+ *
+ * Copyright 2008 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/tee.html
+
+USE_TEE(NEWTOY(tee, "ia", TOYFLAG_USR|TOYFLAG_BIN))
+
+config TEE
+  bool "tee"
+  default y
+  help
+    usage: tee [-ai] [file...]
+
+    Copy stdin to each listed file, and also to stdout.
+    Filename "-" is a synonym for stdout.
+
+    -a	append to files.
+    -i	ignore SIGINT.
+*/
+
+#define FOR_tee
+#include "toys.h"
+
+GLOBALS(
+  void *outputs;
+)
+
+struct fd_list {
+  struct fd_list *next;
+  int fd;
+};
+
+// Open each output file, saving filehandles to a linked list.
+
+static void do_tee_open(int fd, char *name)
+{
+  struct fd_list *temp;
+
+  temp = xmalloc(sizeof(struct fd_list));
+  temp->next = TT.outputs;
+  temp->fd = fd;
+  TT.outputs = temp;
+}
+
+void tee_main(void)
+{
+  if (toys.optflags & FLAG_i) xsignal(SIGINT, SIG_IGN);
+
+  // Open output files
+  loopfiles_rw(toys.optargs,
+    O_RDWR|O_CREAT|((toys.optflags & FLAG_a)?O_APPEND:O_TRUNC),
+    0666, 0, do_tee_open);
+
+  for (;;) {
+    struct fd_list *fdl;
+    int len;
+
+    // Read data from stdin
+    len = xread(0, toybuf, sizeof(toybuf));
+    if (len<1) break;
+
+    // Write data to each output file, plus stdout.
+    fdl = TT.outputs;
+    for (;;) {
+      if(len != writeall(fdl ? fdl->fd : 1, toybuf, len)) toys.exitval=1;
+      if (!fdl) break;
+      fdl = fdl->next;
+    }
+  }
+}
diff --git a/toybox/toys/posix/time.c b/toybox/toys/posix/time.c
new file mode 100644
index 0000000..2151826
--- /dev/null
+++ b/toybox/toys/posix/time.c
@@ -0,0 +1,49 @@
+/* time.c - time a simple command
+ *
+ * Copyright 2013 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/time.html
+
+USE_TIME(NEWTOY(time, "<1^p", TOYFLAG_USR|TOYFLAG_BIN))
+
+config TIME
+  bool "time"
+  default y
+  depends on TOYBOX_FLOAT
+  help
+    usage: time [-p] COMMAND [ARGS...]
+
+    Run command line and report real, user, and system time elapsed in seconds.
+    (real = clock on the wall, user = cpu used by command's code,
+    system = cpu used by OS on behalf of command.)
+
+    -p	posix mode (ignored)
+*/
+
+#include "toys.h"
+
+void time_main(void)
+{
+  pid_t pid;
+  struct timeval tv, tv2;
+
+  gettimeofday(&tv, NULL);
+  if (!(pid = XVFORK())) xexec(toys.optargs);
+  else {
+    int stat;
+    struct rusage ru;
+    float r, u, s;
+
+    wait4(pid, &stat, 0, &ru);
+    gettimeofday(&tv2, NULL);
+    if (tv.tv_usec > tv2.tv_usec) {
+      tv2.tv_usec += 1000000;
+      tv2.tv_sec--;
+    }
+    r = (tv2.tv_sec-tv.tv_sec)+((tv2.tv_usec-tv.tv_usec)/1000000.0);
+    u = ru.ru_utime.tv_sec+(ru.ru_utime.tv_usec/1000000.0);
+    s = ru.ru_stime.tv_sec+(ru.ru_stime.tv_usec/1000000.0);
+    fprintf(stderr, "real %f\nuser %f\nsys %f\n", r, u, s);
+    toys.exitval = WIFEXITED(stat) ? WEXITSTATUS(stat) : WTERMSIG(stat);
+  }
+}
diff --git a/toybox/toys/posix/touch.c b/toybox/toys/posix/touch.c
new file mode 100644
index 0000000..cd7dd53
--- /dev/null
+++ b/toybox/toys/posix/touch.c
@@ -0,0 +1,129 @@
+/* touch.c : change timestamp of a file
+ *
+ * Copyright 2012 Choubey Ji <warior.linux@gmail.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/touch.html
+ *
+ * TODO: have another go at merging the -t and -d stanzas
+
+USE_TOUCH(NEWTOY(touch, "acd:mr:t:h[!dtr]", TOYFLAG_BIN))
+
+config TOUCH
+  bool "touch"
+  default y
+  help
+    usage: touch [-amch] [-d DATE] [-t TIME] [-r FILE] FILE...
+
+    Update the access and modification times of each FILE to the current time.
+
+    -a	change access time
+    -m	change modification time
+    -c	don't create file
+    -h	change symlink
+    -d	set time to DATE (in YYYY-MM-DDThh:mm:SS[.frac][tz] format)
+    -t	set time to TIME (in [[CC]YY]MMDDhhmm[.ss][frac] format)
+    -r	set time same as reference FILE
+*/
+
+#define FOR_touch
+#include "toys.h"
+
+GLOBALS(
+  char *time;
+  char *file;
+  char *date;
+)
+
+void touch_main(void)
+{
+  struct timespec ts[2];
+  char **ss;
+  int fd, i;
+
+  // use current time if no -t or -d
+  ts[0].tv_nsec = UTIME_NOW;
+  if (toys.optflags & (FLAG_t|FLAG_d)) {
+    char *s, *date;
+    struct tm tm;
+    int len = 0;
+
+    localtime_r(&(ts->tv_sec), &tm);
+
+    // Set time from -d?
+
+    if (toys.optflags & FLAG_d) {
+      date = TT.date;
+      i = strlen(date);
+      if (i) {
+        // Trailing Z means UTC timezone, don't expect libc to know this.
+        if (toupper(date[i-1])=='Z') {
+          date[i-1] = 0;
+          setenv("TZ", "UTC0", 1);
+          localtime_r(&(ts->tv_sec), &tm);
+        }
+        s = strptime(date, "%Y-%m-%dT%T", &tm);
+        ts->tv_nsec = 0;
+        if (s && *s=='.' && isdigit(s[1])) 
+          sscanf(s, ".%lu%n", &ts->tv_nsec, &len);
+        else len = 0;
+      } else s = 0;
+
+    // Set time from -t?
+
+    } else {
+      strcpy(toybuf, "%Y%m%d%H%M");
+      date = TT.time;
+      i = ((s = strchr(date, '.'))) ? s-date : strlen(date);
+      if (i < 8 || i%2) error_exit("bad '%s'", date);
+      for (i=0;i<3;i++) {
+        s = strptime(date, toybuf+(i&2), &tm);
+        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) {
+        if (sscanf(s += len, "%lu%n", &ts->tv_nsec, &len) == 1) {
+          s--;
+          len++;
+        } else len = 0;
+      } else len = 0;
+    }
+    if (len) {
+      s += len;
+      if (ts->tv_nsec > 999999999) s = 0;
+      else while (len++ < 10) ts->tv_nsec *= 10;
+    }
+
+    errno = 0;
+    ts->tv_sec = mktime(&tm);
+    if (!s || *s || ts->tv_sec == -1) perror_exit("bad '%s'", date);
+  }
+  ts[1]=ts[0];
+
+  // Set time from -r?
+
+  if (TT.file) {
+    struct stat st;
+
+    xstat(TT.file, &st);
+    ts[0] = st.st_atim;
+    ts[1] = st.st_mtim;
+  }
+
+  // Which time(s) should we actually change?
+  i = toys.optflags & (FLAG_a|FLAG_m);
+  if (i && i!=(FLAG_a|FLAG_m)) ts[i==FLAG_m].tv_nsec = UTIME_OMIT;
+
+  // Loop through files on command line
+  for (ss = toys.optargs; *ss;) {
+
+    // cheat: FLAG_h is rightmost flag, so its value is 1
+    if (!utimensat(AT_FDCWD, *ss, ts,
+        (toys.optflags & FLAG_h)*AT_SYMLINK_NOFOLLOW)) ss++;
+    else if (toys.optflags & FLAG_c) ss++;
+    else if (access(*ss, F_OK) && (-1!=(fd = open(*ss, O_CREAT, 0666))))
+      close(fd);
+    else perror_msg("'%s'", *ss++);
+  }
+}
diff --git a/toybox/toys/posix/true.c b/toybox/toys/posix/true.c
new file mode 100644
index 0000000..2543b82
--- /dev/null
+++ b/toybox/toys/posix/true.c
@@ -0,0 +1,22 @@
+/* true.c - Return zero.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/true.html
+
+USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
+USE_TRUE(OLDTOY(:, true, TOYFLAG_NOFORK|TOYFLAG_NOHELP))
+
+config TRUE
+  bool "true"
+  default y
+  help
+    Return zero.
+*/
+
+#include "toys.h"
+
+void true_main(void)
+{
+  return;
+}
diff --git a/toybox/toys/posix/tty.c b/toybox/toys/posix/tty.c
new file mode 100644
index 0000000..1694d84
--- /dev/null
+++ b/toybox/toys/posix/tty.c
@@ -0,0 +1,32 @@
+/* tty.c - Show stdin's terminal name
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/tty.html
+
+USE_TTY(NEWTOY(tty, "s", TOYFLAG_USR|TOYFLAG_BIN))
+
+config TTY
+  bool "tty"
+  default y
+  help
+    usage: tty [-s]
+
+    Show filename of terminal connected to stdin.
+
+    Prints "not a tty" and exits with nonzero status if no terminal
+    is connected to stdin.
+
+    -s	silent, exit code only
+*/
+
+#include "toys.h"
+
+void tty_main(void)
+{
+  char *tty = ttyname(0);
+
+  if (!toys.optflags) puts(tty ? tty : "not a tty");
+
+  toys.exitval = !tty;
+}
diff --git a/toybox/toys/posix/ulimit.c b/toybox/toys/posix/ulimit.c
new file mode 100644
index 0000000..0aedd2c
--- /dev/null
+++ b/toybox/toys/posix/ulimit.c
@@ -0,0 +1,117 @@
+/* ulimit.c - Modify resource limits
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ulimit.html
+ * And man prlimit(2).
+ *
+ * Deviations from posix: The units on -f are supposed to be 512 byte
+ * "blocks" (no other options are specified, and even hard drives don't
+ * do that anymore). Bash uses 1024 byte blocks, so they don't care either.
+ * We consistently use bytes everywhere we can.
+ *
+ * Deviations from bash: Sizes are in bytes (instead of -p 512 and -f 1024).
+ * Bash's -p value has been wrong since 2010 (git 35f3d14dbbc5).
+ * The kernel implementation of RLIMIT_LOCKS (-x) was removed from Linux in
+ * 2003. Bash never implemented -b (it's in the help but unrecognized at
+ * runtime). We support -P to affect processes other than us.
+
+USE_ULIMIT(NEWTOY(ulimit, ">1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config ULIMIT
+  bool "ulimit"
+  default y
+  depends on TOYBOX_PRLIMIT
+  help
+    usage: ulimit [-P PID] [-SHRacdefilmnpqrstuv] [LIMIT]
+
+    Print or set resource limits for process number PID. If no LIMIT specified
+    (or read-only -ap selected) display current value (sizes in bytes).
+    Default is ulimit -P $PPID -Sf" (show soft filesize of your shell).
+    
+    -S  Set/show soft limit          -H  Set/show hard (maximum) limit
+    -a  Show all limits              -c  Core file size
+    -d  Process data segment         -e  Max scheduling priority
+    -f  Output file size             -i  Pending signal count
+    -l  Locked memory                -m  Resident Set Size
+    -n  Number of open files         -p  Pipe buffer
+    -q  Posix message queue          -r  Max Real-time priority
+    -R  Realtime latency (usec)      -s  Stack size
+    -t  Total CPU time (in seconds)  -u  Maximum processes (under this UID)
+    -v  Virtual memory size          -P  PID to affect (default $PPID)
+*/
+
+#define FOR_ulimit
+#include "toys.h"
+
+GLOBALS(
+  long pid;
+)
+
+// This is a linux kernel syscall added in 2.6.36 (git c022a0acad53) which
+// glibc only exports a wrapper prototype for if you #define _FSF_HURD_RULZE.
+int prlimit(pid_t pid, int resource, const struct rlimit *new_limit,
+  struct rlimit *old_limit);
+
+// I'd like to sort the RLIMIT values 0-15, but mips, alpha and sparc
+// override the asm-generic values for 5-9. Also, the kernel implementation
+// of RLIMIT_LOCKS (-x) was removed from Linux in 2003.
+void ulimit_main(void)
+{
+  struct rlimit rr;
+  int i;
+  // Order is cdefilmnqRrstuv
+  char map[] = {RLIMIT_CORE, RLIMIT_DATA, RLIMIT_NICE, RLIMIT_FSIZE,
+                RLIMIT_SIGPENDING, RLIMIT_MEMLOCK, RLIMIT_RSS, RLIMIT_NOFILE, 0,
+                RLIMIT_MSGQUEUE, RLIMIT_RTTIME, RLIMIT_RTPRIO, RLIMIT_STACK,
+                RLIMIT_CPU, RLIMIT_NPROC, RLIMIT_AS};
+
+  if (!(toys.optflags&(FLAG_H-1))) toys.optflags |= FLAG_f;
+  if ((toys.optflags&(FLAG_a|FLAG_p)) && toys.optc) error_exit("can't set -ap");
+
+  // Fetch data
+  if (!(toys.optflags&FLAG_P)) TT.pid = getppid();
+
+  for (i=0; i<sizeof(map); i++) {
+    char *flags="cdefilmnpqRrstuv";
+
+    int get = toys.optflags&(FLAG_a|(1<<i));
+
+    if (get && prlimit(TT.pid, map[i], 0, &rr)) perror_exit("-%c", flags[i]);
+    if (!toys.optc) {
+      if (toys.optflags&FLAG_a) printf("-%c: ", flags[i]);
+      if (get) {
+        if ((1<<i)&FLAG_p) {
+          if (toys.optflags&FLAG_H)
+            xreadfile("/proc/sys/fs/pipe-max-size", toybuf, sizeof(toybuf));
+          else {
+            int pp[2];
+
+            xpipe(pp);
+            sprintf(toybuf, "%d\n", fcntl(*pp, F_GETPIPE_SZ));
+          }
+          printf("%s", toybuf);
+        } else {
+          rlim_t rl = (toys.optflags&FLAG_H) ? rr.rlim_max : rr.rlim_cur;
+
+          if (rl == RLIM_INFINITY) printf("unlimited\n");
+          else printf("%ld\n", (long)rl);
+        }
+      }
+    }
+    if (toys.optflags&(1<<i)) break;
+  }
+
+  if (toys.optflags&(FLAG_a|FLAG_p)) return;
+
+  if (toys.optc) {
+    rlim_t val;
+
+    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;
+    else rr.rlim_cur = val;
+    if (prlimit(TT.pid, map[i], &rr, 0)) perror_exit(0);
+  }
+}
diff --git a/toybox/toys/posix/uname.c b/toybox/toys/posix/uname.c
new file mode 100644
index 0000000..2e17d38
--- /dev/null
+++ b/toybox/toys/posix/uname.c
@@ -0,0 +1,73 @@
+/* uname.c - return system name
+ *
+ * Copyright 2008 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/uname.html
+
+USE_UNAME(NEWTOY(uname, "oamvrns[+os]", TOYFLAG_BIN))
+
+config UNAME
+  bool "uname"
+  default y
+  help
+    usage: uname [-asnrvm]
+
+    Print system information.
+
+    -s	System name
+    -n	Network (domain) name
+    -r	Kernel Release number
+    -v	Kernel Version 
+    -m	Machine (hardware) name
+    -a	All of the above
+*/
+
+#define FOR_uname
+#include "toys.h"
+
+// If a 32 bit x86 build environment working in a chroot under an x86-64
+// kernel returns x86_64 for -m it confuses ./configure.  Special case it.
+
+#if defined(__i686__)
+#define GROSS "i686"
+#elif defined(__i586__)
+#define GROSS "i586"
+#elif defined(__i486__)
+#define GROSS "i486"
+#elif defined(__i386__)
+#define GROSS "i386"
+#endif
+
+void uname_main(void)
+{
+  int i, flags = toys.optflags, needspace=0;
+
+  uname((void *)toybuf);
+
+  if (!flags) flags = FLAG_s;
+  for (i=0; i<5; i++) {
+    char *c = toybuf+(65*i);
+
+    if (flags & ((1<<i)|FLAG_a)) {
+      int len = strlen(c);
+
+      // This problem originates in autoconf, so of course the solution
+      // is horribly ugly.
+#ifdef GROSS
+      if (i==4 && !strcmp(c,"x86_64")) {
+        printf(GROSS);
+        continue;
+      }
+#endif
+
+      if (needspace++) {
+        // We can't decrement on the first entry, because
+        // needspace would be 0
+        *(--c)=' ';
+        len++;
+      }
+      xwrite(1, c, len);
+    }
+  }
+  putchar('\n');
+}
diff --git a/toybox/toys/posix/uniq.c b/toybox/toys/posix/uniq.c
new file mode 100644
index 0000000..c127cfe
--- /dev/null
+++ b/toybox/toys/posix/uniq.c
@@ -0,0 +1,121 @@
+/* uniq.c - report or filter out repeated lines in a file
+ *
+ * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/uniq.html
+
+USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_USR|TOYFLAG_BIN))
+
+config UNIQ
+  bool "uniq"
+  default y
+  help
+    usage: uniq [-cduiz] [-w maxchars] [-f fields] [-s char] [input_file [output_file]]
+
+    Report or filter out repeated lines in a file
+
+    -c	show counts before each line
+    -d	show only lines that are repeated
+    -u	show only lines that are unique
+    -i	ignore case when comparing lines
+    -z	lines end with \0 not \n
+    -w	compare maximum X chars per line
+    -f	ignore first X fields
+    -s	ignore first X chars
+*/
+
+#define FOR_uniq
+#include "toys.h"
+
+GLOBALS(
+  long maxchars;
+  long nchars;
+  long nfields;
+  long repeats;
+)
+
+static char *skip(char *str)
+{
+  long nchars = TT.nchars, nfields;
+
+  // Skip fields first
+  for (nfields = TT.nfields; nfields; str++) {
+    while (*str && isspace(*str)) str++;
+    while (*str && !isspace(*str)) str++;
+    nfields--;
+  }
+  // Skip chars
+  while (*str && nchars--) str++;
+
+  return str;
+}
+
+static void print_line(FILE *f, char *line)
+{
+  if (toys.optflags & (TT.repeats ? FLAG_u : FLAG_d)) return;
+  if (toys.optflags & FLAG_c) fprintf(f, "%7lu ", TT.repeats + 1);
+  fputs(line, f);
+  if (toys.optflags & FLAG_z) fputc(0, f);
+}
+
+void uniq_main(void)
+{
+  FILE *infile = stdin, *outfile = stdout;
+  char *thisline = NULL, *prevline = NULL, *tmpline, eol = '\n';
+  size_t thissize, prevsize = 0, tmpsize;
+
+  if (toys.optc >= 1) infile = xfopen(toys.optargs[0], "r");
+  if (toys.optc >= 2) outfile = xfopen(toys.optargs[1], "w");
+
+  if (toys.optflags & FLAG_z) eol = 0;
+
+  // If first line can't be read
+  if (getdelim(&prevline, &prevsize, eol, infile) < 0)
+    return;
+
+  while (getdelim(&thisline, &thissize, eol, infile) > 0) {
+    int diff;
+    char *t1, *t2;
+
+    // If requested get the chosen fields + character offsets.
+    if (TT.nfields || TT.nchars) {
+      t1 = skip(thisline);
+      t2 = skip(prevline);
+    } else {
+      t1 = thisline;
+      t2 = prevline;
+    }
+
+    if (TT.maxchars == 0) {
+      diff = !(toys.optflags & FLAG_i) ? strcmp(t1, t2) : strcasecmp(t1, t2);
+    } else {
+      diff = !(toys.optflags & FLAG_i) ? strncmp(t1, t2, TT.maxchars)
+              : strncasecmp(t1, t2, TT.maxchars);
+    }
+
+    if (diff == 0) { // same
+      TT.repeats++;
+    } else {
+      print_line(outfile, prevline);
+
+      TT.repeats = 0;
+
+      tmpline = prevline;
+      prevline = thisline;
+      thisline = tmpline;
+
+      tmpsize = prevsize;
+      prevsize = thissize;
+      thissize = tmpsize;
+    }
+  }
+
+  print_line(outfile, prevline);
+
+  if (CFG_TOYBOX_FREE) {
+    if (outfile != stdout) fclose(outfile);
+    if (infile != stdin) fclose(infile);
+    free(prevline);
+    free(thisline);
+  }
+}
diff --git a/toybox/toys/posix/unlink.c b/toybox/toys/posix/unlink.c
new file mode 100644
index 0000000..4faef9d
--- /dev/null
+++ b/toybox/toys/posix/unlink.c
@@ -0,0 +1,24 @@
+/* unlink.c - delete one file
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/unlink.html
+
+USE_UNLINK(NEWTOY(unlink, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
+
+config UNLINK
+  bool "unlink"
+  default y
+  help
+    usage: unlink FILE
+
+    Deletes one file.
+*/
+
+#include "toys.h"
+
+void unlink_main(void)
+{
+  if (unlink(*toys.optargs))
+    perror_exit("Couldn't unlink `%s'", *toys.optargs);
+}
diff --git a/toybox/toys/posix/uudecode.c b/toybox/toys/posix/uudecode.c
new file mode 100644
index 0000000..238e27e
--- /dev/null
+++ b/toybox/toys/posix/uudecode.c
@@ -0,0 +1,107 @@
+/* uudecode.c - uudecode / base64 decode
+ *
+ * Copyright 2013 Erich Plondke <toybox@erich.wreck.org>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/uudecode.html
+
+USE_UUDECODE(NEWTOY(uudecode, ">1o:", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK))
+
+config UUDECODE
+  bool "uudecode"
+  default y
+  help
+    usage: uudecode [-o OUTFILE] [INFILE]
+
+    Decode file from stdin (or INFILE).
+
+    -o	write to OUTFILE instead of filename in header
+*/
+
+#define FOR_uudecode
+#include "toys.h"
+
+GLOBALS(
+  char *o;
+)
+
+void uudecode_main(void)
+{
+  int ifd = 0, ofd, idx = 0, m = m;
+  char *line = 0, mode[16],
+       *class[] = {"begin%*[ ]%15s%*[ ]%n", "begin-base64%*[ ]%15s%*[ ]%n"};
+
+  if (toys.optc) ifd = xopenro(*toys.optargs);
+
+  while (!idx) {
+    free(line);
+    if (!(line = get_line(ifd))) error_exit("bad EOF");
+    for (m=0; m < 2; m++) {
+      sscanf(line, class[m], mode, &idx);
+      if (idx) break;
+    }
+  }
+
+  ofd = xcreate(TT.o ? TT.o : line+idx, O_WRONLY|O_CREAT|O_TRUNC,
+    string_to_mode(mode, 0777^toys.old_umask));
+
+  for(;;) {
+    char *in, *out;
+    int olen;
+
+    free(line);
+    if (m == 2 || !(line = get_line(ifd))) break;
+    if (!strcmp(line, m ? "====" : "end")) {
+      m = 2;
+      continue;
+    }
+
+    olen = 0;
+    in = out = line;
+    if (!m) olen = (*(in++) - 32) & 0x3f;
+
+    for (;;) {
+      int i = 0, x = 0, len = 4;
+      char c = 0;
+
+      if (!m) {
+        if (olen < 1) break;
+        if (olen < 3) len = olen + 1;
+      }
+
+      while (i < len) {
+        if (!(c = *(in++))) goto line_done;
+
+        if (m) {
+          if (c == '=') {
+            len--;
+            continue;
+          } else if (len != 4) break;
+
+          if (c >= 'A' && c <= 'Z') c -= 'A';
+          else if (c >= 'a' && c <= 'z') c += 26 - 'a';
+          else if (c >= '0' && c <= '9') c += 52 - '0';
+          else if (c == '+') c = 62;
+          else if (c == '/') c = 63;
+          else continue;
+        } else c = (c - 32) & 0x3f;
+
+        x |= c << (6*(3-i));
+
+        if (i && i < len) {
+          *(out++) = (x>>(8*(3-i))) & 0xff;
+          olen--;
+        }
+        i++;
+      }
+
+      if (i && i!=len) error_exit("bad %s", line);
+    }
+line_done:
+    xwrite(ofd, line, out-line);
+  }
+
+  if (CFG_TOYBOX_FREE) {
+    if (ifd) close(ifd);
+    close(ofd);
+  }
+}
diff --git a/toybox/toys/posix/uuencode.c b/toybox/toys/posix/uuencode.c
new file mode 100644
index 0000000..06709d5
--- /dev/null
+++ b/toybox/toys/posix/uuencode.c
@@ -0,0 +1,58 @@
+/* uuencode.c - uuencode / base64 encode
+ *
+ * Copyright 2013 Erich Plondke <toybox@erich.wreck.org>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/uuencode.html
+
+USE_UUENCODE(NEWTOY(uuencode, "<1>2m", TOYFLAG_USR|TOYFLAG_BIN))
+
+config UUENCODE
+  bool "uuencode"
+  default y 
+  help
+    usage: uuencode [-m] [file] encode-filename
+
+    Uuencode stdin (or file) to stdout, with encode-filename in the output.
+
+    -m	base64-encode
+*/
+
+#define FOR_uuencode
+#include "toys.h"
+
+void uuencode_main(void)
+{
+  char *name = toys.optargs[toys.optc-1], buf[(76/4)*3];
+
+  int i, m = toys.optflags & FLAG_m, fd = 0;
+
+  if (toys.optc > 1) fd = xopenro(toys.optargs[0]);
+
+  base64_init(toybuf);
+
+  xprintf("begin%s 744 %s\n", m ? "-base64" : "", name);
+  for (;;) {
+    char *in;
+
+    if (!(i = xread(fd, buf, m ? sizeof(buf) : 45))) break;
+
+    if (!m) xputc(i+32);
+    in = buf;
+
+    for (in = buf; in-buf < i; ) {
+      int j, x, bytes = i - (in-buf);
+
+      if (bytes > 3) bytes = 3;
+
+      for (j = x = 0; j<4; j++) {
+        int out;
+
+        if (j < bytes) x |= (*(in++) & 0x0ff) << (8*(2-j));
+        out = (x>>((3-j)*6)) & 0x3f;
+        xputc(m ? (j > bytes ? '=' : toybuf[out]) : (out ? out + 0x20 : 0x60));
+      } 
+    }
+    xputc('\n');
+  }
+  xputs(m ? "====" : "end");
+}
diff --git a/toybox/toys/posix/wc.c b/toybox/toys/posix/wc.c
new file mode 100644
index 0000000..a8c3e45
--- /dev/null
+++ b/toybox/toys/posix/wc.c
@@ -0,0 +1,111 @@
+/* wc.c - Word count
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/wc.html
+
+USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+
+config WC
+  bool "wc"
+  default y
+  help
+    usage: wc -lwcm [FILE...]
+
+    Count lines, words, and characters in input.
+
+    -l	show lines
+    -w	show words
+    -c	show bytes
+    -m	show characters
+
+    By default outputs lines, words, bytes, and filename for each
+    argument (or from stdin if none). Displays only either bytes
+    or characters.
+*/
+
+#define FOR_wc
+#include "toys.h"
+
+GLOBALS(
+  unsigned long totals[4];
+)
+
+static void show_lengths(unsigned long *lengths, char *name)
+{
+  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) printf(" %s", name);
+  xputc('\n');
+}
+
+static void do_wc(int fd, char *name)
+{
+  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) {
+      lengths[2] = st.st_size;
+      goto show;
+    }
+  }
+
+  for (;;) {
+    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);
+        }
+      } else space = isspace(toybuf[pos]);
+
+      if (space) word=0;
+      else {
+        if (!word) lengths[1]++;
+        word=1;
+      }
+    }
+    if (done) break;
+    if (pos != len) memmove(toybuf, toybuf+pos, len-pos);
+    len -= pos;
+  }
+
+show:
+  show_lengths(lengths, name);
+}
+
+void wc_main(void)
+{
+  if (!toys.optflags) toys.optflags = FLAG_l|FLAG_w|FLAG_c;
+  loopfiles(toys.optargs, do_wc);
+  if (toys.optc>1) show_lengths(TT.totals, "total");
+}
diff --git a/toybox/toys/posix/who.c b/toybox/toys/posix/who.c
new file mode 100644
index 0000000..414cdfc
--- /dev/null
+++ b/toybox/toys/posix/who.c
@@ -0,0 +1,48 @@
+/* who.c - display who is on the system
+ *
+ * Copyright 2012 ProFUSION Embedded Systems
+ *
+ * by Luis Felipe Strano Moraes <lfelipe@profusion.mobi>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/who.html
+ *
+ * Posix says to support many options (-abdHlmpqrstTu) but this
+ * isn't aimed at minicomputers with modem pools.
+
+USE_WHO(NEWTOY(who, "a", TOYFLAG_USR|TOYFLAG_BIN))
+
+config WHO
+  bool "who"
+  default y
+  depends on TOYBOX_UTMPX
+  help
+    usage: who
+
+    Print logged user information on system
+*/
+
+#define FOR_who
+#include "toys.h"
+
+void who_main(void)
+{
+  struct utmpx *entry;
+
+  setutxent();
+
+  while ((entry = getutxent())) {
+    if ((toys.optflags & FLAG_a) || entry->ut_type == USER_PROCESS) {
+      time_t time;
+      int time_size;
+      char *times;
+
+      time = entry->ut_tv.tv_sec;
+      times = ctime(&time);
+      time_size = strlen(times) - 2;
+      printf("%s\t%s\t%*.*s\t(%s)\n", entry->ut_user, entry->ut_line,
+        time_size, time_size, ctime(&time), entry->ut_host);
+    }
+  }
+
+  endutxent();
+}
diff --git a/toybox/toys/posix/xargs.c b/toybox/toys/posix/xargs.c
new file mode 100644
index 0000000..b4cb80a
--- /dev/null
+++ b/toybox/toys/posix/xargs.c
@@ -0,0 +1,190 @@
+/* xargs.c - Run command with arguments taken from stdin.
+ *
+ * Copyright 2011 Rob Landley <rob@landley.net>
+ *
+ * See http://opengroup.org/onlinepubs/9699919799/utilities/xargs.html
+ *
+ * TODO: Rich's whitespace objection, env size isn't fixed anymore.
+
+USE_XARGS(NEWTOY(xargs, "^I:E:L#ptxrn#<1s#0", TOYFLAG_USR|TOYFLAG_BIN))
+
+config XARGS
+  bool "xargs"
+  default y
+  help
+    usage: xargs [-ptxr0] [-s NUM] [-n NUM] [-L NUM] [-E STR] COMMAND...
+
+    Run command line one or more times, appending arguments from stdin.
+
+    If command exits with 255, don't launch another even if arguments remain.
+
+    -s	Size in bytes per command line
+    -n	Max number of arguments per command
+    -0	Each argument is NULL terminated, no whitespace or quote processing
+    #-p	Prompt for y/n from tty before running each command
+    #-t	Trace, print command line to stderr
+    #-x	Exit if can't fit everything in one command
+    #-r	Don't run command with empty input
+    #-L	Max number of lines of input per command
+    -E	stop at line matching string
+
+config XARGS_PEDANTIC
+  bool "TODO xargs pedantic posix compatability"
+  default n
+  depends on XARGS
+  help
+    This version supports insane posix whitespace handling rendered obsolete
+    by -0 mode.
+*/
+
+#define FOR_xargs
+#include "toys.h"
+
+GLOBALS(
+  long max_bytes;
+  long max_entries;
+  long L;
+  char *eofstr;
+  char *I;
+
+  long entries, bytes;
+  char delim;
+)
+
+// If out==NULL count TT.bytes and TT.entries, stopping at max.
+// Otherwise, fill out out[]
+
+// Returning NULL means need more data.
+// Returning char * means hit data limits, start of data left over
+// Returning 1 means hit data limits, but consumed all data
+// Returning 2 means hit -E eofstr
+
+static char *handle_entries(char *data, char **entry)
+{
+  if (TT.delim) {
+    char *s = data;
+
+    // Chop up whitespace delimited string into args
+    while (*s) {
+      char *save;
+
+      while (isspace(*s)) {
+        if (entry) *s = 0;
+        s++;
+      }
+
+      if (TT.max_entries && TT.entries >= TT.max_entries)
+        return *s ? s : (char *)1;
+
+      if (!*s) break;
+      save = s;
+
+      for (;;) {
+        if (++TT.bytes >= TT.max_bytes && TT.max_bytes) return save;
+        if (!*s || isspace(*s)) break;
+        s++;
+      }
+      if (TT.eofstr) {
+        int len = s-save;
+        if (len == strlen(TT.eofstr) && !strncmp(save, TT.eofstr, len))
+          return (char *)2;
+      }
+      if (entry) entry[TT.entries] = save;
+      ++TT.entries;
+    }
+
+  // -0 support
+  } else {
+    TT.bytes += strlen(data)+1;
+    if (TT.max_bytes && TT.bytes >= TT.max_bytes) return data;
+    if (TT.max_entries && TT.entries >= TT.max_entries)
+      return (char *)1;
+    if (entry) entry[TT.entries] = data;
+    TT.entries++;
+  }
+
+  return NULL;
+}
+
+void xargs_main(void)
+{
+  struct double_list *dlist = NULL, *dtemp;
+  int entries, bytes, done = 0, status;
+  char *data = NULL, **out;
+  pid_t pid;
+
+  if (!(toys.optflags & FLAG_0)) TT.delim = '\n';
+
+  // If no optargs, call echo.
+  if (!toys.optc) {
+    free(toys.optargs);
+    *(toys.optargs = xzalloc(2*sizeof(char *)))="echo";
+    toys.optc = 1;
+  }
+
+  for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++)
+    bytes += strlen(toys.optargs[entries]);
+
+  // Loop through exec chunks.
+  while (data || !done) {
+    TT.entries = 0;
+    TT.bytes = bytes;
+
+    // Loop reading input
+    for (;;) {
+
+      // Read line
+      if (!data) {
+        ssize_t l = 0;
+        l = getdelim(&data, (size_t *)&l, TT.delim, stdin);
+
+        if (l<0) {
+          data = 0;
+          done++;
+          break;
+        }
+      }
+      dlist_add(&dlist, data);
+
+      // Count data used
+      data = handle_entries(data, NULL);
+      if (!data) continue;
+      if (data == (char *)2) done++;
+      if ((long)data <= 2) data = 0;
+      else data = xstrdup(data);
+
+      break;
+    }
+
+    // Accumulate cally thing
+
+    if (data && !TT.entries) error_exit("argument too long");
+    out = xzalloc((entries+TT.entries+1)*sizeof(char *));
+
+    // Fill out command line to exec
+    memcpy(out, toys.optargs, entries*sizeof(char *));
+    TT.entries = 0;
+    TT.bytes = bytes;
+    if (dlist) dlist->prev->next = 0;
+    for (dtemp = dlist; dtemp; dtemp = dtemp->next)
+      handle_entries(dtemp->data, out+entries);
+
+    if (!(pid = XVFORK())) {
+      xclose(0);
+      open("/dev/null", O_RDONLY);
+      xexec(out);
+    }
+    waitpid(pid, &status, 0);
+    status = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+127;
+
+    // Abritrary number of execs, can't just leak memory each time...
+    while (dlist) {
+      struct double_list *dtemp = dlist->next;
+
+      free(dlist->data);
+      free(dlist);
+      dlist = dtemp;
+    }
+    free(out);
+  }
+}
diff --git a/toybox/www/about.html b/toybox/www/about.html
new file mode 100755
index 0000000..ce06186
--- /dev/null
+++ b/toybox/www/about.html
@@ -0,0 +1,163 @@
+<html><head><title>What is toybox?</title>
+<!--#include file="header.html" -->
+
+<h2><a name="what" />What is toybox?</h2>
+
+<p>Toybox combines many common Linux command line utilities together into
+a single <a href=license.html>BSD-licensed</a> executable. It's simple, small, fast, and reasonably
+standards-compliant (<a href=http://opengroup.org/onlinepubs/9699919799>POSIX-2008</a> and <a href=http://refspecs.linuxfoundation.org/LSB_4.1.0>LSB 4.1</a>).</p>
+
+<p>Toybox's main goal is to make Android
+<a href=http://landley.net/aboriginal/about.html#selfhost>self-hosting</a>
+by improving Android's command line utilities so it can
+build an installable Android Open Source Project image
+entirely from source under a stock Android system. After a talk at the 2013
+Embedded Linux Conference explaining this plan
+(<a href=http://landley.net/talks/celf-2013.txt>outline</a>,
+<a href=https://www.youtube.com/watch?v=SGmtP5Lg_t0>video</a>), Google
+<a href=https://lwn.net/Articles/629362/>merged toybox into AOSP</a> and
+began shipping toybox in Android Mashmallow.</p>
+
+<p>Toybox aims to provide one quarter of a theoretical "minimal native
+development environment", which is the simplest Linux system capable of
+rebuilding itself from source code and then building
+<a href=http://linuxfromscratch.org/lfs>Linux From Scratch</a>
+and the <a href=https://source.android.com>Android Open Source Project</a>
+under the result. In theory, this should only require four packages:
+1) a set of posix-ish command line utilities,
+2) a compiler<a name="1_back"></a><sup><font size=-3><a href=#1>[1]</a></font></sup>,
+3) a C library, and 4) a kernel. This provides a reproducible and auditable
+base system, which with the addition of a few convienciences (vi, top,
+shell command line history...) can provide a usable interactive experience
+rather than just a headless build server.</p>
+
+<b><h2><a name="why" />Why is toybox?</h2></b>
+
+<p>The <a href=http://landley.net/talks/celf-2015.txt>2015 toybox talk</a>
+starts with links to three previous talks on the history and motivation of
+the project: "Why Toybox", "Why Public Domain", and "Why did I do
+Aboriginal Linux (which led me here)?". If you're really bored,
+there's even a half-finished
+<a href=http://landley.net/aboriginal/history.html>a history page</a>.</p>
+
+<p>The toybox maintainer's earlier minimal self-hosting system project,
+<a href=http://landley.net/aboriginal/about.html>Aboriginal Linux</a>,
+got its minimal native development environment down to seven packages in
+its 1.0 release (busybox, uClibc, gcc, binutils, make, bash, and linux)
+and built Linux From Scratch under the result. That project
+<a href=http://landley.net/aboriginal/history.html>was the reason</a>
+toybox's maintainer became busybox maintainer, having done so
+much work to extend busybox to replace all the gnu tools in a Linux From
+Scratch build that the previous maintainer handed over the project (to
+spend more time on buildroot).</p>
+
+<p>Despite the maintainer's history with busybox, toybox is a fresh
+from-scratch implementation under an
+<a href=https://source.android.com/source/licenses.html>android-compatible</a>
+<a href=license.html>license</a>. Busybox predates Android, but has never
+shipped with Android due to the license. As long as we're starting over anyway,
+we can do a better job.</p>
+
+<p>These days, toybox is replacing busybox
+in Aboriginal Linux one command at a time, and each toybox release is
+regression tested by building Aboriginal Linux with it, then building
+Linux From Scratch under the result with the new toybox commands.
+The list of commands remaining is tracked <a href=roadmap.html#dev_env>in
+the roadmap</a>, and the replacing busybox in Aboriginal Linux is
+one of the main goals for toybox' 1.0 release.</p>
+
+<p>Building LFS requres fewer commands than building AOSP, which has a lot more
+<a href=http://source.android.com/source/initializing.html>build
+prerequisites</a>. In theory some of those can be built from source
+as external packages (we're clearly not including our own java implementation),
+but some early prerequisites may need to be added to bootstrap AOSP far enough
+to build them (such as a read-only version of "git":
+how does repo download the AOSP source otherwise?)
+<a name="2_back"></a><sup><font size=-3><a href=#2>[2]</a></font></sup></p>
+
+<b><h2><a name="status" />What commands are planned/implemented in toybox?</h2></b>
+
+<p>The current list of commands implemented by toybox is on the
+<a href=status.html>status page</a>, which is updated each release.
+There is also a <a href=roadmap.html>roadmap</a> listing all planned commands
+for the 1.0 release and the reasons for including them.</p>
+
+<p>In general, configuring toybox with "make defconfig" enables all the commands
+compete enough to be useful. Configuring "allyesconfig" enables partially
+implemented commands as well, along with debugging features.</p>
+
+<b><h3>Relevant Standards</h3></b>
+
+<p>Most commands are implemented according to POSIX-2008 (I.E.
+<a href=http://opengroup.org/onlinepubs/9699919799/idx/utilities.html>The
+Single Unix Specification version 4</a>) where applicable. This does not mean
+that toybox is implementing every SUSv4 utility: some such as SCCS and ed are
+obsolete, while others such as c99 are outside the scope of the project.
+Toybox also isn't implementing full internationalization support: it should be
+8-bit clean and handle UTF-8, but otherwise we leave this to X11 and higher
+layers. And some things (like $CDPATH support in "cd") await a good
+explanation of why to bother with them. (POSIX provides an important
+frame of reference, but is not an infallable set of commandments to be blindly
+obeyed. We do try to document our deviations from it in the comment section
+at the start of each command under toys/posix.)</p>
+
+<p>The other major sources of commands are the Linux man pages, the
+Linux Standard Base, and testing the behavior of existing command
+implementations (although not generally looking at their
+source code), including the commands in Android's toolbox. SUSv4 does not
+include many basic commands such as "mount", "init", and "mke2fs", which are
+kind of nice to have.</p>
+
+<p>For more on this see the <a href=roadmap.html>roadmap</a> and
+<a href=design.html>design goals</a>.</p>
+
+<b><h2><a name="downloads" />Download</h2></b>
+
+<p>This project is maintained as a <a href=https://github.com/landley/toybox>git
+archive</a>, and also offers <a href=http://landley.net/toybox/downloads>source
+tarballs</a> and <a href=http://landley.net/toybox/bin>static binaries</a>
+of the release versions.</p>
+
+<p>The maintainer's <a href=http://landley.net/notes.html>development log</a> and the project's
+<a href=http://lists.landley.net/listinfo.cgi/toybox-landley.net>mailing
+list</a> are also good ways to track what's going on with the project.</p>
+
+<b><h2><a name="toycans" />What's the toybox logo image?</h2></b>
+
+<p>It's <a href=toycans-big.jpg>carefully stacked soda cans</a>. Specifically,
+it's a bunch of the original "Coke Zero" and "Pepsi One" cans, circa 2006,
+stacked to spell out the binary values of the ascii string "Toybox", with
+null terminator at the bottom. (The big picture's on it's side because
+the camera was held sideways to get a better shot.)</p>
+
+<p>No, it's not photoshopped, I actually had these cans until a coworker
+who Totally Did Not Get It <sup><font size=-3><a href=http://www.timesys.com>tm</a></font></sup> threw them out one day after I'd gone home,
+thinking they were recycling. (I still have two of each kind, but
+Pepsi One seems discontinued and Coke Zero switched its can color
+from black to grey, presumably in celebration. It was fun while it lasted...)</p>
+
+<b><h2>Footnotes</h2></b>
+
+<p><a name="1" /><a href="#1_back">[1]</a> Ok, most toolchains (gcc, llvm, pcc, libfirm...)
+are multiple packages, but the maintainer of toybox used to maintain a
+<a href=http://landley.net/tinycc>fork of tinycc</a> (an integrated
+compiler/assembler/linker which once upon a
+time did <a href=http://bellard.org/tcc/tccboot.html>build a bootable linux
+kernel</a> before its original developer abandoned the project),
+and has <a href=http://landley.net/hg/qcc/file/tip/todo/todo.txt>vague plans</a> of <a href=http://landley.net/qcc>trying
+again someday</a>. The compiler toolchain is _conceptually_ one package,
+implementable as a single multicall binary acting like make, cc, as, ld, cpp,
+strip, readelf, nm, objdump, and so on as necessary. It's just the existing
+packages that do this <strike>kinda suck</strike> don't. (In theory "make"
+belongs in qcc, in practice llvm hasn't got its own make so toybox probably
+needs to add it after 1.0 to eliminate another gpl build prerequite from
+AOSP.)</p>
+
+<p><a name="2" /><a href="#2_back">[2]</a>
+The dividing line is
+"Is there an acceptably licensed version Android can ship, or do we have
+to write one?" Since android is not "GNU/Linux" in any way, we need to
+clean out all traces of gnu software from its build to get a clean
+self-hosting system.</p>
+
+<!--#include file="footer.html" -->
diff --git a/toybox/www/cleanup.html b/toybox/www/cleanup.html
new file mode 100644
index 0000000..801dfb8
--- /dev/null
+++ b/toybox/www/cleanup.html
@@ -0,0 +1,290 @@
+<html><head><title>toybox cleanup</title></head>
+<!--#include file="header.html" -->
+
+<h1>Index</h1>
+
+<ul>
+<li><a href=#intro>Introduction</a></li>
+<li><a href=#advice>Advice</a></li>
+<li>Commands:</li>
+<ul>
+<li><a href=#uuencode>uuencode</a></li>
+<li><a href=#uudecode>uudecode</a></li>
+<li><a href=#ifconfig>ifconfig</a></li>
+<li><a href=#find>find</a></li>
+</ul>
+</ul>
+
+<hr>
+
+<a name=intro />
+<h1>Cleaning up the toybox code.</h1>
+
+<p>Toybox <a href=http://landley.net/notes.html#31-03-2013>hasn't always</a>
+taken proper advantage of external contributions</a>.
+Lots of people want to help, but their contributions languish out of tree
+or in the "pending" directory, awaiting cleanup.</p>
+
+<p>Toybox's design goals require simpler, tighter, and more explicit code
+than most other implementations, among other reasons to allow better security
+auditing. Writing "another" implementation of standard command line tools
+isn't very interesting, they should be _better_ implementations.
+Unfortunately, this means existing, working commands often take more effort to
+clean up to Toybox's standards than writing a new one from scratch, not
+because they don't work, but because we aim for an unusual level of polish.</p>
+
+<p>In hopes of teaching more people how to do this
+cleanup work, I've started breaking cleanup changes into smaller chunks and
+posting explanations of each change to the mailing list.
+Below are indexes of such cleanup series. Each commit and post are meant to
+be read together: each description explains what the corresponding patch
+was trying to accomplish.</p>
+
+<p>Line/byte totals of completed series are given for scale, but the point
+of this work is simplicity and compactness, not size per se.</p>
+
+<p>(Note: mercurial's web viewer doesn't follow renames, so although each
+command name links to a commit list with the bulk of the changes, it may
+not include the final version of each file moved from the "pending"
+directory to its final location. The summaries link the initial and cleaned
+versions of each file when giving line counts.)</p>
+
+<hr>
+
+<a name=advice />
+<h1>General advice and/or policy.</h1>
+
+<p>The <a href=design.html>design of toybox</a> page and the coding
+style section at the start of the <a href=code.html>source code walkthrough</a>
+don't cover everything. Here are some
+links to mailing list messages that cover various programming topics
+not directly related to a specific cleanup series:</p>
+
+<ul>
+<li><a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000850.html>Error messages and internationalization.</a></li>
+<li><a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000891.html>Why not "const"?</a> (Exception: global variables
+outside of GLOBALS can be static const, to go in rodata instead of data.
+This means the pages can be shared between instances.)</li>
+<li><a href=http://lkml.indiana.edu/hypermail/linux/kernel/1308.3/03890.html>Why not "bool"?</a> (explanation from Linus Torvalds)</li>
+<li><a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000893.html>Why not to check in debug code.</a></li>
+<li><a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-June/001044.html>Relationship between /proc and /sys</a> (/proc isn't obsolete and /sys is an ABI)</li>
+<li>"Hiding numbers that are used just once into defines to put them out of
+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>
+
+<a name="uuencode"><h1><a href=/hg/toybox/log/900/toys/pending/uuencode.c>uuencode</a></h1>
+
+<p>This is an example of cleaning up something most projects would be quite
+happy with. The initial submission of uuencode and uudecode was high
+quality code, written by a seasoned developer who did an excellent
+job, but it was still possible to shrink the result almost by half:</p>
+
+<ul>
+<li>old total: <a href=/hg/toybox/file/828/toys/pending/uuencode.c>116 lines (2743
+bytes) in 7 functions</a></li>
+<li>new total: <a href=/hg/toybox/file/841/toys/posix/uuencode.c>67 lines (1440
+bytes) in 1 function</a></li>
+</ul>
+
+<ul>
+<li>commit: <a href=/hg/toybox/rev/830>830</a>: first pass, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000904.html>part 1</a>,
+<a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000903.html>part 2</a></li>
+<li>commit: <a href=/hg/toybox/rev/831>831</a>,
+second pass, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000919.html>part 3</a></li>
+<li>commit: <a href=/hg/toybox/rev/837>837</a>,
+description: fix test suite.</li>
+<li>commit: <a href=/hg/toybox/rev/853>853</a>, description: bugfix.</li>
+</ul>
+
+<p>Status: COMPLETE</p>
+
+<a name="uudecode"><h1><a href=/hg/toybox/log/900/toys/pending/uudecode.c>uudecode</a></h1>
+
+<p>The uudecode cleanup was my second "explain as I go along" cleanup,
+and I tried to do it in smaller stages so it was easier to see what
+changed from the diff:</p>
+
+<ul>
+<li>old: <a href=/hg/toybox/file/828/toys/pending/uudecode.c>175
+lines (4534 bytes) in 9 functions</a></li>
+<li>new: <a href=/hg/toybox/file/840/toys/posix/uudecode.c>107 lines
+(2300 bytes) in 1 function</a></li>
+</ul>
+
+<ul>
+<li>commit: <a href=/hg/toybox/rev/833>833</a>,
+description: preparatory adjustments to test suite.</li>
+<li>commit: <a href=/hg/toybox/rev/835>835</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2014-January/001532.html>Redo command line parsing, redo parsing loop.</a></li>
+<li>commit: <a href=/hg/toybox/rev/838>838</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2014-January/001533.html>Redo b64_1byte, b64_4bytes, and uu_line()</a></li>
+<li>commit: <a href=/hg/toybox/rev/839>839</a>,
+description: todo</a></li>
+<li>commit: <a href=/hg/toybox/rev/840>840</a>,
+description: todo (finish, move pending->posix, default y)</a></li>
+</ul>
+
+<p>Status: COMPLETE</p>
+
+<a name=ifconfig>
+<h1><a href=/hg/toybox/log/tip/toys/pending/ifconfig.c>ifconfig</a></h1>
+
+<p>This series describes a thorough cleanup that took a while to do.</p>
+
+<p>When ifconfig was submitted, it touched a half-dozen files. I glued it
+together into a single self-contained file, which needed a lot of
+cleanup. The final version is about 1/3 the size of the original.</p>
+
+<ul>
+<li>old total: <a href=/hg/toybox/file/841/toys/pending/ifconfig.c>1504 lines (44268 bytes) in 38 functions</a></li>
+<li>new total: <a href=/hg/toybox/file/1133/toys/other/ifconfig.c>521 lines (15963 bytes) in 4 functions</a></li>
+</ul>
+
+<p>This was the first command I started cleaning up with the intent of
+describing the process, and especially the first few entries in this
+series describe many of the low hanging fruit techniques used to clean
+up a codebase.</p>
+
+<ul>
+<li>commit: <a href=/hg/toybox/rev/843>843</a>, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000882.html>Infrastructure in search of a user, code proximity,
+unnecessary #defines, shorter code is easier to read.</a></li>
+<li>commit: <a href=/hg/toybox/rev/844>844</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000881.html>Headers, replacing repeated code with loops,
+logical operators guaranteed to return 0 or 1, math on string constants,
+removing unnecessary variables and tests.</a></li>
+<li>commit: <a href=/hg/toybox/rev/852>852</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000921.html>hg commit numbers, documenting the obvious, ordering
+to avoid prototypes, returning void, collate local declarations,
+use error_exit(), unnecessary parentheses, inline to remove variables/functions
+used only once, using *var instead of var[0], unnecessary typecasts,
+xprintf("\n") vs xputc('\n')</a></li>
+<li>commit: <a href=/hg/toybox/rev/856>856</a>,
+description: one line portability fix from Isaac Dunham</li>
+<li>commit: <a href=/hg/toybox/rev/861>861</a>
+and <a href=/hg/toybox/rev/863>863</a>,
+description:
+<a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000910.html>Help
+infrastructure cleanup from Isaac Dunham</a>
+(which I mis-applied and then <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000920.html>fixed plus some whitespace changes</a>)</li>
+
+<li>commit: <a href=/hg/toybox/rev/862>862</a>, description:
+<a href=http://lists.landley.net/pipermail/toybox-landley.net/2014-January/001525.html>remove unused headers and function, replace local buffer with toybuf, perror_exit(), avoid unnecessary assignment.</a></li>
+<li>commit: <a href=/hg/toybox/rev/864>864</a>, description:
+<a href=http://lists.landley.net/pipermail/toybox-landley.net/2014-January/001526.html>use common linked list functions, inline set_data, add xioctl, clean up error messages, whitespace and comment tweaks, remove NOP return statements</a></li>
+<li>commit: <a href=/hg/toybox/rev/866>866</a>, description:
+<a href=http://lists.landley.net/pipermail/toybox-landley.net/2014-January/001528.html>move standalone globals into GLOBALS() block, collate structs into
+iface_list. Inline/rewrite/remove field_format, iface_flags_str,
+omit_whitespace(), print_iface_flags(), print_media(), get_ifconfig_info(),
+and clear_list(). Merge duplicate function
+calls. Show get_proc_info() version field can't matter in 2.6 or newer kernel,
+and that SIOCGIFMAP has been there since 1994 so doesn't need an #ifdef.
+Loop simplification in readconf() and show_iface().</a></li>
+
+<li>commit: <a href=/hg/toybox/rev/869>869</a> and <a href=/hg/toybox/rev/870>870</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000928.html>869:
+reorder to eliminate prototypes, put command_main() at end of file,
+870: long repeated variable prefixes, replacing struct+sscanf()+printf with a
+loop and a table (from iface_list, get_proc_info(), display_ifconfig()),
+use lib/xwrap.c functions to return void, why xstrcpy() fails closed,
+(functional comment: why multicast failed, CSLIP obsolecense), not being
+_too_ clever.</a></li>
+<li>commit: <a href=/hg/toybox/rev/878>878</a> and <a href=/hg/toybox/rev/879>879</a>:
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000946.html>878: add xsocket(), free(NULL) is a safe NOP (posix!).
+879: inline three functions and simplify, some simplifications only show up
+after repeated inlining</a></li>
+<li>commit: <a href=/hg/toybox/rev/883>883</a>,
+description: move some common code to lib/ and posix headers to toys.h.</li>
+<li>commit: <a href=/hg/toybox/rev/898>898</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-May/000974.html>Argument parsing. (Replace ifconfig_main() if/else staircase with a loop over
+an array, genericize minus prefix logic, inline a use of set_flags().)</a></li>
+<li>commit: <a href=/hg/toybox/rev/905>905</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-May/000992.html>remove unnecessary wrapper function, inlining more functions,
+relying on the values of constants that don't change across architectures
+(binary backwards compatability), more ifconfig_main table work,
+man ioctl_list.</a></li>
+<li>commit: <a href=/hg/toybox/rev/906>906</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-May/000994.html>More ifconfig_main() table work, remove vestigial arguments
+to functions, "a frenzy of inlining", slightly better error reporting,
+don't reinvent libc functions.</a></li>
+<li>commit: <a href=/hg/toybox/rev/907>907</a>,
+<a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-May/000995.html>inlining show_ip_addr() with a loop and a table, inlining hex_to_binary()
+and set_hw_address(), stop validating data we supplied, remove a table
+that's overkill (two entries, we don't even loop over it), when you don't need a
+NULL terminator for array, remove unnecessary memcpy(offsetof()) with
+assignment, trusting -funsigned-char.</a></li>
+<li>commit: <a href=/hg/toybox/rev/919>919</a>,
+<a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-June/001027.html>todo whitespace damage, introduce IFREQ_OFFSZ() and poke() to
+ifconfig_main() table logic to fold more if/else parts into the table</a></li>
+<li>Status update: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-June/001033.html>Entering the home stretch on ifconfig</a> (and a <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-June/001043.html>note about infiniband</a>)</li>
+<li>commit: <a href=/hg/toybox/rev/921>921</a>, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2014-June/003508.html>Inline a couple more functions and make sockfd a global.</li>
+<li>commit: <a href=/hg/toybox/rev/957>957</a>, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-July/001121.html>Remove unused socklen and addr_to_len(), cleanup so we can merge get_device_info()/display_ifconfig().</a></li>
+<li>commit: <a href=/hg/toybox/rev/958>958</a>, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-July/001131.html>This commit removes struct if_list by unifying get_device_info() and display_ifconfig().</a></li>
+<li>commit: <a href=/hg/toybox/rev/1104>1104</a>, description: Merge toynet into toys.h: musl supports it and micromanaging uClibc config options isn't very interesting anymore.</li>
+<li>commit: <a href=/hg/toybox/rev/1127>1127</a>, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-November/001464.html>Start tacling ipv6 issues, beginning with display_ifconfig().</a></li>
+<li>commit: <a href=/hg/toybox/rev/1128>1128</a>, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-November/001463.html>More ipv6, make struct sockaddr_with_len go away, merge more arguments into the table in main().</a></li>
+<li>commit: <a href=/hg/toybox/rev/1132>1132</a>, description: promotion from pending to other</li>
+<li>commit: <a href=/hg/toybox/rev/1132>1133</a>, description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-November/001462.html>cleanup help text, remove obsolete/NOP commands</a></li>
+</ul>
+
+<p>Status: COMPLETE.</p>
+
+<h1><a href=/hg/toybox/log/tip/toys/pending/find.c>find</a></h1>
+
+<pre>
+814 Initial version by Gurang Shastri.
+815
+816
+847 Felix Janda
+848 Whitespace (reindent from tabs -> 2 spaces)
+849 More cleanup
+867 Felix Janda Improve operator processing.
+874 Felix Janda
+875 Felix Janda
+887 Felix Janda fix -mtime
+</pre>
+
+<ul>
+<li>commit: <a href=/hg/toybox/rev/849>849</a>,
+description: <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000895.html>here</a></li>
+</ul>
+
+<p>Status: in progress.</p>
+
+<h1><a href=/hg/toybox/log/917/toys/pending/stat.c>stat</a></h1>
+
+<p>A lot of the stat cleanup was done by Felix Janda.</p>
+
+<ul>
+<li>commit <a href=/hg/toybox/rev/747>747</a>: initial submission</a></li>
+<li>commit <a href=/hg/toybox/rev/810>810</a>: whitespace</li>
+<li>commit <a href=/hg/toybox/rev/811>811</a>: description in commit message.</li>
+<li>commit <a href=/hg/toybox/rev/871>871</a>: whitespace (reindent from 4 spaces to 2)</li>
+<li>commit <a href=/hg/toybox/rev/872>872</a>: Felix Janda - <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000923.html>cleanup</a> (with discussion thread)</li>
+<li>commit <a href=/hg/toybox/rev/875>885</a>: Felix Janda - <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-April/000936.html>move permission formatting (777 -> -rwxrwxrwx) from ls to lib so stat can reuse it.</a></li>
+<li>commit <a href=/hg/toybox/rev/885>886</a>: Felix Janda - remove unimplemented options and clean up help text</li>
+<li>commit <a href=/hg/toybox/rev/910>910</a>: Felix Janda - <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-May/001013.html>Add support for stating multiple files</a>.</li>
+<li>commit <a href=/hg/toybox/rev/911>911</a>: Felix Janda - Separate stat and statfs, give stat_main() a ds[2] array to distinguish FLAG_f vs not cases, and some whitespace changes.</li>
+<li>commit <a href=/hg/toybox/rev/912>912</a>: description in commit message (also <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-May/001019.html>here</a>)</li>
+<li><a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-May/001024.html>design pondering</a> (leading to peek() function in lib/)</li>
+
+<li>commit <a href=/hg/toybox/rev/914>914</a>: description in commit message.</li>
+<li>commit <a href=/hg/toybox/rev/916>916</a>: description in commit message.</li>
+<li>commit: <a href=/hg/toybox/rev/917>917</a>: description in commit message.</li>
+<li>commit: <a href=/hg/toybox/rev/918>918</a>,
+description: done: move pending to posix, default y, no other changes</a>.</li>
+<li><a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-June/001026.html>summary</a></li>
+</ul>
+
+<p>Status: COMPLETE.</p>
+
+<!--#include file="footer.html" -->
diff --git a/toybox/www/code.html b/toybox/www/code.html
new file mode 100644
index 0000000..c0566b4
--- /dev/null
+++ b/toybox/www/code.html
@@ -0,0 +1,1424 @@
+<html><head><title>toybox source code walkthrough</title></head>
+<!--#include file="header.html" -->
+
+<p><h1><a name="style" /><a href="#style">Code style</a></h1></p>
+
+<p>The primary goal of toybox is _simple_ code. Keeping the code small is
+second, with speed and lots of features coming in somewhere after that.
+(For more on that, see the <a href=design.html>design</a> page.)</p>
+
+<p>A simple implementation usually takes up fewer lines of source code,
+meaning more code can fit on the screen at once, meaning the programmer can
+see more of it on the screen and thus keep more if in their head at once.
+This helps code auditing and thus reduces bugs. That said, sometimes being
+more explicit is preferable to being clever enough to outsmart yourself:
+don't be so terse your code is unreadable.</p>
+
+<p>Toybox has an actual coding style guide over on
+<a href=design.html#codestyle>the design page</a>, but in general we just
+want the code to be consistent.</p>
+
+<p><h1><a name="building" /><a href="#building">Building Toybox</a></h1></p>
+
+<p>Toybox is configured using the Kconfig language pioneered by the Linux
+kernel, and adopted by many other projects (uClibc, OpenEmbedded, etc).
+This generates a ".config" file containing the selected options, which
+controls which features are included when compiling toybox.</p>
+
+<p>Each configuration option has a default value. The defaults indicate the
+"maximum sane configuration", I.E. if the feature defaults to "n" then it
+either isn't complete or is a special-purpose option (such as debugging
+code) that isn't intended for general purpose use.</p>
+
+<p>For a more compact human-editable version .config files, you can use the
+<a href=http://landley.net/aboriginal/FAQ.html#dev_miniconfig>miniconfig</a>
+format.</p>
+
+<p>The standard build invocation is:</p>
+
+<ul>
+<li>make defconfig #(or menuconfig)</li>
+<li>make</li>
+<li>make install</li>
+</ul>
+
+<p>Type "make help" to see all available build options.</p>
+
+<p>The file "configure" contains a number of environment variable definitions
+which influence the build, such as specifying which compiler to use or where
+to install the resulting binaries. This file is included by the build, but
+accepts existing definitions of the environment variables, so it may be sourced
+or modified by the developer before building and the definitions exported
+to the environment will take precedence.</p>
+
+<p>(To clarify: ".config" lists the features selected by defconfig/menuconfig,
+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>
+
+<p>The toybox main() function is at the end of main.c at the top level. It has
+two possible codepaths, only one of which is configured into any given build
+of toybox.</p>
+
+<p>If CONFIG_SINGLE is selected, toybox is configured to contain only a single
+command, so most of the normal setup can be skipped. In this case the
+multiplexer isn't used, instead main() calls toy_singleinit() (also in main.c)
+to set up global state and parse command line arguments, calls the command's
+main function out of toy_list (in the CONFIG_SINGLE case the array has a single entry, no need to search), and if the function returns instead of exiting
+it flushes stdout (detecting error) and returns toys.exitval.</p>
+
+<p>When CONFIG_SINGLE is not selected, main() uses basename() to find the
+name it was run as, shifts its argument list one to the right so it lines up
+with where the multiplexer function expects it, and calls toybox_main(). This
+leverages the multiplexer command's infrastructure to find and run the
+appropriate command. (A command name starting with "toybox" will
+recursively call toybox_main(); you can go "./toybox toybox toybox toybox ls"
+if you want to...)</p>
+
+<h2>toybox_main</h2>
+
+<p>The toybox_main() function is also in main,c. It handles a possible
+--help option ("toybox --help ls"), prints the list of available commands if no
+arguments were provided to the multiplexer (or with full path names if any
+other option is provided before a command name, ala "toybox --list").
+Otherwise it calls toy_exec() on its argument list.</p>
+
+<p>Note that the multiplexer is the first entry in toy_list (the rest of the
+list is sorted alphabetically to allow binary search), so toybox_main can
+cheat and just grab the first entry to quickly set up its context without
+searching. Since all command names go through the multiplexer at least once
+in the non-TOYBOX_SINGLE case, this avoids a redundant search of
+the list.</p>
+
+<p>The toy_exec() function is also in main.c. It performs toy_find() to
+perform a binary search on the toy_list array to look up the command's
+entry by name and saves it in the global variable which, calls toy_init()
+to parse command line arguments and set up global state (using which->options),
+and calls the appropriate command's main() function (which->toy_main). On
+return it flushes all pending ansi FILE * I/O, detects if stdout had an
+error, and then calls xexit() (which uses toys.exitval).</p>
+
+<p><h1><a name="infrastructure" /><a href="#infrastructure">Infrastructure</a></h1></p>
+
+<p>The toybox source code is in following directories:</p>
+<ul>
+<li>The <a href="#top">top level directory</a> contains the file main.c (were
+execution starts), the header file toys.h (included by every command), and
+other global infrastructure.</li>
+<li>The <a href="#lib">lib directory</a> contains common functions shared by
+multiple commands:</li>
+<ul>
+<li><a href="#lib_lib">lib/lib.c</a></li>
+<li><a href="#lib_xwrap">lib/xwrap.c</a></li>
+<li><a href="#lib_llist">lib/llist.c</a></li>
+<li><a href="#lib_args">lib/args.c</a></li>
+<li><a href="#lib_dirtree">lib/dirtree.c</a></li>
+</ul>
+<li>The <a href="#toys">toys directory</a> contains the C files implementating
+each command. Currently it contains five subdirectories categorizing the
+commands: posix, lsb, other, example, and pending.</li>
+<li>The <a href="#scripts">scripts directory</a> contains the build and
+test infrastructure.</li>
+<li>The <a href="#kconfig">kconfig directory</a> contains the configuration
+infrastructure implementing menuconfig (copied from the Linux kernel).</li>
+<li>The <a href="#generated">generated directory</a> contains intermediate
+files generated from other parts of the source code.</li>
+</ul>
+
+<a name="adding" />
+<p><h1><a href="#adding">Adding a new command</a></h1></p>
+<p>To add a new command to toybox, add a C file implementing that command to
+one of the subdirectories under the toys directory.  No other files need to
+be modified; the build extracts all the information it needs (such as command
+line arguments) from specially formatted comments and macros in the C file.
+(See the description of the <a href="#generated">"generated" directory</a>
+for details.)</p>
+
+<p>Currently there are five subdirectories under "toys", one for commands
+defined by the POSIX standard, one for commands defined by the Linux Standard
+Base, an "other" directory for commands not covered by an obvious standard,
+a directory of example commands (templates to use when starting new commands),
+and a "pending" directory of commands that need further review/cleanup
+before moving to one of the other directories (run these at your own risk,
+cleanup patches welcome).
+These directories are just for developer convenience sorting the commands,
+the directories are otherwise functionally identical. To add a new category,
+create the appropriate directory with a README file in it whose first line
+is the description menuconfig should use for the directory.)</p>
+
+<p>An easy way to start a new command is copy the file "toys/example/hello.c"
+to the name of the new command, and modify this copy to implement the new
+command (more or less by turning every instance of "hello" into the
+name of your command, updating the command line arguments, globals, and
+help data, and then filling out its "main" function with code that does
+something interesting).</p> 
+
+<p>You could also start with "toys/example/skeleton.c", which provides a lot
+more example code (showing several variants of command line option
+parsing, how to implement multiple commands in the same file, and so on).
+But usually it's just more stuff to delete.</p>
+
+<p>Here's a checklist of steps to turn hello.c into another command:</p>
+
+<ul>
+<li><p>First "cp toys/example/hello.c toys/other/yourcommand.c" and open
+the new file in your preferred text editor.</p>
+<ul><li><p>Note that the
+name of the new file is significant: it's the name of the new command you're
+adding to toybox. The build includes all *.c files under toys/*/ whose
+names are a case insensitive match for an enabled config symbol. So
+toys/posix/cat.c only gets included if you have "CAT=y" in ".config".</p></li>
+</ul></p></li>
+
+<li><p>Change the one line comment at the top of the file (currently
+"hello.c - A hello world program") to describe your new file.</p></li>
+
+<li><p>Change the copyright notice to your name, email, and the current
+year.</p></li>
+
+<li><p>Give a URL to the relevant standards document, where applicable.
+(Sample links to SUSv4 and LSB are provided, feel free to link to other
+documentation or standards as appropriate.)</p></li>
+
+<li><p>Update the USE_YOURCOMMAND(NEWTOY(yourcommand,"blah",0)) line.
+The NEWTOY macro fills out this command's <a href="#toy_list">toy_list</a>
+structure.  The arguments to the NEWTOY macro are:</p>
+
+<ol>
+<li><p>the name used to run your command</p></li>
+<li><p>the command line argument <a href="#lib_args">option parsing string</a> (0 if none)</p></li>
+<li><p>a bitfield of TOYFLAG values
+(defined in toys.h) providing additional information such as where your
+command should be installed on a running system, whether to blank umask
+before running, whether or not the command must run as root (and thus should
+retain root access if installed SUID), and so on.</p></li>
+</ol>
+</li>
+
+<li><p>Change the kconfig data (from "config YOURCOMMAND" to the end of the
+comment block) to supply your command's configuration and help
+information.  The uppper case config symbols are used by menuconfig, and are
+also what the CFG_ and USE_() macros are generated from (see [TODO]).  The
+help information here is used by menuconfig, and also by the "help" command to
+describe your new command.  (See [TODO] for details.)  By convention,
+unfinished commands default to "n" and finished commands default to "y",
+so "make defconfig" selects all finished commands.  (Note, "finished" means
+"ready to be used", not that it'll never change again.)<p>
+
+<p>Each help block should start with a "usage: yourcommand" line explaining
+any command line arguments added by this config option.  The "help" command
+outputs this text, and scripts/config2help.c in the build infrastructure
+collates these usage lines for commands with multiple configuration
+options when producing generated/help.h.</p>
+</li>
+
+<li><p>Change the "#define FOR_hello" line to "#define FOR_yourcommand" right
+before the "#include <toys.h>". (This selects the appropriate FLAG_ macros and
+does a "#define TT this.yourcommand" so you can access the global variables
+out of the space-saving union of structures. If you aren't using any command
+flag bits and aren't defining a GLOBAL block, you can delete this line.)</p></li>
+
+<li><p>Update the GLOBALS() macro to contain your command's global
+variables. If your command has no global variables, delete this macro.</p>
+
+<p>Variables in the GLOBALS() block are are stored in a space saving
+<a href="#toy_union">union of structures</a> format, which may be accessed
+using the TT macro as if TT were a global structure (so TT.membername).
+If you specified two-character command line arguments in
+NEWTOY(), the first few global variables will be initialized by the automatic
+argument parsing logic, and the type and order of these variables must
+correspond to the arguments specified in NEWTOY().
+(See <a href="#lib_args">lib/args.c</a> for details.)</p></li>
+
+<li><p>Rename hello_main() to yourcommand_main().  This is the main() function
+where execution of your command starts. Your command line options are
+already sorted into this.optflags, this.optargs, this.optc, and the GLOBALS()
+as appropriate by the time this function is called. (See
+<a href="#lib_args">get_optflags()</a> for details.)</p></li>
+
+<li><p>Switch on TOYBOX_DEBUG in menuconfig (toybox global settings menu)
+the first time you build and run your new command. If anything is wrong
+with your option string, that will give you error messages.</p>
+
+<p>Otherwise it'll just segfault without
+explanation when it falls off the end because it didn't find a matching
+end parantheses for a longopt, or you put a nonexistent option in a square
+bracket grouping... Since these kind of errors can only be caused by a
+developer, not by end users, we don't normally want runtime checks for
+them. Once you're happy with your option string, you can switch TOYBOX_DEBUG
+back off.</p></li>
+</ul>
+
+<a name="headers" /><h2><a href="#headers">Headers.</a></h2>
+
+<p>Commands generally don't have their own headers. If it's common code
+it can live in lib/, if it isn't put it in the command's .c file. (The line
+between implementing multiple commands in a C file via OLDTOY() to share
+infrastructure and moving that shared infrastructure to lib/ is a judgement
+call. Try to figure out which is simplest.)</p>
+
+<p>The top level toys.h should #include all the standard (posix) headers
+that any command uses. (Partly this is friendly to ccache and partly this
+makes the command implementations shorter.) Individual commands should only
+need to include nonstandard headers that might prevent that command from
+building in some context we'd care about (and thus requiring that command to
+be disabled to avoid a build break).</p>
+
+<p>Target-specific stuff (differences between compiler versions, libc versions,
+or operating systems) should be confined to lib/portability.h and
+lib/portability.c. (There's even some minimal compile-time environment probing
+that writes data to generated/portability.h, see scripts/genconfig.sh.)</p>
+
+<p>Only include linux/*.h headers from individual commands (not from other
+headers), and only if you really need to. Data that varies per architecture
+is a good reason to include a header. If you just need a couple constants
+that haven't changed since the 1990's, it's ok to #define them yourself or
+just use the constant inline with a comment explaining what it is. (A
+#define that's only used once isn't really helping.)</p>
+
+<p><a name="top" /><h1><a href="#top">Top level directory.</a></h1></p>
+
+<p>This directory contains global infrastructure.</p>
+
+<h3>toys.h</h3>
+<p>Each command #includes "toys.h" as part of its standard prolog. It
+may "#define FOR_commandname" before doing so to get some extra entries
+specific to this command.</p>
+
+<p>This file sucks in most of the commonly used standard #includes, so
+individual files can just #include "toys.h" and not have to worry about
+stdargs.h and so on.  Individual commands still need to #include
+special-purpose headers that may not be present on all systems (and thus would
+prevent toybox from building that command on such a system with that command
+enabled).  Examples include regex support, any "linux/" or "asm/" headers, mtab
+support (mntent.h and sys/mount.h), and so on.</p>
+
+<p>The toys.h header also defines structures for most of the global variables
+provided to each command by toybox_main().  These are described in
+detail in the description for main.c, where they are initialized.</p>
+
+<p>The global variables are grouped into structures (and a union) for space
+savings, to more easily track the amount of memory consumed by them,
+so that they may be automatically cleared/initialized as needed, and so
+that access to global variables is more easily distinguished from access to
+local variables.</p>
+
+<h3>main.c</h3>
+<p>Contains the main() function where execution starts, plus
+common infrastructure to initialize global variables and select which command
+to run.  The "toybox" multiplexer command also lives here.  (This is the
+only command defined outside of the toys directory.)</p>
+
+<p>Execution starts in main() which trims any path off of the first command
+name and calls toybox_main(), which calls toy_exec(), which calls toy_find()
+and toy_init() before calling the appropriate command's function from
+toy_list[] (via toys.which->toy_main()).
+If the command is "toybox", execution recurses into toybox_main(), otherwise
+the call goes to the appropriate commandname_main() from a C file in the toys
+directory.</p>
+
+<p>The following global variables are defined in main.c:</p>
+<ul>
+<a name="toy_list" />
+<li><p><b>struct toy_list toy_list[]</b> - array describing all the
+commands currently configured into toybox.  The first entry (toy_list[0]) is
+for the "toybox" multiplexer command, which runs all the other built-in commands
+without symlinks by using its first argument as the name of the command to
+run and the rest as that command's argument list (ala "./toybox echo hello").
+The remaining entries are the commands in alphabetical order (for efficient
+binary search).</p>
+
+<p>This is a read-only array initialized at compile time by
+defining macros and #including generated/newtoys.h.</p>
+
+<p>Members of struct toy_list (defined in "toys.h") include:</p>
+<ul>
+<li><p>char *<b>name</b> - the name of this command.</p></li>
+<li><p>void (*<b>toy_main</b>)(void) - function pointer to run this
+command.</p></li>
+<li><p>char *<b>options</b> - command line option string (used by
+get_optflags() in lib/args.c to intialize toys.optflags, toys.optargs, and
+entries in the toy's GLOBALS struct).  When this is NULL, no option
+parsing is done before calling toy_main().</p></li>
+<li><p>int <b>flags</b> - Behavior flags for this command.  The following flags are currently understood:</p>
+
+<ul>
+<li><b>TOYFLAG_USR</b> - Install this command under /usr</li>
+<li><b>TOYFLAG_BIN</b> - Install this command under /bin</li>
+<li><b>TOYFLAG_SBIN</b> - Install this command under /sbin</li>
+<li><b>TOYFLAG_NOFORK</b> - This command can be used as a shell builtin.</li>
+<li><b>TOYFLAG_UMASK</b> - Call umask(0) before running this command.</li>
+<li><b>TOYFLAG_STAYROOT</b> - Don't drop permissions for this command if toybox is installed SUID root.</li>
+<li><b>TOYFLAG_NEEDROOT</b> - This command cannot function unless run with root access.</li>
+</ul>
+<br>
+
+<p>These flags are combined with | (or).  For example, to install a command
+in /usr/bin, or together TOYFLAG_USR|TOYFLAG_BIN.</p>
+</ul>
+</li>
+
+<li><p><b>struct toy_context toys</b> - global structure containing information
+common to all commands, initializd by toy_init() and defined in "toys.h".
+Members of this structure include:</p>
+<ul>
+<li><p>struct toy_list *<b>which</b> - a pointer to this command's toy_list
+structure.  Mostly used to grab the name of the running command
+(toys->which.name).</p>
+</li>
+<li><p>int <b>exitval</b> - Exit value of this command.  Defaults to zero.  The
+error_exit() functions will return 1 if this is zero, otherwise they'll
+return this value.</p></li>
+<li><p>char **<b>argv</b> - "raw" command line options, I.E. the original
+unmodified string array passed in to main().  Note that modifying this changes
+"ps" output, and is not recommended.  This array is null terminated; a NULL
+entry indicates the end of the array.</p>
+<p>Most commands don't use this field, instead the use optargs, optflags,
+and the fields in the GLOBALS struct initialized by get_optflags().</p>
+</li>
+<li><p>unsigned <b>optflags</b> - Command line option flags, set by
+<a href="#lib_args">get_optflags()</a>.  Indicates which of the command line options listed in
+toys->which.options occurred this time.</p>
+
+<p>The rightmost command line argument listed in toys->which.options sets bit
+1, the next one sets bit 2, and so on.  This means the bits are set in the same
+order the binary digits would be listed if typed out as a string.  For example,
+the option string "abcd" would parse the command line "-c" to set optflags to 2,
+"-a" would set optflags to 8, and "-bd" would set optflags to 6 (4|2).</p>
+
+<p>Only letters are relevant to optflags.  In the string "a*b:c#d", d=1, c=2,
+b=4, a=8.  Punctuation after a letter initializes global variables at the
+start of the GLOBALS() block (see <a href="#toy_union">union toy_union this</a>
+for details).</p>
+
+<p>The build infrastructure creates FLAG_ macros for each option letter,
+corresponding to the bit position, so you can check (toys.optflags & FLAG_x)
+to see if a flag was specified. (The correct set of FLAG_ macros is selected
+by defining FOR_mycommand before #including toys.h. The macros live in
+toys/globals.h which is generated by scripts/make.sh.)</p>
+
+<p>For more information on option parsing, see <a href="#lib_args">get_optflags()</a>.</p>
+
+</li>
+<li><p>char **<b>optargs</b> - Null terminated array of arguments left over
+after get_optflags() removed all the ones it understood.  Note: optarg[0] is
+the first argument, not the command name.  Use toys.which->name for the command
+name.</p></li>
+<li><p>int <b>optc</b> - Optarg count, equivalent to argc but for
+optargs[].<p></li>
+</ul>
+
+<a name="toy_union" />
+<li><p><b>union toy_union this</b> - Union of structures containing each
+command's global variables.</p>
+
+<p>Global variables are useful: they reduce the overhead of passing extra
+command line arguments between functions, they conveniently start prezeroed to
+save initialization costs, and the command line argument parsing infrastructure
+can also initialize global variables with its results.</p>
+
+<p>But since each toybox process can only run one command at a time, allocating
+space for global variables belonging to other commands you aren't currently
+running would be wasteful.</p>
+
+<p>Toybox handles this by encapsulating each command's global variables in
+a structure, and declaring a union of those structures with a single global
+instance (called "this").  The GLOBALS() macro contains the global
+variables that should go in the current command's global structure.  Each
+variable can then be accessed as "this.commandname.varname".
+If you #defined FOR_commandname before including toys.h, the macro TT is
+#defined to this.commandname so the variable can then be accessed as
+"TT.variable".  See toys/hello.c for an example.</p>
+
+<p>A command that needs global variables should declare a structure to
+contain them all, and add that structure to this union.  A command should never
+declare global variables outside of this, because such global variables would
+allocate memory when running other commands that don't use those global
+variables.</p>
+
+<p>The first few fields of this structure can be intialized by <a href="#lib_args">get_optargs()</a>,
+as specified by the options field off this command's toy_list entry.  See
+the get_optargs() description in lib/args.c for details.</p>
+</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>
+<ul>
+<li><p>struct toy_list *<b>toy_find</b>(char *name) - Return the toy_list
+structure for this command name, or NULL if not found.</p></li>
+<li><p>void <b>toy_init</b>(struct toy_list *which, char *argv[]) - fill out
+the global toys structure, calling get_optargs() if necessary.</p></li>
+<li><p>void <b>toy_exec</b>(char *argv[]) - Run a built-in command with
+arguments.</p>
+<p>Calls toy_find() on argv[0] (which must be just a command name
+without path).  Returns if it can't find this command, otherwise calls
+toy_init(), toys->which.toy_main(), and exit() instead of returning.</p>
+
+<p>Use the library function xexec() to fall back to external executables
+in $PATH if toy_exec() can't find a built-in command.  Note that toy_exec()
+does not strip paths before searching for a command, so "./command" will
+never match an internal command.</li>
+
+<li><p>void <b>toybox_main</b>(void) - the main function for the multiplexer
+command (I.E. "toybox").  Given a command name as its first argument, calls
+toy_exec() on its arguments.  With no arguments, it lists available commands.
+If the first argument starts with "-" it lists each command with its default
+install path prepended.</p></li>
+
+</ul>
+
+<h3>Config.in</h3>
+
+<p>Top level configuration file in a stylized variant of
+<a href=http://kernel.org/doc/Documentation/kbuild/kconfig-language.txt>kconfig</a> format.  Includes generated/Config.in.</p>
+
+<p>These files are directly used by "make menuconfig" to select which commands
+to build into toybox (thus generating a .config file), and by
+scripts/config2help.py to create generated/help.h.</p>
+
+<a name="generated" />
+<h1><a href="#generated">Temporary files:</a></h1>
+
+<p>There is one temporary file in the top level source directory:</p>
+<ul>
+<li><p><b>.config</b> - Configuration file generated by kconfig, indicating
+which commands (and options to commands) are currently enabled.  Used
+to make generated/config.h and determine which toys/*/*.c files to build.</p>
+
+<p>You can create a human readable "miniconfig" version of this file using
+<a href=http://landley.net/aboriginal/new_platform.html#miniconfig>these
+instructions</a>.</p>
+</li>
+</ul>
+
+<p><h2>Directory generated/</h2></p>
+
+<p>The remaining temporary files live in the "generated/" directory,
+which is for files generated at build time from other source files.</p>
+
+<ul>
+<li><p><b>generated/Config.in</b> - Kconfig entries for each command, included
+from the top level Config.in. The help text here is used to generate
+help.h.</p>
+
+<p>Each command has a configuration entry with an upper case version of
+the command name. Options to commands start with the command
+name followed by an underscore and the option name. Global options are attached
+to the "toybox" command, and thus use the prefix "TOYBOX_".  This organization
+is used by scripts/cfg2files to select which toys/*/*.c files to compile for a
+given .config.</p>
+</li>
+
+<li><p><b>generated/config.h</b> - list of CFG_SYMBOL and USE_SYMBOL() macros,
+generated from .config by a sed invocation in scripts/make.sh.</p>
+
+<p>CFG_SYMBOL is a comple time constant set to 1 for enabled symbols and 0 for
+disabled symbols. This allows the use of normal if() statements to remove
+code at compile time via the optimizer's dead code elimination (which removes
+from the binary any code that cannot be reached). This saves space without
+cluttering the code with #ifdefs or leading to configuration dependent build
+breaks. (See the 1992 Usenix paper
+<a href=http://doc.cat-v.org/henry_spencer/ifdef_considered_harmful.pdf>#ifdef
+Considered Harmful</a> for more information.)</p>
+
+<p>When you can't entirely avoid an #ifdef, the USE_SYMBOL(code) macro
+provides a less intrusive alternative, evaluating to the code in parentheses
+when the symbol is enabled, and nothing when the symbol is disabled. This
+is most commonly used around NEWTOY() declarations (so only the enabled
+commands show up in toy_list), and in option strings. This can also be used
+for things like varargs or structure members which can't always be
+eliminated by a simple test on CFG_SYMBOL. Remember, unlike CFG_SYMBOL
+this is really just a variant of #ifdef, and can still result in configuration
+dependent build breaks. Use with caution.</p>
+</li>
+
+<li><p><b>generated/flags.h</b> - FLAG_? macros indicating which command
+line options were seen. The option parsing in lib/args.c sets bits in
+toys.optflags, which can be tested by anding with the appropriate FLAG_
+macro. (Bare longopts, which have no corresponding short option, will
+have the longopt name after FLAG_. All others use the single letter short
+option.)</p>
+
+<p>To get the appropriate macros for your command, #define FOR_commandname
+before #including toys.h. To switch macro sets (because you have an OLDTOY()
+with different options in the same .c file), #define CLEANUP_oldcommand
+and also #define FOR_newcommand, then #include "generated/flags.h" to switch.
+</p>
+</li>
+
+<li><p><b>generated/globals.h</b> -
+Declares structures to hold the contents of each command's GLOBALS(),
+and combines them into "global_union this". (Yes, the name was
+chosen to piss off C++ developers who think that C
+is merely a subset of C++, not a language in its own right.)</p>
+
+<p>The union reuses the same memory for each command's global struct:
+since only one command's globals are in use at any given time, collapsing
+them together saves space. The headers #define TT to the appropriate
+"this.commandname", so you can refer to the current command's global
+variables out of "this" as TT.variablename.</p>
+
+<p>The globals start zeroed, and the first few are filled out by the 
+lib/args.c argument parsing code called from main.c.</p>
+</li>
+
+<li><p><b>toys/help.h</b> - Help strings for use by the "help" command and
+--help options. This file #defines a help_symbolname string for each
+symbolname, but only the symbolnames matching command names get used
+by show_help() in lib/help.c to display help for commands.</p>
+
+<p>This file is created by scripts/make.sh, which compiles scripts/config2help.c
+into the binary generated/config2help, and then runs it against the top
+level .config and Config.in files to extract the help text from each config
+entry and collate together dependent options.</p>
+
+<p>This file contains help text for all commands, regardless of current
+configuration, but only the ones currently enabled in the .config file
+wind up in the help_data[] array, and only the enabled dependent options
+have their help text added to the command they depend on.</p>
+</li>
+
+<li><p><b>generated/newtoys.h</b> - 
+All the NEWTOY() and OLDTOY() macros from toys/*/*.c. The "toybox" multiplexer
+is the first entry, the rest are in alphabetical order. Each line should be
+inside an appropriate USE_ macro, so code that #includes this file only sees
+the currently enabled commands.</p>
+
+<p>By #definining NEWTOY() to various things before #including this file,
+it may be used to create function prototypes (in toys.h), initialize the
+help_data array (in lib/help.c),  initialize the toy_list array (in main.c,
+the alphabetical order lets toy_find() do a binary search, the exception to
+the alphabetical order lets it use the multiplexer without searching), and so
+on.  (It's even used to initialize the NEED_OPTIONS macro, which produces a 1
+or 0 for each command using command line option parsing, which is ORed together
+to allow compile-time dead code elimination to remove the whole of
+lib/args.c if nothing currently enabled is using it.)<p>
+
+<p>Each NEWTOY and OLDTOY macro contains the command name, command line
+option string (telling lib/args.c how to parse command line options for
+this command), recommended install location, and miscelaneous data such
+as whether this command should retain root permissions if installed suid.</p>
+</li>
+
+<li><p><b>toys/oldtoys.h</b> - Macros with the command line option parsing
+string for each NEWTOY. This allows an OLDTOY that's just an alias for an
+existing command to refer to the existing option string instead of
+having to repeat it.</p>
+</li>
+</ul>
+
+<a name="lib">
+<h2>Directory lib/</h2>
+
+<p>TODO: document lots more here.</p>
+
+<p>lib: getmountlist(), error_msg/error_exit, xmalloc(),
+strlcpy(), xexec(), xopen()/xread(), xgetcwd(), xabspath(), find_in_path(),
+itoa().</p>
+
+
+
+<a name="lib_xwrap"><h3>lib/xwrap.c</h3>
+
+<p>Functions prefixed with the letter x call perror_exit() when they hit
+errors, to eliminate common error checking. This prints an error message
+and the strerror() string for the errno encountered.</p>
+
+<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><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><b>char *xstrndup(char *s, size_t n)</b></li>
+<li><b>char *xstrdup(char *s)</b></li>
+<li><b>char *xmprintf(char *format, ...)</b></li>
+<li><b>void xprintf(char *format, ...)</b></li>
+<li><b>void xputs(char *s)</b></li>
+<li><b>void xputc(char c)</b></li>
+<li><b>void xflush(void)</b></li>
+<li><b>pid_t xfork(void)</b></li>
+<li><b>void xexec_optargs(int skip)</b></li>
+<li><b>void xexec(char **argv)</b></li>
+<li><b>pid_t xpopen(char **argv, int *pipes)</b></li>
+<li><b>int xpclose(pid_t pid, int *pipes)</b></li>
+<li><b>void xaccess(char *path, int flags)</b></li>
+<li><b>void xunlink(char *path)</b></li>
+<li><p><b>int xcreate(char *path, int flags, int mode)<br />
+int xopen(char *path, int flags)</b></p>
+
+<p>The xopen() and xcreate() functions open an existing file (exiting if
+it's not there) and create a new file (exiting if it can't).</p>
+
+<p>They default to O_CLOEXEC so the filehandles aren't passed on to child
+processes. Feed in O_CLOEXEC to disable this.</p>
+</li>
+<li><p><b>void xclose(int fd)</b></p>
+
+<p>Because NFS is broken, and won't necessarily perform the requested
+operation (and report the error) until you close the file. Of course, this
+being NFS, it's not guaranteed to report the error there either, but it
+_can_.</p>
+
+<p>Nothing else ever reports an error on close, everywhere else it's just a
+VFS operation freeing some resources. NFS is _special_, in a way that
+other network filesystems like smbfs and v9fs aren't..</p>
+</li>
+<li><b>int xdup(int fd)</b></li>
+<li><p><b>size_t xread(int fd, void *buf, size_t len)</b></p>
+
+<p>Can return 0, but not -1.</p>
+</li>
+<li><p><b>void xreadall(int fd, void *buf, size_t len)</b></p>
+
+<p>Reads the entire len-sized buffer, retrying to complete short
+reads. Exits if it can't get enough data.</p></li>
+
+<li><p><b>void xwrite(int fd, void *buf, size_t len)</b></p>
+
+<p>Retries short writes, exits if can't write the entire buffer.</p></li>
+
+<li><b>off_t xlseek(int fd, off_t offset, int whence)</b></li>
+<li><b>char *xgetcwd(void)</b></li>
+<li><b>void xstat(char *path, struct stat *st)</b></li>
+<li><p><b>char *xabspath(char *path, int exact) </b></p>
+
+<p>After several years of
+<a href=http://landley.net/notes-2007.html#18-06-2007>wrestling</a>
+<a href=http://landley.net/notes-2008.html#19-01-2008>with</a> realpath(), 
+I broke down and <a href=http://landley.net/notes-2012.html#20-11-2012>wrote
+my own</a> implementation that doesn't use the one in libc. As I explained:
+
+<blockquote><p>If the path ends with a broken link,
+readlink -f should show where the link points to, not where the broken link
+lives. (The point of readlink -f is "if I write here, where would it attempt
+to create a file".) The problem is, realpath() returns NULL for a path ending
+with a broken link, and I can't beat different behavior out of code locked
+away in libc.</p></blockquote>
+
+<p>
+</li>
+<li><b>void xchdir(char *path)</b></li>
+<li><b>void xchroot(char *path)</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>
+<li><b>int xioctl(int fd, int request, void *data)</b></li>
+<li><b>void xpidfile(char *name)</b></li>
+<li><b>void xsendfile(int in, int out)</b></li>
+<li><b>long xparsetime(char *arg, long units, long *fraction)</b></li>
+<li><b>void xregcomp(regex_t *preg, char *regex, int cflags)</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>
+
+<h3>lib/portability.h</h3>
+
+<p>This file is automatically included from the top of toys.h, and smooths
+over differences between platforms (hardware targets, compilers, C libraries,
+operating systems, etc).</p>
+
+<p>This file provides SWAP macros (SWAP_BE16(x) and SWAP_LE32(x) and so on).</p>
+
+<p>A macro like SWAP_LE32(x) means "The value in x is stored as a little
+endian 32 bit value, so perform the translation to/from whatever the native
+32-bit format is".  You do the swap once on the way in, and once on the way
+out. If your target is already little endian, the macro is a NOP.</p>
+
+<p>The SWAP macros come in BE and LE each with 16, 32, and 64 bit versions.
+In each case, the name of the macro refers to the _external_ representation,
+and converts to/from whatever your native representation happens to be (which
+can vary depending on what you're currently compiling for).</p>
+
+<a name="lib_llist"><h3>lib/llist.c</h3>
+
+<p>Some generic single and doubly linked list functions, which take
+advantage of a couple properties of C:</p>
+
+<ul>
+<li><p>Structure elements are laid out in memory in the order listed, and
+the first element has no padding. This means you can always treat (typecast)
+a pointer to a structure as a pointer to the first element of the structure,
+even if you don't know anything about the data following it.</p></li>
+
+<li><p>An array of length zero at the end of a structure adds no space
+to the sizeof() the structure, but if you calculate how much extra space
+you want when you malloc() the structure it will be available at the end.
+Since C has no bounds checking, this means each struct can have one variable
+length array.</p></li>
+</ul>
+
+<p>Toybox's list structures always have their <b>next</b> pointer as
+the first entry of each struct, and singly linked lists end with a NULL pointer.
+This allows generic code to traverse such lists without knowing anything
+else about the specific structs composing them: if your pointer isn't NULL
+typecast it to void ** and dereference once to get the next entry.</p>
+
+<p><b>lib/lib.h</b> defines three structure types:</p>
+<ul>
+<li><p><b>struct string_list</b> - stores a single string (<b>char str[0]</b>),
+memory for which is allocated as part of the node. (I.E. llist_traverse(list,
+free); can clean up after this type of list.)</p></li>
+
+<li><p><b>struct arg_list</b> - stores a pointer to a single string
+(<b>char *arg</b>) which is stored in a separate chunk of memory.</p></li>
+
+<li><p><b>struct double_list</b> - has a second pointer (<b>struct double_list
+*prev</b> along with a <b>char *data</b> for payload.</p></li>
+</ul>
+
+<b>List Functions</b>
+
+<ul>
+<li><p>void *<b>llist_pop</b>(void **list) - advances through a list ala
+<b>node = llist_pop(&list);</b>  This doesn't modify the list contents,
+but does advance the pointer you feed it (which is why you pass the _address_
+of that pointer, not the pointer itself).</p></li>
+
+<li><p>void <b>llist_traverse</b>(void *list, void (*using)(void *data)) -
+iterate through a list calling a function on each node.</p></li>
+
+<li><p>struct double_list *<b>dlist_add</b>(struct double_list **llist, char *data)
+- append an entry to a circular linked list.
+This function allocates a new struct double_list wrapper and returns the
+pointer to the new entry (which you can usually ignore since it's llist->prev,
+but if llist was NULL you need it). The argument is the ->data field for the
+new node.</p></li>
+<ul><li><p>void <b>dlist_add_nomalloc</b>(struct double_list **llist,
+struct double_list *new) - append existing struct double_list to
+list, does not allocate anything.</p></li></ul>
+</ul>
+
+<b>List code trivia questions:</b>
+
+<ul>
+<li><p><b>Why do arg_list and double_list contain a char * payload instead of
+a void *?</b> - Because you always have to typecast a void * to use it, and
+typecasting a char * does no harm. Since strings are the most common
+payload, and doing math on the pointer ala
+"(type *)(ptr+sizeof(thing)+sizeof(otherthing))" requires ptr to be char *
+anyway (at least according to the C standard), defaulting to char * saves
+a typecast.</p>
+</li>
+
+<li><p><b>Why do the names ->str, ->arg, and ->data differ?</b> - To force
+you to keep track of which one you're using, calling free(node->str) would
+be bad, and _failing_ to free(node->arg) leaks memory.</p></li>
+
+<li><p><b>Why does llist_pop() take a void * instead of void **?</b> -
+because the stupid compiler complains about "type punned pointers" when
+you typecast and dereference on the same line,
+due to insane FSF developers hardwiring limitations of their optimizer
+into gcc's warning system. Since C automatically typecasts any other
+pointer type to and from void *, the current code works fine. It's sad that it
+won't warn you if you forget the &, but the code crashes pretty quickly in
+that case.</p></li>
+
+<li><p><b>How do I assemble a singly-linked-list in order?</b> - use
+a double_list, dlist_add() your entries, and then break the circle with
+<b>list->prev->next = NULL;</b> when done.</li>
+</ul>
+
+<a name="lib_args"><h3>lib/args.c</h3>
+
+<p>Toybox's main.c automatically parses command line options before calling the
+command's main function. Option parsing starts in get_optflags(), which stores
+results in the global structures "toys" (optflags and optargs) and "this".</p>
+
+<p>The option parsing infrastructure stores a bitfield in toys.optflags to
+indicate which options the current command line contained, and defines FLAG
+macros code can use to check whether each argument's bit is set. Arguments
+attached to those options are saved into the command's global structure
+("this"). Any remaining command line arguments are collected together into
+the null-terminated array toys.optargs, with the length in toys.optc. (Note
+that toys.optargs does not contain the current command name at position zero,
+use "toys.which->name" for that.) The raw command line arguments get_optflags()
+parsed are retained unmodified in toys.argv[].</p>
+
+<p>Toybox's option parsing logic is controlled by an "optflags" string, using
+a format reminiscent of getopt's optargs but with several important differences.
+Toybox does not use the getopt()
+function out of the C library, get_optflags() is an independent implementation
+which doesn't permute the original arguments (and thus doesn't change how the
+command is displayed in ps and top), and has many features not present in
+libc optargs() (such as the ability to describe long options in the same string
+as normal options).</p>
+
+<p>Each command's NEWTOY() macro has an optflags string as its middle argument,
+which sets toy_list.options for that command to tell get_optflags() what
+command line arguments to look for, and what to do with them.
+If a command has no option
+definition string (I.E. the argument is NULL), option parsing is skipped
+for that command, which must look at the raw data in toys.argv to parse its
+own arguments. (If no currently enabled command uses option parsing,
+get_optflags() is optimized out of the resulting binary by the compiler's
+--gc-sections option.)</p>
+
+<p>You don't have to free the option strings, which point into the environment
+space (I.E. the string data is not copied). A TOYFLAG_NOFORK command
+that uses the linked list type "*" should free the list objects but not
+the data they point to, via "llist_free(TT.mylist, NULL);". (If it's not
+NOFORK, exit() will free all the malloced data anyway unless you want
+to implement a CONFIG_TOYBOX_FREE cleanup for it.)</p>
+
+<h4>Optflags format string</h4>
+
+<p>Note: the optflags option description string format is much more
+concisely described by a large comment at the top of lib/args.c.</p>
+
+<p>The general theory is that letters set optflags, and punctuation describes
+other actions the option parsing logic should take.</p>
+
+<p>For example, suppose the command line <b>command -b fruit -d walrus -a 42</b>
+is parsed using the optflags string "<b>a#b:c:d</b>".  (I.E.
+toys.which->options="a#b:c:d" and argv = ["command", "-b", "fruit", "-d",
+"walrus", "-a", "42"]).  When get_optflags() returns, the following data is
+available to command_main():
+
+<ul>
+<li><p>In <b>struct toys</b>:
+<ul>
+<li>toys.optflags = 13; // FLAG_a = 8 | FLAG_b = 4 | FLAG_d = 1</li>
+<li>toys.optargs[0] = "walrus"; // leftover argument</li>
+<li>toys.optargs[1] = NULL; // end of list</li>
+<li>toys.optc = 1; // there was 1 leftover argument</li>
+<li>toys.argv[] = {"-b", "fruit", "-d", "walrus", "-a", "42"}; // The original command line arguments
+</ul>
+<p></li>
+
+<li><p>In <b>union this</b> (treated as <b>long this[]</b>):
+<ul>
+<li>this[0] = NULL; // -c didn't get an argument this time, so get_optflags() didn't change it and toys_init() zeroed "this" during setup.)</li>
+<li>this[1] = (long)"fruit"; // argument to -b</li>
+<li>this[2] = 42; // argument to -a</li>
+</ul>
+</p></li>
+</ul>
+
+<p>If the command's globals are:</p>
+
+<blockquote><pre>
+GLOBALS(
+	char *c;
+	char *b;
+	long a;
+)
+</pre></blockquote>
+
+<p>That would mean TT.c == NULL, TT.b == "fruit", and TT.a == 42.  (Remember,
+each entry that receives an argument must be a long or pointer, to line up
+with the array position.  Right to left in the optflags string corresponds to
+top to bottom in GLOBALS().</p>
+
+<p>Put globals not filled out by the option parsing logic at the end of the
+GLOBALS block. Common practice is to list the options one per line (to
+make the ordering explicit, first to last in globals corresponds to right
+to left in the option string), then leave a blank line before any non-option
+globals.</p>
+
+<p><b>long toys.optflags</b></p>
+
+<p>Each option in the optflags string corresponds to a bit position in
+toys.optflags, with the same value as a corresponding binary digit.  The
+rightmost argument is (1<<0), the next to last is (1<<1) and so on.  If
+the option isn't encountered while parsing argv[], its bit remains 0.</p>
+
+<p>Each option -x has a FLAG_x macro for the command letter. Bare --longopts
+with no corresponding short option have a FLAG_longopt macro for the long
+optionname. Commands enable these macros by #defining FOR_commandname before
+#including <toys.h>. When multiple commands are implemented in the same
+source file, you can switch flag contexts later in the file by
+#defining CLEANUP_oldcommand and #defining FOR_newcommand, then
+#including <generated/flags.h>.</p>
+
+<p>Options disabled in the current configuration (wrapped in
+a USE_BLAH() macro for a CONFIG_BLAH that's switched off) have their
+corresponding FLAG macro set to zero, so code checking them ala
+if (toys.optargs & FLAG_x) gets optimized out via dead code elimination.
+#defining FORCE_FLAGS when switching flag context disables this
+behavior: the flag is never zero even if the config is disabled. This
+allows code shared between multiple commands to use the same flag
+values, as long as the common flags match up right to left in both option
+strings.</p>
+
+<p>For example,
+the optflags string "abcd" would parse the command line argument "-c" to set
+optflags to 2, "-a" would set optflags to 8, "-bd" would set optflags to
+6 (I.E. 4|2), and "-a -c" would set optflags to 10 (2|8). To check if -c
+was encountered, code could test: if (toys.optflags & FLAG_c) printf("yup");
+(See the toys/examples directory for more.)</p>
+
+<p>Only letters are relevant to optflags, punctuation is skipped: in the
+string "a*b:c#d", d=1, c=2, b=4, a=8. The punctuation after a letter
+usually indicate that the option takes an argument.</p>
+
+<p>Since toys.optflags is an unsigned int, it only stores 32 bits. (Which is
+the amount a long would have on 32-bit platforms anyway; 64 bit code on
+32 bit platforms is too expensive to require in common code used by almost
+all commands.) Bit positions beyond the 1<<31 aren't recorded, but
+parsing higher options can still set global variables.</p>
+
+<p><b>Automatically setting global variables from arguments (union this)</b></p>
+
+<p>The following punctuation characters may be appended to an optflags
+argument letter, indicating the option takes an additional argument:</p>
+
+<ul>
+<li><b>:</b> - plus a string argument, keep most recent if more than one.</li>
+<li><b>*</b> - plus a string argument, appended to a linked list.</li>
+<li><b>@</b> - plus an occurrence counter (stored in a long)</li>
+<li><b>#</b> - plus a signed long argument.
+<li><b>-</b> - plus a signed long argument defaulting to negative (start argument with + to force a positive value).</li>
+<li><b>.</b> - plus a floating point argument (if CFG_TOYBOX_FLOAT).</li>
+<ul>The following can be appended to a float or double:
+<li><b>&lt;123</b> - error if argument is less than this</li>
+<li><b>&gt;123</b> - error if argument is greater than this</li>
+<li><b>=123</b> - default value if argument not supplied</li>
+</ul>
+</ul>
+
+<p><b>GLOBALS</b></p>
+
+<p>Options which have an argument fill in the corresponding slot in the global
+union "this" (see generated/globals.h), treating it as an array of longs
+with the rightmost saved in this[0].  As described above, using "a*b:c#d",
+"-c 42" would set this[0] = 42; and "-b 42" would set this[1] = "42"; each
+slot is left NULL if the corresponding argument is not encountered.</p>
+
+<p>This behavior is useful because the LP64 standard ensures long and pointer
+are the same size. C99 guarantees structure members will occur in memory
+in the same order they're declared, and that padding won't be inserted between
+consecutive variables of register size.  Thus the first few entries can
+be longs or pointers corresponding to the saved arguments.</p>
+
+<p>See toys/example/*.c for longer examples of parsing options into the
+GLOBALS block.</p>
+
+<p><b>char *toys.optargs[]</b></p>
+
+<p>Command line arguments in argv[] which are not consumed by option parsing
+(I.E. not recognized either as -flags or arguments to -flags) will be copied
+to toys.optargs[], with the length of that array in toys.optc.
+(When toys.optc is 0, no unrecognized command line arguments remain.)
+The order of entries is preserved, and as with argv[] this new array is also
+terminated by a NULL entry.</p>
+
+<p>Option parsing can require a minimum or maximum number of optargs left
+over, by adding "<1" (read "at least one") or ">9" ("at most nine") to the
+start of the optflags string.</p>
+
+<p>The special argument "--" terminates option parsing, storing all remaining
+arguments in optargs.  The "--" itself is consumed.</p>
+
+<p><b>Other optflags control characters</b></p>
+
+<p>The following characters may occur at the start of each command's
+optflags string, before any options that would set a bit in toys.optflags:</p>
+
+<ul>
+<li><b>^</b> - stop at first nonoption argument (for nice, xargs...)</li>
+<li><b>?</b> - allow unknown arguments (pass non-option arguments starting
+with - through to optargs instead of erroring out).</li>
+<li><b>&amp;</b> - the first argument has imaginary dash (ala tar/ps.  If given twice, all arguments have imaginary dash.)</li>
+<li><b>&lt;</b> - must be followed by a decimal digit indicating at least this many leftover arguments are needed in optargs (default 0)</li>
+<li><b>&gt;</b> - must be followed by a decimal digit indicating at most this many leftover arguments allowed (default MAX_INT)</li>
+</ul>
+
+<p>The following characters may be appended to an option character, but do
+not by themselves indicate an extra argument should be saved in this[].
+(Technically any character not recognized as a control character sets an
+optflag, but letters are never control characters.)</p>
+
+<ul>
+<li><b>^</b> - stop parsing options after encountering this option, everything else goes into optargs.</li>
+<li><b>|</b> - this option is required.  If more than one marked, only one is required.</li>
+</ul>
+
+<p>The following may be appended to a float or double:</p>
+
+<ul>
+<li><b>&lt;123</b> - error if argument is less than this</li>
+<li><b>&gt;123</b> - error if argument is greater than this</li>
+<li><b>=123</b> - default value if argument not supplied</li>
+</ul>
+
+<p>Option parsing only understands <>= after . when CFG_TOYBOX_FLOAT
+is enabled. (Otherwise the code to determine where floating point constants
+end drops out.  When disabled, it can reserve a global data slot for the
+argument so offsets won't change, but will never fill it out.) You can handle
+this by using the USE_BLAH() macros with C string concatenation, ala:</p>
+
+<blockquote>"abc." USE_TOYBOX_FLOAT("<1.23>4.56=7.89") "def"</blockquote>
+
+<p><b>--longopts</b></p>
+
+<p>The optflags string can contain long options, which are enclosed in
+parentheses. They may be appended to an existing option character, in
+which case the --longopt is a synonym for that option, ala "a:(--fred)"
+which understands "-a blah" or "--fred blah" as synonyms.</p>
+
+<p>Longopts may also appear before any other options in the optflags string,
+in which case they have no corresponding short argument, but instead set
+their own bit based on position. So for "(walrus)#(blah)xy:z", "command
+--walrus 42" would set toys.optflags = 16 (-z = 1, -y = 2, -x = 4, --blah = 8)
+and would assign this[1] = 42;</p>
+
+<p>A short option may have multiple longopt synonyms, "a(one)(two)", but
+each "bare longopt" (ala "(one)(two)abc" before any option characters)
+always sets its own bit (although you can group them with +X).</p>
+
+<p>Only bare longopts have a FLAG_ macro with the longopt name
+(ala --fred would #define FLAG_fred). Other longopts use the short
+option's FLAG macro to test the toys.optflags bit.</p>
+
+<p>Options with a semicolon ";" after their data type can only set their
+corresponding GLOBALS() entry via "--longopt=value". For example, option
+string "x(boing): y" would set TT.x if it saw "--boing=value", but would
+treat "--boing value" as setting FLAG_x in toys.optargs, leaving TT.x NULL,
+and keeping "value" in toys.optargs[]. (This lets "ls --color" and
+"ls --color=auto" both work.)</p>
+
+<p><b>[groups]</b></p>
+
+<p>At the end of the option string, square bracket groups can define
+relationships between existing options. (This only applies to short
+options, bare --longopts can't participate.)</p>
+
+<p>The first character of the group defines the type, the remaining
+characters are options it applies to:</p>
+
+<ul>
+<li><b>-</b> - Exclusive, switch off all others in this group.</li>
+<li><b>+</b> - Inclusive, switch on all others in this group.</li>
+<li><b>!</b> - Error, fail if more than one defined.</li>
+</ul>
+
+<p>So "abc[-abc]" means -ab = -b, -ba = -a, -abc = -c. "abc[+abc]"
+means -ab=-abc, -c=-abc, and "abc[!abc] means -ab calls error_exit("no -b
+with -a"). Note that [-] groups clear the GLOBALS option slot of
+options they're switching back off, but [+] won't set options it didn't see
+(just the optflags).</p>
+
+<p><b>whitespace</b></p>
+
+<p>Arguments may occur with or without a space (I.E. "-a 42" or "-a42").
+The command line argument "-abc" may be interepreted many different ways:
+the optflags string "cba" sets toys.optflags = 7, "c:ba" sets toys.optflags=4
+and saves "ba" as the argument to -c, and "cb:a" sets optflags to 6 and saves
+"c" as the argument to -b.</p>
+
+<p>Note that &amp; changes whitespace handling, so that the command line
+"tar cvfCj outfile.tar.bz2 topdir filename" is parsed the same as
+"tar filename -c -v -j -f outfile.tar.bz2 -C topdir". Note that "tar -cvfCj
+one two three" would equal "tar -c -v -f Cj one two three". (This matches
+historical usage.)</p>
+
+<p>Appending a space to the option in the option string ("a: b") makes it
+require a space, I.E. "-ab" is interpreted as "-a" "-b". That way "kill -stop"
+differs from "kill -s top".</p>
+
+<p>Appending ; to a longopt in the option string makes its argument optional,
+and only settable with =, so in ls "(color):;" can accept "ls --color" and
+"ls --color=auto" without complaining that the first has no argument.</p>
+
+<a name="lib_dirtree"><h3>lib/dirtree.c</h3>
+
+<p>The directory tree traversal code should be sufficiently generic
+that commands never need to use readdir(), scandir(), or the fts.h family
+of functions.</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
+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>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
+plen isn't NULL then *plen is how many extra bytes to malloc at the end
+of string.</p></li>
+
+<li><p><b>dirtree_parentfd(struct dirtree *node)</b> - return fd of
+directory containing this node, for use with openat() and such.</p></li>
+</ul>
+
+<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>(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>
+
+<p>Each struct dirtree node contains <b>char name[]</b> and <b>struct stat
+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 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
+directory (and use DIRTREE_COMEAGAIN to get the second callback so they can
+close(node->extra) to avoid running out of filehandles).
+This field is not directly used by the dirtree code, and
+thanks to LP64 it's large enough to store a typecast pointer to an
+arbitrary struct.</p>
+
+<p>The return value of the callback combines flags (with boolean or) to tell
+the traversal infrastructure how to behave:</p>
+
+<ul>
+<li><p><b>DIRTREE_SAVE</b> - Save this node, assembling a tree. (Without
+this the struct dirtree is freed after the callback returns. Filtering out
+siblings is fine, but discarding a parent while keeping its child leaks
+memory.)</p></li>
+<li><p><b>DIRTREE_ABORT</b> - Do not examine any more entries in this
+directory. (Does not propagate up tree: to abort entire traversal,
+return DIRTREE_ABORT from parent callbacks too.)</p></li>
+<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 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. 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)
+to other struct dirtree.</p>
+
+<p>The <b>parent</b> pointer indicates the directory
+containing this entry; even when not assembling a persistent tree of
+nodes the parent entries remain live up to the root of the tree while
+child nodes are active. At the top of the tree the parent pointer is
+NULL, meaning the node's name[] is either an absolute path or relative
+to cwd. The function dirtree_parentfd() gets the directory file descriptor
+for use with openat() and friends, returning AT_FDCWD at the top of tree.</p>
+
+<p>The <b>child</b> pointer points to the first node of the list of contents of
+this directory. If the directory contains no files, or the entry isn't
+a directory, child is NULL.</p>
+
+<p>The <b>next</b> pointer indicates sibling nodes in the same directory as this
+node, and since it's the first entry in the struct the llist.c traversal
+mechanisms work to iterate over sibling nodes. Each dirtree node is a
+single malloc() (even char *symlink points to memory at the end of the node),
+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_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>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.
+
+<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
+instead a sort of FIFO order requried by the ls standard.</p>
+
+<a name="toys">
+<h1><a href="#toys">Directory toys/</a></h1>
+
+<p>This directory contains command implementations. Each command is a single
+self-contained file. Adding a new command involves adding a single
+file, and removing a command involves removing that file. Commands use
+shared infrastructure from the lib/ and generated/ directories.</p>
+
+<p>Currently there are five subdirectories under "toys/" containing "posix"
+commands described in POSIX-2008, "lsb" commands described in the Linux
+Standard Base 4.1, "other" commands not described by either standard,
+"pending" commands awaiting cleanup (which default to "n" in menuconfig
+because they don't necessarily work right yet), and "example" code showing
+how toybox infrastructure works and providing template/skeleton files to
+start new commands.</p>
+
+<p>The only difference directory location makes is which menu the command
+shows up in during "make menuconfig", the directories are otherwise identical.
+Note that the commands exist within a single namespace at runtime, so you can't
+have the same command in multiple subdirectories. (The build tries to fail
+informatively when you do that.)</p>
+
+<p>There is one more sub-menus in "make menuconfig" containing global
+configuration options for toybox. This menu is defined in the top level
+Config.in.</p>
+
+<p>See <a href="#adding">adding a new command</a> for details on the
+layout of a command file.</p>
+
+<h2>Directory scripts/</h2>
+
+<p>Build infrastructure. The makefile calls scripts/make.sh for "make"
+and scripts/install.sh for "make install".</p>
+
+<p>There's also a test suite, "make test" calls make/test.sh, which runs all
+the tests in make/test/*. You can run individual tests via
+"scripts/test.sh command", or "TEST_HOST=1 scripts/test.sh command" to run
+that test against the host implementation instead of the toybox one.</p>
+
+<h3>scripts/cfg2files.sh</h3>
+
+<p>Run .config through this filter to get a list of enabled commands, which
+is turned into a list of files in toys via a sed invocation in the top level
+Makefile.
+</p>
+
+<h2>Directory kconfig/</h2>
+
+<p>Menuconfig infrastructure copied from the Linux kernel.  See the
+Linux kernel's Documentation/kbuild/kconfig-language.txt</p>
+
+<!-- todo
+
+Better OLDTOY and multiple command explanation. From Config.in:
+
+<p>A command with multiple names (or multiple similar commands implemented in
+the same .c file) should have config symbols prefixed with the name of their
+C file. I.E. config symbol prefixes are NEWTOY() names. If OLDTOY() names
+have config symbols they must be options (symbols with an underscore and
+suffix) to the NEWTOY() name. (See generated/toylist.h)</p>
+-->
+
+<!--#include file="footer.html" -->
diff --git a/toybox/www/design.html b/toybox/www/design.html
new file mode 100644
index 0000000..993a7f7
--- /dev/null
+++ b/toybox/www/design.html
@@ -0,0 +1,491 @@
+<html><head><title>The design of toybox</title></head>
+<!--#include file="header.html" -->
+
+<b><h2>Design goals</h2></b>
+
+<p>Toybox should be simple, small, fast, and full featured.  Often, these
+things need to be balanced off against each other.  In general, keeping the
+code simple the most important (and hardest) goal, and small is slightly more
+important than fast. Features are the reason we write code in the first
+place but this has all been implemented before so if we can't do a better
+job why bother?  It should be possible to get 80% of the way to each goal
+before they really start to fight.</p>
+
+<p>Here they are in reverse order of importance:</p>
+
+<b><h3>Features</h3></b>
+
+<p>The <a href=roadmap.html>roadmap</a> has the list of features we're
+trying to implement, and the reasons for them. After the 1.0 release
+some of that material may get moved here.</p>
+
+<p>Some things are simply outside the scope of the project: even though
+posix defines commands for compiling and linking, we're not going to include
+a compiler or linker (and support for a potentially infinite number of hardware
+targets). And until somebody comes up with a ~30k ssh implementation, we're
+going to point you at dropbear or polarssl.</p>
+
+<p>Environmental dependencies are a type of complexity, so needing other
+packages to build or run is a big downside.  For example, we don't use curses
+when we can simply output ansi escape sequences and trust all terminal
+programs written in the past 30 years to be able to support them. (A common
+use case is to download a statically linked toybox binary to an arbitrary
+Linux system, and use it in an otherwise unknown environment; being
+self-contained helps support this.)</p>
+
+<b><h3>Speed</h3></b>
+
+<p>It's easy to say lots about optimizing for speed (which is why this section
+is so long), but at the same time it's the optimization we care the least about.
+The essence of speed is being as efficient as possible, which means doing as
+little work as possible.  A design that's small and simple gets you 90% of the
+way there, and most of the rest is either fine-tuning or more trouble than
+it's worth (and often actually counterproductive).  Still, here's some
+advice:</p>
+
+<p>First, understand the darn problem you're trying to solve.  You'd think
+I wouldn't have to say this, but I do.  Trying to find a faster sorting
+algorithm is no substitute for figuring out a way to skip the sorting step
+entirely.  The fastest way to do anything is not to have to do it at all,
+and _all_ optimization boils down to avoiding unnecessary work.</p>
+
+<p>Speed is easy to measure; there are dozens of profiling tools for Linux
+(although personally I find the "time" command a good starting place).
+Don't waste too much time trying to optimize something you can't measure,
+and there's no much point speeding up things you don't spend much time doing
+anyway.</p>
+
+<p>Understand the difference between throughput and latency.  Faster
+processors improve throughput, but don't always do much for latency.
+After 30 years of Moore's Law, most of the remaining problems are latency,
+not throughput.  (There are of course a few exceptions, like data compression
+code, encryption, rsync...)  Worry about throughput inside long-running
+loops, and worry about latency everywhere else.  (And don't worry too much
+about avoiding system calls or function calls or anything else in the name
+of speed unless you are in the middle of a tight loop that's you've already
+proven isn't running fast enough.)</p>
+
+<p>"Locality of reference" is generally nice, in all sorts of contexts.
+It's obvious that waiting for disk access is 1000x slower than doing stuff in
+RAM (and making the disk seek is 10x slower than sequential reads/writes),
+but it's just as true that a loop which stays in L1 cache is many times faster
+than a loop that has to wait for a DRAM fetch on each iteration.  Don't worry
+about whether "&" is faster than "%" until your executable loop stays in L1
+cache and the data access is fetching cache lines intelligently.  (To
+understand DRAM, L1, and L2 cache, read Hannibal's marvelous ram guide at Ars
+Technica:
+<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part1-2.html>part one</a>,
+<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part2-1.html>part two</a>,
+<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part3-1.html>part three</a>,
+plus this
+<a href=http://arstechnica.com/articles/paedia/cpu/caching.ars/1>article on
+cacheing</a>, and this one on
+<a href=http://arstechnica.com/articles/paedia/cpu/bandwidth-latency.ars>bandwidth
+and latency</a>.
+And there's <a href=http://arstechnica.com/paedia/index.html>more where that came from</a>.)
+Running out of L1 cache can execute one instruction per clock cycle, going
+to L2 cache costs a dozen or so clock cycles, and waiting for a worst case dram
+fetch (round trip latency with a bank switch) can cost thousands of
+clock cycles.  (Historically, this disparity has gotten worse with time,
+just like the speed hit for swapping to disk.  These days, a _big_ L1 cache
+is 128k and a big L2 cache is a couple of megabytes.  A cheap low-power
+embedded processor may have 8k of L1 cache and no L2.)</p>
+
+<p>Learn how <a href=http://nommu.org/memory-faq.txt>virtual memory and
+memory managment units work</a>.  Don't touch
+memory you don't have to.  Even just reading memory evicts stuff from L1 and L2
+cache, which may have to be read back in later.  Writing memory can force the
+operating system to break copy-on-write, which allocates more memory.  (The
+memory returned by malloc() is only a virtual allocation, filled with lots of
+copy-on-write mappings of the zero page.  Actual physical pages get allocated
+when the copy-on-write gets broken by writing to the virtual page.  This
+is why checking the return value of malloc() isn't very useful anymore, it
+only detects running out of virtual memory, not physical memory.  Unless
+you're using a <a href=http://nommu.org>NOMMU system</a>, where all bets are off.)</p>
+
+<p>Don't think that just because you don't have a swap file the system can't
+start swap thrashing: any file backed page (ala mmap) can be evicted, and
+there's a reason all running programs require an executable file (they're
+mmaped, and can be flushed back to disk when memory is short).  And long
+before that, disk cache gets reclaimed and has to be read back in.  When the
+operating system really can't free up any more pages it triggers the out of
+memory killer to free up pages by killing processes (the alternative is the
+entire OS freezing solid).  Modern operating systems seldom run out of
+memory gracefully.</p>
+
+<p>Also, it's better to be simple than clever.  Many people think that mmap()
+is faster than read() because it avoids a copy, but twiddling with the memory
+management is itself slow, and can cause unnecessary CPU cache flushes.  And
+if a read faults in dozens of pages sequentially, but your mmap iterates
+backwards through a file (causing lots of seeks, each of which your program
+blocks waiting for), the read can be many times faster.  On the other hand, the
+mmap can sometimes use less memory, since the memory provided by mmap
+comes from the page cache (allocated anyway), and it can be faster if you're
+doing a lot of different updates to the same area.  The moral?  Measure, then
+try to speed things up, and measure again to confirm it actually _did_ speed
+things up rather than made them worse.  (And understanding what's really going
+on underneath is a big help to making it happen faster.)</p>
+
+<p>In general, being simple is better than being clever.  Optimization
+strategies change with time.  For example, decades ago precalculating a table
+of results (for things like isdigit() or cosine(int degrees)) was clearly
+faster because processors were so slow.  Then processors got faster and grew
+math coprocessors, and calculating the value each time became faster than
+the table lookup (because the calculation fit in L1 cache but the lookup
+had to go out to DRAM).  Then cache sizes got bigger (the Pentium M has
+2 megabytes of L2 cache) and the table fit in cache, so the table became
+fast again...  Predicting how changes in hardware will affect your algorithm
+is difficult, and using ten year old optimization advice and produce
+laughably bad results.  But being simple and efficient is always going to
+give at least a reasonable result.</p>
+
+<p>The famous quote from Ken Thompson, "When in doubt, use brute force",
+applies to toybox.  Do the simple thing first, do as little of it as possible,
+and make sure it's right.  You can always speed it up later.</p>
+
+<b><h3>Size</h3></b>
+<p>Again, simple gives you most of this.  An algorithm that does less work
+is generally smaller.  Understand the problem, treat size as a cost, and
+get a good bang for the byte.</p>
+
+<p>Understand the difference between binary size, heap size, and stack size.
+Your binary is the executable file on disk, your heap is where malloc() memory
+lives, and your stack is where local variables (and function call return
+addresses) live.  Optimizing for binary size is generally good: executing
+fewer instructions makes your program run faster (and fits more of it in
+cache).  On embedded systems, binary size is especially precious because
+flash is expensive (and its successor, MRAM, even more so).  Small stack size
+is important for nommu systems because they have to preallocate their stack
+and can't make it bigger via page fault.  And everybody likes a small heap.</p>
+
+<p>Measure the right things.  Especially with modern optimizers, expecting
+something to be smaller is no guarantee it will be after the compiler's done
+with it.  Binary size isn't the most accurate indicator of the impact of a
+given change, because lots of things get combined and rounded during
+compilation and linking.  Matt Mackall's bloat-o-meter is a python script
+which compares two versions of a program, and shows size changes in each
+symbol (using the "nm" command behind the scenes).  To use this, run
+"make baseline" to build a baseline version to compare against, and
+then "make bloatometer" to compare that baseline version against the current
+code.</p>
+
+<p>Avoid special cases.  Whenever you see similar chunks of code in more than
+one place, it might be possible to combine them and have the users call shared
+code. (This is the most commonly cited trick, which doesn't make it easy. If
+seeing two lines of code do the same thing makes you slightly uncomfortable,
+you've got the right mindset.)</p>
+
+<p>Some specific advice: Using a char in place of an int when doing math
+produces significantly larger code on some platforms (notably arm),
+because each time the compiler has to emit code to convert it to int, do the
+math, and convert it back.  Bitfields have this problem on most platforms.
+Because of this, using char to index a for() loop is probably not a net win,
+although using char (or a bitfield) to store a value in a structure that's
+repeated hundreds of times can be a good tradeoff of binary size for heap
+space.</p>
+
+<b><h3>Simple</h3></b>
+
+<p>Complexity is a cost, just like code size or runtime speed. Treat it as
+a cost, and spend your complexity budget wisely. (Sometimes this means you
+can't afford a feature because it complicates the code too much to be
+worth it.)</p>
+
+<p>Simplicity has lots of benefits.  Simple code is easy to maintain, easy to
+port to new processors, easy to audit for security holes, and easy to
+understand.</p>
+
+<p>Simplicity itself can have subtle non-obvious aspects requiring a tradeoff
+between one kind of simplicity and another: simple for the computer to
+execute and simple for a human reader to understand aren't always the
+same thing. A compact and clever algorithm that does very little work may
+not be as easy to explain or understand as a larger more explicit version
+requiring more code, memory, and CPU time. When balancing these, err on the
+side of doing less work, but add comments describing how you
+could be more explicit.</p>
+
+<p>In general, comments are not a substitute for good code (or well chosen
+variable or function names). Commenting "x += y;" with "/* add y to x */"
+can actually detract from the program's readability. If you need to describe
+what the code is doing (rather than _why_ it's doing it), that means the
+code itself isn't very clear.</p>
+
+<p>Prioritizing simplicity tends to serve our other goals: simplifying code
+generally reduces its size (both in terms of binary size and runtime memory
+usage), and avoiding unnecessary work makes code run faster. Smaller code
+also tends to run faster on modern hardware due to CPU cacheing: fitting your
+code into L1 cache is great, and staying in L2 cache is still pretty good.</p>
+
+<p>But a simple implementation is not always the smallest or fastest, and
+balancing simplicity vs the other goals can be difficult. For example, the
+atolx_range() function in lib/lib.c uses the always 64 bit "long long" type,
+which produces larger and slower code on 32 bit platforms and
+often assigned into smaller interger types. Although libc has parallel
+implementations for different data sizes (atoi, atol, atoll) we only
+used the largest, which can cover all cases.</p>
+
+<p>On the other hand, the "tail" command has two codepaths, one for seekable
+files and one for nonseekable files. Although the nonseekable case can handle
+all inputs (and is required when input comes from a pipe or similar, so cannot
+be removed), reading through multiple gigabytes of data to reach the end of
+seekable files was both a common case and hugely penalized by a nonseekable
+approach (half-minute wait vs instant results). This is one example
+where performance did outweigh simplicity of implementation.</p>
+
+<p><a href=http://www.joelonsoftware.com/articles/fog0000000069.html>Joel
+Spolsky argues against throwing code out and starting over</a>, and he has
+good points: an existing debugged codebase contains a huge amount of baked
+in knowledge about strange real-world use cases that the designers didn't
+know about until users hit the bugs, and most of this knowledge is never
+explicitly stated anywhere except in the source code.</p>
+
+<p>That said, the Mythical Man-Month's "build one to throw away" advice points
+out that until you've solved the problem you don't properly understand it, and
+about the time you finish your first version is when you've finally figured
+out what you _should_ have done.  (The corrolary is that if you build one
+expecting to throw it away, you'll actually wind up throwing away two.  You
+don't understand the problem until you _have_ solved it.)</p>
+
+<p>Joel is talking about what closed source software can afford to do: Code
+that works and has been paid for is a corporate asset not lightly abandoned.
+Open source software can afford to re-implement code that works, over and
+over from scratch, for incremental gains.  Before toybox, the unix command line
+has already been reimplemented from scratch several times (the
+original AT&amp;T Unix command line in assembly and then in C, the BSD
+versions, Coherent was the first full from-scratch Unix clone in 1980,
+Minix was another clone which Linux was inspired by and developed under,
+the GNU tools were yet another rewrite intended for use in the stillborn
+"Hurd" project, BusyBox was still another rewrite, and more versions
+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>
+
+<b><h2>Portability issues</h2></b>
+
+<b><h3>Platforms</h3></b>
+<p>Toybox should run on Android (all commands with musl-libc, as large a subset
+as practical with bionic), and every other hardware platform Linux runs on.
+Other posix/susv4 environments (perhaps MacOS X or newlib+libgloss) are vaguely
+interesting but only if they're easy to support; I'm not going to spend much
+effort on them.</p>
+
+<p>I don't do windows.</p>
+
+<p>We depend on C99 and posix-2008 libc features such as the openat() family of
+functions. We also assume certain "modern" linux kernel behavior such
+as large environment sizes (linux commit b6a2fea39318, went into 2.6.22
+released July 2007). In theory this shouldn't prevent us from working on
+older kernels or other implementations (ala BSD), but we don't police their
+corner cases.</p>
+
+<b><h3>32/64 bit</h3></b>
+<p>Toybox should work on both 32 bit and 64 bit systems. 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_
+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
+and MacOS X both implement, and which modern 64 bit processors such as
+x86-64 were <a href=http://www.pagetable.com/?p=6>designed for</a>).  See
+<a href=http://www.unix.org/whitepapers/64bit.html>the LP64 standard</a> and
+<a href=http://www.unix.org/version2/whatsnew/lp64_wp.html>the LP64
+rationale</a> for details.</p>
+
+<p>Note that Windows doesn't work like this, and I don't care.
+<a href=http://blogs.msdn.com/oldnewthing/archive/2005/01/31/363790.aspx>The
+insane legacy reasons why this is broken on Windows are explained here.</a></p>
+
+<b><h3>Signedness of char</h3></b>
+<p>On platforms like x86, variables of type char default to unsigned.  On
+platforms like arm, char defaults to signed.  This difference can lead to
+subtle portability bugs, and to avoid them we specify which one we want by
+feeding the compiler -funsigned-char.</p>
+
+<p>The reason to pick "unsigned" is that way we're 8-bit clean by default.</p>
+
+<p><h3>Error messages and internationalization:</h3></p>
+
+<p>Error messages are extremely terse not just to save bytes, but because we
+don't use any sort of _("string") translation infrastructure. (We're not
+translating the command names themselves, so we must expect a minimum amount of
+english knowledge from our users, but let's keep it to a minimum.)</p>
+
+<p>Thus "bad -A '%c'" is
+preferable to "Unrecognized address base '%c'", because a non-english speaker
+can see that -A was the problem (giving back the command line argument they
+supplied). A user with a ~20 word english vocabulary is
+more likely to know (or guess) "bad" than the longer message, and you can
+use "bad" in place of "invalid", "inappropriate", "unrecognized"...
+Similarly when atolx_range() complains about range constraints with
+"4 < 17" or "12 > 5", it's intentional: those don't need to be translated.</p>
+
+<p>The strerror() messages produced by perror_exit() and friends should be
+localized by libc, and our error functions also prepend the command name
+(which non-english speakers can presumably recognize already). Keep the
+explanation in between to a minimum, and where possible feed back the values
+they passed in to identify _what_ we couldn't process.
+If you say perror_exit("setsockopt"), you've identified the action you
+were trying to take, and the perror gives a translated error message (from libc)
+explaining _why_ it couldn't do it, so you probably don't need to add english
+words like "failed" or "couldn't assign".</p>
+
+<p>All commands should be 8-bit clean, with explicit
+<a href=http://yarchive.net/comp/linux/utf8.html>UTF-8</a> support where
+necessary. Assume all input data might be utf8, and at least preserve
+it and pass it through. (For this reason, our build is -funsigned-char on
+all architectures; "char" is unsigned unless you stick "signed" in front
+of it.)</p>
+
+<p>Locale support isn't currently a goal; that's a presentation layer issue
+(I.E. a GUI problem).</p>
+
+<p><h3>Shared Libraries</h3></p>
+
+<p>Toybox's policy on shared libraries is that they should never be
+required, but can optionally be used to improve performance.</p>
+
+<p>Toybox should provide the command line utilities for
+<a href=roadmap.html#dev_env>self-hosting development evirionments</a>,
+and an easy way to set up "hermetic builds" (I.E. builds which provide
+their own dependencies, isolating the build logic from host command version
+skew with a simple known build environment). In both cases, external
+dependencies defeat the purpose.</p>
+
+<p>This means toybox should provide full functionality without relying
+on any external dependencies (other than libc). But toybox may optionally use
+libraries such as zlib and openssl to improve performance for things like
+deflate and sha1sum, which lets the corresponding built-in implementations
+be simple (and thus slow). But the built-in implementations need to exist and
+work.</p>
+
+<p>(This is why we use an external https wrapper program, because depending on
+openssl or similar to be linked in would change the behavior of toybox.)</p>
+
+<a name="codestyle" />
+<h2>Coding style</h2>
+
+<p>The real coding style holy wars are over things that don't matter
+(whitespace, indentation, curly bracket placement...) and thus have no
+obviously correct answer. As in academia, "the fighting is so vicious because
+the stakes are so small". That said, being consistent makes the code readable,
+so here's how to make toybox code look like other toybox code.</p>
+
+<p>Toybox source uses two spaces per indentation level, and wraps at 80
+columns. (Indentation of continuation lines is awkward no matter what
+you do, sometimes two spaces looks better, sometimes indenting to the
+contents of a parentheses looks better.)</p>
+
+<p>I'm aware this indentation style creeps some people out, so here's
+the sed invocation to convert groups of two leading spaces to tabs:</p>
+<blockquote><pre>
+sed -i ':loop;s/^\( *\)  /\1\t/;t loop' filename
+</pre></blockquote>
+
+<p>And here's the sed invocation to convert leading tabs to two spaces each:</p>
+<blockquote><pre>
+sed -i ':loop;s/^\( *\)\t/\1  /;t loop' filename
+</pre></blockquote>
+
+<p>There's a space after C flow control statements that look like functions, so
+"if (blah)" instead of "if(blah)". (Note that sizeof is actually an
+operator, so we don't give it a space for the same reason ++ doesn't get
+one. Yeah, it doesn't need the parentheses either, but it gets them.
+These rules are mostly to make the code look consistent, and thus easier
+to read.) We also put a space around assignment operators (on both sides),
+so "int x = 0;".</p>
+
+<p>Blank lines (vertical whitespace) go between thoughts. "We were doing that,
+now we're doing this." (Not a hard and fast rule about _where_ it goes,
+but there should be some for the same reason writing has paragraph breaks.)</p>
+
+<p>Variable declarations go at the start of blocks, with a blank line between
+them and other code. Yes, c99 allows you to put them anywhere, but they're
+harder to find if you do that. If there's a large enough distance between
+the declaration and the code using it to make you uncomfortable, maybe the
+function's too big, or is there an if statement or something you can
+use as an excuse to start a new closer block?</p>
+
+<p>If statments with a single line body go on the same line if the result
+fits in 80 columns, on a second line if it doesn't. We usually only use
+curly brackets if we need to, either because the body is multiple lines or
+because we need to distinguish which if an else binds to. Curly brackets go
+on the same line as the test/loop statement. The exception to both cases is
+if the test part of an if statement is long enough to split into multiple
+lines, then we put the curly bracket on its own line afterwards (so it doesn't
+get lost in the multple line variably indented mess), and we put it there
+even if it's only grouping one line (because the indentation level is not
+providing clear information in that case).</p>
+
+<p>I.E.</p>
+
+<blockquote>
+<pre>
+if (thingy) thingy;
+else thingy;
+
+if (thingy) {
+  thingy;
+  thingy;
+} else thingy;
+
+if (blah blah blah...
+    && blah blah blah)
+{
+  thingy;
+}
+</pre></blockquote>
+
+<p>Gotos are allowed for error handling, and for breaking out of
+nested loops. In general, a goto should only jump forward (not back), and
+should either jump to the end of an outer loop, or to error handling code
+at the end of the function. Goto labels are never indented: they override the
+block structure of the file. Putting them at the left edge makes them easy
+to spot as overrides to the normal flow of control, which they are.</p>
+
+<p>When there's a shorter way to say something, we tend to do that for
+consistency. For example, we tend to say "*blah" instead of "blah[0]" unless
+we're referring to more than one element of blah. Similarly, NULL is
+really just 0 (and C will automatically typecast 0 to anything, except in
+varargs), "if (function() != NULL)" is the same as "if (function())",
+"x = (blah == NULL);" is "x = !blah;", and so on.</p>
+
+<p>The goal is to be
+concise, not cryptic: if you're worried about the code being hard to
+understand, splitting it to multiple steps on multiple lines is
+better than a NOP operation like "!= NULL". A common sign of trying to
+hard is nesting ? : three levels deep, sometimes if/else and a temporary
+variable is just plain easier to read. If you think you need a comment,
+you may be right.</p>
+
+<p>Comments are nice, but don't overdo it. Comments should explain _why_,
+not how. If the code doesn't make the how part obvious, that's a problem with
+the code. Sometimes choosing a better variable name is more revealing than a
+comment. Comments on their own line are better than comments on the end of
+lines, and they usually have a blank line before them. Most of toybox's
+comments are c99 style // single line comments, even when there's more than
+one of them. The /* multiline */ style is used at the start for the metadata,
+but not so much in the code itself. They don't nest cleanly, are easy to leave
+accidentally unterminated, need extra nonfunctional * to look right, and if
+you need _that_ much explanation maybe what you really need is a URL citation
+linking to a standards document? Long comments can fall out of sync with what
+the code is doing. Comments do not get regression tested. There's no such
+thing as self-documenting code (if nothing else, code with _no_ comments
+is a bit unfriendly to new readers), but "chocolate sauce isn't the answer
+to bad cooking" either. Don't use comments as a crutch to explain unclear
+code if the code can be fixed.</p>
+
+<!--#include file="footer.html" -->
diff --git a/toybox/www/ext2.html b/toybox/www/ext2.html
new file mode 100644
index 0000000..28bd6cd
--- /dev/null
+++ b/toybox/www/ext2.html
@@ -0,0 +1,108 @@
+<title>Rob's ext2 documentation</title>
+
+<p>This page focuses on the ext2 on-disk format.  The Linux kernel's filesystem
+implementation (the code to read and write it) is documented in the kernel
+source, Documentation/filesystems/ext2.txt.</p>
+
+<p>Note: for our purposes, ext3 and ext4 are just ext2 with some extra data
+fields.</p>
+
+<h2>Overview</h2>
+
+<h2>Blocks and Block Groups</h2>
+
+<p>Every ext2 filesystem consists of blocks, which are divided into block
+groups.  Blocks can be 1k, 2k, or 4k in length.<super><a href="#1">[1]</a></super>
+All ext2 disk layout is done in terms of these logical blocks, never in
+terms of 512-byte logical blocks.</p>
+
+<p>Each block group contains as many blocks as one block can hold a
+bitmap for, so at a 1k block size a block group contains 8192 blocks (1024
+bytes * 8 bits), and at 4k block size a block group contains 32768 blocks.
+Groups are numbered starting at 0, and occur one after another on disk,
+in order, with no gaps between them.</p>
+
+<p>Block groups contain the following structures, in order:</p>
+
+<ul>
+<li>Superblock (sometimes)</li>
+<li>Group table (sometimes)</li>
+<li>Block bitmap</li>
+<li>Inode bitmap</li>
+<li>Inode table</li>
+<li>Data blocks</li>
+</ul>
+
+<p>Not all block groups contain all structures.  Specifically, the first two
+(superblock and group table) only occur in some groups, and other block
+groups start with the block bitmap and go from there.  This frees up more
+data blocks to hold actual file and directory data, see the superblock
+description for details.</p>
+
+<p>Each structure in this list is stored in its' own block (or blocks in the
+case of the group and inode tables), and doesn't share blocks with any other
+structure.  This can involve padding the end of the block with zeroes, or
+extending tables with extra entries to fill up the rest of the block.</p>
+
+<p>The linux/ext2_fs.h #include file defines struct ext2_super_block,
+struct ext2_group_desc, struct ext2_inode, struct ext2_dir_entry_2, and a lot
+of constants.  Toybox doesn't use this file directly, instead it has an e2fs.h
+include of its own containting cleaned-up versions of the data it needs.</p>
+
+<h2>Superblock</h2>
+
+<p>The superblock contains a 1024 byte structure, which toybox calls
+"struct ext2_superblock".  Where exactly this structure is to be found is
+a bit complicated for historical reasons.</p>
+
+<p>For copies of the superblock stored in block groups after the first,
+the superblock structure starts at the beginning of the first block of the
+group, with zero padding afterwards if necessary (I.E. if the block size is
+larger than 1k).  In modern "sparse superblock" filesystems (everything
+anyone still cares about), the superblock occurs in group 0 and in later groups
+that are powers of 3, 5, and 7.  (So groups 0, 1, 3, 5, 7, 9, 25, 27, 49, 81,
+125, 243, 343...)  Any block group starting with a superblock will also
+have a group descriptor table, and ones that don't won't.</p>
+
+<p>The very first superblock is weird.  This is because if you format an entire
+block device (rather than a partition), you stomp the very start of the disk
+which contains the boot sector and the partition table.  Back when ext2 on
+floppies was common, this was a big deal.</p>
+
+<p>So the very first 1024 bytes of the very first block are always left alone.
+When the block size is 1024 bytes, then that block is left alone and the
+superblock is stored in the second block instead<super><a href="#2">[2]</a>.
+When the block size is larger than 1024 bytes, the first superblock starts
+1024 bytes into the block, with the original data preserved by mke2fs and
+appropriate zero padding added to the end of the block (if necessary).</p>
+
+<h2>Group descriptor table</h2>
+<h2>Block bitmap</h2>
+<h2>Inode bitmap</h2>
+<h2>Inode table</h2>
+<h2>Data blocks</h2>
+
+<h2>Directories</h2>
+
+<p>For performance reasons, directory entries are 4-byte aligned (rec_len is
+a multiple of 4), so up to 3 bytes of padding (zeroes) can be added at the end
+of each name.  (This affects rec_len but not the name_len.)</p>
+
+<p>The last directory entry in each block is padded up to block size.  If there
+isn't enough space for another struct ext2_dentry the last </p>
+
+<p>Question: is the length stored in the inode also padded up to block size?</p>
+
+<hr />
+<p><a name="1" />Footnote 1: On some systems blocks can be larger than 4k, but
+for implementation reasons not larger than PAGE_SIZE.  So the Alpha can have
+8k blocks but most other systems couldn't mount them, thus you don't see this
+out in the wild much anymore.</p>
+
+<p><a name="2" />Footnote 2: In this case, the first_data_block field in the
+superblock structure will be set to 1.  Otherwise it's always 0.  How this
+could POSSIBLY be useful information is an open question, since A) you have to
+read the superblock before you can get this information, so you know where
+it came from, B) the first copy of the superblock always starts at offset 1024
+no matter what, and if your block size is 1024 you already know you skipped the
+first block.</p>
diff --git a/toybox/www/faq.html b/toybox/www/faq.html
new file mode 100755
index 0000000..52ea6f5
--- /dev/null
+++ b/toybox/www/faq.html
@@ -0,0 +1,42 @@
+<html><head><title>toybox news</title>
+<!--#include file="header.html" -->
+
+<h2>Q: "Why is there toybox? What was wrong with busybox?"</h2>
+
+<p>A: To answer the first part: Toybox dates back to when its maintainer
+<a href=https://lwn.net/Articles/202106/>handed off BusyBox maintainership</a>
+and <a href=http://landley.net/notes-2006.html#28-09-2006>started over from
+scratch</a> on a new codebase after a
+<a href=http://lists.busybox.net/pipermail/busybox/2006-September/058617.html>protracted licensing argument</a> took all the fun out of
+working on BusyBox. Toybox was just a personal project until it got
+<a href=https://lwn.net/Articles/478308/>relicensed years
+later</a> after its author did a lot of thinking
+<a href=http://landley.net/talks/ohio-2013.txt>about licenses</a>
+and about <a href=http://landley.net/notes-2011.html#21-03-2011>the
+transition to smartphones</a>. This led to the
+<a href=http://landley.net/talks/celf-2013.txt>2013</a>
+<a href=https://www.youtube.com/watch?v=SGmtP5Lg_t0>talk</a> laying
+out a strategy to make Android self-hosting, which helped
+<a href=https://code.google.com/p/android/issues/detail?id=76861>bring
+it to Android's attention</a>, and they
+<a href=https://lwn.net/Articles/629362/>merged it</a> into Android M.</p>
+
+<p>To answer the second part: BusyBox predates Android
+by almost a decade, but Android still doesn't ship with it because GPLv3 came
+out around the same time Android did and caused many people to throw
+out the GPLv2 baby with the GPLv3 bathwater.
+Android <a href=https://source.android.com/source/licenses.html>explicitly
+discourages</a> use of GPL and LGPL licenses in its products, and has gradually
+reimplemented historical GPL components such as its bluetooth stack under the
+Apache license. Similarly, Apple froze xcode at the last GPLv2 releases
+(GCC 4.2.1 with binutils 2.17) for over 5 years while it sponsored the
+development of new projects (clang/llvm/lld) to replace them,
+implemented its SMB server from scratch to replace samba,
+<a href=http://meta.ath0.com/2012/02/05/apples-great-gpl-purge/>and so
+on</a>. Toybox itself exists because somebody with in a legacy position
+just wouldn't shut up about GPLv3, otherwise its maintainer would probably
+still happily be maintaining BusyBox. (For more on how said maintainer wound
+up working on busybox in the first place,
+<a href=http://landley.net/aboriginal/history.html>see here</a>.)</p>
+
+<!--#include file="footer.html" -->
diff --git a/toybox/www/footer.html b/toybox/www/footer.html
new file mode 100644
index 0000000..3902e27
--- /dev/null
+++ b/toybox/www/footer.html
@@ -0,0 +1,4 @@
+</td></tr></table>
+</table>
+</body>
+</html>
diff --git a/toybox/www/header.html b/toybox/www/header.html
new file mode 100644
index 0000000..8c96800
--- /dev/null
+++ b/toybox/www/header.html
@@ -0,0 +1,43 @@
+</head>
+<!-- body style="background: url(toycans.png) repeat;" -->
+<table border=0 cellpadding=0 cellspacing=10>
+
+<tr><td valign=top>
+  <h1>toybox</h1>
+
+  <b>About</b>
+  <ul>
+    <li><a href="index.html">News</a></li>
+    <li>What is it?<br>
+      - <a href="about.html">About</a><br>
+      - <a href="roadmap.html">Roadmap</a><br>
+      - <a href="status.html">Status</a><br>
+      - <a href="help.html">Help</a><br>
+    </li>
+
+    <li>Why is it?<br>
+      <a href="http://youtu.be/SGmtP5Lg_t0">video</a>/<a href=http://landley.net/talks/celf-2013.txt>outline</a><br>
+      <a href="http://www.h-online.com/open/features/Inside-the-ToyBox-An-interview-with-Rob-Landley-1447494.html">Interview</a><br>
+    </li>
+  </ul>
+  <b>Download</b>
+  <ul>
+    <li><a href="https://github.com/landley/toybox">Source control</a></li>
+    <li><a href="downloads">Releases</a></li>
+    <li><a href="bin">Binaries</a></li>
+  </ul>
+  <b>Development</b>
+  <ul>
+    <li><a href="design.html">Design goals</a></li>
+    <li><a href="code.html">Source code walkthrough</a></li>
+    <li><a href="http://lists.landley.net/listinfo.cgi/toybox-landley.net">Mailing List</a> (<a href=http://news.gmane.org/gmane.linux.toybox>backup archive</a>)</li>
+    <li>IRC #toybox on freenode.net</li>
+    <li><a href=https://github.com/landley/toybox/commits/master.atom>Commit RSS feed</a></li>
+    <li><a href="/notes.html">Maintainer's Blog</a></li>
+    <li><a href=cleanup.html>Cleanup</a></li>
+    <li><a href=http://www.ohloh.net/p/toybox-landley>Statistics</a></li>
+  </ul>
+</td>
+
+<td valign=top>
+
diff --git a/toybox/www/index.html b/toybox/www/index.html
new file mode 120000
index 0000000..0def2f1
--- /dev/null
+++ b/toybox/www/index.html
@@ -0,0 +1 @@
+news.html
\ No newline at end of file
diff --git a/toybox/www/license.html b/toybox/www/license.html
new file mode 100755
index 0000000..15104ed
--- /dev/null
+++ b/toybox/www/license.html
@@ -0,0 +1,50 @@
+<html><head><title>Toybox License</title>
+<!--#include file="header.html" -->
+
+<h2>Toybox is released under the following "zero clause" BSD license:</h2>
+
+<blockquote>
+<p>Copyright (C) 2006 by Rob Landley &lt;rob@landley.net&gt;
+
+<p>Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.</p>
+
+<p>THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.</p>
+</blockquote>
+
+<p>The text of the above license is included in the file LICENSE in the source.</p>
+
+<h2>Why 0BSD?</h2>
+
+<p>As with <a href=https://creativecommons.org/publicdomain/zero/1.0/>CC0</a>,
+<a href=http://unlicense.org>unlicense</a>, and <a href=http://wtfpl.net/>wtfpl</a>,
+the intent is to place the licensed material into the public domain,
+which after decades of FUD (such as the time OSI's ex-lawyer compared
+<a href=http://www.cod5.org/archive/>placing code into the public domain</a> to
+<a href=http://www.linuxjournal.com/article/6225>abandoning trash by the
+side of a highway</a>) is considered somehow unsafe. But if some random third
+party
+<a href=https://github.com/mkj/dropbear/blob/master/libtomcrypt/LICENSE>takes
+public domain code</a> and slaps <a href=http://www.opensource.apple.com/source/gnuzip/gnuzip-25/gzip/gzip.c>some other license on it</a>, then it's fine.</p>
+
+<p>To work around this perception, the above license is a standard 2-clause BSD
+license <a href=https://github.com/landley/toybox/commit/ee86b1d8e25cb0ca9d418b33eb0dc5e7716ddc1e>minus the half sentence</a>
+requiring text copied verbatim into derived works. If 2BSD is
+ok, the 0BSD should be ok, despite being equivalent to placing code in the
+public domain.</p>
+
+<p>Modifying the license in this way avoids the hole android toolbox fell into where
+<a href=https://github.com/android/platform_system_core/blob/fd4c6b0a3a25921a9fe24691a695d715aecb6afe/toolbox/NOTICE>33 copies of BSD license text</a>
+were concatenated together when copyright dates changed, or the strange
+solution the busybox developers used to resolve tension between GPLv2's "no
+additional restrictions" and BSD's "you must include this large hunk of text"
+by sticking the two licenses at
+<a href=http://git.busybox.net/busybox/tree/networking/ping.c?id=887a1ad57fe978cd320be358effbe66df8a068bf>opposite ends of the file</a> and hoping nobody
+noticed.</a>
+<!--#include file="footer.html" -->
diff --git a/toybox/www/news.html b/toybox/www/news.html
new file mode 100644
index 0000000..8825475
--- /dev/null
+++ b/toybox/www/news.html
@@ -0,0 +1,1788 @@
+<html><head><title>toybox news</title>
+<!--#include file="header.html" -->
+
+<p>Toybox combines common Linux command line utilities together
+into a single BSD-licensed executable that's simple, small, fast,
+reasonably standards-compliant, and powerful enough to turn Android into
+a development environment. See the links on the left for details.</p>
+
+<h2>News</h2>
+
+<a name="02-02-2016" /><a href="#02-02-2016"><hr><h2><b>February 2, 2016</b></h2></a>
+<blockquote><p>"I checked it very thoroughly," said the computer, "and that
+quite definitely is the answer. I think the problem, to be quite honest with
+you, is that you've never actually known what the question is."
+- The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.7.0.tar.gz>Toybox 0.7.0</a>
+(<a href=https://github.com/landley/toybox/releases/tag/0.7.0>git commit</a>)
+is out.</p>
+
+<p>The new commands in defconfig are <b>iotop</b>, <b>top</b>, <b>pgrep</b>,
+and <b>pkill</b>
+(most replacing corresponding versions from pending). Added grep -ABC,
+swapon -d (discard), mkswap -L (label) and UUID support, and find -delete.
+Izabera added free -h and unshare -f. Josh Gao implemented tail -f.
+Jose Bollo submitted cp --preserve=context,attr. Kylie McClain added
+mktemp -u.</p>
+
+<p>In pending there's the start of a vi command, and Sameer Pradhan contributed
+a new dhcp6. This cycle saw several rounds of route cleanup and a little dhcp
+cleanup, but neither are complete yet. Lipi Lee did some cleanup to netstat.c
+and Elliott Hughes removed warnings from traceroute.</p>
+
+<p>Lots of updates to ps: several new -o options, -k (--sort) -O and -M,
+improved compatibility with Android's historical behavior, and
+extensive internal code cleanup (including the removal of all
+the magic constants).</p>
+
+<h3><b>Website</b></h3>
+
+<p>Dreamhost restored the <a href="#12-21-2015">missing 11 months</a>
+to the mailing list archive, in the process deleting the month after
+that. Now they've asked if I have mbox files archiving the new
+gap (between December 20, 2015 to January 21, 2016, and presumably they
+could also fill in the gap from December 14, 2014 to January 3, 2015 that's
+been there since the last time they did this),
+but due to some gmail filtering I've
+<a href=http://landley.net/notes-2012.html#15-10-2012>never
+been able to disable</a>, my copy of those files is spread among 3 different
+mbox files I'd have to sort/filter/collate. (It's on the todo list.)</p>
+
+<p>Added a code of conduct to the README (we're
+<a href=https://engineering.twitter.com/opensource/code-of-conduct>borrowing twitter's</a>) because somebody
+made it necessary.</p>
+
+<h3><b>Bugfixes</b></h3>
+<p>Fixed another sed bug where any ] right after [ was skipped (not just the
+first one in the range, so [[] didn't terminate). Fixed sort -f and added test cases.
+Assume 80 columns in "ls -m | cat", ls -L is no longer backwards,
+and ls of files with no paths no longer uses an uninitialized (zero) dirfd.
+Several bugfixes
+to find (Gilad Arnold fixed -perm, Daniel K. Levy fixed "find . -exec echo {}",
+and while we're there I fixed find --prune, made "find . -execdir
+echo {} + -execdir ls {} +" work, and ripped out the environment size
+measuring code that checked for a 128k limit removed back in linux 2.6.22).
+Elliott Hughes fixed the date command's parsing of 4 digit
+years and documented the %s escape, fixed hwclock -u, and pointed out
+that runcon needs to exec to do its job (not recursively call another
+command_main() in the same process). Tom Marshall reported that blkid was
+handling ext2 wrong. Mike Moreton corrected cpio extraction's uid and gid
+values, and added a --no-preserve-owner option. Fixed the SUID permission
+dropping logic (which was a bit over-zealous, preventing some commands from
+running at all).</p>
+
+<p>I'm told that debian-testing broke its libc so the nsenter build breaks,
+but my attempts to install the debian-testing network cd image under
+qemu keep breaking. Maybe someday they'll fix it enough I can actually
+reproduce the problem. (Debootstrap under unbuntu builds an ubuntu-flavored
+chroot in which toybox builds fine.)</p>
+
+<h3><b>Documentation</b></h3>
+<p>Rewrite of the about.html page, tweaks to design.html, and a re-triage of
+sbase in roadmap.html. Update to mkstatus.py to collate multiple span
+tags with the same id, resulting in a larger status.html page (which
+was previously ignoring some commands in the roadmap).</p>
+
+<p>Expanded the defconfig/allyesconfig/allnoconfighelp text in "make help"
+to explain what they're for.</p>
+
+<h3><b>infrastructure</b></h3>
+<ul>
+<li><p>Expanded toys.optargs to 64 bits so a command can have more than 32 options.</p></li>
+<li><p>Added NOEXIT() wrapper to turn xwrap() functions into warning versions
+using the existing longjump(toys.rebound) infrastructure.</p></li>
+<li><p>Renamed dirtree->data to dirfd and stopped storing symlink length
+into it (this fixed a bug where following symlinks to directories
+didn't give a valid directory filehandle, noticeable with ls -Z).</p></li>
+<li><p>New TAGGED_ARRAY() infrastructure generates index and bitmask macros
+for arrays of structures starting with a name string.</p></li>
+<li><p>New lib/linestack.c for utf8 fontmetrics (draw_str() and utf8len()
+and so on), and for tracking multiple lines of text
+(vi, less, shell history) that need wordwrapping and scrolling up/down.</p></li>
+<li><p>Upgrades to lib/interestingtimes.c: scan_key() now has a timeout
+in miliseconds and recognizes more sequences including ANSI
+window size probes. New utf8 test files in tests/files/utf8 including
+sequence reversing, stacked combining chars, and all three types of
+unprintable sequences (low ascii <32 ala ^X, invalid utf8 sequences ala
+<AB><CD>, and invalid unicode code points ala U+1234).</p></li>
+<li><p>More comma handling code in lib.c: comma_args()</p></li>
+<li><p>Added error_msg_raw() to shut up fortify's endless static checking false
+positives.</p></li>
+<li><p>readfileat() can now realloc() in a loop to read long files
+("zcat | insmod" needed it).</p></li>
+</ul>
+
+<h3><b>Roadmap</b></h3>
+<p>We're getting close to having a self-hosting development environment
+using toybox for the command line. The remaining busybox commands in
+<a href=http://landley.net/aboriginal/about.html>Aboriginal Linux</a> are:</p>
+
+<blockquote><p><b>
+awk bunzip2 bzcat bzip2 dd diff expr fdisk ftpd ftpget ftpput gunzip gzip
+less ping route sh sha512sum tar test tr unxz vi wget xzcat zcat
+</b></p></blockquote>
+
+<p>And the remaining non-busybox commands in Aboriginal Linux's build/host
+directory (from the distcc, genext2fs, e2fsprogs, zlib, and squashfs packagesi)
+are:</p>
+
+<blockquote><p><b>
+mke2fs fsck.ext2 resize2fs distcc genext2fs unsquashfs distccd mksquashfs tune2fs
+</b></p></blockquote>
+
+<p>Squashfs and distcc are probably out of scope for toybox, but mke2fs,
+fsck.ext2, resize2fs, genext2fs, and tune2fs should all be added to the
+above "busybox" replacement list.</p>
+
+<p>Remind me to include this countdown in future releases. Once they've all
+been replaced, the next goal is <a href=http://landley.net/aboriginal/about.html#selfhost>building AOSP under itself</a>.</p>
+
+<p>See the full <a href=roadmap.html>roadmap</a> and <a href=status.html>status</a>
+pages for more details.</p>
+
+<a name="12-21-2015" /><a href="#12-21-2015"><hr><h2><b>December 21, 2015</b></h2></a>
+
+<p>Yes, 11 months have gone missing from the mailing list web archive.</p>
+
+<p>Yesterday evening Dreamhost's mailman server went down (timing out trying
+to connect). I poked them about it, they
+<a href=https://twitter.com/landley/status/678781271670149121>blamed
+DNS</a>, I explained that the hang was _after_ the DNS lookup and
+entered the dig info into the trouble ticket showing the IPs the DNS
+queries were returning, they reinstalled the server at that IP from what I
+assume was their most recent backup, and that's how 11 months of messages
+vanished out of the archive.</p>
+
+<p>I've <a href=https://twitter.com/landley/status/679114451975467008>continued to poke them about it</a> but I honestly believe that's the best they
+can do. <a href=http://landley.net/dreamhost.txt>Last time</a>
+this sort of thing <a href=http://landley.net/dreamhost2.txt>happened</a>
+we went back and forth for months, so I added a link to a backup web
+archive (in the nav bar on the left) that isn't controlled by dreamhost,
+and thus doesn't gratuitously lose data on a regular basis. (I note
+the earlier hole in Dreamhost's archive was never fixed either. That
+was data never getting archived, this is a year's worth of data that
+was in the archive until yesterday vanishing after the fact.)</p>
+
+<p>If you're wondering why the <a href=http://lists.landley.net>top level</a>
+list page has been "temporarily disabled" for multiple years now... you'd have
+to ask Dreamhost. I know I have. More than a dozen times.</p>
+
+<a name="03-11-2015" /><a href="#03-11-2015"><hr><h2><b>November 3, 2015</b></h2></a>
+<blockquote><p>"Alright," said Ford. "How would you react if I said that I'm
+not from Guildford after all, but from a small planet somewhere in the vicinity
+of Betelgeuse?" Arthur shrugged in a so-so sort of way. "I don't know," he
+said, taking a pull of beer. "Why - do you think it's the sort of thing you're
+likely to say?" - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.6.1.tar.gz>Toybox 0.6.1</a>
+(<a href=https://github.com/landley/toybox/releases/tag/0.6.1>git commit</a>)
+is out.</p>
+
+<p>We have a new <b>ps</b> command with all the -o fields posix wants (although
+it doesn't accept BSD non-dash option syntax yet), and <b>bunzip2</b> (not just
+bzcat but the proper extract-in-place command).
+Sameer Pradhan added <b>hostid</b> and <b>fsync</b>.
+Elliott Hughes added <b>flock</b>.
+
+<p>The people waiting for <b>human readable number support</b> (du -hH, ls -h,
+and so on) can thank Elliott Hughes for implementing it. (Our output doesn't
+exactly match others' because we our "binary" mode will say 1.0G instead of
+1024M, which is a bug in the other one we didn't emulate.)</p>
+
+<p>The other big news is <b>nommu support</b>, tested on the new
+<a href=http://nommu.org/jcore>jcore</a> processor but presumaby working
+on any nommu system. A few commands don't support nommu yet, but those
+are disabled by dependencies on TOYBOX_FORK in menuconfig when building
+for nommu. The roadmap now has a large section analyzing the uClinux
+project (note that <a href=http://nommu.org>nommu.org</a> is slowly replacing
+<a href=http://uclinux.org>uclinux.org</a> as the standard repository of
+all knowledge and wisdom about nommu. The old site <a href=#12-02-2012>contains
+much that is apocryphal</a>, or at least wildly inaccurate, and the new one
+is trying to improve on that).</p>
+
+<p>Both "make change" and scripts/single.sh (for building standalone commands
+without the multiplexer logic) now use the top level .config
+for toybox global settings such as Linux Security Blanket Module selection,
+(so make defconfig before change now).</p>
+
+<p>Documentation updates to the <a href=code.html>code</a> and
+<a href=roadmap.html>roadmap</a> pages.</p>
+
+<h3>pending</h3>
+
+<p>In the pending directory Sameer Pradhan added tftp,
+and Elliott Hughes sent lsof. Isaac Dunham upgraded mdev,
+reboot, init, login, and modprobe, and fixed a distro-specific build break in
+scripts/mkflags.h. Elliott Hughes and Lipi Lee made netstat -p handle
+command lines longer than 21 characters, and Elliott fixed netstat -e and
+some build warnings. Yeongdeok Suh fixed a warning in dhcpd.
+I started cleanup on pgrep/pkill.</p>
+
+<h3>Command updates, bugfixes, and infrastructure</h3>
+
+<p>The multiplexer's "command not found" error exit is now 127, so now you can't
+distinguish between a command not being found in the multiplexer and
+the multiplexer itself not being found by the shell, because people wanted
+that for some reason.</p>
+
+<p>Elliott Hughes made date reject invalid dates rather
+than set the clock to something weird (setting the clock 100 years into the
+future makes most Linux desktops surprisingly unhappy, and ntpdate won't fix it
+either), fixed several ls -l display issues (user/group field ordering,
+make user/group/lsmcontext left aligned), did the aforementioned
+extensive work on human readable number output, fixed ionice's default
+class, fixed a mv overwrite bug, made df's columns auto-size, added
+--ppid and -Z to ps, and teamed up with Daniel K. Levy to fix
+a segfault in find's handling of -newer -group or -user.</p>
+
+<p>Hyejin Kim added stat -c %T support. Colin Cross worked
+on vmstat fixing
+a header printing bug and calculating the bi and bo columns in the right
+units. Isabella Parakiss reported that sed -e "/x/c\" -e "y" added an extra
+newline and that grep -w '\(x\)\1' didn't work, both now fixed.
+Alistair Strachan fixed several problems with switch_root. Kylie McClain
+pointed out env should be able to clear variables via NAME= syntax.
+Dima Krasner added support for running blkid without a partition (so it shows
+all partitions). Hyejin Kim sent in a bunch of static analysis bug reports.</p>
+
+<p>Isabella Parakiss reported that sed -e "/x/c\" -e "y" added an extra
+newline and that grep -w '\(x\)\1' didn't work, both now fixed.
+Alistair Strachan fixed several problems with switch_root. Kylie McClain
+pointed out env should be able to clear variables via NAME= syntax.
+Dima Krasner added support for running blkid without a partition (so it shows
+all partitions). Hyejin Kim sent in a bunch of static analysis bug reports.</p>
+
+<p>Two large thinko fixes in oneit: -3 was always enabled (which would
+eventually block if the child never read the exiting PID numbers from its file
+descriptor #3 until the pipe filled up), and the signal handlers weren't
+set up right (for requesting semi-graceful halt/poweroff/reboot).
+Calling install without a mode is now 0755, and install -g 0 no longer clashes
+with cp --preserve. Better error message for ls -r on unreadable
+directories, and ls -Z now uses O_PATH (with the /proc/self/fd/%d
+workaround for kernel stupidity as necessary).</p>
+
+<p>Date now understands @unixtime[.fraction] and uses -D for
+the set-side format (matching busybox's extension for this). The seq -f
+string now checks that it's got exactly one %f escape with the correct
+attributes (and a whole bunch of test cases for it). Fixed a bug
+in od that screwed up the position indicator on arm and mips.
+In stat the d/h units moved from %d %D to the default string.
+And patch can now correctly apply hunks with trailing context to the start of
+the file.</p>
+
+<p>The prompt argument moved out of yesno() (the caller can print the prompt
+themselves). Replaced toys.exithelp with help_exit(). Added new
+XVFORK() macro, and xpopen_both() calls /proc/self/exe when passed
+a NULL argv (see cpio -p for example usage). Replaced toys.recurse
+with toys.stacktop so the recurse or re-exec decision is now based
+on bytes of stack space used. Marked a bunch of command-local functions
+static.</p>
+
+<p>New additions to lib/ include strlower(), xconnect(), and the
+aforementioned help_exit().
+The testsuite now has some infrastructure tests based on "example"
+commands such as toys/examples/test_human_readable.c.
+The login command finally got a long-overdue cleanup (it's one of the
+commands that predate the "pending" directory but were part of the reason
+for it). Hexedit had an
+uninitialized variable (of course gcc didn't spot it, it was too busy
+warning about "may be used uninitialized but never actually is" variables).</p>
+
+<p>Tweaked makefile so
+"make CROSS_COMPILE=prefix-" (as well as "CROSS_COMPILE=prefix- make",
+which still works). Toybox is now installed chmod -w so broken installers
+(like the bunzip2 package's) that try to overwrite existing binaries won't
+knock out the whole of toybox.
+GCC 5.2.0 stopped being able to compile Linux 2.6.12's kconfig, but
+we added a workaround. You can now build uptime without utmpx.h.
+Alejandro Joya pointed out that enabling smack required smack on the host
+as well as target when cross compiling, which is now fixed.</p>
+
+<p>Note: toybox can autodetect nommu support when building with a uClibc
+toolchain such as <a href=http://landley.net/aboriginal/downloads/binaries/old/1.4.3/cross-compiler-sh2eb.tar.gz>the one from Aboriginal Linux</a>,
+but <a href=http://github.com/richfelker/musl-cross-make>with musl-libc</a>
+you'll have to enable CONFIG_TOYBOX_MUSL_NOMMU_IS_BROKEN to work around the
+fact they provide a non-functional fork() implementation that always returns
+-ENOSYS, to prevent you from compile-time probing for nommu support when
+cross-compiling. Unfortunately "preventing you from probing" seems to be
+an explicit policy with musl, they also don't provide an "#ifdef __MUSL__"
+because their library is perfect and you're only ever allowed to work around
+other people's bugs, not theirs. So we have to use menuconfig to manually
+enable musl-specific bug workarounds.</p>
+
+<a name="23-07-2015" /><a href="#23-07-2015"><hr><h2><b>July 23, 2015</b></h2></a>
+<p>I recreated the <a href=downloads/toybox-0.6.0.tar.gz>0.6.0 source tarball</a>
+(new sha1sum 08fb1c23f520c25a15f262a8a95ea5b676a98d54)
+because I forgot to add --prefix to the git archive command when I updated
+my release script from mercurial, so the files weren't in an enclosing
+directory. (Ooops.)</p>
+
+<a name="19-07-2015" /><a href="#19-07-2015"><hr><h2><b>July 19, 2015</b></h2></a>
+<blockquote><p>
+The reason why it was published in the form of a micro sub meson electronic
+component is that if it were printed in normal book form, an interstellar
+hitchhiker would require several inconveniently large buildings to carry it
+around in." - The Hitchhiker's Guide to the Galaxy </p></blockquote>
+
+<p><a href=downloads/toybox-0.6.0.tar.gz>Toybox 0.6.0</a>
+(<a href=https://github.com/landley/toybox/releases/tag/0.6.0>git commit</a>)
+is out. (Yes, git. See the <a href=#05-04-2015>previous news entry</a>.)</p>
+
+<p>Sorry for the unusually long gap between releases. Since last release Ye
+Olde Project Maintainer traveled to japan twice and had two more "once
+a century" floods at home. (Probably a coincidence.) Still catching up.</p>
+
+<h3><b>CELF/ELC talk and Wikipedia[citation needed] article</b></h3>
+
+<p>I gave another State Of The Toybox talk
+(<a href=https://www.youtube.com/watch?v=04XwAbtPmAg>video</a>
+<a href=http://landley.net/talks/celf-2015.txt>outline</a>), in which I
+repeat my <a href=http://landley.net/notes-2013.html#07-11-2013>perennial</a>
+<a href=https://twitter.com/landley/status/557309224535851009>complaint</a>
+that Wikipedia[citation needed]
+<a href=http://en.wikipedia.org/wiki/Toybox>still</a>
+<a href=https://en.wikipedia.org/wiki/BusyBox#Controversy_over_Toybox>says</a>
+toybox was relicensed before its hiatus, when relicensing was why
+the hiatus ended.</p>
+
+<p>Since Wikipedia[citation needed] seems unable to do the
+<a href=#15-11-2011>most</a>
+<a href=http://landley.net/hg/toybox/log/tip/LICENSE>basic</a>
+<a href=http://landley.net/notes-2011.html#13-11-2011>research</a> on
+this point, and has stuck to an incorrect sequence of events for years,
+I've been gradually escalating my attempts to correct them. Toybox
+came out of mothballs in November 2011 <b>because</b> it could be
+relicensed. That's what opened up a new niche busybox wasn't already
+filling with a 10 year headstart.</p>
+
+<a name="asterisk_back" />
+<p>The article has plenty of smaller issues<a href=#asterisk>*</a>, but
+given that I gave an entire talk at Ohio LinuxFest in 2013
+(<a href=http://landley.net/talks/ohio-2013.txt>outline</a>,
+<a href=https://archive.org/download/OhioLinuxfest2013/24-Rob_Landley-The_Rise_and_Fall_of_Copyleft.mp3>audio</a>) on why I switched away from GPL for
+my projects, that one bugs me.</p>
+
+<h3><b>New stuff this release</b></h3>
+
+<p>There's a new android menu in menuconfig, and rather a lot of Linux
+Security Module support (Smack for Tizen from Xavier Roche and José Bollo,
+and SELinux for Android from Elliott Hughes; see
+the Security Blanket menu under global settings in menuconfig) has
+trickled in, although there's still more to come.</p>
+
+<p><b>New commands:</b> Added reset, nproc, ionice, and iorenice.
+Elliott Hughes contributed xxd, runcon,
+restorecon, load_policy, getenforce, setenforce, getprop, and setprop.
+Promoted shred, nsenter, and hwclock.</p>
+
+<p>You can once again build catv now the flag infrastructure's been updated to
+let it coexist with cat -v.
+And on a long plane flight I wrote
+hexedit, an interactive hex editor that implements the start of
+cursor control infrastructure (for eventual use by less and vi and shell
+command history and so on).</p>
+
+<p><b>New options:</b> Added sed -E as a BSD-compatible synonym for -r.
+Upgraded oneit with -r (restart), -3 (send exiting PID values to child),
+and signal handling. Added -v option to timeout, -m to mknod, -u to shred,
+-t to dmesg, and -123 to head and tail. Added implicit "." to grep -r without
+any files to work on. Hyejin Kim requested prefix support for truncate -s.
+Greg Hackman added -inum to find.
+Jan Cybulski added the smack side of ls -Z support. Various patches also
+added -Z to mkdir, mknod, and mkfifo.
+Basic cp --preserve support went in, but not yet the xattr/LSM parts.</p>
+
+<p>The toybox command now has a --version option,
+which uses "git describe" if available.</p>
+
+<p><b>Build infrastructure:</b>
+The "make change" target now saves the output of each failed standalone
+command build in a .bad file, and "make defconfig" is quieter now.</p>
+
+<p>Paul Barker submitted a large patch changing command install paths so
+"toybox can be installed alongside busybox without confusing
+update-alternatives". (There's some argument over
+what the right paths should be, and I'm waiting for
+people to tell me what else needs fixing because I have no idea. I've
+been symlinking /bin to /usr/bin since 2002
+<a href=http://landley.net/writing/hackermonthly-issue022-pg33.pdf>for
+historical reasons</a>.)</p>
+
+<p><b>Docs:</b> The repository link now goes to github, with another link
+to the commit rss feed.</p>
+
+<p>Elliott Hughes updated the Android section of the roadmap
+(and he would know). Redid bits of scripts/mkstatus.py to make updating
+status.html easier, and the README is larger.</p>
+
+<p>More description of option parsing in code.html, which now describes the
+FLAG_x macros, switching flag macro sets with FOR_newcommand, how
+configuration zeroes flag macros and using FORCE_FLAGS to suppress the
+zeroing of options shared between commands. Also added description of ";"
+to make --longopts take an optional =value part, and more about TOYBOX_DEBUG
+to check NEWTOY() option strings (otherwise a bad option string makes
+lib/args.c obviously segfault, but doesn't explain why).</p>
+
+<p>Added a "Why 0BSD?" section to license.html when submitting zero clause bsd
+to SPDX (according to the pending license spreadsheet, it's been approved for
+SPDX 2.2).</p>
+
+<p>The old list of commands needing cleanup but not in pending was
+removed from toys/pending/README and instead the issues were added
+as TODO comments in the individual commands.</p>
+
+<p><b>Bugfixes:</b>
+Fixed mount -a segfaulting without -O (reported by Janus Troelsen),
+and made it try a "become rw" ioctl() on the block device before falling
+back to mounting read only (because Android expects that).
+Fixed printf -- and printf ---. Lots of tweaks to ls -l spacing with
+different options. Make touch -d and -t actually set time when you don't
+specify nanoseconds.
+Fixed a subtle bug where recursive calls (toybox commands that run other
+toybox commands) weren't resetting all their state. (This manifested as
+a "no }" error from "find | xargs sed", but could cause other problems.)
+And David Halls reported another sed bug trying to compile libiconv (which
+left extra \ at the start of lines in a generated shell script, breaking
+the build). Output an error message for "cat /mnt".</p>
+
+<p>Kylie McClain reported that mktemp broke when $TMPDIR was set to an empty
+string (which is not the same as unset), that install/find didn't support
+numeric uid/gids, and that sort -z affects both input and output.
+Isabella Parakiss fixed a printf.c bug.
+David Halls fixed bugs in install -D and find -exec. Samuel Holland
+fixed unshare -r. Hyejin Kim fixed makedevs with a count of 1, fold -w
+range checking, an error path in scripts/mkflags.c, added -i to dhcpd,
+and stopped su from prompting the root user for the new user's password.
+Jan Cybulski spotted wrong indentation when combining ls -s and -i with -C and
+-x. José Bollo fixed stat %G. Sameer Pradhan fixed a bug in mkfifo -Z.</p>
+
+<p>Elliott Hughes asked for a default SIGPIPE handler to disable
+the signal handler bionic's dynamic loader installs (yes really). Still not
+100% sure what the correct behavior is there. (Posix is
+(<a href=http://permalink.gmane.org/gmane.comp.standards.posix.austin.general/10915>actively unhelpful</a>, but at least they're taking
+<a href=http://austingroupbugs.net/view.php?id=789#c1976>years to
+make up their mind</a>. Elliott also sent patches to fix a typo in
+useradd.test, add missing arguments to error_exit() calls and clean up
+printf() format strings, fix an off by one error in human_readable(),
+fix dmesg -c error reporting, fix a segfault in comma_scan where the option
+was the last item in optlist (triggered by mount -o ro,remount), fix
+hwclock -w, made ifconfig print lowercase MAC addresses (it was bothering
+him), and make terminal_size() read the right environment variable
+(LINES, not ROWS). And he suggested the test suite notice high command exit
+values (corresponding to segfault or other signals).</p>
+
+<p>People are apparently using toys/pending commands, despite the police tape
+and flashing lights, so added louder warnings to toys/pending/README.
+Elliott Hughes fixed various problems with tar, dd, more, and top.
+Hyejin Kim cleaned up syslogd and dumpleases. Isaac Dunham added hotplug
+support to mdev. Yeongdeok Suh added RFC-3315 ipv6 support to dhcpd.</p>
+
+<p>I rewrote ps.c from scratch (in pending), but it's not ready for real use
+yet.</p>
+
+<p><b>Portability:</b>
+On the portability front Bernhard Rosenkranzer fixed a problem where the
+menuconfig code wouldn't compile in C99 mode. (This led to me documenting
+the craptacular nature of kconfig in a README, and the plan to replace it
+sometime before 1.0.) Some extra flags to shut up overzealous llvm warnings
+were added (and have to be probed for because gcc complains about
+arguments it doesn't recognize even when they switch stuff _off_ using
+a standard syntax). Don't depend on malloc(0) to return non-null in ls.
+David Halls fixed some mac/ios portability issues,
+implying somebody's built at least part of toybox on a mac.</p>
+
+<p>Added basename_r() to lib/lib.c because the posix semantics for basename()
+are stupid but what the gnu guys did to it was appalling.
+Turns out bionic already had a basename_r(), but posix still doesn't.
+Fixed it up in portability.h, but this
+could break more stuff in future. (Correct fix is to lobby posix to add it,
+which would probably take about 15 years...)</p>
+
+<p><b>Infrastructure:</b>
+The build now checks $LDFLAGS for linker-only flags, and allows the strip
+command to fail (binflt toolchains provide a strip that doesn't work).
+Since time.c uses floating point, added TOYBOX_FLOAT dependency in config.</p>
+
+<p>There's a lib/lsm.h defining varous inline functions for linux
+security modules stuff, if (lsm_enabled()) should turn into a compile-time
+constant 0 and let code drop out when TOYBOX_LSM_NONE selected, but
+testing against CFG_TOYBOX_LSM_NONE or derived symbols is still useful
+becuase when it _is_ enabled the probe turns into a system call you
+don't want to repeat too much.</p>
+
+<p>Switched a bunch of commands from signal() to xsignal(). Factored out
+xgetgrnamid() and xgetpwnamid() into xwrap.c. Make time.c depend on
+TOYBOX_FLOAT (since it always uses float so shouldn't be available on
+build targets without even software float). Added readfileat() to lib/lib.c.</p>
+
+<p>The dirtree infrastructure now passes in full flags for the old symlink
+field, and the new DIRTREE_SHUTUP flag disables warnings if a file vanishes
+out from under you during traverse. New dirtree_start() wrapper to
+create dirtree root with only two arguments.</p>
+
+<p>The not-curses infrastructure introduced by hexedit mostly moved to
+lib/interestingtimes.c.</p>
+
+<a name="asterisk" />
+<a href="#asterisk_back" />Asterisk:</a> such when
+Tim contacted me (my blog says a couple days before nov 13, 2011, I.E.
+11/11/11 not some specific day 2 months later) to ask if I wanted to work
+on a new project he was proposing called
+<a href=http://www.elinux.org/Busybox_replacement_project>BentoBox</a>
+(because I used to do busybox, he'd forgotten toybox existed
+until I brought it up). And don't ask me what "focuses not on compatibility
+with its GNU counterparts" means when CP_MORE adds 7 non-posix options
+and toys/other has 84 commands in neither posix nor LSB. I think they're
+struggling to explain the difference having dismissed "licensing" as being
+the reason it started up again after a long hiatus? The reason I don't think
+GNU is special is there are a half-dozen other independent
+implementations of the same unix command tools out there (AT&amp;T,
+BSD, Coherent, Minix, plan 9, busybox, toybox, and several more analyzed in
+the <a href=roadmap.html>roadmap</a>, and that's ignoring the implementations
+written for DOS or in assembly over the years). But I do care what
+Linux From Scratch expects, and if it's
+<a href=http://archive.linuxfromscratch.org/lfs-museum/7.6/LFS-BOOK-7.6-NOCHUNKS.html#ch-tools-gcc-pass1>calling mv -v</a>
+then I impelement mv -v
+even if <a href=http://landley.net/toybox/roadmap.html>posix hasn't got
+it</a>. And I don't know why "gnu counterparts" would describe this when
+util-linux isn't a gnu package, nor are info-zip, e2fsprogs, kmod, less,
+procps, shadow, sysklogd, vim, zlib, sudo, dhcpcd...</p>
+
+<a name="05-04-2015" /><a href="#05-04-2015"><hr><h2><b>April 5, 2015</b></h2></a>
+<p>Since <a href=https://android.googlesource.com/platform/external/toybox/>android</a> and
+<a href=https://git.tizen.org/cgit/platform/upstream/toybox.git>tizen</a>
+and <a href=https://github.com/kraj/meta-musl/tree/master/recipes-core/toybox>openembedded</a>
+and <a href=https://packages.gentoo.org/package/sys-apps/toybox>gentoo</a>
+and so on have all been using Georgi Chorbadzhiyski's git mirror rather
+than the mercurial repository, I bit the bullet and switched the project's repo
+<a href=https://github.com/landley/toybox>to git</a>. Georgi's
+<a href=https://github.com/gfto/toybox>mirror</a> is now pulling from that.</p>
+
+<a name="25-02-2015" /><a href="#25-02-2015"><hr><h2><b>February 25, 2015</b></h2></a>
+<blockquote><p>"A common mistake that people make when trying to design
+something completely foolproof is to underestimate the ingenuity of
+complete fools."</p><p>- The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.5.2.tar.gz>Toybox 0.5.2</a>
+(<a href=/hg/toybox/shortlog/1702>commit 1702</a>) is out.</p>
+
+<p>New promoted commands: sed (finally fixed enough it builds Linux From
+Scratch), printf (cleaned up and promoted), shred and
+base64 (the Tizen guys wanted them), getenforce, setenforce, and chcon (android),
+mix (promoted with fixes from Isaac Dunham), nsenter (from
+Andy Lutomirski, merged into unshare).</p>
+
+<p>Elliott Hughes submited a bunch of patches to support Android (to
+both toybox and Bionic libc, which he maintains). On toybox's end this
+involved a lot of fixups to portability.[ch] and fixes to over a dozen
+commands, plus several new ones. Other portability fixes included working
+with buildroot's uclibc fork and building for nommu targets.</p>
+
+<p>The new "make change" target builds each toybox command as a standalone
+binary. Rather a lot of commands that didn't build by themselves (mv depending
+on cp and so on) were hit with a large rock until they built standalone.
+This involved rewriting bits of option parsing, more elaborate dependency
+generation, making each command have its own config
+symbol and main() function (even when it's just a wrapper calling another
+command's main()), and so on. Also, some commands can't be built standalone
+at a conceptual level: "help" describes other enabled commands and "sh"
+has a number of bulitin commands (cd, exit, set) that require the
+multiplexer infrastructure, so "make change" filters them out.</p>
+
+<p>The mailing list's web archive is still screwed up. Dreamhost has
+been trying to fix it since approximately September. There are
+<a href=http://www.mail-archive.com/toybox@lists.landley.net/>two</a>
+<a href=http://news.gmane.org/gmane.linux.toybox>other</a> less broken
+archives, but neither has quite the same UI as mailman.</p>
+
+<h3>Bugfixes and tweaks</h3>
+
+<p>Cynt Rynt sent in tests for ifconfig,
+Robert Thompson taught factor to accept whitespace separated arguments,
+Hyejin Kim pointed out that some of mktemp's longopts were attached to
+the wrong short options,
+Luis Felipe Strano Moraes fixed a wrong free() call in bootchartd in pending.
+Patches from Ashwini Sharma to make "df /dev/node" work, prevent du from
+looping endlessly following symlinks, and to make expr.c
+(in pending) understand == and regex matches. (Speaking of expr, it gets
+priority groupings wrong but the bug was actually in the posix spec's
+HTML conversion. They fixed the posix spec upstream for us. Still need
+to fix the expr code, but it's in pending for a reason...)</p>
+
+<p>Some commands grew new option flags, such as cp --remove-destination
+and touch -h.</p>
+
+<p>The parallel build has better error reporting now. When toybox needs to
+re-exec itself to regain suid root permissions and hasn't got the suid bit,
+it now gives the right error message ("not root" instead of "no such command").
+
+<p>Added a test to "mount" to not mount the same device/directory combination
+over itself (the OS catches this for block devices, but not for tmpfs).
+Make blkid distinguish ext3 from ext4. Added catv back into cat (because
+the Android guys wanted it, and they have historical usage on their side,
+so...). Handle nanoseconds in touch.</p>
+
+<p>Fixed a segfault when CP_MORE was disabled (the resulting option flag list
+no longer defined -d but still had it in option groups at the end).
+Workaround for glibc redefining dirname() and basename() to random non-posix
+semantics because gnu. (They could have created dirname_r() but didn't want
+to.)</p>
+
+<p>Fix an ifconfig test that was preventing assigning an ipv4 address to
+interface aliases. Several cleanup passes on hwclock but not quite
+promoted out of pending yet.<p>
+
+<p>Fixed a wrong error message in rm (if you had a chmod 000 directory and
+did rm -r on it without -f, after the prompt it would complain it was a
+directory, which was not the problem).</p>
+
+<p>The gzip compression code now does "store only" output to stdout, for
+what that's worth.</p>
+
+<p>Cleanup mountpoint and expand, and remove them from toys/pending/README
+(a list of commands that predate the toys/pending directory but needed
+another pass).</p>
+
+<h3>Library and infrastructure:</h3>
+
+<p>Reworked the option parsing infrastructure so more commands build
+standalone (via scripts/single.sh or "make change"). The option flag bit
+values are no longer packed, it leaves spaces where currently disabled
+flags go, and you can #define FORCE_FLAGS so disabled flags aren't zeroed.
+This allows multiple commands to more easily share infrastructure, even if
+your current flag context is for a disabled command (switched off in config),
+you can force them to stay on and as long as the flags read the same right
+to left they'll have the same values.</p>
+
+<p>We've started removing use of strncpy() because it's a hugely broken
+standard C function: the length is the maximum length to _append_, not
+the size of the destination buffer. It memsets the remaining space it didn't
+copy ala "memset(dest+strlen(dest), 0, len);" so
+if you think len is the size of dest you're guaranteed to stomp memory off the
+end). And if it runs out of space it won't null terminate because reasons.
+(Meanwhile sprintf("%*s", len, str) is counting wide characters in your current
+locale, so if you set a locale other than "C" it will also go past your
+allocated buffer size. Whoever is maintining the C library standards is really
+bad at strings.)
+Instead we have xstrncat() which will error_exit() if src+dest+1 doesn't
+fit in the buffer. (Because randomly truncating input data isn't necessarily
+an improvement.) And there's always xmprintf().</p>
+
+<p>Similarly, strtol() doesn't return an error indicator on overflow,
+you have to clear and then check errno. So new xstrtol() that cares
+about overflow.</p>
+
+<p>The bionic and musl guys agree faccessat(AT_SYMLINK_NOFOLLOW) is not
+supported, so stop using it.</p>
+
+<p>Fixed toy_exec() to detect when argc is in optargs, so we don't
+need a separate xexec_optargs().</p>
+
+<a name="18-02-2015" /><a href="#18-02-2015"><hr><h2><b>February 18, 2015</b></h2></a>
+<p>Dreamhost continues to be unable to make mailing list archives work, so
+here's <a href=http://www.mail-archive.com/toybox@lists.landley.net/>another
+list archive</a> with a less awkward interface than gmane.</p>
+
+<p>(Neither gives you the convenient historical monthly views of mailman,
+but I still have hopes dreamhost will someday figure out what they're doing
+wrong. They've only been trying since October. Last month they did a
+<a href=http://www.dreamhoststatus.com/2015/01/14/discussion-list-hardware-maintenance/>hardware upgrade to fix a software problem</a>, and the stale
+data loads much faster now, so that's something.)</p>
+
+<p>Update (Feb 19): the archive started updating again, by discarding
+all the pending data. So there are now _two_ giant holes in Dreamhost's
+web archive, from Dec 15-Jan 3, and then another hole from Jan 16-Feb 18.
+The relevant messages are in both of the other archives. Here's hoping
+the chronic archive constipation problem won't happen a sixth time.</p>
+
+<a name="30-12-2014" /><a href="#30-12-2014"><hr><h2><b>December 30, 2014</b></h2></a>
+<p>Due to Dreamhost's <a href=http://landley.net/dreamhost.txt>ongoing</a>
+<a href=http://landley.net/dreamhost2.txt>inability</a> to make mailman
+work reliably, I've added a link to a backup web archive at
+<a href=http://news.gmane.org/gmane.linux.toybox>gmane</a> to the nav bar
+on the left.</p>
+
+<p>You still subscribe to the list through
+<a href=http://lists.landley.net/listinfo.cgi/toybox-landley.net>the first link</a>.</p>
+
+<p>Update (January 27, 2015): they're <a href=https://twitter.com/landley/status/558428839462703104>still working on it</a>.</p>
+
+<a name="19-11-2014" /><a href="#19-11-2014"><hr><h2><b>November 19, 2014</b></h2></a>
+
+<blockquote><p>"This time it was right, it would work, and no one would have to get nailed to anything." - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.5.1.tar.bz2>Toybox 0.5.1</a>
+(<a href=/hg/toybox/shortlog/1566>commit 1566</a>) is out.</p>
+
+<p>It's an interim release, mostly bugfixes. There are several new commands,
+but they're all in pending.</p>
+
+<h3>Development</h3>
+
+<p>Finally implemented sed, which is still in pending because although
+it's feature complete according to posix, and even passes the parts of
+Busybox's sed test suite that aren't explicitly testing for gnu bugs we
+don't want to copy, it's not yet good enough to build Linux From Scratch.
+(The ./configure stages use very long sed scripts. 20 commits worth of
+implementation and debugging, just under 1000 lines of code, and there's
+still more to do. We're definitely up to some of the "fiddly" commands now.
+Did you know "echo hello | sed p - -" segfaults gnu sed in Ubuntu 12.04?
+Yeah...)</p>
+
+<p>Talked with the Tizen developers to follow up on their desire to
+make toybox a part of the base Tizen system, and got a list of commands
+to add to the roadmap. The tizen todo list is:</p>
+
+<blockquote><p>
+wget, sha256*, gzip, gunzip, bunzip2, rsync, zdiff*,
+less, ar, arch, base64, csplit, dir, fmt, join, 
+nproc, shred, shuf, stdbuf, stty, test, tr, unexpand,
+users, vdir, diff3, sdiff, dosfsck (fsck.vfat), awk, fdisk
+</p></blockquote>
+
+<p>(Most of which was already on the todo list, but it helps prioritize.)</p>
+
+<p>Fixed md5sum and sha1sum on big endian systems (reported by James McMechan).
+Andy Lutomirski fixed unshare's help text and option parsing,
+and submitted nsenter (a tool to use setns(2)) to pending.
+Isaac Dunham implemented acpi -ctV options, and spotted the bug that ls -d
+was inappropraitely following command line symlinks without -H or -L (it
+should act like ls -l does), and ls -F handles symlinks wrong too.
+Lukasz Szpakowski sent in two bugfixes to tail.c. Cynt Rynt spotted an
+unnecessary assignment in lib/password.c.</p>
+
+<p>Ashwini Sharma's team was as busy as usual, submitting tr, crontab, and
+ipcrm, and hwclock to pending, more features to the pending ip.c, and a
+pile of bugfixes (to chgrp, killall, ifconfig, insmod,
+losetup, comm, cp, id, xwrap, netcat, modprobe, nohup...) mostly found by
+static analysis. (These fixes are mostly to seldom-used codepaths like the
+TOYBOX_FREE config option, but test coverage is always appreciated.) Ashwini
+also suggested upgrading ln -f to leave the original target alone if link
+creation fails, and reported that mv -f and -i weren't implemented (now fixed).</p>
+
+<p>New config option: TOYBOX_NORECURSE prevents xexec() from making internal
+function calls (for nommu systems with a finite stack).</p>
+
+<p>The "toybox" multiplexer command no longer adds a trailing space to each
+line of command names, so things like "./toybox | tr ' \n' '|'" to create
+a grep pattern snippet are easier to do. (Why you'd want to is your business,
+but the output is tidier now.)</p>
+
+<h3>Infrastructure</h3>
+
+<p>Isaac Dunham added Android support to portability.h, including compile
+probes for functions missing from bionic-libc, and annotated the commands that
+use those functions. We haven't really tested building against bionic,
+but in theory it's possible now.</p>
+
+<p>Running the test suite now color codes the PASS/SKIP/FAIL notifications
+if output is to a tty. (And in case you missed it last time, VERBOSE=fail
+to stop at the first failure is really useful.)</p>
+
+<p>In loopfiles_rw() use O_CLOEXEC instead of O_RDONLY to request the loop
+function close filehandles for us. (Otherwise the callback function must
+close each supplied filehandle itself.)</p>
+
+<p>The printf-style escape parsing ("\n" and friends) got factored out into
+a new unescape() function.</p>
+
+<a name="02-10-2014" /><a href="#02-10-2014"><hr><h2><b>October 2, 2014</b></h2></a>
+<blockquote><p>"There is an art, it says, or rather, a knack to flying.
+The knack lies in learning how to throw yourself at the ground and miss...
+Clearly, it is this second part, the missing, which presents the
+difficulties." - The Hitchhiker's Guide to the Galaxy.<p></blockquote>
+
+<p><a href=downloads/toybox-0.5.0.tar.bz2>Toybox 0.5.0</a>
+(<a href=/hg/toybox/shortlog/1512>commit 1512</a>) is out.</p>
+
+<h3>New commands</h3>
+
+<p>The new commands are find, install, factor, and mount. Promoted commands
+(cleaned up and moved out of "pending") are lspci, inotifyd, and blockdev.</p>
+
+<p>cp now implements -HL and -F to force delete of pending files, cpio now
+ignores -m and implements -p, ls -C now has utf8 support (using wcwidth
+instead of strlen), and umount got a number of upgrades involving
+looking things up in /proc/mounts. Other minor cleanups happend to
+cut, touch, free, and id.</p>
+
+<p>In pending: Bradley Controy submitted mix (adjusts OSS sound volume). Ashwini
+Sharma submitted diff, userdel, blockdev, ipcs, and crond, upgraded
+fdisk, fsck, and ftpget, and ran a static analyzer on a lot of other code.
+Partial cleanup was done to useradd, userdel, groupadd, and groupdel.</p>
+
+<h3>Build infrastructure</h3>
+
+<p><b>Parallel builds</b></p>
+
+<p>The build now takes advantage of SMP, autodetecting the number of
+processors. (Export the environment variable CPUS to pick a specific number.)
+Other build changes: split out $LDOPTIMIZE because old compilers complain
+about linker options passed with -c, and the entire "generated" directory now
+gets deleted by clean (the README that was in there got merged into code.html).</p>
+
+<p><b>Standalone builds</b></p>
+
+<p>The standalone build infrastructure (scripts/single.sh) got upgraded to
+build more commands as standalone executables. In make.sh the source file
+selection uses a regex to find the source files with the NEWTOY/OLDTOY macro
+for the command. It enables each command's
+sub-options (so CP has CP_MORE), enables I18N and FLOAT support to build
+full-featured commands, and includes --help text (at least when
+the command doesn't use another command's help). The OLDTOY() macro
+now produces (redundant) function prototypes so you can build an OLDTOY
+without the NEWTOY</p>
+
+<p>It doesn't quite have complete coverage yet, the defconfig entries that
+aren't building standalone yet are:</p>
+
+<blockquote><p>chown, egrep, fgrep, fstype, halt, mv, nc, poweroff, unix2dos,
+whoami</p></blockquote>
+
+<p>The main reason for standalone build failures is NEWTOY() or OLDTOY()
+entries that don't have their own config symbol. Another problem is entries
+that depend on another entry in kconfig, usually because common infrastructure
+is using one command's flags (which the other commands copy): if that command
+is disabled, the FLAG macros become 0 so dead code elimination can remove the
+code. It's <a href=http://landley.net/hg/toybox/rev/1503>possible
+to untangle</a> this, but a bit awkward. (It boils down to conflicting
+design goals in the two contexts.)</p>
+
+<p>Standalone builds are used by the test suite when testing individual
+commands.
+
+<p><b>Snapshot builds</b></p>
+
+<p>A new addition to the "generated" directory is generated/build.sh
+containing a single compiler command line to build toybox in its current
+configuration. Combined with the generated/*.{h,sh} files from an
+exisiting build, this may let you build on a new system that hasn't quite
+got enough OS bits working to run a full configureand make.</p>
+
+<h3>Internals</h3>
+
+<p>Library code: xcreate/xopen now O_CLOEXEC by default to avoid leaking
+filehandles to child processes. DIRTREE_COMEAGAIN's second callback is now
+done with the directory filehandle still open (new dir->again variable added
+to distinguish first from second callback, and requesting DIRTREE_RECURSE now
+requires passing in the specific macro value, not just a true/false).
+Use daemon() out of libc instead of hand-rolled daemonize() in various
+pending commands. string_to_mode() now passes through type bits so you can
+use it to more easily modify a file's existing mode.
+Split xpopen() into xpopen_both(), xopen(), and xrun() depending on whether
+we want to redirect both, one, or neither of stdin/stdout.</p>
+
+<p>Bugfixes: Better error message when TOYBOX_SUID option can't drop priviliges
+(which happens when you suid something _other_ than root).
+The old pending version of nbd_client.c wasn't deleted when the
+command was promoted (and the build would break if both were enabled),
+toy_exec() sometimes needs to re-exec from $PATH rather than recurse
+internally (to gain dropped root permissions or limit stack depth),
+always call setlocale() when I18N is enabled to switch it back _off_ when
+we run commands that expect sscanf("%n") to return bytes,
+dirtree() had a memory leak in an error path, patch.c had some bugs in
+error paths (didn't report problem clearly). Ashwini Sharma spotted an
+option parsing bug where [-abc] would forget _all_ command line arguments
+saved in the GLOBALS() block (not just the ones for options being switched
+off), plus various minor fixes to nbd_client and cpio.
+Lukasz Szpakowski fixed rm -f on a broken symlink (failed), and killall
+with no arguments (segfaulted).</p>
+
+<p><b>Portability</b></p>
+
+<p>A somewhat fiddly fix to rm -rf (which needs to chmod directories to u+rwx
+to descend into them) which hit a musl bug in faccessat() which the musl
+maintainer refuses to fix. (He literally wants the man page changed
+instead, despite other libcs working.) Added an #ifdef __MUSL__ section
+to portability.h with a workaround, you may need CFLAGS=-D__MUSL__ in your
+build if your musl build's features.h doesn't #define that. (I may do
+a different workaround in future, but sometimes you've just got to make
+it work so you can ship. Also, toybox grep with multiple patterns
+requires <a href=http://landley.net/hg/aboriginal/rev/1692>a patch
+to musl's regex engine</a>, which applies to 1.1.4 but not to the current
+musl source control.)</p>
+
+<p>More portability.h fixes for uClibc too. (I don't expect that to ever have
+another release, so locally patching around posix-2008 violations is silly).</p>
+
+<p><b>Change to username filtering</b></p>
+
+<p>Posix recommends the username creation logic filter usernames to a small
+allowed set of characters (which even Red Hat breaks by explicitly allowing
+"$" at the end), but this prevents UTF-8 usernames. Posix' stated logic
+is to allow filesystems to create the user's home directory, but Linux
+filesystems can accept any character but NUL and "/". The only characters
+we actually _need_ to filter out are ":" (field separator in passwd),
+newline (line separator in passwd), and "/" (directory separator in
+filesystem).</p>
+
+<h3>Documentation</h3>
+
+<p>Web pages updated: cleanup.html documents more cleanup, code.html
+documents more code, and about.html now capitalizes "toybox" consistently
+(it's just a word, capitalize at start of sentence).</p>
+
+<p>The pending/README file now lists commands that needed review/cleanup
+before the pending directory was added.</p>
+
+<h3>Test Suite</h3>
+
+<p>Moved out of scripts/test into top level "tests" directory, and the
+testing.sh script is now in scripts rather than mixed into the *.test files.</p>
+
+<p>Johan Bergström requested VERBOSE=fail to make tests (telling it to
+stop at the first failure), and spotted a build bug where using gnu
+sort on the host broke in non-C locales.</p>
+
+<p>Divya Kothari submitted tests for chmod, link, tar, bzcat, xzcat, zcat,
+and hostname. (And more, but that's all that's merged so far.)</p>
+
+<a name="07-07-2014" /><a href="#07-07-2014"><hr><h2><b>July 7, 2014</b></h2></a>
+<blockquote><p>"This planet has - or rather had - a problem, which was this:
+most of the people living on it were unhappy for pretty much of the time. Many
+solutions were suggested for this problem, but most of these were largely
+concerned with the movement of small green pieces of paper, which was odd
+because on the whole it wasn't the small green pieces of paper that were
+unhappy." - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.9.tar.bz2>Toybox 0.4.9</a> (<a href=/hg/toybox/shortlog/1385>commit 1385</a>) is out.</p>
+
+<p><b>New commands</b> added to pending include:
+lsattr, chattr, inotifyd, rfkill, sulogin, strings, makedevs,
+killall5, and tar from Ashwini Sharma, arp from Kyungwan Han,
+sysctl by Bilal Qureshi, partprobe from Bertold Van den Bergh,
+host from Rich felker, and I did nbd-client and the first 2/3 of mount.</p>
+
+<p>Finished cleanups (commands promoted out of pending):
+sysctl, rfkill, strings, mkpasswd, makedevs, partprobe, killall5,
+fallocate, and nbd-client.</p>
+
+<p>(Along the way partial cleanups got made to: last, fold, lspci, ps,
+bootchartd, init, fsck, telnetd, telnet, vconfig, toysh, iconv, useradd,
+login, host, openvt, deallocvt, getty, tftpd, and modprobe. But there's
+still more to do on all of those.)</p>
+
+<p>This time around the <a href=bin>static binaries</a> are linked against
+musl instead of uClibc. (That's why there's no sparc version, musl doesn't
+support that target yet.)</p>
+
+<p><b>Documentation:</b></p>
+
+<p>The help text parser expects lower case "usage:" lines with
+a blank line after them, so go through and regularize those. Expand the
+"coding style" section in the docs and move it to design.html. (Not a show
+stopper for incoming
+contributions, just an explanation of some of the things I'll do to them
+during cleanup.) The help text for the "toybox" command now includes
+the shell script snippet to install symlinks to the toybox binary.</p>
+
+<p>The <a href=cleanup.html>cleanup page</a> now has descriptions for the
+full ifconfig cleanup series, among others.</p>
+
+<p>The new toys/examples directory contains hello.c and skeleton.c. The first is
+a simple hello world program in toybox style, the second is a much more
+elaborate example program using showing how to use the command line option
+parsing and how to provide multiple commands in the same C file.</p>
+
+<p><b>Fixes</b>:</p>
+
+<p>Fix od bug reported by Samuel Holland ("od -v -b" was appending the default
+output type even though an output type was specified). Ashwini Sharma reported
+bugs where readfile() was incorrectly freeing its buffer, and where toy_init()
+was zeroing the wrong data because the field it was using to measure (rebound)
+had moved (when I moved it back I added a comment why the field needs to be
+there), fixed a segfault in the dhcp client, and made a 0 length read at
+the start of password entry count as EOF. Make the "we are not root" test
+in the init code show the help text. Posix implies that fflush() can return
+success even when the stream's error bit is set, so call both fflush() and
+ferror() from xprintf().</p>
+
+<p>Isaac Dunham pointed out that bloatcheck couldn't deal with diff
+implementations that only implement "unified diff" format, and that some
+diff implementations can't handle nonseekable input (I.E. reading from
+a pipe). Bugfix so "help -a" works again. Option parsing on nohup now stops
+at first nonoption argument. Fix segfault in "which" if PATH wasn't set,
+which was actually a bug in lib function find_in_path(). Made rm -rf of
+chmod 000 directories actually remove them.</p>
+
+<p>The build now passes the same $CFLAGS to the library probe as the final
+build, because arch linux is so broken it provides different sets of
+libraries for static and dynamic linking.</p>
+
+<p>It turns out sprintf("%.123s", str) is counting characters, not bytes,
+so globally enabling locale support opens stack smashing vulnerabilities.
+So there's a new TOYFLAGS_LOCALE you set in toyflags when you want the
+setup code to setlocale().</p>
+
+<p><b>Upgrades:</b></p>
+
+<p>Isaac Dunham extended cpio to archive unreadable empty files, and I taught it
+to set uid/gid and timestamp when extracting archives. Isaac also
+added tests for cpio, link, and du, added lspci -i, made the pci database
+parsing skip # comment lines, merged logname and whoami into id.</p>
+
+<p>Daniel Verkamp sped up md5sum about 30% with some loop unrolling, making
+it actually smaller in the process. I added -b flags to md5sum and sha1sum
+for "brief" output that's just the hash with no filename. (I'm aware other
+implementations use that for MSDOS "binary" mode, and don't care.)</p>
+
+<p>When building standalone commands (scripts/singleconfig.sh commandname),
+the build now switches on all the sub-options of the command so we get
+a standalone version with all the bells and whistles enabled.</p>
+
+<p>Add -ds flags to date and document +FORMAT escapes. Add the shell NOP
+command ":" as an alias for true (for toysh).</p>
+
+<p>Add uClibc probe for iconv() and fallocate. (The fact it didn't always
+build against uClibc is why fallocate wasn't enabled in defconfig before.)</p>
+
+<p>The umount command now does an losetup -d on the device by default, so
+we don't leak loopback devices. Bugfix to losetup so "losetup /dev/loop0
+filename" actually works again.</p>
+
+<p>Divya Kothari sent in test suite entries for ls, ln, rm, mv, printf, dd,
+and renice. Then a second round for lsattr/chattr, mount, chmod, pgrep/pkill,
+groupadd, groupdel, and useradd. Several of these uncovered bugs, still
+working to fix them.</p>
+
+<p>There are now free() functions for the predefined llist types and a
+dlist_terminate() function to break doubly linked lists. The new
+generic_signal() handler either sets "toys.signal" or writes a byte
+to toys.signalfd with the signal number if signalfd isn't -1 (which it's
+initialized to in toy_init).</p>
+
+<p>The option parsing logic can now detect when a double fits in a long and
+use the more precise type for floating point arguments (the FLOAT macro
+contains the type used). The human_readable() function now just outputs
+decimal kilo/mega/gigabytes (so when du -u says 5.0G it means 5.0 billion
+bytes). The build infrastructure now notices duplicate commands (so if you
+cp toys/pending/command.c toys/other/command.c and forget to delete the
+first one, the build break is now more informative).</p>
+
+<a name="20-04-2014" /><a href="#20-04-2014"><hr><h2><b>April 20, 2014</b></h2></a>
+<blockquote><p>And to this end they built themselves a stupendous supercomputer
+which was so amazingly intelligent that even before the data banks
+had been connected up it had started from "I think therefore I am" and got as
+far as the existence of rice pudding and income tax before anyone managed to
+turn it off. - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.8.tar.bz2>Toybox 0.4.8</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/1262>commit 1262</a>. And
+about time too.</p>
+
+<p>The big news is that the build no longer needs python to generate help.h,
+that's now done in C. The help text generation is also collating help text
+from multiple options, merging command line option blocks and usage: lines.
+There's even a new <a href=help.html>help web page</a>.</p>
+
+<p><b>New commands:</b> Ifconfig, cpio, and su were cleaned up the rest of the
+way and promoted out of pending. That saga is mostly explained on the
+<a href=cleanup.html>cleanup page</a>. Vivek Bhagat's freeramdisk,
+Isaac Dunham's fsfreeze, and Felix Janda's iconv are also new.</p>
+
+<p><b>In pending:</b>
+Ashwini Sharma's team submitted tcpsvd, udpsvd, telnet, telnetd, last, more,
+groupdel/delgroup, arping, brctl, ftpget, ftpput, printf, reset, and added
+ipv6 support to traceroute. Kyungwan Han's team submitted modprobe and getty.
+Vivek Bhagat submitted openvt and deacllocvt. Samuel Holland submitted fold.
+I wrote a new inflate (zip/zlib/gzip decompression) implementation in
+compress.c, and still  need to do a corresponding deflate (compression-side)
+and plug them into gzip and zip and so on. (Right now it does zcat.)</p>
+
+<p>Several commands (vmstat, login, du, vconfig, mountpoint, free, chroot,
+cut, touch, modinfo, expand) predate the "pending" directory, and are thus
+in other directories but still need cleanup. Of these, vmstat got some
+work this time (which would be much easier other vmstat implementations
+documented what their output actually meant).</p>
+
+<p><b>Upgrades:</b> Ifconfig grew /prefix netmask support (ala 1.2.3.4/24). Grep now has -zZ to
+handle null terminated data, cksum grew -H for hex output. Upgraded od so the
+fields align better when producing multiple output types. Help has -a and -h
+options (all commands, html output).
+Bugfix to blkid building for a 32 bit target. The date command can actually
+set dates now. The O_NOFOLLOW compile time probe didn't work with cross
+compiling, so it's back to an #ifdef test in portability.h. Nathan McSween
+sent in a bugfix to od and a portability fix in the common library code.
+Ashwini Sharma spotted a bug in pidof -o, and added verbose (-v) options
+to mkdir and ln, and suggested killall should have an -s option and
+allow -l to take zero arguments. Ashwini Sharma and Felix Janda upgraded
+tftpd.  Fixed dumpleases still using toynet.h after
+that was removed. Corrected killall return code and error reporting.
+Isacc Dunham fixed bugs all over the tree, did cleanup on a bunch of
+pending commands (getty, ftpget, init, openvt, modprobe...), and clarified
+find's help text. Tom Sparrow ran three different static analyzers on
+the code, which resulted in a few cleanups. The peek()/poke() functions
+now use "volatile" to prevent broken compiler "optimizations" to do with
+aliasing.</p>
+
+<p><b>Build stuff:</b> Each FOR_xxxx macro now has a complementary CLEANUP_xxxx macro, so you
+can put multiple commands with different command line options in the same
+.c file, so they can share infrastructure outside of lib. (This let the
+bunzip logic move out of lib into bzcat.c.) See XXX for example.
+i
+<p>The headers #included in toys.h are now grouped by standard, and headers
+not listed in Posix or LSB were moved to portability.h. The old xregcomp.h
+was folded into lib.h because it's posix (and supporting oddball uClibc
+configurations isn't as important as it once was).</p>
+
+<p>Regression tested against Ubuntu 8.04 to fix up bit-rot in defconfig
+build on older systems. (We depend on Posix-2008, but not necessarily
+the absolute latest build environment.)</p>
+
+<p><b>In lib</b>: lib/xwrap.c added xgetpwnam(), xchroot(), and lib/lib.c now has names_to_pid().
+xsetuid() was replaced with xsetuser() which takes a struct passwd
+and sets both gid and uid, mkpathat() got factored out into a library command,
+get_int_value() became atolx_range(), and
+xmsprintf() is now just xmprintf(). The bunzip2 logic moved from lib into
+bzcat.c.</p>
+
+<p><b>Documentation</b>: new <a href=help.html>help page</a> with the
+help text for all the defconfig commands, using the new help -ah output.
+The <a href=code.html>source code walkthrough</a> now says more about
+#including header files, and how the generated/* directory works. The
+<a href=design.html>design page</a> has some new paragraphs about trading
+of different kinds of simplicity, and why comments aren't a substitute for
+good code. The README no longer trails off into obvious unfinished confusion
+at the end. Each page on the website should now have its own title.</p>
+
+<a name="18-11-2013" /><a href="#18-11-2013"><hr><h2><b>November 18, 2013</b></h2></a>
+<blockquote><p>"Space," it says, "is big. Really big. You just won't believe how vastly, hugely, mindbogglingly big it is. I mean, you may think it's a long way down the street to the chemist's, but that's just peanuts to space." -
+The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.7.tar.bz2>Toybox 0.4.7</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/1122>commit 1122</a>.</p>
+
+<p>New commands: Brad Conroy submitted blkid. Elie De Brauwer submitted
+reboot, halt, and poweroff. Strake's nl got cleaned up and promoted from
+pending to posix. In addition, the existing chvt and vconfig got some
+cleanup.</p>
+
+<p>That said, I haven't nearly kept up with the flood of new commands going
+into pending: Ashwini Sharma's team submitted
+dd, dumpleases, traceroute, top, useradd, groupadd, mkpasswd, tftpd, and
+an fsck wrapper (with no filesystem drivers yet). Isaac Dunham sent in cpio.</p>
+
+<p>Bugfixes: Jeroen van Rijn added a user count to uptime. Elie De Brauwer
+added -e to watch, removed a memory leak, and fixed a terminal size problem.
+William Haddon made xargs call its command line once even with blank input
+(the standard is vague, but builds expect it), and fixed an off by one bug
+where grep didn't malloc enough space with -E (leading to a segfault).
+I fixed a glitch in bunzip2 (same one as went into busybox since they're using
+the code I wrote), in od to fix -t co, -J, and -c options. Add uname -o as a
+synonym for -s. Build fix to never use $CC without prefixing it with
+$CROSS_COMPILE (since $HOSTCC could be different). Anca Emanuel spotted
+a typo in the web page.</p>
+
+<p>The compile-time command line option parsing got rewritten (ported from
+bash to C), which should speed up builds a bit and allow code controlled by
+--longopts to drop out properly when disabled in the configuration. Terminal
+querying got refactored. Patch's -x option is now more informative (a
+debug thing if you're trying to figure out why a patch didn't apply).
+The "toynet.h" file got folded into toys.h since musl supports it and
+micromanging uClibc options isn't very interesting anymore. The test suite
+now uses scripts/single.sh when testing a single command.</p>
+
+<a name="17-09-2013" /><a href="#17-09-2013"><hr><h2><b>September 17, 2013</b></h2></a>
+<blockquote><p>"Think of a number," said the computer, "any number."
+Arthur told the computer the telephone number of King's Cross railway
+station passenger inquiries, on the grounds that it must have some function,
+and this might turn out to be it. - The Hitchhiker's Guide to the Galaxy</p>
+</blockquote>
+
+<p><a href=downloads/toybox-0.4.6.tar.bz2>Toybox 0.4.6</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/1068>commit 1068</a>.</p>
+
+<p>This release adds
+several new commands: Felix Janda wrote paste and fallocate, Kyungwan Han
+submitted eject, Strake contributed grep, Ashwini Sharma added pmap (and
+a testsuite entry for grep), Lukasz Skalski sent pwdx, Isaac Dunham posted
+acpi, and I did timeout and umount.</p>
+
+<p>The ls command now has a --color=auto option (suggested by Rich Felker).
+The multiplexer now has a --help option so you can say "./toybox --help blah"
+instead of using the built-in "help" command. (Which is a shell built-in.
+Try it on your command line, it's like man for shell builtins. But a certain
+other project has conditioned people to expect --help, so...) I forget who
+heehooman at gmail is but they pointed out unshare needed PID and UID
+namespace support.</p>
+
+<h3>Pending</h3>
+
+<p>A lot of new commands in toys/pending, to the point the next release should
+probably just focus on cleanup and review of this backlog. We've got klogd,
+dhcp, dhcpd, watch, route, and ps from
+Ashwini Sharma (and an fsck wrapper but no fsck.fstype engines yet),
+syslogd, pgrep, and pkill from Madhur Verma, netstat by Ranjan Kumar,
+test by Felix Janda, lspci by Isaac Dunham, nl, su, and renice by strake (I.E.
+M. Farkas-Dyck), and sysvinit by Kyungwan Han.</p>
+
+<p>Some cleanup work on existing pending commands that aren't
+ready to promote yet: I did a few more rounds on ifconfig
+and Isaac Dunham's did several cleanups to xzcat, Felix Janda cleaned up
+logger and syslogd...</p>
+
+<p>Also some cleanup work on commands that predate the pending directory,
+but weren't quite polished when they went in, most prominently du,
+expand, and touch.</p> 
+
+<h3>Infrastructure</h3>
+
+<p>The new scripts/single.sh builds a standalone command without the
+multiplexer, although not all commands can be built that way yet (NEWTOY yes,
+OLDTOY no) and the space savings aren't anything to write home about. (If a
+command needs the option parsing logic at all, it needs all of it.) If
+you're curious, you can do:</p>
+
+<blockquote><pre>
+make defconfig
+make
+mkdir singles
+for i in $(./toybox)
+do
+  echo $i
+  PREFIX=singles/ scripts/single.sh $i || break
+done
+</pre>
+<p>(And then wait a long time and watch almost half the builds fail.)</p>
+</blockquote>
+
+<p>There is now libbuf analogous to toybuf, another global 4k buffer this
+time for use by lib/ code instead of command code.</p>
+
+<p>The lib directory got split up a bit, lib/pending.c contains functions
+not yet used by anything outside of toys/pending/*, and lib/xwrap.c contains
+functions that wrap other functions and handle failures (via error_exit).
+This leaves lib/lib.c containing actual new functions.</p>
+
+<p>General improvements and bug fixes to argument parsing. The [-abc] exclude
+logic should now clear arguments slots when disabling options. Bare --longopts
+should work now and be able to report errors using their name, the new ;
+option allows optional arguments to longopts only suppliable with = (I.E.
+--color and --color=auto but not --color auto).</p>
+
+<p>I'm gradually weaning the code off of itoa()/utoa() because sprintf
+does this already. In this case "simple" probably means "let libc do it
+for us".</p>
+
+<p>Rewrote for_each_pid_with_name_in() and renamed it to just names_to_pid().
+It shouldn't get confused trying to compare absolute and relative paths quite
+so much anymore.</p>
+
+<p>lib/llist.c grew a new dlist_pop() function for removing a doubly
+linked list entry while maintaining a circular list; tail and patch are
+using it now.</p>
+
+<p>The musl guys suggested a new optimization flag
+(-fno-asynchronous-unwind-tables)
+that shaves about 10% off the binary size by removing a C++ism that crept
+into gcc's idea of C. While I don't normally try to micromanage the compiler,
+"-fstop-being-stupid" is a thing you have to hit gcc with from time to time.</p>
+
+<h3>Bugfixes</h3>
+
+<p>Felix Janda and I did a largeish rewrite of tail to
+finally make it work right (we think). Still need to implement tail -f
+someday (the tricky bit is making -f follow multiple files at once).
+Felix also reported a bug in xpidfile.</p>
+
+<p>Juhani Haverinen pointed out that
+python 3 doesn't work with config2help.py, so the detection logic looks
+for python2 (until I get around to rewriting that in C). Elie De Brauwer
+then fixed our first attempt at this, and also fixed uname's help string.</p>
+
+<p>Ashwini Sharma
+pointed out the build was making a FLAG_ macro for " " which broke some
+configurations. (That's a control character, not a command line option.)</p>
+
+<p>Jacek Bukarewicz pointed out a bug in chdir permission handling, and
+a way to make env segfault. Both should be fixed now.</p> 
+
+<p>The new function xexec_optargs()
+replaces calls to xexec(toys.optargs) to avoid freeing and reusing optargs
+during option parsing screwing stuff up (such as netcat's exec mode).</p>
+
+<p>The stat command's %a output was padded with leading zeroes, which
+didn't match anybody else's behavior and thus made the test suite hiccup
+between TEST_HOST and testing toybox. (If you go "TEST_HOST=1 scripts/test.sh
+command" it sanity checks the tests against the host implementation.)</p>
+
+<p>Last release, "mkdir sub/sub && chmod 007 sub/sub && rm -rf sub" didn't
+delete sub and didn't exit with an error either. Neither was correct, rm
+should now be fixed.</p>
+
+<p>
+<a name="26-07-2013" /><a href="#26-07-2013"><hr><h2><b>July 26, 2013</b></h2></a>
+<p>Georgi Chorbadzhiyski maintains a <a href=https://github.com/gfto/toybox>git
+mirror</a> of the repository on github, automatically updated from the
+mercurial every 6 hours. The mirror is read only, but you can generate patches
+against it and post them to the list.</p>
+
+<a name="02-07-2013" /><a href="#02-07-2013"><hr><h2><b>July 2, 2013</b></h2></a>
+<blockquote><p>"Time is an illusion. Lunchtime doubly so." "Very deep. You
+should send that in to the Reader's Digest. They've got a page for people
+like you." -
+The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.5.tar.bz2>Toybox 0.4.5</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/941>commit 941</a>. It adds
+uuencode and uudecode from Erich Plondke, and enables Luis Morales' "who" by
+default. Felix Janda and I cleaned up last year's "stat" submission and
+enabled it. Ivo van Poorten added "groups".
+Andre Renaud added "lsusb". I implemented "split", "pivot_root", and "mv".
+</p>
+
+<p>The "help" command is implemented differently now (lib/help.c) and
+each command can now understand --help (including both "toybox --help"
+and "toybox --help command" in the multiplexer).</p>
+
+<p>The "pending" directory has several commands (find, xzcat, nbd-client,
+logger, expr) which work but are not enabled by default pending further cleanup.
+Ifconfig is enabled, but still in pending because it's only 2/3 cleaned up.
+(It's an awkward halfway state but I'm not holding up the release for it.)</p>
+
+<p>I'm <a href=cleanup.html>documenting the cleanups</a> to teach
+more people to do it, but the writeups aren't caught up yet. The
+<a href=roadmap.html>roadmap</a> also got updated a bit with further analysis
+of other projects, and the README and about pages got updated.</p>
+
+<p>Fixed _another_ "ls -C" segfault when terminal size can't be detected,
+condensed the ls help text to fit on one page, implented --color, and taught
+-l to print the major, minor numbers when showing block/char devices.
+Argument parsing now handles "--" properly (to end option checking),
+and the infrastructure can now handle bare --longopts that have no
+corresponding short option (both were implemented before but didn't work).
+Fixed an old bug in "patch", chmod grew -f, who grew -a. Isaac Dunham
+fixed "-" vs "_" handling in modinfo, added a "firmware" output
+field, added -b and -k support, and taught it that the ".ko" extension means
+to look for the file at the specified path instead of under /lib. Felix Janda
+moved file permission display code to lib so ls and
+stat could share it. Ashwini Sharma spotted a bug in xabspath when the
+last path component exists but we haven't got permissions to open it
+(ala readlink -f /dev/sda as a normal user).
+</p>
+
+<p>In the build infrastructure, scripts/findglobals.sh finds leaked global
+variables. (Leaked means they aren't part of the global union: Other than glibc
+debris, toybox should define "this", "toy_list", "toybuf", and "toys", and
+that's it; the rest add memory footprint to every command for the benefit of
+just one command; use GLOBALS() to stick 'em in the union.) Static linking
+against libraries other than the host's libc now applies to feature probes
+for unshare and such. Neuter stupid internationalization support that makes
+various host "sort" commands put things in an order other than alphabetical
+(breaking the multiplexer's binary search on command names).
+
+<p>You should now be able to build from a source control snapshot on a build
+system that hasn't got python: if you disable CONFIG_TOYBOX_HELP. (The
+release tarballs ship generated/help.h, but it's not in source control.
+Eventually I should rewrite that python script in C.)</p>
+</p>
+
+<p><b>LICENSE TWEAK</b>: After <a href=http://lists.landley.net/pipermail/toybox-landley.net/2013-March/000794.html>discussion</a> on the mailing list the "2 clause
+BSD" <a href=license.html>license</a> got slightly simplified so the first
+paragraph now says:</p>
+
+<blockquote><p>Permission to use, copy, modify, and/or distribute this
+software for any purpose with or without fee is hereby granted.</p></blockquote>
+
+<p>It used to continue "provided that the above copyright notice and this
+permission notice appear in all copies", but A) what's the point? B) does "all
+copies" mean binaries, or just source code, or what? C) lots of projects
+that consider BSD and GPL compatible have <a href=https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/crypto/aes_generic.c>files with
+both license notices</a> on them (sometimes at <a href=http://git.busybox.net/busybox/tree/shell/ash.c>opposite ends of the file</a> to make the conflict
+less obvious) because "all copies must include this function" would violate
+the GPL but "all copies must include this magic text blob" somehow don't?</p>
+
+<p>I don't want to have to care about this anymore. The tweaked version is more
+or less public domain with a liability disclaimer, but we're still calling it
+BSD (sometimes "0 clause BSD") to avoid explaining.</p>
+
+<a name="21-03-2013" /><a href="#21-03-2013"><hr><h2><b>March 21, 2013</b></h2></a>
+<p>Video of my ELC talk
+"<a href=http://youtu.be/SGmtP5Lg_t0>Why is Toybox?</a>"
+is up on youtube. Related materials include the
+<a href=http://landley.net/talks/celf-2013.txt>talk outline</a> and an
+<a href=/aboriginal/about.html#selfhost>android self-hosting writeup</a>.</p>
+
+<p>[Updated June 4] The following links jump to specific topics in the video. (Sorry about
+the ads, it's The Linux Foundation.)</p>
+
+<ul>
+<li>0m29s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=0m29s>The smartphone is replacing the PC</a></li>
+  <ul>
+  <li>4m22s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=4m22s>Software needed to become self-hosting</a></li>
+  <li>6m20s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=6m20s>Do we care if android or iphone wins?</a></li>
+  </ul>
+<li>9m45s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=9m45s>Android not vanilla: oppose or accept?</a></li>
+  <ul>
+  <li>11m30s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=11m30s>Open source can't do User Interfaces</a></li>
+  </ul>
+<li>15m09s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=15m09s>Android is not copyleft: oppose or accept?</a></li>
+<li>18m23s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=18m23s>Security issues</a></li>
+<li>21m15s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=21m15s>Solutions to the software problems</a></li>
+  <ul>
+  <li>22m55s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=22m55s>What toybox needs to be/do</a></li>
+  <li>28m17s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=28m17s>What is toybox?</a></li>
+    <ul>
+    <li>28m58s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=28m58s>Why toybox started...</a></li>
+    <li>37m50s <a href=http://www.youtube.com/watch?v=SGmtP5Lg_t0#t=37m50s>What does toybox actually implement?</a></li>
+    </ul>
+  </ul>
+</ul>
+</span>
+
+
+<a name="14-03-2013" /><a href="#14-03-2013"><hr><h2><b>March 14, 2013</b></h2></a>
+<blockquote><p>"Ford, you're turning into a penguin. Stop it." -
+The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.4.tar.bz2>Toybox 0.4.4</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/813>commit 813</a>, adding
+the "time" and "readahead" commands, plus some bugfixes.</p>
+
+<p>The "cp" command now implements the -s symlink option, plus bugfixes
+getting various corner cases right as used in actual package builds.
+"id -Gn root" should now print root's groups
+instead of the current user's. Several build fixes so toybox builds under
+Ubuntu 8.04 again (which is about as old a build environment as you
+can expect to find posix-2008 features in).</p>
+
+<p>Unfinished commands have generally been moved to "toys/pending".
+Everything else should "default y" to participate in make defconfig.
+Several of those pending commands got some basic cleanup so allyesconfig
+should at least compile (although defconfig is still what's useful).</p>
+
+<p>Significant roadmap updates, checking several other multicall binaries
+(klibc, sash, sbase, s6...) to see what commands they include.</p>
+
+<a name="18-01-2013" /><a href="#18-01-2013"><hr><h2><b>January 18, 2013</b></h2></a>
+<blockquote><p>This must be Thursday. I never could get the hang of Thursdays. - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.3.tar.bz2>Toybox 0.4.3</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/793>commit 793</a>. There
+are now exactly 100 commands in defconfig (of a little over 220 on the
+<a href=roadmap.html>todo list</a>).</p>
+
+<p>Elie De Brauwer added the rev command, cleaned up tac, implemented the -s
+and -f flags for seq, added -v and -i to killall (and fixed killall not to
+kill itself before finishing its pid list), and added to the test suite.
+Felix Janda added -m to mkdir, pwd -L and -P, and more test suite entries.</p>
+
+<p>Rob Landley added the losetup command, and fixed the existing ls, cp, and
+readlink commands. The segfault in ls
+happened when it couldn't determine the screen size (last release changed the
+default to -C and a screen size of 0 made column view unhappy), and cp got an
+extensive rewrite bringing it up to date with the dirtree changes and fixing
+a number of things it never did right in the first place. The xabspath()
+code in the library now handles a symlink after ".." properly (and the test
+suite checks for it).</p>
+
+<p>Infrastructure-wise the code is better about automatically setting the
+error return code properly. Now error_msg() sets the exit code to 1 if it's
+still defaulting to 0, and the global exit path does a fflush(NULL) with error
+bit check rather than trying to be quite so granular about flushing. (That
+means if we use printf() instead of xprintf() it still exits with the right
+error code, it just doesn't end the program early on an output error.)
+Minor bugfix so TOYBOX_DEBUG
+doesn't always warn about the lack of suid bit when toybox is built with
+at least one STAYROOT command. Bugfix for the option [grouping] logic
+(and then further fixes to the error reporting pointed out by Ashwini Sharma).
+dirtree_handle_callback() now has a prefix like the rest of the dirtree
+functions. A lot of stuff doing manual path handling was switched to using
+libc basename() (including, embarassingly, the basename command), which means
+it now correctly detects "/trailing/slash/" which the previous code didn't.</p>
+
+<p>Also, last release included some accidentally checked in debug code that
+disabled compiler optimization, so the binary size bloated a bit. It's back
+to -Os by default now.</p>
+
+<a name="15-12-2012" /><a href="#15-12-2012"><hr><h2><b>December 15, 2012</b></h2></a>
+<blockquote><p>"The major difference between a thing that might go wrong and a
+thing that cannot possibly go wrong is that when a thing that cannot possibly
+go wrong goes wrong it usually turns out to be impossible to get at or repair."
+</p><p>- The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.2.tar.bz2>Toybox 0.4.2</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/749>commit 749</a> and is
+just a resync. Linux 3.7 came out, meaning it's time to do an Aboriginal
+Linux release, and that should use a stable version of toybox. So here's
+a new stable version.</p>
+
+<p>The new commands are cut (from Jason Kyungwan Han), touch
+(from Choubey Ji), expand (from Jonathan Clairembault, and he fixed a
+bug in login), and rm (from Rob Landley). Felix Janda added UTF-8
+support infrastructure (for non-ascii character sets) with a config option.
+Elie De Brauwer added tests for cat and sha1sum, and -so options to pidof.
+The "ls" command defaults to -C (column view) now, and "readlink" now supports
+-fenq.</p>
+
+<p>Portability work: toybox should now build against the musl C library,
+and against older glibc versions (circa 2008, much before that and kernel
+features we depend on start to drop out).</p>
+
+<p>The whole codebase got reindented from "one tab" to "two spaces" per
+level. The option parsing logic now understands [groups] of commands (when more
+than one in a group is selected it can switch the others off, or error out,
+or other things). The error_exit() infrastructure can now longjmp back to an
+earlier point instead of exiting. Each toys/* directory now has a README,
+the first line of which is the fancy name menuconfig uses for the directory
+(so no more hardwired directory list in scripts/genconfig.sh).</p>
+
+<p>Fixed a filehandle leak in getmountlist().
+Pass parent pointer to dirtree_add_node() so it can give error messages with
+full path. The yesno() function now always reads from stdin and writes to
+stderr (we can retry tty checking complexity once we've got commands needing
+it).</p>
+
+<p>The open group broke their website so the
+<a href=http://opengroup.org/onlinepubs/9699919799>old links</a> to POSIX 2008
+now <a href=http://pubs.opengroup.org/onlinepubs/9699919799>need to start with
+pubs</a>. Some of the links in the tree have been updated, others haven't while
+I wait to see if their webmaster notices and fixes it.</p>
+
+<p>(I note that the current rm implementation is not technically posix compliant
+because the standard requires infinite recursion depth and the current
+implementation uses one filehandle per level. I can add a config option
+to do it Posix's way, which is more brittle and needs extra security checks,
+but am waiting for somebody to complain first. The default "ulimit -n" is 1024
+filehandles, so drilling down over 1000 nested subdirectories).</p>
+
+<a name="13-11-2012" /><a href="#13-11-2012"><hr><h2><b>November 13, 2012</b></h2></a>
+<blockquote><p>"Rule Six: The winning team shall be the first team that wins."
+- The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.1.tar.bz2>Toybox 0.4.1</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/691>commit 691</a>.</p>
+
+<p>Elie De Brauwer contributed usleep, Ashwini Kumar contributed du, and
+Kyungwan Han contributed vconfig. Other new commands include switch_root and
+md5sum, and the remaining shell wrappers are now proper commands (dos2unix,
+unix2dos).</p>
+
+<p>The patch command now supports -l, and gethostname is now enabled by
+default. The df command follows symlinks to get the actual device name.
+Felix Janda added -m support to wc (for utf8).</p>
+
+<p>On the infrastructure side, the commands have now been grouped into
+"posix", "lsb", and "other" subdirectories (for things required by Posix-2008,
+the Linux Standard Base 4.1, and commands in neither). This affects menuconfig
+and the actual source layout (toys/cp.c is now toys/posix/cp.c, and so on).
+An android directory is planned (see the updated
+<a href=roadmap.html#android>android roadmap analysis</a>).</p>
+
+<p>The FLAG_ macros for command option parsing and TT alias for the command's
+global block are now automatically generated, commands should
+#define FOR_commandname before #including <toys.h> to get the macros for that
+command.</p>
+
+<p>An upgrade to the build infrastructure now allows commands with _ and -
+in them, such as switch_root.</p>
+
+<p>Bugfixes: Avery Pennarun spotted a case where ls showed uid twice instead of
+uid and gid, and that nice was using the wrong range of numbers.
+The ls command also recursed inappropriately last time (not quite
+properly converted for the dirtree changes last release), and now it's
+fixed. Roy Tam pointed out a glitch in sh, and fixed df's percentage
+calculation to match the POSIX spec. The kernel build didn't like our mktemp
+and it does now. The wc command wasn't quite posix compliant (trailing spaces
+break stuff). The ls command recursed inappropriately last time (not quite
+properly converted for the dirtree changes last release), and now it's
+fixed. The catv command wasn't displaying byte 255 correctly. Some lib
+fixes (thinko in xpidfile). Fixed uname -m when running a 32 bit x86 binary
+on an x86-64 host (it lies and says the system is i686, i586, or i486 depending
+on what the toolchain that built the binary supported. This makes builds in
+a 32 bit chroot on a 64 bit kernel break less.) The df command was checking
+partitions in the wrong order (displaying undermounts instead of overmounts:
+this used to work but some library code changed out from under it and it
+wasn't updated to match until now). Felix Janda filled out the test suite
+some more. The patch file creation logic got tweaked several times to
+successfully apply more patches. Support for older (pre 2.10) glibc
+versions was added to portability.h.</p>
+
+<p>Miscelaneous cleanups all around (mknod, sha1sum, logname), including a
+rewrite of taskset to be less dependent on libc getting the headers right. All
+the command headers should now point to the current relevant standards
+document, where applicable.</p>
+
+<p>This news page had old news entries from before the relaunch moved into
+a separate <a href=oldnews.html>oldnews</a> page.</p>
+
+<p>I forgot to create <a href=bin>static binaries</a> last time, but they're
+back now.</p>
+</span>
+
+<a name="23-07-2012" /><a href="#23-07-2012"><hr><h2><b>July 23, 2012</b></h2></a>
+<blockquote><p>"Ford", Arthur said. "There's an infinite number of monkeys
+out here who want to talk to us about this script for Hamlet they've worked
+out." - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.4.0.tar.bz2>Toybox 0.4.0</a> is based on
+<a href=http://landley.net/hg/toybox/shortlog/640>commit 640</a>.</p>
+
+<p>The new <a href=status.html>status page</a> is calculated from
+the roadmap info, and should be easier to keep up to date in future.</p>
+
+<p>Andre Renaud contributed od and modinfo. Elie De Brauwer contributed
+taskset, bugfixes to cmp and tail, and tests for sort and tail. Kyungwan Han
+contributed passwd. Gaurang Shastri contributed w. Ashwini Sharma spotted a
+case where dirtree was adding extra slashes to a path.</p>
+
+<p>I rewrote od, cleaned up comm, documented the
+<a href=code.html#lib_llist>llist</a> and
+<a href=code.html#lib_dirtree>dirtree</a> infrastructure, added an -r option
+to date (and fixed a bug where -u wouldn't override /etc/localtime),
+fixed bugs in chmod +stw, fixed ls to show suid bits properly when the
+corresponding executable bit wasn't set, and worked around a longstanding
+glibc bug where static linking prevents stdout from automatically flushing
+pending output on exit.</p>
+
+<a name="25-06-2012" /><a href="#25-06-2012"><hr><h2><b>June 25, 2012</b></h2></a>
+<blockquote><p>"For a moment, nothing happened. Then, after a second or so, nothing continued to happen." - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p><a href=downloads/toybox-0.3.1.tar.bz2>Toybox 0.3.1</a> is based on commit
+<a href=http://landley.net/hg/toybox/shortlog/607>commit 607</a>. It's
+mostly a bugfix release for ls -l (which was unhappy on targets other than
+x86-64), plus a new "date" from Andre Renaud and rewritten chgrp/chown which
+now support the full set of posix flags, plus a little work on the test
+suite and some more header tweaks towards eventual compatability with the
+musl libc.</p>
+
+<p>The todo list runneth over, but "release early, release often", so here
+it is. The roadmap and documentation are a bit behind, and I've got ~40
+pending submissions to review. I need to catch up...</p>
+</span>
+
+<a name="12-06-2012" /><a href="#12-06-2012"><hr><h2><b>June 12, 2012</b></h2></a>
+<blockquote><p>"For instance, on the planet Earth, man had always assumed that
+he was more intelligent than dolphins because he had achieved so much - the
+wheel, New York, wars and so on - whilst all the dolphins had ever done was
+muck about in the water having a good time. But conversely, the dolphins had
+always believed that they were far more intelligent than man - for precisely
+the same reasons." - The Hitchhiker's Guide to the Galaxy.</p></blockquote>
+
+<p>It's well past time for <a href=downloads/toybox-0.3.0.tar.bz2>toybox 0.3.0</a>,
+so here it is, based
+on <a href=http://landley.net/hg/toybox/shortlog/595>commit 595</a>, and the
+statically linked <a href=downloads/binaries>prebuilt binaries</a> should
+actually be statically linked this time (thanks Ashwini Sharma for spotting
+that).</p>
+
+<p>It's hard to figure out where to cut a release, because development
+doesn't stop. "Long before now" is the obviuos answer, of course.
+The project's maintainer also moved house during this development cycle, which
+threw things off for a bit (so many boxes). Releases should hopefully be a bit
+more frequent from here on.</p>
+
+<p>The big things Rob worked on this time were the new dirtree (directory
+tree traversal) infrastructure, and a complete rewrite of ls using that
+which should now implement all 26 posix options.</p>
+
+<p>Georgi Chorbadzhiyski added printenv, whoami, mkdir, mkfifo, chmod, chown,
+chgrp, and uniq. He also added fraction and extension support to sleep (so if
+you need a quarter-second sleep, it can do that now), and fixed a build bug
+on slackware.</p>
+
+<p>Daniel Walter contributed a string to mode_t parser (in use by chmod and
+mkdir -m).  Ilya Kuzmich contributed comm. Elie De Brauwer added mountpoint,
+vmstat, logname, login, and mktemp. Kevin Chase did some portability cleanups.
+Pere Orga fixed some documentation.</p>
+
+<p>The "tac" and "clear" commands are now normal commands instead of shell
+wrappers, and the header #includes have been cleaned up a bit to remove
+deprecated functions and attempt to increase compatability with the bionic and
+musl C libraries, "tail" should now use lseek() for large files, and "id" got
+some cleanups and bugfixes.</p>
+
+<p>The new TOYBOX_FLOAT configuration option selects whether or not
+to include floating point support (for embedded targets where that's
+problematic).</p>
+
+<p>Several random bugfixes: unshare() might actually build portably now,
+yes 'n' | cp -i should no longer bypass stdin and prompt via the tty, the
+SUID support no longer drops permissions going through the toybox
+multiplexer command, and a bugfix to xargs -0 means it should no longer
+segfault. (I have a pending bug report about xargs not doing the full
+posix whitespace handling that -0 obsoleted, but I'll deal with that next
+release.)</p>
+
+<p>The build infrastructure is now automatically generating FLAG_ macros
+for the options, but currently with the wrong names. Some more macro glue
+is necessary, which I haven't quite figured out how to do yet.</p>
+
+<p>A defconfig toybox at the start of the $PATH has successfully built
+Linux From Scratch (in my Aboriginal Linux project). The commands that
+'default n' in the config are often still broken, cleanup is ongoing.
+(The new dirtree stuff broke several of them that haven't been converted
+yet, but if I wait until everything works we won't have a release before
+1.0, so here's a checkpoint.)</p>
+
+
+<a name="03-03-2012" /><a href="#03-03-2012"><hr><h2><b>March 3, 2012</b></h2></a>
+
+<blockquote><p>"They went unnoticed at Goonhilly, passed over Cape Canaveral
+without a blip, and Woomera and Jodrell Bank looked straight through them.
+Which was a pity, because it was exactly the sort of thing they'd been looking
+for all these years."</p></p>- The Hitchhiker's Guide to the Galaxy.</p>
+</p></blockquote>
+
+<p>Here's <a href=downloads/toybox-0.2.1.tar.bz2>toybox 0.2.1</a> based
+on <a href=http://landley.net/hg/toybox/shortlog/512>commit 512</a>.  This
+time around, there are statically linked <a href=downloads/binaries>prebuilt
+binaries</a> for various embedded targets.</p>
+
+<p>It's been a busy few weeks, almost entirely due to new contributors. (I
+have not quite been keeping up.)</p>
+
+<p>Elie De Brauwer contributed free, uptime, swapon, swapoff, lsmod, mknod,
+insmod, rmmod, and fixed a bug in basename.  Andre Renaud contributed ls, ln,
+realpath, and hostname. Andres Heck contributed pidof and killall.  Daniel
+Walter wrote kill and extended id. Timothy Elliott contributed tail and tests
+for cmp. Frank Bergmann sent a warning fix. Bryce Fricke added -i to cp.
+Nathan McSween pointed out an optimization. Georgi Chorbadzhiyski fixed
+cross compiling to work more reliably.</p>
+
+<p>(My own contribution this time around was just tightening up other people's
+code, a build fix to unshare, some random bugfixes, and so on. My only new
+code this time around was writing a bash replacement for the existing python
+bloat-o-meter.)</p>
+
+<p>Last time (the 0.2.0 release) included the first pass at an id command from
+Tim Bird, env and basename from Tryn Mirell, cmp and head from Timothy Elliott,
+more bugfixes from Nathan McSween and Elie De Brauwer, and Luis Felipe Strano
+Moraes did a first pass at the who command plus other bugfixes and
+optimizations.</p>
+
+<p>(For that release I did xargs, cal, truncate, unlink, nohup, tty, wc, link,
+dirname, unshare, and various infrastructure tweaks, but it took me 3 months
+and those guys did their stuff in a week or so.)</p>
+
+
+<a name="12-02-2012" /><a href="#12-02-2012"><hr><h2><b>February 12, 2012</b></h2></a>
+<blockquote><p>
+"for though it has many omissions and contains much that is apocryphal, or at
+least wildly inaccurate, it scores over the older, more pedestrian work in two
+important respects..."</p>
+<p> - The Hitchhiker's Guide to the Galaxy</p></blockquote>
+
+<p>Here's the first BSD licensed release,
+<a href=downloads/toybox-0.2.0.tar.bz2>toybox-0.2.0</a>, more a synchronization
+point than anything particularly useful.  47 commands in a reasonably
+ready-to-use state (what "make defconfig" builds), another ten or so partially
+finished stubs ("make allyesconfig"), and several
+patches pending on the mailing list I need to review and merge.</p>
+
+<p>More to come...</p>
+
+<hr>
+<a name="15-11-2011" /><a href="#15-11-2011"><hr><h2><b>November 15, 2011</b></h2></a>
+- Back from the dead, Toybox is now under a 2
+clause BSD license, and aiming to become the default command line
+implementation of Android systems everywhere.</p>
+
+<p>More to come...</p>
+
+<hr>
+
+<p><a href=oldnews.html>Old news</a> from before the relaunch.</p>
+
+<!--#include file="footer.html" -->
diff --git a/toybox/www/oldnews.html b/toybox/www/oldnews.html
new file mode 100755
index 0000000..92a5a52
--- /dev/null
+++ b/toybox/www/oldnews.html
@@ -0,0 +1,139 @@
+<html><head><title>toybox: old news</title>
+<!--#include file="header.html" -->
+
+<h2>Old News</h2>
+
+<p>This project <a href=http://lists.busybox.net/pipermail/busybox/2006-September/024794.html>started in 2006</a>, got mothballed in 2009
+<a href=http://landley.net/notes-2009.html#18-06-2009>for</a>
+<a href=http://landley.net/notes-2011.html#31-03-2011>various</a>
+<a href=http://landley.net/notes-2011.html#08-06-2011>reasons</a>
+(during which time I
+<a href=http://lists.busybox.net/pipermail/busybox/2010-March/071783.html>contributed</a>
+some toybox code and design ideas to busybox</a> but retained the copyrights to
+my work), then <a href=http://landley.net/notes-2011.html#13-11-2011>relaunched</a>
+under a 2-clause BSD license in 2011.
+The following news entries predate that relaunch:</p>
+
+<hr>
+<p><b>December 1, 2009</b> - <a href=downloads/toybox-0.1.0.tar.bz2>toybox-0.1.0</a> is out.</p>
+
+<p>This release is a couple build fixes and another bugfix to patch.</p>
+
+<hr>
+<p><b>April 17, 2009</b> - Another bugfix release,
+<a href=downloads/toybox-0.0.9.2.tar.bz2>toybox-0.0.9.2</a>, off by one allocation error in patch.</p>
+
+<p>(Darn fiddly command, innit?)</p>
+
+<hr>
+<p><b>March 29, 2009</b> - Released
+<a href=downloads/toybox-0.0.9.1.tar.bz2>toybox 0.0.9.1</a> which is a bugfix
+release for issues with the patch command.</p>
+
+<p>The project is currently on hold while the developers learn Lua and
+decide whether or not to port the whole thing to that language.
+(Also note: the mailing list moved.  See the links on the left.  You'll
+have to resubscribe.)</p>
+
+<hr>
+<p><b>January 29, 2009</b> - Released
+<a href=downloads/toybox-0.0.9.tar.bz2>toybox 0.0.9.tar.bz2</a> which is a minor packaging
+fix for 0.0.8.  (The previous release tarball contained a prebuilt x86-64
+kconfig/conf file, because the release script ran defconfig to
+pregenerate help.h, and didn't run make clean afterwards.)  The actual source
+code is identical to the previous release.</p>
+
+<hr>
+<p><b>January 20, 2009</b> - <a href=downloads/toybox-0.0.8.tar.bz2>toybox 0.0.8</a>
+adds the uname, cksum, and mkswapfs commands.</p>
+
+<p>This uname implementation is cross compile friendly: when built as a 32 bit
+binary on an x86_64 host, it reports "i686" to confuse autoconf less.</p>
+
+<p>This cksum has several extra command line options which can be used to
+produce different cksum variants based on the same crc32 algorithm.  For
+example, the broadcom "trx" image packaging uses a little endian crc,
+pre-inverted instead of post-inverted, and does not include the length.
+(Without these arguments, it produces the normal SUSv4 cksum output.)</p>
+
+<p>It also upgrades netcat with a server mode (-l option) and fixes several
+netcat bugs.  It also fixed multiple bugs in "patch", works around a
+reiserfs bug in cp, and oneit can reboot on exit more reliably.</p>
+
+<p><b>November 12, 2008</b> -
+<a href=downloads/toybox-0.0.7.tar.bz2>toybox 0.0.7</a>
+adds sort and tee commands, upgrades the internal option parsing logic and the
+test suite, and numerous bugfixes (bunzip, chroot, cat, patch).</p>
+
+<p><b>May 26, 2008</b> - <a href=downloads/toybox-0.0.6.tar.bz2>toybox 0.0.6</a>
+adds cat, rmdir, and seq.  Bugfixes to cp and a new -v option.  Updates mdev to
+work with the 2.6.25 kernel.  Updates patch to knows that a file dated
+1969-12-31 means it doesn't exist, and to fail if a file it needs to create
+already exists.  Command line option parsing can now handle things like "echo
+-nex" vs "echo -ne".  Several updates to the test suite (run scripts/test.sh),
+and some build fixes.</p>
+
+<p>
+<hr>
+<p><b>March 29, 2008</b> -
+Time to release <a href=downloads/toybox-0.0.5.tar.bz2>toybox 0.0.5</a>, with
+new commands cp and chvt and several bugfixes.</p>
+
+<p>More makefile targets: "make test" runs the test suite (which needs more test
+scripts), and make install/install_flat/uninstall/uninstall_flat calls
+make/install.sh (with options --long --symlink --force --uninstall depending
+on the context).</p>
+
+<p>Most of the work has been behind the scenes, namely a significant rewrite of
+the build logic so adding each new command consists of adding a single C file to
+the "toys" directory, eliminating the need to touch any other files.
+There are specially formatted comments at the top of the C file to generate
+the other files, see toys/hello.c for an example.  (See generated/README.txt
+and <a href=code.html>code.html</a> for details.)</p>
+
+<p><b>January 2, 2008</b> - And <a href=downloads/toybox-0.0.4.tar.bz2>toybox-0.0.4.tar.bz2</a> is out.
+The new applets this time around include basename, chroot, dirname, dmesg,
+help, mkfifo, netcat, patch, sha1sum, touch, and tty.</p>
+
+<p>Note that this "touch" includes -l to set the length, which can truncate
+a file or create a commpletely sparse file, good for filesystem images.</p>
+
+<p>Expect the next release in about 6 months.</p>
+
+<p><b>December 12, 2007</b> - Updated the list of implemented applications,
+put up a <a href=todo.txt>todo list</a> and <a href=code.html>infrastructure
+documentation</a>.  Expect another release towards the end of the month.</p>
+
+<p><b>June 18, 2007</b> - Put out
+<a href=downloads/toybox-0.0.3.tar.bz2>toybox-0.0.3.tar.bz2</a> since it's
+been too long since I did something like that.  This one implements
+catv, count, df, echo, false, oneit, pwd, sleep, sync, toysh, true, which,
+and yes (which is what "make defconfig" enables).  There are several other
+commands not enabled by defconfig, because they don't really work yet.</p>
+
+<p>Most of the general infrastructure's there now, although lots of tweaking
+and optimizing is still needed.  The test suite is skeletal and not entirely
+checked in yet, but I'm working on that.</p>
+
+<p>I don't have nearly as much time to work on this as I'd like, but I'm making
+a little progress.</p>
+
+<p><b>January 31, 2007</b> -
+Toybox <a href=downloads/toybox-0.0.2.tar.bz2>0.0.2 release</a>.
+Implements count, yes, pwd, echo, bzcat, catv, oneit, and an unfinished
+skeleton of mke2fs.  Adds argument parsing logic and bunzip code to library.
+Now configured with menuconfig.  Adds "make baseline" and "make bloatcheck"
+using Matt Mackall's bloat-o-meter, and scripts/showasm.</p>
+
+<p>Screwing up the web page a bit, adding an index bar along the side
+which doesn't properly connect up to anything yet.  (Busy implementing
+mke2fs and gene2fs.)</p>
+
+<p><b>October 30, 2006</b> -
+Toybox <a href=downloads/toybox-0.0.1.tar.bz2>0.0.1 release</a>.  Implements
+df, a skeletal toysh, and some library functions.  Proof of concept, really.</p>
+
+<p><b>September 7, 2006</b> -
+Project launched, first commit to mercurial archive.</p>
+
+<!--#include file="footer.html" -->
diff --git a/toybox/www/roadmap.html b/toybox/www/roadmap.html
new file mode 100755
index 0000000..4cdafb0
--- /dev/null
+++ b/toybox/www/roadmap.html
@@ -0,0 +1,997 @@
+<html><head><title>toybox roadmap</title>
+<!--#include file="header.html" -->
+<title>Toybox Roadmap</title>
+
+<h2>Goals and use cases</h2>
+
+<p>We have several potential use cases for a new set of command line
+utilities, and are using those to determine which commands to implement
+for Toybox's 1.0 release.</p>
+
+<p>The most interesting standards are POSIX-2008 (also known as the Single
+Unix Specification version 4) and the Linux Standard Base (version 4.1).
+The main test harness including toybox in Aboriginal Linux and if that can
+build itself using the result to build Linux From Scratch (version 6.8).
+We also aim to replace Android's Toolbox.</p>
+
+<p>At a secondary level we'd like to meet other use cases. We've analyzed
+the commands provided by similar projects (klibc, sash, sbase, s6, embutils,
+nash, and beastiebox), along with various vendor configurations of busybox,
+and some end user requests.</p>
+
+<p>Finally, we'd like to provide a good replacement for the Bash shell,
+which was the first program Linux ever ran and remains the standard shell
+of Linux no matter what Ubuntu says. This doesn't mean including the full
+set of Bash 4.x functionality, but does involve {various,features} beyond
+posix.</p>
+
+<p>See the <a href=status.html>status page</a> for the combined list
+and progress towards implementing it.</p>
+
+<ul>
+<li><a href=#susv4>POSIX-2008/SUSv4</a></li>
+<li><a href=#sigh>Linux "Standard" Base</a></li>
+<li><a href=#dev_env>Development Environment</a></li>
+<li><a href=#android>Android Toolbox</a></li>
+<li><a href=#tizen>Tizen Core</a></li>
+<li>Miscelaneous: <a href=#klibc>klibc</a>, <a href=#glibc>glibc</a>,
+<a href=#sash>sash</a>, <a href=#sbase>sbase</a>, <a href=#s6>s6</a>,
+<a href=#uclinux>uclinux</a>...</li>
+</ul>
+
+<hr />
+<a name="standards">
+<h2>Use case: standards compliance.</h2>
+
+<h3><a name=susv4 /><a href="#susv4">POSIX-2008/SUSv4</a></h3>
+<p>The best standards are the kind that describe reality, rather than
+attempting to impose a new one.  (I.E. a good standard should document, not
+legislate.)</p>
+
+<p>The kind of standards which describe existing reality tend to be approved by
+more than one standards body, such ANSI and ISO both approving C.  That's why
+the IEEE POSIX committee's 2008 standard, the Single Unix Specification version
+4, and the Open Group Base Specification edition 7 are all the same standard
+from three sources.</p>
+
+<p>The <a href="http://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html">"utilities"
+section</a>
+of these standards is devoted to the unix command line, and are the best such
+standard for our purposes.  (My earlier work on BusyBox was implemented with
+regard to SUSv3, an earlier version of this standard.)</p>
+
+<h3>Problems with the standard</h3>
+
+<p>Unfortunately, these standards describe a subset of reality, lacking any
+mention of commands such as init, login, or mount required to actually boot a
+system. It provides ipcrm and ipcs, but not ipcmk, so you can use System V IPC
+resources but not create them.</p>
+
+<p>These standards also contain a large number of commands that are
+inappropriate for toybox to implement in its 1.0 release.  (Perhaps some of
+these could be reintroduced in later releases, but not now.)</p>
+
+<p>Starting with the full "utilities" list, we first remove generally obsolete
+commands (compess ed ex pr uncompress uccp uustat uux), commands for the
+pre-CVS "SCCS" source control system (admin delta get prs rmdel sact sccs unget
+val what), fortran support (asa fort77), and batch processing support (batch
+qalter qdel qhold qmove qmsg qrerun qrls qselect qsig qstat qsub).</p>
+
+<p>Some commands are for a compiler toolchain (ar c99 cflow ctags cxref gencat
+iconv lex m4 make nm strings strip tsort yacc), which is outside of toybox's
+mandate and should be supplied externally.  (Again, some of these may be
+revisited later, but not for toybox 1.0.)</p>
+
+<p>Some commands are part of a command shell, and cannot be implemented as
+separate executables (alias bg cd command fc fg getopts hash jobs kill read
+type ulimit umask unalias wait).  These may be revisited as part of a built-in
+toybox shell, but are not exported into $PATH via symlinks.  (If you fork a
+child process and have it "cd" then exit, you've accomplished nothing.
+This is not a complete list, a shell also needs exit, if, while, for, case,
+export, set, unset, trap, exec... And for bash compatability, function and
+source.)</p>
+
+<blockquote><b>
+<span id=shell>
+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>
+
+<p>A few other commands are judgement calls, providing command-line
+internationalization support (iconv locale localedef), System V inter-process
+communication (ipcrm ipcs), and cross-tty communication from the minicomputer
+days (talk mesg write).  The "pax" utility was supplanted by tar, "mailx" is
+a command line email client, and "lp" submits files for printing to... what
+exactly?  (cups?)  The standard defines crontab but not crond.</p>
+
+<p>Removing all of that leaves the following commands, which toybox should
+implement:</p>
+
+<blockquote><b>
+<span id=posix>
+at awk basename bc cal cat chgrp chmod chown cksum cmp comm cp
+csplit cut date dd df diff dirname du echo env expand expr false file find
+fold fuser getconf grep head id join kill link ln logger logname ls man
+mkdir mkfifo more mv newgrp nice nl nohup od paste patch pathchk printf ps
+pwd renice rm rmdir sed sh sleep sort split stty tabs tail tee test time
+touch tput tr true tty uname unexpand uniq unlink uudecode uuencode vi wc
+who xargs zcat
+</span>
+</b></blockquote>
+
+<h3><a name=sigh /><a href="#sigh">Linux Standard Base</a></h3>
+
+<p>One attempt to supplement POSIX towards an actual usable system was the
+Linux Standard Base. Unfortunately, the quality of this "standard" is
+fairly low.</p>
+
+<p>POSIX allowed its standards process to be compromised
+by leaving things out, thus allowing IBM mainframes and Windows NT to drive
+a truck through the holes and declare themselves compilant. But it means what
+they DID standardize tends to be respected (if sometimes obsolete).</p>
+
+<p>The Linux Standard Base's failure mode is different, they respond to
+pressure by including special-case crap, such as allowing Red Hat to shoehorn
+RPM into the standard even though all sorts of distros (Debian, Slackware, Arch,
+Gentoo) don't use it and probably never will. This means anything in the LSB is
+at best a suggestion: arbitrary portions of this standard are widely
+ignored.</p>
+
+<p>The community perception seems to be that the Linux Standard Base is
+the best standard money can buy, I.E. the Linux Foundation is supported by
+financial donations form large companies and the LSB represents the interests
+of those donors more than technical merit. Debian officially
+<a href=http://lwn.net/Articles/658809>washed its hands of LSB</a> when 5.0
+came out in 2015, and no longer even pretends to support it (which may affect
+Debian derivatives like Ubuntu and Knoppix). Toybox hasn't moved to 5.0 for
+similar reasons.</p>
+
+<p>That said, Posix by itself isn't enough, and this is the next most
+comprehensive standards effort for Linux so far.</p>
+
+<p>The LSB specifies a <a href=http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html>list of command line
+utilities</a>:</p>
+
+<blockquote><b>
+ar at awk batch bc chfn chsh col cpio crontab df dmesg du echo egrep 
+fgrep file fuser gettext grep groupadd groupdel groupmod groups 
+gunzip gzip hostname install install_initd ipcrm ipcs killall lpr ls 
+lsb_release m4 md5sum mknod mktemp more mount msgfmt newgrp od passwd 
+patch pidof remove_initd renice sed sendmail seq sh shutdown su sync 
+tar umount useradd userdel usermod xargs zcat
+</b></blockquote>
+
+<p>Where posix specifies one of those commands, LSB's deltas tend to be
+accomodations for broken tool versions which aren't up to date with the
+standard yet. (See <a href=http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/more.html>more</a> and <a href=http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/xargs.html>xargs</a>
+for examples.)</p>
+
+<p>Since we've already committed to using our own judgement to skip bits of
+POSIX, and LSB's "judgement" in this regard is purely bug workarounds to declare
+various legacy tool implementations "compliant", this means we're mostly
+interested in the set of tools that aren't specified in posix at all.</p>
+
+<p>Of these, gettext and msgfmt are internationalization, install_initd and
+remove_initd aren't present on ubuntu 10.04, lpr is out of scope, and
+lsb_release is a distro issue (it's a nice command, but the output of
+lsb_release -a is the name and version number of the linux distro you're
+running, which toybox doesn't know).</p>
+
+<p>This leaves:</p>
+
+<blockquote><b>
+<span id=lsb>
+chfn chsh dmesg egrep fgrep groupadd groupdel groupmod groups
+gunzip gzip hostname install killall md5sum
+mknod mktemp mount passwd pidof sendmail seq shutdown
+su sync tar umount useradd userdel usermod zcat
+</span>
+</b></blockquote>
+
+<hr />
+<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 <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>
+
+<p>This use case includes running init scripts and other shell scripts, running
+configure, make, and install in each package, and providing basic command line
+facilities such as a text editor. (It does not include a compiler toolchain or
+C library, those are outside the scope of this project.)</p>
+
+<blockquote><b>
+<span id=development>
+bzcat cat cp dirname echo env patch rmdir sha1sum sleep sort sync
+true uname wc which yes zcat
+awk basename chmod chown cmp cut date dd diff
+egrep expr fdisk find grep gzip head hostname id install ln ls
+mkdir mktemp mv od readlink rm sed sh tail tar touch tr uniq
+wget whoami xargs chgrp comm gunzip less logname split
+tee test time bunzip2 chgrp chroot comm cpio dmesg
+dnsdomainname ftpd ftpget ftpput gunzip ifconfig init less
+logname losetup mdev mount mountpoint nc pgrep pkill 
+pwd route split stat switch_root tac umount vi
+resize2fs tune2fs fsck.ext2 genext2fs mke2fs xzcat
+</span>
+</b></blockquote>
+
+<p>Note: Aboriginal Linux installs bash 2.05b as #!/bin/sh and its scripts
+require bash extensions not present in shells such as busybox ash.
+This means that toysh needs to supply several bash extensions _and_ work
+when called under the name "bash".</p>
+
+<p>The <a href=http://landley.net/aboriginal>Aboriginal Linux</a>
+self-bootstrapping build still uses the following busybox commands,
+not yet supplied by toybox:</p>
+
+<blockquote><p>
+awk bunzip2 bzcat dd diff expr fdisk ftpd ftpget
+ftpput gunzip gzip less ping route sh
+sha512sum tar test tr unxz vi wget xzcat zcat
+</p></blockquote>
+
+<p>Many of those are in "pending". The remaining "difficult"
+commands are vi, awk, and sh.</p>
+
+<p>Building Linux From Scratch is not the same as building the
+<a href=https://source.android.com>Android Open Source Project</a>,
+but after toybox 1.0 focus may shift to <a href=http://landley.net/aboriginal/about.html#hairball>modifying the AOSP build</a>
+to reduce dependencies. (It's fairly likely we'll have to add at least
+a read-only git utility so repo can download the build's source code,
+but that's actually <a href=https://www.youtube.com/watch?v=P7n6G2IL6eo>not
+that hard</a>. We'll probably also need our own "make" at some point after
+1.0.)</p>
+
+<hr />
+<h2><a name=android /><a href="#android">Use case: Replacing Android Toolbox</a></h2>
+
+<p>Android has a policy against GPL in userspace, so even though BusyBox
+predates Android by many years, they couldn't use it. Instead they grabbed
+an old version of ash and implemented their own command line utility set
+called "toolbox". ash was later replaced by
+<a href="https://www.mirbsd.org/mksh.htm">mksh</a>; toolbox is being
+replaced by toybox.</p>
+
+<p>Toolbox doesn't have its own repository, instead it's part of Android's
+<a href=https://android.googlesource.com/platform/system/core>system/core
+git repository</a>.</p>
+
+<h3>Toolbox commands:</h3>
+
+<p>According to <a href=https://android.googlesource.com/platform/system/core/+/master/toolbox/Android.mk>
+system/core/toolbox/Android.mk</a> the toolbox directory builds the
+following commands:</p>
+
+<blockquote><b>
+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
+subdirectories in the core repository are init,
+logcat, logwrapper, reboot, and run-as.</p>
+
+<ul>
+<li><b>init</b> - Android's PID 1</li>
+<li><b>logcat</b> - read android log format</li>
+<li><b>logwrapper</b> - redirect stdio to android log</li>
+<li><b>reboot</b> - Android's reboot(1)</li>
+<li><b>run-as</b> - subset of sudo</li>
+</ul>
+
+<p>Almost all of these reinvent an existing wheel with less functionality and a
+different user interface. We may want to provide that interface, but
+implementing the full commands (fdisk, init, and sudo) come first.</p>
+
+<h3>Analysis</h3>
+
+<p>For reference, combining everything listed above, we get:</p>
+
+<blockquote><b>
+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
+focus a bit. For our first pass, let's grab just logcat and logwrapper
+from the "core" commands (since the rest have some full/standard version
+providing that functionality, which we can implement a shim interface
+for later).</p>
+
+<p>This means toybox should implement (or finish implementing):</p>
+<blockquote><b>
+<span id=toolbox>
+dd getevent logcat logwrapper newfs_msdos
+</span>
+</b></blockquote>
+
+<p>Update: Android.mk is currently building the following toybox files out
+of "pending". These should be a priority for cleanup:</p>
+
+<blockquote><b>
+dd expr lsof more tar tr traceroute
+</b></blockquote>
+
+<p>Android wishlist:</p>
+
+<blockquote><b>
+mtools genvfatfs mke2fs gene2fs
+</b></blockquote>
+
+<hr />
+<h2><a name=tizen /><a href="#tizen">Use case: Tizen Core</a></h2>
+
+<p>The Tizen project has expressed a desire to eliminate GPLv3 software
+from its core system, and is installing toybox as
+<a href=https://wiki.tizen.org/wiki/Toybox>part of this process</a>.</p>
+
+<p>They have a fairly long list of new commands they'd like to see in toybox:</p>
+
+<blockquote><b>
+<span id=tizen>
+arch base64 users dir vdir unexpand shred join csplit
+hostid nproc runcon sha224sum sha256sum sha384sum sha512sum sha3sum mkfs.vfat fsck.vfat 
+dosfslabel uname stdbuf pinky diff3 sdiff zcmp zdiff zegrep zfgrep zless zmore
+</span>
+</b></blockquote>
+
+<p>In addition, they'd like to use several commands currently in pending:</p>
+
+<blockquote><b>
+<span id=tizen>
+tar diff printf wget rsync fdisk vi less tr test stty fold expr dd
+</span>
+</b></blockquote>
+
+<p>Also, tizen uses a different Linux Security Module called SMACK, so
+many of the SELinux options ala ls -Z need smack alternatives in an
+if/else setup.</p>
+
+<hr /><a name=klibc />
+<h2>klibc:</h2>
+
+<p>Long ago some kernel developers came up with a project called
+<a href=http://en.wikipedia.org/wiki/Klibc>klibc</a>.
+After a decade of development it still has no web page or HOWTO,
+and nobody's quite sure if the license is BSD or GPL. It inexplicably
+<a href=http://www.infoworld.com/d/data-center/perl-isnt-going-anywhere-better-or-worse-211580>requires perl to build</a>, and seems like an ideal candidate for
+replacement.</p>
+
+<p>In addition to a C library even less capable than bionic (obsoleted by
+musl), klibc builds a random assortment of executables to run init scripts
+with. There's no multiplexer command, these are individual executables:</p>
+
+<blockquote><p><b>
+cat chroot cpio dd dmesg false fixdep fstype gunzip gzip halt ipconfig kill
+kinit ln losetup ls minips mkdir mkfifo mknodes
+mksyntax mount mv nfsmount nuke pivot_root poweroff readlink reboot resume
+run-init sh sha1hash sleep sync true umount uname zcat
+</b></p></blockquote>
+
+<p>To get that list, build klibc according to the instructions (I
+<a href=http://landley.net/notes-2013.html#23-01-2013>looked at</a> version
+2.0.2 and did cd klibc-*; ln -s /output/of/kernel/make/headers_install
+linux; make) then <b>echo $(for i in $(find . -type f); do file $i | grep -q
+executable && basename $i; done | grep -v '[.]g$' | sort -u)</b> to find
+executables, then eliminate the *.so files and *.shared duplicates.</p>
+
+<p>Some of those binaries are build-time tools that don't get installed,
+which removes mknodes, mksyntax, sha1hash, and fixdep from the list.
+(And sha1hash is just an unpolished sha1sum anyway.)</p>
+
+<p>The run-init command is more commonly called switch_root, nuke is just
+"rm -rf -- $@", and minips is more commonly called "ps". I'm not doing aliases
+for the oddball names.</p>
+
+<p>Yet more stale forks of dash and gzip sucked in here (see "dubious
+license terms" above), adding nothing to the other projects we've looked at.
+But we still need sh, gunzip, gzip, and zcat to replace this package.</p>
+
+<p>At the time I did the initial analysis toybox already had cat, chroot, dmesg, false,
+kill, ln, losetup, ls, mkdir, mkfifo, readlink, rm, switch_root, sleep, sync,
+true, and uname.</p>
+
+<p>The low hanging fruit is cpio, dd, ps, mv, and pivot_root.</p>
+
+<p>The "kinit" command is another gratuitous rename, it's init running as PID 1.
+The halt, poweroff, and reboot commands work with it.</p>
+
+<p>I've got mount and umount queued up already, fstype and nfsmount go with
+those. (And probably smbmount and p9mount, but this hasn't got one. Those
+are all about querying for login credentials, probably workable into the
+base mount command.)</p>
+
+<p>The ipconfig command here has a built in dhcp client, so it's ifconfig
+and dhcpcd and maybe some other stuff.</p>
+
+<p>The resume command is... weird. It finds a swap partition and reads data
+from it into a /proc file, something the kernel is capable of doing itself.
+(Even though the klibc author
+<a href=http://www.zytor.com/pipermail/klibc/2006-June/001748.html>attempted
+to remove</a> that capability from the kernel, current kernel/power/hibernate.c
+still parses "resume=" on the command line). And yet various distros seem to
+make use of klibc for this.
+Given the history of swsusp/hibernate (and 
+<a href=http://lwn.net/Articles/333007>TuxOnIce</a>
+and <a href=http://lwn.net/Articles/242107>kexec jump</a>) I've lost track
+of the current state of the art here. Ah, Documentation/power/userland-swsusp.txt
+has the API docs, and <a href=http://suspend.sf.net>here's a better
+tool</a>...</p>
+
+<p>So the list of things actually in klibc are:</p>
+
+<blockquote><b>
+<span id=klibc_cmd>
+cat chroot dmesg false kill ln losetup ls mkdir mkfifo readlink rm switch_root
+sleep sync true uname
+
+cpio dd ps mv pivot_root
+mount nfsmount fstype umount
+sh gunzip gzip zcat
+kinit halt poweroff reboot
+ipconfig
+resume
+</span>
+</b></blockquote>
+
+<hr />
+<a name=glibc />
+<h2>glibc</h2>
+
+<p>Rather a lot of command line utilities come bundled with glibc:</p>
+
+<blockquote><b>
+catchsegv getconf getent iconv iconvconfig ldconfig ldd locale localedef
+mtrace nscd rpcent rpcinfo tzselect zdump zic
+</b></blockquote>
+
+<p>Of those, musl libc only implements ldd.</p>
+
+<p>catchsegv is a rudimentary debugger, probably out of scope for toybox.</p>
+
+<p>iconv has been <a href="#susv4">previously discussed</a>.</p>
+
+<p>iconvconfig is only relevant if iconv is user-configurable; musl uses a
+non-configurable iconv.</p>
+
+<p>getconf is a posix utility which displays several variables from 
+unistd.h; it probably belongs in the development toolchain.</p>
+
+<p>getent handles retrieving entries from passwd-style databases
+(in a rather lame way) and is trivially replacable by grep.</p>
+
+<p>locale was discussed under <a href=#susv4>posix</a>.
+localedef compiles locale definitions, which musl currently does not use.</p>
+
+<p>mtrace is a perl script to use the malloc debugging that glibc has built-in;
+this is not relevant for musl, and would necessarily vary with libc. </p>
+
+<p>nscd is a name service caching daemon, which is not yet relevant for musl.
+rpcinfo and rpcent are related to rpc, which musl does not include.</p>
+
+<p>The remaining commands involve glibc's bundled timezone database,
+which seems to be derived from the <a href=http://www.iana.org/time-zones>IANA
+timezone database</a>. Unless we want to maintain our own fork of the
+standards body's database like glibc does, these are of no interest,
+but for completeness:</p>
+
+<p>tzselect outputs a TZ variable correponding to user input. 
+The documentation does not indicate how to use it in a script, but it seems
+that Debian may have done so.
+zdump prints current time in each of several timezones, optionally
+outputting a great deal of extra information about each timezone.
+zic converts a description of a timezone to a file in tz format.</p>
+
+<p>None of glibc's bundled commands are currently of interest to toybox.</p>
+
+</b></blockquote>
+
+<hr />
+<a name=sash />
+<h2>Stand-Alone Shell</h2>
+
+<p>Wikipedia has <a href=http://en.wikipedia.org/wiki/Stand-alone_shell>a good
+summary of sash</a>, with links. The original Stand-Alone Shell project reached
+a stopping point, and then <a href=http://www.baiti.net/sash>"sash plus
+patches"</a> extended it a bit further. The result is a megabyte executable
+that provides 40 commands.</p>
+
+<p>Sash is a shell with built-in commands. It doesn't have a multiplexer
+command, meaning "sash ls -l" doesn't work (you have to go "sash -c 'ls -l'").
+</p>
+
+<p>The list of commands can be obtained via building it and doing
+"echo help | ./sash | awk '{print $1}' | sed 's/^-//' | xargs echo", which
+gives us:</p>
+
+<blockquote><b>
+alias aliasall ar cd chattr chgrp chmod chown cmp cp chroot dd echo ed exec
+exit file find grep gunzip gzip help kill losetup losetup ln ls lsattr mkdir
+mknod more mount mv pivot_root printenv prompt pwd quit rm rmdir setenv source
+sum sync tar touch umask umount unalias where
+</b></blockquote>
+
+<p>Plus sh because it's a shell. A dozen or so commands can only sanely be
+implemented as shell builtins (alias aliasall cd exec exit prompt quit setenv
+source umask unalias), where is an alias for which, and at triage time toybox
+already has chgrp, chmod, chown, cmp, cp, chroot, echo, help, kill, losetup,
+ln, ls, mkdir, mknod, printenv, pwd, rm, rmdir, sync, and touch.</p>
+
+<p>This leaves:</p>
+
+<blockquote><b>
+<span id=sash_cmd>
+ar chattr dd ed file find grep gunzip gzip lsattr more mount mv pivot_root
+sh sum tar umount
+</span>
+</b></blockquote>
+
+<p>(For once, this project doesn't include a fork of gzip, instead
+it sucks in -lz from the host.)</p>
+
+<hr />
+<a name=sbase />
+<h2>sbase:</h2>
+
+<p>It's <a href=http://git.suckless.org/sbase>on suckless</a> in
+<a href=http://git.suckless.org/ubase>two parts</a>. As of November 2015 it's
+implemented the following (renaming "cron" to "crond" for
+consistency, and yanking "sponge", "mesg", "pagesize", "respawn", and
+"vtallow"):</p>
+
+<blockquote><p>
+<span id=sbase_cmd>
+basename cal cat chgrp chmod chown chroot cksum cmp cols comm cp crond cut date
+dirname du echo env expand expr false find flock fold getconf grep head
+hostname join kill link ln logger logname ls md5sum mkdir mkfifo mktemp mv
+nice nl nohup od paste printenv printf pwd readlink renice rm rmdir sed seq
+setsid sha1sum sha256sum sha512sum sleep sort split strings sync tail
+tar tee test tftp time touch tr true tty uname unexpand uniq unlink uudecode
+uuencode wc which xargs yes
+</span>
+</p></blockquote>
+
+<p>and<p>
+
+<blockquote><p>
+<span id=sbase_cmd>
+chvt clear dd df dmesg eject fallocate free id login mknod mountpoint
+passwd pidof ps stat su truncate unshare uptime watch
+who
+</span>
+</p></blockquote>
+
+<hr />
+<a name=s6 />
+<h2>s6</h2>
+
+<p>The website <a href=http://skarnet.org/software/>skarnet</a> has a bunch
+of small utilities as part of something called "s6". This includes the
+<a href=http://skarnet.org/software/s6-portable-utils>s6-portabile-utils</a>
+and the <a href=http://skarnet.org/software/s6-linux-utils>s6-linux-utils</a>.
+</p>
+
+<p>Both packages rely on multiple bespoke external libraries without which
+they can't compile. The source is completely uncommented and doesn't wrap at
+80 characters. Doing a find for *.c files brings up the following commands:</p>
+
+<blockquote><b>
+<span id=s6>
+basename cat chmod chown chroot clock cut devd dirname echo env expr false
+format-filter freeramdisk grep halt head hiercopy hostname linkname ln
+logwatch ls maximumtime memoryhog mkdir mkfifo mount nice nuke pause
+pivotchroot poweroff printenv quote quote-filter reboot rename rmrf sleep
+sort swapoff swapon sync tail test touch true umount uniquename unquote
+unquote-filter update-symlinks
+</span>
+</b></blockquote>
+
+<p>Triage: memoryhog isn't even listed on the website nor does it have
+a documentation file, clock seems like a subset
+of date, devd is some sort of netlink wrapper that spawns its command line
+every time it gets a message (maybe this is meant to implement part of
+udev/mdev?), format-filter is sort of awk's '{print $2}' function split out
+into its own command, hiercopy a subset of "cp -r", maximumtime is something
+I implemented as a shell script (more/timeout.sh in Aboriginal Linux),
+nuke isn't the same as klibc (this one's "kill SIG -1" only with hardwared
+SIG options), pause is a program that literally waits to be killed (I
+generally sleep 999999999 which is a little over 30 years),
+pivotchroot is a subset of switch_root, rmrf is rm -rf...</p>
+
+<p>I see "nuke" resurface, and if "rmrf" wasn't also here I might think
+klibc had a point.</b>
+
+<blockquote>
+basename cat chmod chown chroot cut dirname echo env expr false
+freeramdisk grep halt head hostname linkname ln
+logwatch ls mkdir mkfifo mount nice
+pivotchroot poweroff printenv quote quote-filter reboot rename sleep
+sort swapoff swapon sync tail test touch true umount uniquename unquote
+unquote-filter update-symlinks
+</blockquote>
+
+
+<hr />
+<a name=nash />
+<h2>nash:</h2>
+
+<p>Red Hat's nash was part of its "mkinitrd" package, replacement for a shell
+and utilities on the boot floppy back in the 1990's (the same general idea
+as BusyBox, developed independently). Red Hat discontinued nash development
+in 2010, replacing it with dracut (which collects together existing packages,
+including busybox).</p>
+
+<p>I couldn't figure out how to beat source code out of
+<a href=http://pkgs.fedoraproject.org/git/mkinitrd>Fedora's current git</a>
+repository. The last release version that used it was Fedora Core 12
+which has <a href=http://archive.fedoraproject.org/pub/archive/fedora/linux/releases/12/Fedora/source/SRPMS/mkinitrd-6.0.93-1.fc12.src.rpm>a source rpm</a>
+that can be unwound with "rpm2cpio mkinitrd.src.rpm | cpio -i -d -H newc
+--no-absolute-filenames" and in there is a mkinitrd-6.0.93.tar.bz2 which
+has the source.</p>
+
+<p>In addition to being a bit like a command shell, the nash man page lists the
+following commands:</p>
+
+<blockquote><p>
+access echo find losetup mkdevices mkdir mknod mkdmnod mkrootdev mount
+pivot_root readlink raidautorun setquiet showlabels sleep switchroot umount
+</p></blockquote>
+
+<p>Oddly, the only occurrence of the string pivot_root in the nash source code
+is in the man page, the command isn't there. (It seems to have been removed
+when the underscoreless switchroot went in.)</p>
+
+<p>A more complete list seems to be the handlers[] array in nash.c:</p>
+
+<blockquote><p>
+access buildEnv cat cond cp daemonize dm echo exec exit find kernelopt
+loadDrivers loadpolicy mkchardevs mkblktab mkblkdevs mkdir mkdmnod mknod
+mkrootdev mount netname network null plymouth hotplug killplug losetup
+ln ls raidautorun readlink resume resolveDevice rmparts setDeviceEnv
+setquiet setuproot showelfinterp showlabels sleep stabilized status switchroot
+umount waitdev
+</p></blockquote>
+
+<p>This list is nuts: "plymouth" is an alias for "null" which is basically
+"true" (which thie above list doesn't have). Things like buildEnv and
+loadDrivers are bespoke Red Hat behavior that might as well be hardwired in
+to nash's main() without being called.</p>
+
+<p>Instead of eliminating items
+from the list with an explanation for each, I'm just going to cherry pick
+a few: the device mapper (dm, raidautorun) is probably interesting,
+hotplug (may be obsolete due to kernel changes that now load firmware
+directly), and another "resume" ala klibc.</p>
+
+<p>But mostly: I don't care about this one. And neither does Red Hat anymore.</p>
+
+<p>Verdict: ignore</p>
+
+<hr />
+<a name=beastiebox />
+<h2>Beastiebox</h2>
+
+<p>Back in 2008, the BSD guys vented some busybox-envy
+<a href=http://beastiebox.sourceforge.net>on sourceforge</a>. Then stopped.
+Their repository is still in CVS, hasn't been touched in years, it's a giant
+hairball of existing code sucked together. (The web page says the author
+is aware of crunchgen, but decided to do this by hand anyway. This is not
+a collection of new code, it's a katamari of existing code rolled up in a
+ball.)</p>
+
+<p>Combining the set of commands listed on the web page with the set of
+man pages in the source gives us:</P>
+
+<blockquote><p>
+[ cat chmod cp csh date df disklabel dmesg echo ex fdisk fsck fsck_ffs getty
+halt hostname ifconfig init kill less lesskey ln login ls lv mksh more mount
+mount_ffs mv pfctl ping poweroff ps reboot rm route sed sh stty sysctl tar test
+traceroute umount vi wiconfig
+</p></blockquote>
+
+<p>Apparently lv is the missing link between ed and vi, copyright 1982-1997 (do
+not want), ex is another obsolete vi mode, lesskey is "used to
+specify a set of key bindings to be used with less", and csh is a shell they
+sucked in (even though they have mksh?), [ is an alias for test. Several more bsd-isms that don't have Linux
+equivalents (even in the ubuntu "install this package" search) are
+disklabel, fsck_ffs, mount_ffs, and pfctl. And wiconfig is a
+wavelan interface network card driver utility. Subtracting all that and the
+commands toybox already implements at triage time, we get:</p>
+
+<blockquote><p>
+<span id=beastiebox_cmd>
+fdisk fsck getty halt ifconfig init kill less more mount mv ping poweroff
+ps reboot route sed sh stty sysctl tar test traceroute umount vi
+</span>
+</p></blockquote>
+
+<p>Not a hugely interesting list, but eh.</p>
+
+<p>Verdict: ignore</p>
+
+<hr />
+<a name=BsdBox />
+<h2>BsdBox</h2>
+
+<p>Somebody decided to do a <a href=https://wiki.freebsd.org/AdrianChadd/BsdBox>multicall binary for freebsd</a>.</p>
+
+<p>They based it on crunchgen, a tool that glues existing programs together
+into an archive and uses the name to execute the right one. It has no
+simplification or code sharing benefits whatsoever, it's basically an
+archiver that produces executables.</p>
+
+<p>That's about where I stopped reading.</p>
+
+<p>Verdict: ignore.</p>
+
+<hr />
+<a name=slowaris />
+<h2>OpenSolaris Busybox</h2>
+
+<p>Somebody <a href=http://hub.opensolaris.org/bin/view/Project+busybox/>wrote
+a wiki page</a> saying that Busybox for OpenSolaris would be a good idea.</p>
+
+<p>The corresponding "files" tab is an auto-generated stub. The project never
+even got as far as suggesting commands to include before Oracle discontinued
+OpenSolaris.</p>
+
+<p>Verdict: ignore.</p>
+
+<hr />
+<a name=uclinux />
+<h2>uClinux</h2>
+
+<p>Long ago a hardware developer named Jeff Dionne put together a
+nommu Linux distribution, which involved rewriting a lot of command line
+utilities that relied on <a href=http://nommu.org/memory-faq.txt>features
+unavailable on nommu</a> hardware.</p>
+
+<p>In 2003 Jeff moved to Japan and handed
+the project off to people who allowed it to roll to a stop. The website
+turned into a mess of 404 links, the navigation indexes stopped being
+updated over a decade ago, and the project's CVS repository suffered a
+hard drive failure for which there were no backups. The project continued
+to put out "releases" through 2014 (you have to scroll down in the "news"
+section to find them, the "HTTP download" section in the nav bar on the
+left hasn't been updated in over a decade), which were hand-updated tarball
+snapshots mostly consisting of software from the 1990's. For example the
+2014 release still contained ipfwadm, the package which predated ipchains,
+which predated iptables, which is in the process of being replaced by
+nftables.</p>
+
+<p>Nevertheless, people still try to use this because (at least until the
+launch of <a href=http://nommu.org>nommu.org</a>) the project was viewed
+as the place to discuss, develop, and learn about nommu Linux.
+The role of uclinux.org as an educational resource kept people coming
+to it long after it had collapsed as a Linux distro.</p>
+
+<p>Starting around 0.6.0 toybox began to address nommu support with the goal
+of putting uClinux out of its misery.</p>
+
+<p>An analysis of <a href=http://www.uclinux.org/pub/uClinux/dist/uClinux-dist-20140504.tar.bz2>uClinux-dist-20140504</a> found 312 package
+subdirectories under "user".</p>
+
+<h3>Taking out the trash</h3>
+
+<p>A bunch of packages (<b>inotify-tools, input-event-demon, ipsec-tools, netifd,
+keepalived, mobile-broadband-provider-info, nuttp, readline, snort,
+snort-barnyard, socat, sqlite, sysklogd, sysstat, tcl, ubus, uci, udev,
+unionfs, uqmi, usb_modeswitch, usbutils, util-linux</b>)
+are hard to evaluate because
+uclinux has directories for them, but their source isn't actually in the
+uclinux tree. In some of these the makefiles download a git repo during
+the build, so I'm assuming you can build the external package if you really
+care. (Even when I know what these packages do, I'm skipping them
+because uclinux doesn't actually contain them, and any given snapshot
+of the build system will bitrot as external web links change over time.)</p>
+
+<p>Other packages are orphaned, meaning they're not mentioned from any Kconfig
+or Makefiles outside of their directory, so uclinux can't actually build
+them: <b>mbus</b> is an orphaned i2c test program expecting to run in some sort
+of hardwired hardware context, <b>mkeccbin</b> is an orphaned "ECC annotated
+binary file" generator (meaning it's half of a flash writer),
+<b>wsc_upnp</b> is a "Ralink WPS" driver (some sort of stale wifi chip)...</p>
+
+<p>The majority of the remaining packages are probably not of interest to
+toybox due to being so obsolete or special purpose they may not actually be
+of interest to anybody anymore. (This list also includes a lot of
+special-purpose network back-end stuff that's hard for anybody but
+datacenter admins to evaluate the current relevance of.)</p>
+
+<blockquote><b><p>
+arj asterisk boottools bpalogin br2684ctl camserv can4linux cgi_generic
+cgihtml clamav clamsmtp conntrack-tools cramfs crypto-tools cxxtest
+ddns3-client de2ts-cal debug demo diald discard dnsmasq dnsmasq2
+ethattach expat-examples ez-ipupdate fakeidentd
+fconfig ferret flatfs flthdr freeradius freeswan frob-led frox fswcert
+game gettyd gnugk haserl horch
+hostap hping httptunnel ifattach ipchains
+ipfwadm ipmasqadm ipportfw ipredir ipset iso_client
+jamvm jffs-tools jpegview jquery-ui kendin-config kismet klaxon kmod
+l2tpd lcd ledcmd ledcon lha lilo lirc lissa load loattach
+lpr lrpstat lrzsz mail mbus mgetty microwin ModemManager msntp musicbox
+nooom null openswan openvpn palmbot pam_* pcmcia-cs playrt plugdaemon pop3proxy
+potrace qspitest quagga radauth
+ramimage readprofile rdate readprofile routed rrdtool rtc-ds1302
+sendip ser sethdlc setmac setserial sgutool sigs siproxd slattach
+smtpclient snmpd net-snmp snortrules speedtouch squashfs scep sslwrap stp
+stunnel tcpblast tcpdump tcpwrappers threaddemos tinylogin tinyproxy
+tpt tripwire unrar unzoo version vpnled w3cam xl2tpd zebra
+</p></b></blockquote>
+    
+<p>This stuff is all over the place: arj, lha, rar, and zoo are DOS archivers,
+ethattach describes itself as just "a network tool",
+mail is a textmode smtp mailer literally described as "Some kind of mail
+proggy" in uclinux's kconfig (as opposed to clamsmtp and smtpclient and
+so on), this gettyd isn't a generic version but specifically a
+hardwired ppp dialin utility, mgetty isn't a generic version but is combined
+with "sendfax", hostap is an intersil prism driver, wlan-ng is also an
+intersil prism dirver, null is a program to intentionally dereference a
+null pointer (in case you needed one), iso_client is a
+"Demo Application for the USB Device Driver", kendin-config is
+"for configuring the Micrel Kendin KS8995M over QSPI", speedtouch configures
+a specific brand of asdl modem, portmap is part of Anfs,
+ferret, linux-igd, and miniupnp are all upnp packages,
+lanbypass "can be used to control the LAN
+bypass switches on the Advantech x86 based hardware platforms", lcd is
+"test of lcddma device driver" (an out-of-tree Coldfire driver apparently
+lost to history, the uclinux linux-2.4.x directory has a config symbol for
+it, but nothing in the code actually _uses_ it...), qspitest is another
+coldfire thing, mii-tool-fec is
+"strictly for the FEC Ethernet driver as implemented (and modified) for
+the uCdimm5272", rtc-ds1302 and rtc-m41t11 are usermode drivers for specific
+clock chips, stunnel is basically "openssl s_client -quiet -connect",
+potrace is a bitmap to vector graphic converter, radauth performs command line
+authentication against a radius server,
+clamav, klaxon, ferret, l7-protocols, and nessus are very old network security
+software (it's got a stale snapshot of nmap too), xl2tpd is a PPP over UDP
+tunnel (rfc 2661), zebra is the package quagga replaced,
+lilo is the x86-only bootloader that predated grub (and recently discontinued
+development), lissa is a "framebuffer graphics demo" from
+1998, the squashfs package here is the out of tree patches for 2.4 kernels
+and such before the filesystem was merged upstream (as opposed to the
+squashfs-new package which is a snapshot of the userspace tool from 2011),
+load is basically "dd file /dev/spi", version is basically "cat /proc/version",
+microwin is a port of the WinCE graphics API to Linux, scep is a 2003
+implementation of an IETF draft abandoned in 2010, tpt depends on
+Andrew Morton's 15 year old unmerged "timepegs" kernel patch using the pentium
+cycle counter, vpnled controls a light that reboots systems (what?),
+w3cam is a video4linux 1.0 client (v4l2 showed up during 2.5 and support for
+the old v4l1 was removed in 2.6.38 back in 2011), busybox ate tinylogin
+over a decade ago, lrpstat is a java network monitor
+from 2001, lrzsz is zmodem/ymodem/zmodem, msntp and stp implement rfc2030
+meaning it overflows in 2036 (the package was last updated in 2000), rdate
+is rfc 868 meaning it also overflows in 2036 (which is why ntp was invented
+a few decades back), reiserfsprogs development stopped abruptly after
+Hans Reiser was convicted of murdering his wife Nina (denying it on the
+stand and then leading them to the body as part of his plea bargain during
+sentencing)...
+</p>
+
+<p>Seriously, there's a lot of crap in there. It's hard to analyze most
+of it far enough to prove it _doesn't_ do anything.</p>
+
+<h3>Non-toybox programs</h3>
+
+<p>The following software may actually still do something intelligible
+(although the package versions tend to be years out of date), but
+it's not a direction toybox has chosen to go in.</p>
+
+<p>There are several programming languages (<b>bash, lua, jamvm, tinytcl,
+perl, python</b>) in there. Maybe someone somewhere wants a 2008 release of a
+java virtual machine tested to work on nommu systems (jamvm), but it's out
+of scope for toybox.</p>
+
+<p>A bunch of benchmark programs: <b>cpu, dhrystone, mathtest, nbench, netperf,
+netpipe, and whetstone</b>.</p>
+
+<p>A bunch of web servers: <b>appWeb, boa, fnord (via tcpserver), goahead, httpd,
+mini_httpd, and thttpd</b>.</p>
+
+<p>A bunch of shells: <b>msh</b> is a clever (I.E. obfuscated) little shell,
+<b>nwsh</b> is "new shell" (that's what it called itself in 1999 anyway),
+<b>sash</b> is another shell with a bunch of builtins (ls, ps, df, cp, date, reboot,
+and shutdown, this roadmap analyzes it <a href="#sash">elsewhere</a>),
+<b>sh</b> is a very old minix shell fork, and <b>tcsh</b> is also a shell.</p>
+
+<p>Also in this category, we have:</p>
+
+<blockquote><b><p>
+dropbear jffs-tools jpegview kexec-tools bind ctorrent
+iperf iproute2 ip-sentinel iptables kexec
+nmap oggplay openssl oprofile p7zip pppd pptp play vplay
+hdparm mp3play at clock
+mtd-utils mysql logrotate brcfg bridge-utils flashw
+ebtables etherwake ethtool expect gdb gdbserver hostapd
+lm_sensors load netflash netstat-nat
+radvd recover rootloader resolveip rp-pppoe
+rsyslog rsyslogd samba smbmount squashfs-new squid ssh strace tip
+uboot-envtools ulogd usbhubctrl vconfig vixie-cron watchdogd
+wireless_tools wpa_supplicant
+</p></b></blockquote>
+
+<p>An awful lot of those are borderline: play and vplay are wav file
+audio players, there's oprofile _and_ readprofile (which just reads kernel
+profiling data from /proc/profile),
+radvd is a "routr advertisement daemon" (ipv6 stateless autoconf),
+ctorrent is a bittorent client, 
+lm_sensors is hardware (heat?) monitoring,
+resolveip is dig only less so,
+rp-pppoe is ppp over ethernet,
+ebtables is an ethernet version of iptables (for bridging),
+their dropbear is from 2012, and that ssh version is from 2011
+(which means it's about nine months too _old_ to have the heartbleed bug).
+There's both ulogd and ulogd2 (no idea why), and pppd is version 2.4 but
+there's a ppd-2.3 directory also.</p>
+
+<p>Lots of flash stuff:
+flashw is a flash writer, load is an spi flash loader, netflash writes
+to flash via tftp,
+recover is also a reflash daemon intended to come up when the system can't boot,
+rootloader seems to be another reflash daemon but without dhcp.</p>
+
+<h3>Already in roadmap</h3>
+
+<p>The following packages contain commands already in the toybox roadmap:</p>
+
+<blockquote><b><p>
+agetty cal cksum cron dhcpcd dhcpcd-new dhcpd dhcp-isc dosfstools e2fsprogs
+elvis-tiny levee fdisk fileutils ftp ftpd grep hd hwclock inetd init ntp
+iputils login module-init-tools netcat shutils ntpdate lspci ping procps
+proftpd rsync shadow shutils stty sysutils telnet telnetd tftp tftpd traceroute
+unzip wget mawk net-tools
+</p></b></blockquote>
+
+<p>There are some duplicates in there, levee is a tiny vi implementation
+like elvis-tiny, ntp and ntpdate overlap, etc.</p>
+
+<p>Verdict: We don't really need to do a whole lot special for nommu
+systems, just get the existing toybox roadmap working on nommu and
+we're good. The uClinux project can rest in peace.</p>
+
+<hr />
+<h2>Requests:</h2>
+
+<p>The following additional commands have been requested (and often submitted)
+by various users. I _really_ need to clean up this section.</p>
+
+<p>Also:</p>
+<blockquote><b>
+<span id=request>
+dig freeramdisk getty halt hexdump hwclock klogd modprobe ping ping6 pivot_root
+poweroff readahead rev sfdisk sudo syslogd taskset telnet telnetd tracepath
+traceroute unzip usleep vconfig zip free login modinfo unshare netcat help w
+ntpd iwconfig iwlist rdate
+dos2unix unix2dos catv clear
+pmap realpath setsid timeout truncate
+mkswap swapon swapoff
+count oneit fstype
+acpi blkid eject pwdx
+sulogin rfkill bootchartd
+arp makedevs sysctl killall5 crond crontab deluser last mkpasswd watch
+blockdev rpm2cpio arping brctl dumpleases fsck
+tcpsvd tftpd
+factor fallocate fsfreeze inotifyd lspci nbd-client partprobe strings
+base64 mix
+reset hexedit nsenter shred
+fsync insmod ionice lsmod lsusb rmmod vmstat xxd iotop
+lsof ionice compress dhcp dhcpd addgroup delgroup host iconv ip
+ipcrm ipcs netstat openvt
+deallocvt iorenice
+udpsvd adduser
+</span>
+</b></blockquote>
+
+<!-- #include "footer.html" -->
+
diff --git a/toybox/www/status.html b/toybox/www/status.html
new file mode 100755
index 0000000..8a1a585
--- /dev/null
+++ b/toybox/www/status.html
@@ -0,0 +1,9 @@
+<html><head><title>toybox current status</title>
+<!--#include file="header.html" -->
+<title>Toybox Status</title>
+
+<!--#include file="status.gen" -->
+
+<p>See the <a href=roadmap.html>Roadmap page</a> for more information.</p>
+
+<!-- #include "footer.html" -->
diff --git a/toybox/www/toycans.png b/toybox/www/toycans.png
new file mode 100644
index 0000000..1a133da
--- /dev/null
+++ b/toybox/www/toycans.png
Binary files differ