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.fileo