summaryrefslogtreecommitdiff
path: root/package/toolbox
diff options
context:
space:
mode:
Diffstat (limited to 'package/toolbox')
-rw-r--r--package/toolbox/Makefile24
-rw-r--r--package/toolbox/src/Makefile516
-rw-r--r--package/toolbox/src/cat/Makefile5
-rw-r--r--package/toolbox/src/cat/cat.c163
-rw-r--r--package/toolbox/src/chmod/Makefile3
-rw-r--r--package/toolbox/src/chown/Makefile3
-rw-r--r--package/toolbox/src/clear/Makefile3
-rw-r--r--package/toolbox/src/cmp/Makefile3
-rw-r--r--package/toolbox/src/common.mk21
-rw-r--r--package/toolbox/src/cp/Makefile4
-rw-r--r--package/toolbox/src/cp/cp.c549
-rw-r--r--package/toolbox/src/cp/extern.h63
-rw-r--r--package/toolbox/src/cp/utils.c441
-rw-r--r--package/toolbox/src/date/Makefile5
-rw-r--r--package/toolbox/src/date/date.c272
-rw-r--r--package/toolbox/src/dd/Makefile4
-rw-r--r--package/toolbox/src/df/Makefile3
-rw-r--r--package/toolbox/src/dmesg/Makefile3
-rw-r--r--package/toolbox/src/du/Makefile3
-rw-r--r--package/toolbox/src/exists/Makefile3
-rw-r--r--package/toolbox/src/grep/Makefile4
-rw-r--r--package/toolbox/src/grep/fastgrep.c336
-rw-r--r--package/toolbox/src/grep/file.c215
-rw-r--r--package/toolbox/src/grep/grep.c695
-rw-r--r--package/toolbox/src/grep/grep.h149
-rw-r--r--package/toolbox/src/grep/queue.c116
-rw-r--r--package/toolbox/src/grep/util.c499
-rw-r--r--package/toolbox/src/hd/Makefile3
-rw-r--r--package/toolbox/src/id/Makefile3
-rw-r--r--package/toolbox/src/ifconfig/Makefile3
-rw-r--r--package/toolbox/src/iftop/Makefile3
-rw-r--r--package/toolbox/src/insmod/Makefile3
-rw-r--r--package/toolbox/src/ioctl/Makefile3
-rw-r--r--package/toolbox/src/kill/Makefile3
-rw-r--r--package/toolbox/src/lib/Makefile24
-rw-r--r--package/toolbox/src/lib/fgetln.c48
-rw-r--r--package/toolbox/src/lib/md5.c242
-rw-r--r--package/toolbox/src/lib/md5.h48
-rw-r--r--package/toolbox/src/lib/md5hlp.c13
-rw-r--r--package/toolbox/src/lib/string.h9
-rw-r--r--package/toolbox/src/lib/strlfun.c185
-rw-r--r--package/toolbox/src/ln/Makefile3
-rw-r--r--package/toolbox/src/ls/Makefile4
-rw-r--r--package/toolbox/src/lsof/Makefile3
-rw-r--r--package/toolbox/src/md5/Makefile3
-rw-r--r--package/toolbox/src/mkdir/Makefile3
-rw-r--r--package/toolbox/src/mknod/Makefile6
-rw-r--r--package/toolbox/src/mknod/mknod.c190
-rw-r--r--package/toolbox/src/mknod/setmode.c462
-rw-r--r--package/toolbox/src/mount/Makefile3
-rw-r--r--package/toolbox/src/mv/Makefile3
-rw-r--r--package/toolbox/src/netstat/Makefile3
-rw-r--r--package/toolbox/src/notify/Makefile3
-rw-r--r--package/toolbox/src/printenv/Makefile3
-rw-r--r--package/toolbox/src/ps/Makefile3
-rw-r--r--package/toolbox/src/readlink/Makefile3
-rw-r--r--package/toolbox/src/renice/Makefile3
-rw-r--r--package/toolbox/src/rm/Makefile3
-rw-r--r--package/toolbox/src/rmdir/Makefile3
-rw-r--r--package/toolbox/src/rmmod/Makefile3
-rw-r--r--package/toolbox/src/route/Makefile3
-rw-r--r--package/toolbox/src/schedtop/Makefile3
-rw-r--r--package/toolbox/src/sed/Makefile6
-rw-r--r--package/toolbox/src/sed/compile.c870
-rw-r--r--package/toolbox/src/sed/defs.h147
-rw-r--r--package/toolbox/src/sed/extern.h65
-rw-r--r--package/toolbox/src/sed/main.c523
-rw-r--r--package/toolbox/src/sed/misc.c166
-rw-r--r--package/toolbox/src/sed/process.c642
-rw-r--r--package/toolbox/src/setkey/Makefile3
-rw-r--r--package/toolbox/src/sleep/Makefile3
-rw-r--r--package/toolbox/src/src/chmod.c101
-rw-r--r--package/toolbox/src/src/chown.c73
-rw-r--r--package/toolbox/src/src/clear.c41
-rw-r--r--package/toolbox/src/src/cmp.c91
-rw-r--r--package/toolbox/src/src/dd.c1323
-rw-r--r--package/toolbox/src/src/dd.h94
-rw-r--r--package/toolbox/src/src/df.c85
-rw-r--r--package/toolbox/src/src/dmesg.c64
-rw-r--r--package/toolbox/src/src/du.c322
-rw-r--r--package/toolbox/src/src/dynarray.c104
-rw-r--r--package/toolbox/src/src/dynarray.h80
-rw-r--r--package/toolbox/src/src/exists.c16
-rw-r--r--package/toolbox/src/src/hd.c97
-rw-r--r--package/toolbox/src/src/id.c51
-rw-r--r--package/toolbox/src/src/ifconfig.c164
-rw-r--r--package/toolbox/src/src/iftop.c278
-rw-r--r--package/toolbox/src/src/insmod.c97
-rw-r--r--package/toolbox/src/src/ioctl.c124
-rw-r--r--package/toolbox/src/src/kill.c149
-rw-r--r--package/toolbox/src/src/ln.c34
-rw-r--r--package/toolbox/src/src/ls.c424
-rw-r--r--package/toolbox/src/src/lsof.c253
-rw-r--r--package/toolbox/src/src/md5.c75
-rw-r--r--package/toolbox/src/src/mkdir.c77
-rw-r--r--package/toolbox/src/src/mount.c360
-rw-r--r--package/toolbox/src/src/mv.c59
-rw-r--r--package/toolbox/src/src/netstat.c155
-rw-r--r--package/toolbox/src/src/notify.c145
-rw-r--r--package/toolbox/src/src/printenv.c33
-rw-r--r--package/toolbox/src/src/ps.c244
-rw-r--r--package/toolbox/src/src/readlink.c95
-rw-r--r--package/toolbox/src/src/renice.c161
-rw-r--r--package/toolbox/src/src/rm.c126
-rw-r--r--package/toolbox/src/src/rmdir.c28
-rw-r--r--package/toolbox/src/src/rmmod.c53
-rw-r--r--package/toolbox/src/src/route.c113
-rw-r--r--package/toolbox/src/src/schedtop.c332
-rw-r--r--package/toolbox/src/src/setkey.c91
-rw-r--r--package/toolbox/src/src/sleep.c64
-rw-r--r--package/toolbox/src/src/sync.c7
-rw-r--r--package/toolbox/src/src/top.c542
-rw-r--r--package/toolbox/src/src/touch.c115
-rw-r--r--package/toolbox/src/src/umount.c91
-rw-r--r--package/toolbox/src/src/vmstat.c248
-rw-r--r--package/toolbox/src/sync/Makefile3
-rw-r--r--package/toolbox/src/tool.mk22
-rw-r--r--package/toolbox/src/top/Makefile3
-rw-r--r--package/toolbox/src/touch/Makefile3
-rw-r--r--package/toolbox/src/umount/Makefile3
-rw-r--r--package/toolbox/src/vmstat/Makefile3
121 files changed, 15149 insertions, 0 deletions
diff --git a/package/toolbox/Makefile b/package/toolbox/Makefile
new file mode 100644
index 000000000..af658336a
--- /dev/null
+++ b/package/toolbox/Makefile
@@ -0,0 +1,24 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include ${ADK_TOPDIR}/rules.mk
+
+PKG_NAME:= toolbox
+PKG_VERSION:= 1.0
+PKG_RELEASE:= 1
+PKG_DESCR:= openadk toolbox for very small systems
+PKG_SECTION:= base/apps
+
+NO_DISTFILES:= 1
+
+include ${ADK_TOPDIR}/mk/package.mk
+
+$(eval $(call PKG_template,TOOLBOX,toolbox,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+
+CONFIG_STYLE:= manual
+
+toolbox-install:
+ $(INSTALL_DIR) $(IDIR_TOOLBOX)/bin
+ $(CP) $(WRKINST)/bin/* $(IDIR_TOOLBOX)/bin
+
+include ${ADK_TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/toolbox/src/Makefile b/package/toolbox/src/Makefile
new file mode 100644
index 000000000..50afea707
--- /dev/null
+++ b/package/toolbox/src/Makefile
@@ -0,0 +1,516 @@
+# toolbox for OpenADK on memory-constrained NOMMU binfmt_flat systems
+# Copyright © 2017
+# mirabilos <m@mirbsd.org>
+# Derived from Android Toolbox
+# platform/system/core, as of commit efbf36f2dad8f083de6f48dbb682461d7cfa9781
+#
+# Provided that these terms and disclaimer and all copyright notices
+# are retained or reproduced in an accompanying document, permission
+# is granted to deal in this work without restriction, including un‐
+# limited rights to use, publicly perform, distribute, sell, modify,
+# merge, give away, or sublicence.
+#
+# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
+# the utmost extent permitted by applicable law, neither express nor
+# implied; without malicious intent or gross negligence. In no event
+# may a licensor, author or contributor be held liable for indirect,
+# direct, other damage, loss, or other issues arising in any way out
+# of dealing in the work, even if advised of the possibility of such
+# damage or existence of a defect, except proven that it results out
+# of said person’s immediate fault when using the work as intended.
+#
+# Individual files are covered by their own licence notices, which are
+# also reproduced below (at the end of the top-level Makefile, this file).
+# Changes to those files done within the OpenADK toolbox and the build
+# system of the toolbox are published under Ⓕ The MirOS Licence as above.
+#
+# Summarising the licences used:
+# • 3-clause BSD
+# • ISC (OpenBSD)
+# • MirOS
+# • Public Domain
+
+ SUBDIR+= lib
+
+ SUBDIR+= cat
+ SUBDIR+= chmod
+ SUBDIR+= chown
+ SUBDIR+= clear
+ SUBDIR+= cmp
+ SUBDIR+= cp
+ SUBDIR+= date
+ SUBDIR+= dd
+ SUBDIR+= df
+ SUBDIR+= dmesg
+ SUBDIR+= du
+ SUBDIR+= exists
+ SUBDIR+= grep
+ SUBDIR+= hd
+ SUBDIR+= id
+ SUBDIR+= ifconfig
+ SUBDIR+= iftop
+ SUBDIR+= insmod
+# SUBDIR+= ioctl needs pthread.h
+ SUBDIR+= kill
+ SUBDIR+= ln
+ SUBDIR+= ls
+ SUBDIR+= lsof
+ SUBDIR+= md5
+ SUBDIR+= mkdir
+ SUBDIR+= mknod
+ SUBDIR+= mount
+ SUBDIR+= mv
+ SUBDIR+= netstat
+ SUBDIR+= notify
+ SUBDIR+= printenv
+ SUBDIR+= ps
+ SUBDIR+= readlink
+ SUBDIR+= renice
+ SUBDIR+= rm
+ SUBDIR+= rmdir
+ SUBDIR+= rmmod
+ SUBDIR+= route
+ SUBDIR+= schedtop
+ SUBDIR+= sed
+ SUBDIR+= setkey
+ SUBDIR+= sleep
+ SUBDIR+= sync
+ SUBDIR+= top
+ SUBDIR+= touch
+ SUBDIR+= umount
+ SUBDIR+= vmstat
+
+%:
+ @for subdir in ${SUBDIR}; do \
+ echo "==> $$subdir"; \
+ ${MAKE} --no-print-directory -I.. \
+ -C "$$subdir" $@ || exit $?; \
+ echo "<== $$subdir"; \
+ done
+
+all:
+
+#======================================
+# Now follows the original NOTICE file:
+#======================================
+
+# Copyright (c) 2010, The Android Open Source Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of The Android Open Source Project nor the names
+# of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+# Copyright (c) 2009, The Android Open Source Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of The Android Open Source Project nor the names
+# of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+# Copyright (c) 2008, The Android Open Source Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of The Android Open Source Project nor the names
+# of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+# Copyright (c) 1998 Robert Nordier
+# Copyright (c) 1989, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kevin Fall.
+# This code is derived from software contributed to Berkeley by
+# Keith Muller of the University of California, San Diego and Lance
+# Visser of Convex Computer Corporation.
+# This code is derived from software contributed to Berkeley by
+# Mike Muuss.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+# Copyright (c) 1989, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kevin Fall.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+# Copyright (c) 1991, 1993, 1994
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Keith Muller of the University of California, San Diego and Lance
+# Visser of Convex Computer Corporation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+# /*
+# * Copyright (c) 1985, 1987, 1988, 1993
+# * The Regents of the University of California. All rights reserved.
+# *
+# * Redistribution and use in source and binary forms, with or without
+# * modification, are permitted provided that the following conditions
+# * are met:
+# * 1. Redistributions of source code must retain the above copyright
+# * notice, this list of conditions and the following disclaimer.
+# * 2. Redistributions in binary form must reproduce the above copyright
+# * notice, this list of conditions and the following disclaimer in the
+# * documentation and/or other materials provided with the distribution.
+# * 3. Neither the name of the University nor the names of its contributors
+# * may be used to endorse or promote products derived from this software
+# * without specific prior written permission.
+# *
+# * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# * SUCH DAMAGE.
+# */
+#
+# /*-
+# * Copyright (c) 2007, 2009
+# * Thorsten Glaser <tg@mirbsd.org>
+# *
+# * Provided that these terms and disclaimer and all copyright notices
+# * are retained or reproduced in an accompanying document, permission
+# * is granted to deal in this work without restriction, including un-
+# * limited rights to use, publicly perform, distribute, sell, modify,
+# * merge, give away, or sublicence.
+# *
+# * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+# * the utmost extent permitted by applicable law, neither express nor
+# * implied; without malicious intent or gross negligence. In no event
+# * may a licensor, author or contributor be held liable for indirect,
+# * direct, other damage, loss, or other issues arising in any way out
+# * of dealing in the work, even if advised of the possibility of such
+# * damage or existence of a defect, except proven that it results out
+# * of said person's immediate fault when using the work as intended.
+# */
+#
+# /*
+# * This code implements the MD5 message-digest algorithm.
+# * The algorithm is due to Ron Rivest. This code was
+# * written by Colin Plumb in 1993, no copyright is claimed.
+# * This code is in the public domain; do with it what you wish.
+# */
+#
+# /*-
+# * Copyright (c) 2006, 2008, 2011
+# * mirabilos <m@mirbsd.org>
+# *
+# * Provided that these terms and disclaimer and all copyright notices
+# * are retained or reproduced in an accompanying document, permission
+# * is granted to deal in this work without restriction, including un-
+# * limited rights to use, publicly perform, distribute, sell, modify,
+# * merge, give away, or sublicence.
+# *
+# * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+# * the utmost extent permitted by applicable law, neither express nor
+# * implied; without malicious intent or gross negligence. In no event
+# * may a licensor, author or contributor be held liable for indirect,
+# * direct, other damage, loss, or other issues arising in any way out
+# * of dealing in the work, even if advised of the possibility of such
+# * damage or existence of a defect, except proven that it results out
+# * of said person's immediate fault when using the work as intended.
+# */
+#
+# /*-
+# * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+# *
+# * Permission to use, copy, modify, and distribute this software for any
+# * purpose with or without fee is hereby granted, provided that the above
+# * copyright notice and this permission notice appear in all copies.
+# *
+# * 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.
+# */
+#
+# /*
+# * Copyright (c) 1989, 1990, 1993
+# * The Regents of the University of California. All rights reserved.
+# *
+# * This code is derived from software contributed to Berkeley by
+# * Kevin Fall.
+# *
+# * Redistribution and use in source and binary forms, with or without
+# * modification, are permitted provided that the following conditions
+# * are met:
+# * 1. Redistributions of source code must retain the above copyright
+# * notice, this list of conditions and the following disclaimer.
+# * 2. Redistributions in binary form must reproduce the above copyright
+# * notice, this list of conditions and the following disclaimer in the
+# * documentation and/or other materials provided with the distribution.
+# * 3. Neither the name of the University nor the names of its contributors
+# * may be used to endorse or promote products derived from this software
+# * without specific prior written permission.
+# *
+# * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# * SUCH DAMAGE.
+# */
+#
+# /*
+# * Copyright (c) 1989, 1993, 1994
+# * The Regents of the University of California. All rights reserved.
+# *
+# * This code is derived from software contributed to Berkeley by
+# * Dave Borman at Cray Research, Inc.
+# *
+# * Redistribution and use in source and binary forms, with or without
+# * modification, are permitted provided that the following conditions
+# * are met:
+# * 1. Redistributions of source code must retain the above copyright
+# * notice, this list of conditions and the following disclaimer.
+# * 2. Redistributions in binary form must reproduce the above copyright
+# * notice, this list of conditions and the following disclaimer in the
+# * documentation and/or other materials provided with the distribution.
+# * 3. Neither the name of the University nor the names of its contributors
+# * may be used to endorse or promote products derived from this software
+# * without specific prior written permission.
+# *
+# * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# * SUCH DAMAGE.
+# */
+#
+# /*-
+# * Copyright (c) 2015, 2016, 2017
+# * mirabilos <m@mirbsd.org>
+# * Copyright (c) 1992 Diomidis Spinellis.
+# * Copyright (c) 1992, 1993
+# * The Regents of the University of California. All rights reserved.
+# *
+# * This code is derived from software contributed to Berkeley by
+# * Diomidis Spinellis of Imperial College, University of London.
+# *
+# * Redistribution and use in source and binary forms, with or without
+# * modification, are permitted provided that the following conditions
+# * are met:
+# * 1. Redistributions of source code must retain the above copyright
+# * notice, this list of conditions and the following disclaimer.
+# * 2. Redistributions in binary form must reproduce the above copyright
+# * notice, this list of conditions and the following disclaimer in the
+# * documentation and/or other materials provided with the distribution.
+# * 3. Neither the name of the University nor the names of its contributors
+# * may be used to endorse or promote products derived from this software
+# * without specific prior written permission.
+# *
+# * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# * SUCH DAMAGE.
+# */
+#
+# /*
+# * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+# *
+# * Permission to use, copy, modify, and distribute this software for any
+# * purpose with or without fee is hereby granted, provided that the above
+# * copyright notice and this permission notice appear in all copies.
+# *
+# * 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.
+# */
+#
+# /*-
+# * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+# * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
+# * mirabilos <m@mirbsd.org>
+# *
+# * Provided that these terms and disclaimer and all copyright notices
+# * are retained or reproduced in an accompanying document, permission
+# * is granted to deal in this work without restriction, including un-
+# * limited rights to use, publicly perform, distribute, sell, modify,
+# * merge, give away, or sublicence.
+# *
+# * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+# * the utmost extent permitted by applicable law, neither express nor
+# * implied; without malicious intent or gross negligence. In no event
+# * may a licensor, author or contributor be held liable for indirect,
+# * direct, other damage, loss, or other issues arising in any way out
+# * of dealing in the work, even if advised of the possibility of such
+# * damage or existence of a defect, except proven that it results out
+# * of said person's immediate fault when using the work as intended.
+# */
diff --git a/package/toolbox/src/cat/Makefile b/package/toolbox/src/cat/Makefile
new file mode 100644
index 000000000..61abf9bbd
--- /dev/null
+++ b/package/toolbox/src/cat/Makefile
@@ -0,0 +1,5 @@
+PROG= cat
+
+include ../tool.mk
+
+CFLAGS+=-Wextra
diff --git a/package/toolbox/src/cat/cat.c b/package/toolbox/src/cat/cat.c
new file mode 100644
index 000000000..442f72073
--- /dev/null
+++ b/package/toolbox/src/cat/cat.c
@@ -0,0 +1,163 @@
+/*-
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MKSH_CAT_BUFSIZ 256
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define ksh_sigmask(sig) (((sig) < 1 || (sig) > 127) ? 255 : 128 + (sig))
+
+static char buf[MKSH_CAT_BUFSIZ];
+static volatile sig_atomic_t intrsig;
+
+static const char Tsynerr[] = "cat: syntax error\n";
+static const char unkerr_msg[] = "Unknown error";
+static const char sigint_msg[] = " ...\ncat: Interrupted\n";
+
+static void
+disperr(const char *fn)
+{
+ int e = errno;
+
+ write(2, "cat: ", 5);
+ write(2, fn, strlen(fn));
+ write(2, ": ", 2);
+ if (strerror_r(e, buf, MKSH_CAT_BUFSIZ))
+ write(2, unkerr_msg, sizeof(unkerr_msg) - 1);
+ else
+ write(2, buf, strlen(buf));
+ write(2, "\n", 1);
+}
+
+static void
+sighandler(int signo __attribute__((__unused__)))
+{
+ intrsig = 1;
+}
+
+int
+main(int argc __attribute__((__unused__)), char *wp[])
+{
+ int fd = 0, rv;
+ ssize_t n, w;
+ const char *fn = "<stdin>";
+ char *cp;
+
+ ++wp;
+ /* parse options (POSIX demands this) */
+ while ((cp = *wp) && *cp++ == '-') {
+ if (!cp[0])
+ break;
+ if (cp[0] == '-' && !cp[1]) {
+ ++wp;
+ break;
+ }
+ while (*cp == 'u')
+ ++cp;
+ if (*cp) {
+ write(2, Tsynerr, sizeof(Tsynerr) - 1);
+ return (1);
+ }
+ ++wp;
+ }
+ rv = 0;
+
+ /* catch SIGPIPE */
+ signal(SIGPIPE, SIG_IGN);
+
+ /* abort on SIGINT */
+ signal(SIGINT, sighandler);
+
+ do {
+ if (*wp) {
+ fn = *wp++;
+ if (fn[0] == '-' && !fn[1])
+ fd = 0;
+ else if ((fd = open(fn, O_RDONLY | O_BINARY)) < 0) {
+ disperr(fn);
+ rv = 1;
+ continue;
+ }
+ }
+ while (/* CONSTCOND */ 1) {
+ if ((n = read(fd, (cp = buf), MKSH_CAT_BUFSIZ)) == -1) {
+ if (errno == EINTR) {
+ /* give the user a chance to ^C out */
+ if (intrsig)
+ goto has_intrsig;
+ /* interrupted, try again */
+ continue;
+ }
+ /* an error occured during reading */
+ disperr(fn);
+ rv = 1;
+ break;
+ } else if (n == 0)
+ /* end of file reached */
+ break;
+ while (n) {
+ if (intrsig)
+ goto has_intrsig;
+ if ((w = write(1, cp, n)) != -1) {
+ n -= w;
+ cp += w;
+ continue;
+ }
+ if (errno == EINTR) {
+ has_intrsig:
+ /* give the user a chance to ^C out */
+ if (intrsig) {
+ write(2, sigint_msg,
+ sizeof(sigint_msg) - 1);
+ return (ksh_sigmask(SIGINT));
+ }
+ /* interrupted, try again */
+ continue;
+ }
+ if (errno == EPIPE) {
+ /* fake receiving signal */
+ rv = ksh_sigmask(SIGPIPE);
+ } else {
+ /* an error occured during writing */
+ disperr("<stdout>");
+ rv = 1;
+ }
+ if (fd != 0)
+ close(fd);
+ goto out;
+ }
+ }
+ if (fd != 0)
+ close(fd);
+ } while (*wp);
+
+ out:
+ return (rv);
+}
diff --git a/package/toolbox/src/chmod/Makefile b/package/toolbox/src/chmod/Makefile
new file mode 100644
index 000000000..347b93d77
--- /dev/null
+++ b/package/toolbox/src/chmod/Makefile
@@ -0,0 +1,3 @@
+PROG= chmod
+
+include ../tool.mk
diff --git a/package/toolbox/src/chown/Makefile b/package/toolbox/src/chown/Makefile
new file mode 100644
index 000000000..e2bb26ae7
--- /dev/null
+++ b/package/toolbox/src/chown/Makefile
@@ -0,0 +1,3 @@
+PROG= chown
+
+include ../tool.mk
diff --git a/package/toolbox/src/clear/Makefile b/package/toolbox/src/clear/Makefile
new file mode 100644
index 000000000..8e2919133
--- /dev/null
+++ b/package/toolbox/src/clear/Makefile
@@ -0,0 +1,3 @@
+PROG= clear
+
+include ../tool.mk
diff --git a/package/toolbox/src/cmp/Makefile b/package/toolbox/src/cmp/Makefile
new file mode 100644
index 000000000..68dffd303
--- /dev/null
+++ b/package/toolbox/src/cmp/Makefile
@@ -0,0 +1,3 @@
+PROG= cmp
+
+include ../tool.mk
diff --git a/package/toolbox/src/common.mk b/package/toolbox/src/common.mk
new file mode 100644
index 000000000..ab0728f18
--- /dev/null
+++ b/package/toolbox/src/common.mk
@@ -0,0 +1,21 @@
+OBJS:= ${SRCS:.c=.o}
+CFLAGS?= -Os -Wall
+CPPFLAGS+= -I.
+#CPPFLAGS+= -D_FILE_OFFSET_BITS=64
+CPPFLAGS+= -isystem ../lib
+CPPFLAGS+= -D'__COPYRIGHT(x)=' -D'__RCSID(x)='
+CPPFLAGS+= -D'__unused=__attribute__((__unused__))'
+CPPFLAGS+= -D'__dead=__attribute__((__noreturn__))'
+CLEANFILES+= ${OBJS} ${PROG}
+
+all:
+
+COMPILE.c= ${CC} ${CPPFLAGS} ${CFLAGS} ${CFLAGS_$@} -c
+
+.c.o:
+ ${COMPILE.c} -o $@ $<
+
+clean:
+ rm -f ${CLEANFILES}
+
+# no depend magic; if you change a .h file, just make clean
diff --git a/package/toolbox/src/cp/Makefile b/package/toolbox/src/cp/Makefile
new file mode 100644
index 000000000..17545ac06
--- /dev/null
+++ b/package/toolbox/src/cp/Makefile
@@ -0,0 +1,4 @@
+PROG= cp
+SRCS= cp.c utils.c
+
+include ../tool.mk
diff --git a/package/toolbox/src/cp/cp.c b/package/toolbox/src/cp/cp.c
new file mode 100644
index 000000000..d04702f2a
--- /dev/null
+++ b/package/toolbox/src/cp/cp.c
@@ -0,0 +1,549 @@
+/* $NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * David Hitz of Auspex Systems Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT(
+"@(#) Copyright (c) 1988, 1993, 1994\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cp.c 8.5 (Berkeley) 4/29/95";
+#else
+__RCSID("$NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * Cp copies source files to target files.
+ *
+ * The global PATH_T structure "to" always contains the path to the
+ * current target file. Since fts(3) does not change directories,
+ * this path can be either absolute or dot-relative.
+ *
+ * The basic algorithm is to initialize "to" and use fts(3) to traverse
+ * the file hierarchy rooted in the argument list. A trivial case is the
+ * case of 'cp file1 file2'. The more interesting case is the case of
+ * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
+ * path (relative to the root of the traversal) is appended to dir (stored
+ * in "to") to form the final target path.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define STRIP_TRAILING_SLASH(p) { \
+ while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \
+ *--(p).p_end = '\0'; \
+}
+
+static char empty[] = "";
+PATH_T to = { .p_end = to.p_path, .target_end = empty };
+
+uid_t myuid;
+int Hflag, Lflag, Rflag, Pflag, fflag, iflag, lflag, pflag, rflag, vflag, Nflag;
+mode_t myumask;
+sig_atomic_t pinfo;
+
+enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
+
+static int copy(char *[], enum op, int);
+
+#ifdef SIGINFO
+static void
+progress(int sig __unused)
+{
+
+ pinfo++;
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct stat to_stat, tmp_stat;
+ enum op type;
+ int ch, fts_options, r, have_trailing_slash;
+ char *target, **src;
+
+ Hflag = Lflag = Pflag = Rflag = 0;
+ while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1)
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = Pflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = Pflag = 0;
+ break;
+ case 'N':
+ Nflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ Hflag = Lflag = 0;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'a':
+ Pflag = 1;
+ pflag = 1;
+ Rflag = 1;
+ Hflag = Lflag = 0;
+ break;
+ case 'f':
+ fflag = 1;
+ iflag = 0;
+ break;
+ case 'i':
+ iflag = isatty(fileno(stdin));
+ fflag = 0;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case '?':
+ default:
+ cp_usage();
+ /* NOTREACHED */
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ cp_usage();
+
+ fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
+ if (rflag) {
+ if (Rflag) {
+ errx(EXIT_FAILURE,
+ "the -R and -r options may not be specified together.");
+ /* NOTREACHED */
+ }
+ if (Hflag || Lflag || Pflag) {
+ errx(EXIT_FAILURE,
+ "the -H, -L, and -P options may not be specified with the -r option.");
+ /* NOTREACHED */
+ }
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+
+ if (Rflag) {
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ if (Lflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ } else if (!Pflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
+ }
+
+ myuid = getuid();
+
+ /* Copy the umask for explicit mode setting. */
+ myumask = umask(0);
+ (void)umask(myumask);
+
+ /* Save the target base in "to". */
+ target = argv[--argc];
+ if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path))
+ errx(EXIT_FAILURE, "%s: name too long", target);
+ to.p_end = to.p_path + strlen(to.p_path);
+ have_trailing_slash = (to.p_end[-1] == '/');
+ if (have_trailing_slash)
+ STRIP_TRAILING_SLASH(to);
+ to.target_end = to.p_end;
+
+ /* Set end of argument list for fts(3). */
+ argv[argc] = NULL;
+
+#ifdef SIGINFO
+ (void)signal(SIGINFO, progress);
+#endif
+
+ /*
+ * Cp has two distinct cases:
+ *
+ * cp [-R] source target
+ * cp [-R] source1 ... sourceN directory
+ *
+ * In both cases, source can be either a file or a directory.
+ *
+ * In (1), the target becomes a copy of the source. That is, if the
+ * source is a file, the target will be a file, and likewise for
+ * directories.
+ *
+ * In (2), the real target is not directory, but "directory/source".
+ */
+ if (Pflag)
+ r = lstat(to.p_path, &to_stat);
+ else
+ r = stat(to.p_path, &to_stat);
+ if (r == -1 && errno != ENOENT) {
+ err(EXIT_FAILURE, "%s", to.p_path);
+ /* NOTREACHED */
+ }
+ if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
+ /*
+ * Case (1). Target is not a directory.
+ */
+ if (argc > 1)
+ cp_usage();
+ /*
+ * Need to detect the case:
+ * cp -R dir foo
+ * Where dir is a directory and foo does not exist, where
+ * we want pathname concatenations turned on but not for
+ * the initial mkdir().
+ */
+ if (r == -1) {
+ if (rflag || (Rflag && (Lflag || Hflag)))
+ r = stat(*argv, &tmp_stat);
+ else
+ r = lstat(*argv, &tmp_stat);
+ if (r == -1) {
+ err(EXIT_FAILURE, "%s", *argv);
+ /* NOTREACHED */
+ }
+
+ if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
+ type = DIR_TO_DNE;
+ else
+ type = FILE_TO_FILE;
+ } else
+ type = FILE_TO_FILE;
+
+ if (have_trailing_slash && type == FILE_TO_FILE) {
+ if (r == -1)
+ errx(1, "directory %s does not exist",
+ to.p_path);
+ else
+ errx(1, "%s is not a directory", to.p_path);
+ }
+ } else {
+ /*
+ * Case (2). Target is a directory.
+ */
+ type = FILE_TO_DIR;
+ }
+
+ /*
+ * make "cp -rp src/ dst" behave like "cp -rp src dst" not
+ * like "cp -rp src/. dst"
+ */
+ for (src = argv; *src; src++) {
+ size_t len = strlen(*src);
+ while (len-- > 1 && (*src)[len] == '/')
+ (*src)[len] = '\0';
+ }
+
+ exit(copy(argv, type, fts_options));
+ /* NOTREACHED */
+}
+
+static int dnestack[MAXPATHLEN]; /* unlikely we'll have more nested dirs */
+static ssize_t dnesp;
+static void
+pushdne(int dne)
+{
+
+ dnestack[dnesp++] = dne;
+ assert(dnesp < MAXPATHLEN);
+}
+
+static int
+popdne(void)
+{
+ int rv;
+
+ rv = dnestack[--dnesp];
+ assert(dnesp >= 0);
+ return rv;
+}
+
+static int
+copy(char *argv[], enum op type, int fts_options)
+{
+ struct stat to_stat;
+ FTS *ftsp;
+ FTSENT *curr;
+ int base, dne, sval;
+ int this_failed, any_failed;
+ size_t nlen;
+ char *p, *target_mid;
+
+ base = 0; /* XXX gcc -Wuninitialized (see comment below) */
+
+ if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
+ err(EXIT_FAILURE, "%s", argv[0]);
+ /* NOTREACHED */
+ for (any_failed = 0; (curr = fts_read(ftsp)) != NULL;) {
+ this_failed = 0;
+ switch (curr->fts_info) {
+ case FTS_NS:
+ case FTS_DNR:
+ case FTS_ERR:
+ warnx("%s: %s", curr->fts_path,
+ strerror(curr->fts_errno));
+ this_failed = any_failed = 1;
+ continue;
+ case FTS_DC: /* Warn, continue. */
+ warnx("%s: directory causes a cycle", curr->fts_path);
+ this_failed = any_failed = 1;
+ continue;
+ }
+
+ /*
+ * If we are in case (2) or (3) above, we need to append the
+ * source name to the target name.
+ */
+ if (type != FILE_TO_FILE) {
+ if ((curr->fts_namelen +
+ to.target_end - to.p_path + 1) > MAXPATHLEN) {
+ warnx("%s/%s: name too long (not copied)",
+ to.p_path, curr->fts_name);
+ this_failed = any_failed = 1;
+ continue;
+ }
+
+ /*
+ * Need to remember the roots of traversals to create
+ * correct pathnames. If there's a directory being
+ * copied to a non-existent directory, e.g.
+ * cp -R a/dir noexist
+ * the resulting path name should be noexist/foo, not
+ * noexist/dir/foo (where foo is a file in dir), which
+ * is the case where the target exists.
+ *
+ * Also, check for "..". This is for correct path
+ * concatentation for paths ending in "..", e.g.
+ * cp -R .. /tmp
+ * Paths ending in ".." are changed to ".". This is
+ * tricky, but seems the easiest way to fix the problem.
+ *
+ * XXX
+ * Since the first level MUST be FTS_ROOTLEVEL, base
+ * is always initialized.
+ */
+ if (curr->fts_level == FTS_ROOTLEVEL) {
+ if (type != DIR_TO_DNE) {
+ p = strrchr(curr->fts_path, '/');
+ base = (p == NULL) ? 0 :
+ (int)(p - curr->fts_path + 1);
+
+ if (!strcmp(&curr->fts_path[base],
+ ".."))
+ base += 1;
+ } else
+ base = curr->fts_pathlen;
+ }
+
+ p = &curr->fts_path[base];
+ nlen = curr->fts_pathlen - base;
+ target_mid = to.target_end;
+ if (*p != '/' && target_mid[-1] != '/')
+ *target_mid++ = '/';
+ *target_mid = 0;
+
+ if (target_mid - to.p_path + nlen >= PATH_MAX) {
+ warnx("%s%s: name too long (not copied)",
+ to.p_path, p);
+ this_failed = any_failed = 1;
+ continue;
+ }
+ (void)strncat(target_mid, p, nlen);
+ to.p_end = target_mid + nlen;
+ *to.p_end = 0;
+ STRIP_TRAILING_SLASH(to);
+ }
+
+ sval = Pflag ? lstat(to.p_path, &to_stat) : stat(to.p_path, &to_stat);
+ /* Not an error but need to remember it happened */
+ if (sval == -1)
+ dne = 1;
+ else {
+ if (to_stat.st_dev == curr->fts_statp->st_dev &&
+ to_stat.st_ino == curr->fts_statp->st_ino) {
+ warnx("%s and %s are identical (not copied).",
+ to.p_path, curr->fts_path);
+ this_failed = any_failed = 1;
+ if (S_ISDIR(curr->fts_statp->st_mode))
+ (void)fts_set(ftsp, curr, FTS_SKIP);
+ continue;
+ }
+ if (!S_ISDIR(curr->fts_statp->st_mode) &&
+ S_ISDIR(to_stat.st_mode)) {
+ warnx("cannot overwrite directory %s with non-directory %s",
+ to.p_path, curr->fts_path);
+ this_failed = any_failed = 1;
+ continue;
+ }
+ dne = 0;
+ }
+
+ switch (curr->fts_statp->st_mode & S_IFMT) {
+ case S_IFLNK:
+ /* Catch special case of a non dangling symlink */
+ if((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) {
+ if (copy_file(curr, dne))
+ this_failed = any_failed = 1;
+ } else {
+ if (copy_link(curr, !dne))
+ this_failed = any_failed = 1;
+ }
+ break;
+ case S_IFDIR:
+ if (!Rflag && !rflag) {
+ if (curr->fts_info == FTS_D)
+ warnx("%s is a directory (not copied).",
+ curr->fts_path);
+ (void)fts_set(ftsp, curr, FTS_SKIP);
+ this_failed = any_failed = 1;
+ break;
+ }
+
+ /*
+ * Directories get noticed twice:
+ * In the first pass, create it if needed.
+ * In the second pass, after the children have been copied, set the permissions.
+ */
+ if (curr->fts_info == FTS_D) /* First pass */
+ {
+ /*
+ * If the directory doesn't exist, create the new
+ * one with the from file mode plus owner RWX bits,
+ * modified by the umask. Trade-off between being
+ * able to write the directory (if from directory is
+ * 555) and not causing a permissions race. If the
+ * umask blocks owner writes, we fail..
+ */
+ pushdne(dne);
+ if (dne) {
+ if (mkdir(to.p_path,
+ curr->fts_statp->st_mode | S_IRWXU) < 0)
+ err(EXIT_FAILURE, "%s",
+ to.p_path);
+ /* NOTREACHED */
+ } else if (!S_ISDIR(to_stat.st_mode)) {
+ errno = ENOTDIR;
+ err(EXIT_FAILURE, "%s",
+ to.p_path);
+ /* NOTREACHED */
+ }
+ }
+ else if (curr->fts_info == FTS_DP) /* Second pass */
+ {
+ /*
+ * If not -p and directory didn't exist, set it to be
+ * the same as the from directory, umodified by the
+ * umask; arguably wrong, but it's been that way
+ * forever.
+ */
+ if (pflag && setfile(curr->fts_statp, 0))
+ this_failed = any_failed = 1;
+ else if ((dne = popdne()))
+ (void)chmod(to.p_path,
+ curr->fts_statp->st_mode);
+ }
+ else
+ {
+ warnx("directory %s encountered when not expected.",
+ curr->fts_path);
+ this_failed = any_failed = 1;
+ break;
+ }
+
+ break;
+ case S_IFBLK:
+ case S_IFCHR:
+ if (Rflag) {
+ if (copy_special(curr->fts_statp, !dne))
+ this_failed = any_failed = 1;
+ } else
+ if (copy_file(curr, dne))
+ this_failed = any_failed = 1;
+ break;
+ case S_IFIFO:
+ if (Rflag) {
+ if (copy_fifo(curr->fts_statp, !dne))
+ this_failed = any_failed = 1;
+ } else
+ if (copy_file(curr, dne))
+ this_failed = any_failed = 1;
+ break;
+ default:
+ if (copy_file(curr, dne))
+ this_failed = any_failed = 1;
+ break;
+ }
+ if (vflag && !this_failed)
+ (void)printf("%s -> %s\n", curr->fts_path, to.p_path);
+ }
+ if (errno) {
+ err(EXIT_FAILURE, "fts_read");
+ /* NOTREACHED */
+ }
+ (void)fts_close(ftsp);
+ return (any_failed);
+}
diff --git a/package/toolbox/src/cp/extern.h b/package/toolbox/src/cp/extern.h
new file mode 100644
index 000000000..6aa9b1b5a
--- /dev/null
+++ b/package/toolbox/src/cp/extern.h
@@ -0,0 +1,63 @@
+/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/1/94
+ */
+
+#ifndef _EXTERN_H_
+#define _EXTERN_H_
+
+#include <signal.h>
+
+typedef struct {
+ char *p_end; /* pointer to NULL at end of path */
+ char *target_end; /* pointer to end of target base */
+ char p_path[MAXPATHLEN + 1]; /* pointer to the start of a path */
+} PATH_T;
+
+extern PATH_T to;
+extern uid_t myuid;
+extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag;
+extern mode_t myumask;
+extern sig_atomic_t pinfo;
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int copy_fifo(struct stat *, int);
+int copy_file(FTSENT *, int);
+int copy_link(FTSENT *, int);
+int copy_special(struct stat *, int);
+int set_utimes(const char *, struct stat *);
+int setfile(struct stat *, int);
+void cp_usage(void) __attribute__((__noreturn__));
+__END_DECLS
+
+#endif /* !_EXTERN_H_ */
diff --git a/package/toolbox/src/cp/utils.c b/package/toolbox/src/cp/utils.c
new file mode 100644
index 000000000..cfb254a45
--- /dev/null
+++ b/package/toolbox/src/cp/utils.c
@@ -0,0 +1,441 @@
+/* $NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94";
+#else
+__RCSID("$NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#ifndef BSD
+#define MAXBSIZE 65536
+#endif
+
+#define MMAP_MAX_SIZE (8 * 1048576)
+#define MMAP_MAX_WRITE (64 * 1024)
+
+int
+set_utimes(const char *file, struct stat *fs)
+{
+ static struct timeval tv[2];
+
+#ifndef BSD
+ tv[0].tv_sec = fs->st_atime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = fs->st_mtime;
+ tv[1].tv_usec = 0;
+
+ if (utimes(file, tv)) {
+ warn("utimes: %s", file);
+ return 1;
+ }
+#else
+ TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
+ TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
+
+ if (lutimes(file, tv)) {
+ warn("lutimes: %s", file);
+ return (1);
+ }
+#endif
+ return (0);
+}
+
+struct finfo {
+ const char *from;
+ const char *to;
+ size_t size;
+};
+
+static void
+progress(const struct finfo *fi, size_t written)
+{
+ int pcent = (int)((100.0 * written) / fi->size);
+
+ pinfo = 0;
+ (void)fprintf(stderr, "%s => %s %zu/%zu bytes %d%% written\n",
+ fi->from, fi->to, written, fi->size, pcent);
+}
+
+int
+copy_file(FTSENT *entp, int dne)
+{
+ static char buf[MAXBSIZE];
+ struct stat to_stat, *fs;
+ int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount;
+ char *p;
+ size_t ptotal = 0;
+
+ if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
+ warn("%s", entp->fts_path);
+ return (1);
+ }
+
+ to_fd = -1;
+ fs = entp->fts_statp;
+ tolnk = ((Rflag && !(Lflag || Hflag)) || Pflag);
+
+ /*
+ * If the file exists and we're interactive, verify with the user.
+ * If the file DNE, set the mode to be the from file, minus setuid
+ * bits, modified by the umask; arguably wrong, but it makes copying
+ * executables work right and it's been that way forever. (The
+ * other choice is 666 or'ed with the execute bits on the from file
+ * modified by the umask.)
+ */
+ if (!dne) {
+ struct stat sb;
+ int sval;
+
+ if (iflag) {
+ (void)fprintf(stderr, "overwrite %s? ", to.p_path);
+ checkch = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+ if (checkch != 'y' && checkch != 'Y') {
+ (void)close(from_fd);
+ return (0);
+ }
+ }
+
+ sval = tolnk ?
+ lstat(to.p_path, &sb) : stat(to.p_path, &sb);
+ if (sval == -1) {
+ warn("stat: %s", to.p_path);
+ (void)close(from_fd);
+ return (1);
+ }
+
+ if (!(tolnk && S_ISLNK(sb.st_mode)))
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+ } else
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+
+ if (to_fd == -1 && (fflag || tolnk)) {
+ /*
+ * attempt to remove existing destination file name and
+ * create a new file
+ */
+ (void)unlink(to.p_path);
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+ }
+
+ if (to_fd == -1) {
+ warn("%s", to.p_path);
+ (void)close(from_fd);
+ return (1);
+ }
+
+ rval = 0;
+
+ /* if hard linking then simply close the open fds, link and return */
+ if (lflag) {
+ (void)close(from_fd);
+ (void)close(to_fd);
+ (void)unlink(to.p_path);
+ if (link(entp->fts_path, to.p_path)) {
+ warn("%s", to.p_path);
+ return (1);
+ }
+ return (0);
+ }
+ /* NOTREACHED */
+
+ /*
+ * There's no reason to do anything other than close the file
+ * now if it's empty, so let's not bother.
+ */
+ if (fs->st_size > 0) {
+ struct finfo fi;
+
+ fi.from = entp->fts_path;
+ fi.to = to.p_path;
+ fi.size = (size_t)fs->st_size;
+
+ /*
+ * Mmap and write if less than 8M (the limit is so
+ * we don't totally trash memory on big files).
+ * This is really a minor hack, but it wins some CPU back.
+ */
+ bool use_read;
+
+ use_read = true;
+ if (fs->st_size <= MMAP_MAX_SIZE) {
+ size_t fsize = (size_t)fs->st_size;
+ p = mmap(NULL, fsize, PROT_READ, MAP_FILE|MAP_SHARED,
+ from_fd, (off_t)0);
+ if (p != MAP_FAILED) {
+ size_t remainder;
+
+ use_read = false;
+
+ /* no madvise on noMMU
+ (void) madvise(p, (size_t)fs->st_size,
+ MADV_SEQUENTIAL);
+ */
+
+ /*
+ * Write out the data in small chunks to
+ * avoid locking the output file for a
+ * long time if the reading the data from
+ * the source is slow.
+ */
+ remainder = fsize;
+ do {
+ ssize_t chunk;
+
+ chunk = (remainder > MMAP_MAX_WRITE) ?
+ MMAP_MAX_WRITE : remainder;
+ if (write(to_fd, &p[fsize - remainder],
+ chunk) != chunk) {
+ warn("%s", to.p_path);
+ rval = 1;
+ break;
+ }
+ remainder -= chunk;
+ ptotal += chunk;
+ if (pinfo)
+ progress(&fi, ptotal);
+ } while (remainder > 0);
+
+ if (munmap(p, fsize) < 0) {
+ warn("%s", entp->fts_path);
+ rval = 1;
+ }
+ }
+ }
+
+ if (use_read) {
+ while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ wcount = write(to_fd, buf, (size_t)rcount);
+ if (rcount != wcount || wcount == -1) {
+ warn("%s", to.p_path);
+ rval = 1;
+ break;
+ }
+ ptotal += wcount;
+ if (pinfo)
+ progress(&fi, ptotal);
+ }
+ if (rcount < 0) {
+ warn("%s", entp->fts_path);
+ rval = 1;
+ }
+ }
+ }
+
+ (void)close(from_fd);
+
+ if (rval == 1) {
+ (void)close(to_fd);
+ return (1);
+ }
+
+ if (pflag && setfile(fs, to_fd))
+ rval = 1;
+ /*
+ * If the source was setuid or setgid, lose the bits unless the
+ * copy is owned by the same user and group.
+ */
+#define RETAINBITS \
+ (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+ if (!pflag && dne
+ && fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
+ if (fstat(to_fd, &to_stat)) {
+ warn("%s", to.p_path);
+ rval = 1;
+ } else if (fs->st_gid == to_stat.st_gid &&
+ fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) {
+ warn("%s", to.p_path);
+ rval = 1;
+ }
+ }
+ if (close(to_fd)) {
+ warn("%s", to.p_path);
+ rval = 1;
+ }
+ /* set the mod/access times now after close of the fd */
+ if (pflag && set_utimes(to.p_path, fs)) {
+ rval = 1;
+ }
+ return (rval);
+}
+
+int
+copy_link(FTSENT *p, int exists)
+{
+ int len;
+ char target[MAXPATHLEN];
+
+ if ((len = readlink(p->fts_path, target, sizeof(target)-1)) == -1) {
+ warn("readlink: %s", p->fts_path);
+ return (1);
+ }
+ target[len] = '\0';
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (symlink(target, to.p_path)) {
+ warn("symlink: %s", target);
+ return (1);
+ }
+ return (pflag ? setfile(p->fts_statp, 0) : 0);
+}
+
+int
+copy_fifo(struct stat *from_stat, int exists)
+{
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (mkfifo(to.p_path, from_stat->st_mode)) {
+ warn("mkfifo: %s", to.p_path);
+ return (1);
+ }
+ return (pflag ? setfile(from_stat, 0) : 0);
+}
+
+int
+copy_special(struct stat *from_stat, int exists)
+{
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
+ warn("mknod: %s", to.p_path);
+ return (1);
+ }
+ return (pflag ? setfile(from_stat, 0) : 0);
+}
+
+
+/*
+ * Function: setfile
+ *
+ * Purpose:
+ * Set the owner/group/permissions for the "to" file to the information
+ * in the stat structure. If fd is zero, also call set_utimes() to set
+ * the mod/access times. If fd is non-zero, the caller must do a utimes
+ * itself after close(fd).
+ */
+int
+setfile(struct stat *fs, int fd)
+{
+ int rval = 0;
+#ifdef BSD
+ int islink = S_ISLNK(fs->st_mode);
+#endif
+
+ fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+
+ /*
+ * Changing the ownership probably won't succeed, unless we're root
+ * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
+ * the mode; current BSD behavior is to remove all setuid bits on
+ * chown. If chown fails, lose setuid/setgid bits.
+ */
+ if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
+ lchown(to.p_path, fs->st_uid, fs->st_gid)) {
+ if (errno != EPERM) {
+ warn("chown: %s", to.p_path);
+ rval = 1;
+ }
+ fs->st_mode &= ~(S_ISUID | S_ISGID);
+ }
+#ifndef BSD
+ if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+#else
+ if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
+#endif
+ warn("chmod: %s", to.p_path);
+ rval = 1;
+ }
+
+#ifdef BSD
+ if (!islink && !Nflag) {
+ unsigned long fflags = fs->st_flags;
+ /*
+ * XXX
+ * NFS doesn't support chflags; ignore errors unless
+ * there's reason to believe we're losing bits.
+ * (Note, this still won't be right if the server
+ * supports flags and we were trying to *remove* flags
+ * on a file that we copied, i.e., that we didn't create.)
+ */
+ errno = 0;
+ if ((fd ? fchflags(fd, fflags) :
+ chflags(to.p_path, fflags)) == -1)
+ if (errno != EOPNOTSUPP || fs->st_flags != 0) {
+ warn("chflags: %s", to.p_path);
+ rval = 1;
+ }
+ }
+#endif
+ /* if fd is non-zero, caller must call set_utimes() after close() */
+ if (fd == 0 && set_utimes(to.p_path, fs))
+ rval = 1;
+ return (rval);
+}
+
+void
+cp_usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n"
+ " cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/package/toolbox/src/date/Makefile b/package/toolbox/src/date/Makefile
new file mode 100644
index 000000000..9d733c02f
--- /dev/null
+++ b/package/toolbox/src/date/Makefile
@@ -0,0 +1,5 @@
+PROG= date
+
+include ../tool.mk
+
+CPPFLAGS+= -D'__SCCSID(x)='
diff --git a/package/toolbox/src/date/date.c b/package/toolbox/src/date/date.c
new file mode 100644
index 000000000..c4d5ddc82
--- /dev/null
+++ b/package/toolbox/src/date/date.c
@@ -0,0 +1,272 @@
+/* $OpenBSD: date.c,v 1.26 2003/10/15 15:58:22 mpech Exp $ */
+/* $NetBSD: date.c,v 1.11 1995/09/07 06:21:05 jtc Exp $ */
+
+/*
+ * Copyright (c) 1985, 1987, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+__COPYRIGHT("@(#) Copyright (c) 1985, 1987, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+__SCCSID("@(#)date.c 8.2 (Berkeley) 4/28/95");
+__RCSID("$MirOS: src/bin/date/date.c,v 1.9 2016/01/02 21:32:56 tg Exp $");
+
+extern const char *__progname;
+
+time_t tval;
+int retval;
+int slidetime;
+
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif
+
+static void setthetime(char *);
+static __dead void badformat(void);
+static __dead void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct timezone tz;
+ int ch, rflag;
+ const char *format = NULL;
+ char buf[1024];
+ int whatformat = 0;
+
+ tz.tz_dsttime = tz.tz_minuteswest = 0;
+ rflag = 0;
+ while ((ch = getopt(argc, argv, "ad:nRr:ut:")) != -1)
+ switch((char)ch) {
+ case 'a':
+ slidetime++;
+ break;
+ case 'd': /* daylight saving time */
+ tz.tz_dsttime = atoi(optarg) ? 1 : 0;
+ break;
+ case 'n': /* don't set network */
+ break;
+ case 'R': /* RFC 2822 format */
+ whatformat |= 1;
+ break;
+ case 'r': /* user specified seconds */
+ rflag = 1;
+ tval = atoll(optarg);
+ break;
+ case 'u': /* do everything in UTC */
+ if (setenv("TZ", "GMT0", 1) == -1)
+ err(1, "cannot unsetenv TZ");
+ break;
+ case 't': /* minutes west of GMT */
+ /* error check; don't allow "PST" */
+ if (isdigit(*optarg)) {
+ tz.tz_minuteswest = atoi(optarg);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * If -d or -t, set the timezone or daylight saving time; this
+ * doesn't belong here, the kernel should not know about either.
+ */
+ if ((tz.tz_minuteswest || tz.tz_dsttime) &&
+ settimeofday(NULL, &tz))
+ err(1, "settimeofday");
+
+ if (!rflag && time(&tval) == -1)
+ err(1, "time");
+
+ /* allow the operands in any order */
+ if (*argv && **argv == '+') {
+ if (*(*argv + 1)) {
+ whatformat |= 2;
+ format = *argv + 1;
+ }
+ ++argv;
+ }
+
+ if (*argv) {
+ setthetime(*argv);
+ ++argv;
+ }
+
+ if (*argv && **argv == '+') {
+ whatformat |= 4;
+ format = *argv + 1;
+ }
+
+ if (whatformat == 0)
+ format = "%a %b %e %H:%M:%S %Z %Y";
+ else if (whatformat == 1) {
+ format = "%a, %d %b %Y %H:%M:%S %z";
+ } else if (whatformat != 2 && whatformat != 4)
+ errx(1, "more than one format specified");
+
+ strftime(buf, sizeof (buf), format, localtime(&tval));
+ printf("%s\n", buf);
+ exit(retval);
+}
+
+#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+void
+setthetime(char *p)
+{
+ struct tm *lt;
+ struct timeval tv;
+ char *dot, *t;
+ const char *pc;
+ int bigyear;
+ int yearset = 0;
+
+ for (t = p, dot = NULL; *t; ++t) {
+ if (isdigit(*t))
+ continue;
+ if (*t == '.' && dot == NULL) {
+ dot = t;
+ continue;
+ }
+ badformat();
+ }
+
+ lt = localtime(&tval);
+
+ lt->tm_isdst = -1; /* correct for DST */
+
+ if (dot != NULL) { /* .SS */
+ *dot++ = '\0';
+ if (strlen(dot) != 2)
+ badformat();
+ lt->tm_sec = ATOI2(dot);
+ if (lt->tm_sec > 61)
+ badformat();
+ } else
+ lt->tm_sec = 0;
+
+ switch (strlen(p)) {
+ case 12: /* cc */
+ bigyear = ATOI2(p);
+ lt->tm_year = bigyear * 100 - TM_YEAR_BASE;
+ yearset = 1;
+ /* FALLTHROUGH */
+ case 10: /* yy */
+ if (yearset) {
+ lt->tm_year += ATOI2(p);
+ } else {
+ lt->tm_year = ATOI2(p);
+ if (lt->tm_year < 69) /* hack for 2000 ;-} */
+ lt->tm_year += (2000 - TM_YEAR_BASE);
+ else
+ lt->tm_year += (1900 - TM_YEAR_BASE);
+ }
+ /* FALLTHROUGH */
+ case 8: /* mm */
+ lt->tm_mon = ATOI2(p);
+ if ((lt->tm_mon > 12) || !lt->tm_mon)
+ badformat();
+ --lt->tm_mon; /* time struct is 0 - 11 */
+ /* FALLTHROUGH */
+ case 6: /* dd */
+ lt->tm_mday = ATOI2(p);
+ if ((lt->tm_mday > 31) || !lt->tm_mday)
+ badformat();
+ /* FALLTHROUGH */
+ case 4: /* HH */
+ lt->tm_hour = ATOI2(p);
+ if (lt->tm_hour > 23)
+ badformat();
+ /* FALLTHROUGH */
+ case 2: /* MM */
+ lt->tm_min = ATOI2(p);
+ if (lt->tm_min > 59)
+ badformat();
+ break;
+ default:
+ badformat();
+ }
+
+ /* convert broken-down time to UTC clock time */
+ if ((tval = mktime(lt)) < 0)
+ errx(1, "specified date is outside allowed range");
+
+ /* set the time */
+ if (slidetime) {
+ struct timeval tv_current;
+
+ if (gettimeofday(&tv_current, NULL) == -1)
+ err(1, "Could not get local time of day");
+
+ tv.tv_sec = tval - tv_current.tv_sec;
+ tv.tv_usec = 0;
+ if (adjtime(&tv, NULL) == -1)
+ errx(1, "adjtime");
+ } else {
+ tv.tv_sec = tval;
+ tv.tv_usec = 0;
+ if (settimeofday(&tv, NULL))
+ err(1, "settimeofday");
+ }
+
+ if ((pc = getlogin()) == NULL)
+ pc = "???";
+ syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", pc);
+}
+
+static void
+badformat(void)
+{
+ warnx("illegal time format");
+ usage();
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage:\t%s [-anRu] [-d dst] [-r seconds] [-t west] [+format]\n",
+ __progname);
+ fprintf(stderr, "\t [[[[[[cc]yy]mm]dd]HH]MM[.SS]]\n");
+ exit(1);
+}
diff --git a/package/toolbox/src/dd/Makefile b/package/toolbox/src/dd/Makefile
new file mode 100644
index 000000000..cb4a35107
--- /dev/null
+++ b/package/toolbox/src/dd/Makefile
@@ -0,0 +1,4 @@
+CPPFLAGS+=-D_FILE_OFFSET_BITS=64
+PROG= dd
+
+include ../tool.mk
diff --git a/package/toolbox/src/df/Makefile b/package/toolbox/src/df/Makefile
new file mode 100644
index 000000000..0935a26c0
--- /dev/null
+++ b/package/toolbox/src/df/Makefile
@@ -0,0 +1,3 @@
+PROG= df
+
+include ../tool.mk
diff --git a/package/toolbox/src/dmesg/Makefile b/package/toolbox/src/dmesg/Makefile
new file mode 100644
index 000000000..da1fafcc7
--- /dev/null
+++ b/package/toolbox/src/dmesg/Makefile
@@ -0,0 +1,3 @@
+PROG= dmesg
+
+include ../tool.mk
diff --git a/package/toolbox/src/du/Makefile b/package/toolbox/src/du/Makefile
new file mode 100644
index 000000000..c08670fec
--- /dev/null
+++ b/package/toolbox/src/du/Makefile
@@ -0,0 +1,3 @@
+PROG= du
+
+include ../tool.mk
diff --git a/package/toolbox/src/exists/Makefile b/package/toolbox/src/exists/Makefile
new file mode 100644
index 000000000..f37efc438
--- /dev/null
+++ b/package/toolbox/src/exists/Makefile
@@ -0,0 +1,3 @@
+PROG= exists
+
+include ../tool.mk
diff --git a/package/toolbox/src/grep/Makefile b/package/toolbox/src/grep/Makefile
new file mode 100644
index 000000000..30336ccbe
--- /dev/null
+++ b/package/toolbox/src/grep/Makefile
@@ -0,0 +1,4 @@
+PROG= grep
+SRCS= fastgrep.c file.c grep.c queue.c util.c
+
+include ../tool.mk
diff --git a/package/toolbox/src/grep/fastgrep.c b/package/toolbox/src/grep/fastgrep.c
new file mode 100644
index 000000000..2fcd864e2
--- /dev/null
+++ b/package/toolbox/src/grep/fastgrep.c
@@ -0,0 +1,336 @@
+/* $OpenBSD: util.c,v 1.36 2007/10/02 17:59:18 otto Exp $ */
+/* $FreeBSD: head/usr.bin/grep/fastgrep.c 211496 2010-08-19 09:28:59Z des $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * XXX: This file is a speed up for grep to cover the defects of the
+ * regex library. These optimizations should practically be implemented
+ * there keeping this code clean. This is a future TODO, but for the
+ * meantime, we need to use this workaround.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: fastgrep.c,v 1.5 2011/04/18 03:27:40 joerg Exp $");
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "grep.h"
+
+static inline int grep_cmp(const unsigned char *, const unsigned char *, size_t);
+static inline void grep_revstr(unsigned char *, int);
+
+void
+fgrepcomp(fastgrep_t *fg, const char *pat)
+{
+ unsigned int i;
+
+ /* Initialize. */
+ fg->len = strlen(pat);
+ fg->bol = false;
+ fg->eol = false;
+ fg->reversed = false;
+
+ fg->pattern = (unsigned char *)grep_strdup(pat);
+
+ /* Preprocess pattern. */
+ for (i = 0; i <= UCHAR_MAX; i++)
+ fg->qsBc[i] = fg->len;
+ for (i = 1; i < fg->len; i++)
+ fg->qsBc[fg->pattern[i]] = fg->len - i;
+}
+
+/*
+ * Returns: -1 on failure, 0 on success
+ */
+int
+fastcomp(fastgrep_t *fg, const char *pat)
+{
+ unsigned int i;
+ int firstHalfDot = -1;
+ int firstLastHalfDot = -1;
+ int hasDot = 0;
+ int lastHalfDot = 0;
+ int shiftPatternLen;
+
+ /* Initialize. */
+ fg->len = strlen(pat);
+ fg->bol = false;
+ fg->eol = false;
+ fg->reversed = false;
+ fg->word = wflag;
+
+ /* Remove end-of-line character ('$'). */
+ if (fg->len > 0 && pat[fg->len - 1] == '$') {
+ fg->eol = true;
+ fg->len--;
+ }
+
+ /* Remove beginning-of-line character ('^'). */
+ if (pat[0] == '^') {
+ fg->bol = true;
+ fg->len--;
+ pat++;
+ }
+
+ if (fg->len >= 14 &&
+ memcmp(pat, "[[:<:]]", 7) == 0 &&
+ memcmp(pat + fg->len - 7, "[[:>:]]", 7) == 0) {
+ fg->len -= 14;
+ pat += 7;
+ /* Word boundary is handled separately in util.c */
+ fg->word = true;
+ }
+
+ /*
+ * pat has been adjusted earlier to not include '^', '$' or
+ * the word match character classes at the beginning and ending
+ * of the string respectively.
+ */
+ fg->pattern = grep_malloc(fg->len + 1);
+ memcpy(fg->pattern, pat, fg->len);
+ fg->pattern[fg->len] = '\0';
+
+ /* Look for ways to cheat...er...avoid the full regex engine. */
+ for (i = 0; i < fg->len; i++) {
+ /* Can still cheat? */
+ if (fg->pattern[i] == '.') {
+ hasDot = i;
+ if (i < fg->len / 2) {
+ if (firstHalfDot < 0)
+ /* Closest dot to the beginning */
+ firstHalfDot = i;
+ } else {
+ /* Closest dot to the end of the pattern. */
+ lastHalfDot = i;
+ if (firstLastHalfDot < 0)
+ firstLastHalfDot = i;
+ }
+ } else {
+ /* Free memory and let others know this is empty. */
+ free(fg->pattern);
+ fg->pattern = NULL;
+ return (-1);
+ }
+ }
+
+ /*
+ * Determine if a reverse search would be faster based on the placement
+ * of the dots.
+ */
+ if ((!(lflag || cflag)) && ((!(fg->bol || fg->eol)) &&
+ ((lastHalfDot) && ((firstHalfDot < 0) ||
+ ((fg->len - (lastHalfDot + 1)) < (size_t)firstHalfDot)))) &&
+ !oflag && !color) {
+ fg->reversed = true;
+ hasDot = fg->len - (firstHalfDot < 0 ?
+ firstLastHalfDot : firstHalfDot) - 1;
+ grep_revstr(fg->pattern, fg->len);
+ }
+
+ /*
+ * Normal Quick Search would require a shift based on the position the
+ * next character after the comparison is within the pattern. With
+ * wildcards, the position of the last dot effects the maximum shift
+ * distance.
+ * The closer to the end the wild card is the slower the search. A
+ * reverse version of this algorithm would be useful for wildcards near
+ * the end of the string.
+ *
+ * Examples:
+ * Pattern Max shift
+ * ------- ---------
+ * this 5
+ * .his 4
+ * t.is 3
+ * th.s 2
+ * thi. 1
+ */
+
+ /* Adjust the shift based on location of the last dot ('.'). */
+ shiftPatternLen = fg->len - hasDot;
+
+ /* Preprocess pattern. */
+ for (i = 0; i <= (signed)UCHAR_MAX; i++)
+ fg->qsBc[i] = shiftPatternLen;
+ for (i = hasDot + 1; i < fg->len; i++) {
+ fg->qsBc[fg->pattern[i]] = fg->len - i;
+ }
+
+ /*
+ * Put pattern back to normal after pre-processing to allow for easy
+ * comparisons later.
+ */
+ if (fg->reversed)
+ grep_revstr(fg->pattern, fg->len);
+
+ return (0);
+}
+
+int
+grep_search(fastgrep_t *fg, const unsigned char *data, size_t len, regmatch_t *pmatch)
+{
+ unsigned int j;
+ int ret = REG_NOMATCH;
+
+ if (pmatch->rm_so == (ssize_t)len)
+ return (ret);
+
+ if (fg->bol && pmatch->rm_so != 0) {
+ pmatch->rm_so = len;
+ pmatch->rm_eo = len;
+ return (ret);
+ }
+
+ /* No point in going farther if we do not have enough data. */
+ if (len < fg->len)
+ return (ret);
+
+ /* Only try once at the beginning or ending of the line. */
+ if (fg->bol || fg->eol) {
+ /* Simple text comparison. */
+ /* Verify data is >= pattern length before searching on it. */
+ if (len >= fg->len) {
+ /* Determine where in data to start search at. */
+ j = fg->eol ? len - fg->len : 0;
+ if (!((fg->bol && fg->eol) && (len != fg->len)))
+ if (grep_cmp(fg->pattern, data + j,
+ fg->len) == -1) {
+ pmatch->rm_so = j;
+ pmatch->rm_eo = j + fg->len;
+ ret = 0;
+ }
+ }
+ } else if (fg->reversed) {
+ /* Quick Search algorithm. */
+ j = len;
+ do {
+ if (grep_cmp(fg->pattern, data + j - fg->len,
+ fg->len) == -1) {
+ pmatch->rm_so = j - fg->len;
+ pmatch->rm_eo = j;
+ ret = 0;
+ break;
+ }
+ /* Shift if within bounds, otherwise, we are done. */
+ if (j == fg->len)
+ break;
+ j -= fg->qsBc[data[j - fg->len - 1]];
+ } while (j >= fg->len);
+ } else {
+ /* Quick Search algorithm. */
+ j = pmatch->rm_so;
+ do {
+ if (grep_cmp(fg->pattern, data + j, fg->len) == -1) {
+ pmatch->rm_so = j;
+ pmatch->rm_eo = j + fg->len;
+ ret = 0;
+ break;
+ }
+
+ /* Shift if within bounds, otherwise, we are done. */
+ if (j + fg->len == len)
+ break;
+ else
+ j += fg->qsBc[data[j + fg->len]];
+ } while (j <= (len - fg->len));
+ }
+
+ return (ret);
+}
+
+/*
+ * Returns: i >= 0 on failure (position that it failed)
+ * -1 on success
+ */
+static inline int
+grep_cmp(const unsigned char *pat, const unsigned char *data, size_t len)
+{
+ size_t size;
+ wchar_t *wdata, *wpat;
+ unsigned int i;
+
+ if (iflag) {
+ if ((size = mbstowcs(NULL, (const char *)data, 0)) ==
+ ((size_t) - 1))
+ return (-1);
+
+ wdata = grep_malloc(size * sizeof(wint_t));
+
+ if (mbstowcs(wdata, (const char *)data, size) ==
+ ((size_t) - 1))
+ return (-1);
+
+ if ((size = mbstowcs(NULL, (const char *)pat, 0)) ==
+ ((size_t) - 1))
+ return (-1);
+
+ wpat = grep_malloc(size * sizeof(wint_t));
+
+ if (mbstowcs(wpat, (const char *)pat, size) == ((size_t) - 1))
+ return (-1);
+ for (i = 0; i < len; i++) {
+ if ((towlower(wpat[i]) == towlower(wdata[i])) ||
+ ((grepbehave != GREP_FIXED) && wpat[i] == L'.'))
+ continue;
+ free(wpat);
+ free(wdata);
+ return (i);
+ }
+ } else {
+ for (i = 0; i < len; i++) {
+ if ((pat[i] == data[i]) || ((grepbehave != GREP_FIXED) &&
+ pat[i] == '.'))
+ continue;
+ return (i);
+ }
+ }
+ return (-1);
+}
+
+static inline void
+grep_revstr(unsigned char *str, int len)
+{
+ int i;
+ char c;
+
+ for (i = 0; i < len / 2; i++) {
+ c = str[i];
+ str[i] = str[len - i - 1];
+ str[len - i - 1] = c;
+ }
+}
diff --git a/package/toolbox/src/grep/file.c b/package/toolbox/src/grep/file.c
new file mode 100644
index 000000000..4cbb2a736
--- /dev/null
+++ b/package/toolbox/src/grep/file.c
@@ -0,0 +1,215 @@
+/* $NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $ */
+/* $FreeBSD: head/usr.bin/grep/file.c 211496 2010-08-19 09:28:59Z des $ */
+/* $OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "grep.h"
+
+#define MAXBUFSIZ (32 * 1024)
+#define LNBUFBUMP 80
+
+static unsigned char buffer[MAXBUFSIZ];
+static unsigned char *bufpos;
+static size_t bufrem;
+
+static unsigned char *lnbuf;
+static size_t lnbuflen;
+
+static inline int
+grep_refill(struct file *f)
+{
+ ssize_t nr;
+
+ bufpos = buffer;
+ bufrem = 0;
+
+ nr = read(f->fd, buffer, MAXBUFSIZ);
+
+ if (nr < 0)
+ return (-1);
+
+ bufrem = nr;
+ return (0);
+}
+
+static inline int
+grep_lnbufgrow(size_t newlen)
+{
+
+ if (lnbuflen < newlen) {
+ lnbuf = grep_realloc(lnbuf, newlen);
+ lnbuflen = newlen;
+ }
+
+ return (0);
+}
+
+char *
+grep_fgetln(struct file *f, size_t *lenp)
+{
+ unsigned char *p;
+ char *ret;
+ size_t len;
+ size_t off;
+ ptrdiff_t diff;
+
+ /* Fill the buffer, if necessary */
+ if (bufrem == 0 && grep_refill(f) != 0)
+ goto error;
+
+ if (bufrem == 0) {
+ /* Return zero length to indicate EOF */
+ *lenp = 0;
+ return ((char *)bufpos);
+ }
+
+ /* Look for a newline in the remaining part of the buffer */
+ if ((p = memchr(bufpos, line_sep, bufrem)) != NULL) {
+ ++p; /* advance over newline */
+ ret = (char *)bufpos;
+ len = p - bufpos;
+ bufrem -= len;
+ bufpos = p;
+ *lenp = len;
+ return (ret);
+ }
+
+ /* We have to copy the current buffered data to the line buffer */
+ for (len = bufrem, off = 0; ; len += bufrem) {
+ /* Make sure there is room for more data */
+ if (grep_lnbufgrow(len + LNBUFBUMP))
+ goto error;
+ memcpy(lnbuf + off, bufpos, len - off);
+ off = len;
+ if (grep_refill(f) != 0)
+ goto error;
+ if (bufrem == 0)
+ /* EOF: return partial line */
+ break;
+ if ((p = memchr(bufpos, line_sep, bufrem)) == NULL)
+ continue;
+ /* got it: finish up the line (like code above) */
+ ++p;
+ diff = p - bufpos;
+ len += diff;
+ if (grep_lnbufgrow(len))
+ goto error;
+ memcpy(lnbuf + off, bufpos, diff);
+ bufrem -= diff;
+ bufpos = p;
+ break;
+ }
+ *lenp = len;
+ return ((char *)lnbuf);
+
+error:
+ *lenp = 0;
+ return (NULL);
+}
+
+static inline struct file *
+grep_file_init(struct file *f)
+{
+ /* Fill read buffer, also catches errors early */
+ if (grep_refill(f) != 0)
+ goto error;
+
+ /* Check for binary stuff, if necessary */
+ if (!nulldataflag && binbehave != BINFILE_TEXT &&
+ memchr(bufpos, '\0', bufrem) != NULL)
+ f->binary = true;
+
+ return (f);
+error:
+ close(f->fd);
+ free(f);
+ return (NULL);
+}
+
+/*
+ * Opens a file for processing.
+ */
+struct file *
+grep_open(const char *path)
+{
+ struct file *f;
+
+ f = grep_malloc(sizeof *f);
+ memset(f, 0, sizeof *f);
+ if (path == NULL) {
+ /* Processing stdin implies --line-buffered. */
+ lbflag = true;
+ f->fd = STDIN_FILENO;
+ } else if ((f->fd = open(path, O_RDONLY)) == -1) {
+ free(f);
+ return (NULL);
+ }
+
+ return (grep_file_init(f));
+}
+
+/*
+ * Closes a file.
+ */
+void
+grep_close(struct file *f)
+{
+
+ close(f->fd);
+
+ /* Reset read buffer and line buffer */
+ bufpos = buffer;
+ bufrem = 0;
+
+ free(lnbuf);
+ lnbuf = NULL;
+ lnbuflen = 0;
+}
diff --git a/package/toolbox/src/grep/grep.c b/package/toolbox/src/grep/grep.c
new file mode 100644
index 000000000..6d70f8252
--- /dev/null
+++ b/package/toolbox/src/grep/grep.c
@@ -0,0 +1,695 @@
+/* $NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $ */
+/* $FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $ */
+/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $");
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <libgen.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "grep.h"
+
+/*
+ * Default messags to use when NLS is disabled or no catalogue
+ * is found.
+ */
+const char *errstr[] = {
+ "",
+/* 1*/ "(standard input)",
+/* 2*/ "cannot read bzip2 compressed file",
+/* 3*/ "unknown %s option",
+/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
+/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
+/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
+/* 7*/ "\t[pattern] [file ...]\n",
+/* 8*/ "Binary file %s matches\n",
+/* 9*/ "%s (BSD grep) %s\n",
+};
+
+/* Flags passed to regcomp() and regexec() */
+int cflags = 0;
+int eflags = REG_STARTEND;
+
+/* Searching patterns */
+unsigned int patterns, pattern_sz;
+char **pattern;
+regex_t *r_pattern;
+fastgrep_t *fg_pattern;
+
+/* Filename exclusion/inclusion patterns */
+unsigned int fpatterns, fpattern_sz;
+unsigned int dpatterns, dpattern_sz;
+struct epat *dpattern, *fpattern;
+
+/* For regex errors */
+char re_error[RE_ERROR_BUF + 1];
+
+/* Command-line flags */
+unsigned long long Aflag; /* -A x: print x lines trailing each match */
+unsigned long long Bflag; /* -B x: print x lines leading each match */
+bool Hflag; /* -H: always print file name */
+bool Lflag; /* -L: only show names of files with no matches */
+bool bflag; /* -b: show block numbers for each match */
+bool cflag; /* -c: only show a count of matching lines */
+bool hflag; /* -h: don't print filename headers */
+bool iflag; /* -i: ignore case */
+bool lflag; /* -l: only show names of files with matches */
+bool mflag; /* -m x: stop reading the files after x matches */
+unsigned long long mcount; /* count for -m */
+bool nflag; /* -n: show line numbers in front of matching lines */
+bool oflag; /* -o: print only matching part */
+bool qflag; /* -q: quiet mode (don't output anything) */
+bool sflag; /* -s: silent mode (ignore errors) */
+bool vflag; /* -v: only show non-matching lines */
+bool wflag; /* -w: pattern must start and end on word boundaries */
+bool xflag; /* -x: pattern must match entire line */
+bool lbflag; /* --line-buffered */
+bool nullflag; /* --null */
+bool nulldataflag; /* --null-data */
+unsigned char line_sep = '\n'; /* 0 for --null-data */
+char *label; /* --label */
+const char *color; /* --color */
+int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */
+int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */
+int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */
+int devbehave = DEV_READ; /* -D: handling of devices */
+int dirbehave = DIR_READ; /* -dRr: handling of directories */
+int linkbehave = LINK_READ; /* -OpS: handling of symlinks */
+
+bool dexclude, dinclude; /* --exclude-dir and --include-dir */
+bool fexclude, finclude; /* --exclude and --include */
+
+enum {
+ BIN_OPT = CHAR_MAX + 1,
+ COLOR_OPT,
+ DECOMPRESS_OPT,
+ HELP_OPT,
+ MMAP_OPT,
+ LINEBUF_OPT,
+ LABEL_OPT,
+ R_EXCLUDE_OPT,
+ R_INCLUDE_OPT,
+ R_DEXCLUDE_OPT,
+ R_DINCLUDE_OPT
+};
+
+static inline const char *init_color(const char *);
+
+/* Housekeeping */
+int tail; /* lines left to print */
+bool notfound; /* file not found */
+
+extern char *__progname;
+
+/*
+ * Prints usage information and returns 2.
+ */
+__dead static void
+usage(void)
+{
+ fprintf(stderr, getstr(4), __progname);
+ fprintf(stderr, "%s", getstr(5));
+ fprintf(stderr, "%s", getstr(5));
+ fprintf(stderr, "%s", getstr(6));
+ fprintf(stderr, "%s", getstr(7));
+ exit(2);
+}
+
+static const char optstr[] =
+ "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxyz";
+
+struct option long_options[] =
+{
+ {"binary-files", required_argument, NULL, BIN_OPT},
+ {"decompress", no_argument, NULL, DECOMPRESS_OPT},
+ {"help", no_argument, NULL, HELP_OPT},
+ {"mmap", no_argument, NULL, MMAP_OPT},
+ {"line-buffered", no_argument, NULL, LINEBUF_OPT},
+ {"label", required_argument, NULL, LABEL_OPT},
+ {"color", optional_argument, NULL, COLOR_OPT},
+ {"colour", optional_argument, NULL, COLOR_OPT},
+ {"exclude", required_argument, NULL, R_EXCLUDE_OPT},
+ {"include", required_argument, NULL, R_INCLUDE_OPT},
+ {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
+ {"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
+ {"after-context", required_argument, NULL, 'A'},
+ {"text", no_argument, NULL, 'a'},
+ {"before-context", required_argument, NULL, 'B'},
+ {"byte-offset", no_argument, NULL, 'b'},
+ {"context", optional_argument, NULL, 'C'},
+ {"count", no_argument, NULL, 'c'},
+ {"devices", required_argument, NULL, 'D'},
+ {"directories", required_argument, NULL, 'd'},
+ {"extended-regexp", no_argument, NULL, 'E'},
+ {"regexp", required_argument, NULL, 'e'},
+ {"fixed-strings", no_argument, NULL, 'F'},
+ {"file", required_argument, NULL, 'f'},
+ {"basic-regexp", no_argument, NULL, 'G'},
+ {"no-filename", no_argument, NULL, 'h'},
+ {"with-filename", no_argument, NULL, 'H'},
+ {"ignore-case", no_argument, NULL, 'i'},
+ {"bz2decompress", no_argument, NULL, 'J'},
+ {"files-with-matches", no_argument, NULL, 'l'},
+ {"files-without-match", no_argument, NULL, 'L'},
+ {"max-count", required_argument, NULL, 'm'},
+ {"line-number", no_argument, NULL, 'n'},
+ {"only-matching", no_argument, NULL, 'o'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"silent", no_argument, NULL, 'q'},
+ {"recursive", no_argument, NULL, 'r'},
+ {"no-messages", no_argument, NULL, 's'},
+ {"binary", no_argument, NULL, 'U'},
+ {"unix-byte-offsets", no_argument, NULL, 'u'},
+ {"invert-match", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {"word-regexp", no_argument, NULL, 'w'},
+ {"line-regexp", no_argument, NULL, 'x'},
+ {"null", no_argument, NULL, 'Z'},
+ {"null-data", no_argument, NULL, 'z'},
+ {NULL, no_argument, NULL, 0}
+};
+
+/*
+ * Adds a searching pattern to the internal array.
+ */
+static void
+add_pattern(char *pat, size_t len)
+{
+
+ /* TODO: Check for empty patterns and shortcut */
+
+ /* Increase size if necessary */
+ if (patterns == pattern_sz) {
+ pattern_sz *= 2;
+ pattern = grep_realloc(pattern, ++pattern_sz *
+ sizeof(*pattern));
+ }
+ if (len > 0 && pat[len - 1] == '\n')
+ --len;
+ /* pat may not be NUL-terminated */
+ pattern[patterns] = grep_malloc(len + 1);
+ memcpy(pattern[patterns], pat, len);
+ pattern[patterns][len] = '\0';
+ ++patterns;
+}
+
+/*
+ * Adds a file include/exclude pattern to the internal array.
+ */
+static void
+add_fpattern(const char *pat, int mode)
+{
+
+ /* Increase size if necessary */
+ if (fpatterns == fpattern_sz) {
+ fpattern_sz *= 2;
+ fpattern = grep_realloc(fpattern, ++fpattern_sz *
+ sizeof(struct epat));
+ }
+ fpattern[fpatterns].pat = grep_strdup(pat);
+ fpattern[fpatterns].mode = mode;
+ ++fpatterns;
+}
+
+/*
+ * Adds a directory include/exclude pattern to the internal array.
+ */
+static void
+add_dpattern(const char *pat, int mode)
+{
+
+ /* Increase size if necessary */
+ if (dpatterns == dpattern_sz) {
+ dpattern_sz *= 2;
+ dpattern = grep_realloc(dpattern, ++dpattern_sz *
+ sizeof(struct epat));
+ }
+ dpattern[dpatterns].pat = grep_strdup(pat);
+ dpattern[dpatterns].mode = mode;
+ ++dpatterns;
+}
+
+/*
+ * Reads searching patterns from a file and adds them with add_pattern().
+ */
+static void
+read_patterns(const char *fn)
+{
+ FILE *f;
+ char *line;
+ size_t len;
+ ssize_t rlen;
+
+ if ((f = fopen(fn, "r")) == NULL)
+ err(2, "%s", fn);
+ line = NULL;
+ len = 0;
+#ifndef ANDROID
+ while ((rlen = getline(&line, &len, f)) != -1)
+ add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
+#endif
+ free(line);
+ if (ferror(f))
+ err(2, "%s", fn);
+ fclose(f);
+}
+
+static inline const char *
+init_color(const char *d)
+{
+ char *c;
+
+ c = getenv("GREP_COLOR");
+ return (c != NULL ? c : d);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char **aargv, **eargv, *eopts;
+ char *ep;
+ unsigned long long l;
+ unsigned int aargc, eargc, i, j;
+ int c, lastc, needpattern, newarg, prevoptind;
+
+ /* Check what is the program name of the binary. In this
+ way we can have all the funcionalities in one binary
+ without the need of scripting and using ugly hacks. */
+ switch (__progname[0]) {
+ case 'e':
+ grepbehave = GREP_EXTENDED;
+ break;
+ case 'f':
+ grepbehave = GREP_FIXED;
+ break;
+ case 'g':
+ grepbehave = GREP_BASIC;
+ break;
+ case 'z':
+ filebehave = FILE_GZIP;
+ switch(__progname[1]) {
+ case 'e':
+ grepbehave = GREP_EXTENDED;
+ break;
+ case 'f':
+ grepbehave = GREP_FIXED;
+ break;
+ case 'g':
+ grepbehave = GREP_BASIC;
+ break;
+ }
+ break;
+ }
+
+ lastc = '\0';
+ newarg = 1;
+ prevoptind = 1;
+ needpattern = 1;
+
+ eopts = getenv("GREP_OPTIONS");
+
+ /* support for extra arguments in GREP_OPTIONS */
+ eargc = 0;
+ if (eopts != NULL) {
+ char *str;
+
+ /* make an estimation of how many extra arguments we have */
+ for (j = 0; j < strlen(eopts); j++)
+ if (eopts[j] == ' ')
+ eargc++;
+
+ eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
+
+ eargc = 0;
+ /* parse extra arguments */
+ while ((str = strsep(&eopts, " ")) != NULL)
+ eargv[eargc++] = grep_strdup(str);
+
+ aargv = (char **)grep_calloc(eargc + argc + 1,
+ sizeof(char *));
+
+ aargv[0] = argv[0];
+ for (i = 0; i < eargc; i++)
+ aargv[i + 1] = eargv[i];
+ for (j = 1; j < (unsigned int)argc; j++, i++)
+ aargv[i + 1] = argv[j];
+
+ aargc = eargc + argc;
+ } else {
+ aargv = argv;
+ aargc = argc;
+ }
+
+ while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
+ -1)) {
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (newarg || !isdigit(lastc))
+ Aflag = 0;
+ else if (Aflag > LLONG_MAX / 10) {
+ errno = ERANGE;
+ err(2, NULL);
+ }
+ Aflag = Bflag = (Aflag * 10) + (c - '0');
+ break;
+ case 'C':
+ if (optarg == NULL) {
+ Aflag = Bflag = 2;
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'A':
+ /* FALLTHROUGH */
+ case 'B':
+ errno = 0;
+ l = strtoull(optarg, &ep, 10);
+ if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
+ ((errno == EINVAL) && (l == 0)))
+ err(2, NULL);
+ else if (ep[0] != '\0') {
+ errno = EINVAL;
+ err(2, NULL);
+ }
+ if (c == 'A')
+ Aflag = l;
+ else if (c == 'B')
+ Bflag = l;
+ else
+ Aflag = Bflag = l;
+ break;
+ case 'a':
+ binbehave = BINFILE_TEXT;
+ break;
+ case 'b':
+ bflag = true;
+ break;
+ case 'c':
+ cflag = true;
+ break;
+ case 'D':
+ if (strcasecmp(optarg, "skip") == 0)
+ devbehave = DEV_SKIP;
+ else if (strcasecmp(optarg, "read") == 0)
+ devbehave = DEV_READ;
+ else
+ errx(2, getstr(3), "--devices");
+ break;
+ case 'd':
+ if (strcasecmp("recurse", optarg) == 0) {
+ Hflag = true;
+ dirbehave = DIR_RECURSE;
+ } else if (strcasecmp("skip", optarg) == 0)
+ dirbehave = DIR_SKIP;
+ else if (strcasecmp("read", optarg) == 0)
+ dirbehave = DIR_READ;
+ else
+ errx(2, getstr(3), "--directories");
+ break;
+ case 'E':
+ grepbehave = GREP_EXTENDED;
+ break;
+ case 'e':
+ add_pattern(optarg, strlen(optarg));
+ needpattern = 0;
+ break;
+ case 'F':
+ grepbehave = GREP_FIXED;
+ break;
+ case 'f':
+ read_patterns(optarg);
+ needpattern = 0;
+ break;
+ case 'G':
+ grepbehave = GREP_BASIC;
+ break;
+ case 'H':
+ Hflag = true;
+ break;
+ case 'h':
+ Hflag = false;
+ hflag = true;
+ break;
+ case 'I':
+ binbehave = BINFILE_SKIP;
+ break;
+ case 'i':
+ case 'y':
+ iflag = true;
+ cflags |= REG_ICASE;
+ break;
+ case 'J':
+ filebehave = FILE_BZIP;
+ break;
+ case 'L':
+ lflag = false;
+ Lflag = true;
+ break;
+ case 'l':
+ Lflag = false;
+ lflag = true;
+ break;
+ case 'm':
+ mflag = true;
+ errno = 0;
+ mcount = strtoull(optarg, &ep, 10);
+ if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
+ ((errno == EINVAL) && (mcount == 0)))
+ err(2, NULL);
+ else if (ep[0] != '\0') {
+ errno = EINVAL;
+ err(2, NULL);
+ }
+ break;
+ case 'n':
+ nflag = true;
+ break;
+ case 'O':
+ linkbehave = LINK_EXPLICIT;
+ break;
+ case 'o':
+ oflag = true;
+ break;
+ case 'p':
+ linkbehave = LINK_SKIP;
+ break;
+ case 'q':
+ qflag = true;
+ break;
+ case 'S':
+ linkbehave = LINK_READ;
+ break;
+ case 'R':
+ case 'r':
+ dirbehave = DIR_RECURSE;
+ Hflag = true;
+ break;
+ case 's':
+ sflag = true;
+ break;
+ case 'U':
+ binbehave = BINFILE_BIN;
+ break;
+ case 'u':
+ case MMAP_OPT:
+ /* noop, compatibility */
+ break;
+ case 'V':
+ printf(getstr(9), __progname, VERSION);
+ exit(0);
+ case 'v':
+ vflag = true;
+ break;
+ case 'w':
+ wflag = true;
+ break;
+ case 'x':
+ xflag = true;
+ break;
+ case 'Z':
+ nullflag = true;
+ break;
+ case 'z':
+ nulldataflag = true;
+ line_sep = '\0';
+ break;
+ case BIN_OPT:
+ if (strcasecmp("binary", optarg) == 0)
+ binbehave = BINFILE_BIN;
+ else if (strcasecmp("without-match", optarg) == 0)
+ binbehave = BINFILE_SKIP;
+ else if (strcasecmp("text", optarg) == 0)
+ binbehave = BINFILE_TEXT;
+ else
+ errx(2, getstr(3), "--binary-files");
+ break;
+ case COLOR_OPT:
+ color = NULL;
+ if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
+ strcasecmp("tty", optarg) == 0 ||
+ strcasecmp("if-tty", optarg) == 0) {
+ char *term;
+
+ term = getenv("TERM");
+ if (isatty(STDOUT_FILENO) && term != NULL &&
+ strcasecmp(term, "dumb") != 0)
+ color = init_color("01;31");
+ } else if (strcasecmp("always", optarg) == 0 ||
+ strcasecmp("yes", optarg) == 0 ||
+ strcasecmp("force", optarg) == 0) {
+ color = init_color("01;31");
+ } else if (strcasecmp("never", optarg) != 0 &&
+ strcasecmp("none", optarg) != 0 &&
+ strcasecmp("no", optarg) != 0)
+ errx(2, getstr(3), "--color");
+ break;
+ case DECOMPRESS_OPT:
+ filebehave = FILE_GZIP;
+ break;
+ case LABEL_OPT:
+ label = optarg;
+ break;
+ case LINEBUF_OPT:
+ lbflag = true;
+ break;
+ case R_INCLUDE_OPT:
+ finclude = true;
+ add_fpattern(optarg, INCL_PAT);
+ break;
+ case R_EXCLUDE_OPT:
+ fexclude = true;
+ add_fpattern(optarg, EXCL_PAT);
+ break;
+ case R_DINCLUDE_OPT:
+ dinclude = true;
+ add_dpattern(optarg, INCL_PAT);
+ break;
+ case R_DEXCLUDE_OPT:
+ dexclude = true;
+ add_dpattern(optarg, EXCL_PAT);
+ break;
+ case HELP_OPT:
+ default:
+ usage();
+ }
+ lastc = c;
+ newarg = optind != prevoptind;
+ prevoptind = optind;
+ }
+ aargc -= optind;
+ aargv += optind;
+
+ /* Fail if we don't have any pattern */
+ if (aargc == 0 && needpattern)
+ usage();
+
+ /* Process patterns from command line */
+ if (aargc != 0 && needpattern) {
+ add_pattern(*aargv, strlen(*aargv));
+ --aargc;
+ ++aargv;
+ }
+
+ switch (grepbehave) {
+ case GREP_FIXED:
+ case GREP_BASIC:
+ break;
+ case GREP_EXTENDED:
+ cflags |= REG_EXTENDED;
+ break;
+ default:
+ /* NOTREACHED */
+ usage();
+ }
+
+ fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
+ r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
+/*
+ * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
+ * Optimizations should be done there.
+ */
+ /* Check if cheating is allowed (always is for fgrep). */
+ if (grepbehave == GREP_FIXED) {
+ for (i = 0; i < patterns; ++i)
+ fgrepcomp(&fg_pattern[i], pattern[i]);
+ } else {
+ for (i = 0; i < patterns; ++i) {
+ if (fastcomp(&fg_pattern[i], pattern[i])) {
+ /* Fall back to full regex library */
+ c = regcomp(&r_pattern[i], pattern[i], cflags);
+ if (c != 0) {
+ regerror(c, &r_pattern[i], re_error,
+ RE_ERROR_BUF);
+ errx(2, "%s", re_error);
+ }
+ }
+ }
+ }
+
+ if (lbflag)
+ setlinebuf(stdout);
+
+ if ((aargc == 0 || aargc == 1) && !Hflag)
+ hflag = true;
+
+ if (aargc == 0)
+ exit(!procfile("-"));
+
+ if (dirbehave == DIR_RECURSE)
+ c = grep_tree(aargv);
+ else
+ for (c = 0; aargc--; ++aargv) {
+ if ((finclude || fexclude) && !file_matching(*aargv))
+ continue;
+ c+= procfile(*aargv);
+ }
+
+ /* Find out the correct return value according to the
+ results and the command line option. */
+ exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
+}
diff --git a/package/toolbox/src/grep/grep.h b/package/toolbox/src/grep/grep.h
new file mode 100644
index 000000000..334f67c43
--- /dev/null
+++ b/package/toolbox/src/grep/grep.h
@@ -0,0 +1,149 @@
+/* $NetBSD: grep.h,v 1.8 2012/05/06 22:27:00 joerg Exp $ */
+/* $OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $ */
+/* $FreeBSD: head/usr.bin/grep/grep.h 211496 2010-08-19 09:28:59Z des $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <regex.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#define getstr(n) errstr[n]
+
+extern const char *errstr[];
+
+#define VERSION "2.5.1-FreeBSD"
+
+#define GREP_FIXED 0
+#define GREP_BASIC 1
+#define GREP_EXTENDED 2
+
+#define BINFILE_BIN 0
+#define BINFILE_SKIP 1
+#define BINFILE_TEXT 2
+
+#define FILE_STDIO 0
+#define FILE_GZIP 1
+#define FILE_BZIP 2
+
+#define DIR_READ 0
+#define DIR_SKIP 1
+#define DIR_RECURSE 2
+
+#define DEV_READ 0
+#define DEV_SKIP 1
+
+#define LINK_READ 0
+#define LINK_EXPLICIT 1
+#define LINK_SKIP 2
+
+#define EXCL_PAT 0
+#define INCL_PAT 1
+
+#define MAX_LINE_MATCHES 32
+
+struct file {
+ int fd;
+ bool binary;
+};
+
+struct str {
+ off_t off;
+ size_t len;
+ char *dat;
+ char *file;
+ int line_no;
+};
+
+struct epat {
+ char *pat;
+ int mode;
+};
+
+typedef struct {
+ size_t len;
+ unsigned char *pattern;
+ int qsBc[UCHAR_MAX + 1];
+ /* flags */
+ bool bol;
+ bool eol;
+ bool reversed;
+ bool word;
+} fastgrep_t;
+
+/* Flags passed to regcomp() and regexec() */
+extern int cflags, eflags;
+
+/* Command line flags */
+extern bool Eflag, Fflag, Gflag, Hflag, Lflag,
+ bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag,
+ qflag, sflag, vflag, wflag, xflag;
+extern bool dexclude, dinclude, fexclude, finclude, lbflag, nullflag, nulldataflag;
+extern unsigned char line_sep;
+extern unsigned long long Aflag, Bflag, mcount;
+extern char *label;
+extern const char *color;
+extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;
+
+extern bool notfound;
+extern int tail;
+extern unsigned int dpatterns, fpatterns, patterns;
+extern char **pattern;
+extern struct epat *dpattern, *fpattern;
+extern regex_t *er_pattern, *r_pattern;
+extern fastgrep_t *fg_pattern;
+
+/* For regex errors */
+#define RE_ERROR_BUF 512
+extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */
+
+/* util.c */
+bool file_matching(const char *fname);
+int procfile(const char *fn);
+int grep_tree(char **argv);
+void *grep_malloc(size_t size);
+void *grep_calloc(size_t nmemb, size_t size);
+void *grep_realloc(void *ptr, size_t size);
+char *grep_strdup(const char *str);
+void printline(struct str *line, int sep, regmatch_t *matches, int m);
+
+/* queue.c */
+void enqueue(struct str *x);
+void printqueue(void);
+void clearqueue(void);
+
+/* file.c */
+void grep_close(struct file *f);
+struct file *grep_open(const char *path);
+char *grep_fgetln(struct file *f, size_t *len);
+
+/* fastgrep.c */
+int fastcomp(fastgrep_t *, const char *);
+void fgrepcomp(fastgrep_t *, const char *);
+int grep_search(fastgrep_t *, const unsigned char *, size_t, regmatch_t *);
diff --git a/package/toolbox/src/grep/queue.c b/package/toolbox/src/grep/queue.c
new file mode 100644
index 000000000..e3c6be17a
--- /dev/null
+++ b/package/toolbox/src/grep/queue.c
@@ -0,0 +1,116 @@
+/* $NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $ */
+/* $FreeBSD: head/usr.bin/grep/queue.c 211496 2010-08-19 09:28:59Z des $ */
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * A really poor man's queue. It does only what it has to and gets out of
+ * Dodge. It is used in place of <sys/queue.h> to get a better performance.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "grep.h"
+
+struct qentry {
+ STAILQ_ENTRY(qentry) list;
+ struct str data;
+};
+
+static STAILQ_HEAD(, qentry) queue = STAILQ_HEAD_INITIALIZER(queue);
+static unsigned long long count;
+
+static struct qentry *dequeue(void);
+
+void
+enqueue(struct str *x)
+{
+ struct qentry *item;
+
+ item = grep_malloc(sizeof(struct qentry));
+ item->data.dat = grep_malloc(sizeof(char) * x->len);
+ item->data.len = x->len;
+ item->data.line_no = x->line_no;
+ item->data.off = x->off;
+ memcpy(item->data.dat, x->dat, x->len);
+ item->data.file = x->file;
+
+ STAILQ_INSERT_TAIL(&queue, item, list);
+
+ if (++count > Bflag) {
+ item = dequeue();
+ free(item->data.dat);
+ free(item);
+ }
+}
+
+static struct qentry *
+dequeue(void)
+{
+ struct qentry *item;
+
+ item = STAILQ_FIRST(&queue);
+ if (item == NULL)
+ return (NULL);
+
+ STAILQ_REMOVE_HEAD(&queue, list);
+ --count;
+ return (item);
+}
+
+void
+printqueue(void)
+{
+ struct qentry *item;
+
+ while ((item = dequeue()) != NULL) {
+ printline(&item->data, '-', NULL, 0);
+ free(item->data.dat);
+ free(item);
+ }
+}
+
+void
+clearqueue(void)
+{
+ struct qentry *item;
+
+ while ((item = dequeue()) != NULL) {
+ free(item->data.dat);
+ free(item);
+ }
+}
diff --git a/package/toolbox/src/grep/util.c b/package/toolbox/src/grep/util.c
new file mode 100644
index 000000000..4166d5827
--- /dev/null
+++ b/package/toolbox/src/grep/util.c
@@ -0,0 +1,499 @@
+/* $NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $ */
+/* $FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $ */
+/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $");
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "grep.h"
+
+static bool first, first_global = true;
+static unsigned long long since_printed;
+
+static int procline(struct str *l, int);
+
+bool
+file_matching(const char *fname)
+{
+ char *fname_base, *fname_copy;
+ unsigned int i;
+ bool ret;
+
+ ret = finclude ? false : true;
+ fname_copy = grep_strdup(fname);
+ fname_base = basename(fname_copy);
+
+ for (i = 0; i < fpatterns; ++i) {
+ if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
+ fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
+ if (fpattern[i].mode == EXCL_PAT)
+ return (false);
+ else
+ ret = true;
+ }
+ }
+ free(fname_copy);
+ return (ret);
+}
+
+static inline bool
+dir_matching(const char *dname)
+{
+ unsigned int i;
+ bool ret;
+
+ ret = dinclude ? false : true;
+
+ for (i = 0; i < dpatterns; ++i) {
+ if (dname != NULL &&
+ fnmatch(dname, dpattern[i].pat, 0) == 0) {
+ if (dpattern[i].mode == EXCL_PAT)
+ return (false);
+ else
+ ret = true;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * Processes a directory when a recursive search is performed with
+ * the -R option. Each appropriate file is passed to procfile().
+ */
+int
+grep_tree(char **argv)
+{
+ FTS *fts;
+ FTSENT *p;
+ char *d, *dir = NULL;
+ int c, fts_flags;
+ bool ok;
+
+ c = fts_flags = 0;
+
+ switch(linkbehave) {
+ case LINK_EXPLICIT:
+ fts_flags = FTS_COMFOLLOW;
+ break;
+ case LINK_SKIP:
+ fts_flags = FTS_PHYSICAL;
+ break;
+ default:
+ fts_flags = FTS_LOGICAL;
+
+ }
+
+ fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
+
+ if (!(fts = fts_open(argv, fts_flags, NULL)))
+ err(2, "fts_open");
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_DNR:
+ /* FALLTHROUGH */
+ case FTS_ERR:
+ errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno));
+ break;
+ case FTS_D:
+ /* FALLTHROUGH */
+ case FTS_DP:
+ break;
+ case FTS_DC:
+ /* Print a warning for recursive directory loop */
+ warnx("warning: %s: recursive directory loop",
+ p->fts_path);
+ break;
+ default:
+ /* Check for file exclusion/inclusion */
+ ok = true;
+ if (dexclude || dinclude) {
+ if ((d = strrchr(p->fts_path, '/')) != NULL) {
+ dir = grep_malloc(sizeof(char) *
+ (d - p->fts_path + 1));
+ memcpy(dir, p->fts_path,
+ d - p->fts_path);
+ dir[d - p->fts_path] = '\0';
+ }
+ ok = dir_matching(dir);
+ free(dir);
+ dir = NULL;
+ }
+ if (fexclude || finclude)
+ ok &= file_matching(p->fts_path);
+
+ if (ok)
+ c += procfile(p->fts_path);
+ break;
+ }
+ }
+
+ fts_close(fts);
+ return (c);
+}
+
+/*
+ * Opens a file and processes it. Each file is processed line-by-line
+ * passing the lines to procline().
+ */
+int
+procfile(const char *fn)
+{
+ struct file *f;
+ struct stat sb;
+ struct str ln;
+ mode_t s;
+ int c, t;
+
+ if (mflag && (mcount <= 0))
+ return (0);
+
+ if (strcmp(fn, "-") == 0) {
+ fn = label != NULL ? label : getstr(1);
+ f = grep_open(NULL);
+ } else {
+ if (!stat(fn, &sb)) {
+ /* Check if we need to process the file */
+ s = sb.st_mode & S_IFMT;
+ if (s == S_IFDIR && dirbehave == DIR_SKIP)
+ return (0);
+ if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK
+ || s == S_IFSOCK) && devbehave == DEV_SKIP)
+ return (0);
+ }
+ f = grep_open(fn);
+ }
+ if (f == NULL) {
+ if (!sflag)
+ warn("%s", fn);
+ if (errno == ENOENT)
+ notfound = true;
+ return (0);
+ }
+
+ ln.file = grep_malloc(strlen(fn) + 1);
+ strcpy(ln.file, fn);
+ ln.line_no = 0;
+ ln.len = 0;
+ tail = 0;
+ ln.off = -1;
+
+ for (first = true, c = 0; c == 0 || !(lflag || qflag); ) {
+ ln.off += ln.len + 1;
+ if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0)
+ break;
+ if (ln.len > 0 && ln.dat[ln.len - 1] == line_sep)
+ --ln.len;
+ ln.line_no++;
+
+ /* Return if we need to skip a binary file */
+ if (f->binary && binbehave == BINFILE_SKIP) {
+ grep_close(f);
+ free(ln.file);
+ free(f);
+ return (0);
+ }
+ /* Process the file line-by-line */
+ t = procline(&ln, f->binary);
+ c += t;
+
+ /* Count the matches if we have a match limit */
+ if (mflag) {
+ mcount -= t;
+ if (mcount <= 0)
+ break;
+ }
+ }
+ if (Bflag > 0)
+ clearqueue();
+ grep_close(f);
+
+ if (cflag) {
+ if (!hflag)
+ printf("%s:", ln.file);
+ printf("%u%c", c, line_sep);
+ }
+ if (lflag && !qflag && c != 0)
+ printf("%s%c", fn, line_sep);
+ if (Lflag && !qflag && c == 0)
+ printf("%s%c", fn, line_sep);
+ if (c && !cflag && !lflag && !Lflag &&
+ binbehave == BINFILE_BIN && f->binary && !qflag)
+ printf(getstr(8), fn);
+
+ free(ln.file);
+ free(f);
+ return (c);
+}
+
+#define iswword(x) (iswalnum((x)) || (x) == L'_')
+
+/*
+ * Processes a line comparing it with the specified patterns. Each pattern
+ * is looped to be compared along with the full string, saving each and every
+ * match, which is necessary to colorize the output and to count the
+ * matches. The matching lines are passed to printline() to display the
+ * appropriate output.
+ */
+static int
+procline(struct str *l, int nottext)
+{
+ regmatch_t matches[MAX_LINE_MATCHES];
+ regmatch_t pmatch;
+ size_t st = 0;
+ unsigned int i;
+ int c = 0, m = 0, r = 0;
+
+ /* Loop to process the whole line */
+ while (st <= l->len) {
+ pmatch.rm_so = st;
+ pmatch.rm_eo = l->len;
+
+ /* Loop to compare with all the patterns */
+ for (i = 0; i < patterns; i++) {
+/*
+ * XXX: grep_search() is a workaround for speed up and should be
+ * removed in the future. See fastgrep.c.
+ */
+ if (fg_pattern[i].pattern) {
+ r = grep_search(&fg_pattern[i],
+ (unsigned char *)l->dat,
+ l->len, &pmatch);
+ r = (r == 0) ? 0 : REG_NOMATCH;
+ st = pmatch.rm_eo;
+ } else {
+ r = regexec(&r_pattern[i], l->dat, 1,
+ &pmatch, eflags);
+ r = (r == 0) ? 0 : REG_NOMATCH;
+ st = pmatch.rm_eo;
+ }
+ if (r == REG_NOMATCH)
+ continue;
+ /* Check for full match */
+ if (xflag &&
+ (pmatch.rm_so != 0 ||
+ (size_t)pmatch.rm_eo != l->len))
+ continue;
+ /* Check for whole word match */
+ if (fg_pattern[i].word && pmatch.rm_so != 0) {
+ wchar_t wbegin, wend;
+
+ wbegin = wend = L' ';
+ if (pmatch.rm_so != 0 &&
+ sscanf(&l->dat[pmatch.rm_so - 1],
+ "%lc", &wbegin) != 1)
+ continue;
+ if ((size_t)pmatch.rm_eo != l->len &&
+ sscanf(&l->dat[pmatch.rm_eo],
+ "%lc", &wend) != 1)
+ continue;
+ if (iswword(wbegin) || iswword(wend))
+ continue;
+ }
+ c = 1;
+ if (m < MAX_LINE_MATCHES)
+ matches[m++] = pmatch;
+ /* matches - skip further patterns */
+ if ((color != NULL && !oflag) || qflag || lflag)
+ break;
+ }
+
+ if (vflag) {
+ c = !c;
+ break;
+ }
+ /* One pass if we are not recording matches */
+ if ((color != NULL && !oflag) || qflag || lflag)
+ break;
+
+ if (st == (size_t)pmatch.rm_so)
+ break; /* No matches */
+ }
+
+ if (c && binbehave == BINFILE_BIN && nottext)
+ return (c); /* Binary file */
+
+ /* Dealing with the context */
+ if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) {
+ if (c) {
+ if ((Aflag || Bflag) && !first_global &&
+ (first || since_printed > Bflag))
+ printf("--\n");
+ tail = Aflag;
+ if (Bflag > 0)
+ printqueue();
+ printline(l, ':', matches, m);
+ } else {
+ printline(l, '-', matches, m);
+ tail--;
+ }
+ first = false;
+ first_global = false;
+ since_printed = 0;
+ } else {
+ if (Bflag)
+ enqueue(l);
+ since_printed++;
+ }
+ return (c);
+}
+
+/*
+ * Safe malloc() for internal use.
+ */
+void *
+grep_malloc(size_t size)
+{
+ void *ptr;
+
+ if ((ptr = malloc(size)) == NULL)
+ err(2, "malloc");
+ return (ptr);
+}
+
+/*
+ * Safe calloc() for internal use.
+ */
+void *
+grep_calloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ if ((ptr = calloc(nmemb, size)) == NULL)
+ err(2, "calloc");
+ return (ptr);
+}
+
+/*
+ * Safe realloc() for internal use.
+ */
+void *
+grep_realloc(void *ptr, size_t size)
+{
+
+ if ((ptr = realloc(ptr, size)) == NULL)
+ err(2, "realloc");
+ return (ptr);
+}
+
+/*
+ * Safe strdup() for internal use.
+ */
+char *
+grep_strdup(const char *str)
+{
+ char *ret;
+
+ if ((ret = strdup(str)) == NULL)
+ err(2, "strdup");
+ return (ret);
+}
+
+/*
+ * Prints a matching line according to the command line options.
+ */
+void
+printline(struct str *line, int sep, regmatch_t *matches, int m)
+{
+ size_t a = 0;
+ int i, n = 0;
+
+ if (!hflag) {
+ if (nullflag == 0)
+ fputs(line->file, stdout);
+ else {
+ printf("%s", line->file);
+ putchar(0);
+ }
+ ++n;
+ }
+ if (nflag) {
+ if (n > 0)
+ putchar(sep);
+ printf("%d", line->line_no);
+ ++n;
+ }
+ if (bflag) {
+ if (n > 0)
+ putchar(sep);
+ printf("%lld", (long long)line->off);
+ ++n;
+ }
+ if (n)
+ putchar(sep);
+ /* --color and -o */
+ if ((oflag || color) && m > 0) {
+ for (i = 0; i < m; i++) {
+ if (!oflag)
+ fwrite(line->dat + a, matches[i].rm_so - a, 1,
+ stdout);
+ if (color)
+ fprintf(stdout, "\33[%sm\33[K", color);
+
+ fwrite(line->dat + matches[i].rm_so,
+ matches[i].rm_eo - matches[i].rm_so, 1,
+ stdout);
+
+ if (color)
+ fprintf(stdout, "\33[m\33[K");
+ a = matches[i].rm_eo;
+ if (oflag)
+ putchar('\n');
+ }
+ if (!oflag) {
+ if (line->len - a > 0)
+ fwrite(line->dat + a, line->len - a, 1, stdout);
+ putchar(line_sep);
+ }
+ } else {
+ fwrite(line->dat, line->len, 1, stdout);
+ putchar(line_sep);
+ }
+}
diff --git a/package/toolbox/src/hd/Makefile b/package/toolbox/src/hd/Makefile
new file mode 100644
index 000000000..aa75efcb8
--- /dev/null
+++ b/package/toolbox/src/hd/Makefile
@@ -0,0 +1,3 @@
+PROG= hd
+
+include ../tool.mk
diff --git a/package/toolbox/src/id/Makefile b/package/toolbox/src/id/Makefile
new file mode 100644
index 000000000..2a27f05fe
--- /dev/null
+++ b/package/toolbox/src/id/Makefile
@@ -0,0 +1,3 @@
+PROG= id
+
+include ../tool.mk
diff --git a/package/toolbox/src/ifconfig/Makefile b/package/toolbox/src/ifconfig/Makefile
new file mode 100644
index 000000000..ac39cdf82
--- /dev/null
+++ b/package/toolbox/src/ifconfig/Makefile
@@ -0,0 +1,3 @@
+PROG= ifconfig
+
+include ../tool.mk
diff --git a/package/toolbox/src/iftop/Makefile b/package/toolbox/src/iftop/Makefile
new file mode 100644
index 000000000..03a50994a
--- /dev/null
+++ b/package/toolbox/src/iftop/Makefile
@@ -0,0 +1,3 @@
+PROG= iftop
+
+include ../tool.mk
diff --git a/package/toolbox/src/insmod/Makefile b/package/toolbox/src/insmod/Makefile
new file mode 100644
index 000000000..f9420936e
--- /dev/null
+++ b/package/toolbox/src/insmod/Makefile
@@ -0,0 +1,3 @@
+PROG= insmod
+
+include ../tool.mk
diff --git a/package/toolbox/src/ioctl/Makefile b/package/toolbox/src/ioctl/Makefile
new file mode 100644
index 000000000..ac5592a45
--- /dev/null
+++ b/package/toolbox/src/ioctl/Makefile
@@ -0,0 +1,3 @@
+PROG= ioctl
+
+include ../tool.mk
diff --git a/package/toolbox/src/kill/Makefile b/package/toolbox/src/kill/Makefile
new file mode 100644
index 000000000..3d433ba78
--- /dev/null
+++ b/package/toolbox/src/kill/Makefile
@@ -0,0 +1,3 @@
+PROG= kill
+
+include ../tool.mk
diff --git a/package/toolbox/src/lib/Makefile b/package/toolbox/src/lib/Makefile
new file mode 100644
index 000000000..4954e48c4
--- /dev/null
+++ b/package/toolbox/src/lib/Makefile
@@ -0,0 +1,24 @@
+LIB= oadk_toolbox
+SRCS+= fgetln.c
+SRCS+= md5.c md5hlp.c
+CLEANFILES+= lib${LIB}.a
+
+include ../common.mk
+
+OBJS+= strlcpy.o strlcat.o
+
+all: lib${LIB}.a
+
+lib${LIB}.a: ${OBJS}
+ ar rc $@ ${OBJS}
+ -ranlib $@
+
+CFLAGS_strlcpy.o=-DOUTSIDE_OF_LIBKERN -DL_strlcpy
+strlcpy.o: strlfun.c
+ ${COMPILE.c} -o $@ $<
+CFLAGS_strlcat.o=-DOUTSIDE_OF_LIBKERN -DL_strlcat
+strlcat.o: strlfun.c
+ ${COMPILE.c} -o $@ $<
+
+install:
+ # nothing to do here
diff --git a/package/toolbox/src/lib/fgetln.c b/package/toolbox/src/lib/fgetln.c
new file mode 100644
index 000000000..647cf9faa
--- /dev/null
+++ b/package/toolbox/src/lib/fgetln.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2007, 2009
+ * Thorsten Glaser <tg@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ *-
+ * fgetln() wrapper for operating systems with getline() – glibc
+ */
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE /* for getline() */
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+
+__RCSID("$MirOS: contrib/code/mirmake/dist/contrib/fgetln.c,v 1.7 2014/12/20 22:23:29 tg Exp $");
+
+char *fgetln(FILE *, size_t *);
+
+char *
+fgetln(FILE *stream, size_t *len)
+{
+ static char *lb = NULL;
+ static size_t lbsz = 0;
+
+ if ((*len = getline(&lb, &lbsz, stream)) != (size_t)-1)
+ /* getdelim ensures *len is not 0 here */
+ return (lb);
+
+ /* not required by manpage, but reference implementation does this */
+ *len = 0;
+
+ /* not required to zero lb or lbsz: getdelim manages it */
+ return (NULL);
+}
diff --git a/package/toolbox/src/lib/md5.c b/package/toolbox/src/lib/md5.c
new file mode 100644
index 000000000..ea933408d
--- /dev/null
+++ b/package/toolbox/src/lib/md5.c
@@ -0,0 +1,242 @@
+/* $OpenBSD: md5.c,v 1.8 2005/08/08 08:05:35 espie Exp $ */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <md5.h>
+
+extern const uint8_t RFC1321_padding[64];
+
+__RCSID("$MirOS: src/lib/libc/hash/md5.c,v 1.3 2009/11/09 21:36:39 tg Exp $");
+
+#define PUT_64BIT_LE(cp, value) do { \
+ (cp)[7] = (value) >> 56; \
+ (cp)[6] = (value) >> 48; \
+ (cp)[5] = (value) >> 40; \
+ (cp)[4] = (value) >> 32; \
+ (cp)[3] = (value) >> 24; \
+ (cp)[2] = (value) >> 16; \
+ (cp)[1] = (value) >> 8; \
+ (cp)[0] = (value); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do { \
+ (cp)[3] = (value) >> 24; \
+ (cp)[2] = (value) >> 16; \
+ (cp)[1] = (value) >> 8; \
+ (cp)[0] = (value); } while (0)
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(MD5_CTX *ctx)
+{
+ ctx->count = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len)
+{
+ size_t have, need;
+
+ /* Check how many bytes we already have and how many more we need. */
+ have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
+ need = MD5_BLOCK_LENGTH - have;
+
+ /* Update bitcount */
+ ctx->count += (u_int64_t)len << 3;
+
+ if (len >= need) {
+ if (have != 0) {
+ memcpy(ctx->buffer + have, input, need);
+ MD5Transform(ctx->state, ctx->buffer);
+ input += need;
+ len -= need;
+ have = 0;
+ }
+
+ /* Process data in MD5_BLOCK_LENGTH-byte chunks. */
+ while (len >= MD5_BLOCK_LENGTH) {
+ MD5Transform(ctx->state, input);
+ input += MD5_BLOCK_LENGTH;
+ len -= MD5_BLOCK_LENGTH;
+ }
+ }
+
+ /* Handle any remaining bytes of data. */
+ if (len != 0)
+ memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Pad pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Pad(MD5_CTX *ctx)
+{
+ u_int8_t count[8];
+
+ /* Convert count to 8 bytes in little endian order. */
+ PUT_64BIT_LE(count, ctx->count);
+
+ /* Pad out to 56 mod 64. */
+ MD5Update(ctx, RFC1321_padding, 64 - (((ctx->count >> 3) + 8) & 63));
+ MD5Update(ctx, count, 8);
+}
+
+/*
+ * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
+ */
+void
+MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
+{
+ int i;
+
+ MD5Pad(ctx);
+ if (digest != NULL) {
+ for (i = 0; i < 4; i++)
+ PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+ memset(ctx, 0, sizeof(*ctx));
+ }
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH])
+{
+ u_int32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ memcpy(in, block, sizeof(in));
+#else
+ for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
+ in[a] = (u_int32_t)(
+ (u_int32_t)(block[a * 4 + 0]) |
+ (u_int32_t)(block[a * 4 + 1]) << 8 |
+ (u_int32_t)(block[a * 4 + 2]) << 16 |
+ (u_int32_t)(block[a * 4 + 3]) << 24);
+ }
+#endif
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
diff --git a/package/toolbox/src/lib/md5.h b/package/toolbox/src/lib/md5.h
new file mode 100644
index 000000000..ac47848be
--- /dev/null
+++ b/package/toolbox/src/lib/md5.h
@@ -0,0 +1,48 @@
+/* $MirOS: src/kern/include/md5.h,v 1.4 2014/12/20 22:28:45 tg Exp $ */
+
+#ifndef SYSKERN_MD5_H
+#define SYSKERN_MD5_H
+
+#ifdef __MirBSD__
+#include <machine/types.h>
+#endif
+
+#define MD5_BLOCK_LENGTH 64
+#define MD5_DIGEST_LENGTH 16
+#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1)
+
+typedef struct MD5Context {
+ uint32_t state[4];
+ uint64_t count;
+ uint8_t buffer[MD5_BLOCK_LENGTH];
+} MD5_CTX;
+
+__BEGIN_DECLS
+
+/* low-level functions */
+void MD5Init(MD5_CTX *);
+void MD5Update(MD5_CTX *, const uint8_t *, size_t)
+ __attribute__((__bounded__(__string__, 2, 3)));
+void MD5Pad(MD5_CTX *);
+void MD5Final(uint8_t *, MD5_CTX *)
+ __attribute__((__bounded__(__minbytes__, 1, MD5_DIGEST_LENGTH)));
+void MD5Transform(uint32_t *, const uint8_t *)
+ __attribute__((__bounded__(__minbytes__, 1, 16)))
+ __attribute__((__bounded__(__minbytes__, 2, MD5_BLOCK_LENGTH)));
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+/* high-level functions from helper.c */
+char *MD5End(MD5_CTX *, char *)
+ __attribute__((__bounded__(__minbytes__, 2, MD5_DIGEST_STRING_LENGTH)));
+char *MD5File(const char *, char *)
+ __attribute__((__bounded__(__minbytes__, 2, MD5_DIGEST_STRING_LENGTH)));
+char *MD5FileChunk(const char *, char *, off_t, off_t)
+ __attribute__((__bounded__(__minbytes__, 2, MD5_DIGEST_STRING_LENGTH)));
+char *MD5Data(const uint8_t *, size_t, char *)
+ __attribute__((__bounded__(__string__, 1, 2)))
+ __attribute__((__bounded__(__minbytes__, 3, MD5_DIGEST_STRING_LENGTH)));
+#endif
+
+__END_DECLS
+
+#endif
diff --git a/package/toolbox/src/lib/md5hlp.c b/package/toolbox/src/lib/md5hlp.c
new file mode 100644
index 000000000..9c7958a73
--- /dev/null
+++ b/package/toolbox/src/lib/md5hlp.c
@@ -0,0 +1,13 @@
+/* collection of data, not copyrightable */
+
+#include <sys/types.h>
+#include <stdint.h>
+
+__RCSID("$MirOS: src/kern/c/miscdata.c,v 1.1 2011/11/20 18:28:09 tg Exp $");
+
+const uint8_t RFC1321_padding[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
diff --git a/package/toolbox/src/lib/string.h b/package/toolbox/src/lib/string.h
new file mode 100644
index 000000000..571cba664
--- /dev/null
+++ b/package/toolbox/src/lib/string.h
@@ -0,0 +1,9 @@
+#ifndef LIBOADK_STRING_H
+#define LIBOADK_STRING_H
+
+#include_next <string.h>
+
+size_t strlcat(char *, const char *, size_t);
+size_t strlcpy(char *, const char *, size_t);
+
+#endif
diff --git a/package/toolbox/src/lib/strlfun.c b/package/toolbox/src/lib/strlfun.c
new file mode 100644
index 000000000..123eb3d12
--- /dev/null
+++ b/package/toolbox/src/lib/strlfun.c
@@ -0,0 +1,185 @@
+#if 0 /* comment in gmake; next line ignored by gcc */
+ifeq (0,gmake ignores from here)
+#endif
+/*-
+ * Copyright (c) 2006, 2008, 2011
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ *-
+ * The original implementations of strlcpy(3) and strlcat(3) are from
+ * Todd C. Miller; the licence is reproduced below. However, this ap-
+ * plies only to the strlcpy(3) portion of the code, as Thorsten Gla-
+ * ser write the following strlcat(3) implementation according to the
+ * spec. Both functions below have been optimised according to sugge-
+ * stions from Bodo Eggert. mirabilos merged the code with strxfrm(3)
+ * (Unicode-only systems) and the wide character variants wcslcat(3),
+ * wcslcpy(3), and wcsxfrm(3).
+ */
+
+#include <sys/types.h>
+#ifndef OUTSIDE_OF_LIBKERN
+#include <libckern.h>
+#endif
+
+#ifndef __RCSID
+#define __RCSID(x) static const char __rcsid[] = x
+#endif
+
+__RCSID("$MirOS: src/kern/c/strlfun.c,v 1.5 2016/03/06 13:47:13 tg Exp $");
+
+#ifdef WIDEC
+#ifdef OUTSIDE_OF_LIBKERN
+#ifdef __WCHAR_TYPE__
+typedef __WCHAR_TYPE__ wchar_t;
+#else
+#include <wchar.h>
+#endif
+#endif
+/* wide character string functions */
+#define NUL L'\0'
+#define char_t wchar_t
+#define fn_len wcslen
+#define fn_cat wcslcat
+#define fn_cpy wcslcpy
+#else
+/* (multibyte) string functions */
+#define NUL '\0'
+#define char_t char
+#define fn_len strlen
+#define fn_cat strlcat
+#define fn_cpy strlcpy
+#endif
+
+#ifdef L_strxfrm
+#define strlcpy strxfrm
+#define wcslcpy wcsxfrm
+#define L_strlcpy
+#endif
+
+#ifdef OUTSIDE_OF_LIBKERN
+extern size_t fn_len(const char_t *);
+#endif
+
+#ifndef __predict_true
+#define __predict_true(exp) (exp)
+#define __predict_false(exp) (exp)
+#endif
+
+#ifdef L_strlcat
+/*
+ * Appends src to string dst of size dlen (unlike strncat, dlen is the
+ * full size of dst, not space left). At most dlen-1 characters
+ * will be copied. Always NUL terminates (unless dlen <= strlen(dst)).
+ * Returns strlen(src) + MIN(dlen, strlen(initial dst)), without the
+ * trailing NUL byte counted. If retval >= dlen, truncation occurred.
+ */
+size_t
+fn_cat(char_t *dst, const char_t *src, size_t dlen)
+{
+ size_t n = 0, slen;
+
+ slen = fn_len(src);
+ while (__predict_true(n + 1 < dlen && dst[n] != NUL))
+ ++n;
+ if (__predict_false(dlen == 0 || dst[n] != NUL))
+ return (dlen + slen);
+ while (__predict_true((slen > 0) && (n < (dlen - 1)))) {
+ dst[n++] = *src++;
+ --slen;
+ }
+ dst[n] = NUL;
+ return (n + slen);
+}
+#endif
+
+#ifdef L_strlcpy
+/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
+
+/*-
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * 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.
+ */
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+fn_cpy(char_t *dst, const char_t *src, size_t siz)
+{
+ const char_t *s = src;
+
+ if (__predict_false(siz == 0))
+ goto traverse_src;
+
+ /* copy as many chars as will fit */
+ while (--siz && (*dst++ = *s++))
+ ;
+
+ /* not enough room in dst */
+ if (__predict_false(siz == 0)) {
+ /* safe to NUL-terminate dst since we copied <= siz-1 chars */
+ *dst = NUL;
+ traverse_src:
+ /* traverse rest of src */
+ while (*s++)
+ ;
+ }
+
+ /* count does not include NUL */
+ return (s - src - 1);
+}
+#endif
+
+#if 0 /* gcc ignored from here; gmake stops ignoring */
+endif
+
+USE_WIDEC?= 1
+
+LIB= libstrlfun.a
+OBJS= strlcpy.o strlcat.o
+ifeq (1,$(strip $(USE_WIDEC)))
+OBJS+= wcslcpy.o wcslcat.o
+endif
+DEFS= -DOUTSIDE_OF_LIBKERN
+DEFS_strlcpy.o= -DL_strlcpy
+DEFS_strlcat.o= -DL_strlcat
+DEFS_wcslcpy.o= -DL_strlcpy -DWIDEC
+DEFS_wcslcat.o= -DL_strlcat -DWIDEC
+
+all: $(LIB)
+
+$(LIB): $(OBJS)
+ ar rc $(LIB) $(OBJS)
+ -ranlib $(LIB)
+
+$(OBJS): strlfun.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(DEFS) $(DEFS_$@) -c -o $@ strlfun.c
+
+#endif /* EOF for gmake and gcc */
diff --git a/package/toolbox/src/ln/Makefile b/package/toolbox/src/ln/Makefile
new file mode 100644
index 000000000..42bff383e
--- /dev/null
+++ b/package/toolbox/src/ln/Makefile
@@ -0,0 +1,3 @@
+PROG= ln
+
+include ../tool.mk
diff --git a/package/toolbox/src/ls/Makefile b/package/toolbox/src/ls/Makefile
new file mode 100644
index 000000000..52cb1f4fe
--- /dev/null
+++ b/package/toolbox/src/ls/Makefile
@@ -0,0 +1,4 @@
+PROG= ls
+SRCS= ls.c dynarray.c
+
+include ../tool.mk
diff --git a/package/toolbox/src/lsof/Makefile b/package/toolbox/src/lsof/Makefile
new file mode 100644
index 000000000..778de1506
--- /dev/null
+++ b/package/toolbox/src/lsof/Makefile
@@ -0,0 +1,3 @@
+PROG= lsof
+
+include ../tool.mk
diff --git a/package/toolbox/src/md5/Makefile b/package/toolbox/src/md5/Makefile
new file mode 100644
index 000000000..b37336ccc
--- /dev/null
+++ b/package/toolbox/src/md5/Makefile
@@ -0,0 +1,3 @@
+PROG= md5
+
+include ../tool.mk
diff --git a/package/toolbox/src/mkdir/Makefile b/package/toolbox/src/mkdir/Makefile
new file mode 100644
index 000000000..a2796420f
--- /dev/null
+++ b/package/toolbox/src/mkdir/Makefile
@@ -0,0 +1,3 @@
+PROG= mkdir
+
+include ../tool.mk
diff --git a/package/toolbox/src/mknod/Makefile b/package/toolbox/src/mknod/Makefile
new file mode 100644
index 000000000..35956fad6
--- /dev/null
+++ b/package/toolbox/src/mknod/Makefile
@@ -0,0 +1,6 @@
+PROG= mknod
+SRCS= mknod.c setmode.c
+
+include ../tool.mk
+
+CPPFLAGS+= -D'__SCCSID(x)='
diff --git a/package/toolbox/src/mknod/mknod.c b/package/toolbox/src/mknod/mknod.c
new file mode 100644
index 000000000..f09dfe8c4
--- /dev/null
+++ b/package/toolbox/src/mknod/mknod.c
@@ -0,0 +1,190 @@
+/* $OpenBSD: mknod.c,v 1.13 2003/06/02 20:06:15 millert Exp $ */
+/* $NetBSD: mknod.c,v 1.8 1995/08/11 00:08:18 jtc Exp $ */
+
+/*
+ * Copyright (c) 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kevin Fall.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+__SCCSID("@(#)mknod.c 8.1 (Berkeley) 6/5/93");
+__RCSID("$MirOS: src/sbin/mknod/mknod.c,v 1.3 2016/01/02 21:33:04 tg Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <err.h>
+
+extern char *__progname;
+
+int domknod(int, char **, mode_t);
+int domkfifo(int, char **, mode_t);
+void usage(int);
+
+extern mode_t getmode(const void *, mode_t);
+extern void *setmode(const char *);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, ismkfifo = 0;
+ void *set = NULL;
+ mode_t mode = 0;
+
+ if (strcmp(__progname, "mkfifo") == 0)
+ ismkfifo = 1;
+
+ while ((ch = getopt(argc, argv, "m:")) != -1)
+ switch(ch) {
+ case 'm':
+ if (!(set = setmode(optarg))) {
+ errx(1, "invalid file mode.");
+ /* NOTREACHED */
+ }
+
+ /*
+ * In symbolic mode strings, the + and - operators are
+ * interpreted relative to an assumed initial mode of
+ * a=rw.
+ */
+ mode = getmode(set, DEFFILEMODE);
+ free(set);
+ break;
+ case '?':
+ default:
+ usage(ismkfifo);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argv[0] == NULL)
+ usage(ismkfifo);
+ if (!ismkfifo) {
+ if (argc == 2 && argv[1][0] == 'p') {
+ ismkfifo = 2;
+ argc--;
+ argv[1] = NULL;
+ } else if (argc != 4) {
+ usage(ismkfifo);
+ /* NOTREACHED */
+ }
+ }
+
+ /*
+ * If the user specified a mode via `-m', don't allow the umask
+ * to modified it. If no `-m' flag was specified, the default
+ * mode is the value of the bitwise inclusive or of S_IRUSR,
+ * S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH as modified by
+ * the umask.
+ */
+ if (set)
+ (void)umask(0);
+ else
+ mode = DEFFILEMODE;
+
+ if (ismkfifo)
+ exit(domkfifo(argc, argv, mode));
+ else
+ exit(domknod(argc, argv, mode));
+}
+
+int
+domknod(int argc, char **argv, mode_t mode)
+{
+ dev_t dev;
+ char *endp;
+ u_int major, minor;
+
+ if (argv[1][0] == 'c')
+ mode |= S_IFCHR;
+ else if (argv[1][0] == 'b')
+ mode |= S_IFBLK;
+ else {
+ errx(1, "node must be type 'b' or 'c'.");
+ /* NOTREACHED */
+ }
+
+ major = (long)strtoul(argv[2], &endp, 0);
+ if (endp == argv[2] || *endp != '\0') {
+ errx(1, "non-numeric major number.");
+ /* NOTREACHED */
+ }
+ minor = (long)strtoul(argv[3], &endp, 0);
+ if (endp == argv[3] || *endp != '\0') {
+ errx(1, "non-numeric minor number.");
+ /* NOTREACHED */
+ }
+ dev = makedev(major, minor);
+ if (major(dev) != major || minor(dev) != minor) {
+ errx(1, "major or minor number too large");
+ /* NOTREACHED */
+ }
+ if (mknod(argv[0], mode, dev) < 0) {
+ err(1, "%s", argv[0]);
+ /* NOTREACHED */
+ }
+ return(0);
+}
+
+int
+domkfifo(int argc, char **argv, mode_t mode)
+{
+ int rv;
+
+ for (rv = 0; *argv; ++argv) {
+ if (mkfifo(*argv, mode) < 0) {
+ warn("%s", *argv);
+ rv = 1;
+ }
+ }
+ return(rv);
+}
+
+void
+usage(int ismkfifo)
+{
+
+ if (ismkfifo == 1)
+ (void)fprintf(stderr, "usage: %s [-m mode] fifoname ...\n",
+ __progname);
+ else {
+ (void)fprintf(stderr, "usage: %s [-m mode] name [b | c] major minor\n",
+ __progname);
+ (void)fprintf(stderr, "usage: %s [-m mode] name p\n",
+ __progname);
+ }
+ exit(1);
+}
diff --git a/package/toolbox/src/mknod/setmode.c b/package/toolbox/src/mknod/setmode.c
new file mode 100644
index 000000000..afef02d81
--- /dev/null
+++ b/package/toolbox/src/mknod/setmode.c
@@ -0,0 +1,462 @@
+/* $OpenBSD: setmode.c,v 1.17 2005/08/08 08:05:34 espie Exp $ */
+/* $NetBSD: setmode.c,v 1.15 1997/02/07 22:21:06 christos Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Dave Borman at Cray Research, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef SETMODE_DEBUG
+#include <stdio.h>
+#endif
+
+__SCCSID("@(#)setmode.c 8.2 (Berkeley) 3/25/94");
+__RCSID("$MirOS: src/lib/libc/gen/setmode.c,v 1.15 2010/10/08 17:57:00 tg Exp $");
+
+#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
+#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
+
+#if !defined(S_ISTXT) && defined(S_ISVTX)
+#define S_ISTXT S_ISVTX
+#endif
+
+typedef struct bitcmd {
+ mode_t bits;
+ char cmd;
+ char cmd2;
+} BITCMD;
+
+#define CMD2_CLR 0x01
+#define CMD2_SET 0x02
+#define CMD2_GBITS 0x04
+#define CMD2_OBITS 0x08
+#define CMD2_UBITS 0x10
+
+static BITCMD *addcmd(BITCMD *, int, int, int, u_int);
+static void compress_mode(BITCMD *);
+#ifdef SETMODE_DEBUG
+static void dumpmode(BITCMD *);
+#endif
+
+/*
+ * Given the old mode and an array of bitcmd structures, apply the operations
+ * described in the bitcmd structures to the old mode, and return the new mode.
+ * Note that there is no '=' command; a strict assignment is just a '-' (clear
+ * bits) followed by a '+' (set bits).
+ */
+mode_t
+getmode(const void *bbox, mode_t omode)
+{
+ const BITCMD *set;
+ mode_t clrval, newmode, value;
+
+ set = (const BITCMD *)bbox;
+ newmode = omode;
+ for (value = 0;; set++)
+ switch(set->cmd) {
+ /*
+ * When copying the user, group or other bits around, we "know"
+ * where the bits are in the mode so that we can do shifts to
+ * copy them around. If we don't use shifts, it gets real
+ * grundgy with lots of single bit checks and bit sets.
+ */
+ case 'u':
+ value = (newmode & S_IRWXU) >> 6;
+ goto common;
+
+ case 'g':
+ value = (newmode & S_IRWXG) >> 3;
+ goto common;
+
+ case 'o':
+ value = newmode & S_IRWXO;
+ common:
+ if (set->cmd2 & CMD2_CLR) {
+ clrval =
+ (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
+ if (set->cmd2 & CMD2_UBITS)
+ newmode &= ~((clrval<<6) & set->bits);
+ if (set->cmd2 & CMD2_GBITS)
+ newmode &= ~((clrval<<3) & set->bits);
+ if (set->cmd2 & CMD2_OBITS)
+ newmode &= ~(clrval & set->bits);
+ }
+ if (set->cmd2 & CMD2_SET) {
+ if (set->cmd2 & CMD2_UBITS)
+ newmode |= (value<<6) & set->bits;
+ if (set->cmd2 & CMD2_GBITS)
+ newmode |= (value<<3) & set->bits;
+ if (set->cmd2 & CMD2_OBITS)
+ newmode |= value & set->bits;
+ }
+ break;
+
+ case '+':
+ newmode |= set->bits;
+ break;
+
+ case '-':
+ newmode &= ~set->bits;
+ break;
+
+ case 'X':
+ if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
+ newmode |= set->bits;
+ break;
+
+ case '\0':
+ default:
+#ifdef SETMODE_DEBUG
+ (void)printf("getmode:%04o -> %04o\n", omode, newmode);
+#endif
+ return (newmode);
+ }
+}
+
+#define notoktomul(a, b) ((a) && (b) && (SIZE_MAX / (a) < (b)))
+
+#define ADDCMD(a, b, c, d) \
+ if (set >= endset) { \
+ BITCMD *newset; \
+ setlen += SET_LEN_INCR; \
+ if (notoktomul(setlen, sizeof(BITCMD)) || \
+ (newset = realloc(saveset, setlen * \
+ sizeof(BITCMD))) == NULL) { \
+ free(saveset); \
+ return (NULL); \
+ } \
+ set = newset + (set - saveset); \
+ saveset = newset; \
+ endset = newset + (setlen - 2); \
+ } \
+ set = addcmd(set, (a), (b), (c), (d))
+
+#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
+
+void *
+setmode(const char *p)
+{
+ int perm, who;
+ char op, *ep;
+ BITCMD *set, *saveset, *endset;
+ sigset_t signset, sigoset;
+ mode_t mask;
+ int equalopdone = 0, permXbits, setlen;
+ u_long perml;
+
+ if (!*p)
+ return (NULL);
+
+ /*
+ * Get a copy of the mask for the permissions that are mask relative.
+ * Flip the bits, we want what's not set. Since it's possible that
+ * the caller is opening files inside a signal handler, protect them
+ * as best we can.
+ */
+ sigfillset(&signset);
+ (void)sigprocmask(SIG_BLOCK, &signset, &sigoset);
+ (void)umask(mask = umask(0));
+ mask = ~mask;
+ (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
+
+ setlen = SET_LEN + 2;
+
+ if (notoktomul(setlen, sizeof(BITCMD)) ||
+ (set = malloc(setlen * sizeof(BITCMD))) == NULL)
+ return (NULL);
+ saveset = set;
+ endset = set + (setlen - 2);
+
+ /*
+ * If an absolute number, get it and return; disallow non-octal digits
+ * or illegal bits.
+ */
+ if (isdigit((unsigned char)*p)) {
+ perml = strtoul(p, &ep, 8);
+ /* The test on perml will also catch overflow. */
+ if (*ep != '\0' || (perml & ~(STANDARD_BITS|S_ISTXT))) {
+ free(saveset);
+ errno = ERANGE;
+ return (NULL);
+ }
+ perm = (mode_t)perml;
+ ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
+ set->cmd = 0;
+ return (saveset);
+ }
+
+ /*
+ * Build list of structures to set/clear/copy bits as described by
+ * each clause of the symbolic mode.
+ */
+ for (;;) {
+ /* First, find out which bits might be modified. */
+ for (who = 0;; ++p) {
+ switch (*p) {
+ case 'a':
+ who |= STANDARD_BITS;
+ break;
+ case 'u':
+ who |= S_ISUID|S_IRWXU;
+ break;
+ case 'g':
+ who |= S_ISGID|S_IRWXG;
+ break;
+ case 'o':
+ who |= S_IRWXO;
+ break;
+ default:
+ goto getop;
+ }
+ }
+
+ getop:
+ if ((op = *p++) != '+' && op != '-' && op != '=') {
+ free(saveset);
+ return (NULL);
+ }
+ if (op == '=')
+ equalopdone = 0;
+
+ who &= ~S_ISTXT;
+ for (perm = 0, permXbits = 0;; ++p) {
+ switch (*p) {
+ case 'r':
+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
+ break;
+ case 's':
+ /*
+ * If specific bits where requested and
+ * only "other" bits ignore set-id.
+ */
+ if (who == 0 || (who & ~S_IRWXO))
+ perm |= S_ISUID|S_ISGID;
+ break;
+ case 't':
+ /*
+ * If specific bits where requested and
+ * only "other" bits ignore sticky.
+ */
+ if (who == 0 || (who & ~S_IRWXO)) {
+ who |= S_ISTXT;
+ perm |= S_ISTXT;
+ }
+ break;
+ case 'w':
+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+ break;
+ case 'X':
+ permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
+ break;
+ case 'x':
+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+ break;
+ case 'u':
+ case 'g':
+ case 'o':
+ /*
+ * When ever we hit 'u', 'g', or 'o', we have
+ * to flush out any partial mode that we have,
+ * and then do the copying of the mode bits.
+ */
+ if (perm) {
+ ADDCMD(op, who, perm, mask);
+ perm = 0;
+ }
+ if (op == '=')
+ equalopdone = 1;
+ if (op == '+' && permXbits) {
+ ADDCMD('X', who, permXbits, mask);
+ permXbits = 0;
+ }
+ ADDCMD(*p, who, op, mask);
+ break;
+
+ default:
+ /*
+ * Add any permissions that we haven't already
+ * done.
+ */
+ if (perm || (op == '=' && !equalopdone)) {
+ if (op == '=')
+ equalopdone = 1;
+ ADDCMD(op, who, perm, mask);
+ perm = 0;
+ }
+ if (permXbits) {
+ ADDCMD('X', who, permXbits, mask);
+ permXbits = 0;
+ }
+ goto apply;
+ }
+ }
+
+ apply:
+ if (!*p)
+ break;
+ if (*p != ',')
+ goto getop;
+ ++p;
+ }
+ set->cmd = 0;
+#ifdef SETMODE_DEBUG
+ (void)printf("Before compress_mode()\n");
+ dumpmode(saveset);
+#endif
+ compress_mode(saveset);
+#ifdef SETMODE_DEBUG
+ (void)printf("After compress_mode()\n");
+ dumpmode(saveset);
+#endif
+ return (saveset);
+}
+
+static BITCMD *
+addcmd(BITCMD *set, int op, int who, int oparg, u_int mask)
+{
+ switch (op) {
+ case '=':
+ set->cmd = '-';
+ set->bits = who ? who : STANDARD_BITS;
+ set++;
+
+ op = '+';
+ /* FALLTHROUGH */
+ case '+':
+ case '-':
+ case 'X':
+ set->cmd = op;
+ set->bits = (who ? who : (int)mask) & oparg;
+ break;
+
+ case 'u':
+ case 'g':
+ case 'o':
+ set->cmd = op;
+ if (who) {
+ set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
+ ((who & S_IRGRP) ? CMD2_GBITS : 0) |
+ ((who & S_IROTH) ? CMD2_OBITS : 0);
+ set->bits = (mode_t)~0;
+ } else {
+ set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
+ set->bits = mask;
+ }
+
+ if (oparg == '+')
+ set->cmd2 |= CMD2_SET;
+ else if (oparg == '-')
+ set->cmd2 |= CMD2_CLR;
+ else if (oparg == '=')
+ set->cmd2 |= CMD2_SET|CMD2_CLR;
+ break;
+ }
+ return (set + 1);
+}
+
+#ifdef SETMODE_DEBUG
+static void
+dumpmode(BITCMD *set)
+{
+ for (; set->cmd; ++set)
+ (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
+ set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
+ set->cmd2 & CMD2_CLR ? " CLR" : "",
+ set->cmd2 & CMD2_SET ? " SET" : "",
+ set->cmd2 & CMD2_UBITS ? " UBITS" : "",
+ set->cmd2 & CMD2_GBITS ? " GBITS" : "",
+ set->cmd2 & CMD2_OBITS ? " OBITS" : "");
+}
+#endif
+
+/*
+ * Given an array of bitcmd structures, compress by compacting consecutive
+ * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
+ * 'g' and 'o' commands continue to be separate. They could probably be
+ * compacted, but it's not worth the effort.
+ */
+static void
+compress_mode(BITCMD *set)
+{
+ BITCMD *nset;
+ int setbits, clrbits, Xbits, op;
+
+ for (nset = set;;) {
+ /* Copy over any 'u', 'g' and 'o' commands. */
+ while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
+ *set++ = *nset++;
+ if (!op)
+ return;
+ }
+
+ for (setbits = clrbits = Xbits = 0;; nset++) {
+ if ((op = nset->cmd) == '-') {
+ clrbits |= nset->bits;
+ setbits &= ~nset->bits;
+ Xbits &= ~nset->bits;
+ } else if (op == '+') {
+ setbits |= nset->bits;
+ clrbits &= ~nset->bits;
+ Xbits &= ~nset->bits;
+ } else if (op == 'X')
+ Xbits |= nset->bits & ~setbits;
+ else
+ break;
+ }
+ if (clrbits) {
+ set->cmd = '-';
+ set->cmd2 = 0;
+ set->bits = clrbits;
+ set++;
+ }
+ if (setbits) {
+ set->cmd = '+';
+ set->cmd2 = 0;
+ set->bits = setbits;
+ set++;
+ }
+ if (Xbits) {
+ set->cmd = 'X';
+ set->cmd2 = 0;
+ set->bits = Xbits;
+ set++;
+ }
+ }
+}
diff --git a/package/toolbox/src/mount/Makefile b/package/toolbox/src/mount/Makefile
new file mode 100644
index 000000000..980138b84
--- /dev/null
+++ b/package/toolbox/src/mount/Makefile
@@ -0,0 +1,3 @@
+PROG= mount
+
+include ../tool.mk
diff --git a/package/toolbox/src/mv/Makefile b/package/toolbox/src/mv/Makefile
new file mode 100644
index 000000000..2ec258d71
--- /dev/null
+++ b/package/toolbox/src/mv/Makefile
@@ -0,0 +1,3 @@
+PROG= mv
+
+include ../tool.mk
diff --git a/package/toolbox/src/netstat/Makefile b/package/toolbox/src/netstat/Makefile
new file mode 100644
index 000000000..d2ec384b0
--- /dev/null
+++ b/package/toolbox/src/netstat/Makefile
@@ -0,0 +1,3 @@
+PROG= netstat
+
+include ../tool.mk
diff --git a/package/toolbox/src/notify/Makefile b/package/toolbox/src/notify/Makefile
new file mode 100644
index 000000000..b0ac6746b
--- /dev/null
+++ b/package/toolbox/src/notify/Makefile
@@ -0,0 +1,3 @@
+PROG= notify
+
+include ../tool.mk
diff --git a/package/toolbox/src/printenv/Makefile b/package/toolbox/src/printenv/Makefile
new file mode 100644
index 000000000..1732cc39a
--- /dev/null
+++ b/package/toolbox/src/printenv/Makefile
@@ -0,0 +1,3 @@
+PROG= printenv
+
+include ../tool.mk
diff --git a/package/toolbox/src/ps/Makefile b/package/toolbox/src/ps/Makefile
new file mode 100644
index 000000000..394dcc2e7
--- /dev/null
+++ b/package/toolbox/src/ps/Makefile
@@ -0,0 +1,3 @@
+PROG= ps
+
+include ../tool.mk
diff --git a/package/toolbox/src/readlink/Makefile b/package/toolbox/src/readlink/Makefile
new file mode 100644
index 000000000..bcd3e347b
--- /dev/null
+++ b/package/toolbox/src/readlink/Makefile
@@ -0,0 +1,3 @@
+PROG= readlink
+
+include ../tool.mk
diff --git a/package/toolbox/src/renice/Makefile b/package/toolbox/src/renice/Makefile
new file mode 100644
index 000000000..8c174f82b
--- /dev/null
+++ b/package/toolbox/src/renice/Makefile
@@ -0,0 +1,3 @@
+PROG= renice
+
+include ../tool.mk
diff --git a/package/toolbox/src/rm/Makefile b/package/toolbox/src/rm/Makefile
new file mode 100644
index 000000000..f34eee210
--- /dev/null
+++ b/package/toolbox/src/rm/Makefile
@@ -0,0 +1,3 @@
+PROG= rm
+
+include ../tool.mk
diff --git a/package/toolbox/src/rmdir/Makefile b/package/toolbox/src/rmdir/Makefile
new file mode 100644
index 000000000..40addfb42
--- /dev/null
+++ b/package/toolbox/src/rmdir/Makefile
@@ -0,0 +1,3 @@
+PROG= rmdir
+
+include ../tool.mk
diff --git a/package/toolbox/src/rmmod/Makefile b/package/toolbox/src/rmmod/Makefile
new file mode 100644
index 000000000..63bd4a7d6
--- /dev/null
+++ b/package/toolbox/src/rmmod/Makefile
@@ -0,0 +1,3 @@
+PROG= rmmod
+
+include ../tool.mk
diff --git a/package/toolbox/src/route/Makefile b/package/toolbox/src/route/Makefile
new file mode 100644
index 000000000..06c348a9b
--- /dev/null
+++ b/package/toolbox/src/route/Makefile
@@ -0,0 +1,3 @@
+PROG= route
+
+include ../tool.mk
diff --git a/package/toolbox/src/schedtop/Makefile b/package/toolbox/src/schedtop/Makefile
new file mode 100644
index 000000000..37384bf69
--- /dev/null
+++ b/package/toolbox/src/schedtop/Makefile
@@ -0,0 +1,3 @@
+PROG= schedtop
+
+include ../tool.mk
diff --git a/package/toolbox/src/sed/Makefile b/package/toolbox/src/sed/Makefile
new file mode 100644
index 000000000..cc9e96763
--- /dev/null
+++ b/package/toolbox/src/sed/Makefile
@@ -0,0 +1,6 @@
+PROG= sed
+SRCS= compile.c main.c misc.c process.c
+
+include ../tool.mk
+
+CPPFLAGS+= -D'__SCCSID(x)='
diff --git a/package/toolbox/src/sed/compile.c b/package/toolbox/src/sed/compile.c
new file mode 100644
index 000000000..6d86428ca
--- /dev/null
+++ b/package/toolbox/src/sed/compile.c
@@ -0,0 +1,870 @@
+/* $OpenBSD: compile.c,v 1.42 2017/08/01 18:05:53 martijn Exp $ */
+
+/*-
+ * Copyright (c) 2016
+ * mirabilos <m@mirbsd.org>
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "defs.h"
+#include "extern.h"
+
+__RCSID("$MirOS: src/usr.bin/sed/compile.c,v 1.3 2017/11/20 01:23:56 tg Exp $");
+
+#define LHSZ 128
+#define LHMASK (LHSZ - 1)
+static struct labhash {
+ struct labhash *lh_next;
+ u_int lh_hash;
+ struct s_command *lh_cmd;
+ int lh_ref;
+} *labels[LHSZ];
+
+static char *compile_addr(char *, struct s_addr *);
+static char *compile_ccl(char **, char *);
+static char *compile_delimited(char *, char *, int);
+static char *compile_flags(char *, struct s_subst *);
+static char *compile_re(char *, regex_t **);
+static char *compile_subst(char *, struct s_subst *);
+static char *compile_text(void);
+static char *compile_tr(char *, char **);
+static struct s_command
+ **compile_stream(struct s_command **);
+static char *duptoeol(char *, const char *, char **);
+static void enterlabel(struct s_command *);
+static struct s_command
+ *findlabel(char *);
+static void fixuplabel(struct s_command *, struct s_command *);
+static void uselabel(void);
+
+/*
+ * Command specification. This is used to drive the command parser.
+ */
+struct s_format {
+ char code; /* Command code */
+ int naddr; /* Number of address args */
+ enum e_args args; /* Argument type */
+};
+
+static struct s_format cmd_fmts[] = {
+ {'{', 2, GROUP},
+ {'}', 0, ENDGROUP},
+ {'a', 1, TEXT},
+ {'b', 2, BRANCH},
+ {'c', 2, TEXT},
+ {'d', 2, EMPTY},
+ {'D', 2, EMPTY},
+ {'g', 2, EMPTY},
+ {'G', 2, EMPTY},
+ {'h', 2, EMPTY},
+ {'H', 2, EMPTY},
+ {'i', 1, TEXT},
+ {'l', 2, EMPTY},
+ {'n', 2, EMPTY},
+ {'N', 2, EMPTY},
+ {'p', 2, EMPTY},
+ {'P', 2, EMPTY},
+ {'q', 1, EMPTY},
+ {'r', 1, RFILE},
+ {'s', 2, SUBST},
+ {'t', 2, BRANCH},
+ {'w', 2, WFILE},
+ {'x', 2, EMPTY},
+ {'y', 2, TR},
+ {'!', 2, NONSEL},
+ {':', 0, LABEL},
+ {'#', 0, COMMENT},
+ {'=', 1, EMPTY},
+ {'\0', 0, COMMENT},
+};
+
+/* The compiled program. */
+struct s_command *prog;
+
+/*
+ * Compile the program into prog.
+ * Initialise appends.
+ */
+void
+compile(void)
+{
+ *compile_stream(&prog) = NULL;
+ fixuplabel(prog, NULL);
+ uselabel();
+ appends = xreallocarray(NULL, appendnum, sizeof(struct s_appends));
+ match = xreallocarray(NULL, maxnsub + 1, sizeof(regmatch_t));
+}
+
+#define EATSPACE() do { \
+ if (p) \
+ while (isascii((unsigned char)*p) && \
+ isspace((unsigned char)*p)) \
+ p++; \
+ } while (0)
+
+static struct s_command **
+compile_stream(struct s_command **link)
+{
+ char *p;
+ static char *lbuf; /* To avoid excessive malloc calls */
+ static size_t bufsize;
+ struct s_command *cmd, *cmd2, *stack;
+ struct s_format *fp;
+ int naddr; /* Number of addresses */
+
+ stack = 0;
+ for (;;) {
+ if ((p = cu_fgets(&lbuf, &bufsize)) == NULL) {
+ if (stack != 0)
+ error(COMPILE, "unexpected EOF (pending }'s)");
+ return (link);
+ }
+
+semicolon: EATSPACE();
+ if (*p == '#' || *p == '\0')
+ continue;
+ if (*p == ';') {
+ p++;
+ goto semicolon;
+ }
+ *link = cmd = xmalloc(sizeof(struct s_command));
+ link = &cmd->next;
+ cmd->nonsel = cmd->inrange = 0;
+ /* First parse the addresses */
+ naddr = 0;
+
+/* Valid characters to start an address */
+#define addrchar(c) (strchr("0123456789/\\$", (c)))
+ if (addrchar(*p)) {
+ naddr++;
+ cmd->a1 = xmalloc(sizeof(struct s_addr));
+ p = compile_addr(p, cmd->a1);
+ EATSPACE(); /* EXTENSION */
+ if (*p == ',') {
+ p++;
+ EATSPACE(); /* EXTENSION */
+ naddr++;
+ cmd->a2 = xmalloc(sizeof(struct s_addr));
+ p = compile_addr(p, cmd->a2);
+ EATSPACE();
+ } else {
+ cmd->a2 = 0;
+ }
+ } else {
+ cmd->a1 = cmd->a2 = 0;
+ }
+
+nonsel: /* Now parse the command */
+ if (!*p)
+ error(COMPILE, "command expected");
+ cmd->code = *p;
+ for (fp = cmd_fmts; fp->code; fp++)
+ if (fp->code == *p)
+ break;
+ if (!fp->code)
+ error(COMPILE, "invalid command code %c", *p);
+ if (naddr > fp->naddr)
+ error(COMPILE,
+ "command %c expects up to %d address(es), found %d",
+ *p, fp->naddr, naddr);
+ switch (fp->args) {
+ case NONSEL: /* ! */
+ p++;
+ EATSPACE();
+ cmd->nonsel = 1;
+ goto nonsel;
+ case GROUP: /* { */
+ p++;
+ EATSPACE();
+ cmd->next = stack;
+ stack = cmd;
+ link = &cmd->u.c;
+ if (*p)
+ goto semicolon;
+ break;
+ case ENDGROUP:
+ /*
+ * Short-circuit command processing, since end of
+ * group is really just a noop.
+ */
+ cmd->nonsel = 1;
+ if (stack == 0)
+ error(COMPILE, "unexpected }");
+ cmd2 = stack;
+ stack = cmd2->next;
+ cmd2->next = cmd;
+ /*FALLTHROUGH*/
+ case EMPTY: /* d D g G h H l n N p P q x = \0 */
+ p++;
+ EATSPACE();
+ if (*p == ';') {
+ p++;
+ link = &cmd->next;
+ goto semicolon;
+ }
+ if (*p)
+ error(COMPILE,
+"extra characters at the end of %c command", cmd->code);
+ break;
+ case TEXT: /* a c i */
+ p++;
+ EATSPACE();
+ if (*p != '\\')
+ error(COMPILE, "command %c expects \\ followed by"
+ " text", cmd->code);
+ p++;
+ EATSPACE();
+ if (*p)
+ error(COMPILE, "extra characters after \\ at the"
+ " end of %c command", cmd->code);
+ cmd->t = compile_text();
+ break;
+ case COMMENT: /* \0 # */
+ break;
+ case WFILE: /* w */
+ p++;
+ EATSPACE();
+ if (*p == '\0')
+ error(COMPILE, "filename expected");
+ cmd->t = duptoeol(p, "w command", NULL);
+ if (aflag) {
+ cmd->u.fd = -1;
+ pledge_wpath = 1;
+ }
+ else if ((cmd->u.fd = open(p,
+ O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
+ DEFFILEMODE)) == -1)
+ error(FATAL, "%s: %s", p, strerror(errno));
+ break;
+ case RFILE: /* r */
+ pledge_rpath = 1;
+ p++;
+ EATSPACE();
+ cmd->t = duptoeol(p, "read command", NULL);
+ break;
+ case BRANCH: /* b t */
+ p++;
+ EATSPACE();
+ if (*p == '\0')
+ cmd->t = NULL;
+ else
+ cmd->t = duptoeol(p, "branch", &p);
+ if (*p == ';') {
+ p++;
+ goto semicolon;
+ }
+ break;
+ case LABEL: /* : */
+ p++;
+ EATSPACE();
+ cmd->t = duptoeol(p, "label", &p);
+ if (strlen(cmd->t) == 0)
+ error(COMPILE, "empty label");
+ enterlabel(cmd);
+ if (*p == ';') {
+ p++;
+ goto semicolon;
+ }
+ break;
+ case SUBST: /* s */
+ p++;
+ if (*p == '\0' || *p == '\\')
+ error(COMPILE, "substitute pattern can not be"
+ " delimited by newline or backslash");
+ cmd->u.s = xmalloc(sizeof(struct s_subst));
+ p = compile_re(p, &cmd->u.s->re);
+ if (p == NULL)
+ error(COMPILE, "unterminated substitute pattern");
+ --p;
+ p = compile_subst(p, cmd->u.s);
+ p = compile_flags(p, cmd->u.s);
+ EATSPACE();
+ if (*p == ';') {
+ p++;
+ link = &cmd->next;
+ goto semicolon;
+ }
+ break;
+ case TR: /* y */
+ p++;
+ p = compile_tr(p, (char **)&cmd->u.y);
+ EATSPACE();
+ if (*p == ';') {
+ p++;
+ link = &cmd->next;
+ goto semicolon;
+ }
+ if (*p)
+ error(COMPILE, "extra text at the end of a"
+ " transform command");
+ break;
+ }
+ }
+}
+
+/*
+ * Get a delimited string. P points to the delimeter of the string; d points
+ * to a buffer area. Newline and delimiter escapes are processed; other
+ * escapes are ignored.
+ *
+ * Returns a pointer to the first character after the final delimiter or NULL
+ * in the case of a non-terminated string. The character array d is filled
+ * with the processed string.
+ */
+static char *
+compile_delimited(char *p, char *d, int is_tr)
+{
+ char c;
+
+ c = *p++;
+ if (c == '\0')
+ return (NULL);
+ else if (c == '\\')
+ error(COMPILE, "\\ can not be used as a string delimiter");
+ else if (c == '\n')
+ error(COMPILE, "newline can not be used as a string delimiter");
+ while (*p) {
+ if (*p == '[' && *p != c) {
+ if ((d = compile_ccl(&p, d)) == NULL)
+ error(COMPILE, "unbalanced brackets ([])");
+ continue;
+ } else if (*p == '\\' && p[1] == '[') {
+ *d++ = *p++;
+ } else if (*p == '\\' && p[1] == c) {
+ p++;
+ } else if (*p == '\\' && p[1] == 'n') {
+ *d++ = '\n';
+ p += 2;
+ continue;
+ } else if (*p == '\\' && p[1] == '\\') {
+ if (is_tr)
+ p++;
+ else
+ *d++ = *p++;
+ } else if (*p == c) {
+ *d = '\0';
+ return (p + 1);
+ }
+ *d++ = *p++;
+ }
+ return (NULL);
+}
+
+
+/* compile_ccl: expand a POSIX character class */
+static char *
+compile_ccl(char **sp, char *t)
+{
+ int c, d;
+ char *s = *sp;
+
+ *t++ = *s++;
+ if (*s == '^')
+ *t++ = *s++;
+ if (*s == ']')
+ *t++ = *s++;
+ for (; *s && (*t = *s) != ']'; s++, t++)
+ if (*s == '[' && ((d = *(s+1)) == '.' || d == ':' || d == '=')) {
+ *++t = *++s, t++, s++;
+ for (c = *s; (*t = *s) != ']' || c != d; s++, t++)
+ if ((c = *s) == '\0')
+ return NULL;
+ } else if (*s == '\\' && s[1] == 'n') {
+ *t = '\n';
+ s++;
+ }
+ if (*s == ']') {
+ *sp = ++s;
+ return (++t);
+ } else {
+ return (NULL);
+ }
+}
+
+/*
+ * Get a regular expression. P points to the delimiter of the regular
+ * expression; repp points to the address of a regexp pointer. Newline
+ * and delimiter escapes are processed; other escapes are ignored.
+ * Returns a pointer to the first character after the final delimiter
+ * or NULL in the case of a non terminated regular expression. The regexp
+ * pointer is set to the compiled regular expression.
+ * Cflags are passed to regcomp.
+ */
+static char *
+compile_re(char *p, regex_t **repp)
+{
+ int eval;
+ char *re;
+
+ re = xmalloc(strlen(p) + 1); /* strlen(re) <= strlen(p) */
+ p = compile_delimited(p, re, 0);
+ if (p && strlen(re) == 0) {
+ *repp = NULL;
+ free(re);
+ return (p);
+ }
+ *repp = xmalloc(sizeof(regex_t));
+ if (p && (eval = regcomp(*repp, re, Eflag ? REG_EXTENDED : 0)) != 0)
+ error(COMPILE, "RE error: %s", strregerror(eval, *repp));
+ if (maxnsub < (*repp)->re_nsub)
+ maxnsub = (*repp)->re_nsub;
+ free(re);
+ return (p);
+}
+
+/*
+ * Compile the substitution string of a regular expression and set res to
+ * point to a saved copy of it. Nsub is the number of parenthesized regular
+ * expressions.
+ */
+static char *
+compile_subst(char *p, struct s_subst *s)
+{
+ static char *lbuf;
+ static size_t bufsize;
+ size_t asize, ref, size;
+ char c, *text, *op, *sp;
+ int sawesc = 0;
+
+ c = *p++; /* Terminator character */
+ if (c == '\0')
+ return (NULL);
+
+ s->maxbref = 0;
+ s->linenum = linenum;
+ text = NULL;
+ asize = size = 0;
+ do {
+ size_t len = ROUNDLEN(strlen(p) + 1);
+ if (asize - size < len) {
+ do {
+ asize += len;
+ } while (asize - size < len);
+ text = xrealloc(text, asize);
+ }
+ op = sp = text + size;
+ for (; *p; p++) {
+ if (*p == '\\' || sawesc) {
+ /*
+ * If this is a continuation from the last
+ * buffer, we won't have a character to
+ * skip over.
+ */
+ if (sawesc)
+ sawesc = 0;
+ else
+ p++;
+
+ if (*p == '\0') {
+ /*
+ * This escaped character is continued
+ * in the next part of the line. Note
+ * this fact, then cause the loop to
+ * exit w/ normal EOL case and reenter
+ * above with the new buffer.
+ */
+ sawesc = 1;
+ p--;
+ continue;
+ } else if (strchr("123456789", *p) != NULL) {
+ *sp++ = '\\';
+ ref = *p - '0';
+ if (s->re != NULL &&
+ ref > s->re->re_nsub)
+ error(COMPILE,
+"\\%c not defined in the RE", *p);
+ if (s->maxbref < ref)
+ s->maxbref = ref;
+ } else if (*p == '&' || *p == '\\')
+ *sp++ = '\\';
+ } else if (*p == c) {
+ p++;
+ *sp++ = '\0';
+ size += sp - op;
+ s->new = xrealloc(text, size);
+ return (p);
+ } else if (*p == '\n') {
+ error(COMPILE,
+"unescaped newline inside substitute pattern");
+ }
+ *sp++ = *p;
+ }
+ size += sp - op;
+ } while ((p = cu_fgets(&lbuf, &bufsize)));
+ error(COMPILE, "unterminated substitute in regular expression");
+}
+
+/*
+ * Compile the flags of the s command
+ */
+static char *
+compile_flags(char *p, struct s_subst *s)
+{
+ int gn; /* True if we have seen g or n */
+ long l;
+ char wfile[PATH_MAX], *q, *eq;
+
+ s->n = 1; /* Default */
+ s->p = 0;
+ s->wfile = NULL;
+ s->wfd = -1;
+ for (gn = 0;;) {
+ EATSPACE(); /* EXTENSION */
+ switch (*p) {
+ case 'g':
+ if (gn)
+ error(COMPILE, "more than one number or 'g' in"
+ " substitute flags");
+ gn = 1;
+ s->n = 0;
+ break;
+ case '\0':
+ case '\n':
+ case ';':
+ return (p);
+ case 'p':
+ s->p = 1;
+ break;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ if (gn)
+ error(COMPILE, "more than one number or 'g' in"
+ " substitute flags");
+ gn = 1;
+ l = strtol(p, &p, 10);
+ if (l <= 0 || l >= INT_MAX)
+ error(COMPILE,
+ "number in substitute flags out of range");
+ s->n = (int)l;
+ continue;
+ case 'w':
+ p++;
+#ifdef HISTORIC_PRACTICE
+ if (*p != ' ') {
+ warning("space missing before w wfile");
+ return (p);
+ }
+#endif
+ EATSPACE();
+ q = wfile;
+ eq = wfile + sizeof(wfile) - 1;
+ while (*p) {
+ if (*p == '\n')
+ break;
+ if (q >= eq)
+ error(COMPILE, "wfile too long");
+ *q++ = *p++;
+ }
+ *q = '\0';
+ if (q == wfile)
+ error(COMPILE, "no wfile specified");
+ s->wfile = strdup(wfile);
+ if (aflag)
+ pledge_wpath = 1;
+ else if ((s->wfd = open(wfile,
+ O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
+ DEFFILEMODE)) == -1)
+ error(FATAL, "%s: %s", wfile, strerror(errno));
+ return (p);
+ default:
+ error(COMPILE,
+ "bad flag in substitute command: '%c'", *p);
+ break;
+ }
+ p++;
+ }
+}
+
+/*
+ * Compile a translation set of strings into a lookup table.
+ */
+static char *
+compile_tr(char *p, char **transtab)
+{
+ int i;
+ char *lt, *op, *np;
+ char *old = NULL, *new = NULL;
+
+ if (*p == '\0' || *p == '\\')
+ error(COMPILE,
+"transform pattern can not be delimited by newline or backslash");
+ old = xmalloc(strlen(p) + 1);
+ p = compile_delimited(p, old, 1);
+ if (p == NULL) {
+ error(COMPILE, "unterminated transform source string");
+ goto bad;
+ }
+ new = xmalloc(strlen(p) + 1);
+ p = compile_delimited(--p, new, 1);
+ if (p == NULL) {
+ error(COMPILE, "unterminated transform target string");
+ goto bad;
+ }
+ EATSPACE();
+ if (strlen(new) != strlen(old)) {
+ error(COMPILE, "transform strings are not the same length");
+ goto bad;
+ }
+ /* We assume characters are 8 bits */
+ lt = xmalloc(UCHAR_MAX + 1);
+ for (i = 0; i <= UCHAR_MAX; i++)
+ lt[i] = (char)i;
+ for (op = old, np = new; *op; op++, np++)
+ lt[(u_char)*op] = *np;
+ *transtab = lt;
+ free(old);
+ free(new);
+ return (p);
+bad:
+ free(old);
+ free(new);
+ return (NULL);
+}
+
+/*
+ * Compile the text following an a, c, or i command.
+ */
+static char *
+compile_text(void)
+{
+ size_t asize, size;
+ int esc_nl;
+ char *lbuf, *text, *p, *op, *s;
+ size_t bufsize;
+
+ lbuf = text = NULL;
+ asize = size = 0;
+ while ((p = cu_fgets(&lbuf, &bufsize))) {
+ size_t len = ROUNDLEN(strlen(p) + 1);
+ if (asize - size < len) {
+ do {
+ asize += len;
+ } while (asize - size < len);
+ text = xrealloc(text, asize);
+ }
+ op = s = text + size;
+ for (esc_nl = 0; *p != '\0'; p++) {
+ if (*p == '\\' && p[1] != '\0' && *++p == '\n')
+ esc_nl = 1;
+ *s++ = *p;
+ }
+ size += s - op;
+ if (!esc_nl) {
+ *s = '\0';
+ break;
+ }
+ }
+ free(lbuf);
+ text = xrealloc(text, size + 1);
+ text[size] = '\0';
+ return (text);
+}
+
+/*
+ * Get an address and return a pointer to the first character after
+ * it. Fill the structure pointed to according to the address.
+ */
+static char *
+compile_addr(char *p, struct s_addr *a)
+{
+ char *end;
+
+ switch (*p) {
+ case '\\': /* Context address */
+ ++p;
+ /* FALLTHROUGH */
+ case '/': /* Context address */
+ p = compile_re(p, &a->u.r);
+ if (p == NULL)
+ error(COMPILE, "unterminated regular expression");
+ a->type = AT_RE;
+ return (p);
+
+ case '$': /* Last line */
+ a->type = AT_LAST;
+ return (p + 1);
+ /* Line number */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ a->type = AT_LINE;
+ a->u.l = strtoul(p, &end, 10);
+ return (end);
+ default:
+ error(COMPILE, "expected context address");
+ return (NULL);
+ }
+}
+
+/*
+ * duptoeol --
+ * Return a copy of all the characters up to \n or \0.
+ */
+static char *
+duptoeol(char *s, const char *ctype, char **semi)
+{
+ size_t len;
+ int ws;
+ char *start;
+
+ ws = 0;
+ if (semi) {
+ for (start = s; *s != '\0' && *s != '\n' && *s != ';'; ++s)
+ ws = isspace((unsigned char)*s);
+ } else {
+ for (start = s; *s != '\0' && *s != '\n'; ++s)
+ ws = isspace((unsigned char)*s);
+ *s = '\0';
+ }
+ if (ws)
+ warning("whitespace after %s", ctype);
+ len = s - start + 1;
+ if (semi)
+ *semi = s;
+ s = xmalloc(len);
+ strlcpy(s, start, len);
+ return (s);
+}
+
+/*
+ * Convert goto label names to addresses, and count a and r commands, in
+ * the given subset of the script. Free the memory used by labels in b
+ * and t commands (but not by :).
+ *
+ * TODO: Remove } nodes
+ */
+static void
+fixuplabel(struct s_command *cp, struct s_command *end)
+{
+
+ for (; cp != end; cp = cp->next)
+ switch (cp->code) {
+ case 'a':
+ case 'r':
+ appendnum++;
+ break;
+ case 'b':
+ case 't':
+ /* Resolve branch target. */
+ if (cp->t == NULL) {
+ cp->u.c = NULL;
+ break;
+ }
+ if ((cp->u.c = findlabel(cp->t)) == NULL)
+ error(COMPILE, "undefined label '%s'", cp->t);
+ free(cp->t);
+ break;
+ case '{':
+ /* Do interior commands. */
+ fixuplabel(cp->u.c, cp->next);
+ break;
+ }
+}
+
+/*
+ * Associate the given command label for later lookup.
+ */
+static void
+enterlabel(struct s_command *cp)
+{
+ struct labhash **lhp, *lh;
+ u_char *p;
+ u_int h, c;
+
+ for (h = 0, p = (u_char *)cp->t; (c = *p) != 0; p++)
+ h = (h << 5) + h + c;
+ lhp = &labels[h & LHMASK];
+ for (lh = *lhp; lh != NULL; lh = lh->lh_next)
+ if (lh->lh_hash == h && strcmp(cp->t, lh->lh_cmd->t) == 0)
+ error(COMPILE, "duplicate label '%s'", cp->t);
+ lh = xmalloc(sizeof *lh);
+ lh->lh_next = *lhp;
+ lh->lh_hash = h;
+ lh->lh_cmd = cp;
+ lh->lh_ref = 0;
+ *lhp = lh;
+}
+
+/*
+ * Find the label contained in the command l in the command linked
+ * list cp. L is excluded from the search. Return NULL if not found.
+ */
+static struct s_command *
+findlabel(char *name)
+{
+ struct labhash *lh;
+ u_char *p;
+ u_int h, c;
+
+ for (h = 0, p = (u_char *)name; (c = *p) != 0; p++)
+ h = (h << 5) + h + c;
+ for (lh = labels[h & LHMASK]; lh != NULL; lh = lh->lh_next) {
+ if (lh->lh_hash == h && strcmp(name, lh->lh_cmd->t) == 0) {
+ lh->lh_ref = 1;
+ return (lh->lh_cmd);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Warn about any unused labels. As a side effect, release the label hash
+ * table space.
+ */
+static void
+uselabel(void)
+{
+ struct labhash *lh, *next;
+ int i;
+
+ for (i = 0; i < LHSZ; i++) {
+ for (lh = labels[i]; lh != NULL; lh = next) {
+ next = lh->lh_next;
+ if (!lh->lh_ref)
+ warning("unused label '%s'",
+ lh->lh_cmd->t);
+ free(lh);
+ }
+ }
+}
diff --git a/package/toolbox/src/sed/defs.h b/package/toolbox/src/sed/defs.h
new file mode 100644
index 000000000..14634a49a
--- /dev/null
+++ b/package/toolbox/src/sed/defs.h
@@ -0,0 +1,147 @@
+/** $MirOS: src/usr.bin/sed/defs.h,v 1.3 2017/11/20 01:23:56 tg Exp $ */
+/* $OpenBSD: defs.h,v 1.8 2017/01/20 10:26:16 krw Exp $ */
+/*-
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)defs.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Types of address specifications
+ */
+enum e_atype {
+ AT_RE, /* Line that match RE */
+ AT_LINE, /* Specific line */
+ AT_LAST, /* Last line */
+};
+
+/*
+ * Format of an address
+ */
+struct s_addr {
+ enum e_atype type; /* Address type */
+ union {
+ u_long l; /* Line number */
+ regex_t *r; /* Regular expression */
+ } u;
+};
+
+/*
+ * Substitution command
+ */
+struct s_subst {
+ int n; /* Occurrence to subst. */
+ int p; /* True if p flag */
+ char *wfile; /* NULL if no wfile */
+ int wfd; /* Cached file descriptor */
+ regex_t *re; /* Regular expression */
+ size_t maxbref; /* Largest backreference. */
+ u_long linenum; /* Line number. */
+ char *new; /* Replacement text */
+};
+
+
+/*
+ * An internally compiled command.
+ * Initialy, label references are stored in t, on a second pass they
+ * are updated to pointers.
+ */
+struct s_command {
+ struct s_command *next; /* Pointer to next command */
+ struct s_addr *a1, *a2; /* Start and end address */
+ char *t; /* Text for : a c i r w */
+ union {
+ struct s_command *c; /* Command(s) for b t { */
+ struct s_subst *s; /* Substitute command */
+ u_char *y; /* Replace command array */
+ int fd; /* File descriptor for w */
+ } u;
+ char code; /* Command code */
+ u_int nonsel:1; /* True if ! */
+ u_int inrange:1; /* True if in range */
+};
+
+/*
+ * Types of command arguments recognised by the parser
+ */
+enum e_args {
+ EMPTY, /* d D g G h H l n N p P q x = \0 */
+ TEXT, /* a c i */
+ NONSEL, /* ! */
+ GROUP, /* { */
+ ENDGROUP, /* } */
+ COMMENT, /* # */
+ BRANCH, /* b t */
+ LABEL, /* : */
+ RFILE, /* r */
+ WFILE, /* w */
+ SUBST, /* s */
+ TR /* y */
+};
+
+/*
+ * Structure containing things to append before a line is read
+ */
+struct s_appends {
+ enum {AP_STRING, AP_FILE} type;
+ char *s;
+ size_t len;
+};
+
+enum e_spflag {
+ APPEND, /* Append to the contents. */
+ REPLACE, /* Replace the contents. */
+};
+
+/*
+ * Structure for a space (process, hold, otherwise).
+ */
+typedef struct {
+ char *space; /* Current space pointer. */
+ size_t len; /* Current length. */
+ int deleted; /* If deleted. */
+ int append_newline; /* If originally terminated by \n. */
+ char *back; /* Backing memory. */
+ size_t blen; /* Backing memory length. */
+} SPACE;
+
+/*
+ * Error severity codes:
+ */
+#define FATAL 1 /* Exit immediately with 1 */
+#define COMPILE 2 /* Print error, count and finish script */
+
+/*
+ * Round up to the nearest multiple of _POSIX2_LINE_MAX
+ */
+#define ROUNDLEN(x) \
+ (((x) + _POSIX2_LINE_MAX - 1) & ~(_POSIX2_LINE_MAX - 1))
diff --git a/package/toolbox/src/sed/extern.h b/package/toolbox/src/sed/extern.h
new file mode 100644
index 000000000..01ede9406
--- /dev/null
+++ b/package/toolbox/src/sed/extern.h
@@ -0,0 +1,65 @@
+/** $MirOS: src/usr.bin/sed/extern.h,v 1.3 2017/11/20 01:23:57 tg Exp $ */
+/* $OpenBSD: extern.h,v 1.13 2017/08/01 18:05:53 martijn Exp $ */
+/*-
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+extern struct s_command *prog;
+extern struct s_appends *appends;
+extern regmatch_t *match;
+extern size_t maxnsub;
+extern u_long linenum;
+extern size_t appendnum;
+extern int Eflag, aflag, eflag, nflag;
+extern int pledge_wpath, pledge_rpath;
+extern const char *fname, *outfname;
+extern FILE *infile, *outfile;
+
+void cfclose(struct s_command *, struct s_command *);
+void compile(void);
+void cspace(SPACE *, const char *, size_t, enum e_spflag);
+char *cu_fgets(char **, size_t *);
+void error(int, const char *, ...)
+ __dead
+ __attribute__((__format__(__printf__, 2, 3)));
+void warning(const char *, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+int mf_fgets(SPACE *, enum e_spflag);
+int lastline(void);
+void process(void);
+void resetranges(void);
+char *strregerror(int, regex_t *);
+void *xmalloc(size_t);
+void *xreallocarray(void *, size_t, size_t);
+void *xrealloc(void *, size_t);
diff --git a/package/toolbox/src/sed/main.c b/package/toolbox/src/sed/main.c
new file mode 100644
index 000000000..afa10d4df
--- /dev/null
+++ b/package/toolbox/src/sed/main.c
@@ -0,0 +1,523 @@
+/* $OpenBSD: main.c,v 1.35 2017/08/01 18:05:53 martijn Exp $ */
+
+/*-
+ * Copyright (c) 2016, 2017
+ * mirabilos <m@mirbsd.org>
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <regex.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include "defs.h"
+#include "extern.h"
+
+__RCSID("$MirOS: src/usr.bin/sed/main.c,v 1.3 2017/11/20 01:23:57 tg Exp $");
+
+/*
+ * Linked list of units (strings and files) to be compiled
+ */
+struct s_compunit {
+ struct s_compunit *next;
+ enum e_cut {CU_FILE, CU_STRING} type;
+ char *s; /* Pointer to string or fname */
+};
+
+/*
+ * Linked list pointer to compilation units and pointer to current
+ * next pointer.
+ */
+static struct s_compunit *script, **cu_nextp = &script;
+
+/*
+ * Linked list of files to be processed
+ */
+struct s_flist {
+ char *fname;
+ struct s_flist *next;
+};
+
+/*
+ * Linked list pointer to files and pointer to current
+ * next pointer.
+ */
+static struct s_flist *files, **fl_nextp = &files;
+
+FILE *infile; /* Current input file */
+FILE *outfile; /* Current output file */
+
+int Eflag, aflag, eflag, nflag;
+static int rval; /* Exit status */
+
+/*
+ * Current file and line number; line numbers restart across compilation
+ * units, but span across input files. The latter is optional if editing
+ * in place.
+ */
+const char *fname; /* File name. */
+const char *outfname; /* Output file name */
+static char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */
+static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */
+const char *inplace; /* Inplace edit file extension */
+u_long linenum;
+
+static void add_compunit(enum e_cut, char *);
+static void add_file(char *);
+static int next_files_have_lines(void);
+
+int termwidth;
+
+int pledge_wpath, pledge_rpath;
+
+int
+main(int argc, char *argv[])
+{
+ int c, fflag;
+
+ fflag = 0;
+ inplace = NULL;
+ while ((c = getopt(argc, argv, "Eae:f:i::nru")) != -1)
+ switch (c) {
+ case 'E':
+ case 'r':
+ Eflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ add_compunit(CU_STRING, optarg);
+ break;
+ case 'f':
+ fflag = 1;
+ add_compunit(CU_FILE, optarg);
+ break;
+ case 'i':
+ inplace = optarg ? optarg : "";
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'u':
+ setvbuf(stdout, NULL, _IOLBF, 0);
+ break;
+ default:
+ case '?':
+ (void)fprintf(stderr,
+ "usage: sed [-aEnru] [-i[extension]] command [file ...]\n"
+ " sed [-aEnru] [-e command] [-f command_file] [-i[extension]] [file ...]\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+
+ termwidth = 60;
+
+#if defined(__OpenBSD__) && !defined(__MirBSD__)
+ if (inplace != NULL) {
+ if (pledge("stdio rpath wpath cpath fattr chown", NULL) == -1)
+ error(FATAL, "pledge: %s", strerror(errno));
+ } else {
+ if (pledge("stdio rpath wpath cpath", NULL) == -1)
+ error(FATAL, "pledge: %s", strerror(errno));
+ }
+#endif
+
+ /* First usage case; script is the first arg */
+ if (!eflag && !fflag && *argv) {
+ add_compunit(CU_STRING, *argv);
+ argv++;
+ }
+
+ compile();
+
+ /* Continue with first and start second usage */
+ if (*argv) {
+#if defined(__OpenBSD__) && !defined(__MirBSD__)
+ if (!pledge_wpath && inplace == NULL) {
+ if (pledge("stdio rpath", NULL) == -1)
+ error(FATAL, "pledge: %s", strerror(errno));
+ }
+#endif
+ for (; *argv; argv++)
+ add_file(*argv);
+ } else {
+#if defined(__OpenBSD__) && !defined(__MirBSD__)
+ if (!pledge_wpath && !pledge_rpath) {
+ if (pledge("stdio", NULL) == -1)
+ error(FATAL, "pledge: %s", strerror(errno));
+ } else if (pledge_rpath) {
+ if (pledge("stdio rpath", NULL) == -1)
+ error(FATAL, "pledge: %s", strerror(errno));
+ } else if (pledge_wpath) {
+ if (pledge("stdio wpath cpath", NULL) == -1)
+ error(FATAL, "pledge: %s", strerror(errno));
+ }
+#endif
+ add_file(NULL);
+ }
+ process();
+ cfclose(prog, NULL);
+ if (fclose(stdout))
+ error(FATAL, "stdout: %s", strerror(errno));
+ exit (rval);
+}
+
+/*
+ * Like fgets, but go through the chain of compilation units chaining them
+ * together. Empty strings and files are ignored.
+ */
+char *
+cu_fgets(char **outbuf, size_t *outsize)
+{
+ static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
+ static FILE *f; /* Current open file */
+ static char *s; /* Current pointer inside string */
+ static char string_ident[30];
+ size_t len;
+ char *p;
+
+ if (*outbuf == NULL)
+ *outsize = 0;
+
+again:
+ switch (state) {
+ case ST_EOF:
+ if (script == NULL)
+ goto cu_fgets_nilreturn;
+ linenum = 0;
+ switch (script->type) {
+ case CU_FILE:
+ if ((f = fopen(script->s, "r")) == NULL)
+ error(FATAL,
+ "%s: %s", script->s, strerror(errno));
+ fname = script->s;
+ state = ST_FILE;
+ goto again;
+ case CU_STRING:
+ if (((size_t)snprintf(string_ident,
+ sizeof(string_ident), "\"%s\"", script->s)) >=
+ sizeof(string_ident))
+ strlcpy(string_ident +
+ sizeof(string_ident) - 6, " ...\"", 5);
+ fname = string_ident;
+ s = script->s;
+ state = ST_STRING;
+ goto again;
+ }
+ case ST_FILE:
+ if ((p = fgetln(f, &len)) != NULL) {
+ linenum++;
+ if (len >= *outsize) {
+ free(*outbuf);
+ *outsize = ROUNDLEN(len + 1);
+ *outbuf = xmalloc(*outsize);
+ }
+ memcpy(*outbuf, p, len);
+ (*outbuf)[len] = '\0';
+ if (linenum == 1 && p[0] == '#' && p[1] == 'n')
+ nflag = 1;
+ return (*outbuf);
+ }
+ script = script->next;
+ (void)fclose(f);
+ state = ST_EOF;
+ goto again;
+ case ST_STRING:
+ if (linenum == 0 && s[0] == '#' && s[1] == 'n')
+ nflag = 1;
+ p = *outbuf;
+ len = *outsize;
+ for (;;) {
+ if (len <= 1) {
+ *outbuf = xrealloc(*outbuf,
+ *outsize + _POSIX2_LINE_MAX);
+ p = *outbuf + *outsize - len;
+ len += _POSIX2_LINE_MAX;
+ *outsize += _POSIX2_LINE_MAX;
+ }
+ switch (*s) {
+ case '\0':
+ state = ST_EOF;
+ if (s == script->s) {
+ script = script->next;
+ goto again;
+ } else {
+ script = script->next;
+ *p = '\0';
+ linenum++;
+ return (*outbuf);
+ }
+ case '\n':
+ *p++ = '\n';
+ *p = '\0';
+ s++;
+ linenum++;
+ return (*outbuf);
+ default:
+ *p++ = *s++;
+ len--;
+ }
+ }
+ }
+ /* NOTREACHED */
+ /* but GCC doesn't care, so: */
+ cu_fgets_nilreturn:
+ return (NULL);
+}
+
+/*
+ * Like fgets, but go through the list of files chaining them together.
+ * Set len to the length of the line.
+ */
+int
+mf_fgets(SPACE *sp, enum e_spflag spflag)
+{
+ struct stat sb;
+ size_t len;
+ char *p;
+ int c, fd;
+ static int firstfile;
+
+ if (infile == NULL) {
+ /* stdin? */
+ if (files->fname == NULL) {
+ if (inplace != NULL)
+ error(FATAL, "-i may not be used with stdin");
+ infile = stdin;
+ fname = "stdin";
+ outfile = stdout;
+ outfname = "stdout";
+ }
+
+ firstfile = 1;
+ }
+
+ for (;;) {
+ if (infile != NULL && (c = getc(infile)) != EOF) {
+ (void)ungetc(c, infile);
+ break;
+ }
+ /* If we are here then either eof or no files are open yet */
+ if (infile == stdin) {
+ sp->len = 0;
+ return (0);
+ }
+ if (infile != NULL) {
+ fclose(infile);
+ if (*oldfname != '\0') {
+ if (rename(fname, oldfname) != 0) {
+ warning("rename()");
+ unlink(tmpfname);
+ exit(1);
+ }
+ *oldfname = '\0';
+ }
+ if (*tmpfname != '\0') {
+ if (outfile != NULL && outfile != stdout)
+ fclose(outfile);
+ outfile = NULL;
+ rename(tmpfname, fname);
+ *tmpfname = '\0';
+ }
+ outfname = NULL;
+ }
+ if (firstfile == 0)
+ files = files->next;
+ else
+ firstfile = 0;
+ if (files == NULL) {
+ sp->len = 0;
+ return (0);
+ }
+ fname = files->fname;
+ if (inplace != NULL) {
+ char *tmpdirname;
+
+ if (lstat(fname, &sb) != 0)
+ error(FATAL, "%s: %s", fname,
+ strerror(errno ? errno : EIO));
+ if (!S_ISREG(sb.st_mode))
+ error(FATAL, "%s: %s %s", fname,
+ "in-place editing only",
+ "works for regular files");
+ if (*inplace != '\0') {
+ strlcpy(oldfname, fname,
+ sizeof(oldfname));
+ len = strlcat(oldfname, inplace,
+ sizeof(oldfname));
+ if (len > sizeof(oldfname))
+ error(FATAL, "%s: name too long", fname);
+ }
+ len = snprintf(tmpfname, sizeof(tmpfname), "%s/sedXXXXXXXXXX",
+ dirname(tmpdirname = strdup(fname)));
+ free(tmpdirname);
+ if (len >= sizeof(tmpfname))
+ error(FATAL, "%s: name too long", fname);
+ if ((fd = mkstemp(tmpfname)) == -1)
+ error(FATAL, "%s: %s", fname, strerror(errno));
+ if ((outfile = fdopen(fd, "w")) == NULL) {
+ unlink(tmpfname);
+ error(FATAL, "%s", fname);
+ }
+ fchown(fileno(outfile), sb.st_uid, sb.st_gid);
+ fchmod(fileno(outfile), sb.st_mode & ALLPERMS);
+ outfname = tmpfname;
+ linenum = 0;
+ resetranges();
+ } else {
+ outfile = stdout;
+ outfname = "stdout";
+ }
+ if ((infile = fopen(fname, "r")) == NULL) {
+ warning("%s", strerror(errno));
+ rval = 1;
+ continue;
+ }
+ }
+
+ /*
+ * We are here only when infile is open and we still have something
+ * to read from it.
+ *
+ * Use fgetln so that we can handle essentially infinite input data.
+ * Can't use the pointer into the stdio buffer as the process space
+ * because the ungetc() can cause it to move.
+ */
+ p = fgetln(infile, &len);
+ if (ferror(infile))
+ error(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
+ if (len != 0 && p[len - 1] == '\n') {
+ sp->append_newline = 1;
+ len--;
+ } else if (!lastline()) {
+ sp->append_newline = 1;
+ } else {
+ sp->append_newline = 0;
+ }
+ cspace(sp, p, len, spflag);
+
+ linenum++;
+
+ return (1);
+}
+
+/*
+ * Add a compilation unit to the linked list
+ */
+static void
+add_compunit(enum e_cut type, char *s)
+{
+ struct s_compunit *cu;
+
+ cu = xmalloc(sizeof(struct s_compunit));
+ cu->type = type;
+ cu->s = s;
+ cu->next = NULL;
+ *cu_nextp = cu;
+ cu_nextp = &cu->next;
+}
+
+/*
+ * Add a file to the linked list
+ */
+static void
+add_file(char *s)
+{
+ struct s_flist *fp;
+
+ fp = xmalloc(sizeof(struct s_flist));
+ fp->next = NULL;
+ *fl_nextp = fp;
+ fp->fname = s;
+ fl_nextp = &fp->next;
+}
+
+
+static int
+next_files_have_lines(void)
+{
+ struct s_flist *file;
+ FILE *file_fd;
+ int ch;
+
+ file = files;
+ while ((file = file->next) != NULL) {
+ if ((file_fd = fopen(file->fname, "r")) == NULL)
+ continue;
+
+ if ((ch = getc(file_fd)) != EOF) {
+ /*
+ * This next file has content, therefore current
+ * file doesn't contains the last line.
+ */
+ ungetc(ch, file_fd);
+ fclose(file_fd);
+ return (1);
+ }
+ fclose(file_fd);
+ }
+ return (0);
+}
+
+int
+lastline(void)
+{
+ int ch;
+
+ if (feof(infile)) {
+ return !(
+ (inplace == NULL) &&
+ next_files_have_lines());
+ }
+ if ((ch = getc(infile)) == EOF) {
+ return !(
+ (inplace == NULL) &&
+ next_files_have_lines());
+ }
+ ungetc(ch, infile);
+ return (0);
+}
diff --git a/package/toolbox/src/sed/misc.c b/package/toolbox/src/sed/misc.c
new file mode 100644
index 000000000..1ed230014
--- /dev/null
+++ b/package/toolbox/src/sed/misc.c
@@ -0,0 +1,166 @@
+/* $OpenBSD: misc.c,v 1.12 2017/01/20 10:26:16 krw Exp $ */
+
+/*-
+ * Copyright (c) 2016
+ * mirabilos <m@mirbsd.org>
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * 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.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "defs.h"
+#include "extern.h"
+
+__RCSID("$MirOS: src/usr.bin/sed/misc.c,v 1.3 2017/11/20 01:23:57 tg Exp $");
+
+/*
+ * malloc with result test
+ */
+void *
+xmalloc(size_t size)
+{
+ void *p;
+
+ if ((p = malloc(size)) == NULL)
+ error(FATAL, "%s", strerror(errno));
+ return (p);
+}
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
+
+void *
+xreallocarray(void *o, size_t nmemb, size_t size)
+{
+ void *p;
+
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && __SIZE_MAX__ / nmemb < size) {
+ p = NULL;
+ errno = ENOMEM;
+ } else
+ p = realloc(o, size * nmemb);
+
+ if (p == NULL)
+ error(FATAL, "%s", strerror(errno));
+ return (p);
+}
+
+/*
+ * realloc with result test
+ */
+void *
+xrealloc(void *p, size_t size)
+{
+
+ if ((p = realloc(p, size)) == NULL)
+ error(FATAL, "%s", strerror(errno));
+ return (p);
+}
+
+/*
+ * Return a string for a regular expression error passed. This is a overkill,
+ * because of the silly semantics of regerror (we can never know the size of
+ * the buffer).
+ */
+char *
+strregerror(int errcode, regex_t *preg)
+{
+ static char *oe;
+ size_t s;
+
+ free(oe);
+ s = regerror(errcode, preg, NULL, 0);
+ oe = xmalloc(s);
+ (void)regerror(errcode, preg, oe, s);
+ return (oe);
+}
+
+/*
+ * Error reporting function
+ */
+__dead void
+error(int severity, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)fprintf(stderr, "sed: ");
+ switch (severity) {
+ case COMPILE:
+ (void)fprintf(stderr, "%lu: %s: ", linenum, fname);
+ }
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ exit(1);
+}
+
+void
+warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)fprintf(stderr, "sed: ");
+ (void)fprintf(stderr, "%lu: %s: ", linenum, fname);
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+}
diff --git a/package/toolbox/src/sed/process.c b/package/toolbox/src/sed/process.c
new file mode 100644
index 000000000..b2b2a8717
--- /dev/null
+++ b/package/toolbox/src/sed/process.c
@@ -0,0 +1,642 @@
+/* $OpenBSD: process.c,v 1.32 2017/02/22 14:09:09 tom Exp $ */
+
+/*-
+ * Copyright (c) 2015
+ * mirabilos <m@mirbsd.org>
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+__SCCSID("@(#)process.c 8.1 (Berkeley) 6/6/93");
+__RCSID("$MirOS: src/usr.bin/sed/process.c,v 1.5 2017/11/20 01:23:57 tg Exp $");
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "defs.h"
+#include "extern.h"
+
+static SPACE HS, PS, SS;
+#define pd PS.deleted
+#define ps PS.space
+#define psl PS.len
+#define psanl PS.append_newline
+#define hs HS.space
+#define hsl HS.len
+
+static inline int applies(struct s_command *);
+static void flush_appends(void);
+static void lputs(char *);
+static inline int regexec_e(regex_t *, const char *, int, int, size_t,
+ size_t);
+static void regsub(SPACE *, char *, char *);
+static int substitute(struct s_command *);
+
+struct s_appends *appends; /* Array of pointers to strings to append. */
+static size_t appendx; /* Index into appends array. */
+size_t appendnum; /* Size of appends array. */
+
+static int lastaddr; /* Set by applies if last address of a range. */
+static int sdone; /* If any substitutes since last line input. */
+ /* Iov structure for 'w' commands. */
+static regex_t *defpreg;
+size_t maxnsub;
+regmatch_t *match;
+
+#define OUT() do {\
+ fwrite(ps, 1, psl, outfile);\
+ if (psanl) fputc('\n', outfile);\
+} while (0)
+
+void
+process(void)
+{
+ struct s_command *cp;
+ SPACE tspace;
+ size_t len, oldpsl;
+ char *p;
+
+ for (linenum = 0; mf_fgets(&PS, REPLACE);) {
+ pd = 0;
+top:
+ cp = prog;
+redirect:
+ while (cp != NULL) {
+ if (!applies(cp)) {
+ cp = cp->next;
+ continue;
+ }
+ switch (cp->code) {
+ case '{':
+ cp = cp->u.c;
+ goto redirect;
+ case 'a':
+ if (appendx >= appendnum) {
+ appends = xreallocarray(appends,
+ appendnum,
+ 2 * sizeof(struct s_appends));
+ appendnum *= 2;
+ }
+ appends[appendx].type = AP_STRING;
+ appends[appendx].s = cp->t;
+ appends[appendx].len = strlen(cp->t);
+ appendx++;
+ break;
+ case 'b':
+ cp = cp->u.c;
+ goto redirect;
+ case 'c':
+ pd = 1;
+ psl = 0;
+ if (cp->a2 == NULL || lastaddr || lastline())
+ (void)fprintf(outfile, "%s", cp->t);
+ break;
+ case 'd':
+ pd = 1;
+ goto new;
+ case 'D':
+ if (pd)
+ goto new;
+ if (psl == 0 ||
+ (p = memchr(ps, '\n', psl)) == NULL) {
+ pd = 1;
+ goto new;
+ } else {
+ psl -= (p + 1) - ps;
+ memmove(ps, p + 1, psl);
+ goto top;
+ }
+ case 'g':
+ cspace(&PS, hs, hsl, REPLACE);
+ break;
+ case 'G':
+ cspace(&PS, "\n", 1, 0);
+ cspace(&PS, hs, hsl, 0);
+ break;
+ case 'h':
+ cspace(&HS, ps, psl, REPLACE);
+ break;
+ case 'H':
+ cspace(&HS, "\n", 1, 0);
+ cspace(&HS, ps, psl, 0);
+ break;
+ case 'i':
+ (void)fprintf(outfile, "%s", cp->t);
+ break;
+ case 'l':
+ lputs(ps);
+ break;
+ case 'n':
+ if (!nflag && !pd)
+ OUT();
+ flush_appends();
+ if (!mf_fgets(&PS, REPLACE))
+ exit(0);
+ pd = 0;
+ break;
+ case 'N':
+ flush_appends();
+ cspace(&PS, "\n", 1, 0);
+ if (!mf_fgets(&PS, 0))
+ exit(0);
+ break;
+ case 'p':
+ if (pd)
+ break;
+ OUT();
+ break;
+ case 'P':
+ if (pd)
+ break;
+ if ((p = memchr(ps, '\n', psl)) != NULL) {
+ oldpsl = psl;
+ psl = p - ps;
+ psanl = 1;
+ OUT();
+ psl = oldpsl;
+ } else {
+ OUT();
+ }
+ break;
+ case 'q':
+ if (!nflag && !pd)
+ OUT();
+ flush_appends();
+ exit(0);
+ case 'r':
+ if (appendx >= appendnum) {
+ appends = xreallocarray(appends,
+ appendnum,
+ 2 * sizeof(struct s_appends));
+ appendnum *= 2;
+ }
+ appends[appendx].type = AP_FILE;
+ appends[appendx].s = cp->t;
+ appends[appendx].len = strlen(cp->t);
+ appendx++;
+ break;
+ case 's':
+ sdone |= substitute(cp);
+ break;
+ case 't':
+ if (sdone) {
+ sdone = 0;
+ cp = cp->u.c;
+ goto redirect;
+ }
+ break;
+ case 'w':
+ if (pd)
+ break;
+ if (cp->u.fd == -1 && (cp->u.fd = open(cp->t,
+ O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
+ DEFFILEMODE)) == -1)
+ error(FATAL, "%s: %s",
+ cp->t, strerror(errno));
+ if ((size_t)write(cp->u.fd, ps, psl) != psl ||
+ write(cp->u.fd, "\n", 1) != 1)
+ error(FATAL, "%s: %s",
+ cp->t, strerror(errno));
+ break;
+ case 'x':
+ if (hs == NULL)
+ cspace(&HS, "", 0, REPLACE);
+ tspace = PS;
+ PS = HS;
+ psanl = tspace.append_newline;
+ HS = tspace;
+ break;
+ case 'y':
+ if (pd || psl == 0)
+ break;
+ for (p = ps, len = psl; len--; ++p)
+ *p = cp->u.y[(unsigned char)*p];
+ break;
+ case ':':
+ case '}':
+ break;
+ case '=':
+ (void)fprintf(outfile, "%lu\n", linenum);
+ }
+ cp = cp->next;
+ } /* for all cp */
+
+new: if (!nflag && !pd)
+ OUT();
+ flush_appends();
+ } /* for all lines */
+}
+
+/*
+ * TRUE if the address passed matches the current program state
+ * (lastline, linenumber, ps).
+ */
+#define MATCH(a) \
+ (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, 0, psl) : \
+ (a)->type == AT_LINE ? linenum == (a)->u.l : lastline()
+
+/*
+ * Return TRUE if the command applies to the current line. Sets the inrange
+ * flag to process ranges. Interprets the non-select (``!'') flag.
+ */
+static inline int
+applies(struct s_command *cp)
+{
+ int r;
+
+ lastaddr = 0;
+ if (cp->a1 == NULL && cp->a2 == NULL)
+ r = 1;
+ else if (cp->a2)
+ if (cp->inrange) {
+ if (MATCH(cp->a2)) {
+ cp->inrange = 0;
+ lastaddr = 1;
+ }
+ r = 1;
+ } else if (MATCH(cp->a1)) {
+ /*
+ * If the second address is a number less than or
+ * equal to the line number first selected, only
+ * one line shall be selected.
+ * -- POSIX 1003.2
+ */
+ if (cp->a2->type == AT_LINE &&
+ linenum >= cp->a2->u.l)
+ lastaddr = 1;
+ else
+ cp->inrange = 1;
+ r = 1;
+ } else
+ r = 0;
+ else
+ r = MATCH(cp->a1);
+ return (cp->nonsel ? !r : r);
+}
+
+/*
+ * Reset all inrange markers.
+ */
+void
+resetranges(void)
+{
+ struct s_command *cp;
+
+ for (cp = prog; cp; cp = cp->code == '{' ? cp->u.c : cp->next)
+ if (cp->a2)
+ cp->inrange = 0;
+}
+
+/*
+ * substitute --
+ * Do substitutions in the pattern space. Currently, we build a
+ * copy of the new pattern space in the substitute space structure
+ * and then swap them.
+ */
+static int
+substitute(struct s_command *cp)
+{
+ SPACE tspace;
+ regex_t *re;
+ regoff_t slen;
+ int n, lastempty;
+ size_t le = 0;
+ char *s;
+
+ s = ps;
+ re = cp->u.s->re;
+ if (re == NULL) {
+ if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) {
+ linenum = cp->u.s->linenum;
+ error(COMPILE, "\\%zu not defined in the RE",
+ cp->u.s->maxbref);
+ }
+ }
+ if (!regexec_e(re, ps, 0, 0, 0, psl))
+ return (0);
+
+ SS.len = 0; /* Clean substitute space. */
+ slen = psl;
+ n = cp->u.s->n;
+ lastempty = 1;
+
+ do {
+ /* Copy the leading retained string. */
+ if (n <= 1 && (match[0].rm_so > le))
+ cspace(&SS, s, match[0].rm_so - le, APPEND);
+
+ /* Skip zero-length matches right after other matches. */
+ if (lastempty || (match[0].rm_so - le) ||
+ match[0].rm_so != match[0].rm_eo) {
+ if (n <= 1) {
+ /* Want this match: append replacement. */
+ regsub(&SS, ps, cp->u.s->new);
+ if (n == 1)
+ n = -1;
+ } else {
+ /* Want a later match: append original. */
+ if (match[0].rm_eo - le)
+ cspace(&SS, s, match[0].rm_eo - le,
+ APPEND);
+ n--;
+ }
+ }
+
+ /* Move past this match. */
+ s = ps + match[0].rm_eo;
+ slen = psl - match[0].rm_eo;
+ le = match[0].rm_eo;
+
+ /*
+ * After a zero-length match, advance one byte,
+ * and at the end of the line, terminate.
+ */
+ if (match[0].rm_so == match[0].rm_eo) {
+ if (*s == '\0' || *s == '\n')
+ slen = -1;
+ else
+ slen--;
+ if (*s != '\0') {
+ cspace(&SS, s++, 1, APPEND);
+ le++;
+ }
+ lastempty = 1;
+ } else
+ lastempty = 0;
+
+ } while (n >= 0 && slen >= 0 &&
+ regexec_e(re, ps, REG_NOTBOL, 0, le, psl));
+
+ /* Did not find the requested number of matches. */
+ if (n > 0)
+ return (0);
+
+ /* Copy the trailing retained string. */
+ if (slen > 0)
+ cspace(&SS, s, slen, APPEND);
+
+ /*
+ * Swap the substitute space and the pattern space, and make sure
+ * that any leftover pointers into stdio memory get lost.
+ */
+ tspace = PS;
+ PS = SS;
+ psanl = tspace.append_newline;
+ SS = tspace;
+ SS.space = SS.back;
+
+ /* Handle the 'p' flag. */
+ if (cp->u.s->p)
+ OUT();
+
+ /* Handle the 'w' flag. */
+ if (cp->u.s->wfile && !pd) {
+ if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile,
+ O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1)
+ error(FATAL, "%s: %s", cp->u.s->wfile, strerror(errno));
+ if ((size_t)write(cp->u.s->wfd, ps, psl) != psl ||
+ write(cp->u.s->wfd, "\n", 1) != 1)
+ error(FATAL, "%s: %s", cp->u.s->wfile, strerror(errno));
+ }
+ return (1);
+}
+
+/*
+ * Flush append requests. Always called before reading a line,
+ * therefore it also resets the substitution done (sdone) flag.
+ */
+static void
+flush_appends(void)
+{
+ FILE *f;
+ int count;
+ size_t i;
+ char buf[8 * 1024];
+
+ for (i = 0; i < appendx; i++)
+ switch (appends[i].type) {
+ case AP_STRING:
+ fwrite(appends[i].s, sizeof(char), appends[i].len,
+ outfile);
+ break;
+ case AP_FILE:
+ /*
+ * Read files probably shouldn't be cached. Since
+ * it's not an error to read a non-existent file,
+ * it's possible that another program is interacting
+ * with the sed script through the filesystem. It
+ * would be truly bizarre, but possible. It's probably
+ * not that big a performance win, anyhow.
+ */
+ if ((f = fopen(appends[i].s, "r")) == NULL)
+ break;
+ while ((count = fread(buf, sizeof(char), sizeof(buf), f)))
+ (void)fwrite(buf, sizeof(char), count, outfile);
+ (void)fclose(f);
+ break;
+ }
+ if (ferror(outfile))
+ error(FATAL, "%s: %s", outfname, strerror(errno ? errno : EIO));
+ appendx = sdone = 0;
+}
+
+static void
+lputs(char *s)
+{
+ int count;
+ extern int termwidth;
+ const char *escapes;
+ char *p;
+
+ for (count = 0; *s; ++s) {
+ if (count >= termwidth) {
+ (void)fprintf(outfile, "\\\n");
+ count = 0;
+ }
+ if (isascii((unsigned char)*s) && isprint((unsigned char)*s)
+ && *s != '\\') {
+ (void)fputc(*s, outfile);
+ count++;
+ } else {
+ escapes = "\\\a\b\f\n\r\t\v";
+ if (*s == '\n' && s[1] == '\0') {
+ /* omit trailing newline */
+ break;
+ }
+ (void)fputc('\\', outfile);
+ if ((p = strchr(escapes, *s))) {
+ (void)fputc("\\abfnrtv"[p - escapes], outfile);
+ count += 2;
+ } else {
+ (void)fprintf(outfile, "%03o", *(u_char *)s);
+ count += 4;
+ }
+ }
+ }
+ (void)fputc('$', outfile);
+ (void)fputc('\n', outfile);
+ if (ferror(outfile))
+ error(FATAL, "%s: %s", outfname, strerror(errno ? errno : EIO));
+}
+
+static inline int
+regexec_e(regex_t *preg, const char *string, int eflags,
+ int nomatch, size_t start, size_t stop)
+{
+ int eval;
+
+ if (preg == NULL) {
+ if (defpreg == NULL)
+ error(FATAL, "first RE may not be empty");
+ } else
+ defpreg = preg;
+
+ /* Set anchors */
+ match[0].rm_so = start;
+ match[0].rm_eo = stop;
+
+ eval = regexec(defpreg, string,
+ nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND);
+ switch (eval) {
+ case 0:
+ return (1);
+ case REG_NOMATCH:
+ return (0);
+ }
+ error(FATAL, "RE error: %s", strregerror(eval, defpreg));
+}
+
+/*
+ * regsub - perform substitutions after a regexp match
+ * Based on a routine by Henry Spencer
+ */
+static void
+regsub(SPACE *sp, char *string, char *src)
+{
+ int len, no;
+ char c, *dst;
+
+#define NEEDSP(reqlen) \
+ if (sp->len + (reqlen) + 1 >= sp->blen) { \
+ size_t newlen = sp->blen + (reqlen) + 1024; \
+ sp->space = sp->back = xrealloc(sp->back, newlen); \
+ sp->blen = newlen; \
+ dst = sp->space + sp->len; \
+ }
+
+ dst = sp->space + sp->len;
+ while ((c = *src++) != '\0') {
+ if (c == '&')
+ no = 0;
+ else if (c == '\\' && isdigit((unsigned char)*src))
+ no = *src++ - '0';
+ else
+ no = -1;
+ if (no < 0) { /* Ordinary character. */
+ if (c == '\\' && (*src == '\\' || *src == '&'))
+ c = *src++;
+ NEEDSP(1);
+ *dst++ = c;
+ ++sp->len;
+ } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) {
+ len = match[no].rm_eo - match[no].rm_so;
+ NEEDSP(len);
+ memmove(dst, string + match[no].rm_so, len);
+ dst += len;
+ sp->len += len;
+ }
+ }
+ NEEDSP(1);
+ *dst = '\0';
+}
+
+/*
+ * aspace --
+ * Append the source space to the destination space, allocating new
+ * space as necessary.
+ */
+void
+cspace(SPACE *sp, const char *p, size_t len, enum e_spflag spflag)
+{
+ size_t tlen;
+
+ /* Make sure SPACE has enough memory and ramp up quickly. */
+ tlen = sp->len + len + 1;
+ if (tlen > sp->blen) {
+ size_t newlen = tlen + 1024;
+ sp->space = sp->back = xrealloc(sp->back, newlen);
+ sp->blen = newlen;
+ }
+
+ if (spflag == REPLACE)
+ sp->len = 0;
+
+ memmove(sp->space + sp->len, p, len);
+
+ sp->space[sp->len += len] = '\0';
+}
+
+/*
+ * Close all cached opened files and report any errors
+ */
+void
+cfclose(struct s_command *cp, struct s_command *end)
+{
+
+ for (; cp != end; cp = cp->next)
+ switch (cp->code) {
+ case 's':
+ if (cp->u.s->wfd != -1 && close(cp->u.s->wfd))
+ error(FATAL,
+ "%s: %s", cp->u.s->wfile, strerror(errno));
+ cp->u.s->wfd = -1;
+ break;
+ case 'w':
+ if (cp->u.fd != -1 && close(cp->u.fd))
+ error(FATAL, "%s: %s", cp->t, strerror(errno));
+ cp->u.fd = -1;
+ break;
+ case '{':
+ cfclose(cp->u.c, cp->next);
+ break;
+ }
+}
diff --git a/package/toolbox/src/setkey/Makefile b/package/toolbox/src/setkey/Makefile
new file mode 100644
index 000000000..836a8569e
--- /dev/null
+++ b/package/toolbox/src/setkey/Makefile
@@ -0,0 +1,3 @@
+PROG= setkey
+
+include ../tool.mk
diff --git a/package/toolbox/src/sleep/Makefile b/package/toolbox/src/sleep/Makefile
new file mode 100644
index 000000000..c5de1eef0
--- /dev/null
+++ b/package/toolbox/src/sleep/Makefile
@@ -0,0 +1,3 @@
+PROG= sleep
+
+include ../tool.mk
diff --git a/package/toolbox/src/src/chmod.c b/package/toolbox/src/src/chmod.c
new file mode 100644
index 000000000..1de14aa2c
--- /dev/null
+++ b/package/toolbox/src/src/chmod.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <time.h>
+
+void recurse_chmod(char* path, int mode)
+{
+ struct dirent *dp;
+ DIR *dir = opendir(path);
+ if (dir == NULL) {
+ // not a directory, carry on
+ return;
+ }
+ char *subpath = malloc(sizeof(char)*PATH_MAX);
+ int pathlen = strlen(path);
+
+ while ((dp = readdir(dir)) != NULL) {
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0) continue;
+
+ if (strlen(dp->d_name) + pathlen + 2/*NUL and slash*/ > PATH_MAX) {
+ fprintf(stderr, "Invalid path specified: too long\n");
+ exit(1);
+ }
+
+ strcpy(subpath, path);
+ strcat(subpath, "/");
+ strcat(subpath, dp->d_name);
+
+ if (chmod(subpath, mode) < 0) {
+ fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno));
+ exit(1);
+ }
+
+ recurse_chmod(subpath, mode);
+ }
+ free(subpath);
+ closedir(dir);
+}
+
+static int usage()
+{
+ fprintf(stderr, "Usage: chmod [OPTION] <MODE> <FILE>\n");
+ fprintf(stderr, " -R, --recursive change files and directories recursively\n");
+ fprintf(stderr, " --help display this help and exit\n");
+
+ return 10;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ if (argc < 3 || strcmp(argv[1], "--help") == 0) {
+ return usage();
+ }
+
+ int recursive = (strcmp(argv[1], "-R") == 0 ||
+ strcmp(argv[1], "--recursive") == 0) ? 1 : 0;
+
+ if (recursive && argc < 4) {
+ return usage();
+ }
+
+ if (recursive) {
+ argc--;
+ argv++;
+ }
+
+ int mode = 0;
+ const char* s = argv[1];
+ while (*s) {
+ if (*s >= '0' && *s <= '7') {
+ mode = (mode<<3) | (*s-'0');
+ }
+ else {
+ fprintf(stderr, "Bad mode\n");
+ return 10;
+ }
+ s++;
+ }
+
+ for (i = 2; i < argc; i++) {
+ if (chmod(argv[i], mode) < 0) {
+ fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
+ return 10;
+ }
+ if (recursive) {
+ recurse_chmod(argv[i], mode);
+ }
+ }
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/chown.c b/package/toolbox/src/src/chown.c
new file mode 100644
index 000000000..d02721718
--- /dev/null
+++ b/package/toolbox/src/src/chown.c
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <unistd.h>
+#include <time.h>
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: chown <USER>[:GROUP] <FILE1> [FILE2] ...\n");
+ return 10;
+ }
+
+ // Copy argv[1] to 'user' so we can truncate it at the period
+ // if a group id specified.
+ char user[32];
+ char *group = NULL;
+ strncpy(user, argv[1], sizeof(user));
+ if ((group = strchr(user, ':')) != NULL) {
+ *group++ = '\0';
+ } else if ((group = strchr(user, '.')) != NULL) {
+ *group++ = '\0';
+ }
+
+ // Lookup uid (and gid if specified)
+ struct passwd *pw;
+ struct group *grp = NULL;
+ uid_t uid;
+ gid_t gid = -1; // passing -1 to chown preserves current group
+
+ pw = getpwnam(user);
+ if (pw != NULL) {
+ uid = pw->pw_uid;
+ } else {
+ char* endptr;
+ uid = (int) strtoul(user, &endptr, 0);
+ if (endptr == user) { // no conversion
+ fprintf(stderr, "No such user '%s'\n", user);
+ return 10;
+ }
+ }
+
+ if (group != NULL) {
+ grp = getgrnam(group);
+ if (grp != NULL) {
+ gid = grp->gr_gid;
+ } else {
+ char* endptr;
+ gid = (int) strtoul(group, &endptr, 0);
+ if (endptr == group) { // no conversion
+ fprintf(stderr, "No such group '%s'\n", group);
+ return 10;
+ }
+ }
+ }
+
+ for (i = 2; i < argc; i++) {
+ if (chown(argv[i], uid, gid) < 0) {
+ fprintf(stderr, "Unable to chown %s: %s\n", argv[i], strerror(errno));
+ return 10;
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/clear.c b/package/toolbox/src/src/clear.c
new file mode 100644
index 000000000..434ab4ace
--- /dev/null
+++ b/package/toolbox/src/src/clear.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+ /* This prints the clear screen and move cursor to top-left corner control
+ * characters for VT100 terminals. This means it will not work on
+ * non-VT100 compliant terminals, namely Windows' cmd.exe, but should
+ * work on anything unix-y. */
+ fputs("\x1b[2J\x1b[H", stdout);
+ return 0;
+}
diff --git a/package/toolbox/src/src/cmp.c b/package/toolbox/src/src/cmp.c
new file mode 100644
index 000000000..79e56c41a
--- /dev/null
+++ b/package/toolbox/src/src/cmp.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int fd1, fd2;
+ char buf1[4096], buf2[4096];
+ int res, res1, res2;
+ int rv = 0;
+ int i;
+ int filepos = 0;
+
+ int show_byte = 0;
+ int show_all = 0;
+ int limit = 0;
+
+ do {
+ c = getopt(argc, argv, "bln:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'b':
+ show_byte = 1;
+ break;
+ case 'l':
+ show_all = 1;
+ break;
+ case 'n':
+ limit = atoi(optarg);
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind + 2 != argc) {
+ fprintf(stderr, "Usage: %s [-b] [-l] [-n count] file1 file2\n", argv[0]);
+ exit(1);
+ }
+
+ fd1 = open(argv[optind], O_RDONLY);
+ if(fd1 < 0) {
+ fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
+ return 1;
+ }
+
+ fd2 = open(argv[optind+1], O_RDONLY);
+ if(fd2 < 0) {
+ fprintf(stderr, "could not open %s, %s\n", argv[optind+1], strerror(errno));
+ return 1;
+ }
+
+ while(1) {
+ res1 = read(fd1, &buf1, sizeof(buf1));
+ res2 = read(fd2, &buf2, sizeof(buf2));
+ res = res1 < res2 ? res1 : res2;
+ if(res1 == 0 && res2 == 0) {
+ return rv;
+ }
+ for(i = 0; i < res; i++) {
+ if(buf1[i] != buf2[i]) {
+ printf("%s %s differ byte %d", argv[optind], argv[optind+1], filepos + i);
+ if(show_byte)
+ printf(" 0x%02x 0x%02x", buf1[i], buf2[i]);
+ printf("\n");
+ if(!show_all)
+ return 1;
+ rv = 1;
+ }
+ if(limit) {
+ limit--;
+ if(limit == 0)
+ return rv;
+ }
+ }
+ if(res1 != res2 || res < 0) {
+ printf("%s on %s\n", res < 0 ? "Read error" : "EOF", res1 < res2 ? argv[optind] : argv[optind+1]);
+ return 1;
+ }
+ filepos += res;
+ }
+}
diff --git a/package/toolbox/src/src/dd.c b/package/toolbox/src/src/dd.c
new file mode 100644
index 000000000..605f18775
--- /dev/null
+++ b/package/toolbox/src/src/dd.c
@@ -0,0 +1,1323 @@
+/* $NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+
+//#define NO_CONV
+
+//#include "extern.h"
+void block(void);
+void block_close(void);
+void dd_out(int);
+void def(void);
+void def_close(void);
+void jcl(char **);
+void pos_in(void);
+void pos_out(void);
+void summary(void);
+void summaryx(int);
+void terminate(int);
+void unblock(void);
+void unblock_close(void);
+ssize_t bwrite(int, const void *, size_t);
+
+extern IO in, out;
+extern STAT st;
+extern void (*cfunc)(void);
+extern uint64_t cpy_cnt;
+extern uint64_t cbsz;
+extern u_int ddflags;
+extern u_int files_cnt;
+extern int progress;
+extern const u_char *ctab;
+
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef DEFFILEMODE
+#define DEFFILEMODE (S_IRUSR | S_IWUSR)
+#endif
+
+static void dd_close(void);
+static void dd_in(void);
+static void getfdtype(IO *);
+static int redup_clean_fd(int);
+static void setup(void);
+
+
+IO in, out; /* input/output state */
+STAT st; /* statistics */
+void (*cfunc)(void); /* conversion function */
+uint64_t cpy_cnt; /* # of blocks to copy */
+static off_t pending = 0; /* pending seek if sparse */
+u_int ddflags; /* conversion options */
+uint64_t cbsz; /* conversion block size */
+u_int files_cnt = 1; /* # of files to copy */
+int progress = 0; /* display sign of life */
+const u_char *ctab; /* conversion table */
+sigset_t infoset; /* a set blocking SIGINFO */
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ fprintf(stderr, "usage: dd [operand ...]\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ }
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ jcl(argv);
+ setup();
+
+// (void)signal(SIGINFO, summaryx);
+ (void)signal(SIGINT, terminate);
+ (void)sigemptyset(&infoset);
+// (void)sigaddset(&infoset, SIGINFO);
+
+ (void)atexit(summary);
+
+ while (files_cnt--)
+ dd_in();
+
+ dd_close();
+ exit(0);
+ /* NOTREACHED */
+}
+
+static void
+setup(void)
+{
+
+ if (in.name == NULL) {
+ in.name = "stdin";
+ in.fd = STDIN_FILENO;
+ } else {
+ in.fd = open(in.name, O_RDONLY, 0);
+ if (in.fd < 0) {
+ fprintf(stderr, "%s: cannot open for read: %s\n",
+ in.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ /* Ensure in.fd is outside the stdio descriptor range */
+ in.fd = redup_clean_fd(in.fd);
+ }
+
+ getfdtype(&in);
+
+ if (files_cnt > 1 && !(in.flags & ISTAPE)) {
+ fprintf(stderr,
+ "files is not supported for non-tape devices\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ if (out.name == NULL) {
+ /* No way to check for read access here. */
+ out.fd = STDOUT_FILENO;
+ out.name = "stdout";
+ } else {
+#define OFLAGS \
+ (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
+ out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
+ /*
+ * May not have read access, so try again with write only.
+ * Without read we may have a problem if output also does
+ * not support seeks.
+ */
+ if (out.fd < 0) {
+ out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
+ out.flags |= NOREAD;
+ }
+ if (out.fd < 0) {
+ fprintf(stderr, "%s: cannot open for write: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ /* Ensure out.fd is outside the stdio descriptor range */
+ out.fd = redup_clean_fd(out.fd);
+ }
+
+ getfdtype(&out);
+
+ /*
+ * Allocate space for the input and output buffers. If not doing
+ * record oriented I/O, only need a single buffer.
+ */
+ if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
+ if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) {
+ exit(1);
+ /* NOTREACHED */
+ }
+ out.db = in.db;
+ } else if ((in.db =
+ malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
+ (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
+ exit(1);
+ /* NOTREACHED */
+ }
+ in.dbp = in.db;
+ out.dbp = out.db;
+
+ /* Position the input/output streams. */
+ if (in.offset)
+ pos_in();
+ if (out.offset)
+ pos_out();
+
+ /*
+ * Truncate the output file; ignore errors because it fails on some
+ * kinds of output files, tapes, for example.
+ */
+ if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
+ (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
+
+ (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
+}
+
+static void
+getfdtype(IO *io)
+{
+// struct mtget mt;
+ struct stat sb;
+
+ if (fstat(io->fd, &sb)) {
+ fprintf(stderr, "%s: cannot fstat: %s\n",
+ io->name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (S_ISCHR(sb.st_mode))
+ io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR;
+ else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
+ io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */
+}
+
+/*
+ * Move the parameter file descriptor to a descriptor that is outside the
+ * stdio descriptor range, if necessary. This is required to avoid
+ * accidentally outputting completion or error messages into the
+ * output file that were intended for the tty.
+ */
+static int
+redup_clean_fd(int fd)
+{
+ int newfd;
+
+ if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
+ fd != STDERR_FILENO)
+ /* File descriptor is ok, return immediately. */
+ return fd;
+
+ /*
+ * 3 is the first descriptor greater than STD*_FILENO. Any
+ * free descriptor valued 3 or above is acceptable...
+ */
+ newfd = fcntl(fd, F_DUPFD, 3);
+ if (newfd < 0) {
+ fprintf(stderr, "dupfd IO: %s\n", strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ close(fd);
+
+ return newfd;
+}
+
+static void
+dd_in(void)
+{
+ int flags;
+ int64_t n;
+
+ for (flags = ddflags;;) {
+ if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
+ return;
+
+ /*
+ * Clear the buffer first if doing "sync" on input.
+ * If doing block operations use spaces. This will
+ * affect not only the C_NOERROR case, but also the
+ * last partial input block which should be padded
+ * with zero and not garbage.
+ */
+ if (flags & C_SYNC) {
+ if (flags & (C_BLOCK|C_UNBLOCK))
+ (void)memset(in.dbp, ' ', in.dbsz);
+ else
+ (void)memset(in.dbp, 0, in.dbsz);
+ }
+
+ n = read(in.fd, in.dbp, in.dbsz);
+ if (n == 0) {
+ in.dbrcnt = 0;
+ return;
+ }
+
+ /* Read error. */
+ if (n < 0) {
+
+ /*
+ * If noerror not specified, die. POSIX requires that
+ * the warning message be followed by an I/O display.
+ */
+ fprintf(stderr, "%s: read error: %s\n",
+ in.name, strerror(errno));
+ if (!(flags & C_NOERROR)) {
+ exit(1);
+ /* NOTREACHED */
+ }
+ summary();
+
+ /*
+ * If it's not a tape drive or a pipe, seek past the
+ * error. If your OS doesn't do the right thing for
+ * raw disks this section should be modified to re-read
+ * in sector size chunks.
+ */
+ if (!(in.flags & (ISPIPE|ISTAPE)) &&
+ lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
+ fprintf(stderr, "%s: seek error: %s\n",
+ in.name, strerror(errno));
+
+ /* If sync not specified, omit block and continue. */
+ if (!(ddflags & C_SYNC))
+ continue;
+
+ /* Read errors count as full blocks. */
+ in.dbcnt += in.dbrcnt = in.dbsz;
+ ++st.in_full;
+
+ /* Handle full input blocks. */
+ } else if (n == in.dbsz) {
+ in.dbcnt += in.dbrcnt = n;
+ ++st.in_full;
+
+ /* Handle partial input blocks. */
+ } else {
+ /* If sync, use the entire block. */
+ if (ddflags & C_SYNC)
+ in.dbcnt += in.dbrcnt = in.dbsz;
+ else
+ in.dbcnt += in.dbrcnt = n;
+ ++st.in_part;
+ }
+
+ /*
+ * POSIX states that if bs is set and no other conversions
+ * than noerror, notrunc or sync are specified, the block
+ * is output without buffering as it is read.
+ */
+ if (ddflags & C_BS) {
+ out.dbcnt = in.dbcnt;
+ dd_out(1);
+ in.dbcnt = 0;
+ continue;
+ }
+
+/* if (ddflags & C_SWAB) {
+ if ((n = in.dbrcnt) & 1) {
+ ++st.swab;
+ --n;
+ }
+ swab(in.dbp, in.dbp, n);
+ }
+*/
+ in.dbp += in.dbrcnt;
+ (*cfunc)();
+ }
+}
+
+/*
+ * Cleanup any remaining I/O and flush output. If necesssary, output file
+ * is truncated.
+ */
+static void
+dd_close(void)
+{
+
+ if (cfunc == def)
+ def_close();
+ else if (cfunc == block)
+ block_close();
+ else if (cfunc == unblock)
+ unblock_close();
+ if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
+ (void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
+ out.dbcnt = out.dbsz;
+ }
+ /* If there are pending sparse blocks, make sure
+ * to write out the final block un-sparse
+ */
+ if ((out.dbcnt == 0) && pending) {
+ memset(out.db, 0, out.dbsz);
+ out.dbcnt = out.dbsz;
+ out.dbp = out.db + out.dbcnt;
+ pending -= out.dbsz;
+ }
+ if (out.dbcnt)
+ dd_out(1);
+
+ /*
+ * Reporting nfs write error may be defered until next
+ * write(2) or close(2) system call. So, we need to do an
+ * extra check. If an output is stdout, the file structure
+ * may be shared among with other processes and close(2) just
+ * decreases the reference count.
+ */
+ if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) {
+ fprintf(stderr, "fsync stdout: %s\n", strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (close(out.fd) == -1) {
+ fprintf(stderr, "close: %s\n", strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+}
+
+void
+dd_out(int force)
+{
+ static int warned;
+ int64_t cnt, n, nw;
+ u_char *outp;
+
+ /*
+ * Write one or more blocks out. The common case is writing a full
+ * output block in a single write; increment the full block stats.
+ * Otherwise, we're into partial block writes. If a partial write,
+ * and it's a character device, just warn. If a tape device, quit.
+ *
+ * The partial writes represent two cases. 1: Where the input block
+ * was less than expected so the output block was less than expected.
+ * 2: Where the input block was the right size but we were forced to
+ * write the block in multiple chunks. The original versions of dd(1)
+ * never wrote a block in more than a single write, so the latter case
+ * never happened.
+ *
+ * One special case is if we're forced to do the write -- in that case
+ * we play games with the buffer size, and it's usually a partial write.
+ */
+ outp = out.db;
+ for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
+ for (cnt = n;; cnt -= nw) {
+
+ if (!force && ddflags & C_SPARSE) {
+ int sparse, i;
+ sparse = 1; /* Is buffer sparse? */
+ for (i = 0; i < cnt; i++)
+ if (outp[i] != 0) {
+ sparse = 0;
+ break;
+ }
+ if (sparse) {
+ pending += cnt;
+ outp += cnt;
+ nw = 0;
+ break;
+ }
+ }
+ if (pending != 0) {
+ if (lseek(out.fd, pending, SEEK_CUR) ==
+ -1) {
+ fprintf(stderr,
+ "%s: seek error creating "
+ "sparse file: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ }
+ }
+ nw = bwrite(out.fd, outp, cnt);
+ if (nw <= 0) {
+ if (nw == 0) {
+ fprintf(stderr, "%s: end of device\n",
+ out.name);
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (errno != EINTR) {
+ fprintf(stderr, "%s: write error: %s\n",
+ out.name, strerror(errno));
+ /* NOTREACHED */
+ exit(1);
+ }
+ nw = 0;
+ }
+ if (pending) {
+ st.bytes += pending;
+ st.sparse += pending/out.dbsz;
+ st.out_full += pending/out.dbsz;
+ pending = 0;
+ }
+ outp += nw;
+ st.bytes += nw;
+ if (nw == n) {
+ if (n != out.dbsz)
+ ++st.out_part;
+ else
+ ++st.out_full;
+ break;
+ }
+ ++st.out_part;
+ if (nw == cnt)
+ break;
+ if (out.flags & ISCHR && !warned) {
+ warned = 1;
+ fprintf(stderr, "%s: short write on character "
+ "device\n", out.name);
+ }
+ if (out.flags & ISTAPE) {
+ fprintf(stderr,
+ "%s: short write on tape device",
+ out.name);
+ exit(1);
+ /* NOTREACHED */
+ }
+ }
+ if ((out.dbcnt -= n) < out.dbsz)
+ break;
+ }
+
+ /* Reassemble the output block. */
+ if (out.dbcnt)
+ (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
+ out.dbp = out.db + out.dbcnt;
+
+ if (progress)
+ (void)write(STDERR_FILENO, ".", 1);
+}
+
+/*
+ * A protected against SIGINFO write
+ */
+ssize_t
+bwrite(int fd, const void *buf, size_t len)
+{
+ sigset_t oset;
+ ssize_t rv;
+ int oerrno;
+
+ (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
+ rv = write(fd, buf, len);
+ oerrno = errno;
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ errno = oerrno;
+ return (rv);
+}
+
+/*
+ * Position input/output data streams before starting the copy. Device type
+ * dependent. Seekable devices use lseek, and the rest position by reading.
+ * Seeking past the end of file can cause null blocks to be written to the
+ * output.
+ */
+void
+pos_in(void)
+{
+ int bcnt, cnt, nr, warned;
+
+ /* If not a pipe or tape device, try to seek on it. */
+ if (!(in.flags & (ISPIPE|ISTAPE))) {
+ if (lseek64(in.fd,
+ (off64_t)in.offset * (off64_t)in.dbsz, SEEK_CUR) == -1) {
+ fprintf(stderr, "%s: seek error: %s",
+ in.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ return;
+ /* NOTREACHED */
+ }
+
+ /*
+ * Read the data. If a pipe, read until satisfy the number of bytes
+ * being skipped. No differentiation for reading complete and partial
+ * blocks for other devices.
+ */
+ for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
+ if ((nr = read(in.fd, in.db, bcnt)) > 0) {
+ if (in.flags & ISPIPE) {
+ if (!(bcnt -= nr)) {
+ bcnt = in.dbsz;
+ --cnt;
+ }
+ } else
+ --cnt;
+ continue;
+ }
+
+ if (nr == 0) {
+ if (files_cnt > 1) {
+ --files_cnt;
+ continue;
+ }
+ fprintf(stderr, "skip reached end of input\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Input error -- either EOF with no more files, or I/O error.
+ * If noerror not set die. POSIX requires that the warning
+ * message be followed by an I/O display.
+ */
+ if (ddflags & C_NOERROR) {
+ if (!warned) {
+
+ fprintf(stderr, "%s: error occurred\n",
+ in.name);
+ warned = 1;
+ summary();
+ }
+ continue;
+ }
+ fprintf(stderr, "%s: read error: %s", in.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+}
+
+void
+pos_out(void)
+{
+// struct mtop t_op;
+ int cnt, n;
+
+ /*
+ * If not a tape, try seeking on the file. Seeking on a pipe is
+ * going to fail, but don't protect the user -- they shouldn't
+ * have specified the seek operand.
+ */
+ if (!(out.flags & ISTAPE)) {
+ if (lseek64(out.fd,
+ (off64_t)out.offset * (off64_t)out.dbsz, SEEK_SET) == -1) {
+ fprintf(stderr, "%s: seek error: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ return;
+ }
+
+ /* If no read access, try using mtio. */
+ if (out.flags & NOREAD) {
+/* t_op.mt_op = MTFSR;
+ t_op.mt_count = out.offset;
+
+ if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/
+ fprintf(stderr, "%s: cannot read", out.name);
+ exit(1);
+ /* NOTREACHED */
+ return;
+ }
+
+ /* Read it. */
+ for (cnt = 0; cnt < out.offset; ++cnt) {
+ if ((n = read(out.fd, out.db, out.dbsz)) > 0)
+ continue;
+
+ if (n < 0) {
+ fprintf(stderr, "%s: cannot position by reading: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ /*
+ * If reach EOF, fill with NUL characters; first, back up over
+ * the EOF mark. Note, cnt has not yet been incremented, so
+ * the EOF read does not count as a seek'd block.
+ */
+/* t_op.mt_op = MTBSR;
+ t_op.mt_count = 1;
+ if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ {
+ fprintf(stderr, "%s: cannot position\n", out.name);
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ while (cnt++ < out.offset)
+ if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) {
+ fprintf(stderr, "%s: cannot position "
+ "by writing: %s\n",
+ out.name, strerror(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ break;
+ }
+}
+
+/*
+ * def --
+ * Copy input to output. Input is buffered until reaches obs, and then
+ * output until less than obs remains. Only a single buffer is used.
+ * Worst case buffer calculation is (ibs + obs - 1).
+ */
+void
+def(void)
+{
+ uint64_t cnt;
+ u_char *inp;
+ const u_char *t;
+
+ if ((t = ctab) != NULL)
+ for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
+ *inp = t[*inp];
+
+ /* Make the output buffer look right. */
+ out.dbp = in.dbp;
+ out.dbcnt = in.dbcnt;
+
+ if (in.dbcnt >= out.dbsz) {
+ /* If the output buffer is full, write it. */
+ dd_out(0);
+
+ /*
+ * Ddout copies the leftover output to the beginning of
+ * the buffer and resets the output buffer. Reset the
+ * input buffer to match it.
+ */
+ in.dbp = out.dbp;
+ in.dbcnt = out.dbcnt;
+ }
+}
+
+void
+def_close(void)
+{
+ if (ddflags & C_FDATASYNC) {
+ fdatasync(out.fd);
+ }
+
+ /* Just update the count, everything is already in the buffer. */
+ if (in.dbcnt)
+ out.dbcnt = in.dbcnt;
+}
+
+#ifdef NO_CONV
+/* Build a smaller version (i.e. for a miniroot) */
+/* These can not be called, but just in case... */
+static const char no_block[] = "unblock and -DNO_CONV?\n";
+void block(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
+void block_close(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
+void unblock(void) { fprintf(stderr, "%s", no_block); exit(1); }
+void unblock_close(void) { fprintf(stderr, "%s", no_block); exit(1); }
+#else /* NO_CONV */
+
+/*
+ * Copy variable length newline terminated records with a max size cbsz
+ * bytes to output. Records less than cbs are padded with spaces.
+ *
+ * max in buffer: MAX(ibs, cbsz)
+ * max out buffer: obs + cbsz
+ */
+void
+block(void)
+{
+ static int intrunc;
+ int ch = 0; /* pacify gcc */
+ uint64_t cnt, maxlen;
+ u_char *inp, *outp;
+ const u_char *t;
+
+ /*
+ * Record truncation can cross block boundaries. If currently in a
+ * truncation state, keep tossing characters until reach a newline.
+ * Start at the beginning of the buffer, as the input buffer is always
+ * left empty.
+ */
+ if (intrunc) {
+ for (inp = in.db, cnt = in.dbrcnt;
+ cnt && *inp++ != '\n'; --cnt);
+ if (!cnt) {
+ in.dbcnt = 0;
+ in.dbp = in.db;
+ return;
+ }
+ intrunc = 0;
+ /* Adjust the input buffer numbers. */
+ in.dbcnt = cnt - 1;
+ in.dbp = inp + cnt - 1;
+ }
+
+ /*
+ * Copy records (max cbsz size chunks) into the output buffer. The
+ * translation is done as we copy into the output buffer.
+ */
+ for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
+ maxlen = MIN(cbsz, in.dbcnt);
+ if ((t = ctab) != NULL)
+ for (cnt = 0;
+ cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+ *outp++ = t[ch];
+ else
+ for (cnt = 0;
+ cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+ *outp++ = ch;
+ /*
+ * Check for short record without a newline. Reassemble the
+ * input block.
+ */
+ if (ch != '\n' && in.dbcnt < cbsz) {
+ (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+ break;
+ }
+
+ /* Adjust the input buffer numbers. */
+ in.dbcnt -= cnt;
+ if (ch == '\n')
+ --in.dbcnt;
+
+ /* Pad short records with spaces. */
+ if (cnt < cbsz)
+ (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
+ else {
+ /*
+ * If the next character wouldn't have ended the
+ * block, it's a truncation.
+ */
+ if (!in.dbcnt || *inp != '\n')
+ ++st.trunc;
+
+ /* Toss characters to a newline. */
+ for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
+ if (!in.dbcnt)
+ intrunc = 1;
+ else
+ --in.dbcnt;
+ }
+
+ /* Adjust output buffer numbers. */
+ out.dbp += cbsz;
+ if ((out.dbcnt += cbsz) >= out.dbsz)
+ dd_out(0);
+ outp = out.dbp;
+ }
+ in.dbp = in.db + in.dbcnt;
+}
+
+void
+block_close(void)
+{
+
+ /*
+ * Copy any remaining data into the output buffer and pad to a record.
+ * Don't worry about truncation or translation, the input buffer is
+ * always empty when truncating, and no characters have been added for
+ * translation. The bottom line is that anything left in the input
+ * buffer is a truncated record. Anything left in the output buffer
+ * just wasn't big enough.
+ */
+ if (in.dbcnt) {
+ ++st.trunc;
+ (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
+ (void)memset(out.dbp + in.dbcnt,
+ ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
+ out.dbcnt += cbsz;
+ }
+}
+
+/*
+ * Convert fixed length (cbsz) records to variable length. Deletes any
+ * trailing blanks and appends a newline.
+ *
+ * max in buffer: MAX(ibs, cbsz) + cbsz
+ * max out buffer: obs + cbsz
+ */
+void
+unblock(void)
+{
+ uint64_t cnt;
+ u_char *inp;
+ const u_char *t;
+
+ /* Translation and case conversion. */
+ if ((t = ctab) != NULL)
+ for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
+ *inp = t[*inp];
+ /*
+ * Copy records (max cbsz size chunks) into the output buffer. The
+ * translation has to already be done or we might not recognize the
+ * spaces.
+ */
+ for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
+ for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
+ if (t >= inp) {
+ cnt = t - inp + 1;
+ (void)memmove(out.dbp, inp, cnt);
+ out.dbp += cnt;
+ out.dbcnt += cnt;
+ }
+ ++out.dbcnt;
+ *out.dbp++ = '\n';
+ if (out.dbcnt >= out.dbsz)
+ dd_out(0);
+ }
+ if (in.dbcnt)
+ (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+ in.dbp = in.db + in.dbcnt;
+}
+
+void
+unblock_close(void)
+{
+ uint64_t cnt;
+ u_char *t;
+
+ if (in.dbcnt) {
+ warnx("%s: short input record", in.name);
+ for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
+ if (t >= in.db) {
+ cnt = t - in.db + 1;
+ (void)memmove(out.dbp, in.db, cnt);
+ out.dbp += cnt;
+ out.dbcnt += cnt;
+ }
+ ++out.dbcnt;
+ *out.dbp++ = '\n';
+ }
+}
+
+#endif /* NO_CONV */
+
+#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
+
+void
+summary(void)
+{
+ char buf[100];
+ int64_t mS;
+ struct timeval tv;
+
+ if (progress)
+ (void)write(STDERR_FILENO, "\n", 1);
+
+ (void)gettimeofday(&tv, NULL);
+ mS = tv2mS(tv) - tv2mS(st.start);
+ if (mS == 0)
+ mS = 1;
+ /* Use snprintf(3) so that we don't reenter stdio(3). */
+ (void)snprintf(buf, sizeof(buf),
+ "%llu+%llu records in\n%llu+%llu records out\n",
+ (unsigned long long)st.in_full, (unsigned long long)st.in_part,
+ (unsigned long long)st.out_full, (unsigned long long)st.out_part);
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ if (st.swab) {
+ (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
+ (unsigned long long)st.swab,
+ (st.swab == 1) ? "block" : "blocks");
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ }
+ if (st.trunc) {
+ (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
+ (unsigned long long)st.trunc,
+ (st.trunc == 1) ? "block" : "blocks");
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ }
+ if (st.sparse) {
+ (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
+ (unsigned long long)st.sparse,
+ (st.sparse == 1) ? "block" : "blocks");
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ }
+ (void)snprintf(buf, sizeof(buf),
+ "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
+ (unsigned long long) st.bytes,
+ (long) (mS / 1000),
+ (int) (mS % 1000),
+ (unsigned long long) (st.bytes * 1000LL / mS));
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+void
+terminate(int notused)
+{
+
+ exit(0);
+ /* NOTREACHED */
+}
+
+static int c_arg(const void *, const void *);
+#ifndef NO_CONV
+static int c_conv(const void *, const void *);
+#endif
+static void f_bs(char *);
+static void f_cbs(char *);
+static void f_conv(char *);
+static void f_count(char *);
+static void f_files(char *);
+static void f_ibs(char *);
+static void f_if(char *);
+static void f_obs(char *);
+static void f_of(char *);
+static void f_seek(char *);
+static void f_skip(char *);
+static void f_progress(char *);
+
+static const struct arg {
+ const char *name;
+ void (*f)(char *);
+ u_int set, noset;
+} args[] = {
+ /* the array needs to be sorted by the first column so
+ bsearch() can be used to find commands quickly */
+ { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC },
+ { "cbs", f_cbs, C_CBS, C_CBS },
+ { "conv", f_conv, 0, 0 },
+ { "count", f_count, C_COUNT, C_COUNT },
+ { "files", f_files, C_FILES, C_FILES },
+ { "ibs", f_ibs, C_IBS, C_BS|C_IBS },
+ { "if", f_if, C_IF, C_IF },
+ { "obs", f_obs, C_OBS, C_BS|C_OBS },
+ { "of", f_of, C_OF, C_OF },
+ { "progress", f_progress, 0, 0 },
+ { "seek", f_seek, C_SEEK, C_SEEK },
+ { "skip", f_skip, C_SKIP, C_SKIP },
+};
+
+/*
+ * args -- parse JCL syntax of dd.
+ */
+void
+jcl(char **argv)
+{
+ struct arg *ap, tmp;
+ char *oper, *arg;
+
+ in.dbsz = out.dbsz = 512;
+
+ while ((oper = *++argv) != NULL) {
+ if ((arg = strchr(oper, '=')) == NULL) {
+ fprintf(stderr, "unknown operand %s\n", oper);
+ exit(1);
+ /* NOTREACHED */
+ }
+ *arg++ = '\0';
+ if (!*arg) {
+ fprintf(stderr, "no value specified for %s\n", oper);
+ exit(1);
+ /* NOTREACHED */
+ }
+ tmp.name = oper;
+ if (!(ap = (struct arg *)bsearch(&tmp, args,
+ sizeof(args)/sizeof(struct arg), sizeof(struct arg),
+ c_arg))) {
+ fprintf(stderr, "unknown operand %s\n", tmp.name);
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (ddflags & ap->noset) {
+ fprintf(stderr,
+ "%s: illegal argument combination or already set\n",
+ tmp.name);
+ exit(1);
+ /* NOTREACHED */
+ }
+ ddflags |= ap->set;
+ ap->f(arg);
+ }
+
+ /* Final sanity checks. */
+
+ if (ddflags & C_BS) {
+ /*
+ * Bs is turned off by any conversion -- we assume the user
+ * just wanted to set both the input and output block sizes
+ * and didn't want the bs semantics, so we don't warn.
+ */
+ if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
+ C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
+ ddflags &= ~C_BS;
+ ddflags |= C_IBS|C_OBS;
+ }
+
+ /* Bs supersedes ibs and obs. */
+ if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
+ fprintf(stderr, "bs supersedes ibs and obs\n");
+ }
+
+ /*
+ * Ascii/ebcdic and cbs implies block/unblock.
+ * Block/unblock requires cbs and vice-versa.
+ */
+ if (ddflags & (C_BLOCK|C_UNBLOCK)) {
+ if (!(ddflags & C_CBS)) {
+ fprintf(stderr, "record operations require cbs\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ cfunc = ddflags & C_BLOCK ? block : unblock;
+ } else if (ddflags & C_CBS) {
+ if (ddflags & (C_ASCII|C_EBCDIC)) {
+ if (ddflags & C_ASCII) {
+ ddflags |= C_UNBLOCK;
+ cfunc = unblock;
+ } else {
+ ddflags |= C_BLOCK;
+ cfunc = block;
+ }
+ } else {
+ fprintf(stderr,
+ "cbs meaningless if not doing record operations\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ } else
+ cfunc = def;
+
+ /* Read, write and seek calls take off_t as arguments.
+ *
+ * The following check is not done because an off_t is a quad
+ * for current NetBSD implementations.
+ *
+ * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
+ * errx(1, "seek offsets cannot be larger than %d", INT_MAX);
+ */
+}
+
+static int
+c_arg(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct arg *)a)->name,
+ ((const struct arg *)b)->name));
+}
+
+static long long strsuftoll(const char* name, const char* arg, int def, unsigned long long max)
+{
+ long long result;
+
+ if (sscanf(arg, "%lld", &result) == 0)
+ result = def;
+ return result;
+}
+
+static void
+f_bs(char *arg)
+{
+
+ in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_cbs(char *arg)
+{
+
+ cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
+}
+
+static void
+f_count(char *arg)
+{
+
+ cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
+ if (!cpy_cnt)
+ terminate(0);
+}
+
+static void
+f_files(char *arg)
+{
+
+ files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
+ if (!files_cnt)
+ terminate(0);
+}
+
+static void
+f_ibs(char *arg)
+{
+
+ if (!(ddflags & C_BS))
+ in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_if(char *arg)
+{
+
+ in.name = arg;
+}
+
+static void
+f_obs(char *arg)
+{
+
+ if (!(ddflags & C_BS))
+ out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_of(char *arg)
+{
+
+ out.name = arg;
+}
+
+static void
+f_seek(char *arg)
+{
+
+ out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
+}
+
+static void
+f_skip(char *arg)
+{
+
+ in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
+}
+
+static void
+f_progress(char *arg)
+{
+
+ if (*arg != '0')
+ progress = 1;
+}
+
+#ifdef NO_CONV
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_conv(char *arg)
+{
+
+ fprintf(stderr, "conv option disabled\n");
+ exit(1);
+ /* NOTREACHED */
+}
+#else /* NO_CONV */
+
+static const struct conv {
+ const char *name;
+ u_int set, noset;
+ const u_char *ctab;
+} clist[] = {
+ { "block", C_BLOCK, C_UNBLOCK, NULL },
+ { "fdatasync", C_FDATASYNC, 0, NULL },
+ { "noerror", C_NOERROR, 0, NULL },
+ { "notrunc", C_NOTRUNC, 0, NULL },
+ { "osync", C_OSYNC, C_BS, NULL },
+ { "sparse", C_SPARSE, 0, NULL },
+ { "swab", C_SWAB, 0, NULL },
+ { "sync", C_SYNC, 0, NULL },
+ { "unblock", C_UNBLOCK, C_BLOCK, NULL },
+ /* If you add items to this table, be sure to add the
+ * conversions to the C_BS check in the jcl routine above.
+ */
+};
+
+static void
+f_conv(char *arg)
+{
+ struct conv *cp, tmp;
+
+ while (arg != NULL) {
+ tmp.name = strsep(&arg, ",");
+ if (!(cp = (struct conv *)bsearch(&tmp, clist,
+ sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
+ c_conv))) {
+ errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
+ /* NOTREACHED */
+ }
+ if (ddflags & cp->noset) {
+ errx(EXIT_FAILURE, "%s: illegal conversion combination", tmp.name);
+ /* NOTREACHED */
+ }
+ ddflags |= cp->set;
+ if (cp->ctab)
+ ctab = cp->ctab;
+ }
+}
+
+static int
+c_conv(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct conv *)a)->name,
+ ((const struct conv *)b)->name));
+}
+
+#endif /* NO_CONV */
+
+
diff --git a/package/toolbox/src/src/dd.h b/package/toolbox/src/src/dd.h
new file mode 100644
index 000000000..89f28332c
--- /dev/null
+++ b/package/toolbox/src/src/dd.h
@@ -0,0 +1,94 @@
+/* $NetBSD: dd.h,v 1.12 2004/01/17 20:48:57 dbj Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dd.h 8.3 (Berkeley) 4/2/94
+ */
+
+#include <stdint.h>
+
+/* Input/output stream state. */
+typedef struct {
+ u_char *db; /* buffer address */
+ u_char *dbp; /* current buffer I/O address */
+ uint64_t dbcnt; /* current buffer byte count */
+ int64_t dbrcnt; /* last read byte count */
+ uint64_t dbsz; /* buffer size */
+
+#define ISCHR 0x01 /* character device (warn on short) */
+#define ISPIPE 0x02 /* pipe (not truncatable) */
+#define ISTAPE 0x04 /* tape (not seekable) */
+#define NOREAD 0x08 /* not readable */
+ u_int flags;
+
+ const char *name; /* name */
+ int fd; /* file descriptor */
+ uint64_t offset; /* # of blocks to skip */
+} IO;
+
+typedef struct {
+ uint64_t in_full; /* # of full input blocks */
+ uint64_t in_part; /* # of partial input blocks */
+ uint64_t out_full; /* # of full output blocks */
+ uint64_t out_part; /* # of partial output blocks */
+ uint64_t trunc; /* # of truncated records */
+ uint64_t swab; /* # of odd-length swab blocks */
+ uint64_t sparse; /* # of sparse output blocks */
+ uint64_t bytes; /* # of bytes written */
+ struct timeval start; /* start time of dd */
+} STAT;
+
+/* Flags (in ddflags). */
+#define C_ASCII 0x00001
+#define C_BLOCK 0x00002
+#define C_BS 0x00004
+#define C_CBS 0x00008
+#define C_COUNT 0x00010
+#define C_EBCDIC 0x00020
+#define C_FILES 0x00040
+#define C_IBS 0x00080
+#define C_IF 0x00100
+#define C_LCASE 0x00200
+#define C_NOERROR 0x00400
+#define C_NOTRUNC 0x00800
+#define C_OBS 0x01000
+#define C_OF 0x02000
+#define C_SEEK 0x04000
+#define C_SKIP 0x08000
+#define C_SWAB 0x10000
+#define C_SYNC 0x20000
+#define C_UCASE 0x40000
+#define C_UNBLOCK 0x80000
+#define C_OSYNC 0x100000
+#define C_SPARSE 0x200000
+#define C_FDATASYNC 0x400000
diff --git a/package/toolbox/src/src/df.c b/package/toolbox/src/src/df.c
new file mode 100644
index 000000000..8cff0c8c2
--- /dev/null
+++ b/package/toolbox/src/src/df.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/statfs.h>
+
+static int ok = EXIT_SUCCESS;
+
+static void printsize(long long n)
+{
+ char unit = 'K';
+ long long t;
+
+ n *= 10;
+
+ if (n > 1024*1024*10) {
+ n /= 1024;
+ unit = 'M';
+ }
+
+ if (n > 1024*1024*10) {
+ n /= 1024;
+ unit = 'G';
+ }
+
+ t = (n + 512) / 1024;
+ printf("%4lld.%1lld%c", t/10, t%10, unit);
+}
+
+static void df(char *s, int always) {
+ struct statfs st;
+
+ if (statfs(s, &st) < 0) {
+ fprintf(stderr, "%s: %s\n", s, strerror(errno));
+ ok = EXIT_FAILURE;
+ } else {
+ if (st.f_blocks == 0 && !always)
+ return;
+ printf("%-20s ", s);
+ printsize((long long)st.f_blocks * (long long)st.f_bsize);
+ printf(" ");
+ printsize((long long)(st.f_blocks - (long long)st.f_bfree) * st.f_bsize);
+ printf(" ");
+ printsize((long long)st.f_bfree * (long long)st.f_bsize);
+ printf(" %d\n", (int) st.f_bsize);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ printf("Filesystem Size Used Free Blksize\n");
+ if (argc == 1) {
+ char s[2000];
+ FILE *f = fopen("/proc/mounts", "r");
+
+ while (fgets(s, 2000, f)) {
+ char *c, *e = s;
+
+ for (c = s; *c; c++) {
+ if (*c == ' ') {
+ e = c + 1;
+ break;
+ }
+ }
+
+ for (c = e; *c; c++) {
+ if (*c == ' ') {
+ *c = '\0';
+ break;
+ }
+ }
+
+ df(e, 0);
+ }
+
+ fclose(f);
+ } else {
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ df(argv[i], 1);
+ }
+ }
+
+ exit(ok);
+}
diff --git a/package/toolbox/src/src/dmesg.c b/package/toolbox/src/src/dmesg.c
new file mode 100644
index 000000000..9fac63287
--- /dev/null
+++ b/package/toolbox/src/src/dmesg.c
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/klog.h>
+#include <string.h>
+
+#define FALLBACK_KLOG_BUF_SHIFT 17 /* CONFIG_LOG_BUF_SHIFT from our kernel */
+#define FALLBACK_KLOG_BUF_LEN (1 << FALLBACK_KLOG_BUF_SHIFT)
+
+#ifndef KLOG_SIZE_BUFFER
+#define KLOG_READ_ALL 3
+#define KLOG_READ_CLEAR 4
+#define KLOG_SIZE_BUFFER 10
+#endif
+
+int main(int argc, char **argv)
+{
+ char *buffer;
+ char *p;
+ ssize_t ret;
+ int n, op, klog_buf_len;
+
+ klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0);
+
+ if (klog_buf_len <= 0) {
+ klog_buf_len = FALLBACK_KLOG_BUF_LEN;
+ }
+
+ buffer = (char *)malloc(klog_buf_len + 1);
+
+ if (!buffer) {
+ perror("malloc");
+ return EXIT_FAILURE;
+ }
+
+ p = buffer;
+
+ if((argc == 2) && (!strcmp(argv[1],"-c"))) {
+ op = KLOG_READ_CLEAR;
+ } else {
+ op = KLOG_READ_ALL;
+ }
+
+ n = klogctl(op, buffer, klog_buf_len);
+ if (n < 0) {
+ perror("klogctl");
+ return EXIT_FAILURE;
+ }
+ buffer[n] = '\0';
+
+ while((ret = write(STDOUT_FILENO, p, n))) {
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ perror("write");
+ return EXIT_FAILURE;
+ }
+ p += ret;
+ n -= ret;
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/du.c b/package/toolbox/src/src/du.c
new file mode 100644
index 000000000..8fd6b3644
--- /dev/null
+++ b/package/toolbox/src/src/du.c
@@ -0,0 +1,322 @@
+/* $NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Newcomb.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+int linkchk(dev_t, ino_t);
+void prstat(const char *, int64_t);
+static void usage(void);
+
+long blocksize;
+
+#define howmany(x, y) (((x)+((y)-1))/(y))
+
+int
+main(int argc, char *argv[])
+{
+ FTS *fts;
+ FTSENT *p;
+ int64_t totalblocks;
+ int ftsoptions, listfiles;
+ int depth;
+ int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, rval, sflag;
+ char *noargv[2];
+
+ Hflag = Lflag = aflag = cflag = dflag = gkmflag = sflag = 0;
+ totalblocks = 0;
+ ftsoptions = FTS_PHYSICAL;
+ depth = INT_MAX;
+ while ((ch = getopt(argc, argv, "HLPacd:ghkmnrsx")) != -1)
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = 0;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ depth = atoi(optarg);
+ if (depth < 0 || depth > SHRT_MAX) {
+ warnx("invalid argument to option d: %s",
+ optarg);
+ usage();
+ }
+ break;
+ case 'g':
+ blocksize = 1024 * 1024 * 1024;
+ gkmflag = 1;
+ break;
+ case 'k':
+ blocksize = 1024;
+ gkmflag = 1;
+ break;
+ case 'm':
+ blocksize = 1024 * 1024;
+ gkmflag = 1;
+ break;
+ case 'r':
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * XXX
+ * Because of the way that fts(3) works, logical walks will not count
+ * the blocks actually used by symbolic links. We rationalize this by
+ * noting that users computing logical sizes are likely to do logical
+ * copies, so not counting the links is correct. The real reason is
+ * that we'd have to re-implement the kernel's symbolic link traversing
+ * algorithm to get this right. If, for example, you have relative
+ * symbolic links referencing other relative symbolic links, it gets
+ * very nasty, very fast. The bottom line is that it's documented in
+ * the man page, so it's a feature.
+ */
+ if (Hflag)
+ ftsoptions |= FTS_COMFOLLOW;
+ if (Lflag) {
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+ }
+
+ listfiles = 0;
+ if (aflag) {
+ if (sflag || dflag)
+ usage();
+ listfiles = 1;
+ } else if (sflag) {
+ if (dflag)
+ usage();
+ depth = 0;
+ }
+
+ if (!*argv) {
+ noargv[0] = strdup(".");
+ noargv[1] = NULL;
+ argv = noargv;
+ }
+
+ if (!gkmflag)
+ blocksize = 512;
+ blocksize /= 512;
+
+ if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
+ err(1, "fts_open `%s'", *argv);
+
+ for (rval = 0; (p = fts_read(fts)) != NULL;) {
+ switch (p->fts_info) {
+ case FTS_D: /* Ignore. */
+ break;
+ case FTS_DP:
+ p->fts_parent->fts_number +=
+ p->fts_number += p->fts_statp->st_blocks;
+ if (cflag)
+ totalblocks += p->fts_statp->st_blocks;
+ /*
+ * If listing each directory, or not listing files
+ * or directories and this is post-order of the
+ * root of a traversal, display the total.
+ */
+ if (p->fts_level <= depth
+ || (!listfiles && !p->fts_level))
+ prstat(p->fts_path, p->fts_number);
+ break;
+ case FTS_DC: /* Ignore. */
+ break;
+ case FTS_DNR: /* Warn, continue. */
+ case FTS_ERR:
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ default:
+ if (p->fts_statp->st_nlink > 1 &&
+ linkchk(p->fts_statp->st_dev, p->fts_statp->st_ino))
+ break;
+ /*
+ * If listing each file, or a non-directory file was
+ * the root of a traversal, display the total.
+ */
+ if (listfiles || !p->fts_level)
+ prstat(p->fts_path, p->fts_statp->st_blocks);
+ p->fts_parent->fts_number += p->fts_statp->st_blocks;
+ if (cflag)
+ totalblocks += p->fts_statp->st_blocks;
+ }
+ }
+ if (errno)
+ err(1, "fts_read");
+ if (cflag)
+ prstat("total", totalblocks);
+ exit(rval);
+}
+
+void
+prstat(const char *fname, int64_t blocks)
+{
+ (void)printf("%lld\t%s\n",
+ (long long)howmany(blocks, (int64_t)blocksize),
+ fname);
+}
+
+int
+linkchk(dev_t dev, ino_t ino)
+{
+ static struct entry {
+ dev_t dev;
+ ino_t ino;
+ } *htable;
+ static int htshift; /* log(allocated size) */
+ static int htmask; /* allocated size - 1 */
+ static int htused; /* 2*number of insertions */
+ static int sawzero; /* Whether zero is in table or not */
+ int h, h2;
+ uint64_t tmp;
+ /* this constant is (1<<64)/((1+sqrt(5))/2)
+ * aka (word size)/(golden ratio)
+ */
+ const uint64_t HTCONST = 11400714819323198485ULL;
+ const int HTBITS = CHAR_BIT * sizeof(tmp);
+
+ /* Never store zero in hashtable */
+ if (dev == 0 && ino == 0) {
+ h = sawzero;
+ sawzero = 1;
+ return h;
+ }
+
+ /* Extend hash table if necessary, keep load under 0.5 */
+ if (htused<<1 >= htmask) {
+ struct entry *ohtable;
+
+ if (!htable)
+ htshift = 10; /* starting hashtable size */
+ else
+ htshift++; /* exponential hashtable growth */
+
+ htmask = (1 << htshift) - 1;
+ htused = 0;
+
+ ohtable = htable;
+ htable = calloc(htmask+1, sizeof(*htable));
+ if (!htable)
+ err(1, "calloc");
+
+ /* populate newly allocated hashtable */
+ if (ohtable) {
+ int i;
+ for (i = 0; i <= htmask>>1; i++)
+ if (ohtable[i].ino || ohtable[i].dev)
+ linkchk(ohtable[i].dev, ohtable[i].ino);
+ free(ohtable);
+ }
+ }
+
+ /* multiplicative hashing */
+ tmp = dev;
+ tmp <<= HTBITS>>1;
+ tmp |= ino;
+ tmp *= HTCONST;
+ h = tmp >> (HTBITS - htshift);
+ h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */
+
+ /* open address hashtable search with double hash probing */
+ while (htable[h].ino || htable[h].dev) {
+ if ((htable[h].ino == ino) && (htable[h].dev == dev))
+ return 1;
+ h = (h + h2) & htmask;
+ }
+
+ /* Insert the current entry into hashtable */
+ htable[h].dev = dev;
+ htable[h].ino = ino;
+ htused++;
+ return 0;
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: du [-H | -L | -P] [-a | -d depth | -s] [-cgkmrx] [file ...]\n");
+ exit(1);
+}
diff --git a/package/toolbox/src/src/dynarray.c b/package/toolbox/src/src/dynarray.c
new file mode 100644
index 000000000..3714542e6
--- /dev/null
+++ b/package/toolbox/src/src/dynarray.c
@@ -0,0 +1,104 @@
+#include "dynarray.h"
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+void
+dynarray_init( dynarray_t *a )
+{
+ a->count = a->capacity = 0;
+ a->items = NULL;
+}
+
+
+static void
+dynarray_reserve_more( dynarray_t *a, int count )
+{
+ int old_cap = a->capacity;
+ int new_cap = old_cap;
+ const int max_cap = INT_MAX/sizeof(void*);
+ void** new_items;
+ int new_count = a->count + count;
+
+ if (count <= 0)
+ return;
+
+ if (count > max_cap - a->count)
+ abort();
+
+ new_count = a->count + count;
+
+ while (new_cap < new_count) {
+ old_cap = new_cap;
+ new_cap += (new_cap >> 2) + 4;
+ if (new_cap < old_cap || new_cap > max_cap) {
+ new_cap = max_cap;
+ }
+ }
+ new_items = realloc(a->items, new_cap*sizeof(void*));
+ if (new_items == NULL)
+ abort();
+
+ a->items = new_items;
+ a->capacity = new_cap;
+}
+
+void
+dynarray_append( dynarray_t *a, void* item )
+{
+ if (a->count >= a->capacity)
+ dynarray_reserve_more(a, 1);
+
+ a->items[a->count++] = item;
+}
+
+void
+dynarray_done( dynarray_t *a )
+{
+ free(a->items);
+ a->items = NULL;
+ a->count = a->capacity = 0;
+}
+
+// string arrays
+
+void strlist_init( strlist_t *list )
+{
+ dynarray_init(list);
+}
+
+void strlist_append_b( strlist_t *list, const void* str, size_t slen )
+{
+ char *copy = malloc(slen+1);
+ memcpy(copy, str, slen);
+ copy[slen] = '\0';
+ dynarray_append(list, copy);
+}
+
+void strlist_append_dup( strlist_t *list, const char *str)
+{
+ strlist_append_b(list, str, strlen(str));
+}
+
+void strlist_done( strlist_t *list )
+{
+ STRLIST_FOREACH(list, string, free(string));
+ dynarray_done(list);
+}
+
+static int strlist_compare_strings(const void* a, const void* b)
+{
+ const char *sa = *(const char **)a;
+ const char *sb = *(const char **)b;
+ return strcmp(sa, sb);
+}
+
+void strlist_sort( strlist_t *list )
+{
+ if (list->count > 0) {
+ qsort(list->items,
+ (size_t)list->count,
+ sizeof(void*),
+ strlist_compare_strings);
+ }
+}
diff --git a/package/toolbox/src/src/dynarray.h b/package/toolbox/src/src/dynarray.h
new file mode 100644
index 000000000..f73fb3b9c
--- /dev/null
+++ b/package/toolbox/src/src/dynarray.h
@@ -0,0 +1,80 @@
+#ifndef DYNARRAY_H
+#define DYNARRAY_H
+
+#include <stddef.h>
+
+/* simple dynamic array of pointers */
+typedef struct {
+ int count;
+ int capacity;
+ void** items;
+} dynarray_t;
+
+#define DYNARRAY_INITIALIZER { 0, 0, NULL }
+
+void dynarray_init( dynarray_t *a );
+void dynarray_done( dynarray_t *a );
+
+void dynarray_append( dynarray_t *a, void* item );
+
+/* Used to iterate over a dynarray_t
+ * _array :: pointer to the array
+ * _item_type :: type of objects pointed to by the array
+ * _item :: name of a local variable defined within the loop
+ * with type '_item_type'
+ * _stmnt :: C statement that will be executed in each iteration.
+ *
+ * You case use 'break' and 'continue' within _stmnt
+ *
+ * This macro is only intended for simple uses. I.e. do not add or
+ * remove items from the array during iteration.
+ */
+#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
+ do { \
+ int _nn_##__LINE__ = 0; \
+ for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
+ _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
+ _stmnt; \
+ } \
+ } while (0)
+
+#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
+ DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
+
+/* Simple dynamic string arrays
+ *
+ * NOTE: A strlist_t owns the strings it references.
+ */
+typedef dynarray_t strlist_t;
+
+#define STRLIST_INITIALIZER DYNARRAY_INITIALIZER
+
+/* Used to iterate over a strlist_t
+ * _list :: pointer to strlist_t object
+ * _string :: name of local variable name defined within the loop with
+ * type 'char*'
+ * _stmnt :: C statement executed in each iteration
+ *
+ * This macro is only intended for simple uses. Do not add or remove items
+ * to/from the list during iteration.
+ */
+#define STRLIST_FOREACH(_list,_string,_stmnt) \
+ DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
+
+void strlist_init( strlist_t *list );
+
+/* note: strlist_done will free all the strings owned by the list */
+void strlist_done( strlist_t *list );
+
+/* append a new string made of the first 'slen' characters from 'str'
+ * followed by a trailing zero.
+ */
+void strlist_append_b( strlist_t *list, const void* str, size_t slen );
+
+/* append the copy of a given input string to a strlist_t */
+void strlist_append_dup( strlist_t *list, const char *str);
+
+/* sort the strings in a given list (using strcmp) */
+void strlist_sort( strlist_t *list );
+
+#endif /* DYNARRAY_H */ \ No newline at end of file
diff --git a/package/toolbox/src/src/exists.c b/package/toolbox/src/src/exists.c
new file mode 100644
index 000000000..59c2a272b
--- /dev/null
+++ b/package/toolbox/src/src/exists.c
@@ -0,0 +1,16 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ struct stat s;
+
+ if(argc < 2) return 1;
+
+ if(stat(argv[1], &s)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
diff --git a/package/toolbox/src/src/hd.c b/package/toolbox/src/src/hd.c
new file mode 100644
index 000000000..333042fca
--- /dev/null
+++ b/package/toolbox/src/src/hd.c
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int fd;
+ unsigned char buf[4096];
+ int res;
+ int read_len;
+ int i;
+ int filepos = 0;
+ int sum;
+ int lsum;
+
+ int base = -1;
+ int count = 0;
+ int repeat = 0;
+
+ do {
+ c = getopt(argc, argv, "b:c:r:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'b':
+ base = strtol(optarg, NULL, 0);
+ break;
+ case 'c':
+ count = strtol(optarg, NULL, 0);
+ break;
+ case 'r':
+ repeat = strtol(optarg, NULL, 0);
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind + 1 != argc) {
+ fprintf(stderr, "Usage: %s [-b base] [-c count] [-r delay] file\n", argv[0]);
+ exit(1);
+ }
+
+ fd = open(argv[optind], O_RDONLY);
+ if(fd < 0) {
+ fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
+ return 1;
+ }
+
+ do {
+ if(base >= 0) {
+ lseek(fd, base, SEEK_SET);
+ filepos = base;
+ }
+ sum = 0;
+ lsum = 0;
+ while(1) {
+ read_len = sizeof(buf);
+ if(count > 0 && base + count - filepos < read_len)
+ read_len = base + count - filepos;
+ res = read(fd, &buf, read_len);
+ if(res == 0)
+ break;
+ for(i = 0; i < res; i++) {
+ if((i & 15) == 0) {
+ printf("%08x: ", filepos + i);
+ }
+ lsum += buf[i];
+ sum += buf[i];
+ printf("%02x ", buf[i]);
+ if(((i & 15) == 15) || (i == res - 1)) {
+ printf("s %x\n", lsum);
+ lsum = 0;
+ }
+ }
+ if(res < 0) {
+ printf("Read error on %s, offset %d len %d, %s\n", argv[optind], filepos, read_len, strerror(errno));
+ return 1;
+ }
+ filepos += res;
+ if(filepos == base + count)
+ break;
+ }
+ printf("sum %x\n", sum);
+ if(repeat)
+ sleep(repeat);
+ } while(repeat);
+ return 0;
+}
diff --git a/package/toolbox/src/src/id.c b/package/toolbox/src/src/id.c
new file mode 100644
index 000000000..60c0f0f6d
--- /dev/null
+++ b/package/toolbox/src/src/id.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+static void print_uid(uid_t uid)
+{
+ struct passwd *pw = getpwuid(uid);
+
+ if (pw) {
+ printf("%d(%s)", uid, pw->pw_name);
+ } else {
+ printf("%d",uid);
+ }
+}
+
+static void print_gid(gid_t gid)
+{
+ struct group *gr = getgrgid(gid);
+ if (gr) {
+ printf("%d(%s)", gid, gr->gr_name);
+ } else {
+ printf("%d",gid);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ gid_t list[64];
+ int n, max;
+
+ max = getgroups(64, list);
+ if (max < 0) max = 0;
+
+ printf("uid=");
+ print_uid(getuid());
+ printf(" gid=");
+ print_gid(getgid());
+ if (max) {
+ printf(" groups=");
+ print_gid(list[0]);
+ for(n = 1; n < max; n++) {
+ printf(",");
+ print_gid(list[n]);
+ }
+ }
+ printf("\n");
+ return 0;
+}
diff --git a/package/toolbox/src/src/ifconfig.c b/package/toolbox/src/src/ifconfig.c
new file mode 100644
index 000000000..510d3b555
--- /dev/null
+++ b/package/toolbox/src/src/ifconfig.c
@@ -0,0 +1,164 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <arpa/inet.h>
+
+static void die(const char *s)
+{
+ fprintf(stderr,"error: %s (%s)\n", s, strerror(errno));
+ exit(-1);
+}
+
+static void setflags(int s, struct ifreq *ifr, int set, int clr)
+{
+ if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) die("SIOCGIFFLAGS");
+ ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set;
+ if(ioctl(s, SIOCSIFFLAGS, ifr) < 0) die("SIOCSIFFLAGS");
+}
+
+static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
+{
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+ sin->sin_addr.s_addr = inet_addr(addr);
+}
+
+static void setmtu(int s, struct ifreq *ifr, const char *mtu)
+{
+ int m = atoi(mtu);
+ ifr->ifr_mtu = m;
+ if(ioctl(s, SIOCSIFMTU, ifr) < 0) die("SIOCSIFMTU");
+}
+static void setdstaddr(int s, struct ifreq *ifr, const char *addr)
+{
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_dstaddr, addr);
+ if(ioctl(s, SIOCSIFDSTADDR, ifr) < 0) die("SIOCSIFDSTADDR");
+}
+
+static void setnetmask(int s, struct ifreq *ifr, const char *addr)
+{
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr);
+ if(ioctl(s, SIOCSIFNETMASK, ifr) < 0) die("SIOCSIFNETMASK");
+}
+
+static void setaddr(int s, struct ifreq *ifr, const char *addr)
+{
+ init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr);
+ if(ioctl(s, SIOCSIFADDR, ifr) < 0) die("SIOCSIFADDR");
+}
+
+int main(int argc, char *argv[])
+{
+ struct ifreq ifr;
+ int s;
+ unsigned int addr, mask, flags;
+ char astring[20];
+ char mstring[20];
+ char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
+
+ argc--;
+ argv++;
+
+ if(argc == 0) return 0;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+ argc--, argv++;
+
+ if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ die("cannot open control socket\n");
+ }
+
+ if (argc == 0) {
+ if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return -1;
+ } else
+ addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+
+ if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return -1;
+ } else
+ mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return -1;
+ } else
+ flags = ifr.ifr_flags;
+
+ sprintf(astring, "%d.%d.%d.%d",
+ addr & 0xff,
+ ((addr >> 8) & 0xff),
+ ((addr >> 16) & 0xff),
+ ((addr >> 24) & 0xff));
+ sprintf(mstring, "%d.%d.%d.%d",
+ mask & 0xff,
+ ((mask >> 8) & 0xff),
+ ((mask >> 16) & 0xff),
+ ((mask >> 24) & 0xff));
+ printf("%s: ip %s mask %s flags [", ifr.ifr_name,
+ astring,
+ mstring
+ );
+
+ updown = (flags & IFF_UP) ? "up" : "down";
+ brdcst = (flags & IFF_BROADCAST) ? " broadcast" : "";
+ loopbk = (flags & IFF_LOOPBACK) ? " loopback" : "";
+ ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : "";
+ running = (flags & IFF_RUNNING) ? " running" : "";
+ multi = (flags & IFF_MULTICAST) ? " multicast" : "";
+ printf("%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi);
+ return 0;
+ }
+
+ while(argc > 0) {
+ if (!strcmp(argv[0], "up")) {
+ setflags(s, &ifr, IFF_UP, 0);
+ } else if (!strcmp(argv[0], "mtu")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting a value for parameter \"mtu\"");
+ }
+ setmtu(s, &ifr, argv[0]);
+ } else if (!strcmp(argv[0], "-pointopoint")) {
+ setflags(s, &ifr, IFF_POINTOPOINT, 1);
+ } else if (!strcmp(argv[0], "pointopoint")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting an IP address for parameter \"pointtopoint\"");
+ }
+ setdstaddr(s, &ifr, argv[0]);
+ setflags(s, &ifr, IFF_POINTOPOINT, 0);
+ } else if (!strcmp(argv[0], "down")) {
+ setflags(s, &ifr, 0, IFF_UP);
+ } else if (!strcmp(argv[0], "netmask")) {
+ argc--, argv++;
+ if (!argc) {
+ errno = EINVAL;
+ die("expecting an IP address for parameter \"netmask\"");
+ }
+ setnetmask(s, &ifr, argv[0]);
+ } else if (isdigit(argv[0][0])) {
+ setaddr(s, &ifr, argv[0]);
+ setflags(s, &ifr, IFF_UP, 0);
+ }
+ argc--, argv++;
+ }
+ return 0;
+}
diff --git a/package/toolbox/src/src/iftop.c b/package/toolbox/src/src/iftop.c
new file mode 100644
index 000000000..7bb946895
--- /dev/null
+++ b/package/toolbox/src/src/iftop.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#define PROC_NET_DEV "/proc/net/dev"
+
+#define MAX_IF 8 /* max interfaces we can handle */
+
+#ifndef PAGE_SIZE
+# define PAGE_SIZE 4096
+#endif
+
+#define _STR(s) #s
+#define STR(s) _STR(s)
+
+struct if_stats {
+ char name[IFNAMSIZ];
+
+ unsigned int mtu;
+
+ unsigned int rx_bytes;
+ unsigned int rx_packets;
+ unsigned int rx_errors;
+ unsigned int rx_dropped;
+
+ unsigned int tx_bytes;
+ unsigned int tx_packets;
+ unsigned int tx_errors;
+ unsigned int tx_dropped;
+};
+
+static int get_mtu(const char *if_name)
+{
+ struct ifreq ifr;
+ int s, ret;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ ifr.ifr_addr.sa_family = AF_INET;
+ strcpy(ifr.ifr_name, if_name);
+
+ ret = ioctl(s, SIOCGIFMTU, &ifr);
+ if (ret < 0) {
+ perror("ioctl");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = close(s);
+ if (ret < 0) {
+ perror("close");
+ exit(EXIT_FAILURE);
+ }
+
+ return ifr.ifr_mtu;
+}
+
+static int get_interfaces(struct if_stats *ifs)
+{
+ char buf[PAGE_SIZE];
+ char *p;
+ int ret, nr, fd;
+
+ fd = open(PROC_NET_DEV, O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = read(fd, buf, sizeof(buf) - 1);
+ if (ret < 0) {
+ perror("read");
+ exit(EXIT_FAILURE);
+ } else if (!ret) {
+ fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
+ exit(EXIT_FAILURE);
+ }
+ buf[ret] = '\0';
+
+ /* skip down to the third line */
+ p = strchr(buf, '\n');
+ if (!p) {
+ fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+ exit(EXIT_FAILURE);
+ }
+ p = strchr(p + 1, '\n');
+ if (!p) {
+ fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+ exit(EXIT_FAILURE);
+ }
+ p += 1;
+
+ /*
+ * Key:
+ * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
+ * (Tx) bytes packets errs drop fifo colls carrier compressed
+ */
+ for (nr = 0; nr < MAX_IF; nr++) {
+ char *c;
+
+ ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
+ if (ret != 1) {
+ fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * This works around a bug in the proc file where large interface names
+ * or Rx byte counts eat the delimiter, breaking sscanf.
+ */
+ c = strchr(ifs->name, ':');
+ if (c)
+ *c = '\0';
+
+ p = strchr(p, ':') + 1;
+
+ ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
+ "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
+ &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
+ &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
+ if (ret != 8) {
+ fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ifs->mtu = get_mtu(ifs->name);
+
+ p = strchr(p, '\n') + 1;
+ if (*p == '\0') {
+ nr++;
+ break;
+ }
+
+ ifs++;
+ }
+
+ ret = close(fd);
+ if (ret) {
+ perror("close");
+ exit(EXIT_FAILURE);
+ }
+
+ return nr;
+}
+
+static void print_header(void)
+{
+ printf(" Rx Tx\n");
+ printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
+ "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
+ "packets", "errs", "drpd");
+}
+
+static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
+{
+ int i = 0;
+
+ while (nr--) {
+ if (old->rx_packets || old->tx_packets) {
+ printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
+ new->name, new->mtu,
+ new->rx_bytes - old->rx_bytes,
+ new->rx_packets - old->rx_packets,
+ new->rx_errors - old->rx_errors,
+ new->rx_dropped - old->rx_dropped,
+ new->tx_bytes - old->tx_bytes,
+ new->tx_packets - old->tx_packets,
+ new->tx_errors - old->tx_errors,
+ new->tx_dropped - old->tx_dropped);
+ i++;
+ }
+ old++;
+ new++;
+ }
+
+ return i;
+}
+
+static void usage(const char *cmd)
+{
+ fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
+}
+
+int main(int argc, char *argv[])
+{
+ struct if_stats ifs[2][MAX_IF];
+ int count = 0, header_interval = 22, delay = 1, i;
+ unsigned int toggle = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-d")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -d requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ delay = atoi(argv[i++]);
+ if (!delay)
+ delay = 1;
+ continue;
+ }
+ if (!strcmp(argv[i], "-r")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -r requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ header_interval = atoi(argv[i++]);
+ if (header_interval < MAX_IF)
+ header_interval = MAX_IF;
+ continue;
+ }
+ if (!strcmp(argv[i], "-h")) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ get_interfaces(ifs[!toggle]);
+ if (header_interval)
+ print_header();
+ while (1) {
+ int nr;
+
+ sleep(delay);
+ nr = get_interfaces(ifs[toggle]);
+ if (header_interval && count + nr > header_interval) {
+ print_header();
+ count = 0;
+ }
+ count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
+ toggle = !toggle;
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/insmod.c b/package/toolbox/src/src/insmod.c
new file mode 100644
index 000000000..22e3d6160
--- /dev/null
+++ b/package/toolbox/src/src/insmod.c
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+extern int init_module(void *, unsigned long, const char *);
+
+static void *read_file(const char *filename, ssize_t *_size)
+{
+ int ret, fd;
+ struct stat sb;
+ ssize_t size;
+ void *buffer = NULL;
+
+ /* open the file */
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ /* find out how big it is */
+ if (fstat(fd, &sb) < 0)
+ goto bail;
+ size = sb.st_size;
+
+ /* allocate memory for it to be read into */
+ buffer = malloc(size);
+ if (!buffer)
+ goto bail;
+
+ /* slurp it into our buffer */
+ ret = read(fd, buffer, size);
+ if (ret != size)
+ goto bail;
+
+ /* let the caller know how big it is */
+ *_size = size;
+
+bail:
+ close(fd);
+ return buffer;
+}
+
+#define min(x,y) ((x) < (y) ? (x) : (y))
+int main(int argc, char **argv)
+{
+ void *file;
+ ssize_t size = 0;
+ char opts[1024];
+ int ret;
+
+ /* make sure we've got an argument */
+ if (argc < 2) {
+ fprintf(stderr, "usage: insmod <module.o>\n");
+ return -1;
+ }
+
+ /* read the file into memory */
+ file = read_file(argv[1], &size);
+ if (!file) {
+ fprintf(stderr, "insmod: can't open '%s'\n", argv[1]);
+ return -1;
+ }
+
+ opts[0] = '\0';
+ if (argc > 2) {
+ int i, len;
+ char *end = opts + sizeof(opts) - 1;
+ char *ptr = opts;
+
+ for (i = 2; (i < argc) && (ptr < end); i++) {
+ len = min(strlen(argv[i]), end - ptr);
+ memcpy(ptr, argv[i], len);
+ ptr += len;
+ *ptr++ = ' ';
+ }
+ *(ptr - 1) = '\0';
+ }
+
+ /* pass it to the kernel */
+ ret = init_module(file, size, opts);
+ if (ret != 0) {
+ fprintf(stderr,
+ "insmod: init_module '%s' failed (%s)\n",
+ argv[1], strerror(errno));
+ }
+
+ /* free the file buffer */
+ free(file);
+
+ return ret;
+}
+
diff --git a/package/toolbox/src/src/ioctl.c b/package/toolbox/src/src/ioctl.c
new file mode 100644
index 000000000..abc1bec79
--- /dev/null
+++ b/package/toolbox/src/src/ioctl.c
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <string.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int fd;
+ int res;
+
+ int length = -1;
+ int arg_size = 4;
+ int direct_arg = 0;
+ uint32_t ioctl_nr;
+ void *ioctl_args = NULL;
+ uint8_t *ioctl_argp;
+ uint8_t *ioctl_argp_save = NULL;
+ int rem;
+
+ do {
+ c = getopt(argc, argv, "rdl:a:h");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'd':
+ direct_arg = 1;
+ break;
+ case 'l':
+ length = strtol(optarg, NULL, 0);
+ break;
+ case 'a':
+ arg_size = strtol(optarg, NULL, 0);
+ break;
+ case 'h':
+ fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
+ " -l <lenght> Length of io buffer\n"
+ " -a <argsize> Size of each argument (1-8)\n"
+ " -r Open device in read only mode\n"
+ " -d Direct argument (no iobuffer)\n"
+ " -h Print help\n", argv[0]);
+ return -1;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if(optind + 2 > argc) {
+ fprintf(stderr, "%s: too few arguments\n", argv[0]);
+ exit(1);
+ }
+
+ fd = open(argv[optind], O_RDWR | O_SYNC);
+ if (fd < 0) {
+ fprintf(stderr, "cannot open %s\n", argv[optind]);
+ return 1;
+ }
+ optind++;
+
+ ioctl_nr = strtol(argv[optind], NULL, 0);
+ optind++;
+
+ if(direct_arg) {
+ arg_size = 4;
+ length = 4;
+ }
+
+ if(length < 0) {
+ length = (argc - optind) * arg_size;
+ }
+ if(length) {
+ ioctl_args = calloc(1, length);
+
+ ioctl_argp_save = ioctl_argp = ioctl_args;
+ rem = length;
+ while(optind < argc) {
+ uint64_t tmp = strtoull(argv[optind], NULL, 0);
+ if(rem < arg_size) {
+ fprintf(stderr, "%s: too many arguments\n", argv[0]);
+ exit(1);
+ }
+ memcpy(ioctl_argp, &tmp, arg_size);
+ ioctl_argp += arg_size;
+ rem -= arg_size;
+ optind++;
+ }
+ }
+ printf("sending ioctl 0x%x", ioctl_nr);
+ rem = length;
+ while(rem--) {
+ printf(" 0x%02x", *ioctl_argp_save++);
+ }
+ printf("\n");
+
+ if(direct_arg)
+ res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
+ else if(length)
+ res = ioctl(fd, ioctl_nr, ioctl_args);
+ else
+ res = ioctl(fd, ioctl_nr, 0);
+ if (res < 0) {
+ fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
+ return 1;
+ }
+ if(length) {
+ printf("return buf:");
+ ioctl_argp = ioctl_args;
+ rem = length;
+ while(rem--) {
+ printf(" %02x", *ioctl_argp++);
+ }
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/package/toolbox/src/src/kill.c b/package/toolbox/src/src/kill.c
new file mode 100644
index 000000000..994ad31b2
--- /dev/null
+++ b/package/toolbox/src/src/kill.c
@@ -0,0 +1,149 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <signal.h>
+
+static struct {
+ unsigned int number;
+ char *name;
+} signals[] = {
+#define _SIG(name) {SIG##name, #name}
+ /* Single Unix Specification signals */
+ _SIG(ABRT),
+ _SIG(ALRM),
+ _SIG(FPE),
+ _SIG(HUP),
+ _SIG(ILL),
+ _SIG(INT),
+ _SIG(KILL),
+ _SIG(PIPE),
+ _SIG(QUIT),
+ _SIG(SEGV),
+ _SIG(TERM),
+ _SIG(USR1),
+ _SIG(USR2),
+ _SIG(CHLD),
+ _SIG(CONT),
+ _SIG(STOP),
+ _SIG(TSTP),
+ _SIG(TTIN),
+ _SIG(TTOU),
+ _SIG(BUS),
+ _SIG(POLL),
+ _SIG(PROF),
+ _SIG(SYS),
+ _SIG(TRAP),
+ _SIG(URG),
+ _SIG(VTALRM),
+ _SIG(XCPU),
+ _SIG(XFSZ),
+ /* non-SUS signals */
+ _SIG(IO),
+ _SIG(PWR),
+#ifdef SIGSTKFLT
+ _SIG(STKFLT),
+#endif
+ _SIG(WINCH),
+#undef _SIG
+};
+
+/* To indicate a matching signal was not found */
+static const unsigned int SENTINEL = (unsigned int) -1;
+
+void list_signals()
+{
+ unsigned int sorted_signals[_NSIG];
+ unsigned int i;
+ unsigned int num;
+
+ memset(sorted_signals, SENTINEL, sizeof(sorted_signals));
+
+ // Sort the signals
+ for (i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) {
+ sorted_signals[signals[i].number] = i;
+ }
+
+ num = 0;
+ for (i = 1; i < _NSIG; i++) {
+ unsigned int index = sorted_signals[i];
+ if (index == SENTINEL) {
+ continue;
+ }
+
+ fprintf(stderr, "%2d) SIG%-9s ", i, signals[index].name);
+
+ if ((num++ % 4) == 3) {
+ fprintf(stderr, "\n");
+ }
+ }
+
+ if ((num % 4) == 3) {
+ fprintf(stderr, "\n");
+ }
+}
+
+unsigned int name_to_signal(const char* name)
+{
+ unsigned int i;
+
+ for (i = 1; i < sizeof(signals) / sizeof(signals[0]); i++) {
+ if (!strcasecmp(name, signals[i].name)) {
+ return signals[i].number;
+ }
+ }
+
+ return SENTINEL;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned int sig = SIGTERM;
+ int result = 0;
+
+ argc--;
+ argv++;
+
+ if (argc >= 1 && argv[0][0] == '-') {
+ char *endptr;
+ size_t arg_len = strlen(argv[0]);
+ if (arg_len < 2) {
+ fprintf(stderr, "invalid argument: -\n");
+ return -1;
+ }
+
+ char* arg = argv[0] + 1;
+ if (arg_len == 2 && *arg == 'l') {
+ list_signals();
+ return 0;
+ }
+
+ sig = strtol(arg, &endptr, 10);
+ if (*endptr != '\0') {
+ sig = name_to_signal(arg);
+ if (sig == SENTINEL) {
+ fprintf(stderr, "invalid signal name: %s\n", arg);
+ return -1;
+ }
+ }
+
+ argc--;
+ argv++;
+ }
+
+ while(argc > 0){
+ int pid = atoi(argv[0]);
+ int err = kill(pid, sig);
+ if (err < 0) {
+ result = err;
+ fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno));
+ }
+
+ argc--;
+ argv++;
+ }
+
+ return result;
+}
diff --git a/package/toolbox/src/src/ln.c b/package/toolbox/src/src/ln.c
new file mode 100644
index 000000000..6d67823e8
--- /dev/null
+++ b/package/toolbox/src/src/ln.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static int usage()
+{
+ fprintf(stderr,"ln [-s] <target> <name>\n");
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int symbolic = 0;
+ int ret;
+ if(argc < 2) return usage();
+
+ if(!strcmp(argv[1],"-s")) {
+ symbolic = 1;
+ argc--;
+ argv++;
+ }
+
+ if(argc < 3) return usage();
+
+ if(symbolic) {
+ ret = symlink(argv[1], argv[2]);
+ } else {
+ ret = link(argv[1], argv[2]);
+ }
+ if(ret < 0)
+ fprintf(stderr, "link failed %s\n", strerror(errno));
+ return ret;
+}
diff --git a/package/toolbox/src/src/ls.c b/package/toolbox/src/src/ls.c
new file mode 100644
index 000000000..a56bfaa87
--- /dev/null
+++ b/package/toolbox/src/src/ls.c
@@ -0,0 +1,424 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <pwd.h>
+#include <grp.h>
+
+#include <linux/kdev_t.h>
+#include <limits.h>
+
+#include "dynarray.h"
+
+// bits for flags argument
+#define LIST_LONG (1 << 0)
+#define LIST_ALL (1 << 1)
+#define LIST_RECURSIVE (1 << 2)
+#define LIST_DIRECTORIES (1 << 3)
+#define LIST_SIZE (1 << 4)
+#define LIST_LONG_NUMERIC (1 << 5)
+#define LIST_CLASSIFY (1 << 6)
+#define LIST_INODE (1 << 8)
+
+// fwd
+static int listpath(const char *name, int flags);
+
+static char mode2kind(unsigned mode)
+{
+ switch(mode & S_IFMT){
+ case S_IFSOCK: return 's';
+ case S_IFLNK: return 'l';
+ case S_IFREG: return '-';
+ case S_IFDIR: return 'd';
+ case S_IFBLK: return 'b';
+ case S_IFCHR: return 'c';
+ case S_IFIFO: return 'p';
+ default: return '?';
+ }
+}
+
+static void mode2str(unsigned mode, char *out)
+{
+ *out++ = mode2kind(mode);
+
+ *out++ = (mode & 0400) ? 'r' : '-';
+ *out++ = (mode & 0200) ? 'w' : '-';
+ if(mode & 04000) {
+ *out++ = (mode & 0100) ? 's' : 'S';
+ } else {
+ *out++ = (mode & 0100) ? 'x' : '-';
+ }
+ *out++ = (mode & 040) ? 'r' : '-';
+ *out++ = (mode & 020) ? 'w' : '-';
+ if(mode & 02000) {
+ *out++ = (mode & 010) ? 's' : 'S';
+ } else {
+ *out++ = (mode & 010) ? 'x' : '-';
+ }
+ *out++ = (mode & 04) ? 'r' : '-';
+ *out++ = (mode & 02) ? 'w' : '-';
+ if(mode & 01000) {
+ *out++ = (mode & 01) ? 't' : 'T';
+ } else {
+ *out++ = (mode & 01) ? 'x' : '-';
+ }
+ *out = 0;
+}
+
+static void user2str(unsigned uid, char *out)
+{
+ struct passwd *pw = getpwuid(uid);
+ if(pw) {
+ strcpy(out, pw->pw_name);
+ } else {
+ sprintf(out, "%d", uid);
+ }
+}
+
+static void group2str(unsigned gid, char *out)
+{
+ struct group *gr = getgrgid(gid);
+ if(gr) {
+ strcpy(out, gr->gr_name);
+ } else {
+ sprintf(out, "%d", gid);
+ }
+}
+
+static int show_total_size(const char *dirname, DIR *d, int flags)
+{
+ struct dirent *de;
+ char tmp[1024];
+ struct stat s;
+ int sum = 0;
+
+ /* run through the directory and sum up the file block sizes */
+ while ((de = readdir(d)) != 0) {
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+ if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
+ continue;
+
+ if (strcmp(dirname, "/") == 0)
+ snprintf(tmp, sizeof(tmp), "/%s", de->d_name);
+ else
+ snprintf(tmp, sizeof(tmp), "%s/%s", dirname, de->d_name);
+
+ if (lstat(tmp, &s) < 0) {
+ fprintf(stderr, "stat failed on %s: %s\n", tmp, strerror(errno));
+ rewinddir(d);
+ return -1;
+ }
+
+ sum += s.st_blocks / 2;
+ }
+
+ printf("total %d\n", sum);
+ rewinddir(d);
+ return 0;
+}
+
+static int listfile_size(const char *path, const char *filename, struct stat *s,
+ int flags)
+{
+ if(!s || !path) {
+ return -1;
+ }
+
+ /* blocks are 512 bytes, we want output to be KB */
+ if ((flags & LIST_SIZE) != 0) {
+ printf("%lld ", (long long)(s->st_blocks / 2));
+ }
+
+ if ((flags & LIST_CLASSIFY) != 0) {
+ char filetype = mode2kind(s->st_mode);
+ if (filetype != 'l') {
+ printf("%c ", filetype);
+ } else {
+ struct stat link_dest;
+ if (!stat(path, &link_dest)) {
+ printf("l%c ", mode2kind(link_dest.st_mode));
+ } else {
+ fprintf(stderr, "stat '%s' failed: %s\n", path, strerror(errno));
+ printf("l? ");
+ }
+ }
+ }
+
+ printf("%s\n", filename);
+
+ return 0;
+}
+
+static int listfile_long(const char *path, struct stat *s, int flags)
+{
+ char date[32];
+ char mode[16];
+ char user[16];
+ char group[16];
+ const char *name;
+
+ if(!s || !path) {
+ return -1;
+ }
+
+ /* name is anything after the final '/', or the whole path if none*/
+ name = strrchr(path, '/');
+ if(name == 0) {
+ name = path;
+ } else {
+ name++;
+ }
+
+ mode2str(s->st_mode, mode);
+ if (flags & LIST_LONG_NUMERIC) {
+ sprintf(user, "%ld", (long)s->st_uid);
+ sprintf(group, "%ld", (long)s->st_gid);
+ } else {
+ user2str(s->st_uid, user);
+ group2str(s->st_gid, group);
+ }
+
+ strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s->st_mtime));
+ date[31] = 0;
+
+// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
+// MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK)
+
+ switch(s->st_mode & S_IFMT) {
+ case S_IFBLK:
+ case S_IFCHR:
+ printf("%s %-8s %-8s %3d, %3d %s %s\n",
+ mode, user, group,
+ (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev),
+ date, name);
+ break;
+ case S_IFREG:
+ printf("%s %-8s %-8s %8lld %s %s\n",
+ mode, user, group, (long long)s->st_size, date, name);
+ break;
+ case S_IFLNK: {
+ char linkto[256];
+ int len;
+
+ len = readlink(path, linkto, 256);
+ if(len < 0) return -1;
+
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+
+ printf("%s %-8s %-8s %s %s -> %s\n",
+ mode, user, group, date, name, linkto);
+ break;
+ }
+ default:
+ printf("%s %-8s %-8s %s %s\n",
+ mode, user, group, date, name);
+
+ }
+ return 0;
+}
+
+static int listfile(const char *dirname, const char *filename, int flags)
+{
+ struct stat s;
+
+ if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_INODE)) == 0) {
+ printf("%s\n", filename);
+ return 0;
+ }
+
+ char tmp[4096];
+ const char* pathname = filename;
+
+ if (dirname != NULL) {
+ snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename);
+ pathname = tmp;
+ } else {
+ pathname = filename;
+ }
+
+ if(lstat(pathname, &s) < 0) {
+ return -1;
+ }
+
+ if(flags & LIST_INODE) {
+ printf("%8llu ", (unsigned long long)s.st_ino);
+ }
+
+ if ((flags & LIST_LONG) != 0) {
+ return listfile_long(pathname, &s, flags);
+ } else /*((flags & LIST_SIZE) != 0)*/ {
+ return listfile_size(pathname, filename, &s, flags);
+ }
+}
+
+static int listdir(const char *name, int flags)
+{
+ char tmp[4096];
+ DIR *d;
+ struct dirent *de;
+ strlist_t files = STRLIST_INITIALIZER;
+
+ d = opendir(name);
+ if(d == 0) {
+ fprintf(stderr, "opendir failed, %s\n", strerror(errno));
+ return -1;
+ }
+
+ if ((flags & LIST_SIZE) != 0) {
+ show_total_size(name, d, flags);
+ }
+
+ while((de = readdir(d)) != 0){
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
+ if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue;
+
+ strlist_append_dup(&files, de->d_name);
+ }
+
+ strlist_sort(&files);
+ STRLIST_FOREACH(&files, filename, listfile(name, filename, flags));
+ strlist_done(&files);
+
+ if (flags & LIST_RECURSIVE) {
+ strlist_t subdirs = STRLIST_INITIALIZER;
+
+ rewinddir(d);
+
+ while ((de = readdir(d)) != 0) {
+ struct stat s;
+ int err;
+
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+ if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
+ continue;
+
+ if (!strcmp(name, "/"))
+ snprintf(tmp, sizeof(tmp), "/%s", de->d_name);
+ else
+ snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name);
+
+ /*
+ * If the name ends in a '/', use stat() so we treat it like a
+ * directory even if it's a symlink.
+ */
+ if (tmp[strlen(tmp)-1] == '/')
+ err = stat(tmp, &s);
+ else
+ err = lstat(tmp, &s);
+
+ if (err < 0) {
+ perror(tmp);
+ closedir(d);
+ return -1;
+ }
+
+ if (S_ISDIR(s.st_mode)) {
+ strlist_append_dup(&subdirs, tmp);
+ }
+ }
+ strlist_sort(&subdirs);
+ STRLIST_FOREACH(&subdirs, path, {
+ printf("\n%s:\n", path);
+ listdir(path, flags);
+ });
+ strlist_done(&subdirs);
+ }
+
+ closedir(d);
+ return 0;
+}
+
+static int listpath(const char *name, int flags)
+{
+ struct stat s;
+ int err;
+
+ /*
+ * If the name ends in a '/', use stat() so we treat it like a
+ * directory even if it's a symlink.
+ */
+ if (name[strlen(name)-1] == '/')
+ err = stat(name, &s);
+ else
+ err = lstat(name, &s);
+
+ if (err < 0) {
+ perror(name);
+ return -1;
+ }
+
+ if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) {
+ if (flags & LIST_RECURSIVE)
+ printf("\n%s:\n", name);
+ return listdir(name, flags);
+ } else {
+ /* yeah this calls stat() again*/
+ return listfile(NULL, name, flags);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int flags = 0;
+
+ if(argc > 1) {
+ int i;
+ int err = 0;
+ strlist_t files = STRLIST_INITIALIZER;
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ /* an option ? */
+ const char *arg = argv[i]+1;
+ while (arg[0]) {
+ switch (arg[0]) {
+ case 'l': flags |= LIST_LONG; break;
+ case 'n': flags |= LIST_LONG | LIST_LONG_NUMERIC; break;
+ case 's': flags |= LIST_SIZE; break;
+ case 'R': flags |= LIST_RECURSIVE; break;
+ case 'd': flags |= LIST_DIRECTORIES; break;
+ case 'a': flags |= LIST_ALL; break;
+ case 'F': flags |= LIST_CLASSIFY; break;
+ case 'i': flags |= LIST_INODE; break;
+ default:
+ fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
+ exit(1);
+ }
+ arg++;
+ }
+ } else {
+ /* not an option ? */
+ strlist_append_dup(&files, argv[i]);
+ }
+ }
+
+ if (files.count > 0) {
+ STRLIST_FOREACH(&files, path, {
+ if (listpath(path, flags) != 0) {
+ err = EXIT_FAILURE;
+ }
+ });
+ strlist_done(&files);
+ return err;
+ }
+ }
+
+ // list working directory if no files or directories were specified
+ return listpath(".", flags);
+}
diff --git a/package/toolbox/src/src/lsof.c b/package/toolbox/src/src/lsof.c
new file mode 100644
index 000000000..c4d9c5f30
--- /dev/null
+++ b/package/toolbox/src/src/lsof.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pwd.h>
+#include <sys/stat.h>
+
+#define BUF_MAX 1024
+#define CMD_DISPLAY_MAX (9 + 1)
+#define USER_DISPLAY_MAX (10 + 1)
+
+struct pid_info_t {
+ pid_t pid;
+ char user[USER_DISPLAY_MAX];
+
+ char cmdline[CMD_DISPLAY_MAX];
+
+ char path[PATH_MAX];
+ ssize_t parent_length;
+};
+
+static void print_header()
+{
+ printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
+ "COMMAND",
+ "PID",
+ "USER",
+ "FD",
+ "TYPE",
+ "DEVICE",
+ "SIZE/OFF",
+ "NODE",
+ "NAME");
+}
+
+static void print_type(char *type, struct pid_info_t* info)
+{
+ static ssize_t link_dest_size;
+ static char link_dest[PATH_MAX + 64];
+
+ strlcat(info->path, type, sizeof(info->path));
+ if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) {
+ if (errno == ENOENT)
+ goto out;
+
+ snprintf(link_dest, sizeof(link_dest), "%s (readlink: %s)", info->path, strerror(errno));
+ } else {
+ link_dest[link_dest_size] = '\0';
+ }
+
+ // Things that are just the root filesystem are uninteresting (we already know)
+ if (!strcmp(link_dest, "/"))
+ goto out;
+
+ printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
+ info->cmdline, info->pid, info->user, type,
+ "???", "???", "???", "???", link_dest);
+
+out:
+ info->path[info->parent_length] = '\0';
+}
+
+// Prints out all file that have been memory mapped
+static void print_maps(struct pid_info_t* info)
+{
+ FILE *maps;
+ size_t offset;
+ char device[10];
+ long int inode;
+ char file[PATH_MAX];
+
+ strlcat(info->path, "maps", sizeof(info->path));
+
+ maps = fopen(info->path, "r");
+ if (!maps)
+ goto out;
+
+ while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %s\n", &offset, device, &inode,
+ file) == 4) {
+ // We don't care about non-file maps
+ if (inode == 0 || !strcmp(device, "00:00"))
+ continue;
+
+ printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n",
+ info->cmdline, info->pid, info->user, "mem",
+ "???", device, offset, inode, file);
+ }
+
+ fclose(maps);
+
+out:
+ info->path[info->parent_length] = '\0';
+}
+
+// Prints out all open file descriptors
+static void print_fds(struct pid_info_t* info)
+{
+ static char* fd_path = "fd/";
+ strlcat(info->path, fd_path, sizeof(info->path));
+
+ int previous_length = info->parent_length;
+ info->parent_length += strlen(fd_path);
+
+ DIR *dir = opendir(info->path);
+ if (dir == NULL) {
+ char msg[PATH_MAX + 64];
+ snprintf(msg, sizeof(msg), "%s (opendir: %s)", info->path, strerror(errno));
+ printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
+ info->cmdline, info->pid, info->user, "FDS",
+ "", "", "", "", msg);
+ goto out;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ print_type(de->d_name, info);
+ }
+ closedir(dir);
+
+out:
+ info->parent_length = previous_length;
+ info->path[info->parent_length] = '\0';
+}
+
+static void lsof_dumpinfo(pid_t pid)
+{
+ int fd;
+ struct pid_info_t info;
+ struct stat pidstat;
+ struct passwd *pw;
+
+ info.pid = pid;
+ snprintf(info.path, sizeof(info.path), "/proc/%d/", pid);
+ info.parent_length = strlen(info.path);
+
+ // Get the UID by calling stat on the proc/pid directory.
+ if (!stat(info.path, &pidstat)) {
+ pw = getpwuid(pidstat.st_uid);
+ if (pw) {
+ strlcpy(info.user, pw->pw_name, sizeof(info.user));
+ } else {
+ snprintf(info.user, USER_DISPLAY_MAX, "%d", (int)pidstat.st_uid);
+ }
+ } else {
+ strcpy(info.user, "???");
+ }
+
+ // Read the command line information; each argument is terminated with NULL.
+ strlcat(info.path, "cmdline", sizeof(info.path));
+ fd = open(info.path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Couldn't read %s\n", info.path);
+ return;
+ }
+
+ char cmdline[PATH_MAX];
+ int numRead = read(fd, cmdline, sizeof(cmdline) - 1);
+ close(fd);
+
+ if (numRead < 0) {
+ fprintf(stderr, "Error reading cmdline: %s: %s\n", info.path, strerror(errno));
+ return;
+ }
+
+ cmdline[numRead] = '\0';
+
+ // We only want the basename of the cmdline
+ strlcpy(info.cmdline, basename(cmdline), sizeof(info.cmdline));
+
+ // Read each of these symlinks
+ print_type("cwd", &info);
+ print_type("exe", &info);
+ print_type("root", &info);
+
+ print_fds(&info);
+ print_maps(&info);
+}
+
+int main(int argc, char *argv[])
+{
+ long int pid = 0;
+ char* endptr;
+ if (argc == 2) {
+ pid = strtol(argv[1], &endptr, 10);
+ }
+
+ print_header();
+
+ if (pid) {
+ lsof_dumpinfo(pid);
+ } else {
+ DIR *dir = opendir("/proc");
+ if (dir == NULL) {
+ fprintf(stderr, "Couldn't open /proc\n");
+ return -1;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ // Only inspect directories that are PID numbers
+ pid = strtol(de->d_name, &endptr, 10);
+ if (*endptr != '\0')
+ continue;
+
+ lsof_dumpinfo(pid);
+ }
+ closedir(dir);
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/md5.c b/package/toolbox/src/src/md5.c
new file mode 100644
index 000000000..3261c7fae
--- /dev/null
+++ b/package/toolbox/src/src/md5.c
@@ -0,0 +1,75 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <md5.h>
+
+static int usage()
+{
+ fprintf(stderr,"md5 file ...\n");
+ return -1;
+}
+
+static int do_md5(const char *path)
+{
+ unsigned int i;
+ int fd;
+ MD5_CTX md5_ctx;
+ unsigned char md5[MD5_DIGEST_LENGTH];
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr,"could not open %s, %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ /* Note that bionic's MD5_* functions return void. */
+ MD5Init(&md5_ctx);
+
+ while (1) {
+ char buf[4096];
+ ssize_t rlen;
+ rlen = read(fd, buf, sizeof(buf));
+ if (rlen == 0)
+ break;
+ else if (rlen < 0) {
+ (void)close(fd);
+ fprintf(stderr,"could not read %s, %s\n", path, strerror(errno));
+ return -1;
+ }
+ MD5Update(&md5_ctx, (const void *)buf, rlen);
+ }
+ if (close(fd)) {
+ fprintf(stderr,"could not close %s, %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ MD5Final(md5, &md5_ctx);
+
+ for (i = 0; i < (int)sizeof(md5); i++)
+ printf("%02x", md5[i]);
+ printf(" %s\n", path);
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2)
+ return usage();
+
+ /* loop over the file args */
+ for (i = 1; i < argc; i++) {
+ if (do_md5(argv[i]))
+ ret = 1;
+ }
+
+ return ret;
+}
diff --git a/package/toolbox/src/src/mkdir.c b/package/toolbox/src/src/mkdir.c
new file mode 100644
index 000000000..e0b701291
--- /dev/null
+++ b/package/toolbox/src/src/mkdir.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+static int usage()
+{
+ fprintf(stderr,"mkdir [OPTION] <target>\n");
+ fprintf(stderr," --help display usage and exit\n");
+ fprintf(stderr," -p, --parents create parent directories as needed\n");
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ if(argc < 2 || strcmp(argv[1], "--help") == 0) {
+ return usage();
+ }
+
+ int recursive = (strcmp(argv[1], "-p") == 0 ||
+ strcmp(argv[1], "--parents") == 0) ? 1 : 0;
+
+ if(recursive && argc < 3) {
+ // -p specified without a path
+ return usage();
+ }
+
+ if(recursive) {
+ argc--;
+ argv++;
+ }
+
+ char currpath[PATH_MAX], *pathpiece;
+ struct stat st;
+
+ while(argc > 1) {
+ argc--;
+ argv++;
+ if(recursive) {
+ // reset path
+ strcpy(currpath, "");
+ // create the pieces of the path along the way
+ pathpiece = strtok(argv[0], "/");
+ if(argv[0][0] == '/') {
+ // prepend / if needed
+ strcat(currpath, "/");
+ }
+ while(pathpiece != NULL) {
+ if(strlen(currpath) + strlen(pathpiece) + 2/*NUL and slash*/ > PATH_MAX) {
+ fprintf(stderr, "Invalid path specified: too long\n");
+ return 1;
+ }
+ strcat(currpath, pathpiece);
+ strcat(currpath, "/");
+ if(stat(currpath, &st) != 0) {
+ ret = mkdir(currpath, 0777);
+ if(ret < 0) {
+ fprintf(stderr, "mkdir failed for %s, %s\n", currpath, strerror(errno));
+ return ret;
+ }
+ }
+ pathpiece = strtok(NULL, "/");
+ }
+ } else {
+ ret = mkdir(argv[0], 0777);
+ if(ret < 0) {
+ fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno));
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/mount.c b/package/toolbox/src/src/mount.c
new file mode 100644
index 000000000..af7e5c182
--- /dev/null
+++ b/package/toolbox/src/src/mount.c
@@ -0,0 +1,360 @@
+/*
+ * mount.c, by rmk
+ */
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/loop.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#define DEFAULT_LOOP_DEVICE "/dev/block/loop0"
+#define LOOPDEV_MAXLEN 64
+
+struct mount_opts {
+ const char str[16];
+ unsigned long rwmask;
+ unsigned long rwset;
+ unsigned long rwnoset;
+};
+
+struct extra_opts {
+ char *str;
+ char *end;
+ int used_size;
+ int alloc_size;
+};
+
+/*
+ * These options define the function of "mount(2)".
+ */
+#define MS_TYPE (MS_REMOUNT|MS_BIND|MS_MOVE)
+
+
+static const struct mount_opts options[] = {
+ /* name mask set noset */
+ { "async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS },
+ { "atime", MS_NOATIME, 0, MS_NOATIME },
+ { "bind", MS_TYPE, MS_BIND, 0, },
+ { "dev", MS_NODEV, 0, MS_NODEV },
+ { "diratime", MS_NODIRATIME, 0, MS_NODIRATIME },
+ { "dirsync", MS_DIRSYNC, MS_DIRSYNC, 0 },
+ { "exec", MS_NOEXEC, 0, MS_NOEXEC },
+ { "move", MS_TYPE, MS_MOVE, 0 },
+ { "recurse", MS_REC, MS_REC, 0 },
+ { "rec", MS_REC, MS_REC, 0 },
+ { "remount", MS_TYPE, MS_REMOUNT, 0 },
+ { "ro", MS_RDONLY, MS_RDONLY, 0 },
+ { "rw", MS_RDONLY, 0, MS_RDONLY },
+ { "suid", MS_NOSUID, 0, MS_NOSUID },
+ { "sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0 },
+ { "verbose", MS_SILENT, MS_SILENT, 0 },
+ { "unbindable", MS_UNBINDABLE, MS_UNBINDABLE, 0 },
+ { "private", MS_PRIVATE, MS_PRIVATE, 0 },
+ { "slave", MS_SLAVE, MS_SLAVE, 0 },
+ { "shared", MS_SHARED, MS_SHARED, 0 },
+};
+
+static void add_extra_option(struct extra_opts *extra, char *s)
+{
+ int len = strlen(s);
+ int newlen;
+
+ if (extra->str)
+ len++; /* +1 for ',' */
+ newlen = extra->used_size + len;
+
+ if (newlen >= extra->alloc_size) {
+ char *new;
+
+ new = realloc(extra->str, newlen + 1); /* +1 for NUL */
+ if (!new)
+ return;
+
+ extra->str = new;
+ extra->end = extra->str + extra->used_size;
+ extra->alloc_size = newlen + 1;
+ }
+
+ if (extra->used_size) {
+ *extra->end = ',';
+ extra->end++;
+ }
+ strcpy(extra->end, s);
+ extra->used_size += len;
+
+}
+
+static unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra, int* loop, char *loopdev)
+{
+ char *s;
+
+ *loop = 0;
+ while ((s = strsep(&arg, ",")) != NULL) {
+ char *opt = s;
+ unsigned int i;
+ int res, no = s[0] == 'n' && s[1] == 'o';
+
+ if (no)
+ s += 2;
+
+ if (strncmp(s, "loop=", 5) == 0) {
+ *loop = 1;
+ strlcpy(loopdev, s + 5, LOOPDEV_MAXLEN);
+ continue;
+ }
+
+ if (strcmp(s, "loop") == 0) {
+ *loop = 1;
+ strlcpy(loopdev, DEFAULT_LOOP_DEVICE, LOOPDEV_MAXLEN);
+ continue;
+ }
+ for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
+ res = strcmp(s, options[i].str);
+
+ if (res == 0) {
+ rwflag &= ~options[i].rwmask;
+ if (no)
+ rwflag |= options[i].rwnoset;
+ else
+ rwflag |= options[i].rwset;
+ }
+ if (res <= 0)
+ break;
+ }
+
+ if (res != 0 && s[0])
+ add_extra_option(extra, opt);
+ }
+
+ return rwflag;
+}
+
+/*
+ * Mark the given block device as read-write, using the BLKROSET ioctl.
+ */
+static void fs_set_blk_rw(const char *blockdev)
+{
+ int fd;
+ int OFF = 0;
+
+ fd = open(blockdev, O_RDONLY);
+ if (fd < 0) {
+ // should never happen
+ return;
+ }
+
+ ioctl(fd, BLKROSET, &OFF);
+ close(fd);
+}
+
+static char *progname;
+
+static struct extra_opts extra;
+static unsigned long rwflag;
+
+static int
+do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data, int loop,
+ char *loopdev)
+{
+ char *s;
+ int error = 0;
+
+ if (loop) {
+ int file_fd, device_fd;
+ int flags;
+
+ flags = (rwflag & MS_RDONLY) ? O_RDONLY : O_RDWR;
+
+ file_fd = open(dev, flags);
+ if (file_fd < 0) {
+ perror("open backing file failed");
+ return 1;
+ }
+ device_fd = open(loopdev, flags);
+ if (device_fd < 0) {
+ perror("open loop device failed");
+ close(file_fd);
+ return 1;
+ }
+ if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) {
+ perror("ioctl LOOP_SET_FD failed");
+ close(file_fd);
+ close(device_fd);
+ return 1;
+ }
+
+ close(file_fd);
+ close(device_fd);
+ dev = loopdev;
+ }
+
+ if ((rwflag & MS_RDONLY) == 0) {
+ fs_set_blk_rw(dev);
+ }
+
+ while ((s = strsep(&type, ",")) != NULL) {
+retry:
+ if (mount(dev, dir, s, rwflag, data) == -1) {
+ error = errno;
+ /*
+ * If the filesystem is not found, or the
+ * superblock is invalid, try the next.
+ */
+ if (error == ENODEV || error == EINVAL)
+ continue;
+
+ /*
+ * If we get EACCESS, and we're trying to
+ * mount readwrite and this isn't a remount,
+ * try read only.
+ */
+ if (error == EACCES &&
+ (rwflag & (MS_REMOUNT|MS_RDONLY)) == 0) {
+ rwflag |= MS_RDONLY;
+ goto retry;
+ }
+ break;
+ }
+ }
+
+ if (error) {
+ errno = error;
+ perror("mount");
+ return 255;
+ }
+
+ return 0;
+}
+
+static int print_mounts()
+{
+ FILE* f;
+ int length;
+ char buffer[100];
+
+ f = fopen("/proc/mounts", "r");
+ if (!f) {
+ fprintf(stdout, "could not open /proc/mounts\n");
+ return -1;
+ }
+
+ do {
+ length = fread(buffer, 1, 100, f);
+ if (length > 0)
+ fwrite(buffer, 1, length, stdout);
+ } while (length > 0);
+
+ fclose(f);
+ return 0;
+}
+
+static int get_mounts_dev_dir(const char *arg, char **dev, char **dir)
+{
+ FILE *f;
+ char mount_dev[256];
+ char mount_dir[256];
+ char mount_type[256];
+ char mount_opts[256];
+ int mount_freq;
+ int mount_passno;
+ int match;
+
+ f = fopen("/proc/mounts", "r");
+ if (!f) {
+ fprintf(stdout, "could not open /proc/mounts\n");
+ return -1;
+ }
+
+ do {
+ match = fscanf(f, "%255s %255s %255s %255s %d %d\n",
+ mount_dev, mount_dir, mount_type,
+ mount_opts, &mount_freq, &mount_passno);
+ mount_dev[255] = 0;
+ mount_dir[255] = 0;
+ mount_type[255] = 0;
+ mount_opts[255] = 0;
+ if (match == 6 &&
+ (strcmp(arg, mount_dev) == 0 ||
+ strcmp(arg, mount_dir) == 0)) {
+ *dev = strdup(mount_dev);
+ *dir = strdup(mount_dir);
+ fclose(f);
+ return 0;
+ }
+ } while (match != EOF);
+
+ fclose(f);
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ char *type = NULL;
+ char *dev = NULL;
+ char *dir = NULL;
+ int c;
+ int loop = 0;
+ char loopdev[LOOPDEV_MAXLEN];
+
+ progname = argv[0];
+ rwflag = MS_SILENT;
+
+ // mount with no arguments is equivalent to "cat /proc/mounts"
+ if (argc == 1) return print_mounts();
+
+ do {
+ c = getopt(argc, argv, "o:rt:w");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'o':
+ rwflag = parse_mount_options(optarg, rwflag, &extra, &loop, loopdev);
+ break;
+ case 'r':
+ rwflag |= MS_RDONLY;
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'w':
+ rwflag &= ~MS_RDONLY;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ /*
+ * If remount, bind or move was specified, then we don't
+ * have a "type" as such. Use the dummy "none" type.
+ */
+ if (rwflag & MS_TYPE)
+ type = "none";
+
+ if (optind + 2 == argc) {
+ dev = argv[optind];
+ dir = argv[optind + 1];
+ } else if (optind + 1 == argc && rwflag & MS_REMOUNT) {
+ get_mounts_dev_dir(argv[optind], &dev, &dir);
+ }
+
+ if (dev == NULL || dir == NULL || type == NULL) {
+ fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] "
+ "device directory\n", progname);
+ exit(1);
+ }
+
+ return do_mount(dev, dir, type, rwflag, extra.str, loop, loopdev);
+ /* We leak dev and dir in some cases, but we're about to exit */
+}
diff --git a/package/toolbox/src/src/mv.c b/package/toolbox/src/src/mv.c
new file mode 100644
index 000000000..d5406b8ac
--- /dev/null
+++ b/package/toolbox/src/src/mv.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+int main(int argc, char *argv[])
+{
+ const char* dest;
+ struct stat st;
+ int i;
+
+ if (argc < 3) {
+ fprintf(stderr,"USAGE: %s <source...> <destination>\n", argv[0]);
+ return -1;
+ }
+
+ /* check if destination exists */
+ dest = argv[argc - 1];
+ if (stat(dest, &st)) {
+ /* an error, unless the destination was missing */
+ if (errno != ENOENT) {
+ fprintf(stderr, "failed on %s - %s\n", dest, strerror(errno));
+ return -1;
+ }
+ st.st_mode = 0;
+ }
+
+ for (i = 1; i < argc - 1; i++) {
+ const char *source = argv[i];
+ char fullDest[PATH_MAX + 1 + PATH_MAX + 1];
+ /* assume we build "dest/source", and let rename() fail on pathsize */
+ if (strlen(dest) + 1 + strlen(source) + 1 > sizeof(fullDest)) {
+ fprintf(stderr, "path too long\n");
+ return -1;
+ }
+ strcpy(fullDest, dest);
+
+ /* if destination is a directory, concat the source file name */
+ if (S_ISDIR(st.st_mode)) {
+ const char *fileName = strrchr(source, '/');
+ if (fullDest[strlen(fullDest)-1] != '/') {
+ strcat(fullDest, "/");
+ }
+ strcat(fullDest, fileName ? fileName + 1 : source);
+ }
+
+ /* attempt to move it */
+ if (rename(source, fullDest)) {
+ fprintf(stderr, "failed on '%s' - %s\n", source, strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/netstat.c b/package/toolbox/src/src/netstat.c
new file mode 100644
index 000000000..31365acd6
--- /dev/null
+++ b/package/toolbox/src/src/netstat.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+typedef union iaddr iaddr;
+typedef union iaddr6 iaddr6;
+
+union iaddr {
+ unsigned u;
+ unsigned char b[4];
+};
+
+union iaddr6 {
+ struct {
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned d;
+ } u;
+ unsigned char b[16];
+};
+
+static const char *state2str(unsigned state)
+{
+ switch(state){
+ case 0x1: return "ESTABLISHED";
+ case 0x2: return "SYN_SENT";
+ case 0x3: return "SYN_RECV";
+ case 0x4: return "FIN_WAIT1";
+ case 0x5: return "FIN_WAIT2";
+ case 0x6: return "TIME_WAIT";
+ case 0x7: return "CLOSE";
+ case 0x8: return "CLOSE_WAIT";
+ case 0x9: return "LAST_ACK";
+ case 0xA: return "LISTEN";
+ case 0xB: return "CLOSING";
+ default: return "UNKNOWN";
+ }
+}
+
+/* addr + : + port + \0 */
+#define ADDR_LEN INET6_ADDRSTRLEN + 1 + 5 + 1
+
+static void addr2str(int af, const void *addr, unsigned port, char *buf)
+{
+ if (inet_ntop(af, addr, buf, ADDR_LEN) == NULL) {
+ *buf = '\0';
+ return;
+ }
+ size_t len = strlen(buf);
+ if (port) {
+ snprintf(buf+len, ADDR_LEN-len, ":%d", port);
+ } else {
+ strncat(buf+len, ":*", ADDR_LEN-len-1);
+ }
+}
+
+static void ipv4(const char *filename, const char *label) {
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return;
+ }
+ char buf[BUFSIZ];
+ fgets(buf, BUFSIZ, fp);
+ while (fgets(buf, BUFSIZ, fp)){
+ char lip[ADDR_LEN];
+ char rip[ADDR_LEN];
+ iaddr laddr, raddr;
+ unsigned lport, rport, state, txq, rxq, num;
+ int n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
+ &num, &laddr.u, &lport, &raddr.u, &rport,
+ &state, &txq, &rxq);
+ if (n == 8) {
+ addr2str(AF_INET, &laddr, lport, lip);
+ addr2str(AF_INET, &raddr, rport, rip);
+
+ printf("%4s %6d %6d %-22s %-22s %s\n",
+ label, rxq, txq, lip, rip,
+ state2str(state));
+ }
+ }
+ fclose(fp);
+}
+
+static void ipv6(const char *filename, const char *label) {
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return;
+ }
+ char buf[BUFSIZ];
+ fgets(buf, BUFSIZ, fp);
+ while (fgets(buf, BUFSIZ, fp)){
+ char lip[ADDR_LEN];
+ char rip[ADDR_LEN];
+ iaddr6 laddr6, raddr6;
+ unsigned lport, rport, state, txq, rxq, num;
+ int n = sscanf(buf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x",
+ &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c, &laddr6.u.d, &lport,
+ &raddr6.u.a, &raddr6.u.b, &raddr6.u.c, &raddr6.u.d, &rport,
+ &state, &txq, &rxq);
+ if (n == 14) {
+ addr2str(AF_INET6, &laddr6, lport, lip);
+ addr2str(AF_INET6, &raddr6, rport, rip);
+
+ printf("%4s %6d %6d %-22s %-22s %s\n",
+ label, rxq, txq, lip, rip,
+ state2str(state));
+ }
+ }
+ fclose(fp);
+}
+
+int main(int argc, char *argv[])
+{
+ printf("Proto Recv-Q Send-Q Local Address Foreign Address State\n");
+ ipv4("/proc/net/tcp", "tcp");
+ ipv4("/proc/net/udp", "udp");
+ ipv6("/proc/net/tcp6", "tcp6");
+ ipv6("/proc/net/udp6", "udp6");
+ return 0;
+}
diff --git a/package/toolbox/src/src/notify.c b/package/toolbox/src/src/notify.c
new file mode 100644
index 000000000..56294b73f
--- /dev/null
+++ b/package/toolbox/src/src/notify.c
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/inotify.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int nfd, ffd;
+ int res;
+ char event_buf[512];
+ struct inotify_event *event;
+ int event_mask = IN_ALL_EVENTS;
+ int event_count = 1;
+ int print_files = 0;
+ int verbose = 2;
+ int width = 80;
+ char **file_names;
+ int file_count;
+ int id_offset = 0;
+ int i;
+ char *buf;
+
+ do {
+ c = getopt(argc, argv, "m:c:pv:w:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'm':
+ event_mask = strtol(optarg, NULL, 0);
+ break;
+ case 'c':
+ event_count = atoi(optarg);
+ break;
+ case 'p':
+ print_files = 1;
+ break;
+ case 'v':
+ verbose = atoi(optarg);
+ break;
+ case 'w':
+ width = atoi(optarg);
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (argc <= optind) {
+ fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]);
+ return 1;
+ }
+
+ nfd = inotify_init();
+ if(nfd < 0) {
+ fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
+ return 1;
+ }
+ file_names = argv + optind;
+ file_count = argc - optind;
+ for(i = 0; i < file_count; i++) {
+ res = inotify_add_watch(nfd, file_names[i], event_mask);
+ if(res < 0) {
+ fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno));
+ return 1;
+ }
+ if(i == 0)
+ id_offset = -res;
+ if(res + id_offset != i) {
+ fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i);
+ return 1;
+ }
+ }
+
+ buf = malloc(width + 2);
+
+ while(1) {
+ int event_pos = 0;
+ res = read(nfd, event_buf, sizeof(event_buf));
+ if(res < (int)sizeof(*event)) {
+ if(errno == EINTR)
+ continue;
+ fprintf(stderr, "could not get event, %s\n", strerror(errno));
+ return 1;
+ }
+ //printf("got %d bytes of event information\n", res);
+ while(res >= (int)sizeof(*event)) {
+ int event_size;
+ event = (struct inotify_event *)(event_buf + event_pos);
+ if(verbose >= 2)
+ printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : "");
+ else if(verbose >= 2)
+ printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : "");
+ else if(verbose >= 1)
+ printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
+ if(print_files && (event->mask & IN_MODIFY)) {
+ char filename[512];
+ ssize_t read_len;
+ char *display_name;
+ int buflen;
+ strcpy(filename, file_names[event->wd + id_offset]);
+ if(event->len) {
+ strcat(filename, "/");
+ strcat(filename, event->name);
+ }
+ ffd = open(filename, O_RDONLY);
+ display_name = (verbose >= 2 || event->len == 0) ? filename : event->name;
+ buflen = width - strlen(display_name);
+ read_len = read(ffd, buf, buflen);
+ if(read_len > 0) {
+ if(read_len < buflen && buf[read_len-1] != '\n') {
+ buf[read_len] = '\n';
+ read_len++;
+ }
+ if(read_len == buflen) {
+ buf[--read_len] = '\0';
+ buf[--read_len] = '\n';
+ buf[--read_len] = '.';
+ buf[--read_len] = '.';
+ buf[--read_len] = '.';
+ }
+ else {
+ buf[read_len] = '\0';
+ }
+ printf("%s: %s", display_name, buf);
+ }
+ close(ffd);
+ }
+ if(event_count && --event_count == 0)
+ return 0;
+ event_size = sizeof(*event) + event->len;
+ res -= event_size;
+ event_pos += event_size;
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/printenv.c b/package/toolbox/src/src/printenv.c
new file mode 100644
index 000000000..304258c4a
--- /dev/null
+++ b/package/toolbox/src/src/printenv.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern char** environ;
+
+int main (int argc, char **argv)
+{
+ char** e;
+ char* v;
+ int i;
+
+ if (argc == 1) {
+ e = environ;
+ while (*e) {
+ write(1, *e, strlen(*e));
+ write(1, "\n", 1);
+ e++;
+ }
+ } else {
+ for (i=1; i<argc; i++) {
+ v = getenv(argv[i]);
+ if (v) {
+ write(1, v, strlen(v));
+ write(1, "\n", 1);
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/ps.c b/package/toolbox/src/src/ps.c
new file mode 100644
index 000000000..07fe5c94b
--- /dev/null
+++ b/package/toolbox/src/src/ps.c
@@ -0,0 +1,244 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <pwd.h>
+
+static char *nexttoksep(char **strp, char *sep)
+{
+ char *p = strsep(strp,sep);
+ return (p == 0) ? "" : p;
+}
+static char *nexttok(char **strp)
+{
+ return nexttoksep(strp, " ");
+}
+
+#define SHOW_PRIO 1
+#define SHOW_TIME 2
+#define SHOW_CPU 8
+#define SHOW_MACLABEL 16
+
+static int display_flags = 0;
+
+static int ps_line(int pid, int tid, char *namefilter)
+{
+ char statline[1024];
+ char cmdline[1024];
+ char macline[1024];
+ char user[32];
+ struct stat stats;
+ int fd, r;
+ char *ptr, *name, *state;
+ int ppid;
+ unsigned wchan, rss, vss, eip;
+ unsigned utime, stime;
+ int prio, nice, rtprio, sched, psr;
+ struct passwd *pw;
+
+ sprintf(statline, "/proc/%d", pid);
+ stat(statline, &stats);
+
+ if(tid) {
+ sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
+ cmdline[0] = 0;
+ snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
+ } else {
+ sprintf(statline, "/proc/%d/stat", pid);
+ sprintf(cmdline, "/proc/%d/cmdline", pid);
+ snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
+ fd = open(cmdline, O_RDONLY);
+ if(fd == 0) {
+ r = 0;
+ } else {
+ r = read(fd, cmdline, 1023);
+ close(fd);
+ if(r < 0) r = 0;
+ }
+ cmdline[r] = 0;
+ }
+
+ fd = open(statline, O_RDONLY);
+ if(fd == 0) return -1;
+ r = read(fd, statline, 1023);
+ close(fd);
+ if(r < 0) return -1;
+ statline[r] = 0;
+
+ ptr = statline;
+ nexttok(&ptr); // skip pid
+ ptr++; // skip "("
+
+ name = ptr;
+ ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
+ *ptr++ = '\0'; // and null-terminate name.
+
+ ptr++; // skip " "
+ state = nexttok(&ptr);
+ ppid = atoi(nexttok(&ptr));
+ nexttok(&ptr); // pgrp
+ nexttok(&ptr); // sid
+ nexttok(&ptr); // tty
+
+ nexttok(&ptr); // tpgid
+ nexttok(&ptr); // flags
+ nexttok(&ptr); // minflt
+ nexttok(&ptr); // cminflt
+ nexttok(&ptr); // majflt
+ nexttok(&ptr); // cmajflt
+#if 1
+ utime = atoi(nexttok(&ptr));
+ stime = atoi(nexttok(&ptr));
+#else
+ nexttok(&ptr); // utime
+ nexttok(&ptr); // stime
+#endif
+ nexttok(&ptr); // cutime
+ nexttok(&ptr); // cstime
+ prio = atoi(nexttok(&ptr));
+ nice = atoi(nexttok(&ptr));
+ nexttok(&ptr); // threads
+ nexttok(&ptr); // itrealvalue
+ nexttok(&ptr); // starttime
+ vss = strtoul(nexttok(&ptr), 0, 10); // vsize
+ rss = strtoul(nexttok(&ptr), 0, 10); // rss
+ nexttok(&ptr); // rlim
+ nexttok(&ptr); // startcode
+ nexttok(&ptr); // endcode
+ nexttok(&ptr); // startstack
+ nexttok(&ptr); // kstkesp
+ eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
+ nexttok(&ptr); // signal
+ nexttok(&ptr); // blocked
+ nexttok(&ptr); // sigignore
+ nexttok(&ptr); // sigcatch
+ wchan = strtoul(nexttok(&ptr), 0, 10); // wchan
+ nexttok(&ptr); // nswap
+ nexttok(&ptr); // cnswap
+ nexttok(&ptr); // exit signal
+ psr = atoi(nexttok(&ptr)); // processor
+ rtprio = atoi(nexttok(&ptr)); // rt_priority
+ sched = atoi(nexttok(&ptr)); // scheduling policy
+
+ nexttok(&ptr); // tty
+
+ if(tid != 0) {
+ ppid = pid;
+ pid = tid;
+ }
+
+ pw = getpwuid(stats.st_uid);
+ if(pw == 0) {
+ sprintf(user,"%d",(int)stats.st_uid);
+ } else {
+ strcpy(user,pw->pw_name);
+ }
+
+ if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
+ if (display_flags & SHOW_MACLABEL) {
+ fd = open(macline, O_RDONLY);
+ strcpy(macline, "-");
+ if (fd >= 0) {
+ r = read(fd, macline, sizeof(macline)-1);
+ close(fd);
+ if (r > 0)
+ macline[r] = 0;
+ }
+ printf("%-30s %-9s %-5d %-5d %s\n", macline, user, pid, ppid, cmdline[0] ? cmdline : name);
+ return 0;
+ }
+
+ printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
+ if (display_flags & SHOW_CPU)
+ printf(" %-2d", psr);
+ if (display_flags & SHOW_PRIO)
+ printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
+ printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name);
+ if(display_flags&SHOW_TIME)
+ printf(" (u:%d, s:%d)", utime, stime);
+
+ printf("\n");
+ }
+ return 0;
+}
+
+
+void ps_threads(int pid, char *namefilter)
+{
+ char tmp[128];
+ DIR *d;
+ struct dirent *de;
+
+ sprintf(tmp,"/proc/%d/task",pid);
+ d = opendir(tmp);
+ if(d == 0) return;
+
+ while((de = readdir(d)) != 0){
+ if(isdigit(de->d_name[0])){
+ int tid = atoi(de->d_name);
+ if(tid == pid) continue;
+ ps_line(pid, tid, namefilter);
+ }
+ }
+ closedir(d);
+}
+
+int main(int argc, char **argv)
+{
+ DIR *d;
+ struct dirent *de;
+ char *namefilter = 0;
+ int pidfilter = 0;
+ int threads = 0;
+
+ d = opendir("/proc");
+ if(d == 0) return -1;
+
+ while(argc > 1){
+ if(!strcmp(argv[1],"-t")) {
+ threads = 1;
+ } else if(!strcmp(argv[1],"-x")) {
+ display_flags |= SHOW_TIME;
+ } else if(!strcmp(argv[1], "-Z")) {
+ display_flags |= SHOW_MACLABEL;
+ } else if(!strcmp(argv[1],"-p")) {
+ display_flags |= SHOW_PRIO;
+ } else if(!strcmp(argv[1],"-c")) {
+ display_flags |= SHOW_CPU;
+ } else if(isdigit(argv[1][0])){
+ pidfilter = atoi(argv[1]);
+ } else {
+ namefilter = argv[1];
+ }
+ argc--;
+ argv++;
+ }
+
+ if (display_flags & SHOW_MACLABEL) {
+ printf("LABEL USER PID PPID NAME\n");
+ } else {
+ printf("USER PID PPID VSIZE RSS %s%s WCHAN PC NAME\n",
+ (display_flags&SHOW_CPU)?"CPU ":"",
+ (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"");
+ }
+ while((de = readdir(d)) != 0){
+ if(isdigit(de->d_name[0])){
+ int pid = atoi(de->d_name);
+ if(!pidfilter || (pidfilter == pid)) {
+ ps_line(pid, 0, namefilter);
+ if(threads) ps_threads(pid, namefilter);
+ }
+ }
+ }
+ closedir(d);
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/readlink.c b/package/toolbox/src/src/readlink.c
new file mode 100644
index 000000000..71f74ebb3
--- /dev/null
+++ b/package/toolbox/src/src/readlink.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int skip_newline, quiet_errors, canonicalize;
+
+static void usage(char* name) {
+ fprintf(stderr, "Usage: %s [OPTION]... FILE\n", name);
+}
+
+int main(int argc, char* argv[]) {
+ int c;
+ while ((c = getopt(argc, argv, "nfqs")) != -1) {
+ switch (c) {
+ case 'n':
+ skip_newline = 1;
+ break;
+ case 'f':
+ canonicalize = 1;
+ break;
+ case 'q':
+ case 's':
+ quiet_errors = 1;
+ break;
+ case '?':
+ default:
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+ int index = optind;
+ if (argc - index != 1) {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ char name[PATH_MAX+1];
+ if (canonicalize) {
+ if(!realpath(argv[optind], name)) {
+ if (!quiet_errors) {
+ perror("readlink");
+ }
+ return EXIT_FAILURE;
+ }
+ } else {
+ ssize_t len = readlink(argv[1], name, PATH_MAX);
+
+ if (len < 0) {
+ if (!quiet_errors) {
+ perror("readlink");
+ }
+ return EXIT_FAILURE;
+ }
+ name[len] = '\0';
+ }
+
+ fputs(name, stdout);
+ if (!skip_newline) {
+ fputs("\n", stdout);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/package/toolbox/src/src/renice.c b/package/toolbox/src/src/renice.c
new file mode 100644
index 000000000..dece920a6
--- /dev/null
+++ b/package/toolbox/src/src/renice.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sched.h>
+#include <getopt.h>
+
+static void
+usage(const char *s)
+{
+ fprintf(stderr, "USAGE: %s [[-r] [-t TYPE] priority pids ...] [-g pid]\n", s);
+ exit(EXIT_FAILURE);
+}
+
+void print_prio(pid_t pid)
+{
+ int sched;
+ struct sched_param sp;
+
+ printf("pid %d's priority: %d\n", pid, getpriority(PRIO_PROCESS, pid));
+
+ printf("scheduling class: ");
+ sched = sched_getscheduler(pid);
+ switch (sched) {
+ case SCHED_FIFO:
+ printf("FIFO\n");
+ break;
+ case SCHED_RR:
+ printf("RR\n");
+ break;
+ case SCHED_OTHER:
+ printf("Normal\n");
+ break;
+ case -1:
+ perror("sched_getscheduler");
+ break;
+ default:
+ printf("Unknown\n");
+ }
+
+ sched_getparam(pid, &sp);
+ printf("RT prio: %d (of %d to %d)\n", sp.sched_priority,
+ sched_get_priority_min(sched), sched_get_priority_max(sched));
+}
+
+int get_sched(char *str)
+{
+ if (strcasecmp(str, "RR") == 0)
+ return SCHED_RR;
+ else if (strcasecmp(str, "FIFO") == 0)
+ return SCHED_FIFO;
+ else if (strcasecmp(str, "NORMAL") == 0)
+ return SCHED_OTHER;
+ else if (strcasecmp(str, "OTHER") == 0)
+ return SCHED_OTHER;
+ return SCHED_RR;
+}
+
+int main(int argc, char *argv[])
+{
+ int prio;
+ int realtime = 0;
+ int opt;
+ int sched = SCHED_RR;
+ char *cmd = argv[0];
+
+ do {
+ opt = getopt(argc, argv, "rt:g:");
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 'r':
+ // do realtime priority adjustment
+ realtime = 1;
+ break;
+ case 't':
+ sched = get_sched(optarg);
+ break;
+ case 'g':
+ print_prio(atoi(optarg));
+ return 0;
+ default:
+ usage(cmd);
+ }
+ } while (1);
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage(cmd);
+
+ prio = atoi(argv[0]);
+ argc--;
+ argv++;
+
+ if (argc < 1)
+ usage(cmd);
+
+ while(argc) {
+ pid_t pid;
+
+ pid = atoi(argv[0]);
+ argc--;
+ argv++;
+
+ if (realtime) {
+ struct sched_param sp = { .sched_priority = prio };
+ int ret;
+
+ ret = sched_setscheduler(pid, sched, &sp);
+ if (ret) {
+ perror("sched_set_scheduler");
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ int ret;
+
+ ret = setpriority(PRIO_PROCESS, pid, prio);
+ if (ret) {
+ perror("setpriority");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/rm.c b/package/toolbox/src/src/rm.c
new file mode 100644
index 000000000..4cc4f8a14
--- /dev/null
+++ b/package/toolbox/src/src/rm.c
@@ -0,0 +1,126 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define OPT_RECURSIVE 1
+#define OPT_FORCE 2
+
+static int usage()
+{
+ fprintf(stderr,"Usage: rm [-rR] [-f] <target>\n");
+ return -1;
+}
+
+/* return -1 on failure, with errno set to the first error */
+static int unlink_recursive(const char* name, int flags)
+{
+ struct stat st;
+ DIR *dir;
+ struct dirent *de;
+ int fail = 0;
+
+ /* is it a file or directory? */
+ if (lstat(name, &st) < 0)
+ return ((flags & OPT_FORCE) && errno == ENOENT) ? 0 : -1;
+
+ /* a file, so unlink it */
+ if (!S_ISDIR(st.st_mode))
+ return unlink(name);
+
+ /* a directory, so open handle */
+ dir = opendir(name);
+ if (dir == NULL)
+ return -1;
+
+ /* recurse over components */
+ errno = 0;
+ while ((de = readdir(dir)) != NULL) {
+ char dn[PATH_MAX];
+ if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
+ continue;
+ sprintf(dn, "%s/%s", name, de->d_name);
+ if (unlink_recursive(dn, flags) < 0) {
+ if (!(flags & OPT_FORCE)) {
+ fail = 1;
+ break;
+ }
+ }
+ errno = 0;
+ }
+ /* in case readdir or unlink_recursive failed */
+ if (fail || errno < 0) {
+ int save = errno;
+ closedir(dir);
+ errno = save;
+ return -1;
+ }
+
+ /* close directory handle */
+ if (closedir(dir) < 0)
+ return -1;
+
+ /* delete target directory */
+ return rmdir(name);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ int i, c;
+ int flags = 0;
+ int something_failed = 0;
+
+ if (argc < 2)
+ return usage();
+
+ /* check flags */
+ do {
+ c = getopt(argc, argv, "frR");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'f':
+ flags |= OPT_FORCE;
+ break;
+ case 'r':
+ case 'R':
+ flags |= OPT_RECURSIVE;
+ break;
+ }
+ } while (1);
+
+ if (optind < 1 || optind >= argc) {
+ usage();
+ return -1;
+ }
+
+ /* loop over the file/directory args */
+ for (i = optind; i < argc; i++) {
+
+ if (flags & OPT_RECURSIVE) {
+ ret = unlink_recursive(argv[i], flags);
+ } else {
+ ret = unlink(argv[i]);
+ if (ret < 0 && errno == ENOENT && (flags & OPT_FORCE)) {
+ continue;
+ }
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno));
+ if (!(flags & OPT_FORCE)) {
+ return -1;
+ } else {
+ something_failed = 1;
+ }
+ }
+ }
+
+ return something_failed;
+}
+
diff --git a/package/toolbox/src/src/rmdir.c b/package/toolbox/src/src/rmdir.c
new file mode 100644
index 000000000..bec1f406e
--- /dev/null
+++ b/package/toolbox/src/src/rmdir.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static int usage()
+{
+ fprintf(stderr,"rmdir <directory>\n");
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ if(argc < 2) return usage();
+
+ while(argc > 1) {
+ argc--;
+ argv++;
+ ret = rmdir(argv[0]);
+ if(ret < 0) {
+ fprintf(stderr, "rmdir failed for %s, %s\n", argv[0], strerror(errno));
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/rmmod.c b/package/toolbox/src/src/rmmod.c
new file mode 100644
index 000000000..48ec5b977
--- /dev/null
+++ b/package/toolbox/src/src/rmmod.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <errno.h>
+#include <asm/unistd.h>
+
+extern int delete_module(const char *, unsigned int);
+
+int main(int argc, char **argv)
+{
+ int ret, i;
+ char *modname, *dot;
+
+ /* make sure we've got an argument */
+ if (argc < 2) {
+ fprintf(stderr, "usage: rmmod <module>\n");
+ return -1;
+ }
+
+ /* if given /foo/bar/blah.ko, make a weak attempt
+ * to convert to "blah", just for convenience
+ */
+ modname = strrchr(argv[1], '/');
+ if (!modname)
+ modname = argv[1];
+ else modname++;
+
+ dot = strchr(argv[1], '.');
+ if (dot)
+ *dot = '\0';
+
+ /* Replace "-" with "_". This would keep rmmod
+ * compatible with module-init-tools version of
+ * rmmod
+ */
+ for (i = 0; modname[i] != '\0'; i++) {
+ if (modname[i] == '-')
+ modname[i] = '_';
+ }
+
+ /* pass it to the kernel */
+ ret = delete_module(modname, O_NONBLOCK | O_EXCL);
+ if (ret != 0) {
+ fprintf(stderr, "rmmod: delete_module '%s' failed (errno %d)\n",
+ modname, errno);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/package/toolbox/src/src/route.c b/package/toolbox/src/src/route.c
new file mode 100644
index 000000000..031d52160
--- /dev/null
+++ b/package/toolbox/src/src/route.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2009, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/route.h>
+
+static inline int set_address(const char *address, struct sockaddr *sa) {
+ return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr);
+}
+
+/* current support the following routing entries */
+/* route add default dev wlan0 */
+/* route add default gw 192.168.1.1 dev wlan0 */
+/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
+
+int main(int argc, char *argv[])
+{
+ struct rtentry rt = {
+ .rt_dst = {.sa_family = AF_INET},
+ .rt_genmask = {.sa_family = AF_INET},
+ .rt_gateway = {.sa_family = AF_INET},
+ };
+
+ errno = EINVAL;
+ if (argc > 2 && !strcmp(argv[1], "add")) {
+ if (!strcmp(argv[2], "default")) {
+ /* route add default dev wlan0 */
+ if (argc > 4 && !strcmp(argv[3], "dev")) {
+ rt.rt_flags = RTF_UP;
+ rt.rt_dev = argv[4];
+ errno = 0;
+ goto apply;
+ }
+
+ /* route add default gw 192.168.1.1 dev wlan0 */
+ if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) {
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ rt.rt_dev = argv[6];
+ if (set_address(argv[4], &rt.rt_gateway)) {
+ errno = 0;
+ }
+ goto apply;
+ }
+ }
+
+ /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
+ if (argc > 7 && !strcmp(argv[2], "-net") &&
+ !strcmp(argv[4], "netmask")) {
+ if (!strcmp(argv[6], "gw")) {
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (set_address(argv[3], &rt.rt_dst) &&
+ set_address(argv[5], &rt.rt_genmask) &&
+ set_address(argv[7], &rt.rt_gateway)) {
+ errno = 0;
+ }
+ goto apply;
+ } else if (!strcmp(argv[6], "dev")) {
+ rt.rt_flags = RTF_UP;
+ rt.rt_dev = argv[7];
+ if (set_address(argv[3], &rt.rt_dst) &&
+ set_address(argv[5], &rt.rt_genmask)) {
+ errno = 0;
+ }
+ goto apply;
+ }
+ }
+ }
+
+apply:
+ if (!errno) {
+ int s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) {
+ return 0;
+ }
+ }
+ puts(strerror(errno));
+ return errno;
+}
diff --git a/package/toolbox/src/src/schedtop.c b/package/toolbox/src/src/schedtop.c
new file mode 100644
index 000000000..abbc32861
--- /dev/null
+++ b/package/toolbox/src/src/schedtop.c
@@ -0,0 +1,332 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <stdint.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <signal.h>
+
+#include <pwd.h>
+
+struct thread_info {
+ int pid;
+ int tid;
+ char name[64];
+ unsigned long long exec_time;
+ unsigned long long delay_time;
+ uint32_t run_count;
+};
+
+struct thread_table {
+ size_t allocated;
+ size_t active;
+ struct thread_info *data;
+};
+
+enum {
+ FLAG_BATCH = 1U << 0,
+ FLAG_HIDE_IDLE = 1U << 1,
+ FLAG_SHOW_THREADS = 1U << 2,
+ FLAG_USE_ALTERNATE_SCREEN = 1U << 3,
+};
+
+static int time_dp = 9;
+static int time_div = 1;
+#define NS_TO_S_D(ns) \
+ (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div)
+
+struct thread_table processes;
+struct thread_table last_processes;
+struct thread_table threads;
+struct thread_table last_threads;
+
+static void grow_table(struct thread_table *table)
+{
+ size_t size = table->allocated;
+ struct thread_info *new_table;
+ if (size < 128)
+ size = 128;
+ else
+ size *= 2;
+
+ new_table = realloc(table->data, size * sizeof(*table->data));
+ if (new_table == NULL) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ table->data = new_table;
+ table->allocated = size;
+}
+
+static struct thread_info *get_item(struct thread_table *table)
+{
+ if (table->active >= table->allocated)
+ grow_table(table);
+ return table->data + table->active;
+}
+
+static void commit_item(struct thread_table *table)
+{
+ table->active++;
+}
+
+static int read_line(char *line, size_t line_size)
+{
+ int fd;
+ int len;
+ fd = open(line, O_RDONLY);
+ if(fd == 0)
+ return -1;
+ len = read(fd, line, line_size - 1);
+ close(fd);
+ if (len <= 0)
+ return -1;
+ line[len] = '\0';
+ return 0;
+}
+
+static void add_thread(int pid, int tid, struct thread_info *proc_info)
+{
+ char line[1024];
+ char *name, *name_end;
+ size_t name_len;
+ struct thread_info *info;
+ if(tid == 0)
+ info = get_item(&processes);
+ else
+ info = get_item(&threads);
+ info->pid = pid;
+ info->tid = tid;
+
+ if(tid)
+ sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid);
+ else
+ sprintf(line, "/proc/%d/schedstat", pid);
+ if (read_line(line, sizeof(line)))
+ return;
+ if(sscanf(line, "%llu %llu %u", &info->exec_time, &info->delay_time, &info->run_count) != 3)
+ return;
+ if (proc_info) {
+ proc_info->exec_time += info->exec_time;
+ proc_info->delay_time += info->delay_time;
+ proc_info->run_count += info->run_count;
+ }
+
+ name = NULL;
+ if (!tid) {
+ sprintf(line, "/proc/%d/cmdline", pid);
+ if (read_line(line, sizeof(line)) == 0 && line[0]) {
+ name = line;
+ name_len = strlen(name);
+ }
+ }
+ if (!name) {
+ if (tid)
+ sprintf(line, "/proc/%d/task/%d/stat", pid, tid);
+ else
+ sprintf(line, "/proc/%d/stat", pid);
+ if (read_line(line, sizeof(line)))
+ return;
+ name = strchr(line, '(');
+ if (name == NULL)
+ return;
+ name_end = strchr(name, ')');
+ if (name_end == NULL)
+ return;
+ name++;
+ name_len = name_end - name;
+ }
+ if (name_len >= sizeof(info->name))
+ name_len = sizeof(info->name) - 1;
+ memcpy(info->name, name, name_len);
+ info->name[name_len] = '\0';
+ if(tid == 0)
+ commit_item(&processes);
+ else
+ commit_item(&threads);
+}
+
+static void add_threads(int pid, struct thread_info *proc_info)
+{
+ char path[1024];
+ DIR *d;
+ struct dirent *de;
+ sprintf(path, "/proc/%d/task", pid);
+ d = opendir(path);
+ if(d == 0) return;
+ while((de = readdir(d)) != 0){
+ if(isdigit(de->d_name[0])){
+ int tid = atoi(de->d_name);
+ add_thread(pid, tid, proc_info);
+ }
+ }
+ closedir(d);
+}
+
+static void print_threads(int pid, uint32_t flags)
+{
+ size_t i, j;
+ for (i = 0; i < last_threads.active; i++) {
+ int epid = last_threads.data[i].pid;
+ int tid = last_threads.data[i].tid;
+ if (epid != pid)
+ continue;
+ for (j = 0; j < threads.active; j++)
+ if (tid == threads.data[j].tid)
+ break;
+ if (j == threads.active)
+ printf(" %5u died\n", tid);
+ else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count)
+ printf(" %5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", tid,
+ NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time),
+ NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time),
+ threads.data[j].run_count - last_threads.data[i].run_count,
+ NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time),
+ threads.data[j].run_count, threads.data[j].name);
+ }
+}
+
+static void update_table(DIR *d, uint32_t flags)
+{
+ size_t i, j;
+ struct dirent *de;
+
+ rewinddir(d);
+ while((de = readdir(d)) != 0){
+ if(isdigit(de->d_name[0])){
+ int pid = atoi(de->d_name);
+ struct thread_info *proc_info;
+ add_thread(pid, 0, NULL);
+ proc_info = &processes.data[processes.active - 1];
+ proc_info->exec_time = 0;
+ proc_info->delay_time = 0;
+ proc_info->run_count = 0;
+ add_threads(pid, proc_info);
+ }
+ }
+ if (!(flags & FLAG_BATCH))
+ printf("\e[H\e[0J");
+ printf("Processes: %zu, Threads %zu\n", processes.active, threads.active);
+ switch (time_dp) {
+ case 3:
+ printf(" TID --- SINCE LAST ---- ---------- TOTAL ----------\n");
+ printf(" PID EXEC_T DELAY SCHED EXEC_TIME DELAY_TIM SCHED NAME\n");
+ break;
+ case 6:
+ printf(" TID ------ SINCE LAST ------- ------------ TOTAL -----------\n");
+ printf(" PID EXEC_TIME DELAY_TIM SCHED EXEC_TIME DELAY_TIME SCHED NAME\n");
+ break;
+ default:
+ printf(" TID -------- SINCE LAST -------- ------------- TOTAL -------------\n");
+ printf(" PID EXEC_TIME DELAY_TIME SCHED EXEC_TIME DELAY_TIME SCHED NAME\n");
+ break;
+ }
+ for (i = 0; i < last_processes.active; i++) {
+ int pid = last_processes.data[i].pid;
+ for (j = 0; j < processes.active; j++)
+ if (pid == processes.data[j].pid)
+ break;
+ if (j == processes.active)
+ printf("%5u died\n", pid);
+ else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) {
+ printf("%5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", pid,
+ NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time),
+ NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time),
+ processes.data[j].run_count - last_processes.data[i].run_count,
+ NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time),
+ processes.data[j].run_count, processes.data[j].name);
+ if (flags & FLAG_SHOW_THREADS)
+ print_threads(pid, flags);
+ }
+ }
+
+ {
+ struct thread_table tmp;
+ tmp = last_processes;
+ last_processes = processes;
+ processes = tmp;
+ processes.active = 0;
+ tmp = last_threads;
+ last_threads = threads;
+ threads = tmp;
+ threads.active = 0;
+ }
+}
+
+void
+sig_abort(int signum)
+{
+ printf("\e[?47l");
+ exit(0);
+}
+
+
+int main(int argc, char **argv)
+{
+ int c;
+ DIR *d;
+ uint32_t flags = 0;
+ int delay = 3000000;
+ float delay_f;
+
+ while(1) {
+ c = getopt(argc, argv, "d:ibtamun");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'd':
+ delay_f = atof(optarg);
+ delay = delay_f * 1000000;
+ break;
+ case 'b':
+ flags |= FLAG_BATCH;
+ break;
+ case 'i':
+ flags |= FLAG_HIDE_IDLE;
+ break;
+ case 't':
+ flags |= FLAG_SHOW_THREADS;
+ break;
+ case 'a':
+ flags |= FLAG_USE_ALTERNATE_SCREEN;
+ break;
+ case 'm':
+ time_dp = 3;
+ time_div = 1000000;
+ break;
+ case 'u':
+ time_dp = 6;
+ time_div = 1000;
+ break;
+ case 'n':
+ time_dp = 9;
+ time_div = 1;
+ break;
+ }
+ }
+
+ d = opendir("/proc");
+ if(d == 0) return -1;
+
+ if (!(flags & FLAG_BATCH)) {
+ if(flags & FLAG_USE_ALTERNATE_SCREEN) {
+ signal(SIGINT, sig_abort);
+ signal(SIGPIPE, sig_abort);
+ signal(SIGTERM, sig_abort);
+ printf("\e7\e[?47h");
+ }
+ printf("\e[2J");
+ }
+ while (1) {
+ update_table(d, flags);
+ usleep(delay);
+ }
+ closedir(d);
+ return 0;
+}
diff --git a/package/toolbox/src/src/setkey.c b/package/toolbox/src/src/setkey.c
new file mode 100644
index 000000000..3b4fd700b
--- /dev/null
+++ b/package/toolbox/src/src/setkey.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+static void setkey_usage(char *argv[])
+{
+ fprintf(stderr, "%s [-t <table>] [-k <index>] [-v value] [-r] [-h]\n"
+ " -t <table> Select table\n"
+ " -k <index> Select key\n"
+ " -v <value> Set entry\n"
+ " -r Read current entry\n"
+ " -h Print help\n", argv[0]);
+}
+
+#define TTYDEV "/dev/tty0"
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ struct kbentry kbe;
+ int did_something = 0;
+
+ kbe.kb_table = 0;
+ kbe.kb_index = -1;
+ kbe.kb_value = 0;
+
+ fd = open(TTYDEV, O_RDWR | O_SYNC);
+ if (fd < 0) {
+ fprintf(stderr, "open %s: %s\n", TTYDEV, strerror(errno));
+ return 1;
+ }
+
+ do {
+ int c, ret;
+
+ c = getopt(argc, argv, "t:k:v:hr");
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case 't':
+ kbe.kb_table = strtol(optarg, NULL, 0);
+ break;
+ case 'k':
+ kbe.kb_index = strtol(optarg, NULL, 0);
+ break;
+ case 'v':
+ kbe.kb_value = strtol(optarg, NULL, 0);
+ ret = ioctl(fd, KDSKBENT, &kbe);
+ if (ret < 0) {
+ fprintf(stderr, "KDSKBENT %d %d %d failed: %s\n",
+ kbe.kb_table, kbe.kb_index, kbe.kb_value,
+ strerror(errno));
+ return 1;
+ }
+ did_something = 1;
+ break;
+ case 'r':
+ ret = ioctl(fd, KDGKBENT, &kbe);
+ if (ret < 0) {
+ fprintf(stderr, "KDGKBENT %d %d failed: %s\n",
+ kbe.kb_table, kbe.kb_index, strerror(errno));
+ return 1;
+ }
+ printf("0x%x 0x%x 0x%x\n",
+ kbe.kb_table, kbe.kb_index, kbe.kb_value);
+ did_something = 1;
+ break;
+ case 'h':
+ setkey_usage(argv);
+ return 1;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ return 1;
+ }
+ } while (1);
+
+ if(optind != argc || !did_something) {
+ setkey_usage(argv);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/sleep.c b/package/toolbox/src/src/sleep.c
new file mode 100644
index 000000000..b83e8ecdb
--- /dev/null
+++ b/package/toolbox/src/src/sleep.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static void
+usage(const char *s)
+{
+ fprintf(stderr, "USAGE: %s SECONDS\n", s);
+ exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned long seconds;
+ char *endptr;
+
+ if (argc != 2) {
+ usage(argv[0]);
+ }
+
+ seconds = strtoul(argv[1], &endptr, 10);
+
+ if (endptr == argv[1]) {
+ usage(argv[0]);
+ }
+
+
+ sleep((unsigned int)seconds);
+
+ return 0;
+}
+
+
diff --git a/package/toolbox/src/src/sync.c b/package/toolbox/src/src/sync.c
new file mode 100644
index 000000000..d882a2eef
--- /dev/null
+++ b/package/toolbox/src/src/sync.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ sync();
+ return 0;
+}
diff --git a/package/toolbox/src/src/top.c b/package/toolbox/src/src/top.c
new file mode 100644
index 000000000..c4ac14ce2
--- /dev/null
+++ b/package/toolbox/src/src/top.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+#include <pwd.h>
+
+struct cpu_info {
+ long unsigned utime, ntime, stime, itime;
+ long unsigned iowtime, irqtime, sirqtime;
+};
+
+#define PROC_NAME_LEN 64
+#define THREAD_NAME_LEN 32
+
+struct proc_info {
+ struct proc_info *next;
+ pid_t pid;
+ pid_t tid;
+ uid_t uid;
+ gid_t gid;
+ char name[PROC_NAME_LEN];
+ char tname[THREAD_NAME_LEN];
+ char state;
+ long unsigned utime;
+ long unsigned stime;
+ long unsigned delta_utime;
+ long unsigned delta_stime;
+ long unsigned delta_time;
+ long vss;
+ long rss;
+ int prs;
+ int num_threads;
+};
+
+struct proc_list {
+ struct proc_info **array;
+ int size;
+};
+
+#define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
+
+#define INIT_PROCS 50
+#define THREAD_MULT 8
+static struct proc_info **old_procs, **new_procs;
+static int num_old_procs, num_new_procs;
+static struct proc_info *free_procs;
+static int num_used_procs, num_free_procs;
+
+static int max_procs, delay, iterations, threads;
+
+static struct cpu_info old_cpu, new_cpu;
+
+static struct proc_info *alloc_proc(void);
+static void free_proc(struct proc_info *proc);
+static void read_procs(void);
+static int read_stat(char *filename, struct proc_info *proc);
+static void add_proc(int proc_num, struct proc_info *proc);
+static int read_cmdline(char *filename, struct proc_info *proc);
+static int read_status(char *filename, struct proc_info *proc);
+static void print_procs(void);
+static struct proc_info *find_old_proc(pid_t pid, pid_t tid);
+static void free_old_procs(void);
+static int (*proc_cmp)(const void *a, const void *b);
+static int proc_cpu_cmp(const void *a, const void *b);
+static int proc_vss_cmp(const void *a, const void *b);
+static int proc_rss_cmp(const void *a, const void *b);
+static int proc_thr_cmp(const void *a, const void *b);
+static int numcmp(long long a, long long b);
+static void usage(char *cmd);
+
+int main(int argc, char *argv[]) {
+ int i;
+
+ num_used_procs = num_free_procs = 0;
+
+ max_procs = 0;
+ delay = 3;
+ iterations = -1;
+ proc_cmp = &proc_cpu_cmp;
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-m")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -m expects an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ max_procs = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-n")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -n expects an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ iterations = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-d")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -d expects an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ delay = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-s")) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Option -s expects an argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ ++i;
+ if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; }
+ if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; }
+ if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; }
+ if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; }
+ fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
+ exit(EXIT_FAILURE);
+ }
+ if (!strcmp(argv[i], "-t")) { threads = 1; continue; }
+ if (!strcmp(argv[i], "-h")) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (threads && proc_cmp == &proc_thr_cmp) {
+ fprintf(stderr, "Sorting by threads per thread makes no sense!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ free_procs = NULL;
+
+ num_new_procs = num_old_procs = 0;
+ new_procs = old_procs = NULL;
+
+ read_procs();
+ while ((iterations == -1) || (iterations-- > 0)) {
+ old_procs = new_procs;
+ num_old_procs = num_new_procs;
+ memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
+ sleep(delay);
+ read_procs();
+ print_procs();
+ free_old_procs();
+ }
+
+ return 0;
+}
+
+static struct proc_info *alloc_proc(void) {
+ struct proc_info *proc;
+
+ if (free_procs) {
+ proc = free_procs;
+ free_procs = free_procs->next;
+ num_free_procs--;
+ } else {
+ proc = malloc(sizeof(*proc));
+ if (!proc) die("Could not allocate struct process_info.\n");
+ }
+
+ num_used_procs++;
+
+ return proc;
+}
+
+static void free_proc(struct proc_info *proc) {
+ proc->next = free_procs;
+ free_procs = proc;
+
+ num_used_procs--;
+ num_free_procs++;
+}
+
+#define MAX_LINE 256
+
+static void read_procs(void) {
+ DIR *proc_dir, *task_dir;
+ struct dirent *pid_dir, *tid_dir;
+ char filename[64];
+ FILE *file;
+ int proc_num;
+ struct proc_info *proc;
+ pid_t pid, tid;
+
+ int i;
+
+ proc_dir = opendir("/proc");
+ if (!proc_dir) die("Could not open /proc.\n");
+
+ new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *));
+ num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1);
+
+ file = fopen("/proc/stat", "r");
+ if (!file) die("Could not open /proc/stat.\n");
+ fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime,
+ &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
+ fclose(file);
+
+ proc_num = 0;
+ while ((pid_dir = readdir(proc_dir))) {
+ if (!isdigit(pid_dir->d_name[0]))
+ continue;
+
+ pid = atoi(pid_dir->d_name);
+
+ struct proc_info cur_proc;
+
+ if (!threads) {
+ proc = alloc_proc();
+
+ proc->pid = proc->tid = pid;
+
+ sprintf(filename, "/proc/%d/stat", pid);
+ read_stat(filename, proc);
+
+ sprintf(filename, "/proc/%d/cmdline", pid);
+ read_cmdline(filename, proc);
+
+ sprintf(filename, "/proc/%d/status", pid);
+ read_status(filename, proc);
+
+ proc->num_threads = 0;
+ } else {
+ sprintf(filename, "/proc/%d/cmdline", pid);
+ read_cmdline(filename, &cur_proc);
+
+ sprintf(filename, "/proc/%d/status", pid);
+ read_status(filename, &cur_proc);
+
+ proc = NULL;
+ }
+
+ sprintf(filename, "/proc/%d/task", pid);
+ task_dir = opendir(filename);
+ if (!task_dir) continue;
+
+ while ((tid_dir = readdir(task_dir))) {
+ if (!isdigit(tid_dir->d_name[0]))
+ continue;
+
+ if (threads) {
+ tid = atoi(tid_dir->d_name);
+
+ proc = alloc_proc();
+
+ proc->pid = pid; proc->tid = tid;
+
+ sprintf(filename, "/proc/%d/task/%d/stat", pid, tid);
+ read_stat(filename, proc);
+
+ strcpy(proc->name, cur_proc.name);
+ proc->uid = cur_proc.uid;
+ proc->gid = cur_proc.gid;
+
+ add_proc(proc_num++, proc);
+ } else {
+ proc->num_threads++;
+ }
+ }
+
+ closedir(task_dir);
+
+ if (!threads)
+ add_proc(proc_num++, proc);
+ }
+
+ for (i = proc_num; i < num_new_procs; i++)
+ new_procs[i] = NULL;
+
+ closedir(proc_dir);
+}
+
+static int read_stat(char *filename, struct proc_info *proc) {
+ FILE *file;
+ char buf[MAX_LINE], *open_paren, *close_paren;
+
+ file = fopen(filename, "r");
+ if (!file) return 1;
+ fgets(buf, MAX_LINE, file);
+ fclose(file);
+
+ /* Split at first '(' and last ')' to get process name. */
+ open_paren = strchr(buf, '(');
+ close_paren = strrchr(buf, ')');
+ if (!open_paren || !close_paren) return 1;
+
+ *open_paren = *close_paren = '\0';
+ strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
+ proc->tname[THREAD_NAME_LEN-1] = 0;
+
+ /* Scan rest of string. */
+ sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+ "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld "
+ "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d",
+ &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss, &proc->prs);
+
+ return 0;
+}
+
+static void add_proc(int proc_num, struct proc_info *proc) {
+ int i;
+
+ if (proc_num >= num_new_procs) {
+ new_procs = realloc(new_procs, 2 * num_new_procs * sizeof(struct proc_info *));
+ if (!new_procs) die("Could not expand procs array.\n");
+ for (i = num_new_procs; i < 2 * num_new_procs; i++)
+ new_procs[i] = NULL;
+ num_new_procs = 2 * num_new_procs;
+ }
+ new_procs[proc_num] = proc;
+}
+
+static int read_cmdline(char *filename, struct proc_info *proc) {
+ FILE *file;
+ char line[MAX_LINE];
+
+ line[0] = '\0';
+ file = fopen(filename, "r");
+ if (!file) return 1;
+ fgets(line, MAX_LINE, file);
+ fclose(file);
+ if (strlen(line) > 0) {
+ strncpy(proc->name, line, PROC_NAME_LEN);
+ proc->name[PROC_NAME_LEN-1] = 0;
+ } else
+ proc->name[0] = 0;
+ return 0;
+}
+
+static int read_status(char *filename, struct proc_info *proc) {
+ FILE *file;
+ char line[MAX_LINE];
+ unsigned int uid, gid;
+
+ file = fopen(filename, "r");
+ if (!file) return 1;
+ while (fgets(line, MAX_LINE, file)) {
+ sscanf(line, "Uid: %u", &uid);
+ sscanf(line, "Gid: %u", &gid);
+ }
+ fclose(file);
+ proc->uid = uid; proc->gid = gid;
+ return 0;
+}
+
+static void print_procs(void) {
+ int i;
+ struct proc_info *old_proc, *proc;
+ long unsigned total_delta_time;
+ struct passwd *user;
+ char *user_str, user_buf[20];
+
+ for (i = 0; i < num_new_procs; i++) {
+ if (new_procs[i]) {
+ old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid);
+ if (old_proc) {
+ new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
+ new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
+ } else {
+ new_procs[i]->delta_utime = 0;
+ new_procs[i]->delta_stime = 0;
+ }
+ new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime;
+ }
+ }
+
+ total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime
+ + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
+ - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
+ + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);
+
+ qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
+
+ printf("\n\n\n");
+ printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
+ ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100 / total_delta_time,
+ ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
+ ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time,
+ ((new_cpu.irqtime + new_cpu.sirqtime)
+ - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time);
+ printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n",
+ new_cpu.utime - old_cpu.utime,
+ new_cpu.ntime - old_cpu.ntime,
+ new_cpu.stime - old_cpu.stime,
+ new_cpu.itime - old_cpu.itime,
+ new_cpu.iowtime - old_cpu.iowtime,
+ new_cpu.irqtime - old_cpu.irqtime,
+ new_cpu.sirqtime - old_cpu.sirqtime,
+ total_delta_time);
+ printf("\n");
+ if (!threads)
+ printf("%5s %2s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "PR", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name");
+ else
+ printf("%5s %5s %2s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "PR", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc");
+
+ for (i = 0; i < num_new_procs; i++) {
+ proc = new_procs[i];
+
+ if (!proc || (max_procs && (i >= max_procs)))
+ break;
+ user = getpwuid(proc->uid);
+ if (user && user->pw_name) {
+ user_str = user->pw_name;
+ } else {
+ snprintf(user_buf, 20, "%d", proc->uid);
+ user_str = user_buf;
+ }
+ if (!threads)
+ printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
+ else
+ printf("%5d %5d %2d %3ld%% %c %6ldK %6ldK %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->tname, proc->name);
+ }
+}
+
+static struct proc_info *find_old_proc(pid_t pid, pid_t tid) {
+ int i;
+
+ for (i = 0; i < num_old_procs; i++)
+ if (old_procs[i] && (old_procs[i]->pid == pid) && (old_procs[i]->tid == tid))
+ return old_procs[i];
+
+ return NULL;
+}
+
+static void free_old_procs(void) {
+ int i;
+
+ for (i = 0; i < num_old_procs; i++)
+ if (old_procs[i])
+ free_proc(old_procs[i]);
+
+ free(old_procs);
+}
+
+static int proc_cpu_cmp(const void *a, const void *b) {
+ struct proc_info *pa, *pb;
+
+ pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+ if (!pa && !pb) return 0;
+ if (!pa) return 1;
+ if (!pb) return -1;
+
+ return -numcmp(pa->delta_time, pb->delta_time);
+}
+
+static int proc_vss_cmp(const void *a, const void *b) {
+ struct proc_info *pa, *pb;
+
+ pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+ if (!pa && !pb) return 0;
+ if (!pa) return 1;
+ if (!pb) return -1;
+
+ return -numcmp(pa->vss, pb->vss);
+}
+
+static int proc_rss_cmp(const void *a, const void *b) {
+ struct proc_info *pa, *pb;
+
+ pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+ if (!pa && !pb) return 0;
+ if (!pa) return 1;
+ if (!pb) return -1;
+
+ return -numcmp(pa->rss, pb->rss);
+}
+
+static int proc_thr_cmp(const void *a, const void *b) {
+ struct proc_info *pa, *pb;
+
+ pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+ if (!pa && !pb) return 0;
+ if (!pa) return 1;
+ if (!pb) return -1;
+
+ return -numcmp(pa->num_threads, pb->num_threads);
+}
+
+static int numcmp(long long a, long long b) {
+ if (a < b) return -1;
+ if (a > b) return 1;
+ return 0;
+}
+
+static void usage(char *cmd) {
+ fprintf(stderr, "Usage: %s [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]\n"
+ " -m num Maximum number of processes to display.\n"
+ " -n num Updates to show before exiting.\n"
+ " -d num Seconds to wait between updates.\n"
+ " -s col Column to sort by (cpu,vss,rss,thr).\n"
+ " -t Show threads instead of processes.\n"
+ " -h Display this help screen.\n",
+ cmd);
+}
diff --git a/package/toolbox/src/src/touch.c b/package/toolbox/src/src/touch.c
new file mode 100644
index 000000000..7c38aa05a
--- /dev/null
+++ b/package/toolbox/src/src/touch.c
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+static void usage(void)
+{
+ fprintf(stderr, "touch: usage: touch [-alm] [-t YYYYMMDD[.hhmmss]] <file>\n");
+ exit(1);
+}
+
+static time_t parse_time(char *s)
+{
+ struct tm tm;
+ int day = atoi(s);
+ int hour = 0;
+
+ while (*s && *s != '.') {
+ s++;
+ }
+
+ if (*s) {
+ s++;
+ hour = atoi(s);
+ }
+
+ tm.tm_year = day / 10000 - 1900;
+ tm.tm_mon = (day % 10000) / 100 - 1;
+ tm.tm_mday = day % 100;
+ tm.tm_hour = hour / 10000;
+ tm.tm_min = (hour % 10000) / 100;
+ tm.tm_sec = hour % 100;
+ tm.tm_isdst = -1;
+
+ return mktime(&tm);
+}
+
+int main(int argc, char *argv[])
+{
+ int i, fd, aflag = 0, mflag = 0, debug = 0, flags = 0;
+ struct timespec specified_time, times[2];
+ char *file = 0;
+
+ specified_time.tv_nsec = UTIME_NOW;
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ /* an option */
+ const char *arg = argv[i]+1;
+ while (arg[0]) {
+ switch (arg[0]) {
+ case 'a': aflag = 1; break;
+ case 'm': mflag = 1; break;
+ case 't':
+ if ((i+1) >= argc)
+ usage();
+ specified_time.tv_sec = parse_time(argv[++i]);
+ if (specified_time.tv_sec == -1) {
+ fprintf(stderr, "touch: invalid timestamp specified\n");
+ exit(1);
+ }
+ specified_time.tv_nsec = 0;
+ break;
+ case 'l': flags |= AT_SYMLINK_NOFOLLOW; break;
+ case 'd': debug = 1; break;
+ default:
+ usage();
+ }
+ arg++;
+ }
+ } else {
+ /* not an option, and only accept one filename */
+ if (i+1 != argc)
+ usage();
+ file = argv[i];
+ }
+ }
+
+ if (! file) {
+ fprintf(stderr, "touch: no file specified\n");
+ exit(1);
+ }
+
+ if (access(file, F_OK))
+ if ((fd=creat(file, 0666)) != -1)
+ close(fd);
+
+ if ((mflag == 0) && (aflag == 0))
+ aflag = mflag = 1;
+
+ if (aflag)
+ times[0] = specified_time;
+ else
+ times[0].tv_nsec = UTIME_OMIT;
+
+ if (mflag)
+ times[1] = specified_time;
+ else
+ times[1].tv_nsec = UTIME_OMIT;
+
+ if (debug) {
+ fprintf(stderr, "file = %s\n", file);
+ fprintf(stderr, "times[0].tv_sec = %lld, times[0].tv_nsec = %ld\n", (long long)times[0].tv_sec, (long)times[0].tv_nsec);
+ fprintf(stderr, "times[1].tv_sec = %lld, times[1].tv_nsec = %ld\n", (long long)times[1].tv_sec, (long)times[1].tv_nsec);
+ fprintf(stderr, "flags = 0x%8.8x\n", flags);
+ }
+
+ return utimensat(AT_FDCWD, file, times, flags);
+}
+
diff --git a/package/toolbox/src/src/umount.c b/package/toolbox/src/src/umount.c
new file mode 100644
index 000000000..aee3bdd39
--- /dev/null
+++ b/package/toolbox/src/src/umount.c
@@ -0,0 +1,91 @@
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/loop.h>
+#include <errno.h>
+
+#define LOOPDEV_MAXLEN 64
+#define LOOP_MAJOR 7
+
+static int is_loop(char *dev)
+{
+ struct stat st;
+ int ret = 0;
+
+ if (stat(dev, &st) == 0) {
+ if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) {
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+static int is_loop_mount(const char* path, char *loopdev)
+{
+ FILE* f;
+ int count;
+ char device[256];
+ char mount_path[256];
+ char rest[256];
+ int result = 0;
+
+ f = fopen("/proc/mounts", "r");
+ if (!f) {
+ fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno));
+ return -1;
+ }
+
+ do {
+ count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
+ if (count == 3) {
+ if (is_loop(device) && strcmp(path, mount_path) == 0) {
+ strlcpy(loopdev, device, LOOPDEV_MAXLEN);
+ result = 1;
+ break;
+ }
+ }
+ } while (count == 3);
+
+ fclose(f);
+ return result;
+}
+
+int main(int argc, char *argv[])
+{
+ int loop, loop_fd;
+ char loopdev[LOOPDEV_MAXLEN];
+
+ if(argc != 2) {
+ fprintf(stderr,"umount <path>\n");
+ return 1;
+ }
+
+ loop = is_loop_mount(argv[1], loopdev);
+ if (umount(argv[1])) {
+ fprintf(stderr, "failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ if (loop) {
+ // free the loop device
+ loop_fd = open(loopdev, O_RDONLY);
+ if (loop_fd < 0) {
+ fprintf(stderr, "open loop device failed: %s\n", strerror(errno));
+ return 1;
+ }
+ if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
+ fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno));
+ return 1;
+ }
+
+ close(loop_fd);
+ }
+
+ return 0;
+}
diff --git a/package/toolbox/src/src/vmstat.c b/package/toolbox/src/src/vmstat.c
new file mode 100644
index 000000000..1ede95977
--- /dev/null
+++ b/package/toolbox/src/src/vmstat.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+struct state {
+ long procs_r;
+ long procs_b;
+
+ long mem_free;
+ long mem_mapped;
+ long mem_anon;
+ long mem_slab;
+
+ long sys_in;
+ long sys_cs;
+ long sys_flt;
+
+ long cpu_us;
+ long cpu_ni;
+ long cpu_sy;
+ long cpu_id;
+ long cpu_wa;
+ long cpu_ir;
+ long cpu_si;
+};
+
+#define MAX_LINE 256
+
+char line[MAX_LINE];
+
+static void read_state(struct state *s);
+static int read_meminfo(struct state *s);
+static int read_stat(struct state *s);
+static int read_vmstat(struct state *s);
+static void print_header(void);
+static void print_line(struct state *old, struct state *new);
+static void usage(char *cmd);
+
+int main(int argc, char *argv[]) {
+ struct state s[2];
+ int iterations, delay, header_interval;
+ int toggle, count;
+ int i;
+
+ iterations = -1;
+ delay = 1;
+ header_interval = 20;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-n")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -n requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ iterations = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-d")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -d requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ delay = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-r")) {
+ if (i >= argc - 1) {
+ fprintf(stderr, "Option -r requires an argument.\n");
+ exit(EXIT_FAILURE);
+ }
+ header_interval = atoi(argv[++i]);
+ continue;
+ }
+ if (!strcmp(argv[i], "-h")) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ toggle = 0;
+ count = 0;
+
+ if (!header_interval)
+ print_header();
+ read_state(&s[1 - toggle]);
+ while ((iterations < 0) || (iterations-- > 0)) {
+ sleep(delay);
+ read_state(&s[toggle]);
+ if (header_interval) {
+ if (count == 0)
+ print_header();
+ count = (count + 1) % header_interval;
+ }
+ print_line(&s[1 - toggle], &s[toggle]);
+ toggle = 1 - toggle;
+ }
+
+ return 0;
+}
+
+static void read_state(struct state *s) {
+ int error;
+
+ error = read_meminfo(s);
+ if (error) {
+ fprintf(stderr, "vmstat: could not read /proc/meminfo: %s\n", strerror(error));
+ exit(EXIT_FAILURE);
+ }
+
+ error = read_stat(s);
+ if (error) {
+ fprintf(stderr, "vmstat: could not read /proc/stat: %s\n", strerror(error));
+ exit(EXIT_FAILURE);
+ }
+
+ error = read_vmstat(s);
+ if (error) {
+ fprintf(stderr, "vmstat: could not read /proc/vmstat: %s\n", strerror(error));
+ exit(EXIT_FAILURE);
+ }
+}
+
+static int read_meminfo(struct state *s) {
+ FILE *f;
+
+ f = fopen("/proc/meminfo", "r");
+ if (!f) return errno;
+
+ while (fgets(line, MAX_LINE, f)) {
+ sscanf(line, "MemFree: %ld kB", &s->mem_free);
+ sscanf(line, "AnonPages: %ld kB", &s->mem_anon);
+ sscanf(line, "Mapped: %ld kB", &s->mem_mapped);
+ sscanf(line, "Slab: %ld kB", &s->mem_slab);
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static int read_stat(struct state *s) {
+ FILE *f;
+
+ f = fopen("/proc/stat", "r");
+ if (!f) return errno;
+
+ while (fgets(line, MAX_LINE, f)) {
+ if (!strncmp(line, "cpu ", 4)) {
+ sscanf(line, "cpu %ld %ld %ld %ld %ld %ld %ld",
+ &s->cpu_us, &s->cpu_ni, &s->cpu_sy, &s->cpu_id, &s->cpu_wa,
+ &s->cpu_ir, &s->cpu_si);
+ }
+ sscanf(line, "intr %ld", &s->sys_in);
+ sscanf(line, "ctxt %ld", &s->sys_cs);
+ sscanf(line, "procs_running %ld", &s->procs_r);
+ sscanf(line, "procs_blocked %ld", &s->procs_b);
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static int read_vmstat(struct state *s) {
+ FILE *f;
+
+ f = fopen("/proc/vmstat", "r");
+ if (!f) return errno;
+
+ while (fgets(line, MAX_LINE, f)) {
+ sscanf(line, "pgmajfault %ld", &s->sys_flt);
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static void print_header(void) {
+ printf("%-5s %-27s %-14s %-17s\n", "procs", "memory", "system", "cpu");
+ printf("%2s %2s %6s %6s %6s %6s %4s %4s %4s %2s %2s %2s %2s %2s %2s\n", "r", "b", "free", "mapped", "anon", "slab", "in", "cs", "flt", "us", "ni", "sy", "id", "wa", "ir");
+}
+
+/* Jiffies to percent conversion */
+#define JP(jif) ((jif) * 100 / (HZ))
+#define NORM(var) ((var) = (((var) > 99) ? (99) : (var)))
+
+static void print_line(struct state *old, struct state *new) {
+ int us, ni, sy, id, wa, ir;
+ us = JP(new->cpu_us - old->cpu_us); NORM(us);
+ ni = JP(new->cpu_ni - old->cpu_ni); NORM(ni);
+ sy = JP(new->cpu_sy - old->cpu_sy); NORM(sy);
+ id = JP(new->cpu_id - old->cpu_id); NORM(id);
+ wa = JP(new->cpu_wa - old->cpu_wa); NORM(wa);
+ ir = JP(new->cpu_ir - old->cpu_ir); NORM(ir);
+ printf("%2ld %2ld %6ld %6ld %6ld %6ld %4ld %4ld %4ld %2d %2d %2d %2d %2d %2d\n",
+ new->procs_r ? (new->procs_r - 1) : 0, new->procs_b,
+ new->mem_free, new->mem_mapped, new->mem_anon, new->mem_slab,
+ new->sys_in - old->sys_in, new->sys_cs - old->sys_cs, new->sys_flt - old->sys_flt,
+ us, ni, sy, id, wa, ir);
+}
+
+static void usage(char *cmd) {
+ fprintf(stderr, "Usage: %s [ -h ] [ -n iterations ] [ -d delay ] [ -r header_repeat ]\n"
+ " -n iterations How many rows of data to print.\n"
+ " -d delay How long to sleep between rows.\n"
+ " -r header_repeat How many rows to print before repeating\n"
+ " the header. Zero means never repeat.\n"
+ " -h Displays this help screen.\n",
+ cmd);
+}
diff --git a/package/toolbox/src/sync/Makefile b/package/toolbox/src/sync/Makefile
new file mode 100644
index 000000000..83495e9e8
--- /dev/null
+++ b/package/toolbox/src/sync/Makefile
@@ -0,0 +1,3 @@
+PROG= sync
+
+include ../tool.mk
diff --git a/package/toolbox/src/tool.mk b/package/toolbox/src/tool.mk
new file mode 100644
index 000000000..883518b7d
--- /dev/null
+++ b/package/toolbox/src/tool.mk
@@ -0,0 +1,22 @@
+SRCS?= ${PROG:=.c}
+
+include ./common.mk
+
+CPPFLAGS+= -I../src
+LDFLAGS+= -L../lib
+LIBS+= -loadk_toolbox
+VPATH= ../src
+
+all: ${PROG}
+
+${PROG}: ${OBJS}
+ ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ -Wl,--start-group ${OBJS} ${LIBS} -Wl,--end-group
+
+DESTDIR?=
+BINDIR?=/bin
+INSTALL?=/usr/bin/install
+
+install:
+ ${INSTALL} -d ${DESTDIR}${BINDIR}/
+ ${INSTALL} -c -m 755 ${PROG} ${DESTDIR}${BINDIR}/
diff --git a/package/toolbox/src/top/Makefile b/package/toolbox/src/top/Makefile
new file mode 100644
index 000000000..938b40708
--- /dev/null
+++ b/package/toolbox/src/top/Makefile
@@ -0,0 +1,3 @@
+PROG= top
+
+include ../tool.mk
diff --git a/package/toolbox/src/touch/Makefile b/package/toolbox/src/touch/Makefile
new file mode 100644
index 000000000..a6be25993
--- /dev/null
+++ b/package/toolbox/src/touch/Makefile
@@ -0,0 +1,3 @@
+PROG= touch
+
+include ../tool.mk
diff --git a/package/toolbox/src/umount/Makefile b/package/toolbox/src/umount/Makefile
new file mode 100644
index 000000000..333256097
--- /dev/null
+++ b/package/toolbox/src/umount/Makefile
@@ -0,0 +1,3 @@
+PROG= umount
+
+include ../tool.mk
diff --git a/package/toolbox/src/vmstat/Makefile b/package/toolbox/src/vmstat/Makefile
new file mode 100644
index 000000000..ea1d6b35e
--- /dev/null
+++ b/package/toolbox/src/vmstat/Makefile
@@ -0,0 +1,3 @@
+PROG= vmstat
+
+include ../tool.mk