summaryrefslogtreecommitdiff
path: root/busybox/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'busybox/libbb')
-rw-r--r--busybox/libbb/.cvsignore1
-rw-r--r--busybox/libbb/Makefile32
-rw-r--r--busybox/libbb/Makefile.in107
-rw-r--r--busybox/libbb/README11
-rw-r--r--busybox/libbb/ask_confirmation.c49
-rw-r--r--busybox/libbb/bb_askpass.c87
-rw-r--r--busybox/libbb/bb_asprintf.c22
-rw-r--r--busybox/libbb/change_identity.c62
-rw-r--r--busybox/libbb/chomp.c45
-rw-r--r--busybox/libbb/compare_string_array.c31
-rw-r--r--busybox/libbb/concat_path_file.c44
-rw-r--r--busybox/libbb/concat_subpath_file.c36
-rw-r--r--busybox/libbb/copy_file.c268
-rw-r--r--busybox/libbb/copyfd.c90
-rw-r--r--busybox/libbb/correct_password.c77
-rw-r--r--busybox/libbb/create_icmp6_socket.c39
-rw-r--r--busybox/libbb/create_icmp_socket.c37
-rw-r--r--busybox/libbb/default_error_retval.c32
-rw-r--r--busybox/libbb/device_open.c53
-rw-r--r--busybox/libbb/dump.c819
-rw-r--r--busybox/libbb/error_msg.c46
-rw-r--r--busybox/libbb/error_msg_and_die.c47
-rw-r--r--busybox/libbb/fclose_nonstdin.c37
-rw-r--r--busybox/libbb/fflush_stdout_and_exit.c37
-rw-r--r--busybox/libbb/fgets_str.c67
-rw-r--r--busybox/libbb/find_mount_point.c75
-rw-r--r--busybox/libbb/find_pid_by_name.c70
-rw-r--r--busybox/libbb/find_root_device.c89
-rw-r--r--busybox/libbb/full_read.c63
-rw-r--r--busybox/libbb/full_write.c60
-rw-r--r--busybox/libbb/get_console.c99
-rw-r--r--busybox/libbb/get_last_path_component.c56
-rw-r--r--busybox/libbb/get_line_from_file.c82
-rw-r--r--busybox/libbb/get_terminal_width_height.c66
-rw-r--r--busybox/libbb/get_ug_id.c30
-rw-r--r--busybox/libbb/getopt_ulflags.c171
-rw-r--r--busybox/libbb/hash_fd.c859
-rw-r--r--busybox/libbb/herror_msg.c44
-rw-r--r--busybox/libbb/herror_msg_and_die.c45
-rw-r--r--busybox/libbb/human_readable.c87
-rw-r--r--busybox/libbb/inet_common.c249
-rw-r--r--busybox/libbb/inode_hash.c111
-rw-r--r--busybox/libbb/interface.c2083
-rw-r--r--busybox/libbb/isdirectory.c60
-rw-r--r--busybox/libbb/kernel_version.c60
-rw-r--r--busybox/libbb/last_char_is.c38
-rw-r--r--busybox/libbb/llist_add_to.c15
-rw-r--r--busybox/libbb/login.c128
-rw-r--r--busybox/libbb/loop.c157
-rw-r--r--busybox/libbb/make_directory.c117
-rw-r--r--busybox/libbb/messages.c96
-rw-r--r--busybox/libbb/mode_string.c139
-rw-r--r--busybox/libbb/module_syscalls.c116
-rw-r--r--busybox/libbb/mtab.c116
-rw-r--r--busybox/libbb/mtab_file.c42
-rw-r--r--busybox/libbb/my_getgrgid.c57
-rw-r--r--busybox/libbb/my_getgrnam.c49
-rw-r--r--busybox/libbb/my_getpwnam.c49
-rw-r--r--busybox/libbb/my_getpwuid.c56
-rw-r--r--busybox/libbb/my_getug.c64
-rw-r--r--busybox/libbb/obscure.c251
-rw-r--r--busybox/libbb/parse_mode.c177
-rw-r--r--busybox/libbb/parse_number.c64
-rw-r--r--busybox/libbb/perror_msg.c45
-rw-r--r--busybox/libbb/perror_msg_and_die.c46
-rw-r--r--busybox/libbb/perror_nomsg.c30
-rw-r--r--busybox/libbb/perror_nomsg_and_die.c30
-rw-r--r--busybox/libbb/print_file.c76
-rw-r--r--busybox/libbb/printf.c181
-rw-r--r--busybox/libbb/process_escape_sequence.c112
-rw-r--r--busybox/libbb/procps.c158
-rw-r--r--busybox/libbb/pw_encrypt.c45
-rw-r--r--busybox/libbb/pwd2spwd.c74
-rw-r--r--busybox/libbb/qmodule.c29
-rw-r--r--busybox/libbb/read_package_field.c114
-rw-r--r--busybox/libbb/recursive_action.c141
-rw-r--r--busybox/libbb/remove_file.c124
-rw-r--r--busybox/libbb/restricted_shell.c57
-rw-r--r--busybox/libbb/run_parts.c126
-rw-r--r--busybox/libbb/run_shell.c87
-rw-r--r--busybox/libbb/safe_read.c48
-rw-r--r--busybox/libbb/safe_strncpy.c42
-rw-r--r--busybox/libbb/safe_strtol.c92
-rw-r--r--busybox/libbb/safe_write.c48
-rw-r--r--busybox/libbb/setup_environment.c93
-rw-r--r--busybox/libbb/simplify_path.c64
-rw-r--r--busybox/libbb/skip_whitespace.c33
-rw-r--r--busybox/libbb/speed_table.c130
-rw-r--r--busybox/libbb/syscalls.c105
-rw-r--r--busybox/libbb/syslog_msg_with_name.c0
-rw-r--r--busybox/libbb/trim.c49
-rw-r--r--busybox/libbb/u_signal_names.c189
-rw-r--r--busybox/libbb/vdprintf.c47
-rw-r--r--busybox/libbb/verror_msg.c43
-rw-r--r--busybox/libbb/vfork_daemon_rexec.c78
-rw-r--r--busybox/libbb/vherror_msg.c37
-rw-r--r--busybox/libbb/vperror_msg.c45
-rw-r--r--busybox/libbb/warn_ignoring_args.c30
-rw-r--r--busybox/libbb/wfopen.c44
-rw-r--r--busybox/libbb/wfopen_input.c54
-rw-r--r--busybox/libbb/xconnect.c71
-rw-r--r--busybox/libbb/xfuncs.c197
-rw-r--r--busybox/libbb/xgetcwd.c48
-rw-r--r--busybox/libbb/xgethostbyname.c35
-rw-r--r--busybox/libbb/xgethostbyname2.c37
-rw-r--r--busybox/libbb/xgetlarg.c35
-rw-r--r--busybox/libbb/xgetularg.c160
-rw-r--r--busybox/libbb/xreadlink.c37
-rw-r--r--busybox/libbb/xregcomp.c49
109 files changed, 11781 insertions, 0 deletions
diff --git a/busybox/libbb/.cvsignore b/busybox/libbb/.cvsignore
new file mode 100644
index 0000000..2bbe016
--- /dev/null
+++ b/busybox/libbb/.cvsignore
@@ -0,0 +1 @@
+loop.h
diff --git a/busybox/libbb/Makefile b/busybox/libbb/Makefile
new file mode 100644
index 0000000..e94c052
--- /dev/null
+++ b/busybox/libbb/Makefile
@@ -0,0 +1,32 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+top_srcdir=..
+top_builddir=..
+srcdir=$(top_srcdir)/libbb
+LIBBB_DIR:=./
+include $(top_builddir)/Rules.mak
+include $(top_builddir)/.config
+include Makefile.in
+all: $(libraries-y)
+-include $(top_builddir)/.depend
+
+clean:
+ rm -f *.o *.a $(AR_TARGET)
+
diff --git a/busybox/libbb/Makefile.in b/busybox/libbb/Makefile.in
new file mode 100644
index 0000000..85d4a96
--- /dev/null
+++ b/busybox/libbb/Makefile.in
@@ -0,0 +1,107 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+LIBBB_AR:=libbb.a
+ifndef $(LIBBB_DIR)
+LIBBB_DIR:=$(top_builddir)/libbb/
+endif
+srcdir=$(top_srcdir)/libbb
+
+LIBBB_SRC:= \
+ bb_asprintf.c ask_confirmation.c change_identity.c chomp.c \
+ compare_string_array.c concat_path_file.c copy_file.c copyfd.c \
+ correct_password.c create_icmp_socket.c create_icmp6_socket.c \
+ device_open.c dump.c error_msg.c error_msg_and_die.c find_mount_point.c \
+ find_pid_by_name.c find_root_device.c fgets_str.c full_read.c \
+ full_write.c get_last_path_component.c get_line_from_file.c get_ug_id.c \
+ get_terminal_width_height.c hash_fd.c herror_msg.c herror_msg_and_die.c \
+ human_readable.c inet_common.c inode_hash.c interface.c isdirectory.c \
+ kernel_version.c last_char_is.c llist_add_to.c login.c loop.c \
+ make_directory.c mode_string.c module_syscalls.c mtab.c mtab_file.c \
+ my_getgrgid.c my_getgrnam.c my_getpwnam.c my_getug.c\
+ my_getpwuid.c obscure.c parse_mode.c parse_number.c perror_msg.c \
+ perror_msg_and_die.c print_file.c get_console.c \
+ process_escape_sequence.c procps.c pwd2spwd.c pw_encrypt.c qmodule.c \
+ read_package_field.c recursive_action.c remove_file.c \
+ restricted_shell.c run_parts.c run_shell.c safe_read.c safe_write.c \
+ safe_strncpy.c setup_environment.c simplify_path.c syscalls.c \
+ trim.c u_signal_names.c vdprintf.c verror_msg.c \
+ vherror_msg.c vperror_msg.c wfopen.c xconnect.c xgetcwd.c \
+ xgethostbyname.c xgethostbyname2.c xreadlink.c xregcomp.c xgetlarg.c \
+ get_terminal_width_height.c fclose_nonstdin.c fflush_stdout_and_exit.c \
+ getopt_ulflags.c default_error_retval.c wfopen_input.c speed_table.c \
+ perror_nomsg_and_die.c perror_nomsg.c skip_whitespace.c bb_askpass.c \
+ warn_ignoring_args.c concat_subpath_file.c vfork_daemon_rexec.c
+
+LIBBB_OBJS=$(patsubst %.c,$(LIBBB_DIR)%.o, $(LIBBB_SRC))
+
+LIBBB_MSRC0:=$(srcdir)/messages.c
+LIBBB_MOBJ0:=full_version.o \
+ memory_exhausted.o invalid_date.o io_error.o \
+ write_error.o name_longer_than_foo.o unknown.o \
+ can_not_create_raw_socket.o perm_denied_are_you_root.o \
+ shadow_file.o passwd_file.o group_file.o gshadow_file.o nologin_file.o \
+ securetty_file.o motd_file.o \
+ msg_standard_input.o msg_standard_output.o shell_file.o
+
+LIBBB_MSRC1:=$(srcdir)/xfuncs.c
+LIBBB_MOBJ1:=xmalloc.o xrealloc.o xcalloc.o xstrdup.o xstrndup.o \
+ xfopen.o xopen.o xread.o xread_all.o xread_char.o \
+ xferror.o xferror_stdout.o xfflush_stdout.o strlen.o
+
+LIBBB_MSRC2:=$(srcdir)/printf.c
+LIBBB_MOBJ2:=bb_vfprintf.o bb_vprintf.o bb_fprintf.o bb_printf.o
+
+LIBBB_MSRC3:=$(srcdir)/xgetularg.c
+LIBBB_MOBJ3:=xgetularg_bnd_sfx.o xgetlarg_bnd_sfx.o getlarg10_sfx.o \
+ xgetularg_bnd.o xgetularg10_bnd.o xgetularg10.o
+
+LIBBB_MSRC4:=$(srcdir)/safe_strtol.c
+LIBBB_MOBJ4:=safe_strtoi.o safe_strtod.o safe_strtol.o safe_strtoul.o
+
+LIBBB_MOBJS0=$(patsubst %,$(LIBBB_DIR)%, $(LIBBB_MOBJ0))
+LIBBB_MOBJS1=$(patsubst %,$(LIBBB_DIR)%, $(LIBBB_MOBJ1))
+LIBBB_MOBJS2=$(patsubst %,$(LIBBB_DIR)%, $(LIBBB_MOBJ2))
+LIBBB_MOBJS3=$(patsubst %,$(LIBBB_DIR)%, $(LIBBB_MOBJ3))
+LIBBB_MOBJS4=$(patsubst %,$(LIBBB_DIR)%, $(LIBBB_MOBJ4))
+
+libraries-y+=$(LIBBB_DIR)$(LIBBB_AR)
+
+$(LIBBB_DIR)$(LIBBB_AR): $(LIBBB_OBJS) $(LIBBB_MOBJS0) $(LIBBB_MOBJS1) \
+ $(LIBBB_MOBJS2) $(LIBBB_MOBJS3) $(LIBBB_MOBJS4)
+ $(AR) -ro $@ $(LIBBB_OBJS) $(LIBBB_MOBJS0) $(LIBBB_MOBJS1) \
+ $(LIBBB_MOBJS2) $(LIBBB_MOBJS3) $(LIBBB_MOBJS4)
+
+$(LIBBB_DIR)%.o: $(srcdir)/%.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+$(LIBBB_MOBJS0): $(LIBBB_MSRC0)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DL_$(notdir $*) -c $< -o $@
+
+$(LIBBB_MOBJS1): $(LIBBB_MSRC1)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DL_$(notdir $*) -c $< -o $@
+
+$(LIBBB_MOBJS2): $(LIBBB_MSRC2)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DL_$(notdir $*) -c $< -o $@
+
+$(LIBBB_MOBJS3): $(LIBBB_MSRC3)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DL_$(notdir $*) -c $< -o $@
+
+$(LIBBB_MOBJS4): $(LIBBB_MSRC4)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DL_$(notdir $*) -c $< -o $@
+
diff --git a/busybox/libbb/README b/busybox/libbb/README
new file mode 100644
index 0000000..4f28f7e
--- /dev/null
+++ b/busybox/libbb/README
@@ -0,0 +1,11 @@
+Please see the LICENSE file for copyright information (GPLv2)
+
+libbb is BusyBox's utility library. All of this stuff used to be stuffed into
+a single file named utility.c. When I split utility.c to create libbb, some of
+the very oldest stuff ended up without their original copyright and licensing
+information (which is now lost in the mists of time). If you see something
+that you wrote that is mis-attributed, do let me know so we can fix that up.
+
+ Erik Andersen
+ <andersen@codepoet.org>
+
diff --git a/busybox/libbb/ask_confirmation.c b/busybox/libbb/ask_confirmation.c
new file mode 100644
index 0000000..a99a4e7
--- /dev/null
+++ b/busybox/libbb/ask_confirmation.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_ask_confirmation implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Read a line from stdin. If the first non-whitespace char is 'y' or 'Y',
+ * return 1. Otherwise return 0.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "libbb.h"
+
+int bb_ask_confirmation(void)
+{
+ int retval = 0;
+ int first = 1;
+ int c;
+
+ while (((c = getchar()) != EOF) && (c != '\n')) {
+ /* Make sure we get the actual function call for isspace,
+ * as speed is not critical here. */
+ if (first && !(isspace)(c)) {
+ --first;
+ if ((c == 'y') || (c == 'Y')) {
+ ++retval;
+ }
+ }
+ }
+
+ return retval;
+}
diff --git a/busybox/libbb/bb_askpass.c b/busybox/libbb/bb_askpass.c
new file mode 100644
index 0000000..1ae1520
--- /dev/null
+++ b/busybox/libbb/bb_askpass.c
@@ -0,0 +1,87 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Ask for a password
+ * I use a static buffer in this function. Plan accordingly.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#define PWD_BUFFER_SIZE 256
+
+
+/* do nothing signal handler */
+static void askpass_timeout(int ignore)
+{
+}
+
+char *bb_askpass(int timeout, const char * prompt)
+{
+ char *ret;
+ int i, size;
+ struct sigaction sa;
+ struct termios old, new;
+ static char passwd[PWD_BUFFER_SIZE];
+
+ tcgetattr(STDIN_FILENO, &old);
+
+ size = sizeof(passwd);
+ ret = passwd;
+ memset(passwd, 0, size);
+
+ fputs(prompt, stdout);
+ fflush(stdout);
+
+ tcgetattr(STDIN_FILENO, &new);
+ new.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
+ new.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
+ tcsetattr(STDIN_FILENO, TCSANOW, &new);
+
+ if (timeout) {
+ sa.sa_flags = 0;
+ sa.sa_handler = askpass_timeout;
+ sigaction(SIGALRM, &sa, NULL);
+ alarm(timeout);
+ }
+
+ if (read(STDIN_FILENO, passwd, size-1) <= 0) {
+ ret = NULL;
+ } else {
+ for(i = 0; i < size && passwd[i]; i++) {
+ if (passwd[i]== '\r' || passwd[i] == '\n') {
+ passwd[i]= 0;
+ break;
+ }
+ }
+ }
+
+ if (timeout) {
+ alarm(0);
+ }
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &old);
+ fputs("\n", stdout);
+ fflush(stdout);
+ return ret;
+}
+
diff --git a/busybox/libbb/bb_asprintf.c b/busybox/libbb/bb_asprintf.c
new file mode 100644
index 0000000..a3ba424
--- /dev/null
+++ b/busybox/libbb/bb_asprintf.c
@@ -0,0 +1,22 @@
+/*
+ Copyright (C) 2002 Vladimir Oleynik <dzo@simtreas.ru>
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "libbb.h"
+
+void bb_xasprintf(char **string_ptr, const char *format, ...)
+{
+ va_list p;
+ int r;
+
+ va_start(p, format);
+ r = vasprintf(string_ptr, format, p);
+ va_end(p);
+
+ if (r < 0) {
+ bb_perror_msg_and_die("bb_xasprintf");
+ }
+}
diff --git a/busybox/libbb/change_identity.c b/busybox/libbb/change_identity.c
new file mode 100644
index 0000000..adebad8
--- /dev/null
+++ b/busybox/libbb/change_identity.c
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.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.
+ * 3. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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 <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+
+#include "libbb.h"
+
+
+/* Become the user and group(s) specified by PW. */
+const char *change_identity_e2str ( const struct passwd *pw )
+{
+ if ( initgroups ( pw-> pw_name, pw-> pw_gid ) == -1 )
+ return "cannot set groups";
+ endgrent ( );
+
+ if ( setgid ( pw-> pw_gid ))
+ return "cannot set group id";
+ if ( setuid ( pw->pw_uid ))
+ return "cannot set user id";
+ return NULL;
+}
+
+void change_identity ( const struct passwd *pw )
+{
+ const char *err_msg = change_identity_e2str(pw);
+
+ if(err_msg)
+ bb_perror_msg_and_die ( "%s", err_msg );
+}
diff --git a/busybox/libbb/chomp.c b/busybox/libbb/chomp.c
new file mode 100644
index 0000000..774e533
--- /dev/null
+++ b/busybox/libbb/chomp.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "libbb.h"
+
+
+void chomp(char *s)
+{
+ char *lc = last_char_is(s, '\n');
+
+ if(lc)
+ *lc = 0;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/compare_string_array.c b/busybox/libbb/compare_string_array.c
new file mode 100644
index 0000000..993b462
--- /dev/null
+++ b/busybox/libbb/compare_string_array.c
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+/* returns the array number of the string */
+extern unsigned short compare_string_array(const char *string_array[], const char *key)
+{
+ unsigned short i;
+
+ for (i = 0; string_array[i] != 0; i++) {
+ if (strcmp(string_array[i], key) == 0) {
+ break;
+ }
+ }
+ return(i);
+}
+
diff --git a/busybox/libbb/concat_path_file.c b/busybox/libbb/concat_path_file.c
new file mode 100644
index 0000000..77c0545
--- /dev/null
+++ b/busybox/libbb/concat_path_file.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/* concatenate path and file name to new allocation buffer,
+ * not addition '/' if path name already have '/'
+*/
+
+#include <string.h>
+#include "libbb.h"
+
+extern char *concat_path_file(const char *path, const char *filename)
+{
+ char *outbuf;
+ char *lc;
+
+ if (!path)
+ path="";
+ lc = last_char_is(path, '/');
+ while (*filename == '/')
+ filename++;
+ bb_xasprintf(&outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
+
+ return outbuf;
+}
diff --git a/busybox/libbb/concat_subpath_file.c b/busybox/libbb/concat_subpath_file.c
new file mode 100644
index 0000000..6d86f5e
--- /dev/null
+++ b/busybox/libbb/concat_subpath_file.c
@@ -0,0 +1,36 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ This function make special for recursive actions with usage
+ concat_path_file(path, filename)
+ and skiping "." and ".." directory entries
+*/
+
+#include "libbb.h"
+
+extern char *concat_subpath_file(const char *path, const char *f)
+{
+ if(f && *f == '.' && (!f[1] || (f[1] == '.' && !f[2])))
+ return NULL;
+ return concat_path_file(path, f);
+}
diff --git a/busybox/libbb/copy_file.c b/busybox/libbb/copy_file.c
new file mode 100644
index 0000000..68a1ded
--- /dev/null
+++ b/busybox/libbb/copy_file.c
@@ -0,0 +1,268 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini copy_file implementation for busybox
+ *
+ * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "busybox.h"
+
+int copy_file(const char *source, const char *dest, int flags)
+{
+ struct stat source_stat;
+ struct stat dest_stat;
+ int dest_exists = 0;
+ int status = 0;
+
+ if ((!(flags & FILEUTILS_DEREFERENCE) &&
+ lstat(source, &source_stat) < 0) ||
+ ((flags & FILEUTILS_DEREFERENCE) &&
+ stat(source, &source_stat) < 0)) {
+ bb_perror_msg("%s", source);
+ return -1;
+ }
+
+ if (lstat(dest, &dest_stat) < 0) {
+ if (errno != ENOENT) {
+ bb_perror_msg("unable to stat `%s'", dest);
+ return -1;
+ }
+ } else {
+ if (source_stat.st_dev == dest_stat.st_dev &&
+ source_stat.st_ino == dest_stat.st_ino) {
+ bb_error_msg("`%s' and `%s' are the same file", source, dest);
+ return -1;
+ }
+ dest_exists = 1;
+ }
+
+ if (S_ISDIR(source_stat.st_mode)) {
+ DIR *dp;
+ struct dirent *d;
+ mode_t saved_umask = 0;
+
+ if (!(flags & FILEUTILS_RECUR)) {
+ bb_error_msg("%s: omitting directory", source);
+ return -1;
+ }
+
+ /* Create DEST. */
+ if (dest_exists) {
+ if (!S_ISDIR(dest_stat.st_mode)) {
+ bb_error_msg("`%s' is not a directory", dest);
+ return -1;
+ }
+ } else {
+ mode_t mode;
+ saved_umask = umask(0);
+
+ mode = source_stat.st_mode;
+ if (!(flags & FILEUTILS_PRESERVE_STATUS))
+ mode = source_stat.st_mode & ~saved_umask;
+ mode |= S_IRWXU;
+
+ if (mkdir(dest, mode) < 0) {
+ umask(saved_umask);
+ bb_perror_msg("cannot create directory `%s'", dest);
+ return -1;
+ }
+
+ umask(saved_umask);
+ }
+
+ /* Recursively copy files in SOURCE. */
+ if ((dp = opendir(source)) == NULL) {
+ bb_perror_msg("unable to open directory `%s'", source);
+ status = -1;
+ goto end;
+ }
+
+ while ((d = readdir(dp)) != NULL) {
+ char *new_source, *new_dest;
+
+ new_source = concat_subpath_file(source, d->d_name);
+ if(new_source == NULL)
+ continue;
+ new_dest = concat_path_file(dest, d->d_name);
+ if (copy_file(new_source, new_dest, flags) < 0)
+ status = -1;
+ free(new_source);
+ free(new_dest);
+ }
+ /* closedir have only EBADF error, but "dp" not changes */
+ closedir(dp);
+
+ if (!dest_exists &&
+ chmod(dest, source_stat.st_mode & ~saved_umask) < 0) {
+ bb_perror_msg("unable to change permissions of `%s'", dest);
+ status = -1;
+ }
+ } else if (S_ISREG(source_stat.st_mode)) {
+ int src_fd;
+ int dst_fd;
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+ char *link_name;
+
+ if (!(flags & FILEUTILS_DEREFERENCE) &&
+ is_in_ino_dev_hashtable(&source_stat, &link_name)) {
+ if (link(link_name, dest) < 0) {
+ bb_perror_msg("unable to link `%s'", dest);
+ return -1;
+ }
+
+ return 0;
+ }
+#endif
+ src_fd = open(source, O_RDONLY);
+ if (src_fd == -1) {
+ bb_perror_msg("unable to open `%s'", source);
+ return(-1);
+ }
+
+ if (dest_exists) {
+ if (flags & FILEUTILS_INTERACTIVE) {
+ bb_error_msg("overwrite `%s'? ", dest);
+ if (!bb_ask_confirmation()) {
+ close (src_fd);
+ return 0;
+ }
+ }
+
+ dst_fd = open(dest, O_WRONLY|O_TRUNC);
+ if (dst_fd == -1) {
+ if (!(flags & FILEUTILS_FORCE)) {
+ bb_perror_msg("unable to open `%s'", dest);
+ close(src_fd);
+ return -1;
+ }
+
+ if (unlink(dest) < 0) {
+ bb_perror_msg("unable to remove `%s'", dest);
+ close(src_fd);
+ return -1;
+ }
+
+ dest_exists = 0;
+ }
+ }
+
+ if (!dest_exists) {
+ dst_fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode);
+ if (dst_fd == -1) {
+ bb_perror_msg("unable to open `%s'", dest);
+ close(src_fd);
+ return(-1);
+ }
+ }
+
+ if (bb_copyfd_eof(src_fd, dst_fd) == -1)
+ status = -1;
+
+ if (close(dst_fd) < 0) {
+ bb_perror_msg("unable to close `%s'", dest);
+ status = -1;
+ }
+
+ if (close(src_fd) < 0) {
+ bb_perror_msg("unable to close `%s'", source);
+ status = -1;
+ }
+ }
+ else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
+ S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) ||
+ S_ISLNK(source_stat.st_mode)) {
+
+ if (dest_exists &&
+ ((flags & FILEUTILS_FORCE) == 0 || unlink(dest) < 0)) {
+ bb_perror_msg("unable to remove `%s'", dest);
+ return -1;
+
+ }
+ } else {
+ bb_error_msg("internal error: unrecognized file type");
+ return -1;
+ }
+ if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
+ S_ISSOCK(source_stat.st_mode)) {
+ if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
+ bb_perror_msg("unable to create `%s'", dest);
+ return -1;
+ }
+ } else if (S_ISFIFO(source_stat.st_mode)) {
+ if (mkfifo(dest, source_stat.st_mode) < 0) {
+ bb_perror_msg("cannot create fifo `%s'", dest);
+ return -1;
+ }
+ } else if (S_ISLNK(source_stat.st_mode)) {
+ char *lpath;
+
+ lpath = xreadlink(source);
+ if (symlink(lpath, dest) < 0) {
+ bb_perror_msg("cannot create symlink `%s'", dest);
+ return -1;
+ }
+ free(lpath);
+
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+ if (flags & FILEUTILS_PRESERVE_STATUS)
+ if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
+ bb_perror_msg("unable to preserve ownership of `%s'", dest);
+#endif
+
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+ add_to_ino_dev_hashtable(&source_stat, dest);
+#endif
+
+ return 0;
+ }
+
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+ if (! S_ISDIR(source_stat.st_mode)) {
+ add_to_ino_dev_hashtable(&source_stat, dest);
+ }
+#endif
+
+end:
+
+ if (flags & FILEUTILS_PRESERVE_STATUS) {
+ struct utimbuf times;
+
+ times.actime = source_stat.st_atime;
+ times.modtime = source_stat.st_mtime;
+ if (utime(dest, &times) < 0)
+ bb_perror_msg("unable to preserve times of `%s'", dest);
+ if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
+ source_stat.st_mode &= ~(S_ISUID | S_ISGID);
+ bb_perror_msg("unable to preserve ownership of `%s'", dest);
+ }
+ if (chmod(dest, source_stat.st_mode) < 0)
+ bb_perror_msg("unable to preserve permissions of `%s'", dest);
+ }
+
+ return status;
+}
diff --git a/busybox/libbb/copyfd.c b/busybox/libbb/copyfd.c
new file mode 100644
index 0000000..bf0a390
--- /dev/null
+++ b/busybox/libbb/copyfd.c
@@ -0,0 +1,90 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "busybox.h"
+
+
+#if BUFSIZ < 4096
+#undef BUFSIZ
+#define BUFSIZ 4096
+#endif
+
+
+/* If size is 0 copy until EOF */
+static size_t bb_full_fd_action(int src_fd, int dst_fd, const size_t size)
+{
+ size_t read_total = 0;
+ RESERVE_CONFIG_BUFFER(buffer,BUFSIZ);
+
+ while ((size == 0) || (read_total < size)) {
+ size_t read_try;
+ ssize_t read_actual;
+
+ if ((size == 0) || (size - read_total > BUFSIZ)) {
+ read_try = BUFSIZ;
+ } else {
+ read_try = size - read_total;
+ }
+
+ read_actual = safe_read(src_fd, buffer, read_try);
+ if (read_actual > 0) {
+ if ((dst_fd >= 0) && (bb_full_write(dst_fd, buffer, (size_t) read_actual) != read_actual)) {
+ bb_perror_msg(bb_msg_write_error); /* match Read error below */
+ break;
+ }
+ }
+ else if (read_actual == 0) {
+ if (size) {
+ bb_error_msg("Unable to read all data");
+ }
+ break;
+ } else {
+ /* read_actual < 0 */
+ bb_perror_msg("Read error");
+ break;
+ }
+
+ read_total += read_actual;
+ }
+
+ RELEASE_CONFIG_BUFFER(buffer);
+
+ return(read_total);
+}
+
+
+extern int bb_copyfd_size(int fd1, int fd2, const off_t size)
+{
+ if (size) {
+ return(bb_full_fd_action(fd1, fd2, size));
+ }
+ return(0);
+}
+
+extern int bb_copyfd_eof(int fd1, int fd2)
+{
+ return(bb_full_fd_action(fd1, fd2, 0));
+}
diff --git a/busybox/libbb/correct_password.c b/busybox/libbb/correct_password.c
new file mode 100644
index 0000000..570aa7e
--- /dev/null
+++ b/busybox/libbb/correct_password.c
@@ -0,0 +1,77 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.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.
+ * 3. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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 <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <crypt.h>
+
+#include "libbb.h"
+
+
+
+/* Ask the user for a password.
+ Return 1 if the user gives the correct password for entry PW,
+ 0 if not. Return 1 without asking for a password if run by UID 0
+ or if PW has an empty password. */
+
+int correct_password ( const struct passwd *pw )
+{
+ char *unencrypted, *encrypted, *correct;
+
+#ifdef CONFIG_FEATURE_SHADOWPASSWDS
+ if (( strcmp ( pw-> pw_passwd, "x" ) == 0 ) || ( strcmp ( pw-> pw_passwd, "*" ) == 0 )) {
+ struct spwd *sp = getspnam ( pw-> pw_name );
+
+ if ( !sp )
+ bb_error_msg_and_die ( "no valid shadow password" );
+
+ correct = sp-> sp_pwdp;
+ }
+ else
+#endif
+ correct = pw-> pw_passwd;
+
+ if ( correct == 0 || correct[0] == '\0' )
+ return 1;
+
+ unencrypted = bb_askpass ( 0, "Password: " );
+ if ( !unencrypted )
+ {
+ return 0;
+ }
+ encrypted = crypt ( unencrypted, correct );
+ memset ( unencrypted, 0, bb_strlen ( unencrypted ));
+ return ( strcmp ( encrypted, correct ) == 0 ) ? 1 : 0;
+}
diff --git a/busybox/libbb/create_icmp6_socket.c b/busybox/libbb/create_icmp6_socket.c
new file mode 100644
index 0000000..d8ff35a
--- /dev/null
+++ b/busybox/libbb/create_icmp6_socket.c
@@ -0,0 +1,39 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * create raw socket for icmp (IPv6 version) protocol test permission
+ * and drop root privileges if running setuid
+ *
+ */
+
+#include <sys/types.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libbb.h"
+
+#ifdef CONFIG_FEATURE_IPV6
+int create_icmp6_socket(void)
+{
+ struct protoent *proto;
+ int sock;
+
+ proto = getprotobyname("ipv6-icmp");
+ /* if getprotobyname failed, just silently force
+ * proto->p_proto to have the correct value for "ipv6-icmp" */
+ if ((sock = socket(AF_INET6, SOCK_RAW,
+ (proto ? proto->p_proto : IPPROTO_ICMPV6))) < 0) {
+ if (errno == EPERM)
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ else
+ bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
+ }
+
+ /* drop root privs if running setuid */
+ setuid(getuid());
+
+ return sock;
+}
+#endif
diff --git a/busybox/libbb/create_icmp_socket.c b/busybox/libbb/create_icmp_socket.c
new file mode 100644
index 0000000..26120a6
--- /dev/null
+++ b/busybox/libbb/create_icmp_socket.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * create raw socket for icmp protocol test permission
+ * and drop root privileges if running setuid
+ *
+ */
+
+#include <sys/types.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libbb.h"
+
+int create_icmp_socket(void)
+{
+ struct protoent *proto;
+ int sock;
+
+ proto = getprotobyname("icmp");
+ /* if getprotobyname failed, just silently force
+ * proto->p_proto to have the correct value for "icmp" */
+ if ((sock = socket(AF_INET, SOCK_RAW,
+ (proto ? proto->p_proto : 1))) < 0) { /* 1 == ICMP */
+ if (errno == EPERM)
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ else
+ bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
+ }
+
+ /* drop root privs if running setuid */
+ setuid(getuid());
+
+ return sock;
+}
diff --git a/busybox/libbb/default_error_retval.c b/busybox/libbb/default_error_retval.c
new file mode 100644
index 0000000..35c34b9
--- /dev/null
+++ b/busybox/libbb/default_error_retval.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Seems silly to copyright a global variable. ;-) Oh well.
+ *
+ * At least one applet (cmp) returns a value different from the typical
+ * EXIT_FAILURE values (1) when an error occurs. So, make it configurable
+ * by the applet. I suppose we could use a wrapper function to set it, but
+ * that too seems silly.
+ */
+
+#include <stdlib.h>
+#include "libbb.h"
+
+int bb_default_error_retval = EXIT_FAILURE;
diff --git a/busybox/libbb/device_open.c b/busybox/libbb/device_open.c
new file mode 100644
index 0000000..61f954f
--- /dev/null
+++ b/busybox/libbb/device_open.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include "libbb.h"
+
+
+/* try to open up the specified device */
+extern int device_open(const char *device, int mode)
+{
+ int m, f, fd = -1;
+
+ m = mode | O_NONBLOCK;
+
+ /* Retry up to 5 times */
+ for (f = 0; f < 5; f++)
+ if ((fd = open(device, m, 0600)) >= 0)
+ break;
+ if (fd < 0)
+ return fd;
+ /* Reset original flags. */
+ if (m != mode)
+ fcntl(fd, F_SETFL, mode);
+ return fd;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/dump.c b/busybox/libbb/dump.c
new file mode 100644
index 0000000..98f004f
--- /dev/null
+++ b/busybox/libbb/dump.c
@@ -0,0 +1,819 @@
+/*
+ * Support code for the hexdump and od applets,
+ * based on code from util-linux v 2.11l
+ *
+ * Copyright (c) 1989
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h> /* for isdigit() */
+#include "libbb.h"
+#include "dump.h"
+
+enum _vflag bb_dump_vflag = FIRST;
+FS *bb_dump_fshead; /* head of format strings */
+static FU *endfu;
+static char **_argv;
+static off_t savaddress; /* saved address/offset in stream */
+static off_t eaddress; /* end address */
+static off_t address; /* address/offset in stream */
+off_t bb_dump_skip; /* bytes to skip */
+static int exitval; /* final exit value */
+int bb_dump_blocksize; /* data block size */
+int bb_dump_length = -1; /* max bytes to read */
+
+static const char index_str[] = ".#-+ 0123456789";
+
+static const char size_conv_str[] =
+"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
+
+static const char lcc[] = "diouxX";
+
+int bb_dump_size(FS * fs)
+{
+ register FU *fu;
+ register int bcnt, cur_size;
+ register char *fmt;
+ const char *p;
+ int prec;
+
+ /* figure out the data block bb_dump_size needed for each format unit */
+ for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->bcnt) {
+ cur_size += fu->bcnt * fu->reps;
+ continue;
+ }
+ for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
+ if (*fmt != '%')
+ continue;
+ /*
+ * bb_dump_skip any special chars -- save precision in
+ * case it's a %s format.
+ */
+ while (strchr(index_str + 1, *++fmt));
+ if (*fmt == '.' && isdigit(*++fmt)) {
+ prec = atoi(fmt);
+ while (isdigit(*++fmt));
+ }
+ if (!(p = strchr(size_conv_str + 12, *fmt))) {
+ if (*fmt == 's') {
+ bcnt += prec;
+ } else if (*fmt == '_') {
+ ++fmt;
+ if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
+ bcnt += 1;
+ }
+ }
+ } else {
+ bcnt += size_conv_str[p - (size_conv_str + 12)];
+ }
+ }
+ cur_size += bcnt * fu->reps;
+ }
+ return (cur_size);
+}
+
+static void rewrite(FS * fs)
+{
+ enum { NOTOKAY, USEBCNT, USEPREC } sokay;
+ register PR *pr, **nextpr = NULL;
+ register FU *fu;
+ register char *p1, *p2, *p3;
+ char savech, *fmtp;
+ const char *byte_count_str;
+ int nconv, prec = 0;
+
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ /*
+ * break each format unit into print units; each
+ * conversion character gets its own.
+ */
+ for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
+ /* NOSTRICT */
+ /* DBU:[dvae@cray.com] calloc so that forward ptrs start out NULL*/
+ pr = (PR *) xcalloc(1,sizeof(PR));
+ if (!fu->nextpr)
+ fu->nextpr = pr;
+ /* ignore nextpr -- its unused inside the loop and is
+ * uninitialized 1st time thru.
+ */
+
+ /* bb_dump_skip preceding text and up to the next % sign */
+ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
+
+ /* only text in the string */
+ if (!*p1) {
+ pr->fmt = fmtp;
+ pr->flags = F_TEXT;
+ break;
+ }
+
+ /*
+ * get precision for %s -- if have a byte count, don't
+ * need it.
+ */
+ if (fu->bcnt) {
+ sokay = USEBCNT;
+ /* bb_dump_skip to conversion character */
+ for (++p1; strchr(index_str, *p1); ++p1);
+ } else {
+ /* bb_dump_skip any special chars, field width */
+ while (strchr(index_str + 1, *++p1));
+ if (*p1 == '.' && isdigit(*++p1)) {
+ sokay = USEPREC;
+ prec = atoi(p1);
+ while (isdigit(*++p1));
+ } else
+ sokay = NOTOKAY;
+ }
+
+ p2 = p1 + 1; /* set end pointer */
+
+ /*
+ * figure out the byte count for each conversion;
+ * rewrite the format as necessary, set up blank-
+ * pbb_dump_adding for end of data.
+ */
+
+ if (*p1 == 'c') {
+ pr->flags = F_CHAR;
+ DO_BYTE_COUNT_1:
+ byte_count_str = "\001";
+ DO_BYTE_COUNT:
+ if (fu->bcnt) {
+ do {
+ if (fu->bcnt == *byte_count_str) {
+ break;
+ }
+ } while (*++byte_count_str);
+ }
+ /* Unlike the original, output the remainder of the format string. */
+ if (!*byte_count_str) {
+ bb_error_msg_and_die("bad byte count for conversion character %s.", p1);
+ }
+ pr->bcnt = *byte_count_str;
+ } else if (*p1 == 'l') {
+ ++p2;
+ ++p1;
+ DO_INT_CONV:
+ {
+ const char *e;
+ if (!(e = strchr(lcc, *p1))) {
+ goto DO_BAD_CONV_CHAR;
+ }
+ pr->flags = F_INT;
+ if (e > lcc + 1) {
+ pr->flags = F_UINT;
+ }
+ byte_count_str = "\004\002\001";
+ goto DO_BYTE_COUNT;
+ }
+ /* NOTREACHED */
+ } else if (strchr(lcc, *p1)) {
+ goto DO_INT_CONV;
+ } else if (strchr("eEfgG", *p1)) {
+ pr->flags = F_DBL;
+ byte_count_str = "\010\004";
+ goto DO_BYTE_COUNT;
+ } else if (*p1 == 's') {
+ pr->flags = F_STR;
+ if (sokay == USEBCNT) {
+ pr->bcnt = fu->bcnt;
+ } else if (sokay == USEPREC) {
+ pr->bcnt = prec;
+ } else { /* NOTOKAY */
+ bb_error_msg_and_die("%%s requires a precision or a byte count.");
+ }
+ } else if (*p1 == '_') {
+ ++p2;
+ switch (p1[1]) {
+ case 'A':
+ endfu = fu;
+ fu->flags |= F_IGNORE;
+ /* FALLTHROUGH */
+ case 'a':
+ pr->flags = F_ADDRESS;
+ ++p2;
+ if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
+ goto DO_BAD_CONV_CHAR;
+ }
+ *p1 = p1[2];
+ break;
+ case 'c':
+ pr->flags = F_C;
+ /* *p1 = 'c'; set in conv_c */
+ goto DO_BYTE_COUNT_1;
+ case 'p':
+ pr->flags = F_P;
+ *p1 = 'c';
+ goto DO_BYTE_COUNT_1;
+ case 'u':
+ pr->flags = F_U;
+ /* *p1 = 'c'; set in conv_u */
+ goto DO_BYTE_COUNT_1;
+ default:
+ goto DO_BAD_CONV_CHAR;
+ }
+ } else {
+ DO_BAD_CONV_CHAR:
+ bb_error_msg_and_die("bad conversion character %%%s.\n", p1);
+ }
+
+ /*
+ * copy to PR format string, set conversion character
+ * pointer, update original.
+ */
+ savech = *p2;
+ p1[1] = '\0';
+ pr->fmt = bb_xstrdup(fmtp);
+ *p2 = savech;
+ pr->cchar = pr->fmt + (p1 - fmtp);
+
+ /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
+ * Skip subsequent text and up to the next % sign and tack the
+ * additional text onto fmt: eg. if fmt is "%x is a HEX number",
+ * we lose the " is a HEX number" part of fmt.
+ */
+ for (p3 = p2; *p3 && *p3 != '%'; p3++);
+ if (p3 > p2)
+ {
+ savech = *p3;
+ *p3 = '\0';
+ if (!(pr->fmt = realloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1)))
+ bb_perror_msg_and_die("hexdump");
+ strcat(pr->fmt, p2);
+ *p3 = savech;
+ p2 = p3;
+ }
+
+ fmtp = p2;
+
+ /* only one conversion character if byte count */
+ if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
+ bb_error_msg_and_die("byte count with multiple conversion characters.\n");
+ }
+ }
+ /*
+ * if format unit byte count not specified, figure it out
+ * so can adjust rep count later.
+ */
+ if (!fu->bcnt)
+ for (pr = fu->nextpr; pr; pr = pr->nextpr)
+ fu->bcnt += pr->bcnt;
+ }
+ /*
+ * if the format string interprets any data at all, and it's
+ * not the same as the bb_dump_blocksize, and its last format unit
+ * interprets any data at all, and has no iteration count,
+ * repeat it as necessary.
+ *
+ * if, rep count is greater than 1, no trailing whitespace
+ * gets output from the last iteration of the format unit.
+ */
+ for (fu = fs->nextfu;; fu = fu->nextfu) {
+ if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
+ !(fu->flags & F_SETREP) && fu->bcnt)
+ fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
+ if (fu->reps > 1) {
+ for (pr = fu->nextpr;; pr = pr->nextpr)
+ if (!pr->nextpr)
+ break;
+ for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
+ p2 = isspace(*p1) ? p1 : NULL;
+ if (p2)
+ pr->nospace = p2;
+ }
+ if (!fu->nextfu)
+ break;
+ }
+}
+
+static void do_skip(char *fname, int statok)
+{
+ struct stat sbuf;
+
+ if (statok) {
+ if (fstat(STDIN_FILENO, &sbuf)) {
+ bb_perror_msg_and_die("%s", fname);
+ }
+ if ((!(S_ISCHR(sbuf.st_mode) ||
+ S_ISBLK(sbuf.st_mode) ||
+ S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) {
+ /* If bb_dump_size valid and bb_dump_skip >= size */
+ bb_dump_skip -= sbuf.st_size;
+ address += sbuf.st_size;
+ return;
+ }
+ }
+ if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
+ bb_perror_msg_and_die("%s", fname);
+ }
+ savaddress = address += bb_dump_skip;
+ bb_dump_skip = 0;
+}
+
+static int next(char **argv)
+{
+ static int done;
+ int statok;
+
+ if (argv) {
+ _argv = argv;
+ return (1);
+ }
+ for (;;) {
+ if (*_argv) {
+ if (!(freopen(*_argv, "r", stdin))) {
+ bb_perror_msg("%s", *_argv);
+ exitval = 1;
+ ++_argv;
+ continue;
+ }
+ statok = done = 1;
+ } else {
+ if (done++)
+ return (0);
+ statok = 0;
+ }
+ if (bb_dump_skip)
+ do_skip(statok ? *_argv : "stdin", statok);
+ if (*_argv)
+ ++_argv;
+ if (!bb_dump_skip)
+ return (1);
+ }
+ /* NOTREACHED */
+}
+
+static u_char *get(void)
+{
+ static int ateof = 1;
+ static u_char *curp=NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
+ register int n;
+ int need, nread;
+ u_char *tmpp;
+
+ if (!curp) {
+ address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
+ curp = (u_char *) xmalloc(bb_dump_blocksize);
+ savp = (u_char *) xmalloc(bb_dump_blocksize);
+ } else {
+ tmpp = curp;
+ curp = savp;
+ savp = tmpp;
+ address = savaddress += bb_dump_blocksize;
+ }
+ for (need = bb_dump_blocksize, nread = 0;;) {
+ /*
+ * if read the right number of bytes, or at EOF for one file,
+ * and no other files are available, zero-pad the rest of the
+ * block and set the end flag.
+ */
+ if (!bb_dump_length || (ateof && !next((char **) NULL))) {
+ if (need == bb_dump_blocksize) {
+ return ((u_char *) NULL);
+ }
+ if (bb_dump_vflag != ALL && !bcmp(curp, savp, nread)) {
+ if (bb_dump_vflag != DUP) {
+ printf("*\n");
+ }
+ return ((u_char *) NULL);
+ }
+ bzero((char *) curp + nread, need);
+ eaddress = address + nread;
+ return (curp);
+ }
+ n = fread((char *) curp + nread, sizeof(u_char),
+ bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
+ if (!n) {
+ if (ferror(stdin)) {
+ bb_perror_msg("%s", _argv[-1]);
+ }
+ ateof = 1;
+ continue;
+ }
+ ateof = 0;
+ if (bb_dump_length != -1) {
+ bb_dump_length -= n;
+ }
+ if (!(need -= n)) {
+ if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
+ || bcmp(curp, savp, bb_dump_blocksize)) {
+ if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
+ bb_dump_vflag = WAIT;
+ }
+ return (curp);
+ }
+ if (bb_dump_vflag == WAIT) {
+ printf("*\n");
+ }
+ bb_dump_vflag = DUP;
+ address = savaddress += bb_dump_blocksize;
+ need = bb_dump_blocksize;
+ nread = 0;
+ } else {
+ nread += n;
+ }
+ }
+}
+
+static void bpad(PR * pr)
+{
+ register char *p1, *p2;
+
+ /*
+ * remove all conversion flags; '-' is the only one valid
+ * with %s, and it's not useful here.
+ */
+ pr->flags = F_BPAD;
+ *pr->cchar = 's';
+ for (p1 = pr->fmt; *p1 != '%'; ++p1);
+ for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1);
+ while ((*p2++ = *p1++) != 0);
+}
+
+static const char conv_str[] =
+ "\0\\0\0"
+ "\007\\a\0" /* \a */
+ "\b\\b\0"
+ "\f\\b\0"
+ "\n\\n\0"
+ "\r\\r\0"
+ "\t\\t\0"
+ "\v\\v\0"
+ "\0";
+
+
+static void conv_c(PR * pr, u_char * p)
+{
+ const char *str = conv_str;
+ char buf[10];
+
+ do {
+ if (*p == *str) {
+ ++str;
+ goto strpr;
+ }
+ str += 4;
+ } while (*str);
+
+ if (isprint(*p)) {
+ *pr->cchar = 'c';
+ (void) printf(pr->fmt, *p);
+ } else {
+ sprintf(buf, "%03o", (int) *p);
+ str = buf;
+ strpr:
+ *pr->cchar = 's';
+ printf(pr->fmt, str);
+ }
+}
+
+static void conv_u(PR * pr, u_char * p)
+{
+ static const char list[] =
+ "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
+ "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
+ "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
+ "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
+
+ /* od used nl, not lf */
+ if (*p <= 0x1f) {
+ *pr->cchar = 's';
+ printf(pr->fmt, list + (4 * (int)*p));
+ } else if (*p == 0x7f) {
+ *pr->cchar = 's';
+ printf(pr->fmt, "del");
+ } else if (isprint(*p)) {
+ *pr->cchar = 'c';
+ printf(pr->fmt, *p);
+ } else {
+ *pr->cchar = 'x';
+ printf(pr->fmt, (int) *p);
+ }
+}
+
+static void display(void)
+{
+/* extern FU *endfu; */
+ register FS *fs;
+ register FU *fu;
+ register PR *pr;
+ register int cnt;
+ register u_char *bp;
+
+ off_t saveaddress;
+ u_char savech = 0, *savebp;
+
+ while ((bp = get()) != NULL) {
+ for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
+ fs = fs->nextfs, bp = savebp, address = saveaddress) {
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->flags & F_IGNORE) {
+ break;
+ }
+ for (cnt = fu->reps; cnt; --cnt) {
+ for (pr = fu->nextpr; pr; address += pr->bcnt,
+ bp += pr->bcnt, pr = pr->nextpr) {
+ if (eaddress && address >= eaddress &&
+ !(pr->flags & (F_TEXT | F_BPAD))) {
+ bpad(pr);
+ }
+ if (cnt == 1 && pr->nospace) {
+ savech = *pr->nospace;
+ *pr->nospace = '\0';
+ }
+/* PRINT; */
+ switch (pr->flags) {
+ case F_ADDRESS:
+ printf(pr->fmt, (unsigned int) address);
+ break;
+ case F_BPAD:
+ printf(pr->fmt, "");
+ break;
+ case F_C:
+ conv_c(pr, bp);
+ break;
+ case F_CHAR:
+ printf(pr->fmt, *bp);
+ break;
+ case F_DBL:{
+ double dval;
+ float fval;
+
+ switch (pr->bcnt) {
+ case 4:
+ bcopy((char *) bp, (char *) &fval,
+ sizeof(fval));
+ printf(pr->fmt, fval);
+ break;
+ case 8:
+ bcopy((char *) bp, (char *) &dval,
+ sizeof(dval));
+ printf(pr->fmt, dval);
+ break;
+ }
+ break;
+ }
+ case F_INT:{
+ int ival;
+ short sval;
+
+ switch (pr->bcnt) {
+ case 1:
+ printf(pr->fmt, (int) *bp);
+ break;
+ case 2:
+ bcopy((char *) bp, (char *) &sval,
+ sizeof(sval));
+ printf(pr->fmt, (int) sval);
+ break;
+ case 4:
+ bcopy((char *) bp, (char *) &ival,
+ sizeof(ival));
+ printf(pr->fmt, ival);
+ break;
+ }
+ break;
+ }
+ case F_P:
+ printf(pr->fmt, isprint(*bp) ? *bp : '.');
+ break;
+ case F_STR:
+ printf(pr->fmt, (char *) bp);
+ break;
+ case F_TEXT:
+ printf(pr->fmt);
+ break;
+ case F_U:
+ conv_u(pr, bp);
+ break;
+ case F_UINT:{
+ unsigned int ival;
+ unsigned short sval;
+
+ switch (pr->bcnt) {
+ case 1:
+ printf(pr->fmt, (unsigned int) * bp);
+ break;
+ case 2:
+ bcopy((char *) bp, (char *) &sval,
+ sizeof(sval));
+ printf(pr->fmt, (unsigned int) sval);
+ break;
+ case 4:
+ bcopy((char *) bp, (char *) &ival,
+ sizeof(ival));
+ printf(pr->fmt, ival);
+ break;
+ }
+ break;
+ }
+ }
+ if (cnt == 1 && pr->nospace) {
+ *pr->nospace = savech;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (endfu) {
+ /*
+ * if eaddress not set, error or file bb_dump_size was multiple of
+ * bb_dump_blocksize, and no partial block ever found.
+ */
+ if (!eaddress) {
+ if (!address) {
+ return;
+ }
+ eaddress = address;
+ }
+ for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
+ switch (pr->flags) {
+ case F_ADDRESS:
+ (void) printf(pr->fmt, (unsigned int) eaddress);
+ break;
+ case F_TEXT:
+ (void) printf(pr->fmt);
+ break;
+ }
+ }
+ }
+}
+
+int bb_dump_dump(char **argv)
+{
+ register FS *tfs;
+
+ /* figure out the data block bb_dump_size */
+ for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
+ tfs->bcnt = bb_dump_size(tfs);
+ if (bb_dump_blocksize < tfs->bcnt) {
+ bb_dump_blocksize = tfs->bcnt;
+ }
+ }
+ /* rewrite the rules, do syntax checking */
+ for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
+ rewrite(tfs);
+ }
+
+ next(argv);
+ display();
+
+ return (exitval);
+}
+
+void bb_dump_add(const char *fmt)
+{
+ register const char *p;
+ register char *p1;
+ register char *p2;
+ static FS **nextfs;
+ FS *tfs;
+ FU *tfu, **nextfu;
+ const char *savep;
+
+ /* start new linked list of format units */
+ /* NOSTRICT */
+ tfs = (FS *) xcalloc(1,sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
+ if (!bb_dump_fshead) {
+ bb_dump_fshead = tfs;
+ } else {
+ *nextfs = tfs;
+ }
+ nextfs = &tfs->nextfs;
+ nextfu = &tfs->nextfu;
+
+ /* take the format string and break it up into format units */
+ for (p = fmt;;) {
+ /* bb_dump_skip leading white space */
+ p = bb_skip_whitespace(p);
+ if (!*p) {
+ break;
+ }
+
+ /* allocate a new format unit and link it in */
+ /* NOSTRICT */
+ /* DBU:[dave@cray.com] calloc so that forward pointers start out NULL */
+ tfu = (FU *) xcalloc(1,sizeof(FU));
+ *nextfu = tfu;
+ nextfu = &tfu->nextfu;
+ tfu->reps = 1;
+
+ /* if leading digit, repetition count */
+ if (isdigit(*p)) {
+ for (savep = p; isdigit(*p); ++p);
+ if (!isspace(*p) && *p != '/') {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ /* may overwrite either white space or slash */
+ tfu->reps = atoi(savep);
+ tfu->flags = F_SETREP;
+ /* bb_dump_skip trailing white space */
+ p = bb_skip_whitespace(++p);
+ }
+
+ /* bb_dump_skip slash and trailing white space */
+ if (*p == '/') {
+ p = bb_skip_whitespace(++p);
+ }
+
+ /* byte count */
+ if (isdigit(*p)) {
+ for (savep = p; isdigit(*p); ++p);
+ if (!isspace(*p)) {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ tfu->bcnt = atoi(savep);
+ /* bb_dump_skip trailing white space */
+ p = bb_skip_whitespace(++p);
+ }
+
+ /* format */
+ if (*p != '"') {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ for (savep = ++p; *p != '"';) {
+ if (*p++ == 0) {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ }
+ tfu->fmt = xmalloc(p - savep + 1);
+ strncpy(tfu->fmt, savep, p - savep);
+ tfu->fmt[p - savep] = '\0';
+/* escape(tfu->fmt); */
+
+ p1 = tfu->fmt;
+
+ /* alphabetic escape sequences have to be done in place */
+ for (p2 = p1;; ++p1, ++p2) {
+ if (!*p1) {
+ *p2 = *p1;
+ break;
+ }
+ if (*p1 == '\\') {
+ const char *cs = conv_str + 4;
+ ++p1;
+ *p2 = *p1;
+ do {
+ if (*p1 == cs[2]) {
+ *p2 = cs[0];
+ break;
+ }
+ cs += 4;
+ } while (*cs);
+ }
+ }
+
+ p++;
+ }
+}
+
+/*
+ * Copyright (c) 1989 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.
+ */
diff --git a/busybox/libbb/error_msg.c b/busybox/libbb/error_msg.c
new file mode 100644
index 0000000..18811b8
--- /dev/null
+++ b/busybox/libbb/error_msg.c
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void bb_error_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/error_msg_and_die.c b/busybox/libbb/error_msg_and_die.c
new file mode 100644
index 0000000..0937658
--- /dev/null
+++ b/busybox/libbb/error_msg_and_die.c
@@ -0,0 +1,47 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void bb_error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+ exit(bb_default_error_retval);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/fclose_nonstdin.c b/busybox/libbb/fclose_nonstdin.c
new file mode 100644
index 0000000..8f489c8
--- /dev/null
+++ b/busybox/libbb/fclose_nonstdin.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fclose_nonstdin implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* A number of standard utilities can accept multiple command line args
+ * of '-' for stdin, according to SUSv3. So we encapsulate the check
+ * here to save a little space.
+ */
+
+#include <stdio.h>
+#include <libbb.h>
+
+int bb_fclose_nonstdin(FILE *f)
+{
+ if (f != stdin) {
+ return fclose(f);
+ }
+ return 0;
+}
diff --git a/busybox/libbb/fflush_stdout_and_exit.c b/busybox/libbb/fflush_stdout_and_exit.c
new file mode 100644
index 0000000..cbba042
--- /dev/null
+++ b/busybox/libbb/fflush_stdout_and_exit.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fflush_stdout_and_exit implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Attempt to fflush(stdout), and exit with an error code if stdout is
+ * in an error state.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libbb.h>
+
+void bb_fflush_stdout_and_exit(int retval)
+{
+ if (fflush(stdout)) {
+ retval = bb_default_error_retval;
+ }
+ exit(retval);
+}
diff --git a/busybox/libbb/fgets_str.c b/busybox/libbb/fgets_str.c
new file mode 100644
index 0000000..bf828be
--- /dev/null
+++ b/busybox/libbb/fgets_str.c
@@ -0,0 +1,67 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libbb.h"
+
+/* Read up to (and including) TERMINATING_STRING from FILE and return it.
+ * Return NULL on EOF. */
+
+char *fgets_str(FILE *file, const char *terminating_string)
+{
+ char *linebuf = NULL;
+ const int term_length = strlen(terminating_string);
+ int end_string_offset;
+ int linebufsz = 0;
+ int idx = 0;
+ int ch;
+
+ while (1) {
+ ch = fgetc(file);
+ if (ch == EOF) {
+ free(linebuf);
+ return NULL;
+ }
+
+ /* grow the line buffer as necessary */
+ while (idx > linebufsz - 2) {
+ linebuf = xrealloc(linebuf, linebufsz += 1000);
+ }
+
+ linebuf[idx] = ch;
+ idx++;
+
+ /* Check for terminating string */
+ end_string_offset = idx - term_length;
+ if ((end_string_offset > 0) && (memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0)) {
+ idx -= term_length;
+ break;
+ }
+ }
+ linebuf[idx] = '\0';
+ return(linebuf);
+}
+
diff --git a/busybox/libbb/find_mount_point.c b/busybox/libbb/find_mount_point.c
new file mode 100644
index 0000000..83824de
--- /dev/null
+++ b/busybox/libbb/find_mount_point.c
@@ -0,0 +1,75 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "libbb.h"
+
+
+#include <mntent.h>
+/*
+ * Given a block device, find the mount table entry if that block device
+ * is mounted.
+ *
+ * Given any other file (or directory), find the mount table entry for its
+ * filesystem.
+ */
+extern struct mntent *find_mount_point(const char *name, const char *table)
+{
+ struct stat s;
+ dev_t mountDevice;
+ FILE *mountTable;
+ struct mntent *mountEntry;
+
+ if (stat(name, &s) != 0)
+ return 0;
+
+ if ((s.st_mode & S_IFMT) == S_IFBLK)
+ mountDevice = s.st_rdev;
+ else
+ mountDevice = s.st_dev;
+
+
+ if ((mountTable = setmntent(table, "r")) == 0)
+ return 0;
+
+ while ((mountEntry = getmntent(mountTable)) != 0) {
+ if (strcmp(name, mountEntry->mnt_dir) == 0
+ || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */
+ break;
+ if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */
+ break;
+ if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */
+ break;
+ }
+ endmntent(mountTable);
+ return mountEntry;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/find_pid_by_name.c b/busybox/libbb/find_pid_by_name.c
new file mode 100644
index 0000000..930710f
--- /dev/null
+++ b/busybox/libbb/find_pid_by_name.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+#define COMM_LEN 16 /* synchronize with size of comm in struct task_struct
+ in /usr/include/linux/sched.h */
+
+
+/* find_pid_by_name()
+ *
+ * Modified by Vladimir Oleynik for use with libbb/procps.c
+ * This finds the pid of the specified process.
+ * Currently, it's implemented by rummaging through
+ * the proc filesystem.
+ *
+ * Returns a list of all matching PIDs
+ */
+extern long* find_pid_by_name( const char* pidName)
+{
+ long* pidList;
+ int i=0;
+ procps_status_t * p;
+
+ pidList = xmalloc(sizeof(long));
+#ifdef CONFIG_SELINUX
+ while ((p = procps_scan(0, 0, NULL)) != 0) {
+#else
+ while ((p = procps_scan(0)) != 0) {
+#endif
+ if (strncmp(p->short_cmd, pidName, COMM_LEN-1) == 0) {
+ pidList=xrealloc( pidList, sizeof(long) * (i+2));
+ pidList[i++]=p->pid;
+ }
+ }
+
+ pidList[i] = i==0 ? -1 : 0;
+ return pidList;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/find_root_device.c b/busybox/libbb/find_root_device.c
new file mode 100644
index 0000000..2600ce5
--- /dev/null
+++ b/busybox/libbb/find_root_device.c
@@ -0,0 +1,89 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+
+
+extern char *find_real_root_device_name(void)
+{
+ DIR *dir;
+ struct dirent *entry;
+ struct stat statBuf, rootStat;
+ char *fileName = NULL;
+ dev_t dev;
+
+ if (stat("/", &rootStat) != 0)
+ bb_perror_msg("could not stat '/'");
+ else {
+ /* This check is here in case they pass in /dev name */
+ if ((rootStat.st_mode & S_IFMT) == S_IFBLK)
+ dev = rootStat.st_rdev;
+ else
+ dev = rootStat.st_dev;
+
+ dir = opendir("/dev");
+ if (!dir)
+ bb_perror_msg("could not open '/dev'");
+ else {
+ while((entry = readdir(dir)) != NULL) {
+ const char *myname = entry->d_name;
+ /* Must skip ".." since that is "/", and so we
+ * would get a false positive on ".." */
+ if (myname[0] == '.' && myname[1] == '.' && !myname[2])
+ continue;
+#ifdef CONFIG_FEATURE_DEVFS
+ /* if there is a link named /dev/root skip that too */
+ if (strcmp(myname, "root")==0)
+ continue;
+#endif
+ fileName = concat_path_file("/dev", myname);
+
+ /* Some char devices have the same dev_t as block
+ * devices, so make sure this is a block device */
+ if (stat(fileName, &statBuf) == 0 &&
+ S_ISBLK(statBuf.st_mode)!=0 &&
+ statBuf.st_rdev == dev)
+ break;
+ free(fileName);
+ fileName=NULL;
+ }
+ closedir(dir);
+ }
+ }
+ if(fileName==NULL)
+ fileName = bb_xstrdup("/dev/root");
+ return fileName;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/full_read.c b/busybox/libbb/full_read.c
new file mode 100644
index 0000000..221fc94
--- /dev/null
+++ b/busybox/libbb/full_read.c
@@ -0,0 +1,63 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "libbb.h"
+
+/*
+ * Read all of the supplied buffer from a file.
+ * This does multiple reads as necessary.
+ * Returns the amount read, or -1 on an error.
+ * A short read is returned on an end of file.
+ */
+ssize_t bb_full_read(int fd, void *buf, size_t len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len > 0) {
+ cc = safe_read(fd, buf, len);
+
+ if (cc < 0)
+ return cc; /* read() returns -1 on failure. */
+
+ if (cc == 0)
+ break;
+
+ buf = ((char *)buf) + cc;
+ total += cc;
+ len -= cc;
+ }
+
+ return total;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/full_write.c b/busybox/libbb/full_write.c
new file mode 100644
index 0000000..30de407
--- /dev/null
+++ b/busybox/libbb/full_write.c
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "libbb.h"
+
+/*
+ * Write all of the supplied buffer out to a file.
+ * This does multiple writes as necessary.
+ * Returns the amount written, or -1 on an error.
+ */
+ssize_t bb_full_write(int fd, const void *buf, size_t len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len > 0) {
+ cc = safe_write(fd, buf, len);
+
+ if (cc < 0)
+ return cc; /* write() returns -1 on failure. */
+
+ total += cc;
+ buf = ((const char *)buf) + cc;
+ len -= cc;
+ }
+
+ return total;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/get_console.c b/busybox/libbb/get_console.c
new file mode 100644
index 0000000..bfb7468
--- /dev/null
+++ b/busybox/libbb/get_console.c
@@ -0,0 +1,99 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "libbb.h"
+
+
+
+/* From <linux/kd.h> */
+static const int KDGKBTYPE = 0x4B33; /* get keyboard type */
+
+
+static int open_a_console(const char *fnam)
+{
+ int fd;
+
+ /* try read-write */
+ fd = open(fnam, O_RDWR);
+
+ /* if failed, try read-only */
+ if (fd < 0 && errno == EACCES)
+ fd = open(fnam, O_RDONLY);
+
+ /* if failed, try write-only */
+ if (fd < 0 && errno == EACCES)
+ fd = open(fnam, O_WRONLY);
+
+ return fd;
+}
+
+/*
+ * Get an fd for use with kbd/console ioctls.
+ * We try several things because opening /dev/console will fail
+ * if someone else used X (which does a chown on /dev/console).
+ */
+
+int get_console_fd(void)
+{
+ int fd;
+
+ static const char * const choise_console_names[] = {
+ CONSOLE_DEV, CURRENT_VC, CURRENT_TTY
+ };
+
+ for (fd = 2; fd >= 0; fd--) {
+ int fd4name;
+ int choise_fd;
+ char arg;
+
+ fd4name = open_a_console(choise_console_names[fd]);
+ chk_std:
+ choise_fd = fd4name >= 0 ? fd4name : fd;
+
+ arg = 0;
+ if (ioctl(choise_fd, KDGKBTYPE, &arg) == 0)
+ return choise_fd;
+ if(fd4name >= 0) {
+ close(fd4name);
+ fd4name = -1;
+ goto chk_std;
+ }
+ }
+
+ bb_error_msg("Couldn't get a file descriptor referring to the console");
+ return fd; /* total failure */
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/get_last_path_component.c b/busybox/libbb/get_last_path_component.c
new file mode 100644
index 0000000..497d6ae
--- /dev/null
+++ b/busybox/libbb/get_last_path_component.c
@@ -0,0 +1,56 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_get_last_path_component implementation for busybox
+ *
+ * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Set to 1 if you want basename() behavior for NULL or "". */
+/* WARNING!!! Doing so will break basename applet at least! */
+#define EMULATE_BASENAME 0
+
+char *bb_get_last_path_component(char *path)
+{
+#if EMULATE_BASENAME
+ static const char null_or_empty[] = ".";
+#endif
+ char *first = path;
+ char *last;
+
+#if EMULATE_BASENAME
+ if (!path || !*path) {
+ return (char *) null_or_empty;
+ }
+#endif
+
+ last = path - 1;
+
+ while (*path) {
+ if ((*path != '/') && (path > ++last)) {
+ last = first = path;
+ }
+ ++path;
+ }
+
+ if (*first == '/') {
+ last = first;
+ }
+ last[1] = 0;
+
+ return first;
+}
diff --git a/busybox/libbb/get_line_from_file.c b/busybox/libbb/get_line_from_file.c
new file mode 100644
index 0000000..6d12b21
--- /dev/null
+++ b/busybox/libbb/get_line_from_file.c
@@ -0,0 +1,82 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+/* get_line_from_file() - This function reads an entire line from a text file,
+ * up to a newline. It returns a malloc'ed char * which must be stored and
+ * free'ed by the caller. If 'c' is nonzero, the trailing '\n' (if any)
+ * is removed. In event of a read error or EOF, NULL is returned. */
+
+static char *private_get_line_from_file(FILE *file, int c)
+{
+#define GROWBY (80) /* how large we will grow strings by */
+
+ int ch;
+ int idx = 0;
+ char *linebuf = NULL;
+ int linebufsz = 0;
+
+ while ((ch = getc(file)) != EOF) {
+ /* grow the line buffer as necessary */
+ if (idx > linebufsz - 2) {
+ linebuf = xrealloc(linebuf, linebufsz += GROWBY);
+ }
+ linebuf[idx++] = (char)ch;
+ if (ch == '\n' || ch == '\0') {
+ if (c) {
+ --idx;
+ }
+ break;
+ }
+ }
+ if (linebuf) {
+ if (ferror(file)) {
+ free(linebuf);
+ return NULL;
+ }
+ linebuf[idx] = 0;
+ }
+ return linebuf;
+}
+
+extern char *bb_get_line_from_file(FILE *file)
+{
+ return private_get_line_from_file(file, 0);
+}
+
+extern char *bb_get_chomped_line_from_file(FILE *file)
+{
+ return private_get_line_from_file(file, 1);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/get_terminal_width_height.c b/busybox/libbb/get_terminal_width_height.c
new file mode 100644
index 0000000..7a1af6d
--- /dev/null
+++ b/busybox/libbb/get_terminal_width_height.c
@@ -0,0 +1,66 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Determine the width and height of the terminal.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include "busybox.h"
+
+/* It is perfectly ok to pass in a NULL for either width or for
+ * height, in which case that value will not be set. It is also
+ * perfectly ok to have CONFIG_FEATURE_AUTOWIDTH disabled, in
+ * which case you will always get 80x24 */
+void get_terminal_width_height(int fd, int *width, int *height)
+{
+ struct winsize win = { 0, 0, 0, 0 };
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+ if (ioctl(fd, TIOCGWINSZ, &win) != 0) {
+ win.ws_row = 24;
+ win.ws_col = 80;
+ }
+#endif
+ if (win.ws_row <= 1) {
+ win.ws_row = 24;
+ }
+ if (win.ws_col <= 1) {
+ win.ws_col = 80;
+ }
+ if (height) {
+ *height = (int) win.ws_row;
+ }
+ if (width) {
+ *width = (int) win.ws_col;
+ }
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
+
diff --git a/busybox/libbb/get_ug_id.c b/busybox/libbb/get_ug_id.c
new file mode 100644
index 0000000..b0b9b2e
--- /dev/null
+++ b/busybox/libbb/get_ug_id.c
@@ -0,0 +1,30 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+
+extern unsigned long get_ug_id(const char *s, long (*my_getxxnam)(const char *))
+{
+ unsigned long r;
+ char *p;
+
+ r = strtoul(s, &p, 10);
+ if (*p || (s == p)) {
+ r = my_getxxnam(s);
+ }
+
+ return r;
+}
diff --git a/busybox/libbb/getopt_ulflags.c b/busybox/libbb/getopt_ulflags.c
new file mode 100644
index 0000000..39a7d1d
--- /dev/null
+++ b/busybox/libbb/getopt_ulflags.c
@@ -0,0 +1,171 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * universal getopt_ulflags implementation for busybox
+ *
+ * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <getopt.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+/*
+You can set bb_opt_complementaly as string with one or more
+complementaly or incongruously options.
+If sequential founded option haved from this string
+then your incongruously pairs unsets and complementaly make add sets.
+Format:
+one char - option for check,
+chars - complementaly option for add sets.
+- chars - option triggered for unsets.
+~ chars - option incongruously.
+* - option list, called add_to_list(*ptr_from_usaged, optarg)
+: - separator.
+Example: du applet can have options "-s" and "-d size"
+If getopt found -s then -d option flag unset or if found -d then -s unset.
+For this result you must set bb_opt_complementaly = "s-d:d-s".
+Result have last option flag only from called arguments.
+Warning! You can check returned flag, pointer to "d:" argument seted
+to own optarg always.
+Example two: cut applet must only one type of list may be specified,
+and -b, -c and -f incongruously option, overwited option is error also.
+You must set bb_opt_complementaly = "b~cf:c~bf:f~bc".
+If called have more one specified, return value have error flag -
+high bite set (0x80000000UL).
+Example three: grep applet can have one or more "-e pattern" arguments.
+You should use bb_getopt_ulflags() as
+llist_t *paterns;
+bb_opt_complementaly = "e*";
+bb_getopt_ulflags (argc, argv, "e:", &paterns);
+*/
+
+const char *bb_opt_complementaly;
+
+typedef struct
+{
+ unsigned char opt;
+ char list_flg;
+ unsigned long switch_on;
+ unsigned long switch_off;
+ unsigned long incongruously;
+ void **optarg; /* char **optarg or llist_t **optarg */
+} t_complementaly;
+
+/* You can set bb_applet_long_options for parse called long options */
+
+static const struct option bb_default_long_options[] = {
+ /* { "help", 0, NULL, '?' }, */
+ { 0, 0, 0, 0 }
+};
+
+const struct option *bb_applet_long_options = bb_default_long_options;
+
+
+unsigned long
+bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
+{
+ unsigned long flags = 0;
+ t_complementaly complementaly[sizeof(flags) * 8 + 1];
+ int c;
+ const unsigned char *s;
+ t_complementaly *on_off;
+ va_list p;
+
+ va_start (p, applet_opts);
+
+ /* skip GNU extension */
+ s = applet_opts;
+ if(*s == '+' || *s == '-')
+ s++;
+
+ c = 0;
+ on_off = complementaly;
+ for (; *s; s++) {
+ if(c >= (sizeof(flags)*8))
+ break;
+ on_off->opt = *s;
+ on_off->switch_on = (1 << c);
+ on_off->list_flg = 0;
+ on_off->switch_off = 0;
+ on_off->incongruously = 0;
+ on_off->optarg = NULL;
+ if (s[1] == ':') {
+ on_off->optarg = va_arg (p, void **);
+ do
+ s++;
+ while (s[1] == ':');
+ }
+ on_off++;
+ c++;
+ }
+ on_off->opt = 0;
+ c = 0;
+ for (s = bb_opt_complementaly; s && *s; s++) {
+ t_complementaly *pair;
+
+ if (*s == ':') {
+ c = 0;
+ continue;
+ }
+ if (c)
+ continue;
+ for (on_off = complementaly; on_off->opt; on_off++)
+ if (on_off->opt == *s)
+ break;
+ pair = on_off;
+ for(s++; *s && *s != ':'; s++) {
+ if (*s == '-' || *s == '~') {
+ c = *s;
+ } else if(*s == '*') {
+ pair->list_flg++;
+ } else {
+ unsigned long *pair_switch = &(pair->switch_on);
+
+ if(c)
+ pair_switch = c == '-' ? &(pair->switch_off) : &(pair->incongruously);
+ for (on_off = complementaly; on_off->opt; on_off++)
+ if (on_off->opt == *s) {
+ *pair_switch |= on_off->switch_on;
+ break;
+ }
+ }
+ }
+ s--;
+ }
+
+ while ((c = getopt_long (argc, argv, applet_opts,
+ bb_applet_long_options, NULL)) > 0) {
+ for (on_off = complementaly; on_off->opt != c; on_off++) {
+ if(!on_off->opt)
+ bb_show_usage ();
+ }
+ if(flags & on_off->incongruously)
+ flags |= 0x80000000UL;
+ flags &= ~on_off->switch_off;
+ flags |= on_off->switch_on;
+ if(on_off->list_flg) {
+ *(llist_t **)(on_off->optarg) =
+ llist_add_to(*(llist_t **)(on_off->optarg), optarg);
+ } else if (on_off->optarg) {
+ *(char **)(on_off->optarg) = optarg;
+ }
+ }
+ return flags;
+}
diff --git a/busybox/libbb/hash_fd.c b/busybox/libbb/hash_fd.c
new file mode 100644
index 0000000..e37ac54
--- /dev/null
+++ b/busybox/libbb/hash_fd.c
@@ -0,0 +1,859 @@
+/*
+ * Based on shasum from http://www.netsw.org/crypto/hash/
+ * Majorly hacked up to use Dr Brian Gladman's sha1 code
+ *
+ * Copyright (C) 2003 Glenn L. McGrath
+ * Copyright (C) 2003 Erik Andersen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <byteswap.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "busybox.h"
+
+
+#ifdef CONFIG_SHA1SUM
+/*
+ ---------------------------------------------------------------------------
+ Begin Dr. Gladman's sha1 code
+ ---------------------------------------------------------------------------
+*/
+
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary
+ form is allowed (with or without changes) provided that:
+
+ 1. distributions of this source code include the above copyright
+ notice, this list of conditions and the following disclaimer;
+
+ 2. distributions in binary form include the above copyright
+ notice, this list of conditions and the following disclaimer
+ in the documentation and/or other associated materials;
+
+ 3. the copyright holder's name is not used to endorse products
+ built using this software without specific written permission.
+
+ ALTERNATIVELY, provided that this notice is retained in full, this product
+ may be distributed under the terms of the GNU General Public License (GPL),
+ in which case the provisions of the GPL apply INSTEAD OF those given above.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue Date: 10/11/2002
+
+ This is a byte oriented version of SHA1 that operates on arrays of bytes
+ stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor
+*/
+
+# define SHA1_BLOCK_SIZE 64
+# define SHA1_DIGEST_SIZE 20
+# define SHA1_HASH_SIZE SHA1_DIGEST_SIZE
+# define SHA2_GOOD 0
+# define SHA2_BAD 1
+
+# define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
+
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define swap_b32(x) (x)
+# elif defined(bswap_32)
+# define swap_b32(x) bswap_32(x)
+# else
+# define swap_b32(x) ((rotl32((x), 8) & 0x00ff00ff) | (rotl32((x), 24) & 0xff00ff00))
+# endif /* __BYTE_ORDER */
+
+# define SHA1_MASK (SHA1_BLOCK_SIZE - 1)
+
+/* reverse byte order in 32-bit words */
+#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
+#define parity(x,y,z) ((x) ^ (y) ^ (z))
+#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
+
+/* A normal version as set out in the FIPS. This version uses */
+/* partial loop unrolling and is optimised for the Pentium 4 */
+# define rnd(f,k) \
+ t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; \
+ e = d; d = c; c = rotl32(b, 30); b = t
+
+/* type to hold the SHA1 context */
+struct sha1_ctx_t {
+ uint32_t count[2];
+ uint32_t hash[5];
+ uint32_t wbuf[16];
+};
+
+static void sha1_compile(struct sha1_ctx_t *ctx)
+{
+ uint32_t w[80], i, a, b, c, d, e, t;
+
+ /* note that words are compiled from the buffer into 32-bit */
+ /* words in big-endian order so an order reversal is needed */
+ /* here on little endian machines */
+ for (i = 0; i < SHA1_BLOCK_SIZE / 4; ++i)
+ w[i] = swap_b32(ctx->wbuf[i]);
+
+ for (i = SHA1_BLOCK_SIZE / 4; i < 80; ++i)
+ w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
+
+ a = ctx->hash[0];
+ b = ctx->hash[1];
+ c = ctx->hash[2];
+ d = ctx->hash[3];
+ e = ctx->hash[4];
+
+ for (i = 0; i < 20; ++i) {
+ rnd(ch, 0x5a827999);
+ }
+
+ for (i = 20; i < 40; ++i) {
+ rnd(parity, 0x6ed9eba1);
+ }
+
+ for (i = 40; i < 60; ++i) {
+ rnd(maj, 0x8f1bbcdc);
+ }
+
+ for (i = 60; i < 80; ++i) {
+ rnd(parity, 0xca62c1d6);
+ }
+
+ ctx->hash[0] += a;
+ ctx->hash[1] += b;
+ ctx->hash[2] += c;
+ ctx->hash[3] += d;
+ ctx->hash[4] += e;
+}
+
+static void sha1_begin(struct sha1_ctx_t *ctx)
+{
+ ctx->count[0] = ctx->count[1] = 0;
+ ctx->hash[0] = 0x67452301;
+ ctx->hash[1] = 0xefcdab89;
+ ctx->hash[2] = 0x98badcfe;
+ ctx->hash[3] = 0x10325476;
+ ctx->hash[4] = 0xc3d2e1f0;
+}
+
+/* SHA1 hash data in an array of bytes into hash buffer and call the */
+/* hash_compile function as required. */
+static void sha1_hash(const void *data, size_t len, void *ctx_v)
+{
+ struct sha1_ctx_t *ctx = (struct sha1_ctx_t *) ctx_v;
+ uint32_t pos = (uint32_t) (ctx->count[0] & SHA1_MASK);
+ uint32_t freeb = SHA1_BLOCK_SIZE - pos;
+ const unsigned char *sp = data;
+
+ if ((ctx->count[0] += len) < len)
+ ++(ctx->count[1]);
+
+ while (len >= freeb) { /* tranfer whole blocks while possible */
+ memcpy(((unsigned char *) ctx->wbuf) + pos, sp, freeb);
+ sp += freeb;
+ len -= freeb;
+ freeb = SHA1_BLOCK_SIZE;
+ pos = 0;
+ sha1_compile(ctx);
+ }
+
+ memcpy(((unsigned char *) ctx->wbuf) + pos, sp, len);
+}
+
+/* SHA1 Final padding and digest calculation */
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+static uint32_t mask[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff };
+static uint32_t bits[4] = { 0x00000080, 0x00008000, 0x00800000, 0x80000000 };
+# else
+static uint32_t mask[4] = { 0x00000000, 0xff000000, 0xffff0000, 0xffffff00 };
+static uint32_t bits[4] = { 0x80000000, 0x00800000, 0x00008000, 0x00000080 };
+# endif /* __BYTE_ORDER */
+
+void sha1_end(unsigned char hval[], struct sha1_ctx_t *ctx)
+{
+ uint32_t i, cnt = (uint32_t) (ctx->count[0] & SHA1_MASK);
+
+ /* mask out the rest of any partial 32-bit word and then set */
+ /* the next byte to 0x80. On big-endian machines any bytes in */
+ /* the buffer will be at the top end of 32 bit words, on little */
+ /* endian machines they will be at the bottom. Hence the AND */
+ /* and OR masks above are reversed for little endian systems */
+ ctx->wbuf[cnt >> 2] =
+ (ctx->wbuf[cnt >> 2] & mask[cnt & 3]) | bits[cnt & 3];
+
+ /* we need 9 or more empty positions, one for the padding byte */
+ /* (above) and eight for the length count. If there is not */
+ /* enough space pad and empty the buffer */
+ if (cnt > SHA1_BLOCK_SIZE - 9) {
+ if (cnt < 60)
+ ctx->wbuf[15] = 0;
+ sha1_compile(ctx);
+ cnt = 0;
+ } else /* compute a word index for the empty buffer positions */
+ cnt = (cnt >> 2) + 1;
+
+ while (cnt < 14) /* and zero pad all but last two positions */
+ ctx->wbuf[cnt++] = 0;
+
+ /* assemble the eight byte counter in the buffer in big-endian */
+ /* format */
+
+ ctx->wbuf[14] = swap_b32((ctx->count[1] << 3) | (ctx->count[0] >> 29));
+ ctx->wbuf[15] = swap_b32(ctx->count[0] << 3);
+
+ sha1_compile(ctx);
+
+ /* extract the hash value as bytes in case the hash buffer is */
+ /* misaligned for 32-bit words */
+
+ for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
+ hval[i] = (unsigned char) (ctx->hash[i >> 2] >> 8 * (~i & 3));
+}
+
+/*
+ ---------------------------------------------------------------------------
+ End of Dr. Gladman's sha1 code
+ ---------------------------------------------------------------------------
+*/
+#endif /* CONFIG_SHA1 */
+
+
+
+
+
+#ifdef CONFIG_MD5SUM
+/*
+ * md5sum.c - Compute MD5 checksum of files or strings according to the
+ * definition of MD5 in RFC 1321 from April 1992.
+ *
+ * Copyright (C) 1995-1999 Free Software Foundation, Inc.
+ * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+ *
+ *
+ * June 29, 2001 Manuel Novoa III
+ *
+ * Added MD5SUM_SIZE_VS_SPEED configuration option.
+ *
+ * Current valid values, with data from my system for comparison, are:
+ * (using uClibc and running on linux-2.4.4.tar.bz2)
+ * user times (sec) text size (386)
+ * 0 (fastest) 1.1 6144
+ * 1 1.4 5392
+ * 2 3.0 5088
+ * 3 (smallest) 5.1 4912
+ */
+
+# define MD5SUM_SIZE_VS_SPEED 2
+
+/* Handle endian-ness */
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+# define SWAP(n) (n)
+# elif defined(bswap_32)
+# define SWAP(n) bswap_32(n)
+# else
+# define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
+# endif
+
+# if MD5SUM_SIZE_VS_SPEED == 0
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+# endif /* MD5SUM_SIZE_VS_SPEED == 0 */
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx_t {
+ uint32_t A;
+ uint32_t B;
+ uint32_t C;
+ uint32_t D;
+ uint32_t total[2];
+ uint32_t buflen;
+ char buffer[128];
+};
+
+/* Initialize structure containing state of computation.
+ * (RFC 1321, 3.3: Step 3)
+ */
+static void md5_begin(struct md5_ctx_t *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ * and defined in the RFC 1321. The first function is a little bit optimized
+ * (as found in Colin Plumbs public domain implementation).
+ * #define FF(b, c, d) ((b & c) | (~b & d))
+ */
+# define FF(b, c, d) (d ^ (b & (c ^ d)))
+# define FG(b, c, d) FF (d, b, c)
+# define FH(b, c, d) (b ^ c ^ d)
+# define FI(b, c, d) (c ^ (b | ~d))
+
+/* Starting with the result of former calls of this function (or the
+ * initialization function update the context for the next LEN bytes
+ * starting at BUFFER.
+ * It is necessary that LEN is a multiple of 64!!!
+ */
+static void md5_hash_block(const void *buffer, size_t len, struct md5_ctx_t *ctx)
+{
+ uint32_t correct_words[16];
+ const uint32_t *words = buffer;
+ size_t nwords = len / sizeof(uint32_t);
+ const uint32_t *endp = words + nwords;
+
+# if MD5SUM_SIZE_VS_SPEED > 0
+ static const uint32_t C_array[] = {
+ /* round 1 */
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ /* round 2 */
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ /* round 3 */
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ /* round 4 */
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+ };
+
+ static const char P_array[] = {
+# if MD5SUM_SIZE_VS_SPEED > 1
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
+# endif /* MD5SUM_SIZE_VS_SPEED > 1 */
+ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
+ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
+ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
+ };
+
+# if MD5SUM_SIZE_VS_SPEED > 1
+ static const char S_array[] = {
+ 7, 12, 17, 22,
+ 5, 9, 14, 20,
+ 4, 11, 16, 23,
+ 6, 10, 15, 21
+ };
+# endif /* MD5SUM_SIZE_VS_SPEED > 1 */
+# endif
+
+ uint32_t A = ctx->A;
+ uint32_t B = ctx->B;
+ uint32_t C = ctx->C;
+ uint32_t D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp) {
+ uint32_t *cwp = correct_words;
+ uint32_t A_save = A;
+ uint32_t B_save = B;
+ uint32_t C_save = C;
+ uint32_t D_save = D;
+
+# if MD5SUM_SIZE_VS_SPEED > 1
+# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ const uint32_t *pc;
+ const char *pp;
+ const char *ps;
+ int i;
+ uint32_t temp;
+
+ for (i = 0; i < 16; i++) {
+ cwp[i] = SWAP(words[i]);
+ }
+ words += 16;
+
+# if MD5SUM_SIZE_VS_SPEED > 2
+ pc = C_array;
+ pp = P_array;
+ ps = S_array - 4;
+
+ for (i = 0; i < 64; i++) {
+ if ((i & 0x0f) == 0)
+ ps += 4;
+ temp = A;
+ switch (i >> 4) {
+ case 0:
+ temp += FF(B, C, D);
+ break;
+ case 1:
+ temp += FG(B, C, D);
+ break;
+ case 2:
+ temp += FH(B, C, D);
+ break;
+ case 3:
+ temp += FI(B, C, D);
+ }
+ temp += cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+# else
+ pc = C_array;
+ pp = P_array;
+ ps = S_array;
+
+ for (i = 0; i < 16; i++) {
+ temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+
+ ps += 4;
+ for (i = 0; i < 16; i++) {
+ temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+ ps += 4;
+ for (i = 0; i < 16; i++) {
+ temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+ ps += 4;
+ for (i = 0; i < 16; i++) {
+ temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++;
+ CYCLIC(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+
+# endif /* MD5SUM_SIZE_VS_SPEED > 2 */
+# else
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+# define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+ /* gcc 2.95.4 seems to be --aaronl */
+# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ */
+
+# if MD5SUM_SIZE_VS_SPEED == 1
+ const uint32_t *pc;
+ const char *pp;
+ int i;
+# endif /* MD5SUM_SIZE_VS_SPEED */
+
+ /* Round 1. */
+# if MD5SUM_SIZE_VS_SPEED == 1
+ pc = C_array;
+ for (i = 0; i < 4; i++) {
+ OP(A, B, C, D, 7, *pc++);
+ OP(D, A, B, C, 12, *pc++);
+ OP(C, D, A, B, 17, *pc++);
+ OP(B, C, D, A, 22, *pc++);
+ }
+# else
+ OP(A, B, C, D, 7, 0xd76aa478);
+ OP(D, A, B, C, 12, 0xe8c7b756);
+ OP(C, D, A, B, 17, 0x242070db);
+ OP(B, C, D, A, 22, 0xc1bdceee);
+ OP(A, B, C, D, 7, 0xf57c0faf);
+ OP(D, A, B, C, 12, 0x4787c62a);
+ OP(C, D, A, B, 17, 0xa8304613);
+ OP(B, C, D, A, 22, 0xfd469501);
+ OP(A, B, C, D, 7, 0x698098d8);
+ OP(D, A, B, C, 12, 0x8b44f7af);
+ OP(C, D, A, B, 17, 0xffff5bb1);
+ OP(B, C, D, A, 22, 0x895cd7be);
+ OP(A, B, C, D, 7, 0x6b901122);
+ OP(D, A, B, C, 12, 0xfd987193);
+ OP(C, D, A, B, 17, 0xa679438e);
+ OP(B, C, D, A, 22, 0x49b40821);
+# endif /* MD5SUM_SIZE_VS_SPEED == 1 */
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+# undef OP
+# define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+# if MD5SUM_SIZE_VS_SPEED == 1
+ pp = P_array;
+ for (i = 0; i < 4; i++) {
+ OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++);
+ OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++);
+ OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++);
+ OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++);
+ }
+# else
+ OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP(FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP(FG, D, A, B, C, 10, 9, 0x02441453);
+ OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+# endif /* MD5SUM_SIZE_VS_SPEED == 1 */
+
+ /* Round 3. */
+# if MD5SUM_SIZE_VS_SPEED == 1
+ for (i = 0; i < 4; i++) {
+ OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
+ OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++);
+ OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++);
+ OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++);
+ }
+# else
+ OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP(FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP(FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
+# endif /* MD5SUM_SIZE_VS_SPEED == 1 */
+
+ /* Round 4. */
+# if MD5SUM_SIZE_VS_SPEED == 1
+ for (i = 0; i < 4; i++) {
+ OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
+ OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++);
+ OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++);
+ OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++);
+ }
+# else
+ OP(FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP(FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP(FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
+# endif /* MD5SUM_SIZE_VS_SPEED == 1 */
+# endif /* MD5SUM_SIZE_VS_SPEED > 1 */
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
+
+/* Starting with the result of former calls of this function (or the
+ * initialization function update the context for the next LEN bytes
+ * starting at BUFFER.
+ * It is NOT required that LEN is a multiple of 64.
+ */
+
+static void md5_hash_bytes(const void *buffer, size_t len, struct md5_ctx_t *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0) {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy(&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (left_over + add > 64) {
+ md5_hash_block(ctx->buffer, (left_over + add) & ~63, ctx);
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ (left_over + add) & 63);
+ ctx->buflen = (left_over + add) & 63;
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len > 64) {
+ md5_hash_block(buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0) {
+ memcpy(ctx->buffer, buffer, len);
+ ctx->buflen = len;
+ }
+}
+
+static void md5_hash(const void *buffer, size_t length, void *md5_ctx)
+{
+ if (length % 64 == 0) {
+ md5_hash_block(buffer, length, md5_ctx);
+ } else {
+ md5_hash_bytes(buffer, length, md5_ctx);
+ }
+}
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ * in first 16 bytes following RESBUF. The result is always in little
+ * endian byte order, so that a byte-wise output yields to the wanted
+ * ASCII representation of the message digest.
+ *
+ * IMPORTANT: On some systems it is required that RESBUF is correctly
+ * aligned for a 32 bits value.
+ */
+static void *md5_end(void *resbuf, struct md5_ctx_t *ctx)
+{
+ /* Take yet unprocessed bytes into account. */
+ uint32_t bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+# if MD5SUM_SIZE_VS_SPEED > 0
+ memset(&ctx->buffer[bytes], 0, pad);
+ ctx->buffer[bytes] = 0x80;
+# else
+ memcpy(&ctx->buffer[bytes], fillbuf, pad);
+# endif /* MD5SUM_SIZE_VS_SPEED > 0 */
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(uint32_t *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
+ *(uint32_t *) & ctx->buffer[bytes + pad + 4] =
+ SWAP(((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
+
+ /* Process last bytes. */
+ md5_hash_block(ctx->buffer, bytes + pad + 8, ctx);
+
+ /* Put result from CTX in first 16 bytes following RESBUF. The result is
+ * always in little endian byte order, so that a byte-wise output yields
+ * to the wanted ASCII representation of the message digest.
+ *
+ * IMPORTANT: On some systems it is required that RESBUF is correctly
+ * aligned for a 32 bits value.
+ */
+ ((uint32_t *) resbuf)[0] = SWAP(ctx->A);
+ ((uint32_t *) resbuf)[1] = SWAP(ctx->B);
+ ((uint32_t *) resbuf)[2] = SWAP(ctx->C);
+ ((uint32_t *) resbuf)[3] = SWAP(ctx->D);
+
+ return resbuf;
+}
+#endif /* CONFIG_MD5SUM */
+
+
+
+
+extern int hash_fd(int src_fd, const size_t size, const uint8_t hash_algo,
+ uint8_t * hashval)
+{
+ int result = EXIT_SUCCESS;
+// size_t hashed_count = 0;
+ size_t blocksize = 0;
+ size_t remaining = size;
+ unsigned char *buffer = NULL;
+ void (*hash_fn_ptr)(const void *, size_t, void *) = NULL;
+ void *cx = NULL;
+
+#ifdef CONFIG_SHA1SUM
+ struct sha1_ctx_t sha1_cx;
+#endif
+#ifdef CONFIG_MD5SUM
+ struct md5_ctx_t md5_cx;
+#endif
+
+
+#ifdef CONFIG_SHA1SUM
+ if (hash_algo == HASH_SHA1) {
+ /* Ensure that BLOCKSIZE is a multiple of 64. */
+ blocksize = 65536;
+ buffer = xmalloc(blocksize);
+ hash_fn_ptr = sha1_hash;
+ cx = &sha1_cx;
+ }
+#endif
+#ifdef CONFIG_MD5SUM
+ if (hash_algo == HASH_MD5) {
+ blocksize = 4096;
+ buffer = xmalloc(blocksize + 72);
+ hash_fn_ptr = md5_hash;
+ cx = &md5_cx;
+ }
+#endif
+
+ /* Initialize the computation context. */
+#ifdef CONFIG_SHA1SUM
+ if (hash_algo == HASH_SHA1) {
+ sha1_begin(&sha1_cx);
+ }
+#endif
+#ifdef CONFIG_MD5SUM
+ if (hash_algo == HASH_MD5) {
+ md5_begin(&md5_cx);
+ }
+#endif
+ /* Iterate over full file contents. */
+ while ((remaining == (size_t) -1) || (remaining > 0)) {
+ size_t read_try;
+ ssize_t read_got;
+
+ if (remaining > blocksize) {
+ read_try = blocksize;
+ } else {
+ read_try = remaining;
+ }
+ read_got = bb_full_read(src_fd, buffer, read_try);
+ if (read_got < 1) {
+ /* count == 0 means short read
+ * count == -1 means read error */
+ result = read_got - 1;
+ break;
+ }
+ if (remaining != (size_t) -1) {
+ remaining -= read_got;
+ }
+
+ /* Process buffer */
+ hash_fn_ptr(buffer, read_got, cx);
+ }
+
+ /* Finalize and write the hash into our buffer. */
+#ifdef CONFIG_SHA1SUM
+ if (hash_algo == HASH_SHA1) {
+ sha1_end(hashval, &sha1_cx);
+ }
+#endif
+#ifdef CONFIG_MD5SUM
+ if (hash_algo == HASH_MD5) {
+ md5_end(hashval, &md5_cx);
+ }
+#endif
+
+ free(buffer);
+ return result;
+}
diff --git a/busybox/libbb/herror_msg.c b/busybox/libbb/herror_msg.c
new file mode 100644
index 0000000..87ec15a
--- /dev/null
+++ b/busybox/libbb/herror_msg.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "libbb.h"
+
+extern void bb_herror_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_vherror_msg(s, p);
+ va_end(p);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/herror_msg_and_die.c b/busybox/libbb/herror_msg_and_die.c
new file mode 100644
index 0000000..5c765f1
--- /dev/null
+++ b/busybox/libbb/herror_msg_and_die.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "libbb.h"
+
+extern void bb_herror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_vherror_msg(s, p);
+ va_end(p);
+ exit(bb_default_error_retval);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/human_readable.c b/busybox/libbb/human_readable.c
new file mode 100644
index 0000000..ad9025c
--- /dev/null
+++ b/busybox/libbb/human_readable.c
@@ -0,0 +1,87 @@
+/*
+ * June 30, 2001 Manuel Novoa III
+ *
+ * All-integer version (hey, not everyone has floating point) of
+ * make_human_readable_str, modified from similar code I had written
+ * for busybox several months ago.
+ *
+ * Notes:
+ * 1) I'm using an unsigned long long to hold the product size * block_size,
+ * as df (which calls this routine) could request a representation of a
+ * partition size in bytes > max of unsigned long. If long longs aren't
+ * available, it would be possible to do what's needed using polynomial
+ * representations (say, powers of 1024) and manipulating coefficients.
+ * The base ten "bytes" output could be handled similarly.
+ *
+ * 2) This routine always outputs a decimal point and a tenths digit when
+ * display_unit != 0. Hence, it isn't uncommon for the returned string
+ * to have a length of 5 or 6.
+ *
+ * It might be nice to add a flag to indicate no decimal digits in
+ * that case. This could be either an additional parameter, or a
+ * special value of display_unit. Such a flag would also be nice for du.
+ *
+ * Some code to omit the decimal point and tenths digit is sketched out
+ * and "#if 0"'d below.
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+const char *make_human_readable_str(unsigned long long size,
+ unsigned long block_size, unsigned long display_unit)
+{
+ /* The code will adjust for additional (appended) units. */
+ static const char zero_and_units[] = { '0', 0, 'k', 'M', 'G', 'T' };
+ static const char fmt[] = "%Lu";
+ static const char fmt_tenths[] = "%Lu.%d%c";
+
+ static char str[21]; /* Sufficient for 64 bit unsigned integers. */
+
+ unsigned long long val;
+ int frac;
+ const char *u;
+ const char *f;
+
+ u = zero_and_units;
+ f = fmt;
+ frac = 0;
+
+ val = size * block_size;
+ if (val == 0) {
+ return u;
+ }
+
+ if (display_unit) {
+ val += display_unit/2; /* Deal with rounding. */
+ val /= display_unit; /* Don't combine with the line above!!! */
+ } else {
+ ++u;
+ while ((val >= KILOBYTE)
+ && (u < zero_and_units + sizeof(zero_and_units) - 1)) {
+ f = fmt_tenths;
+ ++u;
+ frac = ((((int)(val % KILOBYTE)) * 10) + (KILOBYTE/2)) / KILOBYTE;
+ val /= KILOBYTE;
+ }
+ if (frac >= 10) { /* We need to round up here. */
+ ++val;
+ frac = 0;
+ }
+#if 0
+ /* Sample code to omit decimal point and tenths digit. */
+ if ( /* no_tenths */ 1 ) {
+ if ( frac >= 5 ) {
+ ++val;
+ }
+ f = "%Lu%*c" /* fmt_no_tenths */ ;
+ frac = 1;
+ }
+#endif
+ }
+
+ /* If f==fmt then 'frac' and 'u' are ignored. */
+ snprintf(str, sizeof(str), f, val, frac, *u);
+
+ return str;
+}
diff --git a/busybox/libbb/inet_common.c b/busybox/libbb/inet_common.c
new file mode 100644
index 0000000..321322d
--- /dev/null
+++ b/busybox/libbb/inet_common.c
@@ -0,0 +1,249 @@
+/*
+ * stolen from net-tools-1.59 and stripped down for busybox by
+ * Erik Andersen <andersen@codepoet.org>
+ *
+ * Heavily modified by Manuel Novoa III Mar 12, 2001
+ *
+ * Version: $Id: inet_common.c,v 1.8 2004/03/10 07:42:38 mjn3 Exp $
+ *
+ */
+
+#include "inet_common.h"
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "libbb.h"
+
+#ifdef DEBUG
+# include <resolv.h>
+#endif
+
+
+const char bb_INET_default[] = "default";
+
+int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst)
+{
+ struct hostent *hp;
+ struct netent *np;
+
+ /* Grmpf. -FvK */
+ s_in->sin_family = AF_INET;
+ s_in->sin_port = 0;
+
+ /* Default is special, meaning 0.0.0.0. */
+ if (!strcmp(name, bb_INET_default)) {
+ s_in->sin_addr.s_addr = INADDR_ANY;
+ return (1);
+ }
+ /* Look to see if it's a dotted quad. */
+ if (inet_aton(name, &s_in->sin_addr)) {
+ return 0;
+ }
+ /* If we expect this to be a hostname, try hostname database first */
+#ifdef DEBUG
+ if (hostfirst) {
+ bb_error_msg("gethostbyname (%s)", name);
+ }
+#endif
+ if (hostfirst && (hp = gethostbyname(name)) != (struct hostent *) NULL) {
+ memcpy((char *) &s_in->sin_addr, (char *) hp->h_addr_list[0],
+ sizeof(struct in_addr));
+ return 0;
+ }
+ /* Try the NETWORKS database to see if this is a known network. */
+#ifdef DEBUG
+ bb_error_msg("getnetbyname (%s)", name);
+#endif
+ if ((np = getnetbyname(name)) != (struct netent *) NULL) {
+ s_in->sin_addr.s_addr = htonl(np->n_net);
+ return 1;
+ }
+ if (hostfirst) {
+ /* Don't try again */
+ errno = h_errno;
+ return -1;
+ }
+#ifdef DEBUG
+ res_init();
+ _res.options |= RES_DEBUG;
+#endif
+
+#ifdef DEBUG
+ bb_error_msg("gethostbyname (%s)", name);
+#endif
+ if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
+ errno = h_errno;
+ return -1;
+ }
+ memcpy((char *) &s_in->sin_addr, (char *) hp->h_addr_list[0],
+ sizeof(struct in_addr));
+
+ return 0;
+}
+
+/* cache */
+struct addr {
+ struct sockaddr_in addr;
+ char *name;
+ int host;
+ struct addr *next;
+};
+
+static struct addr *INET_nn = NULL; /* addr-to-name cache */
+
+/* numeric: & 0x8000: default instead of *,
+ * & 0x4000: host instead of net,
+ * & 0x0fff: don't resolve
+ */
+int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in,
+ int numeric, unsigned int netmask)
+{
+ struct hostent *ent;
+ struct netent *np;
+ struct addr *pn;
+ unsigned long ad, host_ad;
+ int host = 0;
+
+ /* Grmpf. -FvK */
+ if (s_in->sin_family != AF_INET) {
+#ifdef DEBUG
+ bb_error_msg("rresolve: unsupport address family %d !",
+ s_in->sin_family);
+#endif
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ ad = (unsigned long) s_in->sin_addr.s_addr;
+#ifdef DEBUG
+ bb_error_msg("rresolve: %08lx, mask %08x, num %08x", ad, netmask, numeric);
+#endif
+ if (ad == INADDR_ANY) {
+ if ((numeric & 0x0FFF) == 0) {
+ if (numeric & 0x8000)
+ safe_strncpy(name, bb_INET_default, len);
+ else
+ safe_strncpy(name, "*", len);
+ return (0);
+ }
+ }
+ if (numeric & 0x0FFF) {
+ safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
+ return (0);
+ }
+
+ if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
+ host = 1;
+#if 0
+ INET_nn = NULL;
+#endif
+ pn = INET_nn;
+ while (pn != NULL) {
+ if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
+ safe_strncpy(name, pn->name, len);
+#ifdef DEBUG
+ bb_error_msg("rresolve: found %s %08lx in cache",
+ (host ? "host" : "net"), ad);
+#endif
+ return (0);
+ }
+ pn = pn->next;
+ }
+
+ host_ad = ntohl(ad);
+ np = NULL;
+ ent = NULL;
+ if (host) {
+#ifdef DEBUG
+ bb_error_msg("gethostbyaddr (%08lx)", ad);
+#endif
+ ent = gethostbyaddr((char *) &ad, 4, AF_INET);
+ if (ent != NULL) {
+ safe_strncpy(name, ent->h_name, len);
+ }
+ } else {
+#ifdef DEBUG
+ bb_error_msg("getnetbyaddr (%08lx)", host_ad);
+#endif
+ np = getnetbyaddr(host_ad, AF_INET);
+ if (np != NULL) {
+ safe_strncpy(name, np->n_name, len);
+ }
+ }
+ if ((ent == NULL) && (np == NULL)) {
+ safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
+ }
+ pn = (struct addr *) xmalloc(sizeof(struct addr));
+ pn->addr = *s_in;
+ pn->next = INET_nn;
+ pn->host = host;
+ pn->name = bb_xstrdup(name);
+ INET_nn = pn;
+
+ return (0);
+}
+
+#ifdef CONFIG_FEATURE_IPV6
+
+int INET6_resolve(const char *name, struct sockaddr_in6 *sin6)
+{
+ struct addrinfo req, *ai;
+ int s;
+
+ memset(&req, '\0', sizeof req);
+ req.ai_family = AF_INET6;
+ if ((s = getaddrinfo(name, NULL, &req, &ai))) {
+ bb_error_msg("getaddrinfo: %s: %d", name, s);
+ return -1;
+ }
+ memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6));
+
+ freeaddrinfo(ai);
+
+ return (0);
+}
+
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+# define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((__u32 *) (a))[0] == 0 && ((__u32 *) (a))[1] == 0 && \
+ ((__u32 *) (a))[2] == 0 && ((__u32 *) (a))[3] == 0)
+#endif
+
+
+int INET6_rresolve(char *name, size_t len, struct sockaddr_in6 *sin6,
+ int numeric)
+{
+ int s;
+
+ /* Grmpf. -FvK */
+ if (sin6->sin6_family != AF_INET6) {
+#ifdef DEBUG
+ bb_error_msg(_("rresolve: unsupport address family %d !\n"),
+ sin6->sin6_family);
+#endif
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ if (numeric & 0x7FFF) {
+ inet_ntop(AF_INET6, &sin6->sin6_addr, name, len);
+ return (0);
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ if (numeric & 0x8000) {
+ strcpy(name, "default");
+ } else {
+ strcpy(name, "*");
+ }
+ return (0);
+ }
+
+ s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6), name, len, NULL, 0, 0);
+ if (s) {
+ bb_error_msg("getnameinfo failed");
+ return -1;
+ }
+ return (0);
+}
+
+#endif /* CONFIG_FEATURE_IPV6 */
diff --git a/busybox/libbb/inode_hash.c b/busybox/libbb/inode_hash.c
new file mode 100644
index 0000000..fbcd813
--- /dev/null
+++ b/busybox/libbb/inode_hash.c
@@ -0,0 +1,111 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libbb.h"
+
+#define HASH_SIZE 311 /* Should be prime */
+#define hash_inode(i) ((i) % HASH_SIZE)
+
+typedef struct ino_dev_hash_bucket_struct {
+ struct ino_dev_hash_bucket_struct *next;
+ ino_t ino;
+ dev_t dev;
+ char name[1];
+} ino_dev_hashtable_bucket_t;
+
+static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
+
+/*
+ * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
+ * `ino_dev_hashtable', else return 0
+ *
+ * If NAME is a non-NULL pointer to a character pointer, and there is
+ * a match, then set *NAME to the value of the name slot in that
+ * bucket.
+ */
+int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
+{
+ ino_dev_hashtable_bucket_t *bucket;
+
+ bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
+ while (bucket != NULL) {
+ if ((bucket->ino == statbuf->st_ino) &&
+ (bucket->dev == statbuf->st_dev))
+ {
+ if (name) *name = bucket->name;
+ return 1;
+ }
+ bucket = bucket->next;
+ }
+ return 0;
+}
+
+/* Add statbuf to statbuf hash table */
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
+{
+ int i;
+ size_t s;
+ ino_dev_hashtable_bucket_t *bucket;
+
+ i = hash_inode(statbuf->st_ino);
+ s = name ? strlen(name) : 0;
+ bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
+ bucket->ino = statbuf->st_ino;
+ bucket->dev = statbuf->st_dev;
+ if (name)
+ strcpy(bucket->name, name);
+ else
+ bucket->name[0] = '\0';
+ bucket->next = ino_dev_hashtable[i];
+ ino_dev_hashtable[i] = bucket;
+}
+
+#ifdef CONFIG_FEATURE_CLEAN_UP
+/* Clear statbuf hash table */
+void reset_ino_dev_hashtable(void)
+{
+ int i;
+ ino_dev_hashtable_bucket_t *bucket;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+ while (ino_dev_hashtable[i] != NULL) {
+ bucket = ino_dev_hashtable[i]->next;
+ free(ino_dev_hashtable[i]);
+ ino_dev_hashtable[i] = bucket;
+ }
+ }
+}
+#endif
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/interface.c b/busybox/libbb/interface.c
new file mode 100644
index 0000000..fe2d0b4
--- /dev/null
+++ b/busybox/libbb/interface.c
@@ -0,0 +1,2083 @@
+/*
+ * stolen from net-tools-1.59 and stripped down for busybox by
+ * Erik Andersen <andersen@codepoet.org>
+ *
+ * Heavily modified by Manuel Novoa III Mar 12, 2001
+ *
+ * Pruned unused code using KEEP_UNUSED define.
+ * Added print_bytes_scaled function to reduce code size.
+ * Added some (potentially) missing defines.
+ * Improved display support for -a and for a named interface.
+ *
+ * -----------------------------------------------------------
+ *
+ * ifconfig This file contains an implementation of the command
+ * that either displays or sets the characteristics of
+ * one or more of the system's networking interfaces.
+ *
+ * Version: $Id: interface.c,v 1.25 2004/08/26 21:45:21 andersen Exp $
+ *
+ * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ * and others. Copyright 1993 MicroWalt Corporation
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * Patched to support 'add' and 'del' keywords for INET(4) addresses
+ * by Mrs. Brisby <mrs.brisby@nimh.org>
+ *
+ * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * - gettext instead of catgets for i18n
+ * 10/1998 - Andi Kleen. Use interface list primitives.
+ * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
+ * (default AF was wrong)
+ */
+
+/* #define KEEP_UNUSED */
+
+/*
+ *
+ * Protocol Families.
+ *
+ */
+#define HAVE_AFINET 1
+#undef HAVE_AFIPX
+#undef HAVE_AFATALK
+#undef HAVE_AFNETROM
+#undef HAVE_AFX25
+#undef HAVE_AFECONET
+#undef HAVE_AFASH
+
+/*
+ *
+ * Device Hardware types.
+ *
+ */
+#define HAVE_HWETHER 1
+#define HAVE_HWPPP 1
+#undef HAVE_HWSLIP
+
+
+#include "inet_common.h"
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include "libbb.h"
+
+#ifdef CONFIG_FEATURE_IPV6
+# define HAVE_AFINET6 1
+#else
+# undef HAVE_AFINET6
+#endif
+
+#define _(x) x
+#define _PATH_PROCNET_DEV "/proc/net/dev"
+#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
+#define new(p) ((p) = xcalloc(1,sizeof(*(p))))
+#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
+
+#ifdef HAVE_HWSLIP
+#include <net/if_slip.h>
+#endif
+
+#if HAVE_AFINET6
+
+#ifndef _LINUX_IN6_H
+/*
+ * This is in linux/include/net/ipv6.h.
+ */
+
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ uint32_t ifr6_prefixlen;
+ unsigned int ifr6_ifindex;
+};
+
+#endif
+
+#endif /* HAVE_AFINET6 */
+
+#if HAVE_AFIPX
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+#include <netipx/ipx.h>
+#else
+#include "ipx.h"
+#endif
+#endif
+
+/* Defines for glibc2.0 users. */
+#ifndef SIOCSIFTXQLEN
+#define SIOCSIFTXQLEN 0x8943
+#define SIOCGIFTXQLEN 0x8942
+#endif
+
+/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
+#ifndef ifr_qlen
+#define ifr_qlen ifr_ifru.ifru_mtu
+#endif
+
+#ifndef HAVE_TXQUEUELEN
+#define HAVE_TXQUEUELEN 1
+#endif
+
+#ifndef IFF_DYNAMIC
+#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
+#endif
+
+/* This structure defines protocol families and their handlers. */
+struct aftype {
+ const char *name;
+ const char *title;
+ int af;
+ int alen;
+ char *(*print) (unsigned char *);
+ char *(*sprint) (struct sockaddr *, int numeric);
+ int (*input) (int type, char *bufp, struct sockaddr *);
+ void (*herror) (char *text);
+ int (*rprint) (int options);
+ int (*rinput) (int typ, int ext, char **argv);
+
+ /* may modify src */
+ int (*getmask) (char *src, struct sockaddr * mask, char *name);
+
+ int fd;
+ char *flag_file;
+};
+
+#ifdef KEEP_UNUSED
+
+static int flag_unx;
+
+#ifdef HAVE_AFIPX
+static int flag_ipx;
+#endif
+#ifdef HAVE_AFX25
+static int flag_ax25;
+#endif
+#ifdef HAVE_AFATALK
+static int flag_ddp;
+#endif
+#ifdef HAVE_AFNETROM
+static int flag_netrom;
+#endif
+static int flag_inet;
+
+#ifdef HAVE_AFINET6
+static int flag_inet6;
+#endif
+#ifdef HAVE_AFECONET
+static int flag_econet;
+#endif
+#ifdef HAVE_AFX25
+static int flag_x25 = 0;
+#endif
+#ifdef HAVE_AFASH
+static int flag_ash;
+#endif
+
+
+static struct aftrans_t {
+ char *alias;
+ char *name;
+ int *flag;
+} aftrans[] = {
+
+#ifdef HAVE_AFX25
+ {
+ "ax25", "ax25", &flag_ax25},
+#endif
+ {
+ "ip", "inet", &flag_inet},
+#ifdef HAVE_AFINET6
+ {
+ "ip6", "inet6", &flag_inet6},
+#endif
+#ifdef HAVE_AFIPX
+ {
+ "ipx", "ipx", &flag_ipx},
+#endif
+#ifdef HAVE_AFATALK
+ {
+ "appletalk", "ddp", &flag_ddp},
+#endif
+#ifdef HAVE_AFNETROM
+ {
+ "netrom", "netrom", &flag_netrom},
+#endif
+ {
+ "inet", "inet", &flag_inet},
+#ifdef HAVE_AFINET6
+ {
+ "inet6", "inet6", &flag_inet6},
+#endif
+#ifdef HAVE_AFATALK
+ {
+ "ddp", "ddp", &flag_ddp},
+#endif
+ {
+ "unix", "unix", &flag_unx}, {
+ "tcpip", "inet", &flag_inet},
+#ifdef HAVE_AFECONET
+ {
+ "econet", "ec", &flag_econet},
+#endif
+#ifdef HAVE_AFX25
+ {
+ "x25", "x25", &flag_x25},
+#endif
+#ifdef HAVE_AFASH
+ {
+ "ash", "ash", &flag_ash},
+#endif
+ {
+ 0, 0, 0}
+};
+
+static char afname[256] = "";
+#endif /* KEEP_UNUSED */
+
+#if HAVE_AFUNIX
+
+/* Display a UNIX domain address. */
+static char *UNIX_print(unsigned char *ptr)
+{
+ return (ptr);
+}
+
+
+/* Display a UNIX domain address. */
+static char *UNIX_sprint(struct sockaddr *sap, int numeric)
+{
+ static char buf[64];
+
+ if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+ return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
+ return (UNIX_print(sap->sa_data));
+}
+
+
+static struct aftype unix_aftype = {
+ "unix", "UNIX Domain", AF_UNIX, 0,
+ UNIX_print, UNIX_sprint, NULL, NULL,
+ NULL, NULL, NULL,
+ -1,
+ "/proc/net/unix"
+};
+#endif /* HAVE_AFUNIX */
+
+#if HAVE_AFINET
+
+#ifdef KEEP_UNUSED
+static void INET_reserror(char *text)
+{
+ herror(text);
+}
+
+/* Display an Internet socket address. */
+static char *INET_print(unsigned char *ptr)
+{
+ return (inet_ntoa((*(struct in_addr *) ptr)));
+}
+#endif /* KEEP_UNUSED */
+
+/* Display an Internet socket address. */
+static char *INET_sprint(struct sockaddr *sap, int numeric)
+{
+ static char buff[128];
+
+ if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+ return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
+
+ if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
+ numeric, 0xffffff00) != 0)
+ return (NULL);
+
+ return (buff);
+}
+
+#ifdef KEEP_UNUSED
+static char *INET_sprintmask(struct sockaddr *sap, int numeric,
+ unsigned int netmask)
+{
+ static char buff[128];
+
+ if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+ return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
+ if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
+ numeric, netmask) != 0)
+ return (NULL);
+ return (buff);
+}
+
+static int INET_getsock(char *bufp, struct sockaddr *sap)
+{
+ char *sp = bufp, *bp;
+ unsigned int i;
+ unsigned val;
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *) sap;
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+
+ val = 0;
+ bp = (char *) &val;
+ for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
+ *sp = toupper(*sp);
+
+ if ((*sp >= 'A') && (*sp <= 'F'))
+ bp[i] |= (int) (*sp - 'A') + 10;
+ else if ((*sp >= '0') && (*sp <= '9'))
+ bp[i] |= (int) (*sp - '0');
+ else
+ return (-1);
+
+ bp[i] <<= 4;
+ sp++;
+ *sp = toupper(*sp);
+
+ if ((*sp >= 'A') && (*sp <= 'F'))
+ bp[i] |= (int) (*sp - 'A') + 10;
+ else if ((*sp >= '0') && (*sp <= '9'))
+ bp[i] |= (int) (*sp - '0');
+ else
+ return (-1);
+
+ sp++;
+ }
+ sin->sin_addr.s_addr = htonl(val);
+
+ return (sp - bufp);
+}
+
+static int INET_input(int type, char *bufp, struct sockaddr *sap)
+{
+ switch (type) {
+ case 1:
+ return (INET_getsock(bufp, sap));
+ case 256:
+ return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
+ default:
+ return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
+ }
+}
+
+static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
+{
+ struct sockaddr_in *mask = (struct sockaddr_in *) m;
+ char *slash, *end;
+ int prefix;
+
+ if ((slash = strchr(adr, '/')) == NULL)
+ return 0;
+
+ *slash++ = '\0';
+ prefix = strtoul(slash, &end, 0);
+ if (*end != '\0')
+ return -1;
+
+ if (name) {
+ sprintf(name, "/%d", prefix);
+ }
+ mask->sin_family = AF_INET;
+ mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
+ return 1;
+}
+#endif /* KEEP_UNUSED */
+
+static struct aftype inet_aftype = {
+ "inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
+ NULL /* UNUSED INET_print */ , INET_sprint,
+ NULL /* UNUSED INET_input */ , NULL /* UNUSED INET_reserror */ ,
+ NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
+ NULL /* UNUSED INET_getnetmask */ ,
+ -1,
+ NULL
+};
+
+#endif /* HAVE_AFINET */
+
+#if HAVE_AFINET6
+
+#ifdef KEEP_UNUSED
+static void INET6_reserror(char *text)
+{
+ herror(text);
+}
+
+/* Display an Internet socket address. */
+static char *INET6_print(unsigned char *ptr)
+{
+ static char name[80];
+
+ inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80);
+ return name;
+}
+#endif /* KEEP_UNUSED */
+
+/* Display an Internet socket address. */
+/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
+static char *INET6_sprint(struct sockaddr *sap, int numeric)
+{
+ static char buff[128];
+
+ if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+ return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
+ if (INET6_rresolve
+ (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
+ return safe_strncpy(buff, _("[UNKNOWN]"), sizeof(buff));
+ return (buff);
+}
+
+#ifdef KEEP_UNUSED
+static int INET6_getsock(char *bufp, struct sockaddr *sap)
+{
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *) sap;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+
+ if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
+ return (-1);
+
+ return 16; /* ?;) */
+}
+
+static int INET6_input(int type, char *bufp, struct sockaddr *sap)
+{
+ switch (type) {
+ case 1:
+ return (INET6_getsock(bufp, sap));
+ default:
+ return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
+ }
+}
+#endif /* KEEP_UNUSED */
+
+static struct aftype inet6_aftype = {
+ "inet6", "IPv6", AF_INET6, sizeof(struct in6_addr),
+ NULL /* UNUSED INET6_print */ , INET6_sprint,
+ NULL /* UNUSED INET6_input */ , NULL /* UNUSED INET6_reserror */ ,
+ NULL /*INET6_rprint */ , NULL /*INET6_rinput */ ,
+ NULL /* UNUSED INET6_getnetmask */ ,
+ -1,
+ NULL
+};
+
+#endif /* HAVE_AFINET6 */
+
+/* Display an UNSPEC address. */
+static char *UNSPEC_print(unsigned char *ptr)
+{
+ static char buff[sizeof(struct sockaddr) * 3 + 1];
+ char *pos;
+ unsigned int i;
+
+ pos = buff;
+ for (i = 0; i < sizeof(struct sockaddr); i++) {
+ /* careful -- not every libc's sprintf returns # bytes written */
+ sprintf(pos, "%02X-", (*ptr++ & 0377));
+ pos += 3;
+ }
+ /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
+ *--pos = '\0';
+ return (buff);
+}
+
+/* Display an UNSPEC socket address. */
+static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
+{
+ static char buf[64];
+
+ if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
+ return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
+ return (UNSPEC_print(sap->sa_data));
+}
+
+static struct aftype unspec_aftype = {
+ "unspec", "UNSPEC", AF_UNSPEC, 0,
+ UNSPEC_print, UNSPEC_sprint, NULL, NULL,
+ NULL,
+};
+
+static struct aftype *aftypes[] = {
+#if HAVE_AFUNIX
+ &unix_aftype,
+#endif
+#if HAVE_AFINET
+ &inet_aftype,
+#endif
+#if HAVE_AFINET6
+ &inet6_aftype,
+#endif
+#if HAVE_AFAX25
+ &ax25_aftype,
+#endif
+#if HAVE_AFNETROM
+ &netrom_aftype,
+#endif
+#if HAVE_AFROSE
+ &rose_aftype,
+#endif
+#if HAVE_AFIPX
+ &ipx_aftype,
+#endif
+#if HAVE_AFATALK
+ &ddp_aftype,
+#endif
+#if HAVE_AFECONET
+ &ec_aftype,
+#endif
+#if HAVE_AFASH
+ &ash_aftype,
+#endif
+#if HAVE_AFX25
+ &x25_aftype,
+#endif
+ &unspec_aftype,
+ NULL
+};
+
+#ifdef KEEP_UNUSED
+static short sVafinit = 0;
+
+static void afinit()
+{
+ unspec_aftype.title = _("UNSPEC");
+#if HAVE_AFUNIX
+ unix_aftype.title = _("UNIX Domain");
+#endif
+#if HAVE_AFINET
+ inet_aftype.title = _("DARPA Internet");
+#endif
+#if HAVE_AFINET6
+ inet6_aftype.title = _("IPv6");
+#endif
+#if HAVE_AFAX25
+ ax25_aftype.title = _("AMPR AX.25");
+#endif
+#if HAVE_AFNETROM
+ netrom_aftype.title = _("AMPR NET/ROM");
+#endif
+#if HAVE_AFIPX
+ ipx_aftype.title = _("Novell IPX");
+#endif
+#if HAVE_AFATALK
+ ddp_aftype.title = _("Appletalk DDP");
+#endif
+#if HAVE_AFECONET
+ ec_aftype.title = _("Econet");
+#endif
+#if HAVE_AFX25
+ x25_aftype.title = _("CCITT X.25");
+#endif
+#if HAVE_AFROSE
+ rose_aftype.title = _("AMPR ROSE");
+#endif
+#if HAVE_AFASH
+ ash_aftype.title = _("Ash");
+#endif
+ sVafinit = 1;
+}
+
+static int aftrans_opt(const char *arg)
+{
+ struct aftrans_t *paft;
+ char *tmp1, *tmp2;
+ char buf[256];
+
+ safe_strncpy(buf, arg, sizeof(buf));
+
+ tmp1 = buf;
+
+ while (tmp1) {
+
+ tmp2 = strchr(tmp1, ',');
+
+ if (tmp2)
+ *(tmp2++) = '\0';
+
+ paft = aftrans;
+ for (paft = aftrans; paft->alias; paft++) {
+ if (strcmp(tmp1, paft->alias))
+ continue;
+ if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
+ bb_error_msg(_("Too many address family arguments."));
+ return (0);
+ }
+ if (paft->flag)
+ (*paft->flag)++;
+ if (afname[0])
+ strcat(afname, ",");
+ strcat(afname, paft->name);
+ break;
+ }
+ if (!paft->alias) {
+ bb_error_msg(_("Unknown address family `%s'."), tmp1);
+ return (1);
+ }
+ tmp1 = tmp2;
+ }
+
+ return (0);
+}
+
+/* set the default AF list from the program name or a constant value */
+static void aftrans_def(char *tool, char *argv0, char *dflt)
+{
+ char *tmp;
+ char *buf;
+
+ strcpy(afname, dflt);
+
+ if (!(tmp = strrchr(argv0, '/')))
+ tmp = argv0; /* no slash?! */
+ else
+ tmp++;
+
+ if (!(buf = strdup(tmp)))
+ return;
+
+ if (strlen(tool) >= strlen(tmp)) {
+ free(buf);
+ return;
+ }
+ tmp = buf + (strlen(tmp) - strlen(tool));
+
+ if (strcmp(tmp, tool) != 0) {
+ free(buf);
+ return;
+ }
+ *tmp = '\0';
+ if ((tmp = strchr(buf, '_')))
+ *tmp = '\0';
+
+ afname[0] = '\0';
+ if (aftrans_opt(buf))
+ strcpy(afname, buf);
+
+ free(buf);
+}
+
+/* Check our protocol family table for this family. */
+static struct aftype *get_aftype(const char *name)
+{
+ struct aftype **afp;
+
+#ifdef KEEP_UNUSED
+ if (!sVafinit)
+ afinit();
+#endif /* KEEP_UNUSED */
+
+ afp = aftypes;
+ while (*afp != NULL) {
+ if (!strcmp((*afp)->name, name))
+ return (*afp);
+ afp++;
+ }
+ if (strchr(name, ','))
+ bb_error_msg(_("Please don't supply more than one address family."));
+ return (NULL);
+}
+#endif /* KEEP_UNUSED */
+
+/* Check our protocol family table for this family. */
+static struct aftype *get_afntype(int af)
+{
+ struct aftype **afp;
+
+#ifdef KEEP_UNUSED
+ if (!sVafinit)
+ afinit();
+#endif /* KEEP_UNUSED */
+
+ afp = aftypes;
+ while (*afp != NULL) {
+ if ((*afp)->af == af)
+ return (*afp);
+ afp++;
+ }
+ return (NULL);
+}
+
+/* Check our protocol family table for this family and return its socket */
+static int get_socket_for_af(int af)
+{
+ struct aftype **afp;
+
+#ifdef KEEP_UNUSED
+ if (!sVafinit)
+ afinit();
+#endif /* KEEP_UNUSED */
+
+ afp = aftypes;
+ while (*afp != NULL) {
+ if ((*afp)->af == af)
+ return (*afp)->fd;
+ afp++;
+ }
+ return -1;
+}
+
+#ifdef KEEP_UNUSED
+/* type: 0=all, 1=getroute */
+static void print_aflist(int type)
+{
+ int count = 0;
+ char *txt;
+ struct aftype **afp;
+
+#ifdef KEEP_UNUSED
+ if (!sVafinit)
+ afinit();
+#endif /* KEEP_UNUSED */
+
+ afp = aftypes;
+ while (*afp != NULL) {
+ if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
+ afp++;
+ continue;
+ }
+ if ((count % 3) == 0)
+ fprintf(stderr, count ? "\n " : " ");
+ txt = (*afp)->name;
+ if (!txt)
+ txt = "..";
+ fprintf(stderr, "%s (%s) ", txt, _((*afp)->title));
+ count++;
+ afp++;
+ }
+ fprintf(stderr, "\n");
+}
+#endif /* KEEP_UNUSED */
+
+struct user_net_device_stats {
+ unsigned long long rx_packets; /* total packets received */
+ unsigned long long tx_packets; /* total packets transmitted */
+ unsigned long long rx_bytes; /* total bytes received */
+ unsigned long long tx_bytes; /* total bytes transmitted */
+ unsigned long rx_errors; /* bad packets received */
+ unsigned long tx_errors; /* packet transmit problems */
+ unsigned long rx_dropped; /* no space in linux buffers */
+ unsigned long tx_dropped; /* no space available in linux */
+ unsigned long rx_multicast; /* multicast packets received */
+ unsigned long rx_compressed;
+ unsigned long tx_compressed;
+ unsigned long collisions;
+
+ /* detailed rx_errors: */
+ unsigned long rx_length_errors;
+ unsigned long rx_over_errors; /* receiver ring buff overflow */
+ unsigned long rx_crc_errors; /* recved pkt with crc error */
+ unsigned long rx_frame_errors; /* recv'd frame alignment error */
+ unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+ unsigned long rx_missed_errors; /* receiver missed packet */
+ /* detailed tx_errors */
+ unsigned long tx_aborted_errors;
+ unsigned long tx_carrier_errors;
+ unsigned long tx_fifo_errors;
+ unsigned long tx_heartbeat_errors;
+ unsigned long tx_window_errors;
+};
+
+struct interface {
+ struct interface *next, *prev;
+ char name[IFNAMSIZ]; /* interface name */
+ short type; /* if type */
+ short flags; /* various flags */
+ int metric; /* routing metric */
+ int mtu; /* MTU value */
+ int tx_queue_len; /* transmit queue length */
+ struct ifmap map; /* hardware setup */
+ struct sockaddr addr; /* IP address */
+ struct sockaddr dstaddr; /* P-P IP address */
+ struct sockaddr broadaddr; /* IP broadcast address */
+ struct sockaddr netmask; /* IP network mask */
+ struct sockaddr ipxaddr_bb; /* IPX network address */
+ struct sockaddr ipxaddr_sn; /* IPX network address */
+ struct sockaddr ipxaddr_e3; /* IPX network address */
+ struct sockaddr ipxaddr_e2; /* IPX network address */
+ struct sockaddr ddpaddr; /* Appletalk DDP address */
+ struct sockaddr ecaddr; /* Econet address */
+ int has_ip;
+ int has_ipx_bb;
+ int has_ipx_sn;
+ int has_ipx_e3;
+ int has_ipx_e2;
+ int has_ax25;
+ int has_ddp;
+ int has_econet;
+ char hwaddr[32]; /* HW address */
+ int statistics_valid;
+ struct user_net_device_stats stats; /* statistics */
+ int keepalive; /* keepalive value for SLIP */
+ int outfill; /* outfill value for SLIP */
+};
+
+
+int interface_opt_a = 0; /* show all interfaces */
+
+#ifdef KEEP_UNUSED
+static int opt_i = 0; /* show the statistics */
+static int opt_v = 0; /* debugging output flag */
+
+static int addr_family = 0; /* currently selected AF */
+#endif /* KEEP_UNUSED */
+
+static struct interface *int_list, *int_last;
+static int skfd = -1; /* generic raw socket desc. */
+
+
+static int sockets_open(int family)
+{
+ struct aftype **aft;
+ int sfd = -1;
+ static int force = -1;
+
+ if (force < 0) {
+ force = 0;
+ if (get_kernel_revision() < KRELEASE(2, 1, 0))
+ force = 1;
+ if (access("/proc/net", R_OK))
+ force = 1;
+ }
+ for (aft = aftypes; *aft; aft++) {
+ struct aftype *af = *aft;
+ int type = SOCK_DGRAM;
+
+ if (af->af == AF_UNSPEC)
+ continue;
+ if (family && family != af->af)
+ continue;
+ if (af->fd != -1) {
+ sfd = af->fd;
+ continue;
+ }
+ /* Check some /proc file first to not stress kmod */
+ if (!family && !force && af->flag_file) {
+ if (access(af->flag_file, R_OK))
+ continue;
+ }
+#if HAVE_AFNETROM
+ if (af->af == AF_NETROM)
+ type = SOCK_SEQPACKET;
+#endif
+#if HAVE_AFX25
+ if (af->af == AF_X25)
+ type = SOCK_SEQPACKET;
+#endif
+ af->fd = socket(af->af, type, 0);
+ if (af->fd >= 0)
+ sfd = af->fd;
+ }
+ if (sfd < 0) {
+ bb_error_msg(_("No usable address families found."));
+ }
+ return sfd;
+}
+
+/* like strcmp(), but knows about numbers */
+static int nstrcmp(const char *a, const char *b)
+{
+ const char *a_ptr = a;
+ const char *b_ptr = b;
+
+ while (*a == *b) {
+ if (*a == '\0') {
+ return 0;
+ }
+ if (!isdigit(*a) && isdigit(*(a+1))) {
+ a_ptr = a+1;
+ b_ptr = b+1;
+ }
+ a++;
+ b++;
+ }
+
+ if (isdigit(*a) && isdigit(*b)) {
+ return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
+ }
+ return *a - *b;
+}
+
+static struct interface *add_interface(char *name)
+{
+ struct interface *ife, **nextp, *new;
+
+ for (ife = int_last; ife; ife = ife->prev) {
+ int n = nstrcmp(ife->name, name);
+
+ if (n == 0)
+ return ife;
+ if (n < 0)
+ break;
+ }
+ new(new);
+ safe_strncpy(new->name, name, IFNAMSIZ);
+ nextp = ife ? &ife->next : &int_list;
+ new->prev = ife;
+ new->next = *nextp;
+ if (new->next)
+ new->next->prev = new;
+ else
+ int_last = new;
+ *nextp = new;
+ return new;
+}
+
+
+static int if_readconf(void)
+{
+ int numreqs = 30;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ int n, err = -1;
+ int skfd2;
+
+ /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
+ (as of 2.1.128) */
+ skfd2 = get_socket_for_af(AF_INET);
+ if (skfd2 < 0) {
+ bb_perror_msg(("warning: no inet socket available"));
+ /* Try to soldier on with whatever socket we can get hold of. */
+ skfd2 = sockets_open(0);
+ if (skfd2 < 0)
+ return -1;
+ }
+
+ ifc.ifc_buf = NULL;
+ for (;;) {
+ ifc.ifc_len = sizeof(struct ifreq) * numreqs;
+ ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
+
+ if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
+ perror("SIOCGIFCONF");
+ goto out;
+ }
+ if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
+ /* assume it overflowed and try again */
+ numreqs += 10;
+ continue;
+ }
+ break;
+ }
+
+ ifr = ifc.ifc_req;
+ for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
+ add_interface(ifr->ifr_name);
+ ifr++;
+ }
+ err = 0;
+
+ out:
+ free(ifc.ifc_buf);
+ return err;
+}
+
+char *get_name(char *name, char *p)
+{
+ /* Extract <name>[:<alias>] from nul-terminated p where p matches
+ <name>[:<alias>]: after leading whitespace.
+ If match is not made, set name empty and return unchanged p */
+ int namestart=0, nameend=0, aliasend;
+ while (isspace(p[namestart]))
+ namestart++;
+ nameend=namestart;
+ while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
+ nameend++;
+ if (p[nameend]==':') {
+ aliasend=nameend+1;
+ while (p[aliasend] && isdigit(p[aliasend]))
+ aliasend++;
+ if (p[aliasend]==':') {
+ nameend=aliasend;
+ }
+ if ((nameend-namestart)<IFNAMSIZ) {
+ memcpy(name,&p[namestart],nameend-namestart);
+ name[nameend-namestart]='\0';
+ p=&p[nameend];
+ } else {
+ /* Interface name too large */
+ name[0]='\0';
+ }
+ } else {
+ /* first ':' not found - return empty */
+ name[0]='\0';
+ }
+ return p + 1;
+}
+
+/* If scanf supports size qualifiers for %n conversions, then we can
+ * use a modified fmt that simply stores the position in the fields
+ * having no associated fields in the proc string. Of course, we need
+ * to zero them again when we're done. But that is smaller than the
+ * old approach of multiple scanf occurrences with large numbers of
+ * args. */
+
+/* static const char *ss_fmt[] = { */
+/* "%Ln%Lu%lu%lu%lu%lu%ln%ln%Ln%Lu%lu%lu%lu%lu%lu", */
+/* "%Lu%Lu%lu%lu%lu%lu%ln%ln%Lu%Lu%lu%lu%lu%lu%lu", */
+/* "%Lu%Lu%lu%lu%lu%lu%lu%lu%Lu%Lu%lu%lu%lu%lu%lu%lu" */
+/* }; */
+
+ /* Lie about the size of the int pointed to for %n. */
+#if INT_MAX == LONG_MAX
+static const char *ss_fmt[] = {
+ "%n%Lu%u%u%u%u%n%n%n%Lu%u%u%u%u%u",
+ "%Lu%Lu%u%u%u%u%n%n%Lu%Lu%u%u%u%u%u",
+ "%Lu%Lu%u%u%u%u%u%u%Lu%Lu%u%u%u%u%u%u"
+};
+#else
+static const char *ss_fmt[] = {
+ "%n%Lu%lu%lu%lu%lu%n%n%n%Lu%lu%lu%lu%lu%lu",
+ "%Lu%Lu%lu%lu%lu%lu%n%n%Lu%Lu%lu%lu%lu%lu%lu",
+ "%Lu%Lu%lu%lu%lu%lu%lu%lu%Lu%Lu%lu%lu%lu%lu%lu%lu"
+};
+
+#endif
+
+static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
+{
+ memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
+
+ sscanf(bp, ss_fmt[procnetdev_vsn],
+ &ife->stats.rx_bytes, /* missing for 0 */
+ &ife->stats.rx_packets,
+ &ife->stats.rx_errors,
+ &ife->stats.rx_dropped,
+ &ife->stats.rx_fifo_errors,
+ &ife->stats.rx_frame_errors,
+ &ife->stats.rx_compressed, /* missing for <= 1 */
+ &ife->stats.rx_multicast, /* missing for <= 1 */
+ &ife->stats.tx_bytes, /* missing for 0 */
+ &ife->stats.tx_packets,
+ &ife->stats.tx_errors,
+ &ife->stats.tx_dropped,
+ &ife->stats.tx_fifo_errors,
+ &ife->stats.collisions,
+ &ife->stats.tx_carrier_errors,
+ &ife->stats.tx_compressed /* missing for <= 1 */
+ );
+
+ if (procnetdev_vsn <= 1) {
+ if (procnetdev_vsn == 0) {
+ ife->stats.rx_bytes = 0;
+ ife->stats.tx_bytes = 0;
+ }
+ ife->stats.rx_multicast = 0;
+ ife->stats.rx_compressed = 0;
+ ife->stats.tx_compressed = 0;
+ }
+}
+
+static inline int procnetdev_version(char *buf)
+{
+ if (strstr(buf, "compressed"))
+ return 2;
+ if (strstr(buf, "bytes"))
+ return 1;
+ return 0;
+}
+
+static int if_readlist_proc(char *target)
+{
+ static int proc_read;
+ FILE *fh;
+ char buf[512];
+ struct interface *ife;
+ int err, procnetdev_vsn;
+
+ if (proc_read)
+ return 0;
+ if (!target)
+ proc_read = 1;
+
+ fh = fopen(_PATH_PROCNET_DEV, "r");
+ if (!fh) {
+ bb_perror_msg(_("Warning: cannot open %s. Limited output."), _PATH_PROCNET_DEV);
+ return if_readconf();
+ }
+ fgets(buf, sizeof buf, fh); /* eat line */
+ fgets(buf, sizeof buf, fh);
+
+ procnetdev_vsn = procnetdev_version(buf);
+
+ err = 0;
+ while (fgets(buf, sizeof buf, fh)) {
+ char *s, name[128];
+
+ s = get_name(name, buf);
+ ife = add_interface(name);
+ get_dev_fields(s, ife, procnetdev_vsn);
+ ife->statistics_valid = 1;
+ if (target && !strcmp(target, name))
+ break;
+ }
+ if (ferror(fh)) {
+ perror(_PATH_PROCNET_DEV);
+ err = -1;
+ proc_read = 0;
+ }
+ fclose(fh);
+ return err;
+}
+
+static int if_readlist(void)
+{
+ int err = if_readlist_proc(NULL);
+
+ if (!err)
+ err = if_readconf();
+ return err;
+}
+
+static int for_all_interfaces(int (*doit) (struct interface *, void *),
+ void *cookie)
+{
+ struct interface *ife;
+
+ if (!int_list && (if_readlist() < 0))
+ return -1;
+ for (ife = int_list; ife; ife = ife->next) {
+ int err = doit(ife, cookie);
+
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+/* Support for fetching an IPX address */
+
+#if HAVE_AFIPX
+static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
+{
+ ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
+ return ioctl(sock, SIOCGIFADDR, ifr);
+}
+#endif
+
+
+/* Fetch the interface configuration from the kernel. */
+static int if_fetch(struct interface *ife)
+{
+ struct ifreq ifr;
+ int fd;
+ char *ifname = ife->name;
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
+ return (-1);
+ ife->flags = ifr.ifr_flags;
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
+ memset(ife->hwaddr, 0, 32);
+ else
+ memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
+
+ ife->type = ifr.ifr_hwaddr.sa_family;
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
+ ife->metric = 0;
+ else
+ ife->metric = ifr.ifr_metric;
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
+ ife->mtu = 0;
+ else
+ ife->mtu = ifr.ifr_mtu;
+
+#ifdef HAVE_HWSLIP
+ if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
+ ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
+ ife->type == ARPHRD_ADAPT) {
+#ifdef SIOCGOUTFILL
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
+ ife->outfill = 0;
+ else
+ ife->outfill = (unsigned int) ifr.ifr_data;
+#endif
+#ifdef SIOCGKEEPALIVE
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
+ ife->keepalive = 0;
+ else
+ ife->keepalive = (unsigned int) ifr.ifr_data;
+#endif
+ }
+#endif
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
+ memset(&ife->map, 0, sizeof(struct ifmap));
+ else
+ memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
+ memset(&ife->map, 0, sizeof(struct ifmap));
+ else
+ ife->map = ifr.ifr_map;
+
+#ifdef HAVE_TXQUEUELEN
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
+ ife->tx_queue_len = -1; /* unknown value */
+ else
+ ife->tx_queue_len = ifr.ifr_qlen;
+#else
+ ife->tx_queue_len = -1; /* unknown value */
+#endif
+
+#if HAVE_AFINET
+ /* IPv4 address? */
+ fd = get_socket_for_af(AF_INET);
+ if (fd >= 0) {
+ strcpy(ifr.ifr_name, ifname);
+ ifr.ifr_addr.sa_family = AF_INET;
+ if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
+ ife->has_ip = 1;
+ ife->addr = ifr.ifr_addr;
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
+ memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
+ else
+ ife->dstaddr = ifr.ifr_dstaddr;
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
+ memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
+ else
+ ife->broadaddr = ifr.ifr_broadaddr;
+
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
+ memset(&ife->netmask, 0, sizeof(struct sockaddr));
+ else
+ ife->netmask = ifr.ifr_netmask;
+ } else
+ memset(&ife->addr, 0, sizeof(struct sockaddr));
+ }
+#endif
+
+#if HAVE_AFATALK
+ /* DDP address maybe ? */
+ fd = get_socket_for_af(AF_APPLETALK);
+ if (fd >= 0) {
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
+ ife->ddpaddr = ifr.ifr_addr;
+ ife->has_ddp = 1;
+ }
+ }
+#endif
+
+#if HAVE_AFIPX
+ /* Look for IPX addresses with all framing types */
+ fd = get_socket_for_af(AF_IPX);
+ if (fd >= 0) {
+ strcpy(ifr.ifr_name, ifname);
+ if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
+ ife->has_ipx_bb = 1;
+ ife->ipxaddr_bb = ifr.ifr_addr;
+ }
+ strcpy(ifr.ifr_name, ifname);
+ if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
+ ife->has_ipx_sn = 1;
+ ife->ipxaddr_sn = ifr.ifr_addr;
+ }
+ strcpy(ifr.ifr_name, ifname);
+ if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
+ ife->has_ipx_e3 = 1;
+ ife->ipxaddr_e3 = ifr.ifr_addr;
+ }
+ strcpy(ifr.ifr_name, ifname);
+ if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
+ ife->has_ipx_e2 = 1;
+ ife->ipxaddr_e2 = ifr.ifr_addr;
+ }
+ }
+#endif
+
+#if HAVE_AFECONET
+ /* Econet address maybe? */
+ fd = get_socket_for_af(AF_ECONET);
+ if (fd >= 0) {
+ strcpy(ifr.ifr_name, ifname);
+ if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
+ ife->ecaddr = ifr.ifr_addr;
+ ife->has_econet = 1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+static int do_if_fetch(struct interface *ife)
+{
+ if (if_fetch(ife) < 0) {
+ char *errmsg;
+
+ if (errno == ENODEV) {
+ /* Give better error message for this case. */
+ errmsg = _("Device not found");
+ } else {
+ errmsg = strerror(errno);
+ }
+ bb_error_msg(_("%s: error fetching interface information: %s\n"),
+ ife->name, errmsg);
+ return -1;
+ }
+ return 0;
+}
+
+/* This structure defines hardware protocols and their handlers. */
+struct hwtype {
+ const char *name;
+ const char *title;
+ int type;
+ int alen;
+ char *(*print) (unsigned char *);
+ int (*input) (char *, struct sockaddr *);
+ int (*activate) (int fd);
+ int suppress_null_addr;
+};
+
+static struct hwtype unspec_hwtype = {
+ "unspec", "UNSPEC", -1, 0,
+ UNSPEC_print, NULL, NULL
+};
+
+static struct hwtype loop_hwtype = {
+ "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
+ NULL, NULL, NULL
+};
+
+#if HAVE_HWETHER
+#include <net/if_arp.h>
+
+#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+
+/* Display an Ethernet address in readable format. */
+static char *pr_ether(unsigned char *ptr)
+{
+ static char buff[64];
+
+ snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
+ (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
+ (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
+ );
+ return (buff);
+}
+
+#ifdef KEEP_UNUSED
+/* Input an Ethernet address and convert to binary. */
+static int in_ether(char *bufp, struct sockaddr *sap)
+{
+ unsigned char *ptr;
+ char c, *orig;
+ int i;
+ unsigned val;
+
+ sap->sa_family = ether_hwtype.type;
+ ptr = sap->sa_data;
+
+ i = 0;
+ orig = bufp;
+ while ((*bufp != '\0') && (i < ETH_ALEN)) {
+ val = 0;
+ c = *bufp++;
+ if (isdigit(c))
+ val = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ val = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ val = c - 'A' + 10;
+ else {
+#ifdef DEBUG
+ bb_error_msg(_("in_ether(%s): invalid ether address!\n"), orig);
+#endif
+ errno = EINVAL;
+ return (-1);
+ }
+ val <<= 4;
+ c = *bufp;
+ if (isdigit(c))
+ val |= c - '0';
+ else if (c >= 'a' && c <= 'f')
+ val |= c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ val |= c - 'A' + 10;
+ else if (c == ':' || c == 0)
+ val >>= 4;
+ else {
+#ifdef DEBUG
+ bb_error_msg(_("in_ether(%s): invalid ether address!"), orig);
+#endif
+ errno = EINVAL;
+ return (-1);
+ }
+ if (c != 0)
+ bufp++;
+ *ptr++ = (unsigned char) (val & 0377);
+ i++;
+
+ /* We might get a semicolon here - not required. */
+ if (*bufp == ':') {
+#ifdef DEBUG
+ if (i == ETH_ALEN) {
+ bb_error_msg(_("in_ether(%s): trailing : ignored!"), orig);
+ }
+#endif
+ bufp++;
+ }
+ }
+
+#ifdef DEBUG
+ /* That's it. Any trailing junk? */
+ if ((i == ETH_ALEN) && (*bufp != '\0')) {
+ bb_error_msg(_("in_ether(%s): trailing junk!"), orig);
+ errno = EINVAL;
+ return (-1);
+ }
+ bb_error_msg("in_ether(%s): %s", orig, pr_ether(sap->sa_data));
+#endif
+
+ return (0);
+}
+#endif /* KEEP_UNUSED */
+
+
+static struct hwtype ether_hwtype = {
+ "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
+ pr_ether, NULL /* UNUSED in_ether */ , NULL
+};
+
+
+#endif /* HAVE_HWETHER */
+
+
+#if HAVE_HWPPP
+
+#include <net/if_arp.h>
+
+#ifdef KEEP_UNUSED
+/* Start the PPP encapsulation on the file descriptor. */
+static int do_ppp(int fd)
+{
+ bb_error_msg(_("You cannot start PPP with this program."));
+ return -1;
+}
+#endif /* KEEP_UNUSED */
+
+static struct hwtype ppp_hwtype = {
+ "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
+ NULL, NULL, NULL /* UNUSED do_ppp */ , 0
+};
+
+
+#endif /* HAVE_PPP */
+
+static struct hwtype *hwtypes[] = {
+
+ &loop_hwtype,
+
+#if HAVE_HWSLIP
+ &slip_hwtype,
+ &cslip_hwtype,
+ &slip6_hwtype,
+ &cslip6_hwtype,
+ &adaptive_hwtype,
+#endif
+#if HAVE_HWSTRIP
+ &strip_hwtype,
+#endif
+#if HAVE_HWASH
+ &ash_hwtype,
+#endif
+#if HAVE_HWETHER
+ &ether_hwtype,
+#endif
+#if HAVE_HWTR
+ &tr_hwtype,
+#ifdef ARPHRD_IEEE802_TR
+ &tr_hwtype1,
+#endif
+#endif
+#if HAVE_HWAX25
+ &ax25_hwtype,
+#endif
+#if HAVE_HWNETROM
+ &netrom_hwtype,
+#endif
+#if HAVE_HWROSE
+ &rose_hwtype,
+#endif
+#if HAVE_HWTUNNEL
+ &tunnel_hwtype,
+#endif
+#if HAVE_HWPPP
+ &ppp_hwtype,
+#endif
+#if HAVE_HWHDLCLAPB
+ &hdlc_hwtype,
+ &lapb_hwtype,
+#endif
+#if HAVE_HWARC
+ &arcnet_hwtype,
+#endif
+#if HAVE_HWFR
+ &dlci_hwtype,
+ &frad_hwtype,
+#endif
+#if HAVE_HWSIT
+ &sit_hwtype,
+#endif
+#if HAVE_HWFDDI
+ &fddi_hwtype,
+#endif
+#if HAVE_HWHIPPI
+ &hippi_hwtype,
+#endif
+#if HAVE_HWIRDA
+ &irda_hwtype,
+#endif
+#if HAVE_HWEC
+ &ec_hwtype,
+#endif
+#if HAVE_HWX25
+ &x25_hwtype,
+#endif
+ &unspec_hwtype,
+ NULL
+};
+
+#ifdef KEEP_UNUSED
+static short sVhwinit = 0;
+
+static void hwinit()
+{
+ loop_hwtype.title = _("Local Loopback");
+ unspec_hwtype.title = _("UNSPEC");
+#if HAVE_HWSLIP
+ slip_hwtype.title = _("Serial Line IP");
+ cslip_hwtype.title = _("VJ Serial Line IP");
+ slip6_hwtype.title = _("6-bit Serial Line IP");
+ cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
+ adaptive_hwtype.title = _("Adaptive Serial Line IP");
+#endif
+#if HAVE_HWETHER
+ ether_hwtype.title = _("Ethernet");
+#endif
+#if HAVE_HWASH
+ ash_hwtype.title = _("Ash");
+#endif
+#if HAVE_HWFDDI
+ fddi_hwtype.title = _("Fiber Distributed Data Interface");
+#endif
+#if HAVE_HWHIPPI
+ hippi_hwtype.title = _("HIPPI");
+#endif
+#if HAVE_HWAX25
+ ax25_hwtype.title = _("AMPR AX.25");
+#endif
+#if HAVE_HWROSE
+ rose_hwtype.title = _("AMPR ROSE");
+#endif
+#if HAVE_HWNETROM
+ netrom_hwtype.title = _("AMPR NET/ROM");
+#endif
+#if HAVE_HWX25
+ x25_hwtype.title = _("generic X.25");
+#endif
+#if HAVE_HWTUNNEL
+ tunnel_hwtype.title = _("IPIP Tunnel");
+#endif
+#if HAVE_HWPPP
+ ppp_hwtype.title = _("Point-to-Point Protocol");
+#endif
+#if HAVE_HWHDLCLAPB
+ hdlc_hwtype.title = _("(Cisco)-HDLC");
+ lapb_hwtype.title = _("LAPB");
+#endif
+#if HAVE_HWARC
+ arcnet_hwtype.title = _("ARCnet");
+#endif
+#if HAVE_HWFR
+ dlci_hwtype.title = _("Frame Relay DLCI");
+ frad_hwtype.title = _("Frame Relay Access Device");
+#endif
+#if HAVE_HWSIT
+ sit_hwtype.title = _("IPv6-in-IPv4");
+#endif
+#if HAVE_HWIRDA
+ irda_hwtype.title = _("IrLAP");
+#endif
+#if HAVE_HWTR
+ tr_hwtype.title = _("16/4 Mbps Token Ring");
+#ifdef ARPHRD_IEEE802_TR
+ tr_hwtype1.title = _("16/4 Mbps Token Ring (New)");
+#endif
+#endif
+#if HAVE_HWEC
+ ec_hwtype.title = _("Econet");
+#endif
+ sVhwinit = 1;
+}
+#endif /* KEEP_UNUSED */
+
+#ifdef IFF_PORTSEL
+#if 0
+static const char * const if_port_text[][4] = {
+ /* Keep in step with <linux/netdevice.h> */
+ {"unknown", NULL, NULL, NULL},
+ {"10base2", "bnc", "coax", NULL},
+ {"10baseT", "utp", "tpe", NULL},
+ {"AUI", "thick", "db15", NULL},
+ {"100baseT", NULL, NULL, NULL},
+ {"100baseTX", NULL, NULL, NULL},
+ {"100baseFX", NULL, NULL, NULL},
+ {NULL, NULL, NULL, NULL},
+};
+#else
+static const char * const if_port_text[] = {
+ /* Keep in step with <linux/netdevice.h> */
+ "unknown",
+ "10base2",
+ "10baseT",
+ "AUI",
+ "100baseT",
+ "100baseTX",
+ "100baseFX",
+ NULL
+};
+#endif
+#endif
+
+/* Check our hardware type table for this type. */
+static struct hwtype *get_hwntype(int type)
+{
+ struct hwtype **hwp;
+
+#ifdef KEEP_UNUSED
+ if (!sVhwinit)
+ hwinit();
+#endif /* KEEP_UNUSED */
+
+ hwp = hwtypes;
+ while (*hwp != NULL) {
+ if ((*hwp)->type == type)
+ return (*hwp);
+ hwp++;
+ }
+ return (NULL);
+}
+
+/* return 1 if address is all zeros */
+static int hw_null_address(struct hwtype *hw, void *ap)
+{
+ unsigned int i;
+ unsigned char *address = (unsigned char *) ap;
+
+ for (i = 0; i < hw->alen; i++)
+ if (address[i])
+ return 0;
+ return 1;
+}
+
+static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
+
+static void print_bytes_scaled(unsigned long long ull, const char *end)
+{
+ unsigned long long int_part;
+ const char *ext;
+ unsigned int frac_part;
+ int i;
+
+ frac_part = 0;
+ ext = TRext;
+ int_part = ull;
+ i = 4;
+ do {
+#if 0
+ /* This does correct rounding and is a little larger. But it
+ * uses KiB as the smallest displayed unit. */
+ if ((int_part < (1024*1024 - 51)) || !--i) {
+ i = 0;
+ int_part += 51; /* 1024*.05 = 51.2 */
+ frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
+ }
+ int_part /= 1024;
+ ext += 3; /* KiB, MiB, GiB, TiB */
+#else
+ if (int_part >= 1024) {
+ frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
+ int_part /= 1024;
+ ext += 3; /* KiB, MiB, GiB, TiB */
+ }
+ --i;
+#endif
+ } while (i);
+
+ printf("X bytes:%Lu (%Lu.%u %sB)%s", ull, int_part, frac_part, ext, end);
+}
+
+static const char * const ife_print_flags_strs[] = {
+ "UP ",
+ "BROADCAST ",
+ "DEBUG ",
+ "LOOPBACK ",
+ "POINTOPOINT ",
+ "NOTRAILERS ",
+ "RUNNING ",
+ "NOARP ",
+ "PROMISC ",
+ "ALLMULTI ",
+ "SLAVE ",
+ "MASTER ",
+ "MULTICAST ",
+#ifdef HAVE_DYNAMIC
+ "DYNAMIC "
+#endif
+};
+
+static const unsigned short ife_print_flags_mask[] = {
+ IFF_UP,
+ IFF_BROADCAST,
+ IFF_DEBUG,
+ IFF_LOOPBACK,
+ IFF_POINTOPOINT,
+ IFF_NOTRAILERS,
+ IFF_RUNNING,
+ IFF_NOARP,
+ IFF_PROMISC,
+ IFF_ALLMULTI,
+ IFF_SLAVE,
+ IFF_MASTER,
+ IFF_MULTICAST,
+#ifdef HAVE_DYNAMIC
+ IFF_DYNAMIC
+#endif
+ 0
+};
+
+static void ife_print(struct interface *ptr)
+{
+ struct aftype *ap;
+ struct hwtype *hw;
+ int hf;
+ int can_compress = 0;
+
+#if HAVE_AFIPX
+ static struct aftype *ipxtype = NULL;
+#endif
+#if HAVE_AFECONET
+ static struct aftype *ectype = NULL;
+#endif
+#if HAVE_AFATALK
+ static struct aftype *ddptype = NULL;
+#endif
+#if HAVE_AFINET6
+ FILE *f;
+ char addr6[40], devname[20];
+ struct sockaddr_in6 sap;
+ int plen, scope, dad_status, if_idx;
+ char addr6p[8][5];
+#endif
+
+ ap = get_afntype(ptr->addr.sa_family);
+ if (ap == NULL)
+ ap = get_afntype(0);
+
+ hf = ptr->type;
+
+ if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
+ can_compress = 1;
+
+ hw = get_hwntype(hf);
+ if (hw == NULL)
+ hw = get_hwntype(-1);
+
+ printf(_("%-9.9s Link encap:%s "), ptr->name, _(hw->title));
+ /* For some hardware types (eg Ash, ATM) we don't print the
+ hardware address if it's null. */
+ if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
+ hw->suppress_null_addr)))
+ printf(_("HWaddr %s "), hw->print(ptr->hwaddr));
+#ifdef IFF_PORTSEL
+ if (ptr->flags & IFF_PORTSEL) {
+ printf(_("Media:%s"), if_port_text[ptr->map.port] /* [0] */);
+ if (ptr->flags & IFF_AUTOMEDIA)
+ printf(_("(auto)"));
+ }
+#endif
+ printf("\n");
+
+#if HAVE_AFINET
+ if (ptr->has_ip) {
+ printf(_(" %s addr:%s "), ap->name,
+ ap->sprint(&ptr->addr, 1));
+ if (ptr->flags & IFF_POINTOPOINT) {
+ printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
+ }
+ if (ptr->flags & IFF_BROADCAST) {
+ printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
+ }
+ printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
+ }
+#endif
+
+#if HAVE_AFINET6
+
+#define IPV6_ADDR_ANY 0x0000U
+
+#define IPV6_ADDR_UNICAST 0x0001U
+#define IPV6_ADDR_MULTICAST 0x0002U
+#define IPV6_ADDR_ANYCAST 0x0004U
+
+#define IPV6_ADDR_LOOPBACK 0x0010U
+#define IPV6_ADDR_LINKLOCAL 0x0020U
+#define IPV6_ADDR_SITELOCAL 0x0040U
+
+#define IPV6_ADDR_COMPATv4 0x0080U
+
+#define IPV6_ADDR_SCOPE_MASK 0x00f0U
+
+#define IPV6_ADDR_MAPPED 0x1000U
+#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
+
+ if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
+ while (fscanf
+ (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
+ addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
+ addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
+ &dad_status, devname) != EOF) {
+ if (!strcmp(devname, ptr->name)) {
+ sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
+ addr6p[0], addr6p[1], addr6p[2], addr6p[3],
+ addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
+ inet_pton(AF_INET6, addr6,
+ (struct sockaddr *) &sap.sin6_addr);
+ sap.sin6_family = AF_INET6;
+ printf(_(" inet6 addr: %s/%d"),
+ inet6_aftype.sprint((struct sockaddr *) &sap, 1),
+ plen);
+ printf(_(" Scope:"));
+ switch (scope & IPV6_ADDR_SCOPE_MASK) {
+ case 0:
+ printf(_("Global"));
+ break;
+ case IPV6_ADDR_LINKLOCAL:
+ printf(_("Link"));
+ break;
+ case IPV6_ADDR_SITELOCAL:
+ printf(_("Site"));
+ break;
+ case IPV6_ADDR_COMPATv4:
+ printf(_("Compat"));
+ break;
+ case IPV6_ADDR_LOOPBACK:
+ printf(_("Host"));
+ break;
+ default:
+ printf(_("Unknown"));
+ }
+ printf("\n");
+ }
+ }
+ fclose(f);
+ }
+#endif
+
+#if HAVE_AFIPX
+ if (ipxtype == NULL)
+ ipxtype = get_afntype(AF_IPX);
+
+ if (ipxtype != NULL) {
+ if (ptr->has_ipx_bb)
+ printf(_(" IPX/Ethernet II addr:%s\n"),
+ ipxtype->sprint(&ptr->ipxaddr_bb, 1));
+ if (ptr->has_ipx_sn)
+ printf(_(" IPX/Ethernet SNAP addr:%s\n"),
+ ipxtype->sprint(&ptr->ipxaddr_sn, 1));
+ if (ptr->has_ipx_e2)
+ printf(_(" IPX/Ethernet 802.2 addr:%s\n"),
+ ipxtype->sprint(&ptr->ipxaddr_e2, 1));
+ if (ptr->has_ipx_e3)
+ printf(_(" IPX/Ethernet 802.3 addr:%s\n"),
+ ipxtype->sprint(&ptr->ipxaddr_e3, 1));
+ }
+#endif
+
+#if HAVE_AFATALK
+ if (ddptype == NULL)
+ ddptype = get_afntype(AF_APPLETALK);
+ if (ddptype != NULL) {
+ if (ptr->has_ddp)
+ printf(_(" EtherTalk Phase 2 addr:%s\n"),
+ ddptype->sprint(&ptr->ddpaddr, 1));
+ }
+#endif
+
+#if HAVE_AFECONET
+ if (ectype == NULL)
+ ectype = get_afntype(AF_ECONET);
+ if (ectype != NULL) {
+ if (ptr->has_econet)
+ printf(_(" econet addr:%s\n"),
+ ectype->sprint(&ptr->ecaddr, 1));
+ }
+#endif
+
+ printf(" ");
+ /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
+
+ if (ptr->flags == 0) {
+ printf(_("[NO FLAGS] "));
+ } else {
+ int i = 0;
+ do {
+ if (ptr->flags & ife_print_flags_mask[i]) {
+ printf(_(ife_print_flags_strs[i]));
+ }
+ } while (ife_print_flags_mask[++i]);
+ }
+
+ /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
+ printf(_(" MTU:%d Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
+#ifdef SIOCSKEEPALIVE
+ if (ptr->outfill || ptr->keepalive)
+ printf(_(" Outfill:%d Keepalive:%d"), ptr->outfill, ptr->keepalive);
+#endif
+ printf("\n");
+
+ /* If needed, display the interface statistics. */
+
+ if (ptr->statistics_valid) {
+ /* XXX: statistics are currently only printed for the primary address,
+ * not for the aliases, although strictly speaking they're shared
+ * by all addresses.
+ */
+ printf(" ");
+
+ printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
+ ptr->stats.rx_packets, ptr->stats.rx_errors,
+ ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
+ ptr->stats.rx_frame_errors);
+ if (can_compress)
+ printf(_(" compressed:%lu\n"),
+ ptr->stats.rx_compressed);
+ printf(" ");
+ printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
+ ptr->stats.tx_packets, ptr->stats.tx_errors,
+ ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
+ ptr->stats.tx_carrier_errors);
+ printf(_(" collisions:%lu "), ptr->stats.collisions);
+ if (can_compress)
+ printf(_("compressed:%lu "), ptr->stats.tx_compressed);
+ if (ptr->tx_queue_len != -1)
+ printf(_("txqueuelen:%d "), ptr->tx_queue_len);
+ printf("\n R");
+ print_bytes_scaled(ptr->stats.rx_bytes, " T");
+ print_bytes_scaled(ptr->stats.tx_bytes, "\n");
+
+ }
+
+ if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
+ ptr->map.base_addr)) {
+ printf(" ");
+ if (ptr->map.irq)
+ printf(_("Interrupt:%d "), ptr->map.irq);
+ if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
+ I/O maps */
+ printf(_("Base address:0x%lx "),
+ (unsigned long) ptr->map.base_addr);
+ if (ptr->map.mem_start) {
+ printf(_("Memory:%lx-%lx "), ptr->map.mem_start,
+ ptr->map.mem_end);
+ }
+ if (ptr->map.dma)
+ printf(_("DMA chan:%x "), ptr->map.dma);
+ printf("\n");
+ }
+ printf("\n");
+}
+
+
+static int do_if_print(struct interface *ife, void *cookie)
+{
+ int *opt_a = (int *) cookie;
+ int res;
+
+ res = do_if_fetch(ife);
+ if (res >= 0) {
+ if ((ife->flags & IFF_UP) || *opt_a)
+ ife_print(ife);
+ }
+ return res;
+}
+
+static struct interface *lookup_interface(char *name)
+{
+ struct interface *ife = NULL;
+
+ if (if_readlist_proc(name) < 0)
+ return NULL;
+ ife = add_interface(name);
+ return ife;
+}
+
+/* for ipv4 add/del modes */
+static int if_print(char *ifname)
+{
+ int res;
+
+ if (!ifname) {
+ res = for_all_interfaces(do_if_print, &interface_opt_a);
+ } else {
+ struct interface *ife;
+
+ ife = lookup_interface(ifname);
+ res = do_if_fetch(ife);
+ if (res >= 0)
+ ife_print(ife);
+ }
+ return res;
+}
+
+int display_interfaces(char *ifname)
+{
+ int status;
+
+ /* Create a channel to the NET kernel. */
+ if ((skfd = sockets_open(0)) < 0) {
+ bb_perror_msg_and_die("socket");
+ }
+
+ /* Do we have to show the current setup? */
+ status = if_print(ifname);
+ close(skfd);
+ exit(status < 0);
+}
diff --git a/busybox/libbb/isdirectory.c b/busybox/libbb/isdirectory.c
new file mode 100644
index 0000000..7f8f7e4
--- /dev/null
+++ b/busybox/libbb/isdirectory.c
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <sys/stat.h>
+#include "libbb.h"
+
+/*
+ * Return TRUE if a fileName is a directory.
+ * Nonexistent files return FALSE.
+ */
+int is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
+{
+ int status;
+ struct stat astatBuf;
+
+ if (statBuf == NULL) {
+ /* set from auto stack buffer */
+ statBuf = &astatBuf;
+ }
+
+ if (followLinks)
+ status = stat(fileName, statBuf);
+ else
+ status = lstat(fileName, statBuf);
+
+ if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
+ status = FALSE;
+ }
+ else status = TRUE;
+
+ return status;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/kernel_version.c b/busybox/libbb/kernel_version.c
new file mode 100644
index 0000000..e01aafa
--- /dev/null
+++ b/busybox/libbb/kernel_version.c
@@ -0,0 +1,60 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/utsname.h> /* for uname(2) */
+
+#include "libbb.h"
+
+/* Returns kernel version encoded as major*65536 + minor*256 + patch,
+ * so, for example, to check if the kernel is greater than 2.2.11:
+ * if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
+ */
+extern int get_kernel_revision(void)
+{
+ struct utsname name;
+ char *s;
+ int i, r;
+
+ if (uname(&name) == -1) {
+ bb_perror_msg("cannot get system information");
+ return (0);
+ }
+
+ s = name.release;
+ r = 0;
+ for (i=0 ; i<3 ; i++) {
+ r = r * 256 + atoi(strtok(s, "."));
+ s = NULL;
+ }
+ return r;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/last_char_is.c b/busybox/libbb/last_char_is.c
new file mode 100644
index 0000000..9bd7099
--- /dev/null
+++ b/busybox/libbb/last_char_is.c
@@ -0,0 +1,38 @@
+/*
+ * busybox library eXtended function
+ *
+ * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+/* Find out if the last character of a string matches the one given Don't
+ * underrun the buffer if the string length is 0. Also avoids a possible
+ * space-hogging inline of strlen() per usage.
+ */
+char * last_char_is(const char *s, int c)
+{
+ char *sret = (char *)s;
+ if (sret) {
+ sret = strrchr(sret, c);
+ if(sret != NULL && *(sret+1) != 0)
+ sret = NULL;
+ }
+ return sret;
+}
diff --git a/busybox/libbb/llist_add_to.c b/busybox/libbb/llist_add_to.c
new file mode 100644
index 0000000..61e53f0
--- /dev/null
+++ b/busybox/libbb/llist_add_to.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <string.h>
+#include "unarchive.h"
+#include "libbb.h"
+
+extern llist_t *llist_add_to(llist_t *old_head, char *new_item)
+{
+ llist_t *new_head;
+
+ new_head = xmalloc(sizeof(llist_t));
+ new_head->data = new_item;
+ new_head->link = old_head;
+
+ return(new_head);
+}
diff --git a/busybox/libbb/login.c b/busybox/libbb/login.c
new file mode 100644
index 0000000..3f67a81
--- /dev/null
+++ b/busybox/libbb/login.c
@@ -0,0 +1,128 @@
+/*
+ * issue.c: issue printing code
+ *
+ * Copyright (C) 2003 Bastian Blank <waldi@tuxbox.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Optimize and correcting OCRNL by Vladimir Oleynik <dzo@simtreas.ru>
+ */
+
+#include <sys/param.h> /* MAXHOSTNAMELEN */
+#include <stdio.h>
+#include <unistd.h>
+#include "libbb.h"
+
+#include <sys/utsname.h>
+#include <time.h>
+
+#define LOGIN " login: "
+
+static const char fmtstr_d[] = "%A, %d %B %Y";
+static const char fmtstr_t[] = "%H:%M:%S";
+
+void print_login_issue(const char *issue_file, const char *tty)
+{
+ FILE *fd;
+ int c;
+ char buf[256];
+ const char *outbuf;
+ time_t t;
+ struct utsname uts;
+
+ time(&t);
+ uname(&uts);
+
+ puts("\r"); /* start a new line */
+
+ if ((fd = fopen(issue_file, "r"))) {
+ while ((c = fgetc(fd)) != EOF) {
+ outbuf = buf;
+ buf[0] = c;
+ if(c == '\n') {
+ buf[1] = '\r';
+ buf[2] = 0;
+ } else {
+ buf[1] = 0;
+ }
+ if (c == '\\' || c == '%') {
+ c = fgetc(fd);
+ switch (c) {
+ case 's':
+ outbuf = uts.sysname;
+ break;
+
+ case 'n':
+ outbuf = uts.nodename;
+ break;
+
+ case 'r':
+ outbuf = uts.release;
+ break;
+
+ case 'v':
+ outbuf = uts.version;
+ break;
+
+ case 'm':
+ outbuf = uts.machine;
+ break;
+
+ case 'D':
+ case 'o':
+ getdomainname(buf, sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ break;
+
+ case 'd':
+ strftime(buf, sizeof(buf), fmtstr_d, localtime(&t));
+ break;
+
+ case 't':
+ strftime(buf, sizeof(buf), fmtstr_t, localtime(&t));
+ break;
+
+ case 'h':
+ gethostname(buf, sizeof(buf) - 1);
+ break;
+
+ case 'l':
+ outbuf = tty;
+ break;
+
+ default:
+ buf[0] = c;
+ }
+ }
+ fputs(outbuf, stdout);
+ }
+
+ fclose(fd);
+
+ fflush(stdout);
+ }
+}
+
+void print_login_prompt(void)
+{
+ char buf[MAXHOSTNAMELEN+1];
+
+ gethostname(buf, MAXHOSTNAMELEN);
+ fputs(buf, stdout);
+
+ fputs(LOGIN, stdout);
+ fflush(stdout);
+}
+
diff --git a/busybox/libbb/loop.c b/busybox/libbb/loop.c
new file mode 100644
index 0000000..e2287b5
--- /dev/null
+++ b/busybox/libbb/loop.c
@@ -0,0 +1,157 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "libbb.h"
+
+/* Grumble... The 2.6.x kernel breaks asm/posix_types.h
+ * so we get to try and cope as best we can... */
+#include <linux/version.h>
+#include <asm/posix_types.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define __bb_kernel_dev_t __kernel_old_dev_t
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define __bb_kernel_dev_t __kernel_dev_t
+#else
+#define __bb_kernel_dev_t unsigned short
+#endif
+
+/* Stuff stolen from linux/loop.h */
+#define LO_NAME_SIZE 64
+#define LO_KEY_SIZE 32
+#define LOOP_SET_FD 0x4C00
+#define LOOP_CLR_FD 0x4C01
+#define LOOP_SET_STATUS 0x4C02
+#define LOOP_GET_STATUS 0x4C03
+struct loop_info {
+ int lo_number;
+ __bb_kernel_dev_t lo_device;
+ unsigned long lo_inode;
+ __bb_kernel_dev_t lo_rdevice;
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size;
+ int lo_flags;
+ char lo_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE];
+ unsigned long lo_init[2];
+ char reserved[4];
+};
+
+extern int del_loop(const char *device)
+{
+ int fd;
+
+ if ((fd = open(device, O_RDONLY)) < 0) {
+ bb_perror_msg("%s", device);
+ return (FALSE);
+ }
+ if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
+ close(fd);
+ bb_perror_msg("ioctl: LOOP_CLR_FD");
+ return (FALSE);
+ }
+ close(fd);
+ return (TRUE);
+}
+
+extern int set_loop(const char *device, const char *file, int offset,
+ int *loopro)
+{
+ struct loop_info loopinfo;
+ int fd, ffd, mode;
+
+ mode = *loopro ? O_RDONLY : O_RDWR;
+ if ((ffd = open(file, mode)) < 0 && !*loopro
+ && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) {
+ bb_perror_msg("%s", file);
+ return 1;
+ }
+ if ((fd = open(device, mode)) < 0) {
+ close(ffd);
+ bb_perror_msg("%s", device);
+ return 1;
+ }
+ *loopro = (mode == O_RDONLY);
+
+ memset(&loopinfo, 0, sizeof(loopinfo));
+ safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
+
+ loopinfo.lo_offset = offset;
+
+ loopinfo.lo_encrypt_key_size = 0;
+ if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
+ bb_perror_msg("ioctl: LOOP_SET_FD");
+ close(fd);
+ close(ffd);
+ return 1;
+ }
+ if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
+ (void) ioctl(fd, LOOP_CLR_FD, 0);
+ bb_perror_msg("ioctl: LOOP_SET_STATUS");
+ close(fd);
+ close(ffd);
+ return 1;
+ }
+ close(fd);
+ close(ffd);
+ return 0;
+}
+
+extern char *find_unused_loop_device(void)
+{
+ char dev[20];
+ int i, fd;
+ struct stat statbuf;
+ struct loop_info loopinfo;
+
+ for (i = 0; i <= 7; i++) {
+ sprintf(dev, LOOP_FORMAT, i);
+ if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
+ if ((fd = open(dev, O_RDONLY)) >= 0) {
+ if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) != 0) {
+ if (errno == ENXIO) { /* probably free */
+ close(fd);
+ return strdup(dev);
+ }
+ }
+ close(fd);
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/make_directory.c b/busybox/libbb/make_directory.c
new file mode 100644
index 0000000..d96acf0
--- /dev/null
+++ b/busybox/libbb/make_directory.c
@@ -0,0 +1,117 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * parse_mode implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Mar 5, 2003 Manuel Novoa III
+ *
+ * This is the main work function for the 'mkdir' applet. As such, it
+ * strives to be SUSv3 compliant in it's behaviour when recursively
+ * making missing parent dirs, and in it's mode setting of the final
+ * directory 'path'.
+ *
+ * To recursively build all missing intermediate directories, make
+ * sure that (flags & FILEUTILS_RECUR) is non-zero. Newly created
+ * intermediate directories will have at least u+wx perms.
+ *
+ * To set specific permissions on 'path', pass the appropriate 'mode'
+ * val. Otherwise, pass -1 to get default permissions.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "libbb.h"
+
+int bb_make_directory (char *path, long mode, int flags)
+{
+ mode_t mask;
+ const char *fail_msg;
+ char *s = path;
+ char c;
+ struct stat st;
+
+ mask = umask(0);
+ if (mode == -1) {
+ umask(mask);
+ mode = (S_IXUSR | S_IXGRP | S_IXOTH |
+ S_IWUSR | S_IWGRP | S_IWOTH |
+ S_IRUSR | S_IRGRP | S_IROTH) & ~mask;
+ } else {
+ umask(mask & ~0300);
+ }
+
+ do {
+ c = 0;
+
+ if (flags & FILEUTILS_RECUR) { /* Get the parent. */
+ /* Bypass leading non-'/'s and then subsequent '/'s. */
+ while (*s) {
+ if (*s == '/') {
+ do {
+ ++s;
+ } while (*s == '/');
+ c = *s; /* Save the current char */
+ *s = 0; /* and replace it with nul. */
+ break;
+ }
+ ++s;
+ }
+ }
+
+ if (mkdir(path, 0777) < 0) {
+ /* If we failed for any other reason than the directory
+ * already exists, output a diagnostic and return -1.*/
+ if (errno != EEXIST
+ || !(flags & FILEUTILS_RECUR)
+ || (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))) {
+ fail_msg = "create";
+ umask(mask);
+ break;
+ }
+ /* Since the directory exists, don't attempt to change
+ * permissions if it was the full target. Note that
+ * this is not an error conditon. */
+ if (!c) {
+ umask(mask);
+ return 0;
+ }
+ }
+
+ if (!c) {
+ /* Done. If necessary, updated perms on the newly
+ * created directory. Failure to update here _is_
+ * an error.*/
+ umask(mask);
+ if ((mode != -1) && (chmod(path, mode) < 0)){
+ fail_msg = "set permissions of";
+ break;
+ }
+ return 0;
+ }
+
+ /* Remove any inserted nul from the path (recursive mode). */
+ *s = c;
+
+ } while (1);
+
+ bb_perror_msg ("Cannot %s directory `%s'", fail_msg, path);
+ return -1;
+}
diff --git a/busybox/libbb/messages.c b/busybox/libbb/messages.c
new file mode 100644
index 0000000..671c452
--- /dev/null
+++ b/busybox/libbb/messages.c
@@ -0,0 +1,96 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "busybox.h"
+#include "libbb.h"
+
+#ifdef L_full_version
+ const char * const bb_msg_full_version = BB_BANNER " multi-call binary";
+#endif
+#ifdef L_memory_exhausted
+ const char * const bb_msg_memory_exhausted = "memory exhausted";
+#endif
+#ifdef L_invalid_date
+ const char * const bb_msg_invalid_date = "invalid date `%s'";
+#endif
+#ifdef L_io_error
+ const char * const bb_msg_io_error = "%s: input/output error -- %m";
+#endif
+#ifdef L_write_error
+ const char * const bb_msg_write_error = "Write Error";
+#endif
+#ifdef L_name_longer_than_foo
+ const char * const bb_msg_name_longer_than_foo = "Names longer than %d chars not supported.";
+#endif
+#ifdef L_unknown
+ const char * const bb_msg_unknown = "(unknown)";
+#endif
+#ifdef L_can_not_create_raw_socket
+ const char * const bb_msg_can_not_create_raw_socket = "can`t create raw socket";
+#endif
+#ifdef L_perm_denied_are_you_root
+ const char * const bb_msg_perm_denied_are_you_root = "permission denied. (are you root?)";
+#endif
+#ifdef L_msg_standard_input
+ const char * const bb_msg_standard_input = "standard input";
+#endif
+#ifdef L_msg_standard_output
+ const char * const bb_msg_standard_output = "standard output";
+#endif
+
+#ifdef L_passwd_file
+#define PASSWD_FILE "/etc/passwd"
+const char * const bb_path_passwd_file = PASSWD_FILE;
+#endif
+
+#ifdef L_shadow_file
+#define SHADOW_FILE "/etc/shadow"
+const char * const bb_path_shadow_file = SHADOW_FILE;
+#endif
+
+#ifdef L_group_file
+#define GROUP_FILE "/etc/group"
+const char * const bb_path_group_file = GROUP_FILE;
+#endif
+
+#ifdef L_gshadow_file
+#define GSHADOW_FILE "/etc/gshadow"
+const char * const bb_path_gshadow_file = GSHADOW_FILE;
+#endif
+
+#ifdef L_nologin_file
+#define NOLOGIN_FILE "/etc/nologin"
+const char * const bb_path_nologin_file = NOLOGIN_FILE;
+#endif
+
+#ifdef L_securetty_file
+#define SECURETTY_FILE "/etc/securetty"
+const char * const bb_path_securetty_file = SECURETTY_FILE;
+#endif
+
+#ifdef L_motd_file
+#define MOTD_FILE "/etc/motd"
+const char * const bb_path_motd_file = MOTD_FILE;
+#endif
+
+#ifdef L_shell_file
+const char * const bb_default_login_shell = LIBBB_DEFAULT_LOGIN_SHELL;
+#endif
+
diff --git a/busybox/libbb/mode_string.c b/busybox/libbb/mode_string.c
new file mode 100644
index 0000000..83142ba
--- /dev/null
+++ b/busybox/libbb/mode_string.c
@@ -0,0 +1,139 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mode_string implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Aug 13, 2003
+ * Fix a bug reported by junkio@cox.net involving the mode_chars index.
+ */
+
+
+#include <assert.h>
+#include <sys/stat.h>
+
+#if ( S_ISUID != 04000 ) || ( S_ISGID != 02000 ) || ( S_ISVTX != 01000 ) \
+ || ( S_IRUSR != 00400 ) || ( S_IWUSR != 00200 ) || ( S_IXUSR != 00100 ) \
+ || ( S_IRGRP != 00040 ) || ( S_IWGRP != 00020 ) || ( S_IXGRP != 00010 ) \
+ || ( S_IROTH != 00004 ) || ( S_IWOTH != 00002 ) || ( S_IXOTH != 00001 )
+#error permission bitflag value assumption(s) violated!
+#endif
+
+#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \
+ || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 ) \
+ || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \
+ || ( S_IFIFO != 0010000 )
+#warning mode type bitflag value assumption(s) violated! falling back to larger version
+
+#if (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX) == 07777
+#undef mode_t
+#define mode_t unsigned short
+#endif
+
+static const mode_t mode_flags[] = {
+ S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID,
+ S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID,
+ S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX
+};
+
+/* The static const char arrays below are duplicated for the two cases
+ * because moving them ahead of the mode_flags declaration cause a text
+ * size increase with the gcc version I'm using. */
+
+/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
+ * and 'B' types don't appear to be available on linux. So I removed them. */
+static const char type_chars[16] = "?pc?d?b?-?l?s???";
+/* 0123456789abcdef */
+static const char mode_chars[7] = "rwxSTst";
+
+const char *bb_mode_string(int mode)
+{
+ static char buf[12];
+ char *p = buf;
+
+ int i, j, k;
+
+ *p = type_chars[ (mode >> 12) & 0xf ];
+ i = 0;
+ do {
+ j = k = 0;
+ do {
+ *++p = '-';
+ if (mode & mode_flags[i+j]) {
+ *p = mode_chars[j];
+ k = j;
+ }
+ } while (++j < 3);
+ if (mode & mode_flags[i+j]) {
+ *p = mode_chars[3 + (k & 2) + ((i&8) >> 3)];
+ }
+ i += 4;
+ } while (i < 12);
+
+ /* Note: We don't bother with nul termination because bss initialization
+ * should have taken care of that for us. If the user scribbled in buf
+ * memory, they deserve whatever happens. But we'll at least assert. */
+ assert(buf[10] == 0);
+
+ return buf;
+}
+
+#else
+
+/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
+ * and 'B' types don't appear to be available on linux. So I removed them. */
+static const char type_chars[16] = "?pc?d?b?-?l?s???";
+/* 0123456789abcdef */
+static const char mode_chars[7] = "rwxSTst";
+
+const char *bb_mode_string(int mode)
+{
+ static char buf[12];
+ char *p = buf;
+
+ int i, j, k, m;
+
+ *p = type_chars[ (mode >> 12) & 0xf ];
+ i = 0;
+ m = 0400;
+ do {
+ j = k = 0;
+ do {
+ *++p = '-';
+ if (mode & m) {
+ *p = mode_chars[j];
+ k = j;
+ }
+ m >>= 1;
+ } while (++j < 3);
+ ++i;
+ if (mode & (010000 >> i)) {
+ *p = mode_chars[3 + (k & 2) + (i == 3)];
+ }
+ } while (i < 3);
+
+ /* Note: We don't bother with nul termination because bss initialization
+ * should have taken care of that for us. If the user scribbled in buf
+ * memory, they deserve whatever happens. But we'll at least assert. */
+ assert(buf[10] == 0);
+
+ return buf;
+}
+
+#endif
diff --git a/busybox/libbb/module_syscalls.c b/busybox/libbb/module_syscalls.c
new file mode 100644
index 0000000..a2ff528
--- /dev/null
+++ b/busybox/libbb/module_syscalls.c
@@ -0,0 +1,116 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * some system calls possibly missing from libc
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include "libbb.h"
+
+/* uClibc always supplies (possibly ENOSYS) versions of these functions. */
+#ifndef __UCLIBC__
+
+/* These syscalls are not included in very old glibc versions */
+int delete_module(const char *name)
+{
+#ifndef __NR_delete_module
+#warning This kernel does not support the delete_module syscall
+#warning -> The delete_module system call is being stubbed out...
+ errno=ENOSYS;
+ return -1;
+#else
+ return(syscall(__NR_delete_module, name));
+#endif
+}
+
+int get_kernel_syms(__ptr_t ks)
+{
+#ifndef __NR_get_kernel_syms
+#warning This kernel does not support the get_kernel_syms syscall
+#warning -> The get_kernel_syms system call is being stubbed out...
+ errno=ENOSYS;
+ return -1;
+#else
+ return(syscall(__NR_get_kernel_syms, ks));
+#endif
+}
+
+/* This may have 5 arguments (for old 2.0 kernels) or 2 arguments
+ * (for 2.2 and 2.4 kernels). Use the greatest common denominator,
+ * and let the kernel cope with whatever it gets. Its good at that. */
+int init_module(void *first, void *second, void *third, void *fourth, void *fifth)
+{
+#ifndef __NR_init_module
+#warning This kernel does not support the init_module syscall
+#warning -> The init_module system call is being stubbed out...
+ errno=ENOSYS;
+ return -1;
+#else
+ return(syscall(__NR_init_module, first, second, third, fourth, fifth));
+#endif
+}
+
+int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret)
+{
+#ifndef __NR_query_module
+#warning This kernel does not support the query_module syscall
+#warning -> The query_module system call is being stubbed out...
+ bb_error_msg("\n\nTo make this application work, you will need to recompile\n"
+ "BusyBox with a kernel supporting the query_module system call.\n");
+ errno=ENOSYS;
+ return -1;
+#else
+ return(syscall(__NR_query_module, name, which, buf, bufsize, ret));
+#endif
+}
+
+/* Jump through hoops to fixup error return codes */
+unsigned long create_module(const char *name, size_t size)
+{
+#ifndef __NR_create_module
+#warning This kernel does not support the create_module syscall
+#warning -> The create_module system call is being stubbed out...
+ errno=ENOSYS;
+ return -1;
+#else
+ long ret = syscall(__NR_create_module, name, size);
+
+ if (ret == -1 && errno > 125) {
+ ret = -errno;
+ errno = 0;
+ }
+ return ret;
+#endif
+}
+
+
+#endif /* __UCLIBC__ */
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
+
diff --git a/busybox/libbb/mtab.c b/busybox/libbb/mtab.c
new file mode 100644
index 0000000..b1f74c4
--- /dev/null
+++ b/busybox/libbb/mtab.c
@@ -0,0 +1,116 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <mntent.h>
+#include "libbb.h"
+
+#define MTAB_MAX_ENTRIES 40
+static const int MS_RDONLY = 1; /* Mount read-only. */
+
+void erase_mtab(const char *name)
+{
+ struct mntent entries[MTAB_MAX_ENTRIES];
+ int count = 0;
+ FILE *mountTable = setmntent(bb_path_mtab_file, "r");
+ struct mntent *m;
+
+ /* Check if reading the mtab file failed */
+ if (mountTable == 0
+ /* Bummer. fall back on trying the /proc filesystem */
+ && (mountTable = setmntent("/proc/mounts", "r")) == 0) {
+ bb_perror_msg(bb_path_mtab_file);
+ return;
+ }
+
+ while (((m = getmntent(mountTable)) != 0) && (count < MTAB_MAX_ENTRIES))
+ {
+ entries[count].mnt_fsname = strdup(m->mnt_fsname);
+ entries[count].mnt_dir = strdup(m->mnt_dir);
+ entries[count].mnt_type = strdup(m->mnt_type);
+ entries[count].mnt_opts = strdup(m->mnt_opts);
+ entries[count].mnt_freq = m->mnt_freq;
+ entries[count].mnt_passno = m->mnt_passno;
+ count++;
+ }
+ endmntent(mountTable);
+ if ((mountTable = setmntent(bb_path_mtab_file, "w"))) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ int result = (strcmp(entries[i].mnt_fsname, name) == 0
+ || strcmp(entries[i].mnt_dir, name) == 0);
+
+ if (result)
+ continue;
+ else
+ addmntent(mountTable, &entries[i]);
+ }
+ endmntent(mountTable);
+ } else if (errno != EROFS)
+ bb_perror_msg(bb_path_mtab_file);
+}
+
+void write_mtab(char *blockDevice, char *directory,
+ char *filesystemType, long flags, char *string_flags)
+{
+ FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
+ struct mntent m;
+
+ if (mountTable == 0) {
+ bb_perror_msg(bb_path_mtab_file);
+ return;
+ }
+ if (mountTable) {
+ int length = strlen(directory);
+
+ if (length > 1 && directory[length - 1] == '/')
+ directory[length - 1] = '\0';
+
+ if (filesystemType == 0) {
+ struct mntent *p = find_mount_point(blockDevice, "/proc/mounts");
+
+ if (p && p->mnt_type)
+ filesystemType = p->mnt_type;
+ }
+ m.mnt_fsname = blockDevice;
+ m.mnt_dir = directory;
+ m.mnt_type = filesystemType ? filesystemType : "default";
+
+ if (*string_flags) {
+ m.mnt_opts = string_flags;
+ } else {
+ if ((flags | MS_RDONLY) == flags)
+ m.mnt_opts = "ro";
+ else
+ m.mnt_opts = "rw";
+ }
+
+ m.mnt_freq = 0;
+ m.mnt_passno = 0;
+ addmntent(mountTable, &m);
+ endmntent(mountTable);
+ }
+}
diff --git a/busybox/libbb/mtab_file.c b/busybox/libbb/mtab_file.c
new file mode 100644
index 0000000..42504e8
--- /dev/null
+++ b/busybox/libbb/mtab_file.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+
+/* Busybox mount uses either /proc/mounts or /etc/mtab to
+ * get the list of currently mounted filesystems */
+#if defined CONFIG_FEATURE_MTAB_SUPPORT
+const char bb_path_mtab_file[] = CONFIG_FEATURE_MTAB_FILENAME;
+#else
+const char bb_path_mtab_file[] = "/proc/mounts";
+#endif
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/my_getgrgid.c b/busybox/libbb/my_getgrgid.c
new file mode 100644
index 0000000..9ac14a3
--- /dev/null
+++ b/busybox/libbb/my_getgrgid.c
@@ -0,0 +1,57 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ /* Hacked by Tito Ragusa (c) 2004 <farmatito@tiscali.it> to make it more
+ * flexible :
+ *
+ * if bufsize is > 0 char *group cannot be set to NULL.
+ * On success groupname is written on static allocated buffer group
+ * (and a pointer to it is returned).
+ * On failure gid as string is written to static allocated buffer
+ * group and NULL is returned.
+ * if bufsize is = 0 char *group can be set to NULL.
+ * On success groupname is returned.
+ * On failure NULL is returned.
+ * if bufsize is < 0 char *group can be set to NULL.
+ * On success groupname is returned.
+ * On failure an error message is printed and the program exits.
+ */
+
+#include "libbb.h"
+#include "grp_.h"
+
+/* gets a groupname given a gid */
+char * my_getgrgid(char *group, long gid, int bufsize)
+{
+ struct group *mygroup = getgrgid(gid);
+
+ return my_getug(group, (mygroup) ? mygroup->gr_name : (char *)mygroup, gid, bufsize, 'g');
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/my_getgrnam.c b/busybox/libbb/my_getgrnam.c
new file mode 100644
index 0000000..22a617c
--- /dev/null
+++ b/busybox/libbb/my_getgrnam.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "libbb.h"
+#include "pwd_.h"
+#include "grp_.h"
+
+
+/* returns a gid given a group name */
+long my_getgrnam(const char *name)
+{
+ struct group *mygroup;
+
+ mygroup = getgrnam(name);
+ if (mygroup==NULL)
+ bb_error_msg_and_die("unknown group name: %s", name);
+
+ return (mygroup->gr_gid);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/my_getpwnam.c b/busybox/libbb/my_getpwnam.c
new file mode 100644
index 0000000..a9fd0cd
--- /dev/null
+++ b/busybox/libbb/my_getpwnam.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "libbb.h"
+#include "pwd_.h"
+#include "grp_.h"
+
+
+/* returns a uid given a username */
+long my_getpwnam(const char *name)
+{
+ struct passwd *myuser;
+
+ myuser = getpwnam(name);
+ if (myuser==NULL)
+ bb_error_msg_and_die("unknown user name: %s", name);
+
+ return myuser->pw_uid;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/my_getpwuid.c b/busybox/libbb/my_getpwuid.c
new file mode 100644
index 0000000..7da360a
--- /dev/null
+++ b/busybox/libbb/my_getpwuid.c
@@ -0,0 +1,56 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ /* Hacked by Tito Ragusa (c) 2004 <farmatito@tiscali.it> to make it more
+ * flexible :
+ *
+ * if bufsize is > 0 char *name can not be set to NULL.
+ * On success username is written on the static allocated buffer name
+ * (and a pointer to it is returned).
+ * On failure uid as string is written to the static allocated buffer name
+ * and NULL is returned.
+ * if bufsize is = 0 char *name can be set to NULL.
+ * On success username is returned.
+ * On failure NULL is returned.
+ * if bufsize is < 0 char *name can be set to NULL
+ * On success username is returned.
+ * On failure an error message is printed and the program exits.
+ */
+
+#include "libbb.h"
+#include "pwd_.h"
+
+/* gets a username given a uid */
+char * my_getpwuid(char *name, long uid, int bufsize)
+{
+ struct passwd *myuser = getpwuid(uid);
+
+ return my_getug(name, (myuser) ? myuser->pw_name : (char *)myuser , uid, bufsize, 'u');
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/my_getug.c b/busybox/libbb/my_getug.c
new file mode 100644
index 0000000..9b7292d
--- /dev/null
+++ b/busybox/libbb/my_getug.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2004 by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ /*
+ *
+ * if bufsize is > 0 char *buffer can not be set to NULL.
+ * If idname is not NULL it is written on the static allocated buffer
+ * (and a pointer to it is returned).
+ * if idname is NULL, id as string is written to the static allocated buffer
+ * and NULL is returned.
+ * if bufsize is = 0 char *buffer can be set to NULL.
+ * If idname exists a pointer to it is returned,
+ * else NULL is returned.
+ * if bufsize is < 0 char *buffer can be set to NULL.
+ * If idname exists a pointer to it is returned,
+ * else an error message is printed and the program exits.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include "libbb.h"
+
+
+/* internal function for my_getpwuid and my_getgrgid */
+char * my_getug(char *buffer, char *idname, long id, int bufsize, char prefix)
+{
+ if(bufsize > 0 ) {
+ assert(buffer!=NULL);
+ if(idname) {
+ return safe_strncpy(buffer, idname, bufsize);
+ }
+ snprintf(buffer, bufsize, "%ld", id);
+ } else if(bufsize < 0 && !idname) {
+ bb_error_msg_and_die("unknown %cid %ld", prefix, id);
+ }
+ return idname;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/obscure.c b/busybox/libbb/obscure.c
new file mode 100644
index 0000000..aa15e40
--- /dev/null
+++ b/busybox/libbb/obscure.c
@@ -0,0 +1,251 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.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.
+ * 3. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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.
+ */
+
+/*
+ * This version of obscure.c contains modifications to support "cracklib"
+ * by Alec Muffet (alec.muffett@uk.sun.com). You must obtain the Cracklib
+ * library source code for this function to operate.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "libbb.h"
+
+/*
+ * can't be a palindrome - like `R A D A R' or `M A D A M'
+ */
+
+static int palindrome(const char *newval)
+{
+ int i, j;
+
+ i = strlen(newval);
+
+ for (j = 0; j < i; j++)
+ if (newval[i - j - 1] != newval[j])
+ return 0;
+
+ return 1;
+}
+
+/*
+ * more than half of the characters are different ones.
+ */
+
+static int similiar(const char *old, const char *newval)
+{
+ int i, j;
+
+ for (i = j = 0; newval[i] && old[i]; i++)
+ if (strchr(newval, old[i]))
+ j++;
+
+ if (i >= j * 2)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * a nice mix of characters.
+ */
+
+static int simple(const char *newval)
+{
+ int digits = 0;
+ int uppers = 0;
+ int lowers = 0;
+ int others = 0;
+ int c;
+ int size;
+ int i;
+
+ for (i = 0; (c = *newval++) != 0; i++) {
+ if (isdigit(c))
+ digits = c;
+ else if (isupper(c))
+ uppers = c;
+ else if (islower(c))
+ lowers = c;
+ else
+ others = c;
+ }
+
+ /*
+ * The scam is this - a password of only one character type
+ * must be 8 letters long. Two types, 7, and so on.
+ */
+
+ size = 9;
+ if (digits)
+ size--;
+ if (uppers)
+ size--;
+ if (lowers)
+ size--;
+ if (others)
+ size--;
+
+ if (size <= i)
+ return 0;
+
+ return 1;
+}
+
+static char *str_lower(char *string)
+{
+ char *cp;
+
+ for (cp = string; *cp; cp++)
+ *cp = tolower(*cp);
+ return string;
+}
+
+static const char *
+password_check(const char *old, const char *newval, const struct passwd *pwdp)
+{
+ const char *msg;
+ char *newmono, *wrapped;
+ int lenwrap;
+
+ if (strcmp(newval, old) == 0)
+ return "no change";
+ if (simple(newval))
+ return "too simple";
+
+ msg = NULL;
+ newmono = str_lower(bb_xstrdup(newval));
+ lenwrap = strlen(old);
+ wrapped = (char *) xmalloc(lenwrap * 2 + 1);
+ str_lower(strcpy(wrapped, old));
+
+ if (palindrome(newmono))
+ msg = "a palindrome";
+
+ else if (strcmp(wrapped, newmono) == 0)
+ msg = "case changes only";
+
+ else if (similiar(wrapped, newmono))
+ msg = "too similiar";
+
+ else {
+ safe_strncpy(wrapped + lenwrap, wrapped, lenwrap + 1);
+ if (strstr(wrapped, newmono))
+ msg = "rotated";
+ }
+
+ bzero(newmono, strlen(newmono));
+ bzero(wrapped, lenwrap * 2);
+ free(newmono);
+ free(wrapped);
+
+ return msg;
+}
+
+static const char *
+obscure_msg(const char *old, const char *newval, const struct passwd *pwdp)
+{
+ int maxlen, oldlen, newlen;
+ char *new1, *old1;
+ const char *msg;
+
+ oldlen = strlen(old);
+ newlen = strlen(newval);
+
+#if 0 /* why not check the password when set for the first time? --marekm */
+ if (old[0] == '\0')
+ /* return (1); */
+ return NULL;
+#endif
+
+ if (newlen < 5)
+ return "too short";
+
+ /*
+ * Remaining checks are optional.
+ */
+ /* Not for us -- Sean
+ *if (!getdef_bool("OBSCURE_CHECKS_ENAB"))
+ * return NULL;
+ */
+ msg = password_check(old, newval, pwdp);
+ if (msg)
+ return msg;
+
+ /* The traditional crypt() truncates passwords to 8 chars. It is
+ possible to circumvent the above checks by choosing an easy
+ 8-char password and adding some random characters to it...
+ Example: "password$%^&*123". So check it again, this time
+ truncated to the maximum length. Idea from npasswd. --marekm */
+
+ maxlen = 8;
+ if (oldlen <= maxlen && newlen <= maxlen)
+ return NULL;
+
+ new1 = (char *) bb_xstrdup(newval);
+ old1 = (char *) bb_xstrdup(old);
+ if (newlen > maxlen)
+ new1[maxlen] = '\0';
+ if (oldlen > maxlen)
+ old1[maxlen] = '\0';
+
+ msg = password_check(old1, new1, pwdp);
+
+ bzero(new1, newlen);
+ bzero(old1, oldlen);
+ free(new1);
+ free(old1);
+
+ return msg;
+}
+
+/*
+ * Obscure - see if password is obscure enough.
+ *
+ * The programmer is encouraged to add as much complexity to this
+ * routine as desired. Included are some of my favorite ways to
+ * check passwords.
+ */
+
+extern int obscure(const char *old, const char *newval, const struct passwd *pwdp)
+{
+ const char *msg = obscure_msg(old, newval, pwdp);
+
+ /* if (msg) { */
+ if (msg != NULL) {
+ printf("Bad password: %s.\n", msg);
+ /* return 0; */
+ return 1;
+ }
+ /* return 1; */
+ return 0;
+}
diff --git a/busybox/libbb/parse_mode.c b/busybox/libbb/parse_mode.c
new file mode 100644
index 0000000..185957b
--- /dev/null
+++ b/busybox/libbb/parse_mode.c
@@ -0,0 +1,177 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * parse_mode implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include "libbb.h"
+
+#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+
+extern int bb_parse_mode(const char *s, mode_t *current_mode)
+{
+ static const mode_t who_mask[] = {
+ S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
+ S_ISUID | S_IRWXU, /* u */
+ S_ISGID | S_IRWXG, /* g */
+ S_IRWXO /* o */
+ };
+
+ static const mode_t perm_mask[] = {
+ S_IRUSR | S_IRGRP | S_IROTH, /* r */
+ S_IWUSR | S_IWGRP | S_IWOTH, /* w */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* x */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
+ S_ISUID | S_ISGID, /* s */
+ S_ISVTX /* t */
+ };
+
+ static const char who_chars[] = "augo";
+ static const char perm_chars[] = "rwxXst";
+
+ const char *p;
+
+ mode_t wholist;
+ mode_t permlist;
+ mode_t mask;
+ mode_t new_mode;
+ char op;
+
+ assert(s);
+
+ if (((unsigned int)(*s - '0')) < 8) {
+ unsigned long tmp;
+ char *e;
+
+ tmp = strtol(s, &e, 8);
+ if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
+ return 0;
+ }
+ *current_mode = tmp;
+ return 1;
+ }
+
+ mask = umask(0);
+ umask(mask);
+
+ new_mode = *current_mode;
+
+ /* Note: We allow empty clauses, and hence empty modes.
+ * We treat an empty mode as no change to perms. */
+
+ while (*s) { /* Process clauses. */
+
+ if (*s == ',') { /* We allow empty clauses. */
+ ++s;
+ continue;
+ }
+
+ /* Get a wholist. */
+ wholist = 0;
+
+ WHO_LIST:
+ p = who_chars;
+ do {
+ if (*p == *s) {
+ wholist |= who_mask[(int)(p-who_chars)];
+ if (!*++s) {
+ return 0;
+ }
+ goto WHO_LIST;
+ }
+ } while (*++p);
+
+ do { /* Process action list. */
+ if ((*s != '+') && (*s != '-')) {
+ if (*s != '=') {
+ return 0;
+ }
+ /* Since op is '=', clear all bits corresponding to the
+ * wholist, of all file bits if wholist is empty. */
+ permlist = ~FILEMODEBITS;
+ if (wholist) {
+ permlist = ~wholist;
+ }
+ new_mode &= permlist;
+ }
+ op = *s++;
+
+ /* Check for permcopy. */
+ p = who_chars + 1; /* Skip 'a' entry. */
+ do {
+ if (*p == *s) {
+ int i = 0;
+ permlist = who_mask[(int)(p-who_chars)]
+ & (S_IRWXU | S_IRWXG | S_IRWXO)
+ & new_mode;
+ do {
+ if (permlist & perm_mask[i]) {
+ permlist |= perm_mask[i];
+ }
+ } while (++i < 3);
+ ++s;
+ goto GOT_ACTION;
+ }
+ } while (*++p);
+
+ /* It was not a permcopy, so get a permlist. */
+ permlist = 0;
+
+ PERM_LIST:
+ p = perm_chars;
+ do {
+ if (*p == *s) {
+ if ((*p != 'X')
+ || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
+ ) {
+ permlist |= perm_mask[(int)(p-perm_chars)];
+ }
+ if (!*++s) {
+ break;
+ }
+ goto PERM_LIST;
+ }
+ } while (*++p);
+
+ GOT_ACTION:
+ if (permlist) { /* The permlist was nonempty. */
+ mode_t tmp = ~mask;
+ if (wholist) {
+ tmp = wholist;
+ }
+ permlist &= tmp;
+
+ if (op == '-') {
+ new_mode &= ~permlist;
+ } else {
+ new_mode |= permlist;
+ }
+ }
+ } while (*s && (*s != ','));
+ }
+
+ *current_mode = new_mode;
+
+ return 1;
+}
diff --git a/busybox/libbb/parse_number.c b/busybox/libbb/parse_number.c
new file mode 100644
index 0000000..5262239
--- /dev/null
+++ b/busybox/libbb/parse_number.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_xparse_number implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include "libbb.h"
+
+extern
+unsigned long bb_xparse_number(const char *numstr,
+ const struct suffix_mult *suffixes)
+{
+ unsigned long int r;
+ char *e;
+ int old_errno;
+
+ /* Since this is a lib function, we're not allowed to reset errno to 0.
+ * Doing so could break an app that is deferring checking of errno.
+ * So, save the old value so that we can restore it if successful. */
+ old_errno = errno;
+ errno = 0;
+ r = strtoul(numstr, &e, 10);
+
+ if ((numstr != e) && !errno) {
+ errno = old_errno; /* Ok. So restore errno. */
+ if (!*e) {
+ return r;
+ }
+ if (suffixes) {
+ assert(suffixes->suffix); /* No nul suffixes. */
+ do {
+ if (strcmp(suffixes->suffix, e) == 0) {
+ if (ULONG_MAX / suffixes->mult < r) { /* Overflow! */
+ break;
+ }
+ return r * suffixes->mult;
+ }
+ ++suffixes;
+ } while (suffixes->suffix);
+ }
+ }
+ bb_error_msg_and_die("invalid number `%s'", numstr);
+}
diff --git a/busybox/libbb/perror_msg.c b/busybox/libbb/perror_msg.c
new file mode 100644
index 0000000..8ba0531
--- /dev/null
+++ b/busybox/libbb/perror_msg.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void bb_perror_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_vperror_msg(s, p);
+ va_end(p);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/perror_msg_and_die.c b/busybox/libbb/perror_msg_and_die.c
new file mode 100644
index 0000000..15bf042
--- /dev/null
+++ b/busybox/libbb/perror_msg_and_die.c
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void bb_perror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_vperror_msg(s, p);
+ va_end(p);
+ exit(bb_default_error_retval);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/perror_nomsg.c b/busybox/libbb/perror_nomsg.c
new file mode 100644
index 0000000..464cb86
--- /dev/null
+++ b/busybox/libbb/perror_nomsg.c
@@ -0,0 +1,30 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_perror_nomsg implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stddef.h>
+#include <libbb.h>
+
+extern void bb_perror_nomsg(void)
+{
+ /* Ignore the gcc warning about a null format string. */
+ bb_perror_msg(NULL);
+}
diff --git a/busybox/libbb/perror_nomsg_and_die.c b/busybox/libbb/perror_nomsg_and_die.c
new file mode 100644
index 0000000..bab2284
--- /dev/null
+++ b/busybox/libbb/perror_nomsg_and_die.c
@@ -0,0 +1,30 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_perror_nomsg_and_die implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stddef.h>
+#include "libbb.h"
+
+extern void bb_perror_nomsg_and_die(void)
+{
+ /* Ignore the gcc warning about a null format string. */
+ bb_perror_msg_and_die(NULL);
+}
diff --git a/busybox/libbb/print_file.c b/busybox/libbb/print_file.c
new file mode 100644
index 0000000..963db14
--- /dev/null
+++ b/busybox/libbb/print_file.c
@@ -0,0 +1,76 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libbb.h"
+
+extern void bb_xprint_and_close_file(FILE *file)
+{
+ bb_xfflush_stdout();
+ /* Note: Do not use STDOUT_FILENO here, as this is a lib routine
+ * and the calling code may have reassigned stdout. */
+ if (bb_copyfd_eof(fileno(file), STDOUT_FILENO) == -1) {
+ /* bb_copyfd outputs any needed messages, so just die. */
+ exit(bb_default_error_retval);
+ }
+ /* Note: Since we're reading, don't bother checking the return value
+ * of fclose(). The only possible failure is EINTR which
+ * should already have been taken care of. */
+ fclose(file);
+}
+
+/* Returns:
+ * 0 if successful
+ * -1 if 'filename' does not exist or is a directory
+ * exits with default error code if an error occurs
+ */
+
+extern int bb_xprint_file_by_name(const char *filename)
+{
+ FILE *f;
+
+#if 0
+ /* This check shouldn't be necessary for linux, but is left
+ * here disabled just in case. */
+ struct stat statBuf;
+
+ if(is_directory(filename, TRUE, &statBuf)) {
+ bb_error_msg("%s: Is directory", filename);
+ } else
+#endif
+ if ((f = bb_wfopen(filename, "r")) != NULL) {
+ bb_xprint_and_close_file(f);
+ return 0;
+ }
+
+ return -1;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/printf.c b/busybox/libbb/printf.c
new file mode 100644
index 0000000..1156da9
--- /dev/null
+++ b/busybox/libbb/printf.c
@@ -0,0 +1,181 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * *printf implementations for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Mar 12, 2003 Manuel Novoa III
+ *
+ * While fwrite(), fputc(), fputs(), etc. all set the stream error flag
+ * on failure, the *printf functions are unique in that they can fail
+ * for reasons not related to the actual output itself. Among the possible
+ * reasons for failure which don't set the streams error indicator,
+ * SUSv3 lists EILSEQ, EINVAL, and ENOMEM.
+ *
+ * In some cases, it would be desirable to have a group of *printf()
+ * functions available that _always_ set the stream error indicator on
+ * failure. That would allow us to defer error checking until applet
+ * exit. Unfortunately, there is no standard way of setting a streams
+ * error indicator... even though we can clear it with clearerr().
+ *
+ * Therefore, we have to resort to implementation dependent code. Feel
+ * free to send patches for stdio implementations where the following
+ * fails.
+ *
+ * NOTE: None of this is thread safe. As busybox is a non-threaded app,
+ * that isn't currently an issue.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "libbb.h"
+
+#if defined(__UCLIBC__)
+
+# if defined(__FLAG_ERROR)
+/* Using my newer stdio implementation. Unlocked macros are:
+ * #define __CLEARERR(stream) \
+ ((stream)->modeflags &= ~(__FLAG_EOF|__FLAG_ERROR), (void)0)
+ * #define __FEOF(stream) ((stream)->modeflags & __FLAG_EOF)
+ * #define __FERROR(stream) ((stream)->modeflags & __FLAG_ERROR)
+ */
+# if defined(__MASK_READING)
+# define SET_FERROR_UNLOCKED(S) ((S)->__modeflags |= __FLAG_ERROR)
+# else
+# define SET_FERROR_UNLOCKED(S) ((S)->modeflags |= __FLAG_ERROR)
+# endif
+
+# elif defined(__MODE_ERR)
+/* Using either the original stdio implementation (from dev86) or
+ * my original stdio rewrite. Macros were:
+ * #define ferror(fp) (((fp)->mode&__MODE_ERR) != 0)
+ * #define feof(fp) (((fp)->mode&__MODE_EOF) != 0)
+ * #define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR),0)
+ */
+#define SET_FERROR_UNLOCKED(S) ((S)->mode |= __MODE_ERR)
+
+# else
+#error unknown uClibc stdio implemenation!
+# endif
+
+#elif defined(__GLIBC__)
+
+# if defined(_STDIO_USES_IOSTREAM)
+/* Apparently using the newer libio implementation, with associated defines:
+ * #define _IO_feof_unlocked(__fp) (((__fp)->_flags & _IO_EOF_SEEN) != 0)
+ * #define _IO_ferror_unlocked(__fp) (((__fp)->_flags & _IO_ERR_SEEN) != 0)
+ */
+#define SET_FERROR_UNLOCKED(S) ((S)->_flags |= _IO_ERR_SEEN)
+
+# else
+/* Assume the older version of glibc which used a bitfield entry
+ * as a stream error flag. The associated defines were:
+ * #define __clearerr(stream) ((stream)->__error = (stream)->__eof = 0)
+ * #define feof_unlocked(stream) ((stream)->__eof != 0)
+ * #define ferror_unlocked(stream) ((stream)->__error != 0)
+ */
+#define SET_FERROR_UNLOCKED(S) ((S)->__error = 1)
+
+# endif
+
+#elif defined(__NEWLIB_H__)
+/* I honestly don't know if there are different versions of stdio in
+ * newlibs history. Anyway, here's what's current.
+ * #define __sfeof(p) (((p)->_flags & __SEOF) != 0)
+ * #define __sferror(p) (((p)->_flags & __SERR) != 0)
+ * #define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
+ */
+#define SET_FERROR_UNLOCKED(S) ((S)->_flags |= __SERR)
+
+#elif defined(__dietlibc__)
+/*
+ * WARNING!!! dietlibc is quite buggy. WARNING!!!
+ *
+ * Some example bugs as of March 12, 2003...
+ * 1) fputc() doesn't set the error indicator on failure.
+ * 2) freopen() doesn't maintain the same stream object, contrary to
+ * standards. This makes it useless in its primary role of
+ * reassociating stdin/stdout/stderr.
+ * 3) printf() often fails to correctly format output when conversions
+ * involve padding. It is also practically useless for floating
+ * point output.
+ *
+ * But, if you're determined to use it anyway, (as of the current version)
+ * you can extract the information you need from dietstdio.h. See the
+ * other library implementations for examples.
+ */
+#error dietlibc is currently not supported. Please see the commented source.
+
+#else /* some other lib */
+/* Please see the comments for the above supported libraries for examples
+ * of what is required to support your stdio implementation.
+ */
+#error Your stdio library is currently not supported. Please see the commented source.
+#endif
+
+#ifdef L_bb_vfprintf
+extern int bb_vfprintf(FILE * __restrict stream,
+ const char * __restrict format,
+ va_list arg)
+{
+ int rv;
+
+ if ((rv = vfprintf(stream, format, arg)) < 0) {
+ SET_FERROR_UNLOCKED(stream);
+ }
+
+ return rv;
+}
+#endif
+
+#ifdef L_bb_vprintf
+extern int bb_vprintf(const char * __restrict format, va_list arg)
+{
+ return bb_vfprintf(stdout, format, arg);
+}
+#endif
+
+#ifdef L_bb_fprintf
+extern int bb_fprintf(FILE * __restrict stream,
+ const char * __restrict format, ...)
+{
+ va_list arg;
+ int rv;
+
+ va_start(arg, format);
+ rv = bb_vfprintf(stream, format, arg);
+ va_end(arg);
+
+ return rv;
+}
+#endif
+
+#ifdef L_bb_printf
+extern int bb_printf(const char * __restrict format, ...)
+{
+ va_list arg;
+ int rv;
+
+ va_start(arg, format);
+ rv = bb_vfprintf(stdout, format, arg);
+ va_end(arg);
+
+ return rv;
+}
+#endif
diff --git a/busybox/libbb/process_escape_sequence.c b/busybox/libbb/process_escape_sequence.c
new file mode 100644
index 0000000..28b1e36
--- /dev/null
+++ b/busybox/libbb/process_escape_sequence.c
@@ -0,0 +1,112 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) Manuel Novoa III <mjn3@codepoet.org>
+ * and Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include "libbb.h"
+
+#define WANT_HEX_ESCAPES 1
+
+/* Usual "this only works for ascii compatible encodings" disclaimer. */
+#undef _tolower
+#define _tolower(X) ((X)|((char) 0x20))
+
+char bb_process_escape_sequence(const char **ptr)
+{
+ static const char charmap[] = {
+ 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0,
+ '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
+
+ const char *p;
+ const char *q;
+ unsigned int num_digits;
+ unsigned int r;
+ unsigned int n;
+ unsigned int d;
+ unsigned int base;
+
+ num_digits = n = 0;
+ base = 8;
+ q = *ptr;
+
+#ifdef WANT_HEX_ESCAPES
+ if (*q == 'x') {
+ ++q;
+ base = 16;
+ ++num_digits;
+ }
+#endif
+
+ do {
+ d = (unsigned int)(*q - '0');
+#ifdef WANT_HEX_ESCAPES
+ if (d >= 10) {
+ d = ((unsigned int)(_tolower(*q) - 'a')) + 10;
+ }
+#endif
+
+ if (d >= base) {
+#ifdef WANT_HEX_ESCAPES
+ if ((base == 16) && (!--num_digits)) {
+/* return '\\'; */
+ --q;
+ }
+#endif
+ break;
+ }
+
+ r = n * base + d;
+ if (r > UCHAR_MAX) {
+ break;
+ }
+
+ n = r;
+ ++q;
+ } while (++num_digits < 3);
+
+ if (num_digits == 0) { /* mnemonic escape sequence? */
+ p = charmap;
+ do {
+ if (*p == *q) {
+ q++;
+ break;
+ }
+ } while (*++p);
+ n = *(p+(sizeof(charmap)/2));
+ }
+
+ *ptr = q;
+
+ return (char) n;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/procps.c b/busybox/libbb/procps.c
new file mode 100644
index 0000000..e405fb7
--- /dev/null
+++ b/busybox/libbb/procps.c
@@ -0,0 +1,158 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright 1998 by Albert Cahalan; all rights reserved.
+ * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
+ * GNU Library General Public License Version 2, or any later version
+ *
+ */
+
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <asm/page.h>
+
+#include "libbb.h"
+
+extern procps_status_t * procps_scan(int save_user_arg0
+#ifdef CONFIG_SELINUX
+ , int use_selinux , security_id_t *sid
+#endif
+ )
+{
+ static DIR *dir;
+ struct dirent *entry;
+ static procps_status_t ret_status;
+ char *name;
+ int n;
+ char status[32];
+ char buf[1024];
+ FILE *fp;
+ procps_status_t curstatus;
+ int pid;
+ long tasknice;
+ struct stat sb;
+
+ if (!dir) {
+ dir = opendir("/proc");
+ if(!dir)
+ bb_error_msg_and_die("Can't open /proc");
+ }
+ for(;;) {
+ if((entry = readdir(dir)) == NULL) {
+ closedir(dir);
+ dir = 0;
+ return 0;
+ }
+ name = entry->d_name;
+ if (!(*name >= '0' && *name <= '9'))
+ continue;
+
+ memset(&curstatus, 0, sizeof(procps_status_t));
+ pid = atoi(name);
+ curstatus.pid = pid;
+
+ sprintf(status, "/proc/%d", pid);
+ if(stat(status, &sb))
+ continue;
+ my_getpwuid(curstatus.user, sb.st_uid, sizeof(curstatus.user));
+
+ sprintf(status, "/proc/%d/stat", pid);
+ if((fp = fopen(status, "r")) == NULL)
+ continue;
+#ifdef CONFIG_SELINUX
+ if(use_selinux)
+ {
+ if(fstat_secure(fileno(fp), &sb, sid))
+ continue;
+ }
+ else
+#endif
+ name = fgets(buf, sizeof(buf), fp);
+ fclose(fp);
+ if(name == NULL)
+ continue;
+ name = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
+ if(name == 0 || name[1] != ' ')
+ continue;
+ *name = 0;
+ sscanf(buf, "%*s (%15c", curstatus.short_cmd);
+ n = sscanf(name+2,
+ "%c %d "
+ "%*s %*s %*s %*s " /* pgrp, session, tty, tpgid */
+ "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+ "%lu %lu "
+#else
+ "%*s %*s "
+#endif
+ "%*s %*s %*s " /* cutime, cstime, priority */
+ "%ld "
+ "%*s %*s %*s " /* timeout, it_real_value, start_time */
+ "%*s " /* vsize */
+ "%ld",
+ curstatus.state, &curstatus.ppid,
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+ &curstatus.utime, &curstatus.stime,
+#endif
+ &tasknice,
+ &curstatus.rss);
+#ifdef FEATURE_CPU_USAGE_PERCENTAGE
+ if(n != 6)
+#else
+ if(n != 4)
+#endif
+ continue;
+
+ if (curstatus.rss == 0 && curstatus.state[0] != 'Z')
+ curstatus.state[1] = 'W';
+ else
+ curstatus.state[1] = ' ';
+ if (tasknice < 0)
+ curstatus.state[2] = '<';
+ else if (tasknice > 0)
+ curstatus.state[2] = 'N';
+ else
+ curstatus.state[2] = ' ';
+
+#ifdef PAGE_SHIFT
+ curstatus.rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */
+#else
+ curstatus.rss *= (getpagesize() >> 10); /* 2**10 = 1kb */
+#endif
+
+ if(save_user_arg0) {
+ sprintf(status, "/proc/%d/cmdline", pid);
+ if((fp = fopen(status, "r")) == NULL)
+ continue;
+ if((n=fread(buf, 1, sizeof(buf)-1, fp)) > 0) {
+ if(buf[n-1]=='\n')
+ buf[--n] = 0;
+ name = buf;
+ while(n) {
+ if(((unsigned char)*name) < ' ')
+ *name = ' ';
+ name++;
+ n--;
+ }
+ *name = 0;
+ if(buf[0])
+ curstatus.cmd = strdup(buf);
+ /* if NULL it work true also */
+ }
+ fclose(fp);
+ }
+ return memcpy(&ret_status, &curstatus, sizeof(procps_status_t));
+ }
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/pw_encrypt.c b/busybox/libbb/pw_encrypt.c
new file mode 100644
index 0000000..727149d
--- /dev/null
+++ b/busybox/libbb/pw_encrypt.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routine.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <string.h>
+#include <crypt.h>
+#include "libbb.h"
+
+
+extern char *pw_encrypt(const char *clear, const char *salt)
+{
+ static char cipher[128];
+ char *cp;
+
+#ifdef CONFIG_FEATURE_SHA1_PASSWORDS
+ if (strncmp(salt, "$2$", 3) == 0) {
+ return sha1_crypt(clear);
+ }
+#endif
+ cp = (char *) crypt(clear, salt);
+ /* if crypt (a nonstandard crypt) returns a string too large,
+ truncate it so we don't overrun buffers and hope there is
+ enough security in what's left */
+ safe_strncpy(cipher, cp, sizeof(cipher));
+ return cipher;
+}
+
diff --git a/busybox/libbb/pwd2spwd.c b/busybox/libbb/pwd2spwd.c
new file mode 100644
index 0000000..3dd625b
--- /dev/null
+++ b/busybox/libbb/pwd2spwd.c
@@ -0,0 +1,74 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.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.
+ * 3. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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 <time.h>
+#include <sys/types.h>
+#include "libbb.h"
+#include "shadow_.h"
+
+/*
+ * pwd_to_spwd - create entries for new spwd structure
+ *
+ * pwd_to_spwd() creates a new (struct spwd) containing the
+ * information in the pointed-to (struct passwd).
+ */
+#define DAY (24L*3600L)
+#define WEEK (7*DAY)
+#define SCALE DAY
+struct spwd *pwd_to_spwd(const struct passwd *pw)
+{
+ static struct spwd sp;
+
+ /*
+ * Nice, easy parts first. The name and passwd map directly
+ * from the old password structure to the new one.
+ */
+ sp.sp_namp = pw->pw_name;
+ sp.sp_pwdp = pw->pw_passwd;
+
+ /*
+ * Defaults used if there is no pw_age information.
+ */
+ sp.sp_min = 0;
+ sp.sp_max = (10000L * DAY) / SCALE;
+ sp.sp_lstchg = time((time_t *) 0) / SCALE;
+
+ /*
+ * These fields have no corresponding information in the password
+ * file. They are set to uninitialized values.
+ */
+ sp.sp_warn = -1;
+ sp.sp_expire = -1;
+ sp.sp_inact = -1;
+ sp.sp_flag = -1;
+
+ return &sp;
+}
+
diff --git a/busybox/libbb/qmodule.c b/busybox/libbb/qmodule.c
new file mode 100644
index 0000000..fd14d10
--- /dev/null
+++ b/busybox/libbb/qmodule.c
@@ -0,0 +1,29 @@
+/*
+ Copyright (C) 2002 Tim Riker <Tim@Rikers.org>
+ everyone seems to claim it someplace. ;-)
+*/
+
+#include <errno.h>
+
+#include "libbb.h"
+
+int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
+
+int my_query_module(const char *name, int which, void **buf,
+ size_t *bufsize, size_t *ret)
+{
+ int my_ret;
+
+ my_ret = query_module(name, which, *buf, *bufsize, ret);
+
+ if (my_ret == -1 && errno == ENOSPC) {
+ *buf = xrealloc(*buf, *ret);
+ *bufsize = *ret;
+
+ my_ret = query_module(name, which, *buf, *bufsize, ret);
+ }
+
+ return my_ret;
+}
+
+
diff --git a/busybox/libbb/read_package_field.c b/busybox/libbb/read_package_field.c
new file mode 100644
index 0000000..4292689
--- /dev/null
+++ b/busybox/libbb/read_package_field.c
@@ -0,0 +1,114 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "libbb.h"
+
+/*
+ * Gets the next package field from package_buffer, seperated into the field name
+ * and field value, it returns the int offset to the first character of the next field
+ */
+int read_package_field(const char *package_buffer, char **field_name, char **field_value)
+{
+ int offset_name_start = 0;
+ int offset_name_end = 0;
+ int offset_value_start = 0;
+ int offset_value_end = 0;
+ int offset = 0;
+ int next_offset;
+ int name_length;
+ int value_length;
+ int exit_flag = FALSE;
+
+ if (package_buffer == NULL) {
+ *field_name = NULL;
+ *field_value = NULL;
+ return(-1);
+ }
+ while (1) {
+ next_offset = offset + 1;
+ switch (package_buffer[offset]) {
+ case('\0'):
+ exit_flag = TRUE;
+ break;
+ case(':'):
+ if (offset_name_end == 0) {
+ offset_name_end = offset;
+ offset_value_start = next_offset;
+ }
+ /* TODO: Name might still have trailing spaces if ':' isnt
+ * immediately after name */
+ break;
+ case('\n'):
+ /* TODO: The char next_offset may be out of bounds */
+ if (package_buffer[next_offset] != ' ') {
+ exit_flag = TRUE;
+ break;
+ }
+ case('\t'):
+ case(' '):
+ /* increment the value start point if its a just filler */
+ if (offset_name_start == offset) {
+ offset_name_start++;
+ }
+ if (offset_value_start == offset) {
+ offset_value_start++;
+ }
+ break;
+ }
+ if (exit_flag) {
+ /* Check that the names are valid */
+ offset_value_end = offset;
+ name_length = offset_name_end - offset_name_start;
+ value_length = offset_value_end - offset_value_start;
+ if (name_length == 0) {
+ break;
+ }
+ if ((name_length > 0) && (value_length > 0)) {
+ break;
+ }
+
+ /* If not valid, start fresh with next field */
+ exit_flag = FALSE;
+ offset_name_start = offset + 1;
+ offset_name_end = 0;
+ offset_value_start = offset + 1;
+ offset_value_end = offset + 1;
+ offset++;
+ }
+ offset++;
+ }
+ if (name_length == 0) {
+ *field_name = NULL;
+ } else {
+ *field_name = bb_xstrndup(&package_buffer[offset_name_start], name_length);
+ }
+ if (value_length > 0) {
+ *field_value = bb_xstrndup(&package_buffer[offset_value_start], value_length);
+ } else {
+ *field_value = NULL;
+ }
+ return(next_offset);
+}
+
diff --git a/busybox/libbb/recursive_action.c b/busybox/libbb/recursive_action.c
new file mode 100644
index 0000000..d276298
--- /dev/null
+++ b/busybox/libbb/recursive_action.c
@@ -0,0 +1,141 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <stdlib.h> /* free() */
+#include "libbb.h"
+
+#undef DEBUG_RECURS_ACTION
+
+
+/*
+ * Walk down all the directories under the specified
+ * location, and do something (something specified
+ * by the fileAction and dirAction function pointers).
+ *
+ * Unfortunately, while nftw(3) could replace this and reduce
+ * code size a bit, nftw() wasn't supported before GNU libc 2.1,
+ * and so isn't sufficiently portable to take over since glibc2.1
+ * is so stinking huge.
+ */
+int recursive_action(const char *fileName,
+ int recurse, int followLinks, int depthFirst,
+ int (*fileAction) (const char *fileName,
+ struct stat * statbuf,
+ void* userData),
+ int (*dirAction) (const char *fileName,
+ struct stat * statbuf,
+ void* userData),
+ void* userData)
+{
+ int status;
+ struct stat statbuf;
+ struct dirent *next;
+
+ if (followLinks)
+ status = stat(fileName, &statbuf);
+ else
+ status = lstat(fileName, &statbuf);
+
+ if (status < 0) {
+#ifdef DEBUG_RECURS_ACTION
+ bb_error_msg("status=%d followLinks=%d TRUE=%d",
+ status, followLinks, TRUE);
+#endif
+ bb_perror_msg("%s", fileName);
+ return FALSE;
+ }
+
+ if (! followLinks && (S_ISLNK(statbuf.st_mode))) {
+ if (fileAction == NULL)
+ return TRUE;
+ else
+ return fileAction(fileName, &statbuf, userData);
+ }
+
+ if (! recurse) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ if (dirAction != NULL)
+ return (dirAction(fileName, &statbuf, userData));
+ else
+ return TRUE;
+ }
+ }
+
+ if (S_ISDIR(statbuf.st_mode)) {
+ DIR *dir;
+
+ if (dirAction != NULL && ! depthFirst) {
+ status = dirAction(fileName, &statbuf, userData);
+ if (! status) {
+ bb_perror_msg("%s", fileName);
+ return FALSE;
+ } else if (status == SKIP)
+ return TRUE;
+ }
+ dir = opendir(fileName);
+ if (!dir) {
+ bb_perror_msg("%s", fileName);
+ return FALSE;
+ }
+ status = TRUE;
+ while ((next = readdir(dir)) != NULL) {
+ char *nextFile;
+
+ nextFile = concat_subpath_file(fileName, next->d_name);
+ if(nextFile == NULL)
+ continue;
+ if (! recursive_action(nextFile, TRUE, followLinks, depthFirst,
+ fileAction, dirAction, userData)) {
+ status = FALSE;
+ }
+ free(nextFile);
+ }
+ closedir(dir);
+ if (dirAction != NULL && depthFirst) {
+ if (! dirAction(fileName, &statbuf, userData)) {
+ bb_perror_msg("%s", fileName);
+ return FALSE;
+ }
+ }
+ if (! status)
+ return FALSE;
+ } else {
+ if (fileAction == NULL)
+ return TRUE;
+ else
+ return fileAction(fileName, &statbuf, userData);
+ }
+ return TRUE;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/remove_file.c b/busybox/libbb/remove_file.c
new file mode 100644
index 0000000..8b45c58
--- /dev/null
+++ b/busybox/libbb/remove_file.c
@@ -0,0 +1,124 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini remove_file implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <utime.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include "libbb.h"
+
+extern int remove_file(const char *path, int flags)
+{
+ struct stat path_stat;
+ int path_exists = 1;
+
+ if (lstat(path, &path_stat) < 0) {
+ if (errno != ENOENT) {
+ bb_perror_msg("unable to stat `%s'", path);
+ return -1;
+ }
+
+ path_exists = 0;
+ }
+
+ if (!path_exists) {
+ if (!(flags & FILEUTILS_FORCE)) {
+ bb_perror_msg("cannot remove `%s'", path);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (S_ISDIR(path_stat.st_mode)) {
+ DIR *dp;
+ struct dirent *d;
+ int status = 0;
+
+ if (!(flags & FILEUTILS_RECUR)) {
+ bb_error_msg("%s: is a directory", path);
+ return -1;
+ }
+
+ if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 &&
+ isatty(0)) ||
+ (flags & FILEUTILS_INTERACTIVE)) {
+ fprintf(stderr, "%s: descend into directory `%s'? ", bb_applet_name,
+ path);
+ if (!bb_ask_confirmation())
+ return 0;
+ }
+
+ if ((dp = opendir(path)) == NULL) {
+ bb_perror_msg("unable to open `%s'", path);
+ return -1;
+ }
+
+ while ((d = readdir(dp)) != NULL) {
+ char *new_path;
+
+ new_path = concat_subpath_file(path, d->d_name);
+ if(new_path == NULL)
+ continue;
+ if (remove_file(new_path, flags) < 0)
+ status = -1;
+ free(new_path);
+ }
+
+ if (closedir(dp) < 0) {
+ bb_perror_msg("unable to close `%s'", path);
+ return -1;
+ }
+
+ if (flags & FILEUTILS_INTERACTIVE) {
+ fprintf(stderr, "%s: remove directory `%s'? ", bb_applet_name, path);
+ if (!bb_ask_confirmation())
+ return status;
+ }
+
+ if (rmdir(path) < 0) {
+ bb_perror_msg("unable to remove `%s'", path);
+ return -1;
+ }
+
+ return status;
+ } else {
+ if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 &&
+ !S_ISLNK(path_stat.st_mode) &&
+ isatty(0)) ||
+ (flags & FILEUTILS_INTERACTIVE)) {
+ fprintf(stderr, "%s: remove `%s'? ", bb_applet_name, path);
+ if (!bb_ask_confirmation())
+ return 0;
+ }
+
+ if (unlink(path) < 0) {
+ bb_perror_msg("unable to remove `%s'", path);
+ return -1;
+ }
+
+ return 0;
+ }
+}
diff --git a/busybox/libbb/restricted_shell.c b/busybox/libbb/restricted_shell.c
new file mode 100644
index 0000000..74a6414
--- /dev/null
+++ b/busybox/libbb/restricted_shell.c
@@ -0,0 +1,57 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.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.
+ * 3. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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 <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+#include "libbb.h"
+
+
+
+/* Return 1 if SHELL is a restricted shell (one not returned by
+ getusershell), else 0, meaning it is a standard shell. */
+
+int restricted_shell ( const char *shell )
+{
+ char *line;
+
+ setusershell ( );
+ while (( line = getusershell ( ))) {
+ if (( *line != '#' ) && ( strcmp ( line, shell ) == 0 ))
+ break;
+ }
+ endusershell ( );
+ return line ? 0 : 1;
+}
+
diff --git a/busybox/libbb/run_parts.c b/busybox/libbb/run_parts.c
new file mode 100644
index 0000000..4c8841f
--- /dev/null
+++ b/busybox/libbb/run_parts.c
@@ -0,0 +1,126 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * run command from specified directory
+ *
+ *
+ * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it>
+ * rewrite to vfork usage by
+ * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ */
+
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "libbb.h"
+
+/* valid_name */
+/* True or false? Is this a valid filename (upper/lower alpha, digits,
+ * underscores, and hyphens only?)
+ */
+static int valid_name(const struct dirent *d)
+{
+ char *c = d->d_name;
+
+ while (*c) {
+ if (!isalnum(*c) && (*c != '_') && (*c != '-')) {
+ return 0;
+ }
+ ++c;
+ }
+ return 1;
+}
+
+/* test mode = 1 is the same as official run_parts
+ * test_mode = 2 means to fail silently on missing directories
+ */
+
+extern int run_parts(char **args, const unsigned char test_mode, char **env)
+{
+ struct dirent **namelist = 0;
+ struct stat st;
+ char *filename;
+ char *arg0 = args[0];
+ int entries;
+ int i;
+ int exitstatus = 0;
+
+#if __GNUC__
+ /* Avoid longjmp clobbering */
+ (void) &i;
+ (void) &exitstatus;
+#endif
+ /* scandir() isn't POSIX, but it makes things easy. */
+ entries = scandir(arg0, &namelist, valid_name, alphasort);
+
+ if (entries == -1) {
+ if (test_mode & 2) {
+ return(2);
+ }
+ bb_perror_msg_and_die("failed to open directory %s", arg0);
+ }
+
+ for (i = 0; i < entries; i++) {
+
+ filename = concat_path_file(arg0, namelist[i]->d_name);
+
+ if (stat(filename, &st) < 0) {
+ bb_perror_msg_and_die("failed to stat component %s", filename);
+ }
+ if (S_ISREG(st.st_mode) && !access(filename, X_OK)) {
+ if (test_mode) {
+ puts(filename);
+ } else {
+ /* exec_errno is common vfork variable */
+ volatile int exec_errno = 0;
+ int result;
+ int pid;
+
+ if ((pid = vfork()) < 0) {
+ bb_perror_msg_and_die("failed to fork");
+ } else if (!pid) {
+ args[0] = filename;
+ execve(filename, args, env);
+ exec_errno = errno;
+ _exit(1);
+ }
+
+ waitpid(pid, &result, 0);
+ if(exec_errno) {
+ errno = exec_errno;
+ bb_perror_msg("failed to exec %s", filename);
+ exitstatus = 1;
+ }
+ if (WIFEXITED(result) && WEXITSTATUS(result)) {
+ bb_perror_msg("%s exited with return code %d", filename, WEXITSTATUS(result));
+ exitstatus = 1;
+ } else if (WIFSIGNALED(result)) {
+ bb_perror_msg("%s exited because of uncaught signal %d", filename, WTERMSIG(result));
+ exitstatus = 1;
+ }
+ }
+ }
+ else if (!S_ISDIR(st.st_mode)) {
+ bb_error_msg("component %s is not an executable plain file", filename);
+ exitstatus = 1;
+ }
+
+ free(namelist[i]);
+ free(filename);
+ }
+ free(namelist);
+
+ return(exitstatus);
+}
diff --git a/busybox/libbb/run_shell.c b/busybox/libbb/run_shell.c
new file mode 100644
index 0000000..993b4e7
--- /dev/null
+++ b/busybox/libbb/run_shell.c
@@ -0,0 +1,87 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.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.
+ * 3. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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 <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+#include "libbb.h"
+#ifdef CONFIG_SELINUX
+#include <proc_secure.h>
+#endif
+
+/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
+ If COMMAND is nonzero, pass it to the shell with the -c option.
+ If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
+ arguments. */
+
+void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args
+#ifdef CONFIG_SELINUX
+ , security_id_t sid
+#endif
+)
+{
+ const char **args;
+ int argno = 1;
+ int additional_args_cnt = 0;
+
+ for ( args = additional_args; args && *args; args++ )
+ additional_args_cnt++;
+
+ args = (const char **) xmalloc (sizeof (char *) * ( 4 + additional_args_cnt ));
+
+ args [0] = bb_get_last_path_component ( bb_xstrdup ( shell ));
+
+ if ( loginshell ) {
+ char *args0;
+ bb_xasprintf ( &args0, "-%s", args [0] );
+ args [0] = args0;
+ }
+
+ if ( command ) {
+ args [argno++] = "-c";
+ args [argno++] = command;
+ }
+ if ( additional_args ) {
+ for ( ; *additional_args; ++additional_args )
+ args [argno++] = *additional_args;
+ }
+ args [argno] = 0;
+#ifdef CONFIG_SELINUX
+ if(sid)
+ execve_secure(shell, (char **) args, environ, sid);
+ else
+#endif
+ execv ( shell, (char **) args );
+ bb_perror_msg_and_die ( "cannot run %s", shell );
+}
diff --git a/busybox/libbb/safe_read.c b/busybox/libbb/safe_read.c
new file mode 100644
index 0000000..92e1d8a
--- /dev/null
+++ b/busybox/libbb/safe_read.c
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+
+ssize_t safe_read(int fd, void *buf, size_t count)
+{
+ ssize_t n;
+
+ do {
+ n = read(fd, buf, count);
+ } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/safe_strncpy.c b/busybox/libbb/safe_strncpy.c
new file mode 100644
index 0000000..2016e6b
--- /dev/null
+++ b/busybox/libbb/safe_strncpy.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+
+
+/* Like strncpy but make sure the resulting string is always 0 terminated. */
+extern char * safe_strncpy(char *dst, const char *src, size_t size)
+{
+ dst[size-1] = '\0';
+ return strncpy(dst, src, size-1);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/safe_strtol.c b/busybox/libbb/safe_strtol.c
new file mode 100644
index 0000000..fcbdba8
--- /dev/null
+++ b/busybox/libbb/safe_strtol.c
@@ -0,0 +1,92 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include "libbb.h"
+
+#ifdef L_safe_strtoi
+extern
+int safe_strtoi(char *arg, int* value)
+{
+ int error;
+ long lvalue = *value;
+ error = safe_strtol(arg, &lvalue);
+ *value = (int) lvalue;
+ return error;
+}
+#endif
+
+#ifdef L_safe_strtod
+extern
+int safe_strtod(char *arg, double* value)
+{
+ char *endptr;
+ int errno_save = errno;
+
+ assert(arg!=NULL);
+ errno = 0;
+ *value = strtod(arg, &endptr);
+ if (errno != 0 || *endptr!='\0' || endptr==arg) {
+ return 1;
+ }
+ errno = errno_save;
+ return 0;
+}
+#endif
+
+#ifdef L_safe_strtol
+extern
+int safe_strtol(char *arg, long* value)
+{
+ char *endptr;
+ int errno_save = errno;
+
+ assert(arg!=NULL);
+ errno = 0;
+ *value = strtol(arg, &endptr, 0);
+ if (errno != 0 || *endptr!='\0' || endptr==arg) {
+ return 1;
+ }
+ errno = errno_save;
+ return 0;
+}
+#endif
+
+#ifdef L_safe_strtoul
+extern
+int safe_strtoul(char *arg, unsigned long* value)
+{
+ char *endptr;
+ int errno_save = errno;
+
+ assert(arg!=NULL);
+ errno = 0;
+ *value = strtoul(arg, &endptr, 0);
+ if (errno != 0 || *endptr!='\0' || endptr==arg) {
+ return 1;
+ }
+ errno = errno_save;
+ return 0;
+}
+#endif
+
diff --git a/busybox/libbb/safe_write.c b/busybox/libbb/safe_write.c
new file mode 100644
index 0000000..201ea1c
--- /dev/null
+++ b/busybox/libbb/safe_write.c
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+
+ssize_t safe_write(int fd, const void *buf, size_t count)
+{
+ ssize_t n;
+
+ do {
+ n = write(fd, buf, count);
+ } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/setup_environment.c b/busybox/libbb/setup_environment.c
new file mode 100644
index 0000000..aeb285a
--- /dev/null
+++ b/busybox/libbb/setup_environment.c
@@ -0,0 +1,93 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.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.
+ * 3. Neither the name of Julianne F. Haugh 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 JULIE HAUGH 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 JULIE HAUGH 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 <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <ctype.h>
+#include "libbb.h"
+
+
+
+#define DEFAULT_LOGIN_PATH "/bin:/usr/bin"
+#define DEFAULT_ROOT_LOGIN_PATH "/usr/sbin:/bin:/usr/bin:/sbin"
+
+static void xsetenv ( const char *key, const char *value )
+{
+ if ( setenv ( key, value, 1 ))
+ bb_error_msg_and_die (bb_msg_memory_exhausted);
+}
+
+void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw )
+{
+ if ( loginshell ) {
+ const char *term;
+
+ /* Change the current working directory to be the home directory
+ * of the user. It is a fatal error for this process to be unable
+ * to change to that directory. There is no "default" home
+ * directory.
+ * Some systems default to HOME=/
+ */
+ if ( chdir ( pw-> pw_dir )) {
+ if ( chdir ( "/" )) {
+ syslog ( LOG_WARNING, "unable to cd to %s' for user %s'\n", pw-> pw_dir, pw-> pw_name );
+ bb_error_msg_and_die ( "cannot cd to home directory or /" );
+ }
+ fputs ( "warning: cannot change to home directory\n", stderr );
+ }
+
+ /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
+ Unset all other environment variables. */
+ term = getenv ("TERM");
+ clearenv ( );
+ if ( term )
+ xsetenv ( "TERM", term );
+ xsetenv ( "HOME", pw-> pw_dir );
+ xsetenv ( "SHELL", shell );
+ xsetenv ( "USER", pw-> pw_name );
+ xsetenv ( "LOGNAME", pw-> pw_name );
+ xsetenv ( "PATH", ( pw-> pw_uid ? DEFAULT_LOGIN_PATH : DEFAULT_ROOT_LOGIN_PATH ));
+ }
+ else if ( changeenv ) {
+ /* Set HOME, SHELL, and if not becoming a super-user,
+ USER and LOGNAME. */
+ xsetenv ( "HOME", pw-> pw_dir );
+ xsetenv ( "SHELL", shell );
+ if ( pw-> pw_uid ) {
+ xsetenv ( "USER", pw-> pw_name );
+ xsetenv ( "LOGNAME", pw-> pw_name );
+ }
+ }
+}
+
diff --git a/busybox/libbb/simplify_path.c b/busybox/libbb/simplify_path.c
new file mode 100644
index 0000000..743133c
--- /dev/null
+++ b/busybox/libbb/simplify_path.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_simplify_path implementation for busybox
+ *
+ * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+#include "libbb.h"
+
+char *bb_simplify_path(const char *path)
+{
+ char *s, *start, *p;
+
+ if (path[0] == '/')
+ start = bb_xstrdup(path);
+ else {
+ s = xgetcwd(NULL);
+ start = concat_path_file(s, path);
+ free(s);
+ }
+ p = s = start;
+
+ do {
+ if (*p == '/') {
+ if (*s == '/') { /* skip duplicate (or initial) slash */
+ continue;
+ } else if (*s == '.') {
+ if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
+ continue;
+ } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
+ ++s;
+ if (p > start) {
+ while (*--p != '/'); /* omit previous dir */
+ }
+ continue;
+ }
+ }
+ }
+ *++p = *s;
+ } while (*++s);
+
+ if ((p == start) || (*p != '/')) { /* not a trailing slash */
+ ++p; /* so keep last character */
+ }
+ *p = 0;
+
+ return start;
+}
diff --git a/busybox/libbb/skip_whitespace.c b/busybox/libbb/skip_whitespace.c
new file mode 100644
index 0000000..bf049a2
--- /dev/null
+++ b/busybox/libbb/skip_whitespace.c
@@ -0,0 +1,33 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * skip_whitespace implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <ctype.h>
+#include "libbb.h"
+
+extern const char *bb_skip_whitespace(const char *s)
+{
+ while (isspace(*s)) {
+ ++s;
+ }
+
+ return s;
+}
diff --git a/busybox/libbb/speed_table.c b/busybox/libbb/speed_table.c
new file mode 100644
index 0000000..b04429e
--- /dev/null
+++ b/busybox/libbb/speed_table.c
@@ -0,0 +1,130 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * compact speed_t <-> speed functions for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <termios.h>
+#include "libbb.h"
+
+struct speed_map {
+ unsigned short speed;
+ unsigned short value;
+};
+
+static const struct speed_map speeds[] = {
+ {B0, 0},
+ {B50, 50},
+ {B75, 75},
+ {B110, 110},
+ {B134, 134},
+ {B150, 150},
+ {B200, 200},
+ {B300, 300},
+ {B600, 600},
+ {B1200, 1200},
+ {B1800, 1800},
+ {B2400, 2400},
+ {B4800, 4800},
+ {B9600, 9600},
+#ifdef B19200
+ {B19200, 19200},
+#elif defined(EXTA)
+ {EXTA, 19200},
+#endif
+#ifdef B38400
+ {B38400, 38400/256 + 0x8000U},
+#elif defined(EXTB)
+ {EXTB, 38400/256 + 0x8000U},
+#endif
+#ifdef B57600
+ {B57600, 57600/256 + 0x8000U},
+#endif
+#ifdef B115200
+ {B115200, 115200/256 + 0x8000U},
+#endif
+#ifdef B230400
+ {B230400, 230400/256 + 0x8000U},
+#endif
+#ifdef B460800
+ {B460800, 460800/256 + 0x8000U},
+#endif
+};
+
+static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
+
+unsigned long bb_baud_to_value(speed_t speed)
+{
+ int i = 0;
+
+ do {
+ if (speed == speeds[i].speed) {
+ if (speeds[i].value & 0x8000U) {
+ return ((unsigned long) (speeds[i].value) & 0x7fffU) * 256;
+ }
+ return speeds[i].value;
+ }
+ } while (++i < NUM_SPEEDS);
+
+ return 0;
+}
+
+speed_t bb_value_to_baud(unsigned long value)
+{
+ int i = 0;
+
+ do {
+ if (value == bb_baud_to_value(speeds[i].speed)) {
+ return speeds[i].speed;
+ }
+ } while (++i < NUM_SPEEDS);
+
+ return (speed_t) - 1;
+}
+
+#if 0
+/* testing code */
+#include <stdio.h>
+
+int main(void)
+{
+ unsigned long v;
+ speed_t s;
+
+ for (v = 0 ; v < 500000 ; v++) {
+ s = bb_value_to_baud(v);
+ if (s == (speed_t) -1) {
+ continue;
+ }
+ printf("v = %lu -- s = %0lo\n", v, (unsigned long) s);
+ }
+
+ printf("-------------------------------\n");
+
+ for (s = 0 ; s < 010017+1 ; s++) {
+ v = bb_baud_to_value(s);
+ if (!v) {
+ continue;
+ }
+ printf("v = %lu -- s = %0lo\n", v, (unsigned long) s);
+ }
+
+ return 0;
+}
+#endif
diff --git a/busybox/libbb/syscalls.c b/busybox/libbb/syscalls.c
new file mode 100644
index 0000000..9e89dbd
--- /dev/null
+++ b/busybox/libbb/syscalls.c
@@ -0,0 +1,105 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * some system calls possibly missing from libc
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+#include <sys/syscall.h>
+#include "libbb.h"
+
+int sysfs( int option, unsigned int fs_index, char * buf)
+{
+ return(syscall(__NR_sysfs, option, fs_index, buf));
+}
+
+int pivot_root(const char * new_root,const char * put_old)
+{
+#ifndef __NR_pivot_root
+#warning This kernel does not support the pivot_root syscall
+#warning -> The pivot_root system call is being stubbed out...
+ /* BusyBox was compiled against a kernel that did not support
+ * the pivot_root system call. To make this application work,
+ * you will need to recompile with a kernel supporting the
+ * pivot_root system call.
+ */
+ bb_error_msg("\n\nTo make this application work, you will need to recompile\n"
+ "BusyBox with a kernel supporting the pivot_root system call.\n");
+ errno=ENOSYS;
+ return -1;
+#else
+ return(syscall(__NR_pivot_root, new_root, put_old));
+#endif
+}
+
+
+
+/* These syscalls are not included in ancient glibc versions */
+#if ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1))
+
+int bdflush(int func, int data)
+{
+ return(syscall(__NR_bdflush, func, data));
+}
+
+#ifndef __alpha__
+# define __NR_klogctl __NR_syslog
+int klogctl(int type, char *b, int len)
+{
+ return(syscall(__NR_klogctl, type, b, len));
+}
+#endif
+
+
+int umount2(const char * special_file, int flags)
+{
+#ifndef __NR_pivot_root
+#warning This kernel does not support the umount2 syscall
+#warning -> The umount2 system call is being stubbed out...
+ /* BusyBox was compiled against a kernel that did not support
+ * the umount2 system call. To make this application work,
+ * you will need to recompile with a kernel supporting the
+ * umount2 system call.
+ */
+ bb_error_msg("\n\nTo make this application work, you will need to recompile\n"
+ "BusyBox with a kernel supporting the umount2 system call.\n");
+ errno=ENOSYS;
+ return -1;
+#else
+ return(syscall(__NR_umount2, special_file, flags));
+#endif
+}
+
+
+#endif
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/syslog_msg_with_name.c b/busybox/libbb/syslog_msg_with_name.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/busybox/libbb/syslog_msg_with_name.c
diff --git a/busybox/libbb/trim.c b/busybox/libbb/trim.c
new file mode 100644
index 0000000..38aa282
--- /dev/null
+++ b/busybox/libbb/trim.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "libbb.h"
+
+
+void trim(char *s)
+{
+ int len = strlen(s);
+
+ /* trim trailing whitespace */
+ while ( len > 0 && isspace(s[len-1]))
+ s[--len]='\0';
+
+ /* trim leading whitespace */
+ memmove(s, &s[strspn(s, " \n\r\t\v")], len);
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/u_signal_names.c b/busybox/libbb/u_signal_names.c
new file mode 100644
index 0000000..be444a9
--- /dev/null
+++ b/busybox/libbb/u_signal_names.c
@@ -0,0 +1,189 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <signal.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct signal_name {
+ const char *name;
+ int number;
+};
+
+static const struct signal_name signames[] = {
+ /* POSIX signals */
+ { "EXIT", 0 }, /* 0 */
+ { "HUP", SIGHUP }, /* 1 */
+ { "INT", SIGINT }, /* 2 */
+ { "QUIT", SIGQUIT }, /* 3 */
+ { "ILL", SIGILL }, /* 4 */
+ { "ABRT", SIGABRT }, /* 6 */
+ { "FPE", SIGFPE }, /* 8 */
+ { "KILL", SIGKILL }, /* 9 */
+ { "SEGV", SIGSEGV }, /* 11 */
+ { "PIPE", SIGPIPE }, /* 13 */
+ { "ALRM", SIGALRM }, /* 14 */
+ { "TERM", SIGTERM }, /* 15 */
+ { "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
+ { "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
+ { "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
+ { "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
+ { "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
+ { "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
+ { "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
+ { "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
+ /* Miscellaneous other signals */
+#ifdef SIGTRAP
+ { "TRAP", SIGTRAP }, /* 5 */
+#endif
+#ifdef SIGIOT
+ { "IOT", SIGIOT }, /* 6, same as SIGABRT */
+#endif
+#ifdef SIGEMT
+ { "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */
+#endif
+#ifdef SIGBUS
+ { "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
+#endif
+#ifdef SIGSYS
+ { "SYS", SIGSYS }, /* 12 (mips,alpha,sparc*) */
+#endif
+#ifdef SIGSTKFLT
+ { "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */
+#endif
+#ifdef SIGURG
+ { "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
+#endif
+#ifdef SIGIO
+ { "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
+#endif
+#ifdef SIGPOLL
+ { "POLL", SIGPOLL }, /* same as SIGIO */
+#endif
+#ifdef SIGCLD
+ { "CLD", SIGCLD }, /* same as SIGCHLD (mips) */
+#endif
+#ifdef SIGXCPU
+ { "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
+#endif
+#ifdef SIGXFSZ
+ { "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
+#endif
+#ifdef SIGVTALRM
+ { "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
+#endif
+#ifdef SIGPROF
+ { "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
+#endif
+#ifdef SIGPWR
+ { "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
+#endif
+#ifdef SIGINFO
+ { "INFO", SIGINFO }, /* 29 (alpha) */
+#endif
+#ifdef SIGLOST
+ { "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */
+#endif
+#ifdef SIGWINCH
+ { "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
+#endif
+#ifdef SIGUNUSED
+ { "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */
+#endif
+ {0, 0}
+};
+
+/*
+ if str_sig == NULL returned signal name [*signo],
+ if str_sig != NULL - set *signo from signal_name,
+ findings with digit number or with or without SIG-prefix name
+
+ if startnum=0 flag for support finding zero signal,
+ but str_sig="0" always found, (hmm - standart or realize?)
+ if startnum<0 returned reverse signal_number <-> signal_name
+ if found error - returned NULL
+
+*/
+
+const char *
+u_signal_names(const char *str_sig, int *signo, int startnum)
+{
+ static char retstr[16];
+ const struct signal_name *s = signames;
+ static const char prefix[] = "SIG";
+ const char *sptr;
+
+ if(startnum)
+ s++;
+ if(str_sig==NULL) {
+ while (s->name != 0) {
+ if(s->number == *signo)
+ break;
+ s++;
+ }
+ } else {
+ if (isdigit(((unsigned char)*str_sig))) {
+ char *endp;
+ long int sn = strtol(str_sig, &endp, 10);
+ /* test correct and overflow */
+ if(*endp == 0 && sn >= 0 && sn < NSIG) {
+ *signo = (int)sn;
+ /* test for unnamed */
+ sptr = u_signal_names(0, signo, 0);
+ if(sptr==NULL)
+ return NULL;
+ if(sn!=0)
+ sptr += 3;
+ return sptr;
+ }
+ } else {
+ sptr = str_sig;
+ while (s->name != 0) {
+ if (strcasecmp(s->name, sptr) == 0) {
+ *signo = s->number;
+ if(startnum<0) {
+ sprintf(retstr, "%d", *signo);
+ return retstr;
+ }
+ break;
+ }
+ if(s!=signames && sptr == str_sig &&
+ strncasecmp(sptr, prefix, 3) == 0) {
+ sptr += 3; /* strlen(prefix) */
+ continue;
+ }
+ sptr = str_sig;
+ s++;
+ }
+ }
+ }
+ if(s->name==0)
+ return NULL;
+ if(s!=signames)
+ strcpy(retstr, prefix);
+ else
+ retstr[0] = 0;
+ return strcat(retstr, s->name);
+}
diff --git a/busybox/libbb/vdprintf.c b/busybox/libbb/vdprintf.c
new file mode 100644
index 0000000..53fdbd3
--- /dev/null
+++ b/busybox/libbb/vdprintf.c
@@ -0,0 +1,47 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+
+#if (__GLIBC__ < 2)
+extern int vdprintf(int d, const char *format, va_list ap)
+{
+ char buf[BUF_SIZE];
+ int len;
+
+ len = vsprintf(buf, format, ap);
+ return write(d, buf, len);
+}
+#endif
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/verror_msg.c b/busybox/libbb/verror_msg.c
new file mode 100644
index 0000000..07b37e4
--- /dev/null
+++ b/busybox/libbb/verror_msg.c
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void bb_verror_msg(const char *s, va_list p)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s: ", bb_applet_name);
+ vfprintf(stderr, s, p);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/vfork_daemon_rexec.c b/busybox/libbb/vfork_daemon_rexec.c
new file mode 100644
index 0000000..80022b3
--- /dev/null
+++ b/busybox/libbb/vfork_daemon_rexec.c
@@ -0,0 +1,78 @@
+/*
+ * Rexec program for system have fork() as vfork() with foreground option
+ *
+ * Copyright (C) Vladimir N. Oleynik <dzo@simtreas.ru>
+ * Copyright (C) 2003 Russ Dill <Russ.Dill@asu.edu>
+ *
+ * daemon() portion taken from uClibc:
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Modified for uClibc by Erik Andersen <andersee@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <paths.h>
+#include "libbb.h"
+
+
+#if defined(__uClinux__)
+void vfork_daemon_rexec(int nochdir, int noclose,
+ int argc, char **argv, char *foreground_opt)
+{
+ int fd;
+ char **vfork_args;
+ int a = 0;
+
+ setsid();
+
+ if (!nochdir)
+ chdir("/");
+
+ if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ close(fd);
+ }
+
+ vfork_args = xcalloc(sizeof(char *), argc + 3);
+ vfork_args[a++] = "/bin/busybox";
+ while(*argv) {
+ vfork_args[a++] = *argv;
+ argv++;
+ }
+ vfork_args[a] = foreground_opt;
+ switch (vfork()) {
+ case 0: /* child */
+ /* Make certain we are not a session leader, or else we
+ * might reacquire a controlling terminal */
+ if (vfork())
+ _exit(0);
+ execv(vfork_args[0], vfork_args);
+ bb_perror_msg_and_die("execv %s", vfork_args[0]);
+ case -1: /* error */
+ bb_perror_msg_and_die("vfork");
+ default: /* parent */
+ exit(0);
+ }
+}
+#endif /* uClinux */
diff --git a/busybox/libbb/vherror_msg.c b/busybox/libbb/vherror_msg.c
new file mode 100644
index 0000000..1560eb5
--- /dev/null
+++ b/busybox/libbb/vherror_msg.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <netdb.h>
+#include <stdio.h>
+
+#include "libbb.h"
+
+
+extern void bb_vherror_msg(const char *s, va_list p)
+{
+ if(s == 0)
+ s = "";
+ bb_verror_msg(s, p);
+ if (*s)
+ fputs(": ", stderr);
+ herror("");
+}
diff --git a/busybox/libbb/vperror_msg.c b/busybox/libbb/vperror_msg.c
new file mode 100644
index 0000000..5c44696
--- /dev/null
+++ b/busybox/libbb/vperror_msg.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+extern void bb_vperror_msg(const char *s, va_list p)
+{
+ int err=errno;
+ if(s == 0) s = "";
+ bb_verror_msg(s, p);
+ if (*s) s = ": ";
+ fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/warn_ignoring_args.c b/busybox/libbb/warn_ignoring_args.c
new file mode 100644
index 0000000..a1fa528
--- /dev/null
+++ b/busybox/libbb/warn_ignoring_args.c
@@ -0,0 +1,30 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * warn_ignoring_args implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <libbb.h>
+
+extern void bb_warn_ignoring_args(int n)
+{
+ if (n) {
+ bb_perror_msg("ignoring all arguments");
+ }
+}
diff --git a/busybox/libbb/wfopen.c b/busybox/libbb/wfopen.c
new file mode 100644
index 0000000..ab77cb1
--- /dev/null
+++ b/busybox/libbb/wfopen.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "libbb.h"
+
+FILE *bb_wfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL) {
+ bb_perror_msg("%s", path);
+ errno = 0;
+ }
+ return fp;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/wfopen_input.c b/busybox/libbb/wfopen_input.c
new file mode 100644
index 0000000..bff6606
--- /dev/null
+++ b/busybox/libbb/wfopen_input.c
@@ -0,0 +1,54 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * wfopen_input implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* A number of applets need to open a file for reading, where the filename
+ * is a command line arg. Since often that arg is '-' (meaning stdin),
+ * we avoid testing everywhere by consolidating things in this routine.
+ *
+ * Note: We also consider "" to main stdin (for 'cmp' at least).
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <libbb.h>
+
+FILE *bb_wfopen_input(const char *filename)
+{
+ FILE *fp = stdin;
+
+ if ((filename != bb_msg_standard_input)
+ && filename[0] && ((filename[0] != '-') || filename[1])
+ ) {
+#if 0
+ /* This check shouldn't be necessary for linux, but is left
+ * here disabled just in case. */
+ struct stat stat_buf;
+ if (is_directory(filename, 1, &stat_buf)) {
+ bb_error_msg("%s: Is a directory", filename);
+ return NULL;
+ }
+#endif
+ fp = bb_wfopen(filename, "r");
+ }
+
+ return fp;
+}
diff --git a/busybox/libbb/xconnect.c b/busybox/libbb/xconnect.c
new file mode 100644
index 0000000..09a1daa
--- /dev/null
+++ b/busybox/libbb/xconnect.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Connect to host at port using address resolution from getaddrinfo
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "libbb.h"
+
+/* Return network byte ordered port number for a service.
+ * If "port" is a number use it as the port.
+ * If "port" is a name it is looked up in /etc/services, if it isnt found return
+ * default_port
+ */
+unsigned short bb_lookup_port(const char *port, const char *protocol, unsigned short default_port)
+{
+ unsigned short port_nr = htons(default_port);
+ if (port) {
+ char *endptr;
+ int old_errno;
+ long port_long;
+
+ /* Since this is a lib function, we're not allowed to reset errno to 0.
+ * Doing so could break an app that is deferring checking of errno. */
+ old_errno = errno;
+ errno = 0;
+ port_long = strtol(port, &endptr, 10);
+ if (errno != 0 || *endptr!='\0' || endptr==port || port_long < 0 || port_long > 65535) {
+ struct servent *tserv = getservbyname(port, protocol);
+ if (tserv) {
+ port_nr = tserv->s_port;
+ }
+ } else {
+ port_nr = htons(port_long);
+ }
+ errno = old_errno;
+ }
+ return port_nr;
+}
+
+void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
+{
+ struct hostent *he;
+
+ memset(s_in, 0, sizeof(struct sockaddr_in));
+ s_in->sin_family = AF_INET;
+ he = xgethostbyname(host);
+ memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
+}
+
+int xconnect(struct sockaddr_in *s_addr)
+{
+ int s = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(s, (struct sockaddr_in *)s_addr, sizeof(struct sockaddr_in)) < 0)
+ {
+ bb_perror_msg_and_die("Unable to connect to remote host (%s)",
+ inet_ntoa(s_addr->sin_addr));
+ }
+ return s;
+}
diff --git a/busybox/libbb/xfuncs.c b/busybox/libbb/xfuncs.c
new file mode 100644
index 0000000..01b2f87
--- /dev/null
+++ b/busybox/libbb/xfuncs.c
@@ -0,0 +1,197 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "libbb.h"
+
+
+#ifndef DMALLOC
+#ifdef L_xmalloc
+extern void *xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr == NULL && size != 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return ptr;
+}
+#endif
+
+#ifdef L_xrealloc
+extern void *xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL && size != 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return ptr;
+}
+#endif
+
+#ifdef L_xcalloc
+extern void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr = calloc(nmemb, size);
+ if (ptr == NULL && nmemb != 0 && size != 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return ptr;
+}
+#endif
+#endif /* DMALLOC */
+
+#ifdef L_xstrdup
+extern char * bb_xstrdup (const char *s) {
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+
+ t = strdup (s);
+
+ if (t == NULL)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+
+ return t;
+}
+#endif
+
+#ifdef L_xstrndup
+extern char * bb_xstrndup (const char *s, int n) {
+ char *t;
+
+ if (s == NULL)
+ bb_error_msg_and_die("bb_xstrndup bug");
+
+ t = xmalloc(++n);
+
+ return safe_strncpy(t,s,n);
+}
+#endif
+
+#ifdef L_xfopen
+FILE *bb_xfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL)
+ bb_perror_msg_and_die("%s", path);
+ return fp;
+}
+#endif
+
+#ifdef L_xopen
+extern int bb_xopen(const char *pathname, int flags)
+{
+ int ret;
+
+ ret = open(pathname, flags, 0777);
+ if (ret == -1) {
+ bb_perror_msg_and_die("%s", pathname);
+ }
+ return ret;
+}
+#endif
+
+#ifdef L_xread
+extern ssize_t bb_xread(int fd, void *buf, size_t count)
+{
+ ssize_t size;
+
+ size = read(fd, buf, count);
+ if (size == -1) {
+ bb_perror_msg_and_die("Read error");
+ }
+ return(size);
+}
+#endif
+
+#ifdef L_xread_all
+extern void bb_xread_all(int fd, void *buf, size_t count)
+{
+ ssize_t size;
+
+ while (count) {
+ if ((size = bb_xread(fd, buf, count)) == 0) { /* EOF */
+ bb_error_msg_and_die("Short read");
+ }
+ count -= size;
+ buf = ((char *) buf) + size;
+ }
+ return;
+}
+#endif
+
+#ifdef L_xread_char
+extern unsigned char bb_xread_char(int fd)
+{
+ char tmp;
+
+ bb_xread_all(fd, &tmp, 1);
+
+ return(tmp);
+}
+#endif
+
+#ifdef L_xferror
+extern void bb_xferror(FILE *fp, const char *fn)
+{
+ if (ferror(fp)) {
+ bb_error_msg_and_die("%s", fn);
+ }
+}
+#endif
+
+#ifdef L_xferror_stdout
+extern void bb_xferror_stdout(void)
+{
+ bb_xferror(stdout, bb_msg_standard_output);
+}
+#endif
+
+#ifdef L_xfflush_stdout
+extern void bb_xfflush_stdout(void)
+{
+ if (fflush(stdout)) {
+ bb_perror_msg_and_die(bb_msg_standard_output);
+ }
+}
+#endif
+
+#ifdef L_strlen
+/* Stupid gcc always includes its own builtin strlen()... */
+#undef strlen
+size_t bb_strlen(const char *string)
+{
+ return(strlen(string));
+}
+#endif
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox/libbb/xgetcwd.c b/busybox/libbb/xgetcwd.c
new file mode 100644
index 0000000..1fcdba1
--- /dev/null
+++ b/busybox/libbb/xgetcwd.c
@@ -0,0 +1,48 @@
+/*
+ * xgetcwd.c -- return current directory with unlimited length
+ * Copyright (C) 1992, 1996 Free Software Foundation, Inc.
+ * Written by David MacKenzie <djm@gnu.ai.mit.edu>.
+ *
+ * Special function for busybox written by Vladimir Oleynik <dzo@simtreas.ru>
+*/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/param.h>
+#include "libbb.h"
+
+/* Amount to increase buffer size by in each try. */
+#define PATH_INCR 32
+
+/* Return the current directory, newly allocated, arbitrarily long.
+ Return NULL and set errno on error.
+ If argument is not NULL (previous usage allocate memory), call free()
+*/
+
+char *
+xgetcwd (char *cwd)
+{
+ char *ret;
+ unsigned path_max;
+
+ path_max = (unsigned) PATH_MAX;
+ path_max += 2; /* The getcwd docs say to do this. */
+
+ if(cwd==0)
+ cwd = xmalloc (path_max);
+
+ while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) {
+ path_max += PATH_INCR;
+ cwd = xrealloc (cwd, path_max);
+ }
+
+ if (ret == NULL) {
+ free (cwd);
+ bb_perror_msg("getcwd()");
+ return NULL;
+ }
+
+ return cwd;
+}
diff --git a/busybox/libbb/xgethostbyname.c b/busybox/libbb/xgethostbyname.c
new file mode 100644
index 0000000..6b2dff7
--- /dev/null
+++ b/busybox/libbb/xgethostbyname.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini xgethostbyname implementation.
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <netdb.h>
+#include "libbb.h"
+
+
+struct hostent *xgethostbyname(const char *name)
+{
+ struct hostent *retval;
+
+ if ((retval = gethostbyname(name)) == NULL)
+ bb_herror_msg_and_die("%s", name);
+
+ return retval;
+}
diff --git a/busybox/libbb/xgethostbyname2.c b/busybox/libbb/xgethostbyname2.c
new file mode 100644
index 0000000..3a16ae4
--- /dev/null
+++ b/busybox/libbb/xgethostbyname2.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini xgethostbyname2 implementation.
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <netdb.h>
+#include "libbb.h"
+
+
+#ifdef CONFIG_FEATURE_IPV6
+struct hostent *xgethostbyname2(const char *name, int af)
+{
+ struct hostent *retval;
+
+ if ((retval = gethostbyname2(name, af)) == NULL)
+ bb_herror_msg_and_die("%s", name);
+
+ return retval;
+}
+#endif
diff --git a/busybox/libbb/xgetlarg.c b/busybox/libbb/xgetlarg.c
new file mode 100644
index 0000000..56fb60e
--- /dev/null
+++ b/busybox/libbb/xgetlarg.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003-2004 Erik Andersen <andersen@codepoet.org>
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "busybox.h"
+
+extern long bb_xgetlarg(const char *arg, int base, long lower, long upper)
+{
+ long result;
+ char *endptr;
+ int errno_save = errno;
+
+ assert(arg!=NULL);
+
+ /* Don't allow leading whitespace. */
+ if ((isspace)(*arg)) { /* Use an actual funciton call for minimal size. */
+ bb_show_usage();
+ }
+
+ errno = 0;
+ result = strtol(arg, &endptr, base);
+ if (errno != 0 || *endptr!='\0' || endptr==arg || result < lower || result > upper)
+ bb_show_usage();
+ errno = errno_save;
+ return result;
+}
diff --git a/busybox/libbb/xgetularg.c b/busybox/libbb/xgetularg.c
new file mode 100644
index 0000000..e900854
--- /dev/null
+++ b/busybox/libbb/xgetularg.c
@@ -0,0 +1,160 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * xgetularg* implementations for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include "libbb.h"
+
+#ifdef L_xgetularg_bnd_sfx
+extern
+unsigned long bb_xgetularg_bnd_sfx(const char *arg, int base,
+ unsigned long lower,
+ unsigned long upper,
+ const struct suffix_mult *suffixes)
+{
+ unsigned long r;
+ int old_errno;
+ char *e;
+
+ assert(arg);
+
+ /* Disallow '-' and any leading whitespace. Speed isn't critical here
+ * since we're parsing commandline args. So make sure we get the
+ * actual isspace function rather than a larger macro implementaion. */
+ if ((*arg == '-') || (isspace)(*arg)) {
+ bb_show_usage();
+ }
+
+ /* Since this is a lib function, we're not allowed to reset errno to 0.
+ * Doing so could break an app that is deferring checking of errno.
+ * So, save the old value so that we can restore it if successful. */
+ old_errno = errno;
+ errno = 0;
+ r = strtoul(arg, &e, base);
+ /* Do the initial validity check. Note: The standards do not
+ * guarantee that errno is set if no digits were found. So we
+ * must test for this explicitly. */
+ if (errno || (arg == e)) { /* error or no digits */
+ bb_show_usage();
+ }
+ errno = old_errno; /* Ok. So restore errno. */
+
+ /* Do optional suffix parsing. Allow 'empty' suffix tables.
+ * Note that we also all nul suffixes with associated multipliers,
+ * to allow for scaling of the arg by some default multiplier. */
+
+ if (suffixes) {
+ while (suffixes->suffix) {
+ if (strcmp(suffixes->suffix, e) == 0) {
+ if (ULONG_MAX / suffixes->mult < r) { /* Overflow! */
+ bb_show_usage();
+ }
+ ++e;
+ r *= suffixes->mult;
+ break;
+ }
+ ++suffixes;
+ }
+ }
+
+ /* Finally, check for illegal trailing chars and range limits. */
+ /* Note: although we allow leading space (via stroul), trailing space
+ * is an error. It would be easy enough to allow though if desired. */
+ if (*e || (r < lower) || (r > upper)) {
+ bb_show_usage();
+ }
+
+ return r;
+}
+#endif
+
+#ifdef L_xgetlarg_bnd_sfx
+extern
+long bb_xgetlarg_bnd_sfx(const char *arg, int base,
+ long lower,
+ long upper,
+ const struct suffix_mult *suffixes)
+{
+ unsigned long u = LONG_MAX;
+ long r;
+ const char *p = arg;
+
+ if ((*p == '-') && (p[1] != '+')) {
+ ++p;
+#if LONG_MAX == (-(LONG_MIN + 1))
+ ++u; /* two's complement */
+#endif
+ }
+
+ r = bb_xgetularg_bnd_sfx(p, base, 0, u, suffixes);
+
+ if (*arg == '-') {
+ r = -r;
+ }
+
+ if ((r < lower) || (r > upper)) {
+ bb_show_usage();
+ }
+
+ return r;
+}
+#endif
+
+#ifdef L_getlarg10_sfx
+extern
+long bb_xgetlarg10_sfx(const char *arg, const struct suffix_mult *suffixes)
+{
+ return bb_xgetlarg_bnd_sfx(arg, 10, LONG_MIN, LONG_MAX, suffixes);
+}
+#endif
+
+#ifdef L_xgetularg_bnd
+extern
+unsigned long bb_xgetularg_bnd(const char *arg, int base,
+ unsigned long lower,
+ unsigned long upper)
+{
+ return bb_xgetularg_bnd_sfx(arg, base, lower, upper, NULL);
+}
+#endif
+
+#ifdef L_xgetularg10_bnd
+extern
+unsigned long bb_xgetularg10_bnd(const char *arg,
+ unsigned long lower,
+ unsigned long upper)
+{
+ return bb_xgetularg_bnd(arg, 10, lower, upper);
+}
+#endif
+
+#ifdef L_xgetularg10
+extern
+unsigned long bb_xgetularg10(const char *arg)
+{
+ return bb_xgetularg10_bnd(arg, 0, ULONG_MAX);
+}
+#endif
diff --git a/busybox/libbb/xreadlink.c b/busybox/libbb/xreadlink.c
new file mode 100644
index 0000000..49823fa
--- /dev/null
+++ b/busybox/libbb/xreadlink.c
@@ -0,0 +1,37 @@
+/*
+ * xreadlink.c - safe implementation of readlink.
+ * Returns a NULL on failure...
+ */
+
+#include <stdio.h>
+
+/*
+ * NOTE: This function returns a malloced char* that you will have to free
+ * yourself. You have been warned.
+ */
+
+#include <unistd.h>
+#include "libbb.h"
+
+extern char *xreadlink(const char *path)
+{
+ static const int GROWBY = 80; /* how large we will grow strings by */
+
+ char *buf = NULL;
+ int bufsize = 0, readsize = 0;
+
+ do {
+ buf = xrealloc(buf, bufsize += GROWBY);
+ readsize = readlink(path, buf, bufsize); /* 1st try */
+ if (readsize == -1) {
+ bb_perror_msg("%s", path);
+ free(buf);
+ return NULL;
+ }
+ }
+ while (bufsize < readsize + 1);
+
+ buf[readsize] = '\0';
+
+ return buf;
+}
diff --git a/busybox/libbb/xregcomp.c b/busybox/libbb/xregcomp.c
new file mode 100644
index 0000000..fa6c0fa
--- /dev/null
+++ b/busybox/libbb/xregcomp.c
@@ -0,0 +1,49 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+#include <regex.h>
+
+
+
+void xregcomp(regex_t *preg, const char *regex, int cflags)
+{
+ int ret;
+ if ((ret = regcomp(preg, regex, cflags)) != 0) {
+ int errmsgsz = regerror(ret, preg, NULL, 0);
+ char *errmsg = xmalloc(errmsgsz);
+ regerror(ret, preg, errmsg, errmsgsz);
+ bb_error_msg_and_die("xregcomp: %s", errmsg);
+ }
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/