Browse Source

toolbox: add OpenADK toolbox for very small systems, thx Thorsten Glaser

Waldemar Brodkorb 6 years ago
parent
commit
9d7518c2cb
100 changed files with 12802 additions and 0 deletions
  1. 24 0
      package/toolbox/Makefile
  2. 516 0
      package/toolbox/src/Makefile
  3. 5 0
      package/toolbox/src/cat/Makefile
  4. 163 0
      package/toolbox/src/cat/cat.c
  5. 3 0
      package/toolbox/src/chmod/Makefile
  6. 3 0
      package/toolbox/src/chown/Makefile
  7. 3 0
      package/toolbox/src/clear/Makefile
  8. 3 0
      package/toolbox/src/cmp/Makefile
  9. 21 0
      package/toolbox/src/common.mk
  10. 4 0
      package/toolbox/src/cp/Makefile
  11. 549 0
      package/toolbox/src/cp/cp.c
  12. 63 0
      package/toolbox/src/cp/extern.h
  13. 441 0
      package/toolbox/src/cp/utils.c
  14. 5 0
      package/toolbox/src/date/Makefile
  15. 272 0
      package/toolbox/src/date/date.c
  16. 4 0
      package/toolbox/src/dd/Makefile
  17. 3 0
      package/toolbox/src/df/Makefile
  18. 3 0
      package/toolbox/src/dmesg/Makefile
  19. 3 0
      package/toolbox/src/du/Makefile
  20. 3 0
      package/toolbox/src/exists/Makefile
  21. 4 0
      package/toolbox/src/grep/Makefile
  22. 336 0
      package/toolbox/src/grep/fastgrep.c
  23. 215 0
      package/toolbox/src/grep/file.c
  24. 695 0
      package/toolbox/src/grep/grep.c
  25. 149 0
      package/toolbox/src/grep/grep.h
  26. 116 0
      package/toolbox/src/grep/queue.c
  27. 499 0
      package/toolbox/src/grep/util.c
  28. 3 0
      package/toolbox/src/hd/Makefile
  29. 3 0
      package/toolbox/src/id/Makefile
  30. 3 0
      package/toolbox/src/ifconfig/Makefile
  31. 3 0
      package/toolbox/src/iftop/Makefile
  32. 3 0
      package/toolbox/src/insmod/Makefile
  33. 3 0
      package/toolbox/src/ioctl/Makefile
  34. 3 0
      package/toolbox/src/kill/Makefile
  35. 24 0
      package/toolbox/src/lib/Makefile
  36. 48 0
      package/toolbox/src/lib/fgetln.c
  37. 242 0
      package/toolbox/src/lib/md5.c
  38. 48 0
      package/toolbox/src/lib/md5.h
  39. 13 0
      package/toolbox/src/lib/md5hlp.c
  40. 9 0
      package/toolbox/src/lib/string.h
  41. 185 0
      package/toolbox/src/lib/strlfun.c
  42. 3 0
      package/toolbox/src/ln/Makefile
  43. 4 0
      package/toolbox/src/ls/Makefile
  44. 3 0
      package/toolbox/src/lsof/Makefile
  45. 3 0
      package/toolbox/src/md5/Makefile
  46. 3 0
      package/toolbox/src/mkdir/Makefile
  47. 6 0
      package/toolbox/src/mknod/Makefile
  48. 190 0
      package/toolbox/src/mknod/mknod.c
  49. 462 0
      package/toolbox/src/mknod/setmode.c
  50. 3 0
      package/toolbox/src/mount/Makefile
  51. 3 0
      package/toolbox/src/mv/Makefile
  52. 3 0
      package/toolbox/src/netstat/Makefile
  53. 3 0
      package/toolbox/src/notify/Makefile
  54. 3 0
      package/toolbox/src/printenv/Makefile
  55. 3 0
      package/toolbox/src/ps/Makefile
  56. 3 0
      package/toolbox/src/readlink/Makefile
  57. 3 0
      package/toolbox/src/renice/Makefile
  58. 3 0
      package/toolbox/src/rm/Makefile
  59. 3 0
      package/toolbox/src/rmdir/Makefile
  60. 3 0
      package/toolbox/src/rmmod/Makefile
  61. 3 0
      package/toolbox/src/route/Makefile
  62. 3 0
      package/toolbox/src/schedtop/Makefile
  63. 6 0
      package/toolbox/src/sed/Makefile
  64. 870 0
      package/toolbox/src/sed/compile.c
  65. 147 0
      package/toolbox/src/sed/defs.h
  66. 65 0
      package/toolbox/src/sed/extern.h
  67. 523 0
      package/toolbox/src/sed/main.c
  68. 166 0
      package/toolbox/src/sed/misc.c
  69. 642 0
      package/toolbox/src/sed/process.c
  70. 3 0
      package/toolbox/src/setkey/Makefile
  71. 3 0
      package/toolbox/src/sleep/Makefile
  72. 101 0
      package/toolbox/src/src/chmod.c
  73. 73 0
      package/toolbox/src/src/chown.c
  74. 41 0
      package/toolbox/src/src/clear.c
  75. 91 0
      package/toolbox/src/src/cmp.c
  76. 1323 0
      package/toolbox/src/src/dd.c
  77. 94 0
      package/toolbox/src/src/dd.h
  78. 85 0
      package/toolbox/src/src/df.c
  79. 64 0
      package/toolbox/src/src/dmesg.c
  80. 322 0
      package/toolbox/src/src/du.c
  81. 104 0
      package/toolbox/src/src/dynarray.c
  82. 80 0
      package/toolbox/src/src/dynarray.h
  83. 16 0
      package/toolbox/src/src/exists.c
  84. 97 0
      package/toolbox/src/src/hd.c
  85. 51 0
      package/toolbox/src/src/id.c
  86. 164 0
      package/toolbox/src/src/ifconfig.c
  87. 278 0
      package/toolbox/src/src/iftop.c
  88. 97 0
      package/toolbox/src/src/insmod.c
  89. 124 0
      package/toolbox/src/src/ioctl.c
  90. 149 0
      package/toolbox/src/src/kill.c
  91. 34 0
      package/toolbox/src/src/ln.c
  92. 424 0
      package/toolbox/src/src/ls.c
  93. 253 0
      package/toolbox/src/src/lsof.c
  94. 75 0
      package/toolbox/src/src/md5.c
  95. 77 0
      package/toolbox/src/src/mkdir.c
  96. 360 0
      package/toolbox/src/src/mount.c
  97. 59 0
      package/toolbox/src/src/mv.c
  98. 155 0
      package/toolbox/src/src/netstat.c
  99. 145 0
      package/toolbox/src/src/notify.c
  100. 33 0
      package/toolbox/src/src/printenv.c

