From 4aca87515a5083ae0e31ce3177189fd43b6d05ac Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 3 Jan 2015 13:58:15 +0100 Subject: patch to Vanilla Tomato 1.28 --- release/src/router/busybox/libbb/Config.in | 154 ++ release/src/router/busybox/libbb/Kbuild | 155 ++ release/src/router/busybox/libbb/Makefile | 11 - release/src/router/busybox/libbb/Makefile.in | 105 - release/src/router/busybox/libbb/README | 20 +- release/src/router/busybox/libbb/appletlib.c | 783 ++++++++ release/src/router/busybox/libbb/arith.c | 263 --- .../src/router/busybox/libbb/ask_confirmation.c | 61 +- release/src/router/busybox/libbb/bb_askpass.c | 79 + release/src/router/busybox/libbb/bb_asprintf.c | 22 - release/src/router/busybox/libbb/bb_basename.c | 18 + release/src/router/busybox/libbb/bb_do_delay.c | 22 + release/src/router/busybox/libbb/bb_pwd.c | 112 ++ release/src/router/busybox/libbb/bb_qsort.c | 20 + release/src/router/busybox/libbb/bb_strtod.c | 86 + release/src/router/busybox/libbb/bb_strtonum.c | 139 ++ release/src/router/busybox/libbb/change_identity.c | 25 +- release/src/router/busybox/libbb/chomp.c | 44 +- .../router/busybox/libbb/compare_string_array.c | 85 +- .../src/router/busybox/libbb/concat_path_file.c | 27 +- .../src/router/busybox/libbb/concat_subpath_file.c | 21 +- release/src/router/busybox/libbb/copy_file.c | 436 ++-- release/src/router/busybox/libbb/copy_file_chunk.c | 74 - release/src/router/busybox/libbb/copyfd.c | 136 +- .../src/router/busybox/libbb/correct_password.c | 72 +- release/src/router/busybox/libbb/crc32.c | 42 + .../src/router/busybox/libbb/create_icmp6_socket.c | 31 +- .../src/router/busybox/libbb/create_icmp_socket.c | 31 +- release/src/router/busybox/libbb/daemon.c | 101 - .../router/busybox/libbb/default_error_retval.c | 20 +- release/src/router/busybox/libbb/device_open.c | 45 +- .../src/router/busybox/libbb/die_if_bad_username.c | 36 + release/src/router/busybox/libbb/dirname.c | 49 - release/src/router/busybox/libbb/dump.c | 527 ++--- release/src/router/busybox/libbb/error_msg.c | 41 +- .../src/router/busybox/libbb/error_msg_and_die.c | 43 +- release/src/router/busybox/libbb/execable.c | 78 + release/src/router/busybox/libbb/fclose_nonstdin.c | 32 +- .../router/busybox/libbb/fflush_stdout_and_exit.c | 32 +- release/src/router/busybox/libbb/fgets_str.c | 84 +- .../src/router/busybox/libbb/find_mount_point.c | 64 +- .../src/router/busybox/libbb/find_pid_by_name.c | 261 +-- .../src/router/busybox/libbb/find_root_device.c | 116 +- release/src/router/busybox/libbb/full_read.c | 70 - release/src/router/busybox/libbb/full_write.c | 56 +- release/src/router/busybox/libbb/get_console.c | 131 +- .../router/busybox/libbb/get_last_path_component.c | 87 +- .../src/router/busybox/libbb/get_line_from_file.c | 231 ++- release/src/router/busybox/libbb/getopt32.c | 592 ++++++ release/src/router/busybox/libbb/getopt_ulflags.c | 170 -- release/src/router/busybox/libbb/getpty.c | 64 + release/src/router/busybox/libbb/gz_open.c | 35 - release/src/router/busybox/libbb/herror_msg.c | 39 +- .../src/router/busybox/libbb/herror_msg_and_die.c | 41 +- release/src/router/busybox/libbb/human_readable.c | 71 +- release/src/router/busybox/libbb/inet_common.c | 204 +- release/src/router/busybox/libbb/info_msg.c | 56 + release/src/router/busybox/libbb/inode_hash.c | 101 +- release/src/router/busybox/libbb/interface.c | 2113 -------------------- release/src/router/busybox/libbb/isdirectory.c | 55 +- release/src/router/busybox/libbb/kernel_version.c | 47 +- release/src/router/busybox/libbb/last_char_is.c | 38 +- release/src/router/busybox/libbb/libbb.h | 325 --- release/src/router/busybox/libbb/libc5.c | 167 -- release/src/router/busybox/libbb/lineedit.c | 2006 +++++++++++++++++++ .../src/router/busybox/libbb/lineedit_ptr_hack.c | 23 + release/src/router/busybox/libbb/llist.c | 98 + release/src/router/busybox/libbb/llist_add_to.c | 15 - release/src/router/busybox/libbb/login.c | 185 +- release/src/router/busybox/libbb/loop.c | 230 ++- release/src/router/busybox/libbb/make_directory.c | 123 +- release/src/router/busybox/libbb/makedev.c | 24 + release/src/router/busybox/libbb/match_fstype.c | 42 + release/src/router/busybox/libbb/md5.c | 429 ++++ release/src/router/busybox/libbb/md5prime.c | 460 +++++ release/src/router/busybox/libbb/messages.c | 116 +- release/src/router/busybox/libbb/mk_loop_h.sh | 37 - release/src/router/busybox/libbb/mode_string.c | 166 +- release/src/router/busybox/libbb/module_syscalls.c | 88 - release/src/router/busybox/libbb/mtab.c | 104 +- release/src/router/busybox/libbb/mtab_file.c | 49 +- release/src/router/busybox/libbb/my_getgrgid.c | 55 - release/src/router/busybox/libbb/my_getgrnam.c | 56 - release/src/router/busybox/libbb/my_getpwnam.c | 56 - release/src/router/busybox/libbb/my_getpwnamegid.c | 61 - release/src/router/busybox/libbb/my_getpwuid.c | 55 - release/src/router/busybox/libbb/obscure.c | 359 ++-- release/src/router/busybox/libbb/parse_config.c | 219 ++ release/src/router/busybox/libbb/parse_mode.c | 228 ++- release/src/router/busybox/libbb/parse_number.c | 74 - release/src/router/busybox/libbb/perror_msg.c | 44 +- .../src/router/busybox/libbb/perror_msg_and_die.c | 46 +- release/src/router/busybox/libbb/perror_nomsg.c | 30 +- .../router/busybox/libbb/perror_nomsg_and_die.c | 30 +- release/src/router/busybox/libbb/pidfile.c | 40 + release/src/router/busybox/libbb/print_file.c | 61 - release/src/router/busybox/libbb/print_flags.c | 32 + release/src/router/busybox/libbb/printable.c | 34 + release/src/router/busybox/libbb/printf.c | 177 -- .../router/busybox/libbb/process_escape_sequence.c | 109 +- release/src/router/busybox/libbb/procps.c | 558 ++++-- release/src/router/busybox/libbb/ptr_to_globals.c | 35 + release/src/router/busybox/libbb/pw_encrypt.c | 142 +- release/src/router/busybox/libbb/pw_encrypt_des.c | 820 ++++++++ release/src/router/busybox/libbb/pw_encrypt_md5.c | 161 ++ release/src/router/busybox/libbb/pw_encrypt_sha.c | 286 +++ release/src/router/busybox/libbb/pwd2spwd.c | 74 - release/src/router/busybox/libbb/qmodule.c | 29 - release/src/router/busybox/libbb/read.c | 394 ++++ release/src/router/busybox/libbb/read_key.c | 157 ++ .../src/router/busybox/libbb/read_package_field.c | 91 - release/src/router/busybox/libbb/real_loop.h | 37 - .../src/router/busybox/libbb/recursive_action.c | 225 +-- release/src/router/busybox/libbb/remove_file.c | 101 +- .../src/router/busybox/libbb/restricted_shell.c | 25 +- release/src/router/busybox/libbb/rtc.c | 90 + release/src/router/busybox/libbb/run_parts.c | 125 -- release/src/router/busybox/libbb/run_shell.c | 81 +- .../src/router/busybox/libbb/safe_gethostname.c | 66 + release/src/router/busybox/libbb/safe_poll.c | 34 + release/src/router/busybox/libbb/safe_read.c | 54 - release/src/router/busybox/libbb/safe_strncpy.c | 53 +- release/src/router/busybox/libbb/safe_write.c | 21 + release/src/router/busybox/libbb/selinux_common.c | 56 + .../src/router/busybox/libbb/setup_environment.c | 79 +- release/src/router/busybox/libbb/sha1.c | 465 +++++ release/src/router/busybox/libbb/signals.c | 121 ++ release/src/router/busybox/libbb/simplify_path.c | 59 +- release/src/router/busybox/libbb/skip_whitespace.c | 32 +- release/src/router/busybox/libbb/speed_table.c | 32 +- release/src/router/busybox/libbb/str_tolower.c | 14 + release/src/router/busybox/libbb/strrstr.c | 71 + release/src/router/busybox/libbb/syscalls.c | 115 -- .../router/busybox/libbb/syslog_msg_with_name.c | 51 - release/src/router/busybox/libbb/time.c | 66 + release/src/router/busybox/libbb/time_string.c | 68 - release/src/router/busybox/libbb/trim.c | 54 +- release/src/router/busybox/libbb/u_signal_names.c | 278 +-- release/src/router/busybox/libbb/udp_io.c | 168 ++ release/src/router/busybox/libbb/unarchive.c | 601 ------ release/src/router/busybox/libbb/unzip.c | 1007 ---------- release/src/router/busybox/libbb/update_passwd.c | 266 +++ release/src/router/busybox/libbb/uuencode.c | 71 + release/src/router/busybox/libbb/vdprintf.c | 42 +- release/src/router/busybox/libbb/verror_msg.c | 150 +- .../src/router/busybox/libbb/vfork_daemon_rexec.c | 339 +++- release/src/router/busybox/libbb/vherror_msg.c | 44 - release/src/router/busybox/libbb/vperror_msg.c | 51 - .../src/router/busybox/libbb/warn_ignoring_args.c | 23 +- release/src/router/busybox/libbb/wfopen.c | 60 +- release/src/router/busybox/libbb/wfopen_input.c | 60 +- release/src/router/busybox/libbb/write.c | 19 + release/src/router/busybox/libbb/xatonum.c | 70 + .../src/router/busybox/libbb/xatonum_template.c | 191 ++ release/src/router/busybox/libbb/xconnect.c | 460 ++++- release/src/router/busybox/libbb/xfunc_die.c | 40 + release/src/router/busybox/libbb/xfuncs.c | 353 +++- release/src/router/busybox/libbb/xfuncs_printf.c | 548 +++++ release/src/router/busybox/libbb/xgetcwd.c | 65 +- release/src/router/busybox/libbb/xgethostbyname.c | 30 +- release/src/router/busybox/libbb/xgethostbyname2.c | 37 - release/src/router/busybox/libbb/xgetlarg.c | 35 - release/src/router/busybox/libbb/xgetularg.c | 160 -- release/src/router/busybox/libbb/xreadlink.c | 118 +- release/src/router/busybox/libbb/xrealloc_vector.c | 45 + release/src/router/busybox/libbb/xregcomp.c | 53 +- 166 files changed, 14918 insertions(+), 10665 deletions(-) create mode 100644 release/src/router/busybox/libbb/Config.in create mode 100644 release/src/router/busybox/libbb/Kbuild delete mode 100644 release/src/router/busybox/libbb/Makefile delete mode 100755 release/src/router/busybox/libbb/Makefile.in create mode 100644 release/src/router/busybox/libbb/appletlib.c delete mode 100644 release/src/router/busybox/libbb/arith.c create mode 100644 release/src/router/busybox/libbb/bb_askpass.c delete mode 100644 release/src/router/busybox/libbb/bb_asprintf.c create mode 100644 release/src/router/busybox/libbb/bb_basename.c create mode 100644 release/src/router/busybox/libbb/bb_do_delay.c create mode 100644 release/src/router/busybox/libbb/bb_pwd.c create mode 100644 release/src/router/busybox/libbb/bb_qsort.c create mode 100644 release/src/router/busybox/libbb/bb_strtod.c create mode 100644 release/src/router/busybox/libbb/bb_strtonum.c delete mode 100644 release/src/router/busybox/libbb/copy_file_chunk.c create mode 100644 release/src/router/busybox/libbb/crc32.c delete mode 100644 release/src/router/busybox/libbb/daemon.c create mode 100644 release/src/router/busybox/libbb/die_if_bad_username.c delete mode 100644 release/src/router/busybox/libbb/dirname.c create mode 100644 release/src/router/busybox/libbb/execable.c delete mode 100644 release/src/router/busybox/libbb/full_read.c create mode 100644 release/src/router/busybox/libbb/getopt32.c delete mode 100644 release/src/router/busybox/libbb/getopt_ulflags.c create mode 100644 release/src/router/busybox/libbb/getpty.c delete mode 100644 release/src/router/busybox/libbb/gz_open.c create mode 100644 release/src/router/busybox/libbb/info_msg.c delete mode 100644 release/src/router/busybox/libbb/interface.c delete mode 100644 release/src/router/busybox/libbb/libbb.h delete mode 100644 release/src/router/busybox/libbb/libc5.c create mode 100644 release/src/router/busybox/libbb/lineedit.c create mode 100644 release/src/router/busybox/libbb/lineedit_ptr_hack.c create mode 100644 release/src/router/busybox/libbb/llist.c delete mode 100644 release/src/router/busybox/libbb/llist_add_to.c create mode 100644 release/src/router/busybox/libbb/makedev.c create mode 100644 release/src/router/busybox/libbb/match_fstype.c create mode 100644 release/src/router/busybox/libbb/md5.c create mode 100644 release/src/router/busybox/libbb/md5prime.c delete mode 100755 release/src/router/busybox/libbb/mk_loop_h.sh delete mode 100644 release/src/router/busybox/libbb/module_syscalls.c delete mode 100644 release/src/router/busybox/libbb/my_getgrgid.c delete mode 100644 release/src/router/busybox/libbb/my_getgrnam.c delete mode 100644 release/src/router/busybox/libbb/my_getpwnam.c delete mode 100644 release/src/router/busybox/libbb/my_getpwnamegid.c delete mode 100644 release/src/router/busybox/libbb/my_getpwuid.c create mode 100644 release/src/router/busybox/libbb/parse_config.c delete mode 100644 release/src/router/busybox/libbb/parse_number.c create mode 100644 release/src/router/busybox/libbb/pidfile.c delete mode 100644 release/src/router/busybox/libbb/print_file.c create mode 100644 release/src/router/busybox/libbb/print_flags.c create mode 100644 release/src/router/busybox/libbb/printable.c delete mode 100644 release/src/router/busybox/libbb/printf.c create mode 100644 release/src/router/busybox/libbb/ptr_to_globals.c create mode 100644 release/src/router/busybox/libbb/pw_encrypt_des.c create mode 100644 release/src/router/busybox/libbb/pw_encrypt_md5.c create mode 100644 release/src/router/busybox/libbb/pw_encrypt_sha.c delete mode 100644 release/src/router/busybox/libbb/pwd2spwd.c delete mode 100644 release/src/router/busybox/libbb/qmodule.c create mode 100644 release/src/router/busybox/libbb/read.c create mode 100644 release/src/router/busybox/libbb/read_key.c delete mode 100644 release/src/router/busybox/libbb/read_package_field.c delete mode 100644 release/src/router/busybox/libbb/real_loop.h create mode 100644 release/src/router/busybox/libbb/rtc.c delete mode 100644 release/src/router/busybox/libbb/run_parts.c create mode 100644 release/src/router/busybox/libbb/safe_gethostname.c create mode 100644 release/src/router/busybox/libbb/safe_poll.c delete mode 100644 release/src/router/busybox/libbb/safe_read.c create mode 100644 release/src/router/busybox/libbb/safe_write.c create mode 100644 release/src/router/busybox/libbb/selinux_common.c create mode 100644 release/src/router/busybox/libbb/sha1.c create mode 100644 release/src/router/busybox/libbb/signals.c create mode 100644 release/src/router/busybox/libbb/str_tolower.c create mode 100644 release/src/router/busybox/libbb/strrstr.c delete mode 100644 release/src/router/busybox/libbb/syscalls.c delete mode 100644 release/src/router/busybox/libbb/syslog_msg_with_name.c create mode 100644 release/src/router/busybox/libbb/time.c delete mode 100644 release/src/router/busybox/libbb/time_string.c create mode 100644 release/src/router/busybox/libbb/udp_io.c delete mode 100644 release/src/router/busybox/libbb/unarchive.c delete mode 100644 release/src/router/busybox/libbb/unzip.c create mode 100644 release/src/router/busybox/libbb/update_passwd.c create mode 100644 release/src/router/busybox/libbb/uuencode.c delete mode 100644 release/src/router/busybox/libbb/vherror_msg.c delete mode 100644 release/src/router/busybox/libbb/vperror_msg.c create mode 100644 release/src/router/busybox/libbb/write.c create mode 100644 release/src/router/busybox/libbb/xatonum.c create mode 100644 release/src/router/busybox/libbb/xatonum_template.c create mode 100644 release/src/router/busybox/libbb/xfunc_die.c create mode 100644 release/src/router/busybox/libbb/xfuncs_printf.c delete mode 100644 release/src/router/busybox/libbb/xgethostbyname2.c delete mode 100644 release/src/router/busybox/libbb/xgetlarg.c delete mode 100644 release/src/router/busybox/libbb/xgetularg.c create mode 100644 release/src/router/busybox/libbb/xrealloc_vector.c (limited to 'release/src/router/busybox/libbb') 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 +# +# 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 -# -# 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 - - - + Erik Andersen + 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 +#include "busybox.h" + + +/* Declare _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 _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 + * [::space::]*=[::space::]* + * 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("."); + } + *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 []" */ + if (!argv[2]) + goto help; + /* convert to " --help" */ + argv[0] = argv[2]; + argv[2] = NULL; + } else { + /* "busybox 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 - - 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 -#include -#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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#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 + * + * 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 -*/ - -#include -#include -#include -#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 + * + * 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 + * Copyright (C) 2008 by Tito Ragusa + * + * 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 + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include /* 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 + * + * 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 -#include -#include -#include -#include -#include -#include - #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 -#include #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 +#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 #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 * - * 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 + * SELinux support by Yuichi Nakamura * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - #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, ×) < 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 -#include -#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 + * Copyright (C) 1999-2005 by Erik Andersen * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include #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 -#include -#include -#include -#include -#include -#include -#include - #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 + * (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 -#include -#include -#include -#include #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 -#include -#include -#include -#include #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 - * , - * - * 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 -#include -#include -#include - - -#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. - * - * 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 * - * 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 #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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include #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 + * + * 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 -#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 -#include -#include /* 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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include #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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include #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 + * + * 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 * - * 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 -#include +#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 * - * 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 -#include -#include +#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 -#include -#include - -/* - * 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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include #include "libbb.h" - - #include + /* * 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 * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ -#include -#include -#include -#include -#include #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: + +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 + /* 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; icomm[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 , + * 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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include #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 -#include -#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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include #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 -#include -#include -#include -#include #include "libbb.h" +/* From */ +enum { KDGKBTYPE = 0x4B33 }; /* get keyboard type */ - - - -/* From */ -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 */ +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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include #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 + * Copyright (C) 2004 Erik Andersen + * Copyright (C) 2001 Matt Krai * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include +/* 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 + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include +#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__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:", ¶m); + + "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 - * - * 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 -#include -#include -#include -#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 -#include -#include -#include -#include -#include -#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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include - #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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include - #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 #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 * * 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 -#include -#include -#include -#include #include "libbb.h" +#include "inet_common.h" -#ifdef DEBUG -# include -#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 + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include + +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 -#include -#include #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, - * 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 - * - * {1.34} - 19980630 - Arnaldo Carvalho de Melo - * - 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 - */ - -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 - - -#ifdef HAVE_HWSLIP -#include -#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 -#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 -#include - -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 - -#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 - ðer_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 */ - {"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 -#include #include #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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include #include /* 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) { } + * + * if (get_linux_version_code() > KERNEL_VERSION(2,2,11)) { } */ -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, * - * 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 #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 -#include -#include -#include - -#include - -#ifdef DMALLOC -#include "dmalloc.h" -#endif - -#include - -#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 -#include -#include -#include -#include -#include - - -#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 - * , - * - * 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. - * - * 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 + * + * Used ideas: + * Adam Rogoyski + * Dave Cinege + * Jakub Jelinek (c) 1995 + * Erik Andersen (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= or PATH=: */ + 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; /* : */ + 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; /* : */ + 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 + */ + +#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 */ + input_backward(cursor); + break; + case '4': // vt100? linux vt? or what? + case '8': // vt100? linux vt? or what? + case 'F': /* xterm's */ + 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 + +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 + * + * 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 + * + * 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 -#include -#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 * - * 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 + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ #include /* MAXHOSTNAMELEN */ -#include -#include -#include "libbb.h" - #include -#include +#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 + * Copyright (C) 2005 by Rob Landley * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ -#include -#include -#include -#include -#include -#include #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 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#include +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 +#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 * - * 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 -#include -#include -#include -#include -#include - #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 +#include + +#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 , 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): + * 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 + * + * 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 , - * - * 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 * + * 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 +/* 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 -# 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, 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 ' - 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 ' -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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include +/* Aug 13, 2003 + * Fix a bug reported by junkio@cox.net involving the mode_chars index. + */ + + +#include +#include + #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 , - * - * 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 -#include -#include -/* Kernel headers before 2.1.mumble need this on the Alpha to get - _syscall* defined. */ -#define __LIBRARY__ -#include -#ifndef __UCLIBC__ -#include -#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 -#include -#include -#include -#include +/* + * Utility routines. + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + #include #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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include #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 -#include -#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 -#include -#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 -#include -#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 -#include -#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 -#include -#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 - * 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 * - * 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 -#include -#include -#include #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< 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 + * + * 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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include +/* 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 -#include -#include -#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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include #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 ": 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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include #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 ": 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 * - * 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 -#include +/* 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 * - * 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 -#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 + * + * 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 - * - * 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 -#include -#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 + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include + +/* 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 - * - * 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 -#include -#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 - * and Vladimir Oleynik + * Copyright (C) Manuel Novoa III + * and Vladimir Oleynik * - * 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 -#include #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 - * GNU Library General Public License Version 2, or any later version + * SELinux support: (c) 2007 by Yuichi Nakamura * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include -#include - #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 "" */ - 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 "" */ + /*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 + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ + +#include + +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 - * - * 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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include #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 . + * + * 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): + * 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 + * + * + * 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 . + */ + +/* 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 - * 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 -#include -#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 - everyone seems to claim it someplace. ;-) -*/ - -#include - -#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 + * + * 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 + * Copyright (C) 2008 Denys Vlasenko + * + * 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 -#include -#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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include -#include /* 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 * - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include #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 -#include -#include -#include -#include -#include -#include #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 - * rewrite to vfork usage by - * Copyright (C) 2002 by Vladimir Oleynik - * - * 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 -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include #include "libbb.h" -#ifdef CONFIG_SELINUX -#include +#if ENABLE_SELINUX +#include /* 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(¤t_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 + * + * 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 + +/* + * 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 + * + * 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 -#include -#include -#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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include #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 + * + * 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 + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +#include "libbb.h" +#include + +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)", "" 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 -#include -#include -#include -#include -#include -#include #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 , 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 . + * 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 + * 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 * - * 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 #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 * - * 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 #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 * - * 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 #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 +#include +#include +#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 , - * - * 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 -#include -#include -/* Kernel headers before 2.1.mumble need this on the Alpha to get - _syscall* defined. */ -#define __LIBRARY__ - - -#include -#ifndef __UCLIBC__ -#include -#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 -#include -#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 +/* 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 -#include -#include -#include -#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 -#include -#include #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 -#include -#include -#include -#include - -struct signal_name { - const char *name; - int number; -}; +/* vi: set sw=4 ts=4: */ +/* + * Signal name/number conversion routines. + * + * Copyright 2006 Rob Landley + * + * 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 -#include -#include -#include -#include -#include -#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,"!",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 - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * 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 - * - * 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 -#include -#include -#include -#include -#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 + * + * Modified to be able to add or delete users, groups and users to/from groups + * by Tito Ragusa + * + * 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 + * + * 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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include #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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include #include "libbb.h" +#include + +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 + * Copyright (C) 2003 Russ Dill + * + * 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 + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include "libbb.h" +#include +#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 _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 _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 -#include -extern int h_errno; - -#include - -#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 -#include -#include -#include -#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 * - * 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 +#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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include #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 * - * 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 -#include -#include +#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 + * + * 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; /* = _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 -#include -#include -#include -#include -#include #include +#include #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 + * + * 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 + * 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 -#include -#include -#include #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 + * 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 . * - * Special function for busybox written by Vladimir Oleynik -*/ + * Special function for busybox written by Vladimir Oleynik + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ -#include -#include -#include -#include #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 . * - * 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 -extern int h_errno; - +//#include #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 . - * - * 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 -#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 - */ - - -#include -#include -#include -#include -#include -#include - -#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 - * - * 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 -#include -#include -#include -#include -#include -#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 +#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 -#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 #include "libbb.h" -#include - - +#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); + } +} -- cgit v1.2.3-54-g00ecf