summaryrefslogtreecommitdiff
path: root/release/src/router/busybox/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/router/busybox/libbb')
-rw-r--r--release/src/router/busybox/libbb/Config.in154
-rw-r--r--release/src/router/busybox/libbb/Kbuild155
-rw-r--r--release/src/router/busybox/libbb/Makefile11
-rwxr-xr-xrelease/src/router/busybox/libbb/Makefile.in105
-rw-r--r--release/src/router/busybox/libbb/README20
-rw-r--r--release/src/router/busybox/libbb/appletlib.c783
-rw-r--r--release/src/router/busybox/libbb/arith.c263
-rw-r--r--release/src/router/busybox/libbb/ask_confirmation.c61
-rw-r--r--release/src/router/busybox/libbb/bb_askpass.c79
-rw-r--r--release/src/router/busybox/libbb/bb_asprintf.c22
-rw-r--r--release/src/router/busybox/libbb/bb_basename.c18
-rw-r--r--release/src/router/busybox/libbb/bb_do_delay.c22
-rw-r--r--release/src/router/busybox/libbb/bb_pwd.c112
-rw-r--r--release/src/router/busybox/libbb/bb_qsort.c20
-rw-r--r--release/src/router/busybox/libbb/bb_strtod.c86
-rw-r--r--release/src/router/busybox/libbb/bb_strtonum.c139
-rw-r--r--release/src/router/busybox/libbb/change_identity.c25
-rw-r--r--release/src/router/busybox/libbb/chomp.c44
-rw-r--r--release/src/router/busybox/libbb/compare_string_array.c85
-rw-r--r--release/src/router/busybox/libbb/concat_path_file.c27
-rw-r--r--release/src/router/busybox/libbb/concat_subpath_file.c21
-rw-r--r--release/src/router/busybox/libbb/copy_file.c436
-rw-r--r--release/src/router/busybox/libbb/copy_file_chunk.c74
-rw-r--r--release/src/router/busybox/libbb/copyfd.c136
-rw-r--r--release/src/router/busybox/libbb/correct_password.c72
-rw-r--r--release/src/router/busybox/libbb/crc32.c42
-rw-r--r--release/src/router/busybox/libbb/create_icmp6_socket.c31
-rw-r--r--release/src/router/busybox/libbb/create_icmp_socket.c31
-rw-r--r--release/src/router/busybox/libbb/daemon.c101
-rw-r--r--release/src/router/busybox/libbb/default_error_retval.c20
-rw-r--r--release/src/router/busybox/libbb/device_open.c45
-rw-r--r--release/src/router/busybox/libbb/die_if_bad_username.c36
-rw-r--r--release/src/router/busybox/libbb/dirname.c49
-rw-r--r--release/src/router/busybox/libbb/dump.c527
-rw-r--r--release/src/router/busybox/libbb/error_msg.c41
-rw-r--r--release/src/router/busybox/libbb/error_msg_and_die.c43
-rw-r--r--release/src/router/busybox/libbb/execable.c78
-rw-r--r--release/src/router/busybox/libbb/fclose_nonstdin.c32
-rw-r--r--release/src/router/busybox/libbb/fflush_stdout_and_exit.c32
-rw-r--r--release/src/router/busybox/libbb/fgets_str.c84
-rw-r--r--release/src/router/busybox/libbb/find_mount_point.c64
-rw-r--r--release/src/router/busybox/libbb/find_pid_by_name.c261
-rw-r--r--release/src/router/busybox/libbb/find_root_device.c116
-rw-r--r--release/src/router/busybox/libbb/full_read.c70
-rw-r--r--release/src/router/busybox/libbb/full_write.c56
-rw-r--r--release/src/router/busybox/libbb/get_console.c131
-rw-r--r--release/src/router/busybox/libbb/get_last_path_component.c87
-rw-r--r--release/src/router/busybox/libbb/get_line_from_file.c231
-rw-r--r--release/src/router/busybox/libbb/getopt32.c592
-rw-r--r--release/src/router/busybox/libbb/getopt_ulflags.c170
-rw-r--r--release/src/router/busybox/libbb/getpty.c64
-rw-r--r--release/src/router/busybox/libbb/gz_open.c35
-rw-r--r--release/src/router/busybox/libbb/herror_msg.c39
-rw-r--r--release/src/router/busybox/libbb/herror_msg_and_die.c41
-rw-r--r--release/src/router/busybox/libbb/human_readable.c71
-rw-r--r--release/src/router/busybox/libbb/inet_common.c204
-rw-r--r--release/src/router/busybox/libbb/info_msg.c56
-rw-r--r--release/src/router/busybox/libbb/inode_hash.c101
-rw-r--r--release/src/router/busybox/libbb/interface.c2113
-rw-r--r--release/src/router/busybox/libbb/isdirectory.c55
-rw-r--r--release/src/router/busybox/libbb/kernel_version.c47
-rw-r--r--release/src/router/busybox/libbb/last_char_is.c38
-rw-r--r--release/src/router/busybox/libbb/libbb.h325
-rw-r--r--release/src/router/busybox/libbb/libc5.c167
-rw-r--r--release/src/router/busybox/libbb/lineedit.c2006
-rw-r--r--release/src/router/busybox/libbb/lineedit_ptr_hack.c23
-rw-r--r--release/src/router/busybox/libbb/llist.c98
-rw-r--r--release/src/router/busybox/libbb/llist_add_to.c15
-rw-r--r--release/src/router/busybox/libbb/login.c185
-rw-r--r--release/src/router/busybox/libbb/loop.c230
-rw-r--r--release/src/router/busybox/libbb/make_directory.c123
-rw-r--r--release/src/router/busybox/libbb/makedev.c24
-rw-r--r--release/src/router/busybox/libbb/match_fstype.c42
-rw-r--r--release/src/router/busybox/libbb/md5.c429
-rw-r--r--release/src/router/busybox/libbb/md5prime.c460
-rw-r--r--release/src/router/busybox/libbb/messages.c116
-rwxr-xr-xrelease/src/router/busybox/libbb/mk_loop_h.sh37
-rw-r--r--release/src/router/busybox/libbb/mode_string.c166
-rw-r--r--release/src/router/busybox/libbb/module_syscalls.c88
-rw-r--r--release/src/router/busybox/libbb/mtab.c104
-rw-r--r--release/src/router/busybox/libbb/mtab_file.c49
-rw-r--r--release/src/router/busybox/libbb/my_getgrgid.c55
-rw-r--r--release/src/router/busybox/libbb/my_getgrnam.c56
-rw-r--r--release/src/router/busybox/libbb/my_getpwnam.c56
-rw-r--r--release/src/router/busybox/libbb/my_getpwnamegid.c61
-rw-r--r--release/src/router/busybox/libbb/my_getpwuid.c55
-rw-r--r--release/src/router/busybox/libbb/obscure.c359
-rw-r--r--release/src/router/busybox/libbb/parse_config.c219
-rw-r--r--release/src/router/busybox/libbb/parse_mode.c228
-rw-r--r--release/src/router/busybox/libbb/parse_number.c74
-rw-r--r--release/src/router/busybox/libbb/perror_msg.c44
-rw-r--r--release/src/router/busybox/libbb/perror_msg_and_die.c46
-rw-r--r--release/src/router/busybox/libbb/perror_nomsg.c30
-rw-r--r--release/src/router/busybox/libbb/perror_nomsg_and_die.c30
-rw-r--r--release/src/router/busybox/libbb/pidfile.c40
-rw-r--r--release/src/router/busybox/libbb/print_file.c61
-rw-r--r--release/src/router/busybox/libbb/print_flags.c32
-rw-r--r--release/src/router/busybox/libbb/printable.c34
-rw-r--r--release/src/router/busybox/libbb/printf.c177
-rw-r--r--release/src/router/busybox/libbb/process_escape_sequence.c109
-rw-r--r--release/src/router/busybox/libbb/procps.c558
-rw-r--r--release/src/router/busybox/libbb/ptr_to_globals.c35
-rw-r--r--release/src/router/busybox/libbb/pw_encrypt.c142
-rw-r--r--release/src/router/busybox/libbb/pw_encrypt_des.c820
-rw-r--r--release/src/router/busybox/libbb/pw_encrypt_md5.c161
-rw-r--r--release/src/router/busybox/libbb/pw_encrypt_sha.c286
-rw-r--r--release/src/router/busybox/libbb/pwd2spwd.c74
-rw-r--r--release/src/router/busybox/libbb/qmodule.c29
-rw-r--r--release/src/router/busybox/libbb/read.c394
-rw-r--r--release/src/router/busybox/libbb/read_key.c157
-rw-r--r--release/src/router/busybox/libbb/read_package_field.c91
-rw-r--r--release/src/router/busybox/libbb/real_loop.h37
-rw-r--r--release/src/router/busybox/libbb/recursive_action.c225
-rw-r--r--release/src/router/busybox/libbb/remove_file.c101
-rw-r--r--release/src/router/busybox/libbb/restricted_shell.c25
-rw-r--r--release/src/router/busybox/libbb/rtc.c90
-rw-r--r--release/src/router/busybox/libbb/run_parts.c125
-rw-r--r--release/src/router/busybox/libbb/run_shell.c81
-rw-r--r--release/src/router/busybox/libbb/safe_gethostname.c66
-rw-r--r--release/src/router/busybox/libbb/safe_poll.c34
-rw-r--r--release/src/router/busybox/libbb/safe_read.c54
-rw-r--r--release/src/router/busybox/libbb/safe_strncpy.c53
-rw-r--r--release/src/router/busybox/libbb/safe_write.c21
-rw-r--r--release/src/router/busybox/libbb/selinux_common.c56
-rw-r--r--release/src/router/busybox/libbb/setup_environment.c79
-rw-r--r--release/src/router/busybox/libbb/sha1.c465
-rw-r--r--release/src/router/busybox/libbb/signals.c121
-rw-r--r--release/src/router/busybox/libbb/simplify_path.c59
-rw-r--r--release/src/router/busybox/libbb/skip_whitespace.c32
-rw-r--r--release/src/router/busybox/libbb/speed_table.c32
-rw-r--r--release/src/router/busybox/libbb/str_tolower.c14
-rw-r--r--release/src/router/busybox/libbb/strrstr.c71
-rw-r--r--release/src/router/busybox/libbb/syscalls.c115
-rw-r--r--release/src/router/busybox/libbb/syslog_msg_with_name.c51
-rw-r--r--release/src/router/busybox/libbb/time.c66
-rw-r--r--release/src/router/busybox/libbb/time_string.c68
-rw-r--r--release/src/router/busybox/libbb/trim.c54
-rw-r--r--release/src/router/busybox/libbb/u_signal_names.c278
-rw-r--r--release/src/router/busybox/libbb/udp_io.c168
-rw-r--r--release/src/router/busybox/libbb/unarchive.c601
-rw-r--r--release/src/router/busybox/libbb/unzip.c1007
-rw-r--r--release/src/router/busybox/libbb/update_passwd.c266
-rw-r--r--release/src/router/busybox/libbb/uuencode.c71
-rw-r--r--release/src/router/busybox/libbb/vdprintf.c42
-rw-r--r--release/src/router/busybox/libbb/verror_msg.c150
-rw-r--r--release/src/router/busybox/libbb/vfork_daemon_rexec.c339
-rw-r--r--release/src/router/busybox/libbb/vherror_msg.c44
-rw-r--r--release/src/router/busybox/libbb/vperror_msg.c51
-rw-r--r--release/src/router/busybox/libbb/warn_ignoring_args.c23
-rw-r--r--release/src/router/busybox/libbb/wfopen.c60
-rw-r--r--release/src/router/busybox/libbb/wfopen_input.c60
-rw-r--r--release/src/router/busybox/libbb/write.c19
-rw-r--r--release/src/router/busybox/libbb/xatonum.c70
-rw-r--r--release/src/router/busybox/libbb/xatonum_template.c191
-rw-r--r--release/src/router/busybox/libbb/xconnect.c460
-rw-r--r--release/src/router/busybox/libbb/xfunc_die.c40
-rw-r--r--release/src/router/busybox/libbb/xfuncs.c353
-rw-r--r--release/src/router/busybox/libbb/xfuncs_printf.c548
-rw-r--r--release/src/router/busybox/libbb/xgetcwd.c65
-rw-r--r--release/src/router/busybox/libbb/xgethostbyname.c30
-rw-r--r--release/src/router/busybox/libbb/xgethostbyname2.c37
-rw-r--r--release/src/router/busybox/libbb/xgetlarg.c35
-rw-r--r--release/src/router/busybox/libbb/xgetularg.c160
-rw-r--r--release/src/router/busybox/libbb/xreadlink.c118
-rw-r--r--release/src/router/busybox/libbb/xrealloc_vector.c45
-rw-r--r--release/src/router/busybox/libbb/xregcomp.c53
166 files changed, 14918 insertions, 10665 deletions
diff --git a/release/src/router/busybox/libbb/Config.in b/release/src/router/busybox/libbb/Config.in
new file mode 100644
index 00000000..f5b804ff
--- /dev/null
+++ b/release/src/router/busybox/libbb/Config.in
@@ -0,0 +1,154 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Busybox Library Tuning"
+
+config PASSWORD_MINLEN
+ int "Minimum password length"
+ default 6
+ range 5 32
+ help
+ Minimum allowable password length.
+
+config MD5_SIZE_VS_SPEED
+ int "MD5: Trade Bytes for Speed"
+ default 2
+ range 0 3
+ help
+ Trade binary size versus speed for the md5sum algorithm.
+ Approximate values running uClibc and hashing
+ linux-2.4.4.tar.bz2 were:
+ user times (sec) text size (386)
+ 0 (fastest) 1.1 6144
+ 1 1.4 5392
+ 2 3.0 5088
+ 3 (smallest) 5.1 4912
+
+config FEATURE_FAST_TOP
+ bool "Faster /proc scanning code (+100 bytes)"
+ default n
+ help
+ This option makes top (and ps) ~20% faster (or 20% less CPU hungry),
+ but code size is slightly bigger.
+
+config FEATURE_ETC_NETWORKS
+ bool "Support for /etc/networks"
+ default n
+ help
+ Enable support for network names in /etc/networks. This is
+ a rarely used feature which allows you to use names
+ instead of IP/mask pairs in route command.
+
+config FEATURE_EDITING
+ bool "Command line editing"
+ default n
+ help
+ Enable line editing (mainly for shell command line).
+
+config FEATURE_EDITING_MAX_LEN
+ int "Maximum length of input"
+ range 128 8192
+ default 1024
+ depends on FEATURE_EDITING
+ help
+ Line editing code uses on-stack buffers for storage.
+ You may want to decrease this parameter if your target machine
+ benefits from smaller stack usage.
+
+config FEATURE_EDITING_VI
+ bool "vi-style line editing commands"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Enable vi-style line editing. In shells, this mode can be
+ turned on and off with "set -o vi" and "set +o vi".
+
+config FEATURE_EDITING_HISTORY
+ int "History size"
+ range 0 99999
+ default 15
+ depends on FEATURE_EDITING
+ help
+ Specify command history size.
+
+config FEATURE_EDITING_SAVEHISTORY
+ bool "History saving"
+ default n
+ depends on ASH && FEATURE_EDITING
+ help
+ Enable history saving in ash shell.
+
+config FEATURE_TAB_COMPLETION
+ bool "Tab completion"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Enable tab completion.
+
+config FEATURE_USERNAME_COMPLETION
+ bool "Username completion"
+ default n
+ depends on FEATURE_TAB_COMPLETION
+ help
+ Enable username completion.
+
+config FEATURE_EDITING_FANCY_PROMPT
+ bool "Fancy shell prompts"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Setting this option allows for prompts to use things like \w and
+ \$ and escape codes.
+
+config FEATURE_VERBOSE_CP_MESSAGE
+ bool "Give more precise messages when copy fails (cp, mv etc)"
+ default n
+ help
+ Error messages with this feature enabled:
+ $ cp file /does_not_exist/file
+ cp: cannot create '/does_not_exist/file': Path does not exist
+ $ cp file /vmlinuz/file
+ cp: cannot stat '/vmlinuz/file': Path has non-directory component
+ If this feature is not enabled, they will be, respectively:
+ cp: cannot remove '/does_not_exist/file': No such file or directory
+ cp: cannot stat '/vmlinuz/file': Not a directory
+ respectively.
+ This will cost you ~60 bytes.
+
+config FEATURE_COPYBUF_KB
+ int "Copy buffer size, in kilobytes"
+ range 1 1024
+ default 4
+ help
+ Size of buffer used by cp, mv, install etc.
+ Buffers which are 4 kb or less will be allocated on stack.
+ Bigger buffers will be allocated with mmap, with fallback to 4 kb
+ stack buffer if mmap fails.
+
+config MONOTONIC_SYSCALL
+ bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
+ default y
+ help
+ Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring
+ time intervals (time, ping, traceroute etc need this).
+ Probably requires Linux 2.6+. If not selected, gettimeofday
+ will be used instead (which gives wrong results if date/time
+ is reset).
+
+config IOCTL_HEX2STR_ERROR
+ bool "Use ioctl names rather than hex values in error messages"
+ default y
+ help
+ Use ioctl names rather than hex values in error messages
+ (e.g. VT_DISALLOCATE rather than 0x5608). If disabled this
+ saves about 1400 bytes.
+
+config FEATURE_HWIB
+ bool "Support infiniband HW"
+ default y
+ help
+ Support for printing infiniband addresses in
+ network applets.
+endmenu
diff --git a/release/src/router/busybox/libbb/Kbuild b/release/src/router/busybox/libbb/Kbuild
new file mode 100644
index 00000000..8fddabdb
--- /dev/null
+++ b/release/src/router/busybox/libbb/Kbuild
@@ -0,0 +1,155 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+
+lib-y += appletlib.o
+lib-y += ask_confirmation.o
+lib-y += bb_askpass.o
+lib-y += bb_basename.o
+lib-y += bb_do_delay.o
+lib-y += bb_pwd.o
+lib-y += bb_qsort.o
+lib-y += bb_strtod.o
+lib-y += bb_strtonum.o
+lib-y += change_identity.o
+lib-y += chomp.o
+lib-y += compare_string_array.o
+lib-y += concat_path_file.o
+lib-y += concat_subpath_file.o
+lib-y += copy_file.o
+lib-y += copyfd.o
+lib-y += crc32.o
+lib-y += create_icmp6_socket.o
+lib-y += create_icmp_socket.o
+lib-y += default_error_retval.o
+lib-y += device_open.o
+lib-y += dump.o
+lib-y += error_msg.o
+lib-y += error_msg_and_die.o
+lib-y += execable.o
+lib-y += fclose_nonstdin.o
+lib-y += fflush_stdout_and_exit.o
+lib-y += fgets_str.o
+lib-y += find_pid_by_name.o
+lib-y += find_root_device.o
+lib-y += full_write.o
+lib-y += get_console.o
+lib-y += get_last_path_component.o
+lib-y += get_line_from_file.o
+lib-y += getopt32.o
+lib-y += getpty.o
+lib-y += herror_msg.o
+lib-y += herror_msg_and_die.o
+lib-y += human_readable.o
+lib-y += inet_common.o
+lib-y += info_msg.o
+lib-y += inode_hash.o
+lib-y += isdirectory.o
+lib-y += kernel_version.o
+lib-y += last_char_is.o
+lib-y += lineedit.o lineedit_ptr_hack.o
+lib-y += llist.o
+lib-y += login.o
+lib-y += make_directory.o
+lib-y += makedev.o
+lib-y += match_fstype.o
+lib-y += md5.o
+# Alternative (disabled) implementation
+#lib-y += md5prime.o
+lib-y += messages.o
+lib-y += mode_string.o
+lib-y += mtab_file.o
+lib-y += obscure.o
+lib-y += parse_mode.o
+lib-y += parse_config.o
+lib-y += perror_msg.o
+lib-y += perror_msg_and_die.o
+lib-y += perror_nomsg.o
+lib-y += perror_nomsg_and_die.o
+lib-y += pidfile.o
+lib-y += printable.o
+lib-y += print_flags.o
+lib-y += process_escape_sequence.o
+lib-y += procps.o
+lib-y += ptr_to_globals.o
+lib-y += read.o
+lib-y += read_key.o
+lib-y += recursive_action.o
+lib-y += remove_file.o
+lib-y += restricted_shell.o
+lib-y += run_shell.o
+lib-y += safe_gethostname.o
+lib-y += safe_poll.o
+lib-y += safe_strncpy.o
+lib-y += safe_write.o
+lib-y += setup_environment.o
+lib-y += sha1.o
+lib-y += signals.o
+lib-y += simplify_path.o
+lib-y += skip_whitespace.o
+lib-y += speed_table.o
+lib-y += str_tolower.o
+lib-y += strrstr.o
+lib-y += time.o
+lib-y += trim.o
+lib-y += u_signal_names.o
+lib-y += udp_io.o
+lib-y += uuencode.o
+lib-y += vdprintf.o
+lib-y += verror_msg.o
+lib-y += vfork_daemon_rexec.o
+lib-y += warn_ignoring_args.o
+lib-y += wfopen.o
+lib-y += wfopen_input.o
+lib-y += write.o
+lib-y += xatonum.o
+lib-y += xconnect.o
+lib-y += xfuncs.o
+lib-y += xfuncs_printf.o
+lib-y += xfunc_die.o
+lib-y += xgetcwd.o
+lib-y += xgethostbyname.o
+lib-y += xreadlink.o
+lib-y += xrealloc_vector.o
+
+# conditionally compiled objects:
+lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o
+lib-$(CONFIG_LOSETUP) += loop.o
+lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
+lib-$(CONFIG_ADDGROUP) += update_passwd.o
+lib-$(CONFIG_ADDUSER) += update_passwd.o
+lib-$(CONFIG_DELGROUP) += update_passwd.o
+lib-$(CONFIG_DELUSER) += update_passwd.o
+lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o
+lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o
+lib-$(CONFIG_CRYPTPW) += pw_encrypt.o
+lib-$(CONFIG_SULOGIN) += pw_encrypt.o
+lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o
+lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o
+lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o
+lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o
+lib-$(CONFIG_DF) += find_mount_point.o
+lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o
+lib-$(CONFIG_SELINUX) += selinux_common.o
+lib-$(CONFIG_HWCLOCK) += rtc.o
+lib-$(CONFIG_RTCWAKE) += rtc.o
+lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
+
+# We shouldn't build xregcomp.c if we don't need it - this ensures we don't
+# require regex.h to be in the include dir even if we don't need it thereby
+# allowing us to build busybox even if uclibc regex support is disabled.
+
+lib-$(CONFIG_AWK) += xregcomp.o
+lib-$(CONFIG_SED) += xregcomp.o
+lib-$(CONFIG_GREP) += xregcomp.o
+lib-$(CONFIG_EXPR) += xregcomp.o
+lib-$(CONFIG_MDEV) += xregcomp.o
+lib-$(CONFIG_LESS) += xregcomp.o
+lib-$(CONFIG_PGREP) += xregcomp.o
+lib-$(CONFIG_PKILL) += xregcomp.o
+lib-$(CONFIG_DEVFSD) += xregcomp.o
+lib-$(CONFIG_FEATURE_FIND_REGEX) += xregcomp.o
diff --git a/release/src/router/busybox/libbb/Makefile b/release/src/router/busybox/libbb/Makefile
deleted file mode 100644
index a9ea7694..00000000
--- a/release/src/router/busybox/libbb/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Silly wrapper makefile. This Makefile is _not_ used by the build system for
-# busybox, it is just to make working on libbb more conveinient.
-# -Erik Andersen
-
-all:
- make -C .. libbb.a
-
-clean:
- - rm -rf libbb.a
- - find -name \*.o -exec rm -f {} \;
-
diff --git a/release/src/router/busybox/libbb/Makefile.in b/release/src/router/busybox/libbb/Makefile.in
deleted file mode 100755
index b60adc95..00000000
--- a/release/src/router/busybox/libbb/Makefile.in
+++ /dev/null
@@ -1,105 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 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:=$(TOPDIR)libbb/
-endif
-
-LIBBB_SRC:= \
- arith.c 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_console.c \
- get_last_path_component.c get_line_from_file.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_getpwnamegid.c my_getpwuid.c obscure.c parse_mode.c \
- parse_number.c perror_msg.c perror_msg_and_die.c print_file.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_strncpy.c \
- setup_environment.c simplify_path.c syscalls.c syslog_msg_with_name.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 \
- \
- 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 \
- warn_ignoring_args.c concat_subpath_file.c vfork_daemon_rexec.c
-
-LIBBB_OBJS=$(patsubst %.c,$(LIBBB_DIR)%.o, $(LIBBB_SRC))
-
-LIBBB_MSRC0:=$(LIBBB_DIR)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
-
-LIBBB_MSRC1:=$(LIBBB_DIR)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:=$(LIBBB_DIR)printf.c
-LIBBB_MOBJ2:=bb_vfprintf.o bb_vprintf.o bb_fprintf.o bb_printf.o
-
-LIBBB_MSRC3:=$(LIBBB_DIR)xgetularg.c
-LIBBB_MOBJ3:=xgetularg_bnd_sfx.o xgetlarg_bnd_sfx.o getlarg10_sfx.o \
- xgetularg_bnd.o xgetularg10_bnd.o xgetularg10.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))
-
-libraries-y+=$(LIBBB_DIR)$(LIBBB_AR)
-
-$(LIBBB_DIR)$(LIBBB_AR): $(LIBBB_OBJS) $(LIBBB_MOBJS0) $(LIBBB_MOBJS1) \
- $(LIBBB_MOBJS2) $(LIBBB_MOBJS3)
- $(AR) -ro $@ $(LIBBB_OBJS) $(LIBBB_MOBJS0) $(LIBBB_MOBJS1) \
- $(LIBBB_MOBJS2) $(LIBBB_MOBJS3)
-
-$(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_DIR)loop.o: $(LIBBB_DIR)loop.h
-
-$(LIBBB_DIR)loop.h: $(LIBBB_DIR)mk_loop_h.sh
- @ $(SHELL) $< > $@
-
-
diff --git a/release/src/router/busybox/libbb/README b/release/src/router/busybox/libbb/README
index 0e36f84b..4f28f7e3 100644
--- a/release/src/router/busybox/libbb/README
+++ b/release/src/router/busybox/libbb/README
@@ -1,15 +1,11 @@
-Please see the LICENSE file for copyright information.
-
-libbb is BusyBox's utility library. This all used to be in a single file
-(utility.c to be specific). When I split utility.c up to create libbb, I did
-not carefully fix up the copyright and licensing information. I'll do that for
-the next release.
+Please see the LICENSE file for copyright information (GPLv2)
-For now, justtrust me that a bunch of people have worked on this stuff,
-and it is all GPL'ed.
+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@lineo.com>
- <andersee@debian.org>
- <andersee@codepoet.org>
+ Erik Andersen
+ <andersen@codepoet.org>
diff --git a/release/src/router/busybox/libbb/appletlib.c b/release/src/router/busybox/libbb/appletlib.c
new file mode 100644
index 00000000..80380ae0
--- /dev/null
+++ b/release/src/router/busybox/libbb/appletlib.c
@@ -0,0 +1,783 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) tons of folks. Tracking down who wrote what
+ * isn't something I'm going to worry about... If you wrote something
+ * here, please feel free to acknowledge your work.
+ *
+ * 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.
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+/* We are trying to not use printf, this benefits the case when selected
+ * applets are really simple. Example:
+ *
+ * $ ./busybox
+ * ...
+ * Currently defined functions:
+ * basename, false, true
+ *
+ * $ size busybox
+ * text data bss dec hex filename
+ * 4473 52 72 4597 11f5 busybox
+ *
+ * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :(
+ */
+
+#include <assert.h>
+#include "busybox.h"
+
+
+/* Declare <applet>_main() */
+#define PROTOTYPES
+#include "applets.h"
+#undef PROTOTYPES
+
+#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
+/* Define usage_messages[] */
+static const char usage_messages[] ALIGN1 = ""
+#define MAKE_USAGE
+#include "usage.h"
+#include "applets.h"
+;
+#undef MAKE_USAGE
+#else
+#define usage_messages 0
+#endif /* SHOW_USAGE */
+
+
+/* Include generated applet names, pointers to <applet>_main, etc */
+#include "applet_tables.h"
+/* ...and if applet_tables generator says we have only one applet... */
+#ifdef SINGLE_APPLET_MAIN
+#undef ENABLE_FEATURE_INDIVIDUAL
+#define ENABLE_FEATURE_INDIVIDUAL 1
+#undef USE_FEATURE_INDIVIDUAL
+#define USE_FEATURE_INDIVIDUAL(...) __VA_ARGS__
+#endif
+
+
+#if ENABLE_FEATURE_COMPRESS_USAGE
+
+#include "usage_compressed.h"
+#include "unarchive.h"
+
+static const char *unpack_usage_messages(void)
+{
+ char *outbuf = NULL;
+ bunzip_data *bd;
+ int i;
+
+ i = start_bunzip(&bd,
+ /* src_fd: */ -1,
+//FIXME: can avoid storing these 2 bytes!
+ /* inbuf: */ (void *)packed_usage + 2,
+ /* len: */ sizeof(packed_usage));
+ /* read_bunzip can longjmp to start_bunzip, and ultimately
+ * end up here with i != 0 on read data errors! Not trivial */
+ if (!i) {
+ /* Cannot use xmalloc: will leak bd in NOFORK case! */
+ outbuf = malloc_or_warn(SIZEOF_usage_messages);
+ if (outbuf)
+ read_bunzip(bd, outbuf, SIZEOF_usage_messages);
+ }
+ dealloc_bunzip(bd);
+ return outbuf;
+}
+#define dealloc_usage_messages(s) free(s)
+
+#else
+
+#define unpack_usage_messages() usage_messages
+#define dealloc_usage_messages(s) ((void)(s))
+
+#endif /* FEATURE_COMPRESS_USAGE */
+
+
+static void full_write2_str(const char *str)
+{
+ xwrite_str(STDERR_FILENO, str);
+}
+
+void FAST_FUNC bb_show_usage(void)
+{
+ if (ENABLE_SHOW_USAGE) {
+#ifdef SINGLE_APPLET_STR
+ /* Imagine that this applet is "true". Dont suck in printf! */
+ const char *p;
+ const char *usage_string = p = unpack_usage_messages();
+
+ if (*p == '\b') {
+ full_write2_str("No help available.\n\n");
+ } else {
+ full_write2_str("Usage: "SINGLE_APPLET_STR" ");
+ full_write2_str(p);
+ full_write2_str("\n\n");
+ }
+ dealloc_usage_messages((char*)usage_string);
+#else
+ const char *p;
+ const char *usage_string = p = unpack_usage_messages();
+ int ap = find_applet_by_name(applet_name);
+
+ if (ap < 0) /* never happens, paranoia */
+ xfunc_die();
+ while (ap) {
+ while (*p++) continue;
+ ap--;
+ }
+ full_write2_str(bb_banner);
+ full_write2_str(" multi-call binary\n");
+ if (*p == '\b')
+ full_write2_str("\nNo help available.\n\n");
+ else {
+ full_write2_str("\nUsage: ");
+ full_write2_str(applet_name);
+ full_write2_str(" ");
+ full_write2_str(p);
+ full_write2_str("\n\n");
+ }
+ dealloc_usage_messages((char*)usage_string);
+#endif
+ }
+ xfunc_die();
+}
+
+#if NUM_APPLETS > 8
+/* NB: any char pointer will work as well, not necessarily applet_names */
+static int applet_name_compare(const void *name, const void *v)
+{
+ int i = (const char *)v - applet_names;
+ return strcmp(name, APPLET_NAME(i));
+}
+#endif
+int FAST_FUNC find_applet_by_name(const char *name)
+{
+#if NUM_APPLETS > 8
+ /* Do a binary search to find the applet entry given the name. */
+ const char *p;
+ p = bsearch(name, applet_names, ARRAY_SIZE(applet_main), 1, applet_name_compare);
+ if (!p)
+ return -1;
+ return p - applet_names;
+#else
+ /* A version which does not pull in bsearch */
+ int i = 0;
+ const char *p = applet_names;
+ while (i < NUM_APPLETS) {
+ if (strcmp(name, p) == 0)
+ return i;
+ p += strlen(p) + 1;
+ i++;
+ }
+ return -1;
+#endif
+}
+
+
+void lbb_prepare(const char *applet
+ USE_FEATURE_INDIVIDUAL(, char **argv))
+ MAIN_EXTERNALLY_VISIBLE;
+void lbb_prepare(const char *applet
+ USE_FEATURE_INDIVIDUAL(, char **argv))
+{
+#ifdef __GLIBC__
+ (*(int **)&bb_errno) = __errno_location();
+ barrier();
+#endif
+ applet_name = applet;
+
+ /* Set locale for everybody except 'init' */
+ if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
+ setlocale(LC_ALL, "");
+
+#if ENABLE_FEATURE_INDIVIDUAL
+ /* Redundant for busybox (run_applet_and_exit covers that case)
+ * but needed for "individual applet" mode */
+ if (argv[1] && !argv[2] && strcmp(argv[1], "--help") == 0) {
+ /* Special case. POSIX says "test --help"
+ * should be no different from e.g. "test --foo". */
+ if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
+ bb_show_usage();
+ }
+#endif
+}
+
+/* The code below can well be in applets/applets.c, as it is used only
+ * for busybox binary, not "individual" binaries.
+ * However, keeping it here and linking it into libbusybox.so
+ * (together with remaining tiny applets/applets.o)
+ * makes it possible to avoid --whole-archive at link time.
+ * This makes (shared busybox) + libbusybox smaller.
+ * (--gc-sections would be even better....)
+ */
+
+const char *applet_name;
+#if !BB_MMU
+bool re_execed;
+#endif
+
+
+/* If not built as a single-applet executable... */
+#if !defined(SINGLE_APPLET_MAIN)
+
+USE_FEATURE_SUID(static uid_t ruid;) /* real uid */
+
+#if ENABLE_FEATURE_SUID_CONFIG
+
+/* applets[] is const, so we have to define this "override" structure */
+static struct BB_suid_config {
+ int m_applet;
+ uid_t m_uid;
+ gid_t m_gid;
+ mode_t m_mode;
+ struct BB_suid_config *m_next;
+} *suid_config;
+
+static bool suid_cfg_readable;
+
+/* check if u is member of group g */
+static int ingroup(uid_t u, gid_t g)
+{
+ struct group *grp = getgrgid(g);
+
+ if (grp) {
+ char **mem;
+
+ for (mem = grp->gr_mem; *mem; mem++) {
+ struct passwd *pwd = getpwnam(*mem);
+
+ if (pwd && (pwd->pw_uid == u))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* This should probably be a libbb routine. In that case,
+ * I'd probably rename it to something like bb_trimmed_slice.
+ */
+static char *get_trimmed_slice(char *s, char *e)
+{
+ /* First, consider the value at e to be nul and back up until we
+ * reach a non-space char. Set the char after that (possibly at
+ * the original e) to nul. */
+ while (e-- > s) {
+ if (!isspace(*e)) {
+ break;
+ }
+ }
+ e[1] = '\0';
+
+ /* Next, advance past all leading space and return a ptr to the
+ * first non-space char; possibly the terminating nul. */
+ return skip_whitespace(s);
+}
+
+/* Don't depend on the tools to combine strings. */
+static const char config_file[] ALIGN1 = "/etc/busybox.conf";
+
+/* We don't supply a value for the nul, so an index adjustment is
+ * necessary below. Also, we use unsigned short here to save some
+ * space even though these are really mode_t values. */
+static const unsigned short mode_mask[] ALIGN2 = {
+ /* SST sst xxx --- */
+ S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */
+ S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */
+ 0, S_IXOTH, S_IXOTH, 0 /* other */
+};
+
+#define parse_error(x) do { errmsg = x; goto pe_label; } while (0)
+
+static void parse_config_file(void)
+{
+ struct BB_suid_config *sct_head;
+ struct BB_suid_config *sct;
+ int applet_no;
+ FILE *f;
+ const char *errmsg;
+ char *s;
+ char *e;
+ int i;
+ unsigned lc;
+ smallint section;
+ char buffer[256];
+ struct stat st;
+
+ assert(!suid_config); /* Should be set to NULL by bss init. */
+
+ ruid = getuid();
+ if (ruid == 0) /* run by root - don't need to even read config file */
+ return;
+
+ if ((stat(config_file, &st) != 0) /* No config file? */
+ || !S_ISREG(st.st_mode) /* Not a regular file? */
+ || (st.st_uid != 0) /* Not owned by root? */
+ || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */
+ || !(f = fopen_for_read(config_file)) /* Cannot open? */
+ ) {
+ return;
+ }
+
+ suid_cfg_readable = 1;
+ sct_head = NULL;
+ section = lc = 0;
+
+ while (1) {
+ s = buffer;
+
+ if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */
+// why?
+ if (ferror(f)) { /* Make sure it wasn't a read error. */
+ parse_error("reading");
+ }
+ fclose(f);
+ suid_config = sct_head; /* Success, so set the pointer. */
+ return;
+ }
+
+ lc++; /* Got a (partial) line. */
+
+ /* If a line is too long for our buffer, we consider it an error.
+ * The following test does mistreat one corner case though.
+ * If the final line of the file does not end with a newline and
+ * yet exactly fills the buffer, it will be treated as too long
+ * even though there isn't really a problem. But it isn't really
+ * worth adding code to deal with such an unlikely situation, and
+ * we do err on the side of caution. Besides, the line would be
+ * too long if it did end with a newline. */
+ if (!strchr(s, '\n') && !feof(f)) {
+ parse_error("line too long");
+ }
+
+ /* Trim leading and trailing whitespace, ignoring comments, and
+ * check if the resulting string is empty. */
+ s = get_trimmed_slice(s, strchrnul(s, '#'));
+ if (!*s) {
+ continue;
+ }
+
+ /* Check for a section header. */
+
+ if (*s == '[') {
+ /* Unlike the old code, we ignore leading and trailing
+ * whitespace for the section name. We also require that
+ * there are no stray characters after the closing bracket. */
+ e = strchr(s, ']');
+ if (!e /* Missing right bracket? */
+ || e[1] /* Trailing characters? */
+ || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
+ ) {
+ parse_error("section header");
+ }
+ /* Right now we only have one section so just check it.
+ * If more sections are added in the future, please don't
+ * resort to cascading ifs with multiple strcasecmp calls.
+ * That kind of bloated code is all too common. A loop
+ * and a string table would be a better choice unless the
+ * number of sections is very small. */
+ if (strcasecmp(s, "SUID") == 0) {
+ section = 1;
+ continue;
+ }
+ section = -1; /* Unknown section so set to skip. */
+ continue;
+ }
+
+ /* Process sections. */
+
+ if (section == 1) { /* SUID */
+ /* Since we trimmed leading and trailing space above, we're
+ * now looking for strings of the form
+ * <key>[::space::]*=[::space::]*<value>
+ * where both key and value could contain inner whitespace. */
+
+ /* First get the key (an applet name in our case). */
+ e = strchr(s, '=');
+ if (e) {
+ s = get_trimmed_slice(s, e);
+ }
+ if (!e || !*s) { /* Missing '=' or empty key. */
+ parse_error("keyword");
+ }
+
+ /* Ok, we have an applet name. Process the rhs if this
+ * applet is currently built in and ignore it otherwise.
+ * Note: this can hide config file bugs which only pop
+ * up when the busybox configuration is changed. */
+ applet_no = find_applet_by_name(s);
+ if (applet_no >= 0) {
+ /* Note: We currently don't check for duplicates!
+ * The last config line for each applet will be the
+ * one used since we insert at the head of the list.
+ * I suppose this could be considered a feature. */
+ sct = xmalloc(sizeof(struct BB_suid_config));
+ sct->m_applet = applet_no;
+ sct->m_mode = 0;
+ sct->m_next = sct_head;
+ sct_head = sct;
+
+ /* Get the specified mode. */
+
+ e = skip_whitespace(e+1);
+
+ for (i = 0; i < 3; i++) {
+ /* There are 4 chars + 1 nul for each of user/group/other. */
+ static const char mode_chars[] ALIGN1 = "Ssx-\0" "Ssx-\0" "Ttx-";
+
+ const char *q;
+ q = strchrnul(mode_chars + 5*i, *e++);
+ if (!*q) {
+ parse_error("mode");
+ }
+ /* Adjust by -i to account for nul. */
+ sct->m_mode |= mode_mask[(q - mode_chars) - i];
+ }
+
+ /* Now get the the user/group info. */
+
+ s = skip_whitespace(e);
+
+ /* Note: we require whitespace between the mode and the
+ * user/group info. */
+ if ((s == e) || !(e = strchr(s, '.'))) {
+ parse_error("<uid>.<gid>");
+ }
+ *e++ = '\0';
+
+ /* We can't use get_ug_id here since it would exit()
+ * if a uid or gid was not found. Oh well... */
+ sct->m_uid = bb_strtoul(s, NULL, 10);
+ if (errno) {
+ struct passwd *pwd = getpwnam(s);
+ if (!pwd) {
+ parse_error("user");
+ }
+ sct->m_uid = pwd->pw_uid;
+ }
+
+ sct->m_gid = bb_strtoul(e, NULL, 10);
+ if (errno) {
+ struct group *grp;
+ grp = getgrnam(e);
+ if (!grp) {
+ parse_error("group");
+ }
+ sct->m_gid = grp->gr_gid;
+ }
+ }
+ continue;
+ }
+
+ /* Unknown sections are ignored. */
+
+ /* Encountering configuration lines prior to seeing a
+ * section header is treated as an error. This is how
+ * the old code worked, but it may not be desirable.
+ * We may want to simply ignore such lines in case they
+ * are used in some future version of busybox. */
+ if (!section) {
+ parse_error("keyword outside section");
+ }
+
+ } /* while (1) */
+
+ pe_label:
+ fprintf(stderr, "Parse error in %s, line %d: %s\n",
+ config_file, lc, errmsg);
+
+ fclose(f);
+ /* Release any allocated memory before returning. */
+ while (sct_head) {
+ sct = sct_head->m_next;
+ free(sct_head);
+ sct_head = sct;
+ }
+}
+#else
+static inline void parse_config_file(void)
+{
+ USE_FEATURE_SUID(ruid = getuid();)
+}
+#endif /* FEATURE_SUID_CONFIG */
+
+
+#if ENABLE_FEATURE_SUID
+static void check_suid(int applet_no)
+{
+ gid_t rgid; /* real gid */
+
+ if (ruid == 0) /* set by parse_config_file() */
+ return; /* run by root - no need to check more */
+ rgid = getgid();
+
+#if ENABLE_FEATURE_SUID_CONFIG
+ if (suid_cfg_readable) {
+ uid_t uid;
+ struct BB_suid_config *sct;
+ mode_t m;
+
+ for (sct = suid_config; sct; sct = sct->m_next) {
+ if (sct->m_applet == applet_no)
+ goto found;
+ }
+ goto check_need_suid;
+ found:
+ m = sct->m_mode;
+ if (sct->m_uid == ruid)
+ /* same uid */
+ m >>= 6;
+ else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid))
+ /* same group / in group */
+ m >>= 3;
+
+ if (!(m & S_IXOTH)) /* is x bit not set ? */
+ bb_error_msg_and_die("you have no permission to run this applet!");
+
+ /* _both_ sgid and group_exec have to be set for setegid */
+ if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
+ rgid = sct->m_gid;
+ /* else (no setegid) we will set egid = rgid */
+
+ /* We set effective AND saved ids. If saved-id is not set
+ * like we do below, seteiud(0) can still later succeed! */
+ if (setresgid(-1, rgid, rgid))
+ bb_perror_msg_and_die("setresgid");
+
+ /* do we have to set effective uid? */
+ uid = ruid;
+ if (sct->m_mode & S_ISUID)
+ uid = sct->m_uid;
+ /* else (no seteuid) we will set euid = ruid */
+
+ if (setresuid(-1, uid, uid))
+ bb_perror_msg_and_die("setresuid");
+ return;
+ }
+#if !ENABLE_FEATURE_SUID_CONFIG_QUIET
+ {
+ static bool onetime = 0;
+
+ if (!onetime) {
+ onetime = 1;
+ fprintf(stderr, "Using fallback suid method\n");
+ }
+ }
+#endif
+ check_need_suid:
+#endif
+ if (APPLET_SUID(applet_no) == _BB_SUID_ALWAYS) {
+ /* Real uid is not 0. If euid isn't 0 too, suid bit
+ * is most probably not set on our executable */
+ if (geteuid())
+ bb_error_msg_and_die("must be suid to work properly");
+ } else if (APPLET_SUID(applet_no) == _BB_SUID_NEVER) {
+ xsetgid(rgid); /* drop all privileges */
+ xsetuid(ruid);
+ }
+}
+#else
+#define check_suid(x) ((void)0)
+#endif /* FEATURE_SUID */
+
+
+#if ENABLE_FEATURE_INSTALLER
+/* create (sym)links for each applet */
+static void install_links(const char *busybox, int use_symbolic_links)
+{
+ /* directory table
+ * this should be consistent w/ the enum,
+ * busybox.h::bb_install_loc_t, or else... */
+ static const char usr_bin [] ALIGN1 = "/usr/bin";
+ static const char usr_sbin[] ALIGN1 = "/usr/sbin";
+ static const char *const install_dir[] = {
+ &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */
+ &usr_bin [4], /* "/bin" */
+ &usr_sbin[4], /* "/sbin" */
+ usr_bin,
+ usr_sbin
+ };
+
+ int (*lf)(const char *, const char *);
+ char *fpc;
+ unsigned i;
+ int rc;
+
+ lf = link;
+ if (use_symbolic_links)
+ lf = symlink;
+
+ for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
+ fpc = concat_path_file(
+ install_dir[APPLET_INSTALL_LOC(i)],
+ APPLET_NAME(i));
+ // debug: bb_error_msg("%slinking %s to busybox",
+ // use_symbolic_links ? "sym" : "", fpc);
+ rc = lf(busybox, fpc);
+ if (rc != 0 && errno != EEXIST) {
+ bb_simple_perror_msg(fpc);
+ }
+ free(fpc);
+ }
+}
+#else
+#define install_links(x,y) ((void)0)
+#endif /* FEATURE_INSTALLER */
+
+/* If we were called as "busybox..." */
+static int busybox_main(char **argv)
+{
+ if (!argv[1]) {
+ /* Called without arguments */
+ const char *a;
+ unsigned col, output_width;
+ help:
+ output_width = 80;
+ if (ENABLE_FEATURE_AUTOWIDTH) {
+ /* Obtain the terminal width */
+ get_terminal_width_height(0, &output_width, NULL);
+ }
+ /* leading tab and room to wrap */
+ output_width -= MAX_APPLET_NAME_LEN + 8;
+
+ dup2(1, 2);
+ full_write2_str(bb_banner); /* reuse const string... */
+ full_write2_str(" multi-call binary\n"
+ "Copyright (C) 1998-2008 Erik Andersen, Rob Landley, Denys Vlasenko\n"
+ "and others. Licensed under GPLv2.\n"
+ "See source distribution for full notice.\n"
+ "\n"
+ "Usage: busybox [function] [arguments]...\n"
+ " or: function [arguments]...\n"
+ "\n"
+ "\tBusyBox is a multi-call binary that combines many common Unix\n"
+ "\tutilities into a single executable. Most people will create a\n"
+ "\tlink to busybox for each function they wish to use and BusyBox\n"
+ "\twill act like whatever it was invoked as!\n"
+ "\n"
+ "Currently defined functions:\n");
+ col = 0;
+ a = applet_names;
+ while (*a) {
+ int len;
+ if (col > output_width) {
+ full_write2_str(",\n");
+ col = 0;
+ }
+ full_write2_str(col ? ", " : "\t");
+ full_write2_str(a);
+ len = strlen(a);
+ col += len + 2;
+ a += len + 1;
+ }
+ full_write2_str("\n\n");
+ return 0;
+ }
+
+ if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
+ const char *busybox;
+ busybox = xmalloc_readlink(bb_busybox_exec_path);
+ if (!busybox)
+ busybox = bb_busybox_exec_path;
+ /* -s makes symlinks */
+ install_links(busybox, argv[2] && strcmp(argv[2], "-s") == 0);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "--help") == 0) {
+ /* "busybox --help [<applet>]" */
+ if (!argv[2])
+ goto help;
+ /* convert to "<applet> --help" */
+ argv[0] = argv[2];
+ argv[2] = NULL;
+ } else {
+ /* "busybox <applet> arg1 arg2 ..." */
+ argv++;
+ }
+ /* We support "busybox /a/path/to/applet args..." too. Allows for
+ * "#!/bin/busybox"-style wrappers */
+ applet_name = bb_get_last_path_component_nostrip(argv[0]);
+ run_applet_and_exit(applet_name, argv);
+
+ /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+ full_write2_str(applet_name);
+ full_write2_str(": applet not found\n");
+ xfunc_die();
+}
+
+void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
+{
+ int argc = 1;
+
+ while (argv[argc])
+ argc++;
+
+ /* Reinit some shared global data */
+ xfunc_error_retval = EXIT_FAILURE;
+
+ applet_name = APPLET_NAME(applet_no);
+ if (argc == 2 && strcmp(argv[1], "--help") == 0) {
+ /* Special case. POSIX says "test --help"
+ * should be no different from e.g. "test --foo". */
+//TODO: just compare applet_no with APPLET_NO_test
+ if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
+ bb_show_usage();
+ }
+ if (ENABLE_FEATURE_SUID)
+ check_suid(applet_no);
+ exit(applet_main[applet_no](argc, argv));
+}
+
+void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
+{
+ int applet = find_applet_by_name(name);
+ if (applet >= 0)
+ run_applet_no_and_exit(applet, argv);
+ if (!strncmp(name, "busybox", 7))
+ exit(busybox_main(argv));
+}
+
+#endif /* !defined(SINGLE_APPLET_MAIN) */
+
+
+
+#if ENABLE_BUILD_LIBBUSYBOX
+int lbb_main(char **argv)
+#else
+int main(int argc UNUSED_PARAM, char **argv)
+#endif
+{
+#if defined(SINGLE_APPLET_MAIN)
+ /* Only one applet is selected by the user! */
+ /* applet_names in this case is just "applet\0\0" */
+ lbb_prepare(applet_names USE_FEATURE_INDIVIDUAL(, argv));
+ return SINGLE_APPLET_MAIN(argc, argv);
+#else
+ lbb_prepare("busybox" USE_FEATURE_INDIVIDUAL(, argv));
+
+#if !BB_MMU
+ /* NOMMU re-exec trick sets high-order bit in first byte of name */
+ if (argv[0][0] & 0x80) {
+ re_execed = 1;
+ argv[0][0] &= 0x7f;
+ }
+#endif
+ applet_name = argv[0];
+ if (applet_name[0] == '-')
+ applet_name++;
+ applet_name = bb_basename(applet_name);
+
+ parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
+
+ run_applet_and_exit(applet_name, argv);
+
+ /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+ full_write2_str(applet_name);
+ full_write2_str(": applet not found\n");
+ xfunc_die();
+#endif
+}
diff --git a/release/src/router/busybox/libbb/arith.c b/release/src/router/busybox/libbb/arith.c
deleted file mode 100644
index 04c45ec3..00000000
--- a/release/src/router/busybox/libbb/arith.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-/* This is my infix parser/evaluator. It is optimized for size, intended
- * as a replacement for yacc-based parsers. However, it may well be faster
- * than a comparable parser writen in yacc. The supported operators are
- * listed in #defines below. Parens, order of operations, and error handling
- * are supported. This code is threadsafe. */
-
-/* To use the routine, call it with an expression string. It returns an
- * integer result. You will also need to define an "error" function
- * that takes printf arguments and _does not return_, or modify the code
- * to use another error mechanism. */
-
-#include <stdlib.h>
-#include <string.h>
-#include "libbb.h"
-
-typedef char operator;
-
-#define tok_decl(prec,id) (((id)<<5)|(prec))
-#define PREC(op) ((op)&0x1F)
-
-#define TOK_LPAREN tok_decl(0,0)
-
-#define TOK_OR tok_decl(1,0)
-
-#define TOK_AND tok_decl(2,0)
-
-#define TOK_BOR tok_decl(3,0)
-
-#define TOK_BXOR tok_decl(4,0)
-
-#define TOK_BAND tok_decl(5,0)
-
-#define TOK_EQ tok_decl(6,0)
-#define TOK_NE tok_decl(6,1)
-
-#define TOK_LT tok_decl(7,0)
-#define TOK_GT tok_decl(7,1)
-#define TOK_GE tok_decl(7,2)
-#define TOK_LE tok_decl(7,3)
-
-#define TOK_LSHIFT tok_decl(8,0)
-#define TOK_RSHIFT tok_decl(8,1)
-
-#define TOK_ADD tok_decl(9,0)
-#define TOK_SUB tok_decl(9,1)
-
-#define TOK_MUL tok_decl(10,0)
-#define TOK_DIV tok_decl(10,1)
-#define TOK_REM tok_decl(10,2)
-
-#define UNARYPREC 14
-#define TOK_BNOT tok_decl(UNARYPREC,0)
-#define TOK_NOT tok_decl(UNARYPREC,1)
-#define TOK_UMINUS tok_decl(UNARYPREC,2)
-
-#define TOK_NUM tok_decl(15,0)
-
-#define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr)
-#define NUMPTR (*numstackptr)
-static short arith_apply(operator op, long *numstack, long **numstackptr)
-{
- if (NUMPTR == numstack) goto err;
- if (op == TOK_UMINUS)
- NUMPTR[-1] *= -1;
- else if (op == TOK_NOT)
- NUMPTR[-1] = !(NUMPTR[-1]);
- else if (op == TOK_BNOT)
- NUMPTR[-1] = ~(NUMPTR[-1]);
-
- /* Binary operators */
- else {
- if (NUMPTR-1 == numstack) goto err;
- --NUMPTR;
- if (op == TOK_BOR)
- NUMPTR[-1] |= *NUMPTR;
- else if (op == TOK_OR)
- NUMPTR[-1] = *NUMPTR || NUMPTR[-1];
- else if (op == TOK_BAND)
- NUMPTR[-1] &= *NUMPTR;
- else if (op == TOK_AND)
- NUMPTR[-1] = NUMPTR[-1] && *NUMPTR;
- else if (op == TOK_EQ)
- NUMPTR[-1] = (NUMPTR[-1] == *NUMPTR);
- else if (op == TOK_NE)
- NUMPTR[-1] = (NUMPTR[-1] != *NUMPTR);
- else if (op == TOK_GE)
- NUMPTR[-1] = (NUMPTR[-1] >= *NUMPTR);
- else if (op == TOK_RSHIFT)
- NUMPTR[-1] >>= *NUMPTR;
- else if (op == TOK_LSHIFT)
- NUMPTR[-1] <<= *NUMPTR;
- else if (op == TOK_GT)
- NUMPTR[-1] = (NUMPTR[-1] > *NUMPTR);
- else if (op == TOK_LT)
- NUMPTR[-1] = (NUMPTR[-1] < *NUMPTR);
- else if (op == TOK_LE)
- NUMPTR[-1] = (NUMPTR[-1] <= *NUMPTR);
- else if (op == TOK_MUL)
- NUMPTR[-1] *= *NUMPTR;
- else if (op == TOK_DIV) {
- if(*NUMPTR==0)
- return -2;
- NUMPTR[-1] /= *NUMPTR;
- }
- else if (op == TOK_REM) {
- if(*NUMPTR==0)
- return -2;
- NUMPTR[-1] %= *NUMPTR;
- }
- else if (op == TOK_ADD)
- NUMPTR[-1] += *NUMPTR;
- else if (op == TOK_SUB)
- NUMPTR[-1] -= *NUMPTR;
- }
- return 0;
-err: return(-1);
-}
-
-extern long arith (const char *startbuf, int *errcode)
-{
- register char arithval;
- const char *expr = startbuf;
-
- operator lasttok = TOK_MUL, op;
- size_t datasizes = strlen(startbuf);
- unsigned char prec;
-
- long *numstack, *numstackptr;
- operator *stack = alloca(datasizes * sizeof(operator)), *stackptr = stack;
-
- *errcode = 0;
- numstack = alloca((datasizes/2+1)*sizeof(long)), numstackptr = numstack;
-
- while ((arithval = *expr)) {
- if (arithval == ' ' || arithval == '\n' || arithval == '\t')
- goto prologue;
- if ((unsigned)arithval-'0' <= 9) /* isdigit */ {
- *numstackptr++ = strtol(expr, (char **) &expr, 10);
- lasttok = TOK_NUM;
- continue;
- } if (arithval == '(') {
- *stackptr++ = TOK_LPAREN;
- lasttok = TOK_LPAREN;
- goto prologue;
- } if (arithval == ')') {
- lasttok = TOK_NUM;
- while (stackptr != stack) {
- op = *--stackptr;
- if (op == TOK_LPAREN)
- goto prologue;
- *errcode = ARITH_APPLY(op);
- if(*errcode) return *errcode;
- }
- goto err; /* Mismatched parens */
- } if (arithval == '|') {
- if (*++expr == '|')
- op = TOK_OR;
- else {
- --expr;
- op = TOK_BOR;
- }
- } else if (arithval == '&') {
- if (*++expr == '&')
- op = TOK_AND;
- else {
- --expr;
- op = TOK_BAND;
- }
- } else if (arithval == '=') {
- if (*++expr != '=') goto err; /* Unknown token */
- op = TOK_EQ;
- } else if (arithval == '!') {
- if (*++expr == '=')
- op = TOK_NE;
- else {
- --expr;
- op = TOK_NOT;
- }
- } else if (arithval == '>') {
- switch (*++expr) {
- case '=':
- op = TOK_GE;
- break;
- case '>':
- op = TOK_RSHIFT;
- break;
- default:
- --expr;
- op = TOK_GT;
- }
- } else if (arithval == '<') {
- switch (*++expr) {
- case '=':
- op = TOK_LE;
- break;
- case '<':
- op = TOK_LSHIFT;
- break;
- default:
- --expr;
- op = TOK_LT;
- }
- } else if (arithval == '*')
- op = TOK_MUL;
- else if (arithval == '/')
- op = TOK_DIV;
- else if (arithval == '%')
- op = TOK_REM;
- else if (arithval == '+') {
- if (lasttok != TOK_NUM) goto prologue; /* Unary plus */
- op = TOK_ADD;
- } else if (arithval == '-')
- op = (lasttok == TOK_NUM) ? TOK_SUB : TOK_UMINUS;
- else if (arithval == '~')
- op = TOK_BNOT;
- else goto err; /* Unknown token */
-
- prec = PREC(op);
- if (prec != UNARYPREC)
- while (stackptr != stack && PREC(stackptr[-1]) >= prec) {
- *errcode = ARITH_APPLY(*--stackptr);
- if(*errcode) return *errcode;
- }
- *stackptr++ = op;
- lasttok = op;
-prologue: ++expr;
- } /* yay */
-
- while (stackptr != stack) {
- *errcode = ARITH_APPLY(*--stackptr);
- if(*errcode) return *errcode;
- }
- if (numstackptr != numstack+1) {
-err:
- *errcode = -1;
- return -1;
- /* NOTREACHED */
- }
-
- return *numstack;
-}
diff --git a/release/src/router/busybox/libbb/ask_confirmation.c b/release/src/router/busybox/libbb/ask_confirmation.c
index f2922379..d08bc515 100644
--- a/release/src/router/busybox/libbb/ask_confirmation.c
+++ b/release/src/router/busybox/libbb/ask_confirmation.c
@@ -1,53 +1,34 @@
/* vi: set sw=4 ts=4: */
/*
- * Utility routines.
+ * bb_ask_confirmation implementation for busybox
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include "libbb.h"
+/* Read a line from stdin. If the first non-whitespace char is 'y' or 'Y',
+ * return 1. Otherwise return 0.
+ */
+#include "libbb.h"
-int ask_confirmation()
+int FAST_FUNC bb_ask_confirmation(void)
{
- int c = '\0';
- int ret = 0;
+ int retval = 0;
+ int first = 1;
+ int c;
- while (c != '\n') {
- c = getchar();
- if ( c != '\n' ) {
- ret = ((c=='y')||(c=='Y')) ? 1 : 0;
+ 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 ret;
-}
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+ return retval;
+}
diff --git a/release/src/router/busybox/libbb/bb_askpass.c b/release/src/router/busybox/libbb/bb_askpass.c
new file mode 100644
index 00000000..c0dcf0c5
--- /dev/null
+++ b/release/src/router/busybox/libbb/bb_askpass.c
@@ -0,0 +1,79 @@
+/* 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>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* do nothing signal handler */
+static void askpass_timeout(int UNUSED_PARAM ignore)
+{
+}
+
+char* FAST_FUNC bb_ask_stdin(const char *prompt)
+{
+ return bb_ask(STDIN_FILENO, 0, prompt);
+}
+char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
+{
+ /* Was static char[BIGNUM] */
+ enum { sizeof_passwd = 128 };
+ static char *passwd;
+
+ char *ret;
+ int i;
+ struct sigaction sa, oldsa;
+ struct termios tio, oldtio;
+
+ if (!passwd)
+ passwd = xmalloc(sizeof_passwd);
+ memset(passwd, 0, sizeof_passwd);
+
+ tcgetattr(fd, &oldtio);
+ tcflush(fd, TCIFLUSH);
+ tio = oldtio;
+ tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
+ tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
+ tcsetattr_stdin_TCSANOW(&tio);
+
+ memset(&sa, 0, sizeof(sa));
+ /* sa.sa_flags = 0; - no SA_RESTART! */
+ /* SIGINT and SIGALRM will interrupt read below */
+ sa.sa_handler = askpass_timeout;
+ sigaction(SIGINT, &sa, &oldsa);
+ if (timeout) {
+ sigaction_set(SIGALRM, &sa);
+ alarm(timeout);
+ }
+
+ fputs(prompt, stdout);
+ fflush(stdout);
+ ret = NULL;
+ /* On timeout or Ctrl-C, read will hopefully be interrupted,
+ * and we return NULL */
+ if (read(fd, passwd, sizeof_passwd - 1) > 0) {
+ ret = passwd;
+ i = 0;
+ /* Last byte is guaranteed to be 0
+ (read did not overwrite it) */
+ do {
+ if (passwd[i] == '\r' || passwd[i] == '\n')
+ passwd[i] = '\0';
+ } while (passwd[i++]);
+ }
+
+ if (timeout) {
+ alarm(0);
+ }
+ sigaction_set(SIGINT, &oldsa);
+
+ tcsetattr_stdin_TCSANOW(&oldtio);
+ bb_putchar('\n');
+ fflush(stdout);
+ return ret;
+}
diff --git a/release/src/router/busybox/libbb/bb_asprintf.c b/release/src/router/busybox/libbb/bb_asprintf.c
deleted file mode 100644
index 7075b46d..00000000
--- a/release/src/router/busybox/libbb/bb_asprintf.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- 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/release/src/router/busybox/libbb/bb_basename.c b/release/src/router/busybox/libbb/bb_basename.c
new file mode 100644
index 00000000..bab4166d
--- /dev/null
+++ b/release/src/router/busybox/libbb/bb_basename.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+const char* FAST_FUNC bb_basename(const char *name)
+{
+ const char *cp = strrchr(name, '/');
+ if (cp)
+ return cp + 1;
+ return name;
+}
diff --git a/release/src/router/busybox/libbb/bb_do_delay.c b/release/src/router/busybox/libbb/bb_do_delay.c
new file mode 100644
index 00000000..3d52cc56
--- /dev/null
+++ b/release/src/router/busybox/libbb/bb_do_delay.c
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox utility routines.
+ *
+ * Copyright (C) 2005 by Tito Ragusa <tito-wolit@tiscali.it>
+ *
+ * Licensed under the GPL v2, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+void FAST_FUNC bb_do_delay(int seconds)
+{
+ time_t start, now;
+
+ time(&start);
+ now = start;
+ while (difftime(now, start) < seconds) {
+ sleep(seconds);
+ time(&now);
+ }
+}
diff --git a/release/src/router/busybox/libbb/bb_pwd.c b/release/src/router/busybox/libbb/bb_pwd.c
new file mode 100644
index 00000000..d7285777
--- /dev/null
+++ b/release/src/router/busybox/libbb/bb_pwd.c
@@ -0,0 +1,112 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * password utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2008 by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+/* TODO: maybe change API to return malloced data?
+ * This will allow to stop using libc functions returning
+ * pointers to static data (getpwuid)
+ */
+
+struct passwd* FAST_FUNC xgetpwnam(const char *name)
+{
+ struct passwd *pw = getpwnam(name);
+ if (!pw)
+ bb_error_msg_and_die("unknown user %s", name);
+ return pw;
+}
+
+struct group* FAST_FUNC xgetgrnam(const char *name)
+{
+ struct group *gr = getgrnam(name);
+ if (!gr)
+ bb_error_msg_and_die("unknown group %s", name);
+ return gr;
+}
+
+
+struct passwd* FAST_FUNC xgetpwuid(uid_t uid)
+{
+ struct passwd *pw = getpwuid(uid);
+ if (!pw)
+ bb_error_msg_and_die("unknown uid %u", (unsigned)uid);
+ return pw;
+}
+
+struct group* FAST_FUNC xgetgrgid(gid_t gid)
+{
+ struct group *gr = getgrgid(gid);
+ if (!gr)
+ bb_error_msg_and_die("unknown gid %u", (unsigned)gid);
+ return gr;
+}
+
+char* FAST_FUNC xuid2uname(uid_t uid)
+{
+ struct passwd *pw = xgetpwuid(uid);
+ return pw->pw_name;
+}
+
+char* FAST_FUNC xgid2group(gid_t gid)
+{
+ struct group *gr = xgetgrgid(gid);
+ return gr->gr_name;
+}
+
+char* FAST_FUNC uid2uname(uid_t uid)
+{
+ struct passwd *pw = getpwuid(uid);
+ return (pw) ? pw->pw_name : NULL;
+}
+
+char* FAST_FUNC gid2group(gid_t gid)
+{
+ struct group *gr = getgrgid(gid);
+ return (gr) ? gr->gr_name : NULL;
+}
+
+char* FAST_FUNC uid2uname_utoa(long uid)
+{
+ char *name = uid2uname(uid);
+ return (name) ? name : utoa(uid);
+}
+
+char* FAST_FUNC gid2group_utoa(long gid)
+{
+ char *name = gid2group(gid);
+ return (name) ? name : utoa(gid);
+}
+
+long FAST_FUNC xuname2uid(const char *name)
+{
+ struct passwd *myuser;
+
+ myuser = xgetpwnam(name);
+ return myuser->pw_uid;
+}
+
+long FAST_FUNC xgroup2gid(const char *name)
+{
+ struct group *mygroup;
+
+ mygroup = xgetgrnam(name);
+ return mygroup->gr_gid;
+}
+
+unsigned long FAST_FUNC get_ug_id(const char *s,
+ long FAST_FUNC (*xname2id)(const char *))
+{
+ unsigned long r;
+
+ r = bb_strtoul(s, NULL, 10);
+ if (errno)
+ return xname2id(s);
+ return r;
+}
diff --git a/release/src/router/busybox/libbb/bb_qsort.c b/release/src/router/busybox/libbb/bb_qsort.c
new file mode 100644
index 00000000..9773afa6
--- /dev/null
+++ b/release/src/router/busybox/libbb/bb_qsort.c
@@ -0,0 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Wrapper for common string vector sorting operation
+ *
+ * Copyright (c) 2008 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int /* not FAST_FUNC! */ bb_pstrcmp(const void *a, const void *b)
+{
+ return strcmp(*(char**)a, *(char**)b);
+}
+
+void FAST_FUNC qsort_string_vector(char **sv, unsigned count)
+{
+ qsort(sv, count, sizeof(char*), bb_pstrcmp);
+}
diff --git a/release/src/router/busybox/libbb/bb_strtod.c b/release/src/router/busybox/libbb/bb_strtod.c
new file mode 100644
index 00000000..39bdeb5e
--- /dev/null
+++ b/release/src/router/busybox/libbb/bb_strtod.c
@@ -0,0 +1,86 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <math.h> /* just for HUGE_VAL */
+
+#define NOT_DIGIT(a) (((unsigned char)(a-'0')) > 9)
+
+double FAST_FUNC bb_strtod(const char *arg, char **endp)
+{
+ double v;
+ char *endptr;
+
+ /* Allow .NN form. People want to use "sleep .15" etc */
+ if (arg[0] != '-' && arg[0] != '.' && NOT_DIGIT(arg[0]))
+ goto err;
+ errno = 0;
+ v = strtod(arg, &endptr);
+ if (endp)
+ *endp = endptr;
+ if (endptr[0]) {
+ /* "1234abcg" or out-of-range? */
+ if (isalnum(endptr[0]) || errno) {
+ err:
+ errno = ERANGE;
+ return HUGE_VAL;
+ }
+ /* good number, just suspicious terminator */
+ errno = EINVAL;
+ }
+ return v;
+}
+
+#if 0
+/* String to timespec: "NNNN[.NNNNN]" -> struct timespec.
+ * Can be used for other fixed-point needs.
+ * Returns pointer past last converted char,
+ * and returns errno similar to bb_strtoXX functions.
+ */
+char* FAST_FUNC bb_str_to_ts(struct timespec *ts, const char *arg)
+{
+ if (sizeof(ts->tv_sec) <= sizeof(int))
+ ts->tv_sec = bb_strtou(arg, &arg, 10);
+ else if (sizeof(ts->tv_sec) <= sizeof(long))
+ ts->tv_sec = bb_strtoul(arg, &arg, 10);
+ else
+ ts->tv_sec = bb_strtoull(arg, &arg, 10);
+ ts->tv_nsec = 0;
+
+ if (*arg != '.')
+ return arg;
+
+ /* !EINVAL: number is not ok (alphanumeric ending, overflow etc) */
+ if (errno != EINVAL)
+ return arg;
+
+ if (!*++arg) /* "NNN." */
+ return arg;
+
+ { /* "NNN.xxx" - parse xxx */
+ int ndigits;
+ char *p;
+ char buf[10]; /* we never use more than 9 digits */
+
+ /* Need to make a copy to avoid false overflow */
+ safe_strncpy(buf, arg, 10);
+ ts->tv_nsec = bb_strtou(buf, &p, 10);
+ ndigits = p - buf;
+ arg += ndigits;
+ /* normalize to nsec */
+ while (ndigits < 9) {
+ ndigits++;
+ ts->tv_nsec *= 10;
+ }
+ while (isdigit(*arg)) /* skip possible 10th plus digits */
+ arg++;
+ }
+ return arg;
+}
+#endif
diff --git a/release/src/router/busybox/libbb/bb_strtonum.c b/release/src/router/busybox/libbb/bb_strtonum.c
new file mode 100644
index 00000000..87cd744a
--- /dev/null
+++ b/release/src/router/busybox/libbb/bb_strtonum.c
@@ -0,0 +1,139 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* On exit: errno = 0 only if there was non-empty, '\0' terminated value
+ * errno = EINVAL if value was not '\0' terminated, but otherwise ok
+ * Return value is still valid, caller should just check whether end[0]
+ * is a valid terminating char for particular case. OTOH, if caller
+ * requires '\0' terminated input, [s]he can just check errno == 0.
+ * errno = ERANGE if value had alphanumeric terminating char ("1234abcg").
+ * errno = ERANGE if value is out of range, missing, etc.
+ * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok )
+ * return value is all-ones in this case.
+ *
+ * Test code:
+ * char *endptr;
+ * const char *minus = "-";
+ * errno = 0;
+ * bb_strtoi(minus, &endptr, 0); // must set ERANGE
+ * printf("minus:%p endptr:%p errno:%d EINVAL:%d\n", minus, endptr, errno, EINVAL);
+ * errno = 0;
+ * bb_strtoi("-0-", &endptr, 0); // must set EINVAL and point to second '-'
+ * printf("endptr[0]:%c errno:%d EINVAL:%d\n", endptr[0], errno, EINVAL);
+ */
+
+static unsigned long long ret_ERANGE(void)
+{
+ errno = ERANGE; /* this ain't as small as it looks (on glibc) */
+ return ULLONG_MAX;
+}
+
+static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr)
+{
+ if (endp) *endp = endptr;
+
+ /* errno is already set to ERANGE by strtoXXX if value overflowed */
+ if (endptr[0]) {
+ /* "1234abcg" or out-of-range? */
+ if (isalnum(endptr[0]) || errno)
+ return ret_ERANGE();
+ /* good number, just suspicious terminator */
+ errno = EINVAL;
+ }
+ return v;
+}
+
+
+unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base)
+{
+ unsigned long long v;
+ char *endptr;
+
+ /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */
+ /* I don't think that this is right. Preventing this... */
+ if (!isalnum(arg[0])) return ret_ERANGE();
+
+ /* not 100% correct for lib func, but convenient for the caller */
+ errno = 0;
+ v = strtoull(arg, &endptr, base);
+ return handle_errors(v, endp, endptr);
+}
+
+long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base)
+{
+ unsigned long long v;
+ char *endptr;
+
+ /* Check for the weird "feature":
+ * a "-" string is apparently a valid "number" for strto[u]l[l]!
+ * It returns zero and errno is 0! :( */
+ char first = (arg[0] != '-' ? arg[0] : arg[1]);
+ if (!isalnum(first)) return ret_ERANGE();
+
+ errno = 0;
+ v = strtoll(arg, &endptr, base);
+ return handle_errors(v, endp, endptr);
+}
+
+#if ULONG_MAX != ULLONG_MAX
+unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base)
+{
+ unsigned long v;
+ char *endptr;
+
+ if (!isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtoul(arg, &endptr, base);
+ return handle_errors(v, endp, endptr);
+}
+
+long FAST_FUNC bb_strtol(const char *arg, char **endp, int base)
+{
+ long v;
+ char *endptr;
+
+ char first = (arg[0] != '-' ? arg[0] : arg[1]);
+ if (!isalnum(first)) return ret_ERANGE();
+
+ errno = 0;
+ v = strtol(arg, &endptr, base);
+ return handle_errors(v, endp, endptr);
+}
+#endif
+
+#if UINT_MAX != ULONG_MAX
+unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base)
+{
+ unsigned long v;
+ char *endptr;
+
+ if (!isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtoul(arg, &endptr, base);
+ if (v > UINT_MAX) return ret_ERANGE();
+ return handle_errors(v, endp, endptr);
+}
+
+int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base)
+{
+ long v;
+ char *endptr;
+
+ char first = (arg[0] != '-' ? arg[0] : arg[1]);
+ if (!isalnum(first)) return ret_ERANGE();
+
+ errno = 0;
+ v = strtol(arg, &endptr, base);
+ if (v > INT_MAX) return ret_ERANGE();
+ if (v < INT_MIN) return ret_ERANGE();
+ return handle_errors(v, endp, endptr);
+}
+#endif
diff --git a/release/src/router/busybox/libbb/change_identity.c b/release/src/router/busybox/libbb/change_identity.c
index c2b73eeb..619db09a 100644
--- a/release/src/router/busybox/libbb/change_identity.c
+++ b/release/src/router/busybox/libbb/change_identity.c
@@ -28,27 +28,14 @@
* 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. */
-void change_identity ( const struct passwd *pw )
+void FAST_FUNC change_identity(const struct passwd *pw)
{
- if ( initgroups ( pw-> pw_name, pw-> pw_gid ) == -1 )
- bb_perror_msg_and_die ( "cannot set groups" );
- endgrent ( );
-
- if ( setgid ( pw-> pw_gid ))
- bb_perror_msg_and_die ( "cannot set group id" );
- if ( setuid ( pw->pw_uid ))
- bb_perror_msg_and_die ( "cannot set user id" );
+ if (initgroups(pw->pw_name, pw->pw_gid) == -1)
+ bb_perror_msg_and_die("can't set groups");
+ endgrent(); /* helps to close a fd used internally by libc */
+ xsetgid(pw->pw_gid);
+ xsetuid(pw->pw_uid);
}
-
diff --git a/release/src/router/busybox/libbb/chomp.c b/release/src/router/busybox/libbb/chomp.c
index 111d4cf7..ed4bf6be 100644
--- a/release/src/router/busybox/libbb/chomp.c
+++ b/release/src/router/busybox/libbb/chomp.c
@@ -2,48 +2,18 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <string.h>
#include "libbb.h"
-
-void chomp(char *s)
+void FAST_FUNC 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:
-*/
+ if (lc)
+ *lc = '\0';
+}
diff --git a/release/src/router/busybox/libbb/compare_string_array.c b/release/src/router/busybox/libbb/compare_string_array.c
index 993b4626..43c59e8e 100644
--- a/release/src/router/busybox/libbb/compare_string_array.c
+++ b/release/src/router/busybox/libbb/compare_string_array.c
@@ -1,31 +1,78 @@
+/* vi: set sw=4 ts=4: */
/*
- * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <string.h>
+#include "libbb.h"
-/* returns the array number of the string */
-extern unsigned short compare_string_array(const char *string_array[], const char *key)
+/* returns the array index of the string */
+/* (index of first match is returned, or -1) */
+int FAST_FUNC index_in_str_array(const char *const string_array[], const char *key)
{
- unsigned short i;
+ int i;
for (i = 0; string_array[i] != 0; i++) {
if (strcmp(string_array[i], key) == 0) {
- break;
+ return i;
}
}
- return(i);
+ return -1;
}
+int FAST_FUNC index_in_strings(const char *strings, const char *key)
+{
+ int idx = 0;
+
+ while (*strings) {
+ if (strcmp(strings, key) == 0) {
+ return idx;
+ }
+ strings += strlen(strings) + 1; /* skip NUL */
+ idx++;
+ }
+ return -1;
+}
+
+/* returns the array index of the string, even if it matches only a beginning */
+/* (index of first match is returned, or -1) */
+#ifdef UNUSED
+int FAST_FUNC index_in_substr_array(const char *const string_array[], const char *key)
+{
+ int i;
+ int len = strlen(key);
+ if (len) {
+ for (i = 0; string_array[i] != 0; i++) {
+ if (strncmp(string_array[i], key, len) == 0) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+#endif
+
+int FAST_FUNC index_in_substrings(const char *strings, const char *key)
+{
+ int len = strlen(key);
+
+ if (len) {
+ int idx = 0;
+ while (*strings) {
+ if (strncmp(strings, key, len) == 0) {
+ return idx;
+ }
+ strings += strlen(strings) + 1; /* skip NUL */
+ idx++;
+ }
+ }
+ return -1;
+}
+
+const char* FAST_FUNC nth_string(const char *strings, int n)
+{
+ while (n) {
+ n--;
+ strings += strlen(strings) + 1;
+ }
+ return strings;
+}
diff --git a/release/src/router/busybox/libbb/concat_path_file.c b/release/src/router/busybox/libbb/concat_path_file.c
index 86dd2fbb..fb533547 100644
--- a/release/src/router/busybox/libbb/concat_path_file.c
+++ b/release/src/router/busybox/libbb/concat_path_file.c
@@ -1,26 +1,29 @@
+/* vi: set sw=4 ts=4: */
/*
- * busybox library eXtendet funcion
+ * Utility routines.
*
- * concatenate path and file name to new allocation buffer,
- * not addition '/' if path name already have '/'
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
*
-*/
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Concatenate path and filename to new allocated buffer.
+ * Add '/' only as needed (no duplicate // are produced).
+ * If path is NULL, it is assumed to be "/".
+ * filename should not be NULL.
+ */
-#include <string.h>
#include "libbb.h"
-extern char *concat_path_file(const char *path, const char *filename)
+char* FAST_FUNC concat_path_file(const char *path, const char *filename)
{
- char *outbuf;
char *lc;
if (!path)
- path="";
+ path = "";
lc = last_char_is(path, '/');
while (*filename == '/')
filename++;
- outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL));
- sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
-
- return outbuf;
+ return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename);
}
diff --git a/release/src/router/busybox/libbb/concat_subpath_file.c b/release/src/router/busybox/libbb/concat_subpath_file.c
index 6d86f5e8..313fa63c 100644
--- a/release/src/router/busybox/libbb/concat_subpath_file.c
+++ b/release/src/router/busybox/libbb/concat_subpath_file.c
@@ -4,33 +4,20 @@
*
* 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
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/*
This function make special for recursive actions with usage
concat_path_file(path, filename)
- and skiping "." and ".." directory entries
+ and skipping "." and ".." directory entries
*/
#include "libbb.h"
-extern char *concat_subpath_file(const char *path, const char *f)
+char* FAST_FUNC concat_subpath_file(const char *path, const char *f)
{
- if(f && *f == '.' && (!f[1] || (f[1] == '.' && !f[2])))
+ if (f && DOT_OR_DOTDOT(f))
return NULL;
return concat_path_file(path, f);
}
diff --git a/release/src/router/busybox/libbb/copy_file.c b/release/src/router/busybox/libbb/copy_file.c
index c79fbeb1..d804eccf 100644
--- a/release/src/router/busybox/libbb/copy_file.c
+++ b/release/src/router/busybox/libbb/copy_file.c
@@ -2,82 +2,158 @@
/*
* Mini copy_file implementation for busybox
*
- *
* Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
*
- * 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
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
*/
-#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 "libbb.h"
-int copy_file(const char *source, const char *dest, int flags)
+// POSIX: if exists and -i, ask (w/o -i assume yes).
+// Then open w/o EXCL (yes, not unlink!).
+// If open still fails and -f, try unlink, then try open again.
+// Result: a mess:
+// If dest is a softlink, we overwrite softlink's destination!
+// (or fail, if it points to dir/nonexistent location/etc).
+// This is strange, but POSIX-correct.
+// coreutils cp has --remove-destination to override this...
+//
+// NB: we have special code which still allows for "cp file /dev/node"
+// to work POSIX-ly (the only realistic case where it makes sense)
+
+#define DO_POSIX_CP 0 /* 1 - POSIX behavior, 0 - safe behavior */
+
+// errno must be set to relevant value ("why we cannot create dest?")
+// for POSIX mode to give reasonable error message
+static int ask_and_unlink(const char *dest, int flags)
+{
+ int e = errno;
+#if DO_POSIX_CP
+ if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) {
+ // Either it exists, or the *path* doesnt exist
+ bb_perror_msg("cannot create '%s'", dest);
+ return -1;
+ }
+#endif
+ // If !DO_POSIX_CP, act as if -f is always in effect - we don't want
+ // "cannot create" msg, we want unlink to be done (silently unless -i).
+
+ // TODO: maybe we should do it only if ctty is present?
+ if (flags & FILEUTILS_INTERACTIVE) {
+ // We would not do POSIX insanity. -i asks,
+ // then _unlinks_ the offender. Presto.
+ // (No "opening without O_EXCL", no "unlink only if -f")
+ // Or else we will end up having 3 open()s!
+ fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest);
+ if (!bb_ask_confirmation())
+ return 0; // not allowed to overwrite
+ }
+ if (unlink(dest) < 0) {
+#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE
+ if (e == errno && e == ENOENT) {
+ /* e == ENOTDIR is similar: path has non-dir component,
+ * but in this case we don't even reach copy_file() */
+ bb_error_msg("cannot create '%s': Path does not exist", dest);
+ return -1; // error
+ }
+#endif
+ errno = e;
+ bb_perror_msg("cannot create '%s'", dest);
+ return -1; // error
+ }
+ return 1; // ok (to try again)
+}
+
+/* Return:
+ * -1 error, copy not made
+ * 0 copy is made or user answered "no" in interactive mode
+ * (failures to preserve mode/owner/times are not reported in exit code)
+ */
+int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
{
+ /* This is a recursive function, try to minimize stack usage */
+ /* NB: each struct stat is ~100 bytes */
struct stat source_stat;
struct stat dest_stat;
- int dest_exists = 1;
- int status = 0;
-
- if (((flags & FILEUTILS_PRESERVE_SYMLINKS) &&
- lstat(source, &source_stat) < 0) ||
- (!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
- stat(source, &source_stat) < 0)) {
- perror_msg("%s", source);
+ signed char retval = 0;
+ signed char dest_exists = 0;
+ signed char ovr;
+
+/* Inverse of cp -d ("cp without -d") */
+#define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE)
+
+ if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
+ // This may be a dangling symlink.
+ // Making [sym]links to dangling symlinks works, so...
+ if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK))
+ goto make_links;
+ bb_perror_msg("cannot stat '%s'", source);
return -1;
}
- if (stat(dest, &dest_stat) < 0) {
+ if (lstat(dest, &dest_stat) < 0) {
if (errno != ENOENT) {
- perror_msg("unable to stat `%s'", dest);
+ bb_perror_msg("cannot 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 = 0;
+ dest_exists = 1;
}
- if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev &&
- source_stat.st_ino == dest_stat.st_ino) {
- error_msg("`%s' and `%s' are the same file", source, dest);
- return -1;
+#if ENABLE_SELINUX
+ if ((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) && is_selinux_enabled() > 0) {
+ security_context_t con;
+ if (lgetfilecon(source, &con) >= 0) {
+ if (setfscreatecon(con) < 0) {
+ bb_perror_msg("cannot set setfscreatecon %s", con);
+ freecon(con);
+ return -1;
+ }
+ } else if (errno == ENOTSUP || errno == ENODATA) {
+ setfscreatecon_or_die(NULL);
+ } else {
+ bb_perror_msg("cannot lgetfilecon %s", source);
+ return -1;
+ }
}
+#endif
if (S_ISDIR(source_stat.st_mode)) {
DIR *dp;
+ const char *tp;
struct dirent *d;
mode_t saved_umask = 0;
if (!(flags & FILEUTILS_RECUR)) {
- error_msg("%s: omitting directory", source);
+ bb_error_msg("omitting directory '%s'", source);
+ return -1;
+ }
+
+ /* Did we ever create source ourself before? */
+ tp = is_in_ino_dev_hashtable(&source_stat);
+ if (tp) {
+ /* We did! it's a recursion! man the lifeboats... */
+ bb_error_msg("recursion detected, omitting directory '%s'",
+ source);
return -1;
}
- /* Create DEST. */
+ /* Create DEST */
if (dest_exists) {
if (!S_ISDIR(dest_stat.st_mode)) {
- error_msg("`%s' is not a directory", dest);
+ bb_error_msg("target '%s' is not a directory", dest);
return -1;
}
+ /* race here: user can substitute a symlink between
+ * this check and actual creation of files inside dest */
} else {
mode_t mode;
saved_umask = umask(0);
@@ -85,153 +161,239 @@ int copy_file(const char *source, const char *dest, int flags)
mode = source_stat.st_mode;
if (!(flags & FILEUTILS_PRESERVE_STATUS))
mode = source_stat.st_mode & ~saved_umask;
+ /* Allow owner to access new dir (at least for now) */
mode |= S_IRWXU;
-
if (mkdir(dest, mode) < 0) {
umask(saved_umask);
- perror_msg("cannot create directory `%s'", dest);
+ bb_perror_msg("cannot create directory '%s'", dest);
return -1;
}
-
umask(saved_umask);
+ /* need stat info for add_to_ino_dev_hashtable */
+ if (lstat(dest, &dest_stat) < 0) {
+ bb_perror_msg("cannot stat '%s'", dest);
+ return -1;
+ }
}
-
- /* Recursively copy files in SOURCE. */
- if ((dp = opendir(source)) == NULL) {
- perror_msg("unable to open directory `%s'", source);
- status = -1;
- goto end;
+ /* remember (dev,inode) of each created dir.
+ * NULL: name is not remembered */
+ add_to_ino_dev_hashtable(&dest_stat, NULL);
+
+ /* Recursively copy files in SOURCE */
+ dp = opendir(source);
+ if (dp == NULL) {
+ retval = -1;
+ goto preserve_mode_ugid_time;
}
while ((d = readdir(dp)) != NULL) {
char *new_source, *new_dest;
- if (strcmp(d->d_name, ".") == 0 ||
- strcmp(d->d_name, "..") == 0)
+ new_source = concat_subpath_file(source, d->d_name);
+ if (new_source == NULL)
continue;
-
- new_source = concat_path_file(source, d->d_name);
new_dest = concat_path_file(dest, d->d_name);
if (copy_file(new_source, new_dest, flags) < 0)
- status = -1;
+ retval = -1;
free(new_source);
free(new_dest);
}
+ closedir(dp);
- /* ??? What if an error occurs in readdir? */
-
- if (closedir(dp) < 0) {
- perror_msg("unable to close directory `%s'", source);
- status = -1;
- }
-
- if (!dest_exists &&
- chmod(dest, source_stat.st_mode & ~saved_umask) < 0) {
- perror_msg("unable to change permissions of `%s'", dest);
- status = -1;
+ if (!dest_exists
+ && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
+ ) {
+ bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
+ /* retval = -1; - WRONG! copy *WAS* made */
}
- } else if (S_ISREG(source_stat.st_mode)) {
- FILE *sfp, *dfp;
+ goto preserve_mode_ugid_time;
+ }
- if (dest_exists) {
- if (flags & FILEUTILS_INTERACTIVE) {
- fprintf(stderr, "%s: overwrite `%s'? ", applet_name, dest);
- if (!ask_confirmation())
- return 0;
+ if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
+ int (*lf)(const char *oldpath, const char *newpath);
+ make_links:
+ // Hmm... maybe
+ // if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
+ // (but realpath returns NULL on dangling symlinks...)
+ lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link;
+ if (lf(source, dest) < 0) {
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0)
+ return ovr;
+ if (lf(source, dest) < 0) {
+ bb_perror_msg("cannot create link '%s'", dest);
+ return -1;
}
+ }
+ /* _Not_ jumping to preserve_mode_ugid_time:
+ * hard/softlinks don't have those */
+ return 0;
+ }
- if ((dfp = fopen(dest, "w")) == NULL) {
- if (!(flags & FILEUTILS_FORCE)) {
- perror_msg("unable to open `%s'", dest);
- return -1;
- }
+ if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */
+ !(flags & FILEUTILS_RECUR)
+ /* "cp [-opts] regular_file thing2" */
+ || S_ISREG(source_stat.st_mode)
+ /* DEREF uses stat, which never returns S_ISLNK() == true.
+ * So the below is never true: */
+ /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
+ ) {
+ int src_fd;
+ int dst_fd;
+ mode_t new_mode;
+
+ if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) {
+ /* "cp -d symlink dst": create a link */
+ goto dont_cat;
+ }
- if (unlink(dest) < 0) {
- perror_msg("unable to remove `%s'", dest);
- return -1;
+ if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) {
+ const char *link_target;
+ link_target = is_in_ino_dev_hashtable(&source_stat);
+ if (link_target) {
+ if (link(link_target, dest) < 0) {
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0)
+ return ovr;
+ if (link(link_target, dest) < 0) {
+ bb_perror_msg("cannot create link '%s'", dest);
+ return -1;
+ }
}
-
- dest_exists = 0;
+ return 0;
}
+ add_to_ino_dev_hashtable(&source_stat, dest);
}
- if (!dest_exists) {
- int fd;
+ src_fd = open_or_warn(source, O_RDONLY);
+ if (src_fd < 0)
+ return -1;
- if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 ||
- (dfp = fdopen(fd, "w")) == NULL) {
- if (fd >= 0)
- close(fd);
- perror_msg("unable to open `%s'", dest);
+ /* Do not try to open with weird mode fields */
+ new_mode = source_stat.st_mode;
+ if (!S_ISREG(source_stat.st_mode))
+ new_mode = 0666;
+
+ /* POSIX way is a security problem versus symlink attacks,
+ * we do it only for non-symlinks, and only for non-recursive,
+ * non-interactive cp. NB: it is still racy
+ * for "cp file /home/bad_user/file" case
+ * (user can rm file and create a link to /etc/passwd) */
+ if (DO_POSIX_CP
+ || (dest_exists
+ && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE))
+ && !S_ISLNK(dest_stat.st_mode))
+ ) {
+ dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
+ } else /* safe way: */
+ dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
+ if (dst_fd == -1) {
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0) {
+ close(src_fd);
+ return ovr;
+ }
+ /* It shouldn't exist. If it exists, do not open (symlink attack?) */
+ dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
+ if (dst_fd < 0) {
+ close(src_fd);
return -1;
}
}
- if ((sfp = fopen(source, "r")) == NULL) {
- fclose(dfp);
- perror_msg("unable to open `%s'", source);
- status = -1;
- goto end;
+#if ENABLE_SELINUX
+ if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT))
+ && is_selinux_enabled() > 0
+ ) {
+ security_context_t con;
+ if (getfscreatecon(&con) == -1) {
+ bb_perror_msg("getfscreatecon");
+ return -1;
+ }
+ if (con) {
+ if (setfilecon(dest, con) == -1) {
+ bb_perror_msg("setfilecon:%s,%s", dest, con);
+ freecon(con);
+ return -1;
+ }
+ freecon(con);
+ }
}
-
- if (copy_file_chunk(sfp, dfp, -1) < 0)
- status = -1;
-
- if (fclose(dfp) < 0) {
- perror_msg("unable to close `%s'", dest);
- status = -1;
+#endif
+ if (bb_copyfd_eof(src_fd, dst_fd) == -1)
+ retval = -1;
+ /* Ok, writing side I can understand... */
+ if (close(dst_fd) < 0) {
+ bb_perror_msg("cannot close '%s'", dest);
+ retval = -1;
}
-
- if (fclose(sfp) < 0) {
- perror_msg("unable to close `%s'", source);
- status = -1;
+ /* ...but read size is already checked by bb_copyfd_eof */
+ close(src_fd);
+ /* "cp /dev/something new_file" should not
+ * copy mode of /dev/something */
+ if (!S_ISREG(source_stat.st_mode))
+ return retval;
+ goto preserve_mode_ugid_time;
+ }
+ dont_cat:
+
+ /* Source is a symlink or a special file */
+ /* We are lazy here, a bit lax with races... */
+ if (dest_exists) {
+ errno = EEXIST;
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0)
+ return ovr;
+ }
+ if (S_ISLNK(source_stat.st_mode)) {
+ char *lpath = xmalloc_readlink_or_warn(source);
+ if (lpath) {
+ int r = symlink(lpath, dest);
+ free(lpath);
+ if (r < 0) {
+ bb_perror_msg("cannot create symlink '%s'", dest);
+ return -1;
+ }
+ if (flags & FILEUTILS_PRESERVE_STATUS)
+ if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
+ bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
}
- } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
- S_ISSOCK(source_stat.st_mode)) {
+ /* _Not_ jumping to preserve_mode_ugid_time:
+ * symlinks don't have those */
+ return 0;
+ }
+ 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)
+ ) {
if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
- perror_msg("unable to create `%s'", dest);
+ bb_perror_msg("cannot create '%s'", dest);
return -1;
}
- } else if (S_ISFIFO(source_stat.st_mode)) {
- if (mkfifo(dest, source_stat.st_mode) < 0) {
- perror_msg("cannot create fifo `%s'", dest);
- return -1;
- }
- } else if (S_ISLNK(source_stat.st_mode)) {
- char *lpath = xreadlink(source);
- if (symlink(lpath, dest) < 0) {
- 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)
- perror_msg("unable to preserve ownership of `%s'", dest);
-#endif
- return 0;
} else {
- error_msg("internal error: unrecognized file type");
+ bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode);
return -1;
}
-end:
+ preserve_mode_ugid_time:
- if (flags & FILEUTILS_PRESERVE_STATUS) {
+ if (flags & FILEUTILS_PRESERVE_STATUS
+ /* Cannot happen: */
+ /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */
+ ) {
struct utimbuf times;
times.actime = source_stat.st_atime;
times.modtime = source_stat.st_mtime;
+ /* BTW, utimes sets usec-precision time - just FYI */
if (utime(dest, &times) < 0)
- perror_msg("unable to preserve times of `%s'", dest);
+ bb_perror_msg("cannot preserve %s of '%s'", "times", dest);
if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
source_stat.st_mode &= ~(S_ISUID | S_ISGID);
- perror_msg("unable to preserve ownership of `%s'", dest);
+ bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
}
if (chmod(dest, source_stat.st_mode) < 0)
- perror_msg("unable to preserve permissions of `%s'", dest);
+ bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
}
- return status;
+ return retval;
}
diff --git a/release/src/router/busybox/libbb/copy_file_chunk.c b/release/src/router/busybox/libbb/copy_file_chunk.c
deleted file mode 100644
index c440a610..00000000
--- a/release/src/router/busybox/libbb/copy_file_chunk.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include "libbb.h"
-
-/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE
- * to DST_FILE. */
-extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize)
-{
- size_t nread, nwritten, size;
- char buffer[BUFSIZ];
-
- while (chunksize != 0) {
- if (chunksize > BUFSIZ)
- size = BUFSIZ;
- else
- size = chunksize;
-
- nread = fread (buffer, 1, size, src_file);
-
- if (nread != size && ferror (src_file)) {
- perror_msg ("read");
- return -1;
- } else if (nread == 0) {
- if (chunksize != -1) {
- error_msg ("Unable to read all data");
- return -1;
- }
-
- return 0;
- }
-
- nwritten = fwrite (buffer, 1, nread, dst_file);
-
- if (nwritten != nread) {
- if (ferror (dst_file))
- perror_msg ("write");
- else
- error_msg ("Unable to write all data");
- return -1;
- }
-
- if (chunksize != -1)
- chunksize -= nwritten;
- }
-
- return 0;
-}
diff --git a/release/src/router/busybox/libbb/copyfd.c b/release/src/router/busybox/libbb/copyfd.c
index aa938d10..c5f8b5b8 100644
--- a/release/src/router/busybox/libbb/copyfd.c
+++ b/release/src/router/busybox/libbb/copyfd.c
@@ -2,58 +2,118 @@
/*
* Utility routines.
*
- * Copyright (C) 1999-2001 Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1999-2005 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
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
#include "libbb.h"
+/* Used by NOFORK applets (e.g. cat) - must not use xmalloc */
-extern int copyfd(int fd1, int fd2)
+static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
{
- char buf[8192];
- ssize_t nread, nwrote;
+ int status = -1;
+ off_t total = 0;
+#if CONFIG_FEATURE_COPYBUF_KB <= 4
+ char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
+ enum { buffer_size = sizeof(buffer) };
+#else
+ char *buffer;
+ int buffer_size;
+
+ /* We want page-aligned buffer, just in case kernel is clever
+ * and can do page-aligned io more efficiently */
+ buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON,
+ /* ignored: */ -1, 0);
+ buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
+ if (buffer == MAP_FAILED) {
+ buffer = alloca(4 * 1024);
+ buffer_size = 4 * 1024;
+ }
+#endif
+
+ if (src_fd < 0)
+ goto out;
+
+ if (!size) {
+ size = buffer_size;
+ status = 1; /* copy until eof */
+ }
while (1) {
- nread = safe_read(fd1, buf, sizeof(buf));
- if (nread == 0)
+ ssize_t rd;
+
+ rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size);
+
+ if (!rd) { /* eof - all done */
+ status = 0;
break;
- if (nread == -1) {
- perror_msg("read");
- return -1;
}
-
- nwrote = full_write(fd2, buf, nread);
- if (nwrote == -1) {
- perror_msg("write");
- return -1;
+ if (rd < 0) {
+ bb_perror_msg(bb_msg_read_error);
+ break;
+ }
+ /* dst_fd == -1 is a fake, else... */
+ if (dst_fd >= 0) {
+ ssize_t wr = full_write(dst_fd, buffer, rd);
+ if (wr < rd) {
+ bb_perror_msg(bb_msg_write_error);
+ break;
+ }
+ }
+ total += rd;
+ if (status < 0) { /* if we aren't copying till EOF... */
+ size -= rd;
+ if (!size) {
+ /* 'size' bytes copied - all done */
+ status = 0;
+ break;
+ }
}
}
+ out:
+#if CONFIG_FEATURE_COPYBUF_KB > 4
+ if (buffer_size != 4 * 1024)
+ munmap(buffer, buffer_size);
+#endif
+ return status ? -1 : total;
+}
+
+
+#if 0
+void FAST_FUNC complain_copyfd_and_die(off_t sz)
+{
+ if (sz != -1)
+ bb_error_msg_and_die("short read");
+ /* if sz == -1, bb_copyfd_XX already complained */
+ xfunc_die();
+}
+#endif
+
+off_t FAST_FUNC bb_copyfd_size(int fd1, int fd2, off_t size)
+{
+ if (size) {
+ return bb_full_fd_action(fd1, fd2, size);
+ }
return 0;
}
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size)
+{
+ off_t sz = bb_copyfd_size(fd1, fd2, size);
+ if (sz == size)
+ return;
+ if (sz != -1)
+ bb_error_msg_and_die("short read");
+ /* if sz == -1, bb_copyfd_XX already complained */
+ xfunc_die();
+}
+
+off_t FAST_FUNC bb_copyfd_eof(int fd1, int fd2)
+{
+ return bb_full_fd_action(fd1, fd2, 0);
+}
diff --git a/release/src/router/busybox/libbb/correct_password.c b/release/src/router/busybox/libbb/correct_password.c
index 39625361..6301589e 100644
--- a/release/src/router/busybox/libbb/correct_password.c
+++ b/release/src/router/busybox/libbb/correct_password.c
@@ -28,51 +28,53 @@
* 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. */
+ * Return 1 if the user gives the correct password for entry PW,
+ * 0 if not. Return 1 without asking if PW has an empty password.
+ *
+ * NULL pw means "just fake it for login with bad username" */
-int correct_password ( const struct passwd *pw )
+int FAST_FUNC 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;
+ char *unencrypted, *encrypted;
+ const char *correct;
+ int r;
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ /* Using _r function to avoid pulling in static buffers */
+ struct spwd spw;
+ char buffer[256];
+#endif
+
+ /* fake salt. crypt() can choke otherwise. */
+ correct = "aa";
+ if (!pw) {
+ /* "aa" will never match */
+ goto fake_it;
+ }
+ correct = pw->pw_passwd;
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) {
+ /* getspnam_r may return 0 yet set result to NULL.
+ * At least glibc 2.4 does this. Be extra paranoid here. */
+ struct spwd *result = NULL;
+ r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
+ correct = (r || !result) ? "aa" : result->sp_pwdp;
}
- else
#endif
- correct = pw-> pw_passwd;
- if ( correct == 0 || correct[0] == '\0' )
+ if (!correct[0]) /* empty password field? */
return 1;
- unencrypted = getpass ( "Password: " );
- if ( !unencrypted )
- {
- fputs ( "getpass: cannot open /dev/tty\n", stderr );
+ fake_it:
+ unencrypted = bb_ask_stdin("Password: ");
+ if (!unencrypted) {
return 0;
}
- encrypted = crypt ( unencrypted, correct );
- memset ( unencrypted, 0, bb_strlen ( unencrypted ));
- return ( strcmp ( encrypted, correct ) == 0 ) ? 1 : 0;
+ encrypted = pw_encrypt(unencrypted, correct, 1);
+ r = (strcmp(encrypted, correct) == 0);
+ free(encrypted);
+ memset(unencrypted, 0, strlen(unencrypted));
+ return r;
}
diff --git a/release/src/router/busybox/libbb/crc32.c b/release/src/router/busybox/libbb/crc32.c
new file mode 100644
index 00000000..36ac8604
--- /dev/null
+++ b/release/src/router/busybox/libbb/crc32.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * CRC32 table fill function
+ * Copyright (C) 2006 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
+ * (I can't really claim much credit however, as the algorithm is
+ * very well-known)
+ *
+ * The following function creates a CRC32 table depending on whether
+ * a big-endian (0x04c11db7) or little-endian (0xedb88320) CRC32 is
+ * required. Admittedly, there are other CRC32 polynomials floating
+ * around, but Busybox doesn't use them.
+ *
+ * endian = 1: big-endian
+ * endian = 0: little-endian
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian)
+{
+ uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320;
+ uint32_t c;
+ int i, j;
+
+ if (!crc_table)
+ crc_table = xmalloc(256 * sizeof(uint32_t));
+
+ for (i = 0; i < 256; i++) {
+ c = endian ? (i << 24) : i;
+ for (j = 8; j; j--) {
+ if (endian)
+ c = (c&0x80000000) ? ((c << 1) ^ polynomial) : (c << 1);
+ else
+ c = (c&1) ? ((c >> 1) ^ polynomial) : (c >> 1);
+ }
+ *crc_table++ = c;
+ }
+
+ return crc_table - 256;
+}
diff --git a/release/src/router/busybox/libbb/create_icmp6_socket.c b/release/src/router/busybox/libbb/create_icmp6_socket.c
index 59661044..91e478ec 100644
--- a/release/src/router/busybox/libbb/create_icmp6_socket.c
+++ b/release/src/router/busybox/libbb/create_icmp6_socket.c
@@ -2,37 +2,36 @@
/*
* Utility routines.
*
- * create raw socket for icmp (IPv6 version) protocol test permision
- * and drop root privilegies if running setuid
+ * create raw socket for icmp (IPv6 version) protocol
+ * and drop root privileges if running setuid
*
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#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)
+#if ENABLE_FEATURE_IPV6
+int FAST_FUNC create_icmp6_socket(void)
{
- struct protoent *proto;
int sock;
-
+#if 0
+ struct protoent *proto;
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) {
+ sock = socket(AF_INET6, SOCK_RAW,
+ (proto ? proto->p_proto : IPPROTO_ICMPV6));
+#else
+ sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+#endif
+ if (sock < 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);
+ bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
}
/* drop root privs if running setuid */
- setuid(getuid());
+ xsetuid(getuid());
return sock;
}
diff --git a/release/src/router/busybox/libbb/create_icmp_socket.c b/release/src/router/busybox/libbb/create_icmp_socket.c
index d804b398..d75f8452 100644
--- a/release/src/router/busybox/libbb/create_icmp_socket.c
+++ b/release/src/router/busybox/libbb/create_icmp_socket.c
@@ -2,36 +2,35 @@
/*
* Utility routines.
*
- * create raw socket for icmp protocol test permision
- * and drop root privilegies if running setuid
+ * create raw socket for icmp protocol
+ * and drop root privileges if running setuid
*
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#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)
+int FAST_FUNC create_icmp_socket(void)
{
- struct protoent *proto;
int sock;
-
+#if 0
+ struct protoent *proto;
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 */
+ sock = socket(AF_INET, SOCK_RAW,
+ (proto ? proto->p_proto : 1)); /* 1 == ICMP */
+#else
+ sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
+#endif
+ if (sock < 0) {
if (errno == EPERM)
- error_msg_and_die("permission denied. (are you root?)");
- else
- perror_msg_and_die(can_not_create_raw_socket);
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
}
/* drop root privs if running setuid */
- setuid(getuid());
+ xsetuid(getuid());
return sock;
}
diff --git a/release/src/router/busybox/libbb/daemon.c b/release/src/router/busybox/libbb/daemon.c
deleted file mode 100644
index 6d4169ed..00000000
--- a/release/src/router/busybox/libbb/daemon.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * daemon implementation for uClibc
- *
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Modified for uClibc by Erik Andersen
- * <andersee@debian.org>, <andersen@lineo.com>
- *
- * The uClibc Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * The GNU C Library 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 Library General Public
- * License along with the GNU C Library; see the file COPYING.LIB. 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 <features.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <unistd.h>
-
-
-#if __GNU_LIBRARY__ < 5
-
-int daemon( int nochdir, int noclose )
-{
- int fd;
-
- switch (fork()) {
- case -1:
- return(-1);
- case 0:
- break;
- default:
- _exit(0);
- }
-
- if (setsid() == -1)
- return(-1);
-
- 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);
- }
- return(0);
-}
-#endif
-
-
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
- * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
- *
- * 4. 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/release/src/router/busybox/libbb/default_error_retval.c b/release/src/router/busybox/libbb/default_error_retval.c
index 7d2d89bb..0b19f216 100644
--- a/release/src/router/busybox/libbb/default_error_retval.c
+++ b/release/src/router/busybox/libbb/default_error_retval.c
@@ -2,31 +2,17 @@
/*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* 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 configureable
+ * 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;
+int xfunc_error_retval = EXIT_FAILURE;
diff --git a/release/src/router/busybox/libbb/device_open.c b/release/src/router/busybox/libbb/device_open.c
index 8e97ce6c..cf8bcf64 100644
--- a/release/src/router/busybox/libbb/device_open.c
+++ b/release/src/router/busybox/libbb/device_open.c
@@ -2,45 +2,27 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <fcntl.h>
#include "libbb.h"
-
/* try to open up the specified device */
-extern int device_open(char *device, int mode)
+int FAST_FUNC device_open(const char *device, int mode)
{
- int m, f, fd = -1;
+ int m, f, fd;
m = mode | O_NONBLOCK;
/* Retry up to 5 times */
- for (f = 0; f < 5; f++)
- if ((fd = open(device, m, 0600)) >= 0)
+ /* TODO: explain why it can't be considered insane */
+ for (f = 0; f < 5; f++) {
+ fd = open(device, m, 0600);
+ if (fd >= 0)
break;
+ }
if (fd < 0)
return fd;
/* Reset original flags. */
@@ -48,12 +30,3 @@ extern int device_open(char *device, int 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/release/src/router/busybox/libbb/die_if_bad_username.c b/release/src/router/busybox/libbb/die_if_bad_username.c
new file mode 100644
index 00000000..c1641d37
--- /dev/null
+++ b/release/src/router/busybox/libbb/die_if_bad_username.c
@@ -0,0 +1,36 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Check user and group names for illegal characters
+ *
+ * Copyright (C) 2008 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* To avoid problems, the username should consist only of
+ * letters, digits, underscores, periods, at signs and dashes,
+ * and not start with a dash (as defined by IEEE Std 1003.1-2001).
+ * For compatibility with Samba machine accounts $ is also supported
+ * at the end of the username.
+ */
+
+void FAST_FUNC die_if_bad_username(const char *name)
+{
+ goto skip; /* 1st char being dash isn't valid */
+ do {
+ if (*name == '-')
+ continue;
+ skip:
+ if (isalnum(*name)
+ || *name == '_'
+ || *name == '.'
+ || *name == '@'
+ || (*name == '$' && !*(name + 1))
+ ) {
+ continue;
+ }
+ bb_error_msg_and_die("illegal character '%c'", *name);
+ } while (*++name);
+}
diff --git a/release/src/router/busybox/libbb/dirname.c b/release/src/router/busybox/libbb/dirname.c
deleted file mode 100644
index 5f839945..00000000
--- a/release/src/router/busybox/libbb/dirname.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini dirname function.
- *
- * Copyright (C) 2001 Matt Kraai.
- *
- * 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"
-
-/* Return a string on the heap containing the directory component of PATH. */
-
-char *dirname(const char *path)
-{
- const char *s;
-
- /* Go to the end of the string. */
- s = path + strlen(path) - 1;
-
- /* Strip off trailing /s (unless it is also the leading /). */
- while (path < s && s[0] == '/')
- s--;
-
- /* Strip the last component. */
- while (path <= s && s[0] != '/')
- s--;
-
- while (path < s && s[0] == '/')
- s--;
-
- if (s < path)
- return xstrdup (".");
- else
- return xstrndup (path, s - path + 1);
-}
diff --git a/release/src/router/busybox/libbb/dump.c b/release/src/router/busybox/libbb/dump.c
index 5a43b7c7..2e777c35 100644
--- a/release/src/router/busybox/libbb/dump.c
+++ b/release/src/router/busybox/libbb/dump.c
@@ -1,3 +1,4 @@
+/* vi: set sw=4 ts=4: */
/*
* Support code for the hexdump and od applets,
* based on code from util-linux v 2.11l
@@ -5,53 +6,55 @@
* 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
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
* Original copyright notice is retained at the end of this file.
*/
-#include <stdlib.h>
-#include <string.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[] =
+static const char index_str[] ALIGN1 = ".#-+ 0123456789";
+
+static const char size_conv_str[] ALIGN1 =
"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
-static const char lcc[] = "diouxX";
+static const char lcc[] ALIGN1 = "diouxX";
+
+
+typedef struct priv_dumper_t {
+ dumper_t pub;
+
+ char **argv;
+ FU *endfu;
+ off_t savaddress; /* saved address/offset in stream */
+ off_t eaddress; /* end address */
+ off_t address; /* address/offset in stream */
+ int blocksize;
+ smallint exitval; /* final exit value */
+
+ /* former statics */
+ smallint next__done;
+ smallint get__ateof; // = 1;
+ unsigned char *get__curp;
+ unsigned char *get__savp;
+} priv_dumper_t;
-int bb_dump_size(FS * fs)
+dumper_t* FAST_FUNC alloc_dumper(void)
{
- register FU *fu;
- register int bcnt, cur_size;
- register char *fmt;
+ priv_dumper_t *dumper = xzalloc(sizeof(*dumper));
+ dumper->pub.dump_length = -1;
+ dumper->pub.dump_vflag = FIRST;
+ dumper->get__ateof = 1;
+ return &dumper->pub;
+}
+
+
+static NOINLINE int bb_dump_size(FS *fs)
+{
+ FU *fu;
+ int bcnt, cur_size;
+ char *fmt;
const char *p;
int prec;
@@ -65,15 +68,17 @@ int bb_dump_size(FS * fs)
if (*fmt != '%')
continue;
/*
- * bb_dump_skip any special chars -- save precision in
+ * 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));
+ while (isdigit(*++fmt))
+ continue;
}
- if (!(p = strchr(size_conv_str + 12, *fmt))) {
+ p = strchr(size_conv_str + 12, *fmt);
+ if (!p) {
if (*fmt == 's') {
bcnt += prec;
} else if (*fmt == '_') {
@@ -88,15 +93,15 @@ int bb_dump_size(FS * fs)
}
cur_size += bcnt * fu->reps;
}
- return (cur_size);
+ return cur_size;
}
-static void rewrite(FS * fs)
+static void rewrite(priv_dumper_t *dumper, FS *fs)
{
enum { NOTOKAY, USEBCNT, USEPREC } sokay;
- register PR *pr, **nextpr = NULL;
- register FU *fu;
- register char *p1, *p2, *p3;
+ PR *pr, **nextpr = NULL;
+ FU *fu;
+ char *p1, *p2, *p3;
char savech, *fmtp;
const char *byte_count_str;
int nconv, prec = 0;
@@ -108,16 +113,17 @@ static void rewrite(FS * fs)
*/
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));
+ /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/
+ pr = xzalloc(sizeof(PR));
if (!fu->nextpr)
fu->nextpr = pr;
/* ignore nextpr -- its unused inside the loop and is
- * uninitialized 1st time thru.
+ * uninitialized 1st time through.
*/
- /* bb_dump_skip preceding text and up to the next % sign */
- for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
+ /* skip preceding text and up to the next % sign */
+ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1)
+ continue;
/* only text in the string */
if (!*p1) {
@@ -132,32 +138,34 @@ static void rewrite(FS * fs)
*/
if (fu->bcnt) {
sokay = USEBCNT;
- /* bb_dump_skip to conversion character */
- for (++p1; strchr(index_str, *p1); ++p1);
+ /* skip to conversion character */
+ for (++p1; strchr(index_str, *p1); ++p1)
+ continue;
} else {
- /* bb_dump_skip any special chars, field width */
- while (strchr(index_str + 1, *++p1));
+ /* skip any special chars, field width */
+ while (strchr(index_str + 1, *++p1))
+ continue;
if (*p1 == '.' && isdigit(*++p1)) {
sokay = USEPREC;
prec = atoi(p1);
- while (isdigit(*++p1));
+ while (isdigit(*++p1))
+ continue;
} else
sokay = NOTOKAY;
}
- p2 = p1 + 1; /* set end pointer */
+ 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:
+ DO_BYTE_COUNT_1:
byte_count_str = "\001";
- DO_BYTE_COUNT:
+ DO_BYTE_COUNT:
if (fu->bcnt) {
do {
if (fu->bcnt == *byte_count_str) {
@@ -167,16 +175,17 @@ static void rewrite(FS * fs)
}
/* 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);
+ 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:
+ DO_INT_CONV:
{
const char *e;
- if (!(e = strchr(lcc, *p1))) {
+ e = strchr(lcc, *p1);
+ if (!e) {
goto DO_BAD_CONV_CHAR;
}
pr->flags = F_INT;
@@ -200,13 +209,13 @@ static void rewrite(FS * fs)
} else if (sokay == USEPREC) {
pr->bcnt = prec;
} else { /* NOTOKAY */
- bb_error_msg_and_die("%%s requires a precision or a byte count.");
+ bb_error_msg_and_die("%%s requires a precision or a byte count");
}
} else if (*p1 == '_') {
++p2;
switch (p1[1]) {
case 'A':
- endfu = fu;
+ dumper->endfu = fu;
fu->flags |= F_IGNORE;
/* FALLTHROUGH */
case 'a':
@@ -233,8 +242,8 @@ static void rewrite(FS * fs)
goto DO_BAD_CONV_CHAR;
}
} else {
- DO_BAD_CONV_CHAR:
- bb_error_msg_and_die("bad conversion character %%%s.\n", p1);
+ DO_BAD_CONV_CHAR:
+ bb_error_msg_and_die("bad conversion character %%%s", p1);
}
/*
@@ -243,32 +252,33 @@ static void rewrite(FS * fs)
*/
savech = *p2;
p1[1] = '\0';
- pr->fmt = bb_xstrdup(fmtp);
+ pr->fmt = xstrdup(fmtp);
*p2 = savech;
- pr->cchar = pr->fmt + (p1 - fmtp);
+ //Too early! xrealloc can move pr->fmt!
+ //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",
+ * 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)
- {
+ for (p3 = p2; *p3 && *p3 != '%'; p3++)
+ continue;
+ 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");
+ pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt) + (p3-p2) + 1);
strcat(pr->fmt, p2);
*p3 = savech;
p2 = p3;
}
+ pr->cchar = pr->fmt + (p1 - fmtp);
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");
+ bb_error_msg_and_die("byte count with multiple conversion characters");
}
}
/*
@@ -281,17 +291,19 @@ static void rewrite(FS * fs)
}
/*
* 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
+ * not the same as the 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;
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (!fu->nextfu && fs->bcnt < dumper->blocksize
+ && !(fu->flags & F_SETREP) && fu->bcnt
+ ) {
+ fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt;
+ }
if (fu->reps > 1) {
for (pr = fu->nextpr;; pr = pr->nextpr)
if (!pr->nextpr)
@@ -306,128 +318,129 @@ static void rewrite(FS * fs)
}
}
-static void do_skip(char *fname, int statok)
+static void do_skip(priv_dumper_t *dumper, const char *fname, int statok)
{
struct stat sbuf;
if (statok) {
- if (fstat(fileno(stdin), &sbuf)) {
- bb_perror_msg_and_die("%s", fname);
+ if (fstat(STDIN_FILENO, &sbuf)) {
+ bb_simple_perror_msg_and_die(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;
+ if (!(S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode) || S_ISFIFO(sbuf.st_mode))
+ && dumper->pub.dump_skip >= sbuf.st_size
+ ) {
+ /* If bb_dump_size valid and pub.dump_skip >= size */
+ dumper->pub.dump_skip -= sbuf.st_size;
+ dumper->address += sbuf.st_size;
return;
}
}
- if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
- bb_perror_msg_and_die("%s", fname);
+ if (fseek(stdin, dumper->pub.dump_skip, SEEK_SET)) {
+ bb_simple_perror_msg_and_die(fname);
}
- savaddress = address += bb_dump_skip;
- bb_dump_skip = 0;
+ dumper->address += dumper->pub.dump_skip;
+ dumper->savaddress = dumper->address;
+ dumper->pub.dump_skip = 0;
}
-static int next(char **argv)
+static NOINLINE int next(priv_dumper_t *dumper)
{
- 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;
+ if (*dumper->argv) {
+ if (!(freopen(*dumper->argv, "r", stdin))) {
+ bb_simple_perror_msg(*dumper->argv);
+ dumper->exitval = 1;
+ ++dumper->argv;
continue;
}
- statok = done = 1;
+ dumper->next__done = statok = 1;
} else {
- if (done++)
- return (0);
+ if (dumper->next__done)
+ return 0;
+ dumper->next__done = 1;
statok = 0;
}
- if (bb_dump_skip)
- do_skip(statok ? *_argv : "stdin", statok);
- if (*_argv)
- ++_argv;
- if (!bb_dump_skip)
- return (1);
+ if (dumper->pub.dump_skip)
+ do_skip(dumper, statok ? *dumper->argv : "stdin", statok);
+ if (*dumper->argv)
+ ++dumper->argv;
+ if (!dumper->pub.dump_skip)
+ return 1;
}
/* NOTREACHED */
}
-static u_char *get(void)
+static unsigned char *get(priv_dumper_t *dumper)
{
- static int ateof = 1;
- static u_char *curp=NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
- register int n;
+ int n;
int need, nread;
- u_char *tmpp;
+ int blocksize = dumper->blocksize;
- 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);
+ if (!dumper->get__curp) {
+ dumper->address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
+ dumper->get__curp = xmalloc(blocksize);
+ dumper->get__savp = xzalloc(blocksize); /* need to be initialized */
} else {
- tmpp = curp;
- curp = savp;
- savp = tmpp;
- address = savaddress += bb_dump_blocksize;
+ unsigned char *tmp = dumper->get__curp;
+ dumper->get__curp = dumper->get__savp;
+ dumper->get__savp = tmp;
+ dumper->savaddress += blocksize;
+ dumper->address = dumper->savaddress;
}
- for (need = bb_dump_blocksize, nread = 0;;) {
+ need = blocksize;
+ nread = 0;
+ while (1) {
/*
* 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 (!dumper->pub.dump_length || (dumper->get__ateof && !next(dumper))) {
+ if (need == blocksize) {
+ return NULL;
}
- if (bb_dump_vflag != ALL && !bcmp(curp, savp, nread)) {
- if (bb_dump_vflag != DUP) {
- printf("*\n");
+ if (dumper->pub.dump_vflag != ALL && !memcmp(dumper->get__curp, dumper->get__savp, nread)) {
+ if (dumper->pub.dump_vflag != DUP) {
+ puts("*");
}
- return ((u_char *) NULL);
+ return NULL;
}
- bzero((char *) curp + nread, need);
- eaddress = address + nread;
- return (curp);
+ memset(dumper->get__curp + nread, 0, need);
+ dumper->eaddress = dumper->address + nread;
+ return dumper->get__curp;
}
- n = fread((char *) curp + nread, sizeof(u_char),
- bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
+ n = fread(dumper->get__curp + nread, sizeof(unsigned char),
+ dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin);
if (!n) {
if (ferror(stdin)) {
- bb_perror_msg("%s", _argv[-1]);
+ bb_simple_perror_msg(dumper->argv[-1]);
}
- ateof = 1;
+ dumper->get__ateof = 1;
continue;
}
- ateof = 0;
- if (bb_dump_length != -1) {
- bb_dump_length -= n;
+ dumper->get__ateof = 0;
+ if (dumper->pub.dump_length != -1) {
+ dumper->pub.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;
+ need -= n;
+ if (!need) {
+ if (dumper->pub.dump_vflag == ALL || dumper->pub.dump_vflag == FIRST
+ || memcmp(dumper->get__curp, dumper->get__savp, blocksize)
+ ) {
+ if (dumper->pub.dump_vflag == DUP || dumper->pub.dump_vflag == FIRST) {
+ dumper->pub.dump_vflag = WAIT;
}
- return (curp);
+ return dumper->get__curp;
}
- if (bb_dump_vflag == WAIT) {
- printf("*\n");
+ if (dumper->pub.dump_vflag == WAIT) {
+ puts("*");
}
- bb_dump_vflag = DUP;
- address = savaddress += bb_dump_blocksize;
- need = bb_dump_blocksize;
+ dumper->pub.dump_vflag = DUP;
+ dumper->savaddress += blocksize;
+ dumper->address = dumper->savaddress;
+ need = blocksize;
nread = 0;
} else {
nread += n;
@@ -435,9 +448,9 @@ static u_char *get(void)
}
}
-static void bpad(PR * pr)
+static void bpad(PR *pr)
{
- register char *p1, *p2;
+ char *p1, *p2;
/*
* remove all conversion flags; '-' is the only one valid
@@ -445,12 +458,16 @@ static void bpad(PR * pr)
*/
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);
+ for (p1 = pr->fmt; *p1 != '%'; ++p1)
+ continue;
+ for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
+ if (pr->nospace)
+ pr->nospace--;
+ while ((*p2++ = *p1++) != 0)
+ continue;
}
-static const char conv_str[] =
+static const char conv_str[] ALIGN1 =
"\0\\0\0"
"\007\\a\0" /* \a */
"\b\\b\0"
@@ -459,10 +476,10 @@ static const char conv_str[] =
"\r\\r\0"
"\t\\t\0"
"\v\\v\0"
- "\0";
+ ;
-static void conv_c(PR * pr, u_char * p)
+static void conv_c(PR *pr, unsigned char *p)
{
const char *str = conv_str;
char buf[10];
@@ -477,7 +494,7 @@ static void conv_c(PR * pr, u_char * p)
if (isprint(*p)) {
*pr->cchar = 'c';
- (void) printf(pr->fmt, *p);
+ printf(pr->fmt, *p);
} else {
sprintf(buf, "%03o", (int) *p);
str = buf;
@@ -487,9 +504,9 @@ static void conv_c(PR * pr, u_char * p)
}
}
-static void conv_u(PR * pr, u_char * p)
+static void conv_u(PR *pr, unsigned char *p)
{
- static const char list[] =
+ static const char list[] ALIGN1 =
"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"
@@ -498,7 +515,7 @@ static void conv_u(PR * pr, u_char * p)
/* od used nl, not lf */
if (*p <= 0x1f) {
*pr->cchar = 's';
- printf(pr->fmt, list[4 * (int)(*p)]);
+ printf(pr->fmt, list + (4 * (int)*p));
} else if (*p == 0x7f) {
*pr->cchar = 's';
printf(pr->fmt, "del");
@@ -511,30 +528,31 @@ static void conv_u(PR * pr, u_char * p)
}
}
-static void display(void)
+static void display(priv_dumper_t* dumper)
{
-/* extern FU *endfu; */
- register FS *fs;
- register FU *fu;
- register PR *pr;
- register int cnt;
- register u_char *bp;
-
+ FS *fs;
+ FU *fu;
+ PR *pr;
+ int cnt;
+ unsigned char *bp, *savebp;
off_t saveaddress;
- u_char savech = 0, *savebp;
+ unsigned char savech = '\0';
- while ((bp = get()) != NULL) {
- for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
- fs = fs->nextfs, bp = savebp, address = saveaddress) {
+ while ((bp = get(dumper)) != NULL) {
+ fs = dumper->pub.fshead;
+ savebp = bp;
+ saveaddress = dumper->address;
+ for (; fs; fs = fs->nextfs, bp = savebp, dumper->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))) {
+ for (pr = fu->nextpr; pr; dumper->address += pr->bcnt,
+ bp += pr->bcnt, pr = pr->nextpr) {
+ if (dumper->eaddress && dumper->address >= dumper->eaddress
+ && !(pr->flags & (F_TEXT | F_BPAD))
+ ) {
bpad(pr);
}
if (cnt == 1 && pr->nospace) {
@@ -544,7 +562,7 @@ static void display(void)
/* PRINT; */
switch (pr->flags) {
case F_ADDRESS:
- printf(pr->fmt, address);
+ printf(pr->fmt, (unsigned) dumper->address);
break;
case F_BPAD:
printf(pr->fmt, "");
@@ -555,25 +573,23 @@ static void display(void)
case F_CHAR:
printf(pr->fmt, *bp);
break;
- case F_DBL:{
+ case F_DBL: {
double dval;
float fval;
switch (pr->bcnt) {
case 4:
- bcopy((char *) bp, (char *) &fval,
- sizeof(fval));
+ memcpy(&fval, bp, sizeof(fval));
printf(pr->fmt, fval);
break;
case 8:
- bcopy((char *) bp, (char *) &dval,
- sizeof(dval));
+ memcpy(&dval, bp, sizeof(dval));
printf(pr->fmt, dval);
break;
}
break;
}
- case F_INT:{
+ case F_INT: {
int ival;
short sval;
@@ -582,13 +598,11 @@ static void display(void)
printf(pr->fmt, (int) *bp);
break;
case 2:
- bcopy((char *) bp, (char *) &sval,
- sizeof(sval));
+ memcpy(&sval, bp, sizeof(sval));
printf(pr->fmt, (int) sval);
break;
case 4:
- bcopy((char *) bp, (char *) &ival,
- sizeof(ival));
+ memcpy(&ival, bp, sizeof(ival));
printf(pr->fmt, ival);
break;
}
@@ -606,22 +620,20 @@ static void display(void)
case F_U:
conv_u(pr, bp);
break;
- case F_UINT:{
- u_int ival;
- u_short sval;
+ case F_UINT: {
+ unsigned ival;
+ unsigned short sval;
switch (pr->bcnt) {
case 1:
- printf(pr->fmt, (u_int) * bp);
+ printf(pr->fmt, (unsigned) *bp);
break;
case 2:
- bcopy((char *) bp, (char *) &sval,
- sizeof(sval));
- printf(pr->fmt, (u_int) sval);
+ memcpy(&sval, bp, sizeof(sval));
+ printf(pr->fmt, (unsigned) sval);
break;
case 4:
- bcopy((char *) bp, (char *) &ival,
- sizeof(ival));
+ memcpy(&ival, bp, sizeof(ival));
printf(pr->fmt, ival);
break;
}
@@ -636,116 +648,127 @@ static void display(void)
}
}
}
- if (endfu) {
+ if (dumper->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 not set, error or file size was multiple
+ * of blocksize, and no partial block ever found.
*/
- if (!eaddress) {
- if (!address) {
+ if (!dumper->eaddress) {
+ if (!dumper->address) {
return;
}
- eaddress = address;
+ dumper->eaddress = dumper->address;
}
- for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
+ for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) {
switch (pr->flags) {
case F_ADDRESS:
- (void) printf(pr->fmt, eaddress);
+ printf(pr->fmt, (unsigned) dumper->eaddress);
break;
case F_TEXT:
- (void) printf(pr->fmt);
+ printf(pr->fmt);
break;
}
}
}
}
-int bb_dump_dump(char **argv)
+#define dumper ((priv_dumper_t*)pub_dumper)
+int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv)
{
- register FS *tfs;
+ FS *tfs;
+ int blocksize;
/* figure out the data block bb_dump_size */
- for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
+ blocksize = 0;
+ tfs = dumper->pub.fshead;
+ while (tfs) {
tfs->bcnt = bb_dump_size(tfs);
- if (bb_dump_blocksize < tfs->bcnt) {
- bb_dump_blocksize = tfs->bcnt;
+ if (blocksize < tfs->bcnt) {
+ blocksize = tfs->bcnt;
}
+ tfs = tfs->nextfs;
}
+ dumper->blocksize = blocksize;
+
/* rewrite the rules, do syntax checking */
- for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
- rewrite(tfs);
+ for (tfs = dumper->pub.fshead; tfs; tfs = tfs->nextfs) {
+ rewrite(dumper, tfs);
}
- next(argv);
- display();
+ dumper->argv = argv;
+ display(dumper);
- return (exitval);
+ return dumper->exitval;
}
-void bb_dump_add(const char *fmt)
+void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
{
- register const char *p;
- register char *p1;
- register char *p2;
- static FS **nextfs;
+ const char *p;
+ char *p1;
+ char *p2;
FS *tfs;
- FU *tfu, **nextfu;
+ FU *tfu, **nextfupp;
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;
+ tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
+ if (!dumper->pub.fshead) {
+ dumper->pub.fshead = tfs;
} else {
- *nextfs = tfs;
+ FS *fslast = dumper->pub.fshead;
+ while (fslast->nextfs)
+ fslast = fslast->nextfs;
+ fslast->nextfs = tfs;
}
- nextfs = &tfs->nextfs;
- nextfu = &tfs->nextfu;
+ nextfupp = &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);
+ p = fmt;
+ for (;;) {
+ p = 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;
+ /* DBU:[dave@cray.com] zalloc so that forward pointers start out NULL */
+ tfu = xzalloc(sizeof(FU));
+ *nextfupp = tfu;
+ nextfupp = &tfu->nextfu;
tfu->reps = 1;
/* if leading digit, repetition count */
if (isdigit(*p)) {
- for (savep = p; isdigit(*p); ++p);
+ for (savep = p; isdigit(*p); ++p)
+ continue;
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);
+ /* skip trailing white space */
+ p = skip_whitespace(++p);
}
- /* bb_dump_skip slash and trailing white space */
+ /* skip slash and trailing white space */
if (*p == '/') {
- p = bb_skip_whitespace(++p);
+ p = skip_whitespace(++p);
}
/* byte count */
if (isdigit(*p)) {
- for (savep = p; isdigit(*p); ++p);
+// TODO: use bb_strtou
+ savep = p;
+ while (isdigit(*++p))
+ continue;
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);
+ /* skip trailing white space */
+ p = skip_whitespace(++p);
}
/* format */
@@ -757,9 +780,7 @@ void bb_dump_add(const char *fmt)
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';
+ tfu->fmt = xstrndup(savep, p - savep);
/* escape(tfu->fmt); */
p1 = tfu->fmt;
diff --git a/release/src/router/busybox/libbb/error_msg.c b/release/src/router/busybox/libbb/error_msg.c
index c7d5fdb9..802fd571 100644
--- a/release/src/router/busybox/libbb/error_msg.c
+++ b/release/src/router/busybox/libbb/error_msg.c
@@ -2,51 +2,18 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
#include "libbb.h"
-extern void error_msg(const char *s, ...)
+void FAST_FUNC bb_error_msg(const char *s, ...)
{
va_list p;
va_start(p, s);
- verror_msg(s, p);
+ bb_verror_msg(s, p, NULL);
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/release/src/router/busybox/libbb/error_msg_and_die.c b/release/src/router/busybox/libbb/error_msg_and_die.c
index b950ee00..243433b2 100644
--- a/release/src/router/busybox/libbb/error_msg_and_die.c
+++ b/release/src/router/busybox/libbb/error_msg_and_die.c
@@ -2,52 +2,19 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
#include "libbb.h"
-extern void error_msg_and_die(const char *s, ...)
+void FAST_FUNC bb_error_msg_and_die(const char *s, ...)
{
va_list p;
va_start(p, s);
- verror_msg(s, p);
+ bb_verror_msg(s, p, NULL);
va_end(p);
- putc('\n', stderr);
- exit(EXIT_FAILURE);
+ xfunc_die();
}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/execable.c b/release/src/router/busybox/libbb/execable.c
new file mode 100644
index 00000000..5c7ac16a
--- /dev/null
+++ b/release/src/router/busybox/libbb/execable.c
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2006 Gabriel Somlo <somlo at cmu.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* check if path points to an executable file;
+ * return 1 if found;
+ * return 0 otherwise;
+ */
+int FAST_FUNC execable_file(const char *name)
+{
+ struct stat s;
+ return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
+}
+
+/* search (*PATHp) for an executable file;
+ * return allocated string containing full path if found;
+ * PATHp points to the component after the one where it was found
+ * (or NULL),
+ * you may call find_execable again with this PATHp to continue
+ * (if it's not NULL).
+ * return NULL otherwise; (PATHp is undefined)
+ * in all cases (*PATHp) contents will be trashed (s/:/NUL/).
+ */
+char* FAST_FUNC find_execable(const char *filename, char **PATHp)
+{
+ char *p, *n;
+
+ p = *PATHp;
+ while (p) {
+ n = strchr(p, ':');
+ if (n)
+ *n++ = '\0';
+ if (*p != '\0') { /* it's not a PATH="foo::bar" situation */
+ p = concat_path_file(p, filename);
+ if (execable_file(p)) {
+ *PATHp = n;
+ return p;
+ }
+ free(p);
+ }
+ p = n;
+ } /* on loop exit p == NULL */
+ return p;
+}
+
+/* search $PATH for an executable file;
+ * return 1 if found;
+ * return 0 otherwise;
+ */
+int FAST_FUNC exists_execable(const char *filename)
+{
+ char *path = xstrdup(getenv("PATH"));
+ char *tmp = path;
+ char *ret = find_execable(filename, &tmp);
+ free(path);
+ if (ret) {
+ free(ret);
+ return 1;
+ }
+ return 0;
+}
+
+#if ENABLE_FEATURE_PREFER_APPLETS
+/* just like the real execvp, but try to launch an applet named 'file' first
+ */
+int FAST_FUNC bb_execvp(const char *file, char *const argv[])
+{
+ return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file,
+ argv);
+}
+#endif
diff --git a/release/src/router/busybox/libbb/fclose_nonstdin.c b/release/src/router/busybox/libbb/fclose_nonstdin.c
index 97e303e9..6f3f3733 100644
--- a/release/src/router/busybox/libbb/fclose_nonstdin.c
+++ b/release/src/router/busybox/libbb/fclose_nonstdin.c
@@ -4,34 +4,22 @@
*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-/* A number of standard utilites can accept multiple command line args
+/* 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>
+#include "libbb.h"
-int bb_fclose_nonstdin(FILE *f)
+int FAST_FUNC fclose_if_not_stdin(FILE *f)
{
- if (f != stdin) {
- return fclose(f);
- }
- return 0;
+ /* Some more paranoid applets want ferror() check too */
+ int r = ferror(f); /* NB: does NOT set errno! */
+ if (r) errno = EIO; /* so we'll help it */
+ if (f != stdin)
+ return (r | fclose(f)); /* fclose does set errno on error */
+ return r;
}
diff --git a/release/src/router/busybox/libbb/fflush_stdout_and_exit.c b/release/src/router/busybox/libbb/fflush_stdout_and_exit.c
index cbba0420..742fb9f5 100644
--- a/release/src/router/busybox/libbb/fflush_stdout_and_exit.c
+++ b/release/src/router/busybox/libbb/fflush_stdout_and_exit.c
@@ -4,34 +4,26 @@
*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* 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>
+#include "libbb.h"
-void bb_fflush_stdout_and_exit(int retval)
+void FAST_FUNC fflush_stdout_and_exit(int retval)
{
- if (fflush(stdout)) {
- retval = bb_default_error_retval;
+ if (fflush(stdout))
+ bb_perror_msg_and_die(bb_msg_standard_output);
+
+ if (ENABLE_FEATURE_PREFER_APPLETS && die_sleep < 0) {
+ /* We are in NOFORK applet. Do not exit() directly,
+ * but use xfunc_die() */
+ xfunc_error_retval = retval;
+ xfunc_die();
}
+
exit(retval);
}
diff --git a/release/src/router/busybox/libbb/fgets_str.c b/release/src/router/busybox/libbb/fgets_str.c
index 33d8d00c..3fe61cdc 100644
--- a/release/src/router/busybox/libbb/fgets_str.c
+++ b/release/src/router/busybox/libbb/fgets_str.c
@@ -1,31 +1,16 @@
+/* vi: set sw=4 ts=4: */
/*
- * 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.
+ * Utility routines.
*
- * 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.
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
*
- * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
+#include "libbb.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Continue reading from file until the terminating string is encountered.
- * Return data as string.
- * e.g. fgets_str(file, "\n"); will read till end of file
- */
-
-char *fgets_str(FILE *file, const char *terminating_string)
+static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off, size_t *maxsz_p)
{
char *linebuf = NULL;
const int term_length = strlen(terminating_string);
@@ -33,16 +18,24 @@ char *fgets_str(FILE *file, const char *terminating_string)
int linebufsz = 0;
int idx = 0;
int ch;
+ size_t maxsz = *maxsz_p;
while (1) {
ch = fgetc(file);
if (ch == EOF) {
+ if (idx == 0)
+ return linebuf; /* NULL */
break;
}
- /* grow the line buffer as necessary */
- while (idx > linebufsz - 2) {
- linebuf = realloc(linebuf, linebufsz += 1000); /* GROWBY */
+ if (idx >= linebufsz) {
+ linebufsz += 200;
+ linebuf = xrealloc(linebuf, linebufsz);
+ if (idx >= maxsz) {
+ linebuf[idx] = ch;
+ idx++;
+ break;
+ }
}
linebuf[idx] = ch;
@@ -50,15 +43,44 @@ char *fgets_str(FILE *file, const char *terminating_string)
/* 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;
+ if (end_string_offset >= 0
+ && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
+ ) {
+ if (chop_off)
+ idx -= term_length;
break;
}
}
- if (idx == 0) {
- return NULL;
- }
+ /* Grow/shrink *first*, then store NUL */
+ linebuf = xrealloc(linebuf, idx + 1);
linebuf[idx] = '\0';
- return(linebuf);
+ *maxsz_p = idx;
+ return linebuf;
+}
+
+/* Read up to TERMINATING_STRING from FILE and return it,
+ * including terminating string.
+ * Non-terminated string can be returned if EOF is reached.
+ * Return NULL if EOF is reached immediately. */
+char* FAST_FUNC xmalloc_fgets_str(FILE *file, const char *terminating_string)
+{
+ size_t maxsz = INT_MAX - 4095;
+ return xmalloc_fgets_internal(file, terminating_string, 0, &maxsz);
}
+char* FAST_FUNC xmalloc_fgets_str_len(FILE *file, const char *terminating_string, size_t *maxsz_p)
+{
+ size_t maxsz;
+
+ if (!maxsz_p) {
+ maxsz = INT_MAX - 4095;
+ maxsz_p = &maxsz;
+ }
+ return xmalloc_fgets_internal(file, terminating_string, 0, maxsz_p);
+}
+
+char* FAST_FUNC xmalloc_fgetline_str(FILE *file, const char *terminating_string)
+{
+ size_t maxsz = INT_MAX - 4095;
+ return xmalloc_fgets_internal(file, terminating_string, 1, &maxsz);
+}
diff --git a/release/src/router/busybox/libbb/find_mount_point.c b/release/src/router/busybox/libbb/find_mount_point.c
index 2d9481a6..12b2cfce 100644
--- a/release/src/router/busybox/libbb/find_mount_point.c
+++ b/release/src/router/busybox/libbb/find_mount_point.c
@@ -2,35 +2,14 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#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.
@@ -38,7 +17,7 @@
* 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 mntent* FAST_FUNC find_mount_point(const char *name)
{
struct stat s;
dev_t mountDevice;
@@ -46,36 +25,37 @@ extern struct mntent *find_mount_point(const char *name, const char *table)
struct mntent *mountEntry;
if (stat(name, &s) != 0)
- return 0;
+ return NULL;
- if ((s.st_mode & S_IFMT) == S_IFBLK)
+ if (S_ISBLK(s.st_mode))
mountDevice = s.st_rdev;
else
mountDevice = s.st_dev;
- if ((mountTable = setmntent(table, "r")) == 0)
+ mountTable = setmntent(bb_path_mtab_file, "r");
+ if (!mountTable)
return 0;
- while ((mountEntry = getmntent(mountTable)) != 0) {
+ while ((mountEntry = getmntent(mountTable)) != NULL) {
+ /* rootfs mount in Linux 2.6 exists always,
+ * and it makes sense to always ignore it.
+ * Otherwise people can't reference their "real" root! */
+ if (strcmp(mountEntry->mnt_fsname, "rootfs") == 0)
+ continue;
+
if (strcmp(name, mountEntry->mnt_dir) == 0
- || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */
+ || strcmp(name, mountEntry->mnt_fsname) == 0
+ ) { /* String match. */
break;
- if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */
+ }
+ /* Match the device. */
+ if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice)
break;
- if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */
+ /* Match the directory's mount point. */
+ if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice)
break;
}
endmntent(mountTable);
return mountEntry;
}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/find_pid_by_name.c b/release/src/router/busybox/libbb/find_pid_by_name.c
index 7f39dd41..600d4e1a 100644
--- a/release/src/router/busybox/libbb/find_pid_by_name.c
+++ b/release/src/router/busybox/libbb/find_pid_by_name.c
@@ -2,198 +2,115 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
*/
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <dirent.h>
-#include <stdlib.h>
#include "libbb.h"
-#define READ_BUF_SIZE 50
+/*
+In Linux we have three ways to determine "process name":
+1. /proc/PID/stat has "...(name)...", among other things. It's so-called "comm" field.
+2. /proc/PID/cmdline's first NUL-terminated string. It's argv[0] from exec syscall.
+3. /proc/PID/exe symlink. Points to the running executable file.
+
+kernel threads:
+ comm: thread name
+ cmdline: empty
+ exe: <readlink fails>
+
+executable
+ comm: first 15 chars of base name
+ (if executable is a symlink, then first 15 chars of symlink name are used)
+ cmdline: argv[0] from exec syscall
+ exe: points to executable (resolves symlink, unlike comm)
+
+script (an executable with #!/path/to/interpreter):
+ comm: first 15 chars of script's base name (symlinks are not resolved)
+ cmdline: /path/to/interpreter (symlinks are not resolved)
+ (script name is in argv[1], args are pushed into argv[2] etc)
+ exe: points to interpreter's executable (symlinks are resolved)
+
+If FEATURE_PREFER_APPLETS=y (and more so if FEATURE_SH_STANDALONE=y),
+some commands started from busybox shell, xargs or find are started by
+execXXX("/proc/self/exe", applet_name, params....)
+and therefore comm field contains "exe".
+*/
+static int comm_match(procps_status_t *p, const char *procName)
+{
+ int argv1idx;
-/* For Erik's nifty devps device driver */
-#ifdef BB_FEATURE_USE_DEVPS_PATCH
-#include <linux/devps.h>
+ /* comm does not match */
+ if (strncmp(p->comm, procName, 15) != 0)
+ return 0;
-/* find_pid_by_name()
- *
- * This finds the pid of the specified process,
- * by using the /dev/ps device driver.
- *
- * Returns a list of all matching PIDs
- */
-extern pid_t* find_pid_by_name( char* pidName)
-{
- int fd, i, j;
- char device[] = "/dev/ps";
- pid_t num_pids;
- pid_t* pid_array = NULL;
- pid_t* pidList=NULL;
-
- /* open device */
- fd = open(device, O_RDONLY);
- if (fd < 0)
- perror_msg_and_die("open failed for `%s'", device);
-
- /* Find out how many processes there are */
- if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0)
- perror_msg_and_die("\nDEVPS_GET_PID_LIST");
-
- /* Allocate some memory -- grab a few extras just in case
- * some new processes start up while we wait. The kernel will
- * just ignore any extras if we give it too many, and will trunc.
- * the list if we give it too few. */
- pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t));
- pid_array[0] = num_pids+10;
-
- /* Now grab the pid list */
- if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0)
- perror_msg_and_die("\nDEVPS_GET_PID_LIST");
-
- /* Now search for a match */
- for (i=1, j=0; i<pid_array[0] ; i++) {
- char* p;
- struct pid_info info;
-
- info.pid = pid_array[i];
- if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
- perror_msg_and_die("\nDEVPS_GET_PID_INFO");
-
- /* Make sure we only match on the process name */
- p=info.command_line+1;
- while ((*p != 0) && !isspace(*(p)) && (*(p-1) != '\\')) {
- (p)++;
- }
- if (isspace(*(p)))
- *p='\0';
+ /* in Linux, if comm is 15 chars, it may be a truncated */
+ if (p->comm[14] == '\0') /* comm is not truncated - match */
+ return 1;
- if ((strstr(info.command_line, pidName) != NULL)
- && (strlen(pidName) == strlen(info.command_line))) {
- pidList=xrealloc( pidList, sizeof(pid_t) * (j+2));
- pidList[j++]=info.pid;
- }
- }
- if (pidList) {
- pidList[j]=0;
- } else if ( strcmp(pidName, "init")==0) {
- /* If we found nothing and they were trying to kill "init",
- * guess PID 1 and call it good... Perhaps we should simply
- * exit if /proc isn't mounted, but this will do for now. */
- pidList=xrealloc( pidList, sizeof(pid_t));
- pidList[0]=1;
- } else {
- pidList=xrealloc( pidList, sizeof(pid_t));
- pidList[0]=-1;
- }
+ /* comm is truncated, but first 15 chars match.
+ * This can be crazily_long_script_name.sh!
+ * The telltale sign is basename(argv[1]) == procName. */
- /* Free memory */
- free( pid_array);
+ if (!p->argv0)
+ return 0;
- /* close device */
- if (close (fd) != 0)
- perror_msg_and_die("close failed for `%s'", device);
+ argv1idx = strlen(p->argv0) + 1;
+ if (argv1idx >= p->argv_len)
+ return 0;
- return pidList;
-}
+ if (strcmp(bb_basename(p->argv0 + argv1idx), procName) != 0)
+ return 0;
-#else /* BB_FEATURE_USE_DEVPS_PATCH */
+ return 1;
+}
-/* find_pid_by_name()
- *
- * This finds the pid of the specified process.
- * Currently, it's implemented by rummaging through
- * the proc filesystem.
+/* 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
+ * Returns a list of all matching PIDs
+ * It is the caller's duty to free the returned pidlist.
+ *
+ * Modified by Vladimir Oleynik for use with libbb/procps.c
*/
-extern pid_t* find_pid_by_name( char* pidName)
+pid_t* FAST_FUNC find_pid_by_name(const char *procName)
{
- DIR *dir;
- struct dirent *next;
- pid_t* pidList=NULL;
- int i=0;
-
- dir = opendir("/proc");
- if (!dir)
- perror_msg_and_die("Cannot open /proc");
-
- while ((next = readdir(dir)) != NULL) {
- FILE *status;
- char filename[READ_BUF_SIZE];
- char buffer[READ_BUF_SIZE];
- char name[READ_BUF_SIZE];
-
- /* Must skip ".." since that is outside /proc */
- if (strcmp(next->d_name, "..") == 0)
- continue;
-
- /* If it isn't a number, we don't want it */
- if (!isdigit(*next->d_name))
- continue;
-
- sprintf(filename, "/proc/%s/status", next->d_name);
- if (! (status = fopen(filename, "r")) ) {
- continue;
- }
- if (fgets(buffer, READ_BUF_SIZE-1, status) == NULL) {
- fclose(status);
- continue;
- }
- fclose(status);
-
- /* Buffer should contain a string like "Name: binary_name" */
- sscanf(buffer, "%*s %s", name);
- if (strcmp(name, pidName) == 0) {
- pidList=xrealloc( pidList, sizeof(pid_t) * (i+2));
- pidList[i++]=strtol(next->d_name, NULL, 0);
+ pid_t* pidList;
+ int i = 0;
+ procps_status_t* p = NULL;
+
+ pidList = xzalloc(sizeof(*pidList));
+ while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN))) {
+ if (comm_match(p, procName)
+ /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
+ || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
+ /* TODO: we can also try /proc/NUM/exe link, do we want that? */
+ ) {
+ pidList = xrealloc_vector(pidList, 2, i);
+ pidList[i++] = p->pid;
}
}
- if (pidList)
- pidList[i]=0;
- else if ( strcmp(pidName, "init")==0) {
- /* If we found nothing and they were trying to kill "init",
- * guess PID 1 and call it good... Perhaps we should simply
- * exit if /proc isn't mounted, but this will do for now. */
- pidList=xrealloc( pidList, sizeof(pid_t));
- pidList[0]=1;
- } else {
- pidList=xrealloc( pidList, sizeof(pid_t));
- pidList[0]=-1;
- }
+ pidList[i] = 0;
return pidList;
}
-#endif /* BB_FEATURE_USE_DEVPS_PATCH */
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+pid_t* FAST_FUNC pidlist_reverse(pid_t *pidList)
+{
+ int i = 0;
+ while (pidList[i])
+ i++;
+ if (--i >= 0) {
+ pid_t k;
+ int j;
+ for (j = 0; i > j; i--, j++) {
+ k = pidList[i];
+ pidList[i] = pidList[j];
+ pidList[j] = k;
+ }
+ }
+ return pidList;
+}
diff --git a/release/src/router/busybox/libbb/find_root_device.c b/release/src/router/busybox/libbb/find_root_device.c
index f8f68464..ca46bf53 100644
--- a/release/src/router/busybox/libbb/find_root_device.c
+++ b/release/src/router/busybox/libbb/find_root_device.c
@@ -1,84 +1,74 @@
/* vi: set sw=4 ts=4: */
/*
- * Copyright (C) 2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
+ * Utility routines.
*
- * Patched by a bunch of people. Feel free to 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
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <stdlib.h>
#include "libbb.h"
+/* Find block device /dev/XXX which contains specified file
+ * We handle /dev/dir/dir/dir too, at a cost of ~80 more bytes code */
+/* Do not reallocate all this stuff on each recursion */
+enum { DEVNAME_MAX = 256 };
+struct arena {
+ struct stat st;
+ dev_t dev;
+ /* Was PATH_MAX, but we recurse _/dev_. We can assume
+ * people are not crazy enough to have mega-deep tree there */
+ char devpath[DEVNAME_MAX];
+};
-extern char *find_real_root_device_name(const char* name)
+static char *find_block_device_in_dir(struct arena *ap)
{
DIR *dir;
struct dirent *entry;
- struct stat statBuf, rootStat;
- char *fileName = NULL;
- dev_t dev;
-
- if (stat("/", &rootStat) != 0)
- perror_msg("could not stat '/'");
- else {
- if ((dev = rootStat.st_rdev)==0)
- dev=rootStat.st_dev;
+ char *retpath = NULL;
+ int len, rem;
- dir = opendir("/dev");
- if (!dir)
- perror_msg("could not open '/dev'");
- else {
- while((entry = readdir(dir)) != NULL) {
+ dir = opendir(ap->devpath);
+ if (!dir)
+ return NULL;
- /* Must skip ".." since that is "/", and so we
- * would get a false positive on ".." */
- if (strcmp(entry->d_name, "..") == 0)
- continue;
+ len = strlen(ap->devpath);
+ rem = DEVNAME_MAX-2 - len;
+ if (rem <= 0)
+ return NULL;
+ ap->devpath[len++] = '/';
- fileName = concat_path_file("/dev", entry->d_name);
-
- /* 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);
+ while ((entry = readdir(dir)) != NULL) {
+ safe_strncpy(ap->devpath + len, entry->d_name, rem);
+ /* lstat: do not follow links */
+ if (lstat(ap->devpath, &ap->st) != 0)
+ continue;
+ if (S_ISBLK(ap->st.st_mode) && ap->st.st_rdev == ap->dev) {
+ retpath = xstrdup(ap->devpath);
+ break;
+ }
+ if (S_ISDIR(ap->st.st_mode)) {
+ /* Do not recurse for '.' and '..' */
+ if (DOT_OR_DOTDOT(entry->d_name))
+ continue;
+ retpath = find_block_device_in_dir(ap);
+ if (retpath)
+ break;
}
}
- if(fileName==NULL)
- fileName=xstrdup("/dev/root");
- return fileName;
+ closedir(dir);
+
+ return retpath;
}
+char* FAST_FUNC find_block_device(const char *path)
+{
+ struct arena a;
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+ if (stat(path, &a.st) != 0)
+ return NULL;
+ a.dev = S_ISBLK(a.st.st_mode) ? a.st.st_rdev : a.st.st_dev;
+ strcpy(a.devpath, "/dev");
+ return find_block_device_in_dir(&a);
+}
diff --git a/release/src/router/busybox/libbb/full_read.c b/release/src/router/busybox/libbb/full_read.c
deleted file mode 100644
index e9c4bbfc..00000000
--- a/release/src/router/busybox/libbb/full_read.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#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.
- */
-int full_read(int fd, char *buf, int len)
-{
- int cc;
- int total;
-
- total = 0;
-
- while (len > 0) {
- cc = read(fd, buf, len);
-
- if (cc < 0)
- return -1;
-
- if (cc == 0)
- break;
-
- 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/release/src/router/busybox/libbb/full_write.c b/release/src/router/busybox/libbb/full_write.c
index dc9937fa..f353b7d5 100644
--- a/release/src/router/busybox/libbb/full_write.c
+++ b/release/src/router/busybox/libbb/full_write.c
@@ -2,31 +2,11 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <unistd.h>
#include "libbb.h"
/*
@@ -34,33 +14,29 @@
* This does multiple writes as necessary.
* Returns the amount written, or -1 on an error.
*/
-int full_write(int fd, const char *buf, int len)
+ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len)
{
- int cc;
- int total;
+ ssize_t cc;
+ ssize_t total;
total = 0;
- while (len > 0) {
- cc = write(fd, buf, len);
+ while (len) {
+ cc = safe_write(fd, buf, len);
- if (cc < 0)
- return -1;
+ if (cc < 0) {
+ if (total) {
+ /* we already wrote some! */
+ /* user can do another write to know the error code */
+ return total;
+ }
+ return cc; /* write() returns -1 on failure. */
+ }
- buf += cc;
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/release/src/router/busybox/libbb/get_console.c b/release/src/router/busybox/libbb/get_console.c
index 3b36a59e..74022b54 100644
--- a/release/src/router/busybox/libbb/get_console.c
+++ b/release/src/router/busybox/libbb/get_console.c
@@ -2,59 +2,22 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
#include "libbb.h"
+/* From <linux/kd.h> */
+enum { KDGKBTYPE = 0x4B33 }; /* get keyboard type */
-
-
-
-/* From <linux/kd.h> */
-static const int KDGKBTYPE = 0x4B33; /* get keyboard type */
-static const int KB_84 = 0x01;
-static const int KB_101 = 0x02; /* this is what we always answer */
-
-int is_a_console(int fd)
-{
- char arg;
-
- arg = 0;
- return (ioctl(fd, KDGKBTYPE, &arg) == 0
- && ((arg == KB_101) || (arg == KB_84)));
-}
-
-static int open_a_console(char *fnam)
+static int open_a_console(const char *fnam)
{
int fd;
- /* try read-only */
+ /* try read-write */
fd = open(fnam, O_RDWR);
/* if failed, try read-only */
@@ -65,17 +28,6 @@ static int open_a_console(char *fnam)
if (fd < 0 && errno == EACCES)
fd = open(fnam, O_WRONLY);
- /* if failed, fail */
- if (fd < 0)
- return -1;
-
- /* if not a console, fail */
- if (!is_a_console(fd)) {
- close(fd);
- return -1;
- }
-
- /* success */
return fd;
}
@@ -83,47 +35,46 @@ static int open_a_console(char *fnam)
* 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).
- *
- * if tty_name is non-NULL, try this one instead.
*/
-
-int get_console_fd(char *tty_name)
+int FAST_FUNC get_console_fd_or_die(void)
{
+ static const char *const console_names[] = {
+ DEV_CONSOLE, CURRENT_VC, CURRENT_TTY
+ };
+
int fd;
- if (tty_name) {
- if (-1 == (fd = open_a_console(tty_name)))
- return -1;
- else
- return fd;
+ for (fd = 2; fd >= 0; fd--) {
+ int fd4name;
+ int choice_fd;
+ char arg;
+
+ fd4name = open_a_console(console_names[fd]);
+ chk_std:
+ choice_fd = (fd4name >= 0 ? fd4name : fd);
+
+ arg = 0;
+ if (ioctl(choice_fd, KDGKBTYPE, &arg) == 0)
+ return choice_fd;
+ if (fd4name >= 0) {
+ close(fd4name);
+ fd4name = -1;
+ goto chk_std;
+ }
}
- fd = open_a_console(CURRENT_TTY);
- if (fd >= 0)
- return fd;
-
- fd = open_a_console(CURRENT_VC);
- if (fd >= 0)
- return fd;
-
- fd = open_a_console(CONSOLE_DEV);
- if (fd >= 0)
- return fd;
-
- for (fd = 0; fd < 3; fd++)
- if (is_a_console(fd))
- return fd;
-
- error_msg("Couldn't get a file descriptor referring to the console");
- return -1; /* total failure */
+ bb_error_msg_and_die("can't open console");
+ /*return fd; - total failure */
}
+/* From <linux/vt.h> */
+enum {
+ VT_ACTIVATE = 0x5606, /* make vt active */
+ VT_WAITACTIVE = 0x5607 /* wait for vt active */
+};
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+void FAST_FUNC console_make_active(int fd, const int vt_num)
+{
+ xioctl(fd, VT_ACTIVATE, (void *)(ptrdiff_t)vt_num);
+ xioctl(fd, VT_WAITACTIVE, (void *)(ptrdiff_t)vt_num);
+}
diff --git a/release/src/router/busybox/libbb/get_last_path_component.c b/release/src/router/busybox/libbb/get_last_path_component.c
index f1ddfbde..7c99116e 100644
--- a/release/src/router/busybox/libbb/get_last_path_component.c
+++ b/release/src/router/busybox/libbb/get_last_path_component.c
@@ -1,71 +1,42 @@
/* vi: set sw=4 ts=4: */
/*
- * Utility routines.
+ * bb_get_last_path_component implementation for busybox
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <string.h>
#include "libbb.h"
-
-
-char *get_last_path_component(char *path)
+/*
+ * "/" -> "/"
+ * "abc" -> "abc"
+ * "abc/def" -> "def"
+ * "abc/def/" -> ""
+ */
+char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path)
{
- char *s;
- register char *ptr = path;
- register char *prev = 0;
+ char *slash = strrchr(path, '/');
- while (*ptr)
- ptr++;
- s = ptr - 1;
+ if (!slash || (slash == path && !slash[1]))
+ return (char*)path;
- /* strip trailing slashes */
- while (s != path && *s == '/') {
- *s-- = '\0';
- }
-
- /* find last component */
- ptr = path;
- while (*ptr != '\0') {
- if (*ptr == '/')
- prev = ptr;
- ptr++;
- }
- s = prev;
-
- if (s == NULL || s[1] == '\0')
- return path;
- else
- return s+1;
+ return slash + 1;
}
-
-/* END CODE */
/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+ * "/" -> "/"
+ * "abc" -> "abc"
+ * "abc/def" -> "def"
+ * "abc/def/" -> "def" !!
+ */
+char* FAST_FUNC bb_get_last_path_component_strip(char *path)
+{
+ char *slash = last_char_is(path, '/');
+
+ if (slash)
+ while (*slash == '/' && slash != path)
+ *slash-- = '\0';
+
+ return bb_get_last_path_component_nostrip(path);
+}
diff --git a/release/src/router/busybox/libbb/get_line_from_file.c b/release/src/router/busybox/libbb/get_line_from_file.c
index 75948173..3cb46d24 100644
--- a/release/src/router/busybox/libbb/get_line_from_file.c
+++ b/release/src/router/busybox/libbb/get_line_from_file.c
@@ -2,71 +2,206 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 2005, 2006 Rob Landley <rob@landley.net>
+ * Copyright (C) 2004 Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2001 Matt Krai
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
+/* for getline() [GNUism]
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+*/
#include "libbb.h"
+/* This function reads an entire line from a text file, up to a newline
+ * or NUL byte, inclusive. It returns a malloc'ed char * which
+ * must be free'ed by the caller. If end is NULL '\n' isn't considered
+ * end of line. If end isn't NULL, length of the chunk is stored in it.
+ * If lineno is not NULL, *lineno is incremented for each line,
+ * and also trailing '\' is recognized as line continuation.
+ *
+ * Returns NULL if EOF/error. */
+char* FAST_FUNC bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno)
+{
+ 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) {
+ linebufsz += 256;
+ linebuf = xrealloc(linebuf, linebufsz);
+ }
+ linebuf[idx++] = (char) ch;
+ if (!ch)
+ break;
+ if (end && ch == '\n') {
+ if (lineno == NULL)
+ break;
+ (*lineno)++;
+ if (idx < 2 || linebuf[idx-2] != '\\')
+ break;
+ idx -= 2;
+ }
+ }
+ if (end)
+ *end = idx;
+ if (linebuf) {
+ // huh, does fgets discard prior data on error like this?
+ // I don't think so....
+ //if (ferror(file)) {
+ // free(linebuf);
+ // return NULL;
+ //}
+ linebuf = xrealloc(linebuf, idx + 1);
+ linebuf[idx] = '\0';
+ }
+ return linebuf;
+}
-/* 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. */
-extern char *get_line_from_file(FILE *file)
+char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end)
{
- static const int GROWBY = 80; /* how large we will grow strings by */
+ return bb_get_chunk_with_continuation(file, end, NULL);
+}
- int ch;
+/* Get line, including trailing \n if any */
+char* FAST_FUNC xmalloc_fgets(FILE *file)
+{
+ int i;
+
+ return bb_get_chunk_from_file(file, &i);
+}
+/* Get line. Remove trailing \n */
+char* FAST_FUNC xmalloc_fgetline(FILE *file)
+{
+ int i;
+ char *c = bb_get_chunk_from_file(file, &i);
+
+ if (i && c[--i] == '\n')
+ c[i] = '\0';
+
+ return c;
+}
+
+#if 0
+/* GNUism getline() should be faster (not tested) than a loop with fgetc */
+
+/* Get line, including trailing \n if any */
+char* FAST_FUNC xmalloc_fgets(FILE *file)
+{
+ char *res_buf = NULL;
+ size_t res_sz;
+
+ if (getline(&res_buf, &res_sz, file) == -1) {
+ free(res_buf); /* uclibc allocates a buffer even on EOF. WTF? */
+ res_buf = NULL;
+ }
+//TODO: trimming to res_sz?
+ return res_buf;
+}
+/* Get line. Remove trailing \n */
+char* FAST_FUNC xmalloc_fgetline(FILE *file)
+{
+ char *res_buf = NULL;
+ size_t res_sz;
+
+ res_sz = getline(&res_buf, &res_sz, file);
+
+ if ((ssize_t)res_sz != -1) {
+ if (res_buf[res_sz - 1] == '\n')
+ res_buf[--res_sz] = '\0';
+//TODO: trimming to res_sz?
+ } else {
+ free(res_buf); /* uclibc allocates a buffer even on EOF. WTF? */
+ res_buf = NULL;
+ }
+ return res_buf;
+}
+
+#endif
+
+#if 0
+/* Faster routines (~twice as fast). +170 bytes. Unused as of 2008-07.
+ *
+ * NB: they stop at NUL byte too.
+ * Performance is important here. Think "grep 50gigabyte_file"...
+ * Ironically, grep can't use it because of NUL issue.
+ * We sorely need C lib to provide fgets which reports size!
+ *
+ * Update:
+ * Actually, uclibc and glibc have it. man getline. It's GNUism,
+ * but very useful one (if it's as fast as this code).
+ * TODO:
+ * - currently, sed and sort use bb_get_chunk_from_file and heavily
+ * depend on its "stop on \n or \0" behavior, and STILL they fail
+ * to handle all cases with embedded NULs correctly. So:
+ * - audit sed and sort; convert them to getline FIRST.
+ * - THEN ditch bb_get_chunk_from_file, replace it with getline.
+ * - provide getline implementation for non-GNU systems.
+ */
+
+static char* xmalloc_fgets_internal(FILE *file, int *sizep)
+{
+ int len;
int idx = 0;
char *linebuf = NULL;
- int linebufsz = 0;
while (1) {
- ch = fgetc(file);
- if (ch == EOF)
+ char *r;
+
+ linebuf = xrealloc(linebuf, idx + 0x100);
+ r = fgets(&linebuf[idx], 0x100, file);
+ if (!r) {
+ /* need to terminate in case this is error
+ * (EOF puts NUL itself) */
+ linebuf[idx] = '\0';
break;
- /* grow the line buffer as necessary */
- while (idx > linebufsz-2)
- linebuf = xrealloc(linebuf, linebufsz += GROWBY);
- linebuf[idx++] = (char)ch;
- if ((char)ch == '\n')
+ }
+ /* stupid. fgets knows the len, it should report it somehow */
+ len = strlen(&linebuf[idx]);
+ idx += len;
+ if (len != 0xff || linebuf[idx - 1] == '\n')
break;
}
+ *sizep = idx;
+ if (idx) {
+ /* xrealloc(linebuf, idx + 1) is up to caller */
+ return linebuf;
+ }
+ free(linebuf);
+ return NULL;
+}
- if (idx == 0)
- return NULL;
-
- linebuf[idx] = 0;
- return linebuf;
+/* Get line, remove trailing \n */
+char* FAST_FUNC xmalloc_fgetline_fast(FILE *file)
+{
+ int sz;
+ char *r = xmalloc_fgets_internal(file, &sz);
+ if (r && r[sz - 1] == '\n')
+ r[--sz] = '\0';
+ return r; /* not xrealloc(r, sz + 1)! */
}
+char* FAST_FUNC xmalloc_fgets(FILE *file)
+{
+ int sz;
+ return xmalloc_fgets_internal(file, &sz);
+}
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+/* Get line, remove trailing \n */
+char* FAST_FUNC xmalloc_fgetline(FILE *file)
+{
+ int sz;
+ char *r = xmalloc_fgets_internal(file, &sz);
+ if (!r)
+ return r;
+ if (r[sz - 1] == '\n')
+ r[--sz] = '\0';
+ return xrealloc(r, sz + 1);
+}
+#endif
diff --git a/release/src/router/busybox/libbb/getopt32.c b/release/src/router/busybox/libbb/getopt32.c
new file mode 100644
index 00000000..5190fa61
--- /dev/null
+++ b/release/src/router/busybox/libbb/getopt32.c
@@ -0,0 +1,592 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * universal getopt32 implementation for busybox
+ *
+ * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <getopt.h>
+#include "libbb.h"
+
+/* Documentation
+
+uint32_t
+getopt32(char **argv, const char *applet_opts, ...)
+
+ The command line options must be declared in const char
+ *applet_opts as a string of chars, for example:
+
+ flags = getopt32(argv, "rnug");
+
+ If one of the given options is found, a flag value is added to
+ the return value (an unsigned long).
+
+ The flag value is determined by the position of the char in
+ applet_opts string. For example, in the above case:
+
+ flags = getopt32(argv, "rnug");
+
+ "r" will add 1 (bit 0)
+ "n" will add 2 (bit 1)
+ "u" will add 4 (bit 2)
+ "g" will add 8 (bit 3)
+
+ and so on. You can also look at the return value as a bit
+ field and each option sets one bit.
+
+ On exit, global variable optind is set so that if you
+ will do argc -= optind; argv += optind; then
+ argc will be equal to number of remaining non-option
+ arguments, first one would be in argv[0], next in argv[1] and so on
+ (options and their parameters will be moved into argv[]
+ positions prior to argv[optind]).
+
+ ":" If one of the options requires an argument, then add a ":"
+ after the char in applet_opts and provide a pointer to store
+ the argument. For example:
+
+ char *pointer_to_arg_for_a;
+ char *pointer_to_arg_for_b;
+ char *pointer_to_arg_for_c;
+ char *pointer_to_arg_for_d;
+
+ flags = getopt32(argv, "a:b:c:d:",
+ &pointer_to_arg_for_a, &pointer_to_arg_for_b,
+ &pointer_to_arg_for_c, &pointer_to_arg_for_d);
+
+ The type of the pointer (char* or llist_t*) may be controlled
+ by the "::" special separator that is set in the external string
+ opt_complementary (see below for more info).
+
+ "::" If option can have an *optional* argument, then add a "::"
+ after its char in applet_opts and provide a pointer to store
+ the argument. Note that optional arguments _must_
+ immediately follow the option: -oparam, not -o param.
+
+ "+" If the first character in the applet_opts string is a plus,
+ then option processing will stop as soon as a non-option is
+ encountered in the argv array. Useful for applets like env
+ which should not process arguments to subprograms:
+ env -i ls -d /
+ Here we want env to process just the '-i', not the '-d'.
+
+const char *applet_long_options
+
+ This struct allows you to define long options:
+
+ static const char applet_longopts[] ALIGN1 =
+ //"name\0" has_arg val
+ "verbose\0" No_argument "v"
+ ;
+ applet_long_options = applet_longopts;
+
+ The last member of struct option (val) typically is set to
+ matching short option from applet_opts. If there is no matching
+ char in applet_opts, then:
+ - return bit have next position after short options
+ - if has_arg is not "No_argument", use ptr for arg also
+ - opt_complementary affects it too
+
+ Note: a good applet will make long options configurable via the
+ config process and not a required feature. The current standard
+ is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
+
+const char *opt_complementary
+
+ ":" The colon (":") is used to separate groups of two or more chars
+ and/or groups of chars and special characters (stating some
+ conditions to be checked).
+
+ "abc" If groups of two or more chars are specified, the first char
+ is the main option and the other chars are secondary options.
+ Their flags will be turned on if the main option is found even
+ if they are not specifed on the command line. For example:
+
+ opt_complementary = "abc";
+ flags = getopt32(argv, "abcd")
+
+ If getopt() finds "-a" on the command line, then
+ getopt32's return value will be as if "-a -b -c" were
+ found.
+
+ "ww" Adjacent double options have a counter associated which indicates
+ the number of occurences of the option.
+ For example the ps applet needs:
+ if w is given once, GNU ps sets the width to 132,
+ if w is given more than once, it is "unlimited"
+
+ int w_counter = 0; // must be initialized!
+ opt_complementary = "ww";
+ getopt32(argv, "w", &w_counter);
+ if (w_counter)
+ width = (w_counter == 1) ? 132 : INT_MAX;
+ else
+ get_terminal_width(...&width...);
+
+ w_counter is a pointer to an integer. It has to be passed to
+ getopt32() after all other option argument sinks.
+
+ For example: accept multiple -v to indicate the level of verbosity
+ and for each -b optarg, add optarg to my_b. Finally, if b is given,
+ turn off c and vice versa:
+
+ llist_t *my_b = NULL;
+ int verbose_level = 0;
+ opt_complementary = "vv:b::b-c:c-b";
+ f = getopt32(argv, "vb:c", &my_b, &verbose_level);
+ if (f & 2) // -c after -b unsets -b flag
+ while (my_b) dosomething_with(llist_pop(&my_b));
+ if (my_b) // but llist is stored if -b is specified
+ free_llist(my_b);
+ if (verbose_level) printf("verbose level is %d\n", verbose_level);
+
+Special characters:
+
+ "-" A dash as the first char in a opt_complementary group forces
+ all arguments to be treated as options, even if they have
+ no leading dashes. Next char in this case can't be a digit (0-9),
+ use ':' or end of line. For example:
+
+ opt_complementary = "-:w-x:x-w";
+ getopt32(argv, "wx");
+
+ Allows any arguments to be given without a dash (./program w x)
+ as well as with a dash (./program -x).
+
+ NB: getopt32() will leak a small amount of memory if you use
+ this option! Do not use it if there is a possibility of recursive
+ getopt32() calls.
+
+ "--" A double dash at the beginning of opt_complementary means the
+ argv[1] string should always be treated as options, even if it isn't
+ prefixed with a "-". This is useful for special syntax in applets
+ such as "ar" and "tar":
+ tar xvf foo.tar
+
+ NB: getopt32() will leak a small amount of memory if you use
+ this option! Do not use it if there is a possibility of recursive
+ getopt32() calls.
+
+ "-N" A dash as the first char in a opt_complementary group followed
+ by a single digit (0-9) means that at least N non-option
+ arguments must be present on the command line
+
+ "=N" An equal sign as the first char in a opt_complementary group followed
+ by a single digit (0-9) means that exactly N non-option
+ arguments must be present on the command line
+
+ "?N" A "?" as the first char in a opt_complementary group followed
+ by a single digit (0-9) means that at most N arguments must be present
+ on the command line.
+
+ "V-" An option with dash before colon or end-of-line results in
+ bb_show_usage() being called if this option is encountered.
+ This is typically used to implement "print verbose usage message
+ and exit" option.
+
+ "a-b" A dash between two options causes the second of the two
+ to be unset (and ignored) if it is given on the command line.
+
+ [FIXME: what if they are the same? like "x-x"? Is it ever useful?]
+
+ For example:
+ The du applet has the options "-s" and "-d depth". If
+ getopt32 finds -s, then -d is unset or if it finds -d
+ then -s is unset. (Note: busybox implements the GNU
+ "--max-depth" option as "-d".) To obtain this behavior, you
+ set opt_complementary = "s-d:d-s". Only one flag value is
+ added to getopt32's return value depending on the
+ position of the options on the command line. If one of the
+ two options requires an argument pointer (":" in applet_opts
+ as in "d:") optarg is set accordingly.
+
+ char *smax_print_depth;
+
+ opt_complementary = "s-d:d-s:x-x";
+ opt = getopt32(argv, "sd:x", &smax_print_depth);
+
+ if (opt & 2)
+ max_print_depth = atoi(smax_print_depth);
+ if (opt & 4)
+ printf("Detected odd -x usage\n");
+
+ "a--b" A double dash between two options, or between an option and a group
+ of options, means that they are mutually exclusive. Unlike
+ the "-" case above, an error will be forced if the options
+ are used together.
+
+ For example:
+ The cut applet must have only one type of list specified, so
+ -b, -c and -f are mutually exclusive and should raise an error
+ if specified together. In this case you must set
+ opt_complementary = "b--cf:c--bf:f--bc". If two of the
+ mutually exclusive options are found, getopt32 will call
+ bb_show_usage() and die.
+
+ "x--x" Variation of the above, it means that -x option should occur
+ at most once.
+
+ "a+" A plus after a char in opt_complementary means that the parameter
+ for this option is a nonnegative integer. It will be processed
+ with xatoi_u() - allowed range is 0..INT_MAX.
+
+ int param; // "unsigned param;" will also work
+ opt_complementary = "p+";
+ getopt32(argv, "p:", &param);
+
+ "a::" A double colon after a char in opt_complementary means that the
+ option can occur multiple times. Each occurrence will be saved as
+ a llist_t element instead of char*.
+
+ For example:
+ The grep applet can have one or more "-e pattern" arguments.
+ In this case you should use getopt32() as follows:
+
+ llist_t *patterns = NULL;
+
+ (this pointer must be initializated to NULL if the list is empty
+ as required by llist_add_to_end(llist_t **old_head, char *new_item).)
+
+ opt_complementary = "e::";
+
+ getopt32(argv, "e:", &patterns);
+ $ grep -e user -e root /etc/passwd
+ root:x:0:0:root:/root:/bin/bash
+ user:x:500:500::/home/user:/bin/bash
+
+ "a?b" A "?" between an option and a group of options means that
+ at least one of them is required to occur if the first option
+ occurs in preceding command line arguments.
+
+ For example from "id" applet:
+
+ // Don't allow -n -r -rn -ug -rug -nug -rnug
+ opt_complementary = "r?ug:n?ug:u--g:g--u";
+ flags = getopt32(argv, "rnug");
+
+ This example allowed only:
+ $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
+
+ "X" A opt_complementary group with just a single letter means
+ that this option is required. If more than one such group exists,
+ at least one option is required to occur (not all of them).
+ For example from "start-stop-daemon" applet:
+
+ // Don't allow -KS -SK, but -S or -K is required
+ opt_complementary = "K:S:K--S:S--K";
+ flags = getopt32(argv, "KS...);
+
+
+ Don't forget to use ':'. For example, "?322-22-23X-x-a"
+ is interpreted as "?3:22:-2:2-2:2-3Xa:2--x" -
+ max 3 args; count uses of '-2'; min 2 args; if there is
+ a '-2' option then unset '-3', '-X' and '-a'; if there is
+ a '-2' and after it a '-x' then error out.
+ But it's far too obfuscated. Use ':' to separate groups.
+*/
+
+/* Code here assumes that 'unsigned' is at least 32 bits wide */
+
+const char *const bb_argv_dash[] = { "-", NULL };
+
+const char *opt_complementary;
+
+enum {
+ PARAM_STRING,
+ PARAM_LIST,
+ PARAM_INT,
+};
+
+typedef struct {
+ unsigned char opt_char;
+ smallint param_type;
+ unsigned switch_on;
+ unsigned switch_off;
+ unsigned incongruously;
+ unsigned requires;
+ void **optarg; /* char**, llist_t** or int *. */
+ int *counter;
+} t_complementary;
+
+/* You can set applet_long_options for parse called long options */
+#if ENABLE_GETOPT_LONG
+static const struct option bb_null_long_options[1] = {
+ { 0, 0, 0, 0 }
+};
+const char *applet_long_options;
+#endif
+
+uint32_t option_mask32;
+
+uint32_t FAST_FUNC
+getopt32(char **argv, const char *applet_opts, ...)
+{
+ int argc;
+ unsigned flags = 0;
+ unsigned requires = 0;
+ t_complementary complementary[33]; /* last stays zero-filled */
+ int c;
+ const unsigned char *s;
+ t_complementary *on_off;
+ va_list p;
+#if ENABLE_GETOPT_LONG
+ const struct option *l_o;
+ struct option *long_options = (struct option *) &bb_null_long_options;
+#endif
+ unsigned trigger;
+ char **pargv;
+ int min_arg = 0;
+ int max_arg = -1;
+
+#define SHOW_USAGE_IF_ERROR 1
+#define ALL_ARGV_IS_OPTS 2
+#define FIRST_ARGV_IS_OPT 4
+
+ int spec_flgs = 0;
+
+ /* skip 0: some applets cheat: they do not actually HAVE argv[0] */
+ argc = 1;
+ while (argv[argc])
+ argc++;
+
+ va_start(p, applet_opts);
+
+ c = 0;
+ on_off = complementary;
+ memset(on_off, 0, sizeof(complementary));
+
+ /* skip GNU extension */
+ s = (const unsigned char *)applet_opts;
+ if (*s == '+' || *s == '-')
+ s++;
+ while (*s) {
+ if (c >= 32)
+ break;
+ on_off->opt_char = *s;
+ on_off->switch_on = (1 << c);
+ if (*++s == ':') {
+ on_off->optarg = va_arg(p, void **);
+ while (*++s == ':')
+ continue;
+ }
+ on_off++;
+ c++;
+ }
+
+#if ENABLE_GETOPT_LONG
+ if (applet_long_options) {
+ const char *optstr;
+ unsigned i, count;
+
+ count = 1;
+ optstr = applet_long_options;
+ while (optstr[0]) {
+ optstr += strlen(optstr) + 3; /* skip NUL, has_arg, val */
+ count++;
+ }
+ /* count == no. of longopts + 1 */
+ long_options = alloca(count * sizeof(*long_options));
+ memset(long_options, 0, count * sizeof(*long_options));
+ i = 0;
+ optstr = applet_long_options;
+ while (--count) {
+ long_options[i].name = optstr;
+ optstr += strlen(optstr) + 1;
+ long_options[i].has_arg = (unsigned char)(*optstr++);
+ /* long_options[i].flag = NULL; */
+ long_options[i].val = (unsigned char)(*optstr++);
+ i++;
+ }
+ for (l_o = long_options; l_o->name; l_o++) {
+ if (l_o->flag)
+ continue;
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == l_o->val)
+ goto next_long;
+ if (c >= 32)
+ break;
+ on_off->opt_char = l_o->val;
+ on_off->switch_on = (1 << c);
+ if (l_o->has_arg != no_argument)
+ on_off->optarg = va_arg(p, void **);
+ c++;
+ next_long: ;
+ }
+ }
+#endif /* ENABLE_GETOPT_LONG */
+ for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
+ t_complementary *pair;
+ unsigned *pair_switch;
+
+ if (*s == ':')
+ continue;
+ c = s[1];
+ if (*s == '?') {
+ if (c < '0' || c > '9') {
+ spec_flgs |= SHOW_USAGE_IF_ERROR;
+ } else {
+ max_arg = c - '0';
+ s++;
+ }
+ continue;
+ }
+ if (*s == '-') {
+ if (c < '0' || c > '9') {
+ if (c == '-') {
+ spec_flgs |= FIRST_ARGV_IS_OPT;
+ s++;
+ } else
+ spec_flgs |= ALL_ARGV_IS_OPTS;
+ } else {
+ min_arg = c - '0';
+ s++;
+ }
+ continue;
+ }
+ if (*s == '=') {
+ min_arg = max_arg = c - '0';
+ s++;
+ continue;
+ }
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == *s)
+ break;
+ if (c == ':' && s[2] == ':') {
+ on_off->param_type = PARAM_LIST;
+ continue;
+ }
+ if (c == '+' && (s[2] == ':' || s[2] == '\0')) {
+ on_off->param_type = PARAM_INT;
+ continue;
+ }
+ if (c == ':' || c == '\0') {
+ requires |= on_off->switch_on;
+ continue;
+ }
+ if (c == '-' && (s[2] == ':' || s[2] == '\0')) {
+ flags |= on_off->switch_on;
+ on_off->incongruously |= on_off->switch_on;
+ s++;
+ continue;
+ }
+ if (c == *s) {
+ on_off->counter = va_arg(p, int *);
+ s++;
+ }
+ pair = on_off;
+ pair_switch = &(pair->switch_on);
+ for (s++; *s && *s != ':'; s++) {
+ if (*s == '?') {
+ pair_switch = &(pair->requires);
+ } else if (*s == '-') {
+ if (pair_switch == &(pair->switch_off))
+ pair_switch = &(pair->incongruously);
+ else
+ pair_switch = &(pair->switch_off);
+ } else {
+ for (on_off = complementary; on_off->opt_char; on_off++)
+ if (on_off->opt_char == *s) {
+ *pair_switch |= on_off->switch_on;
+ break;
+ }
+ }
+ }
+ s--;
+ }
+ va_end(p);
+
+ if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) {
+ pargv = argv + 1;
+ while (*pargv) {
+ if (pargv[0][0] != '-' && pargv[0][0] != '\0') {
+ /* Can't use alloca: opts with params will
+ * return pointers to stack!
+ * NB: we leak these allocations... */
+ char *pp = xmalloc(strlen(*pargv) + 2);
+ *pp = '-';
+ strcpy(pp + 1, *pargv);
+ *pargv = pp;
+ }
+ if (!(spec_flgs & ALL_ARGV_IS_OPTS))
+ break;
+ pargv++;
+ }
+ }
+
+ /* In case getopt32 was already called:
+ * reset the libc getopt() function, which keeps internal state.
+ * run_nofork_applet_prime() does this, but we might end up here
+ * also via gunzip_main() -> gzip_main(). Play safe.
+ */
+#ifdef __GLIBC__
+ optind = 0;
+#else /* BSD style */
+ optind = 1;
+ /* optreset = 1; */
+#endif
+ /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */
+
+ pargv = NULL;
+
+ /* Note: just "getopt() <= 0" will not work well for
+ * "fake" short options, like this one:
+ * wget $'-\203' "Test: test" http://kernel.org/
+ * (supposed to act as --header, but doesn't) */
+#if ENABLE_GETOPT_LONG
+ while ((c = getopt_long(argc, argv, applet_opts,
+ long_options, NULL)) != -1) {
+#else
+ while ((c = getopt(argc, argv, applet_opts)) != -1) {
+#endif
+ /* getopt prints "option requires an argument -- X"
+ * and returns '?' if an option has no arg, but one is reqd */
+ c &= 0xff; /* fight libc's sign extension */
+ for (on_off = complementary; on_off->opt_char != c; on_off++) {
+ /* c can be NUL if long opt has non-NULL ->flag,
+ * but we construct long opts so that flag
+ * is always NULL (see above) */
+ if (on_off->opt_char == '\0' /* && c != '\0' */) {
+ /* c is probably '?' - "bad option" */
+ bb_show_usage();
+ }
+ }
+ if (flags & on_off->incongruously)
+ bb_show_usage();
+ trigger = on_off->switch_on & on_off->switch_off;
+ flags &= ~(on_off->switch_off ^ trigger);
+ flags |= on_off->switch_on ^ trigger;
+ flags ^= trigger;
+ if (on_off->counter)
+ (*(on_off->counter))++;
+ if (on_off->param_type == PARAM_LIST) {
+ if (optarg)
+ llist_add_to_end((llist_t **)(on_off->optarg), optarg);
+ } else if (on_off->param_type == PARAM_INT) {
+ if (optarg)
+//TODO: xatoi_u indirectly pulls in printf machinery
+ *(unsigned*)(on_off->optarg) = xatoi_u(optarg);
+ } else if (on_off->optarg) {
+ if (optarg)
+ *(char **)(on_off->optarg) = optarg;
+ }
+ if (pargv != NULL)
+ break;
+ }
+
+ /* check depending requires for given options */
+ for (on_off = complementary; on_off->opt_char; on_off++) {
+ if (on_off->requires && (flags & on_off->switch_on) &&
+ (flags & on_off->requires) == 0)
+ bb_show_usage();
+ }
+ if (requires && (flags & requires) == 0)
+ bb_show_usage();
+ argc -= optind;
+ if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
+ bb_show_usage();
+
+ option_mask32 = flags;
+ return flags;
+}
diff --git a/release/src/router/busybox/libbb/getopt_ulflags.c b/release/src/router/busybox/libbb/getopt_ulflags.c
deleted file mode 100644
index 9bf8c055..00000000
--- a/release/src/router/busybox/libbb/getopt_ulflags.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* 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~bcf:c~bcf:f~bcf".
-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
-{
- 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;
- int c = 0;
- const char *s;
- t_complementaly *complementaly;
- t_complementaly *on_off;
- va_list p;
-
- va_start (p, applet_opts);
-
- for (s = applet_opts; *s; s++) {
- c++;
- while (s[1] == ':') {
- /* check GNU extension "o::" - optional arg */
- s++;
- }
- }
- complementaly = xcalloc (c + 1, sizeof (t_complementaly));
- c = 0;
- for (s = applet_opts; *s; s++) {
- complementaly->opt = *s;
- complementaly->switch_on |= (1 << c);
- c++;
- if (s[1] == ':') {
- complementaly->optarg = va_arg (p, void **);
- do
- s++;
- while (s[1] == ':');
- }
- complementaly++;
- }
- complementaly->opt = 0;
- complementaly -= c;
- 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;
- }
- }
- free(complementaly);
- return flags;
-}
diff --git a/release/src/router/busybox/libbb/getpty.c b/release/src/router/busybox/libbb/getpty.c
new file mode 100644
index 00000000..4bffd9ae
--- /dev/null
+++ b/release/src/router/busybox/libbb/getpty.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini getpty implementation for busybox
+ * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define DEBUG 0
+
+int FAST_FUNC xgetpty(char *line)
+{
+ int p;
+
+#if ENABLE_FEATURE_DEVPTS
+ p = open("/dev/ptmx", O_RDWR);
+ if (p > 0) {
+ grantpt(p); /* chmod+chown corresponding slave pty */
+ unlockpt(p); /* (what does this do?) */
+#if 0 /* if ptsname_r is not available... */
+ const char *name;
+ name = ptsname(p); /* find out the name of slave pty */
+ if (!name) {
+ bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)");
+ }
+ safe_strncpy(line, name, GETPTY_BUFSIZE);
+#else
+ /* find out the name of slave pty */
+ if (ptsname_r(p, line, GETPTY_BUFSIZE-1) != 0) {
+ bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)");
+ }
+ line[GETPTY_BUFSIZE-1] = '\0';
+#endif
+ return p;
+ }
+#else
+ struct stat stb;
+ int i;
+ int j;
+
+ strcpy(line, "/dev/ptyXX");
+
+ for (i = 0; i < 16; i++) {
+ line[8] = "pqrstuvwxyzabcde"[i];
+ line[9] = '0';
+ if (stat(line, &stb) < 0) {
+ continue;
+ }
+ for (j = 0; j < 16; j++) {
+ line[9] = j < 10 ? j + '0' : j - 10 + 'a';
+ if (DEBUG)
+ fprintf(stderr, "Trying to open device: %s\n", line);
+ p = open(line, O_RDWR | O_NOCTTY);
+ if (p >= 0) {
+ line[5] = 't';
+ return p;
+ }
+ }
+ }
+#endif /* FEATURE_DEVPTS */
+ bb_error_msg_and_die("can't find free pty");
+}
diff --git a/release/src/router/busybox/libbb/gz_open.c b/release/src/router/busybox/libbb/gz_open.c
deleted file mode 100644
index ef30ff89..00000000
--- a/release/src/router/busybox/libbb/gz_open.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "libbb.h"
-
-extern FILE *gz_open(FILE *compressed_file, int *pid)
-{
- int unzip_pipe[2];
-
- if (pipe(unzip_pipe)!=0) {
- error_msg("pipe error");
- return(NULL);
- }
- if ((*pid = fork()) == -1) {
- error_msg("fork failed");
- return(NULL);
- }
- if (*pid==0) {
- /* child process */
- close(unzip_pipe[0]);
- unzip(compressed_file, fdopen(unzip_pipe[1], "w"));
- fflush(NULL);
- fclose(compressed_file);
- close(unzip_pipe[1]);
- exit(EXIT_SUCCESS);
- }
- close(unzip_pipe[1]);
- if (unzip_pipe[0] == -1) {
- error_msg("gzip stream init failed");
- }
- return(fdopen(unzip_pipe[0], "r"));
-}
diff --git a/release/src/router/busybox/libbb/herror_msg.c b/release/src/router/busybox/libbb/herror_msg.c
index f4210eda..7e4f6404 100644
--- a/release/src/router/busybox/libbb/herror_msg.c
+++ b/release/src/router/busybox/libbb/herror_msg.c
@@ -2,49 +2,18 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdarg.h>
-#include <stdlib.h>
-
#include "libbb.h"
-extern void herror_msg(const char *s, ...)
+void FAST_FUNC bb_herror_msg(const char *s, ...)
{
va_list p;
va_start(p, s);
- vherror_msg(s, p);
+ bb_verror_msg(s, p, hstrerror(h_errno));
va_end(p);
}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/herror_msg_and_die.c b/release/src/router/busybox/libbb/herror_msg_and_die.c
index 0df5ed01..230fe645 100644
--- a/release/src/router/busybox/libbb/herror_msg_and_die.c
+++ b/release/src/router/busybox/libbb/herror_msg_and_die.c
@@ -2,50 +2,19 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdarg.h>
-#include <stdlib.h>
-
#include "libbb.h"
-extern void herror_msg_and_die(const char *s, ...)
+void FAST_FUNC bb_herror_msg_and_die(const char *s, ...)
{
va_list p;
va_start(p, s);
- vherror_msg(s, p);
+ bb_verror_msg(s, p, hstrerror(h_errno));
va_end(p);
- exit(EXIT_FAILURE);
+ xfunc_die();
}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/human_readable.c b/release/src/router/busybox/libbb/human_readable.c
index 21e13dc4..05e7d86e 100644
--- a/release/src/router/busybox/libbb/human_readable.c
+++ b/release/src/router/busybox/libbb/human_readable.c
@@ -1,3 +1,4 @@
+/* vi: set sw=4 ts=4: */
/*
* June 30, 2001 Manuel Novoa III
*
@@ -13,8 +14,8 @@
* 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
+ * 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
@@ -23,52 +24,72 @@
*
* Some code to omit the decimal point and tenths digit is sketched out
* and "#if 0"'d below.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
#include "libbb.h"
-const char *make_human_readable_str(unsigned long size,
- unsigned long block_size,
- unsigned long display_unit)
+const char* FAST_FUNC 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";
+ /* The code will adjust for additional (appended) units */
+ static const char unit_chars[] ALIGN1 = {
+ '\0', 'K', 'M', 'G', 'T', 'P', 'E'
+ };
+ static const char fmt[] ALIGN1 = "%llu";
+ static const char fmt_tenths[] ALIGN1 = "%llu.%d%c";
+
+ static char str[21] ALIGN1; /* Sufficient for 64 bit unsigned integers */
- static char str[21]; /* Sufficient for 64 bit unsigned integers. */
-
unsigned long long val;
int frac;
const char *u;
const char *f;
+ smallint no_tenths;
- u = zero_and_units;
- f = fmt;
- frac = 0;
+ if (size == 0)
+ return "0";
- val = ((unsigned long long) size) * block_size;
- if (val == 0) {
- return u;
+ /* If block_size is 0 then do not print tenths */
+ no_tenths = 0;
+ if (block_size == 0) {
+ no_tenths = 1;
+ block_size = 1;
}
+ u = unit_chars;
+ val = size * block_size;
+ f = fmt;
+ frac = 0;
+
if (display_unit) {
- val += display_unit/2; /* Deal with rounding. */
+ val += display_unit/2; /* Deal with rounding */
val /= display_unit; /* Don't combine with the line above!!! */
+ /* will just print it as ulonglong (below) */
} else {
- ++u;
- while ((val >= KILOBYTE)
- && (u < zero_and_units + sizeof(zero_and_units) - 1)) {
+ while ((val >= 1024)
+ && (u < unit_chars + sizeof(unit_chars) - 1)
+ ) {
f = fmt_tenths;
- ++u;
- frac = ((((int)(val % KILOBYTE)) * 10) + (KILOBYTE/2)) / KILOBYTE;
- val /= KILOBYTE;
+ u++;
+ frac = (((int)(val % 1024)) * 10 + 1024/2) / 1024;
+ val /= 1024;
}
if (frac >= 10) { /* We need to round up here. */
++val;
frac = 0;
}
+#if 1
+ /* Sample code to omit decimal point and tenths digit. */
+ if (no_tenths) {
+ if (frac >= 5) {
+ ++val;
+ }
+ f = "%llu%*c" /* fmt_no_tenths */;
+ frac = 1;
+ }
+#endif
}
/* If f==fmt then 'frac' and 'u' are ignored. */
diff --git a/release/src/router/busybox/libbb/inet_common.c b/release/src/router/busybox/libbb/inet_common.c
index 4e574ea5..fa4d8672 100644
--- a/release/src/router/busybox/libbb/inet_common.c
+++ b/release/src/router/busybox/libbb/inet_common.c
@@ -1,41 +1,31 @@
+/* vi: set sw=4 ts=4: */
/*
* 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.1.3.1 2004/12/29 07:07:45 honor Exp $
- *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include "inet_common.h"
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include "libbb.h"
+#include "inet_common.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)
+int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst)
{
struct hostent *hp;
+#if ENABLE_FEATURE_ETC_NETWORKS
struct netent *np;
+#endif
/* 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)) {
+ if (!strcmp(name, bb_str_default)) {
s_in->sin_addr.s_addr = INADDR_ANY;
- return (1);
+ return 1;
}
/* Look to see if it's a dotted quad. */
if (inet_aton(name, &s_in->sin_addr)) {
@@ -44,206 +34,188 @@ int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst)
/* If we expect this to be a hostname, try hostname database first */
#ifdef DEBUG
if (hostfirst) {
- bb_error_msg("gethostbyname (%s)", name);
+ 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;
+ if (hostfirst) {
+ hp = gethostbyname(name);
+ if (hp != NULL) {
+ memcpy(&s_in->sin_addr, hp->h_addr_list[0],
+ sizeof(struct in_addr));
+ return 0;
+ }
}
+#if ENABLE_FEATURE_ETC_NETWORKS
/* Try the NETWORKS database to see if this is a known network. */
#ifdef DEBUG
- bb_error_msg("getnetbyname (%s)", name);
+ bb_error_msg("getnetbyname(%s)", name);
#endif
- if ((np = getnetbyname(name)) != (struct netent *) NULL) {
+ np = getnetbyname(name);
+ if (np != NULL) {
s_in->sin_addr.s_addr = htonl(np->n_net);
return 1;
}
+#endif
if (hostfirst) {
/* Don't try again */
- errno = h_errno;
return -1;
}
#ifdef DEBUG
res_init();
_res.options |= RES_DEBUG;
+ bb_error_msg("gethostbyname(%s)", name);
#endif
-
-#ifdef DEBUG
- bb_error_msg("gethostbyname (%s)", name);
-#endif
- if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
- errno = h_errno;
+ hp = gethostbyname(name);
+ if (hp == NULL) {
return -1;
}
- memcpy((char *) &s_in->sin_addr, (char *) hp->h_addr_list[0],
- sizeof(struct in_addr));
-
+ memcpy(&s_in->sin_addr, 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)
+char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask)
{
- struct hostent *ent;
- struct netent *np;
+ /* addr-to-name cache */
+ struct addr {
+ struct addr *next;
+ struct sockaddr_in addr;
+ int host;
+ char name[1];
+ };
+ static struct addr *cache = NULL;
+
struct addr *pn;
- unsigned long ad, host_ad;
+ char *name;
+ uint32_t 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 !",
+ bb_error_msg("rresolve: unsupported address family %d!",
s_in->sin_family);
#endif
errno = EAFNOSUPPORT;
- return (-1);
+ return NULL;
}
- ad = (unsigned long) s_in->sin_addr.s_addr;
+ ad = s_in->sin_addr.s_addr;
#ifdef DEBUG
- bb_error_msg("rresolve: %08lx, mask %08x, num %08x", ad, netmask, numeric);
+ bb_error_msg("rresolve: %08x, mask %08x, num %08x", (unsigned)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);
+ return xstrdup(bb_str_default);
+ return xstrdup("*");
}
}
- if (numeric & 0x0FFF) {
- safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
- return (0);
- }
+ if (numeric & 0x0FFF)
+ return xstrdup(inet_ntoa(s_in->sin_addr));
if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
host = 1;
-#if 0
- INET_nn = NULL;
-#endif
- pn = INET_nn;
- while (pn != NULL) {
+ pn = cache;
+ while (pn) {
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);
+ bb_error_msg("rresolve: found %s %08x in cache",
+ (host ? "host" : "net"), (unsigned)ad);
#endif
- return (0);
+ return xstrdup(pn->name);
}
pn = pn->next;
}
host_ad = ntohl(ad);
- np = NULL;
- ent = NULL;
+ name = NULL;
if (host) {
+ struct hostent *ent;
#ifdef DEBUG
- bb_error_msg("gethostbyaddr (%08lx)", ad);
+ bb_error_msg("gethostbyaddr (%08x)", (unsigned)ad);
#endif
ent = gethostbyaddr((char *) &ad, 4, AF_INET);
- if (ent != NULL) {
- safe_strncpy(name, ent->h_name, len);
- }
- } else {
+ if (ent)
+ name = xstrdup(ent->h_name);
+ } else if (ENABLE_FEATURE_ETC_NETWORKS) {
+ struct netent *np;
#ifdef DEBUG
- bb_error_msg("getnetbyaddr (%08lx)", host_ad);
+ bb_error_msg("getnetbyaddr (%08x)", (unsigned)host_ad);
#endif
np = getnetbyaddr(host_ad, AF_INET);
- if (np != NULL) {
- safe_strncpy(name, np->n_name, len);
- }
+ if (np)
+ name = xstrdup(np->n_name);
}
- if ((ent == NULL) && (np == NULL)) {
- safe_strncpy(name, inet_ntoa(s_in->sin_addr), len);
- }
- pn = (struct addr *) xmalloc(sizeof(struct addr));
+ if (!name)
+ name = xstrdup(inet_ntoa(s_in->sin_addr));
+ pn = xmalloc(sizeof(*pn) + strlen(name)); /* no '+ 1', it's already accounted for */
+ pn->next = cache;
pn->addr = *s_in;
- pn->next = INET_nn;
pn->host = host;
- pn->name = bb_xstrdup(name);
- INET_nn = pn;
-
- return (0);
+ strcpy(pn->name, name);
+ cache = pn;
+ return name;
}
-#ifdef CONFIG_FEATURE_IPV6
+#if ENABLE_FEATURE_IPV6
-int INET6_resolve(char *name, struct sockaddr_in6 *sin6)
+int FAST_FUNC 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))) {
+ s = getaddrinfo(name, NULL, &req, &ai);
+ if (s) {
bb_error_msg("getaddrinfo: %s: %d", name, s);
return -1;
}
memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6));
-
freeaddrinfo(ai);
-
- return (0);
+ 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)
+ (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \
+ ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0)
#endif
-int INET6_rresolve(char *name, size_t len, struct sockaddr_in6 *sin6,
- int numeric)
+char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)
{
+ char name[128];
int s;
- /* Grmpf. -FvK */
if (sin6->sin6_family != AF_INET6) {
#ifdef DEBUG
- bb_error_msg(_("rresolve: unsupport address family %d !\n"),
+ bb_error_msg("rresolve: unsupport address family %d!",
sin6->sin6_family);
#endif
errno = EAFNOSUPPORT;
- return (-1);
+ return NULL;
}
if (numeric & 0x7FFF) {
- inet_ntop(AF_INET6, &sin6->sin6_addr, name, len);
- return (0);
+ inet_ntop(AF_INET6, &sin6->sin6_addr, name, sizeof(name));
+ return xstrdup(name);
}
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- if (numeric & 0x8000) {
- strcpy(name, "default");
- } else {
- strcpy(name, "*");
- }
- return (0);
+ if (numeric & 0x8000)
+ return xstrdup(bb_str_default);
+ return xstrdup("*");
}
- s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6), name, len, NULL, 0, 0);
+ s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6),
+ name, sizeof(name), NULL, 0, 0);
if (s) {
bb_error_msg("getnameinfo failed");
- return -1;
+ return NULL;
}
- return (0);
+ return xstrdup(name);
}
-#endif /* CONFIG_FEATURE_IPV6 */
+#endif /* CONFIG_FEATURE_IPV6 */
diff --git a/release/src/router/busybox/libbb/info_msg.c b/release/src/router/busybox/libbb/info_msg.c
new file mode 100644
index 00000000..8b8a1fcc
--- /dev/null
+++ b/release/src/router/busybox/libbb/info_msg.c
@@ -0,0 +1,56 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include <syslog.h>
+
+void FAST_FUNC bb_info_msg(const char *s, ...)
+{
+#ifdef THIS_ONE_DOESNT_DO_SINGLE_WRITE
+ va_list p;
+ /* va_copy is used because it is not portable
+ * to use va_list p twice */
+ va_list p2;
+
+ va_start(p, s);
+ va_copy(p2, p);
+ if (logmode & LOGMODE_STDIO) {
+ vprintf(s, p);
+ fputs(msg_eol, stdout);
+ }
+ if (ENABLE_FEATURE_SYSLOG && (logmode & LOGMODE_SYSLOG))
+ vsyslog(LOG_INFO, s, p2);
+ va_end(p2);
+ va_end(p);
+#else
+ int used;
+ char *msg;
+ va_list p;
+
+ if (logmode == 0)
+ return;
+
+ va_start(p, s);
+ used = vasprintf(&msg, s, p);
+ if (used < 0)
+ return;
+
+ if (ENABLE_FEATURE_SYSLOG && (logmode & LOGMODE_SYSLOG))
+ syslog(LOG_INFO, "%s", msg);
+ if (logmode & LOGMODE_STDIO) {
+ fflush(stdout);
+ /* used = strlen(msg); - must be true already */
+ msg[used++] = '\n';
+ full_write(STDOUT_FILENO, msg, used);
+ }
+
+ free(msg);
+ va_end(p);
+#endif
+}
diff --git a/release/src/router/busybox/libbb/inode_hash.c b/release/src/router/busybox/libbb/inode_hash.c
index 790af8f3..b32bd26b 100644
--- a/release/src/router/busybox/libbb/inode_hash.c
+++ b/release/src/router/busybox/libbb/inode_hash.c
@@ -2,105 +2,86 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include "libbb.h"
+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;
+
#define HASH_SIZE 311 /* Should be prime */
#define hash_inode(i) ((i) % HASH_SIZE)
-static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
+/* array of [HASH_SIZE] elements */
+static ino_dev_hashtable_bucket_t **ino_dev_hashtable;
/*
- * 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.
+ * Return name if statbuf->st_ino && statbuf->st_dev are recorded in
+ * ino_dev_hashtable, else return NULL
*/
-int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
+char* FAST_FUNC is_in_ino_dev_hashtable(const struct stat *statbuf)
{
ino_dev_hashtable_bucket_t *bucket;
+ if (!ino_dev_hashtable)
+ return NULL;
+
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;
+ if ((bucket->ino == statbuf->st_ino)
+ && (bucket->dev == statbuf->st_dev)
+ ) {
+ return bucket->name;
+ }
+ bucket = bucket->next;
}
- return 0;
+ return NULL;
}
/* Add statbuf to statbuf hash table */
-void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
+void FAST_FUNC 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);
+ if (!name)
+ name = "";
+ bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name));
bucket->ino = statbuf->st_ino;
bucket->dev = statbuf->st_dev;
- if (name)
- strcpy(bucket->name, name);
- else
- bucket->name[0] = '\0';
+ strcpy(bucket->name, name);
+
+ if (!ino_dev_hashtable)
+ ino_dev_hashtable = xzalloc(HASH_SIZE * sizeof(*ino_dev_hashtable));
+
bucket->next = ino_dev_hashtable[i];
ino_dev_hashtable[i] = bucket;
}
+#if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP
/* Clear statbuf hash table */
-void reset_ino_dev_hashtable(void)
+void FAST_FUNC reset_ino_dev_hashtable(void)
{
int i;
ino_dev_hashtable_bucket_t *bucket;
- for (i = 0; i < HASH_SIZE; i++) {
+ for (i = 0; ino_dev_hashtable && 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;
}
}
+ free(ino_dev_hashtable);
+ ino_dev_hashtable = NULL;
}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+#endif
diff --git a/release/src/router/busybox/libbb/interface.c b/release/src/router/busybox/libbb/interface.c
deleted file mode 100644
index 4af35fcb..00000000
--- a/release/src/router/busybox/libbb/interface.c
+++ /dev/null
@@ -1,2113 +0,0 @@
-/*
- * 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.1.1.4 2003/10/14 08:09:39 sparq 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)
- * stolen from net-tools-1.59 and stripped down for busybox by
- * Erik Andersen <andersee@debian.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.
- */
-
-/* #define KEEP_UNUSED */
-
-/*
- *
- * Protocol Families.
- *
- */
-#define HAVE_AFINET 1
-#undef HAVE_AFINET6
-#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 <features.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include "libbb.h"
-
-#define _(x) x
-#define _PATH_PROCNET_DEV "/proc/net/dev"
-#define new(p) ((p) = xcalloc(1,sizeof(*(p))))
-#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
-
-static int procnetdev_vsn = 1;
-
-
-/* Ugh. But libc5 doesn't provide POSIX types. */
-#include <asm/types.h>
-
-
-#ifdef HAVE_HWSLIP
-#include <linux/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;
- __u32 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;
-};
-
-static struct aftype *aftypes[];
-
-#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
-
-
-/* cache */
-struct addr {
- struct sockaddr_in addr;
- char *name;
- int host;
- struct addr *next;
-};
-
-static struct addr *INET_nn = NULL; /* addr-to-name cache */
-
-#ifdef KEEP_UNUSED
-static int INET_resolve(char *name, struct sockaddr_in *sin, int hostfirst)
-{
- struct hostent *hp;
- struct netent *np;
-
- /* Grmpf. -FvK */
- sin->sin_family = AF_INET;
- sin->sin_port = 0;
-
- /* Default is special, meaning 0.0.0.0. */
- if (!strcmp(name, "default")) {
- sin->sin_addr.s_addr = INADDR_ANY;
- return (1);
- }
- /* Look to see if it's a dotted quad. */
- if (inet_aton(name, &sin->sin_addr)) {
- return 0;
- }
- /* If we expect this to be a hostname, try hostname database first */
-#ifdef DEBUG
- if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name);
-#endif
- if (hostfirst &&
- (hp = gethostbyname(name)) != (struct hostent *) NULL) {
- memcpy((char *) &sin->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
- fprintf (stderr, "getnetbyname (%s)\n", name);
-#endif
- if ((np = getnetbyname(name)) != (struct netent *) NULL) {
- sin->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
- fprintf (stderr, "gethostbyname (%s)\n", name);
-#endif
- if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
- errno = h_errno;
- return -1;
- }
- memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0],
- sizeof(struct in_addr));
-
- return 0;
-}
-#endif /* KEEP_UNUSED */
-
-/* numeric: & 0x8000: default instead of *,
- * & 0x4000: host instead of net,
- * & 0x0fff: don't resolve
- */
-static 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
- fprintf(stderr, _("rresolve: unsupport address family %d !\n"), s_in->sin_family);
-#endif
- errno = EAFNOSUPPORT;
- return (-1);
- }
- ad = (unsigned long) s_in->sin_addr.s_addr;
-#ifdef DEBUG
- fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric);
-#endif
- if (ad == INADDR_ANY) {
- if ((numeric & 0x0FFF) == 0) {
- if (numeric & 0x8000)
- safe_strncpy(name, "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;
- 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
- fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad);
-#endif
- return (0);
- }
- pn = pn->next;
- }
-
- host_ad = ntohl(ad);
- np = NULL;
- ent = NULL;
- if (host) {
-#ifdef DEBUG
- fprintf (stderr, "gethostbyaddr (%08lx)\n", ad);
-#endif
- ent = gethostbyaddr((char *) &ad, 4, AF_INET);
- if (ent != NULL)
- safe_strncpy(name, ent->h_name, len);
- } else {
-#ifdef DEBUG
- fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad);
-#endif
- }
- 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 = (char *) xmalloc(strlen(name) + 1);
- strcpy(pn->name, name);
- INET_nn = pn;
-
- return (0);
-}
-
-#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 */
-
-/* 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)) {
- fprintf(stderr, _("Too much address family arguments.\n"));
- return (0);
- }
- if (paft->flag)
- (*paft->flag)++;
- if (afname[0])
- strcat(afname, ",");
- strcat(afname, paft->name);
- break;
- }
- if (!paft->alias) {
- fprintf(stderr, _("Unknown address family `%s'.\n"), 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, ','))
- fprintf(stderr, _("Please don't supply more than one address family.\n"));
- 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)
- fprintf(stderr, _("No usable address families found.\n"));
- return sfd;
-}
-
-/* like strcmp(), but knows about numbers */
-static int nstrcmp(const char *astr, const char *b)
-{
- const char *a = astr;
-
- while (*a == *b) {
- if (*a == '\0')
- return 0;
- a++;
- b++;
- }
- if (isdigit(*a)) {
- if (!isdigit(*b))
- return -1;
- while (a > astr) {
- a--;
- if (!isdigit(*a)) {
- a++;
- break;
- }
- if (!isdigit(*b))
- return -1;
- b--;
- }
- return atoi(a) > atoi(b) ? 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) {
- fprintf(stderr, _("warning: no inet socket available: %s\n"),
- strerror(errno));
- /* 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;
-}
-
-static char *get_name(char *name, char *p)
-{
- while (isspace(*p))
- p++;
- while (*p) {
- if (isspace(*p))
- break;
- if (*p == ':') { /* could be an alias */
- char *dot = p, *dotname = name;
- *name++ = *p++;
- while (isdigit(*p))
- *name++ = *p++;
- if (*p != ':') { /* it wasn't, backup */
- p = dot;
- name = dotname;
- }
- if (*p == '\0')
- return NULL;
- p++;
- break;
- }
- *name++ = *p++;
- }
- *name++ = '\0';
- return p;
-}
-
-static int get_dev_fields(char *bp, struct interface *ife)
-{
- switch (procnetdev_vsn) {
- case 3:
- sscanf(bp,
- "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
- &ife->stats.rx_bytes,
- &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,
- &ife->stats.rx_multicast,
-
- &ife->stats.tx_bytes,
- &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);
- break;
- case 2:
- sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
- &ife->stats.rx_bytes,
- &ife->stats.rx_packets,
- &ife->stats.rx_errors,
- &ife->stats.rx_dropped,
- &ife->stats.rx_fifo_errors,
- &ife->stats.rx_frame_errors,
-
- &ife->stats.tx_bytes,
- &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.rx_multicast = 0;
- break;
- case 1:
- sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
- &ife->stats.rx_packets,
- &ife->stats.rx_errors,
- &ife->stats.rx_dropped,
- &ife->stats.rx_fifo_errors,
- &ife->stats.rx_frame_errors,
-
- &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.rx_bytes = 0;
- ife->stats.tx_bytes = 0;
- ife->stats.rx_multicast = 0;
- break;
- }
- return 0;
-}
-
-static inline int procnetdev_version(char *buf)
-{
- if (strstr(buf, "compressed"))
- return 3;
- if (strstr(buf, "bytes"))
- return 2;
- return 1;
-}
-
-static int if_readlist_proc(char *target)
-{
- static int proc_read;
- FILE *fh;
- char buf[512];
- struct interface *ife;
- int err;
-
- if (proc_read)
- return 0;
- if (!target)
- proc_read = 1;
-
- fh = fopen(_PATH_PROCNET_DEV, "r");
- if (!fh) {
- fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
- _PATH_PROCNET_DEV, strerror(errno));
- 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[IFNAMSIZ];
- s = get_name(name, buf);
- ife = add_interface(name);
- get_dev_fields(s, ife);
- 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);
- }
- fprintf(stderr, _("%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>
-#include <linux/if_ether.h>
-
-static struct hwtype ether_hwtype;
-
-/* 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
- fprintf(stderr, _("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
- fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), 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 == ':') {
- if (i == ETH_ALEN) {
-#ifdef DEBUG
- fprintf(stderr, _("in_ether(%s): trailing : ignored!\n"),
- orig)
-#endif
- ; /* nothing */
- }
- bufp++;
- }
- }
-
- /* That's it. Any trailing junk? */
- if ((i == ETH_ALEN) && (*bufp != '\0')) {
-#ifdef DEBUG
- fprintf(stderr, _("in_ether(%s): trailing junk!\n"), orig);
- errno = EINVAL;
- return (-1);
-#endif
- }
-#ifdef DEBUG
- fprintf(stderr, "in_ether(%s): %s\n", 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)
-{
- fprintf(stderr, _("You cannot start PPP with this program.\n"));
- 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
-static const char *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},
-};
-#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\0k\0M";
-
-static void print_bytes_scaled(unsigned long long ull, const char *end)
-{
- unsigned long long int_part;
- unsigned long frac_part;
- const char *ext;
- int i;
-
- frac_part = 0;
- ext = TRext;
- int_part = ull;
- for (i=0 ; i<2 ; i++) {
- if (int_part >= 1024) {
- frac_part = ((int_part % 1024) * 10) / 1024;
- int_part /= 1024;
- ext += 2; /* Kb, Mb */
- }
- }
-
- printf("X bytes:%Lu (%Lu.%lu %sb)%s", ull, int_part, frac_part, ext, end);
-}
-
-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;
- extern struct aftype inet6_aftype;
- 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
-
- 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]);
- inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
- printf(_(" inet6 addr: %s/%d"),
- inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen);
- printf(_(" Scope:"));
- switch (scope) {
- 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] "));
- if (ptr->flags & IFF_UP)
- printf(_("UP "));
- if (ptr->flags & IFF_BROADCAST)
- printf(_("BROADCAST "));
- if (ptr->flags & IFF_DEBUG)
- printf(_("DEBUG "));
- if (ptr->flags & IFF_LOOPBACK)
- printf(_("LOOPBACK "));
- if (ptr->flags & IFF_POINTOPOINT)
- printf(_("POINTOPOINT "));
- if (ptr->flags & IFF_NOTRAILERS)
- printf(_("NOTRAILERS "));
- if (ptr->flags & IFF_RUNNING)
- printf(_("RUNNING "));
- if (ptr->flags & IFF_NOARP)
- printf(_("NOARP "));
- if (ptr->flags & IFF_PROMISC)
- printf(_("PROMISC "));
- if (ptr->flags & IFF_ALLMULTI)
- printf(_("ALLMULTI "));
- if (ptr->flags & IFF_SLAVE)
- printf(_("SLAVE "));
- if (ptr->flags & IFF_MASTER)
- printf(_("MASTER "));
- if (ptr->flags & IFF_MULTICAST)
- printf(_("MULTICAST "));
-#ifdef HAVE_DYNAMIC
- if (ptr->flags & IFF_DYNAMIC)
- printf(_("DYNAMIC "));
-#endif
- /* 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) {
- 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%x "), 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) {
- 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/release/src/router/busybox/libbb/isdirectory.c b/release/src/router/busybox/libbb/isdirectory.c
index 65f4fee0..28ed3ec2 100644
--- a/release/src/router/busybox/libbb/isdirectory.c
+++ b/release/src/router/busybox/libbb/isdirectory.c
@@ -2,70 +2,35 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * 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.
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <stdlib.h>
#include <sys/stat.h>
#include "libbb.h"
/*
- * Return TRUE if a fileName is a directory.
- * Nonexistant files return FALSE.
+ * Return TRUE if fileName is a directory.
+ * Nonexistent files return FALSE.
*/
-int is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
+int FAST_FUNC is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
{
int status;
- int didMalloc = 0;
+ struct stat astatBuf;
if (statBuf == NULL) {
- statBuf = (struct stat *)xmalloc(sizeof(struct stat));
- ++didMalloc;
+ /* use auto stack buffer */
+ statBuf = &astatBuf;
}
- if (followLinks == TRUE)
+ if (followLinks)
status = stat(fileName, statBuf);
else
status = lstat(fileName, statBuf);
- if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
- status = FALSE;
- }
- else status = TRUE;
+ status = (status == 0 && S_ISDIR(statBuf->st_mode));
- if (didMalloc) {
- free(statBuf);
- statBuf = NULL;
- }
return status;
}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/kernel_version.c b/release/src/router/busybox/libbb/kernel_version.c
index 09cd582c..8b9c4ec2 100644
--- a/release/src/router/busybox/libbb/kernel_version.c
+++ b/release/src/router/busybox/libbb/kernel_version.c
@@ -2,65 +2,36 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#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,
+/* Returns current 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> }
+ *
+ * if (get_linux_version_code() > KERNEL_VERSION(2,2,11)) { <stuff> }
*/
-extern int get_kernel_revision(void)
+int FAST_FUNC get_linux_version_code(void)
{
struct utsname name;
char *s;
int i, r;
if (uname(&name) == -1) {
- perror_msg("cannot get system information");
- return (0);
+ bb_perror_msg("cannot get system information");
+ return 0;
}
s = name.release;
r = 0;
- for (i=0 ; i<3 ; i++) {
+ 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/release/src/router/busybox/libbb/last_char_is.c b/release/src/router/busybox/libbb/last_char_is.c
index 4e2ee92e..b0592568 100644
--- a/release/src/router/busybox/libbb/last_char_is.c
+++ b/release/src/router/busybox/libbb/last_char_is.c
@@ -1,40 +1,24 @@
+/* vi: set sw=4 ts=4: */
/*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#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.
+/* Find out if the last character of a string matches the one given.
+ * Don't underrun the buffer if the string length is 0.
*/
-char * last_char_is(const char *s, int c)
+char* FAST_FUNC last_char_is(const char *s, int c)
{
- char *sret;
- if (!s)
- return NULL;
- sret = (char *)s+strlen(s)-1;
- if (sret>=s && *sret == c) {
- return sret;
- } else {
- return NULL;
+ if (s && *s) {
+ size_t sz = strlen(s) - 1;
+ s += sz;
+ if ( (unsigned char)*s == c)
+ return (char*)s;
}
+ return NULL;
}
diff --git a/release/src/router/busybox/libbb/libbb.h b/release/src/router/busybox/libbb/libbb.h
deleted file mode 100644
index 04ed2ae8..00000000
--- a/release/src/router/busybox/libbb/libbb.h
+++ /dev/null
@@ -1,325 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Busybox main internal header file
- *
- *
- * 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
- *
- * 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.
- *
- */
-#ifndef __LIBBB_H__
-#define __LIBBB_H__ 1
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <netdb.h>
-
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
-
-#include <features.h>
-
-#ifndef _BB_INTERNAL_H_
-#include "../busybox.h"
-#endif
-
-#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__)
-/* libc5 doesn't define socklen_t */
-typedef unsigned int socklen_t;
-/* libc5 doesn't implement BSD 4.4 daemon() */
-extern int daemon (int nochdir, int noclose);
-/* libc5 doesn't implement strtok_r */
-char *strtok_r(char *s, const char *delim, char **ptrptr);
-#endif
-
-/* Some useful definitions */
-#define FALSE ((int) 0)
-#define TRUE ((int) 1)
-#define SKIP ((int) 2)
-
-/* for mtab.c */
-#define MTAB_GETMOUNTPT '1'
-#define MTAB_GETDEVICE '2'
-
-#define BUF_SIZE 8192
-#define EXPAND_ALLOC 1024
-
-static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); }
-static inline int is_octal(int ch) { return ((ch >= '0') && (ch <= '7')); }
-
-/* Macros for min/max. */
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-
-#ifndef MAX
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#endif
-
-
-
-extern void show_usage(void) __attribute__ ((noreturn));
-extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
-extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
-extern void perror_msg(const char *s, ...);
-extern void perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
-extern void vherror_msg(const char *s, va_list p);
-extern void herror_msg(const char *s, ...);
-extern void herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn));
-
-/* These two are used internally -- you shouldn't need to use them */
-extern void verror_msg(const char *s, va_list p);
-extern void vperror_msg(const char *s, va_list p);
-
-const char *mode_string(int mode);
-const char *time_string(time_t timeVal);
-int is_directory(const char *name, int followLinks, struct stat *statBuf);
-int isDevice(const char *name);
-
-int remove_file(const char *path, int flags);
-int copy_file(const char *source, const char *dest, int flags);
-int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize);
-char *buildName(const char *dirName, const char *fileName);
-int makeString(int argc, const char **argv, char *buf, int bufLen);
-char *getChunk(int size);
-char *chunkstrdup(const char *str);
-void freeChunks(void);
-ssize_t safe_read(int fd, void *buf, size_t count);
-int full_write(int fd, const char *buf, int len);
-int full_read(int fd, char *buf, int len);
-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);
-
-extern int parse_mode( const char* s, mode_t* theMode);
-
-extern int get_kernel_revision(void);
-
-extern int get_console_fd(char* tty_name);
-extern struct mntent *find_mount_point(const char *name, const char *table);
-extern void write_mtab(char* blockDevice, char* directory,
- char* filesystemType, long flags, char* string_flags);
-extern void erase_mtab(const char * name);
-extern long atoi_w_units (const char *cp);
-extern pid_t* find_pid_by_name( char* pidName);
-extern char *find_real_root_device_name(const char* name);
-extern char *get_line_from_file(FILE *file);
-extern void print_file(FILE *file);
-extern int copyfd(int fd1, int fd2);
-extern int print_file_by_name(char *filename);
-extern char process_escape_sequence(const char **ptr);
-extern char *get_last_path_component(char *path);
-extern FILE *wfopen(const char *path, const char *mode);
-extern FILE *xfopen(const char *path, const char *mode);
-extern void chomp(char *s);
-extern void trim(char *s);
-extern struct BB_applet *find_applet_by_name(const char *name);
-void run_applet_by_name(const char *name, int argc, char **argv);
-
-#ifndef DMALLOC
-extern void *xmalloc (size_t size);
-extern void *xrealloc(void *old, size_t size);
-extern void *xcalloc(size_t nmemb, size_t size);
-extern char *xstrdup (const char *s);
-#endif
-extern char *xstrndup (const char *s, int n);
-extern char * safe_strncpy(char *dst, const char *src, size_t size);
-
-struct suffix_mult {
- const char *suffix;
- int mult;
-};
-
-extern unsigned long parse_number(const char *numstr,
- const struct suffix_mult *suffixes);
-
-
-/* These parse entries in /etc/passwd and /etc/group. This is desirable
- * for BusyBox since we want to avoid using the glibc NSS stuff, which
- * increases target size and is often not needed embedded systems. */
-extern long my_getpwnam(const char *name);
-extern long my_getgrnam(const char *name);
-extern void my_getpwuid(char *name, long uid);
-extern void my_getgrgid(char *group, long gid);
-extern long my_getpwnamegid(const char *name);
-
-extern int device_open(char *device, int mode);
-
-extern int del_loop(const char *device);
-extern int set_loop(const char *device, const char *file, int offset, int *loopro);
-extern char *find_unused_loop_device (void);
-
-
-#if (__GLIBC__ < 2)
-extern int vdprintf(int d, const char *format, va_list ap);
-#endif
-
-int nfsmount(const char *spec, const char *node, int *flags,
- char **extra_opts, char **mount_opts, int running_bg);
-
-void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg);
-void syslog_msg(int facility, int pri, const char *msg);
-
-/* Include our own copy of struct sysinfo to avoid binary compatability
- * problems with Linux 2.4, which changed things. Grumble, grumble. */
-struct sysinfo {
- long uptime; /* Seconds since boot */
- unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
- unsigned long totalram; /* Total usable main memory size */
- unsigned long freeram; /* Available memory size */
- unsigned long sharedram; /* Amount of shared memory */
- unsigned long bufferram; /* Memory used by buffers */
- unsigned long totalswap; /* Total swap space size */
- unsigned long freeswap; /* swap space still available */
- unsigned short procs; /* Number of current processes */
- unsigned short pad; /* Padding needed for m68k */
- unsigned long totalhigh; /* Total high memory size */
- unsigned long freehigh; /* Available high memory size */
- unsigned int mem_unit; /* Memory unit size in bytes */
- char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
-};
-extern int sysinfo (struct sysinfo* info);
-
-enum {
- KILOBYTE = 1024,
- MEGABYTE = (KILOBYTE*1024),
- GIGABYTE = (MEGABYTE*1024)
-};
-const char *make_human_readable_str(unsigned long size, unsigned long block_size, unsigned long display_unit);
-
-int ask_confirmation(void);
-int klogctl(int type, char * b, int len);
-
-char *xgetcwd(char *cwd);
-char *xreadlink(const char *path);
-char *concat_path_file(const char *path, const char *filename);
-char *last_char_is(const char *s, int c);
-
-extern long arith (const char *startbuf, int *errcode);
-
-typedef struct file_headers_s {
- char *name;
- char *link_name;
- off_t size;
- uid_t uid;
- gid_t gid;
- mode_t mode;
- time_t mtime;
- dev_t device;
-} file_header_t;
-file_header_t *get_header_ar(FILE *in_file);
-file_header_t *get_header_cpio(FILE *src_stream);
-file_header_t *get_header_tar(FILE *tar_stream);
-
-enum extract_functions_e {
- extract_verbose_list = 1,
- extract_list = 2,
- extract_one_to_buffer = 4,
- extract_to_stdout = 8,
- extract_all_to_fs = 16,
- extract_preserve_date = 32,
- extract_data_tar_gz = 64,
- extract_control_tar_gz = 128,
- extract_unzip_only = 256,
- extract_unconditional = 512,
- extract_create_leading_dirs = 1024,
- extract_quiet = 2048,
- extract_exclude_list = 4096
-};
-char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_header)(FILE *),
- const int extract_function, const char *prefix, char **extract_names);
-char *deb_extract(const char *package_filename, FILE *out_stream, const int extract_function,
- const char *prefix, const char *filename);
-int read_package_field(const char *package_buffer, char **field_name, char **field_value);
-char *fgets_str(FILE *file, const char *terminating_string);
-
-extern int unzip(FILE *l_in_file, FILE *l_out_file);
-extern void gz_close(int gunzip_pid);
-extern FILE *gz_open(FILE *compressed_file, int *pid);
-
-extern struct hostent *xgethostbyname(const char *name);
-extern int create_icmp_socket(void);
-
-char *dirname (const char *path);
-
-int make_directory (char *path, long mode, int flags);
-
-const char *u_signal_names(const char *str_sig, int *signo, int startnum);
-
-#define CT_AUTO 0
-#define CT_UNIX2DOS 1
-#define CT_DOS2UNIX 2
-/* extern int convert(char *fn, int ConvType); */
-
-enum {
- FILEUTILS_PRESERVE_STATUS = 1,
- FILEUTILS_PRESERVE_SYMLINKS = 2,
- FILEUTILS_RECUR = 4,
- FILEUTILS_FORCE = 8,
- FILEUTILS_INTERACTIVE = 16
-};
-
-extern const char *applet_name;
-extern const char * const full_version;
-extern const char * const name_too_long;
-extern const char * const omitting_directory;
-extern const char * const not_a_directory;
-extern const char * const memory_exhausted;
-extern const char * const invalid_date;
-extern const char * const invalid_option;
-extern const char * const io_error;
-extern const char * const dash_dash_help;
-extern const char * const write_error;
-extern const char * const too_few_args;
-extern const char * const name_longer_than_foo;
-extern const char * const unknown;
-extern const char * const can_not_create_raw_socket;
-
-#ifdef BB_FEATURE_DEVFS
-# define CURRENT_VC "/dev/vc/0"
-# define VC_1 "/dev/vc/1"
-# define VC_2 "/dev/vc/2"
-# define VC_3 "/dev/vc/3"
-# define VC_4 "/dev/vc/4"
-# define VC_5 "/dev/vc/5"
-# define SC_0 "/dev/tts/0"
-# define SC_1 "/dev/tts/1"
-# define VC_FORMAT "/dev/vc/%d"
-# define SC_FORMAT "/dev/tts/%d"
-#else
-# define CURRENT_VC "/dev/tty0"
-# define VC_1 "/dev/tty1"
-# define VC_2 "/dev/tty2"
-# define VC_3 "/dev/tty3"
-# define VC_4 "/dev/tty4"
-# define VC_5 "/dev/tty5"
-# define SC_0 "/dev/ttyS0"
-# define SC_1 "/dev/ttyS1"
-# define VC_FORMAT "/dev/tty%d"
-# define SC_FORMAT "/dev/ttyS%d"
-#endif
-
-/* The following devices are the same on devfs and non-devfs systems. */
-#define CURRENT_TTY "/dev/tty"
-#define CONSOLE_DEV "/dev/console"
-
-#endif /* __LIBBB_H__ */
diff --git a/release/src/router/busybox/libbb/libc5.c b/release/src/router/busybox/libbb/libc5.c
deleted file mode 100644
index 20295fd4..00000000
--- a/release/src/router/busybox/libbb/libc5.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/* vi: set sw=4 ts=4: */
-
-
-#include <features.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <unistd.h>
-
-
-#if __GNU_LIBRARY__ < 5
-
-
-/* Copyright (C) 1991 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
-
-The GNU C Library 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 Library General Public
-License along with the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-/*
- * Modified by Manuel Novoa III Mar 1, 2001
- *
- * Converted original strtok.c code of strtok to __strtok_r.
- * Cleaned up logic and reduced code size.
- */
-
-
-char *strtok_r(char *s, const char *delim, char **save_ptr)
-{
- char *token;
-
- token = 0; /* Initialize to no token. */
-
- if (s == 0) { /* If not first time called... */
- s = *save_ptr; /* restart from where we left off. */
- }
-
- if (s != 0) { /* If not finished... */
- *save_ptr = 0;
-
- s += strspn(s, delim); /* Skip past any leading delimiters. */
- if (*s != '\0') { /* We have a token. */
- token = s;
- *save_ptr = strpbrk(token, delim); /* Find token's end. */
- if (*save_ptr != 0) {
- /* Terminate the token and make SAVE_PTR point past it. */
- *(*save_ptr)++ = '\0';
- }
- }
- }
-
- return token;
-}
-
-/* Basically getdelim() with the delimiter hard wired to '\n' */
-ssize_t getline(char **linebuf, size_t *n, FILE *file)
-{
- return (getdelim (linebuf, n, '\n', file));
-}
-
-
-/*
- * daemon implementation for uClibc
- *
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Modified for uClibc by Erik Andersen
- * <andersee@debian.org>, <andersen@lineo.com>
- *
- * The uClibc Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * The GNU C Library 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 Library General Public
- * License along with the GNU C Library; see the file COPYING.LIB. 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.
- */
-
-int daemon( int nochdir, int noclose )
-{
- int fd;
-
- switch (fork()) {
- case -1:
- return(-1);
- case 0:
- break;
- default:
- _exit(0);
- }
-
- if (setsid() == -1)
- return(-1);
-
- 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);
- }
- return(0);
-}
-
-
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
- * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
- *
- * 4. 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.
- */
-
-
-#endif
-
diff --git a/release/src/router/busybox/libbb/lineedit.c b/release/src/router/busybox/libbb/lineedit.c
new file mode 100644
index 00000000..7bcdb954
--- /dev/null
+++ b/release/src/router/busybox/libbb/lineedit.c
@@ -0,0 +1,2006 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Termios command line History and Editing.
+ *
+ * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
+ * Written by: Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Used ideas:
+ * Adam Rogoyski <rogoyski@cs.utexas.edu>
+ * Dave Cinege <dcinege@psychosis.com>
+ * Jakub Jelinek (c) 1995
+ * Erik Andersen <andersen@codepoet.org> (Majorly adjusted for busybox)
+ *
+ * This code is 'as is' with no warranty.
+ */
+
+/*
+ * Usage and known bugs:
+ * Terminal key codes are not extensive, and more will probably
+ * need to be added. This version was created on Debian GNU/Linux 2.x.
+ * Delete, Backspace, Home, End, and the arrow keys were tested
+ * to work in an Xterm and console. Ctrl-A also works as Home.
+ * Ctrl-E also works as End.
+ *
+ * lineedit does not know that the terminal escape sequences do not
+ * take up space on the screen. The redisplay code assumes, unless
+ * told otherwise, that each character in the prompt is a printable
+ * character that takes up one character position on the screen.
+ * You need to tell lineedit that some sequences of characters
+ * in the prompt take up no screen space. Compatibly with readline,
+ * use the \[ escape to begin a sequence of non-printing characters,
+ * and the \] escape to signal the end of such a sequence. Example:
+ *
+ * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
+ */
+
+#include "libbb.h"
+
+
+/* FIXME: obsolete CONFIG item? */
+#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
+
+
+#ifdef TEST
+
+#define ENABLE_FEATURE_EDITING 0
+#define ENABLE_FEATURE_TAB_COMPLETION 0
+#define ENABLE_FEATURE_USERNAME_COMPLETION 0
+#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
+
+#endif /* TEST */
+
+
+/* Entire file (except TESTing part) sits inside this #if */
+#if ENABLE_FEATURE_EDITING
+
+#if ENABLE_LOCALE_SUPPORT
+#define Isprint(c) isprint(c)
+#else
+#define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233'))
+#endif
+
+#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
+ (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
+#define USE_FEATURE_GETUSERNAME_AND_HOMEDIR(...)
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+#undef USE_FEATURE_GETUSERNAME_AND_HOMEDIR
+#define USE_FEATURE_GETUSERNAME_AND_HOMEDIR(...) __VA_ARGS__
+#endif
+
+enum {
+ /* We use int16_t for positions, need to limit line len */
+ MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
+ ? CONFIG_FEATURE_EDITING_MAX_LEN
+ : 0x7ff0
+};
+
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+static const char null_str[] ALIGN1 = "";
+#endif
+
+/* We try to minimize both static and stack usage. */
+struct lineedit_statics {
+ line_input_t *state;
+
+ volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
+ sighandler_t previous_SIGWINCH_handler;
+
+ unsigned cmdedit_x; /* real x terminal position */
+ unsigned cmdedit_y; /* pseudoreal y terminal position */
+ unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
+
+ unsigned cursor;
+ unsigned command_len;
+ char *command_ps;
+
+ const char *cmdedit_prompt;
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ int num_ok_lines; /* = 1; */
+#endif
+
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ char *user_buf;
+ char *home_pwd_buf; /* = (char*)null_str; */
+#endif
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ char **matches;
+ unsigned num_matches;
+#endif
+
+#if ENABLE_FEATURE_EDITING_VI
+#define DELBUFSIZ 128
+ char *delptr;
+ smallint newdelflag; /* whether delbuf should be reused yet */
+ char delbuf[DELBUFSIZ]; /* a place to store deleted characters */
+#endif
+
+ /* Formerly these were big buffers on stack: */
+#if ENABLE_FEATURE_TAB_COMPLETION
+ char exe_n_cwd_tab_completion__dirbuf[MAX_LINELEN];
+ char input_tab__matchBuf[MAX_LINELEN];
+ int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */
+ int16_t find_match__pos_buf[MAX_LINELEN + 1];
+#endif
+};
+
+/* See lineedit_ptr_hack.c */
+extern struct lineedit_statics *const lineedit_ptr_to_statics;
+
+#define S (*lineedit_ptr_to_statics)
+#define state (S.state )
+#define cmdedit_termw (S.cmdedit_termw )
+#define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler)
+#define cmdedit_x (S.cmdedit_x )
+#define cmdedit_y (S.cmdedit_y )
+#define cmdedit_prmt_len (S.cmdedit_prmt_len)
+#define cursor (S.cursor )
+#define command_len (S.command_len )
+#define command_ps (S.command_ps )
+#define cmdedit_prompt (S.cmdedit_prompt )
+#define num_ok_lines (S.num_ok_lines )
+#define user_buf (S.user_buf )
+#define home_pwd_buf (S.home_pwd_buf )
+#define matches (S.matches )
+#define num_matches (S.num_matches )
+#define delptr (S.delptr )
+#define newdelflag (S.newdelflag )
+#define delbuf (S.delbuf )
+
+#define INIT_S() do { \
+ (*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \
+ barrier(); \
+ cmdedit_termw = 80; \
+ USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
+ USE_FEATURE_GETUSERNAME_AND_HOMEDIR(home_pwd_buf = (char*)null_str;) \
+} while (0)
+static void deinit_S(void)
+{
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ /* This one is allocated only if FANCY_PROMPT is on
+ * (otherwise it points to verbatim prompt (NOT malloced) */
+ free((char*)cmdedit_prompt);
+#endif
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ free(user_buf);
+ if (home_pwd_buf != null_str)
+ free(home_pwd_buf);
+#endif
+ free(lineedit_ptr_to_statics);
+}
+#define DEINIT_S() deinit_S()
+
+
+/* Put 'command_ps[cursor]', cursor++.
+ * Advance cursor on screen. If we reached right margin, scroll text up
+ * and remove terminal margin effect by printing 'next_char' */
+#define HACK_FOR_WRONG_WIDTH 1
+#if HACK_FOR_WRONG_WIDTH
+static void cmdedit_set_out_char(void)
+#define cmdedit_set_out_char(next_char) cmdedit_set_out_char()
+#else
+static void cmdedit_set_out_char(int next_char)
+#endif
+{
+ int c = (unsigned char)command_ps[cursor];
+
+ if (c == '\0') {
+ /* erase character after end of input string */
+ c = ' ';
+ }
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
+ /* Display non-printable characters in reverse */
+ if (!Isprint(c)) {
+ if (c >= 128)
+ c -= 128;
+ if (c < ' ')
+ c += '@';
+ if (c == 127)
+ c = '?';
+ printf("\033[7m%c\033[0m", c);
+ } else
+#endif
+ {
+ bb_putchar(c);
+ }
+ if (++cmdedit_x >= cmdedit_termw) {
+ /* terminal is scrolled down */
+ cmdedit_y++;
+ cmdedit_x = 0;
+#if HACK_FOR_WRONG_WIDTH
+ /* This works better if our idea of term width is wrong
+ * and it is actually wider (often happens on serial lines).
+ * Printing CR,LF *forces* cursor to next line.
+ * OTOH if terminal width is correct AND terminal does NOT
+ * have automargin (IOW: it is moving cursor to next line
+ * by itself (which is wrong for VT-10x terminals)),
+ * this will break things: there will be one extra empty line */
+ puts("\r"); /* + implicit '\n' */
+#else
+ /* Works ok only if cmdedit_termw is correct */
+ /* destroy "(auto)margin" */
+ bb_putchar(next_char);
+ bb_putchar('\b');
+#endif
+ }
+// Huh? What if command_ps[cursor] == '\0' (we are at the end already?)
+ cursor++;
+}
+
+/* Move to end of line (by printing all chars till the end) */
+static void input_end(void)
+{
+ while (cursor < command_len)
+ cmdedit_set_out_char(' ');
+}
+
+/* Go to the next line */
+static void goto_new_line(void)
+{
+ input_end();
+ if (cmdedit_x)
+ bb_putchar('\n');
+}
+
+
+static void out1str(const char *s)
+{
+ if (s)
+ fputs(s, stdout);
+}
+
+static void beep(void)
+{
+ bb_putchar('\007');
+}
+
+/* Move back one character */
+/* (optimized for slow terminals) */
+static void input_backward(unsigned num)
+{
+ int count_y;
+
+ if (num > cursor)
+ num = cursor;
+ if (!num)
+ return;
+ cursor -= num;
+
+ if (cmdedit_x >= num) {
+ cmdedit_x -= num;
+ if (num <= 4) {
+ /* This is longer by 5 bytes on x86.
+ * Also gets miscompiled for ARM users
+ * (busybox.net/bugs/view.php?id=2274).
+ * printf(("\b\b\b\b" + 4) - num);
+ * return;
+ */
+ do {
+ bb_putchar('\b');
+ } while (--num);
+ return;
+ }
+ printf("\033[%uD", num);
+ return;
+ }
+
+ /* Need to go one or more lines up */
+ num -= cmdedit_x;
+ {
+ unsigned w = cmdedit_termw; /* volatile var */
+ count_y = 1 + (num / w);
+ cmdedit_y -= count_y;
+ cmdedit_x = w * count_y - num;
+ }
+ /* go to 1st column; go up; go to correct column */
+ printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x);
+}
+
+static void put_prompt(void)
+{
+ out1str(cmdedit_prompt);
+ cursor = 0;
+ {
+ unsigned w = cmdedit_termw; /* volatile var */
+ cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
+ cmdedit_x = cmdedit_prmt_len % w;
+ }
+}
+
+/* draw prompt, editor line, and clear tail */
+static void redraw(int y, int back_cursor)
+{
+ if (y > 0) /* up to start y */
+ printf("\033[%dA", y);
+ bb_putchar('\r');
+ put_prompt();
+ input_end(); /* rewrite */
+ printf("\033[J"); /* erase after cursor */
+ input_backward(back_cursor);
+}
+
+/* Delete the char in front of the cursor, optionally saving it
+ * for later putback */
+#if !ENABLE_FEATURE_EDITING_VI
+static void input_delete(void)
+#define input_delete(save) input_delete()
+#else
+static void input_delete(int save)
+#endif
+{
+ int j = cursor;
+
+ if (j == (int)command_len)
+ return;
+
+#if ENABLE_FEATURE_EDITING_VI
+ if (save) {
+ if (newdelflag) {
+ delptr = delbuf;
+ newdelflag = 0;
+ }
+ if ((delptr - delbuf) < DELBUFSIZ)
+ *delptr++ = command_ps[j];
+ }
+#endif
+
+ overlapping_strcpy(command_ps + j, command_ps + j + 1);
+ command_len--;
+ input_end(); /* rewrite new line */
+ cmdedit_set_out_char(' '); /* erase char */
+ input_backward(cursor - j); /* back to old pos cursor */
+}
+
+#if ENABLE_FEATURE_EDITING_VI
+static void put(void)
+{
+ int ocursor;
+ int j = delptr - delbuf;
+
+ if (j == 0)
+ return;
+ ocursor = cursor;
+ /* open hole and then fill it */
+ memmove(command_ps + cursor + j, command_ps + cursor, command_len - cursor + 1);
+ strncpy(command_ps + cursor, delbuf, j);
+ command_len += j;
+ input_end(); /* rewrite new line */
+ input_backward(cursor - ocursor - j + 1); /* at end of new text */
+}
+#endif
+
+/* Delete the char in back of the cursor */
+static void input_backspace(void)
+{
+ if (cursor > 0) {
+ input_backward(1);
+ input_delete(0);
+ }
+}
+
+/* Move forward one character */
+static void input_forward(void)
+{
+ if (cursor < command_len)
+ cmdedit_set_out_char(command_ps[cursor + 1]);
+}
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+
+static void free_tab_completion_data(void)
+{
+ if (matches) {
+ while (num_matches)
+ free(matches[--num_matches]);
+ free(matches);
+ matches = NULL;
+ }
+}
+
+static void add_match(char *matched)
+{
+ matches = xrealloc_vector(matches, 4, num_matches);
+ matches[num_matches] = matched;
+ num_matches++;
+}
+
+#if ENABLE_FEATURE_USERNAME_COMPLETION
+static void username_tab_completion(char *ud, char *with_shash_flg)
+{
+ struct passwd *entry;
+ int userlen;
+
+ ud++; /* ~user/... to user/... */
+ userlen = strlen(ud);
+
+ if (with_shash_flg) { /* "~/..." or "~user/..." */
+ char *sav_ud = ud - 1;
+ char *home = NULL;
+
+ if (*ud == '/') { /* "~/..." */
+ home = home_pwd_buf;
+ } else {
+ /* "~user/..." */
+ char *temp;
+ temp = strchr(ud, '/');
+ *temp = '\0'; /* ~user\0 */
+ entry = getpwnam(ud);
+ *temp = '/'; /* restore ~user/... */
+ ud = temp;
+ if (entry)
+ home = entry->pw_dir;
+ }
+ if (home) {
+ if ((userlen + strlen(home) + 1) < MAX_LINELEN) {
+ /* /home/user/... */
+ sprintf(sav_ud, "%s%s", home, ud);
+ }
+ }
+ } else {
+ /* "~[^/]*" */
+ /* Using _r function to avoid pulling in static buffers */
+ char line_buff[256];
+ struct passwd pwd;
+ struct passwd *result;
+
+ setpwent();
+ while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {
+ /* Null usernames should result in all users as possible completions. */
+ if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) {
+ add_match(xasprintf("~%s/", pwd.pw_name));
+ }
+ }
+ endpwent();
+ }
+}
+#endif /* FEATURE_COMMAND_USERNAME_COMPLETION */
+
+enum {
+ FIND_EXE_ONLY = 0,
+ FIND_DIR_ONLY = 1,
+ FIND_FILE_ONLY = 2,
+};
+
+static int path_parse(char ***p, int flags)
+{
+ int npth;
+ const char *pth;
+ char *tmp;
+ char **res;
+
+ /* if not setenv PATH variable, to search cur dir "." */
+ if (flags != FIND_EXE_ONLY)
+ return 1;
+
+ if (state->flags & WITH_PATH_LOOKUP)
+ pth = state->path_lookup;
+ else
+ pth = getenv("PATH");
+ /* PATH=<empty> or PATH=:<empty> */
+ if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
+ return 1;
+
+ tmp = (char*)pth;
+ npth = 1; /* path component count */
+ while (1) {
+ tmp = strchr(tmp, ':');
+ if (!tmp)
+ break;
+ if (*++tmp == '\0')
+ break; /* :<empty> */
+ npth++;
+ }
+
+ res = xmalloc(npth * sizeof(char*));
+ res[0] = tmp = xstrdup(pth);
+ npth = 1;
+ while (1) {
+ tmp = strchr(tmp, ':');
+ if (!tmp)
+ break;
+ *tmp++ = '\0'; /* ':' -> '\0' */
+ if (*tmp == '\0')
+ break; /* :<empty> */
+ res[npth++] = tmp;
+ }
+ *p = res;
+ return npth;
+}
+
+static void exe_n_cwd_tab_completion(char *command, int type)
+{
+ DIR *dir;
+ struct dirent *next;
+ struct stat st;
+ char *path1[1];
+ char **paths = path1;
+ int npaths;
+ int i;
+ char *found;
+ char *pfind = strrchr(command, '/');
+/* char dirbuf[MAX_LINELEN]; */
+#define dirbuf (S.exe_n_cwd_tab_completion__dirbuf)
+
+ npaths = 1;
+ path1[0] = (char*)".";
+
+ if (pfind == NULL) {
+ /* no dir, if flags==EXE_ONLY - get paths, else "." */
+ npaths = path_parse(&paths, type);
+ pfind = command;
+ } else {
+ /* dirbuf = ".../.../.../" */
+ safe_strncpy(dirbuf, command, (pfind - command) + 2);
+#if ENABLE_FEATURE_USERNAME_COMPLETION
+ if (dirbuf[0] == '~') /* ~/... or ~user/... */
+ username_tab_completion(dirbuf, dirbuf);
+#endif
+ paths[0] = dirbuf;
+ /* point to 'l' in "..../last_component" */
+ pfind++;
+ }
+
+ for (i = 0; i < npaths; i++) {
+ dir = opendir(paths[i]);
+ if (!dir)
+ continue; /* don't print an error */
+
+ while ((next = readdir(dir)) != NULL) {
+ int len1;
+ const char *str_found = next->d_name;
+
+ /* matched? */
+ if (strncmp(str_found, pfind, strlen(pfind)))
+ continue;
+ /* not see .name without .match */
+ if (*str_found == '.' && *pfind == '\0') {
+ if (NOT_LONE_CHAR(paths[i], '/') || str_found[1])
+ continue;
+ str_found = ""; /* only "/" */
+ }
+ found = concat_path_file(paths[i], str_found);
+ /* hmm, remove in progress? */
+ /* NB: stat() first so that we see is it a directory;
+ * but if that fails, use lstat() so that
+ * we still match dangling links */
+ if (stat(found, &st) && lstat(found, &st))
+ goto cont;
+ /* find with dirs? */
+ if (paths[i] != dirbuf)
+ strcpy(found, next->d_name); /* only name */
+
+ len1 = strlen(found);
+ found = xrealloc(found, len1 + 2);
+ found[len1] = '\0';
+ found[len1+1] = '\0';
+
+ if (S_ISDIR(st.st_mode)) {
+ /* name is a directory */
+ if (found[len1-1] != '/') {
+ found[len1] = '/';
+ }
+ } else {
+ /* not put found file if search only dirs for cd */
+ if (type == FIND_DIR_ONLY)
+ goto cont;
+ }
+ /* Add it to the list */
+ add_match(found);
+ continue;
+ cont:
+ free(found);
+ }
+ closedir(dir);
+ }
+ if (paths != path1) {
+ free(paths[0]); /* allocated memory is only in first member */
+ free(paths);
+ }
+#undef dirbuf
+}
+
+#define QUOT (UCHAR_MAX+1)
+
+#define collapse_pos(is, in) do { \
+ memmove(int_buf+(is), int_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \
+ memmove(pos_buf+(is), pos_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \
+} while (0)
+
+static int find_match(char *matchBuf, int *len_with_quotes)
+{
+ int i, j;
+ int command_mode;
+ int c, c2;
+/* int16_t int_buf[MAX_LINELEN + 1]; */
+/* int16_t pos_buf[MAX_LINELEN + 1]; */
+#define int_buf (S.find_match__int_buf)
+#define pos_buf (S.find_match__pos_buf)
+
+ /* set to integer dimension characters and own positions */
+ for (i = 0;; i++) {
+ int_buf[i] = (unsigned char)matchBuf[i];
+ if (int_buf[i] == 0) {
+ pos_buf[i] = -1; /* indicator end line */
+ break;
+ }
+ pos_buf[i] = i;
+ }
+
+ /* mask \+symbol and convert '\t' to ' ' */
+ for (i = j = 0; matchBuf[i]; i++, j++)
+ if (matchBuf[i] == '\\') {
+ collapse_pos(j, j + 1);
+ int_buf[j] |= QUOT;
+ i++;
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
+ if (matchBuf[i] == '\t') /* algorithm equivalent */
+ int_buf[j] = ' ' | QUOT;
+#endif
+ }
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
+ else if (matchBuf[i] == '\t')
+ int_buf[j] = ' ';
+#endif
+
+ /* mask "symbols" or 'symbols' */
+ c2 = 0;
+ for (i = 0; int_buf[i]; i++) {
+ c = int_buf[i];
+ if (c == '\'' || c == '"') {
+ if (c2 == 0)
+ c2 = c;
+ else {
+ if (c == c2)
+ c2 = 0;
+ else
+ int_buf[i] |= QUOT;
+ }
+ } else if (c2 != 0 && c != '$')
+ int_buf[i] |= QUOT;
+ }
+
+ /* skip commands with arguments if line has commands delimiters */
+ /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */
+ for (i = 0; int_buf[i]; i++) {
+ c = int_buf[i];
+ c2 = int_buf[i + 1];
+ j = i ? int_buf[i - 1] : -1;
+ command_mode = 0;
+ if (c == ';' || c == '&' || c == '|') {
+ command_mode = 1 + (c == c2);
+ if (c == '&') {
+ if (j == '>' || j == '<')
+ command_mode = 0;
+ } else if (c == '|' && j == '>')
+ command_mode = 0;
+ }
+ if (command_mode) {
+ collapse_pos(0, i + command_mode);
+ i = -1; /* hack incremet */
+ }
+ }
+ /* collapse `command...` */
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] == '`') {
+ for (j = i + 1; int_buf[j]; j++)
+ if (int_buf[j] == '`') {
+ collapse_pos(i, j + 1);
+ j = 0;
+ break;
+ }
+ if (j) {
+ /* not found close ` - command mode, collapse all previous */
+ collapse_pos(0, i + 1);
+ break;
+ } else
+ i--; /* hack incremet */
+ }
+
+ /* collapse (command...(command...)...) or {command...{command...}...} */
+ c = 0; /* "recursive" level */
+ c2 = 0;
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] == '(' || int_buf[i] == '{') {
+ if (int_buf[i] == '(')
+ c++;
+ else
+ c2++;
+ collapse_pos(0, i + 1);
+ i = -1; /* hack incremet */
+ }
+ for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++)
+ if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
+ if (int_buf[i] == ')')
+ c--;
+ else
+ c2--;
+ collapse_pos(0, i + 1);
+ i = -1; /* hack incremet */
+ }
+
+ /* skip first not quote space */
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] != ' ')
+ break;
+ if (i)
+ collapse_pos(0, i);
+
+ /* set find mode for completion */
+ command_mode = FIND_EXE_ONLY;
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
+ if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY
+ && matchBuf[pos_buf[0]] == 'c'
+ && matchBuf[pos_buf[1]] == 'd'
+ ) {
+ command_mode = FIND_DIR_ONLY;
+ } else {
+ command_mode = FIND_FILE_ONLY;
+ break;
+ }
+ }
+ for (i = 0; int_buf[i]; i++)
+ /* "strlen" */;
+ /* find last word */
+ for (--i; i >= 0; i--) {
+ c = int_buf[i];
+ if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
+ collapse_pos(0, i + 1);
+ break;
+ }
+ }
+ /* skip first not quoted '\'' or '"' */
+ for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
+ /*skip*/;
+ /* collapse quote or unquote // or /~ */
+ while ((int_buf[i] & ~QUOT) == '/'
+ && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~')
+ ) {
+ i++;
+ }
+
+ /* set only match and destroy quotes */
+ j = 0;
+ for (c = 0; pos_buf[i] >= 0; i++) {
+ matchBuf[c++] = matchBuf[pos_buf[i]];
+ j = pos_buf[i] + 1;
+ }
+ matchBuf[c] = '\0';
+ /* old length matchBuf with quotes symbols */
+ *len_with_quotes = j ? j - pos_buf[0] : 0;
+
+ return command_mode;
+#undef int_buf
+#undef pos_buf
+}
+
+/*
+ * display by column (original idea from ls applet,
+ * very optimized by me :)
+ */
+static void showfiles(void)
+{
+ int ncols, row;
+ int column_width = 0;
+ int nfiles = num_matches;
+ int nrows = nfiles;
+ int l;
+
+ /* find the longest file name- use that as the column width */
+ for (row = 0; row < nrows; row++) {
+ l = strlen(matches[row]);
+ if (column_width < l)
+ column_width = l;
+ }
+ column_width += 2; /* min space for columns */
+ ncols = cmdedit_termw / column_width;
+
+ if (ncols > 1) {
+ nrows /= ncols;
+ if (nfiles % ncols)
+ nrows++; /* round up fractionals */
+ } else {
+ ncols = 1;
+ }
+ for (row = 0; row < nrows; row++) {
+ int n = row;
+ int nc;
+
+ for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) {
+ printf("%s%-*s", matches[n],
+ (int)(column_width - strlen(matches[n])), "");
+ }
+ puts(matches[n]);
+ }
+}
+
+static char *add_quote_for_spec_chars(char *found)
+{
+ int l = 0;
+ char *s = xmalloc((strlen(found) + 1) * 2);
+
+ while (*found) {
+ if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
+ s[l++] = '\\';
+ s[l++] = *found++;
+ }
+ s[l] = 0;
+ return s;
+}
+
+/* Do TAB completion */
+static void input_tab(smallint *lastWasTab)
+{
+ if (!(state->flags & TAB_COMPLETION))
+ return;
+
+ if (!*lastWasTab) {
+ char *tmp, *tmp1;
+ size_t len_found;
+/* char matchBuf[MAX_LINELEN]; */
+#define matchBuf (S.input_tab__matchBuf)
+ int find_type;
+ int recalc_pos;
+
+ *lastWasTab = TRUE; /* flop trigger */
+
+ /* Make a local copy of the string -- up
+ * to the position of the cursor */
+ tmp = strncpy(matchBuf, command_ps, cursor);
+ tmp[cursor] = '\0';
+
+ find_type = find_match(matchBuf, &recalc_pos);
+
+ /* Free up any memory already allocated */
+ free_tab_completion_data();
+
+#if ENABLE_FEATURE_USERNAME_COMPLETION
+ /* If the word starts with `~' and there is no slash in the word,
+ * then try completing this word as a username. */
+ if (state->flags & USERNAME_COMPLETION)
+ if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
+ username_tab_completion(matchBuf, NULL);
+#endif
+ /* Try to match any executable in our path and everything
+ * in the current working directory */
+ if (!matches)
+ exe_n_cwd_tab_completion(matchBuf, find_type);
+ /* Sort, then remove any duplicates found */
+ if (matches) {
+ unsigned i;
+ int n = 0;
+ qsort_string_vector(matches, num_matches);
+ for (i = 0; i < num_matches - 1; ++i) {
+ if (matches[i] && matches[i+1]) { /* paranoia */
+ if (strcmp(matches[i], matches[i+1]) == 0) {
+ free(matches[i]);
+ matches[i] = NULL; /* paranoia */
+ } else {
+ matches[n++] = matches[i];
+ }
+ }
+ }
+ matches[n] = matches[i];
+ num_matches = n + 1;
+ }
+ /* Did we find exactly one match? */
+ if (!matches || num_matches > 1) {
+ beep();
+ if (!matches)
+ return; /* not found */
+ /* find minimal match */
+ tmp1 = xstrdup(matches[0]);
+ for (tmp = tmp1; *tmp; tmp++)
+ for (len_found = 1; len_found < num_matches; len_found++)
+ if (matches[len_found][(tmp - tmp1)] != *tmp) {
+ *tmp = '\0';
+ break;
+ }
+ if (*tmp1 == '\0') { /* have unique */
+ free(tmp1);
+ return;
+ }
+ tmp = add_quote_for_spec_chars(tmp1);
+ free(tmp1);
+ } else { /* one match */
+ tmp = add_quote_for_spec_chars(matches[0]);
+ /* for next completion current found */
+ *lastWasTab = FALSE;
+
+ len_found = strlen(tmp);
+ if (tmp[len_found-1] != '/') {
+ tmp[len_found] = ' ';
+ tmp[len_found+1] = '\0';
+ }
+ }
+ len_found = strlen(tmp);
+ /* have space to placed match? */
+ if ((len_found - strlen(matchBuf) + command_len) < MAX_LINELEN) {
+ /* before word for match */
+ command_ps[cursor - recalc_pos] = '\0';
+ /* save tail line */
+ strcpy(matchBuf, command_ps + cursor);
+ /* add match */
+ strcat(command_ps, tmp);
+ /* add tail */
+ strcat(command_ps, matchBuf);
+ /* back to begin word for match */
+ input_backward(recalc_pos);
+ /* new pos */
+ recalc_pos = cursor + len_found;
+ /* new len */
+ command_len = strlen(command_ps);
+ /* write out the matched command */
+ redraw(cmdedit_y, command_len - recalc_pos);
+ }
+ free(tmp);
+#undef matchBuf
+ } else {
+ /* Ok -- the last char was a TAB. Since they
+ * just hit TAB again, print a list of all the
+ * available choices... */
+ if (matches && num_matches > 0) {
+ int sav_cursor = cursor; /* change goto_new_line() */
+
+ /* Go to the next line */
+ goto_new_line();
+ showfiles();
+ redraw(0, command_len - sav_cursor);
+ }
+ }
+}
+
+#endif /* FEATURE_COMMAND_TAB_COMPLETION */
+
+
+line_input_t* FAST_FUNC new_line_input_t(int flags)
+{
+ line_input_t *n = xzalloc(sizeof(*n));
+ n->flags = flags;
+ return n;
+}
+
+
+#if MAX_HISTORY > 0
+
+static void save_command_ps_at_cur_history(void)
+{
+ if (command_ps[0] != '\0') {
+ int cur = state->cur_history;
+ free(state->history[cur]);
+ state->history[cur] = xstrdup(command_ps);
+ }
+}
+
+/* state->flags is already checked to be nonzero */
+static int get_previous_history(void)
+{
+ if ((state->flags & DO_HISTORY) && state->cur_history) {
+ save_command_ps_at_cur_history();
+ state->cur_history--;
+ return 1;
+ }
+ beep();
+ return 0;
+}
+
+static int get_next_history(void)
+{
+ if (state->flags & DO_HISTORY) {
+ if (state->cur_history < state->cnt_history) {
+ save_command_ps_at_cur_history(); /* save the current history line */
+ return ++state->cur_history;
+ }
+ }
+ beep();
+ return 0;
+}
+
+#if ENABLE_FEATURE_EDITING_SAVEHISTORY
+/* We try to ensure that concurrent additions to the history
+ * do not overwrite each other.
+ * Otherwise shell users get unhappy.
+ *
+ * History file is trimmed lazily, when it grows several times longer
+ * than configured MAX_HISTORY lines.
+ */
+
+static void free_line_input_t(line_input_t *n)
+{
+ int i = n->cnt_history;
+ while (i > 0)
+ free(n->history[--i]);
+ free(n);
+}
+
+/* state->flags is already checked to be nonzero */
+static void load_history(line_input_t *st_parm)
+{
+ char *temp_h[MAX_HISTORY];
+ char *line;
+ FILE *fp;
+ unsigned idx, i, line_len;
+
+ /* NB: do not trash old history if file can't be opened */
+
+ fp = fopen_for_read(st_parm->hist_file);
+ if (fp) {
+ /* clean up old history */
+ for (idx = st_parm->cnt_history; idx > 0;) {
+ idx--;
+ free(st_parm->history[idx]);
+ st_parm->history[idx] = NULL;
+ }
+
+ /* fill temp_h[], retaining only last MAX_HISTORY lines */
+ memset(temp_h, 0, sizeof(temp_h));
+ st_parm->cnt_history_in_file = idx = 0;
+ while ((line = xmalloc_fgetline(fp)) != NULL) {
+ if (line[0] == '\0') {
+ free(line);
+ continue;
+ }
+ free(temp_h[idx]);
+ temp_h[idx] = line;
+ st_parm->cnt_history_in_file++;
+ idx++;
+ if (idx == MAX_HISTORY)
+ idx = 0;
+ }
+ fclose(fp);
+
+ /* find first non-NULL temp_h[], if any */
+ if (st_parm->cnt_history_in_file) {
+ while (temp_h[idx] == NULL) {
+ idx++;
+ if (idx == MAX_HISTORY)
+ idx = 0;
+ }
+ }
+
+ /* copy temp_h[] to st_parm->history[] */
+ for (i = 0; i < MAX_HISTORY;) {
+ line = temp_h[idx];
+ if (!line)
+ break;
+ idx++;
+ if (idx == MAX_HISTORY)
+ idx = 0;
+ line_len = strlen(line);
+ if (line_len >= MAX_LINELEN)
+ line[MAX_LINELEN-1] = '\0';
+ st_parm->history[i++] = line;
+ }
+ st_parm->cnt_history = i;
+ }
+}
+
+/* state->flags is already checked to be nonzero */
+static void save_history(char *str)
+{
+ int fd;
+ int len, len2;
+
+ fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0666);
+ if (fd < 0)
+ return;
+ xlseek(fd, 0, SEEK_END); /* paranoia */
+ len = strlen(str);
+ str[len] = '\n'; /* we (try to) do atomic write */
+ len2 = full_write(fd, str, len + 1);
+ str[len] = '\0';
+ close(fd);
+ if (len2 != len + 1)
+ return; /* "wtf?" */
+
+ /* did we write so much that history file needs trimming? */
+ state->cnt_history_in_file++;
+ if (state->cnt_history_in_file > MAX_HISTORY * 4) {
+ FILE *fp;
+ char *new_name;
+ line_input_t *st_temp;
+ int i;
+
+ /* we may have concurrently written entries from others.
+ * load them */
+ st_temp = new_line_input_t(state->flags);
+ st_temp->hist_file = state->hist_file;
+ load_history(st_temp);
+
+ /* write out temp file and replace hist_file atomically */
+ new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid());
+ fp = fopen_for_write(new_name);
+ if (fp) {
+ for (i = 0; i < st_temp->cnt_history; i++)
+ fprintf(fp, "%s\n", st_temp->history[i]);
+ fclose(fp);
+ if (rename(new_name, state->hist_file) == 0)
+ state->cnt_history_in_file = st_temp->cnt_history;
+ }
+ free(new_name);
+ free_line_input_t(st_temp);
+ }
+}
+#else
+#define load_history(a) ((void)0)
+#define save_history(a) ((void)0)
+#endif /* FEATURE_COMMAND_SAVEHISTORY */
+
+static void remember_in_history(char *str)
+{
+ int i;
+
+ if (!(state->flags & DO_HISTORY))
+ return;
+ if (str[0] == '\0')
+ return;
+ i = state->cnt_history;
+ /* Don't save dupes */
+ if (i && strcmp(state->history[i-1], str) == 0)
+ return;
+
+ free(state->history[MAX_HISTORY]); /* redundant, paranoia */
+ state->history[MAX_HISTORY] = NULL; /* redundant, paranoia */
+
+ /* If history[] is full, remove the oldest command */
+ /* we need to keep history[MAX_HISTORY] empty, hence >=, not > */
+ if (i >= MAX_HISTORY) {
+ free(state->history[0]);
+ for (i = 0; i < MAX_HISTORY-1; i++)
+ state->history[i] = state->history[i+1];
+ /* i == MAX_HISTORY-1 */
+ }
+ /* i <= MAX_HISTORY-1 */
+ state->history[i++] = xstrdup(str);
+ /* i <= MAX_HISTORY */
+ state->cur_history = i;
+ state->cnt_history = i;
+#if ENABLE_FEATURE_EDITING_SAVEHISTORY
+ if ((state->flags & SAVE_HISTORY) && state->hist_file)
+ save_history(str);
+#endif
+ USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
+}
+
+#else /* MAX_HISTORY == 0 */
+#define remember_in_history(a) ((void)0)
+#endif /* MAX_HISTORY */
+
+
+/*
+ * This function is used to grab a character buffer
+ * from the input file descriptor and allows you to
+ * a string with full command editing (sort of like
+ * a mini readline).
+ *
+ * The following standard commands are not implemented:
+ * ESC-b -- Move back one word
+ * ESC-f -- Move forward one word
+ * ESC-d -- Delete back one word
+ * ESC-h -- Delete forward one word
+ * CTL-t -- Transpose two characters
+ *
+ * Minimalist vi-style command line editing available if configured.
+ * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
+ */
+
+#if ENABLE_FEATURE_EDITING_VI
+static void
+vi_Word_motion(char *command, int eat)
+{
+ while (cursor < command_len && !isspace(command[cursor]))
+ input_forward();
+ if (eat) while (cursor < command_len && isspace(command[cursor]))
+ input_forward();
+}
+
+static void
+vi_word_motion(char *command, int eat)
+{
+ if (isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor < command_len
+ && (isalnum(command[cursor+1]) || command[cursor+1] == '_'))
+ input_forward();
+ } else if (ispunct(command[cursor])) {
+ while (cursor < command_len && ispunct(command[cursor+1]))
+ input_forward();
+ }
+
+ if (cursor < command_len)
+ input_forward();
+
+ if (eat && cursor < command_len && isspace(command[cursor]))
+ while (cursor < command_len && isspace(command[cursor]))
+ input_forward();
+}
+
+static void
+vi_End_motion(char *command)
+{
+ input_forward();
+ while (cursor < command_len && isspace(command[cursor]))
+ input_forward();
+ while (cursor < command_len-1 && !isspace(command[cursor+1]))
+ input_forward();
+}
+
+static void
+vi_end_motion(char *command)
+{
+ if (cursor >= command_len-1)
+ return;
+ input_forward();
+ while (cursor < command_len-1 && isspace(command[cursor]))
+ input_forward();
+ if (cursor >= command_len-1)
+ return;
+ if (isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor < command_len-1
+ && (isalnum(command[cursor+1]) || command[cursor+1] == '_')
+ ) {
+ input_forward();
+ }
+ } else if (ispunct(command[cursor])) {
+ while (cursor < command_len-1 && ispunct(command[cursor+1]))
+ input_forward();
+ }
+}
+
+static void
+vi_Back_motion(char *command)
+{
+ while (cursor > 0 && isspace(command[cursor-1]))
+ input_backward(1);
+ while (cursor > 0 && !isspace(command[cursor-1]))
+ input_backward(1);
+}
+
+static void
+vi_back_motion(char *command)
+{
+ if (cursor <= 0)
+ return;
+ input_backward(1);
+ while (cursor > 0 && isspace(command[cursor]))
+ input_backward(1);
+ if (cursor <= 0)
+ return;
+ if (isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor > 0
+ && (isalnum(command[cursor-1]) || command[cursor-1] == '_')
+ ) {
+ input_backward(1);
+ }
+ } else if (ispunct(command[cursor])) {
+ while (cursor > 0 && ispunct(command[cursor-1]))
+ input_backward(1);
+ }
+}
+#endif
+
+
+/*
+ * read_line_input and its helpers
+ */
+
+#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
+static void parse_and_put_prompt(const char *prmt_ptr)
+{
+ cmdedit_prompt = prmt_ptr;
+ cmdedit_prmt_len = strlen(prmt_ptr);
+ put_prompt();
+}
+#else
+static void parse_and_put_prompt(const char *prmt_ptr)
+{
+ int prmt_len = 0;
+ size_t cur_prmt_len = 0;
+ char flg_not_length = '[';
+ char *prmt_mem_ptr = xzalloc(1);
+ char *cwd_buf = xrealloc_getcwd_or_warn(NULL);
+ char cbuf[2];
+ char c;
+ char *pbuf;
+
+ cmdedit_prmt_len = 0;
+
+ if (!cwd_buf) {
+ cwd_buf = (char *)bb_msg_unknown;
+ }
+
+ cbuf[1] = '\0'; /* never changes */
+
+ while (*prmt_ptr) {
+ char *free_me = NULL;
+
+ pbuf = cbuf;
+ c = *prmt_ptr++;
+ if (c == '\\') {
+ const char *cp = prmt_ptr;
+ int l;
+
+ c = bb_process_escape_sequence(&prmt_ptr);
+ if (prmt_ptr == cp) {
+ if (*cp == '\0')
+ break;
+ c = *prmt_ptr++;
+
+ switch (c) {
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ case 'u':
+ pbuf = user_buf ? user_buf : (char*)"";
+ break;
+#endif
+ case 'h':
+ pbuf = free_me = safe_gethostname();
+ *strchrnul(pbuf, '.') = '\0';
+ break;
+ case '$':
+ c = (geteuid() == 0 ? '#' : '$');
+ break;
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ case 'w':
+ /* /home/user[/something] -> ~[/something] */
+ pbuf = cwd_buf;
+ l = strlen(home_pwd_buf);
+ if (l != 0
+ && strncmp(home_pwd_buf, cwd_buf, l) == 0
+ && (cwd_buf[l]=='/' || cwd_buf[l]=='\0')
+ && strlen(cwd_buf + l) < PATH_MAX
+ ) {
+ pbuf = free_me = xasprintf("~%s", cwd_buf + l);
+ }
+ break;
+#endif
+ case 'W':
+ pbuf = cwd_buf;
+ cp = strrchr(pbuf, '/');
+ if (cp != NULL && cp != pbuf)
+ pbuf += (cp-pbuf) + 1;
+ break;
+ case '!':
+ pbuf = free_me = xasprintf("%d", num_ok_lines);
+ break;
+ case 'e': case 'E': /* \e \E = \033 */
+ c = '\033';
+ break;
+ case 'x': case 'X': {
+ char buf2[4];
+ for (l = 0; l < 3;) {
+ unsigned h;
+ buf2[l++] = *prmt_ptr;
+ buf2[l] = '\0';
+ h = strtoul(buf2, &pbuf, 16);
+ if (h > UCHAR_MAX || (pbuf - buf2) < l) {
+ buf2[--l] = '\0';
+ break;
+ }
+ prmt_ptr++;
+ }
+ c = (char)strtoul(buf2, NULL, 16);
+ if (c == 0)
+ c = '?';
+ pbuf = cbuf;
+ break;
+ }
+ case '[': case ']':
+ if (c == flg_not_length) {
+ flg_not_length = (flg_not_length == '[' ? ']' : '[');
+ continue;
+ }
+ break;
+ } /* switch */
+ } /* if */
+ } /* if */
+ cbuf[0] = c;
+ cur_prmt_len = strlen(pbuf);
+ prmt_len += cur_prmt_len;
+ if (flg_not_length != ']')
+ cmdedit_prmt_len += cur_prmt_len;
+ prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
+ free(free_me);
+ } /* while */
+
+ if (cwd_buf != (char *)bb_msg_unknown)
+ free(cwd_buf);
+ cmdedit_prompt = prmt_mem_ptr;
+ put_prompt();
+}
+#endif
+
+static void cmdedit_setwidth(unsigned w, int redraw_flg)
+{
+ cmdedit_termw = w;
+ if (redraw_flg) {
+ /* new y for current cursor */
+ int new_y = (cursor + cmdedit_prmt_len) / w;
+ /* redraw */
+ redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
+ fflush(stdout);
+ }
+}
+
+static void win_changed(int nsig)
+{
+ unsigned width;
+ get_terminal_width_height(0, &width, NULL);
+ cmdedit_setwidth(width, nsig /* - just a yes/no flag */);
+ if (nsig == SIGWINCH)
+ signal(SIGWINCH, win_changed); /* rearm ourself */
+}
+
+/*
+ * The emacs and vi modes share much of the code in the big
+ * command loop. Commands entered when in vi's command mode (aka
+ * "escape mode") get an extra bit added to distinguish them --
+ * this keeps them from being self-inserted. This clutters the
+ * big switch a bit, but keeps all the code in one place.
+ */
+
+#define vbit 0x100
+
+/* leave out the "vi-mode"-only case labels if vi editing isn't
+ * configured. */
+#define vi_case(caselabel) USE_FEATURE_EDITING(case caselabel)
+
+/* convert uppercase ascii to equivalent control char, for readability */
+#undef CTRL
+#define CTRL(a) ((a) & ~0x40)
+
+/* Returns:
+ * -1 on read errors or EOF, or on bare Ctrl-D,
+ * 0 on ctrl-C (the line entered is still returned in 'command'),
+ * >0 length of input string, including terminating '\n'
+ */
+int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st)
+{
+ int len;
+#if ENABLE_FEATURE_TAB_COMPLETION
+ smallint lastWasTab = FALSE;
+#endif
+ unsigned ic;
+ unsigned char c;
+ smallint break_out = 0;
+#if ENABLE_FEATURE_EDITING_VI
+ smallint vi_cmdmode = 0;
+ smalluint prevc;
+#endif
+ struct termios initial_settings;
+ struct termios new_settings;
+
+ INIT_S();
+
+ if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
+ || !(initial_settings.c_lflag & ECHO)
+ ) {
+ /* Happens when e.g. stty -echo was run before */
+ parse_and_put_prompt(prompt);
+ fflush(stdout);
+ if (fgets(command, maxsize, stdin) == NULL)
+ len = -1; /* EOF or error */
+ else
+ len = strlen(command);
+ DEINIT_S();
+ return len;
+ }
+
+// FIXME: audit & improve this
+ if (maxsize > MAX_LINELEN)
+ maxsize = MAX_LINELEN;
+
+ /* With null flags, no other fields are ever used */
+ state = st ? st : (line_input_t*) &const_int_0;
+#if ENABLE_FEATURE_EDITING_SAVEHISTORY
+ if ((state->flags & SAVE_HISTORY) && state->hist_file)
+ if (state->cnt_history == 0)
+ load_history(state);
+#endif
+ if (state->flags & DO_HISTORY)
+ state->cur_history = state->cnt_history;
+
+ /* prepare before init handlers */
+ cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
+ command_len = 0;
+ command_ps = command;
+ command[0] = '\0';
+
+ new_settings = initial_settings;
+ new_settings.c_lflag &= ~ICANON; /* unbuffered input */
+ /* Turn off echoing and CTRL-C, so we can trap it */
+ new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
+ /* Hmm, in linux c_cc[] is not parsed if ICANON is off */
+ new_settings.c_cc[VMIN] = 1;
+ new_settings.c_cc[VTIME] = 0;
+ /* Turn off CTRL-C, so we can trap it */
+#ifndef _POSIX_VDISABLE
+#define _POSIX_VDISABLE '\0'
+#endif
+ new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
+ tcsetattr_stdin_TCSANOW(&new_settings);
+
+ /* Now initialize things */
+ previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
+ win_changed(0); /* do initial resizing */
+#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
+ {
+ struct passwd *entry;
+
+ entry = getpwuid(geteuid());
+ if (entry) {
+ user_buf = xstrdup(entry->pw_name);
+ home_pwd_buf = xstrdup(entry->pw_dir);
+ }
+ }
+#endif
+
+#if 0
+ for (ic = 0; ic <= MAX_HISTORY; ic++)
+ bb_error_msg("history[%d]:'%s'", ic, state->history[ic]);
+ bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history);
+#endif
+
+ /* Print out the command prompt */
+ parse_and_put_prompt(prompt);
+
+ while (1) {
+ fflush(NULL);
+
+ if (nonblock_safe_read(STDIN_FILENO, &c, 1) < 1) {
+ /* if we can't read input then exit */
+ goto prepare_to_die;
+ }
+
+ ic = c;
+
+#if ENABLE_FEATURE_EDITING_VI
+ newdelflag = 1;
+ if (vi_cmdmode)
+ ic |= vbit;
+#endif
+ switch (ic) {
+ case '\n':
+ case '\r':
+ vi_case('\n'|vbit:)
+ vi_case('\r'|vbit:)
+ /* Enter */
+ goto_new_line();
+ break_out = 1;
+ break;
+ case CTRL('A'):
+ vi_case('0'|vbit:)
+ /* Control-a -- Beginning of line */
+ input_backward(cursor);
+ break;
+ case CTRL('B'):
+ vi_case('h'|vbit:)
+ vi_case('\b'|vbit:)
+ vi_case('\x7f'|vbit:) /* DEL */
+ /* Control-b -- Move back one character */
+ input_backward(1);
+ break;
+ case CTRL('C'):
+ vi_case(CTRL('C')|vbit:)
+ /* Control-c -- stop gathering input */
+ goto_new_line();
+ command_len = 0;
+ break_out = -1; /* "do not append '\n'" */
+ break;
+ case CTRL('D'):
+ /* Control-d -- Delete one character, or exit
+ * if the len=0 and no chars to delete */
+ if (command_len == 0) {
+ errno = 0;
+ prepare_to_die:
+ /* to control stopped jobs */
+ break_out = command_len = -1;
+ break;
+ }
+ input_delete(0);
+ break;
+
+ case CTRL('E'):
+ vi_case('$'|vbit:)
+ /* Control-e -- End of line */
+ input_end();
+ break;
+ case CTRL('F'):
+ vi_case('l'|vbit:)
+ vi_case(' '|vbit:)
+ /* Control-f -- Move forward one character */
+ input_forward();
+ break;
+
+ case '\b':
+ case '\x7f': /* DEL */
+ /* Control-h and DEL */
+ input_backspace();
+ break;
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ case '\t':
+ input_tab(&lastWasTab);
+ break;
+#endif
+
+ case CTRL('K'):
+ /* Control-k -- clear to end of line */
+ command[cursor] = 0;
+ command_len = cursor;
+ printf("\033[J");
+ break;
+ case CTRL('L'):
+ vi_case(CTRL('L')|vbit:)
+ /* Control-l -- clear screen */
+ printf("\033[H");
+ redraw(0, command_len - cursor);
+ break;
+
+#if MAX_HISTORY > 0
+ case CTRL('N'):
+ vi_case(CTRL('N')|vbit:)
+ vi_case('j'|vbit:)
+ /* Control-n -- Get next command in history */
+ if (get_next_history())
+ goto rewrite_line;
+ break;
+ case CTRL('P'):
+ vi_case(CTRL('P')|vbit:)
+ vi_case('k'|vbit:)
+ /* Control-p -- Get previous command from history */
+ if (get_previous_history())
+ goto rewrite_line;
+ break;
+#endif
+
+ case CTRL('U'):
+ vi_case(CTRL('U')|vbit:)
+ /* Control-U -- Clear line before cursor */
+ if (cursor) {
+ overlapping_strcpy(command, command + cursor);
+ command_len -= cursor;
+ redraw(cmdedit_y, command_len);
+ }
+ break;
+ case CTRL('W'):
+ vi_case(CTRL('W')|vbit:)
+ /* Control-W -- Remove the last word */
+ while (cursor > 0 && isspace(command[cursor-1]))
+ input_backspace();
+ while (cursor > 0 && !isspace(command[cursor-1]))
+ input_backspace();
+ break;
+
+#if ENABLE_FEATURE_EDITING_VI
+ case 'i'|vbit:
+ vi_cmdmode = 0;
+ break;
+ case 'I'|vbit:
+ input_backward(cursor);
+ vi_cmdmode = 0;
+ break;
+ case 'a'|vbit:
+ input_forward();
+ vi_cmdmode = 0;
+ break;
+ case 'A'|vbit:
+ input_end();
+ vi_cmdmode = 0;
+ break;
+ case 'x'|vbit:
+ input_delete(1);
+ break;
+ case 'X'|vbit:
+ if (cursor > 0) {
+ input_backward(1);
+ input_delete(1);
+ }
+ break;
+ case 'W'|vbit:
+ vi_Word_motion(command, 1);
+ break;
+ case 'w'|vbit:
+ vi_word_motion(command, 1);
+ break;
+ case 'E'|vbit:
+ vi_End_motion(command);
+ break;
+ case 'e'|vbit:
+ vi_end_motion(command);
+ break;
+ case 'B'|vbit:
+ vi_Back_motion(command);
+ break;
+ case 'b'|vbit:
+ vi_back_motion(command);
+ break;
+ case 'C'|vbit:
+ vi_cmdmode = 0;
+ /* fall through */
+ case 'D'|vbit:
+ goto clear_to_eol;
+
+ case 'c'|vbit:
+ vi_cmdmode = 0;
+ /* fall through */
+ case 'd'|vbit: {
+ int nc, sc;
+ sc = cursor;
+ prevc = ic;
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ if (c == (prevc & 0xff)) {
+ /* "cc", "dd" */
+ input_backward(cursor);
+ goto clear_to_eol;
+ break;
+ }
+ switch (c) {
+ case 'w':
+ case 'W':
+ case 'e':
+ case 'E':
+ switch (c) {
+ case 'w': /* "dw", "cw" */
+ vi_word_motion(command, vi_cmdmode);
+ break;
+ case 'W': /* 'dW', 'cW' */
+ vi_Word_motion(command, vi_cmdmode);
+ break;
+ case 'e': /* 'de', 'ce' */
+ vi_end_motion(command);
+ input_forward();
+ break;
+ case 'E': /* 'dE', 'cE' */
+ vi_End_motion(command);
+ input_forward();
+ break;
+ }
+ nc = cursor;
+ input_backward(cursor - sc);
+ while (nc-- > cursor)
+ input_delete(1);
+ break;
+ case 'b': /* "db", "cb" */
+ case 'B': /* implemented as B */
+ if (c == 'b')
+ vi_back_motion(command);
+ else
+ vi_Back_motion(command);
+ while (sc-- > cursor)
+ input_delete(1);
+ break;
+ case ' ': /* "d ", "c " */
+ input_delete(1);
+ break;
+ case '$': /* "d$", "c$" */
+ clear_to_eol:
+ while (cursor < command_len)
+ input_delete(1);
+ break;
+ }
+ break;
+ }
+ case 'p'|vbit:
+ input_forward();
+ /* fallthrough */
+ case 'P'|vbit:
+ put();
+ break;
+ case 'r'|vbit:
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ if (c == 0)
+ beep();
+ else {
+ *(command + cursor) = c;
+ bb_putchar(c);
+ bb_putchar('\b');
+ }
+ break;
+#endif /* FEATURE_COMMAND_EDITING_VI */
+
+ case '\x1b': /* ESC */
+
+#if ENABLE_FEATURE_EDITING_VI
+ if (state->flags & VI_MODE) {
+ /* ESC: insert mode --> command mode */
+ vi_cmdmode = 1;
+ input_backward(1);
+ break;
+ }
+#endif
+ /* escape sequence follows */
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ /* different vt100 emulations */
+ if (c == '[' || c == 'O') {
+ vi_case('['|vbit:)
+ vi_case('O'|vbit:)
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ }
+ if (c >= '1' && c <= '9') {
+ unsigned char dummy;
+
+ if (safe_read(STDIN_FILENO, &dummy, 1) < 1)
+ goto prepare_to_die;
+ if (dummy != '~')
+ c = '\0';
+ }
+
+ switch (c) {
+#if ENABLE_FEATURE_TAB_COMPLETION
+ case '\t': /* Alt-Tab */
+ input_tab(&lastWasTab);
+ break;
+#endif
+#if MAX_HISTORY > 0
+ case 'A':
+ /* Up Arrow -- Get previous command from history */
+ if (get_previous_history())
+ goto rewrite_line;
+ beep();
+ break;
+ case 'B':
+ /* Down Arrow -- Get next command in history */
+ if (!get_next_history())
+ break;
+ rewrite_line:
+ /* Rewrite the line with the selected history item */
+ /* change command */
+ command_len = strlen(strcpy(command, state->history[state->cur_history] ? : ""));
+ /* redraw and go to eol (bol, in vi */
+ redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
+ break;
+#endif
+ case 'C':
+ /* Right Arrow -- Move forward one character */
+ input_forward();
+ break;
+ case 'D':
+ /* Left Arrow -- Move back one character */
+ input_backward(1);
+ break;
+ case '3':
+ /* Delete */
+ input_delete(0);
+ break;
+ case '1': // vt100? linux vt? or what?
+ case '7': // vt100? linux vt? or what?
+ case 'H': /* xterm's <Home> */
+ input_backward(cursor);
+ break;
+ case '4': // vt100? linux vt? or what?
+ case '8': // vt100? linux vt? or what?
+ case 'F': /* xterm's <End> */
+ input_end();
+ break;
+ default:
+ c = '\0';
+ beep();
+ }
+ break;
+
+ default: /* If it's regular input, do the normal thing */
+
+ /* Control-V -- force insert of next char */
+ if (c == CTRL('V')) {
+ if (safe_read(STDIN_FILENO, &c, 1) < 1)
+ goto prepare_to_die;
+ if (c == 0) {
+ beep();
+ break;
+ }
+ }
+
+#if ENABLE_FEATURE_EDITING_VI
+ if (vi_cmdmode) /* Don't self-insert */
+ break;
+#endif
+ if ((int)command_len >= (maxsize - 2)) /* Need to leave space for enter */
+ break;
+
+ command_len++;
+ if (cursor == (command_len - 1)) { /* Append if at the end of the line */
+ command[cursor] = c;
+ command[cursor+1] = '\0';
+ cmdedit_set_out_char(' ');
+ } else { /* Insert otherwise */
+ int sc = cursor;
+
+ memmove(command + sc + 1, command + sc, command_len - sc);
+ command[sc] = c;
+ sc++;
+ /* rewrite from cursor */
+ input_end();
+ /* to prev x pos + 1 */
+ input_backward(cursor - sc);
+ }
+ break;
+ }
+ if (break_out) /* Enter is the command terminator, no more input. */
+ break;
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ if (c != '\t')
+ lastWasTab = FALSE;
+#endif
+ }
+
+ if (command_len > 0)
+ remember_in_history(command);
+
+ if (break_out > 0) {
+ command[command_len++] = '\n';
+ command[command_len] = '\0';
+ }
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ free_tab_completion_data();
+#endif
+
+ /* restore initial_settings */
+ tcsetattr_stdin_TCSANOW(&initial_settings);
+ /* restore SIGWINCH handler */
+ signal(SIGWINCH, previous_SIGWINCH_handler);
+ fflush(stdout);
+
+ len = command_len;
+ DEINIT_S();
+
+ return len; /* can't return command_len, DEINIT_S() destroys it */
+}
+
+#else
+
+#undef read_line_input
+int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize)
+{
+ fputs(prompt, stdout);
+ fflush(stdout);
+ fgets(command, maxsize, stdin);
+ return strlen(command);
+}
+
+#endif /* FEATURE_COMMAND_EDITING */
+
+
+/*
+ * Testing
+ */
+
+#ifdef TEST
+
+#include <locale.h>
+
+const char *applet_name = "debug stuff usage";
+
+int main(int argc, char **argv)
+{
+ char buff[MAX_LINELEN];
+ char *prompt =
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:"
+ "\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] "
+ "\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
+#else
+ "% ";
+#endif
+
+#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
+ setlocale(LC_ALL, "");
+#endif
+ while (1) {
+ int l;
+ l = read_line_input(prompt, buff);
+ if (l <= 0 || buff[l-1] != '\n')
+ break;
+ buff[l-1] = 0;
+ printf("*** read_line_input() returned line =%s=\n", buff);
+ }
+ printf("*** read_line_input() detect ^D\n");
+ return 0;
+}
+
+#endif /* TEST */
diff --git a/release/src/router/busybox/libbb/lineedit_ptr_hack.c b/release/src/router/busybox/libbb/lineedit_ptr_hack.c
new file mode 100644
index 00000000..53716a23
--- /dev/null
+++ b/release/src/router/busybox/libbb/lineedit_ptr_hack.c
@@ -0,0 +1,23 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+struct lineedit_statics;
+
+#ifndef GCC_COMBINE
+
+/* We cheat here. It is declared as const ptr in libbb.h,
+ * but here we make it live in R/W memory */
+struct lineedit_statics *lineedit_ptr_to_statics;
+
+#else
+
+/* gcc -combine will see through and complain */
+/* Using alternative method which is more likely to break
+ * on weird architectures, compilers, linkers and so on */
+struct lineedit_statics *const lineedit_ptr_to_statics __attribute__ ((section (".data")));
+
+#endif
diff --git a/release/src/router/busybox/libbb/llist.c b/release/src/router/busybox/libbb/llist.c
new file mode 100644
index 00000000..51b1ce6c
--- /dev/null
+++ b/release/src/router/busybox/libbb/llist.c
@@ -0,0 +1,98 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * linked list helper functions.
+ *
+ * Copyright (C) 2003 Glenn McGrath
+ * Copyright (C) 2005 Vladimir Oleynik
+ * Copyright (C) 2005 Bernhard Reutner-Fischer
+ * Copyright (C) 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+/* Add data to the start of the linked list. */
+void FAST_FUNC llist_add_to(llist_t **old_head, void *data)
+{
+ llist_t *new_head = xmalloc(sizeof(llist_t));
+
+ new_head->data = data;
+ new_head->link = *old_head;
+ *old_head = new_head;
+}
+
+/* Add data to the end of the linked list. */
+void FAST_FUNC llist_add_to_end(llist_t **list_head, void *data)
+{
+ while (*list_head)
+ list_head = &(*list_head)->link;
+ *list_head = xzalloc(sizeof(llist_t));
+ (*list_head)->data = data;
+ /*(*list_head)->link = NULL;*/
+}
+
+/* Remove first element from the list and return it */
+void* FAST_FUNC llist_pop(llist_t **head)
+{
+ void *data = NULL;
+ llist_t *temp = *head;
+
+ if (temp) {
+ data = temp->data;
+ *head = temp->link;
+ free(temp);
+ }
+ return data;
+}
+
+/* Unlink arbitrary given element from the list */
+void FAST_FUNC llist_unlink(llist_t **head, llist_t *elm)
+{
+ if (!elm)
+ return;
+ while (*head) {
+ if (*head == elm) {
+ *head = (*head)->link;
+ break;
+ }
+ head = &(*head)->link;
+ }
+}
+
+/* Recursively free all elements in the linked list. If freeit != NULL
+ * call it on each datum in the list */
+void FAST_FUNC llist_free(llist_t *elm, void (*freeit) (void *data))
+{
+ while (elm) {
+ void *data = llist_pop(&elm);
+
+ if (freeit)
+ freeit(data);
+ }
+}
+
+/* Reverse list order. */
+llist_t* FAST_FUNC llist_rev(llist_t *list)
+{
+ llist_t *rev = NULL;
+
+ while (list) {
+ llist_t *next = list->link;
+
+ list->link = rev;
+ rev = list;
+ list = next;
+ }
+ return rev;
+}
+
+llist_t* FAST_FUNC llist_find_str(llist_t *list, const char *str)
+{
+ while (list) {
+ if (strcmp(list->data, str) == 0)
+ break;
+ list = list->link;
+ }
+ return list;
+}
diff --git a/release/src/router/busybox/libbb/llist_add_to.c b/release/src/router/busybox/libbb/llist_add_to.c
deleted file mode 100644
index 61e53f0c..00000000
--- a/release/src/router/busybox/libbb/llist_add_to.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#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/release/src/router/busybox/libbb/login.c b/release/src/router/busybox/libbb/login.c
index 3f67a819..b3e199ce 100644
--- a/release/src/router/busybox/libbb/login.c
+++ b/release/src/router/busybox/libbb/login.c
@@ -1,43 +1,28 @@
+/* vi: set sw=4 ts=4: */
/*
* 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>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include <sys/param.h> /* MAXHOSTNAMELEN */
-#include <stdio.h>
-#include <unistd.h>
-#include "libbb.h"
-
#include <sys/utsname.h>
-#include <time.h>
+#include "libbb.h"
#define LOGIN " login: "
-static const char fmtstr_d[] = "%A, %d %B %Y";
-static const char fmtstr_t[] = "%H:%M:%S";
+static const char fmtstr_d[] ALIGN1 = "%A, %d %B %Y";
+static const char fmtstr_t[] ALIGN1 = "%H:%M:%S";
-void print_login_issue(const char *issue_file, const char *tty)
+void FAST_FUNC print_login_issue(const char *issue_file, const char *tty)
{
- FILE *fd;
+ FILE *fp;
int c;
- char buf[256];
+ char buf[256+1];
const char *outbuf;
time_t t;
struct utsname uts;
@@ -47,82 +32,98 @@ void print_login_issue(const char *issue_file, const char *tty)
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;
- }
+ fp = fopen_for_read(issue_file);
+ if (!fp)
+ return;
+ while ((c = fgetc(fp)) != EOF) {
+ outbuf = buf;
+ buf[0] = c;
+ buf[1] = '\0';
+ if (c == '\n') {
+ buf[1] = '\r';
+ buf[2] = '\0';
}
- fputs(outbuf, stdout);
+ if (c == '\\' || c == '%') {
+ c = fgetc(fp);
+ switch (c) {
+ case 's':
+ outbuf = uts.sysname;
+ break;
+ case 'n':
+ case 'h':
+ 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':
+ outbuf = uts.domainname;
+ break;
+ case 'd':
+ strftime(buf, sizeof(buf), fmtstr_d, localtime(&t));
+ break;
+ case 't':
+ strftime(buf, sizeof(buf), fmtstr_t, localtime(&t));
+ break;
+ case 'l':
+ outbuf = tty;
+ break;
+ default:
+ buf[0] = c;
+ }
}
-
- fclose(fd);
-
- fflush(stdout);
+ fputs(outbuf, stdout);
}
+ fclose(fp);
+ fflush(stdout);
}
-void print_login_prompt(void)
+void FAST_FUNC print_login_prompt(void)
{
- char buf[MAXHOSTNAMELEN+1];
-
- gethostname(buf, MAXHOSTNAMELEN);
- fputs(buf, stdout);
+ char *hostname = safe_gethostname();
+ fputs(hostname, stdout);
fputs(LOGIN, stdout);
fflush(stdout);
+ free(hostname);
}
+/* Clear dangerous stuff, set PATH */
+static const char forbid[] ALIGN1 =
+ "ENV" "\0"
+ "BASH_ENV" "\0"
+ "HOME" "\0"
+ "IFS" "\0"
+ "SHELL" "\0"
+ "LD_LIBRARY_PATH" "\0"
+ "LD_PRELOAD" "\0"
+ "LD_TRACE_LOADED_OBJECTS" "\0"
+ "LD_BIND_NOW" "\0"
+ "LD_AOUT_LIBRARY_PATH" "\0"
+ "LD_AOUT_PRELOAD" "\0"
+ "LD_NOWARN" "\0"
+ "LD_KEEPDIR" "\0";
+
+int FAST_FUNC sanitize_env_if_suid(void)
+{
+ const char *p;
+
+ if (getuid() == geteuid())
+ return 0;
+
+ p = forbid;
+ do {
+ unsetenv(p);
+ p += strlen(p) + 1;
+ } while (*p);
+ putenv((char*)bb_PATH_root_path);
+
+ return 1; /* we indeed were run by different user! */
+}
diff --git a/release/src/router/busybox/libbb/loop.c b/release/src/router/busybox/libbb/loop.c
index 4754b8da..7d2b420b 100644
--- a/release/src/router/busybox/libbb/loop.c
+++ b/release/src/router/busybox/libbb/loop.c
@@ -2,127 +2,153 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Rob Landley <rob@landley.net>
*
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
*/
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
#include "libbb.h"
-#include "loop.h" /* Pull in loop device support */
-extern int del_loop(const char *device)
+/* For 2.6, use the cleaned up header to get the 64 bit API. */
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include <linux/loop.h>
+typedef struct loop_info64 bb_loop_info;
+#define BB_LOOP_SET_STATUS LOOP_SET_STATUS64
+#define BB_LOOP_GET_STATUS LOOP_GET_STATUS64
+
+/* For 2.4 and earlier, use the 32 bit API (and don't trust the headers) */
+#else
+/* Stuff stolen from linux/loop.h for 2.4 and earlier kernels*/
+#include <linux/posix_types.h>
+#define LO_NAME_SIZE 64
+#define LO_KEY_SIZE 32
+#define LOOP_SET_FD 0x4C00
+#define LOOP_CLR_FD 0x4C01
+#define BB_LOOP_SET_STATUS 0x4C02
+#define BB_LOOP_GET_STATUS 0x4C03
+typedef struct {
+ int lo_number;
+ __kernel_dev_t lo_device;
+ unsigned long lo_inode;
+ __kernel_dev_t lo_rdevice;
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size;
+ int lo_flags;
+ char lo_file_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE];
+ unsigned long lo_init[2];
+ char reserved[4];
+} bb_loop_info;
+#endif
+
+char* FAST_FUNC query_loop(const char *device)
{
int fd;
+ bb_loop_info loopinfo;
+ char *dev = 0;
- if ((fd = open(device, O_RDONLY)) < 0) {
- perror_msg("%s", device);
- return (FALSE);
- }
- if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
- perror_msg("ioctl: LOOP_CLR_FD");
- return (FALSE);
- }
+ fd = open(device, O_RDONLY);
+ if (fd < 0) return 0;
+ if (!ioctl(fd, BB_LOOP_GET_STATUS, &loopinfo))
+ dev = xasprintf("%ld %s", (long) loopinfo.lo_offset,
+ (char *)loopinfo.lo_file_name);
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)) {
- perror_msg("%s", file);
- return 1;
- }
- if ((fd = open(device, mode)) < 0) {
- close(ffd);
- perror_msg("%s", device);
- return 1;
- }
- *loopro = (mode == O_RDONLY);
+ return dev;
+}
- memset(&loopinfo, 0, sizeof(loopinfo));
- safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
- loopinfo.lo_offset = offset;
+int FAST_FUNC del_loop(const char *device)
+{
+ int fd, rc;
- loopinfo.lo_encrypt_key_size = 0;
- if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
- 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);
- perror_msg("ioctl: LOOP_SET_STATUS");
- close(fd);
- close(ffd);
- return 1;
- }
+ fd = open(device, O_RDONLY);
+ if (fd < 0) return 1;
+ rc = ioctl(fd, LOOP_CLR_FD, 0);
close(fd);
- close(ffd);
- return 0;
+
+ return rc;
}
-extern char *find_unused_loop_device(void)
+/* Returns 0 if mounted RW, 1 if mounted read-only, <0 for error.
+ *device is loop device to use, or if *device==NULL finds a loop device to
+ mount it on and sets *device to a strdup of that loop device name. This
+ search will re-use an existing loop device already bound to that
+ file/offset if it finds one.
+ */
+int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset)
{
- char dev[20];
- int i, fd;
+ char dev[LOOP_NAMESIZE];
+ char *try;
+ bb_loop_info loopinfo;
struct stat statbuf;
- struct loop_info loopinfo;
-
- for (i = 0; i <= 7; i++) {
- sprintf(dev, "/dev/loop%d", 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);
+ int i, dfd, ffd, mode, rc = -1;
+
+ /* Open the file. Barf if this doesn't work. */
+ mode = O_RDWR;
+ ffd = open(file, mode);
+ if (ffd < 0) {
+ mode = O_RDONLY;
+ ffd = open(file, mode);
+ if (ffd < 0)
+ return -errno;
+ }
+
+ /* Find a loop device. */
+ try = *device ? : dev;
+ for (i = 0; rc; i++) {
+ sprintf(dev, LOOP_FORMAT, i);
+
+ /* Ran out of block devices, return failure. */
+ if (stat(try, &statbuf) || !S_ISBLK(statbuf.st_mode)) {
+ rc = -ENOENT;
+ break;
+ }
+ /* Open the sucker and check its loopiness. */
+ dfd = open(try, mode);
+ if (dfd < 0 && errno == EROFS) {
+ mode = O_RDONLY;
+ dfd = open(try, mode);
+ }
+ if (dfd < 0)
+ goto try_again;
+
+ rc = ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo);
+
+ /* If device is free, claim it. */
+ if (rc && errno == ENXIO) {
+ memset(&loopinfo, 0, sizeof(loopinfo));
+ safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
+ loopinfo.lo_offset = offset;
+ /* Associate free loop device with file. */
+ if (!ioctl(dfd, LOOP_SET_FD, ffd)) {
+ if (!ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo))
+ rc = 0;
+ else
+ ioctl(dfd, LOOP_CLR_FD, 0);
}
+
+ /* If this block device already set up right, re-use it.
+ (Yes this is racy, but associating two loop devices with the same
+ file isn't pretty either. In general, mounting the same file twice
+ without using losetup manually is problematic.)
+ */
+ } else if (strcmp(file, (char *)loopinfo.lo_file_name) != 0
+ || offset != loopinfo.lo_offset) {
+ rc = -1;
}
+ close(dfd);
+ try_again:
+ if (*device) break;
+ }
+ close(ffd);
+ if (!rc) {
+ if (!*device)
+ *device = xstrdup(dev);
+ return (mode == O_RDONLY); /* 1:ro, 0:rw */
}
- return NULL;
+ return rc;
}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/make_directory.c b/release/src/router/busybox/libbb/make_directory.c
index 0a9d7b16..391493cd 100644
--- a/release/src/router/busybox/libbb/make_directory.c
+++ b/release/src/router/busybox/libbb/make_directory.c
@@ -1,67 +1,98 @@
/* vi: set sw=4 ts=4: */
/*
- * Mini make_directory implementation for busybox
+ * parse_mode implementation for busybox
*
- * Copyright (C) 2001 Matt Kraai.
+ * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Mar 5, 2003 Manuel Novoa III
*
- * 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.
+ * 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'.
*
- * 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
+ * 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 <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdlib.h>
-
#include "libbb.h"
-/* Create the directory PATH with mode MODE, or the default if MODE is -1.
- * Also create parent directories as necessary if flags contains
- * FILEUTILS_RECUR. */
+/* This function is used from NOFORK applets. It must not allocate anything */
-int make_directory (char *path, long mode, int flags)
+int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
{
- if (!(flags & FILEUTILS_RECUR)) {
- if (mkdir (path, 0777) < 0) {
- perror_msg ("Cannot create directory `%s'", path);
- return -1;
- }
+ mode_t mask;
+ const char *fail_msg;
+ char *s = path;
+ char c;
+ struct stat st;
- if (mode != -1 && chmod (path, mode) < 0) {
- perror_msg ("Cannot set permissions of directory `%s'", path);
- return -1;
+ mask = umask(0);
+ umask(mask & ~0300); /* Ensure intermediate dirs are wx */
+
+ while (1) {
+ 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;
+ }
}
- } else {
- struct stat st;
- if (stat (path, &st) < 0 && errno == ENOENT) {
- char *parent = dirname (path);
- mode_t mask = umask (0);
- umask (mask);
+ if (!c) /* Last component uses orig umask */
+ umask(mask);
- if (make_directory (parent, (0777 & ~mask) | 0300,
- FILEUTILS_RECUR) < 0)
- return -1;
- free (parent);
+ 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 condition. */
+ if (!c) {
+ umask(mask);
+ return 0;
+ }
+ }
- if (make_directory (path, mode, 0) < 0)
- return -1;
+ if (!c) {
+ /* Done. If necessary, update perms on the newly
+ * created directory. Failure to update here _is_
+ * an error. */
+ if ((mode != -1) && (chmod(path, mode) < 0)) {
+ fail_msg = "set permissions of";
+ break;
+ }
+ return 0;
}
- }
- 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/release/src/router/busybox/libbb/makedev.c b/release/src/router/busybox/libbb/makedev.c
new file mode 100644
index 00000000..ca71fdba
--- /dev/null
+++ b/release/src/router/busybox/libbb/makedev.c
@@ -0,0 +1,24 @@
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+/* We do not include libbb.h - #define makedev() is there! */
+#include "platform.h"
+#include <features.h>
+#include <sys/sysmacros.h>
+
+#ifdef __GLIBC__
+/* At least glibc has horrendously large inline for this, so wrap it */
+/* uclibc people please check - do we need "&& !__UCLIBC__" above? */
+
+/* suppress gcc "no previous prototype" warning */
+unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor);
+unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor)
+{
+ return makedev(major, minor);
+}
+#endif
diff --git a/release/src/router/busybox/libbb/match_fstype.c b/release/src/router/busybox/libbb/match_fstype.c
new file mode 100644
index 00000000..9360e757
--- /dev/null
+++ b/release/src/router/busybox/libbb/match_fstype.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Match fstypes for use in mount unmount
+ * We accept notmpfs,nfs but not notmpfs,nonfs
+ * This allows us to match fstypes that start with no like so
+ * mount -at ,noddy
+ *
+ * Returns 1 for a match, otherwise 0
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype)
+{
+ int match = 1;
+ int len;
+
+ if (!t_fstype)
+ return match;
+
+ if (t_fstype[0] == 'n' && t_fstype[1] == 'o') {
+ match--;
+ t_fstype += 2;
+ }
+
+ len = strlen(mt->mnt_type);
+ while (1) {
+ if (strncmp(mt->mnt_type, t_fstype, len) == 0
+ && (t_fstype[len] == '\0' || t_fstype[len] == ',')
+ ) {
+ return match;
+ }
+ t_fstype = strchr(t_fstype, ',');
+ if (!t_fstype)
+ break;
+ t_fstype++;
+ }
+
+ return !match;
+}
diff --git a/release/src/router/busybox/libbb/md5.c b/release/src/router/busybox/libbb/md5.c
new file mode 100644
index 00000000..768dfbcb
--- /dev/null
+++ b/release/src/router/busybox/libbb/md5.c
@@ -0,0 +1,429 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * md5.c - Compute MD5 checksum of strings according to the
+ * definition of MD5 in RFC 1321 from April 1992.
+ *
+ * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+ *
+ * Copyright (C) 1995-1999 Free Software Foundation, Inc.
+ * Copyright (C) 2001 Manuel Novoa III
+ * Copyright (C) 2003 Glenn L. McGrath
+ * Copyright (C) 2003 Erik Andersen
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+/* 0: fastest, 3: smallest */
+#if CONFIG_MD5_SIZE_VS_SPEED < 0
+# define MD5_SIZE_VS_SPEED 0
+#elif CONFIG_MD5_SIZE_VS_SPEED > 3
+# define MD5_SIZE_VS_SPEED 3
+#else
+# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED
+#endif
+
+/* Initialize structure containing state of computation.
+ * (RFC 1321, 3.3: Step 3)
+ */
+void FAST_FUNC md5_begin(md5_ctx_t *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+ ctx->total = 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))
+
+#define rotl32(w, s) (((w) << (s)) | ((w) >> (32 - (s))))
+
+/* Hash a single block, 64 bytes long and 4-byte aligned. */
+static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
+{
+ uint32_t correct_words[16];
+ const uint32_t *words = buffer;
+
+#if MD5_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[] ALIGN1 = {
+# if MD5_SIZE_VS_SPEED > 1
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
+# endif
+ 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 MD5_SIZE_VS_SPEED > 1
+ static const char S_array[] ALIGN1 = {
+ 7, 12, 17, 22,
+ 5, 9, 14, 20,
+ 4, 11, 16, 23,
+ 6, 10, 15, 21
+ };
+# endif /* MD5_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;
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ 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 MD5_SIZE_VS_SPEED > 1
+ const uint32_t *pc;
+ const char *pp;
+ const char *ps;
+ int i;
+ uint32_t temp;
+
+ for (i = 0; i < 16; i++)
+ cwp[i] = SWAP_LE32(words[i]);
+ words += 16;
+
+# if MD5_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++;
+ temp = rotl32(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++;
+ temp = rotl32(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++;
+ temp = rotl32(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++;
+ temp = rotl32(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++;
+ temp = rotl32(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+
+# endif /* MD5_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_LE32(*words)) + T; \
+ ++words; \
+ a = rotl32(a, s); \
+ a += b; \
+ } while (0)
+
+ /* 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 MD5_SIZE_VS_SPEED == 1
+ const uint32_t *pc;
+ const char *pp;
+ int i;
+# endif /* MD5_SIZE_VS_SPEED */
+
+ /* Round 1. */
+# if MD5_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/* MD5_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; \
+ a = rotl32(a, s); \
+ a += b; \
+ } while (0)
+
+ /* Round 2. */
+# if MD5_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/* MD5_SIZE_VS_SPEED == 1 */
+
+ /* Round 3. */
+# if MD5_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/* MD5_SIZE_VS_SPEED == 1 */
+
+ /* Round 4. */
+# if MD5_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 /* MD5_SIZE_VS_SPEED == 1 */
+#endif /* MD5_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;
+}
+
+/* Feed data through a temporary buffer to call md5_hash_aligned_block()
+ * with chunks of data that are 4-byte aligned and a multiple of 64 bytes.
+ * This function's internal buffer remembers previous data until it has 64
+ * bytes worth to pass on. Call md5_end() to flush this buffer. */
+void FAST_FUNC md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx)
+{
+ char *buf = (char *)buffer;
+
+ /* RFC 1321 specifies the possible length of the file up to 2^64 bits,
+ * Here we only track the number of bytes. */
+ ctx->total += len;
+
+ /* Process all input. */
+ while (len) {
+ unsigned i = 64 - ctx->buflen;
+
+ /* Copy data into aligned buffer. */
+ if (i > len) i = len;
+ memcpy(ctx->buffer + ctx->buflen, buf, i);
+ len -= i;
+ ctx->buflen += i;
+ buf += i;
+
+ /* When buffer fills up, process it. */
+ if (ctx->buflen == 64) {
+ md5_hash_block(ctx->buffer, ctx);
+ ctx->buflen = 0;
+ }
+ }
+}
+
+/* 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.
+ */
+void FAST_FUNC md5_end(void *resbuf, md5_ctx_t *ctx)
+{
+ char *buf = ctx->buffer;
+ int i;
+
+ /* Pad data to block size. */
+ buf[ctx->buflen++] = 0x80;
+ memset(buf + ctx->buflen, 0, 128 - ctx->buflen);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ ctx->total <<= 3;
+ if (ctx->buflen > 56)
+ buf += 64;
+ for (i = 0; i < 8; i++)
+ buf[56 + i] = ctx->total >> (i*8);
+
+ /* Process last bytes. */
+ if (buf != ctx->buffer)
+ md5_hash_block(ctx->buffer, ctx);
+ md5_hash_block(buf, ctx);
+
+ /* The MD5 result is in little endian byte order.
+ * We (ab)use the fact that A-D are consecutive in memory.
+ */
+#if BB_BIG_ENDIAN
+ ctx->A = SWAP_LE32(ctx->A);
+ ctx->B = SWAP_LE32(ctx->B);
+ ctx->C = SWAP_LE32(ctx->C);
+ ctx->D = SWAP_LE32(ctx->D);
+#endif
+ memcpy(resbuf, &ctx->A, sizeof(ctx->A) * 4);
+}
diff --git a/release/src/router/busybox/libbb/md5prime.c b/release/src/router/busybox/libbb/md5prime.c
new file mode 100644
index 00000000..7986f4d2
--- /dev/null
+++ b/release/src/router/busybox/libbb/md5prime.c
@@ -0,0 +1,460 @@
+/* This file is not used by busybox right now.
+ * However, the code here seems to be a tiny bit smaller
+ * than one in md5.c. Need to investigate which one
+ * is better overall...
+ * Hint: grep for md5prime to find places where you can switch
+ * md5.c/md5prime.c
+ */
+
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
+ *
+ * This code is the same as the code published by RSA Inc. It has been
+ * edited for clarity and style only.
+ *
+ * ----------------------------------------------------------------------------
+ * The md5_crypt() function was taken from freeBSD's libcrypt and contains
+ * this license:
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ *
+ * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
+ *
+ * ----------------------------------------------------------------------------
+ * On April 19th, 2001 md5_crypt() was modified to make it reentrant
+ * by Erik Andersen <andersen@uclibc.org>
+ *
+ * June 28, 2001 Manuel Novoa III
+ *
+ * "Un-inlined" code using loops and static const tables in order to
+ * reduce generated code size (on i386 from approx 4k to approx 2.5k).
+ *
+ * June 29, 2001 Manuel Novoa III
+ *
+ * Completely removed static PADDING array.
+ *
+ * Reintroduced the loop unrolling in md5_transform and added the
+ * MD5_SIZE_VS_SPEED option for configurability. Define below as:
+ * 0 fully unrolled loops
+ * 1 partially unrolled (4 ops per loop)
+ * 2 no unrolling -- introduces the need to swap 4 variables (slow)
+ * 3 no unrolling and all 4 loops merged into one with switch
+ * in each loop (glacial)
+ * On i386, sizes are roughly (-Os -fno-builtin):
+ * 0: 3k 1: 2.5k 2: 2.2k 3: 2k
+ *
+ * Since SuSv3 does not require crypt_r, modified again August 7, 2002
+ * by Erik Andersen to remove reentrance stuff...
+ */
+
+#include "libbb.h"
+
+/* 1: fastest, 3: smallest */
+#if CONFIG_MD5_SIZE_VS_SPEED < 1
+# define MD5_SIZE_VS_SPEED 1
+#elif CONFIG_MD5_SIZE_VS_SPEED > 3
+# define MD5_SIZE_VS_SPEED 3
+#else
+# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED
+#endif
+
+#if BB_LITTLE_ENDIAN
+#define memcpy32_cpu2le memcpy
+#define memcpy32_le2cpu memcpy
+#else
+/* Encodes input (uint32_t) into output (unsigned char).
+ * Assumes len is a multiple of 4. */
+static void
+memcpy32_cpu2le(unsigned char *output, uint32_t *input, unsigned len)
+{
+ unsigned i, j;
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = input[i];
+ output[j+1] = (input[i] >> 8);
+ output[j+2] = (input[i] >> 16);
+ output[j+3] = (input[i] >> 24);
+ }
+}
+/* Decodes input (unsigned char) into output (uint32_t).
+ * Assumes len is a multiple of 4. */
+static void
+memcpy32_le2cpu(uint32_t *output, const unsigned char *input, unsigned len)
+{
+ unsigned i, j;
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((uint32_t)input[j])
+ | (((uint32_t)input[j+1]) << 8)
+ | (((uint32_t)input[j+2]) << 16)
+ | (((uint32_t)input[j+3]) << 24);
+}
+#endif /* i386 */
+
+/* F, G, H and I are basic MD5 functions. */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+/* rotl32 rotates x left n bits. */
+#define rotl32(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/*
+ * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ * Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = rotl32((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = rotl32((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = rotl32((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = rotl32((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void md5_transform(uint32_t state[4], const unsigned char block[64])
+{
+ uint32_t a, b, c, d, x[16];
+#if MD5_SIZE_VS_SPEED > 1
+ uint32_t temp;
+ const unsigned char *ps;
+
+ static const unsigned char S[] = {
+ 7, 12, 17, 22,
+ 5, 9, 14, 20,
+ 4, 11, 16, 23,
+ 6, 10, 15, 21
+ };
+#endif /* MD5_SIZE_VS_SPEED > 1 */
+
+#if MD5_SIZE_VS_SPEED > 0
+ const uint32_t *pc;
+ const unsigned char *pp;
+ int i;
+
+ static const uint32_t C[] = {
+ /* 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 unsigned char P[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 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 */
+ };
+
+#endif /* MD5_SIZE_VS_SPEED > 0 */
+
+ memcpy32_le2cpu(x, block, 64);
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+#if MD5_SIZE_VS_SPEED > 2
+ pc = C;
+ pp = P;
+ ps = S - 4;
+ for (i = 0; i < 64; i++) {
+ if ((i & 0x0f) == 0) ps += 4;
+ temp = a;
+ switch (i>>4) {
+ case 0:
+ temp += F(b, c, d);
+ break;
+ case 1:
+ temp += G(b, c, d);
+ break;
+ case 2:
+ temp += H(b, c, d);
+ break;
+ case 3:
+ temp += I(b, c, d);
+ break;
+ }
+ temp += x[*pp++] + *pc++;
+ temp = rotl32(temp, ps[i & 3]);
+ temp += b;
+ a = d; d = c; c = b; b = temp;
+ }
+#elif MD5_SIZE_VS_SPEED > 1
+ pc = C;
+ pp = P;
+ ps = S;
+ /* Round 1 */
+ for (i = 0; i < 16; i++) {
+ FF(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+ temp = d; d = c; c = b; b = a; a = temp;
+ }
+ /* Round 2 */
+ ps += 4;
+ for (; i < 32; i++) {
+ GG(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+ temp = d; d = c; c = b; b = a; a = temp;
+ }
+ /* Round 3 */
+ ps += 4;
+ for (; i < 48; i++) {
+ HH(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+ temp = d; d = c; c = b; b = a; a = temp;
+ }
+ /* Round 4 */
+ ps += 4;
+ for (; i < 64; i++) {
+ II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+ temp = d; d = c; c = b; b = a; a = temp;
+ }
+#elif MD5_SIZE_VS_SPEED > 0
+ pc = C;
+ pp = P;
+ /* Round 1 */
+ for (i = 0; i < 4; i++) {
+ FF(a, b, c, d, x[*pp], 7, *pc); pp++; pc++;
+ FF(d, a, b, c, x[*pp], 12, *pc); pp++; pc++;
+ FF(c, d, a, b, x[*pp], 17, *pc); pp++; pc++;
+ FF(b, c, d, a, x[*pp], 22, *pc); pp++; pc++;
+ }
+ /* Round 2 */
+ for (i = 0; i < 4; i++) {
+ GG(a, b, c, d, x[*pp], 5, *pc); pp++; pc++;
+ GG(d, a, b, c, x[*pp], 9, *pc); pp++; pc++;
+ GG(c, d, a, b, x[*pp], 14, *pc); pp++; pc++;
+ GG(b, c, d, a, x[*pp], 20, *pc); pp++; pc++;
+ }
+ /* Round 3 */
+ for (i = 0; i < 4; i++) {
+ HH(a, b, c, d, x[*pp], 4, *pc); pp++; pc++;
+ HH(d, a, b, c, x[*pp], 11, *pc); pp++; pc++;
+ HH(c, d, a, b, x[*pp], 16, *pc); pp++; pc++;
+ HH(b, c, d, a, x[*pp], 23, *pc); pp++; pc++;
+ }
+ /* Round 4 */
+ for (i = 0; i < 4; i++) {
+ II(a, b, c, d, x[*pp], 6, *pc); pp++; pc++;
+ II(d, a, b, c, x[*pp], 10, *pc); pp++; pc++;
+ II(c, d, a, b, x[*pp], 15, *pc); pp++; pc++;
+ II(b, c, d, a, x[*pp], 21, *pc); pp++; pc++;
+ }
+#else
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+#endif
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information. */
+ memset(x, 0, sizeof(x));
+}
+
+
+/* MD5 initialization. */
+void FAST_FUNC md5_begin(md5_ctx_t *context)
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants. */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/*
+ * MD5 block update operation. Continues an MD5 message-digest
+ * operation, processing another message block, and updating
+ * the context.
+ */
+void FAST_FUNC md5_hash(const void *buffer, size_t inputLen, md5_ctx_t *context)
+{
+ unsigned i, idx, partLen;
+ const unsigned char *input = buffer;
+
+ /* Compute number of bytes mod 64 */
+ idx = (context->count[0] >> 3) & 0x3F;
+
+ /* Update number of bits */
+ context->count[0] += (inputLen << 3);
+ if (context->count[0] < (inputLen << 3))
+ context->count[1]++;
+ context->count[1] += (inputLen >> 29);
+
+ /* Transform as many times as possible. */
+ i = 0;
+ partLen = 64 - idx;
+ if (inputLen >= partLen) {
+ memcpy(&context->buffer[idx], input, partLen);
+ md5_transform(context->state, context->buffer);
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ md5_transform(context->state, &input[i]);
+ idx = 0;
+ }
+
+ /* Buffer remaining input */
+ memcpy(&context->buffer[idx], &input[i], inputLen - i);
+}
+
+/*
+ * MD5 finalization. Ends an MD5 message-digest operation,
+ * writing the message digest.
+ */
+void FAST_FUNC md5_end(void *digest, md5_ctx_t *context)
+{
+ unsigned idx, padLen;
+ unsigned char bits[8];
+ unsigned char padding[64];
+
+ /* Add padding followed by original length. */
+ memset(padding, 0, sizeof(padding));
+ padding[0] = 0x80;
+ /* save number of bits */
+ memcpy32_cpu2le(bits, context->count, 8);
+ /* pad out to 56 mod 64 */
+ idx = (context->count[0] >> 3) & 0x3f;
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ md5_hash(padding, padLen, context);
+ /* append length (before padding) */
+ md5_hash(bits, 8, context);
+
+ /* Store state in digest */
+ memcpy32_cpu2le(digest, context->state, 16);
+}
diff --git a/release/src/router/busybox/libbb/messages.c b/release/src/router/busybox/libbb/messages.c
index 552c3ab5..90090283 100644
--- a/release/src/router/busybox/libbb/messages.c
+++ b/release/src/router/busybox/libbb/messages.c
@@ -1,67 +1,73 @@
/* vi: set sw=4 ts=4: */
/*
- * Copyright (C) 2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <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
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include "libbb.h"
-#ifdef L_full_version
- const char * const full_version = BB_BANNER " multi-call binary";
-#endif
-#ifdef L_name_too_long
- const char * const name_too_long = "file name too long";
+/* allow default system PATH to be extended via CFLAGS */
+#ifndef BB_ADDITIONAL_PATH
+#define BB_ADDITIONAL_PATH ""
#endif
-#ifdef L_omitting_directory
- const char * const omitting_directory = "%s: omitting directory";
-#endif
-#ifdef L_not_a_directory
- const char * const not_a_directory = "%s: not a directory";
-#endif
-#ifdef L_memory_exhausted
- const char * const memory_exhausted = "memory exhausted";
-#endif
-#ifdef L_invalid_date
- const char * const invalid_date = "invalid date `%s'";
-#endif
-#ifdef L_invalid_option
- const char * const invalid_option = "invalid option -- %c";
-#endif
-#ifdef L_io_error
- const char * const io_error = "%s: input/output error -- %s";
-#endif
-#ifdef L_dash_dash_help
- const char * const dash_dash_help = "--help";
-#endif
-#ifdef L_write_error
- const char * const write_error = "Write Error";
-#endif
-#ifdef L_too_few_args
- const char * const too_few_args = "too few arguments";
-#endif
-#ifdef L_name_longer_than_foo
- const char * const name_longer_than_foo = "Names longer than %d chars not supported.";
-#endif
-#ifdef L_unknown
- const char * const unknown = "(unknown)";
+/* allow version to be extended, via CFLAGS */
+#ifndef BB_EXTRA_VERSION
+#define BB_EXTRA_VERSION BB_BT
#endif
-#ifdef L_can_not_create_raw_socket
- const char * const can_not_create_raw_socket = "can`t create raw socket";
+#define BANNER "BusyBox v" BB_VER " (" BB_EXTRA_VERSION ")"
+
+const char bb_banner[] ALIGN1 = BANNER;
+
+
+const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted";
+const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'";
+const char bb_msg_write_error[] ALIGN1 = "write error";
+const char bb_msg_read_error[] ALIGN1 = "read error";
+const char bb_msg_unknown[] ALIGN1 = "(unknown)";
+const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket";
+const char bb_msg_perm_denied_are_you_root[] ALIGN1 = "permission denied. (are you root?)";
+const char bb_msg_requires_arg[] ALIGN1 = "%s requires an argument";
+const char bb_msg_invalid_arg[] ALIGN1 = "invalid argument '%s' to '%s'";
+const char bb_msg_standard_input[] ALIGN1 = "standard input";
+const char bb_msg_standard_output[] ALIGN1 = "standard output";
+
+const char bb_str_default[] ALIGN1 = "default";
+const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
+
+const char bb_path_passwd_file[] ALIGN1 = "/etc/passwd";
+const char bb_path_shadow_file[] ALIGN1 = "/etc/shadow";
+const char bb_path_group_file[] ALIGN1 = "/etc/group";
+const char bb_path_gshadow_file[] ALIGN1 = "/etc/gshadow";
+const char bb_path_motd_file[] ALIGN1 = "/etc/motd";
+const char bb_dev_null[] ALIGN1 = "/dev/null";
+const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
+const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
+/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
+ * but I want to save a few bytes here. Check libbb.h before changing! */
+const char bb_PATH_root_path[] ALIGN1 =
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH;
+
+
+const int const_int_1 = 1;
+/* explicitly = 0, otherwise gcc may make it a common variable
+ * and it will end up in bss */
+const int const_int_0 = 0;
+
+#include <utmp.h>
+/* This is usually something like "/var/adm/wtmp" or "/var/log/wtmp" */
+const char bb_path_wtmp_file[] ALIGN1 =
+#if defined _PATH_WTMP
+ _PATH_WTMP;
+#elif defined WTMP_FILE
+ WTMP_FILE;
+#else
+#error unknown path to wtmp file
#endif
+
+/* We use it for "global" data via *(struct global*)&bb_common_bufsiz1.
+ * Since gcc insists on aligning struct global's members, it would be a pity
+ * (and an alignment fault on some CPUs) to mess it up. */
+char bb_common_bufsiz1[COMMON_BUFSIZE] ALIGNED(sizeof(long long));
diff --git a/release/src/router/busybox/libbb/mk_loop_h.sh b/release/src/router/busybox/libbb/mk_loop_h.sh
deleted file mode 100755
index 71c98737..00000000
--- a/release/src/router/busybox/libbb/mk_loop_h.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-#
-# Figure out (i) the type of dev_t (ii) the defines for loop stuff
-#
-# Output of this script is normally redirected to "loop.h".
-
-# Since 1.3.79 there is an include file <asm/posix_types.h>
-# that defines __kernel_dev_t.
-# (The file itself appeared in 1.3.78, but there it defined __dev_t.)
-# If it exists, we use it, or, rather, <linux/posix_types.h> which
-# avoids namespace pollution. Otherwise we guess that __kernel_dev_t
-# is an unsigned short (which is true on i386, but false on alpha).
-
-# BUG: This test is actually broken if your gcc is not configured to
-# search /usr/include, as may well happen with cross-compilers.
-# It would be better to ask $(CC) if these files can be found.
-
-if [ -f /usr/include/linux/posix_types.h ]; then
- echo '#include <linux/posix_types.h>'
- echo '#undef dev_t'
- echo '#define dev_t __kernel_dev_t'
-else
- echo '#undef dev_t'
- echo '#define dev_t unsigned short'
-fi
-
-# Next we have to find the loop stuff itself.
-# First try kernel source, then a private version.
-
-if [ -f /usr/include/linux/loop.h ]; then
- echo '#include <linux/loop.h>'
-else
- echo '#include "real_loop.h"'
-fi
-
-echo '#undef dev_t'
-
diff --git a/release/src/router/busybox/libbb/mode_string.c b/release/src/router/busybox/libbb/mode_string.c
index 0a3d6e6f..7d4e514b 100644
--- a/release/src/router/busybox/libbb/mode_string.c
+++ b/release/src/router/busybox/libbb/mode_string.c
@@ -1,82 +1,128 @@
/* vi: set sw=4 ts=4: */
/*
- * Utility routines.
+ * mode_string implementation for busybox
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
+/* Aug 13, 2003
+ * Fix a bug reported by junkio@cox.net involving the mode_chars index.
+ */
+
+
+#include <assert.h>
+#include <sys/stat.h>
+
#include "libbb.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
-#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
-#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+#if (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX) == 07777
+#undef mode_t
+#define mode_t unsigned short
+#endif
-/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
-static const mode_t SBIT[] = {
- 0, 0, S_ISUID,
- 0, 0, S_ISGID,
- 0, 0, S_ISVTX
+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 9 mode bits to test */
-static const mode_t MBIT[] = {
- S_IRUSR, S_IWUSR, S_IXUSR,
- S_IRGRP, S_IWGRP, S_IXGRP,
- S_IROTH, S_IWOTH, S_IXOTH
-};
+/* 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. */
-static const char MODE1[] = "rwxrwxrwx";
-static const char MODE0[] = "---------";
-static const char SMODE1[] = "..s..s..t";
-static const char SMODE0[] = "..S..S..T";
+/* 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] ALIGN1 = "?pc?d?b?-?l?s???";
+/***************************************** 0123456789abcdef */
+static const char mode_chars[7] ALIGN1 = "rwxSTst";
-/*
- * Return the standard ls-like mode string from a file mode.
- * This is static and so is overwritten on each call.
- */
-const char *mode_string(int mode)
+const char* FAST_FUNC bb_mode_string(mode_t 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);
- int i;
+ /* 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);
- buf[0] = TYPECHAR(mode);
- for (i = 0; i < 9; i++) {
- if (mode & SBIT[i])
- buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
- else
- buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
- }
return buf;
}
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+#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* FAST_FUNC bb_mode_string(mode_t 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/release/src/router/busybox/libbb/module_syscalls.c b/release/src/router/busybox/libbb/module_syscalls.c
deleted file mode 100644
index 36b75fb9..00000000
--- a/release/src/router/busybox/libbb/module_syscalls.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * some system calls possibly missing from libc
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <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 <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>
-#ifndef __UCLIBC__
-#include <asm/unistd.h>
-#endif
-#include "libbb.h"
-
-
-#if __GNU_LIBRARY__ < 5
-/* These syscalls are not included as part of libc5 */
-_syscall1(int, delete_module, const char *, name);
-_syscall1(int, get_kernel_syms, __ptr_t, ks);
-
-/* 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. */
-_syscall5(int, init_module, void *, first, void *, second, void *, third,
- void *, fourth, void *, fifth);
-
-#ifndef __NR_query_module
-#warning This kernel does not support the query_module syscall
-#warning -> The query_module system call is being stubbed out...
-int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret)
-{
- fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n");
- fprintf(stderr, "with a kernel supporting the query_module system call. -Erik\n\n");
- errno=ENOSYS;
- return -1;
-}
-#else
-_syscall5(int, query_module, const char *, name, int, which,
- void *, buf, size_t, bufsize, size_t*, ret);
-#endif
-
-/* Jump through hoops to fixup error return codes */
-#define __NR___create_module __NR_create_module
-static inline _syscall2(long, __create_module, const char *, name, size_t, size)
-unsigned long create_module(const char *name, size_t size)
-{
- long ret = __create_module(name, size);
-
- if (ret == -1 && errno > 125) {
- ret = -errno;
- errno = 0;
- }
- return ret;
-}
-
-#endif /* __GNU_LIBRARY__ < 5 */
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
-
diff --git a/release/src/router/busybox/libbb/mtab.c b/release/src/router/busybox/libbb/mtab.c
index 28c9978e..586a6619 100644
--- a/release/src/router/busybox/libbb/mtab.c
+++ b/release/src/router/busybox/libbb/mtab.c
@@ -1,95 +1,55 @@
/* vi: set sw=4 ts=4: */
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
#include <mntent.h>
#include "libbb.h"
-extern const char mtab_file[]; /* Defined in utility.c */
-static const int MS_RDONLY = 1; /* Mount read-only. */
-
-void erase_mtab(const char *name)
+#if ENABLE_FEATURE_MTAB_SUPPORT
+void FAST_FUNC erase_mtab(const char *name)
{
- struct mntent entries[20];
- int count = 0;
- FILE *mountTable = setmntent(mtab_file, "r");
+ struct mntent *entries;
+ int i, count;
+ FILE *mountTable;
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) {
- perror_msg("%s", mtab_file);
+ mountTable = setmntent(bb_path_mtab_file, "r");
+ /* Bummer. Fall back on trying the /proc filesystem */
+ if (!mountTable) mountTable = setmntent("/proc/mounts", "r");
+ if (!mountTable) {
+ bb_perror_msg(bb_path_mtab_file);
return;
}
+ entries = NULL;
+ count = 0;
while ((m = getmntent(mountTable)) != 0) {
- 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 = xrealloc_vector(entries, 3, count);
+ entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
+ entries[count].mnt_dir = xstrdup(m->mnt_dir);
+ entries[count].mnt_type = xstrdup(m->mnt_type);
+ entries[count].mnt_opts = xstrdup(m->mnt_opts);
entries[count].mnt_freq = m->mnt_freq;
entries[count].mnt_passno = m->mnt_passno;
count++;
}
endmntent(mountTable);
- if ((mountTable = setmntent(mtab_file, "w"))) {
- int i;
+//TODO: make update atomic
+ mountTable = setmntent(bb_path_mtab_file, "w");
+ if (mountTable) {
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
+ if (strcmp(entries[i].mnt_fsname, name) != 0
+ && strcmp(entries[i].mnt_dir, name) != 0)
addmntent(mountTable, &entries[i]);
}
endmntent(mountTable);
} else if (errno != EROFS)
- perror_msg("%s", mtab_file);
-}
-
-void write_mtab(char *blockDevice, char *directory,
- char *filesystemType, long flags, char *string_flags)
-{
- FILE *mountTable = setmntent(mtab_file, "a+");
- struct mntent m;
-
- if (mountTable == 0) {
- perror_msg("%s", 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);
- }
+ bb_perror_msg(bb_path_mtab_file);
}
+#endif
diff --git a/release/src/router/busybox/libbb/mtab_file.c b/release/src/router/busybox/libbb/mtab_file.c
index c872b9a7..030b148d 100644
--- a/release/src/router/busybox/libbb/mtab_file.c
+++ b/release/src/router/busybox/libbb/mtab_file.c
@@ -2,51 +2,14 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
#include "libbb.h"
-
-/* Busybox mount uses either /proc/mounts or /dev/mtab to
- * get the list of currently mounted filesystems */
-#if defined BB_FEATURE_MOUNT_MTAB_SUPPORT
-const char mtab_file[] = "/etc/mtab";
-#else
-# if defined BB_FEATURE_USE_DEVPS_PATCH
- const char mtab_file[] = "/dev/mtab";
-# else
- const char mtab_file[] = "/proc/mounts";
-# endif
-#endif
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+/* Busybox mount uses either /proc/mounts or /etc/mtab to
+ * get the list of currently mounted filesystems */
+const char bb_path_mtab_file[] ALIGN1 =
+USE_FEATURE_MTAB_SUPPORT("/etc/mtab")SKIP_FEATURE_MTAB_SUPPORT("/proc/mounts");
diff --git a/release/src/router/busybox/libbb/my_getgrgid.c b/release/src/router/busybox/libbb/my_getgrgid.c
deleted file mode 100644
index fabd4776..00000000
--- a/release/src/router/busybox/libbb/my_getgrgid.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-/* gets a groupname given a gid */
-void my_getgrgid(char *group, long gid)
-{
- struct group *mygroup;
-
- mygroup = getgrgid(gid);
- if (mygroup==NULL)
- sprintf(group, "%-8ld ", (long)gid);
- else
- strcpy(group, mygroup->gr_name);
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/my_getgrnam.c b/release/src/router/busybox/libbb/my_getgrnam.c
deleted file mode 100644
index e3226a27..00000000
--- a/release/src/router/busybox/libbb/my_getgrnam.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-
-/* returns a gid given a group name */
-long my_getgrnam(const char *name)
-{
- struct group *mygroup;
-
- mygroup = getgrnam(name);
- if (mygroup==NULL)
- 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/release/src/router/busybox/libbb/my_getpwnam.c b/release/src/router/busybox/libbb/my_getpwnam.c
deleted file mode 100644
index ae73ae7f..00000000
--- a/release/src/router/busybox/libbb/my_getpwnam.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-
-/* returns a uid given a username */
-long my_getpwnam(const char *name)
-{
- struct passwd *myuser;
-
- myuser = getpwnam(name);
- if (myuser==NULL)
- 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/release/src/router/busybox/libbb/my_getpwnamegid.c b/release/src/router/busybox/libbb/my_getpwnamegid.c
deleted file mode 100644
index fb3d148c..00000000
--- a/release/src/router/busybox/libbb/my_getpwnamegid.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-
-/* gets a gid given a user name */
-long my_getpwnamegid(const char *name)
-{
- struct group *mygroup;
- struct passwd *myuser;
-
- myuser=getpwnam(name);
- if (myuser==NULL)
- error_msg_and_die("unknown user name: %s", name);
-
- mygroup = getgrgid(myuser->pw_gid);
- if (mygroup==NULL)
- error_msg_and_die("unknown gid %ld", (long)myuser->pw_gid);
-
- return mygroup->gr_gid;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/my_getpwuid.c b/release/src/router/busybox/libbb/my_getpwuid.c
deleted file mode 100644
index 46c7a884..00000000
--- a/release/src/router/busybox/libbb/my_getpwuid.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "../pwd_grp/pwd.h"
-#include "../pwd_grp/grp.h"
-#include "libbb.h"
-
-
-
-/* gets a username given a uid */
-void my_getpwuid(char *name, long uid)
-{
- struct passwd *myuser;
-
- myuser = getpwuid(uid);
- if (myuser==NULL)
- sprintf(name, "%-8ld ", (long)uid);
- else
- strcpy(name, myuser->pw_name);
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/obscure.c b/release/src/router/busybox/libbb/obscure.c
index 537d4484..19b87523 100644
--- a/release/src/router/busybox/libbb/obscure.c
+++ b/release/src/router/busybox/libbb/obscure.c
@@ -1,251 +1,170 @@
/* vi: set sw=4 ts=4: */
/*
- * Copyright 1989 - 1994, Julianne Frances Haugh <jockgrrl@austin.rr.com>
- * All rights reserved.
+ * Mini weak password checker implementation for busybox
*
- * 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.
+ * Copyright (C) 2006 Tito Ragusa <farmatito@tiscali.it>
*
- * 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-/*
- * 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.
- */
+/* A good password:
+ 1) should contain at least six characters (man passwd);
+ 2) empty passwords are not permitted;
+ 3) should contain a mix of four different types of characters
+ upper case letters,
+ lower case letters,
+ numbers,
+ special characters such as !@#$%^&*,;".
+ This password types should not be permitted:
+ a) pure numbers: birthdates, social security number, license plate, phone numbers;
+ b) words and all letters only passwords (uppercase, lowercase or mixed)
+ as palindromes, consecutive or repetitive letters
+ or adjacent letters on your keyboard;
+ c) username, real name, company name or (e-mail?) address
+ in any form (as-is, reversed, capitalized, doubled, etc.).
+ (we can check only against username, gecos and hostname)
+ d) common and obvious letter-number replacements
+ (e.g. replace the letter O with number 0)
+ such as "M1cr0$0ft" or "P@ssw0rd" (CAVEAT: we cannot check for them
+ without the use of a dictionary).
+
+ For each missing type of characters an increase of password length is
+ requested.
+
+ If user is root we warn only.
+
+ CAVEAT: some older versions of crypt() truncates passwords to 8 chars,
+ so that aaaaaaaa1Q$ is equal to aaaaaaaa making it possible to fool
+ some of our checks. We don't test for this special case as newer versions
+ of crypt do not truncate passwords.
+*/
-#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);
+static int string_checker_helper(const char *p1, const char *p2) __attribute__ ((__pure__));
- 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)
+static int string_checker_helper(const char *p1, const char *p2)
{
- 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;
+ /* as-is or capitalized */
+ if (strcasecmp(p1, p2) == 0
+ /* as sub-string */
+ || strcasestr(p2, p1) != NULL
+ /* invert in case haystack is shorter than needle */
+ || strcasestr(p1, p2) != NULL)
+ return 1;
+ return 0;
}
-/*
- * a nice mix of characters.
- */
-
-static int simple(const char *newval)
+static int string_checker(const char *p1, const char *p2)
{
- 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;
+ /* check string */
+ int ret = string_checker_helper(p1, p2);
+ /* Make our own copy */
+ char *p = xstrdup(p1);
+ /* reverse string */
+ size = strlen(p);
+
+ while (size--) {
+ *p = p1[size];
+ p++;
}
-
- /*
- * 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;
+ /* restore pointer */
+ p -= strlen(p1);
+ /* check reversed string */
+ ret |= string_checker_helper(p, p2);
+ /* clean up */
+ memset(p, 0, strlen(p1));
+ free(p);
+ return ret;
}
-static char *str_lower(char *string)
-{
- char *cp;
-
- for (cp = string; *cp; cp++)
- *cp = tolower(*cp);
- return string;
-}
+#define LOWERCASE 1
+#define UPPERCASE 2
+#define NUMBERS 4
+#define SPECIAL 8
-static const char *
-password_check(const char *old, const char *newval, const struct passwd *pwdp)
+static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw)
{
- 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) * 2 + 1;
- wrapped = (char *) xmalloc(lenwrap);
- 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";
+ int i;
+ int c;
+ int length;
+ int mixed = 0;
+ /* Add 2 for each type of characters to the minlen of password */
+ int size = CONFIG_PASSWORD_MINLEN + 8;
+ const char *p;
+ char *hostname;
+
+ /* size */
+ if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN)
+ return "too short";
- else {
- safe_strncpy(wrapped + lenwrap, wrapped, lenwrap + 1);
- if (strstr(wrapped, newmono))
- msg = "rotated";
+ /* no username as-is, as sub-string, reversed, capitalized, doubled */
+ if (string_checker(new_p, pw->pw_name)) {
+ return "similar to username";
}
-
- bzero(newmono, strlen(newmono));
- bzero(wrapped, lenwrap);
- free(newmono);
- free(wrapped);
-
- return msg;
+ /* no gecos as-is, as sub-string, reversed, capitalized, doubled */
+ if (*pw->pw_gecos && string_checker(new_p, pw->pw_gecos)) {
+ return "similar to gecos";
+ }
+ /* hostname as-is, as sub-string, reversed, capitalized, doubled */
+ hostname = safe_gethostname();
+ i = string_checker(new_p, hostname);
+ free(hostname);
+ if (i)
+ return "similar to hostname";
+
+ /* Should / Must contain a mix of: */
+ for (i = 0; i < length; i++) {
+ if (islower(new_p[i])) { /* a-z */
+ mixed |= LOWERCASE;
+ } else if (isupper(new_p[i])) { /* A-Z */
+ mixed |= UPPERCASE;
+ } else if (isdigit(new_p[i])) { /* 0-9 */
+ mixed |= NUMBERS;
+ } else { /* special characters */
+ mixed |= SPECIAL;
+ }
+ /* More than 50% similar characters ? */
+ c = 0;
+ p = new_p;
+ while (1) {
+ p = strchr(p, new_p[i]);
+ if (p == NULL) {
+ break;
+ }
+ c++;
+ if (!++p) {
+ break; /* move past the matched char if possible */
+ }
+ }
+
+ if (c >= (length / 2)) {
+ return "too many similar characters";
+ }
+ }
+ for (i=0; i<4; i++)
+ if (mixed & (1<<i)) size -= 2;
+ if (length < size)
+ return "too weak";
+
+ if (old_p && old_p[0] != '\0') {
+ /* check vs. old password */
+ if (string_checker(new_p, old_p)) {
+ return "similar to old password";
+ }
+ }
+ return NULL;
}
-static const char *
-obscure_msg(const char *old, const char *newval, const struct passwd *pwdp)
+int FAST_FUNC obscure(const char *old, const char *newval, const struct passwd *pw)
{
- 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; */
+ msg = obscure_msg(old, newval, pw);
+ if (msg) {
+ printf("Bad password: %s\n", msg);
return 1;
}
- /* return 1; */
return 0;
}
diff --git a/release/src/router/busybox/libbb/parse_config.c b/release/src/router/busybox/libbb/parse_config.c
new file mode 100644
index 00000000..74f0524e
--- /dev/null
+++ b/release/src/router/busybox/libbb/parse_config.c
@@ -0,0 +1,219 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * config file parser helper
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later.
+ */
+
+#include "libbb.h"
+
+#if defined ENABLE_PARSE && ENABLE_PARSE
+int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int parse_main(int argc UNUSED_PARAM, char **argv)
+{
+ const char *delims = "# \t";
+ unsigned flags = PARSE_NORMAL;
+ int mintokens = 0, ntokens = 128;
+
+ opt_complementary = "-1:n+:m+:f+";
+ getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags);
+ //argc -= optind;
+ argv += optind;
+ while (*argv) {
+ parser_t *p = config_open(*argv);
+ if (p) {
+ int n;
+ char **t = xmalloc(sizeof(char *) * ntokens);
+ while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) {
+ for (int i = 0; i < n; ++i)
+ printf("[%s]", t[i]);
+ puts("");
+ }
+ config_close(p);
+ }
+ argv++;
+ }
+ return EXIT_SUCCESS;
+}
+#endif
+
+/*
+
+Typical usage:
+
+----- CUT -----
+ char *t[3]; // tokens placeholder
+ parser_t *p = config_open(filename);
+ if (p) {
+ // parse line-by-line
+ while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens
+ // use tokens
+ bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]);
+ }
+ ...
+ // free parser
+ config_close(p);
+ }
+----- CUT -----
+
+*/
+
+parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path))
+{
+ FILE* fp;
+ parser_t *parser;
+
+ fp = fopen_func(filename);
+ if (!fp)
+ return NULL;
+ parser = xzalloc(sizeof(*parser));
+ parser->fp = fp;
+ return parser;
+}
+
+parser_t* FAST_FUNC config_open(const char *filename)
+{
+ return config_open2(filename, fopen_or_warn_stdin);
+}
+
+static void config_free_data(parser_t *const parser)
+{
+ free(parser->line);
+ parser->line = NULL;
+ if (PARSE_KEEP_COPY) { /* compile-time constant */
+ free(parser->data);
+ parser->data = NULL;
+ }
+}
+
+void FAST_FUNC config_close(parser_t *parser)
+{
+ if (parser) {
+ config_free_data(parser);
+ fclose(parser->fp);
+ free(parser);
+ }
+}
+
+/*
+0. If parser is NULL return 0.
+1. Read a line from config file. If nothing to read then return 0.
+ Handle continuation character. Advance lineno for each physical line.
+ Discard everything past comment characher.
+2. if PARSE_TRIM is set (default), remove leading and trailing delimiters.
+3. If resulting line is empty goto 1.
+4. Look for first delimiter. If !PARSE_COLLAPSE or !PARSE_TRIM is set then
+ remember the token as empty.
+5. Else (default) if number of seen tokens is equal to max number of tokens
+ (token is the last one) and PARSE_GREEDY is set then the remainder
+ of the line is the last token.
+ Else (token is not last or PARSE_GREEDY is not set) just replace
+ first delimiter with '\0' thus delimiting the token.
+6. Advance line pointer past the end of token. If number of seen tokens
+ is less than required number of tokens then goto 4.
+7. Check the number of seen tokens is not less the min number of tokens.
+ Complain or die otherwise depending on PARSE_MIN_DIE.
+8. Return the number of seen tokens.
+
+mintokens > 0 make config_read() print error message if less than mintokens
+(but more than 0) are found. Empty lines are always skipped (not warned about).
+*/
+#undef config_read
+int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims)
+{
+ char *line;
+ int ntokens, mintokens;
+ int t, len;
+
+ ntokens = flags & 0xFF;
+ mintokens = (flags & 0xFF00) >> 8;
+
+ if (parser == NULL)
+ return 0;
+
+again:
+ memset(tokens, 0, sizeof(tokens[0]) * ntokens);
+ config_free_data(parser);
+
+ /* Read one line (handling continuations with backslash) */
+ line = bb_get_chunk_with_continuation(parser->fp, &len, &parser->lineno);
+ if (line == NULL)
+ return 0;
+ parser->line = line;
+
+ /* Strip trailing line-feed if any */
+ if (len && line[len-1] == '\n')
+ line[len-1] = '\0';
+
+ /* Skip token in the start of line? */
+ if (flags & PARSE_TRIM)
+ line += strspn(line, delims + 1);
+
+ if (line[0] == '\0' || line[0] == delims[0])
+ goto again;
+
+ if (flags & PARSE_KEEP_COPY)
+ parser->data = xstrdup(line);
+
+ /* Tokenize the line */
+ for (t = 0; *line && *line != delims[0] && t < ntokens; t++) {
+ /* Pin token */
+ tokens[t] = line;
+
+ /* Combine remaining arguments? */
+ if ((t != (ntokens-1)) || !(flags & PARSE_GREEDY)) {
+ /* Vanilla token, find next delimiter */
+ line += strcspn(line, delims[0] ? delims : delims + 1);
+ } else {
+ /* Combining, find comment char if any */
+ line = strchrnul(line, delims[0]);
+
+ /* Trim any extra delimiters from the end */
+ if (flags & PARSE_TRIM) {
+ while (strchr(delims + 1, line[-1]) != NULL)
+ line--;
+ }
+ }
+
+ /* Token not terminated? */
+ if (line[0] == delims[0])
+ *line = '\0';
+ else if (line[0] != '\0')
+ *(line++) = '\0';
+
+#if 0 /* unused so far */
+ if (flags & PARSE_ESCAPE) {
+ const char *from;
+ char *to;
+
+ from = to = tokens[t];
+ while (*from) {
+ if (*from == '\\') {
+ from++;
+ *to++ = bb_process_escape_sequence(&from);
+ } else {
+ *to++ = *from++;
+ }
+ }
+ *to = '\0';
+ }
+#endif
+
+ /* Skip possible delimiters */
+ if (flags & PARSE_COLLAPSE)
+ line += strspn(line, delims + 1);
+ }
+
+ if (t < mintokens) {
+ bb_error_msg("bad line %u: %d tokens found, %d needed",
+ parser->lineno, t, mintokens);
+ if (flags & PARSE_MIN_DIE)
+ xfunc_die();
+ goto again;
+ }
+
+ return t;
+}
diff --git a/release/src/router/busybox/libbb/parse_mode.c b/release/src/router/busybox/libbb/parse_mode.c
index 30d2f21c..40105dd3 100644
--- a/release/src/router/busybox/libbb/parse_mode.c
+++ b/release/src/router/busybox/libbb/parse_mode.c
@@ -1,138 +1,150 @@
/* vi: set sw=4 ts=4: */
/*
- * Utility routines.
+ * parse_mode implementation for busybox
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <stdlib.h>
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
+
#include "libbb.h"
+/* This function is used from NOFORK applets. It must not allocate anything */
+
+#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
-/* This function parses the sort of string you might pass
- * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the
- * correct mode described by the string. */
-extern int parse_mode(const char *s, mode_t * theMode)
+int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode)
{
- static const mode_t group_set[] = {
- S_ISUID | S_IRWXU, /* u */
- S_ISGID | S_IRWXG, /* g */
- S_IRWXO, /* o */
- S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */
+ 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 mode_set[] = {
+ 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_ISUID | S_ISGID, /* s */
- S_ISVTX /* t */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
+ S_ISUID | S_ISGID, /* s */
+ S_ISVTX /* t */
};
-
- static const char group_chars[] = "ugoa";
- static const char mode_chars[] = "rwxst";
+ static const char who_chars[] ALIGN1 = "augo";
+ static const char perm_chars[] ALIGN1 = "rwxXst";
const char *p;
+ mode_t wholist;
+ mode_t permlist;
+ mode_t new_mode;
+ char op;
- mode_t andMode =
- S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
- mode_t orMode = 0;
- mode_t mode;
- mode_t groups;
- char type;
- char c;
+ if (((unsigned int)(*s - '0')) < 8) {
+ unsigned long tmp;
+ char *e;
- if (s==NULL) {
- return (FALSE);
+ tmp = strtoul(s, &e, 8);
+ if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
+ return 0;
+ }
+ *current_mode = tmp;
+ return 1;
}
- do {
- mode = 0;
- groups = 0;
- NEXT_GROUP:
- if ((c = *s++) == '\0') {
- return -1;
+ 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;
}
- for (p=group_chars ; *p ; p++) {
- if (*p == c) {
- groups |= group_set[(int)(p-group_chars)];
- goto NEXT_GROUP;
+
+ /* 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;
}
- }
- switch (c) {
- case '=':
- case '+':
- case '-':
- type = c;
- if (groups == 0) { /* The default is "all" */
- groups |= S_ISUID | S_ISGID | S_ISVTX
- | S_IRWXU | S_IRWXG | S_IRWXO;
+ } while (*++p);
+
+ do { /* Process action list. */
+ if ((*s != '+') && (*s != '-')) {
+ if (*s != '=') {
+ return 0;
}
- break;
- default:
- if ((c < '0') || (c > '7') || (mode | groups)) {
- return (FALSE);
- } else {
- *theMode = strtol(--s, NULL, 8);
- return (TRUE);
+ /* Since op is '=', clear all bits corresponding to the
+ * wholist, or all file bits if wholist is empty. */
+ permlist = ~FILEMODEBITS;
+ if (wholist) {
+ permlist = ~wholist;
}
- }
+ new_mode &= permlist;
+ }
+ op = *s++;
- NEXT_MODE:
- if (((c = *s++) != '\0') && (c != ',')) {
- for (p=mode_chars ; *p ; p++) {
- if (*p == c) {
- mode |= mode_set[(int)(p-mode_chars)];
- goto NEXT_MODE;
+ /* 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;
}
- }
- break; /* We're done so break out of loop.*/
- }
- switch (type) {
- case '=':
- andMode &= ~(groups); /* Now fall through. */
- case '+':
- orMode |= mode & groups;
- break;
- case '-':
- andMode &= ~(mode & groups);
- orMode &= ~(mode & groups);
- break;
- }
- } while (c == ',');
+ } while (*++p);
- *theMode &= andMode;
- *theMode |= orMode;
+ /* 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 = wholist;
+ if (!wholist) {
+ mode_t u_mask = umask(0);
+ umask(u_mask);
+ tmp = ~u_mask;
+ }
+ permlist &= tmp;
+ if (op == '-') {
+ new_mode &= ~permlist;
+ } else {
+ new_mode |= permlist;
+ }
+ }
+ } while (*s && (*s != ','));
+ }
- return TRUE;
+ *current_mode = new_mode;
+ return 1;
}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/parse_number.c b/release/src/router/busybox/libbb/parse_number.c
deleted file mode 100644
index c90511dc..00000000
--- a/release/src/router/busybox/libbb/parse_number.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-
-unsigned long parse_number(const char *numstr,
- const struct suffix_mult *suffixes)
-{
- const struct suffix_mult *sm;
- unsigned long int ret;
- int len;
- char *end;
-
- ret = strtoul(numstr, &end, 10);
- if (numstr == end)
- error_msg_and_die("invalid number `%s'", numstr);
- while (end[0] != '\0') {
- sm = suffixes;
- while ( sm != 0 ) {
- if(sm->suffix) {
- len = strlen(sm->suffix);
- if (strncmp(sm->suffix, end, len) == 0) {
- ret *= sm->mult;
- end += len;
- break;
- }
- sm++;
-
- } else
- sm = 0;
- }
- if (sm == 0)
- error_msg_and_die("invalid number `%s'", numstr);
- }
- return ret;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/perror_msg.c b/release/src/router/busybox/libbb/perror_msg.c
index 18c71ab1..6c8e1b51 100644
--- a/release/src/router/busybox/libbb/perror_msg.c
+++ b/release/src/router/busybox/libbb/perror_msg.c
@@ -2,50 +2,24 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
#include "libbb.h"
-extern void perror_msg(const char *s, ...)
+void FAST_FUNC bb_perror_msg(const char *s, ...)
{
va_list p;
va_start(p, s);
- vperror_msg(s, p);
+ /* Guard against "<error message>: Success" */
+ bb_verror_msg(s, p, errno ? strerror(errno) : NULL);
va_end(p);
}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+void FAST_FUNC bb_simple_perror_msg(const char *s)
+{
+ bb_perror_msg("%s", s);
+}
diff --git a/release/src/router/busybox/libbb/perror_msg_and_die.c b/release/src/router/busybox/libbb/perror_msg_and_die.c
index 9d304a26..15615fa2 100644
--- a/release/src/router/busybox/libbb/perror_msg_and_die.c
+++ b/release/src/router/busybox/libbb/perror_msg_and_die.c
@@ -2,51 +2,25 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
#include "libbb.h"
-extern void perror_msg_and_die(const char *s, ...)
+void FAST_FUNC bb_perror_msg_and_die(const char *s, ...)
{
va_list p;
va_start(p, s);
- vperror_msg(s, p);
+ /* Guard against "<error message>: Success" */
+ bb_verror_msg(s, p, errno ? strerror(errno) : NULL);
va_end(p);
- exit(EXIT_FAILURE);
+ xfunc_die();
}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+void FAST_FUNC bb_simple_perror_msg_and_die(const char *s)
+{
+ bb_perror_msg_and_die("%s", s);
+}
diff --git a/release/src/router/busybox/libbb/perror_nomsg.c b/release/src/router/busybox/libbb/perror_nomsg.c
index 464cb86c..a157caa1 100644
--- a/release/src/router/busybox/libbb/perror_nomsg.c
+++ b/release/src/router/busybox/libbb/perror_nomsg.c
@@ -4,27 +4,19 @@
*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stddef.h>
-#include <libbb.h>
+/* gcc warns about a null format string, therefore we provide
+ * modified definition without "attribute (format)"
+ * instead of including libbb.h */
+//#include "libbb.h"
+#include "platform.h"
+extern void bb_perror_msg(const char *s, ...) FAST_FUNC;
-extern void bb_perror_nomsg(void)
+/* suppress gcc "no previous prototype" warning */
+void FAST_FUNC bb_perror_nomsg(void);
+void FAST_FUNC bb_perror_nomsg(void)
{
- /* Ignore the gcc warning about a null format string. */
- bb_perror_msg(NULL);
+ bb_perror_msg(0);
}
diff --git a/release/src/router/busybox/libbb/perror_nomsg_and_die.c b/release/src/router/busybox/libbb/perror_nomsg_and_die.c
index bab22845..d56e05d3 100644
--- a/release/src/router/busybox/libbb/perror_nomsg_and_die.c
+++ b/release/src/router/busybox/libbb/perror_nomsg_and_die.c
@@ -4,27 +4,19 @@
*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stddef.h>
-#include "libbb.h"
+/* gcc warns about a null format string, therefore we provide
+ * modified definition without "attribute (format)"
+ * instead of including libbb.h */
+//#include "libbb.h"
+#include "platform.h"
+extern void bb_perror_msg_and_die(const char *s, ...) FAST_FUNC;
-extern void bb_perror_nomsg_and_die(void)
+/* suppress gcc "no previous prototype" warning */
+void FAST_FUNC bb_perror_nomsg_and_die(void);
+void FAST_FUNC bb_perror_nomsg_and_die(void)
{
- /* Ignore the gcc warning about a null format string. */
- bb_perror_msg_and_die(NULL);
+ bb_perror_msg_and_die(0);
}
diff --git a/release/src/router/busybox/libbb/pidfile.c b/release/src/router/busybox/libbb/pidfile.c
new file mode 100644
index 00000000..7b8fee21
--- /dev/null
+++ b/release/src/router/busybox/libbb/pidfile.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pid file routines
+ *
+ * Copyright (C) 2007 by Stephane Billiart <stephane.billiart@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* Override ENABLE_FEATURE_PIDFILE */
+#define WANT_PIDFILE 1
+#include "libbb.h"
+
+smallint wrote_pidfile;
+
+void FAST_FUNC write_pidfile(const char *path)
+{
+ int pid_fd;
+ char *end;
+ char buf[sizeof(int)*3 + 2];
+ struct stat sb;
+
+ if (!path)
+ return;
+ /* we will overwrite stale pidfile */
+ pid_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (pid_fd < 0)
+ return;
+
+ /* path can be "/dev/null"! Test for such cases */
+ wrote_pidfile = (fstat(pid_fd, &sb) == 0) && S_ISREG(sb.st_mode);
+
+ if (wrote_pidfile) {
+ /* few bytes larger, but doesn't use stdio */
+ end = utoa_to_buf(getpid(), buf, sizeof(buf));
+ *end = '\n';
+ full_write(pid_fd, buf, end - buf + 1);
+ }
+ close(pid_fd);
+}
diff --git a/release/src/router/busybox/libbb/print_file.c b/release/src/router/busybox/libbb/print_file.c
deleted file mode 100644
index bfedc5ef..00000000
--- a/release/src/router/busybox/libbb/print_file.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) 1999-2001 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 <stdio.h>
-#include <sys/stat.h>
-#include "libbb.h"
-
-
-extern void print_file(FILE *file)
-{
- fflush(stdout);
- copyfd(fileno(file), fileno(stdout));
- fclose(file);
-}
-
-extern int print_file_by_name(char *filename)
-{
- struct stat statBuf;
- int status = TRUE;
-
- if(is_directory(filename, TRUE, &statBuf)==TRUE) {
- error_msg("%s: Is directory", filename);
- status = FALSE;
- } else {
- FILE *f = wfopen(filename, "r");
- if(f!=NULL)
- print_file(f);
- else
- status = FALSE;
- }
-
- return status;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/print_flags.c b/release/src/router/busybox/libbb/print_flags.c
new file mode 100644
index 00000000..afa75503
--- /dev/null
+++ b/release/src/router/busybox/libbb/print_flags.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/* Print string that matches bit masked flags
+ *
+ * Copyright (C) 2008 Natanael Copa <natanael.copa@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <libbb.h>
+
+/* returns a set with the flags not printed */
+int FAST_FUNC print_flags_separated(const int *masks, const char *labels, int flags, const char *separator)
+{
+ const char *need_separator = NULL;
+ while (*labels) {
+ if (flags & *masks) {
+ printf("%s%s",
+ need_separator ? need_separator : "",
+ labels);
+ need_separator = separator;
+ flags &= ~ *masks;
+ }
+ masks++;
+ labels += strlen(labels) + 1;
+ }
+ return flags;
+}
+
+int FAST_FUNC print_flags(const masks_labels_t *ml, int flags)
+{
+ return print_flags_separated(ml->masks, ml->labels, flags, NULL);
+}
diff --git a/release/src/router/busybox/libbb/printable.c b/release/src/router/busybox/libbb/printable.c
new file mode 100644
index 00000000..ae933593
--- /dev/null
+++ b/release/src/router/busybox/libbb/printable.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+void FAST_FUNC fputc_printable(int ch, FILE *file)
+{
+ if ((ch & (0x80 + PRINTABLE_META)) == (0x80 + PRINTABLE_META)) {
+ fputs("M-", file);
+ ch &= 0x7f;
+ }
+ ch = (unsigned char) ch;
+ if (ch == 0x9b) {
+ /* VT100's CSI, aka Meta-ESC, is not printable on vt-100 */
+ ch = '{';
+ goto print_caret;
+ }
+ if (ch < ' ') {
+ ch += '@';
+ goto print_caret;
+ }
+ if (ch == 0x7f) {
+ ch = '?';
+ print_caret:
+ fputc('^', file);
+ }
+ fputc(ch, file);
+}
diff --git a/release/src/router/busybox/libbb/printf.c b/release/src/router/busybox/libbb/printf.c
deleted file mode 100644
index 923c5a1a..00000000
--- a/release/src/router/busybox/libbb/printf.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/* 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 desireable 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 threadsafe. As busybox is a nonthreaded 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)
- */
-#define SET_FERROR_UNLOCKED(S) ((S)->modeflags |= __FLAG_ERROR)
-
-#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, contary 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 libaries 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/release/src/router/busybox/libbb/process_escape_sequence.c b/release/src/router/busybox/libbb/process_escape_sequence.c
index 67b0490c..6de2cacd 100644
--- a/release/src/router/busybox/libbb/process_escape_sequence.c
+++ b/release/src/router/busybox/libbb/process_escape_sequence.c
@@ -2,79 +2,88 @@
/*
* Utility routines.
*
- * Copyright (C) Manuel Nova III <mnovoa3@bellsouth.net>
- * and Vladimir Oleynik <vodz@usa.net>
+ * 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
- *
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <limits.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 process_escape_sequence(const char **ptr)
+char FAST_FUNC 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', '\\', '\\' };
+ /* bash builtin "echo -e '\ec'" interprets \e as ESC,
+ * but coreutils "/bin/echo -e '\ec'" does not.
+ * manpages tend to support coreutils way. */
+ static const char charmap[] ALIGN1 = {
+ 'a', 'b', /*'e',*/ 'f', 'n', 'r', 't', 'v', '\\', 0,
+ '\a', '\b', /*27,*/ '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
const char *p;
const char *q;
- int num_digits;
- unsigned int n;
-
- n = 0;
+ unsigned num_digits;
+ unsigned r;
+ unsigned n;
+ unsigned d;
+ unsigned base;
+
+ num_digits = n = 0;
+ base = 8;
q = *ptr;
- for ( num_digits = 0 ; num_digits < 3 ; ++num_digits) {
- if ((*q < '0') || (*q > '7')) { /* not a digit? */
+#ifdef WANT_HEX_ESCAPES
+ if (*q == 'x') {
+ ++q;
+ base = 16;
+ ++num_digits;
+ }
+#endif
+
+ do {
+ d = (unsigned char)(*q) - '0';
+#ifdef WANT_HEX_ESCAPES
+ if (d >= 10) {
+ d = (unsigned char)(_tolower(*q)) - 'a' + 10;
+ }
+#endif
+
+ if (d >= base) {
+#ifdef WANT_HEX_ESCAPES
+ if ((base == 16) && (!--num_digits)) {
+/* return '\\'; */
+ --q;
+ }
+#endif
break;
}
- n = n * 8 + (*q++ - '0');
- }
+
+ r = n * base + d;
+ if (r > UCHAR_MAX) {
+ break;
+ }
+
+ n = r;
+ ++q;
+ } while (++num_digits < 3);
if (num_digits == 0) { /* mnemonic escape sequence? */
- for (p=charmap ; *p ; p++) {
+ p = charmap;
+ do {
if (*p == *q) {
q++;
break;
}
- }
- n = *(p+(sizeof(charmap)/2));
- }
-
- /* doesn't hurt to fall through to here from mnemonic case */
- if (n > UCHAR_MAX) { /* is octal code too big for a char? */
- n /= 8; /* adjust value and */
- --q; /* back up one char */
+ } 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/release/src/router/busybox/libbb/procps.c b/release/src/router/busybox/libbb/procps.c
index 44103fae..c5e40bf8 100644
--- a/release/src/router/busybox/libbb/procps.c
+++ b/release/src/router/busybox/libbb/procps.c
@@ -4,149 +4,473 @@
*
* 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
+ * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#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
+
+typedef struct unsigned_to_name_map_t {
+ long id;
+ char name[USERNAME_MAX_SIZE];
+} unsigned_to_name_map_t;
+
+typedef struct cache_t {
+ unsigned_to_name_map_t *cache;
+ int size;
+} cache_t;
+
+static cache_t username, groupname;
+
+static void clear_cache(cache_t *cp)
+{
+ free(cp->cache);
+ cp->cache = NULL;
+ cp->size = 0;
+}
+void FAST_FUNC clear_username_cache(void)
+{
+ clear_cache(&username);
+ clear_cache(&groupname);
+}
+
+#if 0 /* more generic, but we don't need that yet */
+/* Returns -N-1 if not found. */
+/* cp->cache[N] is allocated and must be filled in this case */
+static int get_cached(cache_t *cp, unsigned id)
+{
+ int i;
+ for (i = 0; i < cp->size; i++)
+ if (cp->cache[i].id == id)
+ return i;
+ i = cp->size++;
+ cp->cache = xrealloc_vector(cp->cache, 2, i);
+ cp->cache[i++].id = id;
+ return -i;
+}
+#endif
+
+static char* get_cached(cache_t *cp, long id,
+ char* FAST_FUNC x2x_utoa(long id))
+{
+ int i;
+ for (i = 0; i < cp->size; i++)
+ if (cp->cache[i].id == id)
+ return cp->cache[i].name;
+ i = cp->size++;
+ cp->cache = xrealloc_vector(cp->cache, 2, i);
+ cp->cache[i].id = id;
+ /* Never fails. Generates numeric string if name isn't found */
+ safe_strncpy(cp->cache[i].name, x2x_utoa(id), sizeof(cp->cache[i].name));
+ return cp->cache[i].name;
+}
+const char* FAST_FUNC get_cached_username(uid_t uid)
+{
+ return get_cached(&username, uid, uid2uname_utoa);
+}
+const char* FAST_FUNC get_cached_groupname(gid_t gid)
+{
+ return get_cached(&groupname, gid, gid2group_utoa);
+}
+
+
+#define PROCPS_BUFSIZE 1024
+
+static int read_to_buf(const char *filename, void *buf)
+{
+ int fd;
+ /* open_read_close() would do two reads, checking for EOF.
+ * When you have 10000 /proc/$NUM/stat to read, it isn't desirable */
+ ssize_t ret = -1;
+ fd = open(filename, O_RDONLY);
+ if (fd >= 0) {
+ ret = read(fd, buf, PROCPS_BUFSIZE-1);
+ close(fd);
+ }
+ ((char *)buf)[ret > 0 ? ret : 0] = '\0';
+ return ret;
+}
+
+static procps_status_t* FAST_FUNC alloc_procps_scan(void)
+{
+ unsigned n = getpagesize();
+ procps_status_t* sp = xzalloc(sizeof(procps_status_t));
+ sp->dir = xopendir("/proc");
+ while (1) {
+ n >>= 1;
+ if (!n) break;
+ sp->shift_pages_to_bytes++;
+ }
+ sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10;
+ return sp;
+}
+
+void FAST_FUNC free_procps_scan(procps_status_t* sp)
+{
+ closedir(sp->dir);
+ free(sp->argv0);
+ USE_SELINUX(free(sp->context);)
+ free(sp);
+}
+
+#if ENABLE_FEATURE_TOPMEM
+static unsigned long fast_strtoul_16(char **endptr)
+{
+ unsigned char c;
+ char *str = *endptr;
+ unsigned long n = 0;
+
+ while ((c = *str++) != ' ') {
+ c = ((c|0x20) - '0');
+ if (c > 9)
+ // c = c + '0' - 'a' + 10:
+ c = c - ('a' - '0' - 10);
+ n = n*16 + c;
+ }
+ *endptr = str; /* We skip trailing space! */
+ return n;
+}
+/* TOPMEM uses fast_strtoul_10, so... */
+#undef ENABLE_FEATURE_FAST_TOP
+#define ENABLE_FEATURE_FAST_TOP 1
+#endif
+
+#if ENABLE_FEATURE_FAST_TOP
+/* We cut a lot of corners here for speed */
+static unsigned long fast_strtoul_10(char **endptr)
+{
+ char c;
+ char *str = *endptr;
+ unsigned long n = *str - '0';
+
+ while ((c = *++str) != ' ')
+ n = n*10 + (c - '0');
+
+ *endptr = str + 1; /* We skip trailing space! */
+ return n;
+}
+static char *skip_fields(char *str, int count)
+{
+ do {
+ while (*str++ != ' ')
+ continue;
+ /* we found a space char, str points after it */
+ } while (--count);
+ return str;
+}
#endif
- )
+
+void BUG_comm_size(void);
+procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
{
- 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;
+ char buf[PROCPS_BUFSIZE];
+ char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
+ char *filename_tail;
long tasknice;
+ unsigned pid;
+ int n;
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;
+ if (!sp)
+ sp = alloc_procps_scan();
+
+ for (;;) {
+ entry = readdir(sp->dir);
+ if (entry == NULL) {
+ free_procps_scan(sp);
+ return NULL;
}
- name = entry->d_name;
- if (!(*name >= '0' && *name <= '9'))
+ pid = bb_strtou(entry->d_name, NULL, 10);
+ if (errno)
continue;
- memset(&curstatus, 0, sizeof(procps_status_t));
- pid = atoi(name);
- curstatus.pid = pid;
+ /* After this point we have to break, not continue
+ * ("continue" would mean that current /proc/NNN
+ * is not a valid process info) */
- 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;
+ memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
+
+ sp->pid = pid;
+ if (!(flags & ~PSSCAN_PID)) break;
+
+#if ENABLE_SELINUX
+ if (flags & PSSCAN_CONTEXT) {
+ if (getpidcon(sp->pid, &sp->context) < 0)
+ sp->context = NULL;
}
- else
#endif
- if(fstat(fileno(fp), &sb))
- continue;
- my_getpwuid(curstatus.user, sb.st_uid);
- 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 "
+
+ filename_tail = filename + sprintf(filename, "/proc/%d", pid);
+
+ if (flags & PSSCAN_UIDGID) {
+ if (stat(filename, &sb))
+ break;
+ /* Need comment - is this effective or real UID/GID? */
+ sp->uid = sb.st_uid;
+ sp->gid = sb.st_gid;
+ }
+
+ if (flags & PSSCAN_STAT) {
+ char *cp, *comm1;
+ int tty;
+#if !ENABLE_FEATURE_FAST_TOP
+ unsigned long vsz, rss;
+#endif
+ /* see proc(5) for some details on this */
+ strcpy(filename_tail, "/stat");
+ n = read_to_buf(filename, buf);
+ if (n < 0)
+ break;
+ cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
+ /*if (!cp || cp[1] != ' ')
+ break;*/
+ cp[0] = '\0';
+ if (sizeof(sp->comm) < 16)
+ BUG_comm_size();
+ comm1 = strchr(buf, '(');
+ /*if (comm1)*/
+ safe_strncpy(sp->comm, comm1 + 1, sizeof(sp->comm));
+
+#if !ENABLE_FEATURE_FAST_TOP
+ n = sscanf(cp+2,
+ "%c %u " /* state, ppid */
+ "%u %u %d %*s " /* pgid, sid, tty, tpgid */
+ "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+ "%lu %lu " /* utime, stime */
+ "%*s %*s %*s " /* cutime, cstime, priority */
+ "%ld " /* nice */
+ "%*s %*s " /* timeout, it_real_value */
+ "%lu " /* start_time */
+ "%lu " /* vsize */
+ "%lu " /* rss */
+#if ENABLE_FEATURE_TOP_SMP_PROCESS
+ "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
+ "%*s %*s %*s %*s " /*signal, blocked, sigignore, sigcatch */
+ "%*s %*s %*s %*s " /*wchan, nswap, cnswap, exit_signal */
+ "%d" /*cpu last seen on*/
+#endif
+ ,
+ sp->state, &sp->ppid,
+ &sp->pgid, &sp->sid, &tty,
+ &sp->utime, &sp->stime,
+ &tasknice,
+ &sp->start_time,
+ &vsz,
+ &rss
+#if ENABLE_FEATURE_TOP_SMP_PROCESS
+ , &sp->last_seen_on_cpu
#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,
+ );
+
+ if (n < 11)
+ break;
+#if ENABLE_FEATURE_TOP_SMP_PROCESS
+ if (n < 11+15)
+ sp->last_seen_on_cpu = 0;
#endif
- &tasknice,
- &curstatus.rss);
-#ifdef FEATURE_CPU_USAGE_PERCENTAGE
- if(n != 6)
+
+ /* vsz is in bytes and we want kb */
+ sp->vsz = vsz >> 10;
+ /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
+ sp->rss = rss << sp->shift_pages_to_kb;
+ sp->tty_major = (tty >> 8) & 0xfff;
+ sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
#else
- if(n != 4)
+/* This costs ~100 bytes more but makes top faster by 20%
+ * If you run 10000 processes, this may be important for you */
+ sp->state[0] = cp[2];
+ cp += 4;
+ sp->ppid = fast_strtoul_10(&cp);
+ sp->pgid = fast_strtoul_10(&cp);
+ sp->sid = fast_strtoul_10(&cp);
+ tty = fast_strtoul_10(&cp);
+ sp->tty_major = (tty >> 8) & 0xfff;
+ sp->tty_minor = (tty & 0xff) | ((tty >> 12) & 0xfff00);
+ cp = skip_fields(cp, 6); /* tpgid, flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+ sp->utime = fast_strtoul_10(&cp);
+ sp->stime = fast_strtoul_10(&cp);
+ cp = skip_fields(cp, 3); /* cutime, cstime, priority */
+ tasknice = fast_strtoul_10(&cp);
+ cp = skip_fields(cp, 2); /* timeout, it_real_value */
+ sp->start_time = fast_strtoul_10(&cp);
+ /* vsz is in bytes and we want kb */
+ sp->vsz = fast_strtoul_10(&cp) >> 10;
+ /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
+ sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb;
+#if ENABLE_FEATURE_TOP_SMP_PROCESS
+ /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
+ /* (4): signal, blocked, sigignore, sigcatch */
+ /* (4): wchan, nswap, cnswap, exit_signal */
+ cp = skip_fields(cp, 14);
+//FIXME: is it safe to assume this field exists?
+ sp->last_seen_on_cpu = fast_strtoul_10(&cp);
#endif
- continue;
+#endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */
- 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] = ' ';
-
- curstatus.rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */
-
- 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--;
+ if (sp->vsz == 0 && sp->state[0] != 'Z')
+ sp->state[1] = 'W';
+ else
+ sp->state[1] = ' ';
+ if (tasknice < 0)
+ sp->state[2] = '<';
+ else if (tasknice) /* > 0 */
+ sp->state[2] = 'N';
+ else
+ sp->state[2] = ' ';
+ }
+
+#if ENABLE_FEATURE_TOPMEM
+ if (flags & (PSSCAN_SMAPS)) {
+ FILE *file;
+
+ strcpy(filename_tail, "/smaps");
+ file = fopen_for_read(filename);
+ if (!file)
+ break;
+ while (fgets(buf, sizeof(buf), file)) {
+ unsigned long sz;
+ char *tp;
+ char w;
+#define SCAN(str, name) \
+ if (strncmp(buf, str, sizeof(str)-1) == 0) { \
+ tp = skip_whitespace(buf + sizeof(str)-1); \
+ sp->name += fast_strtoul_10(&tp); \
+ continue; \
+ }
+ SCAN("Shared_Clean:" , shared_clean );
+ SCAN("Shared_Dirty:" , shared_dirty );
+ SCAN("Private_Clean:", private_clean);
+ SCAN("Private_Dirty:", private_dirty);
+#undef SCAN
+ // f7d29000-f7d39000 rw-s ADR M:m OFS FILE
+ tp = strchr(buf, '-');
+ if (tp) {
+ *tp = ' ';
+ tp = buf;
+ sz = fast_strtoul_16(&tp); /* start */
+ sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */
+ // tp -> "rw-s" string
+ w = tp[1];
+ // skipping "rw-s ADR M:m OFS "
+ tp = skip_whitespace(skip_fields(tp, 4));
+ // filter out /dev/something (something != zero)
+ if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) {
+ if (w == 'w') {
+ sp->mapped_rw += sz;
+ } else if (w == '-') {
+ sp->mapped_ro += sz;
+ }
+ }
+//else printf("DROPPING %s (%s)\n", buf, tp);
+ if (strcmp(tp, "[stack]\n") == 0)
+ sp->stack += sz;
}
- *name = 0;
- if(buf[0])
- curstatus.cmd = strdup(buf);
- /* if NULL it work true also */
}
- fclose(fp);
+ fclose(file);
+ }
+#endif /* TOPMEM */
+
+#if 0 /* PSSCAN_CMD is not used */
+ if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) {
+ free(sp->argv0);
+ sp->argv0 = NULL;
+ free(sp->cmd);
+ sp->cmd = NULL;
+ strcpy(filename_tail, "/cmdline");
+ /* TODO: to get rid of size limits, read into malloc buf,
+ * then realloc it down to real size. */
+ n = read_to_buf(filename, buf);
+ if (n <= 0)
+ break;
+ if (flags & PSSCAN_ARGV0)
+ sp->argv0 = xstrdup(buf);
+ if (flags & PSSCAN_CMD) {
+ do {
+ n--;
+ if ((unsigned char)(buf[n]) < ' ')
+ buf[n] = ' ';
+ } while (n);
+ sp->cmd = xstrdup(buf);
+ }
+ }
+#else
+ if (flags & (PSSCAN_ARGV0|PSSCAN_ARGVN)) {
+ free(sp->argv0);
+ sp->argv0 = NULL;
+ strcpy(filename_tail, "/cmdline");
+ n = read_to_buf(filename, buf);
+ if (n <= 0)
+ break;
+ if (flags & PSSCAN_ARGVN) {
+ sp->argv_len = n;
+ sp->argv0 = xmalloc(n + 1);
+ memcpy(sp->argv0, buf, n + 1);
+ /* sp->argv0[n] = '\0'; - buf has it */
+ } else {
+ sp->argv_len = 0;
+ sp->argv0 = xstrdup(buf);
+ }
}
- return memcpy(&ret_status, &curstatus, sizeof(procps_status_t));
+#endif
+ break;
}
+ return sp;
}
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
+void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
+{
+ ssize_t sz;
+ char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
+
+ sprintf(filename, "/proc/%u/cmdline", pid);
+ sz = open_read_close(filename, buf, col);
+ if (sz > 0) {
+ buf[sz] = '\0';
+ while (--sz >= 0)
+ if ((unsigned char)(buf[sz]) < ' ')
+ buf[sz] = ' ';
+ } else {
+ snprintf(buf, col, "[%s]", comm);
+ }
+}
+
+/* from kernel:
+ // pid comm S ppid pgid sid tty_nr tty_pgrp flg
+ sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
+%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
+ task->pid,
+ tcomm,
+ state,
+ ppid,
+ pgid,
+ sid,
+ tty_nr,
+ tty_pgrp,
+ task->flags,
+ min_flt,
+ cmin_flt,
+ maj_flt,
+ cmaj_flt,
+ cputime_to_clock_t(utime),
+ cputime_to_clock_t(stime),
+ cputime_to_clock_t(cutime),
+ cputime_to_clock_t(cstime),
+ priority,
+ nice,
+ num_threads,
+ // 0,
+ start_time,
+ vsize,
+ mm ? get_mm_rss(mm) : 0,
+ rsslim,
+ mm ? mm->start_code : 0,
+ mm ? mm->end_code : 0,
+ mm ? mm->start_stack : 0,
+ esp,
+ eip,
+the rest is some obsolete cruft
*/
diff --git a/release/src/router/busybox/libbb/ptr_to_globals.c b/release/src/router/busybox/libbb/ptr_to_globals.c
new file mode 100644
index 00000000..5f30e2a6
--- /dev/null
+++ b/release/src/router/busybox/libbb/ptr_to_globals.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include <errno.h>
+
+struct globals;
+
+#ifndef GCC_COMBINE
+
+/* We cheat here. It is declared as const ptr in libbb.h,
+ * but here we make it live in R/W memory */
+struct globals *ptr_to_globals;
+
+#ifdef __GLIBC__
+int *bb_errno;
+#endif
+
+
+#else
+
+
+/* gcc -combine will see through and complain */
+/* Using alternative method which is more likely to break
+ * on weird architectures, compilers, linkers and so on */
+struct globals *const ptr_to_globals __attribute__ ((section (".data")));
+
+#ifdef __GLIBC__
+int *const bb_errno __attribute__ ((section (".data")));
+#endif
+
+#endif
diff --git a/release/src/router/busybox/libbb/pw_encrypt.c b/release/src/router/busybox/libbb/pw_encrypt.c
index ce607853..6fc0ba87 100644
--- a/release/src/router/busybox/libbb/pw_encrypt.c
+++ b/release/src/router/busybox/libbb/pw_encrypt.c
@@ -1,45 +1,127 @@
/* vi: set sw=4 ts=4: */
/*
- * Utility routine.
+ * Utility routines.
*
- * Copyright (C) 1999-2003 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
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <string.h>
-#include <crypt.h>
#include "libbb.h"
+/* static const uint8_t ascii64[] =
+ * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ */
-extern char *pw_encrypt(const char *clear, const char *salt)
+static int i64c(int i)
{
- static char cipher[128];
- char *cp;
+ i &= 0x3f;
+ if (i == 0)
+ return '.';
+ if (i == 1)
+ return '/';
+ if (i < 12)
+ return ('0' - 2 + i);
+ if (i < 38)
+ return ('A' - 12 + i);
+ return ('a' - 38 + i);
+}
+
+int FAST_FUNC crypt_make_salt(char *p, int cnt, int x)
+{
+ x += getpid() + time(NULL);
+ do {
+ /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
+ * (low-order bit is not "random", etc...),
+ * but for our purposes it is good enough */
+ x = x*1664525 + 1013904223;
+ /* BTW, Park and Miller's "minimal standard generator" is
+ * x = x*16807 % ((2^31)-1)
+ * It has no problem with visibly alternating lowest bit
+ * but is also weak in cryptographic sense + needs div,
+ * which needs more code (and slower) on many CPUs */
+ *p++ = i64c(x >> 16);
+ *p++ = i64c(x >> 22);
+ } while (--cnt);
+ *p = '\0';
+ return x;
+}
+
+#if ENABLE_USE_BB_CRYPT
-#ifdef CONFIG_FEATURE_SHA1_PASSWORDS
- if (strncmp(salt, "$2$", 3) == 0) {
- return sha1_crypt(clear);
+static char*
+to64(char *s, unsigned v, int n)
+{
+ while (--n >= 0) {
+ /* *s++ = ascii64[v & 0x3f]; */
+ *s++ = i64c(v);
+ v >>= 6;
}
+ return s;
+}
+
+/*
+ * DES and MD5 crypt implementations are taken from uclibc.
+ * They were modified to not use static buffers.
+ */
+
+#include "pw_encrypt_des.c"
+#include "pw_encrypt_md5.c"
+#if ENABLE_USE_BB_CRYPT_SHA
+#include "pw_encrypt_sha.c"
+#endif
+
+/* Other advanced crypt ids (TODO?): */
+/* $2$ or $2a$: Blowfish */
+
+static struct const_des_ctx *des_cctx;
+static struct des_ctx *des_ctx;
+
+/* my_crypt returns malloc'ed data */
+static char *my_crypt(const char *key, const char *salt)
+{
+ /* MD5 or SHA? */
+ if (salt[0] == '$' && salt[1] && salt[2] == '$') {
+ if (salt[1] == '1')
+ return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
+#if ENABLE_USE_BB_CRYPT_SHA
+ if (salt[1] == '5' || salt[1] == '6')
+ return sha_crypt((char*)key, (char*)salt);
#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;
+ }
+
+ if (!des_cctx)
+ des_cctx = const_des_init();
+ des_ctx = des_init(des_ctx, des_cctx);
+ return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
+}
+
+/* So far nobody wants to have it public */
+static void my_crypt_cleanup(void)
+{
+ free(des_cctx);
+ free(des_ctx);
+ des_cctx = NULL;
+ des_ctx = NULL;
+}
+
+char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
+{
+ char *encrypted;
+
+ encrypted = my_crypt(clear, salt);
+
+ if (cleanup)
+ my_crypt_cleanup();
+
+ return encrypted;
}
+#else /* if !ENABLE_USE_BB_CRYPT */
+
+char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
+{
+ return xstrdup(crypt(clear, salt));
+}
+
+#endif
diff --git a/release/src/router/busybox/libbb/pw_encrypt_des.c b/release/src/router/busybox/libbb/pw_encrypt_des.c
new file mode 100644
index 00000000..c8e02ddf
--- /dev/null
+++ b/release/src/router/busybox/libbb/pw_encrypt_des.c
@@ -0,0 +1,820 @@
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * All rights reserved.
+ *
+ * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
+ * this file should now *only* export crypt(), in order to make
+ * binaries of libcrypt exportable from the USA
+ *
+ * Adapted for FreeBSD-4.0 by Mark R V Murray
+ * this file should now *only* export crypt_des(), in order to make
+ * a module that can be optionally included in libcrypt.
+ *
+ * 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 author nor the names of other contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ * B. Schneier, Applied Cryptography: protocols, algorithms,
+ * and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author). A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * ARCHITECTURE ASSUMPTIONS:
+ * It is assumed that the 8-byte arrays passed by reference can be
+ * addressed as arrays of uint32_t's (ie. the CPU is not picky about
+ * alignment).
+ */
+
+
+/* Parts busybox doesn't need or had optimized */
+#define USE_PRECOMPUTED_u_sbox 1
+#define USE_REPETITIVE_SPEEDUP 0
+#define USE_ip_mask 0
+#define USE_de_keys 0
+
+
+/* A pile of data */
+static const uint8_t IP[64] = {
+ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+static const uint8_t key_perm[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+static const uint8_t key_shifts[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static const uint8_t comp_perm[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * No E box is used, as it's replaced by some ANDs, shifts, and ORs.
+ */
+#if !USE_PRECOMPUTED_u_sbox
+static const uint8_t sbox[8][64] = {
+ { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
+ },
+ { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
+ },
+ { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
+ },
+ { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
+ },
+ { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
+ },
+ { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
+ },
+ { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
+ },
+ { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
+ }
+};
+#else /* precomputed, with half-bytes packed into one byte */
+static const uint8_t u_sbox[8][32] = {
+ { 0x0e, 0xf4, 0x7d, 0x41, 0xe2, 0x2f, 0xdb, 0x18,
+ 0xa3, 0x6a, 0xc6, 0xbc, 0x95, 0x59, 0x30, 0x87,
+ 0xf4, 0xc1, 0x8e, 0x28, 0x4d, 0x96, 0x12, 0x7b,
+ 0x5f, 0xbc, 0x39, 0xe7, 0xa3, 0x0a, 0x65, 0xd0,
+ },
+ { 0x3f, 0xd1, 0x48, 0x7e, 0xf6, 0x2b, 0x83, 0xe4,
+ 0xc9, 0x07, 0x12, 0xad, 0x6c, 0x90, 0xb5, 0x5a,
+ 0xd0, 0x8e, 0xa7, 0x1b, 0x3a, 0xf4, 0x4d, 0x21,
+ 0xb5, 0x68, 0x7c, 0xc6, 0x09, 0x53, 0xe2, 0x9f,
+ },
+ { 0xda, 0x70, 0x09, 0x9e, 0x36, 0x43, 0x6f, 0xa5,
+ 0x21, 0x8d, 0x5c, 0xe7, 0xcb, 0xb4, 0xf2, 0x18,
+ 0x1d, 0xa6, 0xd4, 0x09, 0x68, 0x9f, 0x83, 0x70,
+ 0x4b, 0xf1, 0xe2, 0x3c, 0xb5, 0x5a, 0x2e, 0xc7,
+ },
+ { 0xd7, 0x8d, 0xbe, 0x53, 0x60, 0xf6, 0x09, 0x3a,
+ 0x41, 0x72, 0x28, 0xc5, 0x1b, 0xac, 0xe4, 0x9f,
+ 0x3a, 0xf6, 0x09, 0x60, 0xac, 0x1b, 0xd7, 0x8d,
+ 0x9f, 0x41, 0x53, 0xbe, 0xc5, 0x72, 0x28, 0xe4,
+ },
+ { 0xe2, 0xbc, 0x24, 0xc1, 0x47, 0x7a, 0xdb, 0x16,
+ 0x58, 0x05, 0xf3, 0xaf, 0x3d, 0x90, 0x8e, 0x69,
+ 0xb4, 0x82, 0xc1, 0x7b, 0x1a, 0xed, 0x27, 0xd8,
+ 0x6f, 0xf9, 0x0c, 0x95, 0xa6, 0x43, 0x50, 0x3e,
+ },
+ { 0xac, 0xf1, 0x4a, 0x2f, 0x79, 0xc2, 0x96, 0x58,
+ 0x60, 0x1d, 0xd3, 0xe4, 0x0e, 0xb7, 0x35, 0x8b,
+ 0x49, 0x3e, 0x2f, 0xc5, 0x92, 0x58, 0xfc, 0xa3,
+ 0xb7, 0xe0, 0x14, 0x7a, 0x61, 0x0d, 0x8b, 0xd6,
+ },
+ { 0xd4, 0x0b, 0xb2, 0x7e, 0x4f, 0x90, 0x18, 0xad,
+ 0xe3, 0x3c, 0x59, 0xc7, 0x25, 0xfa, 0x86, 0x61,
+ 0x61, 0xb4, 0xdb, 0x8d, 0x1c, 0x43, 0xa7, 0x7e,
+ 0x9a, 0x5f, 0x06, 0xf8, 0xe0, 0x25, 0x39, 0xc2,
+ },
+ { 0x1d, 0xf2, 0xd8, 0x84, 0xa6, 0x3f, 0x7b, 0x41,
+ 0xca, 0x59, 0x63, 0xbe, 0x05, 0xe0, 0x9c, 0x27,
+ 0x27, 0x1b, 0xe4, 0x71, 0x49, 0xac, 0x8e, 0xd2,
+ 0xf0, 0xc6, 0x9a, 0x0d, 0x3f, 0x53, 0x65, 0xb8,
+ },
+};
+#endif
+
+static const uint8_t pbox[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+static const uint32_t bits32[32] =
+{
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const uint8_t bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+
+static int
+ascii_to_bin(char ch)
+{
+ if (ch > 'z')
+ return 0;
+ if (ch >= 'a')
+ return (ch - 'a' + 38);
+ if (ch > 'Z')
+ return 0;
+ if (ch >= 'A')
+ return (ch - 'A' + 12);
+ if (ch > '9')
+ return 0;
+ if (ch >= '.')
+ return (ch - '.');
+ return 0;
+}
+
+
+/* Static stuff that stays resident and doesn't change after
+ * being initialized, and therefore doesn't need to be made
+ * reentrant. */
+struct const_des_ctx {
+#if USE_ip_mask
+ uint8_t init_perm[64]; /* referenced 2 times */
+#endif
+ uint8_t final_perm[64]; /* 2 times */
+ uint8_t m_sbox[4][4096]; /* 5 times */
+};
+#define C (*cctx)
+#define init_perm (C.init_perm )
+#define final_perm (C.final_perm)
+#define m_sbox (C.m_sbox )
+
+static struct const_des_ctx*
+const_des_init(void)
+{
+ unsigned i, j, b;
+ struct const_des_ctx *cctx;
+
+#if !USE_PRECOMPUTED_u_sbox
+ uint8_t u_sbox[8][64];
+
+ cctx = xmalloc(sizeof(*cctx));
+
+ /* Invert the S-boxes, reordering the input bits. */
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 64; j++) {
+ b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
+ u_sbox[i][j] = sbox[i][b];
+ }
+ }
+ for (i = 0; i < 8; i++) {
+ fprintf(stderr, "\t{\t");
+ for (j = 0; j < 64; j+=2)
+ fprintf(stderr, " 0x%02x,", u_sbox[i][j] + u_sbox[i][j+1]*16);
+ fprintf(stderr, "\n\t},\n");
+ }
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 64; i++)
+ for (j = 0; j < 64; j++)
+ m_sbox[b][(i << 6) | j] =
+ (uint8_t)((u_sbox[(b << 1)][i] << 4) |
+ u_sbox[(b << 1) + 1][j]);
+#else
+ cctx = xmalloc(sizeof(*cctx));
+
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 64; i++)
+ for (j = 0; j < 64; j++) {
+ uint8_t lo, hi;
+ hi = u_sbox[(b << 1)][i / 2];
+ if (!(i & 1))
+ hi <<= 4;
+ lo = u_sbox[(b << 1) + 1][j / 2];
+ if (j & 1)
+ lo >>= 4;
+ m_sbox[b][(i << 6) | j] = (hi & 0xf0) | (lo & 0x0f);
+ }
+#endif
+
+ /*
+ * Set up the initial & final permutations into a useful form.
+ */
+ for (i = 0; i < 64; i++) {
+ final_perm[i] = IP[i] - 1;
+#if USE_ip_mask
+ init_perm[final_perm[i]] = (uint8_t)i;
+#endif
+ }
+
+ return cctx;
+}
+
+
+struct des_ctx {
+ const struct const_des_ctx *const_ctx;
+ uint32_t saltbits; /* referenced 5 times */
+#if USE_REPETITIVE_SPEEDUP
+ uint32_t old_salt; /* 3 times */
+ uint32_t old_rawkey0, old_rawkey1; /* 3 times each */
+#endif
+ uint8_t un_pbox[32]; /* 2 times */
+ uint8_t inv_comp_perm[56]; /* 3 times */
+ uint8_t inv_key_perm[64]; /* 3 times */
+ uint32_t en_keysl[16], en_keysr[16]; /* 2 times each */
+#if USE_de_keys
+ uint32_t de_keysl[16], de_keysr[16]; /* 2 times each */
+#endif
+#if USE_ip_mask
+ uint32_t ip_maskl[8][256], ip_maskr[8][256]; /* 9 times each */
+#endif
+ uint32_t fp_maskl[8][256], fp_maskr[8][256]; /* 9 times each */
+ uint32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; /* 9 times */
+ uint32_t comp_maskl[8][128], comp_maskr[8][128]; /* 9 times each */
+ uint32_t psbox[4][256]; /* 5 times */
+};
+#define D (*ctx)
+#define const_ctx (D.const_ctx )
+#define saltbits (D.saltbits )
+#define old_salt (D.old_salt )
+#define old_rawkey0 (D.old_rawkey0 )
+#define old_rawkey1 (D.old_rawkey1 )
+#define un_pbox (D.un_pbox )
+#define inv_comp_perm (D.inv_comp_perm )
+#define inv_key_perm (D.inv_key_perm )
+#define en_keysl (D.en_keysl )
+#define en_keysr (D.en_keysr )
+#define de_keysl (D.de_keysl )
+#define de_keysr (D.de_keysr )
+#define ip_maskl (D.ip_maskl )
+#define ip_maskr (D.ip_maskr )
+#define fp_maskl (D.fp_maskl )
+#define fp_maskr (D.fp_maskr )
+#define key_perm_maskl (D.key_perm_maskl )
+#define key_perm_maskr (D.key_perm_maskr )
+#define comp_maskl (D.comp_maskl )
+#define comp_maskr (D.comp_maskr )
+#define psbox (D.psbox )
+
+static struct des_ctx*
+des_init(struct des_ctx *ctx, const struct const_des_ctx *cctx)
+{
+ int i, j, b, k, inbit, obit;
+ uint32_t p;
+ const uint32_t *bits28, *bits24;
+
+ if (!ctx)
+ ctx = xmalloc(sizeof(*ctx));
+ const_ctx = cctx;
+
+#if USE_REPETITIVE_SPEEDUP
+ old_rawkey0 = old_rawkey1 = 0;
+ old_salt = 0;
+#endif
+ saltbits = 0;
+ bits28 = bits32 + 4;
+ bits24 = bits28 + 4;
+
+ /* Initialise the inverted key permutation. */
+ for (i = 0; i < 64; i++) {
+ inv_key_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key permutation and initialise the inverted key
+ * compression permutation.
+ */
+ for (i = 0; i < 56; i++) {
+ inv_key_perm[key_perm[i] - 1] = (uint8_t)i;
+ inv_comp_perm[i] = 255;
+ }
+
+ /* Invert the key compression permutation. */
+ for (i = 0; i < 48; i++) {
+ inv_comp_perm[comp_perm[i] - 1] = (uint8_t)i;
+ }
+
+ /*
+ * Set up the OR-mask arrays for the initial and final permutations,
+ * and for the key initial and compression permutations.
+ */
+ for (k = 0; k < 8; k++) {
+ uint32_t il, ir;
+ uint32_t fl, fr;
+ for (i = 0; i < 256; i++) {
+#if USE_ip_mask
+ il = 0;
+ ir = 0;
+#endif
+ fl = 0;
+ fr = 0;
+ for (j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j]) {
+#if USE_ip_mask
+ obit = init_perm[inbit];
+ if (obit < 32)
+ il |= bits32[obit];
+ else
+ ir |= bits32[obit - 32];
+#endif
+ obit = final_perm[inbit];
+ if (obit < 32)
+ fl |= bits32[obit];
+ else
+ fr |= bits32[obit - 32];
+ }
+ }
+#if USE_ip_mask
+ ip_maskl[k][i] = il;
+ ip_maskr[k][i] = ir;
+#endif
+ fp_maskl[k][i] = fl;
+ fp_maskr[k][i] = fr;
+ }
+ for (i = 0; i < 128; i++) {
+ il = 0;
+ ir = 0;
+ for (j = 0; j < 7; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j + 1]) {
+ obit = inv_key_perm[inbit];
+ if (obit == 255)
+ continue;
+ if (obit < 28)
+ il |= bits28[obit];
+ else
+ ir |= bits28[obit - 28];
+ }
+ }
+ key_perm_maskl[k][i] = il;
+ key_perm_maskr[k][i] = ir;
+ il = 0;
+ ir = 0;
+ for (j = 0; j < 7; j++) {
+ inbit = 7 * k + j;
+ if (i & bits8[j + 1]) {
+ obit = inv_comp_perm[inbit];
+ if (obit == 255)
+ continue;
+ if (obit < 24)
+ il |= bits24[obit];
+ else
+ ir |= bits24[obit - 24];
+ }
+ }
+ comp_maskl[k][i] = il;
+ comp_maskr[k][i] = ir;
+ }
+ }
+
+ /*
+ * Invert the P-box permutation, and convert into OR-masks for
+ * handling the output of the S-box arrays setup above.
+ */
+ for (i = 0; i < 32; i++)
+ un_pbox[pbox[i] - 1] = (uint8_t)i;
+
+ for (b = 0; b < 4; b++) {
+ for (i = 0; i < 256; i++) {
+ p = 0;
+ for (j = 0; j < 8; j++) {
+ if (i & bits8[j])
+ p |= bits32[un_pbox[8 * b + j]];
+ }
+ psbox[b][i] = p;
+ }
+ }
+
+ return ctx;
+}
+
+
+static void
+setup_salt(struct des_ctx *ctx, uint32_t salt)
+{
+ uint32_t obit, saltbit;
+ int i;
+
+#if USE_REPETITIVE_SPEEDUP
+ if (salt == old_salt)
+ return;
+ old_salt = salt;
+#endif
+
+ saltbits = 0;
+ saltbit = 1;
+ obit = 0x800000;
+ for (i = 0; i < 24; i++) {
+ if (salt & saltbit)
+ saltbits |= obit;
+ saltbit <<= 1;
+ obit >>= 1;
+ }
+}
+
+static void
+des_setkey(struct des_ctx *ctx, const char *key)
+{
+ uint32_t k0, k1, rawkey0, rawkey1;
+ int shifts, round;
+
+ rawkey0 = ntohl(*(const uint32_t *) key);
+ rawkey1 = ntohl(*(const uint32_t *) (key + 4));
+
+#if USE_REPETITIVE_SPEEDUP
+ if ((rawkey0 | rawkey1)
+ && rawkey0 == old_rawkey0
+ && rawkey1 == old_rawkey1
+ ) {
+ /*
+ * Already setup for this key.
+ * This optimisation fails on a zero key (which is weak and
+ * has bad parity anyway) in order to simplify the starting
+ * conditions.
+ */
+ return;
+ }
+ old_rawkey0 = rawkey0;
+ old_rawkey1 = rawkey1;
+#endif
+
+ /*
+ * Do key permutation and split into two 28-bit subkeys.
+ */
+ k0 = key_perm_maskl[0][rawkey0 >> 25]
+ | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskl[4][rawkey1 >> 25]
+ | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+ k1 = key_perm_maskr[0][rawkey0 >> 25]
+ | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskr[4][rawkey1 >> 25]
+ | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+ /*
+ * Rotate subkeys and do compression permutation.
+ */
+ shifts = 0;
+ for (round = 0; round < 16; round++) {
+ uint32_t t0, t1;
+
+ shifts += key_shifts[round];
+
+ t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+ t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+#if USE_de_keys
+ de_keysl[15 - round] =
+#endif
+ en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+ | comp_maskl[1][(t0 >> 14) & 0x7f]
+ | comp_maskl[2][(t0 >> 7) & 0x7f]
+ | comp_maskl[3][t0 & 0x7f]
+ | comp_maskl[4][(t1 >> 21) & 0x7f]
+ | comp_maskl[5][(t1 >> 14) & 0x7f]
+ | comp_maskl[6][(t1 >> 7) & 0x7f]
+ | comp_maskl[7][t1 & 0x7f];
+
+#if USE_de_keys
+ de_keysr[15 - round] =
+#endif
+ en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]
+ | comp_maskr[1][(t0 >> 14) & 0x7f]
+ | comp_maskr[2][(t0 >> 7) & 0x7f]
+ | comp_maskr[3][t0 & 0x7f]
+ | comp_maskr[4][(t1 >> 21) & 0x7f]
+ | comp_maskr[5][(t1 >> 14) & 0x7f]
+ | comp_maskr[6][(t1 >> 7) & 0x7f]
+ | comp_maskr[7][t1 & 0x7f];
+ }
+}
+
+
+static void
+do_des(struct des_ctx *ctx, /*uint32_t l_in, uint32_t r_in,*/ uint32_t *l_out, uint32_t *r_out, int count)
+{
+ const struct const_des_ctx *cctx = const_ctx;
+ /*
+ * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+ */
+ uint32_t l, r, *kl, *kr;
+ uint32_t f = f; /* silence gcc */
+ uint32_t r48l, r48r;
+ int round;
+
+ /* Do initial permutation (IP). */
+#if USE_ip_mask
+ uint32_t l_in = 0;
+ uint32_t r_in = 0;
+ l = ip_maskl[0][l_in >> 24]
+ | ip_maskl[1][(l_in >> 16) & 0xff]
+ | ip_maskl[2][(l_in >> 8) & 0xff]
+ | ip_maskl[3][l_in & 0xff]
+ | ip_maskl[4][r_in >> 24]
+ | ip_maskl[5][(r_in >> 16) & 0xff]
+ | ip_maskl[6][(r_in >> 8) & 0xff]
+ | ip_maskl[7][r_in & 0xff];
+ r = ip_maskr[0][l_in >> 24]
+ | ip_maskr[1][(l_in >> 16) & 0xff]
+ | ip_maskr[2][(l_in >> 8) & 0xff]
+ | ip_maskr[3][l_in & 0xff]
+ | ip_maskr[4][r_in >> 24]
+ | ip_maskr[5][(r_in >> 16) & 0xff]
+ | ip_maskr[6][(r_in >> 8) & 0xff]
+ | ip_maskr[7][r_in & 0xff];
+#elif 0 /* -65 bytes (using the fact that l_in == r_in == 0) */
+ l = r = 0;
+ for (round = 0; round < 8; round++) {
+ l |= ip_maskl[round][0];
+ r |= ip_maskr[round][0];
+ }
+ bb_error_msg("l:%x r:%x", l, r); /* reports 0, 0 always! */
+#else /* using the fact that ip_maskX[] is constant (written to by des_init) */
+ l = r = 0;
+#endif
+
+ do {
+ /* Do each round. */
+ kl = en_keysl;
+ kr = en_keysr;
+ round = 16;
+ do {
+ /* Expand R to 48 bits (simulate the E-box). */
+ r48l = ((r & 0x00000001) << 23)
+ | ((r & 0xf8000000) >> 9)
+ | ((r & 0x1f800000) >> 11)
+ | ((r & 0x01f80000) >> 13)
+ | ((r & 0x001f8000) >> 15);
+
+ r48r = ((r & 0x0001f800) << 7)
+ | ((r & 0x00001f80) << 5)
+ | ((r & 0x000001f8) << 3)
+ | ((r & 0x0000001f) << 1)
+ | ((r & 0x80000000) >> 31);
+ /*
+ * Do salting for crypt() and friends, and
+ * XOR with the permuted key.
+ */
+ f = (r48l ^ r48r) & saltbits;
+ r48l ^= f ^ *kl++;
+ r48r ^= f ^ *kr++;
+ /*
+ * Do sbox lookups (which shrink it back to 32 bits)
+ * and do the pbox permutation at the same time.
+ */
+ f = psbox[0][m_sbox[0][r48l >> 12]]
+ | psbox[1][m_sbox[1][r48l & 0xfff]]
+ | psbox[2][m_sbox[2][r48r >> 12]]
+ | psbox[3][m_sbox[3][r48r & 0xfff]];
+ /* Now that we've permuted things, complete f(). */
+ f ^= l;
+ l = r;
+ r = f;
+ } while (--round);
+ r = l;
+ l = f;
+ } while (--count);
+
+ /* Do final permutation (inverse of IP). */
+ *l_out = fp_maskl[0][l >> 24]
+ | fp_maskl[1][(l >> 16) & 0xff]
+ | fp_maskl[2][(l >> 8) & 0xff]
+ | fp_maskl[3][l & 0xff]
+ | fp_maskl[4][r >> 24]
+ | fp_maskl[5][(r >> 16) & 0xff]
+ | fp_maskl[6][(r >> 8) & 0xff]
+ | fp_maskl[7][r & 0xff];
+ *r_out = fp_maskr[0][l >> 24]
+ | fp_maskr[1][(l >> 16) & 0xff]
+ | fp_maskr[2][(l >> 8) & 0xff]
+ | fp_maskr[3][l & 0xff]
+ | fp_maskr[4][r >> 24]
+ | fp_maskr[5][(r >> 16) & 0xff]
+ | fp_maskr[6][(r >> 8) & 0xff]
+ | fp_maskr[7][r & 0xff];
+}
+
+#define DES_OUT_BUFSIZE 21
+
+static void
+to64_msb_first(char *s, unsigned v)
+{
+#if 0
+ *s++ = ascii64[(v >> 18) & 0x3f]; /* bits 23..18 */
+ *s++ = ascii64[(v >> 12) & 0x3f]; /* bits 17..12 */
+ *s++ = ascii64[(v >> 6) & 0x3f]; /* bits 11..6 */
+ *s = ascii64[v & 0x3f]; /* bits 5..0 */
+#endif
+ *s++ = i64c(v >> 18); /* bits 23..18 */
+ *s++ = i64c(v >> 12); /* bits 17..12 */
+ *s++ = i64c(v >> 6); /* bits 11..6 */
+ *s = i64c(v); /* bits 5..0 */
+}
+
+static char *
+NOINLINE
+des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
+ const unsigned char *key, const unsigned char *setting)
+{
+ uint32_t salt, r0, r1, keybuf[2];
+ uint8_t *q;
+
+ /*
+ * Copy the key, shifting each character up by one bit
+ * and padding with zeros.
+ */
+ q = (uint8_t *)keybuf;
+ while (q - (uint8_t *)keybuf != 8) {
+ *q = *key << 1;
+ if (*q)
+ key++;
+ q++;
+ }
+ des_setkey(ctx, (char *)keybuf);
+
+ /*
+ * setting - 2 bytes of salt
+ * key - up to 8 characters
+ */
+ salt = (ascii_to_bin(setting[1]) << 6)
+ | ascii_to_bin(setting[0]);
+
+ output[0] = setting[0];
+ /*
+ * If the encrypted password that the salt was extracted from
+ * is only 1 character long, the salt will be corrupted. We
+ * need to ensure that the output string doesn't have an extra
+ * NUL in it!
+ */
+ output[1] = setting[1] ? setting[1] : output[0];
+
+ setup_salt(ctx, salt);
+ /* Do it. */
+ do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */);
+
+ /* Now encode the result. */
+#if 0
+{
+ uint32_t l = (r0 >> 8);
+ q = (uint8_t *)output + 2;
+ *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 31..26 of r0 */
+ *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 25..20 of r0 */
+ *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 19..14 of r0 */
+ *q++ = ascii64[l & 0x3f]; /* bits 13..8 of r0 */
+ l = ((r0 << 16) | (r1 >> 16));
+ *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 7..2 of r0 */
+ *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 1..2 of r0 and 31..28 of r1 */
+ *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 27..22 of r1 */
+ *q++ = ascii64[l & 0x3f]; /* bits 21..16 of r1 */
+ l = r1 << 2;
+ *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 15..10 of r1 */
+ *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 9..4 of r1 */
+ *q++ = ascii64[l & 0x3f]; /* bits 3..0 of r1 + 00 */
+ *q = 0;
+}
+#else
+ /* Each call takes low-order 24 bits and stores 4 chars */
+ /* bits 31..8 of r0 */
+ to64_msb_first(output + 2, (r0 >> 8));
+ /* bits 7..0 of r0 and 31..16 of r1 */
+ to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16));
+ /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */
+ to64_msb_first(output + 10, (r1 << 8));
+ /* extra zero byte is encoded as '.', fixing it */
+ output[13] = '\0';
+#endif
+
+ return output;
+}
+
+#undef USE_PRECOMPUTED_u_sbox
+#undef USE_REPETITIVE_SPEEDUP
+#undef USE_ip_mask
+#undef USE_de_keys
+
+#undef C
+#undef init_perm
+#undef final_perm
+#undef m_sbox
+#undef D
+#undef const_ctx
+#undef saltbits
+#undef old_salt
+#undef old_rawkey0
+#undef old_rawkey1
+#undef un_pbox
+#undef inv_comp_perm
+#undef inv_key_perm
+#undef en_keysl
+#undef en_keysr
+#undef de_keysl
+#undef de_keysr
+#undef ip_maskl
+#undef ip_maskr
+#undef fp_maskl
+#undef fp_maskr
+#undef key_perm_maskl
+#undef key_perm_maskr
+#undef comp_maskl
+#undef comp_maskr
+#undef psbox
diff --git a/release/src/router/busybox/libbb/pw_encrypt_md5.c b/release/src/router/busybox/libbb/pw_encrypt_md5.c
new file mode 100644
index 00000000..58964b56
--- /dev/null
+++ b/release/src/router/busybox/libbb/pw_encrypt_md5.c
@@ -0,0 +1,161 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
+ *
+ * This code is the same as the code published by RSA Inc. It has been
+ * edited for clarity and style only.
+ *
+ * ----------------------------------------------------------------------------
+ * The md5_crypt() function was taken from freeBSD's libcrypt and contains
+ * this license:
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ *
+ * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
+ *
+ * ----------------------------------------------------------------------------
+ * On April 19th, 2001 md5_crypt() was modified to make it reentrant
+ * by Erik Andersen <andersen@uclibc.org>
+ *
+ *
+ * June 28, 2001 Manuel Novoa III
+ *
+ * "Un-inlined" code using loops and static const tables in order to
+ * reduce generated code size (on i386 from approx 4k to approx 2.5k).
+ *
+ * June 29, 2001 Manuel Novoa III
+ *
+ * Completely removed static PADDING array.
+ *
+ * Reintroduced the loop unrolling in MD5_Transform and added the
+ * MD5_SIZE_OVER_SPEED option for configurability. Define below as:
+ * 0 fully unrolled loops
+ * 1 partially unrolled (4 ops per loop)
+ * 2 no unrolling -- introduces the need to swap 4 variables (slow)
+ * 3 no unrolling and all 4 loops merged into one with switch
+ * in each loop (glacial)
+ * On i386, sizes are roughly (-Os -fno-builtin):
+ * 0: 3k 1: 2.5k 2: 2.2k 3: 2k
+ *
+ * Since SuSv3 does not require crypt_r, modified again August 7, 2002
+ * by Erik Andersen to remove reentrance stuff...
+ */
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+#define MD5_OUT_BUFSIZE 36
+static char *
+NOINLINE
+md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt)
+{
+ char *p;
+ unsigned char final[17]; /* final[16] exists only to aid in looping */
+ int sl, pl, i, pw_len;
+ md5_ctx_t ctx, ctx1;
+
+ /* NB: in busybox, "$1$" in salt is always present */
+
+ /* Refine the Salt first */
+
+ /* Get the length of the salt including "$1$" */
+ sl = 3;
+ while (salt[sl] && salt[sl] != '$' && sl < (3 + 8))
+ sl++;
+
+ /* Hash. the password first, since that is what is most unknown */
+ md5_begin(&ctx);
+ pw_len = strlen((char*)pw);
+ md5_hash(pw, pw_len, &ctx);
+
+ /* Then the salt including "$1$" */
+ md5_hash(salt, sl, &ctx);
+
+ /* Copy salt to result; skip "$1$" */
+ memcpy(result, salt, sl);
+ result[sl] = '$';
+ salt += 3;
+ sl -= 3;
+
+ /* Then just as many characters of the MD5(pw, salt, pw) */
+ md5_begin(&ctx1);
+ md5_hash(pw, pw_len, &ctx1);
+ md5_hash(salt, sl, &ctx1);
+ md5_hash(pw, pw_len, &ctx1);
+ md5_end(final, &ctx1);
+ for (pl = pw_len; pl > 0; pl -= 16)
+ md5_hash(final, pl > 16 ? 16 : pl, &ctx);
+
+ /* Then something really weird... */
+ memset(final, 0, sizeof(final));
+ for (i = pw_len; i; i >>= 1) {
+ md5_hash(((i & 1) ? final : (const unsigned char *) pw), 1, &ctx);
+ }
+ md5_end(final, &ctx);
+
+ /* And now, just to make sure things don't run too fast.
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for (i = 0; i < 1000; i++) {
+ md5_begin(&ctx1);
+ if (i & 1)
+ md5_hash(pw, pw_len, &ctx1);
+ else
+ md5_hash(final, 16, &ctx1);
+
+ if (i % 3)
+ md5_hash(salt, sl, &ctx1);
+
+ if (i % 7)
+ md5_hash(pw, pw_len, &ctx1);
+
+ if (i & 1)
+ md5_hash(final, 16, &ctx1);
+ else
+ md5_hash(pw, pw_len, &ctx1);
+ md5_end(final, &ctx1);
+ }
+
+ p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */
+
+ /* Add 5*4+2 = 22 bytes of hash, + NUL byte. */
+ final[16] = final[5];
+ for (i = 0; i < 5; i++) {
+ unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
+ p = to64(p, l, 4);
+ }
+ p = to64(p, final[11], 2);
+ *p = '\0';
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof(final));
+
+ return result;
+}
diff --git a/release/src/router/busybox/libbb/pw_encrypt_sha.c b/release/src/router/busybox/libbb/pw_encrypt_sha.c
new file mode 100644
index 00000000..070e0d44
--- /dev/null
+++ b/release/src/router/busybox/libbb/pw_encrypt_sha.c
@@ -0,0 +1,286 @@
+/* SHA256 and SHA512-based Unix crypt implementation.
+ * Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>.
+ */
+
+/* Prefix for optional rounds specification. */
+static const char str_rounds[] = "rounds=%u$";
+
+/* Maximum salt string length. */
+#define SALT_LEN_MAX 16
+/* Default number of rounds if not explicitly specified. */
+#define ROUNDS_DEFAULT 5000
+/* Minimum number of rounds. */
+#define ROUNDS_MIN 1000
+/* Maximum number of rounds. */
+#define ROUNDS_MAX 999999999
+
+static char *
+NOINLINE
+sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
+{
+ void (*sha_begin)(void *ctx) FAST_FUNC;
+ void (*sha_hash)(const void *buffer, size_t len, void *ctx) FAST_FUNC;
+ void (*sha_end)(void *resbuf, void *ctx) FAST_FUNC;
+ int _32or64;
+
+ char *result, *resptr;
+
+ /* btw, sha256 needs [32] and uint32_t only */
+ struct {
+ unsigned char alt_result[64];
+ unsigned char temp_result[64];
+ union {
+ sha256_ctx_t x;
+ sha512_ctx_t y;
+ } ctx;
+ union {
+ sha256_ctx_t x;
+ sha512_ctx_t y;
+ } alt_ctx;
+ } L __attribute__((__aligned__(__alignof__(uint64_t))));
+#define alt_result (L.alt_result )
+#define temp_result (L.temp_result)
+#define ctx (L.ctx )
+#define alt_ctx (L.alt_ctx )
+ unsigned salt_len;
+ unsigned key_len;
+ unsigned cnt;
+ unsigned rounds;
+ char *cp;
+ char is_sha512;
+
+ /* Analyze salt, construct already known part of result */
+ cnt = strlen(salt_data) + 1 + 43 + 1;
+ is_sha512 = salt_data[1];
+ if (is_sha512 == '6')
+ cnt += 43;
+ result = resptr = xzalloc(cnt); /* will provide NUL terminator */
+ *resptr++ = '$';
+ *resptr++ = is_sha512;
+ *resptr++ = '$';
+ rounds = ROUNDS_DEFAULT;
+ salt_data += 3;
+ if (strncmp(salt_data, str_rounds, 7) == 0) {
+ /* 7 == strlen("rounds=") */
+ char *endp;
+ cnt = bb_strtou(salt_data + 7, &endp, 10);
+ if (*endp == '$') {
+ salt_data = endp + 1;
+ rounds = cnt;
+ if (rounds < ROUNDS_MIN)
+ rounds = ROUNDS_MIN;
+ if (rounds > ROUNDS_MAX)
+ rounds = ROUNDS_MAX;
+ /* add "rounds=NNNNN$" to result */
+ resptr += sprintf(resptr, str_rounds, rounds);
+ }
+ }
+ salt_len = strchrnul(salt_data, '$') - salt_data;
+ if (salt_len > SALT_LEN_MAX)
+ salt_len = SALT_LEN_MAX;
+ /* xstrdup assures suitable alignment; also we will use it
+ as a scratch space later. */
+ salt_data = xstrndup(salt_data, salt_len);
+ /* add "salt$" to result */
+ strcpy(resptr, salt_data);
+ resptr += salt_len;
+ *resptr++ = '$';
+ /* key data doesn't need much processing */
+ key_len = strlen(key_data);
+ key_data = xstrdup(key_data);
+
+ /* Which flavor of SHAnnn ops to use? */
+ sha_begin = (void*)sha256_begin;
+ sha_hash = (void*)sha256_hash;
+ sha_end = (void*)sha256_end;
+ _32or64 = 32;
+ if (is_sha512 == '6') {
+ sha_begin = (void*)sha512_begin;
+ sha_hash = (void*)sha512_hash;
+ sha_end = (void*)sha512_end;
+ _32or64 = 64;
+ }
+
+ /* Add KEY, SALT. */
+ sha_begin(&ctx);
+ sha_hash(key_data, key_len, &ctx);
+ sha_hash(salt_data, salt_len, &ctx);
+
+ /* Compute alternate SHA sum with input KEY, SALT, and KEY.
+ The final result will be added to the first context. */
+ sha_begin(&alt_ctx);
+ sha_hash(key_data, key_len, &alt_ctx);
+ sha_hash(salt_data, salt_len, &alt_ctx);
+ sha_hash(key_data, key_len, &alt_ctx);
+ sha_end(alt_result, &alt_ctx);
+
+ /* Add result of this to the other context. */
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > _32or64; cnt -= _32or64)
+ sha_hash(alt_result, _32or64, &ctx);
+ sha_hash(alt_result, cnt, &ctx);
+
+ /* Take the binary representation of the length of the key and for every
+ 1 add the alternate sum, for every 0 the key. */
+ for (cnt = key_len; cnt != 0; cnt >>= 1)
+ if ((cnt & 1) != 0)
+ sha_hash(alt_result, _32or64, &ctx);
+ else
+ sha_hash(key_data, key_len, &ctx);
+
+ /* Create intermediate result. */
+ sha_end(alt_result, &ctx);
+
+ /* Start computation of P byte sequence. */
+ /* For every character in the password add the entire password. */
+ sha_begin(&alt_ctx);
+ for (cnt = 0; cnt < key_len; ++cnt)
+ sha_hash(key_data, key_len, &alt_ctx);
+ sha_end(temp_result, &alt_ctx);
+
+ /* NB: past this point, raw key_data is not used anymore */
+
+ /* Create byte sequence P. */
+#define p_bytes key_data /* reuse the buffer as it is of the key_len size */
+ cp = p_bytes; /* was: ... = alloca(key_len); */
+ for (cnt = key_len; cnt >= _32or64; cnt -= _32or64) {
+ cp = memcpy(cp, temp_result, _32or64);
+ cp += _32or64;
+ }
+ memcpy(cp, temp_result, cnt);
+
+ /* Start computation of S byte sequence. */
+ /* For every character in the password add the entire password. */
+ sha_begin(&alt_ctx);
+ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
+ sha_hash(salt_data, salt_len, &alt_ctx);
+ sha_end(temp_result, &alt_ctx);
+
+ /* NB: past this point, raw salt_data is not used anymore */
+
+ /* Create byte sequence S. */
+#define s_bytes salt_data /* reuse the buffer as it is of the salt_len size */
+ cp = s_bytes; /* was: ... = alloca(salt_len); */
+ for (cnt = salt_len; cnt >= _32or64; cnt -= _32or64) {
+ cp = memcpy(cp, temp_result, _32or64);
+ cp += _32or64;
+ }
+ memcpy(cp, temp_result, cnt);
+
+ /* Repeatedly run the collected hash value through SHA to burn
+ CPU cycles. */
+ for (cnt = 0; cnt < rounds; ++cnt) {
+ sha_begin(&ctx);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ sha_hash(p_bytes, key_len, &ctx);
+ else
+ sha_hash(alt_result, _32or64, &ctx);
+ /* Add salt for numbers not divisible by 3. */
+ if (cnt % 3 != 0)
+ sha_hash(s_bytes, salt_len, &ctx);
+ /* Add key for numbers not divisible by 7. */
+ if (cnt % 7 != 0)
+ sha_hash(p_bytes, key_len, &ctx);
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ sha_hash(alt_result, _32or64, &ctx);
+ else
+ sha_hash(p_bytes, key_len, &ctx);
+
+ sha_end(alt_result, &ctx);
+ }
+
+ /* Append encrypted password to result buffer */
+//TODO: replace with something like
+// bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64);
+#define b64_from_24bit(B2, B1, B0, N) \
+do { \
+ unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \
+ resptr = to64(resptr, w, N); \
+} while (0)
+ if (is_sha512 == '5') {
+ unsigned i = 0;
+ while (1) {
+ unsigned j = i + 10;
+ unsigned k = i + 20;
+ if (j >= 30) j -= 30;
+ if (k >= 30) k -= 30;
+ b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4);
+ if (k == 29)
+ break;
+ i = k + 1;
+ }
+ b64_from_24bit(0, alt_result[31], alt_result[30], 3);
+ /* was:
+ b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4);
+ b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4);
+ b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4);
+ b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4);
+ b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4);
+ b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4);
+ b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4);
+ b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4);
+ b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4);
+ b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4);
+ b64_from_24bit(0, alt_result[31], alt_result[30], 3);
+ */
+ } else {
+ unsigned i = 0;
+ while (1) {
+ unsigned j = i + 21;
+ unsigned k = i + 42;
+ if (j >= 63) j -= 63;
+ if (k >= 63) k -= 63;
+ b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4);
+ if (j == 20)
+ break;
+ i = j + 1;
+ }
+ b64_from_24bit(0, 0, alt_result[63], 2);
+ /* was:
+ b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4);
+ b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4);
+ b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4);
+ b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4);
+ b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4);
+ b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4);
+ b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4);
+ b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4);
+ b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4);
+ b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4);
+ b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4);
+ b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4);
+ b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4);
+ b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4);
+ b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4);
+ b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4);
+ b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4);
+ b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4);
+ b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4);
+ b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4);
+ b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4);
+ b64_from_24bit(0, 0, alt_result[63], 2);
+ */
+ }
+ /* *resptr = '\0'; - xzalloc did it */
+#undef b64_from_24bit
+
+ /* Clear the buffer for the intermediate result so that people
+ attaching to processes or reading core dumps cannot get any
+ information. */
+ memset(&L, 0, sizeof(L)); /* [alt]_ctx and XXX_result buffers */
+ memset(key_data, 0, key_len); /* also p_bytes */
+ memset(salt_data, 0, salt_len); /* also s_bytes */
+ free(key_data);
+ free(salt_data);
+#undef p_bytes
+#undef s_bytes
+
+ return result;
+#undef alt_result
+#undef temp_result
+#undef ctx
+#undef alt_ctx
+}
diff --git a/release/src/router/busybox/libbb/pwd2spwd.c b/release/src/router/busybox/libbb/pwd2spwd.c
deleted file mode 100644
index 3dd625b2..00000000
--- a/release/src/router/busybox/libbb/pwd2spwd.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* 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/release/src/router/busybox/libbb/qmodule.c b/release/src/router/busybox/libbb/qmodule.c
deleted file mode 100644
index fd14d10f..00000000
--- a/release/src/router/busybox/libbb/qmodule.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- 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/release/src/router/busybox/libbb/read.c b/release/src/router/busybox/libbb/read.c
new file mode 100644
index 00000000..4654f737
--- /dev/null
+++ b/release/src/router/busybox/libbb/read.c
@@ -0,0 +1,394 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \
+ || ENABLE_FEATURE_SEAMLESS_BZ2 \
+ || ENABLE_FEATURE_SEAMLESS_GZ \
+ /* || ENABLE_FEATURE_SEAMLESS_Z */ \
+)
+
+#if ZIPPED
+#include "unarchive.h"
+#endif
+
+ssize_t FAST_FUNC 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;
+}
+
+/* Suppose that you are a shell. You start child processes.
+ * They work and eventually exit. You want to get user input.
+ * You read stdin. But what happens if last child switched
+ * its stdin into O_NONBLOCK mode?
+ *
+ * *** SURPRISE! It will affect the parent too! ***
+ * *** BIG SURPRISE! It stays even after child exits! ***
+ *
+ * This is a design bug in UNIX API.
+ * fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
+ * will set nonblocking mode not only on _your_ stdin, but
+ * also on stdin of your parent, etc.
+ *
+ * In general,
+ * fd2 = dup(fd1);
+ * fcntl(fd2, F_SETFL, fcntl(fd2, F_GETFL, 0) | O_NONBLOCK);
+ * sets both fd1 and fd2 to O_NONBLOCK. This includes cases
+ * where duping is done implicitly by fork() etc.
+ *
+ * We need
+ * fcntl(fd2, F_SETFD, fcntl(fd2, F_GETFD, 0) | O_NONBLOCK);
+ * (note SETFD, not SETFL!) but such thing doesn't exist.
+ *
+ * Alternatively, we need nonblocking_read(fd, ...) which doesn't
+ * require O_NONBLOCK dance at all. Actually, it exists:
+ * n = recv(fd, buf, len, MSG_DONTWAIT);
+ * "MSG_DONTWAIT:
+ * Enables non-blocking operation; if the operation
+ * would block, EAGAIN is returned."
+ * but recv() works only for sockets!
+ *
+ * So far I don't see any good solution, I can only propose
+ * that affected readers should be careful and use this routine,
+ * which detects EAGAIN and uses poll() to wait on the fd.
+ * Thankfully, poll() doesn't care about O_NONBLOCK flag.
+ */
+ssize_t FAST_FUNC nonblock_safe_read(int fd, void *buf, size_t count)
+{
+ struct pollfd pfd[1];
+ ssize_t n;
+
+ while (1) {
+ n = safe_read(fd, buf, count);
+ if (n >= 0 || errno != EAGAIN)
+ return n;
+ /* fd is in O_NONBLOCK mode. Wait using poll and repeat */
+ pfd[0].fd = fd;
+ pfd[0].events = POLLIN;
+ safe_poll(pfd, 1, -1);
+ }
+}
+
+/*
+ * 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 FAST_FUNC full_read(int fd, void *buf, size_t len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len) {
+ cc = safe_read(fd, buf, len);
+
+ if (cc < 0) {
+ if (total) {
+ /* we already have some! */
+ /* user can do another read to know the error code */
+ return total;
+ }
+ return cc; /* read() returns -1 on failure. */
+ }
+ if (cc == 0)
+ break;
+ buf = ((char *)buf) + cc;
+ total += cc;
+ len -= cc;
+ }
+
+ return total;
+}
+
+/* Die with an error message if we can't read the entire buffer. */
+void FAST_FUNC xread(int fd, void *buf, size_t count)
+{
+ if (count) {
+ ssize_t size = full_read(fd, buf, count);
+ if ((size_t)size != count)
+ bb_error_msg_and_die("short read");
+ }
+}
+
+/* Die with an error message if we can't read one character. */
+unsigned char FAST_FUNC xread_char(int fd)
+{
+ char tmp;
+ xread(fd, &tmp, 1);
+ return tmp;
+}
+
+// Reads one line a-la fgets (but doesn't save terminating '\n').
+// Reads byte-by-byte. Useful when it is important to not read ahead.
+// Bytes are appended to pfx (which must be malloced, or NULL).
+char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p)
+{
+ char *p;
+ size_t sz = buf ? strlen(buf) : 0;
+ size_t maxsz = maxsz_p ? *maxsz_p : (INT_MAX - 4095);
+
+ goto jump_in;
+ while (sz < maxsz) {
+ if ((size_t)(p - buf) == sz) {
+ jump_in:
+ buf = xrealloc(buf, sz + 128);
+ p = buf + sz;
+ sz += 128;
+ }
+ /* nonblock_safe_read() because we are used by e.g. shells */
+ if (nonblock_safe_read(fd, p, 1) != 1) { /* EOF/error */
+ if (p == buf) { /* we read nothing */
+ free(buf);
+ return NULL;
+ }
+ break;
+ }
+ if (*p == '\n')
+ break;
+ p++;
+ }
+ *p = '\0';
+ if (maxsz_p)
+ *maxsz_p = p - buf;
+ p++;
+ return xrealloc(buf, p - buf);
+}
+
+ssize_t FAST_FUNC read_close(int fd, void *buf, size_t size)
+{
+ /*int e;*/
+ size = full_read(fd, buf, size);
+ /*e = errno;*/
+ close(fd);
+ /*errno = e;*/
+ return size;
+}
+
+ssize_t FAST_FUNC open_read_close(const char *filename, void *buf, size_t size)
+{
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return fd;
+ return read_close(fd, buf, size);
+}
+
+
+// Read (potentially big) files in one go. File size is estimated
+// by stat. Extra '\0' byte is appended.
+void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
+{
+ char *buf;
+ size_t size, rd_size, total;
+ size_t to_read;
+ struct stat st;
+
+ to_read = maxsz_p ? *maxsz_p : (INT_MAX - 4095); /* max to read */
+
+ /* Estimate file size */
+ st.st_size = 0; /* in case fstat fails, assume 0 */
+ fstat(fd, &st);
+ /* /proc/N/stat files report st_size 0 */
+ /* In order to make such files readable, we add small const */
+ size = (st.st_size | 0x3ff) + 1;
+
+ total = 0;
+ buf = NULL;
+ while (1) {
+ if (to_read < size)
+ size = to_read;
+ buf = xrealloc(buf, total + size + 1);
+ rd_size = full_read(fd, buf + total, size);
+ if ((ssize_t)rd_size == (ssize_t)(-1)) { /* error */
+ free(buf);
+ return NULL;
+ }
+ total += rd_size;
+ if (rd_size < size) /* EOF */
+ break;
+ if (to_read <= rd_size)
+ break;
+ to_read -= rd_size;
+ /* grow by 1/8, but in [1k..64k] bounds */
+ size = ((total / 8) | 0x3ff) + 1;
+ if (size > 64*1024)
+ size = 64*1024;
+ }
+ buf = xrealloc(buf, total + 1);
+ buf[total] = '\0';
+
+ if (maxsz_p)
+ *maxsz_p = total;
+ return buf;
+}
+
+#ifdef USING_LSEEK_TO_GET_SIZE
+/* Alternatively, file size can be obtained by lseek to the end.
+ * The code is slightly bigger. Retained in case fstat approach
+ * will not work for some weird cases (/proc, block devices, etc).
+ * (NB: lseek also can fail to work for some weird files) */
+
+// Read (potentially big) files in one go. File size is estimated by
+// lseek to end.
+void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p)
+{
+ char *buf;
+ size_t size;
+ int fd;
+ off_t len;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ /* /proc/N/stat files report len 0 here */
+ /* In order to make such files readable, we add small const */
+ size = 0x3ff; /* read only 1k on unseekable files */
+ len = lseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */
+ if (len != (off_t)-1) {
+ xlseek(fd, 0, SEEK_SET);
+ size = maxsz_p ? *maxsz_p : (INT_MAX - 4095);
+ if (len < size)
+ size = len;
+ }
+
+ buf = xmalloc(size + 1);
+ size = read_close(fd, buf, size);
+ if ((ssize_t)size < 0) {
+ free(buf);
+ return NULL;
+ }
+ buf = xrealloc(buf, size + 1);
+ buf[size] = '\0';
+
+ if (maxsz_p)
+ *maxsz_p = size;
+ return buf;
+}
+#endif
+
+// Read (potentially big) files in one go. File size is estimated
+// by stat.
+void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p)
+{
+ char *buf;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ buf = xmalloc_read(fd, maxsz_p);
+ close(fd);
+ return buf;
+}
+
+void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p)
+{
+ void *buf = xmalloc_open_read_close(filename, maxsz_p);
+ if (!buf)
+ bb_perror_msg_and_die("can't read '%s'", filename);
+ return buf;
+}
+
+int FAST_FUNC open_zipped(const char *fname)
+{
+#if !ZIPPED
+ return open(fname, O_RDONLY);
+#else
+ unsigned char magic[2];
+ char *sfx;
+ int fd;
+#if BB_MMU
+ USE_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd);
+ enum { xformer_prog = 0 };
+#else
+ enum { xformer = 0 };
+ const char *xformer_prog;
+#endif
+
+ fd = open(fname, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ sfx = strrchr(fname, '.');
+ if (sfx) {
+ if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, ".lzma") == 0)
+ /* .lzma has no header/signature, just trust it */
+ open_transformer(fd, unpack_lzma_stream, "unlzma");
+ else
+ if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0)
+ || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0)
+ ) {
+ /* .gz and .bz2 both have 2-byte signature, and their
+ * unpack_XXX_stream want this header skipped. */
+ xread(fd, &magic, 2);
+#if ENABLE_FEATURE_SEAMLESS_GZ
+#if BB_MMU
+ xformer = unpack_gz_stream;
+#else
+ xformer_prog = "gunzip";
+#endif
+#endif
+ if (!ENABLE_FEATURE_SEAMLESS_GZ
+ || magic[0] != 0x1f || magic[1] != 0x8b
+ ) {
+ if (!ENABLE_FEATURE_SEAMLESS_BZ2
+ || magic[0] != 'B' || magic[1] != 'Z'
+ ) {
+ bb_error_msg_and_die("no gzip"
+ USE_FEATURE_SEAMLESS_BZ2("/bzip2")
+ " magic");
+ }
+#if BB_MMU
+ xformer = unpack_bz2_stream;
+#else
+ xformer_prog = "bunzip2";
+#endif
+ } else {
+#if !BB_MMU
+ /* NOMMU version of open_transformer execs
+ * an external unzipper that wants
+ * file position at the start of the file */
+ xlseek(fd, 0, SEEK_SET);
+#endif
+ }
+ open_transformer(fd, xformer, xformer_prog);
+ }
+ }
+
+ return fd;
+#endif
+}
+
+void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
+{
+ int fd;
+ char *image;
+
+ fd = open_zipped(fname);
+ if (fd < 0)
+ return NULL;
+
+ image = xmalloc_read(fd, maxsz_p);
+ if (!image)
+ bb_perror_msg("read error from '%s'", fname);
+ close(fd);
+
+ return image;
+}
diff --git a/release/src/router/busybox/libbb/read_key.c b/release/src/router/busybox/libbb/read_key.c
new file mode 100644
index 00000000..0f36d20b
--- /dev/null
+++ b/release/src/router/busybox/libbb/read_key.c
@@ -0,0 +1,157 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 Rob Landley <rob@landley.net>
+ * Copyright (C) 2008 Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer)
+{
+ struct pollfd pfd;
+ const char *seq;
+ int n;
+ int c;
+
+ /* Known escape sequences for cursor and function keys */
+ static const char esccmds[] ALIGN1 = {
+ 'O','A' |0x80,KEYCODE_UP ,
+ 'O','B' |0x80,KEYCODE_DOWN ,
+ 'O','C' |0x80,KEYCODE_RIGHT ,
+ 'O','D' |0x80,KEYCODE_LEFT ,
+ 'O','H' |0x80,KEYCODE_HOME ,
+ 'O','F' |0x80,KEYCODE_END ,
+#if 0
+ 'O','P' |0x80,KEYCODE_FUN1 ,
+ /* [ESC] ESC O [2] P - [Alt-][Shift-]F1 */
+ /* Ctrl- seems to not affect sequences */
+ 'O','Q' |0x80,KEYCODE_FUN2 ,
+ 'O','R' |0x80,KEYCODE_FUN3 ,
+ 'O','S' |0x80,KEYCODE_FUN4 ,
+#endif
+ '[','A' |0x80,KEYCODE_UP ,
+ '[','B' |0x80,KEYCODE_DOWN ,
+ '[','C' |0x80,KEYCODE_RIGHT ,
+ '[','D' |0x80,KEYCODE_LEFT ,
+ '[','H' |0x80,KEYCODE_HOME , /* xterm */
+ /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */
+ '[','F' |0x80,KEYCODE_END , /* xterm */
+ '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */
+ '[','2','~' |0x80,KEYCODE_INSERT ,
+ '[','3','~' |0x80,KEYCODE_DELETE ,
+ /* [ESC] ESC [ 3 [;2] ~ - [Alt-][Shift-]Delete */
+ '[','4','~' |0x80,KEYCODE_END , /* vt100? linux vt? or what? */
+ '[','5','~' |0x80,KEYCODE_PAGEUP ,
+ '[','6','~' |0x80,KEYCODE_PAGEDOWN,
+ '[','7','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */
+ '[','8','~' |0x80,KEYCODE_END , /* vt100? linux vt? or what? */
+#if 0
+ '[','1','1','~'|0x80,KEYCODE_FUN1 ,
+ '[','1','2','~'|0x80,KEYCODE_FUN2 ,
+ '[','1','3','~'|0x80,KEYCODE_FUN3 ,
+ '[','1','4','~'|0x80,KEYCODE_FUN4 ,
+ '[','1','5','~'|0x80,KEYCODE_FUN5 ,
+ /* [ESC] ESC [ 1 5 [;2] ~ - [Alt-][Shift-]F5 */
+ '[','1','7','~'|0x80,KEYCODE_FUN6 ,
+ '[','1','8','~'|0x80,KEYCODE_FUN7 ,
+ '[','1','9','~'|0x80,KEYCODE_FUN8 ,
+ '[','2','0','~'|0x80,KEYCODE_FUN9 ,
+ '[','2','1','~'|0x80,KEYCODE_FUN10 ,
+ '[','2','3','~'|0x80,KEYCODE_FUN11 ,
+ '[','2','4','~'|0x80,KEYCODE_FUN12 ,
+#endif
+ 0
+ };
+
+ n = 0;
+ if (nbuffered)
+ n = *nbuffered;
+ if (n == 0) {
+ /* If no data, block waiting for input. If we read more
+ * than the minimal ESC sequence size, the "n=0" below
+ * would instead have to figure out how much to keep,
+ * resulting in larger code. */
+ n = safe_read(fd, buffer, 3);
+ if (n <= 0)
+ return -1;
+ }
+
+ /* Grab character to return from buffer */
+ c = (unsigned char)buffer[0];
+ n--;
+ if (n)
+ memmove(buffer, buffer + 1, n);
+
+ /* Only ESC starts ESC sequences */
+ if (c != 27)
+ goto ret;
+
+ /* Loop through known ESC sequences */
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ seq = esccmds;
+ while (*seq != '\0') {
+ /* n - position in sequence we did not read yet */
+ int i = 0; /* position in sequence to compare */
+
+ /* Loop through chars in this sequence */
+ while (1) {
+ /* So far escape sequence matched up to [i-1] */
+ if (n <= i) {
+ /* Need more chars, read another one if it wouldn't block.
+ * Note that escape sequences come in as a unit,
+ * so if we block for long it's not really an escape sequence.
+ * Timeout is needed to reconnect escape sequences
+ * split up by transmission over a serial console. */
+ if (safe_poll(&pfd, 1, 50) == 0) {
+ /* No more data!
+ * Array is sorted from shortest to longest,
+ * we can't match anything later in array,
+ * break out of both loops. */
+ goto ret;
+ }
+ errno = 0;
+ if (safe_read(fd, buffer + n, 1) <= 0) {
+ /* If EAGAIN, then fd is O_NONBLOCK and poll lied:
+ * in fact, there is no data. */
+ if (errno != EAGAIN)
+ c = -1; /* otherwise it's EOF/error */
+ goto ret;
+ }
+ n++;
+ }
+ if (buffer[i] != (seq[i] & 0x7f)) {
+ /* This seq doesn't match, go to next */
+ seq += i;
+ /* Forward to last char */
+ while (!(*seq & 0x80))
+ seq++;
+ /* Skip it and the keycode which follows */
+ seq += 2;
+ break;
+ }
+ if (seq[i] & 0x80) {
+ /* Entire seq matched */
+ c = (signed char)seq[i+1];
+ n = 0;
+ /* n -= i; memmove(...);
+ * would be more correct,
+ * but we never read ahead that much,
+ * and n == i here. */
+ goto ret;
+ }
+ i++;
+ }
+ }
+ /* We did not find matching sequence, it was a bare ESC.
+ * We possibly read and stored more input in buffer[]
+ * by now. */
+
+ ret:
+ if (nbuffered)
+ *nbuffered = n;
+ return c;
+}
diff --git a/release/src/router/busybox/libbb/read_package_field.c b/release/src/router/busybox/libbb/read_package_field.c
deleted file mode 100644
index f561df83..00000000
--- a/release/src/router/busybox/libbb/read_package_field.c
+++ /dev/null
@@ -1,91 +0,0 @@
-#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 == TRUE) {
- /* 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 = xstrndup(&package_buffer[offset_name_start], name_length);
- }
- if (value_length > 0) {
- *field_value = xstrndup(&package_buffer[offset_value_start], value_length);
- } else {
- *field_value = NULL;
- }
- return(next_offset);
-}
-
diff --git a/release/src/router/busybox/libbb/real_loop.h b/release/src/router/busybox/libbb/real_loop.h
deleted file mode 100644
index 1bd7fa87..00000000
--- a/release/src/router/busybox/libbb/real_loop.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * include/linux/loop.h
- *
- * Written by Theodore Ts'o, 3/29/93.
- *
- * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
- * permitted under the GNU Public License.
- */
-
-#define LO_NAME_SIZE 64
-#define LO_KEY_SIZE 32
-
-struct loop_info {
- int lo_number; /* ioctl r/o */
- dev_t lo_device; /* ioctl r/o */
- unsigned long lo_inode; /* ioctl r/o */
- dev_t lo_rdevice; /* ioctl r/o */
- int lo_offset;
- int lo_encrypt_type;
- int lo_encrypt_key_size; /* ioctl w/o */
- int lo_flags; /* ioctl r/o */
- char lo_name[LO_NAME_SIZE];
- unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
- unsigned long lo_init[2];
- char reserved[4];
-};
-
-#define LO_CRYPT_NONE 0
-#define LO_CRYPT_XOR 1
-#define LO_CRYPT_DES 2
-#define LO_CRYPT_IDEA 3
-#define MAX_LO_CRYPT 4
-
-#define LOOP_SET_FD 0x4C00
-#define LOOP_CLR_FD 0x4C01
-#define LOOP_SET_STATUS 0x4C02
-#define LOOP_GET_STATUS 0x4C03
diff --git a/release/src/router/busybox/libbb/recursive_action.c b/release/src/router/busybox/libbb/recursive_action.c
index 6672db17..3ec596a3 100644
--- a/release/src/router/busybox/libbb/recursive_action.c
+++ b/release/src/router/busybox/libbb/recursive_action.c
@@ -2,149 +2,146 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#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
+ * 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,
+ * 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)
+
+static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM,
+ struct stat *statbuf UNUSED_PARAM,
+ void* userData UNUSED_PARAM,
+ int depth UNUSED_PARAM)
+{
+ return TRUE;
+}
+
+/* fileAction return value of 0 on any file in directory will make
+ * recursive_action() return 0, but it doesn't stop directory traversal
+ * (fileAction/dirAction will be called on each file).
+ *
+ * If !ACTION_RECURSE, dirAction is called on the directory and its
+ * return value is returned from recursive_action(). No recursion.
+ *
+ * If ACTION_RECURSE, recursive_action() is called on each directory.
+ * If any one of these calls returns 0, current recursive_action() returns 0.
+ *
+ * If ACTION_DEPTHFIRST, dirAction is called after recurse.
+ * If it returns 0, the warning is printed and recursive_action() returns 0.
+ *
+ * If !ACTION_DEPTHFIRST, dirAction is called before we recurse.
+ * Return value of 0 (FALSE) or 2 (SKIP) prevents recursion
+ * into that directory, instead recursive_action() returns 0 (if FALSE)
+ * or 1 (if SKIP)
+ *
+ * followLinks=0/1 differs mainly in handling of links to dirs.
+ * 0: lstat(statbuf). Calls fileAction on link name even if points to dir.
+ * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir.
+ */
+
+int FAST_FUNC recursive_action(const char *fileName,
+ unsigned flags,
+ int FAST_FUNC (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
+ int FAST_FUNC (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
+ void* userData,
+ unsigned depth)
{
- int status;
struct stat statbuf;
+ int status;
+ DIR *dir;
struct dirent *next;
- if (followLinks == TRUE)
- status = stat(fileName, &statbuf);
- else
- status = lstat(fileName, &statbuf);
+ if (!fileAction) fileAction = true_action;
+ if (!dirAction) dirAction = true_action;
+ status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */
+ if (!depth)
+ status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
+ status = ((flags & status) ? stat : lstat)(fileName, &statbuf);
if (status < 0) {
#ifdef DEBUG_RECURS_ACTION
- fprintf(stderr,
- "status=%d followLinks=%d TRUE=%d\n",
- status, followLinks, TRUE);
+ bb_error_msg("status=%d flags=%x", status, flags);
#endif
- perror_msg("%s", fileName);
- return FALSE;
+ goto done_nak_warn;
}
- if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) {
- if (fileAction == NULL)
- return TRUE;
- else
- return fileAction(fileName, &statbuf, userData);
+ /* If S_ISLNK(m), then we know that !S_ISDIR(m).
+ * Then we can skip checking first part: if it is true, then
+ * (!dir) is also true! */
+ if ( /* (!(flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */
+ !S_ISDIR(statbuf.st_mode)
+ ) {
+ return fileAction(fileName, &statbuf, userData, depth);
}
- if (recurse == FALSE) {
- if (S_ISDIR(statbuf.st_mode)) {
- if (dirAction != NULL)
- return (dirAction(fileName, &statbuf, userData));
- else
- return TRUE;
- }
+ /* It's a directory (or a link to one, and followLinks is set) */
+
+ if (!(flags & ACTION_RECURSE)) {
+ return dirAction(fileName, &statbuf, userData, depth);
}
- if (S_ISDIR(statbuf.st_mode)) {
- DIR *dir;
-
- if (dirAction != NULL && depthFirst == FALSE) {
- status = dirAction(fileName, &statbuf, userData);
- if (status == FALSE) {
- perror_msg("%s", fileName);
- return FALSE;
- } else if (status == SKIP)
- return TRUE;
- }
- dir = opendir(fileName);
- if (!dir) {
- perror_msg("%s", fileName);
- return FALSE;
- }
- status = TRUE;
- while ((next = readdir(dir)) != NULL) {
- char *nextFile;
-
- if ((strcmp(next->d_name, "..") == 0)
- || (strcmp(next->d_name, ".") == 0)) {
- continue;
- }
- nextFile = concat_path_file(fileName, next->d_name);
- if (recursive_action(nextFile, TRUE, followLinks, depthFirst,
- fileAction, dirAction, userData) == FALSE) {
- status = FALSE;
- }
- free(nextFile);
- }
- closedir(dir);
- if (dirAction != NULL && depthFirst == TRUE) {
- if (dirAction(fileName, &statbuf, userData) == FALSE) {
- perror_msg("%s", fileName);
- return FALSE;
- }
- }
- if (status == FALSE)
- return FALSE;
- } else {
- if (fileAction == NULL)
+ if (!(flags & ACTION_DEPTHFIRST)) {
+ status = dirAction(fileName, &statbuf, userData, depth);
+ if (!status)
+ goto done_nak_warn;
+ if (status == SKIP)
return TRUE;
- else
- return fileAction(fileName, &statbuf, userData);
}
- return TRUE;
-}
+ dir = opendir(fileName);
+ if (!dir) {
+ /* findutils-4.1.20 reports this */
+ /* (i.e. it doesn't silently return with exit code 1) */
+ /* To trigger: "find -exec rm -rf {} \;" */
+ goto done_nak_warn;
+ }
+ status = TRUE;
+ while ((next = readdir(dir)) != NULL) {
+ char *nextFile;
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+ nextFile = concat_subpath_file(fileName, next->d_name);
+ if (nextFile == NULL)
+ continue;
+ /* process every file (NB: ACTION_RECURSE is set in flags) */
+ if (!recursive_action(nextFile, flags, fileAction, dirAction,
+ userData, depth + 1))
+ status = FALSE;
+// s = recursive_action(nextFile, flags, fileAction, dirAction,
+// userData, depth + 1);
+ free(nextFile);
+//#define RECURSE_RESULT_ABORT 3
+// if (s == RECURSE_RESULT_ABORT) {
+// closedir(dir);
+// return s;
+// }
+// if (s == FALSE)
+// status = FALSE;
+ }
+ closedir(dir);
+
+ if (flags & ACTION_DEPTHFIRST) {
+ if (!dirAction(fileName, &statbuf, userData, depth))
+ goto done_nak_warn;
+ }
+
+ return status;
+
+ done_nak_warn:
+ if (!(flags & ACTION_QUIET))
+ bb_simple_perror_msg(fileName);
+ return FALSE;
+}
diff --git a/release/src/router/busybox/libbb/remove_file.c b/release/src/router/busybox/libbb/remove_file.c
index 3b84680c..8b14f07c 100644
--- a/release/src/router/busybox/libbb/remove_file.c
+++ b/release/src/router/busybox/libbb/remove_file.c
@@ -2,54 +2,26 @@
/*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#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)
+/* Used from NOFORK applets. Must not allocate anything */
+
+int FAST_FUNC remove_file(const char *path, int flags)
{
struct stat path_stat;
- int path_exists = 1;
if (lstat(path, &path_stat) < 0) {
if (errno != ENOENT) {
- perror_msg("unable to stat `%s'", path);
+ bb_perror_msg("cannot stat '%s'", path);
return -1;
}
-
- path_exists = 0;
- }
-
- if (!path_exists) {
if (!(flags & FILEUTILS_FORCE)) {
- perror_msg("cannot remove `%s'", path);
+ bb_perror_msg("cannot remove '%s'", path);
return -1;
}
return 0;
@@ -61,69 +33,70 @@ extern int remove_file(const char *path, int flags)
int status = 0;
if (!(flags & FILEUTILS_RECUR)) {
- error_msg("%s: is a directory", path);
+ 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'? ", applet_name,
+ if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && isatty(0))
+ || (flags & FILEUTILS_INTERACTIVE)
+ ) {
+ fprintf(stderr, "%s: descend into directory '%s'? ", applet_name,
path);
- if (!ask_confirmation())
+ if (!bb_ask_confirmation())
return 0;
}
- if ((dp = opendir(path)) == NULL) {
- perror_msg("unable to open `%s'", path);
+ dp = opendir(path);
+ if (dp == NULL) {
return -1;
}
while ((d = readdir(dp)) != NULL) {
char *new_path;
- if (strcmp(d->d_name, ".") == 0 ||
- strcmp(d->d_name, "..") == 0)
+ new_path = concat_subpath_file(path, d->d_name);
+ if (new_path == NULL)
continue;
-
- new_path = concat_path_file(path, d->d_name);
if (remove_file(new_path, flags) < 0)
status = -1;
free(new_path);
}
if (closedir(dp) < 0) {
- perror_msg("unable to close `%s'", path);
+ bb_perror_msg("cannot close '%s'", path);
return -1;
}
if (flags & FILEUTILS_INTERACTIVE) {
- fprintf(stderr, "%s: remove directory `%s'? ", applet_name, path);
- if (!ask_confirmation())
+ fprintf(stderr, "%s: remove directory '%s'? ", applet_name, path);
+ if (!bb_ask_confirmation())
return status;
}
if (rmdir(path) < 0) {
- perror_msg("unable to remove `%s'", path);
+ bb_perror_msg("cannot 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'? ", applet_name, path);
- if (!ask_confirmation())
- return 0;
- }
+ }
- if (unlink(path) < 0) {
- perror_msg("unable to remove `%s'", path);
- return -1;
- }
+ /* !ISDIR */
+ 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'? ", applet_name, path);
+ if (!bb_ask_confirmation())
+ return 0;
+ }
- return 0;
+ if (unlink(path) < 0) {
+ bb_perror_msg("cannot remove '%s'", path);
+ return -1;
}
+
+ return 0;
}
diff --git a/release/src/router/busybox/libbb/restricted_shell.c b/release/src/router/busybox/libbb/restricted_shell.c
index 74a64140..2a5073f0 100644
--- a/release/src/router/busybox/libbb/restricted_shell.c
+++ b/release/src/router/busybox/libbb/restricted_shell.c
@@ -28,30 +28,19 @@
* 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 )
+int FAST_FUNC restricted_shell(const char *shell)
{
char *line;
- setusershell ( );
- while (( line = getusershell ( ))) {
- if (( *line != '#' ) && ( strcmp ( line, shell ) == 0 ))
- break;
+ setusershell();
+ while ((line = getusershell())) {
+ if (*line != '#' && strcmp(line, shell) == 0)
+ return 0;
}
- endusershell ( );
- return line ? 0 : 1;
+ endusershell();
+ return 1;
}
-
diff --git a/release/src/router/busybox/libbb/rtc.c b/release/src/router/busybox/libbb/rtc.c
new file mode 100644
index 00000000..51834f8f
--- /dev/null
+++ b/release/src/router/busybox/libbb/rtc.c
@@ -0,0 +1,90 @@
+/*
+ * Common RTC functions
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "rtc_.h"
+
+#if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS
+# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
+#else
+# define ADJTIME_PATH "/etc/adjtime"
+#endif
+
+int FAST_FUNC rtc_adjtime_is_utc(void)
+{
+ int utc = 0;
+ FILE *f = fopen_for_read(ADJTIME_PATH);
+
+ if (f) {
+ RESERVE_CONFIG_BUFFER(buffer, 128);
+
+ while (fgets(buffer, sizeof(buffer), f)) {
+ int len = strlen(buffer);
+
+ while (len && isspace(buffer[len - 1]))
+ len--;
+
+ buffer[len] = 0;
+
+ if (strncmp(buffer, "UTC", 3) == 0) {
+ utc = 1;
+ break;
+ }
+ }
+ fclose(f);
+
+ RELEASE_CONFIG_BUFFER(buffer);
+ }
+
+ return utc;
+}
+
+int FAST_FUNC rtc_xopen(const char **default_rtc, int flags)
+{
+ int rtc;
+
+ if (!*default_rtc) {
+ *default_rtc = "/dev/rtc";
+ rtc = open(*default_rtc, flags);
+ if (rtc >= 0)
+ return rtc;
+ *default_rtc = "/dev/rtc0";
+ rtc = open(*default_rtc, flags);
+ if (rtc >= 0)
+ return rtc;
+ *default_rtc = "/dev/misc/rtc";
+ }
+
+ return xopen(*default_rtc, flags);
+}
+
+time_t FAST_FUNC rtc_read_time(int fd, int utc)
+{
+ struct tm tm;
+ char *oldtz = 0;
+ time_t t = 0;
+
+ memset(&tm, 0, sizeof(struct tm));
+ xioctl(fd, RTC_RD_TIME, &tm);
+ tm.tm_isdst = -1; /* not known */
+
+ if (utc) {
+ oldtz = getenv("TZ");
+ putenv((char*)"TZ=UTC0");
+ tzset();
+ }
+
+ t = mktime(&tm);
+
+ if (utc) {
+ unsetenv("TZ");
+ if (oldtz)
+ putenv(oldtz - 3);
+ tzset();
+ }
+
+ return t;
+}
diff --git a/release/src/router/busybox/libbb/run_parts.c b/release/src/router/busybox/libbb/run_parts.c
deleted file mode 100644
index 171d9379..00000000
--- a/release/src/router/busybox/libbb/run_parts.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/* 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 offical run_parts
- * test_mode = 2 means to fail siliently 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 & 1) {
- 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_and_die("failed to exec %s", filename);
- }
- 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/release/src/router/busybox/libbb/run_shell.c b/release/src/router/busybox/libbb/run_shell.c
index 4855d763..2ccb3a12 100644
--- a/release/src/router/busybox/libbb/run_shell.c
+++ b/release/src/router/busybox/libbb/run_shell.c
@@ -28,16 +28,25 @@
* 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>
+#if ENABLE_SELINUX
+#include <selinux/selinux.h> /* for setexeccon */
+#endif
+
+#if ENABLE_SELINUX
+static security_context_t current_sid;
+
+void FAST_FUNC renew_current_security_context(void)
+{
+ freecon(current_sid); /* Release old context */
+ getcon(&current_sid); /* update */
+}
+void FAST_FUNC set_current_security_context(security_context_t sid)
+{
+ freecon(current_sid); /* Release old context */
+ current_sid = sid;
+}
+
#endif
/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
@@ -45,43 +54,37 @@
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
-)
+void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args)
{
const char **args;
int argno = 1;
int additional_args_cnt = 0;
-
- for ( args = additional_args; args && *args; args++ )
+
+ 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;
+ args = xmalloc(sizeof(char*) * (4 + additional_args_cnt));
+
+ args[0] = bb_get_last_path_component_nostrip(xstrdup(shell));
+
+ if (loginshell)
+ args[0] = xasprintf("-%s", args[0]);
+
+ if (command) {
+ args[argno++] = "-c";
+ args[argno++] = command;
}
- if ( additional_args ) {
- for ( ; *additional_args; ++additional_args )
- args [argno++] = *additional_args;
+ 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
+ args[argno] = NULL;
+#if ENABLE_SELINUX
+ if (current_sid)
+ setexeccon(current_sid);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ freecon(current_sid);
#endif
- execv ( shell, (char **) args );
- bb_perror_msg_and_die ( "cannot run %s", shell );
+ execv(shell, (char **) args);
+ bb_perror_msg_and_die("cannot run %s", shell);
}
diff --git a/release/src/router/busybox/libbb/safe_gethostname.c b/release/src/router/busybox/libbb/safe_gethostname.c
new file mode 100644
index 00000000..7407fb78
--- /dev/null
+++ b/release/src/router/busybox/libbb/safe_gethostname.c
@@ -0,0 +1,66 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Safe gethostname implementation for busybox
+ *
+ * Copyright (C) 2008 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/*
+ * SUSv2 guarantees that "Host names are limited to 255 bytes"
+ * POSIX.1-2001 guarantees that "Host names (not including the terminating
+ * null byte) are limited to HOST_NAME_MAX bytes" (64 bytes on my box).
+ *
+ * RFC1123 says:
+ *
+ * The syntax of a legal Internet host name was specified in RFC-952
+ * [DNS:4]. One aspect of host name syntax is hereby changed: the
+ * restriction on the first character is relaxed to allow either a
+ * letter or a digit. Host software MUST support this more liberal
+ * syntax.
+ *
+ * Host software MUST handle host names of up to 63 characters and
+ * SHOULD handle host names of up to 255 characters.
+ */
+
+#include "libbb.h"
+#include <sys/utsname.h>
+
+/*
+ * On success return the current malloced and NUL terminated hostname.
+ * On error return malloced and NUL terminated string "?".
+ * This is an illegal first character for a hostname.
+ * The returned malloced string must be freed by the caller.
+ */
+char* FAST_FUNC safe_gethostname(void)
+{
+ struct utsname uts;
+
+ /* The length of the arrays in a struct utsname is unspecified;
+ * the fields are terminated by a null byte.
+ * Note that there is no standard that says that the hostname
+ * set by sethostname(2) is the same string as the nodename field of the
+ * struct returned by uname (indeed, some systems allow a 256-byte host-
+ * name and an 8-byte nodename), but this is true on Linux. The same holds
+ * for setdomainname(2) and the domainname field.
+ */
+
+ /* Uname can fail only if you pass a bad pointer to it. */
+ uname(&uts);
+ return xstrndup(!uts.nodename[0] ? "?" : uts.nodename, sizeof(uts.nodename));
+}
+
+/*
+ * On success return the current malloced and NUL terminated domainname.
+ * On error return malloced and NUL terminated string "?".
+ * This is an illegal first character for a domainname.
+ * The returned malloced string must be freed by the caller.
+ */
+char* FAST_FUNC safe_getdomainname(void)
+{
+ struct utsname uts;
+
+ uname(&uts);
+ return xstrndup(!uts.domainname[0] ? "?" : uts.domainname, sizeof(uts.domainname));
+}
diff --git a/release/src/router/busybox/libbb/safe_poll.c b/release/src/router/busybox/libbb/safe_poll.c
new file mode 100644
index 00000000..58c7bda5
--- /dev/null
+++ b/release/src/router/busybox/libbb/safe_poll.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Wrapper which restarts poll on EINTR or ENOMEM.
+ * On other errors does perror("poll") and returns.
+ * Warning! May take longer than timeout_ms to return! */
+int FAST_FUNC safe_poll(struct pollfd *ufds, nfds_t nfds, int timeout)
+{
+ while (1) {
+ int n = poll(ufds, nfds, timeout);
+ if (n >= 0)
+ return n;
+ /* Make sure we inch towards completion */
+ if (timeout > 0)
+ timeout--;
+ /* E.g. strace causes poll to return this */
+ if (errno == EINTR)
+ continue;
+ /* Kernel is very low on memory. Retry. */
+ /* I doubt many callers would handle this correctly! */
+ if (errno == ENOMEM)
+ continue;
+ bb_perror_msg("poll");
+ return n;
+ }
+}
diff --git a/release/src/router/busybox/libbb/safe_read.c b/release/src/router/busybox/libbb/safe_read.c
deleted file mode 100644
index dbf4aa7e..00000000
--- a/release/src/router/busybox/libbb/safe_read.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#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/release/src/router/busybox/libbb/safe_strncpy.c b/release/src/router/busybox/libbb/safe_strncpy.c
index 55ec7980..4acd9766 100644
--- a/release/src/router/busybox/libbb/safe_strncpy.c
+++ b/release/src/router/busybox/libbb/safe_strncpy.c
@@ -2,47 +2,26 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#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);
+/* Like strncpy but make sure the resulting string is always 0 terminated. */
+char* FAST_FUNC safe_strncpy(char *dst, const char *src, size_t size)
+{
+ if (!size) return dst;
+ dst[--size] = '\0';
+ return strncpy(dst, src, size);
}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+/* Like strcpy but can copy overlapping strings. */
+void FAST_FUNC overlapping_strcpy(char *dst, const char *src)
+{
+ while ((*dst = *src) != '\0') {
+ dst++;
+ src++;
+ }
+}
diff --git a/release/src/router/busybox/libbb/safe_write.c b/release/src/router/busybox/libbb/safe_write.c
new file mode 100644
index 00000000..e3561f3c
--- /dev/null
+++ b/release/src/router/busybox/libbb/safe_write.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+ssize_t FAST_FUNC 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;
+}
diff --git a/release/src/router/busybox/libbb/selinux_common.c b/release/src/router/busybox/libbb/selinux_common.c
new file mode 100644
index 00000000..275a761d
--- /dev/null
+++ b/release/src/router/busybox/libbb/selinux_common.c
@@ -0,0 +1,56 @@
+/*
+ * libbb/selinux_common.c
+ * -- common SELinux utility functions
+ *
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+#include <selinux/context.h>
+
+context_t FAST_FUNC set_security_context_component(security_context_t cur_context,
+ char *user, char *role, char *type, char *range)
+{
+ context_t con = context_new(cur_context);
+ if (!con)
+ return NULL;
+
+ if (user && context_user_set(con, user))
+ goto error;
+ if (type && context_type_set(con, type))
+ goto error;
+ if (range && context_range_set(con, range))
+ goto error;
+ if (role && context_role_set(con, role))
+ goto error;
+ return con;
+
+error:
+ context_free(con);
+ return NULL;
+}
+
+void FAST_FUNC setfscreatecon_or_die(security_context_t scontext)
+{
+ if (setfscreatecon(scontext) < 0) {
+ /* Can be NULL. All known printf implementations
+ * display "(null)", "<null>" etc */
+ bb_perror_msg_and_die("cannot set default "
+ "file creation context to %s", scontext);
+ }
+}
+
+void FAST_FUNC selinux_preserve_fcontext(int fdesc)
+{
+ security_context_t context;
+
+ if (fgetfilecon(fdesc, &context) < 0) {
+ if (errno == ENODATA || errno == ENOTSUP)
+ return;
+ bb_perror_msg_and_die("fgetfilecon failed");
+ }
+ setfscreatecon_or_die(context);
+ freecon(context);
+}
+
diff --git a/release/src/router/busybox/libbb/setup_environment.c b/release/src/router/busybox/libbb/setup_environment.c
index b18f8967..78318ce6 100644
--- a/release/src/router/busybox/libbb/setup_environment.c
+++ b/release/src/router/busybox/libbb/setup_environment.c
@@ -28,66 +28,43 @@
* 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 )
+void FAST_FUNC setup_environment(const char *shell, int clear_env, int change_env, const struct passwd *pw)
{
- if ( setenv ( key, value, 1 ))
- bb_error_msg_and_die (bb_msg_memory_exhausted);
-}
+ /* Change the current working directory to be the home directory
+ * of the user */
+ if (chdir(pw->pw_dir)) {
+ xchdir("/");
+ bb_error_msg("can't chdir to home directory '%s'", pw->pw_dir);
+ }
-void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw )
-{
- if ( loginshell ) {
+ if (clear_env) {
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.
+ /* 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 ));
+ term = getenv("TERM");
+ clearenv();
+ if (term)
+ xsetenv("TERM", term);
+ xsetenv("PATH", (pw->pw_uid ? bb_default_path : bb_default_root_path));
+ goto shortcut;
+ // No, gcc (4.2.1) is not clever enougn to do it itself.
+ //xsetenv("USER", pw->pw_name);
+ //xsetenv("LOGNAME", pw->pw_name);
+ //xsetenv("HOME", pw->pw_dir);
+ //xsetenv("SHELL", shell);
}
- else if ( changeenv ) {
+ else if (change_env) {
/* 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 );
+ USER and LOGNAME. */
+ if (pw->pw_uid) {
+ shortcut:
+ xsetenv("USER", pw->pw_name);
+ xsetenv("LOGNAME", pw->pw_name);
}
+ xsetenv("HOME", pw->pw_dir);
+ xsetenv("SHELL", shell);
}
}
-
diff --git a/release/src/router/busybox/libbb/sha1.c b/release/src/router/busybox/libbb/sha1.c
new file mode 100644
index 00000000..9fa095e8
--- /dev/null
+++ b/release/src/router/busybox/libbb/sha1.c
@@ -0,0 +1,465 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Based on shasum from http://www.netsw.org/crypto/hash/
+ * Majorly hacked up to use Dr Brian Gladman's sha1 code
+ *
+ * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
+ * Copyright (C) 2003 Glenn L. McGrath
+ * Copyright (C) 2003 Erik Andersen
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * ---------------------------------------------------------------------------
+ * 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
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * SHA256 and SHA512 parts are:
+ * Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>.
+ * Shrank by Denys Vlasenko.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * The best way to test random blocksizes is to go to coreutils/md5_sha1_sum.c
+ * and replace "4096" with something like "2000 + time(NULL) % 2097",
+ * then rebuild and compare "shaNNNsum bigfile" results.
+ */
+
+#include "libbb.h"
+
+#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n))))
+/* for sha512: */
+#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n))))
+#if BB_LITTLE_ENDIAN
+static inline uint64_t hton64(uint64_t v)
+{
+ return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32);
+}
+#else
+#define hton64(v) (v)
+#endif
+#define ntoh64(v) hton64(v)
+
+/* To check alignment gcc has an appropriate operator. Other
+ compilers don't. */
+#if defined(__GNUC__) && __GNUC__ >= 2
+# define UNALIGNED_P(p,type) (((uintptr_t) p) % __alignof__(type) != 0)
+#else
+# define UNALIGNED_P(p,type) (((uintptr_t) p) % sizeof(type) != 0)
+#endif
+
+
+static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx)
+{
+ unsigned t;
+ uint32_t W[80], a, b, c, d, e;
+ const uint32_t *words = (uint32_t*) ctx->wbuffer;
+
+ for (t = 0; t < 16; ++t) {
+ W[t] = ntohl(*words);
+ words++;
+ }
+
+ for (/*t = 16*/; t < 80; ++t) {
+ uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
+ W[t] = rotl32(T, 1);
+ }
+
+ a = ctx->hash[0];
+ b = ctx->hash[1];
+ c = ctx->hash[2];
+ d = ctx->hash[3];
+ e = ctx->hash[4];
+
+/* 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) \
+ do { \
+ uint32_t T = a; \
+ a = rotl32(a, 5) + f(b, c, d) + e + k + W[t]; \
+ e = d; \
+ d = c; \
+ c = rotl32(b, 30); \
+ b = T; \
+ } while (0)
+
+ for (t = 0; t < 20; ++t)
+ rnd(ch, 0x5a827999);
+
+ for (/*t = 20*/; t < 40; ++t)
+ rnd(parity, 0x6ed9eba1);
+
+ for (/*t = 40*/; t < 60; ++t)
+ rnd(maj, 0x8f1bbcdc);
+
+ for (/*t = 60*/; t < 80; ++t)
+ rnd(parity, 0xca62c1d6);
+#undef ch
+#undef parity
+#undef maj
+#undef rnd
+
+ ctx->hash[0] += a;
+ ctx->hash[1] += b;
+ ctx->hash[2] += c;
+ ctx->hash[3] += d;
+ ctx->hash[4] += e;
+}
+
+/* Constants for SHA512 from FIPS 180-2:4.2.3.
+ * SHA256 constants from FIPS 180-2:4.2.2
+ * are the most significant half of first 64 elements
+ * of the same array.
+ */
+static const uint64_t sha_K[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, /* [64]+ are used for sha512 only */
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+static void FAST_FUNC sha256_process_block64(sha256_ctx_t *ctx)
+{
+ unsigned t;
+ uint32_t W[64], a, b, c, d, e, f, g, h;
+ const uint32_t *words = (uint32_t*) ctx->wbuffer;
+
+ /* Operators defined in FIPS 180-2:4.1.2. */
+#define Ch(x, y, z) ((x & y) ^ (~x & z))
+#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+#define S0(x) (rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22))
+#define S1(x) (rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25))
+#define R0(x) (rotr32(x, 7) ^ rotr32(x, 18) ^ (x >> 3))
+#define R1(x) (rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10))
+
+ /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */
+ for (t = 0; t < 16; ++t) {
+ W[t] = ntohl(*words);
+ words++;
+ }
+
+ for (/*t = 16*/; t < 64; ++t)
+ W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16];
+
+ a = ctx->hash[0];
+ b = ctx->hash[1];
+ c = ctx->hash[2];
+ d = ctx->hash[3];
+ e = ctx->hash[4];
+ f = ctx->hash[5];
+ g = ctx->hash[6];
+ h = ctx->hash[7];
+
+ /* The actual computation according to FIPS 180-2:6.2.2 step 3. */
+ for (t = 0; t < 64; ++t) {
+ /* Need to fetch upper half of sha_K[t]
+ * (I hope compiler is clever enough to just fetch
+ * upper half)
+ */
+ uint32_t K_t = sha_K[t] >> 32;
+ uint32_t T1 = h + S1(e) + Ch(e, f, g) + K_t + W[t];
+ uint32_t T2 = S0(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+#undef Ch
+#undef Maj
+#undef S0
+#undef S1
+#undef R0
+#undef R1
+ /* Add the starting values of the context according to FIPS 180-2:6.2.2
+ step 4. */
+ ctx->hash[0] += a;
+ ctx->hash[1] += b;
+ ctx->hash[2] += c;
+ ctx->hash[3] += d;
+ ctx->hash[4] += e;
+ ctx->hash[5] += f;
+ ctx->hash[6] += g;
+ ctx->hash[7] += h;
+}
+
+static void FAST_FUNC sha512_process_block128(sha512_ctx_t *ctx)
+{
+ unsigned t;
+ uint64_t W[80];
+ /* On i386, having assignments here (not later as sha256 does)
+ * produces 99 bytes smaller code with gcc 4.3.1
+ */
+ uint64_t a = ctx->hash[0];
+ uint64_t b = ctx->hash[1];
+ uint64_t c = ctx->hash[2];
+ uint64_t d = ctx->hash[3];
+ uint64_t e = ctx->hash[4];
+ uint64_t f = ctx->hash[5];
+ uint64_t g = ctx->hash[6];
+ uint64_t h = ctx->hash[7];
+ const uint64_t *words = (uint64_t*) ctx->wbuffer;
+
+ /* Operators defined in FIPS 180-2:4.1.2. */
+#define Ch(x, y, z) ((x & y) ^ (~x & z))
+#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+#define S0(x) (rotr64(x, 28) ^ rotr64(x, 34) ^ rotr64(x, 39))
+#define S1(x) (rotr64(x, 14) ^ rotr64(x, 18) ^ rotr64(x, 41))
+#define R0(x) (rotr64(x, 1) ^ rotr64(x, 8) ^ (x >> 7))
+#define R1(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ (x >> 6))
+
+ /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */
+ for (t = 0; t < 16; ++t) {
+ W[t] = ntoh64(*words);
+ words++;
+ }
+ for (/*t = 16*/; t < 80; ++t)
+ W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16];
+
+ /* The actual computation according to FIPS 180-2:6.3.2 step 3. */
+ for (t = 0; t < 80; ++t) {
+ uint64_t T1 = h + S1(e) + Ch(e, f, g) + sha_K[t] + W[t];
+ uint64_t T2 = S0(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+#undef Ch
+#undef Maj
+#undef S0
+#undef S1
+#undef R0
+#undef R1
+ /* Add the starting values of the context according to FIPS 180-2:6.3.2
+ step 4. */
+ ctx->hash[0] += a;
+ ctx->hash[1] += b;
+ ctx->hash[2] += c;
+ ctx->hash[3] += d;
+ ctx->hash[4] += e;
+ ctx->hash[5] += f;
+ ctx->hash[6] += g;
+ ctx->hash[7] += h;
+}
+
+
+void FAST_FUNC sha1_begin(sha1_ctx_t *ctx)
+{
+ ctx->hash[0] = 0x67452301;
+ ctx->hash[1] = 0xefcdab89;
+ ctx->hash[2] = 0x98badcfe;
+ ctx->hash[3] = 0x10325476;
+ ctx->hash[4] = 0xc3d2e1f0;
+ ctx->total64 = 0;
+ ctx->process_block = sha1_process_block64;
+}
+
+static const uint32_t init256[] = {
+ 0x6a09e667,
+ 0xbb67ae85,
+ 0x3c6ef372,
+ 0xa54ff53a,
+ 0x510e527f,
+ 0x9b05688c,
+ 0x1f83d9ab,
+ 0x5be0cd19
+};
+static const uint32_t init512_lo[] = {
+ 0xf3bcc908,
+ 0x84caa73b,
+ 0xfe94f82b,
+ 0x5f1d36f1,
+ 0xade682d1,
+ 0x2b3e6c1f,
+ 0xfb41bd6b,
+ 0x137e2179
+};
+
+/* Initialize structure containing state of computation.
+ (FIPS 180-2:5.3.2) */
+void FAST_FUNC sha256_begin(sha256_ctx_t *ctx)
+{
+ memcpy(ctx->hash, init256, sizeof(init256));
+ ctx->total64 = 0;
+ ctx->process_block = sha256_process_block64;
+}
+
+/* Initialize structure containing state of computation.
+ (FIPS 180-2:5.3.3) */
+void FAST_FUNC sha512_begin(sha512_ctx_t *ctx)
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ ctx->hash[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i];
+ ctx->total64[0] = ctx->total64[1] = 0;
+}
+
+
+/* Used also for sha256 */
+void FAST_FUNC sha1_hash(const void *buffer, size_t len, sha1_ctx_t *ctx)
+{
+ unsigned in_buf = ctx->total64 & 63;
+ unsigned add = 64 - in_buf;
+
+ ctx->total64 += len;
+
+ while (len >= add) { /* transfer whole blocks while possible */
+ memcpy(ctx->wbuffer + in_buf, buffer, add);
+ buffer = (const char *)buffer + add;
+ len -= add;
+ add = 64;
+ in_buf = 0;
+ ctx->process_block(ctx);
+ }
+
+ memcpy(ctx->wbuffer + in_buf, buffer, len);
+}
+
+void FAST_FUNC sha512_hash(const void *buffer, size_t len, sha512_ctx_t *ctx)
+{
+ unsigned in_buf = ctx->total64[0] & 127;
+ unsigned add = 128 - in_buf;
+
+ /* First increment the byte count. FIPS 180-2 specifies the possible
+ length of the file up to 2^128 _bits_.
+ We compute the number of _bytes_ and convert to bits later. */
+ ctx->total64[0] += len;
+ if (ctx->total64[0] < len)
+ ctx->total64[1]++;
+
+ while (len >= add) { /* transfer whole blocks while possible */
+ memcpy(ctx->wbuffer + in_buf, buffer, add);
+ buffer = (const char *)buffer + add;
+ len -= add;
+ add = 128;
+ in_buf = 0;
+ sha512_process_block128(ctx);
+ }
+
+ memcpy(ctx->wbuffer + in_buf, buffer, len);
+}
+
+
+/* Used also for sha256 */
+void FAST_FUNC sha1_end(void *resbuf, sha1_ctx_t *ctx)
+{
+ unsigned i, pad, in_buf;
+
+ in_buf = ctx->total64 & 63;
+ /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
+ ctx->wbuffer[in_buf++] = 0x80;
+
+ /* This loop iterates either once or twice, no more, no less */
+ while (1) {
+ pad = 64 - in_buf;
+ memset(ctx->wbuffer + in_buf, 0, pad);
+ in_buf = 0;
+ /* Do we have enough space for the length count? */
+ if (pad >= 8) {
+ /* Store the 64-bit counter of bits in the buffer in BE format */
+ uint64_t t = ctx->total64 << 3;
+ t = hton64(t);
+ /* wbuffer is suitably aligned for this */
+ *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t;
+ }
+ ctx->process_block(ctx);
+ if (pad >= 8)
+ break;
+ }
+
+ in_buf = (ctx->process_block == sha1_process_block64) ? 5 : 8;
+ /* This way we do not impose alignment constraints on resbuf: */
+#if BB_LITTLE_ENDIAN
+ for (i = 0; i < in_buf; ++i)
+ ctx->hash[i] = htonl(ctx->hash[i]);
+#endif
+ memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * in_buf);
+}
+
+void FAST_FUNC sha512_end(void *resbuf, sha512_ctx_t *ctx)
+{
+ unsigned i, pad, in_buf;
+
+ in_buf = ctx->total64[0] & 127;
+ /* Pad the buffer to the next 128-byte boundary with 0x80,0,0,0...
+ * (FIPS 180-2:5.1.2)
+ */
+ ctx->wbuffer[in_buf++] = 0x80;
+
+ while (1) {
+ pad = 128 - in_buf;
+ memset(ctx->wbuffer + in_buf, 0, pad);
+ in_buf = 0;
+ if (pad >= 16) {
+ /* Store the 128-bit counter of bits in the buffer in BE format */
+ uint64_t t;
+ t = ctx->total64[0] << 3;
+ t = hton64(t);
+ *(uint64_t *) (&ctx->wbuffer[128 - 8]) = t;
+ t = (ctx->total64[1] << 3) | (ctx->total64[0] >> 61);
+ t = hton64(t);
+ *(uint64_t *) (&ctx->wbuffer[128 - 16]) = t;
+ }
+ sha512_process_block128(ctx);
+ if (pad >= 16)
+ break;
+ }
+
+#if BB_LITTLE_ENDIAN
+ for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i)
+ ctx->hash[i] = hton64(ctx->hash[i]);
+#endif
+ memcpy(resbuf, ctx->hash, sizeof(ctx->hash));
+}
diff --git a/release/src/router/busybox/libbb/signals.c b/release/src/router/busybox/libbb/signals.c
new file mode 100644
index 00000000..a528756f
--- /dev/null
+++ b/release/src/router/busybox/libbb/signals.c
@@ -0,0 +1,121 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* All known arches use small ints for signals */
+smallint bb_got_signal;
+
+void record_signo(int signo)
+{
+ bb_got_signal = signo;
+}
+
+/* Saves 2 bytes on x86! Oh my... */
+int FAST_FUNC sigaction_set(int signum, const struct sigaction *act)
+{
+ return sigaction(signum, act, NULL);
+}
+
+int FAST_FUNC sigprocmask_allsigs(int how)
+{
+ sigset_t set;
+ sigfillset(&set);
+ return sigprocmask(how, &set, NULL);
+}
+
+void FAST_FUNC bb_signals(int sigs, void (*f)(int))
+{
+ int sig_no = 0;
+ int bit = 1;
+
+ while (sigs) {
+ if (sigs & bit) {
+ sigs &= ~bit;
+ signal(sig_no, f);
+ }
+ sig_no++;
+ bit <<= 1;
+ }
+}
+
+void FAST_FUNC bb_signals_recursive_norestart(int sigs, void (*f)(int))
+{
+ int sig_no = 0;
+ int bit = 1;
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = f;
+ /*sa.sa_flags = 0;*/
+ /*sigemptyset(&sa.sa_mask); - hope memset did it*/
+
+ while (sigs) {
+ if (sigs & bit) {
+ sigs &= ~bit;
+ sigaction_set(sig_no, &sa);
+ }
+ sig_no++;
+ bit <<= 1;
+ }
+}
+
+void FAST_FUNC sig_block(int sig)
+{
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigaddset(&ss, sig);
+ sigprocmask(SIG_BLOCK, &ss, NULL);
+}
+
+void FAST_FUNC sig_unblock(int sig)
+{
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigaddset(&ss, sig);
+ sigprocmask(SIG_UNBLOCK, &ss, NULL);
+}
+
+void FAST_FUNC wait_for_any_sig(void)
+{
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigsuspend(&ss);
+}
+
+/* Assuming the sig is fatal */
+void FAST_FUNC kill_myself_with_sig(int sig)
+{
+ signal(sig, SIG_DFL);
+ sig_unblock(sig);
+ raise(sig);
+ _exit(EXIT_FAILURE); /* Should not reach it */
+}
+
+void FAST_FUNC signal_SA_RESTART_empty_mask(int sig, void (*handler)(int))
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ /*sigemptyset(&sa.sa_mask);*/
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = handler;
+ sigaction_set(sig, &sa);
+}
+
+void FAST_FUNC signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int))
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ /*sigemptyset(&sa.sa_mask);*/
+ /*sa.sa_flags = 0;*/
+ sa.sa_handler = handler;
+ sigaction_set(sig, &sa);
+}
diff --git a/release/src/router/busybox/libbb/simplify_path.c b/release/src/router/busybox/libbb/simplify_path.c
index 743133cd..f80e3e8a 100644
--- a/release/src/router/busybox/libbb/simplify_path.c
+++ b/release/src/router/busybox/libbb/simplify_path.c
@@ -4,49 +4,29 @@
*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-
-#include <stdlib.h>
#include "libbb.h"
-char *bb_simplify_path(const char *path)
+char* FAST_FUNC bb_simplify_abs_path_inplace(char *start)
{
- char *s, *start, *p;
+ char *s, *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 '.' */
+ }
+ if (*s == '.') {
+ if (s[1] == '/' || !s[1]) { /* remove extra '.' */
continue;
- } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
+ }
+ if ((s[1] == '.') && (s[2] == '/' || !s[2])) {
++s;
if (p > start) {
- while (*--p != '/'); /* omit previous dir */
+ while (*--p != '/') /* omit previous dir */
+ continue;
}
continue;
}
@@ -58,7 +38,22 @@ char *bb_simplify_path(const char *path)
if ((p == start) || (*p != '/')) { /* not a trailing slash */
++p; /* so keep last character */
}
- *p = 0;
+ *p = '\0';
+ return p;
+}
+
+char* FAST_FUNC bb_simplify_path(const char *path)
+{
+ char *s, *p;
+
+ if (path[0] == '/')
+ s = xstrdup(path);
+ else {
+ p = xrealloc_getcwd_or_warn(NULL);
+ s = concat_path_file(p, path);
+ free(p);
+ }
- return start;
+ bb_simplify_abs_path_inplace(s);
+ return s;
}
diff --git a/release/src/router/busybox/libbb/skip_whitespace.c b/release/src/router/busybox/libbb/skip_whitespace.c
index bf049a2d..e85f3859 100644
--- a/release/src/router/busybox/libbb/skip_whitespace.c
+++ b/release/src/router/busybox/libbb/skip_whitespace.c
@@ -4,30 +4,22 @@
*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <ctype.h>
#include "libbb.h"
-extern const char *bb_skip_whitespace(const char *s)
+char* FAST_FUNC skip_whitespace(const char *s)
+{
+ /* NB: isspace('\0') returns 0 */
+ while (isspace(*s)) ++s;
+
+ return (char *) s;
+}
+
+char* FAST_FUNC skip_non_whitespace(const char *s)
{
- while (isspace(*s)) {
- ++s;
- }
+ while (*s && !isspace(*s)) ++s;
- return s;
+ return (char *) s;
}
diff --git a/release/src/router/busybox/libbb/speed_table.c b/release/src/router/busybox/libbb/speed_table.c
index b04429e9..05fe66c6 100644
--- a/release/src/router/busybox/libbb/speed_table.c
+++ b/release/src/router/busybox/libbb/speed_table.c
@@ -4,23 +4,9 @@
*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <termios.h>
#include "libbb.h"
struct speed_map {
@@ -67,9 +53,9 @@ static const struct speed_map speeds[] = {
#endif
};
-static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
+enum { NUM_SPEEDS = ARRAY_SIZE(speeds) };
-unsigned long bb_baud_to_value(speed_t speed)
+unsigned FAST_FUNC tty_baud_to_value(speed_t speed)
{
int i = 0;
@@ -85,12 +71,12 @@ unsigned long bb_baud_to_value(speed_t speed)
return 0;
}
-speed_t bb_value_to_baud(unsigned long value)
+speed_t FAST_FUNC tty_value_to_baud(unsigned int value)
{
int i = 0;
do {
- if (value == bb_baud_to_value(speeds[i].speed)) {
+ if (value == tty_baud_to_value(speeds[i].speed)) {
return speeds[i].speed;
}
} while (++i < NUM_SPEEDS);
@@ -107,8 +93,8 @@ int main(void)
unsigned long v;
speed_t s;
- for (v = 0 ; v < 500000 ; v++) {
- s = bb_value_to_baud(v);
+ for (v = 0 ; v < 500000; v++) {
+ s = tty_value_to_baud(v);
if (s == (speed_t) -1) {
continue;
}
@@ -117,8 +103,8 @@ int main(void)
printf("-------------------------------\n");
- for (s = 0 ; s < 010017+1 ; s++) {
- v = bb_baud_to_value(s);
+ for (s = 0 ; s < 010017+1; s++) {
+ v = tty_baud_to_value(s);
if (!v) {
continue;
}
diff --git a/release/src/router/busybox/libbb/str_tolower.c b/release/src/router/busybox/libbb/str_tolower.c
new file mode 100644
index 00000000..f402e8e6
--- /dev/null
+++ b/release/src/router/busybox/libbb/str_tolower.c
@@ -0,0 +1,14 @@
+/* vi set: sw=4 ts=4: */
+/* Convert string str to lowercase, return str.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+char* FAST_FUNC str_tolower(char *str)
+{
+ char *c;
+ for (c = str; *c; ++c)
+ *c = tolower(*c);
+ return str;
+}
diff --git a/release/src/router/busybox/libbb/strrstr.c b/release/src/router/busybox/libbb/strrstr.c
new file mode 100644
index 00000000..a803dd98
--- /dev/null
+++ b/release/src/router/busybox/libbb/strrstr.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 Bernhard Reutner-Fischer
+ *
+ * Licensed under GPLv2 or later, see file License in this tarball for details.
+ */
+
+#ifdef __DO_STRRSTR_TEST
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#else
+#include "libbb.h"
+#endif
+
+/*
+ * The strrstr() function finds the last occurrence of the substring needle
+ * in the string haystack. The terminating nul characters are not compared.
+ */
+char* FAST_FUNC strrstr(const char *haystack, const char *needle)
+{
+ char *r = NULL;
+
+ if (!needle[0])
+ return (char*)haystack + strlen(haystack);
+ while (1) {
+ char *p = strstr(haystack, needle);
+ if (!p)
+ return r;
+ r = p;
+ haystack = p + 1;
+ }
+}
+
+#ifdef __DO_STRRSTR_TEST
+int main(int argc, char **argv)
+{
+ static const struct {
+ const char *h, *n;
+ int pos;
+ } test_array[] = {
+ /* 0123456789 */
+ { "baaabaaab", "aaa", 5 },
+ { "baaabaaaab", "aaa", 6 },
+ { "baaabaab", "aaa", 1 },
+ { "aaa", "aaa", 0 },
+ { "aaa", "a", 2 },
+ { "aaa", "bbb", -1 },
+ { "a", "aaa", -1 },
+ { "aaa", "", 3 },
+ { "", "aaa", -1 },
+ { "", "", 0 },
+ };
+
+ int i;
+
+ i = 0;
+ while (i < sizeof(test_array) / sizeof(test_array[0])) {
+ const char *r = strrstr(test_array[i].h, test_array[i].n);
+ printf("'%s' vs. '%s': '%s' - ", test_array[i].h, test_array[i].n, r);
+ if (r == NULL)
+ r = test_array[i].h - 1;
+ printf("%s\n", r == test_array[i].h + test_array[i].pos ? "PASSED" : "FAILED");
+ i++;
+ }
+
+ return 0;
+}
+#endif
diff --git a/release/src/router/busybox/libbb/syscalls.c b/release/src/router/busybox/libbb/syscalls.c
deleted file mode 100644
index 426a14aa..00000000
--- a/release/src/router/busybox/libbb/syscalls.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * some system calls possibly missing from libc
- *
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <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 <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>
-#ifndef __UCLIBC__
-#include <asm/unistd.h>
-#endif
-#include "libbb.h"
-
-#if defined(__ia64__)
-int sysfs( int option, unsigned int fs_index, char * buf)
-{
- return(syscall(__NR_sysfs, option, fs_index, buf));
-}
-#else
-_syscall3(int, sysfs, int, option, unsigned int, fs_index, char *, buf);
-#endif
-
-#ifndef __NR_pivot_root
-#warning This kernel does not support the pivot_root syscall
-#warning -> The pivot_root system call is being stubbed out...
-int pivot_root(const char * new_root,const char * put_old)
-{
- /* 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.
- */
- fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n");
- fprintf(stderr, "with a kernel supporting the pivot_root system call. -Erik\n\n");
- errno=ENOSYS;
- return -1;
-}
-#else
-# if defined(__ia64__)
- int pivot_root(const char * new_root,const char * put_old)
- {
- return(syscall(__NR_pivot_root, new_root, put_old));
- }
-# else
- _syscall2(int,pivot_root,const char *,new_root,const char *,put_old);
-# endif
-#endif
-
-
-
-
-#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1))
-/* These syscalls are not included as part of libc5 */
-_syscall2(int, bdflush, int, func, int, data);
-
-#ifndef __alpha__
-# define __NR_klogctl __NR_syslog
- _syscall3(int, klogctl, int, type, char *, b, int, len);
-#endif
-
-#ifndef __NR_umount2
-# warning This kernel does not support the umount2 syscall
-# warning -> The umount2 system call is being stubbed out...
-int umount2(const char * special_file, int flags)
-{
- /* 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.
- */
- fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n");
- fprintf(stderr, "with a kernel supporting the umount2 system call. -Erik\n\n");
- errno=ENOSYS;
- return -1;
-}
-# else
-_syscall2(int, umount2, const char *, special_file, int, flags);
-#endif
-
-
-#endif /* __GNU_LIBRARY__ < 5 */
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/syslog_msg_with_name.c b/release/src/router/busybox/libbb/syslog_msg_with_name.c
deleted file mode 100644
index 5dadcc43..00000000
--- a/release/src/router/busybox/libbb/syslog_msg_with_name.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <sys/syslog.h>
-#include "libbb.h"
-
-void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg)
-{
- openlog(name, 0, facility);
- syslog(pri, "%s", msg);
- closelog();
-}
-
-void syslog_msg(int facility, int pri, const char *msg)
-{
- syslog_msg_with_name(applet_name, facility, pri, msg);
-}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/time.c b/release/src/router/busybox/libbb/time.c
new file mode 100644
index 00000000..850ac154
--- /dev/null
+++ b/release/src/router/busybox/libbb/time.c
@@ -0,0 +1,66 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#if ENABLE_MONOTONIC_SYSCALL
+
+#include <sys/syscall.h>
+/* Old glibc (< 2.3.4) does not provide this constant. We use syscall
+ * directly so this definition is safe. */
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 1
+#endif
+
+/* libc has incredibly messy way of doing this,
+ * typically requiring -lrt. We just skip all this mess */
+static void get_mono(struct timespec *ts)
+{
+ if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
+ bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
+}
+unsigned long long FAST_FUNC monotonic_ns(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+}
+unsigned long long FAST_FUNC monotonic_us(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
+}
+unsigned FAST_FUNC monotonic_sec(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec;
+}
+
+#else
+
+unsigned long long FAST_FUNC monotonic_ns(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
+}
+unsigned long long FAST_FUNC monotonic_us(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000ULL + tv.tv_usec;
+}
+unsigned FAST_FUNC monotonic_sec(void)
+{
+ return time(NULL);
+}
+
+#endif
diff --git a/release/src/router/busybox/libbb/time_string.c b/release/src/router/busybox/libbb/time_string.c
deleted file mode 100644
index 07652900..00000000
--- a/release/src/router/busybox/libbb/time_string.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <utime.h>
-#include "libbb.h"
-
-
-/*
- * Return the standard ls-like time string from a time_t
- * This is static and so is overwritten on each call.
- */
-const char *time_string(time_t timeVal)
-{
- time_t now;
- char *str;
- static char buf[26];
-
- time(&now);
-
- str = ctime(&timeVal);
-
- strcpy(buf, &str[4]);
- buf[12] = '\0';
-
- if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
- strcpy(&buf[7], &str[20]);
- buf[11] = '\0';
- }
-
- return buf;
-}
-
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/trim.c b/release/src/router/busybox/libbb/trim.c
index 76b87ca1..ea20ff37 100644
--- a/release/src/router/busybox/libbb/trim.c
+++ b/release/src/router/busybox/libbb/trim.c
@@ -2,52 +2,30 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
#include "libbb.h"
-
-void trim(char *s)
+void FAST_FUNC trim(char *s)
{
- int len = strlen(s);
+ size_t len = strlen(s);
+ size_t lws;
/* trim trailing whitespace */
- while ( len > 0 && isspace(s[len-1]))
- s[--len]='\0';
+ while (len && isspace(s[len-1]))
+ --len;
/* trim leading whitespace */
- memmove(s, &s[strspn(s, " \n\r\t\v")], len);
+ if (len) {
+ lws = strspn(s, " \n\r\t\v");
+ if (lws) {
+ len -= lws;
+ memmove(s, s + lws, len);
+ }
+ }
+ s[len] = '\0';
}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/libbb/u_signal_names.c b/release/src/router/busybox/libbb/u_signal_names.c
index 623b1031..915eea57 100644
--- a/release/src/router/busybox/libbb/u_signal_names.c
+++ b/release/src/router/busybox/libbb/u_signal_names.c
@@ -1,166 +1,180 @@
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-struct signal_name {
- const char *name;
- int number;
-};
+/* vi: set sw=4 ts=4: */
+/*
+ * Signal name/number conversion routines.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
-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 */
+#include "libbb.h"
+
+/* Believe it or not, but some arches have more than 32 SIGs!
+ * HPPA: SIGSTKFLT == 36. */
+
+static const char signals[][7] = {
+ // SUSv3 says kill must support these, and specifies the numerical values,
+ // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html
+ // {0, "EXIT"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"},
+ // {6, "ABRT"}, {9, "KILL"}, {14, "ALRM"}, {15, "TERM"}
+ // And Posix adds the following:
+ // {SIGILL, "ILL"}, {SIGTRAP, "TRAP"}, {SIGFPE, "FPE"}, {SIGUSR1, "USR1"},
+ // {SIGSEGV, "SEGV"}, {SIGUSR2, "USR2"}, {SIGPIPE, "PIPE"}, {SIGCHLD, "CHLD"},
+ // {SIGCONT, "CONT"}, {SIGSTOP, "STOP"}, {SIGTSTP, "TSTP"}, {SIGTTIN, "TTIN"},
+ // {SIGTTOU, "TTOU"}
+
+ [0] = "EXIT",
+#ifdef SIGHUP
+ [SIGHUP ] = "HUP",
#endif
-#ifdef SIGIOT
- { "IOT", SIGIOT }, /* 6, same as SIGABRT */
+#ifdef SIGINT
+ [SIGINT ] = "INT",
#endif
-#ifdef SIGEMT
- { "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */
+#ifdef SIGQUIT
+ [SIGQUIT ] = "QUIT",
+#endif
+#ifdef SIGILL
+ [SIGILL ] = "ILL",
+#endif
+#ifdef SIGTRAP
+ [SIGTRAP ] = "TRAP",
+#endif
+#ifdef SIGABRT
+ [SIGABRT ] = "ABRT",
#endif
#ifdef SIGBUS
- { "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
+ [SIGBUS ] = "BUS",
#endif
-#ifdef SIGSYS
- { "SYS", SIGSYS }, /* 12 (mips,alpha,sparc*) */
+#ifdef SIGFPE
+ [SIGFPE ] = "FPE",
+#endif
+#ifdef SIGKILL
+ [SIGKILL ] = "KILL",
+#endif
+#ifdef SIGUSR1
+ [SIGUSR1 ] = "USR1",
+#endif
+#ifdef SIGSEGV
+ [SIGSEGV ] = "SEGV",
+#endif
+#ifdef SIGUSR2
+ [SIGUSR2 ] = "USR2",
+#endif
+#ifdef SIGPIPE
+ [SIGPIPE ] = "PIPE",
+#endif
+#ifdef SIGALRM
+ [SIGALRM ] = "ALRM",
+#endif
+#ifdef SIGTERM
+ [SIGTERM ] = "TERM",
#endif
#ifdef SIGSTKFLT
- { "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */
+ [SIGSTKFLT] = "STKFLT",
#endif
-#ifdef SIGURG
- { "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
+#ifdef SIGCHLD
+ [SIGCHLD ] = "CHLD",
#endif
-#ifdef SIGIO
- { "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
+#ifdef SIGCONT
+ [SIGCONT ] = "CONT",
#endif
-#ifdef SIGPOLL
- { "POLL", SIGPOLL }, /* same as SIGIO */
+#ifdef SIGSTOP
+ [SIGSTOP ] = "STOP",
+#endif
+#ifdef SIGTSTP
+ [SIGTSTP ] = "TSTP",
#endif
-#ifdef SIGCLD
- { "CLD", SIGCLD }, /* same as SIGCHLD (mips) */
+#ifdef SIGTTIN
+ [SIGTTIN ] = "TTIN",
+#endif
+#ifdef SIGTTOU
+ [SIGTTOU ] = "TTOU",
+#endif
+#ifdef SIGURG
+ [SIGURG ] = "URG",
#endif
#ifdef SIGXCPU
- { "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
+ [SIGXCPU ] = "XCPU",
#endif
#ifdef SIGXFSZ
- { "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
+ [SIGXFSZ ] = "XFSZ",
#endif
#ifdef SIGVTALRM
- { "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
+ [SIGVTALRM] = "VTALRM",
#endif
#ifdef SIGPROF
- { "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
+ [SIGPROF ] = "PROF",
+#endif
+#ifdef SIGWINCH
+ [SIGWINCH ] = "WINCH",
+#endif
+#ifdef SIGPOLL
+ [SIGPOLL ] = "POLL",
#endif
#ifdef SIGPWR
- { "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
+ [SIGPWR ] = "PWR",
#endif
-#ifdef SIGINFO
- { "INFO", SIGINFO }, /* 29 (alpha) */
+#ifdef SIGSYS
+ [SIGSYS ] = "SYS",
#endif
-#ifdef SIGLOST
- { "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */
+};
+
+// Convert signal name to number.
+
+int FAST_FUNC get_signum(const char *name)
+{
+ unsigned i;
+
+ i = bb_strtou(name, NULL, 10);
+ if (!errno)
+ return i;
+ if (strncasecmp(name, "SIG", 3) == 0)
+ name += 3;
+ for (i = 0; i < ARRAY_SIZE(signals); i++)
+ if (strcasecmp(name, signals[i]) == 0)
+ return i;
+
+#if ENABLE_DESKTOP && (defined(SIGIOT) || defined(SIGIO))
+ /* SIGIO[T] are aliased to other names,
+ * thus cannot be stored in the signals[] array.
+ * Need special code to recognize them */
+ if ((name[0] | 0x20) == 'i' && (name[1] | 0x20) == 'o') {
+#ifdef SIGIO
+ if (!name[2])
+ return SIGIO;
#endif
-#ifdef SIGWINCH
- { "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
+#ifdef SIGIOT
+ if ((name[2] | 0x20) == 't' && !name[3])
+ return SIGIOT;
#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
+ return -1;
+}
+
+// Convert signal number to name
+
+const char* FAST_FUNC get_signame(int number)
+{
+ if ((unsigned)number < ARRAY_SIZE(signals)) {
+ if (signals[number][0]) /* if it's not an empty str */
+ return signals[number];
+ }
+
+ return itoa(number);
+}
- 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
-*/
+// Print the whole signal list
-const char *
-u_signal_names(const char *str_sig, int *signo, int startnum)
+void FAST_FUNC print_signames(void)
{
- 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++;
- }
- }
+ unsigned signo;
+
+ for (signo = 1; signo < ARRAY_SIZE(signals); signo++) {
+ const char *name = signals[signo];
+ if (name[0])
+ puts(name);
}
- if(s->name==0)
- return NULL;
- if(s!=signames)
- strcpy(retstr, prefix);
- else
- retstr[0] = 0;
- return strcat(retstr, s->name);
}
diff --git a/release/src/router/busybox/libbb/udp_io.c b/release/src/router/busybox/libbb/udp_io.c
new file mode 100644
index 00000000..b31f2841
--- /dev/null
+++ b/release/src/router/busybox/libbb/udp_io.c
@@ -0,0 +1,168 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/*
+ * This asks kernel to let us know dst addr/port of incoming packets
+ * We don't check for errors here. Not supported == won't be used
+ */
+void FAST_FUNC
+socket_want_pktinfo(int fd)
+{
+#ifdef IP_PKTINFO
+ setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int));
+#endif
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &const_int_1, sizeof(int));
+#endif
+}
+
+
+ssize_t FAST_FUNC
+send_to_from(int fd, void *buf, size_t len, int flags,
+ const struct sockaddr *to,
+ const struct sockaddr *from,
+ socklen_t tolen)
+{
+#ifndef IP_PKTINFO
+ return sendto(fd, buf, len, flags, to, tolen);
+#else
+ struct iovec iov[1];
+ struct msghdr msg;
+ union {
+ char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+ } u;
+ struct cmsghdr* cmsgptr;
+
+ if (from->sa_family != AF_INET
+#if ENABLE_FEATURE_IPV6
+ && from->sa_family != AF_INET6
+#endif
+ ) {
+ /* ANY local address */
+ return sendto(fd, buf, len, flags, to, tolen);
+ }
+
+ /* man recvmsg and man cmsg is needed to make sense of code below */
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+
+ memset(&u, 0, sizeof(u));
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (void *)(struct sockaddr *)to; /* or compiler will annoy us */
+ msg.msg_namelen = tolen;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &u;
+ msg.msg_controllen = sizeof(u);
+ msg.msg_flags = flags;
+
+ cmsgptr = CMSG_FIRSTHDR(&msg);
+ if (to->sa_family == AF_INET && from->sa_family == AF_INET) {
+ struct in_pktinfo *pktptr;
+ cmsgptr->cmsg_level = IPPROTO_IP;
+ cmsgptr->cmsg_type = IP_PKTINFO;
+ cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr));
+ /* pktptr->ipi_ifindex = 0; -- already done by memset(cbuf...) */
+ pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
+ }
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
+ struct in6_pktinfo *pktptr;
+ cmsgptr->cmsg_level = IPPROTO_IPV6;
+ cmsgptr->cmsg_type = IPV6_PKTINFO;
+ cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr));
+ /* pktptr->ipi6_ifindex = 0; -- already done by memset(cbuf...) */
+ pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr;
+ }
+#endif
+ msg.msg_controllen = cmsgptr->cmsg_len;
+
+ return sendmsg(fd, &msg, flags);
+#endif
+}
+
+/* NB: this will never set port# in 'to'!
+ * _Only_ IP/IPv6 address part of 'to' is _maybe_ modified.
+ * Typical usage is to preinit 'to' with "default" value
+ * before calling recv_from_to(). */
+ssize_t FAST_FUNC
+recv_from_to(int fd, void *buf, size_t len, int flags,
+ struct sockaddr *from, struct sockaddr *to,
+ socklen_t sa_size)
+{
+#ifndef IP_PKTINFO
+ return recvfrom(fd, buf, len, flags, from, &sa_size);
+#else
+ /* man recvmsg and man cmsg is needed to make sense of code below */
+ struct iovec iov[1];
+ union {
+ char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+ } u;
+ struct cmsghdr *cmsgptr;
+ struct msghdr msg;
+ ssize_t recv_length;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (struct sockaddr *)from;
+ msg.msg_namelen = sa_size;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &u;
+ msg.msg_controllen = sizeof(u);
+
+ recv_length = recvmsg(fd, &msg, flags);
+ if (recv_length < 0)
+ return recv_length;
+
+ /* Here we try to retrieve destination IP and memorize it */
+ for (cmsgptr = CMSG_FIRSTHDR(&msg);
+ cmsgptr != NULL;
+ cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)
+ ) {
+ if (cmsgptr->cmsg_level == IPPROTO_IP
+ && cmsgptr->cmsg_type == IP_PKTINFO
+ ) {
+#define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) )
+ to->sa_family = AF_INET;
+ ((struct sockaddr_in*)to)->sin_addr = pktinfo(cmsgptr)->ipi_addr;
+ /* ((struct sockaddr_in*)to)->sin_port = 123; */
+#undef pktinfo
+ break;
+ }
+#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ if (cmsgptr->cmsg_level == IPPROTO_IPV6
+ && cmsgptr->cmsg_type == IPV6_PKTINFO
+ ) {
+#define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) )
+ to->sa_family = AF_INET6;
+ ((struct sockaddr_in6*)to)->sin6_addr = pktinfo(cmsgptr)->ipi6_addr;
+ /* ((struct sockaddr_in6*)to)->sin6_port = 123; */
+#undef pktinfo
+ break;
+ }
+#endif
+ }
+ return recv_length;
+#endif
+}
diff --git a/release/src/router/busybox/libbb/unarchive.c b/release/src/router/busybox/libbb/unarchive.c
deleted file mode 100644
index 91db2e3b..00000000
--- a/release/src/router/busybox/libbb/unarchive.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright (C) 2000 by Glenn McGrath
- * Copyright (C) 2001 by Laurence Anderson
- *
- * Based on previous work by busybox developers and others.
- *
- * 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 <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <utime.h>
-#include "libbb.h"
-
-extern void seek_sub_file(FILE *src_stream, const int count);
-extern char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry,
- const int function, const char *prefix);
-
-
-#ifdef L_archive_offset
-off_t archive_offset;
-#else
-extern off_t archive_offset;
-#endif
-
-#ifdef L_seek_sub_file
-void seek_sub_file(FILE *src_stream, const int count)
-{
- int i;
- /* Try to fseek as faster */
- archive_offset += count;
- if (fseek(src_stream, count, SEEK_CUR) != 0 && errno == ESPIPE) {
- for (i = 0; i < count; i++) {
- fgetc(src_stream);
- }
- }
- return;
-}
-#endif
-
-
-
-#ifdef L_extract_archive
-/* Extract the data postioned at src_stream to either filesystem, stdout or
- * buffer depending on the value of 'function' which is defined in libbb.h
- *
- * prefix doesnt have to be just a directory, it may prefix the filename as well.
- *
- * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath
- * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have
- * 'dpkg.' as their prefix
- *
- * For this reason if prefix does point to a dir then it must end with a
- * trailing '/' or else the last dir will be assumed to be the file prefix
- */
-char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry,
- const int function, const char *prefix)
-{
- FILE *dst_stream = NULL;
- char *full_name = NULL;
- char *buffer = NULL;
- struct utimbuf t;
-
- /* prefix doesnt have to be a proper path it may prepend
- * the filename as well */
- if (prefix != NULL) {
- /* strip leading '/' in filename to extract as prefix may not be dir */
- /* Cant use concat_path_file here as prefix might not be a directory */
- char *path = file_entry->name;
- if (strncmp("./", path, 2) == 0) {
- path += 2;
- if (strlen(path) == 0) {
- return(NULL);
- }
- }
- full_name = xmalloc(strlen(prefix) + strlen(path) + 1);
- strcpy(full_name, prefix);
- strcat(full_name, path);
- } else {
- full_name = file_entry->name;
- }
- if (function & extract_to_stdout) {
- if (S_ISREG(file_entry->mode)) {
- copy_file_chunk(src_stream, out_stream, file_entry->size);
- archive_offset += file_entry->size;
- }
- }
- else if (function & extract_one_to_buffer) {
- if (S_ISREG(file_entry->mode)) {
- buffer = (char *) xmalloc(file_entry->size + 1);
- fread(buffer, 1, file_entry->size, src_stream);
- buffer[file_entry->size] = '\0';
- archive_offset += file_entry->size;
- return(buffer);
- }
- }
- else if (function & extract_all_to_fs) {
- struct stat oldfile;
- int stat_res;
- stat_res = lstat (full_name, &oldfile);
- if (stat_res == 0) { /* The file already exists */
- if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) {
- if (!S_ISDIR(oldfile.st_mode)) {
- unlink(full_name); /* Directories might not be empty etc */
- }
- } else {
- if ((function & extract_quiet) != extract_quiet) {
- error_msg("%s not created: newer or same age file exists", file_entry->name);
- }
- seek_sub_file(src_stream, file_entry->size);
- return (NULL);
- }
- }
- if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */
- char *parent = dirname(full_name);
- if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) {
- if ((function & extract_quiet) != extract_quiet) {
- error_msg("couldn't create leading directories");
- }
- }
- free (parent);
- }
- switch(file_entry->mode & S_IFMT) {
- case S_IFREG:
- if (file_entry->link_name) { /* Found a cpio hard link */
- if (link(file_entry->link_name, full_name) != 0) {
- if ((function & extract_quiet) != extract_quiet) {
- perror_msg("Cannot link from %s to '%s'",
- file_entry->name, file_entry->link_name);
- }
- }
- } else {
- if ((dst_stream = wfopen(full_name, "w")) == NULL) {
- seek_sub_file(src_stream, file_entry->size);
- return NULL;
- }
- archive_offset += file_entry->size;
- copy_file_chunk(src_stream, dst_stream, file_entry->size);
- fclose(dst_stream);
- }
- break;
- case S_IFDIR:
- if (stat_res != 0) {
- if (mkdir(full_name, file_entry->mode) < 0) {
- if ((function & extract_quiet) != extract_quiet) {
- perror_msg("extract_archive: ");
- }
- }
- }
- break;
- case S_IFLNK:
- if (symlink(file_entry->link_name, full_name) < 0) {
- if ((function & extract_quiet) != extract_quiet) {
- perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name);
- }
- return NULL;
- }
- break;
- case S_IFSOCK:
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- if (mknod(full_name, file_entry->mode, file_entry->device) == -1) {
- if ((function & extract_quiet) != extract_quiet) {
- perror_msg("Cannot create node %s", file_entry->name);
- }
- return NULL;
- }
- break;
- }
-
- /* Changing a symlink's properties normally changes the properties of the
- * file pointed to, so dont try and change the date or mode, lchown does
- * does the right thing, but isnt available in older versions of libc */
- if (S_ISLNK(file_entry->mode)) {
-#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1)
- lchown(full_name, file_entry->uid, file_entry->gid);
-#endif
- } else {
- if (function & extract_preserve_date) {
- t.actime = file_entry->mtime;
- t.modtime = file_entry->mtime;
- utime(full_name, &t);
- }
- chmod(full_name, file_entry->mode);
- chown(full_name, file_entry->uid, file_entry->gid);
- }
- } else {
- /* If we arent extracting data we have to skip it,
- * if data size is 0 then then just do it anyway
- * (saves testing for it) */
- seek_sub_file(src_stream, file_entry->size);
- }
-
- /* extract_list and extract_verbose_list can be used in conjunction
- * with one of the above four extraction functions, so do this seperately */
- if (function & extract_verbose_list) {
- fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode),
- file_entry->uid, file_entry->gid,
- (int) file_entry->size, time_string(file_entry->mtime));
- }
- if ((function & extract_list) || (function & extract_verbose_list)){
- /* fputs doesnt add a trailing \n, so use fprintf */
- fprintf(out_stream, "%s\n", file_entry->name);
- }
-
- free(full_name);
-
- return(NULL); /* Maybe we should say if failed */
-}
-#endif
-
-#ifdef L_unarchive
-char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_headers)(FILE *),
- const int extract_function, const char *prefix, char **extract_names)
-{
- file_header_t *file_entry;
- int found;
- int i;
- char *buffer = NULL;
-
- archive_offset = 0;
- while ((file_entry = get_headers(src_stream)) != NULL) {
- found = FALSE;
- if (extract_names == NULL) {
- found = TRUE;
- } else {
- for(i = 0; extract_names[i] != 0; i++) {
- if (strcmp(extract_names[i], file_entry->name) == 0) {
- found = TRUE;
- }
- }
- }
-
- if (found) {
- buffer = extract_archive(src_stream, out_stream, file_entry, extract_function, prefix);
- } else {
- /* seek past the data entry */
- seek_sub_file(src_stream, file_entry->size);
- }
- }
- return(buffer);
-}
-#endif
-
-#ifdef L_get_header_ar
-file_header_t *get_header_ar(FILE *src_stream)
-{
- file_header_t *typed;
- union {
- char raw[60];
- struct {
- char name[16];
- char date[12];
- char uid[6];
- char gid[6];
- char mode[8];
- char size[10];
- char magic[2];
- } formated;
- } ar;
- static char *ar_long_names;
-
- if (fread(ar.raw, 1, 60, src_stream) != 60) {
- return(NULL);
- }
- archive_offset += 60;
- /* align the headers based on the header magic */
- if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) {
- /* some version of ar, have an extra '\n' after each data entry,
- * this puts the next header out by 1 */
- if (ar.formated.magic[1] != '`') {
- error_msg("Invalid magic");
- return(NULL);
- }
- /* read the next char out of what would be the data section,
- * if its a '\n' then it is a valid header offset by 1*/
- archive_offset++;
- if (fgetc(src_stream) != '\n') {
- error_msg("Invalid magic");
- return(NULL);
- }
- /* fix up the header, we started reading 1 byte too early */
- /* raw_header[60] wont be '\n' as it should, but it doesnt matter */
- memmove(ar.raw, &ar.raw[1], 59);
- }
-
- typed = (file_header_t *) xcalloc(1, sizeof(file_header_t));
-
- typed->size = (size_t) atoi(ar.formated.size);
- /* long filenames have '/' as the first character */
- if (ar.formated.name[0] == '/') {
- if (ar.formated.name[1] == '/') {
- /* If the second char is a '/' then this entries data section
- * stores long filename for multiple entries, they are stored
- * in static variable long_names for use in future entries */
- ar_long_names = (char *) xrealloc(ar_long_names, typed->size);
- fread(ar_long_names, 1, typed->size, src_stream);
- archive_offset += typed->size;
- /* This ar entries data section only contained filenames for other records
- * they are stored in the static ar_long_names for future reference */
- return (get_header_ar(src_stream)); /* Return next header */
- } else if (ar.formated.name[1] == ' ') {
- /* This is the index of symbols in the file for compilers */
- seek_sub_file(src_stream, typed->size);
- return (get_header_ar(src_stream)); /* Return next header */
- } else {
- /* The number after the '/' indicates the offset in the ar data section
- (saved in variable long_name) that conatains the real filename */
- if (!ar_long_names) {
- error_msg("Cannot resolve long file name");
- return (NULL);
- }
- typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1]));
- }
- } else {
- /* short filenames */
- typed->name = xcalloc(1, 16);
- strncpy(typed->name, ar.formated.name, 16);
- }
- typed->name[strcspn(typed->name, " /")]='\0';
-
- /* convert the rest of the now valid char header to its typed struct */
- parse_mode(ar.formated.mode, &typed->mode);
- typed->mtime = atoi(ar.formated.date);
- typed->uid = atoi(ar.formated.uid);
- typed->gid = atoi(ar.formated.gid);
-
- return(typed);
-}
-#endif
-
-#ifdef L_get_header_cpio
-struct hardlinks {
- file_header_t *entry;
- int inode;
- struct hardlinks *next;
-};
-
-file_header_t *get_header_cpio(FILE *src_stream)
-{
- file_header_t *cpio_entry = NULL;
- char cpio_header[110];
- int namesize;
- char dummy[16];
- int major, minor, nlink, inode;
- static struct hardlinks *saved_hardlinks = NULL;
- static int pending_hardlinks = 0;
-
- if (pending_hardlinks) { /* Deal with any pending hardlinks */
- struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL;
- while (tmp) {
- if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
- cpio_entry = tmp->entry;
- if (oldtmp) oldtmp->next = tmp->next; /* Remove item from linked list */
- else saved_hardlinks = tmp->next;
- free(tmp);
- return (cpio_entry);
- }
- oldtmp = tmp;
- tmp = tmp->next;
- }
- pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
- }
-
- /* There can be padding before archive header */
- seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4);
- if (fread(cpio_header, 1, 110, src_stream) == 110) {
- archive_offset += 110;
- if (strncmp(cpio_header, "07070", 5) != 0) {
- error_msg("Unsupported format or invalid magic");
- return(NULL);
- }
- switch (cpio_header[5]) {
- case '2': /* "crc" header format */
- /* Doesnt do the crc check yet */
- case '1': /* "newc" header format */
- cpio_entry = (file_header_t *) xcalloc(1, sizeof(file_header_t));
- sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
- dummy, &inode, (unsigned int*)&cpio_entry->mode,
- (unsigned int*)&cpio_entry->uid, (unsigned int*)&cpio_entry->gid,
- &nlink, &cpio_entry->mtime, &cpio_entry->size,
- dummy, &major, &minor, &namesize, dummy);
-
- cpio_entry->name = (char *) xcalloc(1, namesize);
- fread(cpio_entry->name, 1, namesize, src_stream); /* Read in filename */
- archive_offset += namesize;
- /* Skip padding before file contents */
- seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4);
- if (strcmp(cpio_entry->name, "TRAILER!!!") == 0) {
- printf("%d blocks\n", (int) (archive_offset % 512 ? (archive_offset / 512) + 1 : archive_offset / 512)); /* Always round up */
- if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
- struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL;
- while (tmp) {
- error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
- oldtmp = tmp;
- tmp = tmp->next;
- free (oldtmp->entry->name);
- free (oldtmp->entry);
- free (oldtmp);
- }
- saved_hardlinks = NULL;
- pending_hardlinks = 0;
- }
- return(NULL);
- }
-
- if (S_ISLNK(cpio_entry->mode)) {
- cpio_entry->link_name = (char *) xcalloc(1, cpio_entry->size + 1);
- fread(cpio_entry->link_name, 1, cpio_entry->size, src_stream);
- archive_offset += cpio_entry->size;
- cpio_entry->size = 0; /* Stop possiable seeks in future */
- }
- if (nlink > 1 && !S_ISDIR(cpio_entry->mode)) {
- if (cpio_entry->size == 0) { /* Put file on a linked list for later */
- struct hardlinks *new = xmalloc(sizeof(struct hardlinks));
- new->next = saved_hardlinks;
- new->inode = inode;
- new->entry = cpio_entry;
- saved_hardlinks = new;
- return(get_header_cpio(src_stream)); /* Recurse to next file */
- } else { /* Found the file with data in */
- struct hardlinks *tmp = saved_hardlinks;
- pending_hardlinks = 1;
- while (tmp) {
- if (tmp->inode == inode) {
- tmp->entry->link_name = xstrdup(cpio_entry->name);
- nlink--;
- }
- tmp = tmp->next;
- }
- if (nlink > 1) error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
- }
- }
- cpio_entry->device = (major << 8) | minor;
- break;
- default:
- error_msg("Unsupported format");
- return(NULL);
- }
- if (ferror(src_stream) || feof(src_stream)) {
- perror_msg("Stream error");
- return(NULL);
- }
- }
- return(cpio_entry);
-}
-#endif
-
-#ifdef L_get_header_tar
-file_header_t *get_header_tar(FILE *tar_stream)
-{
- union {
- unsigned char raw[512];
- struct {
- char name[100]; /* 0-99 */
- char mode[8]; /* 100-107 */
- char uid[8]; /* 108-115 */
- char gid[8]; /* 116-123 */
- char size[12]; /* 124-135 */
- char mtime[12]; /* 136-147 */
- char chksum[8]; /* 148-155 */
- char typeflag; /* 156-156 */
- char linkname[100]; /* 157-256 */
- char magic[6]; /* 257-262 */
- char version[2]; /* 263-264 */
- char uname[32]; /* 265-296 */
- char gname[32]; /* 297-328 */
- char devmajor[8]; /* 329-336 */
- char devminor[8]; /* 337-344 */
- char prefix[155]; /* 345-499 */
- char padding[12]; /* 500-512 */
- } formated;
- } tar;
- file_header_t *tar_entry = NULL;
- long i;
- long sum = 0;
-
- if (archive_offset % 512 != 0) {
- seek_sub_file(tar_stream, 512 - (archive_offset % 512));
- }
-
- if (fread(tar.raw, 1, 512, tar_stream) != 512) {
- /* Unfortunatly its common for tar files to have all sorts of
- * trailing garbage, fail silently */
-// error_msg("Couldnt read header");
- return(NULL);
- }
- archive_offset += 512;
-
- /* Check header has valid magic, unfortunately some tar files
- * have empty (0'ed) tar entries at the end, which will
- * cause this to fail, so fail silently for now
- */
- if (strncmp(tar.formated.magic, "ustar", 5) != 0) {
- return(NULL);
- }
-
- /* Do checksum on headers */
- for (i = 0; i < 148 ; i++) {
- sum += tar.raw[i];
- }
- sum += ' ' * 8;
- for (i = 156; i < 512 ; i++) {
- sum += tar.raw[i];
- }
- if (sum != strtol(tar.formated.chksum, NULL, 8)) {
- error_msg("Invalid tar header checksum");
- return(NULL);
- }
-
- /* convert to type'ed variables */
- tar_entry = xcalloc(1, sizeof(file_header_t));
- tar_entry->name = xstrdup(tar.formated.name);
-
- parse_mode(tar.formated.mode, &tar_entry->mode);
- tar_entry->uid = strtol(tar.formated.uid, NULL, 8);
- tar_entry->gid = strtol(tar.formated.gid, NULL, 8);
- tar_entry->size = strtol(tar.formated.size, NULL, 8);
- tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8);
- tar_entry->link_name = strlen(tar.formated.linkname) ?
- xstrdup(tar.formated.linkname) : NULL;
- tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) +
- strtol(tar.formated.devminor, NULL, 8);
-
- return(tar_entry);
-}
-#endif
-
-#ifdef L_deb_extract
-char *deb_extract(const char *package_filename, FILE *out_stream,
- const int extract_function, const char *prefix, const char *filename)
-{
- FILE *deb_stream;
- FILE *uncompressed_stream = NULL;
- file_header_t *ar_header = NULL;
- char **file_list = NULL;
- char *output_buffer = NULL;
- char *ared_file = NULL;
- char ar_magic[8];
- int gunzip_pid;
-
- if (filename != NULL) {
- file_list = xmalloc(sizeof(char *) * 2);
- file_list[0] = xstrdup(filename);
- file_list[1] = NULL;
- }
-
- if (extract_function & extract_control_tar_gz) {
- ared_file = xstrdup("control.tar.gz");
- }
- else if (extract_function & extract_data_tar_gz) {
- ared_file = xstrdup("data.tar.gz");
- }
-
- /* open the debian package to be worked on */
- deb_stream = wfopen(package_filename, "r");
- if (deb_stream == NULL) {
- return(NULL);
- }
- /* set the buffer size */
- setvbuf(deb_stream, NULL, _IOFBF, 0x8000);
-
- /* check ar magic */
- fread(ar_magic, 1, 8, deb_stream);
- if (strncmp(ar_magic,"!<arch>",7) != 0) {
- error_msg_and_die("invalid magic");
- }
- archive_offset = 8;
-
- while ((ar_header = get_header_ar(deb_stream)) != NULL) {
- if (strcmp(ared_file, ar_header->name) == 0) {
- /* open a stream of decompressed data */
- uncompressed_stream = gz_open(deb_stream, &gunzip_pid);
- archive_offset = 0;
- output_buffer = unarchive(uncompressed_stream, out_stream, get_header_tar, extract_function, prefix, file_list);
- }
- seek_sub_file(deb_stream, ar_header->size);
- }
- gz_close(gunzip_pid);
- fclose(deb_stream);
- fclose(uncompressed_stream);
- free(ared_file);
- return(output_buffer);
-}
-#endif
diff --git a/release/src/router/busybox/libbb/unzip.c b/release/src/router/busybox/libbb/unzip.c
deleted file mode 100644
index 67cb540d..00000000
--- a/release/src/router/busybox/libbb/unzip.c
+++ /dev/null
@@ -1,1007 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * gunzip implementation for busybox
- *
- * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
- * based on gzip sources
- *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
- *
- * General cleanup to better adhere to the style guide and make use of standard
- * busybox functions by Glenn McGrath <bug1@optushome.com.au>
- *
- * 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
- *
- *
- * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include "libbb.h"
-
-static FILE *in_file, *out_file;
-
-/* these are freed by gz_close */
-static unsigned char *window;
-static unsigned long *crc_table;
-
-static unsigned long crc = 0xffffffffL; /* shift register contents */
-
-/* Return codes from gzip */
-static const int ERROR = 1;
-
-/*
- * window size--must be a power of two, and
- * at least 32K for zip's deflate method
- */
-static const int WSIZE = 0x8000;
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */
-static const int N_MAX = 288; /* maximum number of codes in any set */
-
-static long bytes_out; /* number of output bytes */
-static unsigned long outcnt; /* bytes in output buffer */
-
-static unsigned hufts; /* track memory usage */
-static unsigned long bb; /* bit buffer */
-static unsigned bk; /* bits in bit buffer */
-
-typedef struct huft_s {
- unsigned char e; /* number of extra bits or operation */
- unsigned char b; /* number of bits in this code or subcode */
- union {
- unsigned short n; /* literal, length base, or distance base */
- struct huft_s *t; /* pointer to next level of table */
- } v;
-} huft_t;
-
-static const unsigned short mask_bits[] = {
- 0x0000,
- 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
- 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-//static int error_number = 0;
-/* ========================================================================
- * Signal and error handler.
- */
-
-static void abort_gzip()
-{
- error_msg("gzip aborted\n");
- exit(ERROR);
-}
-
-static void make_crc_table()
-{
- unsigned long table_entry; /* crc shift register */
- unsigned long poly = 0; /* polynomial exclusive-or pattern */
- int i; /* counter for all possible eight bit values */
- int k; /* byte being shifted into crc apparatus */
-
- /* terms of polynomial defining this crc (except x^32): */
- static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
- crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long));
-
- /* Make exclusive-or pattern from polynomial (0xedb88320) */
- for (i = 0; i < sizeof(p)/sizeof(int); i++)
- poly |= 1L << (31 - p[i]);
-
- /* Compute and print table of CRC's, five per line */
- for (i = 0; i < 256; i++) {
- table_entry = i;
- /* The idea to initialize the register with the byte instead of
- * zero was stolen from Haruhiko Okumura's ar002
- */
- for (k = 8; k; k--) {
- table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1;
- }
- crc_table[i]=table_entry;
- }
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
- int n;
-
- if (outcnt == 0)
- return;
-
- for (n = 0; n < outcnt; n++) {
- crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8);
- }
-
- if (fwrite(window, 1, outcnt, out_file) != outcnt) {
- error_msg_and_die("Couldnt write");
- }
- bytes_out += (unsigned long) outcnt;
- outcnt = 0;
-}
-
-/*
- * Free the malloc'ed tables built by huft_build(), which makes a linked
- * list of the tables it made, with the links in a dummy first entry of
- * each table.
- * t: table to free
- */
-static int huft_free(huft_t *t)
-{
- huft_t *p, *q;
-
- /* Go through linked list, freeing from the malloced (t[-1]) address. */
- p = t;
- while (p != (huft_t *) NULL) {
- q = (--p)->v.t;
- free((char *) p);
- p = q;
- }
- return 0;
-}
-
-/* Given a list of code lengths and a maximum table size, make a set of
- * tables to decode that set of codes. Return zero on success, one if
- * the given code set is incomplete (the tables are still built in this
- * case), two if the input is invalid (all zero length codes or an
- * oversubscribed set of lengths), and three if not enough memory.
- *
- * b: code lengths in bits (all assumed <= BMAX)
- * n: number of codes (assumed <= N_MAX)
- * s: number of simple-valued codes (0..s-1)
- * d: list of base values for non-simple codes
- * e: list of extra bits for non-simple codes
- * t: result: starting table
- * m: maximum lookup bits, returns actual
- */
-static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s,
- const unsigned short *d, const unsigned short *e, huft_t **t, int *m)
-{
- unsigned a; /* counter for codes of length k */
- unsigned c[BMAX + 1]; /* bit length count table */
- unsigned f; /* i repeats in table every f entries */
- int g; /* maximum code length */
- int h; /* table level */
- register unsigned i; /* counter, current code */
- register unsigned j; /* counter */
- register int k; /* number of bits in current code */
- int l; /* bits per table (returned in m) */
- register unsigned *p; /* pointer into c[], b[], or v[] */
- register huft_t *q; /* points to current table */
- huft_t r; /* table entry for structure assignment */
- huft_t *u[BMAX]; /* table stack */
- unsigned v[N_MAX]; /* values in order of bit length */
- register int w; /* bits before this table == (l * h) */
- unsigned x[BMAX + 1]; /* bit offsets, then code stack */
- unsigned *xp; /* pointer into x */
- int y; /* number of dummy codes added */
- unsigned z; /* number of entries in current table */
-
- /* Generate counts for each bit length */
- memset ((void *)(c), 0, sizeof(c));
- p = b;
- i = n;
- do {
- c[*p]++; /* assume all entries <= BMAX */
- p++; /* Can't combine with above line (Solaris bug) */
- } while (--i);
- if (c[0] == n) { /* null input--all zero length codes */
- *t = (huft_t *) NULL;
- *m = 0;
- return 0;
- }
-
- /* Find minimum and maximum length, bound *m by those */
- l = *m;
- for (j = 1; j <= BMAX; j++)
- if (c[j])
- break;
- k = j; /* minimum code length */
- if ((unsigned) l < j)
- l = j;
- for (i = BMAX; i; i--)
- if (c[i])
- break;
- g = i; /* maximum code length */
- if ((unsigned) l > i)
- l = i;
- *m = l;
-
- /* Adjust last length count to fill out codes, if needed */
- for (y = 1 << j; j < i; j++, y <<= 1)
- if ((y -= c[j]) < 0)
- return 2; /* bad input: more codes than bits */
- if ((y -= c[i]) < 0)
- return 2;
- c[i] += y;
-
- /* Generate starting offsets into the value table for each length */
- x[1] = j = 0;
- p = c + 1;
- xp = x + 2;
- while (--i) { /* note that i == g from above */
- *xp++ = (j += *p++);
- }
-
- /* Make a table of values in order of bit lengths */
- p = b;
- i = 0;
- do {
- if ((j = *p++) != 0)
- v[x[j]++] = i;
- } while (++i < n);
-
- /* Generate the Huffman codes and for each, make the table entries */
- x[0] = i = 0; /* first Huffman code is zero */
- p = v; /* grab values in bit order */
- h = -1; /* no tables yet--level -1 */
- w = -l; /* bits decoded == (l * h) */
- u[0] = (huft_t *) NULL; /* just to keep compilers happy */
- q = (huft_t *) NULL; /* ditto */
- z = 0; /* ditto */
-
- /* go through the bit lengths (k already is bits in shortest code) */
- for (; k <= g; k++) {
- a = c[k];
- while (a--) {
- /* here i is the Huffman code of length k bits for value *p */
- /* make tables up to required level */
- while (k > w + l) {
- h++;
- w += l; /* previous table always l bits */
-
- /* compute minimum size table less than or equal to l bits */
- z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
- if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */
- f -= a + 1; /* deduct codes from patterns left */
- xp = c + k;
- while (++j < z) { /* try smaller tables up to z bits */
- if ((f <<= 1) <= *++xp)
- break; /* enough codes to use up j bits */
- f -= *xp; /* else deduct codes from patterns */
- }
- }
- z = 1 << j; /* table entries for j-bit table */
-
- /* allocate and link in new table */
- if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) {
- if (h) {
- huft_free(u[0]);
- }
- return 3; /* not enough memory */
- }
- hufts += z + 1; /* track memory usage */
- *t = q + 1; /* link to list for huft_free() */
- *(t = &(q->v.t)) = NULL;
- u[h] = ++q; /* table starts after link */
-
- /* connect to last table, if there is one */
- if (h) {
- x[h] = i; /* save pattern for backing up */
- r.b = (unsigned char) l; /* bits to dump before this table */
- r.e = (unsigned char) (16 + j); /* bits in this table */
- r.v.t = q; /* pointer to this table */
- j = i >> (w - l); /* (get around Turbo C bug) */
- u[h - 1][j] = r; /* connect to last table */
- }
- }
-
- /* set up table entry in r */
- r.b = (unsigned char) (k - w);
- if (p >= v + n)
- r.e = 99; /* out of values--invalid code */
- else if (*p < s) {
- r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */
- r.v.n = (unsigned short) (*p); /* simple code is just the value */
- p++; /* one compiler does not like *p++ */
- } else {
- r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */
- r.v.n = d[*p++ - s];
- }
-
- /* fill code-like entries with r */
- f = 1 << (k - w);
- for (j = i >> w; j < z; j += f)
- q[j] = r;
-
- /* backwards increment the k-bit code i */
- for (j = 1 << (k - 1); i & j; j >>= 1)
- i ^= j;
- i ^= j;
-
- /* backup over finished tables */
- while ((i & ((1 << w) - 1)) != x[h]) {
- h--; /* don't need to update q */
- w -= l;
- }
- }
- }
- /* Return true (1) if we were given an incomplete table */
- return y != 0 && g != 1;
-}
-
-/*
- * inflate (decompress) the codes in a deflated (compressed) block.
- * Return an error code or zero if it all goes ok.
- *
- * tl, td: literal/length and distance decoder tables
- * bl, bd: number of bits decoded by tl[] and td[]
- */
-static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd)
-{
- register unsigned long e; /* table entry flag/number of extra bits */
- unsigned long n, d; /* length and index for copy */
- unsigned long w; /* current window position */
- huft_t *t; /* pointer to table entry */
- unsigned ml, md; /* masks for bl and bd bits */
- register unsigned long b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
- /* make local copies of globals */
- b = bb; /* initialize bit buffer */
- k = bk;
- w = outcnt; /* initialize window position */
-
- /* inflate the coded data */
- ml = mask_bits[bl]; /* precompute masks for speed */
- md = mask_bits[bd];
- for (;;) { /* do until end of block */
- while (k < (unsigned) bl) {
- b |= ((unsigned long)fgetc(in_file)) << k;
- k += 8;
- }
- if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
- do {
- if (e == 99) {
- return 1;
- }
- b >>= t->b;
- k -= t->b;
- e -= 16;
- while (k < e) {
- b |= ((unsigned long)fgetc(in_file)) << k;
- k += 8;
- }
- } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
- b >>= t->b;
- k -= t->b;
- if (e == 16) { /* then it's a literal */
- window[w++] = (unsigned char) t->v.n;
- if (w == WSIZE) {
- outcnt=(w),
- flush_window();
- w = 0;
- }
- } else { /* it's an EOB or a length */
-
- /* exit if end of block */
- if (e == 15) {
- break;
- }
-
- /* get length of block to copy */
- while (k < e) {
- b |= ((unsigned long)fgetc(in_file)) << k;
- k += 8;
- }
- n = t->v.n + ((unsigned) b & mask_bits[e]);
- b >>= e;
- k -= e;
-
- /* decode distance of block to copy */
- while (k < (unsigned) bd) {
- b |= ((unsigned long)fgetc(in_file)) << k;
- k += 8;
- }
-
- if ((e = (t = td + ((unsigned) b & md))->e) > 16)
- do {
- if (e == 99)
- return 1;
- b >>= t->b;
- k -= t->b;
- e -= 16;
- while (k < e) {
- b |= ((unsigned long)fgetc(in_file)) << k;
- k += 8;
- }
- } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
- b >>= t->b;
- k -= t->b;
- while (k < e) {
- b |= ((unsigned long)fgetc(in_file)) << k;
- k += 8;
- }
- d = w - t->v.n - ((unsigned) b & mask_bits[e]);
- b >>= e;
- k -= e;
-
- /* do the copy */
- do {
- n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e);
-#if !defined(NOMEMCPY) && !defined(DEBUG)
- if (w - d >= e) { /* (this test assumes unsigned comparison) */
- memcpy(window + w, window + d, e);
- w += e;
- d += e;
- } else /* do it slow to avoid memcpy() overlap */
-#endif /* !NOMEMCPY */
- do {
- window[w++] = window[d++];
- } while (--e);
- if (w == WSIZE) {
- outcnt=(w),
- flush_window();
- w = 0;
- }
- } while (n);
- }
- }
-
- /* restore the globals from the locals */
- outcnt = w; /* restore global window pointer */
- bb = b; /* restore global bit buffer */
- bk = k;
-
- /* done */
- return 0;
-}
-
-/*
- * decompress an inflated block
- * e: last block flag
- *
- * GLOBAL VARIABLES: bb, kk,
- */
-static int inflate_block(int *e)
-{
- unsigned t; /* block type */
- register unsigned long b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
- static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
- };
- /* note: see note #13 above about the 258 in this list. */
- static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
- }; /* 99==invalid */
- static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577
- };
- static unsigned short cpdext[] = { /* Extra bits for distance codes */
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 13, 13
- };
-
- /* make local bit buffer */
- b = bb;
- k = bk;
-
- /* read in last block bit */
- while (k < 1) {
- b |= ((unsigned long)fgetc(in_file)) << k;
- k += 8;
- }
- *e = (int) b & 1;
- b >>= 1;
- k -= 1;
-
- /* read in block type */
- while (k < 2) {
- b |= ((unsigned long)fgetc(in_file)) << k;
- k += 8;
- }
- t = (unsigned) b & 3;
- b >>= 2;
- k -= 2;
-
- /* restore the global bit buffer */
- bb = b;
- bk = k;
-
- /* inflate that block type */
- switch (t) {
- case 0: /* Inflate stored */
- {
- unsigned long n; /* number of bytes in block */
- unsigned long w; /* current window position */
- register unsigned long b_stored; /* bit buffer */
- register unsigned long k_stored; /* number of bits in bit buffer */
-
- /* make local copies of globals */
- b_stored = bb; /* initialize bit buffer */
- k_stored = bk;
- w = outcnt; /* initialize window position */
-
- /* go to byte boundary */
- n = k_stored & 7;
- b_stored >>= n;
- k_stored -= n;
-
- /* get the length and its complement */
- while (k_stored < 16) {
- b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
- k_stored += 8;
- }
- n = ((unsigned) b_stored & 0xffff);
- b_stored >>= 16;
- k_stored -= 16;
- while (k_stored < 16) {
- b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
- k_stored += 8;
- }
- if (n != (unsigned) ((~b_stored) & 0xffff)) {
- return 1; /* error in compressed data */
- }
- b_stored >>= 16;
- k_stored -= 16;
-
- /* read and output the compressed data */
- while (n--) {
- while (k_stored < 8) {
- b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
- k_stored += 8;
- }
- window[w++] = (unsigned char) b_stored;
- if (w == (unsigned long)WSIZE) {
- outcnt=(w),
- flush_window();
- w = 0;
- }
- b_stored >>= 8;
- k_stored -= 8;
- }
-
- /* restore the globals from the locals */
- outcnt = w; /* restore global window pointer */
- bb = b_stored; /* restore global bit buffer */
- bk = k_stored;
- return 0;
- }
- case 1: /* Inflate fixed
- * decompress an inflated type 1 (fixed Huffman codes) block. We should
- * either replace this with a custom decoder, or at least precompute the
- * Huffman tables.
- */
- {
- int i; /* temporary variable */
- huft_t *tl; /* literal/length code table */
- huft_t *td; /* distance code table */
- int bl; /* lookup bits for tl */
- int bd; /* lookup bits for td */
- unsigned int l[288]; /* length list for huft_build */
-
- /* set up literal table */
- for (i = 0; i < 144; i++) {
- l[i] = 8;
- }
- for (; i < 256; i++) {
- l[i] = 9;
- }
- for (; i < 280; i++) {
- l[i] = 7;
- }
- for (; i < 288; i++) { /* make a complete, but wrong code set */
- l[i] = 8;
- }
- bl = 7;
- if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
- return i;
- }
-
- /* set up distance table */
- for (i = 0; i < 30; i++) { /* make an incomplete code set */
- l[i] = 5;
- }
- bd = 5;
- if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
- huft_free(tl);
- return i;
- }
-
- /* decompress until an end-of-block code */
- if (inflate_codes(tl, td, bl, bd))
- return 1;
-
- /* free the decoding tables, return */
- huft_free(tl);
- huft_free(td);
- return 0;
- }
- case 2: /* Inflate dynamic */
- {
- /* Tables for deflate from PKZIP's appnote.txt. */
- static unsigned border[] = { /* Order of the bit length code lengths */
- 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
- };
- int dbits = 6; /* bits in base distance lookup table */
- int lbits = 9; /* bits in base literal/length lookup table */
-
- int i; /* temporary variables */
- unsigned j;
- unsigned l; /* last length */
- unsigned m; /* mask for bit lengths table */
- unsigned n; /* number of lengths to get */
- huft_t *tl; /* literal/length code table */
- huft_t *td; /* distance code table */
- int bl; /* lookup bits for tl */
- int bd; /* lookup bits for td */
- unsigned nb; /* number of bit length codes */
- unsigned nl; /* number of literal/length codes */
- unsigned nd; /* number of distance codes */
-
- unsigned ll[286 + 30]; /* literal/length and distance code lengths */
- register unsigned long b_dynamic; /* bit buffer */
- register unsigned k_dynamic; /* number of bits in bit buffer */
-
- /* make local bit buffer */
- b_dynamic = bb;
- k_dynamic = bk;
-
- /* read in table lengths */
- while (k_dynamic < 5) {
- b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
- k_dynamic += 8;
- }
- nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */
- b_dynamic >>= 5;
- k_dynamic -= 5;
- while (k_dynamic < 5) {
- b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
- k_dynamic += 8;
- }
- nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
- b_dynamic >>= 5;
- k_dynamic -= 5;
- while (k_dynamic < 4) {
- b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
- k_dynamic += 8;
- }
- nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */
- b_dynamic >>= 4;
- k_dynamic -= 4;
- if (nl > 286 || nd > 30) {
- return 1; /* bad lengths */
- }
-
- /* read in bit-length-code lengths */
- for (j = 0; j < nb; j++) {
- while (k_dynamic < 3) {
- b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
- k_dynamic += 8;
- }
- ll[border[j]] = (unsigned) b_dynamic & 7;
- b_dynamic >>= 3;
- k_dynamic -= 3;
- }
- for (; j < 19; j++) {
- ll[border[j]] = 0;
- }
-
- /* build decoding table for trees--single level, 7 bit lookup */
- bl = 7;
- if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) {
- if (i == 1) {
- huft_free(tl);
- }
- return i; /* incomplete code set */
- }
-
- /* read in literal and distance code lengths */
- n = nl + nd;
- m = mask_bits[bl];
- i = l = 0;
- while ((unsigned) i < n) {
- while (k_dynamic < (unsigned) bl) {
- b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
- k_dynamic += 8;
- }
- j = (td = tl + ((unsigned) b_dynamic & m))->b;
- b_dynamic >>= j;
- k_dynamic -= j;
- j = td->v.n;
- if (j < 16) { /* length of code in bits (0..15) */
- ll[i++] = l = j; /* save last length in l */
- }
- else if (j == 16) { /* repeat last length 3 to 6 times */
- while (k_dynamic < 2) {
- b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
- k_dynamic += 8;
- }
- j = 3 + ((unsigned) b_dynamic & 3);
- b_dynamic >>= 2;
- k_dynamic -= 2;
- if ((unsigned) i + j > n) {
- return 1;
- }
- while (j--) {
- ll[i++] = l;
- }
- } else if (j == 17) { /* 3 to 10 zero length codes */
- while (k_dynamic < 3) {
- b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
- k_dynamic += 8;
- }
- j = 3 + ((unsigned) b_dynamic & 7);
- b_dynamic >>= 3;
- k_dynamic -= 3;
- if ((unsigned) i + j > n) {
- return 1;
- }
- while (j--) {
- ll[i++] = 0;
- }
- l = 0;
- } else { /* j == 18: 11 to 138 zero length codes */
- while (k_dynamic < 7) {
- b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
- k_dynamic += 8;
- }
- j = 11 + ((unsigned) b_dynamic & 0x7f);
- b_dynamic >>= 7;
- k_dynamic -= 7;
- if ((unsigned) i + j > n) {
- return 1;
- }
- while (j--) {
- ll[i++] = 0;
- }
- l = 0;
- }
- }
-
- /* free decoding table for trees */
- huft_free(tl);
-
- /* restore the global bit buffer */
- bb = b_dynamic;
- bk = k_dynamic;
-
- /* build the decoding tables for literal/length and distance codes */
- bl = lbits;
- if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
- if (i == 1) {
- error_msg("Incomplete literal tree");
- huft_free(tl);
- }
- return i; /* incomplete code set */
- }
- bd = dbits;
- if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
- if (i == 1) {
- error_msg("incomplete distance tree");
- huft_free(td);
- }
- huft_free(tl);
- return i; /* incomplete code set */
- }
-
- /* decompress until an end-of-block code */
- if (inflate_codes(tl, td, bl, bd))
- return 1;
-
- /* free the decoding tables, return */
- huft_free(tl);
- huft_free(td);
- return 0;
- }
- default:
- /* bad block type */
- return 2;
- }
-}
-
-/*
- * decompress an inflated entry
- *
- * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
- */
-static int inflate()
-{
- int e; /* last block flag */
- int r; /* result code */
- unsigned h = 0; /* maximum struct huft's malloc'ed */
-
- /* initialize window, bit buffer */
- outcnt = 0;
- bk = 0;
- bb = 0;
-
- /* decompress until the last block */
- do {
- hufts = 0;
- if ((r = inflate_block(&e)) != 0) {
- return r;
- }
- if (hufts > h) {
- h = hufts;
- }
- } while (!e);
-
- /* flush out window */
- flush_window();
-
- /* return success */
- return 0;
-}
-
-/* ===========================================================================
- * Unzip in to out. This routine works on both gzip and pkzip files.
- *
- * IN assertions: the buffer inbuf contains already the beginning of
- * the compressed data, from offsets inptr to insize-1 included.
- * The magic header has already been checked. The output buffer is cleared.
- * in, out: input and output file descriptors
- */
-extern int unzip(FILE *l_in_file, FILE *l_out_file)
-{
- const int extra_field = 0x04; /* bit 2 set: extra field present */
- const int orig_name = 0x08; /* bit 3 set: original file name present */
- const int comment = 0x10; /* bit 4 set: file comment present */
- unsigned char buf[8]; /* extended local header */
- unsigned char flags; /* compression flags */
- char magic[2]; /* magic header */
- int method;
- typedef void (*sig_type) (int);
- int exit_code=0; /* program exit code */
- int i;
-
- in_file = l_in_file;
- out_file = l_out_file;
-
- if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
- (void) signal(SIGINT, (sig_type) abort_gzip);
- }
-#ifdef SIGTERM
-// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
-// (void) signal(SIGTERM, (sig_type) abort_gzip);
-// }
-#endif
-#ifdef SIGHUP
- if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
- (void) signal(SIGHUP, (sig_type) abort_gzip);
- }
-#endif
-
- /* Allocate all global buffers (for DYN_ALLOC option) */
- window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
- outcnt = 0;
- bytes_out = 0L;
-
- magic[0] = fgetc(in_file);
- magic[1] = fgetc(in_file);
-
- /* Magic header for gzip files, 1F 8B = \037\213 */
- if (memcmp(magic, "\037\213", 2) != 0) {
- error_msg("Invalid gzip magic");
- return EXIT_FAILURE;
- }
-
- method = (int) fgetc(in_file);
- if (method != 8) {
- error_msg("unknown method %d -- get newer version of gzip", method);
- exit_code = 1;
- return -1;
- }
-
- flags = (unsigned char) fgetc(in_file);
-
- /* Ignore time stamp(4), extra flags(1), OS type(1) */
- for (i = 0; i < 6; i++)
- fgetc(in_file);
-
- if ((flags & extra_field) != 0) {
- size_t extra;
- extra = fgetc(in_file);
- extra += fgetc(in_file) << 8;
-
- for (i = 0; i < extra; i++)
- fgetc(in_file);
- }
-
- /* Discard original name if any */
- if ((flags & orig_name) != 0) {
- while (fgetc(in_file) != 0); /* null */
- }
-
- /* Discard file comment if any */
- if ((flags & comment) != 0) {
- while (fgetc(in_file) != 0); /* null */
- }
-
- if (method < 0) {
- printf("it failed\n");
- return(exit_code); /* error message already emitted */
- }
-
- make_crc_table();
-
- /* Decompress */
- if (method == 8) {
-
- int res = inflate();
-
- if (res == 3) {
- error_msg(memory_exhausted);
- } else if (res != 0) {
- error_msg("invalid compressed data--format violated");
- }
-
- } else {
- error_msg("internal error, invalid method");
- }
-
- /* Get the crc and original length
- * crc32 (see algorithm.doc)
- * uncompressed input size modulo 2^32
- */
- fread(buf, 1, 8, in_file);
-
- /* Validate decompression - crc */
- if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
- error_msg("invalid compressed data--crc error");
- }
- /* Validate decompression - size */
- if (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) {
- error_msg("invalid compressed data--length error");
- }
-
- free(window);
- free(crc_table);
-
- return 0;
-}
-
-/*
- * This needs access to global variables wondow and crc_table, so its not in its own file.
- */
-extern void gz_close(int gunzip_pid)
-{
- if (kill(gunzip_pid, SIGTERM) == -1) {
- error_msg_and_die("*** Couldnt kill old gunzip process *** aborting");
- }
-
- if (waitpid(gunzip_pid, NULL, 0) == -1) {
- printf("Couldnt wait ?");
- }
- free(window);
- free(crc_table);
-}
diff --git a/release/src/router/busybox/libbb/update_passwd.c b/release/src/router/busybox/libbb/update_passwd.c
new file mode 100644
index 00000000..35b89a5b
--- /dev/null
+++ b/release/src/router/busybox/libbb/update_passwd.c
@@ -0,0 +1,266 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * update_passwd
+ *
+ * update_passwd is a common function for passwd and chpasswd applets;
+ * it is responsible for updating password file (i.e. /etc/passwd or
+ * /etc/shadow) for a given user and password.
+ *
+ * Moved from loginutils/passwd.c by Alexander Shishkin <virtuoso@slind.org>
+ *
+ * Modified to be able to add or delete users, groups and users to/from groups
+ * by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+#if ENABLE_SELINUX
+static void check_selinux_update_passwd(const char *username)
+{
+ security_context_t context;
+ char *seuser;
+
+ if (getuid() != (uid_t)0 || is_selinux_enabled() == 0)
+ return; /* No need to check */
+
+ if (getprevcon_raw(&context) < 0)
+ bb_perror_msg_and_die("getprevcon failed");
+ seuser = strtok(context, ":");
+ if (!seuser)
+ bb_error_msg_and_die("invalid context '%s'", context);
+ if (strcmp(seuser, username) != 0) {
+ if (checkPasswdAccess(PASSWD__PASSWD) != 0)
+ bb_error_msg_and_die("SELinux: access denied");
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ freecon(context);
+}
+#else
+# define check_selinux_update_passwd(username) ((void)0)
+#endif
+
+/*
+ 1) add a user: update_passwd(FILE, USER, REMAINING_PWLINE, NULL)
+ only if CONFIG_ADDUSER=y and applet_name[0] == 'a' like in adduser
+
+ 2) add a group: update_passwd(FILE, GROUP, REMAINING_GRLINE, NULL)
+ only if CONFIG_ADDGROUP=y and applet_name[0] == 'a' like in addgroup
+
+ 3) add a user to a group: update_passwd(FILE, GROUP, NULL, MEMBER)
+ only if CONFIG_FEATURE_ADDUSER_TO_GROUP=y, applet_name[0] == 'a'
+ like in addgroup and member != NULL
+
+ 4) delete a user: update_passwd(FILE, USER, NULL, NULL)
+
+ 5) delete a group: update_passwd(FILE, GROUP, NULL, NULL)
+
+ 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER)
+ only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL
+
+ 7) change user's passord: update_passwd(FILE, USER, NEW_PASSWD, NULL)
+ only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd
+ or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd
+
+ This function does not validate the arguments fed to it
+ so the calling program should take care of that.
+
+ Returns number of lines changed, or -1 on error.
+*/
+int FAST_FUNC update_passwd(const char *filename,
+ const char *name,
+ const char *new_passwd,
+ const char *member)
+{
+#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP)
+#define member NULL
+#endif
+ struct stat sb;
+ struct flock lock;
+ FILE *old_fp;
+ FILE *new_fp;
+ char *fnamesfx;
+ char *sfx_char;
+ unsigned user_len;
+ int old_fd;
+ int new_fd;
+ int i;
+ int changed_lines;
+ int ret = -1; /* failure */
+
+ filename = xmalloc_follow_symlinks(filename);
+ if (filename == NULL)
+ return ret;
+
+ check_selinux_update_passwd(name);
+
+ /* New passwd file, "/etc/passwd+" for now */
+ fnamesfx = xasprintf("%s+", filename);
+ sfx_char = &fnamesfx[strlen(fnamesfx)-1];
+ name = xasprintf("%s:", name);
+ user_len = strlen(name);
+
+ if (strstr(filename, "shadow"))
+ old_fp = fopen(filename, "r+");
+ else
+ old_fp = fopen_or_warn(filename, "r+");
+ if (!old_fp)
+ goto free_mem;
+ old_fd = fileno(old_fp);
+
+ selinux_preserve_fcontext(old_fd);
+
+ /* Try to create "/etc/passwd+". Wait if it exists. */
+ i = 30;
+ do {
+ // FIXME: on last iteration try w/o O_EXCL but with O_TRUNC?
+ new_fd = open(fnamesfx, O_WRONLY|O_CREAT|O_EXCL, 0600);
+ if (new_fd >= 0) goto created;
+ if (errno != EEXIST) break;
+ usleep(100000); /* 0.1 sec */
+ } while (--i);
+ bb_perror_msg("can't create '%s'", fnamesfx);
+ goto close_old_fp;
+
+ created:
+ if (!fstat(old_fd, &sb)) {
+ fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
+ fchown(new_fd, sb.st_uid, sb.st_gid);
+ }
+ errno = 0;
+ new_fp = fdopen(new_fd, "w");
+ if (!new_fp) {
+ bb_perror_nomsg();
+ close(new_fd);
+ goto unlink_new;
+ }
+
+ /* Backup file is "/etc/passwd-" */
+ *sfx_char = '-';
+ /* Delete old backup */
+ i = (unlink(fnamesfx) && errno != ENOENT);
+ /* Create backup as a hardlink to current */
+ if (i || link(filename, fnamesfx))
+ bb_perror_msg("warning: can't create backup copy '%s'",
+ fnamesfx);
+ *sfx_char = '+';
+
+ /* Lock the password file before updating */
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if (fcntl(old_fd, F_SETLK, &lock) < 0)
+ bb_perror_msg("warning: can't lock '%s'", filename);
+ lock.l_type = F_UNLCK;
+
+ /* Read current password file, write updated /etc/passwd+ */
+ changed_lines = 0;
+ while (1) {
+ char *cp, *line;
+
+ line = xmalloc_fgetline(old_fp);
+ if (!line) /* EOF/error */
+ break;
+ if (strncmp(name, line, user_len) != 0) {
+ fprintf(new_fp, "%s\n", line);
+ goto next;
+ }
+
+ /* We have a match with "name:"... */
+ cp = line + user_len; /* move past name: */
+
+#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
+ if (member) {
+ /* It's actually /etc/group+, not /etc/passwd+ */
+ if (ENABLE_FEATURE_ADDUSER_TO_GROUP
+ && applet_name[0] == 'a'
+ ) {
+ /* Add user to group */
+ fprintf(new_fp, "%s%s%s\n", line,
+ last_char_is(line, ':') ? "" : ",",
+ member);
+ changed_lines++;
+ } else if (ENABLE_FEATURE_DEL_USER_FROM_GROUP
+ /* && applet_name[0] == 'd' */
+ ) {
+ /* Delete user from group */
+ char *tmp;
+ const char *fmt = "%s";
+
+ /* find the start of the member list: last ':' */
+ cp = strrchr(line, ':');
+ /* cut it */
+ *cp++ = '\0';
+ /* write the cut line name:passwd:gid:
+ * or name:!:: */
+ fprintf(new_fp, "%s:", line);
+ /* parse the tokens of the member list */
+ tmp = cp;
+ while ((cp = strsep(&tmp, ",")) != NULL) {
+ if (strcmp(member, cp) != 0) {
+ fprintf(new_fp, fmt, cp);
+ fmt = ",%s";
+ } else {
+ /* found member, skip it */
+ changed_lines++;
+ }
+ }
+ fprintf(new_fp, "\n");
+ }
+ } else
+#endif
+ if ((ENABLE_PASSWD && applet_name[0] == 'p')
+ || (ENABLE_CHPASSWD && applet_name[0] == 'c')
+ ) {
+ /* Change passwd */
+ cp = strchrnul(cp, ':'); /* move past old passwd */
+ /* name: + new_passwd + :rest of line */
+ fprintf(new_fp, "%s%s%s\n", name, new_passwd, cp);
+ changed_lines++;
+ } /* else delete user or group: skip the line */
+ next:
+ free(line);
+ }
+
+ if (changed_lines == 0) {
+#if ENABLE_FEATURE_DEL_USER_FROM_GROUP
+ if (member)
+ bb_error_msg("can't find %s in %s", member, filename);
+#endif
+ if ((ENABLE_ADDUSER || ENABLE_ADDGROUP)
+ && applet_name[0] == 'a' && !member
+ ) {
+ /* add user or group */
+ fprintf(new_fp, "%s%s\n", name, new_passwd);
+ changed_lines++;
+ }
+ }
+
+ fcntl(old_fd, F_SETLK, &lock);
+
+ /* We do want all of them to execute, thus | instead of || */
+ errno = 0;
+ if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp))
+ || rename(fnamesfx, filename)
+ ) {
+ /* At least one of those failed */
+ bb_perror_nomsg();
+ goto unlink_new;
+ }
+ /* Success: ret >= 0 */
+ ret = changed_lines;
+
+ unlink_new:
+ if (ret < 0)
+ unlink(fnamesfx);
+
+ close_old_fp:
+ fclose(old_fp);
+
+ free_mem:
+ free(fnamesfx);
+ free((char *)filename);
+ free((char *)name);
+ return ret;
+}
diff --git a/release/src/router/busybox/libbb/uuencode.c b/release/src/router/busybox/libbb/uuencode.c
new file mode 100644
index 00000000..67d98d59
--- /dev/null
+++ b/release/src/router/busybox/libbb/uuencode.c
@@ -0,0 +1,71 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Conversion table. for base 64 */
+const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/',
+ '=' /* termination character */,
+ '\n', '\0' /* needed for uudecode.c */
+};
+
+const char bb_uuenc_tbl_std[65] ALIGN1 = {
+ '`', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`' /* termination character */
+};
+
+/*
+ * Encode bytes at S of length LENGTH to uuencode or base64 format and place it
+ * to STORE. STORE will be 0-terminated, and must point to a writable
+ * buffer of at least 1+BASE64_LENGTH(length) bytes.
+ * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
+ */
+void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl)
+{
+ const unsigned char *s = src;
+
+ /* Transform the 3x8 bits to 4x6 bits */
+ while (length > 0) {
+ unsigned s1, s2;
+
+ /* Are s[1], s[2] valid or should be assumed 0? */
+ s1 = s2 = 0;
+ length -= 3; /* can be >=0, -1, -2 */
+ if (length >= -1) {
+ s1 = s[1];
+ if (length >= 0)
+ s2 = s[2];
+ }
+ *p++ = tbl[s[0] >> 2];
+ *p++ = tbl[((s[0] & 3) << 4) + (s1 >> 4)];
+ *p++ = tbl[((s1 & 0xf) << 2) + (s2 >> 6)];
+ *p++ = tbl[s2 & 0x3f];
+ s += 3;
+ }
+ /* Zero-terminate */
+ *p = '\0';
+ /* If length is -2 or -1, pad last char or two */
+ while (length) {
+ *--p = tbl[64];
+ length++;
+ }
+}
diff --git a/release/src/router/busybox/libbb/vdprintf.c b/release/src/router/busybox/libbb/vdprintf.c
index 8c3e32a7..09fffbca 100644
--- a/release/src/router/busybox/libbb/vdprintf.c
+++ b/release/src/router/busybox/libbb/vdprintf.c
@@ -2,52 +2,20 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <unistd.h>
#include "libbb.h"
-
-
-#if (__GLIBC__ < 2)
-extern int vdprintf(int d, const char *format, va_list ap)
+#if defined(__GLIBC__) && __GLIBC__ < 2
+int FAST_FUNC vdprintf(int d, const char *format, va_list ap)
{
char buf[BUF_SIZE];
int len;
- len = vsprintf(buf, format, ap);
+ len = vsnprintf(buf, BUF_SIZE, 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/release/src/router/busybox/libbb/verror_msg.c b/release/src/router/busybox/libbb/verror_msg.c
index b3482156..58846d56 100644
--- a/release/src/router/busybox/libbb/verror_msg.c
+++ b/release/src/router/busybox/libbb/verror_msg.c
@@ -2,48 +2,126 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
#include "libbb.h"
+#include <syslog.h>
+
+smallint logmode = LOGMODE_STDIO;
+const char *msg_eol = "\n";
-extern void verror_msg(const char *s, va_list p)
+void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
{
- fflush(stdout);
- fprintf(stderr, "%s: ", applet_name);
- vfprintf(stderr, s, p);
+ char *msg;
+ int applet_len, strerr_len, msgeol_len, used;
+
+ if (!logmode)
+ return;
+
+ if (!s) /* nomsg[_and_die] uses NULL fmt */
+ s = ""; /* some libc don't like printf(NULL) */
+
+ used = vasprintf(&msg, s, p);
+ if (used < 0)
+ return;
+
+ /* This is ugly and costs +60 bytes compared to multiple
+ * fprintf's, but is guaranteed to do a single write.
+ * This is needed for e.g. httpd logging, when multiple
+ * children can produce log messages simultaneously. */
+
+ applet_len = strlen(applet_name) + 2; /* "applet: " */
+ strerr_len = strerr ? strlen(strerr) : 0;
+ msgeol_len = strlen(msg_eol);
+ /* +3 is for ": " before strerr and for terminating NUL */
+ msg = xrealloc(msg, applet_len + used + strerr_len + msgeol_len + 3);
+ /* TODO: maybe use writev instead of memmoving? Need full_writev? */
+ memmove(msg + applet_len, msg, used);
+ used += applet_len;
+ strcpy(msg, applet_name);
+ msg[applet_len - 2] = ':';
+ msg[applet_len - 1] = ' ';
+ if (strerr) {
+ if (s[0]) { /* not perror_nomsg? */
+ msg[used++] = ':';
+ msg[used++] = ' ';
+ }
+ strcpy(&msg[used], strerr);
+ used += strerr_len;
+ }
+ strcpy(&msg[used], msg_eol);
+
+ if (logmode & LOGMODE_STDIO) {
+ fflush(stdout);
+ full_write(STDERR_FILENO, msg, used + msgeol_len);
+ }
+ if (logmode & LOGMODE_SYSLOG) {
+ syslog(LOG_ERR, "%s", msg + applet_len);
+ }
+ free(msg);
}
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+#ifdef VERSION_WITH_WRITEV
+
+/* Code size is approximately the same, but currently it's the only user
+ * of writev in entire bbox. __libc_writev in uclibc is ~50 bytes. */
+
+void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
+{
+ int strerr_len, msgeol_len;
+ struct iovec iov[3];
+
+#define used (iov[2].iov_len)
+#define msgv (iov[2].iov_base)
+#define msgc ((char*)(iov[2].iov_base))
+#define msgptr (&(iov[2].iov_base))
+
+ if (!logmode)
+ return;
+
+ if (!s) /* nomsg[_and_die] uses NULL fmt */
+ s = ""; /* some libc don't like printf(NULL) */
+
+ /* Prevent "derefing type-punned ptr will break aliasing rules" */
+ used = vasprintf((char**)(void*)msgptr, s, p);
+ if (used < 0)
+ return;
+
+ /* This is ugly and costs +60 bytes compared to multiple
+ * fprintf's, but is guaranteed to do a single write.
+ * This is needed for e.g. httpd logging, when multiple
+ * children can produce log messages simultaneously. */
+
+ strerr_len = strerr ? strlen(strerr) : 0;
+ msgeol_len = strlen(msg_eol);
+ /* +3 is for ": " before strerr and for terminating NUL */
+ msgv = xrealloc(msgv, used + strerr_len + msgeol_len + 3);
+ if (strerr) {
+ msgc[used++] = ':';
+ msgc[used++] = ' ';
+ strcpy(msgc + used, strerr);
+ used += strerr_len;
+ }
+ strcpy(msgc + used, msg_eol);
+ used += msgeol_len;
+
+ if (logmode & LOGMODE_STDIO) {
+ iov[0].iov_base = (char*)applet_name;
+ iov[0].iov_len = strlen(applet_name);
+ iov[1].iov_base = (char*)": ";
+ iov[1].iov_len = 2;
+ /*iov[2].iov_base = msgc;*/
+ /*iov[2].iov_len = used;*/
+ fflush(stdout);
+ writev(2, iov, 3);
+ }
+ if (logmode & LOGMODE_SYSLOG) {
+ syslog(LOG_ERR, "%s", msgc);
+ }
+ free(msgc);
+}
+#endif
diff --git a/release/src/router/busybox/libbb/vfork_daemon_rexec.c b/release/src/router/busybox/libbb/vfork_daemon_rexec.c
index c8f9d277..f64239a9 100644
--- a/release/src/router/busybox/libbb/vfork_daemon_rexec.c
+++ b/release/src/router/busybox/libbb/vfork_daemon_rexec.c
@@ -1,27 +1,330 @@
+/* vi: set sw=4 ts=4: */
/*
- * Rexec program for system have fork() as vfork() with foregound option
- * Copyright (C) Vladminr Oleynik and many different people.
+ * 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>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <unistd.h>
-#include "libbb.h"
+#include <paths.h>
+#include "busybox.h" /* uses applet tables */
+/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
+ * -1 for failure. Runs argv[0], searching path if that has no / in it. */
+pid_t FAST_FUNC spawn(char **argv)
+{
+ /* Compiler should not optimize stores here */
+ volatile int failed;
+ pid_t pid;
+
+// Ain't it a good place to fflush(NULL)?
+
+ /* Be nice to nommu machines. */
+ failed = 0;
+ pid = vfork();
+ if (pid < 0) /* error */
+ return pid;
+ if (!pid) { /* child */
+ /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
+ BB_EXECVP(argv[0], argv);
+
+ /* We are (maybe) sharing a stack with blocked parent,
+ * let parent know we failed and then exit to unblock parent
+ * (but don't run atexit() stuff, which would screw up parent.)
+ */
+ failed = errno;
+ _exit(111);
+ }
+ /* parent */
+ /* Unfortunately, this is not reliable: according to standards
+ * vfork() can be equivalent to fork() and we won't see value
+ * of 'failed'.
+ * Interested party can wait on pid and learn exit code.
+ * If 111 - then it (most probably) failed to exec */
+ if (failed) {
+ errno = failed;
+ return -1;
+ }
+ return pid;
+}
+
+/* Die with an error message if we can't spawn a child process. */
+pid_t FAST_FUNC xspawn(char **argv)
+{
+ pid_t pid = spawn(argv);
+ if (pid < 0)
+ bb_simple_perror_msg_and_die(*argv);
+ return pid;
+}
+
+pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options)
+{
+ pid_t r;
+
+ do
+ r = waitpid(pid, wstat, options);
+ while ((r == -1) && (errno == EINTR));
+ return r;
+}
+
+pid_t FAST_FUNC wait_any_nohang(int *wstat)
+{
+ return safe_waitpid(-1, wstat, WNOHANG);
+}
+
+// Wait for the specified child PID to exit, returning child's error return.
+int FAST_FUNC wait4pid(pid_t pid)
+{
+ int status;
+
+ if (pid <= 0) {
+ /*errno = ECHILD; -- wrong. */
+ /* we expect errno to be already set from failed [v]fork/exec */
+ return -1;
+ }
+ if (safe_waitpid(pid, &status, 0) == -1)
+ return -1;
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ if (WIFSIGNALED(status))
+ return WTERMSIG(status) + 1000;
+ return 0;
+}
+
+#if ENABLE_FEATURE_PREFER_APPLETS
+void FAST_FUNC save_nofork_data(struct nofork_save_area *save)
+{
+ memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
+ save->applet_name = applet_name;
+ save->xfunc_error_retval = xfunc_error_retval;
+ save->option_mask32 = option_mask32;
+ save->die_sleep = die_sleep;
+ save->saved = 1;
+}
+
+void FAST_FUNC restore_nofork_data(struct nofork_save_area *save)
+{
+ memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
+ applet_name = save->applet_name;
+ xfunc_error_retval = save->xfunc_error_retval;
+ option_mask32 = save->option_mask32;
+ die_sleep = save->die_sleep;
+}
-#if defined(__uClinux__)
-void vfork_daemon_rexec(int argc, char **argv, char *foreground_opt)
+int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv)
{
- char **vfork_args;
- int a = 0;
+ int rc, argc;
+
+ applet_name = APPLET_NAME(applet_no);
+
+ xfunc_error_retval = EXIT_FAILURE;
+
+ /* Special flag for xfunc_die(). If xfunc will "die"
+ * in NOFORK applet, xfunc_die() sees negative
+ * die_sleep and longjmp here instead. */
+ die_sleep = -1;
+
+ /* In case getopt() or getopt32() was already called:
+ * reset the libc getopt() function, which keeps internal state.
+ *
+ * BSD-derived getopt() functions require that optind be set to 1 in
+ * order to reset getopt() state. This used to be generally accepted
+ * way of resetting getopt(). However, glibc's getopt()
+ * has additional getopt() state beyond optind, and requires that
+ * optind be set to zero to reset its state. So the unfortunate state of
+ * affairs is that BSD-derived versions of getopt() misbehave if
+ * optind is set to 0 in order to reset getopt(), and glibc's getopt()
+ * will core dump if optind is set 1 in order to reset getopt().
+ *
+ * More modern versions of BSD require that optreset be set to 1 in
+ * order to reset getopt(). Sigh. Standards, anyone?
+ */
+#ifdef __GLIBC__
+ optind = 0;
+#else /* BSD style */
+ optind = 1;
+ /* optreset = 1; */
+#endif
+ /* optarg = NULL; opterr = 1; optopt = 63; - do we need this too? */
+ /* (values above are what they initialized to in glibc and uclibc) */
+ /* option_mask32 = 0; - not needed, no applet depends on it being 0 */
- vfork_args = xcalloc(sizeof(char *), argc + 3);
- while(*argv) {
- vfork_args[a++] = *argv;
- argv++;
+ argc = 1;
+ while (argv[argc])
+ argc++;
+
+ rc = setjmp(die_jmp);
+ if (!rc) {
+ /* Some callers (xargs)
+ * need argv untouched because they free argv[i]! */
+ char *tmp_argv[argc+1];
+ memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
+ /* Finally we can call NOFORK applet's main() */
+ rc = applet_main[applet_no](argc, tmp_argv);
+
+ /* The whole reason behind nofork_save_area is that <applet>_main
+ * may exit non-locally! For example, in hush Ctrl-Z tries
+ * (modulo bugs) to dynamically create a child (backgrounded task)
+ * if it detects that Ctrl-Z was pressed when a NOFORK was running.
+ * Testcase: interactive "rm -i".
+ * Don't fool yourself into thinking "and <applet>_main() returns
+ * quickly here" and removing "useless" nofork_save_area code. */
+
+ } else { /* xfunc died in NOFORK applet */
+ /* in case they meant to return 0... */
+ if (rc == -2222)
+ rc = 0;
}
- vfork_args[a] = foreground_opt;
- execvp("/proc/self/exe", vfork_args);
- vfork_args[0] = "/bin/busybox";
- execv(vfork_args[0], vfork_args);
- bb_perror_msg_and_die("execv %s", vfork_args[0]);
+
+ /* Restoring some globals */
+ restore_nofork_data(old);
+
+ /* Other globals can be simply reset to defaults */
+#ifdef __GLIBC__
+ optind = 0;
+#else /* BSD style */
+ optind = 1;
+#endif
+
+ return rc & 0xff; /* don't confuse people with "exitcodes" >255 */
+}
+
+int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
+{
+ struct nofork_save_area old;
+
+ /* Saving globals */
+ save_nofork_data(&old);
+ return run_nofork_applet_prime(&old, applet_no, argv);
+}
+#endif /* FEATURE_PREFER_APPLETS */
+
+int FAST_FUNC spawn_and_wait(char **argv)
+{
+ int rc;
+#if ENABLE_FEATURE_PREFER_APPLETS
+ int a = find_applet_by_name(argv[0]);
+
+ if (a >= 0 && (APPLET_IS_NOFORK(a)
+#if BB_MMU
+ || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */
+#endif
+ )) {
+#if BB_MMU
+ if (APPLET_IS_NOFORK(a))
+#endif
+ {
+ return run_nofork_applet(a, argv);
+ }
+#if BB_MMU
+ /* MMU only */
+ /* a->noexec is true */
+ rc = fork();
+ if (rc) /* parent or error */
+ return wait4pid(rc);
+ /* child */
+ xfunc_error_retval = EXIT_FAILURE;
+ run_applet_no_and_exit(a, argv);
+#endif
+ }
+#endif /* FEATURE_PREFER_APPLETS */
+ rc = spawn(argv);
+ return wait4pid(rc);
+}
+
+#if !BB_MMU
+void FAST_FUNC re_exec(char **argv)
+{
+ /* high-order bit of first char in argv[0] is a hidden
+ * "we have (already) re-execed, don't do it again" flag */
+ argv[0][0] |= 0x80;
+ execv(bb_busybox_exec_path, argv);
+ bb_perror_msg_and_die("exec %s", bb_busybox_exec_path);
+}
+
+pid_t FAST_FUNC fork_or_rexec(char **argv)
+{
+ pid_t pid;
+ /* Maybe we are already re-execed and come here again? */
+ if (re_execed)
+ return 0; /* child */
+
+ pid = vfork();
+ if (pid < 0) /* wtf? */
+ bb_perror_msg_and_die("vfork");
+ if (pid) /* parent */
+ return pid;
+ /* child - re-exec ourself */
+ re_exec(argv);
+}
+#else
+/* Dance around (void)...*/
+#undef fork_or_rexec
+pid_t FAST_FUNC fork_or_rexec(void)
+{
+ pid_t pid;
+ pid = fork();
+ if (pid < 0) /* wtf? */
+ bb_perror_msg_and_die("fork");
+ return pid;
+}
+#define fork_or_rexec(argv) fork_or_rexec()
+#endif
+
+/* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
+ * char **argv "vanishes" */
+void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
+{
+ int fd;
+
+ if (flags & DAEMON_CHDIR_ROOT)
+ xchdir("/");
+
+ if (flags & DAEMON_DEVNULL_STDIO) {
+ close(0);
+ close(1);
+ close(2);
+ }
+
+ fd = open(bb_dev_null, O_RDWR);
+ if (fd < 0) {
+ /* NB: we can be called as bb_sanitize_stdio() from init
+ * or mdev, and there /dev/null may legitimately not (yet) exist!
+ * Do not use xopen above, but obtain _ANY_ open descriptor,
+ * even bogus one as below. */
+ fd = xopen("/", O_RDONLY); /* don't believe this can fail */
+ }
+
+ while ((unsigned)fd < 2)
+ fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
+
+ if (!(flags & DAEMON_ONLY_SANITIZE)) {
+ if (fork_or_rexec(argv))
+ exit(EXIT_SUCCESS); /* parent */
+ /* if daemonizing, make sure we detach from stdio & ctty */
+ setsid();
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ }
+ while (fd > 2) {
+ close(fd--);
+ if (!(flags & DAEMON_CLOSE_EXTRA_FDS))
+ return;
+ /* else close everything after fd#2 */
+ }
+}
+
+void FAST_FUNC bb_sanitize_stdio(void)
+{
+ bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
}
-#endif /* uClinux */
diff --git a/release/src/router/busybox/libbb/vherror_msg.c b/release/src/router/busybox/libbb/vherror_msg.c
deleted file mode 100644
index ee0bb500..00000000
--- a/release/src/router/busybox/libbb/vherror_msg.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdarg.h>
-#include <netdb.h>
-extern int h_errno;
-
-#include <stdio.h>
-
-#include "libbb.h"
-
-extern void vherror_msg(const char *s, va_list p)
-{
- if(s == 0)
- s = "";
- verror_msg(s, p);
- if (*s)
- fputs(": ", stderr);
- herror("");
-}
diff --git a/release/src/router/busybox/libbb/vperror_msg.c b/release/src/router/busybox/libbb/vperror_msg.c
deleted file mode 100644
index ca9361e4..00000000
--- a/release/src/router/busybox/libbb/vperror_msg.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Utility routines.
- *
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include "libbb.h"
-
-extern void vperror_msg(const char *s, va_list p)
-{
- int err=errno;
- if(s == 0) s = "";
- 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/release/src/router/busybox/libbb/warn_ignoring_args.c b/release/src/router/busybox/libbb/warn_ignoring_args.c
index 223831fd..65dea321 100644
--- a/release/src/router/busybox/libbb/warn_ignoring_args.c
+++ b/release/src/router/busybox/libbb/warn_ignoring_args.c
@@ -1,30 +1,17 @@
/* vi: set sw=4 ts=4: */
/*
- * warn_ingoring_args implementations for busybox
+ * 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <libbb.h>
+#include "libbb.h"
-extern void bb_warn_ignoring_args(int n)
+void FAST_FUNC bb_warn_ignoring_args(int n)
{
if (n) {
- bb_perror_msg("ignoring all arguments");
+ bb_error_msg("ignoring all arguments");
}
}
diff --git a/release/src/router/busybox/libbb/wfopen.c b/release/src/router/busybox/libbb/wfopen.c
index 8b074d2f..1cb871ef 100644
--- a/release/src/router/busybox/libbb/wfopen.c
+++ b/release/src/router/busybox/libbb/wfopen.c
@@ -2,49 +2,39 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <errno.h>
#include "libbb.h"
-FILE *wfopen(const char *path, const char *mode)
+FILE* FAST_FUNC fopen_or_warn(const char *path, const char *mode)
{
- FILE *fp;
- if ((fp = fopen(path, mode)) == NULL) {
- perror_msg("%s", path);
- errno = 0;
+ FILE *fp = fopen(path, mode);
+ if (!fp) {
+ bb_simple_perror_msg(path);
+ //errno = 0; /* why? */
}
return fp;
}
+FILE* FAST_FUNC fopen_for_read(const char *path)
+{
+ return fopen(path, "r");
+}
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+FILE* FAST_FUNC xfopen_for_read(const char *path)
+{
+ return xfopen(path, "r");
+}
+
+FILE* FAST_FUNC fopen_for_write(const char *path)
+{
+ return fopen(path, "w");
+}
+
+FILE* FAST_FUNC xfopen_for_write(const char *path)
+{
+ return xfopen(path, "w");
+}
diff --git a/release/src/router/busybox/libbb/wfopen_input.c b/release/src/router/busybox/libbb/wfopen_input.c
index bff6606b..46ff7a6d 100644
--- a/release/src/router/busybox/libbb/wfopen_input.c
+++ b/release/src/router/busybox/libbb/wfopen_input.c
@@ -4,51 +4,45 @@
*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* 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>
+#include "libbb.h"
-FILE *bb_wfopen_input(const char *filename)
+FILE* FAST_FUNC fopen_or_warn_stdin(const char *filename)
{
FILE *fp = stdin;
- if ((filename != bb_msg_standard_input)
- && filename[0] && ((filename[0] != '-') || filename[1])
+ if (filename != bb_msg_standard_input
+ && NOT_LONE_DASH(filename)
) {
-#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");
+ fp = fopen_or_warn(filename, "r");
}
-
return fp;
}
+
+FILE* FAST_FUNC xfopen_stdin(const char *filename)
+{
+ FILE *fp = fopen_or_warn_stdin(filename);
+ if (fp)
+ return fp;
+ xfunc_die(); /* We already output an error message. */
+}
+
+int FAST_FUNC open_or_warn_stdin(const char *filename)
+{
+ int fd = STDIN_FILENO;
+
+ if (filename != bb_msg_standard_input
+ && NOT_LONE_DASH(filename)
+ ) {
+ fd = open_or_warn(filename, O_RDONLY);
+ }
+
+ return fd;
+}
diff --git a/release/src/router/busybox/libbb/write.c b/release/src/router/busybox/libbb/write.c
new file mode 100644
index 00000000..116e4d15
--- /dev/null
+++ b/release/src/router/busybox/libbb/write.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 Bernhard Reutner-Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Open file and write string str to it, close file.
+ * Die on any open or write error. */
+void FAST_FUNC xopen_xwrite_close(const char* file, const char* str)
+{
+ int fd = xopen(file, O_WRONLY);
+ xwrite_str(fd, str);
+ close(fd);
+}
diff --git a/release/src/router/busybox/libbb/xatonum.c b/release/src/router/busybox/libbb/xatonum.c
new file mode 100644
index 00000000..3cdf6342
--- /dev/null
+++ b/release/src/router/busybox/libbb/xatonum.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ascii-to-numbers implementations for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define type long long
+#define xstrtou(rest) xstrtoull##rest
+#define xstrto(rest) xstrtoll##rest
+#define xatou(rest) xatoull##rest
+#define xato(rest) xatoll##rest
+#define XSTR_UTYPE_MAX ULLONG_MAX
+#define XSTR_TYPE_MAX LLONG_MAX
+#define XSTR_TYPE_MIN LLONG_MIN
+#define XSTR_STRTOU strtoull
+#include "xatonum_template.c"
+
+#if ULONG_MAX != ULLONG_MAX
+#define type long
+#define xstrtou(rest) xstrtoul##rest
+#define xstrto(rest) xstrtol##rest
+#define xatou(rest) xatoul##rest
+#define xato(rest) xatol##rest
+#define XSTR_UTYPE_MAX ULONG_MAX
+#define XSTR_TYPE_MAX LONG_MAX
+#define XSTR_TYPE_MIN LONG_MIN
+#define XSTR_STRTOU strtoul
+#include "xatonum_template.c"
+#endif
+
+#if UINT_MAX != ULONG_MAX
+static ALWAYS_INLINE
+unsigned bb_strtoui(const char *str, char **end, int b)
+{
+ unsigned long v = strtoul(str, end, b);
+ if (v > UINT_MAX) {
+ errno = ERANGE;
+ return UINT_MAX;
+ }
+ return v;
+}
+#define type int
+#define xstrtou(rest) xstrtou##rest
+#define xstrto(rest) xstrtoi##rest
+#define xatou(rest) xatou##rest
+#define xato(rest) xatoi##rest
+#define XSTR_UTYPE_MAX UINT_MAX
+#define XSTR_TYPE_MAX INT_MAX
+#define XSTR_TYPE_MIN INT_MIN
+/* libc has no strtoui, so we need to create/use our own */
+#define XSTR_STRTOU bb_strtoui
+#include "xatonum_template.c"
+#endif
+
+/* A few special cases */
+
+int FAST_FUNC xatoi_u(const char *numstr)
+{
+ return xatou_range(numstr, 0, INT_MAX);
+}
+
+uint16_t FAST_FUNC xatou16(const char *numstr)
+{
+ return xatou_range(numstr, 0, 0xffff);
+}
diff --git a/release/src/router/busybox/libbb/xatonum_template.c b/release/src/router/busybox/libbb/xatonum_template.c
new file mode 100644
index 00000000..5e0bb59e
--- /dev/null
+++ b/release/src/router/busybox/libbb/xatonum_template.c
@@ -0,0 +1,191 @@
+/*
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+/*
+You need to define the following (example):
+
+#define type long
+#define xstrtou(rest) xstrtoul##rest
+#define xstrto(rest) xstrtol##rest
+#define xatou(rest) xatoul##rest
+#define xato(rest) xatol##rest
+#define XSTR_UTYPE_MAX ULONG_MAX
+#define XSTR_TYPE_MAX LONG_MAX
+#define XSTR_TYPE_MIN LONG_MIN
+#define XSTR_STRTOU strtoul
+*/
+
+unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base,
+ unsigned type lower,
+ unsigned type upper,
+ const struct suffix_mult *suffixes)
+{
+ unsigned type r;
+ int old_errno;
+ char *e;
+
+ /* Disallow '-' and any leading whitespace. Make sure we get the
+ * actual isspace function rather than a macro implementaion. */
+ if (*numstr == '-' || *numstr == '+' || (isspace)(*numstr))
+ goto inval;
+
+ /* 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 = XSTR_STRTOU(numstr, &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 || numstr == e)
+ goto inval; /* error / no digits / illegal trailing chars */
+
+ errno = old_errno; /* Ok. So restore errno. */
+
+ /* Do optional suffix parsing. Allow 'empty' suffix tables.
+ * Note that we also allow nul suffixes with associated multipliers,
+ * to allow for scaling of the numstr by some default multiplier. */
+ if (suffixes) {
+ while (suffixes->mult) {
+ if (strcmp(suffixes->suffix, e) == 0) {
+ if (XSTR_UTYPE_MAX / suffixes->mult < r)
+ goto range; /* overflow! */
+ r *= suffixes->mult;
+ goto chk_range;
+ }
+ ++suffixes;
+ }
+ }
+
+ /* Note: trailing space is an error.
+ It would be easy enough to allow though if desired. */
+ if (*e)
+ goto inval;
+ chk_range:
+ /* Finally, check for range limits. */
+ if (r >= lower && r <= upper)
+ return r;
+ range:
+ bb_error_msg_and_die("number %s is not in %llu..%llu range",
+ numstr, (unsigned long long)lower,
+ (unsigned long long)upper);
+ inval:
+ bb_error_msg_and_die("invalid number '%s'", numstr);
+}
+
+unsigned type FAST_FUNC xstrtou(_range)(const char *numstr, int base,
+ unsigned type lower,
+ unsigned type upper)
+{
+ return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL);
+}
+
+unsigned type FAST_FUNC xstrtou(_sfx)(const char *numstr, int base,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes);
+}
+
+unsigned type FAST_FUNC xstrtou()(const char *numstr, int base)
+{
+ return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL);
+}
+
+unsigned type FAST_FUNC xatou(_range_sfx)(const char *numstr,
+ unsigned type lower,
+ unsigned type upper,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes);
+}
+
+unsigned type FAST_FUNC xatou(_range)(const char *numstr,
+ unsigned type lower,
+ unsigned type upper)
+{
+ return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL);
+}
+
+unsigned type FAST_FUNC xatou(_sfx)(const char *numstr,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes);
+}
+
+unsigned type FAST_FUNC xatou()(const char *numstr)
+{
+ return xatou(_sfx)(numstr, NULL);
+}
+
+/* Signed ones */
+
+type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base,
+ type lower,
+ type upper,
+ const struct suffix_mult *suffixes)
+{
+ unsigned type u = XSTR_TYPE_MAX;
+ type r;
+ const char *p = numstr;
+
+ /* NB: if you'll decide to disallow '+':
+ * at least renice applet needs to allow it */
+ if (p[0] == '+' || p[0] == '-') {
+ ++p;
+ if (p[0] == '-')
+ ++u; /* = <type>_MIN (01111... + 1 == 10000...) */
+ }
+
+ r = xstrtou(_range_sfx)(p, base, 0, u, suffixes);
+
+ if (*numstr == '-') {
+ r = -r;
+ }
+
+ if (r < lower || r > upper) {
+ bb_error_msg_and_die("number %s is not in %lld..%lld range",
+ numstr, (long long)lower, (long long)upper);
+ }
+
+ return r;
+}
+
+type FAST_FUNC xstrto(_range)(const char *numstr, int base, type lower, type upper)
+{
+ return xstrto(_range_sfx)(numstr, base, lower, upper, NULL);
+}
+
+type FAST_FUNC xato(_range_sfx)(const char *numstr,
+ type lower,
+ type upper,
+ const struct suffix_mult *suffixes)
+{
+ return xstrto(_range_sfx)(numstr, 10, lower, upper, suffixes);
+}
+
+type FAST_FUNC xato(_range)(const char *numstr, type lower, type upper)
+{
+ return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL);
+}
+
+type FAST_FUNC xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes)
+{
+ return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes);
+}
+
+type FAST_FUNC xato()(const char *numstr)
+{
+ return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL);
+}
+
+#undef type
+#undef xstrtou
+#undef xstrto
+#undef xatou
+#undef xato
+#undef XSTR_UTYPE_MAX
+#undef XSTR_TYPE_MAX
+#undef XSTR_TYPE_MIN
+#undef XSTR_STRTOU
diff --git a/release/src/router/busybox/libbb/xconnect.c b/release/src/router/busybox/libbb/xconnect.c
index 2945d760..f5d7983a 100644
--- a/release/src/router/busybox/libbb/xconnect.c
+++ b/release/src/router/busybox/libbb/xconnect.c
@@ -2,78 +2,422 @@
/*
* Utility routines.
*
- * Connect to host at port using address resolusion from getaddrinfo
+ * Connect to host at port using address resolution from getaddrinfo
*
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
#include <netinet/in.h>
+#include <net/if.h>
#include "libbb.h"
-int xconnect(const char *host, const char *port)
-{
-#ifdef CONFIG_FEATURE_IPV6
- struct addrinfo hints;
- struct addrinfo *res;
- struct addrinfo *addr_info;
- int error;
- int s;
-
- memset(&hints, 0, sizeof(hints));
- /* set-up hints structure */
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- error = getaddrinfo(host, port, &hints, &res);
- if (error||!res)
- bb_perror_msg_and_die(gai_strerror(error));
- addr_info=res;
- while (res) {
- s=socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (s<0)
- {
- error=s;
- res=res->ai_next;
- continue;
- }
- /* try to connect() to res->ai_addr */
- error = connect(s, res->ai_addr, res->ai_addrlen);
- if (error >= 0)
- break;
- close(s);
- res=res->ai_next;
+void FAST_FUNC setsockopt_reuseaddr(int fd)
+{
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
+}
+int FAST_FUNC setsockopt_broadcast(int fd)
+{
+ return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
+}
+int FAST_FUNC setsockopt_bindtodevice(int fd, const char *iface)
+{
+ int r;
+ struct ifreq ifr;
+ strncpy_IFNAMSIZ(ifr.ifr_name, iface);
+ /* NB: passing (iface, strlen(iface) + 1) does not work!
+ * (maybe it works on _some_ kernels, but not on 2.6.26)
+ * Actually, ifr_name is at offset 0, and in practice
+ * just giving char[IFNAMSIZ] instead of struct ifreq works too.
+ * But just in case it's not true on some obscure arch... */
+ r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
+ if (r)
+ bb_perror_msg("can't bind to interface %s", iface);
+ return r;
+}
+
+len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd)
+{
+ len_and_sockaddr *lsa;
+ socklen_t len = 0;
+
+ /* Can be optimized to do only one getsockname() */
+ if (getsockname(fd, NULL, &len) != 0)
+ return NULL;
+ lsa = xzalloc(LSA_LEN_SIZE + len);
+ lsa->len = len;
+ getsockname(fd, &lsa->u.sa, &lsa->len);
+ return lsa;
+}
+
+void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
+{
+ if (connect(s, s_addr, addrlen) < 0) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(s);
+ if (s_addr->sa_family == AF_INET)
+ bb_perror_msg_and_die("%s (%s)",
+ "cannot connect to remote host",
+ inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
+ bb_perror_msg_and_die("cannot connect to remote host");
}
- freeaddrinfo(addr_info);
- if (error < 0)
- {
- bb_perror_msg_and_die("Unable to connect to remote host (%s)", host);
+}
+
+/* Return 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 FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port)
+{
+ unsigned port_nr = default_port;
+ if (port) {
+ 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. */
+ old_errno = errno;
+ port_nr = bb_strtou(port, NULL, 10);
+ if (errno || port_nr > 65535) {
+ struct servent *tserv = getservbyname(port, protocol);
+ port_nr = default_port;
+ if (tserv)
+ port_nr = ntohs(tserv->s_port);
+ }
+ errno = old_errno;
}
+ return (uint16_t)port_nr;
+}
+
+
+/* "Old" networking API - only IPv4 */
+
+/*
+void FAST_FUNC 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 FAST_FUNC xconnect_tcp_v4(struct sockaddr_in *s_addr)
+{
+ int s = xsocket(AF_INET, SOCK_STREAM, 0);
+ xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
return s;
+}
+*/
+
+/* "New" networking API */
+
+
+int FAST_FUNC get_nport(const struct sockaddr *sa)
+{
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ return ((struct sockaddr_in6*)sa)->sin6_port;
+ }
+#endif
+ if (sa->sa_family == AF_INET) {
+ return ((struct sockaddr_in*)sa)->sin_port;
+ }
+ /* What? UNIX socket? IPX?? :) */
+ return -1;
+}
+
+void FAST_FUNC set_nport(len_and_sockaddr *lsa, unsigned port)
+{
+#if ENABLE_FEATURE_IPV6
+ if (lsa->u.sa.sa_family == AF_INET6) {
+ lsa->u.sin6.sin6_port = port;
+ return;
+ }
+#endif
+ if (lsa->u.sa.sa_family == AF_INET) {
+ lsa->u.sin.sin_port = port;
+ return;
+ }
+ /* What? UNIX socket? IPX?? :) */
+}
+
+/* We hijack this constant to mean something else */
+/* It doesn't hurt because we will remove this bit anyway */
+#define DIE_ON_ERROR AI_CANONNAME
+
+/* host: "1.2.3.4[:port]", "www.google.com[:port]"
+ * port: if neither of above specifies port # */
+static len_and_sockaddr* str2sockaddr(
+ const char *host, int port,
+USE_FEATURE_IPV6(sa_family_t af,)
+ int ai_flags)
+{
+ int rc;
+ len_and_sockaddr *r = NULL;
+ struct addrinfo *result = NULL;
+ struct addrinfo *used_res;
+ const char *org_host = host; /* only for error msg */
+ const char *cp;
+ struct addrinfo hint;
+
+ /* Ugly parsing of host:addr */
+ if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
+ /* Even uglier parsing of [xx]:nn */
+ host++;
+ cp = strchr(host, ']');
+ if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
+ /* Malformed: must be [xx]:nn or [xx] */
+ bb_error_msg("bad address '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ return NULL;
+ }
+ } else {
+ cp = strrchr(host, ':');
+ if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) {
+ /* There is more than one ':' (e.g. "::1") */
+ cp = NULL; /* it's not a port spec */
+ }
+ }
+ if (cp) { /* points to ":" or "]:" */
+ int sz = cp - host + 1;
+ host = safe_strncpy(alloca(sz), host, sz);
+ if (ENABLE_FEATURE_IPV6 && *cp != ':') {
+ cp++; /* skip ']' */
+ if (*cp == '\0') /* [xx] without port */
+ goto skip;
+ }
+ cp++; /* skip ':' */
+ port = bb_strtou(cp, NULL, 10);
+ if (errno || (unsigned)port > 0xffff) {
+ bb_error_msg("bad port spec '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ return NULL;
+ }
+ skip: ;
+ }
+
+ memset(&hint, 0 , sizeof(hint));
+#if !ENABLE_FEATURE_IPV6
+ hint.ai_family = AF_INET; /* do not try to find IPv6 */
#else
- struct sockaddr_in s_addr;
- int s = socket(AF_INET, SOCK_STREAM, 0);
- struct servent *tserv;
- int port_nr=htons(atoi(port));
- struct hostent * he;
+ hint.ai_family = af;
+#endif
+ /* Needed. Or else we will get each address thrice (or more)
+ * for each possible socket type (tcp,udp,raw...): */
+ hint.ai_socktype = SOCK_STREAM;
+ hint.ai_flags = ai_flags & ~DIE_ON_ERROR;
+ rc = getaddrinfo(host, NULL, &hint, &result);
+ if (rc || !result) {
+ bb_error_msg("bad address '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ goto ret;
+ }
+ used_res = result;
+#if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
+ while (1) {
+ if (used_res->ai_family == AF_INET)
+ break;
+ used_res = used_res->ai_next;
+ if (!used_res) {
+ used_res = result;
+ break;
+ }
+ }
+#endif
+ r = xmalloc(offsetof(len_and_sockaddr, u.sa) + used_res->ai_addrlen);
+ r->len = used_res->ai_addrlen;
+ memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
+ set_nport(r, htons(port));
+ ret:
+ freeaddrinfo(result);
+ return r;
+}
+#if !ENABLE_FEATURE_IPV6
+#define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
+#endif
- if (port_nr==0 && (tserv = getservbyname(port, "tcp")) != NULL)
- port_nr = tserv->s_port;
+#if ENABLE_FEATURE_IPV6
+len_and_sockaddr* FAST_FUNC host_and_af2sockaddr(const char *host, int port, sa_family_t af)
+{
+ return str2sockaddr(host, port, af, 0);
+}
- memset(&s_addr, 0, sizeof(struct sockaddr_in));
- s_addr.sin_family = AF_INET;
- s_addr.sin_port = port_nr;
+len_and_sockaddr* FAST_FUNC xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)
+{
+ return str2sockaddr(host, port, af, DIE_ON_ERROR);
+}
+#endif
- he = xgethostbyname(host);
- memcpy(&s_addr.sin_addr, he->h_addr, sizeof s_addr.sin_addr);
+len_and_sockaddr* FAST_FUNC host2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, 0);
+}
+
+len_and_sockaddr* FAST_FUNC xhost2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
+}
- if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0)
- {
- bb_perror_msg_and_die("Unable to connect to remote host (%s)", host);
+len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
+}
+
+#undef xsocket_type
+int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type)
+{
+ SKIP_FEATURE_IPV6(enum { family = AF_INET };)
+ len_and_sockaddr *lsa;
+ int fd;
+ int len;
+
+#if ENABLE_FEATURE_IPV6
+ if (family == AF_UNSPEC) {
+ fd = socket(AF_INET6, sock_type, 0);
+ if (fd >= 0) {
+ family = AF_INET6;
+ goto done;
+ }
+ family = AF_INET;
+ }
+#endif
+ fd = xsocket(family, sock_type, 0);
+ len = sizeof(struct sockaddr_in);
+#if ENABLE_FEATURE_IPV6
+ if (family == AF_INET6) {
+ done:
+ len = sizeof(struct sockaddr_in6);
}
- return s;
#endif
+ lsa = xzalloc(offsetof(len_and_sockaddr, u.sa) + len);
+ lsa->len = len;
+ lsa->u.sa.sa_family = family;
+ *lsap = lsa;
+ return fd;
+}
+
+int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap)
+{
+ return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
+}
+
+static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
+{
+ int fd;
+ len_and_sockaddr *lsa;
+
+ if (bindaddr && bindaddr[0]) {
+ lsa = xdotted2sockaddr(bindaddr, port);
+ /* user specified bind addr dictates family */
+ fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
+ } else {
+ fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type);
+ set_nport(lsa, htons(port));
+ }
+ setsockopt_reuseaddr(fd);
+ xbind(fd, &lsa->u.sa, lsa->len);
+ free(lsa);
+ return fd;
+}
+
+int FAST_FUNC create_and_bind_stream_or_die(const char *bindaddr, int port)
+{
+ return create_and_bind_or_die(bindaddr, port, SOCK_STREAM);
+}
+
+int FAST_FUNC create_and_bind_dgram_or_die(const char *bindaddr, int port)
+{
+ return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM);
+}
+
+
+int FAST_FUNC create_and_connect_stream_or_die(const char *peer, int port)
+{
+ int fd;
+ len_and_sockaddr *lsa;
+
+ lsa = xhost2sockaddr(peer, port);
+ fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
+ setsockopt_reuseaddr(fd);
+ xconnect(fd, &lsa->u.sa, lsa->len);
+ free(lsa);
+ return fd;
+}
+
+int FAST_FUNC xconnect_stream(const len_and_sockaddr *lsa)
+{
+ int fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
+ xconnect(fd, &lsa->u.sa, lsa->len);
+ return fd;
+}
+
+/* We hijack this constant to mean something else */
+/* It doesn't hurt because we will add this bit anyway */
+#define IGNORE_PORT NI_NUMERICSERV
+static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags)
+{
+ char host[128];
+ char serv[16];
+ int rc;
+ socklen_t salen;
+
+ salen = LSA_SIZEOF_SA;
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET)
+ salen = sizeof(struct sockaddr_in);
+ if (sa->sa_family == AF_INET6)
+ salen = sizeof(struct sockaddr_in6);
+#endif
+ rc = getnameinfo(sa, salen,
+ host, sizeof(host),
+ /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
+ serv, sizeof(serv),
+ /* do not resolve port# into service _name_ */
+ flags | NI_NUMERICSERV
+ );
+ if (rc)
+ return NULL;
+ if (flags & IGNORE_PORT)
+ return xstrdup(host);
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ if (strchr(host, ':')) /* heh, it's not a resolved hostname */
+ return xasprintf("[%s]:%s", host, serv);
+ /*return xasprintf("%s:%s", host, serv);*/
+ /* - fall through instead */
+ }
+#endif
+ /* For now we don't support anything else, so it has to be INET */
+ /*if (sa->sa_family == AF_INET)*/
+ return xasprintf("%s:%s", host, serv);
+ /*return xstrdup(host);*/
+}
+
+char* FAST_FUNC xmalloc_sockaddr2host(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, 0);
+}
+
+char* FAST_FUNC xmalloc_sockaddr2host_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, IGNORE_PORT);
+}
+
+char* FAST_FUNC xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT);
+}
+char* FAST_FUNC xmalloc_sockaddr2dotted(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NUMERICHOST);
+}
+
+char* FAST_FUNC xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT);
}
diff --git a/release/src/router/busybox/libbb/xfunc_die.c b/release/src/router/busybox/libbb/xfunc_die.c
new file mode 100644
index 00000000..ba9fe935
--- /dev/null
+++ b/release/src/router/busybox/libbb/xfunc_die.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+/* Keeping it separate allows to NOT suck in stdio for VERY small applets.
+ * Try building busybox with only "true" enabled... */
+
+#include "libbb.h"
+
+int die_sleep;
+#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH
+jmp_buf die_jmp;
+#endif
+
+void FAST_FUNC xfunc_die(void)
+{
+ if (die_sleep) {
+ if ((ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH)
+ && die_sleep < 0
+ ) {
+ /* Special case. We arrive here if NOFORK applet
+ * calls xfunc, which then decides to die.
+ * We don't die, but jump instead back to caller.
+ * NOFORK applets still cannot carelessly call xfuncs:
+ * p = xmalloc(10);
+ * q = xmalloc(10); // BUG! if this dies, we leak p!
+ */
+ /* -2222 means "zero" (longjmp can't pass 0)
+ * run_nofork_applet() catches -2222. */
+ longjmp(die_jmp, xfunc_error_retval ? xfunc_error_retval : -2222);
+ }
+ sleep(die_sleep);
+ }
+ exit(xfunc_error_retval);
+}
diff --git a/release/src/router/busybox/libbb/xfuncs.c b/release/src/router/busybox/libbb/xfuncs.c
index eb93bf13..a86efc29 100644
--- a/release/src/router/busybox/libbb/xfuncs.c
+++ b/release/src/router/busybox/libbb/xfuncs.c
@@ -2,111 +2,314 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to acknowledge your work.
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
*
- * 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
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+/* We need to have separate xfuncs.c and xfuncs_printf.c because
+ * with current linkers, even with section garbage collection,
+ * if *.o module references any of XXXprintf functions, you pull in
+ * entire printf machinery. Even if you do not use the function
+ * which uses XXXprintf.
*
- * 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.
+ * xfuncs.c contains functions (not necessarily xfuncs)
+ * which do not pull in printf, directly or indirectly.
+ * xfunc_printf.c contains those which do.
*
+ * TODO: move xmalloc() and xatonum() here.
*/
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
#include "libbb.h"
+/* Turn on nonblocking I/O on a fd */
+int FAST_FUNC ndelay_on(int fd)
+{
+ return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);
+}
+
+int FAST_FUNC ndelay_off(int fd)
+{
+ return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK);
+}
+
+int FAST_FUNC close_on_exec_on(int fd)
+{
+ return fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src)
+{
+#ifndef IFNAMSIZ
+ enum { IFNAMSIZ = 16 };
+#endif
+ return strncpy(dst, src, IFNAMSIZ);
+}
-#ifndef DMALLOC
-extern void *xmalloc(size_t size)
+/* Convert unsigned long long value into compact 4-char
+ * representation. Examples: "1234", "1.2k", " 27M", "123T"
+ * String is not terminated (buf[4] is untouched) */
+void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale)
{
- void *ptr = malloc(size);
+ const char *fmt;
+ char c;
+ unsigned v, u, idx = 0;
+
+ if (ul > 9999) { // do not scale if 9999 or less
+ ul *= 10;
+ do {
+ ul /= 1024;
+ idx++;
+ } while (ul >= 10000);
+ }
+ v = ul; // ullong divisions are expensive, avoid them
- if (!ptr)
- error_msg_and_die(memory_exhausted);
- return ptr;
+ fmt = " 123456789";
+ u = v / 10;
+ v = v % 10;
+ if (!idx) {
+ // 9999 or less: use "1234" format
+ // u is value/10, v is last digit
+ c = buf[0] = " 123456789"[u/100];
+ if (c != ' ') fmt = "0123456789";
+ c = buf[1] = fmt[u/10%10];
+ if (c != ' ') fmt = "0123456789";
+ buf[2] = fmt[u%10];
+ buf[3] = "0123456789"[v];
+ } else {
+ // u is value, v is 1/10ths (allows for 9.2M format)
+ if (u >= 10) {
+ // value is >= 10: use "123M', " 12M" formats
+ c = buf[0] = " 123456789"[u/100];
+ if (c != ' ') fmt = "0123456789";
+ v = u % 10;
+ u = u / 10;
+ buf[1] = fmt[u%10];
+ } else {
+ // value is < 10: use "9.2M" format
+ buf[0] = "0123456789"[u];
+ buf[1] = '.';
+ }
+ buf[2] = "0123456789"[v];
+ buf[3] = scale[idx]; /* typically scale = " kmgt..." */
+ }
}
-extern void *xrealloc(void *old, size_t size)
+/* Convert unsigned long long value into compact 5-char representation.
+ * String is not terminated (buf[5] is untouched) */
+void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale)
{
- void *ptr;
-
- /* SuS2 says "If size is 0 and ptr is not a null pointer, the
- * object pointed to is freed." Do that here, in case realloc
- * returns a NULL, since we don't want to choke in that case. */
- if (size==0 && old) {
- free(old);
- return NULL;
+ const char *fmt;
+ char c;
+ unsigned v, u, idx = 0;
+
+ if (ul > 99999) { // do not scale if 99999 or less
+ ul *= 10;
+ do {
+ ul /= 1024;
+ idx++;
+ } while (ul >= 100000);
}
+ v = ul; // ullong divisions are expensive, avoid them
- ptr = realloc(old, size);
- if (!ptr)
- error_msg_and_die(memory_exhausted);
- return ptr;
+ fmt = " 123456789";
+ u = v / 10;
+ v = v % 10;
+ if (!idx) {
+ // 99999 or less: use "12345" format
+ // u is value/10, v is last digit
+ c = buf[0] = " 123456789"[u/1000];
+ if (c != ' ') fmt = "0123456789";
+ c = buf[1] = fmt[u/100%10];
+ if (c != ' ') fmt = "0123456789";
+ c = buf[2] = fmt[u/10%10];
+ if (c != ' ') fmt = "0123456789";
+ buf[3] = fmt[u%10];
+ buf[4] = "0123456789"[v];
+ } else {
+ // value has been scaled into 0..9999.9 range
+ // u is value, v is 1/10ths (allows for 92.1M format)
+ if (u >= 100) {
+ // value is >= 100: use "1234M', " 123M" formats
+ c = buf[0] = " 123456789"[u/1000];
+ if (c != ' ') fmt = "0123456789";
+ c = buf[1] = fmt[u/100%10];
+ if (c != ' ') fmt = "0123456789";
+ v = u % 10;
+ u = u / 10;
+ buf[2] = fmt[u%10];
+ } else {
+ // value is < 100: use "92.1M" format
+ c = buf[0] = " 123456789"[u/10];
+ if (c != ' ') fmt = "0123456789";
+ buf[1] = fmt[u%10];
+ buf[2] = '.';
+ }
+ buf[3] = "0123456789"[v];
+ buf[4] = scale[idx]; /* typically scale = " kmgt..." */
+ }
}
-extern void *xcalloc(size_t nmemb, size_t size)
+
+// Convert unsigned integer to ascii, writing into supplied buffer.
+// A truncated result contains the first few digits of the result ala strncpy.
+// Returns a pointer past last generated digit, does _not_ store NUL.
+void BUG_sizeof_unsigned_not_4(void);
+char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen)
{
- void *ptr = calloc(nmemb, size);
- if (!ptr)
- error_msg_and_die(memory_exhausted);
- return ptr;
+ unsigned i, out, res;
+ if (sizeof(unsigned) != 4)
+ BUG_sizeof_unsigned_not_4();
+ if (buflen) {
+ out = 0;
+ for (i = 1000000000; i; i /= 10) {
+ res = n / i;
+ if (res || out || i == 1) {
+ if (!--buflen) break;
+ out++;
+ n -= res*i;
+ *buf++ = '0' + res;
+ }
+ }
+ }
+ return buf;
}
-extern char * xstrdup (const char *s) {
- char *t;
+/* Convert signed integer to ascii, like utoa_to_buf() */
+char* FAST_FUNC itoa_to_buf(int n, char *buf, unsigned buflen)
+{
+ if (buflen && n < 0) {
+ n = -n;
+ *buf++ = '-';
+ buflen--;
+ }
+ return utoa_to_buf((unsigned)n, buf, buflen);
+}
- if (s == NULL)
- return NULL;
+// The following two functions use a static buffer, so calling either one a
+// second time will overwrite previous results.
+//
+// The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes.
+// It so happens that sizeof(int) * 3 is enough for 32+ bits.
+// (sizeof(int) * 3 + 2 is correct for any width, even 8-bit)
- t = strdup (s);
+static char local_buf[sizeof(int) * 3];
- if (t == NULL)
- error_msg_and_die(memory_exhausted);
+// Convert unsigned integer to ascii using a static buffer (returned).
+char* FAST_FUNC utoa(unsigned n)
+{
+ *(utoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
- return t;
+ return local_buf;
}
-#endif
-extern char * xstrndup (const char *s, int n) {
- char *t;
+/* Convert signed integer to ascii using a static buffer (returned). */
+char* FAST_FUNC itoa(int n)
+{
+ *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
- if (s == NULL)
- error_msg_and_die("xstrndup bug");
+ return local_buf;
+}
- t = xmalloc(++n);
-
- return safe_strncpy(t,s,n);
+/* Emit a string of hex representation of bytes */
+char* FAST_FUNC bin2hex(char *p, const char *cp, int count)
+{
+ while (count) {
+ unsigned char c = *cp++;
+ /* put lowercase hex digits */
+ *p++ = 0x20 | bb_hexdigits_upcase[c >> 4];
+ *p++ = 0x20 | bb_hexdigits_upcase[c & 0xf];
+ count--;
+ }
+ return p;
}
-FILE *xfopen(const char *path, const char *mode)
+/* Return how long the file at fd is, if there's any way to determine it. */
+#ifdef UNUSED
+off_t FAST_FUNC fdlength(int fd)
{
- FILE *fp;
- if ((fp = fopen(path, mode)) == NULL)
- perror_msg_and_die("%s", path);
- return fp;
+ off_t bottom = 0, top = 0, pos;
+ long size;
+
+ // If the ioctl works for this, return it.
+
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512;
+
+ // FIXME: explain why lseek(SEEK_END) is not used here!
+
+ // If not, do a binary search for the last location we can read. (Some
+ // block devices don't do BLKGETSIZE right.)
+
+ do {
+ char temp;
+
+ pos = bottom + (top - bottom) / 2;
+
+ // If we can read from the current location, it's bigger.
+
+ if (lseek(fd, pos, SEEK_SET)>=0 && safe_read(fd, &temp, 1)==1) {
+ if (bottom == top) bottom = top = (top+1) * 2;
+ else bottom = pos;
+
+ // If we can't, it's smaller.
+
+ } else {
+ if (bottom == top) {
+ if (!top) return 0;
+ bottom = top/2;
+ }
+ else top = pos;
+ }
+ } while (bottom + 1 != top);
+
+ return pos + 1;
}
+#endif
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+char* FAST_FUNC xmalloc_ttyname(int fd)
+{
+ char *buf = xzalloc(128);
+ int r = ttyname_r(fd, buf, 127);
+ if (r) {
+ free(buf);
+ buf = NULL;
+ }
+ return buf;
+}
+
+/* It is perfectly ok to pass in a NULL for either width or for
+ * height, in which case that value will not be set. */
+int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height)
+{
+ struct winsize win = { 0, 0, 0, 0 };
+ int ret = ioctl(fd, TIOCGWINSZ, &win);
+
+ if (height) {
+ if (!win.ws_row) {
+ char *s = getenv("LINES");
+ if (s) win.ws_row = atoi(s);
+ }
+ if (win.ws_row <= 1 || win.ws_row >= 30000)
+ win.ws_row = 24;
+ *height = (int) win.ws_row;
+ }
+
+ if (width) {
+ if (!win.ws_col) {
+ char *s = getenv("COLUMNS");
+ if (s) win.ws_col = atoi(s);
+ }
+ if (win.ws_col <= 1 || win.ws_col >= 30000)
+ win.ws_col = 80;
+ *width = (int) win.ws_col;
+ }
+
+ return ret;
+}
+
+int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
+{
+ return tcsetattr(STDIN_FILENO, TCSANOW, tp);
+}
diff --git a/release/src/router/busybox/libbb/xfuncs_printf.c b/release/src/router/busybox/libbb/xfuncs_printf.c
new file mode 100644
index 00000000..6d0fa6e8
--- /dev/null
+++ b/release/src/router/busybox/libbb/xfuncs_printf.c
@@ -0,0 +1,548 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+
+/* We need to have separate xfuncs.c and xfuncs_printf.c because
+ * with current linkers, even with section garbage collection,
+ * if *.o module references any of XXXprintf functions, you pull in
+ * entire printf machinery. Even if you do not use the function
+ * which uses XXXprintf.
+ *
+ * xfuncs.c contains functions (not necessarily xfuncs)
+ * which do not pull in printf, directly or indirectly.
+ * xfunc_printf.c contains those which do.
+ */
+
+#include "libbb.h"
+
+
+/* All the functions starting with "x" call bb_error_msg_and_die() if they
+ * fail, so callers never need to check for errors. If it returned, it
+ * succeeded. */
+
+#ifndef DMALLOC
+/* dmalloc provides variants of these that do abort() on failure.
+ * Since dmalloc's prototypes overwrite the impls here as they are
+ * included after these prototypes in libbb.h, all is well.
+ */
+// Warn if we can't allocate size bytes of memory.
+void* FAST_FUNC malloc_or_warn(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr == NULL && size != 0)
+ bb_error_msg(bb_msg_memory_exhausted);
+ return ptr;
+}
+
+// Die if we can't allocate size bytes of memory.
+void* FAST_FUNC xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr == NULL && size != 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return ptr;
+}
+
+// Die if we can't resize previously allocated memory. (This returns a pointer
+// to the new memory, which may or may not be the same as the old memory.
+// It'll copy the contents to a new chunk and free the old one if necessary.)
+void* FAST_FUNC 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 /* DMALLOC */
+
+// Die if we can't allocate and zero size bytes of memory.
+void* FAST_FUNC xzalloc(size_t size)
+{
+ void *ptr = xmalloc(size);
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+// Die if we can't copy a string to freshly allocated memory.
+char* FAST_FUNC 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;
+}
+
+// Die if we can't allocate n+1 bytes (space for the null terminator) and copy
+// the (possibly truncated to length n) string into it.
+char* FAST_FUNC xstrndup(const char *s, int n)
+{
+ int m;
+ char *t;
+
+ if (ENABLE_DEBUG && s == NULL)
+ bb_error_msg_and_die("xstrndup bug");
+
+ /* We can just xmalloc(n+1) and strncpy into it, */
+ /* but think about xstrndup("abc", 10000) wastage! */
+ m = n;
+ t = (char*) s;
+ while (m) {
+ if (!*t) break;
+ m--;
+ t++;
+ }
+ n -= m;
+ t = xmalloc(n + 1);
+ t[n] = '\0';
+
+ return memcpy(t, s, n);
+}
+
+// Die if we can't open a file and return a FILE* to it.
+// Notice we haven't got xfread(), This is for use with fscanf() and friends.
+FILE* FAST_FUNC xfopen(const char *path, const char *mode)
+{
+ FILE *fp = fopen(path, mode);
+ if (fp == NULL)
+ bb_perror_msg_and_die("can't open '%s'", path);
+ return fp;
+}
+
+// Die if we can't open a file and return a fd.
+int FAST_FUNC xopen3(const char *pathname, int flags, int mode)
+{
+ int ret;
+
+ ret = open(pathname, flags, mode);
+ if (ret < 0) {
+ bb_perror_msg_and_die("can't open '%s'", pathname);
+ }
+ return ret;
+}
+
+// Die if we can't open an existing file and return a fd.
+int FAST_FUNC xopen(const char *pathname, int flags)
+{
+ return xopen3(pathname, flags, 0666);
+}
+
+// Warn if we can't open a file and return a fd.
+int FAST_FUNC open3_or_warn(const char *pathname, int flags, int mode)
+{
+ int ret;
+
+ ret = open(pathname, flags, mode);
+ if (ret < 0) {
+ bb_perror_msg("can't open '%s'", pathname);
+ }
+ return ret;
+}
+
+// Warn if we can't open a file and return a fd.
+int FAST_FUNC open_or_warn(const char *pathname, int flags)
+{
+ return open3_or_warn(pathname, flags, 0666);
+}
+
+void FAST_FUNC xunlink(const char *pathname)
+{
+ if (unlink(pathname))
+ bb_perror_msg_and_die("can't remove file '%s'", pathname);
+}
+
+void FAST_FUNC xrename(const char *oldpath, const char *newpath)
+{
+ if (rename(oldpath, newpath))
+ bb_perror_msg_and_die("can't move '%s' to '%s'", oldpath, newpath);
+}
+
+int FAST_FUNC rename_or_warn(const char *oldpath, const char *newpath)
+{
+ int n = rename(oldpath, newpath);
+ if (n)
+ bb_perror_msg("can't move '%s' to '%s'", oldpath, newpath);
+ return n;
+}
+
+void FAST_FUNC xpipe(int filedes[2])
+{
+ if (pipe(filedes))
+ bb_perror_msg_and_die("can't create pipe");
+}
+
+void FAST_FUNC xdup2(int from, int to)
+{
+ if (dup2(from, to) != to)
+ bb_perror_msg_and_die("can't duplicate file descriptor");
+}
+
+// "Renumber" opened fd
+void FAST_FUNC xmove_fd(int from, int to)
+{
+ if (from == to)
+ return;
+ xdup2(from, to);
+ close(from);
+}
+
+// Die with an error message if we can't write the entire buffer.
+void FAST_FUNC xwrite(int fd, const void *buf, size_t count)
+{
+ if (count) {
+ ssize_t size = full_write(fd, buf, count);
+ if ((size_t)size != count)
+ bb_error_msg_and_die("short write");
+ }
+}
+void FAST_FUNC xwrite_str(int fd, const char *str)
+{
+ xwrite(fd, str, strlen(str));
+}
+
+// Die with an error message if we can't lseek to the right spot.
+off_t FAST_FUNC xlseek(int fd, off_t offset, int whence)
+{
+ off_t off = lseek(fd, offset, whence);
+ if (off == (off_t)-1) {
+ if (whence == SEEK_SET)
+ bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset);
+ bb_perror_msg_and_die("lseek");
+ }
+ return off;
+}
+
+// Die with supplied filename if this FILE* has ferror set.
+void FAST_FUNC die_if_ferror(FILE *fp, const char *fn)
+{
+ if (ferror(fp)) {
+ /* ferror doesn't set useful errno */
+ bb_error_msg_and_die("%s: I/O error", fn);
+ }
+}
+
+// Die with an error message if stdout has ferror set.
+void FAST_FUNC die_if_ferror_stdout(void)
+{
+ die_if_ferror(stdout, bb_msg_standard_output);
+}
+
+// Die with an error message if we have trouble flushing stdout.
+void FAST_FUNC xfflush_stdout(void)
+{
+ if (fflush(stdout)) {
+ bb_perror_msg_and_die(bb_msg_standard_output);
+ }
+}
+
+
+int FAST_FUNC bb_putchar(int ch)
+{
+ /* time.c needs putc(ch, stdout), not putchar(ch).
+ * it does "stdout = stderr;", but then glibc's putchar()
+ * doesn't work as expected. bad glibc, bad */
+ return putc(ch, stdout);
+}
+
+/* Die with an error message if we can't copy an entire FILE* to stdout,
+ * then close that file. */
+void FAST_FUNC xprint_and_close_file(FILE *file)
+{
+ fflush(stdout);
+ // copyfd outputs error messages for us.
+ if (bb_copyfd_eof(fileno(file), 1) == -1)
+ xfunc_die();
+
+ fclose(file);
+}
+
+// Die with an error message if we can't malloc() enough space and do an
+// sprintf() into that space.
+char* FAST_FUNC xasprintf(const char *format, ...)
+{
+ va_list p;
+ int r;
+ char *string_ptr;
+
+#if 1
+ // GNU extension
+ va_start(p, format);
+ r = vasprintf(&string_ptr, format, p);
+ va_end(p);
+#else
+ // Bloat for systems that haven't got the GNU extension.
+ va_start(p, format);
+ r = vsnprintf(NULL, 0, format, p);
+ va_end(p);
+ string_ptr = xmalloc(r+1);
+ va_start(p, format);
+ r = vsnprintf(string_ptr, r+1, format, p);
+ va_end(p);
+#endif
+
+ if (r < 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return string_ptr;
+}
+
+#if 0 /* If we will ever meet a libc which hasn't [f]dprintf... */
+int FAST_FUNC fdprintf(int fd, const char *format, ...)
+{
+ va_list p;
+ int r;
+ char *string_ptr;
+
+#if 1
+ // GNU extension
+ va_start(p, format);
+ r = vasprintf(&string_ptr, format, p);
+ va_end(p);
+#else
+ // Bloat for systems that haven't got the GNU extension.
+ va_start(p, format);
+ r = vsnprintf(NULL, 0, format, p) + 1;
+ va_end(p);
+ string_ptr = malloc(r);
+ if (string_ptr) {
+ va_start(p, format);
+ r = vsnprintf(string_ptr, r, format, p);
+ va_end(p);
+ }
+#endif
+
+ if (r >= 0) {
+ full_write(fd, string_ptr, r);
+ free(string_ptr);
+ }
+ return r;
+}
+#endif
+
+void FAST_FUNC xsetenv(const char *key, const char *value)
+{
+ if (setenv(key, value, 1))
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+}
+
+/* Handles "VAR=VAL" strings, even those which are part of environ
+ * _right now_
+ */
+void FAST_FUNC bb_unsetenv(const char *var)
+{
+ char *tp = strchr(var, '=');
+
+ if (!tp) {
+ unsetenv(var);
+ return;
+ }
+
+ /* In case var was putenv'ed, we can't replace '='
+ * with NUL and unsetenv(var) - it won't work,
+ * env is modified by the replacement, unsetenv
+ * sees "VAR" instead of "VAR=VAL" and does not remove it!
+ * horror :( */
+ tp = xstrndup(var, tp - var);
+ unsetenv(tp);
+ free(tp);
+}
+
+
+// Die with an error message if we can't set gid. (Because resource limits may
+// limit this user to a given number of processes, and if that fills up the
+// setgid() will fail and we'll _still_be_root_, which is bad.)
+void FAST_FUNC xsetgid(gid_t gid)
+{
+ if (setgid(gid)) bb_perror_msg_and_die("setgid");
+}
+
+// Die with an error message if we can't set uid. (See xsetgid() for why.)
+void FAST_FUNC xsetuid(uid_t uid)
+{
+ if (setuid(uid)) bb_perror_msg_and_die("setuid");
+}
+
+// Die if we can't chdir to a new path.
+void FAST_FUNC xchdir(const char *path)
+{
+ if (chdir(path))
+ bb_perror_msg_and_die("chdir(%s)", path);
+}
+
+void FAST_FUNC xchroot(const char *path)
+{
+ if (chroot(path))
+ bb_perror_msg_and_die("can't change root directory to %s", path);
+}
+
+// Print a warning message if opendir() fails, but don't die.
+DIR* FAST_FUNC warn_opendir(const char *path)
+{
+ DIR *dp;
+
+ dp = opendir(path);
+ if (!dp)
+ bb_perror_msg("can't open '%s'", path);
+ return dp;
+}
+
+// Die with an error message if opendir() fails.
+DIR* FAST_FUNC xopendir(const char *path)
+{
+ DIR *dp;
+
+ dp = opendir(path);
+ if (!dp)
+ bb_perror_msg_and_die("can't open '%s'", path);
+ return dp;
+}
+
+// Die with an error message if we can't open a new socket.
+int FAST_FUNC xsocket(int domain, int type, int protocol)
+{
+ int r = socket(domain, type, protocol);
+
+ if (r < 0) {
+ /* Hijack vaguely related config option */
+#if ENABLE_VERBOSE_RESOLUTION_ERRORS
+ const char *s = "INET";
+ if (domain == AF_PACKET) s = "PACKET";
+ if (domain == AF_NETLINK) s = "NETLINK";
+USE_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
+ bb_perror_msg_and_die("socket(AF_%s)", s);
+#else
+ bb_perror_msg_and_die("socket");
+#endif
+ }
+
+ return r;
+}
+
+// Die with an error message if we can't bind a socket to an address.
+void FAST_FUNC xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
+{
+ if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind");
+}
+
+// Die with an error message if we can't listen for connections on a socket.
+void FAST_FUNC xlisten(int s, int backlog)
+{
+ if (listen(s, backlog)) bb_perror_msg_and_die("listen");
+}
+
+/* Die with an error message if sendto failed.
+ * Return bytes sent otherwise */
+ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
+ socklen_t tolen)
+{
+ ssize_t ret = sendto(s, buf, len, 0, to, tolen);
+ if (ret < 0) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ close(s);
+ bb_perror_msg_and_die("sendto");
+ }
+ return ret;
+}
+
+// xstat() - a stat() which dies on failure with meaningful error message
+void FAST_FUNC xstat(const char *name, struct stat *stat_buf)
+{
+ if (stat(name, stat_buf))
+ bb_perror_msg_and_die("can't stat '%s'", name);
+}
+
+// selinux_or_die() - die if SELinux is disabled.
+void FAST_FUNC selinux_or_die(void)
+{
+#if ENABLE_SELINUX
+ int rc = is_selinux_enabled();
+ if (rc == 0) {
+ bb_error_msg_and_die("SELinux is disabled");
+ } else if (rc < 0) {
+ bb_error_msg_and_die("is_selinux_enabled() failed");
+ }
+#else
+ bb_error_msg_and_die("SELinux support is disabled");
+#endif
+}
+
+int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...)
+{
+ int ret;
+ va_list p;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0) {
+ va_start(p, fmt);
+ bb_verror_msg(fmt, p, strerror(errno));
+ /* xfunc_die can actually longjmp, so be nice */
+ va_end(p);
+ xfunc_die();
+ }
+ return ret;
+}
+
+int FAST_FUNC ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...)
+{
+ va_list p;
+ int ret = ioctl(fd, request, argp);
+
+ if (ret < 0) {
+ va_start(p, fmt);
+ bb_verror_msg(fmt, p, strerror(errno));
+ va_end(p);
+ }
+ return ret;
+}
+
+#if ENABLE_IOCTL_HEX2STR_ERROR
+int FAST_FUNC bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name)
+{
+ int ret;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0)
+ bb_simple_perror_msg(ioctl_name);
+ return ret;
+}
+int FAST_FUNC bb_xioctl(int fd, unsigned request, void *argp, const char *ioctl_name)
+{
+ int ret;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0)
+ bb_simple_perror_msg_and_die(ioctl_name);
+ return ret;
+}
+#else
+int FAST_FUNC bb_ioctl_or_warn(int fd, unsigned request, void *argp)
+{
+ int ret;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0)
+ bb_perror_msg("ioctl %#x failed", request);
+ return ret;
+}
+int FAST_FUNC bb_xioctl(int fd, unsigned request, void *argp)
+{
+ int ret;
+
+ ret = ioctl(fd, request, argp);
+ if (ret < 0)
+ bb_perror_msg_and_die("ioctl %#x failed", request);
+ return ret;
+}
+#endif
diff --git a/release/src/router/busybox/libbb/xgetcwd.c b/release/src/router/busybox/libbb/xgetcwd.c
index 27466816..10febe32 100644
--- a/release/src/router/busybox/libbb/xgetcwd.c
+++ b/release/src/router/busybox/libbb/xgetcwd.c
@@ -1,52 +1,43 @@
+/* vi: set sw=4 ts=4: */
/*
* 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 <vodz@usa.net>
-*/
+ * Special function for busybox written by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.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* FAST_FUNC
+xrealloc_getcwd_or_warn(char *cwd)
{
- char *ret;
- unsigned path_max;
-
- errno = 0;
- path_max = (unsigned) PATH_MAX;
- path_max += 2; /* The getcwd docs say to do this. */
-
- if(cwd==0)
- cwd = xmalloc (path_max);
-
- errno = 0;
- while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) {
- path_max += PATH_INCR;
- cwd = xrealloc (cwd, path_max);
- errno = 0;
- }
-
- if (ret == NULL) {
- int save_errno = errno;
- free (cwd);
- errno = save_errno;
- perror_msg("getcwd()");
- return NULL;
- }
-
- return cwd;
+#define PATH_INCR 64
+
+ char *ret;
+ unsigned path_max;
+
+ path_max = 128; /* 128 + 64 should be enough for 99% of cases */
+
+ while (1) {
+ path_max += PATH_INCR;
+ cwd = xrealloc(cwd, path_max);
+ ret = getcwd(cwd, path_max);
+ if (ret == NULL) {
+ if (errno == ERANGE)
+ continue;
+ free(cwd);
+ bb_perror_msg("getcwd");
+ return NULL;
+ }
+ cwd = xrealloc(cwd, strlen(cwd) + 1);
+ return cwd;
+ }
}
diff --git a/release/src/router/busybox/libbb/xgethostbyname.c b/release/src/router/busybox/libbb/xgethostbyname.c
index 25851033..f1839f7e 100644
--- a/release/src/router/busybox/libbb/xgethostbyname.c
+++ b/release/src/router/busybox/libbb/xgethostbyname.c
@@ -2,36 +2,18 @@
/*
* 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
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <netdb.h>
-extern int h_errno;
-
+//#include <netdb.h>
#include "libbb.h"
-struct hostent *xgethostbyname(const char *name)
+struct hostent* FAST_FUNC xgethostbyname(const char *name)
{
- struct hostent *retval;
-
- if ((retval = gethostbyname(name)) == NULL)
- herror_msg_and_die("%s", name);
-
+ struct hostent *retval = gethostbyname(name);
+ if (!retval)
+ bb_herror_msg_and_die("%s", name);
return retval;
}
diff --git a/release/src/router/busybox/libbb/xgethostbyname2.c b/release/src/router/busybox/libbb/xgethostbyname2.c
deleted file mode 100644
index 3a16ae4d..00000000
--- a/release/src/router/busybox/libbb/xgethostbyname2.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/* 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/release/src/router/busybox/libbb/xgetlarg.c b/release/src/router/busybox/libbb/xgetlarg.c
deleted file mode 100644
index ed5d3eb4..00000000
--- a/release/src/router/busybox/libbb/xgetlarg.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Copyright (C) 2003 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/release/src/router/busybox/libbb/xgetularg.c b/release/src/router/busybox/libbb/xgetularg.c
deleted file mode 100644
index d743520c..00000000
--- a/release/src/router/busybox/libbb/xgetularg.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* 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/release/src/router/busybox/libbb/xreadlink.c b/release/src/router/busybox/libbb/xreadlink.c
index 932e487a..8d232f16 100644
--- a/release/src/router/busybox/libbb/xreadlink.c
+++ b/release/src/router/busybox/libbb/xreadlink.c
@@ -1,37 +1,117 @@
+/* vi: set sw=4 ts=4: */
/*
- * xreadlink.c - safe implementation of readlink.
- * Returns a NULL on failure...
+ * xreadlink.c - safe implementation of readlink.
+ * Returns a NULL on failure...
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
+#include "libbb.h"
/*
* NOTE: This function returns a malloced char* that you will have to free
- * yourself. You have been warned.
+ * yourself.
*/
+char* FAST_FUNC xmalloc_readlink(const char *path)
+{
+ enum { GROWBY = 80 }; /* how large we will grow strings by */
-#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;
+ char *buf = NULL;
int bufsize = 0, readsize = 0;
do {
- buf = xrealloc(buf, bufsize += GROWBY);
- readsize = readlink(path, buf, bufsize); /* 1st try */
+ bufsize += GROWBY;
+ buf = xrealloc(buf, bufsize);
+ readsize = readlink(path, buf, bufsize);
if (readsize == -1) {
- perror_msg("%s:%s", applet_name, path);
- return NULL;
+ free(buf);
+ return NULL;
}
- }
- while (bufsize < readsize + 1);
+ } while (bufsize < readsize + 1);
buf[readsize] = '\0';
return buf;
-}
+}
+
+/*
+ * This routine is not the same as realpath(), which
+ * canonicalizes the given path completely. This routine only
+ * follows trailing symlinks until a real file is reached and
+ * returns its name. If the path ends in a dangling link or if
+ * the target doesn't exist, the path is returned in any case.
+ * Intermediate symlinks in the path are not expanded -- only
+ * those at the tail.
+ * A malloced char* is returned, which must be freed by the caller.
+ */
+char* FAST_FUNC xmalloc_follow_symlinks(const char *path)
+{
+ char *buf;
+ char *lpc;
+ char *linkpath;
+ int bufsize;
+ int looping = MAXSYMLINKS + 1;
+
+ buf = xstrdup(path);
+ goto jump_in;
+
+ while (1) {
+ linkpath = xmalloc_readlink(buf);
+ if (!linkpath) {
+ /* not a symlink, or doesn't exist */
+ if (errno == EINVAL || errno == ENOENT)
+ return buf;
+ goto free_buf_ret_null;
+ }
+
+ if (!--looping) {
+ free(linkpath);
+ free_buf_ret_null:
+ free(buf);
+ return NULL;
+ }
+
+ if (*linkpath != '/') {
+ bufsize += strlen(linkpath);
+ buf = xrealloc(buf, bufsize);
+ lpc = bb_get_last_path_component_strip(buf);
+ strcpy(lpc, linkpath);
+ free(linkpath);
+ } else {
+ free(buf);
+ buf = linkpath;
+ jump_in:
+ bufsize = strlen(buf) + 1;
+ }
+ }
+}
+
+char* FAST_FUNC xmalloc_readlink_or_warn(const char *path)
+{
+ char *buf = xmalloc_readlink(path);
+ if (!buf) {
+ /* EINVAL => "file: Invalid argument" => puzzled user */
+ const char *errmsg = "not a symlink";
+ int err = errno;
+ if (err != EINVAL)
+ errmsg = strerror(err);
+ bb_error_msg("%s: cannot read link: %s", path, errmsg);
+ }
+ return buf;
+}
+
+/* UNUSED */
+#if 0
+char* FAST_FUNC xmalloc_realpath(const char *path)
+{
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+ /* glibc provides a non-standard extension */
+ return realpath(path, NULL);
+#else
+ char buf[PATH_MAX+1];
+ /* on error returns NULL (xstrdup(NULL) ==NULL) */
+ return xstrdup(realpath(path, buf));
+#endif
+}
+#endif
diff --git a/release/src/router/busybox/libbb/xrealloc_vector.c b/release/src/router/busybox/libbb/xrealloc_vector.c
new file mode 100644
index 00000000..bbd5ab8a
--- /dev/null
+++ b/release/src/router/busybox/libbb/xrealloc_vector.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Resize (grow) malloced vector.
+ *
+ * #define magic packed two parameters into one:
+ * sizeof = sizeof_and_shift >> 8
+ * shift = (sizeof_and_shift) & 0xff
+ *
+ * Lets say shift = 4. 1 << 4 == 0x10.
+ * If idx == 0, 0x10, 0x20 etc, vector[] is resized to next higher
+ * idx step, plus one: if idx == 0x20, vector[] is resized to 0x31,
+ * thus last usable element is vector[0x30].
+ *
+ * In other words: after xrealloc_vector(v, 4, idx) it's ok to use
+ * at least v[idx] and v[idx+1], for all idx values.
+ *
+ * New elements are zeroed out, but only if realloc was done
+ * (not on every call). You can depend on v[idx] and v[idx+1] being
+ * zeroed out if you use it like this:
+ * v = xrealloc_vector(v, 4, idx);
+ * v[idx].some_fields = ...; - the rest stays 0/NULL
+ * idx++;
+ * If you do not advance idx like above, you should be more careful.
+ * Next call to xrealloc_vector(v, 4, idx) may or may not zero out v[idx].
+ */
+void* FAST_FUNC xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx)
+{
+ int mask = 1 << (uint8_t)sizeof_and_shift;
+
+ if (!(idx & (mask - 1))) {
+ sizeof_and_shift >>= 8; /* sizeof(vector[0]) */
+ vector = xrealloc(vector, sizeof_and_shift * (idx + mask + 1));
+ memset((char*)vector + (sizeof_and_shift * idx), 0, sizeof_and_shift * (mask + 1));
+ }
+ return vector;
+}
diff --git a/release/src/router/busybox/libbb/xregcomp.c b/release/src/router/busybox/libbb/xregcomp.c
index 6f5e2f0c..61efb5bc 100644
--- a/release/src/router/busybox/libbb/xregcomp.c
+++ b/release/src/router/busybox/libbb/xregcomp.c
@@ -2,52 +2,31 @@
/*
* Utility routines.
*
- * Copyright (C) tons of folks. Tracking down who wrote what
- * isn't something I'm going to worry about... If you wrote something
- * here, please feel free to 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
- *
- * 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.
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
#include "libbb.h"
-#include <regex.h>
-
-
+#include "xregex.h"
-void xregcomp(regex_t *preg, const char *regex, int cflags)
+char* FAST_FUNC regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags)
{
- int ret;
- if ((ret = regcomp(preg, regex, cflags)) != 0) {
+ int ret = regcomp(preg, regex, cflags);
+ if (ret) {
int errmsgsz = regerror(ret, preg, NULL, 0);
char *errmsg = xmalloc(errmsgsz);
regerror(ret, preg, errmsg, errmsgsz);
- error_msg_and_die("xregcomp: %s", errmsg);
+ return errmsg;
}
+ return NULL;
}
-
-/* END CODE */
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
+void FAST_FUNC xregcomp(regex_t *preg, const char *regex, int cflags)
+{
+ char *errmsg = regcomp_or_errmsg(preg, regex, cflags);
+ if (errmsg) {
+ bb_error_msg_and_die("bad regex '%s': %s", regex, errmsg);
+ }
+}