diff options
122 files changed, 15154 insertions, 0 deletions
diff --git a/package/toolbox/Makefile b/package/toolbox/Makefile new file mode 100644 index 000000000..af658336a --- /dev/null +++ b/package/toolbox/Makefile @@ -0,0 +1,24 @@ +# This file is part of the OpenADK project. OpenADK is copyrighted +# material, please see the LICENCE file in the top-level directory. + +include ${ADK_TOPDIR}/rules.mk + +PKG_NAME:= toolbox +PKG_VERSION:= 1.0 +PKG_RELEASE:= 1 +PKG_DESCR:= openadk toolbox for very small systems +PKG_SECTION:= base/apps + +NO_DISTFILES:= 1 + +include ${ADK_TOPDIR}/mk/package.mk + +$(eval $(call PKG_template,TOOLBOX,toolbox,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) + +CONFIG_STYLE:= manual + +toolbox-install: + $(INSTALL_DIR) $(IDIR_TOOLBOX)/bin + $(CP) $(WRKINST)/bin/* $(IDIR_TOOLBOX)/bin + +include ${ADK_TOPDIR}/mk/pkg-bottom.mk diff --git a/package/toolbox/src/Makefile b/package/toolbox/src/Makefile new file mode 100644 index 000000000..50afea707 --- /dev/null +++ b/package/toolbox/src/Makefile @@ -0,0 +1,516 @@ +# toolbox for OpenADK on memory-constrained NOMMU binfmt_flat systems +# Copyright © 2017 +# mirabilos <m@mirbsd.org> +# Derived from Android Toolbox +# platform/system/core, as of commit efbf36f2dad8f083de6f48dbb682461d7cfa9781 +# +# Provided that these terms and disclaimer and all copyright notices +# are retained or reproduced in an accompanying document, permission +# is granted to deal in this work without restriction, including un‐ +# limited rights to use, publicly perform, distribute, sell, modify, +# merge, give away, or sublicence. +# +# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to +# the utmost extent permitted by applicable law, neither express nor +# implied; without malicious intent or gross negligence. In no event +# may a licensor, author or contributor be held liable for indirect, +# direct, other damage, loss, or other issues arising in any way out +# of dealing in the work, even if advised of the possibility of such +# damage or existence of a defect, except proven that it results out +# of said person’s immediate fault when using the work as intended. +# +# Individual files are covered by their own licence notices, which are +# also reproduced below (at the end of the top-level Makefile, this file). +# Changes to those files done within the OpenADK toolbox and the build +# system of the toolbox are published under Ⓕ The MirOS Licence as above. +# +# Summarising the licences used: +# • 3-clause BSD +# • ISC (OpenBSD) +# • MirOS +# • Public Domain + + SUBDIR+= lib + + SUBDIR+= cat + SUBDIR+= chmod + SUBDIR+= chown + SUBDIR+= clear + SUBDIR+= cmp + SUBDIR+= cp + SUBDIR+= date + SUBDIR+= dd + SUBDIR+= df + SUBDIR+= dmesg + SUBDIR+= du + SUBDIR+= exists + SUBDIR+= grep + SUBDIR+= hd + SUBDIR+= id + SUBDIR+= ifconfig + SUBDIR+= iftop + SUBDIR+= insmod +# SUBDIR+= ioctl needs pthread.h + SUBDIR+= kill + SUBDIR+= ln + SUBDIR+= ls + SUBDIR+= lsof + SUBDIR+= md5 + SUBDIR+= mkdir + SUBDIR+= mknod + SUBDIR+= mount + SUBDIR+= mv + SUBDIR+= netstat + SUBDIR+= notify + SUBDIR+= printenv + SUBDIR+= ps + SUBDIR+= readlink + SUBDIR+= renice + SUBDIR+= rm + SUBDIR+= rmdir + SUBDIR+= rmmod + SUBDIR+= route + SUBDIR+= schedtop + SUBDIR+= sed + SUBDIR+= setkey + SUBDIR+= sleep + SUBDIR+= sync + SUBDIR+= top + SUBDIR+= touch + SUBDIR+= umount + SUBDIR+= vmstat + +%: + @for subdir in ${SUBDIR}; do \ + echo "==> $$subdir"; \ + ${MAKE} --no-print-directory -I.. \ + -C "$$subdir" $@ || exit $?; \ + echo "<== $$subdir"; \ + done + +all: + +#====================================== +# Now follows the original NOTICE file: +#====================================== + +# Copyright (c) 2010, The Android Open Source Project. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of The Android Open Source Project nor the names +# of its contributors may be used to endorse or promote products +# derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +# Copyright (c) 2009, The Android Open Source Project. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of The Android Open Source Project nor the names +# of its contributors may be used to endorse or promote products +# derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +# Copyright (c) 2008, The Android Open Source Project. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of The Android Open Source Project nor the names +# of its contributors may be used to endorse or promote products +# derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +# Copyright (c) 1998 Robert Nordier +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# This code is derived from software contributed to Berkeley by +# Kevin Fall. +# This code is derived from software contributed to Berkeley by +# Keith Muller of the University of California, San Diego and Lance +# Visser of Convex Computer Corporation. +# This code is derived from software contributed to Berkeley by +# Mike Muuss. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# This code is derived from software contributed to Berkeley by +# Kevin Fall. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +# Copyright (c) 1991, 1993, 1994 +# The Regents of the University of California. All rights reserved. +# +# This code is derived from software contributed to Berkeley by +# Keith Muller of the University of California, San Diego and Lance +# Visser of Convex Computer Corporation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +# /* +# * Copyright (c) 1985, 1987, 1988, 1993 +# * The Regents of the University of California. All rights reserved. +# * +# * Redistribution and use in source and binary forms, with or without +# * modification, are permitted provided that the following conditions +# * are met: +# * 1. Redistributions of source code must retain the above copyright +# * notice, this list of conditions and the following disclaimer. +# * 2. Redistributions in binary form must reproduce the above copyright +# * notice, this list of conditions and the following disclaimer in the +# * documentation and/or other materials provided with the distribution. +# * 3. Neither the name of the University nor the names of its contributors +# * may be used to endorse or promote products derived from this software +# * without specific prior written permission. +# * +# * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# * SUCH DAMAGE. +# */ +# +# /*- +# * Copyright (c) 2007, 2009 +# * Thorsten Glaser <tg@mirbsd.org> +# * +# * Provided that these terms and disclaimer and all copyright notices +# * are retained or reproduced in an accompanying document, permission +# * is granted to deal in this work without restriction, including un- +# * limited rights to use, publicly perform, distribute, sell, modify, +# * merge, give away, or sublicence. +# * +# * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to +# * the utmost extent permitted by applicable law, neither express nor +# * implied; without malicious intent or gross negligence. In no event +# * may a licensor, author or contributor be held liable for indirect, +# * direct, other damage, loss, or other issues arising in any way out +# * of dealing in the work, even if advised of the possibility of such +# * damage or existence of a defect, except proven that it results out +# * of said person's immediate fault when using the work as intended. +# */ +# +# /* +# * This code implements the MD5 message-digest algorithm. +# * The algorithm is due to Ron Rivest. This code was +# * written by Colin Plumb in 1993, no copyright is claimed. +# * This code is in the public domain; do with it what you wish. +# */ +# +# /*- +# * Copyright (c) 2006, 2008, 2011 +# * mirabilos <m@mirbsd.org> +# * +# * Provided that these terms and disclaimer and all copyright notices +# * are retained or reproduced in an accompanying document, permission +# * is granted to deal in this work without restriction, including un- +# * limited rights to use, publicly perform, distribute, sell, modify, +# * merge, give away, or sublicence. +# * +# * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to +# * the utmost extent permitted by applicable law, neither express nor +# * implied; without malicious intent or gross negligence. In no event +# * may a licensor, author or contributor be held liable for indirect, +# * direct, other damage, loss, or other issues arising in any way out +# * of dealing in the work, even if advised of the possibility of such +# * damage or existence of a defect, except proven that it results out +# * of said person's immediate fault when using the work as intended. +# */ +# +# /*- +# * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> +# * +# * Permission to use, copy, modify, and distribute this software for any +# * purpose with or without fee is hereby granted, provided that the above +# * copyright notice and this permission notice appear in all copies. +# * +# * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# */ +# +# /* +# * Copyright (c) 1989, 1990, 1993 +# * The Regents of the University of California. All rights reserved. +# * +# * This code is derived from software contributed to Berkeley by +# * Kevin Fall. +# * +# * Redistribution and use in source and binary forms, with or without +# * modification, are permitted provided that the following conditions +# * are met: +# * 1. Redistributions of source code must retain the above copyright +# * notice, this list of conditions and the following disclaimer. +# * 2. Redistributions in binary form must reproduce the above copyright +# * notice, this list of conditions and the following disclaimer in the +# * documentation and/or other materials provided with the distribution. +# * 3. Neither the name of the University nor the names of its contributors +# * may be used to endorse or promote products derived from this software +# * without specific prior written permission. +# * +# * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# * SUCH DAMAGE. +# */ +# +# /* +# * Copyright (c) 1989, 1993, 1994 +# * The Regents of the University of California. All rights reserved. +# * +# * This code is derived from software contributed to Berkeley by +# * Dave Borman at Cray Research, Inc. +# * +# * Redistribution and use in source and binary forms, with or without +# * modification, are permitted provided that the following conditions +# * are met: +# * 1. Redistributions of source code must retain the above copyright +# * notice, this list of conditions and the following disclaimer. +# * 2. Redistributions in binary form must reproduce the above copyright +# * notice, this list of conditions and the following disclaimer in the +# * documentation and/or other materials provided with the distribution. +# * 3. Neither the name of the University nor the names of its contributors +# * may be used to endorse or promote products derived from this software +# * without specific prior written permission. +# * +# * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# * SUCH DAMAGE. +# */ +# +# /*- +# * Copyright (c) 2015, 2016, 2017 +# * mirabilos <m@mirbsd.org> +# * Copyright (c) 1992 Diomidis Spinellis. +# * Copyright (c) 1992, 1993 +# * The Regents of the University of California. All rights reserved. +# * +# * This code is derived from software contributed to Berkeley by +# * Diomidis Spinellis of Imperial College, University of London. +# * +# * Redistribution and use in source and binary forms, with or without +# * modification, are permitted provided that the following conditions +# * are met: +# * 1. Redistributions of source code must retain the above copyright +# * notice, this list of conditions and the following disclaimer. +# * 2. Redistributions in binary form must reproduce the above copyright +# * notice, this list of conditions and the following disclaimer in the +# * documentation and/or other materials provided with the distribution. +# * 3. Neither the name of the University nor the names of its contributors +# * may be used to endorse or promote products derived from this software +# * without specific prior written permission. +# * +# * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# * SUCH DAMAGE. +# */ +# +# /* +# * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> +# * +# * Permission to use, copy, modify, and distribute this software for any +# * purpose with or without fee is hereby granted, provided that the above +# * copyright notice and this permission notice appear in all copies. +# * +# * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# */ +# +# /*- +# * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, +# * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 +# * mirabilos <m@mirbsd.org> +# * +# * Provided that these terms and disclaimer and all copyright notices +# * are retained or reproduced in an accompanying document, permission +# * is granted to deal in this work without restriction, including un- +# * limited rights to use, publicly perform, distribute, sell, modify, +# * merge, give away, or sublicence. +# * +# * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to +# * the utmost extent permitted by applicable law, neither express nor +# * implied; without malicious intent or gross negligence. In no event +# * may a licensor, author or contributor be held liable for indirect, +# * direct, other damage, loss, or other issues arising in any way out +# * of dealing in the work, even if advised of the possibility of such +# * damage or existence of a defect, except proven that it results out +# * of said person's immediate fault when using the work as intended. +# */ diff --git a/package/toolbox/src/cat/Makefile b/package/toolbox/src/cat/Makefile new file mode 100644 index 000000000..61abf9bbd --- /dev/null +++ b/package/toolbox/src/cat/Makefile @@ -0,0 +1,5 @@ +PROG= cat + +include ../tool.mk + +CFLAGS+=-Wextra diff --git a/package/toolbox/src/cat/cat.c b/package/toolbox/src/cat/cat.c new file mode 100644 index 000000000..442f72073 --- /dev/null +++ b/package/toolbox/src/cat/cat.c @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * mirabilos <m@mirbsd.org> + * + * Provided that these terms and disclaimer and all copyright notices + * are retained or reproduced in an accompanying document, permission + * is granted to deal in this work without restriction, including un- + * limited rights to use, publicly perform, distribute, sell, modify, + * merge, give away, or sublicence. + * + * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to + * the utmost extent permitted by applicable law, neither express nor + * implied; without malicious intent or gross negligence. In no event + * may a licensor, author or contributor be held liable for indirect, + * direct, other damage, loss, or other issues arising in any way out + * of dealing in the work, even if advised of the possibility of such + * damage or existence of a defect, except proven that it results out + * of said person's immediate fault when using the work as intended. + */ + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#define MKSH_CAT_BUFSIZ 256 + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define ksh_sigmask(sig) (((sig) < 1 || (sig) > 127) ? 255 : 128 + (sig)) + +static char buf[MKSH_CAT_BUFSIZ]; +static volatile sig_atomic_t intrsig; + +static const char Tsynerr[] = "cat: syntax error\n"; +static const char unkerr_msg[] = "Unknown error"; +static const char sigint_msg[] = " ...\ncat: Interrupted\n"; + +static void +disperr(const char *fn) +{ + int e = errno; + + write(2, "cat: ", 5); + write(2, fn, strlen(fn)); + write(2, ": ", 2); + if (strerror_r(e, buf, MKSH_CAT_BUFSIZ)) + write(2, unkerr_msg, sizeof(unkerr_msg) - 1); + else + write(2, buf, strlen(buf)); + write(2, "\n", 1); +} + +static void +sighandler(int signo __attribute__((__unused__))) +{ + intrsig = 1; +} + +int +main(int argc __attribute__((__unused__)), char *wp[]) +{ + int fd = 0, rv; + ssize_t n, w; + const char *fn = "<stdin>"; + char *cp; + + ++wp; + /* parse options (POSIX demands this) */ + while ((cp = *wp) && *cp++ == '-') { + if (!cp[0]) + break; + if (cp[0] == '-' && !cp[1]) { + ++wp; + break; + } + while (*cp == 'u') + ++cp; + if (*cp) { + write(2, Tsynerr, sizeof(Tsynerr) - 1); + return (1); + } + ++wp; + } + rv = 0; + + /* catch SIGPIPE */ + signal(SIGPIPE, SIG_IGN); + + /* abort on SIGINT */ + signal(SIGINT, sighandler); + + do { + if (*wp) { + fn = *wp++; + if (fn[0] == '-' && !fn[1]) + fd = 0; + else if ((fd = open(fn, O_RDONLY | O_BINARY)) < 0) { + disperr(fn); + rv = 1; + continue; + } + } + while (/* CONSTCOND */ 1) { + if ((n = read(fd, (cp = buf), MKSH_CAT_BUFSIZ)) == -1) { + if (errno == EINTR) { + /* give the user a chance to ^C out */ + if (intrsig) + goto has_intrsig; + /* interrupted, try again */ + continue; + } + /* an error occured during reading */ + disperr(fn); + rv = 1; + break; + } else if (n == 0) + /* end of file reached */ + break; + while (n) { + if (intrsig) + goto has_intrsig; + if ((w = write(1, cp, n)) != -1) { + n -= w; + cp += w; + continue; + } + if (errno == EINTR) { + has_intrsig: + /* give the user a chance to ^C out */ + if (intrsig) { + write(2, sigint_msg, + sizeof(sigint_msg) - 1); + return (ksh_sigmask(SIGINT)); + } + /* interrupted, try again */ + continue; + } + if (errno == EPIPE) { + /* fake receiving signal */ + rv = ksh_sigmask(SIGPIPE); + } else { + /* an error occured during writing */ + disperr("<stdout>"); + rv = 1; + } + if (fd != 0) + close(fd); + goto out; + } + } + if (fd != 0) + close(fd); + } while (*wp); + + out: + return (rv); +} diff --git a/package/toolbox/src/chmod/Makefile b/package/toolbox/src/chmod/Makefile new file mode 100644 index 000000000..347b93d77 --- /dev/null +++ b/package/toolbox/src/chmod/Makefile @@ -0,0 +1,3 @@ +PROG= chmod + +include ../tool.mk diff --git a/package/toolbox/src/chown/Makefile b/package/toolbox/src/chown/Makefile new file mode 100644 index 000000000..e2bb26ae7 --- /dev/null +++ b/package/toolbox/src/chown/Makefile @@ -0,0 +1,3 @@ +PROG= chown + +include ../tool.mk diff --git a/package/toolbox/src/clear/Makefile b/package/toolbox/src/clear/Makefile new file mode 100644 index 000000000..8e2919133 --- /dev/null +++ b/package/toolbox/src/clear/Makefile @@ -0,0 +1,3 @@ +PROG= clear + +include ../tool.mk diff --git a/package/toolbox/src/cmp/Makefile b/package/toolbox/src/cmp/Makefile new file mode 100644 index 000000000..68dffd303 --- /dev/null +++ b/package/toolbox/src/cmp/Makefile @@ -0,0 +1,3 @@ +PROG= cmp + +include ../tool.mk diff --git a/package/toolbox/src/common.mk b/package/toolbox/src/common.mk new file mode 100644 index 000000000..ab0728f18 --- /dev/null +++ b/package/toolbox/src/common.mk @@ -0,0 +1,21 @@ +OBJS:= ${SRCS:.c=.o} +CFLAGS?= -Os -Wall +CPPFLAGS+= -I. +#CPPFLAGS+= -D_FILE_OFFSET_BITS=64 +CPPFLAGS+= -isystem ../lib +CPPFLAGS+= -D'__COPYRIGHT(x)=' -D'__RCSID(x)=' +CPPFLAGS+= -D'__unused=__attribute__((__unused__))' +CPPFLAGS+= -D'__dead=__attribute__((__noreturn__))' +CLEANFILES+= ${OBJS} ${PROG} + +all: + +COMPILE.c= ${CC} ${CPPFLAGS} ${CFLAGS} ${CFLAGS_$@} -c + +.c.o: + ${COMPILE.c} -o $@ $< + +clean: + rm -f ${CLEANFILES} + +# no depend magic; if you change a .h file, just make clean diff --git a/package/toolbox/src/cp/Makefile b/package/toolbox/src/cp/Makefile new file mode 100644 index 000000000..17545ac06 --- /dev/null +++ b/package/toolbox/src/cp/Makefile @@ -0,0 +1,4 @@ +PROG= cp +SRCS= cp.c utils.c + +include ../tool.mk diff --git a/package/toolbox/src/cp/cp.c b/package/toolbox/src/cp/cp.c new file mode 100644 index 000000000..d04702f2a --- /dev/null +++ b/package/toolbox/src/cp/cp.c @@ -0,0 +1,549 @@ +/* $NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $ */ + +/* + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David Hitz of Auspex Systems Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT( +"@(#) Copyright (c) 1988, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cp.c 8.5 (Berkeley) 4/29/95"; +#else +__RCSID("$NetBSD: cp.c,v 1.58 2012/01/04 15:58:37 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * Cp copies source files to target files. + * + * The global PATH_T structure "to" always contains the path to the + * current target file. Since fts(3) does not change directories, + * this path can be either absolute or dot-relative. + * + * The basic algorithm is to initialize "to" and use fts(3) to traverse + * the file hierarchy rooted in the argument list. A trivial case is the + * case of 'cp file1 file2'. The more interesting case is the case of + * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the + * path (relative to the root of the traversal) is appended to dir (stored + * in "to") to form the final target path. + */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <fts.h> +#include <locale.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "extern.h" + +#define STRIP_TRAILING_SLASH(p) { \ + while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \ + *--(p).p_end = '\0'; \ +} + +static char empty[] = ""; +PATH_T to = { .p_end = to.p_path, .target_end = empty }; + +uid_t myuid; +int Hflag, Lflag, Rflag, Pflag, fflag, iflag, lflag, pflag, rflag, vflag, Nflag; +mode_t myumask; +sig_atomic_t pinfo; + +enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; + +static int copy(char *[], enum op, int); + +#ifdef SIGINFO +static void +progress(int sig __unused) +{ + + pinfo++; +} +#endif + +int +main(int argc, char *argv[]) +{ + struct stat to_stat, tmp_stat; + enum op type; + int ch, fts_options, r, have_trailing_slash; + char *target, **src; + + Hflag = Lflag = Pflag = Rflag = 0; + while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1) + switch (ch) { + case 'H': + Hflag = 1; + Lflag = Pflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = Pflag = 0; + break; + case 'N': + Nflag = 1; + break; + case 'P': + Pflag = 1; + Hflag = Lflag = 0; + break; + case 'R': + Rflag = 1; + break; + case 'a': + Pflag = 1; + pflag = 1; + Rflag = 1; + Hflag = Lflag = 0; + break; + case 'f': + fflag = 1; + iflag = 0; + break; + case 'i': + iflag = isatty(fileno(stdin)); + fflag = 0; + break; + case 'l': + lflag = 1; + break; + case 'p': + pflag = 1; + break; + case 'r': + rflag = 1; + break; + case 'v': + vflag = 1; + break; + case '?': + default: + cp_usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; + + if (argc < 2) + cp_usage(); + + fts_options = FTS_NOCHDIR | FTS_PHYSICAL; + if (rflag) { + if (Rflag) { + errx(EXIT_FAILURE, + "the -R and -r options may not be specified together."); + /* NOTREACHED */ + } + if (Hflag || Lflag || Pflag) { + errx(EXIT_FAILURE, + "the -H, -L, and -P options may not be specified with the -r option."); + /* NOTREACHED */ + } + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + } + + if (Rflag) { + if (Hflag) + fts_options |= FTS_COMFOLLOW; + if (Lflag) { + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + } + } else if (!Pflag) { + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL | FTS_COMFOLLOW; + } + + myuid = getuid(); + + /* Copy the umask for explicit mode setting. */ + myumask = umask(0); + (void)umask(myumask); + + /* Save the target base in "to". */ + target = argv[--argc]; + if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) + errx(EXIT_FAILURE, "%s: name too long", target); + to.p_end = to.p_path + strlen(to.p_path); + have_trailing_slash = (to.p_end[-1] == '/'); + if (have_trailing_slash) + STRIP_TRAILING_SLASH(to); + to.target_end = to.p_end; + + /* Set end of argument list for fts(3). */ + argv[argc] = NULL; + +#ifdef SIGINFO + (void)signal(SIGINFO, progress); +#endif + + /* + * Cp has two distinct cases: + * + * cp [-R] source target + * cp [-R] source1 ... sourceN directory + * + * In both cases, source can be either a file or a directory. + * + * In (1), the target becomes a copy of the source. That is, if the + * source is a file, the target will be a file, and likewise for + * directories. + * + * In (2), the real target is not directory, but "directory/source". + */ + if (Pflag) + r = lstat(to.p_path, &to_stat); + else + r = stat(to.p_path, &to_stat); + if (r == -1 && errno != ENOENT) { + err(EXIT_FAILURE, "%s", to.p_path); + /* NOTREACHED */ + } + if (r == -1 || !S_ISDIR(to_stat.st_mode)) { + /* + * Case (1). Target is not a directory. + */ + if (argc > 1) + cp_usage(); + /* + * Need to detect the case: + * cp -R dir foo + * Where dir is a directory and foo does not exist, where + * we want pathname concatenations turned on but not for + * the initial mkdir(). + */ + if (r == -1) { + if (rflag || (Rflag && (Lflag || Hflag))) + r = stat(*argv, &tmp_stat); + else + r = lstat(*argv, &tmp_stat); + if (r == -1) { + err(EXIT_FAILURE, "%s", *argv); + /* NOTREACHED */ + } + + if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag)) + type = DIR_TO_DNE; + else + type = FILE_TO_FILE; + } else + type = FILE_TO_FILE; + + if (have_trailing_slash && type == FILE_TO_FILE) { + if (r == -1) + errx(1, "directory %s does not exist", + to.p_path); + else + errx(1, "%s is not a directory", to.p_path); + } + } else { + /* + * Case (2). Target is a directory. + */ + type = FILE_TO_DIR; + } + + /* + * make "cp -rp src/ dst" behave like "cp -rp src dst" not + * like "cp -rp src/. dst" + */ + for (src = argv; *src; src++) { + size_t len = strlen(*src); + while (len-- > 1 && (*src)[len] == '/') + (*src)[len] = '\0'; + } + + exit(copy(argv, type, fts_options)); + /* NOTREACHED */ +} + +static int dnestack[MAXPATHLEN]; /* unlikely we'll have more nested dirs */ +static ssize_t dnesp; +static void +pushdne(int dne) +{ + + dnestack[dnesp++] = dne; + assert(dnesp < MAXPATHLEN); +} + +static int +popdne(void) +{ + int rv; + + rv = dnestack[--dnesp]; + assert(dnesp >= 0); + return rv; +} + +static int +copy(char *argv[], enum op type, int fts_options) +{ + struct stat to_stat; + FTS *ftsp; + FTSENT *curr; + int base, dne, sval; + int this_failed, any_failed; + size_t nlen; + char *p, *target_mid; + + base = 0; /* XXX gcc -Wuninitialized (see comment below) */ + + if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) + err(EXIT_FAILURE, "%s", argv[0]); + /* NOTREACHED */ + for (any_failed = 0; (curr = fts_read(ftsp)) != NULL;) { + this_failed = 0; + switch (curr->fts_info) { + case FTS_NS: + case FTS_DNR: + case FTS_ERR: + warnx("%s: %s", curr->fts_path, + strerror(curr->fts_errno)); + this_failed = any_failed = 1; + continue; + case FTS_DC: /* Warn, continue. */ + warnx("%s: directory causes a cycle", curr->fts_path); + this_failed = any_failed = 1; + continue; + } + + /* + * If we are in case (2) or (3) above, we need to append the + * source name to the target name. + */ + if (type != FILE_TO_FILE) { + if ((curr->fts_namelen + + to.target_end - to.p_path + 1) > MAXPATHLEN) { + warnx("%s/%s: name too long (not copied)", + to.p_path, curr->fts_name); + this_failed = any_failed = 1; + continue; + } + + /* + * Need to remember the roots of traversals to create + * correct pathnames. If there's a directory being + * copied to a non-existent directory, e.g. + * cp -R a/dir noexist + * the resulting path name should be noexist/foo, not + * noexist/dir/foo (where foo is a file in dir), which + * is the case where the target exists. + * + * Also, check for "..". This is for correct path + * concatentation for paths ending in "..", e.g. + * cp -R .. /tmp + * Paths ending in ".." are changed to ".". This is + * tricky, but seems the easiest way to fix the problem. + * + * XXX + * Since the first level MUST be FTS_ROOTLEVEL, base + * is always initialized. + */ + if (curr->fts_level == FTS_ROOTLEVEL) { + if (type != DIR_TO_DNE) { + p = strrchr(curr->fts_path, '/'); + base = (p == NULL) ? 0 : + (int)(p - curr->fts_path + 1); + + if (!strcmp(&curr->fts_path[base], + "..")) + base += 1; + } else + base = curr->fts_pathlen; + } + + p = &curr->fts_path[base]; + nlen = curr->fts_pathlen - base; + target_mid = to.target_end; + if (*p != '/' && target_mid[-1] != '/') + *target_mid++ = '/'; + *target_mid = 0; + + if (target_mid - to.p_path + nlen >= PATH_MAX) { + warnx("%s%s: name too long (not copied)", + to.p_path, p); + this_failed = any_failed = 1; + continue; + } + (void)strncat(target_mid, p, nlen); + to.p_end = target_mid + nlen; + *to.p_end = 0; + STRIP_TRAILING_SLASH(to); + } + + sval = Pflag ? lstat(to.p_path, &to_stat) : stat(to.p_path, &to_stat); + /* Not an error but need to remember it happened */ + if (sval == -1) + dne = 1; + else { + if (to_stat.st_dev == curr->fts_statp->st_dev && + to_stat.st_ino == curr->fts_statp->st_ino) { + warnx("%s and %s are identical (not copied).", + to.p_path, curr->fts_path); + this_failed = any_failed = 1; + if (S_ISDIR(curr->fts_statp->st_mode)) + (void)fts_set(ftsp, curr, FTS_SKIP); + continue; + } + if (!S_ISDIR(curr->fts_statp->st_mode) && + S_ISDIR(to_stat.st_mode)) { + warnx("cannot overwrite directory %s with non-directory %s", + to.p_path, curr->fts_path); + this_failed = any_failed = 1; + continue; + } + dne = 0; + } + + switch (curr->fts_statp->st_mode & S_IFMT) { + case S_IFLNK: + /* Catch special case of a non dangling symlink */ + if((fts_options & FTS_LOGICAL) || + ((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) { + if (copy_file(curr, dne)) + this_failed = any_failed = 1; + } else { + if (copy_link(curr, !dne)) + this_failed = any_failed = 1; + } + break; + case S_IFDIR: + if (!Rflag && !rflag) { + if (curr->fts_info == FTS_D) + warnx("%s is a directory (not copied).", + curr->fts_path); + (void)fts_set(ftsp, curr, FTS_SKIP); + this_failed = any_failed = 1; + break; + } + + /* + * Directories get noticed twice: + * In the first pass, create it if needed. + * In the second pass, after the children have been copied, set the permissions. + */ + if (curr->fts_info == FTS_D) /* First pass */ + { + /* + * If the directory doesn't exist, create the new + * one with the from file mode plus owner RWX bits, + * modified by the umask. Trade-off between being + * able to write the directory (if from directory is + * 555) and not causing a permissions race. If the + * umask blocks owner writes, we fail.. + */ + pushdne(dne); + if (dne) { + if (mkdir(to.p_path, + curr->fts_statp->st_mode | S_IRWXU) < 0) + err(EXIT_FAILURE, "%s", + to.p_path); + /* NOTREACHED */ + } else if (!S_ISDIR(to_stat.st_mode)) { + errno = ENOTDIR; + err(EXIT_FAILURE, "%s", + to.p_path); + /* NOTREACHED */ + } + } + else if (curr->fts_info == FTS_DP) /* Second pass */ + { + /* + * If not -p and directory didn't exist, set it to be + * the same as the from directory, umodified by the + * umask; arguably wrong, but it's been that way + * forever. + */ + if (pflag && setfile(curr->fts_statp, 0)) + this_failed = any_failed = 1; + else if ((dne = popdne())) + (void)chmod(to.p_path, + curr->fts_statp->st_mode); + } + else + { + warnx("directory %s encountered when not expected.", + curr->fts_path); + this_failed = any_failed = 1; + break; + } + + break; + case S_IFBLK: + case S_IFCHR: + if (Rflag) { + if (copy_special(curr->fts_statp, !dne)) + this_failed = any_failed = 1; + } else + if (copy_file(curr, dne)) + this_failed = any_failed = 1; + break; + case S_IFIFO: + if (Rflag) { + if (copy_fifo(curr->fts_statp, !dne)) + this_failed = any_failed = 1; + } else + if (copy_file(curr, dne)) + this_failed = any_failed = 1; + break; + default: + if (copy_file(curr, dne)) + this_failed = any_failed = 1; + break; + } + if (vflag && !this_failed) + (void)printf("%s -> %s\n", curr->fts_path, to.p_path); + } + if (errno) { + err(EXIT_FAILURE, "fts_read"); + /* NOTREACHED */ + } + (void)fts_close(ftsp); + return (any_failed); +} diff --git a/package/toolbox/src/cp/extern.h b/package/toolbox/src/cp/extern.h new file mode 100644 index 000000000..6aa9b1b5a --- /dev/null +++ b/package/toolbox/src/cp/extern.h @@ -0,0 +1,63 @@ +/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.2 (Berkeley) 4/1/94 + */ + +#ifndef _EXTERN_H_ +#define _EXTERN_H_ + +#include <signal.h> + +typedef struct { + char *p_end; /* pointer to NULL at end of path */ + char *target_end; /* pointer to end of target base */ + char p_path[MAXPATHLEN + 1]; /* pointer to the start of a path */ +} PATH_T; + +extern PATH_T to; +extern uid_t myuid; +extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag; +extern mode_t myumask; +extern sig_atomic_t pinfo; + +#include <sys/cdefs.h> + +__BEGIN_DECLS +int copy_fifo(struct stat *, int); +int copy_file(FTSENT *, int); +int copy_link(FTSENT *, int); +int copy_special(struct stat *, int); +int set_utimes(const char *, struct stat *); +int setfile(struct stat *, int); +void cp_usage(void) __attribute__((__noreturn__)); +__END_DECLS + +#endif /* !_EXTERN_H_ */ diff --git a/package/toolbox/src/cp/utils.c b/package/toolbox/src/cp/utils.c new file mode 100644 index 000000000..cfb254a45 --- /dev/null +++ b/package/toolbox/src/cp/utils.c @@ -0,0 +1,441 @@ +/* $NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; +#else +__RCSID("$NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $"); +#endif +#endif /* not lint */ + +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "extern.h" + +#ifndef BSD +#define MAXBSIZE 65536 +#endif + +#define MMAP_MAX_SIZE (8 * 1048576) +#define MMAP_MAX_WRITE (64 * 1024) + +int +set_utimes(const char *file, struct stat *fs) +{ + static struct timeval tv[2]; + +#ifndef BSD + tv[0].tv_sec = fs->st_atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = fs->st_mtime; + tv[1].tv_usec = 0; + + if (utimes(file, tv)) { + warn("utimes: %s", file); + return 1; + } +#else + TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); + TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); + + if (lutimes(file, tv)) { + warn("lutimes: %s", file); + return (1); + } +#endif + return (0); +} + +struct finfo { + const char *from; + const char *to; + size_t size; +}; + +static void +progress(const struct finfo *fi, size_t written) +{ + int pcent = (int)((100.0 * written) / fi->size); + + pinfo = 0; + (void)fprintf(stderr, "%s => %s %zu/%zu bytes %d%% written\n", + fi->from, fi->to, written, fi->size, pcent); +} + +int +copy_file(FTSENT *entp, int dne) +{ + static char buf[MAXBSIZE]; + struct stat to_stat, *fs; + int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount; + char *p; + size_t ptotal = 0; + + if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { + warn("%s", entp->fts_path); + return (1); + } + + to_fd = -1; + fs = entp->fts_statp; + tolnk = ((Rflag && !(Lflag || Hflag)) || Pflag); + + /* + * If the file exists and we're interactive, verify with the user. + * If the file DNE, set the mode to be the from file, minus setuid + * bits, modified by the umask; arguably wrong, but it makes copying + * executables work right and it's been that way forever. (The + * other choice is 666 or'ed with the execute bits on the from file + * modified by the umask.) + */ + if (!dne) { + struct stat sb; + int sval; + + if (iflag) { + (void)fprintf(stderr, "overwrite %s? ", to.p_path); + checkch = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (checkch != 'y' && checkch != 'Y') { + (void)close(from_fd); + return (0); + } + } + + sval = tolnk ? + lstat(to.p_path, &sb) : stat(to.p_path, &sb); + if (sval == -1) { + warn("stat: %s", to.p_path); + (void)close(from_fd); + return (1); + } + + if (!(tolnk && S_ISLNK(sb.st_mode))) + to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); + } else + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + fs->st_mode & ~(S_ISUID | S_ISGID)); + + if (to_fd == -1 && (fflag || tolnk)) { + /* + * attempt to remove existing destination file name and + * create a new file + */ + (void)unlink(to.p_path); + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + fs->st_mode & ~(S_ISUID | S_ISGID)); + } + + if (to_fd == -1) { + warn("%s", to.p_path); + (void)close(from_fd); + return (1); + } + + rval = 0; + + /* if hard linking then simply close the open fds, link and return */ + if (lflag) { + (void)close(from_fd); + (void)close(to_fd); + (void)unlink(to.p_path); + if (link(entp->fts_path, to.p_path)) { + warn("%s", to.p_path); + return (1); + } + return (0); + } + /* NOTREACHED */ + + /* + * There's no reason to do anything other than close the file + * now if it's empty, so let's not bother. + */ + if (fs->st_size > 0) { + struct finfo fi; + + fi.from = entp->fts_path; + fi.to = to.p_path; + fi.size = (size_t)fs->st_size; + + /* + * Mmap and write if less than 8M (the limit is so + * we don't totally trash memory on big files). + * This is really a minor hack, but it wins some CPU back. + */ + bool use_read; + + use_read = true; + if (fs->st_size <= MMAP_MAX_SIZE) { + size_t fsize = (size_t)fs->st_size; + p = mmap(NULL, fsize, PROT_READ, MAP_FILE|MAP_SHARED, + from_fd, (off_t)0); + if (p != MAP_FAILED) { + size_t remainder; + + use_read = false; + + /* no madvise on noMMU + (void) madvise(p, (size_t)fs->st_size, + MADV_SEQUENTIAL); + */ + + /* + * Write out the data in small chunks to + * avoid locking the output file for a + * long time if the reading the data from + * the source is slow. + */ + remainder = fsize; + do { + ssize_t chunk; + + chunk = (remainder > MMAP_MAX_WRITE) ? + MMAP_MAX_WRITE : remainder; + if (write(to_fd, &p[fsize - remainder], + chunk) != chunk) { + warn("%s", to.p_path); + rval = 1; + break; + } + remainder -= chunk; + ptotal += chunk; + if (pinfo) + progress(&fi, ptotal); + } while (remainder > 0); + + if (munmap(p, fsize) < 0) { + warn("%s", entp->fts_path); + rval = 1; + } + } + } + + if (use_read) { + while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { + wcount = write(to_fd, buf, (size_t)rcount); + if (rcount != wcount || wcount == -1) { + warn("%s", to.p_path); + rval = 1; + break; + } + ptotal += wcount; + if (pinfo) + progress(&fi, ptotal); + } + if (rcount < 0) { + warn("%s", entp->fts_path); + rval = 1; + } + } + } + + (void)close(from_fd); + + if (rval == 1) { + (void)close(to_fd); + return (1); + } + + if (pflag && setfile(fs, to_fd)) + rval = 1; + /* + * If the source was setuid or setgid, lose the bits unless the + * copy is owned by the same user and group. + */ +#define RETAINBITS \ + (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) + if (!pflag && dne + && fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) { + if (fstat(to_fd, &to_stat)) { + warn("%s", to.p_path); + rval = 1; + } else if (fs->st_gid == to_stat.st_gid && + fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) { + warn("%s", to.p_path); + rval = 1; + } + } + if (close(to_fd)) { + warn("%s", to.p_path); + rval = 1; + } + /* set the mod/access times now after close of the fd */ + if (pflag && set_utimes(to.p_path, fs)) { + rval = 1; + } + return (rval); +} + +int +copy_link(FTSENT *p, int exists) +{ + int len; + char target[MAXPATHLEN]; + + if ((len = readlink(p->fts_path, target, sizeof(target)-1)) == -1) { + warn("readlink: %s", p->fts_path); + return (1); + } + target[len] = '\0'; + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (symlink(target, to.p_path)) { + warn("symlink: %s", target); + return (1); + } + return (pflag ? setfile(p->fts_statp, 0) : 0); +} + +int +copy_fifo(struct stat *from_stat, int exists) +{ + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (mkfifo(to.p_path, from_stat->st_mode)) { + warn("mkfifo: %s", to.p_path); + return (1); + } + return (pflag ? setfile(from_stat, 0) : 0); +} + +int +copy_special(struct stat *from_stat, int exists) +{ + if (exists && unlink(to.p_path)) { + warn("unlink: %s", to.p_path); + return (1); + } + if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) { + warn("mknod: %s", to.p_path); + return (1); + } + return (pflag ? setfile(from_stat, 0) : 0); +} + + +/* + * Function: setfile + * + * Purpose: + * Set the owner/group/permissions for the "to" file to the information + * in the stat structure. If fd is zero, also call set_utimes() to set + * the mod/access times. If fd is non-zero, the caller must do a utimes + * itself after close(fd). + */ +int +setfile(struct stat *fs, int fd) +{ + int rval = 0; +#ifdef BSD + int islink = S_ISLNK(fs->st_mode); +#endif + + fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; + + /* + * Changing the ownership probably won't succeed, unless we're root + * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting + * the mode; current BSD behavior is to remove all setuid bits on + * chown. If chown fails, lose setuid/setgid bits. + */ + if (fd ? fchown(fd, fs->st_uid, fs->st_gid) : + lchown(to.p_path, fs->st_uid, fs->st_gid)) { + if (errno != EPERM) { + warn("chown: %s", to.p_path); + rval = 1; + } + fs->st_mode &= ~(S_ISUID | S_ISGID); + } +#ifndef BSD + if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) { +#else + if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) { +#endif + warn("chmod: %s", to.p_path); + rval = 1; + } + +#ifdef BSD + if (!islink && !Nflag) { + unsigned long fflags = fs->st_flags; + /* + * XXX + * NFS doesn't support chflags; ignore errors unless + * there's reason to believe we're losing bits. + * (Note, this still won't be right if the server + * supports flags and we were trying to *remove* flags + * on a file that we copied, i.e., that we didn't create.) + */ + errno = 0; + if ((fd ? fchflags(fd, fflags) : + chflags(to.p_path, fflags)) == -1) + if (errno != EOPNOTSUPP || fs->st_flags != 0) { + warn("chflags: %s", to.p_path); + rval = 1; + } + } +#endif + /* if fd is non-zero, caller must call set_utimes() after close() */ + if (fd == 0 && set_utimes(to.p_path, fs)) + rval = 1; + return (rval); +} + +void +cp_usage(void) +{ + (void)fprintf(stderr, + "usage: cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n" + " cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/package/toolbox/src/date/Makefile b/package/toolbox/src/date/Makefile new file mode 100644 index 000000000..9d733c02f --- /dev/null +++ b/package/toolbox/src/date/Makefile @@ -0,0 +1,5 @@ +PROG= date + +include ../tool.mk + +CPPFLAGS+= -D'__SCCSID(x)=' diff --git a/package/toolbox/src/date/date.c b/package/toolbox/src/date/date.c new file mode 100644 index 000000000..c4d5ddc82 --- /dev/null +++ b/package/toolbox/src/date/date.c @@ -0,0 +1,272 @@ +/* $OpenBSD: date.c,v 1.26 2003/10/15 15:58:22 mpech Exp $ */ +/* $NetBSD: date.c,v 1.11 1995/09/07 06:21:05 jtc Exp $ */ + +/* + * Copyright (c) 1985, 1987, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/time.h> + +#include <ctype.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> + +__COPYRIGHT("@(#) Copyright (c) 1985, 1987, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"); +__SCCSID("@(#)date.c 8.2 (Berkeley) 4/28/95"); +__RCSID("$MirOS: src/bin/date/date.c,v 1.9 2016/01/02 21:32:56 tg Exp $"); + +extern const char *__progname; + +time_t tval; +int retval; +int slidetime; + +#ifndef TM_YEAR_BASE +#define TM_YEAR_BASE 1900 +#endif + +static void setthetime(char *); +static __dead void badformat(void); +static __dead void usage(void); + +int +main(int argc, char *argv[]) +{ + struct timezone tz; + int ch, rflag; + const char *format = NULL; + char buf[1024]; + int whatformat = 0; + + tz.tz_dsttime = tz.tz_minuteswest = 0; + rflag = 0; + while ((ch = getopt(argc, argv, "ad:nRr:ut:")) != -1) + switch((char)ch) { + case 'a': + slidetime++; + break; + case 'd': /* daylight saving time */ + tz.tz_dsttime = atoi(optarg) ? 1 : 0; + break; + case 'n': /* don't set network */ + break; + case 'R': /* RFC 2822 format */ + whatformat |= 1; + break; + case 'r': /* user specified seconds */ + rflag = 1; + tval = atoll(optarg); + break; + case 'u': /* do everything in UTC */ + if (setenv("TZ", "GMT0", 1) == -1) + err(1, "cannot unsetenv TZ"); + break; + case 't': /* minutes west of GMT */ + /* error check; don't allow "PST" */ + if (isdigit(*optarg)) { + tz.tz_minuteswest = atoi(optarg); + break; + } + /* FALLTHROUGH */ + default: + usage(); + } + argc -= optind; + argv += optind; + + /* + * If -d or -t, set the timezone or daylight saving time; this + * doesn't belong here, the kernel should not know about either. + */ + if ((tz.tz_minuteswest || tz.tz_dsttime) && + settimeofday(NULL, &tz)) + err(1, "settimeofday"); + + if (!rflag && time(&tval) == -1) + err(1, "time"); + + /* allow the operands in any order */ + if (*argv && **argv == '+') { + if (*(*argv + 1)) { + whatformat |= 2; + format = *argv + 1; + } + ++argv; + } + + if (*argv) { + setthetime(*argv); + ++argv; + } + + if (*argv && **argv == '+') { + whatformat |= 4; + format = *argv + 1; + } + + if (whatformat == 0) + format = "%a %b %e %H:%M:%S %Z %Y"; + else if (whatformat == 1) { + format = "%a, %d %b %Y %H:%M:%S %z"; + } else if (whatformat != 2 && whatformat != 4) + errx(1, "more than one format specified"); + + strftime(buf, sizeof (buf), format, localtime(&tval)); + printf("%s\n", buf); + exit(retval); +} + +#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; +void +setthetime(char *p) +{ + struct tm *lt; + struct timeval tv; + char *dot, *t; + const char *pc; + int bigyear; + int yearset = 0; + + for (t = p, dot = NULL; *t; ++t) { + if (isdigit(*t)) + continue; + if (*t == '.' && dot == NULL) { + dot = t; + continue; + } + badformat(); + } + + lt = localtime(&tval); + + lt->tm_isdst = -1; /* correct for DST */ + + if (dot != NULL) { /* .SS */ + *dot++ = '\0'; + if (strlen(dot) != 2) + badformat(); + lt->tm_sec = ATOI2(dot); + if (lt->tm_sec > 61) + badformat(); + } else + lt->tm_sec = 0; + + switch (strlen(p)) { + case 12: /* cc */ + bigyear = ATOI2(p); + lt->tm_year = bigyear * 100 - TM_YEAR_BASE; + yearset = 1; + /* FALLTHROUGH */ + case 10: /* yy */ + if (yearset) { + lt->tm_year += ATOI2(p); + } else { + lt->tm_year = ATOI2(p); + if (lt->tm_year < 69) /* hack for 2000 ;-} */ + lt->tm_year += (2000 - TM_YEAR_BASE); + else + lt->tm_year += (1900 - TM_YEAR_BASE); + } + /* FALLTHROUGH */ + case 8: /* mm */ + lt->tm_mon = ATOI2(p); + if ((lt->tm_mon > 12) || !lt->tm_mon) + badformat(); + --lt->tm_mon; /* time struct is 0 - 11 */ + /* FALLTHROUGH */ + case 6: /* dd */ + lt->tm_mday = ATOI2(p); + if ((lt->tm_mday > 31) || !lt->tm_mday) + badformat(); + /* FALLTHROUGH */ + case 4: /* HH */ + lt->tm_hour = ATOI2(p); + if (lt->tm_hour > 23) + badformat(); + /* FALLTHROUGH */ + case 2: /* MM */ + lt->tm_min = ATOI2(p); + if (lt->tm_min > 59) + badformat(); + break; + default: + badformat(); + } + + /* convert broken-down time to UTC clock time */ + if ((tval = mktime(lt)) < 0) + errx(1, "specified date is outside allowed range"); + + /* set the time */ + if (slidetime) { + struct timeval tv_current; + + if (gettimeofday(&tv_current, NULL) == -1) + err(1, "Could not get local time of day"); + + tv.tv_sec = tval - tv_current.tv_sec; + tv.tv_usec = 0; + if (adjtime(&tv, NULL) == -1) + errx(1, "adjtime"); + } else { + tv.tv_sec = tval; + tv.tv_usec = 0; + if (settimeofday(&tv, NULL)) + err(1, "settimeofday"); + } + + if ((pc = getlogin()) == NULL) + pc = "???"; + syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", pc); +} + +static void +badformat(void) +{ + warnx("illegal time format"); + usage(); +} + +static void +usage(void) +{ + fprintf(stderr, + "usage:\t%s [-anRu] [-d dst] [-r seconds] [-t west] [+format]\n", + __progname); + fprintf(stderr, "\t [[[[[[cc]yy]mm]dd]HH]MM[.SS]]\n"); + exit(1); +} diff --git a/package/toolbox/src/dd/Makefile b/package/toolbox/src/dd/Makefile new file mode 100644 index 000000000..cb4a35107 --- /dev/null +++ b/package/toolbox/src/dd/Makefile @@ -0,0 +1,4 @@ +CPPFLAGS+=-D_FILE_OFFSET_BITS=64 +PROG= dd + +include ../tool.mk diff --git a/package/toolbox/src/df/Makefile b/package/toolbox/src/df/Makefile new file mode 100644 index 000000000..0935a26c0 --- /dev/null +++ b/package/toolbox/src/df/Makefile @@ -0,0 +1,3 @@ +PROG= df + +include ../tool.mk diff --git a/package/toolbox/src/dmesg/Makefile b/package/toolbox/src/dmesg/Makefile new file mode 100644 index 000000000..da1fafcc7 --- /dev/null +++ b/package/toolbox/src/dmesg/Makefile @@ -0,0 +1,3 @@ +PROG= dmesg + +include ../tool.mk diff --git a/package/toolbox/src/du/Makefile b/package/toolbox/src/du/Makefile new file mode 100644 index 000000000..c08670fec --- /dev/null +++ b/package/toolbox/src/du/Makefile @@ -0,0 +1,3 @@ +PROG= du + +include ../tool.mk diff --git a/package/toolbox/src/exists/Makefile b/package/toolbox/src/exists/Makefile new file mode 100644 index 000000000..f37efc438 --- /dev/null +++ b/package/toolbox/src/exists/Makefile @@ -0,0 +1,3 @@ +PROG= exists + +include ../tool.mk diff --git a/package/toolbox/src/grep/Makefile b/package/toolbox/src/grep/Makefile new file mode 100644 index 000000000..30336ccbe --- /dev/null +++ b/package/toolbox/src/grep/Makefile @@ -0,0 +1,4 @@ +PROG= grep +SRCS= fastgrep.c file.c grep.c queue.c util.c + +include ../tool.mk diff --git a/package/toolbox/src/grep/fastgrep.c b/package/toolbox/src/grep/fastgrep.c new file mode 100644 index 000000000..2fcd864e2 --- /dev/null +++ b/package/toolbox/src/grep/fastgrep.c @@ -0,0 +1,336 @@ +/* $OpenBSD: util.c,v 1.36 2007/10/02 17:59:18 otto Exp $ */ +/* $FreeBSD: head/usr.bin/grep/fastgrep.c 211496 2010-08-19 09:28:59Z des $ */ + +/*- + * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav + * Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * XXX: This file is a speed up for grep to cover the defects of the + * regex library. These optimizations should practically be implemented + * there keeping this code clean. This is a future TODO, but for the + * meantime, we need to use this workaround. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: fastgrep.c,v 1.5 2011/04/18 03:27:40 joerg Exp $"); + +#include <limits.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> + +#include "grep.h" + +static inline int grep_cmp(const unsigned char *, const unsigned char *, size_t); +static inline void grep_revstr(unsigned char *, int); + +void +fgrepcomp(fastgrep_t *fg, const char *pat) +{ + unsigned int i; + + /* Initialize. */ + fg->len = strlen(pat); + fg->bol = false; + fg->eol = false; + fg->reversed = false; + + fg->pattern = (unsigned char *)grep_strdup(pat); + + /* Preprocess pattern. */ + for (i = 0; i <= UCHAR_MAX; i++) + fg->qsBc[i] = fg->len; + for (i = 1; i < fg->len; i++) + fg->qsBc[fg->pattern[i]] = fg->len - i; +} + +/* + * Returns: -1 on failure, 0 on success + */ +int +fastcomp(fastgrep_t *fg, const char *pat) +{ + unsigned int i; + int firstHalfDot = -1; + int firstLastHalfDot = -1; + int hasDot = 0; + int lastHalfDot = 0; + int shiftPatternLen; + + /* Initialize. */ + fg->len = strlen(pat); + fg->bol = false; + fg->eol = false; + fg->reversed = false; + fg->word = wflag; + + /* Remove end-of-line character ('$'). */ + if (fg->len > 0 && pat[fg->len - 1] == '$') { + fg->eol = true; + fg->len--; + } + + /* Remove beginning-of-line character ('^'). */ + if (pat[0] == '^') { + fg->bol = true; + fg->len--; + pat++; + } + + if (fg->len >= 14 && + memcmp(pat, "[[:<:]]", 7) == 0 && + memcmp(pat + fg->len - 7, "[[:>:]]", 7) == 0) { + fg->len -= 14; + pat += 7; + /* Word boundary is handled separately in util.c */ + fg->word = true; + } + + /* + * pat has been adjusted earlier to not include '^', '$' or + * the word match character classes at the beginning and ending + * of the string respectively. + */ + fg->pattern = grep_malloc(fg->len + 1); + memcpy(fg->pattern, pat, fg->len); + fg->pattern[fg->len] = '\0'; + + /* Look for ways to cheat...er...avoid the full regex engine. */ + for (i = 0; i < fg->len; i++) { + /* Can still cheat? */ + if (fg->pattern[i] == '.') { + hasDot = i; + if (i < fg->len / 2) { + if (firstHalfDot < 0) + /* Closest dot to the beginning */ + firstHalfDot = i; + } else { + /* Closest dot to the end of the pattern. */ + lastHalfDot = i; + if (firstLastHalfDot < 0) + firstLastHalfDot = i; + } + } else { + /* Free memory and let others know this is empty. */ + free(fg->pattern); + fg->pattern = NULL; + return (-1); + } + } + + /* + * Determine if a reverse search would be faster based on the placement + * of the dots. + */ + if ((!(lflag || cflag)) && ((!(fg->bol || fg->eol)) && + ((lastHalfDot) && ((firstHalfDot < 0) || + ((fg->len - (lastHalfDot + 1)) < (size_t)firstHalfDot)))) && + !oflag && !color) { + fg->reversed = true; + hasDot = fg->len - (firstHalfDot < 0 ? + firstLastHalfDot : firstHalfDot) - 1; + grep_revstr(fg->pattern, fg->len); + } + + /* + * Normal Quick Search would require a shift based on the position the + * next character after the comparison is within the pattern. With + * wildcards, the position of the last dot effects the maximum shift + * distance. + * The closer to the end the wild card is the slower the search. A + * reverse version of this algorithm would be useful for wildcards near + * the end of the string. + * + * Examples: + * Pattern Max shift + * ------- --------- + * this 5 + * .his 4 + * t.is 3 + * th.s 2 + * thi. 1 + */ + + /* Adjust the shift based on location of the last dot ('.'). */ + shiftPatternLen = fg->len - hasDot; + + /* Preprocess pattern. */ + for (i = 0; i <= (signed)UCHAR_MAX; i++) + fg->qsBc[i] = shiftPatternLen; + for (i = hasDot + 1; i < fg->len; i++) { + fg->qsBc[fg->pattern[i]] = fg->len - i; + } + + /* + * Put pattern back to normal after pre-processing to allow for easy + * comparisons later. + */ + if (fg->reversed) + grep_revstr(fg->pattern, fg->len); + + return (0); +} + +int +grep_search(fastgrep_t *fg, const unsigned char *data, size_t len, regmatch_t *pmatch) +{ + unsigned int j; + int ret = REG_NOMATCH; + + if (pmatch->rm_so == (ssize_t)len) + return (ret); + + if (fg->bol && pmatch->rm_so != 0) { + pmatch->rm_so = len; + pmatch->rm_eo = len; + return (ret); + } + + /* No point in going farther if we do not have enough data. */ + if (len < fg->len) + return (ret); + + /* Only try once at the beginning or ending of the line. */ + if (fg->bol || fg->eol) { + /* Simple text comparison. */ + /* Verify data is >= pattern length before searching on it. */ + if (len >= fg->len) { + /* Determine where in data to start search at. */ + j = fg->eol ? len - fg->len : 0; + if (!((fg->bol && fg->eol) && (len != fg->len))) + if (grep_cmp(fg->pattern, data + j, + fg->len) == -1) { + pmatch->rm_so = j; + pmatch->rm_eo = j + fg->len; + ret = 0; + } + } + } else if (fg->reversed) { + /* Quick Search algorithm. */ + j = len; + do { + if (grep_cmp(fg->pattern, data + j - fg->len, + fg->len) == -1) { + pmatch->rm_so = j - fg->len; + pmatch->rm_eo = j; + ret = 0; + break; + } + /* Shift if within bounds, otherwise, we are done. */ + if (j == fg->len) + break; + j -= fg->qsBc[data[j - fg->len - 1]]; + } while (j >= fg->len); + } else { + /* Quick Search algorithm. */ + j = pmatch->rm_so; + do { + if (grep_cmp(fg->pattern, data + j, fg->len) == -1) { + pmatch->rm_so = j; + pmatch->rm_eo = j + fg->len; + ret = 0; + break; + } + + /* Shift if within bounds, otherwise, we are done. */ + if (j + fg->len == len) + break; + else + j += fg->qsBc[data[j + fg->len]]; + } while (j <= (len - fg->len)); + } + + return (ret); +} + +/* + * Returns: i >= 0 on failure (position that it failed) + * -1 on success + */ +static inline int +grep_cmp(const unsigned char *pat, const unsigned char *data, size_t len) +{ + size_t size; + wchar_t *wdata, *wpat; + unsigned int i; + + if (iflag) { + if ((size = mbstowcs(NULL, (const char *)data, 0)) == + ((size_t) - 1)) + return (-1); + + wdata = grep_malloc(size * sizeof(wint_t)); + + if (mbstowcs(wdata, (const char *)data, size) == + ((size_t) - 1)) + return (-1); + + if ((size = mbstowcs(NULL, (const char *)pat, 0)) == + ((size_t) - 1)) + return (-1); + + wpat = grep_malloc(size * sizeof(wint_t)); + + if (mbstowcs(wpat, (const char *)pat, size) == ((size_t) - 1)) + return (-1); + for (i = 0; i < len; i++) { + if ((towlower(wpat[i]) == towlower(wdata[i])) || + ((grepbehave != GREP_FIXED) && wpat[i] == L'.')) + continue; + free(wpat); + free(wdata); + return (i); + } + } else { + for (i = 0; i < len; i++) { + if ((pat[i] == data[i]) || ((grepbehave != GREP_FIXED) && + pat[i] == '.')) + continue; + return (i); + } + } + return (-1); +} + +static inline void +grep_revstr(unsigned char *str, int len) +{ + int i; + char c; + + for (i = 0; i < len / 2; i++) { + c = str[i]; + str[i] = str[len - i - 1]; + str[len - i - 1] = c; + } +} diff --git a/package/toolbox/src/grep/file.c b/package/toolbox/src/grep/file.c new file mode 100644 index 000000000..4cbb2a736 --- /dev/null +++ b/package/toolbox/src/grep/file.c @@ -0,0 +1,215 @@ +/* $NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $ */ +/* $FreeBSD: head/usr.bin/grep/file.c 211496 2010-08-19 09:28:59Z des $ */ +/* $OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $ */ + +/*- + * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav + * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org> + * Copyright (C) 2010 Dimitry Andric <dimitry@andric.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: file.c,v 1.7 2011/04/18 22:46:48 joerg Exp $"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wchar.h> +#include <wctype.h> + +#include "grep.h" + +#define MAXBUFSIZ (32 * 1024) +#define LNBUFBUMP 80 + +static unsigned char buffer[MAXBUFSIZ]; +static unsigned char *bufpos; +static size_t bufrem; + +static unsigned char *lnbuf; +static size_t lnbuflen; + +static inline int +grep_refill(struct file *f) +{ + ssize_t nr; + + bufpos = buffer; + bufrem = 0; + + nr = read(f->fd, buffer, MAXBUFSIZ); + + if (nr < 0) + return (-1); + + bufrem = nr; + return (0); +} + +static inline int +grep_lnbufgrow(size_t newlen) +{ + + if (lnbuflen < newlen) { + lnbuf = grep_realloc(lnbuf, newlen); + lnbuflen = newlen; + } + + return (0); +} + +char * +grep_fgetln(struct file *f, size_t *lenp) +{ + unsigned char *p; + char *ret; + size_t len; + size_t off; + ptrdiff_t diff; + + /* Fill the buffer, if necessary */ + if (bufrem == 0 && grep_refill(f) != 0) + goto error; + + if (bufrem == 0) { + /* Return zero length to indicate EOF */ + *lenp = 0; + return ((char *)bufpos); + } + + /* Look for a newline in the remaining part of the buffer */ + if ((p = memchr(bufpos, line_sep, bufrem)) != NULL) { + ++p; /* advance over newline */ + ret = (char *)bufpos; + len = p - bufpos; + bufrem -= len; + bufpos = p; + *lenp = len; + return (ret); + } + + /* We have to copy the current buffered data to the line buffer */ + for (len = bufrem, off = 0; ; len += bufrem) { + /* Make sure there is room for more data */ + if (grep_lnbufgrow(len + LNBUFBUMP)) + goto error; + memcpy(lnbuf + off, bufpos, len - off); + off = len; + if (grep_refill(f) != 0) + goto error; + if (bufrem == 0) + /* EOF: return partial line */ + break; + if ((p = memchr(bufpos, line_sep, bufrem)) == NULL) + continue; + /* got it: finish up the line (like code above) */ + ++p; + diff = p - bufpos; + len += diff; + if (grep_lnbufgrow(len)) + goto error; + memcpy(lnbuf + off, bufpos, diff); + bufrem -= diff; + bufpos = p; + break; + } + *lenp = len; + return ((char *)lnbuf); + +error: + *lenp = 0; + return (NULL); +} + +static inline struct file * +grep_file_init(struct file *f) +{ + /* Fill read buffer, also catches errors early */ + if (grep_refill(f) != 0) + goto error; + + /* Check for binary stuff, if necessary */ + if (!nulldataflag && binbehave != BINFILE_TEXT && + memchr(bufpos, '\0', bufrem) != NULL) + f->binary = true; + + return (f); +error: + close(f->fd); + free(f); + return (NULL); +} + +/* + * Opens a file for processing. + */ +struct file * +grep_open(const char *path) +{ + struct file *f; + + f = grep_malloc(sizeof *f); + memset(f, 0, sizeof *f); + if (path == NULL) { + /* Processing stdin implies --line-buffered. */ + lbflag = true; + f->fd = STDIN_FILENO; + } else if ((f->fd = open(path, O_RDONLY)) == -1) { + free(f); + return (NULL); + } + + return (grep_file_init(f)); +} + +/* + * Closes a file. + */ +void +grep_close(struct file *f) +{ + + close(f->fd); + + /* Reset read buffer and line buffer */ + bufpos = buffer; + bufrem = 0; + + free(lnbuf); + lnbuf = NULL; + lnbuflen = 0; +} diff --git a/package/toolbox/src/grep/grep.c b/package/toolbox/src/grep/grep.c new file mode 100644 index 000000000..6d70f8252 --- /dev/null +++ b/package/toolbox/src/grep/grep.c @@ -0,0 +1,695 @@ +/* $NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $ */ +/* $FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $ */ +/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */ + +/*- + * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav + * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $"); + +#include <sys/stat.h> +#include <sys/types.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <getopt.h> +#include <limits.h> +#include <libgen.h> +#include <locale.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "grep.h" + +/* + * Default messags to use when NLS is disabled or no catalogue + * is found. + */ +const char *errstr[] = { + "", +/* 1*/ "(standard input)", +/* 2*/ "cannot read bzip2 compressed file", +/* 3*/ "unknown %s option", +/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n", +/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", +/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", +/* 7*/ "\t[pattern] [file ...]\n", +/* 8*/ "Binary file %s matches\n", +/* 9*/ "%s (BSD grep) %s\n", +}; + +/* Flags passed to regcomp() and regexec() */ +int cflags = 0; +int eflags = REG_STARTEND; + +/* Searching patterns */ +unsigned int patterns, pattern_sz; +char **pattern; +regex_t *r_pattern; +fastgrep_t *fg_pattern; + +/* Filename exclusion/inclusion patterns */ +unsigned int fpatterns, fpattern_sz; +unsigned int dpatterns, dpattern_sz; +struct epat *dpattern, *fpattern; + +/* For regex errors */ +char re_error[RE_ERROR_BUF + 1]; + +/* Command-line flags */ +unsigned long long Aflag; /* -A x: print x lines trailing each match */ +unsigned long long Bflag; /* -B x: print x lines leading each match */ +bool Hflag; /* -H: always print file name */ +bool Lflag; /* -L: only show names of files with no matches */ +bool bflag; /* -b: show block numbers for each match */ +bool cflag; /* -c: only show a count of matching lines */ +bool hflag; /* -h: don't print filename headers */ +bool iflag; /* -i: ignore case */ +bool lflag; /* -l: only show names of files with matches */ +bool mflag; /* -m x: stop reading the files after x matches */ +unsigned long long mcount; /* count for -m */ +bool nflag; /* -n: show line numbers in front of matching lines */ +bool oflag; /* -o: print only matching part */ +bool qflag; /* -q: quiet mode (don't output anything) */ +bool sflag; /* -s: silent mode (ignore errors) */ +bool vflag; /* -v: only show non-matching lines */ +bool wflag; /* -w: pattern must start and end on word boundaries */ +bool xflag; /* -x: pattern must match entire line */ +bool lbflag; /* --line-buffered */ +bool nullflag; /* --null */ +bool nulldataflag; /* --null-data */ +unsigned char line_sep = '\n'; /* 0 for --null-data */ +char *label; /* --label */ +const char *color; /* --color */ +int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ +int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ +int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ +int devbehave = DEV_READ; /* -D: handling of devices */ +int dirbehave = DIR_READ; /* -dRr: handling of directories */ +int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ + +bool dexclude, dinclude; /* --exclude-dir and --include-dir */ +bool fexclude, finclude; /* --exclude and --include */ + +enum { + BIN_OPT = CHAR_MAX + 1, + COLOR_OPT, + DECOMPRESS_OPT, + HELP_OPT, + MMAP_OPT, + LINEBUF_OPT, + LABEL_OPT, + R_EXCLUDE_OPT, + R_INCLUDE_OPT, + R_DEXCLUDE_OPT, + R_DINCLUDE_OPT +}; + +static inline const char *init_color(const char *); + +/* Housekeeping */ +int tail; /* lines left to print */ +bool notfound; /* file not found */ + +extern char *__progname; + +/* + * Prints usage information and returns 2. + */ +__dead static void +usage(void) +{ + fprintf(stderr, getstr(4), __progname); + fprintf(stderr, "%s", getstr(5)); + fprintf(stderr, "%s", getstr(5)); + fprintf(stderr, "%s", getstr(6)); + fprintf(stderr, "%s", getstr(7)); + exit(2); +} + +static const char optstr[] = + "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxyz"; + +struct option long_options[] = +{ + {"binary-files", required_argument, NULL, BIN_OPT}, + {"decompress", no_argument, NULL, DECOMPRESS_OPT}, + {"help", no_argument, NULL, HELP_OPT}, + {"mmap", no_argument, NULL, MMAP_OPT}, + {"line-buffered", no_argument, NULL, LINEBUF_OPT}, + {"label", required_argument, NULL, LABEL_OPT}, + {"color", optional_argument, NULL, COLOR_OPT}, + {"colour", optional_argument, NULL, COLOR_OPT}, + {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, + {"include", required_argument, NULL, R_INCLUDE_OPT}, + {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, + {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, + {"after-context", required_argument, NULL, 'A'}, + {"text", no_argument, NULL, 'a'}, + {"before-context", required_argument, NULL, 'B'}, + {"byte-offset", no_argument, NULL, 'b'}, + {"context", optional_argument, NULL, 'C'}, + {"count", no_argument, NULL, 'c'}, + {"devices", required_argument, NULL, 'D'}, + {"directories", required_argument, NULL, 'd'}, + {"extended-regexp", no_argument, NULL, 'E'}, + {"regexp", required_argument, NULL, 'e'}, + {"fixed-strings", no_argument, NULL, 'F'}, + {"file", required_argument, NULL, 'f'}, + {"basic-regexp", no_argument, NULL, 'G'}, + {"no-filename", no_argument, NULL, 'h'}, + {"with-filename", no_argument, NULL, 'H'}, + {"ignore-case", no_argument, NULL, 'i'}, + {"bz2decompress", no_argument, NULL, 'J'}, + {"files-with-matches", no_argument, NULL, 'l'}, + {"files-without-match", no_argument, NULL, 'L'}, + {"max-count", required_argument, NULL, 'm'}, + {"line-number", no_argument, NULL, 'n'}, + {"only-matching", no_argument, NULL, 'o'}, + {"quiet", no_argument, NULL, 'q'}, + {"silent", no_argument, NULL, 'q'}, + {"recursive", no_argument, NULL, 'r'}, + {"no-messages", no_argument, NULL, 's'}, + {"binary", no_argument, NULL, 'U'}, + {"unix-byte-offsets", no_argument, NULL, 'u'}, + {"invert-match", no_argument, NULL, 'v'}, + {"version", no_argument, NULL, 'V'}, + {"word-regexp", no_argument, NULL, 'w'}, + {"line-regexp", no_argument, NULL, 'x'}, + {"null", no_argument, NULL, 'Z'}, + {"null-data", no_argument, NULL, 'z'}, + {NULL, no_argument, NULL, 0} +}; + +/* + * Adds a searching pattern to the internal array. + */ +static void +add_pattern(char *pat, size_t len) +{ + + /* TODO: Check for empty patterns and shortcut */ + + /* Increase size if necessary */ + if (patterns == pattern_sz) { + pattern_sz *= 2; + pattern = grep_realloc(pattern, ++pattern_sz * + sizeof(*pattern)); + } + if (len > 0 && pat[len - 1] == '\n') + --len; + /* pat may not be NUL-terminated */ + pattern[patterns] = grep_malloc(len + 1); + memcpy(pattern[patterns], pat, len); + pattern[patterns][len] = '\0'; + ++patterns; +} + +/* + * Adds a file include/exclude pattern to the internal array. + */ +static void +add_fpattern(const char *pat, int mode) +{ + + /* Increase size if necessary */ + if (fpatterns == fpattern_sz) { + fpattern_sz *= 2; + fpattern = grep_realloc(fpattern, ++fpattern_sz * + sizeof(struct epat)); + } + fpattern[fpatterns].pat = grep_strdup(pat); + fpattern[fpatterns].mode = mode; + ++fpatterns; +} + +/* + * Adds a directory include/exclude pattern to the internal array. + */ +static void +add_dpattern(const char *pat, int mode) +{ + + /* Increase size if necessary */ + if (dpatterns == dpattern_sz) { + dpattern_sz *= 2; + dpattern = grep_realloc(dpattern, ++dpattern_sz * + sizeof(struct epat)); + } + dpattern[dpatterns].pat = grep_strdup(pat); + dpattern[dpatterns].mode = mode; + ++dpatterns; +} + +/* + * Reads searching patterns from a file and adds them with add_pattern(). + */ +static void +read_patterns(const char *fn) +{ + FILE *f; + char *line; + size_t len; + ssize_t rlen; + + if ((f = fopen(fn, "r")) == NULL) + err(2, "%s", fn); + line = NULL; + len = 0; +#ifndef ANDROID + while ((rlen = getline(&line, &len, f)) != -1) + add_pattern(line, *line == '\n' ? 0 : (size_t)rlen); +#endif + free(line); + if (ferror(f)) + err(2, "%s", fn); + fclose(f); +} + +static inline const char * +init_color(const char *d) +{ + char *c; + + c = getenv("GREP_COLOR"); + return (c != NULL ? c : d); +} + +int +main(int argc, char *argv[]) +{ + char **aargv, **eargv, *eopts; + char *ep; + unsigned long long l; + unsigned int aargc, eargc, i, j; + int c, lastc, needpattern, newarg, prevoptind; + + /* Check what is the program name of the binary. In this + way we can have all the funcionalities in one binary + without the need of scripting and using ugly hacks. */ + switch (__progname[0]) { + case 'e': + grepbehave = GREP_EXTENDED; + break; + case 'f': + grepbehave = GREP_FIXED; + break; + case 'g': + grepbehave = GREP_BASIC; + break; + case 'z': + filebehave = FILE_GZIP; + switch(__progname[1]) { + case 'e': + grepbehave = GREP_EXTENDED; + break; + case 'f': + grepbehave = GREP_FIXED; + break; + case 'g': + grepbehave = GREP_BASIC; + break; + } + break; + } + + lastc = '\0'; + newarg = 1; + prevoptind = 1; + needpattern = 1; + + eopts = getenv("GREP_OPTIONS"); + + /* support for extra arguments in GREP_OPTIONS */ + eargc = 0; + if (eopts != NULL) { + char *str; + + /* make an estimation of how many extra arguments we have */ + for (j = 0; j < strlen(eopts); j++) + if (eopts[j] == ' ') + eargc++; + + eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); + + eargc = 0; + /* parse extra arguments */ + while ((str = strsep(&eopts, " ")) != NULL) + eargv[eargc++] = grep_strdup(str); + + aargv = (char **)grep_calloc(eargc + argc + 1, + sizeof(char *)); + + aargv[0] = argv[0]; + for (i = 0; i < eargc; i++) + aargv[i + 1] = eargv[i]; + for (j = 1; j < (unsigned int)argc; j++, i++) + aargv[i + 1] = argv[j]; + + aargc = eargc + argc; + } else { + aargv = argv; + aargc = argc; + } + + while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != + -1)) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (newarg || !isdigit(lastc)) + Aflag = 0; + else if (Aflag > LLONG_MAX / 10) { + errno = ERANGE; + err(2, NULL); + } + Aflag = Bflag = (Aflag * 10) + (c - '0'); + break; + case 'C': + if (optarg == NULL) { + Aflag = Bflag = 2; + break; + } + /* FALLTHROUGH */ + case 'A': + /* FALLTHROUGH */ + case 'B': + errno = 0; + l = strtoull(optarg, &ep, 10); + if (((errno == ERANGE) && (l == ULLONG_MAX)) || + ((errno == EINVAL) && (l == 0))) + err(2, NULL); + else if (ep[0] != '\0') { + errno = EINVAL; + err(2, NULL); + } + if (c == 'A') + Aflag = l; + else if (c == 'B') + Bflag = l; + else + Aflag = Bflag = l; + break; + case 'a': + binbehave = BINFILE_TEXT; + break; + case 'b': + bflag = true; + break; + case 'c': + cflag = true; + break; + case 'D': + if (strcasecmp(optarg, "skip") == 0) + devbehave = DEV_SKIP; + else if (strcasecmp(optarg, "read") == 0) + devbehave = DEV_READ; + else + errx(2, getstr(3), "--devices"); + break; + case 'd': + if (strcasecmp("recurse", optarg) == 0) { + Hflag = true; + dirbehave = DIR_RECURSE; + } else if (strcasecmp("skip", optarg) == 0) + dirbehave = DIR_SKIP; + else if (strcasecmp("read", optarg) == 0) + dirbehave = DIR_READ; + else + errx(2, getstr(3), "--directories"); + break; + case 'E': + grepbehave = GREP_EXTENDED; + break; + case 'e': + add_pattern(optarg, strlen(optarg)); + needpattern = 0; + break; + case 'F': + grepbehave = GREP_FIXED; + break; + case 'f': + read_patterns(optarg); + needpattern = 0; + break; + case 'G': + grepbehave = GREP_BASIC; + break; + case 'H': + Hflag = true; + break; + case 'h': + Hflag = false; + hflag = true; + break; + case 'I': + binbehave = BINFILE_SKIP; + break; + case 'i': + case 'y': + iflag = true; + cflags |= REG_ICASE; + break; + case 'J': + filebehave = FILE_BZIP; + break; + case 'L': + lflag = false; + Lflag = true; + break; + case 'l': + Lflag = false; + lflag = true; + break; + case 'm': + mflag = true; + errno = 0; + mcount = strtoull(optarg, &ep, 10); + if (((errno == ERANGE) && (mcount == ULLONG_MAX)) || + ((errno == EINVAL) && (mcount == 0))) + err(2, NULL); + else if (ep[0] != '\0') { + errno = EINVAL; + err(2, NULL); + } + break; + case 'n': + nflag = true; + break; + case 'O': + linkbehave = LINK_EXPLICIT; + break; + case 'o': + oflag = true; + break; + case 'p': + linkbehave = LINK_SKIP; + break; + case 'q': + qflag = true; + break; + case 'S': + linkbehave = LINK_READ; + break; + case 'R': + case 'r': + dirbehave = DIR_RECURSE; + Hflag = true; + break; + case 's': + sflag = true; + break; + case 'U': + binbehave = BINFILE_BIN; + break; + case 'u': + case MMAP_OPT: + /* noop, compatibility */ + break; + case 'V': + printf(getstr(9), __progname, VERSION); + exit(0); + case 'v': + vflag = true; + break; + case 'w': + wflag = true; + break; + case 'x': + xflag = true; + break; + case 'Z': + nullflag = true; + break; + case 'z': + nulldataflag = true; + line_sep = '\0'; + break; + case BIN_OPT: + if (strcasecmp("binary", optarg) == 0) + binbehave = BINFILE_BIN; + else if (strcasecmp("without-match", optarg) == 0) + binbehave = BINFILE_SKIP; + else if (strcasecmp("text", optarg) == 0) + binbehave = BINFILE_TEXT; + else + errx(2, getstr(3), "--binary-files"); + break; + case COLOR_OPT: + color = NULL; + if (optarg == NULL || strcasecmp("auto", optarg) == 0 || + strcasecmp("tty", optarg) == 0 || + strcasecmp("if-tty", optarg) == 0) { + char *term; + + term = getenv("TERM"); + if (isatty(STDOUT_FILENO) && term != NULL && + strcasecmp(term, "dumb") != 0) + color = init_color("01;31"); + } else if (strcasecmp("always", optarg) == 0 || + strcasecmp("yes", optarg) == 0 || + strcasecmp("force", optarg) == 0) { + color = init_color("01;31"); + } else if (strcasecmp("never", optarg) != 0 && + strcasecmp("none", optarg) != 0 && + strcasecmp("no", optarg) != 0) + errx(2, getstr(3), "--color"); + break; + case DECOMPRESS_OPT: + filebehave = FILE_GZIP; + break; + case LABEL_OPT: + label = optarg; + break; + case LINEBUF_OPT: + lbflag = true; + break; + case R_INCLUDE_OPT: + finclude = true; + add_fpattern(optarg, INCL_PAT); + break; + case R_EXCLUDE_OPT: + fexclude = true; + add_fpattern(optarg, EXCL_PAT); + break; + case R_DINCLUDE_OPT: + dinclude = true; + add_dpattern(optarg, INCL_PAT); + break; + case R_DEXCLUDE_OPT: + dexclude = true; + add_dpattern(optarg, EXCL_PAT); + break; + case HELP_OPT: + default: + usage(); + } + lastc = c; + newarg = optind != prevoptind; + prevoptind = optind; + } + aargc -= optind; + aargv += optind; + + /* Fail if we don't have any pattern */ + if (aargc == 0 && needpattern) + usage(); + + /* Process patterns from command line */ + if (aargc != 0 && needpattern) { + add_pattern(*aargv, strlen(*aargv)); + --aargc; + ++aargv; + } + + switch (grepbehave) { + case GREP_FIXED: + case GREP_BASIC: + break; + case GREP_EXTENDED: + cflags |= REG_EXTENDED; + break; + default: + /* NOTREACHED */ + usage(); + } + + fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); + r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); +/* + * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance. + * Optimizations should be done there. + */ + /* Check if cheating is allowed (always is for fgrep). */ + if (grepbehave == GREP_FIXED) { + for (i = 0; i < patterns; ++i) + fgrepcomp(&fg_pattern[i], pattern[i]); + } else { + for (i = 0; i < patterns; ++i) { + if (fastcomp(&fg_pattern[i], pattern[i])) { + /* Fall back to full regex library */ + c = regcomp(&r_pattern[i], pattern[i], cflags); + if (c != 0) { + regerror(c, &r_pattern[i], re_error, + RE_ERROR_BUF); + errx(2, "%s", re_error); + } + } + } + } + + if (lbflag) + setlinebuf(stdout); + + if ((aargc == 0 || aargc == 1) && !Hflag) + hflag = true; + + if (aargc == 0) + exit(!procfile("-")); + + if (dirbehave == DIR_RECURSE) + c = grep_tree(aargv); + else + for (c = 0; aargc--; ++aargv) { + if ((finclude || fexclude) && !file_matching(*aargv)) + continue; + c+= procfile(*aargv); + } + + /* Find out the correct return value according to the + results and the command line option. */ + exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1)); +} diff --git a/package/toolbox/src/grep/grep.h b/package/toolbox/src/grep/grep.h new file mode 100644 index 000000000..334f67c43 --- /dev/null +++ b/package/toolbox/src/grep/grep.h @@ -0,0 +1,149 @@ +/* $NetBSD: grep.h,v 1.8 2012/05/06 22:27:00 joerg Exp $ */ +/* $OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $ */ +/* $FreeBSD: head/usr.bin/grep/grep.h 211496 2010-08-19 09:28:59Z des $ */ + +/*- + * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav + * Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <limits.h> +#include <regex.h> +#include <stdbool.h> +#include <stdio.h> + +#define getstr(n) errstr[n] + +extern const char *errstr[]; + +#define VERSION "2.5.1-FreeBSD" + +#define GREP_FIXED 0 +#define GREP_BASIC 1 +#define GREP_EXTENDED 2 + +#define BINFILE_BIN 0 +#define BINFILE_SKIP 1 +#define BINFILE_TEXT 2 + +#define FILE_STDIO 0 +#define FILE_GZIP 1 +#define FILE_BZIP 2 + +#define DIR_READ 0 +#define DIR_SKIP 1 +#define DIR_RECURSE 2 + +#define DEV_READ 0 +#define DEV_SKIP 1 + +#define LINK_READ 0 +#define LINK_EXPLICIT 1 +#define LINK_SKIP 2 + +#define EXCL_PAT 0 +#define INCL_PAT 1 + +#define MAX_LINE_MATCHES 32 + +struct file { + int fd; + bool binary; +}; + +struct str { + off_t off; + size_t len; + char *dat; + char *file; + int line_no; +}; + +struct epat { + char *pat; + int mode; +}; + +typedef struct { + size_t len; + unsigned char *pattern; + int qsBc[UCHAR_MAX + 1]; + /* flags */ + bool bol; + bool eol; + bool reversed; + bool word; +} fastgrep_t; + +/* Flags passed to regcomp() and regexec() */ +extern int cflags, eflags; + +/* Command line flags */ +extern bool Eflag, Fflag, Gflag, Hflag, Lflag, + bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag, + qflag, sflag, vflag, wflag, xflag; +extern bool dexclude, dinclude, fexclude, finclude, lbflag, nullflag, nulldataflag; +extern unsigned char line_sep; +extern unsigned long long Aflag, Bflag, mcount; +extern char *label; +extern const char *color; +extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave; + +extern bool notfound; +extern int tail; +extern unsigned int dpatterns, fpatterns, patterns; +extern char **pattern; +extern struct epat *dpattern, *fpattern; +extern regex_t *er_pattern, *r_pattern; +extern fastgrep_t *fg_pattern; + +/* For regex errors */ +#define RE_ERROR_BUF 512 +extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */ + +/* util.c */ +bool file_matching(const char *fname); +int procfile(const char *fn); +int grep_tree(char **argv); +void *grep_malloc(size_t size); +void *grep_calloc(size_t nmemb, size_t size); +void *grep_realloc(void *ptr, size_t size); +char *grep_strdup(const char *str); +void printline(struct str *line, int sep, regmatch_t *matches, int m); + +/* queue.c */ +void enqueue(struct str *x); +void printqueue(void); +void clearqueue(void); + +/* file.c */ +void grep_close(struct file *f); +struct file *grep_open(const char *path); +char *grep_fgetln(struct file *f, size_t *len); + +/* fastgrep.c */ +int fastcomp(fastgrep_t *, const char *); +void fgrepcomp(fastgrep_t *, const char *); +int grep_search(fastgrep_t *, const unsigned char *, size_t, regmatch_t *); diff --git a/package/toolbox/src/grep/queue.c b/package/toolbox/src/grep/queue.c new file mode 100644 index 000000000..e3c6be17a --- /dev/null +++ b/package/toolbox/src/grep/queue.c @@ -0,0 +1,116 @@ +/* $NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $ */ +/* $FreeBSD: head/usr.bin/grep/queue.c 211496 2010-08-19 09:28:59Z des $ */ +/*- + * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * A really poor man's queue. It does only what it has to and gets out of + * Dodge. It is used in place of <sys/queue.h> to get a better performance. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $"); + +#include <sys/param.h> +#include <sys/queue.h> + +#include <stdlib.h> +#include <string.h> + +#include "grep.h" + +struct qentry { + STAILQ_ENTRY(qentry) list; + struct str data; +}; + +static STAILQ_HEAD(, qentry) queue = STAILQ_HEAD_INITIALIZER(queue); +static unsigned long long count; + +static struct qentry *dequeue(void); + +void +enqueue(struct str *x) +{ + struct qentry *item; + + item = grep_malloc(sizeof(struct qentry)); + item->data.dat = grep_malloc(sizeof(char) * x->len); + item->data.len = x->len; + item->data.line_no = x->line_no; + item->data.off = x->off; + memcpy(item->data.dat, x->dat, x->len); + item->data.file = x->file; + + STAILQ_INSERT_TAIL(&queue, item, list); + + if (++count > Bflag) { + item = dequeue(); + free(item->data.dat); + free(item); + } +} + +static struct qentry * +dequeue(void) +{ + struct qentry *item; + + item = STAILQ_FIRST(&queue); + if (item == NULL) + return (NULL); + + STAILQ_REMOVE_HEAD(&queue, list); + --count; + return (item); +} + +void +printqueue(void) +{ + struct qentry *item; + + while ((item = dequeue()) != NULL) { + printline(&item->data, '-', NULL, 0); + free(item->data.dat); + free(item); + } +} + +void +clearqueue(void) +{ + struct qentry *item; + + while ((item = dequeue()) != NULL) { + free(item->data.dat); + free(item); + } +} diff --git a/package/toolbox/src/grep/util.c b/package/toolbox/src/grep/util.c new file mode 100644 index 000000000..4166d5827 --- /dev/null +++ b/package/toolbox/src/grep/util.c @@ -0,0 +1,499 @@ +/* $NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $ */ +/* $FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $ */ +/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */ + +/*- + * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav + * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $"); + +#include <sys/stat.h> +#include <sys/types.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fnmatch.h> +#include <fts.h> +#include <libgen.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wchar.h> +#include <wctype.h> + +#include "grep.h" + +static bool first, first_global = true; +static unsigned long long since_printed; + +static int procline(struct str *l, int); + +bool +file_matching(const char *fname) +{ + char *fname_base, *fname_copy; + unsigned int i; + bool ret; + + ret = finclude ? false : true; + fname_copy = grep_strdup(fname); + fname_base = basename(fname_copy); + + for (i = 0; i < fpatterns; ++i) { + if (fnmatch(fpattern[i].pat, fname, 0) == 0 || + fnmatch(fpattern[i].pat, fname_base, 0) == 0) { + if (fpattern[i].mode == EXCL_PAT) + return (false); + else + ret = true; + } + } + free(fname_copy); + return (ret); +} + +static inline bool +dir_matching(const char *dname) +{ + unsigned int i; + bool ret; + + ret = dinclude ? false : true; + + for (i = 0; i < dpatterns; ++i) { + if (dname != NULL && + fnmatch(dname, dpattern[i].pat, 0) == 0) { + if (dpattern[i].mode == EXCL_PAT) + return (false); + else + ret = true; + } + } + return (ret); +} + +/* + * Processes a directory when a recursive search is performed with + * the -R option. Each appropriate file is passed to procfile(). + */ +int +grep_tree(char **argv) +{ + FTS *fts; + FTSENT *p; + char *d, *dir = NULL; + int c, fts_flags; + bool ok; + + c = fts_flags = 0; + + switch(linkbehave) { + case LINK_EXPLICIT: + fts_flags = FTS_COMFOLLOW; + break; + case LINK_SKIP: + fts_flags = FTS_PHYSICAL; + break; + default: + fts_flags = FTS_LOGICAL; + + } + + fts_flags |= FTS_NOSTAT | FTS_NOCHDIR; + + if (!(fts = fts_open(argv, fts_flags, NULL))) + err(2, "fts_open"); + while ((p = fts_read(fts)) != NULL) { + switch (p->fts_info) { + case FTS_DNR: + /* FALLTHROUGH */ + case FTS_ERR: + errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno)); + break; + case FTS_D: + /* FALLTHROUGH */ + case FTS_DP: + break; + case FTS_DC: + /* Print a warning for recursive directory loop */ + warnx("warning: %s: recursive directory loop", + p->fts_path); + break; + default: + /* Check for file exclusion/inclusion */ + ok = true; + if (dexclude || dinclude) { + if ((d = strrchr(p->fts_path, '/')) != NULL) { + dir = grep_malloc(sizeof(char) * + (d - p->fts_path + 1)); + memcpy(dir, p->fts_path, + d - p->fts_path); + dir[d - p->fts_path] = '\0'; + } + ok = dir_matching(dir); + free(dir); + dir = NULL; + } + if (fexclude || finclude) + ok &= file_matching(p->fts_path); + + if (ok) + c += procfile(p->fts_path); + break; + } + } + + fts_close(fts); + return (c); +} + +/* + * Opens a file and processes it. Each file is processed line-by-line + * passing the lines to procline(). + */ +int +procfile(const char *fn) +{ + struct file *f; + struct stat sb; + struct str ln; + mode_t s; + int c, t; + + if (mflag && (mcount <= 0)) + return (0); + + if (strcmp(fn, "-") == 0) { + fn = label != NULL ? label : getstr(1); + f = grep_open(NULL); + } else { + if (!stat(fn, &sb)) { + /* Check if we need to process the file */ + s = sb.st_mode & S_IFMT; + if (s == S_IFDIR && dirbehave == DIR_SKIP) + return (0); + if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK + || s == S_IFSOCK) && devbehave == DEV_SKIP) + return (0); + } + f = grep_open(fn); + } + if (f == NULL) { + if (!sflag) + warn("%s", fn); + if (errno == ENOENT) + notfound = true; + return (0); + } + + ln.file = grep_malloc(strlen(fn) + 1); + strcpy(ln.file, fn); + ln.line_no = 0; + ln.len = 0; + tail = 0; + ln.off = -1; + + for (first = true, c = 0; c == 0 || !(lflag || qflag); ) { + ln.off += ln.len + 1; + if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0) + break; + if (ln.len > 0 && ln.dat[ln.len - 1] == line_sep) + --ln.len; + ln.line_no++; + + /* Return if we need to skip a binary file */ + if (f->binary && binbehave == BINFILE_SKIP) { + grep_close(f); + free(ln.file); + free(f); + return (0); + } + /* Process the file line-by-line */ + t = procline(&ln, f->binary); + c += t; + + /* Count the matches if we have a match limit */ + if (mflag) { + mcount -= t; + if (mcount <= 0) + break; + } + } + if (Bflag > 0) + clearqueue(); + grep_close(f); + + if (cflag) { + if (!hflag) + printf("%s:", ln.file); + printf("%u%c", c, line_sep); + } + if (lflag && !qflag && c != 0) + printf("%s%c", fn, line_sep); + if (Lflag && !qflag && c == 0) + printf("%s%c", fn, line_sep); + if (c && !cflag && !lflag && !Lflag && + binbehave == BINFILE_BIN && f->binary && !qflag) + printf(getstr(8), fn); + + free(ln.file); + free(f); + return (c); +} + +#define iswword(x) (iswalnum((x)) || (x) == L'_') + +/* + * Processes a line comparing it with the specified patterns. Each pattern + * is looped to be compared along with the full string, saving each and every + * match, which is necessary to colorize the output and to count the + * matches. The matching lines are passed to printline() to display the + * appropriate output. + */ +static int +procline(struct str *l, int nottext) +{ + regmatch_t matches[MAX_LINE_MATCHES]; + regmatch_t pmatch; + size_t st = 0; + unsigned int i; + int c = 0, m = 0, r = 0; + + /* Loop to process the whole line */ + while (st <= l->len) { + pmatch.rm_so = st; + pmatch.rm_eo = l->len; + + /* Loop to compare with all the patterns */ + for (i = 0; i < patterns; i++) { +/* + * XXX: grep_search() is a workaround for speed up and should be + * removed in the future. See fastgrep.c. + */ + if (fg_pattern[i].pattern) { + r = grep_search(&fg_pattern[i], + (unsigned char *)l->dat, + l->len, &pmatch); + r = (r == 0) ? 0 : REG_NOMATCH; + st = pmatch.rm_eo; + } else { + r = regexec(&r_pattern[i], l->dat, 1, + &pmatch, eflags); + r = (r == 0) ? 0 : REG_NOMATCH; + st = pmatch.rm_eo; + } + if (r == REG_NOMATCH) + continue; + /* Check for full match */ + if (xflag && + (pmatch.rm_so != 0 || + (size_t)pmatch.rm_eo != l->len)) + continue; + /* Check for whole word match */ + if (fg_pattern[i].word && pmatch.rm_so != 0) { + wchar_t wbegin, wend; + + wbegin = wend = L' '; + if (pmatch.rm_so != 0 && + sscanf(&l->dat[pmatch.rm_so - 1], + "%lc", &wbegin) != 1) + continue; + if ((size_t)pmatch.rm_eo != l->len && + sscanf(&l->dat[pmatch.rm_eo], + "%lc", &wend) != 1) + continue; + if (iswword(wbegin) || iswword(wend)) + continue; + } + c = 1; + if (m < MAX_LINE_MATCHES) + matches[m++] = pmatch; + /* matches - skip further patterns */ + if ((color != NULL && !oflag) || qflag || lflag) + break; + } + + if (vflag) { + c = !c; + break; + } + /* One pass if we are not recording matches */ + if ((color != NULL && !oflag) || qflag || lflag) + break; + + if (st == (size_t)pmatch.rm_so) + break; /* No matches */ + } + + if (c && binbehave == BINFILE_BIN && nottext) + return (c); /* Binary file */ + + /* Dealing with the context */ + if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) { + if (c) { + if ((Aflag || Bflag) && !first_global && + (first || since_printed > Bflag)) + printf("--\n"); + tail = Aflag; + if (Bflag > 0) + printqueue(); + printline(l, ':', matches, m); + } else { + printline(l, '-', matches, m); + tail--; + } + first = false; + first_global = false; + since_printed = 0; + } else { + if (Bflag) + enqueue(l); + since_printed++; + } + return (c); +} + +/* + * Safe malloc() for internal use. + */ +void * +grep_malloc(size_t size) +{ + void *ptr; + + if ((ptr = malloc(size)) == NULL) + err(2, "malloc"); + return (ptr); +} + +/* + * Safe calloc() for internal use. + */ +void * +grep_calloc(size_t nmemb, size_t size) +{ + void *ptr; + + if ((ptr = calloc(nmemb, size)) == NULL) + err(2, "calloc"); + return (ptr); +} + +/* + * Safe realloc() for internal use. + */ +void * +grep_realloc(void *ptr, size_t size) +{ + + if ((ptr = realloc(ptr, size)) == NULL) + err(2, "realloc"); + return (ptr); +} + +/* + * Safe strdup() for internal use. + */ +char * +grep_strdup(const char *str) +{ + char *ret; + + if ((ret = strdup(str)) == NULL) + err(2, "strdup"); + return (ret); +} + +/* + * Prints a matching line according to the command line options. + */ +void +printline(struct str *line, int sep, regmatch_t *matches, int m) +{ + size_t a = 0; + int i, n = 0; + + if (!hflag) { + if (nullflag == 0) + fputs(line->file, stdout); + else { + printf("%s", line->file); + putchar(0); + } + ++n; + } + if (nflag) { + if (n > 0) + putchar(sep); + printf("%d", line->line_no); + ++n; + } + if (bflag) { + if (n > 0) + putchar(sep); + printf("%lld", (long long)line->off); + ++n; + } + if (n) + putchar(sep); + /* --color and -o */ + if ((oflag || color) && m > 0) { + for (i = 0; i < m; i++) { + if (!oflag) + fwrite(line->dat + a, matches[i].rm_so - a, 1, + stdout); + if (color) + fprintf(stdout, "\33[%sm\33[K", color); + + fwrite(line->dat + matches[i].rm_so, + matches[i].rm_eo - matches[i].rm_so, 1, + stdout); + + if (color) + fprintf(stdout, "\33[m\33[K"); + a = matches[i].rm_eo; + if (oflag) + putchar('\n'); + } + if (!oflag) { + if (line->len - a > 0) + fwrite(line->dat + a, line->len - a, 1, stdout); + putchar(line_sep); + } + } else { + fwrite(line->dat, line->len, 1, stdout); + putchar(line_sep); + } +} diff --git a/package/toolbox/src/hd/Makefile b/package/toolbox/src/hd/Makefile new file mode 100644 index 000000000..aa75efcb8 --- /dev/null +++ b/package/toolbox/src/hd/Makefile @@ -0,0 +1,3 @@ +PROG= hd + +include ../tool.mk diff --git a/package/toolbox/src/id/Makefile b/package/toolbox/src/id/Makefile new file mode 100644 index 000000000..2a27f05fe --- /dev/null +++ b/package/toolbox/src/id/Makefile @@ -0,0 +1,3 @@ +PROG= id + +include ../tool.mk diff --git a/package/toolbox/src/ifconfig/Makefile b/package/toolbox/src/ifconfig/Makefile new file mode 100644 index 000000000..ac39cdf82 --- /dev/null +++ b/package/toolbox/src/ifconfig/Makefile @@ -0,0 +1,3 @@ +PROG= ifconfig + +include ../tool.mk diff --git a/package/toolbox/src/iftop/Makefile b/package/toolbox/src/iftop/Makefile new file mode 100644 index 000000000..03a50994a --- /dev/null +++ b/package/toolbox/src/iftop/Makefile @@ -0,0 +1,3 @@ +PROG= iftop + +include ../tool.mk diff --git a/package/toolbox/src/insmod/Makefile b/package/toolbox/src/insmod/Makefile new file mode 100644 index 000000000..f9420936e --- /dev/null +++ b/package/toolbox/src/insmod/Makefile @@ -0,0 +1,3 @@ +PROG= insmod + +include ../tool.mk diff --git a/package/toolbox/src/ioctl/Makefile b/package/toolbox/src/ioctl/Makefile new file mode 100644 index 000000000..ac5592a45 --- /dev/null +++ b/package/toolbox/src/ioctl/Makefile @@ -0,0 +1,3 @@ +PROG= ioctl + +include ../tool.mk diff --git a/package/toolbox/src/kill/Makefile b/package/toolbox/src/kill/Makefile new file mode 100644 index 000000000..3d433ba78 --- /dev/null +++ b/package/toolbox/src/kill/Makefile @@ -0,0 +1,3 @@ +PROG= kill + +include ../tool.mk diff --git a/package/toolbox/src/lib/Makefile b/package/toolbox/src/lib/Makefile new file mode 100644 index 000000000..4954e48c4 --- /dev/null +++ b/package/toolbox/src/lib/Makefile @@ -0,0 +1,24 @@ +LIB= oadk_toolbox +SRCS+= fgetln.c +SRCS+= md5.c md5hlp.c +CLEANFILES+= lib${LIB}.a + +include ../common.mk + +OBJS+= strlcpy.o strlcat.o + +all: lib${LIB}.a + +lib${LIB}.a: ${OBJS} + ar rc $@ ${OBJS} + -ranlib $@ + +CFLAGS_strlcpy.o=-DOUTSIDE_OF_LIBKERN -DL_strlcpy +strlcpy.o: strlfun.c + ${COMPILE.c} -o $@ $< +CFLAGS_strlcat.o=-DOUTSIDE_OF_LIBKERN -DL_strlcat +strlcat.o: strlfun.c + ${COMPILE.c} -o $@ $< + +install: + # nothing to do here diff --git a/package/toolbox/src/lib/fgetln.c b/package/toolbox/src/lib/fgetln.c new file mode 100644 index 000000000..647cf9faa --- /dev/null +++ b/package/toolbox/src/lib/fgetln.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2007, 2009 + * Thorsten Glaser <tg@mirbsd.org> + * + * Provided that these terms and disclaimer and all copyright notices + * are retained or reproduced in an accompanying document, permission + * is granted to deal in this work without restriction, including un- + * limited rights to use, publicly perform, distribute, sell, modify, + * merge, give away, or sublicence. + * + * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to + * the utmost extent permitted by applicable law, neither express nor + * implied; without malicious intent or gross negligence. In no event + * may a licensor, author or contributor be held liable for indirect, + * direct, other damage, loss, or other issues arising in any way out + * of dealing in the work, even if advised of the possibility of such + * damage or existence of a defect, except proven that it results out + * of said person's immediate fault when using the work as intended. + *- + * fgetln() wrapper for operating systems with getline() – glibc + */ + +#undef _GNU_SOURCE +#define _GNU_SOURCE /* for getline() */ +#include <sys/types.h> +#include <stdio.h> +#include <string.h> + +__RCSID("$MirOS: contrib/code/mirmake/dist/contrib/fgetln.c,v 1.7 2014/12/20 22:23:29 tg Exp $"); + +char *fgetln(FILE *, size_t *); + +char * +fgetln(FILE *stream, size_t *len) +{ + static char *lb = NULL; + static size_t lbsz = 0; + + if ((*len = getline(&lb, &lbsz, stream)) != (size_t)-1) + /* getdelim ensures *len is not 0 here */ + return (lb); + + /* not required by manpage, but reference implementation does this */ + *len = 0; + + /* not required to zero lb or lbsz: getdelim manages it */ + return (NULL); +} diff --git a/package/toolbox/src/lib/md5.c b/package/toolbox/src/lib/md5.c new file mode 100644 index 000000000..ea933408d --- /dev/null +++ b/package/toolbox/src/lib/md5.c @@ -0,0 +1,242 @@ +/* $OpenBSD: md5.c,v 1.8 2005/08/08 08:05:35 espie Exp $ */ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include <sys/types.h> +#include <stdint.h> +#include <string.h> +#include <md5.h> + +extern const uint8_t RFC1321_padding[64]; + +__RCSID("$MirOS: src/lib/libc/hash/md5.c,v 1.3 2009/11/09 21:36:39 tg Exp $"); + +#define PUT_64BIT_LE(cp, value) do { \ + (cp)[7] = (value) >> 56; \ + (cp)[6] = (value) >> 48; \ + (cp)[5] = (value) >> 40; \ + (cp)[4] = (value) >> 32; \ + (cp)[3] = (value) >> 24; \ + (cp)[2] = (value) >> 16; \ + (cp)[1] = (value) >> 8; \ + (cp)[0] = (value); } while (0) + +#define PUT_32BIT_LE(cp, value) do { \ + (cp)[3] = (value) >> 24; \ + (cp)[2] = (value) >> 16; \ + (cp)[1] = (value) >> 8; \ + (cp)[0] = (value); } while (0) + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(MD5_CTX *ctx) +{ + ctx->count = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len) +{ + size_t have, need; + + /* Check how many bytes we already have and how many more we need. */ + have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); + need = MD5_BLOCK_LENGTH - have; + + /* Update bitcount */ + ctx->count += (u_int64_t)len << 3; + + if (len >= need) { + if (have != 0) { + memcpy(ctx->buffer + have, input, need); + MD5Transform(ctx->state, ctx->buffer); + input += need; + len -= need; + have = 0; + } + + /* Process data in MD5_BLOCK_LENGTH-byte chunks. */ + while (len >= MD5_BLOCK_LENGTH) { + MD5Transform(ctx->state, input); + input += MD5_BLOCK_LENGTH; + len -= MD5_BLOCK_LENGTH; + } + } + + /* Handle any remaining bytes of data. */ + if (len != 0) + memcpy(ctx->buffer + have, input, len); +} + +/* + * Pad pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Pad(MD5_CTX *ctx) +{ + u_int8_t count[8]; + + /* Convert count to 8 bytes in little endian order. */ + PUT_64BIT_LE(count, ctx->count); + + /* Pad out to 56 mod 64. */ + MD5Update(ctx, RFC1321_padding, 64 - (((ctx->count >> 3) + 8) & 63)); + MD5Update(ctx, count, 8); +} + +/* + * Final wrapup--call MD5Pad, fill in digest and zero out ctx. + */ +void +MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) +{ + int i; + + MD5Pad(ctx); + if (digest != NULL) { + for (i = 0; i < 4; i++) + PUT_32BIT_LE(digest + i * 4, ctx->state[i]); + memset(ctx, 0, sizeof(*ctx)); + } +} + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH]) +{ + u_int32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4]; + +#if BYTE_ORDER == LITTLE_ENDIAN + memcpy(in, block, sizeof(in)); +#else + for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) { + in[a] = (u_int32_t)( + (u_int32_t)(block[a * 4 + 0]) | + (u_int32_t)(block[a * 4 + 1]) << 8 | + (u_int32_t)(block[a * 4 + 2]) << 16 | + (u_int32_t)(block[a * 4 + 3]) << 24); + } +#endif + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + + MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; +} diff --git a/package/toolbox/src/lib/md5.h b/package/toolbox/src/lib/md5.h new file mode 100644 index 000000000..ac47848be --- /dev/null +++ b/package/toolbox/src/lib/md5.h @@ -0,0 +1,48 @@ +/* $MirOS: src/kern/include/md5.h,v 1.4 2014/12/20 22:28:45 tg Exp $ */ + +#ifndef SYSKERN_MD5_H +#define SYSKERN_MD5_H + +#ifdef __MirBSD__ +#include <machine/types.h> +#endif + +#define MD5_BLOCK_LENGTH 64 +#define MD5_DIGEST_LENGTH 16 +#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1) + +typedef struct MD5Context { + uint32_t state[4]; + uint64_t count; + uint8_t buffer[MD5_BLOCK_LENGTH]; +} MD5_CTX; + +__BEGIN_DECLS + +/* low-level functions */ +void MD5Init(MD5_CTX *); +void MD5Update(MD5_CTX *, const uint8_t *, size_t) + __attribute__((__bounded__(__string__, 2, 3))); +void MD5Pad(MD5_CTX *); +void MD5Final(uint8_t *, MD5_CTX *) + __attribute__((__bounded__(__minbytes__, 1, MD5_DIGEST_LENGTH))); +void MD5Transform(uint32_t *, const uint8_t *) + __attribute__((__bounded__(__minbytes__, 1, 16))) + __attribute__((__bounded__(__minbytes__, 2, MD5_BLOCK_LENGTH))); + +#if !defined(_KERNEL) && !defined(_STANDALONE) +/* high-level functions from helper.c */ +char *MD5End(MD5_CTX *, char *) + __attribute__((__bounded__(__minbytes__, 2, MD5_DIGEST_STRING_LENGTH))); +char *MD5File(const char *, char *) + __attribute__((__bounded__(__minbytes__, 2, MD5_DIGEST_STRING_LENGTH))); +char *MD5FileChunk(const char *, char *, off_t, off_t) + __attribute__((__bounded__(__minbytes__, 2, MD5_DIGEST_STRING_LENGTH))); +char *MD5Data(const uint8_t *, size_t, char *) + __attribute__((__bounded__(__string__, 1, 2))) + __attribute__((__bounded__(__minbytes__, 3, MD5_DIGEST_STRING_LENGTH))); +#endif + +__END_DECLS + +#endif diff --git a/package/toolbox/src/lib/md5hlp.c b/package/toolbox/src/lib/md5hlp.c new file mode 100644 index 000000000..9c7958a73 --- /dev/null +++ b/package/toolbox/src/lib/md5hlp.c @@ -0,0 +1,13 @@ +/* collection of data, not copyrightable */ + +#include <sys/types.h> +#include <stdint.h> + +__RCSID("$MirOS: src/kern/c/miscdata.c,v 1.1 2011/11/20 18:28:09 tg Exp $"); + +const uint8_t RFC1321_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; diff --git a/package/toolbox/src/lib/string.h b/package/toolbox/src/lib/string.h new file mode 100644 index 000000000..571cba664 --- /dev/null +++ b/package/toolbox/src/lib/string.h @@ -0,0 +1,9 @@ +#ifndef LIBOADK_STRING_H +#define LIBOADK_STRING_H + +#include_next <string.h> + +size_t strlcat(char *, const char *, size_t); +size_t strlcpy(char *, const char *, size_t); + +#endif diff --git a/package/toolbox/src/lib/strlfun.c b/package/toolbox/src/lib/strlfun.c new file mode 100644 index 000000000..123eb3d12 --- /dev/null +++ b/package/toolbox/src/lib/strlfun.c @@ -0,0 +1,185 @@ +#if 0 /* comment in gmake; next line ignored by gcc */ +ifeq (0,gmake ignores from here) +#endif +/*- + * Copyright (c) 2006, 2008, 2011 + * mirabilos <m@mirbsd.org> + * + * Provided that these terms and disclaimer and all copyright notices + * are retained or reproduced in an accompanying document, permission + * is granted to deal in this work without restriction, including un- + * limited rights to use, publicly perform, distribute, sell, modify, + * merge, give away, or sublicence. + * + * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to + * the utmost extent permitted by applicable law, neither express nor + * implied; without malicious intent or gross negligence. In no event + * may a licensor, author or contributor be held liable for indirect, + * direct, other damage, loss, or other issues arising in any way out + * of dealing in the work, even if advised of the possibility of such + * damage or existence of a defect, except proven that it results out + * of said person's immediate fault when using the work as intended. + *- + * The original implementations of strlcpy(3) and strlcat(3) are from + * Todd C. Miller; the licence is reproduced below. However, this ap- + * plies only to the strlcpy(3) portion of the code, as Thorsten Gla- + * ser write the following strlcat(3) implementation according to the + * spec. Both functions below have been optimised according to sugge- + * stions from Bodo Eggert. mirabilos merged the code with strxfrm(3) + * (Unicode-only systems) and the wide character variants wcslcat(3), + * wcslcpy(3), and wcsxfrm(3). + */ + +#include <sys/types.h> +#ifndef OUTSIDE_OF_LIBKERN +#include <libckern.h> +#endif + +#ifndef __RCSID +#define __RCSID(x) static const char __rcsid[] = x +#endif + +__RCSID("$MirOS: src/kern/c/strlfun.c,v 1.5 2016/03/06 13:47:13 tg Exp $"); + +#ifdef WIDEC +#ifdef OUTSIDE_OF_LIBKERN +#ifdef __WCHAR_TYPE__ +typedef __WCHAR_TYPE__ wchar_t; +#else +#include <wchar.h> +#endif +#endif +/* wide character string functions */ +#define NUL L'\0' +#define char_t wchar_t +#define fn_len wcslen +#define fn_cat wcslcat +#define fn_cpy wcslcpy +#else +/* (multibyte) string functions */ +#define NUL '\0' +#define char_t char +#define fn_len strlen +#define fn_cat strlcat +#define fn_cpy strlcpy +#endif + +#ifdef L_strxfrm +#define strlcpy strxfrm +#define wcslcpy wcsxfrm +#define L_strlcpy +#endif + +#ifdef OUTSIDE_OF_LIBKERN +extern size_t fn_len(const char_t *); +#endif + +#ifndef __predict_true +#define __predict_true(exp) (exp) +#define __predict_false(exp) (exp) +#endif + +#ifdef L_strlcat +/* + * Appends src to string dst of size dlen (unlike strncat, dlen is the + * full size of dst, not space left). At most dlen-1 characters + * will be copied. Always NUL terminates (unless dlen <= strlen(dst)). + * Returns strlen(src) + MIN(dlen, strlen(initial dst)), without the + * trailing NUL byte counted. If retval >= dlen, truncation occurred. + */ +size_t +fn_cat(char_t *dst, const char_t *src, size_t dlen) +{ + size_t n = 0, slen; + + slen = fn_len(src); + while (__predict_true(n + 1 < dlen && dst[n] != NUL)) + ++n; + if (__predict_false(dlen == 0 || dst[n] != NUL)) + return (dlen + slen); + while (__predict_true((slen > 0) && (n < (dlen - 1)))) { + dst[n++] = *src++; + --slen; + } + dst[n] = NUL; + return (n + slen); +} +#endif + +#ifdef L_strlcpy +/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ + +/*- + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +fn_cpy(char_t *dst, const char_t *src, size_t siz) +{ + const char_t *s = src; + + if (__predict_false(siz == 0)) + goto traverse_src; + + /* copy as many chars as will fit */ + while (--siz && (*dst++ = *s++)) + ; + + /* not enough room in dst */ + if (__predict_false(siz == 0)) { + /* safe to NUL-terminate dst since we copied <= siz-1 chars */ + *dst = NUL; + traverse_src: + /* traverse rest of src */ + while (*s++) + ; + } + + /* count does not include NUL */ + return (s - src - 1); +} +#endif + +#if 0 /* gcc ignored from here; gmake stops ignoring */ +endif + +USE_WIDEC?= 1 + +LIB= libstrlfun.a +OBJS= strlcpy.o strlcat.o +ifeq (1,$(strip $(USE_WIDEC))) +OBJS+= wcslcpy.o wcslcat.o +endif +DEFS= -DOUTSIDE_OF_LIBKERN +DEFS_strlcpy.o= -DL_strlcpy +DEFS_strlcat.o= -DL_strlcat +DEFS_wcslcpy.o= -DL_strlcpy -DWIDEC +DEFS_wcslcat.o= -DL_strlcat -DWIDEC + +all: $(LIB) + +$(LIB): $(OBJS) + ar rc $(LIB) $(OBJS) + -ranlib $(LIB) + +$(OBJS): strlfun.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(DEFS) $(DEFS_$@) -c -o $@ strlfun.c + +#endif /* EOF for gmake and gcc */ diff --git a/package/toolbox/src/ln/Makefile b/package/toolbox/src/ln/Makefile new file mode 100644 index 000000000..42bff383e --- /dev/null +++ b/package/toolbox/src/ln/Makefile @@ -0,0 +1,3 @@ +PROG= ln + +include ../tool.mk diff --git a/package/toolbox/src/ls/Makefile b/package/toolbox/src/ls/Makefile new file mode 100644 index 000000000..52cb1f4fe --- /dev/null +++ b/package/toolbox/src/ls/Makefile @@ -0,0 +1,4 @@ +PROG= ls +SRCS= ls.c dynarray.c + +include ../tool.mk diff --git a/package/toolbox/src/lsof/Makefile b/package/toolbox/src/lsof/Makefile new file mode 100644 index 000000000..778de1506 --- /dev/null +++ b/package/toolbox/src/lsof/Makefile @@ -0,0 +1,3 @@ +PROG= lsof + +include ../tool.mk diff --git a/package/toolbox/src/md5/Makefile b/package/toolbox/src/md5/Makefile new file mode 100644 index 000000000..b37336ccc --- /dev/null +++ b/package/toolbox/src/md5/Makefile @@ -0,0 +1,3 @@ +PROG= md5 + +include ../tool.mk diff --git a/package/toolbox/src/mkdir/Makefile b/package/toolbox/src/mkdir/Makefile new file mode 100644 index 000000000..a2796420f --- /dev/null +++ b/package/toolbox/src/mkdir/Makefile @@ -0,0 +1,3 @@ +PROG= mkdir + +include ../tool.mk diff --git a/package/toolbox/src/mknod/Makefile b/package/toolbox/src/mknod/Makefile new file mode 100644 index 000000000..35956fad6 --- /dev/null +++ b/package/toolbox/src/mknod/Makefile @@ -0,0 +1,6 @@ +PROG= mknod +SRCS= mknod.c setmode.c + +include ../tool.mk + +CPPFLAGS+= -D'__SCCSID(x)=' diff --git a/package/toolbox/src/mknod/mknod.c b/package/toolbox/src/mknod/mknod.c new file mode 100644 index 000000000..f09dfe8c4 --- /dev/null +++ b/package/toolbox/src/mknod/mknod.c @@ -0,0 +1,190 @@ +/* $OpenBSD: mknod.c,v 1.13 2003/06/02 20:06:15 millert Exp $ */ +/* $NetBSD: mknod.c,v 1.8 1995/08/11 00:08:18 jtc Exp $ */ + +/* + * Copyright (c) 1989, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kevin Fall. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"); +__SCCSID("@(#)mknod.c 8.1 (Berkeley) 6/5/93"); +__RCSID("$MirOS: src/sbin/mknod/mknod.c,v 1.3 2016/01/02 21:33:04 tg Exp $"); + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <locale.h> +#include <err.h> + +extern char *__progname; + +int domknod(int, char **, mode_t); +int domkfifo(int, char **, mode_t); +void usage(int); + +extern mode_t getmode(const void *, mode_t); +extern void *setmode(const char *); + +int +main(int argc, char *argv[]) +{ + int ch, ismkfifo = 0; + void *set = NULL; + mode_t mode = 0; + + if (strcmp(__progname, "mkfifo") == 0) + ismkfifo = 1; + + while ((ch = getopt(argc, argv, "m:")) != -1) + switch(ch) { + case 'm': + if (!(set = setmode(optarg))) { + errx(1, "invalid file mode."); + /* NOTREACHED */ + } + + /* + * In symbolic mode strings, the + and - operators are + * interpreted relative to an assumed initial mode of + * a=rw. + */ + mode = getmode(set, DEFFILEMODE); + free(set); + break; + case '?': + default: + usage(ismkfifo); + } + argc -= optind; + argv += optind; + + if (argv[0] == NULL) + usage(ismkfifo); + if (!ismkfifo) { + if (argc == 2 && argv[1][0] == 'p') { + ismkfifo = 2; + argc--; + argv[1] = NULL; + } else if (argc != 4) { + usage(ismkfifo); + /* NOTREACHED */ + } + } + + /* + * If the user specified a mode via `-m', don't allow the umask + * to modified it. If no `-m' flag was specified, the default + * mode is the value of the bitwise inclusive or of S_IRUSR, + * S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH as modified by + * the umask. + */ + if (set) + (void)umask(0); + else + mode = DEFFILEMODE; + + if (ismkfifo) + exit(domkfifo(argc, argv, mode)); + else + exit(domknod(argc, argv, mode)); +} + +int +domknod(int argc, char **argv, mode_t mode) +{ + dev_t dev; + char *endp; + u_int major, minor; + + if (argv[1][0] == 'c') + mode |= S_IFCHR; + else if (argv[1][0] == 'b') + mode |= S_IFBLK; + else { + errx(1, "node must be type 'b' or 'c'."); + /* NOTREACHED */ + } + + major = (long)strtoul(argv[2], &endp, 0); + if (endp == argv[2] || *endp != '\0') { + errx(1, "non-numeric major number."); + /* NOTREACHED */ + } + minor = (long)strtoul(argv[3], &endp, 0); + if (endp == argv[3] || *endp != '\0') { + errx(1, "non-numeric minor number."); + /* NOTREACHED */ + } + dev = makedev(major, minor); + if (major(dev) != major || minor(dev) != minor) { + errx(1, "major or minor number too large"); + /* NOTREACHED */ + } + if (mknod(argv[0], mode, dev) < 0) { + err(1, "%s", argv[0]); + /* NOTREACHED */ + } + return(0); +} + +int +domkfifo(int argc, char **argv, mode_t mode) +{ + int rv; + + for (rv = 0; *argv; ++argv) { + if (mkfifo(*argv, mode) < 0) { + warn("%s", *argv); + rv = 1; + } + } + return(rv); +} + +void +usage(int ismkfifo) +{ + + if (ismkfifo == 1) + (void)fprintf(stderr, "usage: %s [-m mode] fifoname ...\n", + __progname); + else { + (void)fprintf(stderr, "usage: %s [-m mode] name [b | c] major minor\n", + __progname); + (void)fprintf(stderr, "usage: %s [-m mode] name p\n", + __progname); + } + exit(1); +} diff --git a/package/toolbox/src/mknod/setmode.c b/package/toolbox/src/mknod/setmode.c new file mode 100644 index 000000000..afef02d81 --- /dev/null +++ b/package/toolbox/src/mknod/setmode.c @@ -0,0 +1,462 @@ +/* $OpenBSD: setmode.c,v 1.17 2005/08/08 08:05:34 espie Exp $ */ +/* $NetBSD: setmode.c,v 1.15 1997/02/07 22:21:06 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Dave Borman at Cray Research, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <errno.h> +#include <signal.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef SETMODE_DEBUG +#include <stdio.h> +#endif + +__SCCSID("@(#)setmode.c 8.2 (Berkeley) 3/25/94"); +__RCSID("$MirOS: src/lib/libc/gen/setmode.c,v 1.15 2010/10/08 17:57:00 tg Exp $"); + +#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ +#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ + +#if !defined(S_ISTXT) && defined(S_ISVTX) +#define S_ISTXT S_ISVTX +#endif + +typedef struct bitcmd { + mode_t bits; + char cmd; + char cmd2; +} BITCMD; + +#define CMD2_CLR 0x01 +#define CMD2_SET 0x02 +#define CMD2_GBITS 0x04 +#define CMD2_OBITS 0x08 +#define CMD2_UBITS 0x10 + +static BITCMD *addcmd(BITCMD *, int, int, int, u_int); +static void compress_mode(BITCMD *); +#ifdef SETMODE_DEBUG +static void dumpmode(BITCMD *); +#endif + +/* + * Given the old mode and an array of bitcmd structures, apply the operations + * described in the bitcmd structures to the old mode, and return the new mode. + * Note that there is no '=' command; a strict assignment is just a '-' (clear + * bits) followed by a '+' (set bits). + */ +mode_t +getmode(const void *bbox, mode_t omode) +{ + const BITCMD *set; + mode_t clrval, newmode, value; + + set = (const BITCMD *)bbox; + newmode = omode; + for (value = 0;; set++) + switch(set->cmd) { + /* + * When copying the user, group or other bits around, we "know" + * where the bits are in the mode so that we can do shifts to + * copy them around. If we don't use shifts, it gets real + * grundgy with lots of single bit checks and bit sets. + */ + case 'u': + value = (newmode & S_IRWXU) >> 6; + goto common; + + case 'g': + value = (newmode & S_IRWXG) >> 3; + goto common; + + case 'o': + value = newmode & S_IRWXO; + common: + if (set->cmd2 & CMD2_CLR) { + clrval = + (set->cmd2 & CMD2_SET) ? S_IRWXO : value; + if (set->cmd2 & CMD2_UBITS) + newmode &= ~((clrval<<6) & set->bits); + if (set->cmd2 & CMD2_GBITS) + newmode &= ~((clrval<<3) & set->bits); + if (set->cmd2 & CMD2_OBITS) + newmode &= ~(clrval & set->bits); + } + if (set->cmd2 & CMD2_SET) { + if (set->cmd2 & CMD2_UBITS) + newmode |= (value<<6) & set->bits; + if (set->cmd2 & CMD2_GBITS) + newmode |= (value<<3) & set->bits; + if (set->cmd2 & CMD2_OBITS) + newmode |= value & set->bits; + } + break; + + case '+': + newmode |= set->bits; + break; + + case '-': + newmode &= ~set->bits; + break; + + case 'X': + if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) + newmode |= set->bits; + break; + + case '\0': + default: +#ifdef SETMODE_DEBUG + (void)printf("getmode:%04o -> %04o\n", omode, newmode); +#endif + return (newmode); + } +} + +#define notoktomul(a, b) ((a) && (b) && (SIZE_MAX / (a) < (b))) + +#define ADDCMD(a, b, c, d) \ + if (set >= endset) { \ + BITCMD *newset; \ + setlen += SET_LEN_INCR; \ + if (notoktomul(setlen, sizeof(BITCMD)) || \ + (newset = realloc(saveset, setlen * \ + sizeof(BITCMD))) == NULL) { \ + free(saveset); \ + return (NULL); \ + } \ + set = newset + (set - saveset); \ + saveset = newset; \ + endset = newset + (setlen - 2); \ + } \ + set = addcmd(set, (a), (b), (c), (d)) + +#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) + +void * +setmode(const char *p) +{ + int perm, who; + char op, *ep; + BITCMD *set, *saveset, *endset; + sigset_t signset, sigoset; + mode_t mask; + int equalopdone = 0, permXbits, setlen; + u_long perml; + + if (!*p) + return (NULL); + + /* + * Get a copy of the mask for the permissions that are mask relative. + * Flip the bits, we want what's not set. Since it's possible that + * the caller is opening files inside a signal handler, protect them + * as best we can. + */ + sigfillset(&signset); + (void)sigprocmask(SIG_BLOCK, &signset, &sigoset); + (void)umask(mask = umask(0)); + mask = ~mask; + (void)sigprocmask(SIG_SETMASK, &sigoset, NULL); + + setlen = SET_LEN + 2; + + if (notoktomul(setlen, sizeof(BITCMD)) || + (set = malloc(setlen * sizeof(BITCMD))) == NULL) + return (NULL); + saveset = set; + endset = set + (setlen - 2); + + /* + * If an absolute number, get it and return; disallow non-octal digits + * or illegal bits. + */ + if (isdigit((unsigned char)*p)) { + perml = strtoul(p, &ep, 8); + /* The test on perml will also catch overflow. */ + if (*ep != '\0' || (perml & ~(STANDARD_BITS|S_ISTXT))) { + free(saveset); + errno = ERANGE; + return (NULL); + } + perm = (mode_t)perml; + ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); + set->cmd = 0; + return (saveset); + } + + /* + * Build list of structures to set/clear/copy bits as described by + * each clause of the symbolic mode. + */ + for (;;) { + /* First, find out which bits might be modified. */ + for (who = 0;; ++p) { + switch (*p) { + case 'a': + who |= STANDARD_BITS; + break; + case 'u': + who |= S_ISUID|S_IRWXU; + break; + case 'g': + who |= S_ISGID|S_IRWXG; + break; + case 'o': + who |= S_IRWXO; + break; + default: + goto getop; + } + } + + getop: + if ((op = *p++) != '+' && op != '-' && op != '=') { + free(saveset); + return (NULL); + } + if (op == '=') + equalopdone = 0; + + who &= ~S_ISTXT; + for (perm = 0, permXbits = 0;; ++p) { + switch (*p) { + case 'r': + perm |= S_IRUSR|S_IRGRP|S_IROTH; + break; + case 's': + /* + * If specific bits where requested and + * only "other" bits ignore set-id. + */ + if (who == 0 || (who & ~S_IRWXO)) + perm |= S_ISUID|S_ISGID; + break; + case 't': + /* + * If specific bits where requested and + * only "other" bits ignore sticky. + */ + if (who == 0 || (who & ~S_IRWXO)) { + who |= S_ISTXT; + perm |= S_ISTXT; + } + break; + case 'w': + perm |= S_IWUSR|S_IWGRP|S_IWOTH; + break; + case 'X': + permXbits = S_IXUSR|S_IXGRP|S_IXOTH; + break; + case 'x': + perm |= S_IXUSR|S_IXGRP|S_IXOTH; + break; + case 'u': + case 'g': + case 'o': + /* + * When ever we hit 'u', 'g', or 'o', we have + * to flush out any partial mode that we have, + * and then do the copying of the mode bits. + */ + if (perm) { + ADDCMD(op, who, perm, mask); + perm = 0; + } + if (op == '=') + equalopdone = 1; + if (op == '+' && permXbits) { + ADDCMD('X', who, permXbits, mask); + permXbits = 0; + } + ADDCMD(*p, who, op, mask); + break; + + default: + /* + * Add any permissions that we haven't already + * done. + */ + if (perm || (op == '=' && !equalopdone)) { + if (op == '=') + equalopdone = 1; + ADDCMD(op, who, perm, mask); + perm = 0; + } + if (permXbits) { + ADDCMD('X', who, permXbits, mask); + permXbits = 0; + } + goto apply; + } + } + + apply: + if (!*p) + break; + if (*p != ',') + goto getop; + ++p; + } + set->cmd = 0; +#ifdef SETMODE_DEBUG + (void)printf("Before compress_mode()\n"); + dumpmode(saveset); +#endif + compress_mode(saveset); +#ifdef SETMODE_DEBUG + (void)printf("After compress_mode()\n"); + dumpmode(saveset); +#endif + return (saveset); +} + +static BITCMD * +addcmd(BITCMD *set, int op, int who, int oparg, u_int mask) +{ + switch (op) { + case '=': + set->cmd = '-'; + set->bits = who ? who : STANDARD_BITS; + set++; + + op = '+'; + /* FALLTHROUGH */ + case '+': + case '-': + case 'X': + set->cmd = op; + set->bits = (who ? who : (int)mask) & oparg; + break; + + case 'u': + case 'g': + case 'o': + set->cmd = op; + if (who) { + set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) | + ((who & S_IRGRP) ? CMD2_GBITS : 0) | + ((who & S_IROTH) ? CMD2_OBITS : 0); + set->bits = (mode_t)~0; + } else { + set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; + set->bits = mask; + } + + if (oparg == '+') + set->cmd2 |= CMD2_SET; + else if (oparg == '-') + set->cmd2 |= CMD2_CLR; + else if (oparg == '=') + set->cmd2 |= CMD2_SET|CMD2_CLR; + break; + } + return (set + 1); +} + +#ifdef SETMODE_DEBUG +static void +dumpmode(BITCMD *set) +{ + for (; set->cmd; ++set) + (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n", + set->cmd, set->bits, set->cmd2 ? " cmd2:" : "", + set->cmd2 & CMD2_CLR ? " CLR" : "", + set->cmd2 & CMD2_SET ? " SET" : "", + set->cmd2 & CMD2_UBITS ? " UBITS" : "", + set->cmd2 & CMD2_GBITS ? " GBITS" : "", + set->cmd2 & CMD2_OBITS ? " OBITS" : ""); +} +#endif + +/* + * Given an array of bitcmd structures, compress by compacting consecutive + * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', + * 'g' and 'o' commands continue to be separate. They could probably be + * compacted, but it's not worth the effort. + */ +static void +compress_mode(BITCMD *set) +{ + BITCMD *nset; + int setbits, clrbits, Xbits, op; + + for (nset = set;;) { + /* Copy over any 'u', 'g' and 'o' commands. */ + while ((op = nset->cmd) != '+' && op != '-' && op != 'X') { + *set++ = *nset++; + if (!op) + return; + } + + for (setbits = clrbits = Xbits = 0;; nset++) { + if ((op = nset->cmd) == '-') { + clrbits |= nset->bits; + setbits &= ~nset->bits; + Xbits &= ~nset->bits; + } else if (op == '+') { + setbits |= nset->bits; + clrbits &= ~nset->bits; + Xbits &= ~nset->bits; + } else if (op == 'X') + Xbits |= nset->bits & ~setbits; + else + break; + } + if (clrbits) { + set->cmd = '-'; + set->cmd2 = 0; + set->bits = clrbits; + set++; + } + if (setbits) { + set->cmd = '+'; + set->cmd2 = 0; + set->bits = setbits; + set++; + } + if (Xbits) { + set->cmd = 'X'; + set->cmd2 = 0; + set->bits = Xbits; + set++; + } + } +} diff --git a/package/toolbox/src/mount/Makefile b/package/toolbox/src/mount/Makefile new file mode 100644 index 000000000..980138b84 --- /dev/null +++ b/package/toolbox/src/mount/Makefile @@ -0,0 +1,3 @@ +PROG= mount + +include ../tool.mk diff --git a/package/toolbox/src/mv/Makefile b/package/toolbox/src/mv/Makefile new file mode 100644 index 000000000..2ec258d71 --- /dev/null +++ b/package/toolbox/src/mv/Makefile @@ -0,0 +1,3 @@ +PROG= mv + +include ../tool.mk diff --git a/package/toolbox/src/netstat/Makefile b/package/toolbox/src/netstat/Makefile new file mode 100644 index 000000000..d2ec384b0 --- /dev/null +++ b/package/toolbox/src/netstat/Makefile @@ -0,0 +1,3 @@ +PROG= netstat + +include ../tool.mk diff --git a/package/toolbox/src/notify/Makefile b/package/toolbox/src/notify/Makefile new file mode 100644 index 000000000..b0ac6746b --- /dev/null +++ b/package/toolbox/src/notify/Makefile @@ -0,0 +1,3 @@ +PROG= notify + +include ../tool.mk diff --git a/package/toolbox/src/printenv/Makefile b/package/toolbox/src/printenv/Makefile new file mode 100644 index 000000000..1732cc39a --- /dev/null +++ b/package/toolbox/src/printenv/Makefile @@ -0,0 +1,3 @@ +PROG= printenv + +include ../tool.mk diff --git a/package/toolbox/src/ps/Makefile b/package/toolbox/src/ps/Makefile new file mode 100644 index 000000000..394dcc2e7 --- /dev/null +++ b/package/toolbox/src/ps/Makefile @@ -0,0 +1,3 @@ +PROG= ps + +include ../tool.mk diff --git a/package/toolbox/src/readlink/Makefile b/package/toolbox/src/readlink/Makefile new file mode 100644 index 000000000..bcd3e347b --- /dev/null +++ b/package/toolbox/src/readlink/Makefile @@ -0,0 +1,3 @@ +PROG= readlink + +include ../tool.mk diff --git a/package/toolbox/src/renice/Makefile b/package/toolbox/src/renice/Makefile new file mode 100644 index 000000000..8c174f82b --- /dev/null +++ b/package/toolbox/src/renice/Makefile @@ -0,0 +1,3 @@ +PROG= renice + +include ../tool.mk diff --git a/package/toolbox/src/rm/Makefile b/package/toolbox/src/rm/Makefile new file mode 100644 index 000000000..f34eee210 --- /dev/null +++ b/package/toolbox/src/rm/Makefile @@ -0,0 +1,3 @@ +PROG= rm + +include ../tool.mk diff --git a/package/toolbox/src/rmdir/Makefile b/package/toolbox/src/rmdir/Makefile new file mode 100644 index 000000000..40addfb42 --- /dev/null +++ b/package/toolbox/src/rmdir/Makefile @@ -0,0 +1,3 @@ +PROG= rmdir + +include ../tool.mk diff --git a/package/toolbox/src/rmmod/Makefile b/package/toolbox/src/rmmod/Makefile new file mode 100644 index 000000000..63bd4a7d6 --- /dev/null +++ b/package/toolbox/src/rmmod/Makefile @@ -0,0 +1,3 @@ +PROG= rmmod + +include ../tool.mk diff --git a/package/toolbox/src/route/Makefile b/package/toolbox/src/route/Makefile new file mode 100644 index 000000000..06c348a9b --- /dev/null +++ b/package/toolbox/src/route/Makefile @@ -0,0 +1,3 @@ +PROG= route + +include ../tool.mk diff --git a/package/toolbox/src/schedtop/Makefile b/package/toolbox/src/schedtop/Makefile new file mode 100644 index 000000000..37384bf69 --- /dev/null +++ b/package/toolbox/src/schedtop/Makefile @@ -0,0 +1,3 @@ +PROG= schedtop + +include ../tool.mk diff --git a/package/toolbox/src/sed/Makefile b/package/toolbox/src/sed/Makefile new file mode 100644 index 000000000..cc9e96763 --- /dev/null +++ b/package/toolbox/src/sed/Makefile @@ -0,0 +1,6 @@ +PROG= sed +SRCS= compile.c main.c misc.c process.c + +include ../tool.mk + +CPPFLAGS+= -D'__SCCSID(x)=' diff --git a/package/toolbox/src/sed/compile.c b/package/toolbox/src/sed/compile.c new file mode 100644 index 000000000..6d86428ca --- /dev/null +++ b/package/toolbox/src/sed/compile.c @@ -0,0 +1,870 @@ +/* $OpenBSD: compile.c,v 1.42 2017/08/01 18:05:53 martijn Exp $ */ + +/*- + * Copyright (c) 2016 + * mirabilos <m@mirbsd.org> + * Copyright (c) 1992 Diomidis Spinellis. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Diomidis Spinellis of Imperial College, University of London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "defs.h" +#include "extern.h" + +__RCSID("$MirOS: src/usr.bin/sed/compile.c,v 1.3 2017/11/20 01:23:56 tg Exp $"); + +#define LHSZ 128 +#define LHMASK (LHSZ - 1) +static struct labhash { + struct labhash *lh_next; + u_int lh_hash; + struct s_command *lh_cmd; + int lh_ref; +} *labels[LHSZ]; + +static char *compile_addr(char *, struct s_addr *); +static char *compile_ccl(char **, char *); +static char *compile_delimited(char *, char *, int); +static char *compile_flags(char *, struct s_subst *); +static char *compile_re(char *, regex_t **); +static char *compile_subst(char *, struct s_subst *); +static char *compile_text(void); +static char *compile_tr(char *, char **); +static struct s_command + **compile_stream(struct s_command **); +static char *duptoeol(char *, const char *, char **); +static void enterlabel(struct s_command *); +static struct s_command + *findlabel(char *); +static void fixuplabel(struct s_command *, struct s_command *); +static void uselabel(void); + +/* + * Command specification. This is used to drive the command parser. + */ +struct s_format { + char code; /* Command code */ + int naddr; /* Number of address args */ + enum e_args args; /* Argument type */ +}; + +static struct s_format cmd_fmts[] = { + {'{', 2, GROUP}, + {'}', 0, ENDGROUP}, + {'a', 1, TEXT}, + {'b', 2, BRANCH}, + {'c', 2, TEXT}, + {'d', 2, EMPTY}, + {'D', 2, EMPTY}, + {'g', 2, EMPTY}, + {'G', 2, EMPTY}, + {'h', 2, EMPTY}, + {'H', 2, EMPTY}, + {'i', 1, TEXT}, + {'l', 2, EMPTY}, + {'n', 2, EMPTY}, + {'N', 2, EMPTY}, + {'p', 2, EMPTY}, + {'P', 2, EMPTY}, + {'q', 1, EMPTY}, + {'r', 1, RFILE}, + {'s', 2, SUBST}, + {'t', 2, BRANCH}, + {'w', 2, WFILE}, + {'x', 2, EMPTY}, + {'y', 2, TR}, + {'!', 2, NONSEL}, + {':', 0, LABEL}, + {'#', 0, COMMENT}, + {'=', 1, EMPTY}, + {'\0', 0, COMMENT}, +}; + +/* The compiled program. */ +struct s_command *prog; + +/* + * Compile the program into prog. + * Initialise appends. + */ +void +compile(void) +{ + *compile_stream(&prog) = NULL; + fixuplabel(prog, NULL); + uselabel(); + appends = xreallocarray(NULL, appendnum, sizeof(struct s_appends)); + match = xreallocarray(NULL, maxnsub + 1, sizeof(regmatch_t)); +} + +#define EATSPACE() do { \ + if (p) \ + while (isascii((unsigned char)*p) && \ + isspace((unsigned char)*p)) \ + p++; \ + } while (0) + +static struct s_command ** +compile_stream(struct s_command **link) +{ + char *p; + static char *lbuf; /* To avoid excessive malloc calls */ + static size_t bufsize; + struct s_command *cmd, *cmd2, *stack; + struct s_format *fp; + int naddr; /* Number of addresses */ + + stack = 0; + for (;;) { + if ((p = cu_fgets(&lbuf, &bufsize)) == NULL) { + if (stack != 0) + error(COMPILE, "unexpected EOF (pending }'s)"); + return (link); + } + +semicolon: EATSPACE(); + if (*p == '#' || *p == '\0') + continue; + if (*p == ';') { + p++; + goto semicolon; + } + *link = cmd = xmalloc(sizeof(struct s_command)); + link = &cmd->next; + cmd->nonsel = cmd->inrange = 0; + /* First parse the addresses */ + naddr = 0; + +/* Valid characters to start an address */ +#define addrchar(c) (strchr("0123456789/\\$", (c))) + if (addrchar(*p)) { + naddr++; + cmd->a1 = xmalloc(sizeof(struct s_addr)); + p = compile_addr(p, cmd->a1); + EATSPACE(); /* EXTENSION */ + if (*p == ',') { + p++; + EATSPACE(); /* EXTENSION */ + naddr++; + cmd->a2 = xmalloc(sizeof(struct s_addr)); + p = compile_addr(p, cmd->a2); + EATSPACE(); + } else { + cmd->a2 = 0; + } + } else { + cmd->a1 = cmd->a2 = 0; + } + +nonsel: /* Now parse the command */ + if (!*p) + error(COMPILE, "command expected"); + cmd->code = *p; + for (fp = cmd_fmts; fp->code; fp++) + if (fp->code == *p) + break; + if (!fp->code) + error(COMPILE, "invalid command code %c", *p); + if (naddr > fp->naddr) + error(COMPILE, + "command %c expects up to %d address(es), found %d", + *p, fp->naddr, naddr); + switch (fp->args) { + case NONSEL: /* ! */ + p++; + EATSPACE(); + cmd->nonsel = 1; + goto nonsel; + case GROUP: /* { */ + p++; + EATSPACE(); + cmd->next = stack; + stack = cmd; + link = &cmd->u.c; + if (*p) + goto semicolon; + break; + case ENDGROUP: + /* + * Short-circuit command processing, since end of + * group is really just a noop. + */ + cmd->nonsel = 1; + if (stack == 0) + error(COMPILE, "unexpected }"); + cmd2 = stack; + stack = cmd2->next; + cmd2->next = cmd; + /*FALLTHROUGH*/ + case EMPTY: /* d D g G h H l n N p P q x = \0 */ + p++; + EATSPACE(); + if (*p == ';') { + p++; + link = &cmd->next; + goto semicolon; + } + if (*p) + error(COMPILE, +"extra characters at the end of %c command", cmd->code); + break; + case TEXT: /* a c i */ + p++; + EATSPACE(); + if (*p != '\\') + error(COMPILE, "command %c expects \\ followed by" + " text", cmd->code); + p++; + EATSPACE(); + if (*p) + error(COMPILE, "extra characters after \\ at the" + " end of %c command", cmd->code); + cmd->t = compile_text(); + break; + case COMMENT: /* \0 # */ + break; + case WFILE: /* w */ + p++; + EATSPACE(); + if (*p == '\0') + error(COMPILE, "filename expected"); + cmd->t = duptoeol(p, "w command", NULL); + if (aflag) { + cmd->u.fd = -1; + pledge_wpath = 1; + } + else if ((cmd->u.fd = open(p, + O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, + DEFFILEMODE)) == -1) + error(FATAL, "%s: %s", p, strerror(errno)); + break; + case RFILE: /* r */ + pledge_rpath = 1; + p++; + EATSPACE(); + cmd->t = duptoeol(p, "read command", NULL); + break; + case BRANCH: /* b t */ + p++; + EATSPACE(); + if (*p == '\0') + cmd->t = NULL; + else + cmd->t = duptoeol(p, "branch", &p); + if (*p == ';') { + p++; + goto semicolon; + } + break; + case LABEL: /* : */ + p++; + EATSPACE(); + cmd->t = duptoeol(p, "label", &p); + if (strlen(cmd->t) == 0) + error(COMPILE, "empty label"); + enterlabel(cmd); + if (*p == ';') { + p++; + goto semicolon; + } + break; + case SUBST: /* s */ + p++; + if (*p == '\0' || *p == '\\') + error(COMPILE, "substitute pattern can not be" + " delimited by newline or backslash"); + cmd->u.s = xmalloc(sizeof(struct s_subst)); + p = compile_re(p, &cmd->u.s->re); + if (p == NULL) + error(COMPILE, "unterminated substitute pattern"); + --p; + p = compile_subst(p, cmd->u.s); + p = compile_flags(p, cmd->u.s); + EATSPACE(); + if (*p == ';') { + p++; + link = &cmd->next; + goto semicolon; + } + break; + case TR: /* y */ + p++; + p = compile_tr(p, (char **)&cmd->u.y); + EATSPACE(); + if (*p == ';') { + p++; + link = &cmd->next; + goto semicolon; + } + if (*p) + error(COMPILE, "extra text at the end of a" + " transform command"); + break; + } + } +} + +/* + * Get a delimited string. P points to the delimeter of the string; d points + * to a buffer area. Newline and delimiter escapes are processed; other + * escapes are ignored. + * + * Returns a pointer to the first character after the final delimiter or NULL + * in the case of a non-terminated string. The character array d is filled + * with the processed string. + */ +static char * +compile_delimited(char *p, char *d, int is_tr) +{ + char c; + + c = *p++; + if (c == '\0') + return (NULL); + else if (c == '\\') + error(COMPILE, "\\ can not be used as a string delimiter"); + else if (c == '\n') + error(COMPILE, "newline can not be used as a string delimiter"); + while (*p) { + if (*p == '[' && *p != c) { + if ((d = compile_ccl(&p, d)) == NULL) + error(COMPILE, "unbalanced brackets ([])"); + continue; + } else if (*p == '\\' && p[1] == '[') { + *d++ = *p++; + } else if (*p == '\\' && p[1] == c) { + p++; + } else if (*p == '\\' && p[1] == 'n') { + *d++ = '\n'; + p += 2; + continue; + } else if (*p == '\\' && p[1] == '\\') { + if (is_tr) + p++; + else + *d++ = *p++; + } else if (*p == c) { + *d = '\0'; + return (p + 1); + } + *d++ = *p++; + } + return (NULL); +} + + +/* compile_ccl: expand a POSIX character class */ +static char * +compile_ccl(char **sp, char *t) +{ + int c, d; + char *s = *sp; + + *t++ = *s++; + if (*s == '^') + *t++ = *s++; + if (*s == ']') + *t++ = *s++; + for (; *s && (*t = *s) != ']'; s++, t++) + if (*s == '[' && ((d = *(s+1)) == '.' || d == ':' || d == '=')) { + *++t = *++s, t++, s++; + for (c = *s; (*t = *s) != ']' || c != d; s++, t++) + if ((c = *s) == '\0') + return NULL; + } else if (*s == '\\' && s[1] == 'n') { + *t = '\n'; + s++; + } + if (*s == ']') { + *sp = ++s; + return (++t); + } else { + return (NULL); + } +} + +/* + * Get a regular expression. P points to the delimiter of the regular + * expression; repp points to the address of a regexp pointer. Newline + * and delimiter escapes are processed; other escapes are ignored. + * Returns a pointer to the first character after the final delimiter + * or NULL in the case of a non terminated regular expression. The regexp + * pointer is set to the compiled regular expression. + * Cflags are passed to regcomp. + */ +static char * +compile_re(char *p, regex_t **repp) +{ + int eval; + char *re; + + re = xmalloc(strlen(p) + 1); /* strlen(re) <= strlen(p) */ + p = compile_delimited(p, re, 0); + if (p && strlen(re) == 0) { + *repp = NULL; + free(re); + return (p); + } + *repp = xmalloc(sizeof(regex_t)); + if (p && (eval = regcomp(*repp, re, Eflag ? REG_EXTENDED : 0)) != 0) + error(COMPILE, "RE error: %s", strregerror(eval, *repp)); + if (maxnsub < (*repp)->re_nsub) + maxnsub = (*repp)->re_nsub; + free(re); + return (p); +} + +/* + * Compile the substitution string of a regular expression and set res to + * point to a saved copy of it. Nsub is the number of parenthesized regular + * expressions. + */ +static char * +compile_subst(char *p, struct s_subst *s) +{ + static char *lbuf; + static size_t bufsize; + size_t asize, ref, size; + char c, *text, *op, *sp; + int sawesc = 0; + + c = *p++; /* Terminator character */ + if (c == '\0') + return (NULL); + + s->maxbref = 0; + s->linenum = linenum; + text = NULL; + asize = size = 0; + do { + size_t len = ROUNDLEN(strlen(p) + 1); + if (asize - size < len) { + do { + asize += len; + } while (asize - size < len); + text = xrealloc(text, asize); + } + op = sp = text + size; + for (; *p; p++) { + if (*p == '\\' || sawesc) { + /* + * If this is a continuation from the last + * buffer, we won't have a character to + * skip over. + */ + if (sawesc) + sawesc = 0; + else + p++; + + if (*p == '\0') { + /* + * This escaped character is continued + * in the next part of the line. Note + * this fact, then cause the loop to + * exit w/ normal EOL case and reenter + * above with the new buffer. + */ + sawesc = 1; + p--; + continue; + } else if (strchr("123456789", *p) != NULL) { + *sp++ = '\\'; + ref = *p - '0'; + if (s->re != NULL && + ref > s->re->re_nsub) + error(COMPILE, +"\\%c not defined in the RE", *p); + if (s->maxbref < ref) + s->maxbref = ref; + } else if (*p == '&' || *p == '\\') + *sp++ = '\\'; + } else if (*p == c) { + p++; + *sp++ = '\0'; + size += sp - op; + s->new = xrealloc(text, size); + return (p); + } else if (*p == '\n') { + error(COMPILE, +"unescaped newline inside substitute pattern"); + } + *sp++ = *p; + } + size += sp - op; + } while ((p = cu_fgets(&lbuf, &bufsize))); + error(COMPILE, "unterminated substitute in regular expression"); +} + +/* + * Compile the flags of the s command + */ +static char * +compile_flags(char *p, struct s_subst *s) +{ + int gn; /* True if we have seen g or n */ + long l; + char wfile[PATH_MAX], *q, *eq; + + s->n = 1; /* Default */ + s->p = 0; + s->wfile = NULL; + s->wfd = -1; + for (gn = 0;;) { + EATSPACE(); /* EXTENSION */ + switch (*p) { + case 'g': + if (gn) + error(COMPILE, "more than one number or 'g' in" + " substitute flags"); + gn = 1; + s->n = 0; + break; + case '\0': + case '\n': + case ';': + return (p); + case 'p': + s->p = 1; + break; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + if (gn) + error(COMPILE, "more than one number or 'g' in" + " substitute flags"); + gn = 1; + l = strtol(p, &p, 10); + if (l <= 0 || l >= INT_MAX) + error(COMPILE, + "number in substitute flags out of range"); + s->n = (int)l; + continue; + case 'w': + p++; +#ifdef HISTORIC_PRACTICE + if (*p != ' ') { + warning("space missing before w wfile"); + return (p); + } +#endif + EATSPACE(); + q = wfile; + eq = wfile + sizeof(wfile) - 1; + while (*p) { + if (*p == '\n') + break; + if (q >= eq) + error(COMPILE, "wfile too long"); + *q++ = *p++; + } + *q = '\0'; + if (q == wfile) + error(COMPILE, "no wfile specified"); + s->wfile = strdup(wfile); + if (aflag) + pledge_wpath = 1; + else if ((s->wfd = open(wfile, + O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, + DEFFILEMODE)) == -1) + error(FATAL, "%s: %s", wfile, strerror(errno)); + return (p); + default: + error(COMPILE, + "bad flag in substitute command: '%c'", *p); + break; + } + p++; + } +} + +/* + * Compile a translation set of strings into a lookup table. + */ +static char * +compile_tr(char *p, char **transtab) +{ + int i; + char *lt, *op, *np; + char *old = NULL, *new = NULL; + + if (*p == '\0' || *p == '\\') + error(COMPILE, +"transform pattern can not be delimited by newline or backslash"); + old = xmalloc(strlen(p) + 1); + p = compile_delimited(p, old, 1); + if (p == NULL) { + error(COMPILE, "unterminated transform source string"); + goto bad; + } + new = xmalloc(strlen(p) + 1); + p = compile_delimited(--p, new, 1); + if (p == NULL) { + error(COMPILE, "unterminated transform target string"); + goto bad; + } + EATSPACE(); + if (strlen(new) != strlen(old)) { + error(COMPILE, "transform strings are not the same length"); + goto bad; + } + /* We assume characters are 8 bits */ + lt = xmalloc(UCHAR_MAX + 1); + for (i = 0; i <= UCHAR_MAX; i++) + lt[i] = (char)i; + for (op = old, np = new; *op; op++, np++) + lt[(u_char)*op] = *np; + *transtab = lt; + free(old); + free(new); + return (p); +bad: + free(old); + free(new); + return (NULL); +} + +/* + * Compile the text following an a, c, or i command. + */ +static char * +compile_text(void) +{ + size_t asize, size; + int esc_nl; + char *lbuf, *text, *p, *op, *s; + size_t bufsize; + + lbuf = text = NULL; + asize = size = 0; + while ((p = cu_fgets(&lbuf, &bufsize))) { + size_t len = ROUNDLEN(strlen(p) + 1); + if (asize - size < len) { + do { + asize += len; + } while (asize - size < len); + text = xrealloc(text, asize); + } + op = s = text + size; + for (esc_nl = 0; *p != '\0'; p++) { + if (*p == '\\' && p[1] != '\0' && *++p == '\n') + esc_nl = 1; + *s++ = *p; + } + size += s - op; + if (!esc_nl) { + *s = '\0'; + break; + } + } + free(lbuf); + text = xrealloc(text, size + 1); + text[size] = '\0'; + return (text); +} + +/* + * Get an address and return a pointer to the first character after + * it. Fill the structure pointed to according to the address. + */ +static char * +compile_addr(char *p, struct s_addr *a) +{ + char *end; + + switch (*p) { + case '\\': /* Context address */ + ++p; + /* FALLTHROUGH */ + case '/': /* Context address */ + p = compile_re(p, &a->u.r); + if (p == NULL) + error(COMPILE, "unterminated regular expression"); + a->type = AT_RE; + return (p); + + case '$': /* Last line */ + a->type = AT_LAST; + return (p + 1); + /* Line number */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + a->type = AT_LINE; + a->u.l = strtoul(p, &end, 10); + return (end); + default: + error(COMPILE, "expected context address"); + return (NULL); + } +} + +/* + * duptoeol -- + * Return a copy of all the characters up to \n or \0. + */ +static char * +duptoeol(char *s, const char *ctype, char **semi) +{ + size_t len; + int ws; + char *start; + + ws = 0; + if (semi) { + for (start = s; *s != '\0' && *s != '\n' && *s != ';'; ++s) + ws = isspace((unsigned char)*s); + } else { + for (start = s; *s != '\0' && *s != '\n'; ++s) + ws = isspace((unsigned char)*s); + *s = '\0'; + } + if (ws) + warning("whitespace after %s", ctype); + len = s - start + 1; + if (semi) + *semi = s; + s = xmalloc(len); + strlcpy(s, start, len); + return (s); +} + +/* + * Convert goto label names to addresses, and count a and r commands, in + * the given subset of the script. Free the memory used by labels in b + * and t commands (but not by :). + * + * TODO: Remove } nodes + */ +static void +fixuplabel(struct s_command *cp, struct s_command *end) +{ + + for (; cp != end; cp = cp->next) + switch (cp->code) { + case 'a': + case 'r': + appendnum++; + break; + case 'b': + case 't': + /* Resolve branch target. */ + if (cp->t == NULL) { + cp->u.c = NULL; + break; + } + if ((cp->u.c = findlabel(cp->t)) == NULL) + error(COMPILE, "undefined label '%s'", cp->t); + free(cp->t); + break; + case '{': + /* Do interior commands. */ + fixuplabel(cp->u.c, cp->next); + break; + } +} + +/* + * Associate the given command label for later lookup. + */ +static void +enterlabel(struct s_command *cp) +{ + struct labhash **lhp, *lh; + u_char *p; + u_int h, c; + + for (h = 0, p = (u_char *)cp->t; (c = *p) != 0; p++) + h = (h << 5) + h + c; + lhp = &labels[h & LHMASK]; + for (lh = *lhp; lh != NULL; lh = lh->lh_next) + if (lh->lh_hash == h && strcmp(cp->t, lh->lh_cmd->t) == 0) + error(COMPILE, "duplicate label '%s'", cp->t); + lh = xmalloc(sizeof *lh); + lh->lh_next = *lhp; + lh->lh_hash = h; + lh->lh_cmd = cp; + lh->lh_ref = 0; + *lhp = lh; +} + +/* + * Find the label contained in the command l in the command linked + * list cp. L is excluded from the search. Return NULL if not found. + */ +static struct s_command * +findlabel(char *name) +{ + struct labhash *lh; + u_char *p; + u_int h, c; + + for (h = 0, p = (u_char *)name; (c = *p) != 0; p++) + h = (h << 5) + h + c; + for (lh = labels[h & LHMASK]; lh != NULL; lh = lh->lh_next) { + if (lh->lh_hash == h && strcmp(name, lh->lh_cmd->t) == 0) { + lh->lh_ref = 1; + return (lh->lh_cmd); + } + } + return (NULL); +} + +/* + * Warn about any unused labels. As a side effect, release the label hash + * table space. + */ +static void +uselabel(void) +{ + struct labhash *lh, *next; + int i; + + for (i = 0; i < LHSZ; i++) { + for (lh = labels[i]; lh != NULL; lh = next) { + next = lh->lh_next; + if (!lh->lh_ref) + warning("unused label '%s'", + lh->lh_cmd->t); + free(lh); + } + } +} diff --git a/package/toolbox/src/sed/defs.h b/package/toolbox/src/sed/defs.h new file mode 100644 index 000000000..14634a49a --- /dev/null +++ b/package/toolbox/src/sed/defs.h @@ -0,0 +1,147 @@ +/** $MirOS: src/usr.bin/sed/defs.h,v 1.3 2017/11/20 01:23:56 tg Exp $ */ +/* $OpenBSD: defs.h,v 1.8 2017/01/20 10:26:16 krw Exp $ */ +/*- + * Copyright (c) 1992 Diomidis Spinellis. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Diomidis Spinellis of Imperial College, University of London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)defs.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Types of address specifications + */ +enum e_atype { + AT_RE, /* Line that match RE */ + AT_LINE, /* Specific line */ + AT_LAST, /* Last line */ +}; + +/* + * Format of an address + */ +struct s_addr { + enum e_atype type; /* Address type */ + union { + u_long l; /* Line number */ + regex_t *r; /* Regular expression */ + } u; +}; + +/* + * Substitution command + */ +struct s_subst { + int n; /* Occurrence to subst. */ + int p; /* True if p flag */ + char *wfile; /* NULL if no wfile */ + int wfd; /* Cached file descriptor */ + regex_t *re; /* Regular expression */ + size_t maxbref; /* Largest backreference. */ + u_long linenum; /* Line number. */ + char *new; /* Replacement text */ +}; + + +/* + * An internally compiled command. + * Initialy, label references are stored in t, on a second pass they + * are updated to pointers. + */ +struct s_command { + struct s_command *next; /* Pointer to next command */ + struct s_addr *a1, *a2; /* Start and end address */ + char *t; /* Text for : a c i r w */ + union { + struct s_command *c; /* Command(s) for b t { */ + struct s_subst *s; /* Substitute command */ + u_char *y; /* Replace command array */ + int fd; /* File descriptor for w */ + } u; + char code; /* Command code */ + u_int nonsel:1; /* True if ! */ + u_int inrange:1; /* True if in range */ +}; + +/* + * Types of command arguments recognised by the parser + */ +enum e_args { + EMPTY, /* d D g G h H l n N p P q x = \0 */ + TEXT, /* a c i */ + NONSEL, /* ! */ + GROUP, /* { */ + ENDGROUP, /* } */ + COMMENT, /* # */ + BRANCH, /* b t */ + LABEL, /* : */ + RFILE, /* r */ + WFILE, /* w */ + SUBST, /* s */ + TR /* y */ +}; + +/* + * Structure containing things to append before a line is read + */ +struct s_appends { + enum {AP_STRING, AP_FILE} type; + char *s; + size_t len; +}; + +enum e_spflag { + APPEND, /* Append to the contents. */ + REPLACE, /* Replace the contents. */ +}; + +/* + * Structure for a space (process, hold, otherwise). + */ +typedef struct { + char *space; /* Current space pointer. */ + size_t len; /* Current length. */ + int deleted; /* If deleted. */ + int append_newline; /* If originally terminated by \n. */ + char *back; /* Backing memory. */ + size_t blen; /* Backing memory length. */ +} SPACE; + +/* + * Error severity codes: + */ +#define FATAL 1 /* Exit immediately with 1 */ +#define COMPILE 2 /* Print error, count and finish script */ + +/* + * Round up to the nearest multiple of _POSIX2_LINE_MAX + */ +#define ROUNDLEN(x) \ + (((x) + _POSIX2_LINE_MAX - 1) & ~(_POSIX2_LINE_MAX - 1)) diff --git a/package/toolbox/src/sed/extern.h b/package/toolbox/src/sed/extern.h new file mode 100644 index 000000000..01ede9406 --- /dev/null +++ b/package/toolbox/src/sed/extern.h @@ -0,0 +1,65 @@ +/** $MirOS: src/usr.bin/sed/extern.h,v 1.3 2017/11/20 01:23:57 tg Exp $ */ +/* $OpenBSD: extern.h,v 1.13 2017/08/01 18:05:53 martijn Exp $ */ +/*- + * Copyright (c) 1992 Diomidis Spinellis. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Diomidis Spinellis of Imperial College, University of London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +extern struct s_command *prog; +extern struct s_appends *appends; +extern regmatch_t *match; +extern size_t maxnsub; +extern u_long linenum; +extern size_t appendnum; +extern int Eflag, aflag, eflag, nflag; +extern int pledge_wpath, pledge_rpath; +extern const char *fname, *outfname; +extern FILE *infile, *outfile; + +void cfclose(struct s_command *, struct s_command *); +void compile(void); +void cspace(SPACE *, const char *, size_t, enum e_spflag); +char *cu_fgets(char **, size_t *); +void error(int, const char *, ...) + __dead + __attribute__((__format__(__printf__, 2, 3))); +void warning(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); +int mf_fgets(SPACE *, enum e_spflag); +int lastline(void); +void process(void); +void resetranges(void); +char *strregerror(int, regex_t *); +void *xmalloc(size_t); +void *xreallocarray(void *, size_t, size_t); +void *xrealloc(void *, size_t); diff --git a/package/toolbox/src/sed/main.c b/package/toolbox/src/sed/main.c new file mode 100644 index 000000000..afa10d4df --- /dev/null +++ b/package/toolbox/src/sed/main.c @@ -0,0 +1,523 @@ +/* $OpenBSD: main.c,v 1.35 2017/08/01 18:05:53 martijn Exp $ */ + +/*- + * Copyright (c) 2016, 2017 + * mirabilos <m@mirbsd.org> + * Copyright (c) 1992 Diomidis Spinellis. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Diomidis Spinellis of Imperial College, University of London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <regex.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <libgen.h> + +#include "defs.h" +#include "extern.h" + +__RCSID("$MirOS: src/usr.bin/sed/main.c,v 1.3 2017/11/20 01:23:57 tg Exp $"); + +/* + * Linked list of units (strings and files) to be compiled + */ +struct s_compunit { + struct s_compunit *next; + enum e_cut {CU_FILE, CU_STRING} type; + char *s; /* Pointer to string or fname */ +}; + +/* + * Linked list pointer to compilation units and pointer to current + * next pointer. + */ +static struct s_compunit *script, **cu_nextp = &script; + +/* + * Linked list of files to be processed + */ +struct s_flist { + char *fname; + struct s_flist *next; +}; + +/* + * Linked list pointer to files and pointer to current + * next pointer. + */ +static struct s_flist *files, **fl_nextp = &files; + +FILE *infile; /* Current input file */ +FILE *outfile; /* Current output file */ + +int Eflag, aflag, eflag, nflag; +static int rval; /* Exit status */ + +/* + * Current file and line number; line numbers restart across compilation + * units, but span across input files. The latter is optional if editing + * in place. + */ +const char *fname; /* File name. */ +const char *outfname; /* Output file name */ +static char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */ +static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */ +const char *inplace; /* Inplace edit file extension */ +u_long linenum; + +static void add_compunit(enum e_cut, char *); +static void add_file(char *); +static int next_files_have_lines(void); + +int termwidth; + +int pledge_wpath, pledge_rpath; + +int +main(int argc, char *argv[]) +{ + int c, fflag; + + fflag = 0; + inplace = NULL; + while ((c = getopt(argc, argv, "Eae:f:i::nru")) != -1) + switch (c) { + case 'E': + case 'r': + Eflag = 1; + break; + case 'a': + aflag = 1; + break; + case 'e': + eflag = 1; + add_compunit(CU_STRING, optarg); + break; + case 'f': + fflag = 1; + add_compunit(CU_FILE, optarg); + break; + case 'i': + inplace = optarg ? optarg : ""; + break; + case 'n': + nflag = 1; + break; + case 'u': + setvbuf(stdout, NULL, _IOLBF, 0); + break; + default: + case '?': + (void)fprintf(stderr, + "usage: sed [-aEnru] [-i[extension]] command [file ...]\n" + " sed [-aEnru] [-e command] [-f command_file] [-i[extension]] [file ...]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + termwidth = 60; + +#if defined(__OpenBSD__) && !defined(__MirBSD__) + if (inplace != NULL) { + if (pledge("stdio rpath wpath cpath fattr chown", NULL) == -1) + error(FATAL, "pledge: %s", strerror(errno)); + } else { + if (pledge("stdio rpath wpath cpath", NULL) == -1) + error(FATAL, "pledge: %s", strerror(errno)); + } +#endif + + /* First usage case; script is the first arg */ + if (!eflag && !fflag && *argv) { + add_compunit(CU_STRING, *argv); + argv++; + } + + compile(); + + /* Continue with first and start second usage */ + if (*argv) { +#if defined(__OpenBSD__) && !defined(__MirBSD__) + if (!pledge_wpath && inplace == NULL) { + if (pledge("stdio rpath", NULL) == -1) + error(FATAL, "pledge: %s", strerror(errno)); + } +#endif + for (; *argv; argv++) + add_file(*argv); + } else { +#if defined(__OpenBSD__) && !defined(__MirBSD__) + if (!pledge_wpath && !pledge_rpath) { + if (pledge("stdio", NULL) == -1) + error(FATAL, "pledge: %s", strerror(errno)); + } else if (pledge_rpath) { + if (pledge("stdio rpath", NULL) == -1) + error(FATAL, "pledge: %s", strerror(errno)); + } else if (pledge_wpath) { + if (pledge("stdio wpath cpath", NULL) == -1) + error(FATAL, "pledge: %s", strerror(errno)); + } +#endif + add_file(NULL); + } + process(); + cfclose(prog, NULL); + if (fclose(stdout)) + error(FATAL, "stdout: %s", strerror(errno)); + exit (rval); +} + +/* + * Like fgets, but go through the chain of compilation units chaining them + * together. Empty strings and files are ignored. + */ +char * +cu_fgets(char **outbuf, size_t *outsize) +{ + static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; + static FILE *f; /* Current open file */ + static char *s; /* Current pointer inside string */ + static char string_ident[30]; + size_t len; + char *p; + + if (*outbuf == NULL) + *outsize = 0; + +again: + switch (state) { + case ST_EOF: + if (script == NULL) + goto cu_fgets_nilreturn; + linenum = 0; + switch (script->type) { + case CU_FILE: + if ((f = fopen(script->s, "r")) == NULL) + error(FATAL, + "%s: %s", script->s, strerror(errno)); + fname = script->s; + state = ST_FILE; + goto again; + case CU_STRING: + if (((size_t)snprintf(string_ident, + sizeof(string_ident), "\"%s\"", script->s)) >= + sizeof(string_ident)) + strlcpy(string_ident + + sizeof(string_ident) - 6, " ...\"", 5); + fname = string_ident; + s = script->s; + state = ST_STRING; + goto again; + } + case ST_FILE: + if ((p = fgetln(f, &len)) != NULL) { + linenum++; + if (len >= *outsize) { + free(*outbuf); + *outsize = ROUNDLEN(len + 1); + *outbuf = xmalloc(*outsize); + } + memcpy(*outbuf, p, len); + (*outbuf)[len] = '\0'; + if (linenum == 1 && p[0] == '#' && p[1] == 'n') + nflag = 1; + return (*outbuf); + } + script = script->next; + (void)fclose(f); + state = ST_EOF; + goto again; + case ST_STRING: + if (linenum == 0 && s[0] == '#' && s[1] == 'n') + nflag = 1; + p = *outbuf; + len = *outsize; + for (;;) { + if (len <= 1) { + *outbuf = xrealloc(*outbuf, + *outsize + _POSIX2_LINE_MAX); + p = *outbuf + *outsize - len; + len += _POSIX2_LINE_MAX; + *outsize += _POSIX2_LINE_MAX; + } + switch (*s) { + case '\0': + state = ST_EOF; + if (s == script->s) { + script = script->next; + goto again; + } else { + script = script->next; + *p = '\0'; + linenum++; + return (*outbuf); + } + case '\n': + *p++ = '\n'; + *p = '\0'; + s++; + linenum++; + return (*outbuf); + default: + *p++ = *s++; + len--; + } + } + } + /* NOTREACHED */ + /* but GCC doesn't care, so: */ + cu_fgets_nilreturn: + return (NULL); +} + +/* + * Like fgets, but go through the list of files chaining them together. + * Set len to the length of the line. + */ +int +mf_fgets(SPACE *sp, enum e_spflag spflag) +{ + struct stat sb; + size_t len; + char *p; + int c, fd; + static int firstfile; + + if (infile == NULL) { + /* stdin? */ + if (files->fname == NULL) { + if (inplace != NULL) + error(FATAL, "-i may not be used with stdin"); + infile = stdin; + fname = "stdin"; + outfile = stdout; + outfname = "stdout"; + } + + firstfile = 1; + } + + for (;;) { + if (infile != NULL && (c = getc(infile)) != EOF) { + (void)ungetc(c, infile); + break; + } + /* If we are here then either eof or no files are open yet */ + if (infile == stdin) { + sp->len = 0; + return (0); + } + if (infile != NULL) { + fclose(infile); + if (*oldfname != '\0') { + if (rename(fname, oldfname) != 0) { + warning("rename()"); + unlink(tmpfname); + exit(1); + } + *oldfname = '\0'; + } + if (*tmpfname != '\0') { + if (outfile != NULL && outfile != stdout) + fclose(outfile); + outfile = NULL; + rename(tmpfname, fname); + *tmpfname = '\0'; + } + outfname = NULL; + } + if (firstfile == 0) + files = files->next; + else + firstfile = 0; + if (files == NULL) { + sp->len = 0; + return (0); + } + fname = files->fname; + if (inplace != NULL) { + char *tmpdirname; + + if (lstat(fname, &sb) != 0) + error(FATAL, "%s: %s", fname, + strerror(errno ? errno : EIO)); + if (!S_ISREG(sb.st_mode)) + error(FATAL, "%s: %s %s", fname, + "in-place editing only", + "works for regular files"); + if (*inplace != '\0') { + strlcpy(oldfname, fname, + sizeof(oldfname)); + len = strlcat(oldfname, inplace, + sizeof(oldfname)); + if (len > sizeof(oldfname)) + error(FATAL, "%s: name too long", fname); + } + len = snprintf(tmpfname, sizeof(tmpfname), "%s/sedXXXXXXXXXX", + dirname(tmpdirname = strdup(fname))); + free(tmpdirname); + if (len >= sizeof(tmpfname)) + error(FATAL, "%s: name too long", fname); + if ((fd = mkstemp(tmpfname)) == -1) + error(FATAL, "%s: %s", fname, strerror(errno)); + if ((outfile = fdopen(fd, "w")) == NULL) { + unlink(tmpfname); + error(FATAL, "%s", fname); + } + fchown(fileno(outfile), sb.st_uid, sb.st_gid); + fchmod(fileno(outfile), sb.st_mode & ALLPERMS); + outfname = tmpfname; + linenum = 0; + resetranges(); + } else { + outfile = stdout; + outfname = "stdout"; + } + if ((infile = fopen(fname, "r")) == NULL) { + warning("%s", strerror(errno)); + rval = 1; + continue; + } + } + + /* + * We are here only when infile is open and we still have something + * to read from it. + * + * Use fgetln so that we can handle essentially infinite input data. + * Can't use the pointer into the stdio buffer as the process space + * because the ungetc() can cause it to move. + */ + p = fgetln(infile, &len); + if (ferror(infile)) + error(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO)); + if (len != 0 && p[len - 1] == '\n') { + sp->append_newline = 1; + len--; + } else if (!lastline()) { + sp->append_newline = 1; + } else { + sp->append_newline = 0; + } + cspace(sp, p, len, spflag); + + linenum++; + + return (1); +} + +/* + * Add a compilation unit to the linked list + */ +static void +add_compunit(enum e_cut type, char *s) +{ + struct s_compunit *cu; + + cu = xmalloc(sizeof(struct s_compunit)); + cu->type = type; + cu->s = s; + cu->next = NULL; + *cu_nextp = cu; + cu_nextp = &cu->next; +} + +/* + * Add a file to the linked list + */ +static void +add_file(char *s) +{ + struct s_flist *fp; + + fp = xmalloc(sizeof(struct s_flist)); + fp->next = NULL; + *fl_nextp = fp; + fp->fname = s; + fl_nextp = &fp->next; +} + + +static int +next_files_have_lines(void) +{ + struct s_flist *file; + FILE *file_fd; + int ch; + + file = files; + while ((file = file->next) != NULL) { + if ((file_fd = fopen(file->fname, "r")) == NULL) + continue; + + if ((ch = getc(file_fd)) != EOF) { + /* + * This next file has content, therefore current + * file doesn't contains the last line. + */ + ungetc(ch, file_fd); + fclose(file_fd); + return (1); + } + fclose(file_fd); + } + return (0); +} + +int +lastline(void) +{ + int ch; + + if (feof(infile)) { + return !( + (inplace == NULL) && + next_files_have_lines()); + } + if ((ch = getc(infile)) == EOF) { + return !( + (inplace == NULL) && + next_files_have_lines()); + } + ungetc(ch, infile); + return (0); +} diff --git a/package/toolbox/src/sed/misc.c b/package/toolbox/src/sed/misc.c new file mode 100644 index 000000000..1ed230014 --- /dev/null +++ b/package/toolbox/src/sed/misc.c @@ -0,0 +1,166 @@ +/* $OpenBSD: misc.c,v 1.12 2017/01/20 10:26:16 krw Exp $ */ + +/*- + * Copyright (c) 2016 + * mirabilos <m@mirbsd.org> + * Copyright (c) 1992 Diomidis Spinellis. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Diomidis Spinellis of Imperial College, University of London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <errno.h> +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "defs.h" +#include "extern.h" + +__RCSID("$MirOS: src/usr.bin/sed/misc.c,v 1.3 2017/11/20 01:23:57 tg Exp $"); + +/* + * malloc with result test + */ +void * +xmalloc(size_t size) +{ + void *p; + + if ((p = malloc(size)) == NULL) + error(FATAL, "%s", strerror(errno)); + return (p); +} + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) + +void * +xreallocarray(void *o, size_t nmemb, size_t size) +{ + void *p; + + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && __SIZE_MAX__ / nmemb < size) { + p = NULL; + errno = ENOMEM; + } else + p = realloc(o, size * nmemb); + + if (p == NULL) + error(FATAL, "%s", strerror(errno)); + return (p); +} + +/* + * realloc with result test + */ +void * +xrealloc(void *p, size_t size) +{ + + if ((p = realloc(p, size)) == NULL) + error(FATAL, "%s", strerror(errno)); + return (p); +} + +/* + * Return a string for a regular expression error passed. This is a overkill, + * because of the silly semantics of regerror (we can never know the size of + * the buffer). + */ +char * +strregerror(int errcode, regex_t *preg) +{ + static char *oe; + size_t s; + + free(oe); + s = regerror(errcode, preg, NULL, 0); + oe = xmalloc(s); + (void)regerror(errcode, preg, oe, s); + return (oe); +} + +/* + * Error reporting function + */ +__dead void +error(int severity, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)fprintf(stderr, "sed: "); + switch (severity) { + case COMPILE: + (void)fprintf(stderr, "%lu: %s: ", linenum, fname); + } + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); +} + +void +warning(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)fprintf(stderr, "sed: "); + (void)fprintf(stderr, "%lu: %s: ", linenum, fname); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); +} diff --git a/package/toolbox/src/sed/process.c b/package/toolbox/src/sed/process.c new file mode 100644 index 000000000..b2b2a8717 --- /dev/null +++ b/package/toolbox/src/sed/process.c @@ -0,0 +1,642 @@ +/* $OpenBSD: process.c,v 1.32 2017/02/22 14:09:09 tom Exp $ */ + +/*- + * Copyright (c) 2015 + * mirabilos <m@mirbsd.org> + * Copyright (c) 1992 Diomidis Spinellis. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Diomidis Spinellis of Imperial College, University of London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/uio.h> + +__SCCSID("@(#)process.c 8.1 (Berkeley) 6/6/93"); +__RCSID("$MirOS: src/usr.bin/sed/process.c,v 1.5 2017/11/20 01:23:57 tg Exp $"); + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "defs.h" +#include "extern.h" + +static SPACE HS, PS, SS; +#define pd PS.deleted +#define ps PS.space +#define psl PS.len +#define psanl PS.append_newline +#define hs HS.space +#define hsl HS.len + +static inline int applies(struct s_command *); +static void flush_appends(void); +static void lputs(char *); +static inline int regexec_e(regex_t *, const char *, int, int, size_t, + size_t); +static void regsub(SPACE *, char *, char *); +static int substitute(struct s_command *); + +struct s_appends *appends; /* Array of pointers to strings to append. */ +static size_t appendx; /* Index into appends array. */ +size_t appendnum; /* Size of appends array. */ + +static int lastaddr; /* Set by applies if last address of a range. */ +static int sdone; /* If any substitutes since last line input. */ + /* Iov structure for 'w' commands. */ +static regex_t *defpreg; +size_t maxnsub; +regmatch_t *match; + +#define OUT() do {\ + fwrite(ps, 1, psl, outfile);\ + if (psanl) fputc('\n', outfile);\ +} while (0) + +void +process(void) +{ + struct s_command *cp; + SPACE tspace; + size_t len, oldpsl; + char *p; + + for (linenum = 0; mf_fgets(&PS, REPLACE);) { + pd = 0; +top: + cp = prog; +redirect: + while (cp != NULL) { + if (!applies(cp)) { + cp = cp->next; + continue; + } + switch (cp->code) { + case '{': + cp = cp->u.c; + goto redirect; + case 'a': + if (appendx >= appendnum) { + appends = xreallocarray(appends, + appendnum, + 2 * sizeof(struct s_appends)); + appendnum *= 2; + } + appends[appendx].type = AP_STRING; + appends[appendx].s = cp->t; + appends[appendx].len = strlen(cp->t); + appendx++; + break; + case 'b': + cp = cp->u.c; + goto redirect; + case 'c': + pd = 1; + psl = 0; + if (cp->a2 == NULL || lastaddr || lastline()) + (void)fprintf(outfile, "%s", cp->t); + break; + case 'd': + pd = 1; + goto new; + case 'D': + if (pd) + goto new; + if (psl == 0 || + (p = memchr(ps, '\n', psl)) == NULL) { + pd = 1; + goto new; + } else { + psl -= (p + 1) - ps; + memmove(ps, p + 1, psl); + goto top; + } + case 'g': + cspace(&PS, hs, hsl, REPLACE); + break; + case 'G': + cspace(&PS, "\n", 1, 0); + cspace(&PS, hs, hsl, 0); + break; + case 'h': + cspace(&HS, ps, psl, REPLACE); + break; + case 'H': + cspace(&HS, "\n", 1, 0); + cspace(&HS, ps, psl, 0); + break; + case 'i': + (void)fprintf(outfile, "%s", cp->t); + break; + case 'l': + lputs(ps); + break; + case 'n': + if (!nflag && !pd) + OUT(); + flush_appends(); + if (!mf_fgets(&PS, REPLACE)) + exit(0); + pd = 0; + break; + case 'N': + flush_appends(); + cspace(&PS, "\n", 1, 0); + if (!mf_fgets(&PS, 0)) + exit(0); + break; + case 'p': + if (pd) + break; + OUT(); + break; + case 'P': + if (pd) + break; + if ((p = memchr(ps, '\n', psl)) != NULL) { + oldpsl = psl; + psl = p - ps; + psanl = 1; + OUT(); + psl = oldpsl; + } else { + OUT(); + } + break; + case 'q': + if (!nflag && !pd) + OUT(); + flush_appends(); + exit(0); + case 'r': + if (appendx >= appendnum) { + appends = xreallocarray(appends, + appendnum, + 2 * sizeof(struct s_appends)); + appendnum *= 2; + } + appends[appendx].type = AP_FILE; + appends[appendx].s = cp->t; + appends[appendx].len = strlen(cp->t); + appendx++; + break; + case 's': + sdone |= substitute(cp); + break; + case 't': + if (sdone) { + sdone = 0; + cp = cp->u.c; + goto redirect; + } + break; + case 'w': + if (pd) + break; + if (cp->u.fd == -1 && (cp->u.fd = open(cp->t, + O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, + DEFFILEMODE)) == -1) + error(FATAL, "%s: %s", + cp->t, strerror(errno)); + if ((size_t)write(cp->u.fd, ps, psl) != psl || + write(cp->u.fd, "\n", 1) != 1) + error(FATAL, "%s: %s", + cp->t, strerror(errno)); + break; + case 'x': + if (hs == NULL) + cspace(&HS, "", 0, REPLACE); + tspace = PS; + PS = HS; + psanl = tspace.append_newline; + HS = tspace; + break; + case 'y': + if (pd || psl == 0) + break; + for (p = ps, len = psl; len--; ++p) + *p = cp->u.y[(unsigned char)*p]; + break; + case ':': + case '}': + break; + case '=': + (void)fprintf(outfile, "%lu\n", linenum); + } + cp = cp->next; + } /* for all cp */ + +new: if (!nflag && !pd) + OUT(); + flush_appends(); + } /* for all lines */ +} + +/* + * TRUE if the address passed matches the current program state + * (lastline, linenumber, ps). + */ +#define MATCH(a) \ + (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, 0, psl) : \ + (a)->type == AT_LINE ? linenum == (a)->u.l : lastline() + +/* + * Return TRUE if the command applies to the current line. Sets the inrange + * flag to process ranges. Interprets the non-select (``!'') flag. + */ +static inline int +applies(struct s_command *cp) +{ + int r; + + lastaddr = 0; + if (cp->a1 == NULL && cp->a2 == NULL) + r = 1; + else if (cp->a2) + if (cp->inrange) { + if (MATCH(cp->a2)) { + cp->inrange = 0; + lastaddr = 1; + } + r = 1; + } else if (MATCH(cp->a1)) { + /* + * If the second address is a number less than or + * equal to the line number first selected, only + * one line shall be selected. + * -- POSIX 1003.2 + */ + if (cp->a2->type == AT_LINE && + linenum >= cp->a2->u.l) + lastaddr = 1; + else + cp->inrange = 1; + r = 1; + } else + r = 0; + else + r = MATCH(cp->a1); + return (cp->nonsel ? !r : r); +} + +/* + * Reset all inrange markers. + */ +void +resetranges(void) +{ + struct s_command *cp; + + for (cp = prog; cp; cp = cp->code == '{' ? cp->u.c : cp->next) + if (cp->a2) + cp->inrange = 0; +} + +/* + * substitute -- + * Do substitutions in the pattern space. Currently, we build a + * copy of the new pattern space in the substitute space structure + * and then swap them. + */ +static int +substitute(struct s_command *cp) +{ + SPACE tspace; + regex_t *re; + regoff_t slen; + int n, lastempty; + size_t le = 0; + char *s; + + s = ps; + re = cp->u.s->re; + if (re == NULL) { + if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) { + linenum = cp->u.s->linenum; + error(COMPILE, "\\%zu not defined in the RE", + cp->u.s->maxbref); + } + } + if (!regexec_e(re, ps, 0, 0, 0, psl)) + return (0); + + SS.len = 0; /* Clean substitute space. */ + slen = psl; + n = cp->u.s->n; + lastempty = 1; + + do { + /* Copy the leading retained string. */ + if (n <= 1 && (match[0].rm_so > le)) + cspace(&SS, s, match[0].rm_so - le, APPEND); + + /* Skip zero-length matches right after other matches. */ + if (lastempty || (match[0].rm_so - le) || + match[0].rm_so != match[0].rm_eo) { + if (n <= 1) { + /* Want this match: append replacement. */ + regsub(&SS, ps, cp->u.s->new); + if (n == 1) + n = -1; + } else { + /* Want a later match: append original. */ + if (match[0].rm_eo - le) + cspace(&SS, s, match[0].rm_eo - le, + APPEND); + n--; + } + } + + /* Move past this match. */ + s = ps + match[0].rm_eo; + slen = psl - match[0].rm_eo; + le = match[0].rm_eo; + + /* + * After a zero-length match, advance one byte, + * and at the end of the line, terminate. + */ + if (match[0].rm_so == match[0].rm_eo) { + if (*s == '\0' || *s == '\n') + slen = -1; + else + slen--; + if (*s != '\0') { + cspace(&SS, s++, 1, APPEND); + le++; + } + lastempty = 1; + } else + lastempty = 0; + + } while (n >= 0 && slen >= 0 && + regexec_e(re, ps, REG_NOTBOL, 0, le, psl)); + + /* Did not find the requested number of matches. */ + if (n > 0) + return (0); + + /* Copy the trailing retained string. */ + if (slen > 0) + cspace(&SS, s, slen, APPEND); + + /* + * Swap the substitute space and the pattern space, and make sure + * that any leftover pointers into stdio memory get lost. + */ + tspace = PS; + PS = SS; + psanl = tspace.append_newline; + SS = tspace; + SS.space = SS.back; + + /* Handle the 'p' flag. */ + if (cp->u.s->p) + OUT(); + + /* Handle the 'w' flag. */ + if (cp->u.s->wfile && !pd) { + if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, + O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1) + error(FATAL, "%s: %s", cp->u.s->wfile, strerror(errno)); + if ((size_t)write(cp->u.s->wfd, ps, psl) != psl || + write(cp->u.s->wfd, "\n", 1) != 1) + error(FATAL, "%s: %s", cp->u.s->wfile, strerror(errno)); + } + return (1); +} + +/* + * Flush append requests. Always called before reading a line, + * therefore it also resets the substitution done (sdone) flag. + */ +static void +flush_appends(void) +{ + FILE *f; + int count; + size_t i; + char buf[8 * 1024]; + + for (i = 0; i < appendx; i++) + switch (appends[i].type) { + case AP_STRING: + fwrite(appends[i].s, sizeof(char), appends[i].len, + outfile); + break; + case AP_FILE: + /* + * Read files probably shouldn't be cached. Since + * it's not an error to read a non-existent file, + * it's possible that another program is interacting + * with the sed script through the filesystem. It + * would be truly bizarre, but possible. It's probably + * not that big a performance win, anyhow. + */ + if ((f = fopen(appends[i].s, "r")) == NULL) + break; + while ((count = fread(buf, sizeof(char), sizeof(buf), f))) + (void)fwrite(buf, sizeof(char), count, outfile); + (void)fclose(f); + break; + } + if (ferror(outfile)) + error(FATAL, "%s: %s", outfname, strerror(errno ? errno : EIO)); + appendx = sdone = 0; +} + +static void +lputs(char *s) +{ + int count; + extern int termwidth; + const char *escapes; + char *p; + + for (count = 0; *s; ++s) { + if (count >= termwidth) { + (void)fprintf(outfile, "\\\n"); + count = 0; + } + if (isascii((unsigned char)*s) && isprint((unsigned char)*s) + && *s != '\\') { + (void)fputc(*s, outfile); + count++; + } else { + escapes = "\\\a\b\f\n\r\t\v"; + if (*s == '\n' && s[1] == '\0') { + /* omit trailing newline */ + break; + } + (void)fputc('\\', outfile); + if ((p = strchr(escapes, *s))) { + (void)fputc("\\abfnrtv"[p - escapes], outfile); + count += 2; + } else { + (void)fprintf(outfile, "%03o", *(u_char *)s); + count += 4; + } + } + } + (void)fputc('$', outfile); + (void)fputc('\n', outfile); + if (ferror(outfile)) + error(FATAL, "%s: %s", outfname, strerror(errno ? errno : EIO)); +} + +static inline int +regexec_e(regex_t *preg, const char *string, int eflags, + int nomatch, size_t start, size_t stop) +{ + int eval; + + if (preg == NULL) { + if (defpreg == NULL) + error(FATAL, "first RE may not be empty"); + } else + defpreg = preg; + + /* Set anchors */ + match[0].rm_so = start; + match[0].rm_eo = stop; + + eval = regexec(defpreg, string, + nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND); + switch (eval) { + case 0: + return (1); + case REG_NOMATCH: + return (0); + } + error(FATAL, "RE error: %s", strregerror(eval, defpreg)); +} + +/* + * regsub - perform substitutions after a regexp match + * Based on a routine by Henry Spencer + */ +static void +regsub(SPACE *sp, char *string, char *src) +{ + int len, no; + char c, *dst; + +#define NEEDSP(reqlen) \ + if (sp->len + (reqlen) + 1 >= sp->blen) { \ + size_t newlen = sp->blen + (reqlen) + 1024; \ + sp->space = sp->back = xrealloc(sp->back, newlen); \ + sp->blen = newlen; \ + dst = sp->space + sp->len; \ + } + + dst = sp->space + sp->len; + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && isdigit((unsigned char)*src)) + no = *src++ - '0'; + else + no = -1; + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; + NEEDSP(1); + *dst++ = c; + ++sp->len; + } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) { + len = match[no].rm_eo - match[no].rm_so; + NEEDSP(len); + memmove(dst, string + match[no].rm_so, len); + dst += len; + sp->len += len; + } + } + NEEDSP(1); + *dst = '\0'; +} + +/* + * aspace -- + * Append the source space to the destination space, allocating new + * space as necessary. + */ +void +cspace(SPACE *sp, const char *p, size_t len, enum e_spflag spflag) +{ + size_t tlen; + + /* Make sure SPACE has enough memory and ramp up quickly. */ + tlen = sp->len + len + 1; + if (tlen > sp->blen) { + size_t newlen = tlen + 1024; + sp->space = sp->back = xrealloc(sp->back, newlen); + sp->blen = newlen; + } + + if (spflag == REPLACE) + sp->len = 0; + + memmove(sp->space + sp->len, p, len); + + sp->space[sp->len += len] = '\0'; +} + +/* + * Close all cached opened files and report any errors + */ +void +cfclose(struct s_command *cp, struct s_command *end) +{ + + for (; cp != end; cp = cp->next) + switch (cp->code) { + case 's': + if (cp->u.s->wfd != -1 && close(cp->u.s->wfd)) + error(FATAL, + "%s: %s", cp->u.s->wfile, strerror(errno)); + cp->u.s->wfd = -1; + break; + case 'w': + if (cp->u.fd != -1 && close(cp->u.fd)) + error(FATAL, "%s: %s", cp->t, strerror(errno)); + cp->u.fd = -1; + break; + case '{': + cfclose(cp->u.c, cp->next); + break; + } +} diff --git a/package/toolbox/src/setkey/Makefile b/package/toolbox/src/setkey/Makefile new file mode 100644 index 000000000..836a8569e --- /dev/null +++ b/package/toolbox/src/setkey/Makefile @@ -0,0 +1,3 @@ +PROG= setkey + +include ../tool.mk diff --git a/package/toolbox/src/sleep/Makefile b/package/toolbox/src/sleep/Makefile new file mode 100644 index 000000000..c5de1eef0 --- /dev/null +++ b/package/toolbox/src/sleep/Makefile @@ -0,0 +1,3 @@ +PROG= sleep + +include ../tool.mk diff --git a/package/toolbox/src/src/chmod.c b/package/toolbox/src/src/chmod.c new file mode 100644 index 000000000..1de14aa2c --- /dev/null +++ b/package/toolbox/src/src/chmod.c @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <limits.h> +#include <sys/stat.h> + +#include <unistd.h> +#include <time.h> + +void recurse_chmod(char* path, int mode) +{ + struct dirent *dp; + DIR *dir = opendir(path); + if (dir == NULL) { + // not a directory, carry on + return; + } + char *subpath = malloc(sizeof(char)*PATH_MAX); + int pathlen = strlen(path); + + while ((dp = readdir(dir)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) continue; + + if (strlen(dp->d_name) + pathlen + 2/*NUL and slash*/ > PATH_MAX) { + fprintf(stderr, "Invalid path specified: too long\n"); + exit(1); + } + + strcpy(subpath, path); + strcat(subpath, "/"); + strcat(subpath, dp->d_name); + + if (chmod(subpath, mode) < 0) { + fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno)); + exit(1); + } + + recurse_chmod(subpath, mode); + } + free(subpath); + closedir(dir); +} + +static int usage() +{ + fprintf(stderr, "Usage: chmod [OPTION] <MODE> <FILE>\n"); + fprintf(stderr, " -R, --recursive change files and directories recursively\n"); + fprintf(stderr, " --help display this help and exit\n"); + + return 10; +} + +int main(int argc, char **argv) +{ + int i; + + if (argc < 3 || strcmp(argv[1], "--help") == 0) { + return usage(); + } + + int recursive = (strcmp(argv[1], "-R") == 0 || + strcmp(argv[1], "--recursive") == 0) ? 1 : 0; + + if (recursive && argc < 4) { + return usage(); + } + + if (recursive) { + argc--; + argv++; + } + + int mode = 0; + const char* s = argv[1]; + while (*s) { + if (*s >= '0' && *s <= '7') { + mode = (mode<<3) | (*s-'0'); + } + else { + fprintf(stderr, "Bad mode\n"); + return 10; + } + s++; + } + + for (i = 2; i < argc; i++) { + if (chmod(argv[i], mode) < 0) { + fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno)); + return 10; + } + if (recursive) { + recurse_chmod(argv[i], mode); + } + } + return 0; +} + diff --git a/package/toolbox/src/src/chown.c b/package/toolbox/src/src/chown.c new file mode 100644 index 000000000..d02721718 --- /dev/null +++ b/package/toolbox/src/src/chown.c @@ -0,0 +1,73 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> + +#include <unistd.h> +#include <time.h> + +int main(int argc, char **argv) +{ + int i; + + if (argc < 3) { + fprintf(stderr, "Usage: chown <USER>[:GROUP] <FILE1> [FILE2] ...\n"); + return 10; + } + + // Copy argv[1] to 'user' so we can truncate it at the period + // if a group id specified. + char user[32]; + char *group = NULL; + strncpy(user, argv[1], sizeof(user)); + if ((group = strchr(user, ':')) != NULL) { + *group++ = '\0'; + } else if ((group = strchr(user, '.')) != NULL) { + *group++ = '\0'; + } + + // Lookup uid (and gid if specified) + struct passwd *pw; + struct group *grp = NULL; + uid_t uid; + gid_t gid = -1; // passing -1 to chown preserves current group + + pw = getpwnam(user); + if (pw != NULL) { + uid = pw->pw_uid; + } else { + char* endptr; + uid = (int) strtoul(user, &endptr, 0); + if (endptr == user) { // no conversion + fprintf(stderr, "No such user '%s'\n", user); + return 10; + } + } + + if (group != NULL) { + grp = getgrnam(group); + if (grp != NULL) { + gid = grp->gr_gid; + } else { + char* endptr; + gid = (int) strtoul(group, &endptr, 0); + if (endptr == group) { // no conversion + fprintf(stderr, "No such group '%s'\n", group); + return 10; + } + } + } + + for (i = 2; i < argc; i++) { + if (chown(argv[i], uid, gid) < 0) { + fprintf(stderr, "Unable to chown %s: %s\n", argv[i], strerror(errno)); + return 10; + } + } + + return 0; +} diff --git a/package/toolbox/src/src/clear.c b/package/toolbox/src/src/clear.c new file mode 100644 index 000000000..434ab4ace --- /dev/null +++ b/package/toolbox/src/src/clear.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> + +int main(int argc, char **argv) { + /* This prints the clear screen and move cursor to top-left corner control + * characters for VT100 terminals. This means it will not work on + * non-VT100 compliant terminals, namely Windows' cmd.exe, but should + * work on anything unix-y. */ + fputs("\x1b[2J\x1b[H", stdout); + return 0; +} diff --git a/package/toolbox/src/src/cmp.c b/package/toolbox/src/src/cmp.c new file mode 100644 index 000000000..79e56c41a --- /dev/null +++ b/package/toolbox/src/src/cmp.c @@ -0,0 +1,91 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <errno.h> + +int main(int argc, char *argv[]) +{ + int c; + int fd1, fd2; + char buf1[4096], buf2[4096]; + int res, res1, res2; + int rv = 0; + int i; + int filepos = 0; + + int show_byte = 0; + int show_all = 0; + int limit = 0; + + do { + c = getopt(argc, argv, "bln:"); + if (c == EOF) + break; + switch (c) { + case 'b': + show_byte = 1; + break; + case 'l': + show_all = 1; + break; + case 'n': + limit = atoi(optarg); + break; + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + argv[0], optopt); + exit(1); + } + } while (1); + + if (optind + 2 != argc) { + fprintf(stderr, "Usage: %s [-b] [-l] [-n count] file1 file2\n", argv[0]); + exit(1); + } + + fd1 = open(argv[optind], O_RDONLY); + if(fd1 < 0) { + fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno)); + return 1; + } + + fd2 = open(argv[optind+1], O_RDONLY); + if(fd2 < 0) { + fprintf(stderr, "could not open %s, %s\n", argv[optind+1], strerror(errno)); + return 1; + } + + while(1) { + res1 = read(fd1, &buf1, sizeof(buf1)); + res2 = read(fd2, &buf2, sizeof(buf2)); + res = res1 < res2 ? res1 : res2; + if(res1 == 0 && res2 == 0) { + return rv; + } + for(i = 0; i < res; i++) { + if(buf1[i] != buf2[i]) { + printf("%s %s differ byte %d", argv[optind], argv[optind+1], filepos + i); + if(show_byte) + printf(" 0x%02x 0x%02x", buf1[i], buf2[i]); + printf("\n"); + if(!show_all) + return 1; + rv = 1; + } + if(limit) { + limit--; + if(limit == 0) + return rv; + } + } + if(res1 != res2 || res < 0) { + printf("%s on %s\n", res < 0 ? "Read error" : "EOF", res1 < res2 ? argv[optind] : argv[optind+1]); + return 1; + } + filepos += res; + } +} diff --git a/package/toolbox/src/src/dd.c b/package/toolbox/src/src/dd.c new file mode 100644 index 000000000..605f18775 --- /dev/null +++ b/package/toolbox/src/src/dd.c @@ -0,0 +1,1323 @@ +/* $NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/time.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dd.h" + +//#define NO_CONV + +//#include "extern.h" +void block(void); +void block_close(void); +void dd_out(int); +void def(void); +void def_close(void); +void jcl(char **); +void pos_in(void); +void pos_out(void); +void summary(void); +void summaryx(int); +void terminate(int); +void unblock(void); +void unblock_close(void); +ssize_t bwrite(int, const void *, size_t); + +extern IO in, out; +extern STAT st; +extern void (*cfunc)(void); +extern uint64_t cpy_cnt; +extern uint64_t cbsz; +extern u_int ddflags; +extern u_int files_cnt; +extern int progress; +extern const u_char *ctab; + + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef DEFFILEMODE +#define DEFFILEMODE (S_IRUSR | S_IWUSR) +#endif + +static void dd_close(void); +static void dd_in(void); +static void getfdtype(IO *); +static int redup_clean_fd(int); +static void setup(void); + + +IO in, out; /* input/output state */ +STAT st; /* statistics */ +void (*cfunc)(void); /* conversion function */ +uint64_t cpy_cnt; /* # of blocks to copy */ +static off_t pending = 0; /* pending seek if sparse */ +u_int ddflags; /* conversion options */ +uint64_t cbsz; /* conversion block size */ +u_int files_cnt = 1; /* # of files to copy */ +int progress = 0; /* display sign of life */ +const u_char *ctab; /* conversion table */ +sigset_t infoset; /* a set blocking SIGINFO */ + +int +main(int argc, char *argv[]) +{ + int ch; + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + default: + fprintf(stderr, "usage: dd [operand ...]\n"); + exit(1); + /* NOTREACHED */ + } + } + argc -= (optind - 1); + argv += (optind - 1); + + jcl(argv); + setup(); + +// (void)signal(SIGINFO, summaryx); + (void)signal(SIGINT, terminate); + (void)sigemptyset(&infoset); +// (void)sigaddset(&infoset, SIGINFO); + + (void)atexit(summary); + + while (files_cnt--) + dd_in(); + + dd_close(); + exit(0); + /* NOTREACHED */ +} + +static void +setup(void) +{ + + if (in.name == NULL) { + in.name = "stdin"; + in.fd = STDIN_FILENO; + } else { + in.fd = open(in.name, O_RDONLY, 0); + if (in.fd < 0) { + fprintf(stderr, "%s: cannot open for read: %s\n", + in.name, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + + /* Ensure in.fd is outside the stdio descriptor range */ + in.fd = redup_clean_fd(in.fd); + } + + getfdtype(&in); + + if (files_cnt > 1 && !(in.flags & ISTAPE)) { + fprintf(stderr, + "files is not supported for non-tape devices\n"); + exit(1); + /* NOTREACHED */ + } + + if (out.name == NULL) { + /* No way to check for read access here. */ + out.fd = STDOUT_FILENO; + out.name = "stdout"; + } else { +#define OFLAGS \ + (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) + out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE); + /* + * May not have read access, so try again with write only. + * Without read we may have a problem if output also does + * not support seeks. + */ + if (out.fd < 0) { + out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE); + out.flags |= NOREAD; + } + if (out.fd < 0) { + fprintf(stderr, "%s: cannot open for write: %s\n", + out.name, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + + /* Ensure out.fd is outside the stdio descriptor range */ + out.fd = redup_clean_fd(out.fd); + } + + getfdtype(&out); + + /* + * Allocate space for the input and output buffers. If not doing + * record oriented I/O, only need a single buffer. + */ + if (!(ddflags & (C_BLOCK|C_UNBLOCK))) { + if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) { + exit(1); + /* NOTREACHED */ + } + out.db = in.db; + } else if ((in.db = + malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL || + (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) { + exit(1); + /* NOTREACHED */ + } + in.dbp = in.db; + out.dbp = out.db; + + /* Position the input/output streams. */ + if (in.offset) + pos_in(); + if (out.offset) + pos_out(); + + /* + * Truncate the output file; ignore errors because it fails on some + * kinds of output files, tapes, for example. + */ + if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK)) + (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz); + + (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */ +} + +static void +getfdtype(IO *io) +{ +// struct mtget mt; + struct stat sb; + + if (fstat(io->fd, &sb)) { + fprintf(stderr, "%s: cannot fstat: %s\n", + io->name, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + if (S_ISCHR(sb.st_mode)) + io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR; + else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) + io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */ +} + +/* + * Move the parameter file descriptor to a descriptor that is outside the + * stdio descriptor range, if necessary. This is required to avoid + * accidentally outputting completion or error messages into the + * output file that were intended for the tty. + */ +static int +redup_clean_fd(int fd) +{ + int newfd; + + if (fd != STDIN_FILENO && fd != STDOUT_FILENO && + fd != STDERR_FILENO) + /* File descriptor is ok, return immediately. */ + return fd; + + /* + * 3 is the first descriptor greater than STD*_FILENO. Any + * free descriptor valued 3 or above is acceptable... + */ + newfd = fcntl(fd, F_DUPFD, 3); + if (newfd < 0) { + fprintf(stderr, "dupfd IO: %s\n", strerror(errno)); + exit(1); + /* NOTREACHED */ + } + + close(fd); + + return newfd; +} + +static void +dd_in(void) +{ + int flags; + int64_t n; + + for (flags = ddflags;;) { + if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt) + return; + + /* + * Clear the buffer first if doing "sync" on input. + * If doing block operations use spaces. This will + * affect not only the C_NOERROR case, but also the + * last partial input block which should be padded + * with zero and not garbage. + */ + if (flags & C_SYNC) { + if (flags & (C_BLOCK|C_UNBLOCK)) + (void)memset(in.dbp, ' ', in.dbsz); + else + (void)memset(in.dbp, 0, in.dbsz); + } + + n = read(in.fd, in.dbp, in.dbsz); + if (n == 0) { + in.dbrcnt = 0; + return; + } + + /* Read error. */ + if (n < 0) { + + /* + * If noerror not specified, die. POSIX requires that + * the warning message be followed by an I/O display. + */ + fprintf(stderr, "%s: read error: %s\n", + in.name, strerror(errno)); + if (!(flags & C_NOERROR)) { + exit(1); + /* NOTREACHED */ + } + summary(); + + /* + * If it's not a tape drive or a pipe, seek past the + * error. If your OS doesn't do the right thing for + * raw disks this section should be modified to re-read + * in sector size chunks. + */ + if (!(in.flags & (ISPIPE|ISTAPE)) && + lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) + fprintf(stderr, "%s: seek error: %s\n", + in.name, strerror(errno)); + + /* If sync not specified, omit block and continue. */ + if (!(ddflags & C_SYNC)) + continue; + + /* Read errors count as full blocks. */ + in.dbcnt += in.dbrcnt = in.dbsz; + ++st.in_full; + + /* Handle full input blocks. */ + } else if (n == in.dbsz) { + in.dbcnt += in.dbrcnt = n; + ++st.in_full; + + /* Handle partial input blocks. */ + } else { + /* If sync, use the entire block. */ + if (ddflags & C_SYNC) + in.dbcnt += in.dbrcnt = in.dbsz; + else + in.dbcnt += in.dbrcnt = n; + ++st.in_part; + } + + /* + * POSIX states that if bs is set and no other conversions + * than noerror, notrunc or sync are specified, the block + * is output without buffering as it is read. + */ + if (ddflags & C_BS) { + out.dbcnt = in.dbcnt; + dd_out(1); + in.dbcnt = 0; + continue; + } + +/* if (ddflags & C_SWAB) { + if ((n = in.dbrcnt) & 1) { + ++st.swab; + --n; + } + swab(in.dbp, in.dbp, n); + } +*/ + in.dbp += in.dbrcnt; + (*cfunc)(); + } +} + +/* + * Cleanup any remaining I/O and flush output. If necesssary, output file + * is truncated. + */ +static void +dd_close(void) +{ + + if (cfunc == def) + def_close(); + else if (cfunc == block) + block_close(); + else if (cfunc == unblock) + unblock_close(); + if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) { + (void)memset(out.dbp, 0, out.dbsz - out.dbcnt); + out.dbcnt = out.dbsz; + } + /* If there are pending sparse blocks, make sure + * to write out the final block un-sparse + */ + if ((out.dbcnt == 0) && pending) { + memset(out.db, 0, out.dbsz); + out.dbcnt = out.dbsz; + out.dbp = out.db + out.dbcnt; + pending -= out.dbsz; + } + if (out.dbcnt) + dd_out(1); + + /* + * Reporting nfs write error may be defered until next + * write(2) or close(2) system call. So, we need to do an + * extra check. If an output is stdout, the file structure + * may be shared among with other processes and close(2) just + * decreases the reference count. + */ + if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) { + fprintf(stderr, "fsync stdout: %s\n", strerror(errno)); + exit(1); + /* NOTREACHED */ + } + if (close(out.fd) == -1) { + fprintf(stderr, "close: %s\n", strerror(errno)); + exit(1); + /* NOTREACHED */ + } +} + +void +dd_out(int force) +{ + static int warned; + int64_t cnt, n, nw; + u_char *outp; + + /* + * Write one or more blocks out. The common case is writing a full + * output block in a single write; increment the full block stats. + * Otherwise, we're into partial block writes. If a partial write, + * and it's a character device, just warn. If a tape device, quit. + * + * The partial writes represent two cases. 1: Where the input block + * was less than expected so the output block was less than expected. + * 2: Where the input block was the right size but we were forced to + * write the block in multiple chunks. The original versions of dd(1) + * never wrote a block in more than a single write, so the latter case + * never happened. + * + * One special case is if we're forced to do the write -- in that case + * we play games with the buffer size, and it's usually a partial write. + */ + outp = out.db; + for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { + for (cnt = n;; cnt -= nw) { + + if (!force && ddflags & C_SPARSE) { + int sparse, i; + sparse = 1; /* Is buffer sparse? */ + for (i = 0; i < cnt; i++) + if (outp[i] != 0) { + sparse = 0; + break; + } + if (sparse) { + pending += cnt; + outp += cnt; + nw = 0; + break; + } + } + if (pending != 0) { + if (lseek(out.fd, pending, SEEK_CUR) == + -1) { + fprintf(stderr, + "%s: seek error creating " + "sparse file: %s\n", + out.name, strerror(errno)); + exit(1); + } + } + nw = bwrite(out.fd, outp, cnt); + if (nw <= 0) { + if (nw == 0) { + fprintf(stderr, "%s: end of device\n", + out.name); + exit(1); + /* NOTREACHED */ + } + if (errno != EINTR) { + fprintf(stderr, "%s: write error: %s\n", + out.name, strerror(errno)); + /* NOTREACHED */ + exit(1); + } + nw = 0; + } + if (pending) { + st.bytes += pending; + st.sparse += pending/out.dbsz; + st.out_full += pending/out.dbsz; + pending = 0; + } + outp += nw; + st.bytes += nw; + if (nw == n) { + if (n != out.dbsz) + ++st.out_part; + else + ++st.out_full; + break; + } + ++st.out_part; + if (nw == cnt) + break; + if (out.flags & ISCHR && !warned) { + warned = 1; + fprintf(stderr, "%s: short write on character " + "device\n", out.name); + } + if (out.flags & ISTAPE) { + fprintf(stderr, + "%s: short write on tape device", + out.name); + exit(1); + /* NOTREACHED */ + } + } + if ((out.dbcnt -= n) < out.dbsz) + break; + } + + /* Reassemble the output block. */ + if (out.dbcnt) + (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); + out.dbp = out.db + out.dbcnt; + + if (progress) + (void)write(STDERR_FILENO, ".", 1); +} + +/* + * A protected against SIGINFO write + */ +ssize_t +bwrite(int fd, const void *buf, size_t len) +{ + sigset_t oset; + ssize_t rv; + int oerrno; + + (void)sigprocmask(SIG_BLOCK, &infoset, &oset); + rv = write(fd, buf, len); + oerrno = errno; + (void)sigprocmask(SIG_SETMASK, &oset, NULL); + errno = oerrno; + return (rv); +} + +/* + * Position input/output data streams before starting the copy. Device type + * dependent. Seekable devices use lseek, and the rest position by reading. + * Seeking past the end of file can cause null blocks to be written to the + * output. + */ +void +pos_in(void) +{ + int bcnt, cnt, nr, warned; + + /* If not a pipe or tape device, try to seek on it. */ + if (!(in.flags & (ISPIPE|ISTAPE))) { + if (lseek64(in.fd, + (off64_t)in.offset * (off64_t)in.dbsz, SEEK_CUR) == -1) { + fprintf(stderr, "%s: seek error: %s", + in.name, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + return; + /* NOTREACHED */ + } + + /* + * Read the data. If a pipe, read until satisfy the number of bytes + * being skipped. No differentiation for reading complete and partial + * blocks for other devices. + */ + for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { + if ((nr = read(in.fd, in.db, bcnt)) > 0) { + if (in.flags & ISPIPE) { + if (!(bcnt -= nr)) { + bcnt = in.dbsz; + --cnt; + } + } else + --cnt; + continue; + } + + if (nr == 0) { + if (files_cnt > 1) { + --files_cnt; + continue; + } + fprintf(stderr, "skip reached end of input\n"); + exit(1); + /* NOTREACHED */ + } + + /* + * Input error -- either EOF with no more files, or I/O error. + * If noerror not set die. POSIX requires that the warning + * message be followed by an I/O display. + */ + if (ddflags & C_NOERROR) { + if (!warned) { + + fprintf(stderr, "%s: error occurred\n", + in.name); + warned = 1; + summary(); + } + continue; + } + fprintf(stderr, "%s: read error: %s", in.name, strerror(errno)); + exit(1); + /* NOTREACHED */ + } +} + +void +pos_out(void) +{ +// struct mtop t_op; + int cnt, n; + + /* + * If not a tape, try seeking on the file. Seeking on a pipe is + * going to fail, but don't protect the user -- they shouldn't + * have specified the seek operand. + */ + if (!(out.flags & ISTAPE)) { + if (lseek64(out.fd, + (off64_t)out.offset * (off64_t)out.dbsz, SEEK_SET) == -1) { + fprintf(stderr, "%s: seek error: %s\n", + out.name, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + return; + } + + /* If no read access, try using mtio. */ + if (out.flags & NOREAD) { +/* t_op.mt_op = MTFSR; + t_op.mt_count = out.offset; + + if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/ + fprintf(stderr, "%s: cannot read", out.name); + exit(1); + /* NOTREACHED */ + return; + } + + /* Read it. */ + for (cnt = 0; cnt < out.offset; ++cnt) { + if ((n = read(out.fd, out.db, out.dbsz)) > 0) + continue; + + if (n < 0) { + fprintf(stderr, "%s: cannot position by reading: %s\n", + out.name, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + + /* + * If reach EOF, fill with NUL characters; first, back up over + * the EOF mark. Note, cnt has not yet been incremented, so + * the EOF read does not count as a seek'd block. + */ +/* t_op.mt_op = MTBSR; + t_op.mt_count = 1; + if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ { + fprintf(stderr, "%s: cannot position\n", out.name); + exit(1); + /* NOTREACHED */ + } + + while (cnt++ < out.offset) + if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) { + fprintf(stderr, "%s: cannot position " + "by writing: %s\n", + out.name, strerror(errno)); + exit(1); + /* NOTREACHED */ + } + break; + } +} + +/* + * def -- + * Copy input to output. Input is buffered until reaches obs, and then + * output until less than obs remains. Only a single buffer is used. + * Worst case buffer calculation is (ibs + obs - 1). + */ +void +def(void) +{ + uint64_t cnt; + u_char *inp; + const u_char *t; + + if ((t = ctab) != NULL) + for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) + *inp = t[*inp]; + + /* Make the output buffer look right. */ + out.dbp = in.dbp; + out.dbcnt = in.dbcnt; + + if (in.dbcnt >= out.dbsz) { + /* If the output buffer is full, write it. */ + dd_out(0); + + /* + * Ddout copies the leftover output to the beginning of + * the buffer and resets the output buffer. Reset the + * input buffer to match it. + */ + in.dbp = out.dbp; + in.dbcnt = out.dbcnt; + } +} + +void +def_close(void) +{ + if (ddflags & C_FDATASYNC) { + fdatasync(out.fd); + } + + /* Just update the count, everything is already in the buffer. */ + if (in.dbcnt) + out.dbcnt = in.dbcnt; +} + +#ifdef NO_CONV +/* Build a smaller version (i.e. for a miniroot) */ +/* These can not be called, but just in case... */ +static const char no_block[] = "unblock and -DNO_CONV?\n"; +void block(void) { fprintf(stderr, "%s", no_block + 2); exit(1); } +void block_close(void) { fprintf(stderr, "%s", no_block + 2); exit(1); } +void unblock(void) { fprintf(stderr, "%s", no_block); exit(1); } +void unblock_close(void) { fprintf(stderr, "%s", no_block); exit(1); } +#else /* NO_CONV */ + +/* + * Copy variable length newline terminated records with a max size cbsz + * bytes to output. Records less than cbs are padded with spaces. + * + * max in buffer: MAX(ibs, cbsz) + * max out buffer: obs + cbsz + */ +void +block(void) +{ + static int intrunc; + int ch = 0; /* pacify gcc */ + uint64_t cnt, maxlen; + u_char *inp, *outp; + const u_char *t; + + /* + * Record truncation can cross block boundaries. If currently in a + * truncation state, keep tossing characters until reach a newline. + * Start at the beginning of the buffer, as the input buffer is always + * left empty. + */ + if (intrunc) { + for (inp = in.db, cnt = in.dbrcnt; + cnt && *inp++ != '\n'; --cnt); + if (!cnt) { + in.dbcnt = 0; + in.dbp = in.db; + return; + } + intrunc = 0; + /* Adjust the input buffer numbers. */ + in.dbcnt = cnt - 1; + in.dbp = inp + cnt - 1; + } + + /* + * Copy records (max cbsz size chunks) into the output buffer. The + * translation is done as we copy into the output buffer. + */ + for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { + maxlen = MIN(cbsz, in.dbcnt); + if ((t = ctab) != NULL) + for (cnt = 0; + cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) + *outp++ = t[ch]; + else + for (cnt = 0; + cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) + *outp++ = ch; + /* + * Check for short record without a newline. Reassemble the + * input block. + */ + if (ch != '\n' && in.dbcnt < cbsz) { + (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); + break; + } + + /* Adjust the input buffer numbers. */ + in.dbcnt -= cnt; + if (ch == '\n') + --in.dbcnt; + + /* Pad short records with spaces. */ + if (cnt < cbsz) + (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); + else { + /* + * If the next character wouldn't have ended the + * block, it's a truncation. + */ + if (!in.dbcnt || *inp != '\n') + ++st.trunc; + + /* Toss characters to a newline. */ + for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt); + if (!in.dbcnt) + intrunc = 1; + else + --in.dbcnt; + } + + /* Adjust output buffer numbers. */ + out.dbp += cbsz; + if ((out.dbcnt += cbsz) >= out.dbsz) + dd_out(0); + outp = out.dbp; + } + in.dbp = in.db + in.dbcnt; +} + +void +block_close(void) +{ + + /* + * Copy any remaining data into the output buffer and pad to a record. + * Don't worry about truncation or translation, the input buffer is + * always empty when truncating, and no characters have been added for + * translation. The bottom line is that anything left in the input + * buffer is a truncated record. Anything left in the output buffer + * just wasn't big enough. + */ + if (in.dbcnt) { + ++st.trunc; + (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); + (void)memset(out.dbp + in.dbcnt, + ctab ? ctab[' '] : ' ', cbsz - in.dbcnt); + out.dbcnt += cbsz; + } +} + +/* + * Convert fixed length (cbsz) records to variable length. Deletes any + * trailing blanks and appends a newline. + * + * max in buffer: MAX(ibs, cbsz) + cbsz + * max out buffer: obs + cbsz + */ +void +unblock(void) +{ + uint64_t cnt; + u_char *inp; + const u_char *t; + + /* Translation and case conversion. */ + if ((t = ctab) != NULL) + for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--) + *inp = t[*inp]; + /* + * Copy records (max cbsz size chunks) into the output buffer. The + * translation has to already be done or we might not recognize the + * spaces. + */ + for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { + for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t); + if (t >= inp) { + cnt = t - inp + 1; + (void)memmove(out.dbp, inp, cnt); + out.dbp += cnt; + out.dbcnt += cnt; + } + ++out.dbcnt; + *out.dbp++ = '\n'; + if (out.dbcnt >= out.dbsz) + dd_out(0); + } + if (in.dbcnt) + (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); + in.dbp = in.db + in.dbcnt; +} + +void +unblock_close(void) +{ + uint64_t cnt; + u_char *t; + + if (in.dbcnt) { + warnx("%s: short input record", in.name); + for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t); + if (t >= in.db) { + cnt = t - in.db + 1; + (void)memmove(out.dbp, in.db, cnt); + out.dbp += cnt; + out.dbcnt += cnt; + } + ++out.dbcnt; + *out.dbp++ = '\n'; + } +} + +#endif /* NO_CONV */ + +#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000) + +void +summary(void) +{ + char buf[100]; + int64_t mS; + struct timeval tv; + + if (progress) + (void)write(STDERR_FILENO, "\n", 1); + + (void)gettimeofday(&tv, NULL); + mS = tv2mS(tv) - tv2mS(st.start); + if (mS == 0) + mS = 1; + /* Use snprintf(3) so that we don't reenter stdio(3). */ + (void)snprintf(buf, sizeof(buf), + "%llu+%llu records in\n%llu+%llu records out\n", + (unsigned long long)st.in_full, (unsigned long long)st.in_part, + (unsigned long long)st.out_full, (unsigned long long)st.out_part); + (void)write(STDERR_FILENO, buf, strlen(buf)); + if (st.swab) { + (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n", + (unsigned long long)st.swab, + (st.swab == 1) ? "block" : "blocks"); + (void)write(STDERR_FILENO, buf, strlen(buf)); + } + if (st.trunc) { + (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n", + (unsigned long long)st.trunc, + (st.trunc == 1) ? "block" : "blocks"); + (void)write(STDERR_FILENO, buf, strlen(buf)); + } + if (st.sparse) { + (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n", + (unsigned long long)st.sparse, + (st.sparse == 1) ? "block" : "blocks"); + (void)write(STDERR_FILENO, buf, strlen(buf)); + } + (void)snprintf(buf, sizeof(buf), + "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n", + (unsigned long long) st.bytes, + (long) (mS / 1000), + (int) (mS % 1000), + (unsigned long long) (st.bytes * 1000LL / mS)); + (void)write(STDERR_FILENO, buf, strlen(buf)); +} + +void +terminate(int notused) +{ + + exit(0); + /* NOTREACHED */ +} + +static int c_arg(const void *, const void *); +#ifndef NO_CONV +static int c_conv(const void *, const void *); +#endif +static void f_bs(char *); +static void f_cbs(char *); +static void f_conv(char *); +static void f_count(char *); +static void f_files(char *); +static void f_ibs(char *); +static void f_if(char *); +static void f_obs(char *); +static void f_of(char *); +static void f_seek(char *); +static void f_skip(char *); +static void f_progress(char *); + +static const struct arg { + const char *name; + void (*f)(char *); + u_int set, noset; +} args[] = { + /* the array needs to be sorted by the first column so + bsearch() can be used to find commands quickly */ + { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, + { "cbs", f_cbs, C_CBS, C_CBS }, + { "conv", f_conv, 0, 0 }, + { "count", f_count, C_COUNT, C_COUNT }, + { "files", f_files, C_FILES, C_FILES }, + { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, + { "if", f_if, C_IF, C_IF }, + { "obs", f_obs, C_OBS, C_BS|C_OBS }, + { "of", f_of, C_OF, C_OF }, + { "progress", f_progress, 0, 0 }, + { "seek", f_seek, C_SEEK, C_SEEK }, + { "skip", f_skip, C_SKIP, C_SKIP }, +}; + +/* + * args -- parse JCL syntax of dd. + */ +void +jcl(char **argv) +{ + struct arg *ap, tmp; + char *oper, *arg; + + in.dbsz = out.dbsz = 512; + + while ((oper = *++argv) != NULL) { + if ((arg = strchr(oper, '=')) == NULL) { + fprintf(stderr, "unknown operand %s\n", oper); + exit(1); + /* NOTREACHED */ + } + *arg++ = '\0'; + if (!*arg) { + fprintf(stderr, "no value specified for %s\n", oper); + exit(1); + /* NOTREACHED */ + } + tmp.name = oper; + if (!(ap = (struct arg *)bsearch(&tmp, args, + sizeof(args)/sizeof(struct arg), sizeof(struct arg), + c_arg))) { + fprintf(stderr, "unknown operand %s\n", tmp.name); + exit(1); + /* NOTREACHED */ + } + if (ddflags & ap->noset) { + fprintf(stderr, + "%s: illegal argument combination or already set\n", + tmp.name); + exit(1); + /* NOTREACHED */ + } + ddflags |= ap->set; + ap->f(arg); + } + + /* Final sanity checks. */ + + if (ddflags & C_BS) { + /* + * Bs is turned off by any conversion -- we assume the user + * just wanted to set both the input and output block sizes + * and didn't want the bs semantics, so we don't warn. + */ + if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | + C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) { + ddflags &= ~C_BS; + ddflags |= C_IBS|C_OBS; + } + + /* Bs supersedes ibs and obs. */ + if (ddflags & C_BS && ddflags & (C_IBS|C_OBS)) + fprintf(stderr, "bs supersedes ibs and obs\n"); + } + + /* + * Ascii/ebcdic and cbs implies block/unblock. + * Block/unblock requires cbs and vice-versa. + */ + if (ddflags & (C_BLOCK|C_UNBLOCK)) { + if (!(ddflags & C_CBS)) { + fprintf(stderr, "record operations require cbs\n"); + exit(1); + /* NOTREACHED */ + } + cfunc = ddflags & C_BLOCK ? block : unblock; + } else if (ddflags & C_CBS) { + if (ddflags & (C_ASCII|C_EBCDIC)) { + if (ddflags & C_ASCII) { + ddflags |= C_UNBLOCK; + cfunc = unblock; + } else { + ddflags |= C_BLOCK; + cfunc = block; + } + } else { + fprintf(stderr, + "cbs meaningless if not doing record operations\n"); + exit(1); + /* NOTREACHED */ + } + } else + cfunc = def; + + /* Read, write and seek calls take off_t as arguments. + * + * The following check is not done because an off_t is a quad + * for current NetBSD implementations. + * + * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz) + * errx(1, "seek offsets cannot be larger than %d", INT_MAX); + */ +} + +static int +c_arg(const void *a, const void *b) +{ + + return (strcmp(((const struct arg *)a)->name, + ((const struct arg *)b)->name)); +} + +static long long strsuftoll(const char* name, const char* arg, int def, unsigned long long max) +{ + long long result; + + if (sscanf(arg, "%lld", &result) == 0) + result = def; + return result; +} + +static void +f_bs(char *arg) +{ + + in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX); +} + +static void +f_cbs(char *arg) +{ + + cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX); +} + +static void +f_count(char *arg) +{ + + cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX); + if (!cpy_cnt) + terminate(0); +} + +static void +f_files(char *arg) +{ + + files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX); + if (!files_cnt) + terminate(0); +} + +static void +f_ibs(char *arg) +{ + + if (!(ddflags & C_BS)) + in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX); +} + +static void +f_if(char *arg) +{ + + in.name = arg; +} + +static void +f_obs(char *arg) +{ + + if (!(ddflags & C_BS)) + out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX); +} + +static void +f_of(char *arg) +{ + + out.name = arg; +} + +static void +f_seek(char *arg) +{ + + out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX); +} + +static void +f_skip(char *arg) +{ + + in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX); +} + +static void +f_progress(char *arg) +{ + + if (*arg != '0') + progress = 1; +} + +#ifdef NO_CONV +/* Build a small version (i.e. for a ramdisk root) */ +static void +f_conv(char *arg) +{ + + fprintf(stderr, "conv option disabled\n"); + exit(1); + /* NOTREACHED */ +} +#else /* NO_CONV */ + +static const struct conv { + const char *name; + u_int set, noset; + const u_char *ctab; +} clist[] = { + { "block", C_BLOCK, C_UNBLOCK, NULL }, + { "fdatasync", C_FDATASYNC, 0, NULL }, + { "noerror", C_NOERROR, 0, NULL }, + { "notrunc", C_NOTRUNC, 0, NULL }, + { "osync", C_OSYNC, C_BS, NULL }, + { "sparse", C_SPARSE, 0, NULL }, + { "swab", C_SWAB, 0, NULL }, + { "sync", C_SYNC, 0, NULL }, + { "unblock", C_UNBLOCK, C_BLOCK, NULL }, + /* If you add items to this table, be sure to add the + * conversions to the C_BS check in the jcl routine above. + */ +}; + +static void +f_conv(char *arg) +{ + struct conv *cp, tmp; + + while (arg != NULL) { + tmp.name = strsep(&arg, ","); + if (!(cp = (struct conv *)bsearch(&tmp, clist, + sizeof(clist)/sizeof(struct conv), sizeof(struct conv), + c_conv))) { + errx(EXIT_FAILURE, "unknown conversion %s", tmp.name); + /* NOTREACHED */ + } + if (ddflags & cp->noset) { + errx(EXIT_FAILURE, "%s: illegal conversion combination", tmp.name); + /* NOTREACHED */ + } + ddflags |= cp->set; + if (cp->ctab) + ctab = cp->ctab; + } +} + +static int +c_conv(const void *a, const void *b) +{ + + return (strcmp(((const struct conv *)a)->name, + ((const struct conv *)b)->name)); +} + +#endif /* NO_CONV */ + + diff --git a/package/toolbox/src/src/dd.h b/package/toolbox/src/src/dd.h new file mode 100644 index 000000000..89f28332c --- /dev/null +++ b/package/toolbox/src/src/dd.h @@ -0,0 +1,94 @@ +/* $NetBSD: dd.h,v 1.12 2004/01/17 20:48:57 dbj Exp $ */ + +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dd.h 8.3 (Berkeley) 4/2/94 + */ + +#include <stdint.h> + +/* Input/output stream state. */ +typedef struct { + u_char *db; /* buffer address */ + u_char *dbp; /* current buffer I/O address */ + uint64_t dbcnt; /* current buffer byte count */ + int64_t dbrcnt; /* last read byte count */ + uint64_t dbsz; /* buffer size */ + +#define ISCHR 0x01 /* character device (warn on short) */ +#define ISPIPE 0x02 /* pipe (not truncatable) */ +#define ISTAPE 0x04 /* tape (not seekable) */ +#define NOREAD 0x08 /* not readable */ + u_int flags; + + const char *name; /* name */ + int fd; /* file descriptor */ + uint64_t offset; /* # of blocks to skip */ +} IO; + +typedef struct { + uint64_t in_full; /* # of full input blocks */ + uint64_t in_part; /* # of partial input blocks */ + uint64_t out_full; /* # of full output blocks */ + uint64_t out_part; /* # of partial output blocks */ + uint64_t trunc; /* # of truncated records */ + uint64_t swab; /* # of odd-length swab blocks */ + uint64_t sparse; /* # of sparse output blocks */ + uint64_t bytes; /* # of bytes written */ + struct timeval start; /* start time of dd */ +} STAT; + +/* Flags (in ddflags). */ +#define C_ASCII 0x00001 +#define C_BLOCK 0x00002 +#define C_BS 0x00004 +#define C_CBS 0x00008 +#define C_COUNT 0x00010 +#define C_EBCDIC 0x00020 +#define C_FILES 0x00040 +#define C_IBS 0x00080 +#define C_IF 0x00100 +#define C_LCASE 0x00200 +#define C_NOERROR 0x00400 +#define C_NOTRUNC 0x00800 +#define C_OBS 0x01000 +#define C_OF 0x02000 +#define C_SEEK 0x04000 +#define C_SKIP 0x08000 +#define C_SWAB 0x10000 +#define C_SYNC 0x20000 +#define C_UCASE 0x40000 +#define C_UNBLOCK 0x80000 +#define C_OSYNC 0x100000 +#define C_SPARSE 0x200000 +#define C_FDATASYNC 0x400000 diff --git a/package/toolbox/src/src/df.c b/package/toolbox/src/src/df.c new file mode 100644 index 000000000..8cff0c8c2 --- /dev/null +++ b/package/toolbox/src/src/df.c @@ -0,0 +1,85 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/statfs.h> + +static int ok = EXIT_SUCCESS; + +static void printsize(long long n) +{ + char unit = 'K'; + long long t; + + n *= 10; + + if (n > 1024*1024*10) { + n /= 1024; + unit = 'M'; + } + + if (n > 1024*1024*10) { + n /= 1024; + unit = 'G'; + } + + t = (n + 512) / 1024; + printf("%4lld.%1lld%c", t/10, t%10, unit); +} + +static void df(char *s, int always) { + struct statfs st; + + if (statfs(s, &st) < 0) { + fprintf(stderr, "%s: %s\n", s, strerror(errno)); + ok = EXIT_FAILURE; + } else { + if (st.f_blocks == 0 && !always) + return; + printf("%-20s ", s); + printsize((long long)st.f_blocks * (long long)st.f_bsize); + printf(" "); + printsize((long long)(st.f_blocks - (long long)st.f_bfree) * st.f_bsize); + printf(" "); + printsize((long long)st.f_bfree * (long long)st.f_bsize); + printf(" %d\n", (int) st.f_bsize); + } +} + +int main(int argc, char *argv[]) { + printf("Filesystem Size Used Free Blksize\n"); + if (argc == 1) { + char s[2000]; + FILE *f = fopen("/proc/mounts", "r"); + + while (fgets(s, 2000, f)) { + char *c, *e = s; + + for (c = s; *c; c++) { + if (*c == ' ') { + e = c + 1; + break; + } + } + + for (c = e; *c; c++) { + if (*c == ' ') { + *c = '\0'; + break; + } + } + + df(e, 0); + } + + fclose(f); + } else { + int i; + + for (i = 1; i < argc; i++) { + df(argv[i], 1); + } + } + + exit(ok); +} diff --git a/package/toolbox/src/src/dmesg.c b/package/toolbox/src/src/dmesg.c new file mode 100644 index 000000000..9fac63287 --- /dev/null +++ b/package/toolbox/src/src/dmesg.c @@ -0,0 +1,64 @@ +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <sys/klog.h> +#include <string.h> + +#define FALLBACK_KLOG_BUF_SHIFT 17 /* CONFIG_LOG_BUF_SHIFT from our kernel */ +#define FALLBACK_KLOG_BUF_LEN (1 << FALLBACK_KLOG_BUF_SHIFT) + +#ifndef KLOG_SIZE_BUFFER +#define KLOG_READ_ALL 3 +#define KLOG_READ_CLEAR 4 +#define KLOG_SIZE_BUFFER 10 +#endif + +int main(int argc, char **argv) +{ + char *buffer; + char *p; + ssize_t ret; + int n, op, klog_buf_len; + + klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0); + + if (klog_buf_len <= 0) { + klog_buf_len = FALLBACK_KLOG_BUF_LEN; + } + + buffer = (char *)malloc(klog_buf_len + 1); + + if (!buffer) { + perror("malloc"); + return EXIT_FAILURE; + } + + p = buffer; + + if((argc == 2) && (!strcmp(argv[1],"-c"))) { + op = KLOG_READ_CLEAR; + } else { + op = KLOG_READ_ALL; + } + + n = klogctl(op, buffer, klog_buf_len); + if (n < 0) { + perror("klogctl"); + return EXIT_FAILURE; + } + buffer[n] = '\0'; + + while((ret = write(STDOUT_FILENO, p, n))) { + if (ret == -1) { + if (errno == EINTR) + continue; + perror("write"); + return EXIT_FAILURE; + } + p += ret; + n -= ret; + } + + return 0; +} diff --git a/package/toolbox/src/src/du.c b/package/toolbox/src/src/du.c new file mode 100644 index 000000000..8fd6b3644 --- /dev/null +++ b/package/toolbox/src/src/du.c @@ -0,0 +1,322 @@ +/* $NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Newcomb. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <err.h> +#include <errno.h> +#include <fts.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> + +int linkchk(dev_t, ino_t); +void prstat(const char *, int64_t); +static void usage(void); + +long blocksize; + +#define howmany(x, y) (((x)+((y)-1))/(y)) + +int +main(int argc, char *argv[]) +{ + FTS *fts; + FTSENT *p; + int64_t totalblocks; + int ftsoptions, listfiles; + int depth; + int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, rval, sflag; + char *noargv[2]; + + Hflag = Lflag = aflag = cflag = dflag = gkmflag = sflag = 0; + totalblocks = 0; + ftsoptions = FTS_PHYSICAL; + depth = INT_MAX; + while ((ch = getopt(argc, argv, "HLPacd:ghkmnrsx")) != -1) + switch (ch) { + case 'H': + Hflag = 1; + Lflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = 0; + break; + case 'P': + Hflag = Lflag = 0; + break; + case 'a': + aflag = 1; + break; + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + depth = atoi(optarg); + if (depth < 0 || depth > SHRT_MAX) { + warnx("invalid argument to option d: %s", + optarg); + usage(); + } + break; + case 'g': + blocksize = 1024 * 1024 * 1024; + gkmflag = 1; + break; + case 'k': + blocksize = 1024; + gkmflag = 1; + break; + case 'm': + blocksize = 1024 * 1024; + gkmflag = 1; + break; + case 'r': + break; + case 's': + sflag = 1; + break; + case 'x': + ftsoptions |= FTS_XDEV; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* + * XXX + * Because of the way that fts(3) works, logical walks will not count + * the blocks actually used by symbolic links. We rationalize this by + * noting that users computing logical sizes are likely to do logical + * copies, so not counting the links is correct. The real reason is + * that we'd have to re-implement the kernel's symbolic link traversing + * algorithm to get this right. If, for example, you have relative + * symbolic links referencing other relative symbolic links, it gets + * very nasty, very fast. The bottom line is that it's documented in + * the man page, so it's a feature. + */ + if (Hflag) + ftsoptions |= FTS_COMFOLLOW; + if (Lflag) { + ftsoptions &= ~FTS_PHYSICAL; + ftsoptions |= FTS_LOGICAL; + } + + listfiles = 0; + if (aflag) { + if (sflag || dflag) + usage(); + listfiles = 1; + } else if (sflag) { + if (dflag) + usage(); + depth = 0; + } + + if (!*argv) { + noargv[0] = strdup("."); + noargv[1] = NULL; + argv = noargv; + } + + if (!gkmflag) + blocksize = 512; + blocksize /= 512; + + if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) + err(1, "fts_open `%s'", *argv); + + for (rval = 0; (p = fts_read(fts)) != NULL;) { + switch (p->fts_info) { + case FTS_D: /* Ignore. */ + break; + case FTS_DP: + p->fts_parent->fts_number += + p->fts_number += p->fts_statp->st_blocks; + if (cflag) + totalblocks += p->fts_statp->st_blocks; + /* + * If listing each directory, or not listing files + * or directories and this is post-order of the + * root of a traversal, display the total. + */ + if (p->fts_level <= depth + || (!listfiles && !p->fts_level)) + prstat(p->fts_path, p->fts_number); + break; + case FTS_DC: /* Ignore. */ + break; + case FTS_DNR: /* Warn, continue. */ + case FTS_ERR: + case FTS_NS: + warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); + rval = 1; + break; + default: + if (p->fts_statp->st_nlink > 1 && + linkchk(p->fts_statp->st_dev, p->fts_statp->st_ino)) + break; + /* + * If listing each file, or a non-directory file was + * the root of a traversal, display the total. + */ + if (listfiles || !p->fts_level) + prstat(p->fts_path, p->fts_statp->st_blocks); + p->fts_parent->fts_number += p->fts_statp->st_blocks; + if (cflag) + totalblocks += p->fts_statp->st_blocks; + } + } + if (errno) + err(1, "fts_read"); + if (cflag) + prstat("total", totalblocks); + exit(rval); +} + +void +prstat(const char *fname, int64_t blocks) +{ + (void)printf("%lld\t%s\n", + (long long)howmany(blocks, (int64_t)blocksize), + fname); +} + +int +linkchk(dev_t dev, ino_t ino) +{ + static struct entry { + dev_t dev; + ino_t ino; + } *htable; + static int htshift; /* log(allocated size) */ + static int htmask; /* allocated size - 1 */ + static int htused; /* 2*number of insertions */ + static int sawzero; /* Whether zero is in table or not */ + int h, h2; + uint64_t tmp; + /* this constant is (1<<64)/((1+sqrt(5))/2) + * aka (word size)/(golden ratio) + */ + const uint64_t HTCONST = 11400714819323198485ULL; + const int HTBITS = CHAR_BIT * sizeof(tmp); + + /* Never store zero in hashtable */ + if (dev == 0 && ino == 0) { + h = sawzero; + sawzero = 1; + return h; + } + + /* Extend hash table if necessary, keep load under 0.5 */ + if (htused<<1 >= htmask) { + struct entry *ohtable; + + if (!htable) + htshift = 10; /* starting hashtable size */ + else + htshift++; /* exponential hashtable growth */ + + htmask = (1 << htshift) - 1; + htused = 0; + + ohtable = htable; + htable = calloc(htmask+1, sizeof(*htable)); + if (!htable) + err(1, "calloc"); + + /* populate newly allocated hashtable */ + if (ohtable) { + int i; + for (i = 0; i <= htmask>>1; i++) + if (ohtable[i].ino || ohtable[i].dev) + linkchk(ohtable[i].dev, ohtable[i].ino); + free(ohtable); + } + } + + /* multiplicative hashing */ + tmp = dev; + tmp <<= HTBITS>>1; + tmp |= ino; + tmp *= HTCONST; + h = tmp >> (HTBITS - htshift); + h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */ + + /* open address hashtable search with double hash probing */ + while (htable[h].ino || htable[h].dev) { + if ((htable[h].ino == ino) && (htable[h].dev == dev)) + return 1; + h = (h + h2) & htmask; + } + + /* Insert the current entry into hashtable */ + htable[h].dev = dev; + htable[h].ino = ino; + htused++; + return 0; +} + +static void +usage(void) +{ + + (void)fprintf(stderr, + "usage: du [-H | -L | -P] [-a | -d depth | -s] [-cgkmrx] [file ...]\n"); + exit(1); +} diff --git a/package/toolbox/src/src/dynarray.c b/package/toolbox/src/src/dynarray.c new file mode 100644 index 000000000..3714542e6 --- /dev/null +++ b/package/toolbox/src/src/dynarray.c @@ -0,0 +1,104 @@ +#include "dynarray.h" +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +void +dynarray_init( dynarray_t *a ) +{ + a->count = a->capacity = 0; + a->items = NULL; +} + + +static void +dynarray_reserve_more( dynarray_t *a, int count ) +{ + int old_cap = a->capacity; + int new_cap = old_cap; + const int max_cap = INT_MAX/sizeof(void*); + void** new_items; + int new_count = a->count + count; + + if (count <= 0) + return; + + if (count > max_cap - a->count) + abort(); + + new_count = a->count + count; + + while (new_cap < new_count) { + old_cap = new_cap; + new_cap += (new_cap >> 2) + 4; + if (new_cap < old_cap || new_cap > max_cap) { + new_cap = max_cap; + } + } + new_items = realloc(a->items, new_cap*sizeof(void*)); + if (new_items == NULL) + abort(); + + a->items = new_items; + a->capacity = new_cap; +} + +void +dynarray_append( dynarray_t *a, void* item ) +{ + if (a->count >= a->capacity) + dynarray_reserve_more(a, 1); + + a->items[a->count++] = item; +} + +void +dynarray_done( dynarray_t *a ) +{ + free(a->items); + a->items = NULL; + a->count = a->capacity = 0; +} + +// string arrays + +void strlist_init( strlist_t *list ) +{ + dynarray_init(list); +} + +void strlist_append_b( strlist_t *list, const void* str, size_t slen ) +{ + char *copy = malloc(slen+1); + memcpy(copy, str, slen); + copy[slen] = '\0'; + dynarray_append(list, copy); +} + +void strlist_append_dup( strlist_t *list, const char *str) +{ + strlist_append_b(list, str, strlen(str)); +} + +void strlist_done( strlist_t *list ) +{ + STRLIST_FOREACH(list, string, free(string)); + dynarray_done(list); +} + +static int strlist_compare_strings(const void* a, const void* b) +{ + const char *sa = *(const char **)a; + const char *sb = *(const char **)b; + return strcmp(sa, sb); +} + +void strlist_sort( strlist_t *list ) +{ + if (list->count > 0) { + qsort(list->items, + (size_t)list->count, + sizeof(void*), + strlist_compare_strings); + } +} diff --git a/package/toolbox/src/src/dynarray.h b/package/toolbox/src/src/dynarray.h new file mode 100644 index 000000000..f73fb3b9c --- /dev/null +++ b/package/toolbox/src/src/dynarray.h @@ -0,0 +1,80 @@ +#ifndef DYNARRAY_H +#define DYNARRAY_H + +#include <stddef.h> + +/* simple dynamic array of pointers */ +typedef struct { + int count; + int capacity; + void** items; +} dynarray_t; + +#define DYNARRAY_INITIALIZER { 0, 0, NULL } + +void dynarray_init( dynarray_t *a ); +void dynarray_done( dynarray_t *a ); + +void dynarray_append( dynarray_t *a, void* item ); + +/* Used to iterate over a dynarray_t + * _array :: pointer to the array + * _item_type :: type of objects pointed to by the array + * _item :: name of a local variable defined within the loop + * with type '_item_type' + * _stmnt :: C statement that will be executed in each iteration. + * + * You case use 'break' and 'continue' within _stmnt + * + * This macro is only intended for simple uses. I.e. do not add or + * remove items from the array during iteration. + */ +#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \ + do { \ + int _nn_##__LINE__ = 0; \ + for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \ + _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \ + _stmnt; \ + } \ + } while (0) + +#define DYNARRAY_FOREACH(_array,_item,_stmnt) \ + DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt) + +/* Simple dynamic string arrays + * + * NOTE: A strlist_t owns the strings it references. + */ +typedef dynarray_t strlist_t; + +#define STRLIST_INITIALIZER DYNARRAY_INITIALIZER + +/* Used to iterate over a strlist_t + * _list :: pointer to strlist_t object + * _string :: name of local variable name defined within the loop with + * type 'char*' + * _stmnt :: C statement executed in each iteration + * + * This macro is only intended for simple uses. Do not add or remove items + * to/from the list during iteration. + */ +#define STRLIST_FOREACH(_list,_string,_stmnt) \ + DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt) + +void strlist_init( strlist_t *list ); + +/* note: strlist_done will free all the strings owned by the list */ +void strlist_done( strlist_t *list ); + +/* append a new string made of the first 'slen' characters from 'str' + * followed by a trailing zero. + */ +void strlist_append_b( strlist_t *list, const void* str, size_t slen ); + +/* append the copy of a given input string to a strlist_t */ +void strlist_append_dup( strlist_t *list, const char *str); + +/* sort the strings in a given list (using strcmp) */ +void strlist_sort( strlist_t *list ); + +#endif /* DYNARRAY_H */
\ No newline at end of file diff --git a/package/toolbox/src/src/exists.c b/package/toolbox/src/src/exists.c new file mode 100644 index 000000000..59c2a272b --- /dev/null +++ b/package/toolbox/src/src/exists.c @@ -0,0 +1,16 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +int main(int argc, char *argv[]) +{ + struct stat s; + + if(argc < 2) return 1; + + if(stat(argv[1], &s)) { + return 1; + } else { + return 0; + } +} diff --git a/package/toolbox/src/src/hd.c b/package/toolbox/src/src/hd.c new file mode 100644 index 000000000..333042fca --- /dev/null +++ b/package/toolbox/src/src/hd.c @@ -0,0 +1,97 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <errno.h> + +int main(int argc, char *argv[]) +{ + int c; + int fd; + unsigned char buf[4096]; + int res; + int read_len; + int i; + int filepos = 0; + int sum; + int lsum; + + int base = -1; + int count = 0; + int repeat = 0; + + do { + c = getopt(argc, argv, "b:c:r:"); + if (c == EOF) + break; + switch (c) { + case 'b': + base = strtol(optarg, NULL, 0); + break; + case 'c': + count = strtol(optarg, NULL, 0); + break; + case 'r': + repeat = strtol(optarg, NULL, 0); + break; + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + argv[0], optopt); + exit(1); + } + } while (1); + + if (optind + 1 != argc) { + fprintf(stderr, "Usage: %s [-b base] [-c count] [-r delay] file\n", argv[0]); + exit(1); + } + + fd = open(argv[optind], O_RDONLY); + if(fd < 0) { + fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno)); + return 1; + } + + do { + if(base >= 0) { + lseek(fd, base, SEEK_SET); + filepos = base; + } + sum = 0; + lsum = 0; + while(1) { + read_len = sizeof(buf); + if(count > 0 && base + count - filepos < read_len) + read_len = base + count - filepos; + res = read(fd, &buf, read_len); + if(res == 0) + break; + for(i = 0; i < res; i++) { + if((i & 15) == 0) { + printf("%08x: ", filepos + i); + } + lsum += buf[i]; + sum += buf[i]; + printf("%02x ", buf[i]); + if(((i & 15) == 15) || (i == res - 1)) { + printf("s %x\n", lsum); + lsum = 0; + } + } + if(res < 0) { + printf("Read error on %s, offset %d len %d, %s\n", argv[optind], filepos, read_len, strerror(errno)); + return 1; + } + filepos += res; + if(filepos == base + count) + break; + } + printf("sum %x\n", sum); + if(repeat) + sleep(repeat); + } while(repeat); + return 0; +} diff --git a/package/toolbox/src/src/id.c b/package/toolbox/src/src/id.c new file mode 100644 index 000000000..60c0f0f6d --- /dev/null +++ b/package/toolbox/src/src/id.c @@ -0,0 +1,51 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> + +static void print_uid(uid_t uid) +{ + struct passwd *pw = getpwuid(uid); + + if (pw) { + printf("%d(%s)", uid, pw->pw_name); + } else { + printf("%d",uid); + } +} + +static void print_gid(gid_t gid) +{ + struct group *gr = getgrgid(gid); + if (gr) { + printf("%d(%s)", gid, gr->gr_name); + } else { + printf("%d",gid); + } +} + +int main(int argc, char **argv) +{ + gid_t list[64]; + int n, max; + + max = getgroups(64, list); + if (max < 0) max = 0; + + printf("uid="); + print_uid(getuid()); + printf(" gid="); + print_gid(getgid()); + if (max) { + printf(" groups="); + print_gid(list[0]); + for(n = 1; n < max; n++) { + printf(","); + print_gid(list[n]); + } + } + printf("\n"); + return 0; +} diff --git a/package/toolbox/src/src/ifconfig.c b/package/toolbox/src/src/ifconfig.c new file mode 100644 index 000000000..510d3b555 --- /dev/null +++ b/package/toolbox/src/src/ifconfig.c @@ -0,0 +1,164 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <errno.h> +#include <string.h> +#include <ctype.h> + +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <linux/if.h> +#include <linux/sockios.h> +#include <arpa/inet.h> + +static void die(const char *s) +{ + fprintf(stderr,"error: %s (%s)\n", s, strerror(errno)); + exit(-1); +} + +static void setflags(int s, struct ifreq *ifr, int set, int clr) +{ + if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) die("SIOCGIFFLAGS"); + ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set; + if(ioctl(s, SIOCSIFFLAGS, ifr) < 0) die("SIOCSIFFLAGS"); +} + +static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr) +{ + sin->sin_family = AF_INET; + sin->sin_port = 0; + sin->sin_addr.s_addr = inet_addr(addr); +} + +static void setmtu(int s, struct ifreq *ifr, const char *mtu) +{ + int m = atoi(mtu); + ifr->ifr_mtu = m; + if(ioctl(s, SIOCSIFMTU, ifr) < 0) die("SIOCSIFMTU"); +} +static void setdstaddr(int s, struct ifreq *ifr, const char *addr) +{ + init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_dstaddr, addr); + if(ioctl(s, SIOCSIFDSTADDR, ifr) < 0) die("SIOCSIFDSTADDR"); +} + +static void setnetmask(int s, struct ifreq *ifr, const char *addr) +{ + init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr); + if(ioctl(s, SIOCSIFNETMASK, ifr) < 0) die("SIOCSIFNETMASK"); +} + +static void setaddr(int s, struct ifreq *ifr, const char *addr) +{ + init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr); + if(ioctl(s, SIOCSIFADDR, ifr) < 0) die("SIOCSIFADDR"); +} + +int main(int argc, char *argv[]) +{ + struct ifreq ifr; + int s; + unsigned int addr, mask, flags; + char astring[20]; + char mstring[20]; + char *updown, *brdcst, *loopbk, *ppp, *running, *multi; + + argc--; + argv++; + + if(argc == 0) return 0; + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, argv[0], IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = 0; + argc--, argv++; + + if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + die("cannot open control socket\n"); + } + + if (argc == 0) { + if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { + perror(ifr.ifr_name); + return -1; + } else + addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + + if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) { + perror(ifr.ifr_name); + return -1; + } else + mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + + if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { + perror(ifr.ifr_name); + return -1; + } else + flags = ifr.ifr_flags; + + sprintf(astring, "%d.%d.%d.%d", + addr & 0xff, + ((addr >> 8) & 0xff), + ((addr >> 16) & 0xff), + ((addr >> 24) & 0xff)); + sprintf(mstring, "%d.%d.%d.%d", + mask & 0xff, + ((mask >> 8) & 0xff), + ((mask >> 16) & 0xff), + ((mask >> 24) & 0xff)); + printf("%s: ip %s mask %s flags [", ifr.ifr_name, + astring, + mstring + ); + + updown = (flags & IFF_UP) ? "up" : "down"; + brdcst = (flags & IFF_BROADCAST) ? " broadcast" : ""; + loopbk = (flags & IFF_LOOPBACK) ? " loopback" : ""; + ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : ""; + running = (flags & IFF_RUNNING) ? " running" : ""; + multi = (flags & IFF_MULTICAST) ? " multicast" : ""; + printf("%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi); + return 0; + } + + while(argc > 0) { + if (!strcmp(argv[0], "up")) { + setflags(s, &ifr, IFF_UP, 0); + } else if (!strcmp(argv[0], "mtu")) { + argc--, argv++; + if (!argc) { + errno = EINVAL; + die("expecting a value for parameter \"mtu\""); + } + setmtu(s, &ifr, argv[0]); + } else if (!strcmp(argv[0], "-pointopoint")) { + setflags(s, &ifr, IFF_POINTOPOINT, 1); + } else if (!strcmp(argv[0], "pointopoint")) { + argc--, argv++; + if (!argc) { + errno = EINVAL; + die("expecting an IP address for parameter \"pointtopoint\""); + } + setdstaddr(s, &ifr, argv[0]); + setflags(s, &ifr, IFF_POINTOPOINT, 0); + } else if (!strcmp(argv[0], "down")) { + setflags(s, &ifr, 0, IFF_UP); + } else if (!strcmp(argv[0], "netmask")) { + argc--, argv++; + if (!argc) { + errno = EINVAL; + die("expecting an IP address for parameter \"netmask\""); + } + setnetmask(s, &ifr, argv[0]); + } else if (isdigit(argv[0][0])) { + setaddr(s, &ifr, argv[0]); + setflags(s, &ifr, IFF_UP, 0); + } + argc--, argv++; + } + return 0; +} diff --git a/package/toolbox/src/src/iftop.c b/package/toolbox/src/src/iftop.c new file mode 100644 index 000000000..7bb946895 --- /dev/null +++ b/package/toolbox/src/src/iftop.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2008, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> + +#define PROC_NET_DEV "/proc/net/dev" + +#define MAX_IF 8 /* max interfaces we can handle */ + +#ifndef PAGE_SIZE +# define PAGE_SIZE 4096 +#endif + +#define _STR(s) #s +#define STR(s) _STR(s) + +struct if_stats { + char name[IFNAMSIZ]; + + unsigned int mtu; + + unsigned int rx_bytes; + unsigned int rx_packets; + unsigned int rx_errors; + unsigned int rx_dropped; + + unsigned int tx_bytes; + unsigned int tx_packets; + unsigned int tx_errors; + unsigned int tx_dropped; +}; + +static int get_mtu(const char *if_name) +{ + struct ifreq ifr; + int s, ret; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + exit(EXIT_FAILURE); + } + + memset(&ifr, 0, sizeof(struct ifreq)); + ifr.ifr_addr.sa_family = AF_INET; + strcpy(ifr.ifr_name, if_name); + + ret = ioctl(s, SIOCGIFMTU, &ifr); + if (ret < 0) { + perror("ioctl"); + exit(EXIT_FAILURE); + } + + ret = close(s); + if (ret < 0) { + perror("close"); + exit(EXIT_FAILURE); + } + + return ifr.ifr_mtu; +} + +static int get_interfaces(struct if_stats *ifs) +{ + char buf[PAGE_SIZE]; + char *p; + int ret, nr, fd; + + fd = open(PROC_NET_DEV, O_RDONLY); + if (fd < 0) { + perror("open"); + exit(EXIT_FAILURE); + } + + ret = read(fd, buf, sizeof(buf) - 1); + if (ret < 0) { + perror("read"); + exit(EXIT_FAILURE); + } else if (!ret) { + fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n"); + exit(EXIT_FAILURE); + } + buf[ret] = '\0'; + + /* skip down to the third line */ + p = strchr(buf, '\n'); + if (!p) { + fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n"); + exit(EXIT_FAILURE); + } + p = strchr(p + 1, '\n'); + if (!p) { + fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n"); + exit(EXIT_FAILURE); + } + p += 1; + + /* + * Key: + * if: (Rx) bytes packets errs drop fifo frame compressed multicast \ + * (Tx) bytes packets errs drop fifo colls carrier compressed + */ + for (nr = 0; nr < MAX_IF; nr++) { + char *c; + + ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name); + if (ret != 1) { + fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n"); + exit(EXIT_FAILURE); + } + + /* + * This works around a bug in the proc file where large interface names + * or Rx byte counts eat the delimiter, breaking sscanf. + */ + c = strchr(ifs->name, ':'); + if (c) + *c = '\0'; + + p = strchr(p, ':') + 1; + + ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u " + "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets, + &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes, + &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped); + if (ret != 8) { + fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n"); + exit(EXIT_FAILURE); + } + + ifs->mtu = get_mtu(ifs->name); + + p = strchr(p, '\n') + 1; + if (*p == '\0') { + nr++; + break; + } + + ifs++; + } + + ret = close(fd); + if (ret) { + perror("close"); + exit(EXIT_FAILURE); + } + + return nr; +} + +static void print_header(void) +{ + printf(" Rx Tx\n"); + printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n", + "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes", + "packets", "errs", "drpd"); +} + +static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr) +{ + int i = 0; + + while (nr--) { + if (old->rx_packets || old->tx_packets) { + printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n", + new->name, new->mtu, + new->rx_bytes - old->rx_bytes, + new->rx_packets - old->rx_packets, + new->rx_errors - old->rx_errors, + new->rx_dropped - old->rx_dropped, + new->tx_bytes - old->tx_bytes, + new->tx_packets - old->tx_packets, + new->tx_errors - old->tx_errors, + new->tx_dropped - old->tx_dropped); + i++; + } + old++; + new++; + } + + return i; +} + +static void usage(const char *cmd) +{ + fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd); +} + +int main(int argc, char *argv[]) +{ + struct if_stats ifs[2][MAX_IF]; + int count = 0, header_interval = 22, delay = 1, i; + unsigned int toggle = 0; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-d")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -d requires an argument.\n"); + exit(EXIT_FAILURE); + } + delay = atoi(argv[i++]); + if (!delay) + delay = 1; + continue; + } + if (!strcmp(argv[i], "-r")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -r requires an argument.\n"); + exit(EXIT_FAILURE); + } + header_interval = atoi(argv[i++]); + if (header_interval < MAX_IF) + header_interval = MAX_IF; + continue; + } + if (!strcmp(argv[i], "-h")) { + usage(argv[0]); + exit(EXIT_SUCCESS); + } + usage(argv[0]); + exit(EXIT_FAILURE); + } + + get_interfaces(ifs[!toggle]); + if (header_interval) + print_header(); + while (1) { + int nr; + + sleep(delay); + nr = get_interfaces(ifs[toggle]); + if (header_interval && count + nr > header_interval) { + print_header(); + count = 0; + } + count += print_interfaces(ifs[!toggle], ifs[toggle], nr); + toggle = !toggle; + } + + return 0; +} diff --git a/package/toolbox/src/src/insmod.c b/package/toolbox/src/src/insmod.c new file mode 100644 index 000000000..22e3d6160 --- /dev/null +++ b/package/toolbox/src/src/insmod.c @@ -0,0 +1,97 @@ +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <malloc.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +extern int init_module(void *, unsigned long, const char *); + +static void *read_file(const char *filename, ssize_t *_size) +{ + int ret, fd; + struct stat sb; + ssize_t size; + void *buffer = NULL; + + /* open the file */ + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + + /* find out how big it is */ + if (fstat(fd, &sb) < 0) + goto bail; + size = sb.st_size; + + /* allocate memory for it to be read into */ + buffer = malloc(size); + if (!buffer) + goto bail; + + /* slurp it into our buffer */ + ret = read(fd, buffer, size); + if (ret != size) + goto bail; + + /* let the caller know how big it is */ + *_size = size; + +bail: + close(fd); + return buffer; +} + +#define min(x,y) ((x) < (y) ? (x) : (y)) +int main(int argc, char **argv) +{ + void *file; + ssize_t size = 0; + char opts[1024]; + int ret; + + /* make sure we've got an argument */ + if (argc < 2) { + fprintf(stderr, "usage: insmod <module.o>\n"); + return -1; + } + + /* read the file into memory */ + file = read_file(argv[1], &size); + if (!file) { + fprintf(stderr, "insmod: can't open '%s'\n", argv[1]); + return -1; + } + + opts[0] = '\0'; + if (argc > 2) { + int i, len; + char *end = opts + sizeof(opts) - 1; + char *ptr = opts; + + for (i = 2; (i < argc) && (ptr < end); i++) { + len = min(strlen(argv[i]), end - ptr); + memcpy(ptr, argv[i], len); + ptr += len; + *ptr++ = ' '; + } + *(ptr - 1) = '\0'; + } + + /* pass it to the kernel */ + ret = init_module(file, size, opts); + if (ret != 0) { + fprintf(stderr, + "insmod: init_module '%s' failed (%s)\n", + argv[1], strerror(errno)); + } + + /* free the file buffer */ + free(file); + + return ret; +} + diff --git a/package/toolbox/src/src/ioctl.c b/package/toolbox/src/src/ioctl.c new file mode 100644 index 000000000..abc1bec79 --- /dev/null +++ b/package/toolbox/src/src/ioctl.c @@ -0,0 +1,124 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <fcntl.h> +#include <getopt.h> +#include <string.h> +#include <linux/kd.h> +#include <linux/vt.h> +#include <errno.h> +#include <pthread.h> +#include <sys/ioctl.h> + +int main(int argc, char *argv[]) +{ + int c; + int fd; + int res; + + int length = -1; + int arg_size = 4; + int direct_arg = 0; + uint32_t ioctl_nr; + void *ioctl_args = NULL; + uint8_t *ioctl_argp; + uint8_t *ioctl_argp_save = NULL; + int rem; + + do { + c = getopt(argc, argv, "rdl:a:h"); + if (c == EOF) + break; + switch (c) { + case 'd': + direct_arg = 1; + break; + case 'l': + length = strtol(optarg, NULL, 0); + break; + case 'a': + arg_size = strtol(optarg, NULL, 0); + break; + case 'h': + fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n" + " -l <lenght> Length of io buffer\n" + " -a <argsize> Size of each argument (1-8)\n" + " -r Open device in read only mode\n" + " -d Direct argument (no iobuffer)\n" + " -h Print help\n", argv[0]); + return -1; + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + argv[0], optopt); + exit(1); + } + } while (1); + + if(optind + 2 > argc) { + fprintf(stderr, "%s: too few arguments\n", argv[0]); + exit(1); + } + + fd = open(argv[optind], O_RDWR | O_SYNC); + if (fd < 0) { + fprintf(stderr, "cannot open %s\n", argv[optind]); + return 1; + } + optind++; + + ioctl_nr = strtol(argv[optind], NULL, 0); + optind++; + + if(direct_arg) { + arg_size = 4; + length = 4; + } + + if(length < 0) { + length = (argc - optind) * arg_size; + } + if(length) { + ioctl_args = calloc(1, length); + + ioctl_argp_save = ioctl_argp = ioctl_args; + rem = length; + while(optind < argc) { + uint64_t tmp = strtoull(argv[optind], NULL, 0); + if(rem < arg_size) { + fprintf(stderr, "%s: too many arguments\n", argv[0]); + exit(1); + } + memcpy(ioctl_argp, &tmp, arg_size); + ioctl_argp += arg_size; + rem -= arg_size; + optind++; + } + } + printf("sending ioctl 0x%x", ioctl_nr); + rem = length; + while(rem--) { + printf(" 0x%02x", *ioctl_argp_save++); + } + printf("\n"); + + if(direct_arg) + res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args); + else if(length) + res = ioctl(fd, ioctl_nr, ioctl_args); + else + res = ioctl(fd, ioctl_nr, 0); + if (res < 0) { + fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res); + return 1; + } + if(length) { + printf("return buf:"); + ioctl_argp = ioctl_args; + rem = length; + while(rem--) { + printf(" %02x", *ioctl_argp++); + } + printf("\n"); + } + return 0; +} diff --git a/package/toolbox/src/src/kill.c b/package/toolbox/src/src/kill.c new file mode 100644 index 000000000..994ad31b2 --- /dev/null +++ b/package/toolbox/src/src/kill.c @@ -0,0 +1,149 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <sys/types.h> +#include <signal.h> + +static struct { + unsigned int number; + char *name; +} signals[] = { +#define _SIG(name) {SIG##name, #name} + /* Single Unix Specification signals */ + _SIG(ABRT), + _SIG(ALRM), + _SIG(FPE), + _SIG(HUP), + _SIG(ILL), + _SIG(INT), + _SIG(KILL), + _SIG(PIPE), + _SIG(QUIT), + _SIG(SEGV), + _SIG(TERM), + _SIG(USR1), + _SIG(USR2), + _SIG(CHLD), + _SIG(CONT), + _SIG(STOP), + _SIG(TSTP), + _SIG(TTIN), + _SIG(TTOU), + _SIG(BUS), + _SIG(POLL), + _SIG(PROF), + _SIG(SYS), + _SIG(TRAP), + _SIG(URG), + _SIG(VTALRM), + _SIG(XCPU), + _SIG(XFSZ), + /* non-SUS signals */ + _SIG(IO), + _SIG(PWR), +#ifdef SIGSTKFLT + _SIG(STKFLT), +#endif + _SIG(WINCH), +#undef _SIG +}; + +/* To indicate a matching signal was not found */ +static const unsigned int SENTINEL = (unsigned int) -1; + +void list_signals() +{ + unsigned int sorted_signals[_NSIG]; + unsigned int i; + unsigned int num; + + memset(sorted_signals, SENTINEL, sizeof(sorted_signals)); + + // Sort the signals + for (i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) { + sorted_signals[signals[i].number] = i; + } + + num = 0; + for (i = 1; i < _NSIG; i++) { + unsigned int index = sorted_signals[i]; + if (index == SENTINEL) { + continue; + } + + fprintf(stderr, "%2d) SIG%-9s ", i, signals[index].name); + + if ((num++ % 4) == 3) { + fprintf(stderr, "\n"); + } + } + + if ((num % 4) == 3) { + fprintf(stderr, "\n"); + } +} + +unsigned int name_to_signal(const char* name) +{ + unsigned int i; + + for (i = 1; i < sizeof(signals) / sizeof(signals[0]); i++) { + if (!strcasecmp(name, signals[i].name)) { + return signals[i].number; + } + } + + return SENTINEL; +} + +int main(int argc, char **argv) +{ + unsigned int sig = SIGTERM; + int result = 0; + + argc--; + argv++; + + if (argc >= 1 && argv[0][0] == '-') { + char *endptr; + size_t arg_len = strlen(argv[0]); + if (arg_len < 2) { + fprintf(stderr, "invalid argument: -\n"); + return -1; + } + + char* arg = argv[0] + 1; + if (arg_len == 2 && *arg == 'l') { + list_signals(); + return 0; + } + + sig = strtol(arg, &endptr, 10); + if (*endptr != '\0') { + sig = name_to_signal(arg); + if (sig == SENTINEL) { + fprintf(stderr, "invalid signal name: %s\n", arg); + return -1; + } + } + + argc--; + argv++; + } + + while(argc > 0){ + int pid = atoi(argv[0]); + int err = kill(pid, sig); + if (err < 0) { + result = err; + fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno)); + } + + argc--; + argv++; + } + + return result; +} diff --git a/package/toolbox/src/src/ln.c b/package/toolbox/src/src/ln.c new file mode 100644 index 000000000..6d67823e8 --- /dev/null +++ b/package/toolbox/src/src/ln.c @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +static int usage() +{ + fprintf(stderr,"ln [-s] <target> <name>\n"); + return -1; +} + +int main(int argc, char *argv[]) +{ + int symbolic = 0; + int ret; + if(argc < 2) return usage(); + + if(!strcmp(argv[1],"-s")) { + symbolic = 1; + argc--; + argv++; + } + + if(argc < 3) return usage(); + + if(symbolic) { + ret = symlink(argv[1], argv[2]); + } else { + ret = link(argv[1], argv[2]); + } + if(ret < 0) + fprintf(stderr, "link failed %s\n", strerror(errno)); + return ret; +} diff --git a/package/toolbox/src/src/ls.c b/package/toolbox/src/src/ls.c new file mode 100644 index 000000000..a56bfaa87 --- /dev/null +++ b/package/toolbox/src/src/ls.c @@ -0,0 +1,424 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <time.h> + +#include <pwd.h> +#include <grp.h> + +#include <linux/kdev_t.h> +#include <limits.h> + +#include "dynarray.h" + +// bits for flags argument +#define LIST_LONG (1 << 0) +#define LIST_ALL (1 << 1) +#define LIST_RECURSIVE (1 << 2) +#define LIST_DIRECTORIES (1 << 3) +#define LIST_SIZE (1 << 4) +#define LIST_LONG_NUMERIC (1 << 5) +#define LIST_CLASSIFY (1 << 6) +#define LIST_INODE (1 << 8) + +// fwd +static int listpath(const char *name, int flags); + +static char mode2kind(unsigned mode) +{ + switch(mode & S_IFMT){ + case S_IFSOCK: return 's'; + case S_IFLNK: return 'l'; + case S_IFREG: return '-'; + case S_IFDIR: return 'd'; + case S_IFBLK: return 'b'; + case S_IFCHR: return 'c'; + case S_IFIFO: return 'p'; + default: return '?'; + } +} + +static void mode2str(unsigned mode, char *out) +{ + *out++ = mode2kind(mode); + + *out++ = (mode & 0400) ? 'r' : '-'; + *out++ = (mode & 0200) ? 'w' : '-'; + if(mode & 04000) { + *out++ = (mode & 0100) ? 's' : 'S'; + } else { + *out++ = (mode & 0100) ? 'x' : '-'; + } + *out++ = (mode & 040) ? 'r' : '-'; + *out++ = (mode & 020) ? 'w' : '-'; + if(mode & 02000) { + *out++ = (mode & 010) ? 's' : 'S'; + } else { + *out++ = (mode & 010) ? 'x' : '-'; + } + *out++ = (mode & 04) ? 'r' : '-'; + *out++ = (mode & 02) ? 'w' : '-'; + if(mode & 01000) { + *out++ = (mode & 01) ? 't' : 'T'; + } else { + *out++ = (mode & 01) ? 'x' : '-'; + } + *out = 0; +} + +static void user2str(unsigned uid, char *out) +{ + struct passwd *pw = getpwuid(uid); + if(pw) { + strcpy(out, pw->pw_name); + } else { + sprintf(out, "%d", uid); + } +} + +static void group2str(unsigned gid, char *out) +{ + struct group *gr = getgrgid(gid); + if(gr) { + strcpy(out, gr->gr_name); + } else { + sprintf(out, "%d", gid); + } +} + +static int show_total_size(const char *dirname, DIR *d, int flags) +{ + struct dirent *de; + char tmp[1024]; + struct stat s; + int sum = 0; + + /* run through the directory and sum up the file block sizes */ + while ((de = readdir(d)) != 0) { + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) + continue; + + if (strcmp(dirname, "/") == 0) + snprintf(tmp, sizeof(tmp), "/%s", de->d_name); + else + snprintf(tmp, sizeof(tmp), "%s/%s", dirname, de->d_name); + + if (lstat(tmp, &s) < 0) { + fprintf(stderr, "stat failed on %s: %s\n", tmp, strerror(errno)); + rewinddir(d); + return -1; + } + + sum += s.st_blocks / 2; + } + + printf("total %d\n", sum); + rewinddir(d); + return 0; +} + +static int listfile_size(const char *path, const char *filename, struct stat *s, + int flags) +{ + if(!s || !path) { + return -1; + } + + /* blocks are 512 bytes, we want output to be KB */ + if ((flags & LIST_SIZE) != 0) { + printf("%lld ", (long long)(s->st_blocks / 2)); + } + + if ((flags & LIST_CLASSIFY) != 0) { + char filetype = mode2kind(s->st_mode); + if (filetype != 'l') { + printf("%c ", filetype); + } else { + struct stat link_dest; + if (!stat(path, &link_dest)) { + printf("l%c ", mode2kind(link_dest.st_mode)); + } else { + fprintf(stderr, "stat '%s' failed: %s\n", path, strerror(errno)); + printf("l? "); + } + } + } + + printf("%s\n", filename); + + return 0; +} + +static int listfile_long(const char *path, struct stat *s, int flags) +{ + char date[32]; + char mode[16]; + char user[16]; + char group[16]; + const char *name; + + if(!s || !path) { + return -1; + } + + /* name is anything after the final '/', or the whole path if none*/ + name = strrchr(path, '/'); + if(name == 0) { + name = path; + } else { + name++; + } + + mode2str(s->st_mode, mode); + if (flags & LIST_LONG_NUMERIC) { + sprintf(user, "%ld", (long)s->st_uid); + sprintf(group, "%ld", (long)s->st_gid); + } else { + user2str(s->st_uid, user); + group2str(s->st_gid, group); + } + + strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s->st_mtime)); + date[31] = 0; + +// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 +// MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK) + + switch(s->st_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + printf("%s %-8s %-8s %3d, %3d %s %s\n", + mode, user, group, + (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev), + date, name); + break; + case S_IFREG: + printf("%s %-8s %-8s %8lld %s %s\n", + mode, user, group, (long long)s->st_size, date, name); + break; + case S_IFLNK: { + char linkto[256]; + int len; + + len = readlink(path, linkto, 256); + if(len < 0) return -1; + + if(len > 255) { + linkto[252] = '.'; + linkto[253] = '.'; + linkto[254] = '.'; + linkto[255] = 0; + } else { + linkto[len] = 0; + } + + printf("%s %-8s %-8s %s %s -> %s\n", + mode, user, group, date, name, linkto); + break; + } + default: + printf("%s %-8s %-8s %s %s\n", + mode, user, group, date, name); + + } + return 0; +} + +static int listfile(const char *dirname, const char *filename, int flags) +{ + struct stat s; + + if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_INODE)) == 0) { + printf("%s\n", filename); + return 0; + } + + char tmp[4096]; + const char* pathname = filename; + + if (dirname != NULL) { + snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename); + pathname = tmp; + } else { + pathname = filename; + } + + if(lstat(pathname, &s) < 0) { + return -1; + } + + if(flags & LIST_INODE) { + printf("%8llu ", (unsigned long long)s.st_ino); + } + + if ((flags & LIST_LONG) != 0) { + return listfile_long(pathname, &s, flags); + } else /*((flags & LIST_SIZE) != 0)*/ { + return listfile_size(pathname, filename, &s, flags); + } +} + +static int listdir(const char *name, int flags) +{ + char tmp[4096]; + DIR *d; + struct dirent *de; + strlist_t files = STRLIST_INITIALIZER; + + d = opendir(name); + if(d == 0) { + fprintf(stderr, "opendir failed, %s\n", strerror(errno)); + return -1; + } + + if ((flags & LIST_SIZE) != 0) { + show_total_size(name, d, flags); + } + + while((de = readdir(d)) != 0){ + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; + if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue; + + strlist_append_dup(&files, de->d_name); + } + + strlist_sort(&files); + STRLIST_FOREACH(&files, filename, listfile(name, filename, flags)); + strlist_done(&files); + + if (flags & LIST_RECURSIVE) { + strlist_t subdirs = STRLIST_INITIALIZER; + + rewinddir(d); + + while ((de = readdir(d)) != 0) { + struct stat s; + int err; + + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) + continue; + + if (!strcmp(name, "/")) + snprintf(tmp, sizeof(tmp), "/%s", de->d_name); + else + snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name); + + /* + * If the name ends in a '/', use stat() so we treat it like a + * directory even if it's a symlink. + */ + if (tmp[strlen(tmp)-1] == '/') + err = stat(tmp, &s); + else + err = lstat(tmp, &s); + + if (err < 0) { + perror(tmp); + closedir(d); + return -1; + } + + if (S_ISDIR(s.st_mode)) { + strlist_append_dup(&subdirs, tmp); + } + } + strlist_sort(&subdirs); + STRLIST_FOREACH(&subdirs, path, { + printf("\n%s:\n", path); + listdir(path, flags); + }); + strlist_done(&subdirs); + } + + closedir(d); + return 0; +} + +static int listpath(const char *name, int flags) +{ + struct stat s; + int err; + + /* + * If the name ends in a '/', use stat() so we treat it like a + * directory even if it's a symlink. + */ + if (name[strlen(name)-1] == '/') + err = stat(name, &s); + else + err = lstat(name, &s); + + if (err < 0) { + perror(name); + return -1; + } + + if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) { + if (flags & LIST_RECURSIVE) + printf("\n%s:\n", name); + return listdir(name, flags); + } else { + /* yeah this calls stat() again*/ + return listfile(NULL, name, flags); + } +} + +int main(int argc, char **argv) +{ + int flags = 0; + + if(argc > 1) { + int i; + int err = 0; + strlist_t files = STRLIST_INITIALIZER; + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + /* an option ? */ + const char *arg = argv[i]+1; + while (arg[0]) { + switch (arg[0]) { + case 'l': flags |= LIST_LONG; break; + case 'n': flags |= LIST_LONG | LIST_LONG_NUMERIC; break; + case 's': flags |= LIST_SIZE; break; + case 'R': flags |= LIST_RECURSIVE; break; + case 'd': flags |= LIST_DIRECTORIES; break; + case 'a': flags |= LIST_ALL; break; + case 'F': flags |= LIST_CLASSIFY; break; + case 'i': flags |= LIST_INODE; break; + default: + fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]); + exit(1); + } + arg++; + } + } else { + /* not an option ? */ + strlist_append_dup(&files, argv[i]); + } + } + + if (files.count > 0) { + STRLIST_FOREACH(&files, path, { + if (listpath(path, flags) != 0) { + err = EXIT_FAILURE; + } + }); + strlist_done(&files); + return err; + } + } + + // list working directory if no files or directories were specified + return listpath(".", flags); +} diff --git a/package/toolbox/src/src/lsof.c b/package/toolbox/src/src/lsof.c new file mode 100644 index 000000000..c4d9c5f30 --- /dev/null +++ b/package/toolbox/src/src/lsof.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2010, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <pwd.h> +#include <sys/stat.h> + +#define BUF_MAX 1024 +#define CMD_DISPLAY_MAX (9 + 1) +#define USER_DISPLAY_MAX (10 + 1) + +struct pid_info_t { + pid_t pid; + char user[USER_DISPLAY_MAX]; + + char cmdline[CMD_DISPLAY_MAX]; + + char path[PATH_MAX]; + ssize_t parent_length; +}; + +static void print_header() +{ + printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n", + "COMMAND", + "PID", + "USER", + "FD", + "TYPE", + "DEVICE", + "SIZE/OFF", + "NODE", + "NAME"); +} + +static void print_type(char *type, struct pid_info_t* info) +{ + static ssize_t link_dest_size; + static char link_dest[PATH_MAX + 64]; + + strlcat(info->path, type, sizeof(info->path)); + if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) { + if (errno == ENOENT) + goto out; + + snprintf(link_dest, sizeof(link_dest), "%s (readlink: %s)", info->path, strerror(errno)); + } else { + link_dest[link_dest_size] = '\0'; + } + + // Things that are just the root filesystem are uninteresting (we already know) + if (!strcmp(link_dest, "/")) + goto out; + + printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n", + info->cmdline, info->pid, info->user, type, + "???", "???", "???", "???", link_dest); + +out: + info->path[info->parent_length] = '\0'; +} + +// Prints out all file that have been memory mapped +static void print_maps(struct pid_info_t* info) +{ + FILE *maps; + size_t offset; + char device[10]; + long int inode; + char file[PATH_MAX]; + + strlcat(info->path, "maps", sizeof(info->path)); + + maps = fopen(info->path, "r"); + if (!maps) + goto out; + + while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %s\n", &offset, device, &inode, + file) == 4) { + // We don't care about non-file maps + if (inode == 0 || !strcmp(device, "00:00")) + continue; + + printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n", + info->cmdline, info->pid, info->user, "mem", + "???", device, offset, inode, file); + } + + fclose(maps); + +out: + info->path[info->parent_length] = '\0'; +} + +// Prints out all open file descriptors +static void print_fds(struct pid_info_t* info) +{ + static char* fd_path = "fd/"; + strlcat(info->path, fd_path, sizeof(info->path)); + + int previous_length = info->parent_length; + info->parent_length += strlen(fd_path); + + DIR *dir = opendir(info->path); + if (dir == NULL) { + char msg[PATH_MAX + 64]; + snprintf(msg, sizeof(msg), "%s (opendir: %s)", info->path, strerror(errno)); + printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n", + info->cmdline, info->pid, info->user, "FDS", + "", "", "", "", msg); + goto out; + } + + struct dirent* de; + while ((de = readdir(dir))) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + + print_type(de->d_name, info); + } + closedir(dir); + +out: + info->parent_length = previous_length; + info->path[info->parent_length] = '\0'; +} + +static void lsof_dumpinfo(pid_t pid) +{ + int fd; + struct pid_info_t info; + struct stat pidstat; + struct passwd *pw; + + info.pid = pid; + snprintf(info.path, sizeof(info.path), "/proc/%d/", pid); + info.parent_length = strlen(info.path); + + // Get the UID by calling stat on the proc/pid directory. + if (!stat(info.path, &pidstat)) { + pw = getpwuid(pidstat.st_uid); + if (pw) { + strlcpy(info.user, pw->pw_name, sizeof(info.user)); + } else { + snprintf(info.user, USER_DISPLAY_MAX, "%d", (int)pidstat.st_uid); + } + } else { + strcpy(info.user, "???"); + } + + // Read the command line information; each argument is terminated with NULL. + strlcat(info.path, "cmdline", sizeof(info.path)); + fd = open(info.path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Couldn't read %s\n", info.path); + return; + } + + char cmdline[PATH_MAX]; + int numRead = read(fd, cmdline, sizeof(cmdline) - 1); + close(fd); + + if (numRead < 0) { + fprintf(stderr, "Error reading cmdline: %s: %s\n", info.path, strerror(errno)); + return; + } + + cmdline[numRead] = '\0'; + + // We only want the basename of the cmdline + strlcpy(info.cmdline, basename(cmdline), sizeof(info.cmdline)); + + // Read each of these symlinks + print_type("cwd", &info); + print_type("exe", &info); + print_type("root", &info); + + print_fds(&info); + print_maps(&info); +} + +int main(int argc, char *argv[]) +{ + long int pid = 0; + char* endptr; + if (argc == 2) { + pid = strtol(argv[1], &endptr, 10); + } + + print_header(); + + if (pid) { + lsof_dumpinfo(pid); + } else { + DIR *dir = opendir("/proc"); + if (dir == NULL) { + fprintf(stderr, "Couldn't open /proc\n"); + return -1; + } + + struct dirent* de; + while ((de = readdir(dir))) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + + // Only inspect directories that are PID numbers + pid = strtol(de->d_name, &endptr, 10); + if (*endptr != '\0') + continue; + + lsof_dumpinfo(pid); + } + closedir(dir); + } + + return 0; +} diff --git a/package/toolbox/src/src/md5.c b/package/toolbox/src/src/md5.c new file mode 100644 index 000000000..3261c7fae --- /dev/null +++ b/package/toolbox/src/src/md5.c @@ -0,0 +1,75 @@ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <md5.h> + +static int usage() +{ + fprintf(stderr,"md5 file ...\n"); + return -1; +} + +static int do_md5(const char *path) +{ + unsigned int i; + int fd; + MD5_CTX md5_ctx; + unsigned char md5[MD5_DIGEST_LENGTH]; + + fd = open(path, O_RDONLY); + if (fd < 0) { + fprintf(stderr,"could not open %s, %s\n", path, strerror(errno)); + return -1; + } + + /* Note that bionic's MD5_* functions return void. */ + MD5Init(&md5_ctx); + + while (1) { + char buf[4096]; + ssize_t rlen; + rlen = read(fd, buf, sizeof(buf)); + if (rlen == 0) + break; + else if (rlen < 0) { + (void)close(fd); + fprintf(stderr,"could not read %s, %s\n", path, strerror(errno)); + return -1; + } + MD5Update(&md5_ctx, (const void *)buf, rlen); + } + if (close(fd)) { + fprintf(stderr,"could not close %s, %s\n", path, strerror(errno)); + return -1; + } + + MD5Final(md5, &md5_ctx); + + for (i = 0; i < (int)sizeof(md5); i++) + printf("%02x", md5[i]); + printf(" %s\n", path); + + return 0; +} + +int +main(int argc, char *argv[]) +{ + int i, ret = 0; + + if (argc < 2) + return usage(); + + /* loop over the file args */ + for (i = 1; i < argc; i++) { + if (do_md5(argv[i])) + ret = 1; + } + + return ret; +} diff --git a/package/toolbox/src/src/mkdir.c b/package/toolbox/src/src/mkdir.c new file mode 100644 index 000000000..e0b701291 --- /dev/null +++ b/package/toolbox/src/src/mkdir.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <sys/stat.h> + +static int usage() +{ + fprintf(stderr,"mkdir [OPTION] <target>\n"); + fprintf(stderr," --help display usage and exit\n"); + fprintf(stderr," -p, --parents create parent directories as needed\n"); + return -1; +} + +int main(int argc, char *argv[]) +{ + int ret; + if(argc < 2 || strcmp(argv[1], "--help") == 0) { + return usage(); + } + + int recursive = (strcmp(argv[1], "-p") == 0 || + strcmp(argv[1], "--parents") == 0) ? 1 : 0; + + if(recursive && argc < 3) { + // -p specified without a path + return usage(); + } + + if(recursive) { + argc--; + argv++; + } + + char currpath[PATH_MAX], *pathpiece; + struct stat st; + + while(argc > 1) { + argc--; + argv++; + if(recursive) { + // reset path + strcpy(currpath, ""); + // create the pieces of the path along the way + pathpiece = strtok(argv[0], "/"); + if(argv[0][0] == '/') { + // prepend / if needed + strcat(currpath, "/"); + } + while(pathpiece != NULL) { + if(strlen(currpath) + strlen(pathpiece) + 2/*NUL and slash*/ > PATH_MAX) { + fprintf(stderr, "Invalid path specified: too long\n"); + return 1; + } + strcat(currpath, pathpiece); + strcat(currpath, "/"); + if(stat(currpath, &st) != 0) { + ret = mkdir(currpath, 0777); + if(ret < 0) { + fprintf(stderr, "mkdir failed for %s, %s\n", currpath, strerror(errno)); + return ret; + } + } + pathpiece = strtok(NULL, "/"); + } + } else { + ret = mkdir(argv[0], 0777); + if(ret < 0) { + fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno)); + return ret; + } + } + } + + return 0; +} diff --git a/package/toolbox/src/src/mount.c b/package/toolbox/src/src/mount.c new file mode 100644 index 000000000..af7e5c182 --- /dev/null +++ b/package/toolbox/src/src/mount.c @@ -0,0 +1,360 @@ +/* + * mount.c, by rmk + */ + +#include <sys/mount.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <linux/loop.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#define DEFAULT_LOOP_DEVICE "/dev/block/loop0" +#define LOOPDEV_MAXLEN 64 + +struct mount_opts { + const char str[16]; + unsigned long rwmask; + unsigned long rwset; + unsigned long rwnoset; +}; + +struct extra_opts { + char *str; + char *end; + int used_size; + int alloc_size; +}; + +/* + * These options define the function of "mount(2)". + */ +#define MS_TYPE (MS_REMOUNT|MS_BIND|MS_MOVE) + + +static const struct mount_opts options[] = { + /* name mask set noset */ + { "async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS }, + { "atime", MS_NOATIME, 0, MS_NOATIME }, + { "bind", MS_TYPE, MS_BIND, 0, }, + { "dev", MS_NODEV, 0, MS_NODEV }, + { "diratime", MS_NODIRATIME, 0, MS_NODIRATIME }, + { "dirsync", MS_DIRSYNC, MS_DIRSYNC, 0 }, + { "exec", MS_NOEXEC, 0, MS_NOEXEC }, + { "move", MS_TYPE, MS_MOVE, 0 }, + { "recurse", MS_REC, MS_REC, 0 }, + { "rec", MS_REC, MS_REC, 0 }, + { "remount", MS_TYPE, MS_REMOUNT, 0 }, + { "ro", MS_RDONLY, MS_RDONLY, 0 }, + { "rw", MS_RDONLY, 0, MS_RDONLY }, + { "suid", MS_NOSUID, 0, MS_NOSUID }, + { "sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0 }, + { "verbose", MS_SILENT, MS_SILENT, 0 }, + { "unbindable", MS_UNBINDABLE, MS_UNBINDABLE, 0 }, + { "private", MS_PRIVATE, MS_PRIVATE, 0 }, + { "slave", MS_SLAVE, MS_SLAVE, 0 }, + { "shared", MS_SHARED, MS_SHARED, 0 }, +}; + +static void add_extra_option(struct extra_opts *extra, char *s) +{ + int len = strlen(s); + int newlen; + + if (extra->str) + len++; /* +1 for ',' */ + newlen = extra->used_size + len; + + if (newlen >= extra->alloc_size) { + char *new; + + new = realloc(extra->str, newlen + 1); /* +1 for NUL */ + if (!new) + return; + + extra->str = new; + extra->end = extra->str + extra->used_size; + extra->alloc_size = newlen + 1; + } + + if (extra->used_size) { + *extra->end = ','; + extra->end++; + } + strcpy(extra->end, s); + extra->used_size += len; + +} + +static unsigned long +parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra, int* loop, char *loopdev) +{ + char *s; + + *loop = 0; + while ((s = strsep(&arg, ",")) != NULL) { + char *opt = s; + unsigned int i; + int res, no = s[0] == 'n' && s[1] == 'o'; + + if (no) + s += 2; + + if (strncmp(s, "loop=", 5) == 0) { + *loop = 1; + strlcpy(loopdev, s + 5, LOOPDEV_MAXLEN); + continue; + } + + if (strcmp(s, "loop") == 0) { + *loop = 1; + strlcpy(loopdev, DEFAULT_LOOP_DEVICE, LOOPDEV_MAXLEN); + continue; + } + for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) { + res = strcmp(s, options[i].str); + + if (res == 0) { + rwflag &= ~options[i].rwmask; + if (no) + rwflag |= options[i].rwnoset; + else + rwflag |= options[i].rwset; + } + if (res <= 0) + break; + } + + if (res != 0 && s[0]) + add_extra_option(extra, opt); + } + + return rwflag; +} + +/* + * Mark the given block device as read-write, using the BLKROSET ioctl. + */ +static void fs_set_blk_rw(const char *blockdev) +{ + int fd; + int OFF = 0; + + fd = open(blockdev, O_RDONLY); + if (fd < 0) { + // should never happen + return; + } + + ioctl(fd, BLKROSET, &OFF); + close(fd); +} + +static char *progname; + +static struct extra_opts extra; +static unsigned long rwflag; + +static int +do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data, int loop, + char *loopdev) +{ + char *s; + int error = 0; + + if (loop) { + int file_fd, device_fd; + int flags; + + flags = (rwflag & MS_RDONLY) ? O_RDONLY : O_RDWR; + + file_fd = open(dev, flags); + if (file_fd < 0) { + perror("open backing file failed"); + return 1; + } + device_fd = open(loopdev, flags); + if (device_fd < 0) { + perror("open loop device failed"); + close(file_fd); + return 1; + } + if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) { + perror("ioctl LOOP_SET_FD failed"); + close(file_fd); + close(device_fd); + return 1; + } + + close(file_fd); + close(device_fd); + dev = loopdev; + } + + if ((rwflag & MS_RDONLY) == 0) { + fs_set_blk_rw(dev); + } + + while ((s = strsep(&type, ",")) != NULL) { +retry: + if (mount(dev, dir, s, rwflag, data) == -1) { + error = errno; + /* + * If the filesystem is not found, or the + * superblock is invalid, try the next. + */ + if (error == ENODEV || error == EINVAL) + continue; + + /* + * If we get EACCESS, and we're trying to + * mount readwrite and this isn't a remount, + * try read only. + */ + if (error == EACCES && + (rwflag & (MS_REMOUNT|MS_RDONLY)) == 0) { + rwflag |= MS_RDONLY; + goto retry; + } + break; + } + } + + if (error) { + errno = error; + perror("mount"); + return 255; + } + + return 0; +} + +static int print_mounts() +{ + FILE* f; + int length; + char buffer[100]; + + f = fopen("/proc/mounts", "r"); + if (!f) { + fprintf(stdout, "could not open /proc/mounts\n"); + return -1; + } + + do { + length = fread(buffer, 1, 100, f); + if (length > 0) + fwrite(buffer, 1, length, stdout); + } while (length > 0); + + fclose(f); + return 0; +} + +static int get_mounts_dev_dir(const char *arg, char **dev, char **dir) +{ + FILE *f; + char mount_dev[256]; + char mount_dir[256]; + char mount_type[256]; + char mount_opts[256]; + int mount_freq; + int mount_passno; + int match; + + f = fopen("/proc/mounts", "r"); + if (!f) { + fprintf(stdout, "could not open /proc/mounts\n"); + return -1; + } + + do { + match = fscanf(f, "%255s %255s %255s %255s %d %d\n", + mount_dev, mount_dir, mount_type, + mount_opts, &mount_freq, &mount_passno); + mount_dev[255] = 0; + mount_dir[255] = 0; + mount_type[255] = 0; + mount_opts[255] = 0; + if (match == 6 && + (strcmp(arg, mount_dev) == 0 || + strcmp(arg, mount_dir) == 0)) { + *dev = strdup(mount_dev); + *dir = strdup(mount_dir); + fclose(f); + return 0; + } + } while (match != EOF); + + fclose(f); + return -1; +} + +int main(int argc, char *argv[]) +{ + char *type = NULL; + char *dev = NULL; + char *dir = NULL; + int c; + int loop = 0; + char loopdev[LOOPDEV_MAXLEN]; + + progname = argv[0]; + rwflag = MS_SILENT; + + // mount with no arguments is equivalent to "cat /proc/mounts" + if (argc == 1) return print_mounts(); + + do { + c = getopt(argc, argv, "o:rt:w"); + if (c == EOF) + break; + switch (c) { + case 'o': + rwflag = parse_mount_options(optarg, rwflag, &extra, &loop, loopdev); + break; + case 'r': + rwflag |= MS_RDONLY; + break; + case 't': + type = optarg; + break; + case 'w': + rwflag &= ~MS_RDONLY; + break; + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + progname, optopt); + exit(1); + } + } while (1); + + /* + * If remount, bind or move was specified, then we don't + * have a "type" as such. Use the dummy "none" type. + */ + if (rwflag & MS_TYPE) + type = "none"; + + if (optind + 2 == argc) { + dev = argv[optind]; + dir = argv[optind + 1]; + } else if (optind + 1 == argc && rwflag & MS_REMOUNT) { + get_mounts_dev_dir(argv[optind], &dev, &dir); + } + + if (dev == NULL || dir == NULL || type == NULL) { + fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] " + "device directory\n", progname); + exit(1); + } + + return do_mount(dev, dir, type, rwflag, extra.str, loop, loopdev); + /* We leak dev and dir in some cases, but we're about to exit */ +} diff --git a/package/toolbox/src/src/mv.c b/package/toolbox/src/src/mv.c new file mode 100644 index 000000000..d5406b8ac --- /dev/null +++ b/package/toolbox/src/src/mv.c @@ -0,0 +1,59 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <sys/stat.h> +#include <sys/types.h> + + +int main(int argc, char *argv[]) +{ + const char* dest; + struct stat st; + int i; + + if (argc < 3) { + fprintf(stderr,"USAGE: %s <source...> <destination>\n", argv[0]); + return -1; + } + + /* check if destination exists */ + dest = argv[argc - 1]; + if (stat(dest, &st)) { + /* an error, unless the destination was missing */ + if (errno != ENOENT) { + fprintf(stderr, "failed on %s - %s\n", dest, strerror(errno)); + return -1; + } + st.st_mode = 0; + } + + for (i = 1; i < argc - 1; i++) { + const char *source = argv[i]; + char fullDest[PATH_MAX + 1 + PATH_MAX + 1]; + /* assume we build "dest/source", and let rename() fail on pathsize */ + if (strlen(dest) + 1 + strlen(source) + 1 > sizeof(fullDest)) { + fprintf(stderr, "path too long\n"); + return -1; + } + strcpy(fullDest, dest); + + /* if destination is a directory, concat the source file name */ + if (S_ISDIR(st.st_mode)) { + const char *fileName = strrchr(source, '/'); + if (fullDest[strlen(fullDest)-1] != '/') { + strcat(fullDest, "/"); + } + strcat(fullDest, fileName ? fileName + 1 : source); + } + + /* attempt to move it */ + if (rename(source, fullDest)) { + fprintf(stderr, "failed on '%s' - %s\n", source, strerror(errno)); + return -1; + } + } + + return 0; +} + diff --git a/package/toolbox/src/src/netstat.c b/package/toolbox/src/src/netstat.c new file mode 100644 index 000000000..31365acd6 --- /dev/null +++ b/package/toolbox/src/src/netstat.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2008, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> + +typedef union iaddr iaddr; +typedef union iaddr6 iaddr6; + +union iaddr { + unsigned u; + unsigned char b[4]; +}; + +union iaddr6 { + struct { + unsigned a; + unsigned b; + unsigned c; + unsigned d; + } u; + unsigned char b[16]; +}; + +static const char *state2str(unsigned state) +{ + switch(state){ + case 0x1: return "ESTABLISHED"; + case 0x2: return "SYN_SENT"; + case 0x3: return "SYN_RECV"; + case 0x4: return "FIN_WAIT1"; + case 0x5: return "FIN_WAIT2"; + case 0x6: return "TIME_WAIT"; + case 0x7: return "CLOSE"; + case 0x8: return "CLOSE_WAIT"; + case 0x9: return "LAST_ACK"; + case 0xA: return "LISTEN"; + case 0xB: return "CLOSING"; + default: return "UNKNOWN"; + } +} + +/* addr + : + port + \0 */ +#define ADDR_LEN INET6_ADDRSTRLEN + 1 + 5 + 1 + +static void addr2str(int af, const void *addr, unsigned port, char *buf) +{ + if (inet_ntop(af, addr, buf, ADDR_LEN) == NULL) { + *buf = '\0'; + return; + } + size_t len = strlen(buf); + if (port) { + snprintf(buf+len, ADDR_LEN-len, ":%d", port); + } else { + strncat(buf+len, ":*", ADDR_LEN-len-1); + } +} + +static void ipv4(const char *filename, const char *label) { + FILE *fp = fopen(filename, "r"); + if (fp == NULL) { + return; + } + char buf[BUFSIZ]; + fgets(buf, BUFSIZ, fp); + while (fgets(buf, BUFSIZ, fp)){ + char lip[ADDR_LEN]; + char rip[ADDR_LEN]; + iaddr laddr, raddr; + unsigned lport, rport, state, txq, rxq, num; + int n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x", + &num, &laddr.u, &lport, &raddr.u, &rport, + &state, &txq, &rxq); + if (n == 8) { + addr2str(AF_INET, &laddr, lport, lip); + addr2str(AF_INET, &raddr, rport, rip); + + printf("%4s %6d %6d %-22s %-22s %s\n", + label, rxq, txq, lip, rip, + state2str(state)); + } + } + fclose(fp); +} + +static void ipv6(const char *filename, const char *label) { + FILE *fp = fopen(filename, "r"); + if (fp == NULL) { + return; + } + char buf[BUFSIZ]; + fgets(buf, BUFSIZ, fp); + while (fgets(buf, BUFSIZ, fp)){ + char lip[ADDR_LEN]; + char rip[ADDR_LEN]; + iaddr6 laddr6, raddr6; + unsigned lport, rport, state, txq, rxq, num; + int n = sscanf(buf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x", + &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c, &laddr6.u.d, &lport, + &raddr6.u.a, &raddr6.u.b, &raddr6.u.c, &raddr6.u.d, &rport, + &state, &txq, &rxq); + if (n == 14) { + addr2str(AF_INET6, &laddr6, lport, lip); + addr2str(AF_INET6, &raddr6, rport, rip); + + printf("%4s %6d %6d %-22s %-22s %s\n", + label, rxq, txq, lip, rip, + state2str(state)); + } + } + fclose(fp); +} + +int main(int argc, char *argv[]) +{ + printf("Proto Recv-Q Send-Q Local Address Foreign Address State\n"); + ipv4("/proc/net/tcp", "tcp"); + ipv4("/proc/net/udp", "udp"); + ipv6("/proc/net/tcp6", "tcp6"); + ipv6("/proc/net/udp6", "udp6"); + return 0; +} diff --git a/package/toolbox/src/src/notify.c b/package/toolbox/src/src/notify.c new file mode 100644 index 000000000..56294b73f --- /dev/null +++ b/package/toolbox/src/src/notify.c @@ -0,0 +1,145 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/inotify.h> +#include <errno.h> + +int main(int argc, char *argv[]) +{ + int c; + int nfd, ffd; + int res; + char event_buf[512]; + struct inotify_event *event; + int event_mask = IN_ALL_EVENTS; + int event_count = 1; + int print_files = 0; + int verbose = 2; + int width = 80; + char **file_names; + int file_count; + int id_offset = 0; + int i; + char *buf; + + do { + c = getopt(argc, argv, "m:c:pv:w:"); + if (c == EOF) + break; + switch (c) { + case 'm': + event_mask = strtol(optarg, NULL, 0); + break; + case 'c': + event_count = atoi(optarg); + break; + case 'p': + print_files = 1; + break; + case 'v': + verbose = atoi(optarg); + break; + case 'w': + width = atoi(optarg); + break; + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + argv[0], optopt); + exit(1); + } + } while (1); + + if (argc <= optind) { + fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]); + return 1; + } + + nfd = inotify_init(); + if(nfd < 0) { + fprintf(stderr, "inotify_init failed, %s\n", strerror(errno)); + return 1; + } + file_names = argv + optind; + file_count = argc - optind; + for(i = 0; i < file_count; i++) { + res = inotify_add_watch(nfd, file_names[i], event_mask); + if(res < 0) { + fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno)); + return 1; + } + if(i == 0) + id_offset = -res; + if(res + id_offset != i) { + fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i); + return 1; + } + } + + buf = malloc(width + 2); + + while(1) { + int event_pos = 0; + res = read(nfd, event_buf, sizeof(event_buf)); + if(res < (int)sizeof(*event)) { + if(errno == EINTR) + continue; + fprintf(stderr, "could not get event, %s\n", strerror(errno)); + return 1; + } + //printf("got %d bytes of event information\n", res); + while(res >= (int)sizeof(*event)) { + int event_size; + event = (struct inotify_event *)(event_buf + event_pos); + if(verbose >= 2) + printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : ""); + else if(verbose >= 2) + printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : ""); + else if(verbose >= 1) + printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); + if(print_files && (event->mask & IN_MODIFY)) { + char filename[512]; + ssize_t read_len; + char *display_name; + int buflen; + strcpy(filename, file_names[event->wd + id_offset]); + if(event->len) { + strcat(filename, "/"); + strcat(filename, event->name); + } + ffd = open(filename, O_RDONLY); + display_name = (verbose >= 2 || event->len == 0) ? filename : event->name; + buflen = width - strlen(display_name); + read_len = read(ffd, buf, buflen); + if(read_len > 0) { + if(read_len < buflen && buf[read_len-1] != '\n') { + buf[read_len] = '\n'; + read_len++; + } + if(read_len == buflen) { + buf[--read_len] = '\0'; + buf[--read_len] = '\n'; + buf[--read_len] = '.'; + buf[--read_len] = '.'; + buf[--read_len] = '.'; + } + else { + buf[read_len] = '\0'; + } + printf("%s: %s", display_name, buf); + } + close(ffd); + } + if(event_count && --event_count == 0) + return 0; + event_size = sizeof(*event) + event->len; + res -= event_size; + event_pos += event_size; + } + } + + return 0; +} diff --git a/package/toolbox/src/src/printenv.c b/package/toolbox/src/src/printenv.c new file mode 100644 index 000000000..304258c4a --- /dev/null +++ b/package/toolbox/src/src/printenv.c @@ -0,0 +1,33 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +extern char** environ; + +int main (int argc, char **argv) +{ + char** e; + char* v; + int i; + + if (argc == 1) { + e = environ; + while (*e) { + write(1, *e, strlen(*e)); + write(1, "\n", 1); + e++; + } + } else { + for (i=1; i<argc; i++) { + v = getenv(argv[i]); + if (v) { + write(1, v, strlen(v)); + write(1, "\n", 1); + } + } + } + + return 0; +} + diff --git a/package/toolbox/src/src/ps.c b/package/toolbox/src/src/ps.c new file mode 100644 index 000000000..07fe5c94b --- /dev/null +++ b/package/toolbox/src/src/ps.c @@ -0,0 +1,244 @@ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <unistd.h> + +#include <string.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> + +#include <pwd.h> + +static char *nexttoksep(char **strp, char *sep) +{ + char *p = strsep(strp,sep); + return (p == 0) ? "" : p; +} +static char *nexttok(char **strp) +{ + return nexttoksep(strp, " "); +} + +#define SHOW_PRIO 1 +#define SHOW_TIME 2 +#define SHOW_CPU 8 +#define SHOW_MACLABEL 16 + +static int display_flags = 0; + +static int ps_line(int pid, int tid, char *namefilter) +{ + char statline[1024]; + char cmdline[1024]; + char macline[1024]; + char user[32]; + struct stat stats; + int fd, r; + char *ptr, *name, *state; + int ppid; + unsigned wchan, rss, vss, eip; + unsigned utime, stime; + int prio, nice, rtprio, sched, psr; + struct passwd *pw; + + sprintf(statline, "/proc/%d", pid); + stat(statline, &stats); + + if(tid) { + sprintf(statline, "/proc/%d/task/%d/stat", pid, tid); + cmdline[0] = 0; + snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid); + } else { + sprintf(statline, "/proc/%d/stat", pid); + sprintf(cmdline, "/proc/%d/cmdline", pid); + snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid); + fd = open(cmdline, O_RDONLY); + if(fd == 0) { + r = 0; + } else { + r = read(fd, cmdline, 1023); + close(fd); + if(r < 0) r = 0; + } + cmdline[r] = 0; + } + + fd = open(statline, O_RDONLY); + if(fd == 0) return -1; + r = read(fd, statline, 1023); + close(fd); + if(r < 0) return -1; + statline[r] = 0; + + ptr = statline; + nexttok(&ptr); // skip pid + ptr++; // skip "(" + + name = ptr; + ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')', + *ptr++ = '\0'; // and null-terminate name. + + ptr++; // skip " " + state = nexttok(&ptr); + ppid = atoi(nexttok(&ptr)); + nexttok(&ptr); // pgrp + nexttok(&ptr); // sid + nexttok(&ptr); // tty + + nexttok(&ptr); // tpgid + nexttok(&ptr); // flags + nexttok(&ptr); // minflt + nexttok(&ptr); // cminflt + nexttok(&ptr); // majflt + nexttok(&ptr); // cmajflt +#if 1 + utime = atoi(nexttok(&ptr)); + stime = atoi(nexttok(&ptr)); +#else + nexttok(&ptr); // utime + nexttok(&ptr); // stime +#endif + nexttok(&ptr); // cutime + nexttok(&ptr); // cstime + prio = atoi(nexttok(&ptr)); + nice = atoi(nexttok(&ptr)); + nexttok(&ptr); // threads + nexttok(&ptr); // itrealvalue + nexttok(&ptr); // starttime + vss = strtoul(nexttok(&ptr), 0, 10); // vsize + rss = strtoul(nexttok(&ptr), 0, 10); // rss + nexttok(&ptr); // rlim + nexttok(&ptr); // startcode + nexttok(&ptr); // endcode + nexttok(&ptr); // startstack + nexttok(&ptr); // kstkesp + eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip + nexttok(&ptr); // signal + nexttok(&ptr); // blocked + nexttok(&ptr); // sigignore + nexttok(&ptr); // sigcatch + wchan = strtoul(nexttok(&ptr), 0, 10); // wchan + nexttok(&ptr); // nswap + nexttok(&ptr); // cnswap + nexttok(&ptr); // exit signal + psr = atoi(nexttok(&ptr)); // processor + rtprio = atoi(nexttok(&ptr)); // rt_priority + sched = atoi(nexttok(&ptr)); // scheduling policy + + nexttok(&ptr); // tty + + if(tid != 0) { + ppid = pid; + pid = tid; + } + + pw = getpwuid(stats.st_uid); + if(pw == 0) { + sprintf(user,"%d",(int)stats.st_uid); + } else { + strcpy(user,pw->pw_name); + } + + if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) { + if (display_flags & SHOW_MACLABEL) { + fd = open(macline, O_RDONLY); + strcpy(macline, "-"); + if (fd >= 0) { + r = read(fd, macline, sizeof(macline)-1); + close(fd); + if (r > 0) + macline[r] = 0; + } + printf("%-30s %-9s %-5d %-5d %s\n", macline, user, pid, ppid, cmdline[0] ? cmdline : name); + return 0; + } + + printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4); + if (display_flags & SHOW_CPU) + printf(" %-2d", psr); + if (display_flags & SHOW_PRIO) + printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched); + printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name); + if(display_flags&SHOW_TIME) + printf(" (u:%d, s:%d)", utime, stime); + + printf("\n"); + } + return 0; +} + + +void ps_threads(int pid, char *namefilter) +{ + char tmp[128]; + DIR *d; + struct dirent *de; + + sprintf(tmp,"/proc/%d/task",pid); + d = opendir(tmp); + if(d == 0) return; + + while((de = readdir(d)) != 0){ + if(isdigit(de->d_name[0])){ + int tid = atoi(de->d_name); + if(tid == pid) continue; + ps_line(pid, tid, namefilter); + } + } + closedir(d); +} + +int main(int argc, char **argv) +{ + DIR *d; + struct dirent *de; + char *namefilter = 0; + int pidfilter = 0; + int threads = 0; + + d = opendir("/proc"); + if(d == 0) return -1; + + while(argc > 1){ + if(!strcmp(argv[1],"-t")) { + threads = 1; + } else if(!strcmp(argv[1],"-x")) { + display_flags |= SHOW_TIME; + } else if(!strcmp(argv[1], "-Z")) { + display_flags |= SHOW_MACLABEL; + } else if(!strcmp(argv[1],"-p")) { + display_flags |= SHOW_PRIO; + } else if(!strcmp(argv[1],"-c")) { + display_flags |= SHOW_CPU; + } else if(isdigit(argv[1][0])){ + pidfilter = atoi(argv[1]); + } else { + namefilter = argv[1]; + } + argc--; + argv++; + } + + if (display_flags & SHOW_MACLABEL) { + printf("LABEL USER PID PPID NAME\n"); + } else { + printf("USER PID PPID VSIZE RSS %s%s WCHAN PC NAME\n", + (display_flags&SHOW_CPU)?"CPU ":"", + (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":""); + } + while((de = readdir(d)) != 0){ + if(isdigit(de->d_name[0])){ + int pid = atoi(de->d_name); + if(!pidfilter || (pidfilter == pid)) { + ps_line(pid, 0, namefilter); + if(threads) ps_threads(pid, namefilter); + } + } + } + closedir(d); + return 0; +} + diff --git a/package/toolbox/src/src/readlink.c b/package/toolbox/src/src/readlink.c new file mode 100644 index 000000000..71f74ebb3 --- /dev/null +++ b/package/toolbox/src/src/readlink.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static int skip_newline, quiet_errors, canonicalize; + +static void usage(char* name) { + fprintf(stderr, "Usage: %s [OPTION]... FILE\n", name); +} + +int main(int argc, char* argv[]) { + int c; + while ((c = getopt(argc, argv, "nfqs")) != -1) { + switch (c) { + case 'n': + skip_newline = 1; + break; + case 'f': + canonicalize = 1; + break; + case 'q': + case 's': + quiet_errors = 1; + break; + case '?': + default: + usage(argv[0]); + return EXIT_FAILURE; + } + } + int index = optind; + if (argc - index != 1) { + usage(argv[0]); + return EXIT_FAILURE; + } + + char name[PATH_MAX+1]; + if (canonicalize) { + if(!realpath(argv[optind], name)) { + if (!quiet_errors) { + perror("readlink"); + } + return EXIT_FAILURE; + } + } else { + ssize_t len = readlink(argv[1], name, PATH_MAX); + + if (len < 0) { + if (!quiet_errors) { + perror("readlink"); + } + return EXIT_FAILURE; + } + name[len] = '\0'; + } + + fputs(name, stdout); + if (!skip_newline) { + fputs("\n", stdout); + } + + return EXIT_SUCCESS; +} diff --git a/package/toolbox/src/src/renice.c b/package/toolbox/src/src/renice.c new file mode 100644 index 000000000..dece920a6 --- /dev/null +++ b/package/toolbox/src/src/renice.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2008, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sched.h> +#include <getopt.h> + +static void +usage(const char *s) +{ + fprintf(stderr, "USAGE: %s [[-r] [-t TYPE] priority pids ...] [-g pid]\n", s); + exit(EXIT_FAILURE); +} + +void print_prio(pid_t pid) +{ + int sched; + struct sched_param sp; + + printf("pid %d's priority: %d\n", pid, getpriority(PRIO_PROCESS, pid)); + + printf("scheduling class: "); + sched = sched_getscheduler(pid); + switch (sched) { + case SCHED_FIFO: + printf("FIFO\n"); + break; + case SCHED_RR: + printf("RR\n"); + break; + case SCHED_OTHER: + printf("Normal\n"); + break; + case -1: + perror("sched_getscheduler"); + break; + default: + printf("Unknown\n"); + } + + sched_getparam(pid, &sp); + printf("RT prio: %d (of %d to %d)\n", sp.sched_priority, + sched_get_priority_min(sched), sched_get_priority_max(sched)); +} + +int get_sched(char *str) +{ + if (strcasecmp(str, "RR") == 0) + return SCHED_RR; + else if (strcasecmp(str, "FIFO") == 0) + return SCHED_FIFO; + else if (strcasecmp(str, "NORMAL") == 0) + return SCHED_OTHER; + else if (strcasecmp(str, "OTHER") == 0) + return SCHED_OTHER; + return SCHED_RR; +} + +int main(int argc, char *argv[]) +{ + int prio; + int realtime = 0; + int opt; + int sched = SCHED_RR; + char *cmd = argv[0]; + + do { + opt = getopt(argc, argv, "rt:g:"); + if (opt == -1) + break; + switch (opt) { + case 'r': + // do realtime priority adjustment + realtime = 1; + break; + case 't': + sched = get_sched(optarg); + break; + case 'g': + print_prio(atoi(optarg)); + return 0; + default: + usage(cmd); + } + } while (1); + + argc -= optind; + argv += optind; + + if (argc < 1) + usage(cmd); + + prio = atoi(argv[0]); + argc--; + argv++; + + if (argc < 1) + usage(cmd); + + while(argc) { + pid_t pid; + + pid = atoi(argv[0]); + argc--; + argv++; + + if (realtime) { + struct sched_param sp = { .sched_priority = prio }; + int ret; + + ret = sched_setscheduler(pid, sched, &sp); + if (ret) { + perror("sched_set_scheduler"); + exit(EXIT_FAILURE); + } + } else { + int ret; + + ret = setpriority(PRIO_PROCESS, pid, prio); + if (ret) { + perror("setpriority"); + exit(EXIT_FAILURE); + } + } + } + + return 0; +} diff --git a/package/toolbox/src/src/rm.c b/package/toolbox/src/src/rm.c new file mode 100644 index 000000000..4cc4f8a14 --- /dev/null +++ b/package/toolbox/src/src/rm.c @@ -0,0 +1,126 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <dirent.h> +#include <limits.h> +#include <sys/stat.h> +#include <sys/types.h> + +#define OPT_RECURSIVE 1 +#define OPT_FORCE 2 + +static int usage() +{ + fprintf(stderr,"Usage: rm [-rR] [-f] <target>\n"); + return -1; +} + +/* return -1 on failure, with errno set to the first error */ +static int unlink_recursive(const char* name, int flags) +{ + struct stat st; + DIR *dir; + struct dirent *de; + int fail = 0; + + /* is it a file or directory? */ + if (lstat(name, &st) < 0) + return ((flags & OPT_FORCE) && errno == ENOENT) ? 0 : -1; + + /* a file, so unlink it */ + if (!S_ISDIR(st.st_mode)) + return unlink(name); + + /* a directory, so open handle */ + dir = opendir(name); + if (dir == NULL) + return -1; + + /* recurse over components */ + errno = 0; + while ((de = readdir(dir)) != NULL) { + char dn[PATH_MAX]; + if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) + continue; + sprintf(dn, "%s/%s", name, de->d_name); + if (unlink_recursive(dn, flags) < 0) { + if (!(flags & OPT_FORCE)) { + fail = 1; + break; + } + } + errno = 0; + } + /* in case readdir or unlink_recursive failed */ + if (fail || errno < 0) { + int save = errno; + closedir(dir); + errno = save; + return -1; + } + + /* close directory handle */ + if (closedir(dir) < 0) + return -1; + + /* delete target directory */ + return rmdir(name); +} + +int main(int argc, char *argv[]) +{ + int ret; + int i, c; + int flags = 0; + int something_failed = 0; + + if (argc < 2) + return usage(); + + /* check flags */ + do { + c = getopt(argc, argv, "frR"); + if (c == EOF) + break; + switch (c) { + case 'f': + flags |= OPT_FORCE; + break; + case 'r': + case 'R': + flags |= OPT_RECURSIVE; + break; + } + } while (1); + + if (optind < 1 || optind >= argc) { + usage(); + return -1; + } + + /* loop over the file/directory args */ + for (i = optind; i < argc; i++) { + + if (flags & OPT_RECURSIVE) { + ret = unlink_recursive(argv[i], flags); + } else { + ret = unlink(argv[i]); + if (ret < 0 && errno == ENOENT && (flags & OPT_FORCE)) { + continue; + } + } + + if (ret < 0) { + fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno)); + if (!(flags & OPT_FORCE)) { + return -1; + } else { + something_failed = 1; + } + } + } + + return something_failed; +} + diff --git a/package/toolbox/src/src/rmdir.c b/package/toolbox/src/src/rmdir.c new file mode 100644 index 000000000..bec1f406e --- /dev/null +++ b/package/toolbox/src/src/rmdir.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +static int usage() +{ + fprintf(stderr,"rmdir <directory>\n"); + return -1; +} + +int main(int argc, char *argv[]) +{ + int ret; + if(argc < 2) return usage(); + + while(argc > 1) { + argc--; + argv++; + ret = rmdir(argv[0]); + if(ret < 0) { + fprintf(stderr, "rmdir failed for %s, %s\n", argv[0], strerror(errno)); + return ret; + } + } + + return 0; +} diff --git a/package/toolbox/src/src/rmmod.c b/package/toolbox/src/src/rmmod.c new file mode 100644 index 000000000..48ec5b977 --- /dev/null +++ b/package/toolbox/src/src/rmmod.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <malloc.h> +#include <errno.h> +#include <asm/unistd.h> + +extern int delete_module(const char *, unsigned int); + +int main(int argc, char **argv) +{ + int ret, i; + char *modname, *dot; + + /* make sure we've got an argument */ + if (argc < 2) { + fprintf(stderr, "usage: rmmod <module>\n"); + return -1; + } + + /* if given /foo/bar/blah.ko, make a weak attempt + * to convert to "blah", just for convenience + */ + modname = strrchr(argv[1], '/'); + if (!modname) + modname = argv[1]; + else modname++; + + dot = strchr(argv[1], '.'); + if (dot) + *dot = '\0'; + + /* Replace "-" with "_". This would keep rmmod + * compatible with module-init-tools version of + * rmmod + */ + for (i = 0; modname[i] != '\0'; i++) { + if (modname[i] == '-') + modname[i] = '_'; + } + + /* pass it to the kernel */ + ret = delete_module(modname, O_NONBLOCK | O_EXCL); + if (ret != 0) { + fprintf(stderr, "rmmod: delete_module '%s' failed (errno %d)\n", + modname, errno); + return -1; + } + + return 0; +} + diff --git a/package/toolbox/src/src/route.c b/package/toolbox/src/src/route.c new file mode 100644 index 000000000..031d52160 --- /dev/null +++ b/package/toolbox/src/src/route.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <linux/route.h> + +static inline int set_address(const char *address, struct sockaddr *sa) { + return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr); +} + +/* current support the following routing entries */ +/* route add default dev wlan0 */ +/* route add default gw 192.168.1.1 dev wlan0 */ +/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */ + +int main(int argc, char *argv[]) +{ + struct rtentry rt = { + .rt_dst = {.sa_family = AF_INET}, + .rt_genmask = {.sa_family = AF_INET}, + .rt_gateway = {.sa_family = AF_INET}, + }; + + errno = EINVAL; + if (argc > 2 && !strcmp(argv[1], "add")) { + if (!strcmp(argv[2], "default")) { + /* route add default dev wlan0 */ + if (argc > 4 && !strcmp(argv[3], "dev")) { + rt.rt_flags = RTF_UP; + rt.rt_dev = argv[4]; + errno = 0; + goto apply; + } + + /* route add default gw 192.168.1.1 dev wlan0 */ + if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) { + rt.rt_flags = RTF_UP | RTF_GATEWAY; + rt.rt_dev = argv[6]; + if (set_address(argv[4], &rt.rt_gateway)) { + errno = 0; + } + goto apply; + } + } + + /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */ + if (argc > 7 && !strcmp(argv[2], "-net") && + !strcmp(argv[4], "netmask")) { + if (!strcmp(argv[6], "gw")) { + rt.rt_flags = RTF_UP | RTF_GATEWAY; + if (set_address(argv[3], &rt.rt_dst) && + set_address(argv[5], &rt.rt_genmask) && + set_address(argv[7], &rt.rt_gateway)) { + errno = 0; + } + goto apply; + } else if (!strcmp(argv[6], "dev")) { + rt.rt_flags = RTF_UP; + rt.rt_dev = argv[7]; + if (set_address(argv[3], &rt.rt_dst) && + set_address(argv[5], &rt.rt_genmask)) { + errno = 0; + } + goto apply; + } + } + } + +apply: + if (!errno) { + int s = socket(AF_INET, SOCK_DGRAM, 0); + if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) { + return 0; + } + } + puts(strerror(errno)); + return errno; +} diff --git a/package/toolbox/src/src/schedtop.c b/package/toolbox/src/src/schedtop.c new file mode 100644 index 000000000..abbc32861 --- /dev/null +++ b/package/toolbox/src/src/schedtop.c @@ -0,0 +1,332 @@ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <unistd.h> + +#include <stdint.h> +#include <string.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <signal.h> + +#include <pwd.h> + +struct thread_info { + int pid; + int tid; + char name[64]; + unsigned long long exec_time; + unsigned long long delay_time; + uint32_t run_count; +}; + +struct thread_table { + size_t allocated; + size_t active; + struct thread_info *data; +}; + +enum { + FLAG_BATCH = 1U << 0, + FLAG_HIDE_IDLE = 1U << 1, + FLAG_SHOW_THREADS = 1U << 2, + FLAG_USE_ALTERNATE_SCREEN = 1U << 3, +}; + +static int time_dp = 9; +static int time_div = 1; +#define NS_TO_S_D(ns) \ + (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div) + +struct thread_table processes; +struct thread_table last_processes; +struct thread_table threads; +struct thread_table last_threads; + +static void grow_table(struct thread_table *table) +{ + size_t size = table->allocated; + struct thread_info *new_table; + if (size < 128) + size = 128; + else + size *= 2; + + new_table = realloc(table->data, size * sizeof(*table->data)); + if (new_table == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + table->data = new_table; + table->allocated = size; +} + +static struct thread_info *get_item(struct thread_table *table) +{ + if (table->active >= table->allocated) + grow_table(table); + return table->data + table->active; +} + +static void commit_item(struct thread_table *table) +{ + table->active++; +} + +static int read_line(char *line, size_t line_size) +{ + int fd; + int len; + fd = open(line, O_RDONLY); + if(fd == 0) + return -1; + len = read(fd, line, line_size - 1); + close(fd); + if (len <= 0) + return -1; + line[len] = '\0'; + return 0; +} + +static void add_thread(int pid, int tid, struct thread_info *proc_info) +{ + char line[1024]; + char *name, *name_end; + size_t name_len; + struct thread_info *info; + if(tid == 0) + info = get_item(&processes); + else + info = get_item(&threads); + info->pid = pid; + info->tid = tid; + + if(tid) + sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid); + else + sprintf(line, "/proc/%d/schedstat", pid); + if (read_line(line, sizeof(line))) + return; + if(sscanf(line, "%llu %llu %u", &info->exec_time, &info->delay_time, &info->run_count) != 3) + return; + if (proc_info) { + proc_info->exec_time += info->exec_time; + proc_info->delay_time += info->delay_time; + proc_info->run_count += info->run_count; + } + + name = NULL; + if (!tid) { + sprintf(line, "/proc/%d/cmdline", pid); + if (read_line(line, sizeof(line)) == 0 && line[0]) { + name = line; + name_len = strlen(name); + } + } + if (!name) { + if (tid) + sprintf(line, "/proc/%d/task/%d/stat", pid, tid); + else + sprintf(line, "/proc/%d/stat", pid); + if (read_line(line, sizeof(line))) + return; + name = strchr(line, '('); + if (name == NULL) + return; + name_end = strchr(name, ')'); + if (name_end == NULL) + return; + name++; + name_len = name_end - name; + } + if (name_len >= sizeof(info->name)) + name_len = sizeof(info->name) - 1; + memcpy(info->name, name, name_len); + info->name[name_len] = '\0'; + if(tid == 0) + commit_item(&processes); + else + commit_item(&threads); +} + +static void add_threads(int pid, struct thread_info *proc_info) +{ + char path[1024]; + DIR *d; + struct dirent *de; + sprintf(path, "/proc/%d/task", pid); + d = opendir(path); + if(d == 0) return; + while((de = readdir(d)) != 0){ + if(isdigit(de->d_name[0])){ + int tid = atoi(de->d_name); + add_thread(pid, tid, proc_info); + } + } + closedir(d); +} + +static void print_threads(int pid, uint32_t flags) +{ + size_t i, j; + for (i = 0; i < last_threads.active; i++) { + int epid = last_threads.data[i].pid; + int tid = last_threads.data[i].tid; + if (epid != pid) + continue; + for (j = 0; j < threads.active; j++) + if (tid == threads.data[j].tid) + break; + if (j == threads.active) + printf(" %5u died\n", tid); + else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count) + printf(" %5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", tid, + NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time), + NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time), + threads.data[j].run_count - last_threads.data[i].run_count, + NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time), + threads.data[j].run_count, threads.data[j].name); + } +} + +static void update_table(DIR *d, uint32_t flags) +{ + size_t i, j; + struct dirent *de; + + rewinddir(d); + while((de = readdir(d)) != 0){ + if(isdigit(de->d_name[0])){ + int pid = atoi(de->d_name); + struct thread_info *proc_info; + add_thread(pid, 0, NULL); + proc_info = &processes.data[processes.active - 1]; + proc_info->exec_time = 0; + proc_info->delay_time = 0; + proc_info->run_count = 0; + add_threads(pid, proc_info); + } + } + if (!(flags & FLAG_BATCH)) + printf("\e[H\e[0J"); + printf("Processes: %zu, Threads %zu\n", processes.active, threads.active); + switch (time_dp) { + case 3: + printf(" TID --- SINCE LAST ---- ---------- TOTAL ----------\n"); + printf(" PID EXEC_T DELAY SCHED EXEC_TIME DELAY_TIM SCHED NAME\n"); + break; + case 6: + printf(" TID ------ SINCE LAST ------- ------------ TOTAL -----------\n"); + printf(" PID EXEC_TIME DELAY_TIM SCHED EXEC_TIME DELAY_TIME SCHED NAME\n"); + break; + default: + printf(" TID -------- SINCE LAST -------- ------------- TOTAL -------------\n"); + printf(" PID EXEC_TIME DELAY_TIME SCHED EXEC_TIME DELAY_TIME SCHED NAME\n"); + break; + } + for (i = 0; i < last_processes.active; i++) { + int pid = last_processes.data[i].pid; + for (j = 0; j < processes.active; j++) + if (pid == processes.data[j].pid) + break; + if (j == processes.active) + printf("%5u died\n", pid); + else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) { + printf("%5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", pid, + NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time), + NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time), + processes.data[j].run_count - last_processes.data[i].run_count, + NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time), + processes.data[j].run_count, processes.data[j].name); + if (flags & FLAG_SHOW_THREADS) + print_threads(pid, flags); + } + } + + { + struct thread_table tmp; + tmp = last_processes; + last_processes = processes; + processes = tmp; + processes.active = 0; + tmp = last_threads; + last_threads = threads; + threads = tmp; + threads.active = 0; + } +} + +void +sig_abort(int signum) +{ + printf("\e[?47l"); + exit(0); +} + + +int main(int argc, char **argv) +{ + int c; + DIR *d; + uint32_t flags = 0; + int delay = 3000000; + float delay_f; + + while(1) { + c = getopt(argc, argv, "d:ibtamun"); + if (c == EOF) + break; + switch (c) { + case 'd': + delay_f = atof(optarg); + delay = delay_f * 1000000; + break; + case 'b': + flags |= FLAG_BATCH; + break; + case 'i': + flags |= FLAG_HIDE_IDLE; + break; + case 't': + flags |= FLAG_SHOW_THREADS; + break; + case 'a': + flags |= FLAG_USE_ALTERNATE_SCREEN; + break; + case 'm': + time_dp = 3; + time_div = 1000000; + break; + case 'u': + time_dp = 6; + time_div = 1000; + break; + case 'n': + time_dp = 9; + time_div = 1; + break; + } + } + + d = opendir("/proc"); + if(d == 0) return -1; + + if (!(flags & FLAG_BATCH)) { + if(flags & FLAG_USE_ALTERNATE_SCREEN) { + signal(SIGINT, sig_abort); + signal(SIGPIPE, sig_abort); + signal(SIGTERM, sig_abort); + printf("\e7\e[?47h"); + } + printf("\e[2J"); + } + while (1) { + update_table(d, flags); + usleep(delay); + } + closedir(d); + return 0; +} diff --git a/package/toolbox/src/src/setkey.c b/package/toolbox/src/src/setkey.c new file mode 100644 index 000000000..3b4fd700b --- /dev/null +++ b/package/toolbox/src/src/setkey.c @@ -0,0 +1,91 @@ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <linux/kd.h> +#include <linux/vt.h> +#include <errno.h> +#include <sys/ioctl.h> + +static void setkey_usage(char *argv[]) +{ + fprintf(stderr, "%s [-t <table>] [-k <index>] [-v value] [-r] [-h]\n" + " -t <table> Select table\n" + " -k <index> Select key\n" + " -v <value> Set entry\n" + " -r Read current entry\n" + " -h Print help\n", argv[0]); +} + +#define TTYDEV "/dev/tty0" + +int main(int argc, char *argv[]) +{ + int fd; + struct kbentry kbe; + int did_something = 0; + + kbe.kb_table = 0; + kbe.kb_index = -1; + kbe.kb_value = 0; + + fd = open(TTYDEV, O_RDWR | O_SYNC); + if (fd < 0) { + fprintf(stderr, "open %s: %s\n", TTYDEV, strerror(errno)); + return 1; + } + + do { + int c, ret; + + c = getopt(argc, argv, "t:k:v:hr"); + if (c == EOF) + break; + + switch (c) { + case 't': + kbe.kb_table = strtol(optarg, NULL, 0); + break; + case 'k': + kbe.kb_index = strtol(optarg, NULL, 0); + break; + case 'v': + kbe.kb_value = strtol(optarg, NULL, 0); + ret = ioctl(fd, KDSKBENT, &kbe); + if (ret < 0) { + fprintf(stderr, "KDSKBENT %d %d %d failed: %s\n", + kbe.kb_table, kbe.kb_index, kbe.kb_value, + strerror(errno)); + return 1; + } + did_something = 1; + break; + case 'r': + ret = ioctl(fd, KDGKBENT, &kbe); + if (ret < 0) { + fprintf(stderr, "KDGKBENT %d %d failed: %s\n", + kbe.kb_table, kbe.kb_index, strerror(errno)); + return 1; + } + printf("0x%x 0x%x 0x%x\n", + kbe.kb_table, kbe.kb_index, kbe.kb_value); + did_something = 1; + break; + case 'h': + setkey_usage(argv); + return 1; + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + argv[0], optopt); + return 1; + } + } while (1); + + if(optind != argc || !did_something) { + setkey_usage(argv); + return 1; + } + + return 0; +} diff --git a/package/toolbox/src/src/sleep.c b/package/toolbox/src/src/sleep.c new file mode 100644 index 000000000..b83e8ecdb --- /dev/null +++ b/package/toolbox/src/src/sleep.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2008, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +static void +usage(const char *s) +{ + fprintf(stderr, "USAGE: %s SECONDS\n", s); + exit(-1); +} + +int main(int argc, char *argv[]) +{ + unsigned long seconds; + char *endptr; + + if (argc != 2) { + usage(argv[0]); + } + + seconds = strtoul(argv[1], &endptr, 10); + + if (endptr == argv[1]) { + usage(argv[0]); + } + + + sleep((unsigned int)seconds); + + return 0; +} + + diff --git a/package/toolbox/src/src/sync.c b/package/toolbox/src/src/sync.c new file mode 100644 index 000000000..d882a2eef --- /dev/null +++ b/package/toolbox/src/src/sync.c @@ -0,0 +1,7 @@ +#include <unistd.h> + +int main(int argc, char **argv) +{ + sync(); + return 0; +} diff --git a/package/toolbox/src/src/top.c b/package/toolbox/src/src/top.c new file mode 100644 index 000000000..c4ac14ce2 --- /dev/null +++ b/package/toolbox/src/src/top.c @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2008, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctype.h> +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <grp.h> +#include <pwd.h> + +struct cpu_info { + long unsigned utime, ntime, stime, itime; + long unsigned iowtime, irqtime, sirqtime; +}; + +#define PROC_NAME_LEN 64 +#define THREAD_NAME_LEN 32 + +struct proc_info { + struct proc_info *next; + pid_t pid; + pid_t tid; + uid_t uid; + gid_t gid; + char name[PROC_NAME_LEN]; + char tname[THREAD_NAME_LEN]; + char state; + long unsigned utime; + long unsigned stime; + long unsigned delta_utime; + long unsigned delta_stime; + long unsigned delta_time; + long vss; + long rss; + int prs; + int num_threads; +}; + +struct proc_list { + struct proc_info **array; + int size; +}; + +#define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } + +#define INIT_PROCS 50 +#define THREAD_MULT 8 +static struct proc_info **old_procs, **new_procs; +static int num_old_procs, num_new_procs; +static struct proc_info *free_procs; +static int num_used_procs, num_free_procs; + +static int max_procs, delay, iterations, threads; + +static struct cpu_info old_cpu, new_cpu; + +static struct proc_info *alloc_proc(void); +static void free_proc(struct proc_info *proc); +static void read_procs(void); +static int read_stat(char *filename, struct proc_info *proc); +static void add_proc(int proc_num, struct proc_info *proc); +static int read_cmdline(char *filename, struct proc_info *proc); +static int read_status(char *filename, struct proc_info *proc); +static void print_procs(void); +static struct proc_info *find_old_proc(pid_t pid, pid_t tid); +static void free_old_procs(void); +static int (*proc_cmp)(const void *a, const void *b); +static int proc_cpu_cmp(const void *a, const void *b); +static int proc_vss_cmp(const void *a, const void *b); +static int proc_rss_cmp(const void *a, const void *b); +static int proc_thr_cmp(const void *a, const void *b); +static int numcmp(long long a, long long b); +static void usage(char *cmd); + +int main(int argc, char *argv[]) { + int i; + + num_used_procs = num_free_procs = 0; + + max_procs = 0; + delay = 3; + iterations = -1; + proc_cmp = &proc_cpu_cmp; + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-m")) { + if (i + 1 >= argc) { + fprintf(stderr, "Option -m expects an argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + max_procs = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-n")) { + if (i + 1 >= argc) { + fprintf(stderr, "Option -n expects an argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + iterations = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-d")) { + if (i + 1 >= argc) { + fprintf(stderr, "Option -d expects an argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + delay = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-s")) { + if (i + 1 >= argc) { + fprintf(stderr, "Option -s expects an argument.\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + ++i; + if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; } + if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; } + if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; } + if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; } + fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]); + exit(EXIT_FAILURE); + } + if (!strcmp(argv[i], "-t")) { threads = 1; continue; } + if (!strcmp(argv[i], "-h")) { + usage(argv[0]); + exit(EXIT_SUCCESS); + } + fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + if (threads && proc_cmp == &proc_thr_cmp) { + fprintf(stderr, "Sorting by threads per thread makes no sense!\n"); + exit(EXIT_FAILURE); + } + + free_procs = NULL; + + num_new_procs = num_old_procs = 0; + new_procs = old_procs = NULL; + + read_procs(); + while ((iterations == -1) || (iterations-- > 0)) { + old_procs = new_procs; + num_old_procs = num_new_procs; + memcpy(&old_cpu, &new_cpu, sizeof(old_cpu)); + sleep(delay); + read_procs(); + print_procs(); + free_old_procs(); + } + + return 0; +} + +static struct proc_info *alloc_proc(void) { + struct proc_info *proc; + + if (free_procs) { + proc = free_procs; + free_procs = free_procs->next; + num_free_procs--; + } else { + proc = malloc(sizeof(*proc)); + if (!proc) die("Could not allocate struct process_info.\n"); + } + + num_used_procs++; + + return proc; +} + +static void free_proc(struct proc_info *proc) { + proc->next = free_procs; + free_procs = proc; + + num_used_procs--; + num_free_procs++; +} + +#define MAX_LINE 256 + +static void read_procs(void) { + DIR *proc_dir, *task_dir; + struct dirent *pid_dir, *tid_dir; + char filename[64]; + FILE *file; + int proc_num; + struct proc_info *proc; + pid_t pid, tid; + + int i; + + proc_dir = opendir("/proc"); + if (!proc_dir) die("Could not open /proc.\n"); + + new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *)); + num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1); + + file = fopen("/proc/stat", "r"); + if (!file) die("Could not open /proc/stat.\n"); + fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime, + &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime); + fclose(file); + + proc_num = 0; + while ((pid_dir = readdir(proc_dir))) { + if (!isdigit(pid_dir->d_name[0])) + continue; + + pid = atoi(pid_dir->d_name); + + struct proc_info cur_proc; + + if (!threads) { + proc = alloc_proc(); + + proc->pid = proc->tid = pid; + + sprintf(filename, "/proc/%d/stat", pid); + read_stat(filename, proc); + + sprintf(filename, "/proc/%d/cmdline", pid); + read_cmdline(filename, proc); + + sprintf(filename, "/proc/%d/status", pid); + read_status(filename, proc); + + proc->num_threads = 0; + } else { + sprintf(filename, "/proc/%d/cmdline", pid); + read_cmdline(filename, &cur_proc); + + sprintf(filename, "/proc/%d/status", pid); + read_status(filename, &cur_proc); + + proc = NULL; + } + + sprintf(filename, "/proc/%d/task", pid); + task_dir = opendir(filename); + if (!task_dir) continue; + + while ((tid_dir = readdir(task_dir))) { + if (!isdigit(tid_dir->d_name[0])) + continue; + + if (threads) { + tid = atoi(tid_dir->d_name); + + proc = alloc_proc(); + + proc->pid = pid; proc->tid = tid; + + sprintf(filename, "/proc/%d/task/%d/stat", pid, tid); + read_stat(filename, proc); + + strcpy(proc->name, cur_proc.name); + proc->uid = cur_proc.uid; + proc->gid = cur_proc.gid; + + add_proc(proc_num++, proc); + } else { + proc->num_threads++; + } + } + + closedir(task_dir); + + if (!threads) + add_proc(proc_num++, proc); + } + + for (i = proc_num; i < num_new_procs; i++) + new_procs[i] = NULL; + + closedir(proc_dir); +} + +static int read_stat(char *filename, struct proc_info *proc) { + FILE *file; + char buf[MAX_LINE], *open_paren, *close_paren; + + file = fopen(filename, "r"); + if (!file) return 1; + fgets(buf, MAX_LINE, file); + fclose(file); + + /* Split at first '(' and last ')' to get process name. */ + open_paren = strchr(buf, '('); + close_paren = strrchr(buf, ')'); + if (!open_paren || !close_paren) return 1; + + *open_paren = *close_paren = '\0'; + strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN); + proc->tname[THREAD_NAME_LEN-1] = 0; + + /* Scan rest of string. */ + sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " + "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld " + "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d", + &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss, &proc->prs); + + return 0; +} + +static void add_proc(int proc_num, struct proc_info *proc) { + int i; + + if (proc_num >= num_new_procs) { + new_procs = realloc(new_procs, 2 * num_new_procs * sizeof(struct proc_info *)); + if (!new_procs) die("Could not expand procs array.\n"); + for (i = num_new_procs; i < 2 * num_new_procs; i++) + new_procs[i] = NULL; + num_new_procs = 2 * num_new_procs; + } + new_procs[proc_num] = proc; +} + +static int read_cmdline(char *filename, struct proc_info *proc) { + FILE *file; + char line[MAX_LINE]; + + line[0] = '\0'; + file = fopen(filename, "r"); + if (!file) return 1; + fgets(line, MAX_LINE, file); + fclose(file); + if (strlen(line) > 0) { + strncpy(proc->name, line, PROC_NAME_LEN); + proc->name[PROC_NAME_LEN-1] = 0; + } else + proc->name[0] = 0; + return 0; +} + +static int read_status(char *filename, struct proc_info *proc) { + FILE *file; + char line[MAX_LINE]; + unsigned int uid, gid; + + file = fopen(filename, "r"); + if (!file) return 1; + while (fgets(line, MAX_LINE, file)) { + sscanf(line, "Uid: %u", &uid); + sscanf(line, "Gid: %u", &gid); + } + fclose(file); + proc->uid = uid; proc->gid = gid; + return 0; +} + +static void print_procs(void) { + int i; + struct proc_info *old_proc, *proc; + long unsigned total_delta_time; + struct passwd *user; + char *user_str, user_buf[20]; + + for (i = 0; i < num_new_procs; i++) { + if (new_procs[i]) { + old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid); + if (old_proc) { + new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime; + new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime; + } else { + new_procs[i]->delta_utime = 0; + new_procs[i]->delta_stime = 0; + } + new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime; + } + } + + total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime + + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime) + - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime + + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime); + + qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp); + + printf("\n\n\n"); + printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n", + ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100 / total_delta_time, + ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time, + ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time, + ((new_cpu.irqtime + new_cpu.sirqtime) + - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time); + printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n", + new_cpu.utime - old_cpu.utime, + new_cpu.ntime - old_cpu.ntime, + new_cpu.stime - old_cpu.stime, + new_cpu.itime - old_cpu.itime, + new_cpu.iowtime - old_cpu.iowtime, + new_cpu.irqtime - old_cpu.irqtime, + new_cpu.sirqtime - old_cpu.sirqtime, + total_delta_time); + printf("\n"); + if (!threads) + printf("%5s %2s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "PR", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name"); + else + printf("%5s %5s %2s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "PR", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc"); + + for (i = 0; i < num_new_procs; i++) { + proc = new_procs[i]; + + if (!proc || (max_procs && (i >= max_procs))) + break; + user = getpwuid(proc->uid); + if (user && user->pw_name) { + user_str = user->pw_name; + } else { + snprintf(user_buf, 20, "%d", proc->uid); + user_str = user_buf; + } + if (!threads) + printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads, + proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->name[0] != 0 ? proc->name : proc->tname); + else + printf("%5d %5d %2d %3ld%% %c %6ldK %6ldK %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, + proc->vss / 1024, proc->rss * getpagesize() / 1024, user_str, proc->tname, proc->name); + } +} + +static struct proc_info *find_old_proc(pid_t pid, pid_t tid) { + int i; + + for (i = 0; i < num_old_procs; i++) + if (old_procs[i] && (old_procs[i]->pid == pid) && (old_procs[i]->tid == tid)) + return old_procs[i]; + + return NULL; +} + +static void free_old_procs(void) { + int i; + + for (i = 0; i < num_old_procs; i++) + if (old_procs[i]) + free_proc(old_procs[i]); + + free(old_procs); +} + +static int proc_cpu_cmp(const void *a, const void *b) { + struct proc_info *pa, *pb; + + pa = *((struct proc_info **)a); pb = *((struct proc_info **)b); + + if (!pa && !pb) return 0; + if (!pa) return 1; + if (!pb) return -1; + + return -numcmp(pa->delta_time, pb->delta_time); +} + +static int proc_vss_cmp(const void *a, const void *b) { + struct proc_info *pa, *pb; + + pa = *((struct proc_info **)a); pb = *((struct proc_info **)b); + + if (!pa && !pb) return 0; + if (!pa) return 1; + if (!pb) return -1; + + return -numcmp(pa->vss, pb->vss); +} + +static int proc_rss_cmp(const void *a, const void *b) { + struct proc_info *pa, *pb; + + pa = *((struct proc_info **)a); pb = *((struct proc_info **)b); + + if (!pa && !pb) return 0; + if (!pa) return 1; + if (!pb) return -1; + + return -numcmp(pa->rss, pb->rss); +} + +static int proc_thr_cmp(const void *a, const void *b) { + struct proc_info *pa, *pb; + + pa = *((struct proc_info **)a); pb = *((struct proc_info **)b); + + if (!pa && !pb) return 0; + if (!pa) return 1; + if (!pb) return -1; + + return -numcmp(pa->num_threads, pb->num_threads); +} + +static int numcmp(long long a, long long b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +static void usage(char *cmd) { + fprintf(stderr, "Usage: %s [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]\n" + " -m num Maximum number of processes to display.\n" + " -n num Updates to show before exiting.\n" + " -d num Seconds to wait between updates.\n" + " -s col Column to sort by (cpu,vss,rss,thr).\n" + " -t Show threads instead of processes.\n" + " -h Display this help screen.\n", + cmd); +} diff --git a/package/toolbox/src/src/touch.c b/package/toolbox/src/src/touch.c new file mode 100644 index 000000000..7c38aa05a --- /dev/null +++ b/package/toolbox/src/src/touch.c @@ -0,0 +1,115 @@ +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <fcntl.h> +#include <time.h> +#include <unistd.h> + +static void usage(void) +{ + fprintf(stderr, "touch: usage: touch [-alm] [-t YYYYMMDD[.hhmmss]] <file>\n"); + exit(1); +} + +static time_t parse_time(char *s) +{ + struct tm tm; + int day = atoi(s); + int hour = 0; + + while (*s && *s != '.') { + s++; + } + + if (*s) { + s++; + hour = atoi(s); + } + + tm.tm_year = day / 10000 - 1900; + tm.tm_mon = (day % 10000) / 100 - 1; + tm.tm_mday = day % 100; + tm.tm_hour = hour / 10000; + tm.tm_min = (hour % 10000) / 100; + tm.tm_sec = hour % 100; + tm.tm_isdst = -1; + + return mktime(&tm); +} + +int main(int argc, char *argv[]) +{ + int i, fd, aflag = 0, mflag = 0, debug = 0, flags = 0; + struct timespec specified_time, times[2]; + char *file = 0; + + specified_time.tv_nsec = UTIME_NOW; + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + /* an option */ + const char *arg = argv[i]+1; + while (arg[0]) { + switch (arg[0]) { + case 'a': aflag = 1; break; + case 'm': mflag = 1; break; + case 't': + if ((i+1) >= argc) + usage(); + specified_time.tv_sec = parse_time(argv[++i]); + if (specified_time.tv_sec == -1) { + fprintf(stderr, "touch: invalid timestamp specified\n"); + exit(1); + } + specified_time.tv_nsec = 0; + break; + case 'l': flags |= AT_SYMLINK_NOFOLLOW; break; + case 'd': debug = 1; break; + default: + usage(); + } + arg++; + } + } else { + /* not an option, and only accept one filename */ + if (i+1 != argc) + usage(); + file = argv[i]; + } + } + + if (! file) { + fprintf(stderr, "touch: no file specified\n"); + exit(1); + } + + if (access(file, F_OK)) + if ((fd=creat(file, 0666)) != -1) + close(fd); + + if ((mflag == 0) && (aflag == 0)) + aflag = mflag = 1; + + if (aflag) + times[0] = specified_time; + else + times[0].tv_nsec = UTIME_OMIT; + + if (mflag) + times[1] = specified_time; + else + times[1].tv_nsec = UTIME_OMIT; + + if (debug) { + fprintf(stderr, "file = %s\n", file); + fprintf(stderr, "times[0].tv_sec = %lld, times[0].tv_nsec = %ld\n", (long long)times[0].tv_sec, (long)times[0].tv_nsec); + fprintf(stderr, "times[1].tv_sec = %lld, times[1].tv_nsec = %ld\n", (long long)times[1].tv_sec, (long)times[1].tv_nsec); + fprintf(stderr, "flags = 0x%8.8x\n", flags); + } + + return utimensat(AT_FDCWD, file, times, flags); +} + diff --git a/package/toolbox/src/src/umount.c b/package/toolbox/src/src/umount.c new file mode 100644 index 000000000..aee3bdd39 --- /dev/null +++ b/package/toolbox/src/src/umount.c @@ -0,0 +1,91 @@ + +#include <sys/mount.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <linux/loop.h> +#include <errno.h> + +#define LOOPDEV_MAXLEN 64 +#define LOOP_MAJOR 7 + +static int is_loop(char *dev) +{ + struct stat st; + int ret = 0; + + if (stat(dev, &st) == 0) { + if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) { + ret = 1; + } + } + + return ret; +} + +static int is_loop_mount(const char* path, char *loopdev) +{ + FILE* f; + int count; + char device[256]; + char mount_path[256]; + char rest[256]; + int result = 0; + + f = fopen("/proc/mounts", "r"); + if (!f) { + fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno)); + return -1; + } + + do { + count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest); + if (count == 3) { + if (is_loop(device) && strcmp(path, mount_path) == 0) { + strlcpy(loopdev, device, LOOPDEV_MAXLEN); + result = 1; + break; + } + } + } while (count == 3); + + fclose(f); + return result; +} + +int main(int argc, char *argv[]) +{ + int loop, loop_fd; + char loopdev[LOOPDEV_MAXLEN]; + + if(argc != 2) { + fprintf(stderr,"umount <path>\n"); + return 1; + } + + loop = is_loop_mount(argv[1], loopdev); + if (umount(argv[1])) { + fprintf(stderr, "failed: %s\n", strerror(errno)); + return 1; + } + + if (loop) { + // free the loop device + loop_fd = open(loopdev, O_RDONLY); + if (loop_fd < 0) { + fprintf(stderr, "open loop device failed: %s\n", strerror(errno)); + return 1; + } + if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) { + fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno)); + return 1; + } + + close(loop_fd); + } + + return 0; +} diff --git a/package/toolbox/src/src/vmstat.c b/package/toolbox/src/src/vmstat.c new file mode 100644 index 000000000..1ede95977 --- /dev/null +++ b/package/toolbox/src/src/vmstat.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2008, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <unistd.h> + +struct state { + long procs_r; + long procs_b; + + long mem_free; + long mem_mapped; + long mem_anon; + long mem_slab; + + long sys_in; + long sys_cs; + long sys_flt; + + long cpu_us; + long cpu_ni; + long cpu_sy; + long cpu_id; + long cpu_wa; + long cpu_ir; + long cpu_si; +}; + +#define MAX_LINE 256 + +char line[MAX_LINE]; + +static void read_state(struct state *s); +static int read_meminfo(struct state *s); +static int read_stat(struct state *s); +static int read_vmstat(struct state *s); +static void print_header(void); +static void print_line(struct state *old, struct state *new); +static void usage(char *cmd); + +int main(int argc, char *argv[]) { + struct state s[2]; + int iterations, delay, header_interval; + int toggle, count; + int i; + + iterations = -1; + delay = 1; + header_interval = 20; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-n")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -n requires an argument.\n"); + exit(EXIT_FAILURE); + } + iterations = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-d")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -d requires an argument.\n"); + exit(EXIT_FAILURE); + } + delay = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-r")) { + if (i >= argc - 1) { + fprintf(stderr, "Option -r requires an argument.\n"); + exit(EXIT_FAILURE); + } + header_interval = atoi(argv[++i]); + continue; + } + if (!strcmp(argv[i], "-h")) { + usage(argv[0]); + exit(EXIT_SUCCESS); + } + fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + toggle = 0; + count = 0; + + if (!header_interval) + print_header(); + read_state(&s[1 - toggle]); + while ((iterations < 0) || (iterations-- > 0)) { + sleep(delay); + read_state(&s[toggle]); + if (header_interval) { + if (count == 0) + print_header(); + count = (count + 1) % header_interval; + } + print_line(&s[1 - toggle], &s[toggle]); + toggle = 1 - toggle; + } + + return 0; +} + +static void read_state(struct state *s) { + int error; + + error = read_meminfo(s); + if (error) { + fprintf(stderr, "vmstat: could not read /proc/meminfo: %s\n", strerror(error)); + exit(EXIT_FAILURE); + } + + error = read_stat(s); + if (error) { + fprintf(stderr, "vmstat: could not read /proc/stat: %s\n", strerror(error)); + exit(EXIT_FAILURE); + } + + error = read_vmstat(s); + if (error) { + fprintf(stderr, "vmstat: could not read /proc/vmstat: %s\n", strerror(error)); + exit(EXIT_FAILURE); + } +} + +static int read_meminfo(struct state *s) { + FILE *f; + + f = fopen("/proc/meminfo", "r"); + if (!f) return errno; + + while (fgets(line, MAX_LINE, f)) { + sscanf(line, "MemFree: %ld kB", &s->mem_free); + sscanf(line, "AnonPages: %ld kB", &s->mem_anon); + sscanf(line, "Mapped: %ld kB", &s->mem_mapped); + sscanf(line, "Slab: %ld kB", &s->mem_slab); + } + + fclose(f); + + return 0; +} + +static int read_stat(struct state *s) { + FILE *f; + + f = fopen("/proc/stat", "r"); + if (!f) return errno; + + while (fgets(line, MAX_LINE, f)) { + if (!strncmp(line, "cpu ", 4)) { + sscanf(line, "cpu %ld %ld %ld %ld %ld %ld %ld", + &s->cpu_us, &s->cpu_ni, &s->cpu_sy, &s->cpu_id, &s->cpu_wa, + &s->cpu_ir, &s->cpu_si); + } + sscanf(line, "intr %ld", &s->sys_in); + sscanf(line, "ctxt %ld", &s->sys_cs); + sscanf(line, "procs_running %ld", &s->procs_r); + sscanf(line, "procs_blocked %ld", &s->procs_b); + } + + fclose(f); + + return 0; +} + +static int read_vmstat(struct state *s) { + FILE *f; + + f = fopen("/proc/vmstat", "r"); + if (!f) return errno; + + while (fgets(line, MAX_LINE, f)) { + sscanf(line, "pgmajfault %ld", &s->sys_flt); + } + + fclose(f); + + return 0; +} + +static void print_header(void) { + printf("%-5s %-27s %-14s %-17s\n", "procs", "memory", "system", "cpu"); + printf("%2s %2s %6s %6s %6s %6s %4s %4s %4s %2s %2s %2s %2s %2s %2s\n", "r", "b", "free", "mapped", "anon", "slab", "in", "cs", "flt", "us", "ni", "sy", "id", "wa", "ir"); +} + +/* Jiffies to percent conversion */ +#define JP(jif) ((jif) * 100 / (HZ)) +#define NORM(var) ((var) = (((var) > 99) ? (99) : (var))) + +static void print_line(struct state *old, struct state *new) { + int us, ni, sy, id, wa, ir; + us = JP(new->cpu_us - old->cpu_us); NORM(us); + ni = JP(new->cpu_ni - old->cpu_ni); NORM(ni); + sy = JP(new->cpu_sy - old->cpu_sy); NORM(sy); + id = JP(new->cpu_id - old->cpu_id); NORM(id); + wa = JP(new->cpu_wa - old->cpu_wa); NORM(wa); + ir = JP(new->cpu_ir - old->cpu_ir); NORM(ir); + printf("%2ld %2ld %6ld %6ld %6ld %6ld %4ld %4ld %4ld %2d %2d %2d %2d %2d %2d\n", + new->procs_r ? (new->procs_r - 1) : 0, new->procs_b, + new->mem_free, new->mem_mapped, new->mem_anon, new->mem_slab, + new->sys_in - old->sys_in, new->sys_cs - old->sys_cs, new->sys_flt - old->sys_flt, + us, ni, sy, id, wa, ir); +} + +static void usage(char *cmd) { + fprintf(stderr, "Usage: %s [ -h ] [ -n iterations ] [ -d delay ] [ -r header_repeat ]\n" + " -n iterations How many rows of data to print.\n" + " -d delay How long to sleep between rows.\n" + " -r header_repeat How many rows to print before repeating\n" + " the header. Zero means never repeat.\n" + " -h Displays this help screen.\n", + cmd); +} diff --git a/package/toolbox/src/sync/Makefile b/package/toolbox/src/sync/Makefile new file mode 100644 index 000000000..83495e9e8 --- /dev/null +++ b/package/toolbox/src/sync/Makefile @@ -0,0 +1,3 @@ +PROG= sync + +include ../tool.mk diff --git a/package/toolbox/src/tool.mk b/package/toolbox/src/tool.mk new file mode 100644 index 000000000..883518b7d --- /dev/null +++ b/package/toolbox/src/tool.mk @@ -0,0 +1,22 @@ +SRCS?= ${PROG:=.c} + +include ./common.mk + +CPPFLAGS+= -I../src +LDFLAGS+= -L../lib +LIBS+= -loadk_toolbox +VPATH= ../src + +all: ${PROG} + +${PROG}: ${OBJS} + ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + -Wl,--start-group ${OBJS} ${LIBS} -Wl,--end-group + +DESTDIR?= +BINDIR?=/bin +INSTALL?=/usr/bin/install + +install: + ${INSTALL} -d ${DESTDIR}${BINDIR}/ + ${INSTALL} -c -m 755 ${PROG} ${DESTDIR}${BINDIR}/ diff --git a/package/toolbox/src/top/Makefile b/package/toolbox/src/top/Makefile new file mode 100644 index 000000000..938b40708 --- /dev/null +++ b/package/toolbox/src/top/Makefile @@ -0,0 +1,3 @@ +PROG= top + +include ../tool.mk diff --git a/package/toolbox/src/touch/Makefile b/package/toolbox/src/touch/Makefile new file mode 100644 index 000000000..a6be25993 --- /dev/null +++ b/package/toolbox/src/touch/Makefile @@ -0,0 +1,3 @@ +PROG= touch + +include ../tool.mk diff --git a/package/toolbox/src/umount/Makefile b/package/toolbox/src/umount/Makefile new file mode 100644 index 000000000..333256097 --- /dev/null +++ b/package/toolbox/src/umount/Makefile @@ -0,0 +1,3 @@ +PROG= umount + +include ../tool.mk diff --git a/package/toolbox/src/vmstat/Makefile b/package/toolbox/src/vmstat/Makefile new file mode 100644 index 000000000..ea1d6b35e --- /dev/null +++ b/package/toolbox/src/vmstat/Makefile @@ -0,0 +1,3 @@ +PROG= vmstat + +include ../tool.mk diff --git a/target/config/Config.in.runtime b/target/config/Config.in.runtime index 67ec0ef1a..74caa19e8 100644 --- a/target/config/Config.in.runtime +++ b/target/config/Config.in.runtime @@ -85,6 +85,7 @@ endchoice choice prompt "base applications" depends on !ADK_APPLIANCE_TOOLCHAIN +default ADK_RUNTIME_BASE_TOOLBOX if ADK_TARGET_ARCH_H8300 default ADK_RUNTIME_BASE_BUSYBOX config ADK_RUNTIME_BASE_BUSYBOX @@ -95,6 +96,10 @@ config ADK_RUNTIME_BASE_TOYBOX bool "Use toybox" select ADK_PACKAGE_TOYBOX +config ADK_RUNTIME_BASE_TOOLBOX + bool "Use toolbox" + select ADK_PACKAGE_TOOLBOX + config ADK_RUNTIME_BASE_COREUTILS bool "Use coreutils" select ADK_PACKAGE_COREUTILS |