+ 24 - 0
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

+ 516 - 0
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.
+#  */

+ 5 - 0
package/toolbox/src/cat/Makefile

@@ -0,0 +1,5 @@
+PROG=	cat
+
+include ../tool.mk
+
+CFLAGS+=-Wextra

+ 163 - 0
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);
+}

+ 3 - 0
package/toolbox/src/chmod/Makefile

@@ -0,0 +1,3 @@
+PROG=	chmod
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/chown/Makefile

@@ -0,0 +1,3 @@
+PROG=	chown
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/clear/Makefile

@@ -0,0 +1,3 @@
+PROG=	clear
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/cmp/Makefile

@@ -0,0 +1,3 @@
+PROG=	cmp
+
+include ../tool.mk

+ 21 - 0
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

+ 4 - 0
package/toolbox/src/cp/Makefile

@@ -0,0 +1,4 @@
+PROG=	cp
+SRCS=	cp.c utils.c
+
+include ../tool.mk

+ 549 - 0
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);
+}

+ 63 - 0
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_ */

+ 441 - 0
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 */
+}

+ 5 - 0
package/toolbox/src/date/Makefile

@@ -0,0 +1,5 @@
+PROG=	date
+
+include ../tool.mk
+
+CPPFLAGS+=	-D'__SCCSID(x)='

+ 272 - 0
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);
+}

+ 4 - 0
package/toolbox/src/dd/Makefile

@@ -0,0 +1,4 @@
+CPPFLAGS+=-D_FILE_OFFSET_BITS=64
+PROG=	dd
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/df/Makefile

@@ -0,0 +1,3 @@
+PROG=	df
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/dmesg/Makefile

@@ -0,0 +1,3 @@
+PROG=	dmesg
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/du/Makefile

@@ -0,0 +1,3 @@
+PROG=	du
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/exists/Makefile

@@ -0,0 +1,3 @@
+PROG=	exists
+
+include ../tool.mk

+ 4 - 0
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

+ 336 - 0
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;
+	}
+}

+ 215 - 0
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;
+}

+ 695 - 0
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));
+}

+ 149 - 0
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 *);

+ 116 - 0
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);
+	}
+}

+ 499 - 0
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);
+	}
+}

+ 3 - 0
package/toolbox/src/hd/Makefile

@@ -0,0 +1,3 @@
+PROG=	hd
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/id/Makefile

@@ -0,0 +1,3 @@
+PROG=	id
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/ifconfig/Makefile

@@ -0,0 +1,3 @@
+PROG=	ifconfig
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/iftop/Makefile

@@ -0,0 +1,3 @@
+PROG=	iftop
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/insmod/Makefile

@@ -0,0 +1,3 @@
+PROG=	insmod
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/ioctl/Makefile

@@ -0,0 +1,3 @@
+PROG=	ioctl
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/kill/Makefile

@@ -0,0 +1,3 @@
+PROG=	kill
+
+include ../tool.mk

+ 24 - 0
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

+ 48 - 0
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);
+}

+ 242 - 0
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;
+}

+ 48 - 0
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

+ 13 - 0
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
+};

+ 9 - 0
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

+ 185 - 0
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 */

+ 3 - 0
package/toolbox/src/ln/Makefile

@@ -0,0 +1,3 @@
+PROG=	ln
+
+include ../tool.mk

+ 4 - 0
package/toolbox/src/ls/Makefile

@@ -0,0 +1,4 @@
+PROG=	ls
+SRCS=	ls.c dynarray.c
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/lsof/Makefile

@@ -0,0 +1,3 @@
+PROG=	lsof
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/md5/Makefile

@@ -0,0 +1,3 @@
+PROG=	md5
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/mkdir/Makefile

@@ -0,0 +1,3 @@
+PROG=	mkdir
+
+include ../tool.mk

+ 6 - 0
package/toolbox/src/mknod/Makefile

@@ -0,0 +1,6 @@
+PROG=	mknod
+SRCS=	mknod.c setmode.c
+
+include ../tool.mk
+
+CPPFLAGS+=	-D'__SCCSID(x)='

+ 190 - 0
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);
+}

+ 462 - 0
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++;
+		}
+	}
+}

+ 3 - 0
package/toolbox/src/mount/Makefile

@@ -0,0 +1,3 @@
+PROG=	mount
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/mv/Makefile

@@ -0,0 +1,3 @@
+PROG=	mv
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/netstat/Makefile

@@ -0,0 +1,3 @@
+PROG=	netstat
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/notify/Makefile

@@ -0,0 +1,3 @@
+PROG=	notify
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/printenv/Makefile

@@ -0,0 +1,3 @@
+PROG=	printenv
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/ps/Makefile

@@ -0,0 +1,3 @@
+PROG=	ps
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/readlink/Makefile

@@ -0,0 +1,3 @@
+PROG=	readlink
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/renice/Makefile

@@ -0,0 +1,3 @@
+PROG=	renice
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/rm/Makefile

@@ -0,0 +1,3 @@
+PROG=	rm
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/rmdir/Makefile

@@ -0,0 +1,3 @@
+PROG=	rmdir
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/rmmod/Makefile

@@ -0,0 +1,3 @@
+PROG=	rmmod
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/route/Makefile

@@ -0,0 +1,3 @@
+PROG=	route
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/schedtop/Makefile

@@ -0,0 +1,3 @@
+PROG=	schedtop
+
+include ../tool.mk

+ 6 - 0
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)='

+ 870 - 0
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);
+		}
+	}
+}

+ 147 - 0
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))

+ 65 - 0
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);

+ 523 - 0
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);
+}

+ 166 - 0
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");
+}

+ 642 - 0
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;
+		}
+}

+ 3 - 0
package/toolbox/src/setkey/Makefile

@@ -0,0 +1,3 @@
+PROG=	setkey
+
+include ../tool.mk

+ 3 - 0
package/toolbox/src/sleep/Makefile

@@ -0,0 +1,3 @@
+PROG=	sleep
+
+include ../tool.mk

+ 101 - 0
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;
+}
+

+ 73 - 0
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;
+}

+ 41 - 0
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;
+}

+ 91 - 0
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;
+    }
+}

+ 1323 - 0
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 */
+
+

+ 94 - 0
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

+ 85 - 0
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);
+}

+ 64 - 0
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;
+}

+ 322 - 0
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);
+}

+ 104 - 0
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);
+    }
+}

+ 80 - 0
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 */

+ 16 - 0
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;
+    }
+}

+ 97 - 0
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;
+}

+ 51 - 0
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;
+}

+ 164 - 0
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;
+}

+ 278 - 0
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;
+}

+ 97 - 0
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;
+}
+

+ 124 - 0
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;
+}

+ 149 - 0
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;
+}

+ 34 - 0
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;
+}

+ 424 - 0
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);
+}

+ 253 - 0
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;
+}

+ 75 - 0
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;
+}

+ 77 - 0
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;
+}

+ 360 - 0
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 */
+}

+ 59 - 0
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;
+}
+

+ 155 - 0
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;
+}

+ 145 - 0
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;
+}

+ 33 - 0
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;
+}
+

Some files were not shown because too many files changed in this diff