[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/app/busybox/src/libbb/Config.src b/ap/app/busybox/src/libbb/Config.src
new file mode 100644
index 0000000..19021fe
--- /dev/null
+++ b/ap/app/busybox/src/libbb/Config.src
@@ -0,0 +1,235 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Busybox Library Tuning"
+
+INSERT
+
+config PASSWORD_MINLEN
+ int "Minimum password length"
+ default 6
+ range 5 32
+ help
+ Minimum allowable password length.
+
+config MD5_SMALL
+ int "MD5: Trade bytes for speed (0:fast, 3:slow)"
+ default 1
+ 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 SHA3_SMALL
+ int "SHA3: Trade bytes for speed (0:fast, 1:slow)"
+ default 1
+ range 0 1
+ help
+ Trade binary size versus speed for the sha3sum algorithm.
+ SHA3_SMALL=0 compared to SHA3_SMALL=1 (approximate):
+ 64-bit x86: +270 bytes of code, 45% faster
+ 32-bit x86: +450 bytes of code, 75% faster
+
+config FEATURE_FAST_TOP
+ bool "Faster /proc scanning code (+100 bytes)"
+ default y
+ 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_USE_TERMIOS
+ bool "Use termios to manipulate the screen"
+ default y
+ depends on MORE || TOP || POWERTOP
+ help
+ This option allows utilities such as 'more' and 'top' to determine
+ the size of the screen. If you leave this disabled, your utilities
+ that display things on the screen will be especially primitive and
+ will be unable to determine the current screen size, and will be
+ unable to move the cursor.
+
+config FEATURE_EDITING
+ bool "Command line editing"
+ default y
+ 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"
+ # Don't allow way too big values here, code uses fixed "char *history[N]" struct member
+ range 0 9999
+ default 255
+ depends on FEATURE_EDITING
+ help
+ Specify command history size (0 - disable).
+
+config FEATURE_EDITING_SAVEHISTORY
+ bool "History saving"
+ default y
+ depends on FEATURE_EDITING
+ help
+ Enable history saving in shells.
+
+config FEATURE_EDITING_SAVE_ON_EXIT
+ bool "Save history on shell exit, not after every command"
+ default n
+ depends on FEATURE_EDITING_SAVEHISTORY
+ help
+ Save history on shell exit, not after every command.
+
+config FEATURE_REVERSE_SEARCH
+ bool "Reverse history search"
+ default y
+ depends on FEATURE_EDITING_SAVEHISTORY
+ help
+ Enable readline-like Ctrl-R combination for reverse history search.
+ Increases code by about 0.5k.
+
+config FEATURE_TAB_COMPLETION
+ bool "Tab completion"
+ default y
+ 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 y
+ depends on FEATURE_EDITING
+ help
+ Setting this option allows for prompts to use things like \w and
+ \$ and escape codes.
+
+config FEATURE_EDITING_ASK_TERMINAL
+ bool "Query cursor position from terminal"
+ default n
+ depends on FEATURE_EDITING
+ help
+ Allow usage of "ESC [ 6 n" sequence. Terminal answers back with
+ current cursor position. This information is used to make line
+ editing more robust in some cases.
+ If you are not sure whether your terminals respond to this code
+ correctly, or want to save on code size (about 400 bytes),
+ then do not turn this option on.
+
+config FEATURE_NON_POSIX_CP
+ bool "Non-POSIX, but safer, copying to special nodes"
+ default y
+ help
+ With this option, "cp file symlink" will delete symlink
+ and create a regular file. This does not conform to POSIX,
+ but prevents a symlink attack.
+ Similarly, "cp file device" will not send file's data
+ to the device. (To do that, use "cat file >device")
+
+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 create '/does_not_exist/file': No such file or directory
+ cp: cannot stat '/vmlinuz/file': Not a directory
+ 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, wget 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 FEATURE_SKIP_ROOTFS
+ bool "Skip rootfs in mount table"
+ default y
+ help
+ Ignore rootfs entry in mount table.
+
+ In Linux, kernel has a special filesystem, rootfs, which is initially
+ mounted on /. It contains initramfs data, if kernel is configured
+ to have one. Usually, another file system is mounted over / early
+ in boot process, and therefore most tools which manipulate
+ mount table, such as df, will skip rootfs entry.
+
+ However, some systems do not mount anything on /.
+ If you need to configure busybox for one of these systems,
+ you may find it useful to turn this option off to make df show
+ initramfs statistics.
+
+ Otherwise, choose Y.
+
+config MONOTONIC_SYSCALL
+ bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
+ default n
+ select PLATFORM_LINUX
+ 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/ap/app/busybox/src/libbb/Kbuild.src b/ap/app/busybox/src/libbb/Kbuild.src
new file mode 100644
index 0000000..61eec26
--- /dev/null
+++ b/ap/app/busybox/src/libbb/Kbuild.src
@@ -0,0 +1,189 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under GPLv2, see file LICENSE in this source tree.
+
+libbb/appletlib.o: include/usage_compressed.h
+
+lib-y:=
+
+INSERT
+
+lib-y += appletlib.o
+lib-y += ask_confirmation.o
+lib-y += bb_askpass.o
+lib-y += bb_bswap_64.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 += 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 += get_volsize.o
+lib-y += herror_msg.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 += hash_md5_sha.o
+# Alternative (disabled) MD5 implementation
+#lib-y += hash_md5prime.o
+lib-y += messages.o
+lib-y += mode_string.o
+lib-y += parse_mode.o
+lib-y += perror_msg.o
+lib-y += perror_nomsg.o
+lib-y += perror_nomsg_and_die.o
+lib-y += pidfile.o
+lib-y += platform.o
+lib-y += printable.o
+lib-y += printable_string.o
+lib-y += print_flags.o
+lib-y += process_escape_sequence.o
+lib-y += procps.o
+lib-y += progress.o
+lib-y += ptr_to_globals.o
+lib-y += read.o
+lib-y += read_printf.o
+lib-y += read_key.o
+lib-y += recursive_action.o
+lib-y += remove_file.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 += signals.o
+lib-y += simplify_path.o
+lib-y += single_argv.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 += 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
+
+lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o
+
+lib-$(CONFIG_FEATURE_UTMP) += utmp.o
+
+# A mix of optimizations (why build stuff we know won't be used)
+# and objects which may fail to build (SELinux on selinux-less system)
+lib-$(CONFIG_SELINUX) += selinux_common.o
+lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
+lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o
+lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
+
+lib-$(CONFIG_NC) += udp_io.o
+lib-$(CONFIG_DNSD) += udp_io.o
+lib-$(CONFIG_NTPD) += udp_io.o
+lib-$(CONFIG_TFTP) += udp_io.o
+lib-$(CONFIG_TFTPD) += udp_io.o
+lib-$(CONFIG_TCPSVD) += udp_io.o
+lib-$(CONFIG_UDPSVD) += udp_io.o
+lib-$(CONFIG_TRACEROUTE) += udp_io.o
+
+lib-$(CONFIG_LOSETUP) += loop.o
+lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.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 obscure.o
+lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o
+lib-$(CONFIG_CRYPTPW) += pw_encrypt.o
+lib-$(CONFIG_SULOGIN) += 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_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o
+
+lib-$(CONFIG_DF) += find_mount_point.o
+lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o
+lib-$(CONFIG_MKFS_EXT2) += find_mount_point.o
+lib-$(CONFIG_MKFS_REISER) += find_mount_point.o
+lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o
+lib-$(CONFIG_MOUNT) += find_mount_point.o
+
+lib-$(CONFIG_HWCLOCK) += rtc.o
+lib-$(CONFIG_RTCWAKE) += rtc.o
+
+lib-$(CONFIG_IOSTAT) += get_cpu_count.o
+lib-$(CONFIG_MPSTAT) += get_cpu_count.o
+lib-$(CONFIG_POWERTOP) += get_cpu_count.o
+
+lib-$(CONFIG_PING) += inet_cksum.o
+lib-$(CONFIG_TRACEROUTE) += inet_cksum.o
+lib-$(CONFIG_TRACEROUTE6) += inet_cksum.o
+lib-$(CONFIG_UDHCPC) += inet_cksum.o
+lib-$(CONFIG_UDHCPC6) += inet_cksum.o
+lib-$(CONFIG_UDHCPD) += inet_cksum.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/ap/app/busybox/src/libbb/README b/ap/app/busybox/src/libbb/README
new file mode 100644
index 0000000..6e63dc5
--- /dev/null
+++ b/ap/app/busybox/src/libbb/README
@@ -0,0 +1,10 @@
+Please see the LICENSE file for copyright information (GPLv2)
+
+libbb is BusyBox's utility library. All of this stuff used to be stuffed into
+a single file named utility.c. When I split utility.c to create libbb, some of
+the very oldest stuff ended up without their original copyright and licensing
+information (which is now lost in the mists of time). If you see something
+that you wrote that is mis-attributed, do let me know so we can fix that up.
+
+ Erik Andersen
+ <andersen@codepoet.org>
diff --git a/ap/app/busybox/src/libbb/appletlib.c b/ap/app/busybox/src/libbb/appletlib.c
new file mode 100644
index 0000000..67df446
--- /dev/null
+++ b/ap/app/busybox/src/libbb/appletlib.c
@@ -0,0 +1,830 @@
+/* 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 GPL.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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 "busybox.h"
+
+#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
+ || defined(__APPLE__) \
+ )
+# include <malloc.h> /* for mallopt */
+#endif
+
+
+/* Declare <applet>_main() */
+#define PROTOTYPES
+#include "applets.h"
+#undef PROTOTYPES
+
+/* Include generated applet names, pointers to <applet>_main, etc */
+#include "applet_tables.h"
+/* ...and if applet_tables generator says we have only one applet... */
+#ifdef SINGLE_APPLET_MAIN
+# undef ENABLE_FEATURE_INDIVIDUAL
+# define ENABLE_FEATURE_INDIVIDUAL 1
+# undef IF_FEATURE_INDIVIDUAL
+# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__
+#endif
+
+#include "usage_compressed.h"
+
+
+#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
+static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
+#else
+# define usage_messages 0
+#endif
+
+#if ENABLE_FEATURE_COMPRESS_USAGE
+
+static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
+# include "bb_archive.h"
+static const char *unpack_usage_messages(void)
+{
+ char *outbuf = NULL;
+ bunzip_data *bd;
+ int i;
+
+ i = start_bunzip(&bd,
+ /* src_fd: */ -1,
+ /* inbuf: */ packed_usage,
+ /* 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(UNPACKED_USAGE));
+ if (outbuf)
+ read_bunzip(bd, outbuf, sizeof(UNPACKED_USAGE));
+ }
+ 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 */
+
+
+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 *usage_string = unpack_usage_messages();
+
+ if (*usage_string == '\b') {
+ full_write2_str("No help available.\n\n");
+ } else {
+ full_write2_str("Usage: "SINGLE_APPLET_STR" ");
+ full_write2_str(usage_string);
+ full_write2_str("\n\n");
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ 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");
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ dealloc_usage_messages((char*)usage_string);
+#endif
+ }
+ xfunc_die();
+}
+
+#if NUM_APPLETS > 8
+static int applet_name_compare(const void *name, const void *idx)
+{
+ int i = (int)(ptrdiff_t)idx - 1;
+ 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, (void*)(ptrdiff_t)1, ARRAY_SIZE(applet_main), 1, applet_name_compare);
+ /*
+ * if (!p) return -1;
+ * ^^^^^^^^^^^^^^^^^^ the code below will do this if p == NULL :)
+ */
+ return (int)(ptrdiff_t)p - 1;
+#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
+ IF_FEATURE_INDIVIDUAL(, char **argv))
+ MAIN_EXTERNALLY_VISIBLE;
+void lbb_prepare(const char *applet
+ IF_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
+ && strncmp(applet, "busybox", 7) != 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)
+
+IF_FEATURE_SUID(static uid_t ruid;) /* real uid */
+
+# if ENABLE_FEATURE_SUID_CONFIG
+
+static struct suid_config_t {
+ /* next ptr must be first: this struct needs to be llist-compatible */
+ struct suid_config_t *m_next;
+ struct bb_uidgid_t m_ugid;
+ int m_applet;
+ mode_t m_mode;
+} *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;
+}
+
+/* libbb candidate */
+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);
+}
+
+static void parse_config_file(void)
+{
+ /* Don't depend on the tools to combine strings. */
+ static const char config_file[] ALIGN1 = "/etc/busybox.conf";
+
+ struct suid_config_t *sct_head;
+ int applet_no;
+ FILE *f;
+ const char *errmsg;
+ unsigned lc;
+ smallint section;
+ struct stat st;
+
+ 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) {
+ char buffer[256];
+ char *s;
+
+ if (!fgets(buffer, sizeof(buffer), f)) { /* Are we done? */
+ // Looks like bloat
+ //if (ferror(f)) { /* Make sure it wasn't a read error. */
+ // errmsg = "reading";
+ // goto pe_label;
+ //}
+ fclose(f);
+ suid_config = sct_head; /* Success, so set the pointer. */
+ return;
+ }
+
+ s = buffer;
+ 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)) {
+ errmsg = "line too long";
+ goto pe_label;
+ }
+
+ /* 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. */
+ char *e = strchr(s, ']');
+ if (!e /* Missing right bracket? */
+ || e[1] /* Trailing characters? */
+ || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
+ ) {
+ errmsg = "section header";
+ goto pe_label;
+ }
+ /* Right now we only have one section so just check it.
+ * If more sections are added in the future, please don't
+ * resort to cascading ifs with multiple strcasecmp calls.
+ * That kind of bloated code is all too common. A loop
+ * and a string table would be a better choice unless the
+ * number of sections is very small. */
+ if (strcasecmp(s, "SUID") == 0) {
+ section = 1;
+ continue;
+ }
+ section = -1; /* Unknown section so set to skip. */
+ continue;
+ }
+
+ /* Process sections. */
+
+ if (section == 1) { /* SUID */
+ /* Since we trimmed leading and trailing space above, we're
+ * now looking for strings of the form
+ * <key>[::space::]*=[::space::]*<value>
+ * where both key and value could contain inner whitespace. */
+
+ /* First get the key (an applet name in our case). */
+ char *e = strchr(s, '=');
+ if (e) {
+ s = get_trimmed_slice(s, e);
+ }
+ if (!e || !*s) { /* Missing '=' or empty key. */
+ errmsg = "keyword";
+ goto pe_label;
+ }
+
+ /* 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) {
+ unsigned i;
+ struct suid_config_t *sct;
+
+ /* 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 = xzalloc(sizeof(*sct));
+ 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 for each of user/group/other.
+ * "x-xx" instead of "x-" are to make
+ * "idx > 3" check catch invalid chars.
+ */
+ static const char mode_chars[] ALIGN1 = "Ssx-" "Ssx-" "x-xx";
+ static const unsigned short mode_mask[] ALIGN2 = {
+ S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* Ssx- */
+ S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* Ssx- */
+ S_IXOTH, 0 /* x- */
+ };
+ const char *q = strchrnul(mode_chars + 4*i, *e);
+ unsigned idx = q - (mode_chars + 4*i);
+ if (idx > 3) {
+ errmsg = "mode";
+ goto pe_label;
+ }
+ sct->m_mode |= mode_mask[q - mode_chars];
+ e++;
+ }
+
+ /* Now get the user/group info. */
+
+ s = skip_whitespace(e);
+ /* Default is 0.0, else parse USER.GROUP: */
+ if (*s) {
+ /* We require whitespace between mode and USER.GROUP */
+ if ((s == e) || !(e = strchr(s, '.'))) {
+ errmsg = "uid.gid";
+ goto pe_label;
+ }
+ *e = ':'; /* get_uidgid needs USER:GROUP syntax */
+ if (get_uidgid(&sct->m_ugid, s, /*allow_numeric:*/ 1) == 0) {
+ errmsg = "unknown user/group";
+ goto pe_label;
+ }
+ }
+ }
+ 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) {
+ errmsg = "keyword outside section";
+ goto pe_label;
+ }
+
+ } /* while (1) */
+
+ pe_label:
+ fclose(f);
+ bb_error_msg("parse error in %s, line %u: %s", config_file, lc, errmsg);
+
+ /* Release any allocated memory before returning. */
+ llist_free((llist_t*)sct_head, NULL);
+}
+# else
+static inline void parse_config_file(void)
+{
+ IF_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 suid_config_t *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:
+ /* Is this user allowed to run this applet? */
+ m = sct->m_mode;
+ if (sct->m_ugid.uid == ruid)
+ /* same uid */
+ m >>= 6;
+ else if ((sct->m_ugid.gid == rgid) || ingroup(ruid, sct->m_ugid.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");
+
+ /* We set effective AND saved ids. If saved-id is not set
+ * like we do below, seteuid(0) can still later succeed! */
+
+ /* Are we directed to change gid
+ * (APPLET = *s* USER.GROUP or APPLET = *S* USER.GROUP)?
+ */
+ if (sct->m_mode & S_ISGID)
+ rgid = sct->m_ugid.gid;
+ /* else: we will set egid = rgid, thus dropping sgid effect */
+ if (setresgid(-1, rgid, rgid))
+ bb_perror_msg_and_die("setresgid");
+
+ /* Are we directed to change uid
+ * (APPLET = s** USER.GROUP or APPLET = S** USER.GROUP)?
+ */
+ uid = ruid;
+ if (sct->m_mode & S_ISUID)
+ uid = sct->m_ugid.uid;
+ /* else: we will set euid = ruid, thus dropping suid effect */
+ if (setresuid(-1, uid, uid))
+ bb_perror_msg_and_die("setresuid");
+
+ goto ret;
+ }
+# if !ENABLE_FEATURE_SUID_CONFIG_QUIET
+ {
+ static bool onetime = 0;
+
+ if (!onetime) {
+ onetime = 1;
+ bb_error_msg("using fallback suid method");
+ }
+ }
+# endif
+ check_need_suid:
+# endif
+ if (APPLET_SUID(applet_no) == BB_SUID_REQUIRE) {
+ /* 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_DROP) {
+ xsetgid(rgid); /* drop all privileges */
+ xsetuid(ruid);
+ }
+# if ENABLE_FEATURE_SUID_CONFIG
+ ret: ;
+ llist_free((llist_t*)suid_config, NULL);
+# endif
+}
+# else
+# define check_suid(x) ((void)0)
+# endif /* FEATURE_SUID */
+
+
+# if ENABLE_FEATURE_INSTALLER
+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], /* "/" */
+ &usr_bin [4], /* "/bin/" */
+ &usr_sbin[4] /* "/sbin/" */
+# if !ENABLE_INSTALL_NO_USR
+ ,usr_bin
+ ,usr_sbin
+# endif
+};
+
+/* create (sym)links for each applet */
+static void install_links(const char *busybox, int use_symbolic_links,
+ char *custom_install_dir)
+{
+ /* directory table
+ * this should be consistent w/ the enum,
+ * busybox.h::bb_install_loc_t, or else... */
+ 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(
+ custom_install_dir ? custom_install_dir : 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,z) ((void)0)
+# endif
+
+/* If we were called as "busybox..." */
+static int busybox_main(char **argv)
+{
+ if (!argv[1]) {
+ /* Called without arguments */
+ const char *a;
+ int col;
+ unsigned output_width;
+ help:
+ output_width = 80;
+ if (ENABLE_FEATURE_AUTOWIDTH) {
+ /* Obtain the terminal width */
+ get_terminal_width_height(0, &output_width, NULL);
+ }
+
+ dup2(1, 2);
+ full_write2_str(bb_banner); /* reuse const string */
+ full_write2_str(" multi-call binary.\n"); /* reuse */
+ full_write2_str(
+ "BusyBox is copyrighted by many authors between 1998-2012.\n"
+ "Licensed under GPLv2. See source distribution for detailed\n"
+ "copyright notices.\n"
+ "\n"
+ "Usage: busybox [function [arguments]...]\n"
+ " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
+ IF_FEATURE_INSTALLER(
+ " or: busybox --install [-s] [DIR]\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;
+ /* prevent last comma to be in the very last pos */
+ output_width--;
+ while (*a) {
+ int len2 = strlen(a) + 2;
+ if (col >= (int)output_width - len2) {
+ full_write2_str(",\n");
+ col = 0;
+ }
+ if (col == 0) {
+ col = 6;
+ full_write2_str("\t");
+ } else {
+ full_write2_str(", ");
+ }
+ full_write2_str(a);
+ col += len2;
+ a += len2 - 1;
+ }
+ full_write2_str("\n\n");
+ return 0;
+ }
+
+ if (strncmp(argv[1], "--list", 6) == 0) {
+ unsigned i = 0;
+ const char *a = applet_names;
+ dup2(1, 2);
+ while (*a) {
+# if ENABLE_FEATURE_INSTALLER
+ if (argv[1][6]) /* --list-full? */
+ full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
+# endif
+ full_write2_str(a);
+ full_write2_str("\n");
+ i++;
+ a += strlen(a) + 1;
+ }
+ return 0;
+ }
+
+ if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
+ int use_symbolic_links;
+ const char *busybox;
+
+ busybox = xmalloc_readlink(bb_busybox_exec_path);
+ if (!busybox) {
+ /* bb_busybox_exec_path is usually "/proc/self/exe".
+ * In chroot, readlink("/proc/self/exe") usually fails.
+ * In such case, better use argv[0] as symlink target
+ * if it is a full path name.
+ */
+ if (argv[0][0] != '/')
+ bb_error_msg_and_die("'%s' is not an absolute path", argv[0]);
+ busybox = argv[0];
+ }
+ /* busybox --install [-s] [DIR]:
+ * -s: make symlinks
+ * DIR: directory to install links to
+ */
+ use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
+ install_links(busybox, use_symbolic_links, argv[2]);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "--help") == 0) {
+ /* "busybox --help [<applet>]" */
+ if (!argv[2])
+ goto help;
+ /* convert to "<applet> --help" */
+ argv[0] = argv[2];
+ argv[2] = NULL;
+ } else {
+ /* "busybox <applet> arg1 arg2 ..." */
+ argv++;
+ }
+ /* We support "busybox /a/path/to/applet args..." too. Allows for
+ * "#!/bin/busybox"-style wrappers */
+ applet_name = bb_get_last_path_component_nostrip(argv[0]);
+ run_applet_and_exit(applet_name, argv);
+
+ /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+ full_write2_str(applet_name);
+ full_write2_str(": applet not found\n");
+ xfunc_die();
+}
+
+void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
+{
+ int argc = 1;
+
+ while (argv[argc])
+ argc++;
+
+ /* Reinit some shared global data */
+ xfunc_error_retval = EXIT_FAILURE;
+
+ applet_name = APPLET_NAME(applet_no);
+ if (argc == 2 && strcmp(argv[1], "--help") == 0) {
+ /* Special case. POSIX says "test --help"
+ * should be no different from e.g. "test --foo". */
+//TODO: just compare applet_no with APPLET_NO_test
+ if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) {
+ /* If you want "foo --help" to return 0: */
+ /*xfunc_error_retval = 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) == 0)
+ 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
+{
+ /* Tweak malloc for reduced memory consumption */
+#ifdef M_TRIM_THRESHOLD
+ /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory
+ * to keep before releasing to the OS
+ * Default is way too big: 256k
+ */
+ mallopt(M_TRIM_THRESHOLD, 8 * 1024);
+#endif
+#ifdef M_MMAP_THRESHOLD
+ /* M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ * Default is too big: 256k
+ */
+ mallopt(M_MMAP_THRESHOLD, 32 * 1024 - 256);
+#endif
+
+#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
+
+#if defined(SINGLE_APPLET_MAIN)
+ /* Only one applet is selected in .config */
+ if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) {
+ /* "busybox <applet> <params>" should still work as expected */
+ argv++;
+ }
+ /* applet_names in this case is just "applet\0\0" */
+ lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv));
+ return SINGLE_APPLET_MAIN(argc, argv);
+#else
+ lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
+
+ 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/ap/app/busybox/src/libbb/ask_confirmation.c b/ap/app/busybox/src/libbb/ask_confirmation.c
new file mode 100644
index 0000000..d95729c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/ask_confirmation.c
@@ -0,0 +1,27 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_ask_confirmation implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* Read a line from stdin. If the first non-whitespace char is 'y' or 'Y',
+ * return 1. Otherwise return 0.
+ */
+#include "libbb.h"
+
+int FAST_FUNC bb_ask_confirmation(void)
+{
+ char first = 0;
+ int c;
+
+ while (((c = getchar()) != EOF) && (c != '\n')) {
+ if (first == 0 && !isblank(c)) {
+ first = c|0x20;
+ }
+ }
+
+ return first == 'y';
+}
diff --git a/ap/app/busybox/src/libbb/bb_askpass.c b/ap/app/busybox/src/libbb/bb_askpass.c
new file mode 100644
index 0000000..fe2b506
--- /dev/null
+++ b/ap/app/busybox/src/libbb/bb_askpass.c
@@ -0,0 +1,90 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Ask for a password
+ * I use a static buffer in this function. Plan accordingly.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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;
+
+ fputs(prompt, stdout);
+ fflush_all();
+ tcflush(fd, TCIFLUSH);
+
+ tcgetattr(fd, &oldtio);
+ tio = oldtio;
+#if 0
+ /* Switch off UPPERCASE->lowercase conversion (never used since 198x)
+ * and XON/XOFF (why we want to mess with this??)
+ */
+# ifndef IUCLC
+# define IUCLC 0
+# endif
+ tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
+#endif
+ /* Switch off echo */
+ tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL);
+ tcsetattr(fd, TCSANOW, &tio);
+
+ memset(&sa, 0, sizeof(sa));
+ /* sa.sa_flags = 0; - no SA_RESTART! */
+ /* SIGINT and SIGALRM will interrupt reads below */
+ sa.sa_handler = askpass_timeout;
+ sigaction(SIGINT, &sa, &oldsa);
+ if (timeout) {
+ sigaction_set(SIGALRM, &sa);
+ alarm(timeout);
+ }
+
+ if (!passwd)
+ passwd = xmalloc(sizeof_passwd);
+ ret = passwd;
+ i = 0;
+ while (1) {
+ int r = read(fd, &ret[i], 1);
+ if (r < 0) {
+ /* read is interrupted by timeout or ^C */
+ ret = NULL;
+ break;
+ }
+ if (r == 0 /* EOF */
+ || ret[i] == '\r' || ret[i] == '\n' /* EOL */
+ || ++i == sizeof_passwd-1 /* line limit */
+ ) {
+ ret[i] = '\0';
+ break;
+ }
+ }
+
+ if (timeout) {
+ alarm(0);
+ }
+ sigaction_set(SIGINT, &oldsa);
+ tcsetattr(fd, TCSANOW, &oldtio);
+ bb_putchar('\n');
+ fflush_all();
+ return ret;
+}
diff --git a/ap/app/busybox/src/libbb/bb_bswap_64.c b/ap/app/busybox/src/libbb/bb_bswap_64.c
new file mode 100644
index 0000000..ce9d53b
--- /dev/null
+++ b/ap/app/busybox/src/libbb/bb_bswap_64.c
@@ -0,0 +1,16 @@
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2010 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+#if !(ULONG_MAX > 0xffffffff)
+uint64_t FAST_FUNC bb_bswap_64(uint64_t x)
+{
+ return bswap_64(x);
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/bb_do_delay.c b/ap/app/busybox/src/libbb/bb_do_delay.c
new file mode 100644
index 0000000..05c879f
--- /dev/null
+++ b/ap/app/busybox/src/libbb/bb_do_delay.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox utility routines.
+ *
+ * Copyright (C) 2005 by Tito Ragusa <tito-wolit@tiscali.it>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+void FAST_FUNC bb_do_delay(int seconds)
+{
+ time_t start, now;
+
+ start = time(NULL);
+ do {
+ sleep(seconds);
+ now = time(NULL);
+ } while ((now - start) < seconds);
+}
diff --git a/ap/app/busybox/src/libbb/bb_pwd.c b/ap/app/busybox/src/libbb/bb_pwd.c
new file mode 100644
index 0000000..4829b72
--- /dev/null
+++ b/ap/app/busybox/src/libbb/bb_pwd.c
@@ -0,0 +1,112 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * password utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2008 by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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(uid_t uid)
+{
+ char *name = uid2uname(uid);
+ return (name) ? name : utoa(uid);
+}
+
+char* FAST_FUNC gid2group_utoa(gid_t 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/ap/app/busybox/src/libbb/bb_qsort.c b/ap/app/busybox/src/libbb/bb_qsort.c
new file mode 100644
index 0000000..a54e723
--- /dev/null
+++ b/ap/app/busybox/src/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 source tree.
+ */
+
+#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/ap/app/busybox/src/libbb/bb_strtod.c b/ap/app/busybox/src/libbb/bb_strtod.c
new file mode 100644
index 0000000..5dde784
--- /dev/null
+++ b/ap/app/busybox/src/libbb/bb_strtod.c
@@ -0,0 +1,88 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include <math.h> /* just for HUGE_VAL */
+
+#define NOT_DIGIT(a) (((unsigned char)(a-'0')) > 9)
+
+#if 0 // UNUSED
+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;
+}
+#endif
+
+#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/ap/app/busybox/src/libbb/bb_strtonum.c b/ap/app/busybox/src/libbb/bb_strtonum.c
new file mode 100644
index 0000000..949f26b
--- /dev/null
+++ b/ap/app/busybox/src/libbb/bb_strtonum.c
@@ -0,0 +1,160 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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 next_ch = **endp;
+
+ /* errno is already set to ERANGE by strtoXXX if value overflowed */
+ if (next_ch) {
+ /* "1234abcg" or out-of-range? */
+ if (isalnum(next_ch) || 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;
+
+ if (!endp) endp = &endptr;
+ *endp = (char*) arg;
+
+ /* 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, endp, base);
+ return handle_errors(v, endp);
+}
+
+long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base)
+{
+ unsigned long long v;
+ char *endptr;
+ char first;
+
+ if (!endp) endp = &endptr;
+ *endp = (char*) arg;
+
+ /* Check for the weird "feature":
+ * a "-" string is apparently a valid "number" for strto[u]l[l]!
+ * It returns zero and errno is 0! :( */
+ first = (arg[0] != '-' ? arg[0] : arg[1]);
+ if (!isalnum(first)) return ret_ERANGE();
+
+ errno = 0;
+ v = strtoll(arg, endp, base);
+ return handle_errors(v, endp);
+}
+
+#if ULONG_MAX != ULLONG_MAX
+unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base)
+{
+ unsigned long v;
+ char *endptr;
+
+ if (!endp) endp = &endptr;
+ *endp = (char*) arg;
+
+ if (!isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtoul(arg, endp, base);
+ return handle_errors(v, endp);
+}
+
+long FAST_FUNC bb_strtol(const char *arg, char **endp, int base)
+{
+ long v;
+ char *endptr;
+ char first;
+
+ if (!endp) endp = &endptr;
+ *endp = (char*) arg;
+
+ first = (arg[0] != '-' ? arg[0] : arg[1]);
+ if (!isalnum(first)) return ret_ERANGE();
+
+ errno = 0;
+ v = strtol(arg, endp, base);
+ return handle_errors(v, endp);
+}
+#endif
+
+#if UINT_MAX != ULONG_MAX
+unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base)
+{
+ unsigned long v;
+ char *endptr;
+
+ if (!endp) endp = &endptr;
+ *endp = (char*) arg;
+
+ if (!isalnum(arg[0])) return ret_ERANGE();
+ errno = 0;
+ v = strtoul(arg, endp, base);
+ if (v > UINT_MAX) return ret_ERANGE();
+ return handle_errors(v, endp);
+}
+
+int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base)
+{
+ long v;
+ char *endptr;
+ char first;
+
+ if (!endp) endp = &endptr;
+ *endp = (char*) arg;
+
+ first = (arg[0] != '-' ? arg[0] : arg[1]);
+ if (!isalnum(first)) return ret_ERANGE();
+
+ errno = 0;
+ v = strtol(arg, endp, base);
+ if (v > INT_MAX) return ret_ERANGE();
+ if (v < INT_MIN) return ret_ERANGE();
+ return handle_errors(v, endp);
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/change_identity.c b/ap/app/busybox/src/libbb/change_identity.c
new file mode 100644
index 0000000..619db09
--- /dev/null
+++ b/ap/app/busybox/src/libbb/change_identity.c
@@ -0,0 +1,41 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libbb.h"
+
+/* Become the user and group(s) specified by PW. */
+void FAST_FUNC change_identity(const struct passwd *pw)
+{
+ 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/ap/app/busybox/src/libbb/chomp.c b/ap/app/busybox/src/libbb/chomp.c
new file mode 100644
index 0000000..cb92bef
--- /dev/null
+++ b/ap/app/busybox/src/libbb/chomp.c
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+void FAST_FUNC chomp(char *s)
+{
+ char *lc = last_char_is(s, '\n');
+
+ if (lc)
+ *lc = '\0';
+}
diff --git a/ap/app/busybox/src/libbb/compare_string_array.c b/ap/app/busybox/src/libbb/compare_string_array.c
new file mode 100644
index 0000000..4b10cc1
--- /dev/null
+++ b/ap/app/busybox/src/libbb/compare_string_array.c
@@ -0,0 +1,95 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* 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)
+{
+ int i;
+
+ for (i = 0; string_array[i] != 0; i++) {
+ if (strcmp(string_array[i], key) == 0) {
+ 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 matched_idx = -1;
+ const int len = strlen(key);
+
+ if (len) {
+ int idx = 0;
+ while (*strings) {
+ if (strncmp(strings, key, len) == 0) {
+ if (strings[len] == '\0')
+ return idx; /* exact match */
+ if (matched_idx >= 0)
+ return -1; /* ambiguous match */
+ matched_idx = idx;
+ }
+ strings += strlen(strings) + 1; /* skip NUL */
+ idx++;
+ }
+ }
+ return matched_idx;
+}
+
+const char* FAST_FUNC nth_string(const char *strings, int n)
+{
+ while (n) {
+ n--;
+ strings += strlen(strings) + 1;
+ }
+ return strings;
+}
+
+#ifdef UNUSED_SO_FAR /* only brctl.c needs it yet */
+/* Returns 0 for no, 1 for yes or a negative value on error. */
+smallint FAST_FUNC yesno(const char *str)
+{
+ static const char no_yes[] ALIGN1 =
+ "0\0" "off\0" "no\0"
+ "1\0" "on\0" "yes\0";
+ int ret = index_in_substrings(no_yes, str);
+ return ret / 3;
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/concat_path_file.c b/ap/app/busybox/src/libbb/concat_path_file.c
new file mode 100644
index 0000000..9ed2959
--- /dev/null
+++ b/ap/app/busybox/src/libbb/concat_path_file.c
@@ -0,0 +1,29 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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 "libbb.h"
+
+char* FAST_FUNC concat_path_file(const char *path, const char *filename)
+{
+ char *lc;
+
+ if (!path)
+ path = "";
+ lc = last_char_is(path, '/');
+ while (*filename == '/')
+ filename++;
+ return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename);
+}
diff --git a/ap/app/busybox/src/libbb/concat_subpath_file.c b/ap/app/busybox/src/libbb/concat_subpath_file.c
new file mode 100644
index 0000000..c9167d4
--- /dev/null
+++ b/ap/app/busybox/src/libbb/concat_subpath_file.c
@@ -0,0 +1,23 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/*
+ This function make special for recursive actions with usage
+ concat_path_file(path, filename)
+ and skipping "." and ".." directory entries
+*/
+
+#include "libbb.h"
+
+char* FAST_FUNC concat_subpath_file(const char *path, const char *f)
+{
+ if (f && DOT_OR_DOTDOT(f))
+ return NULL;
+ return concat_path_file(path, f);
+}
diff --git a/ap/app/busybox/src/libbb/copy_file.c b/ap/app/busybox/src/libbb/copy_file.c
new file mode 100644
index 0000000..b42a776
--- /dev/null
+++ b/ap/app/busybox/src/libbb/copy_file.c
@@ -0,0 +1,393 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini copy_file implementation for busybox
+ *
+ * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+// FEATURE_NON_POSIX_CP:
+//
+// 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 (sym)link, we overwrite link 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...
+
+/* Called if open of destination, link creation etc fails.
+ * errno must be set to relevant value ("why we cannot create dest?")
+ * to give reasonable error message */
+static int ask_and_unlink(const char *dest, int flags)
+{
+ int e = errno;
+
+#if !ENABLE_FEATURE_NON_POSIX_CP
+ if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) {
+ /* Either it exists, or the *path* doesnt exist */
+ bb_perror_msg("can't create '%s'", dest);
+ return -1;
+ }
+#endif
+ // else: act as if -f is always in effect.
+ // We don't want "can't create" msg, we want unlink to be done
+ // (silently unless -i). Why? POSIX cp usually succeeds with
+ // O_TRUNC open of existing file, and user is left ignorantly happy.
+ // With above block unconditionally enabled, non-POSIX cp
+ // will complain a lot more than POSIX one.
+
+ /* 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("can't create '%s': Path does not exist", dest);
+ return -1; /* error */
+ }
+#endif
+ errno = e; /* do not use errno from unlink */
+ bb_perror_msg("can't 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;
+ smallint retval = 0;
+ smallint dest_exists = 0;
+ smallint ovr;
+
+/* Inverse of cp -d ("cp without -d") */
+#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))
+
+ 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("can't stat '%s'", source);
+ return -1;
+ }
+
+ if (lstat(dest, &dest_stat) < 0) {
+ if (errno != ENOENT) {
+ bb_perror_msg("can't stat '%s'", dest);
+ return -1;
+ }
+ } else {
+ if (source_stat.st_dev == dest_stat.st_dev
+ && source_stat.st_ino == dest_stat.st_ino
+ ) {
+ bb_error_msg("'%s' and '%s' are the same file", source, dest);
+ return -1;
+ }
+ dest_exists = 1;
+ }
+
+#if 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("can't set setfscreatecon %s", con);
+ freecon(con);
+ return -1;
+ }
+ } else if (errno == ENOTSUP || errno == ENODATA) {
+ setfscreatecon_or_die(NULL);
+ } else {
+ bb_perror_msg("can't 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)) {
+ 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;
+ }
+
+ if (dest_exists) {
+ if (!S_ISDIR(dest_stat.st_mode)) {
+ 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 {
+ /* Create DEST */
+ mode_t mode;
+ saved_umask = umask(0);
+
+ 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);
+ bb_perror_msg("can't 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("can't stat '%s'", dest);
+ return -1;
+ }
+ }
+ /* 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;
+
+ new_source = concat_subpath_file(source, d->d_name);
+ if (new_source == NULL)
+ continue;
+ new_dest = concat_path_file(dest, d->d_name);
+ if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0)
+ retval = -1;
+ free(new_source);
+ free(new_dest);
+ }
+ closedir(dp);
+
+ if (!dest_exists
+ && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
+ ) {
+ bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
+ /* retval = -1; - WRONG! copy *WAS* made */
+ }
+ goto preserve_mode_ugid_time;
+ }
+
+ 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("can't create link '%s'", dest);
+ return -1;
+ }
+ }
+ /* _Not_ jumping to preserve_mode_ugid_time:
+ * (sym)links don't have those */
+ return 0;
+ }
+
+ 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 (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("can't create link '%s'", dest);
+ return -1;
+ }
+ }
+ return 0;
+ }
+ add_to_ino_dev_hashtable(&source_stat, dest);
+ }
+
+ src_fd = open_or_warn(source, O_RDONLY);
+ if (src_fd < 0)
+ return -1;
+
+ /* 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 (sym)link attacks
+ if (!ENABLE_FEATURE_NON_POSIX_CP && !(flags & FILEUTILS_INTERACTIVE)) {
+ 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 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);
+ }
+ }
+#endif
+ if (bb_copyfd_eof(src_fd, dst_fd) == -1)
+ retval = -1;
+ /* Careful with writing... */
+ if (close(dst_fd) < 0) {
+ bb_perror_msg("error writing to '%s'", dest);
+ retval = -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("can't 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("can't preserve %s of '%s'", "ownership", dest);
+ }
+ /* _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) {
+ bb_perror_msg("can't create '%s'", dest);
+ return -1;
+ }
+ } else {
+ bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode);
+ return -1;
+ }
+
+ preserve_mode_ugid_time:
+
+ if (flags & FILEUTILS_PRESERVE_STATUS
+ /* Cannot happen: */
+ /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */
+ ) {
+ struct timeval times[2];
+
+ times[1].tv_sec = times[0].tv_sec = source_stat.st_mtime;
+ times[1].tv_usec = times[0].tv_usec = 0;
+ /* BTW, utimes sets usec-precision time - just FYI */
+ if (utimes(dest, times) < 0)
+ bb_perror_msg("can't 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);
+ bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
+ }
+ if (chmod(dest, source_stat.st_mode) < 0)
+ bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
+ }
+
+ return retval;
+}
diff --git a/ap/app/busybox/src/libbb/copyfd.c b/ap/app/busybox/src/libbb/copyfd.c
new file mode 100644
index 0000000..eda2747
--- /dev/null
+++ b/ap/app/busybox/src/libbb/copyfd.c
@@ -0,0 +1,135 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* Used by NOFORK applets (e.g. cat) - must not use xmalloc.
+ * size < 0 means "ignore write errors", used by tar --to-command
+ * size = 0 means "copy till EOF"
+ */
+static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
+{
+ int status = -1;
+ off_t total = 0;
+ bool continue_on_write_error = 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;
+#endif
+
+ if (size < 0) {
+ size = -size;
+ continue_on_write_error = 1;
+ }
+
+#if CONFIG_FEATURE_COPYBUF_KB > 4
+ if (size > 0 && size <= 4 * 1024)
+ goto use_small_buf;
+ /* 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) {
+ use_small_buf:
+ 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) {
+ ssize_t rd;
+
+ rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size);
+
+ if (!rd) { /* eof - all done */
+ status = 0;
+ break;
+ }
+ 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) {
+ if (!continue_on_write_error) {
+ bb_perror_msg(bb_msg_write_error);
+ break;
+ }
+ dst_fd = -1;
+ }
+ }
+ 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;
+}
+
+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 >= 0 ? size : -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/ap/app/busybox/src/libbb/correct_password.c b/ap/app/busybox/src/libbb/correct_password.c
new file mode 100644
index 0000000..7cabd33
--- /dev/null
+++ b/ap/app/busybox/src/libbb/correct_password.c
@@ -0,0 +1,77 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "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 if PW has an empty password.
+ *
+ * NULL pw means "just fake it for login with bad username" */
+
+int FAST_FUNC correct_password(const struct passwd *pw)
+{
+ char *unencrypted, *encrypted;
+ const char *correct;
+ int r;
+ /* 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
+ /* Using _r function to avoid pulling in static buffers */
+ if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) {
+ struct spwd spw;
+ char buffer[256];
+ /* 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;
+ }
+#endif
+
+ if (!correct[0]) /* empty password field? */
+ return 1;
+
+ fake_it:
+ unencrypted = bb_ask_stdin("Password: ");
+ if (!unencrypted) {
+ return 0;
+ }
+ encrypted = pw_encrypt(unencrypted, correct, 1);
+ r = (strcmp(encrypted, correct) == 0);
+ free(encrypted);
+ memset(unencrypted, 0, strlen(unencrypted));
+ return r;
+}
diff --git a/ap/app/busybox/src/libbb/crc32.c b/ap/app/busybox/src/libbb/crc32.c
new file mode 100644
index 0000000..ac9836c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/crc32.c
@@ -0,0 +1,66 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * CRC32 table fill function
+ * Copyright (C) 2006 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
+ * (I can't really claim much credit however, as the algorithm is
+ * very well-known)
+ *
+ * The following function creates a CRC32 table depending on whether
+ * a big-endian (0x04c11db7) or little-endian (0xedb88320) CRC32 is
+ * required. Admittedly, there are other CRC32 polynomials floating
+ * around, but Busybox doesn't use them.
+ *
+ * endian = 1: big-endian
+ * endian = 0: little-endian
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+uint32_t *global_crc32_table;
+
+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;
+}
+
+uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table)
+{
+ const void *end = (uint8_t*)buf + len;
+
+ while (buf != end) {
+ val = (val << 8) ^ crc_table[(val >> 24) ^ *(uint8_t*)buf];
+ buf = (uint8_t*)buf + 1;
+ }
+ return val;
+}
+
+uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table)
+{
+ const void *end = (uint8_t*)buf + len;
+
+ while (buf != end) {
+ val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8);
+ buf = (uint8_t*)buf + 1;
+ }
+ return val;
+}
diff --git a/ap/app/busybox/src/libbb/create_icmp6_socket.c b/ap/app/busybox/src/libbb/create_icmp6_socket.c
new file mode 100644
index 0000000..368c690
--- /dev/null
+++ b/ap/app/busybox/src/libbb/create_icmp6_socket.c
@@ -0,0 +1,38 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * create raw socket for icmp (IPv6 version) protocol
+ * and drop root privileges if running setuid
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+#if ENABLE_FEATURE_IPV6
+int FAST_FUNC create_icmp6_socket(void)
+{
+ 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" */
+ 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);
+ bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
+ }
+
+ /* drop root privs if running setuid */
+ xsetuid(getuid());
+
+ return sock;
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/create_icmp_socket.c b/ap/app/busybox/src/libbb/create_icmp_socket.c
new file mode 100644
index 0000000..5856269
--- /dev/null
+++ b/ap/app/busybox/src/libbb/create_icmp_socket.c
@@ -0,0 +1,36 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * create raw socket for icmp protocol
+ * and drop root privileges if running setuid
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+int FAST_FUNC create_icmp_socket(void)
+{
+ 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" */
+ 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)
+ 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 */
+ xsetuid(getuid());
+
+ return sock;
+}
diff --git a/ap/app/busybox/src/libbb/default_error_retval.c b/ap/app/busybox/src/libbb/default_error_retval.c
new file mode 100644
index 0000000..4f6395f
--- /dev/null
+++ b/ap/app/busybox/src/libbb/default_error_retval.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* Seems silly to copyright a global variable. ;-) Oh well.
+ *
+ * At least one applet (cmp) returns a value different from the typical
+ * EXIT_FAILURE values (1) when an error occurs. So, make it configurable
+ * by the applet. I suppose we could use a wrapper function to set it, but
+ * that too seems silly.
+ */
+
+#include "libbb.h"
+
+uint8_t xfunc_error_retval = EXIT_FAILURE;
diff --git a/ap/app/busybox/src/libbb/device_open.c b/ap/app/busybox/src/libbb/device_open.c
new file mode 100644
index 0000000..a8fe2fc
--- /dev/null
+++ b/ap/app/busybox/src/libbb/device_open.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* try to open up the specified device */
+int FAST_FUNC device_open(const char *device, int mode)
+{
+ int m, f, fd;
+
+ m = mode | O_NONBLOCK;
+
+ /* Retry up to 5 times */
+ /* 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. */
+ if (m != mode)
+ fcntl(fd, F_SETFL, mode);
+ return fd;
+}
diff --git a/ap/app/busybox/src/libbb/die_if_bad_username.c b/ap/app/busybox/src/libbb/die_if_bad_username.c
new file mode 100644
index 0000000..cf1297b
--- /dev/null
+++ b/ap/app/busybox/src/libbb/die_if_bad_username.c
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Check user and group names for illegal characters
+ *
+ * Copyright (C) 2008 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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)
+{
+ const char *start = name;
+
+ /* 1st char being dash or dot isn't valid:
+ * for example, name like ".." can make adduser
+ * chown "/home/.." recursively - NOT GOOD.
+ * Name of just a single "$" is also rejected.
+ */
+ goto skip;
+
+ do {
+ unsigned char ch;
+
+ /* These chars are valid unless they are at the 1st pos: */
+ if (*name == '-'
+ || *name == '.'
+ /* $ is allowed if it's the last char: */
+ || (*name == '$' && !name[1])
+ ) {
+ continue;
+ }
+ skip:
+ ch = *name;
+ if (ch == '_'
+ /* || ch == '@' -- we disallow this too. Think about "user@host" */
+ /* open-coded isalnum: */
+ || (ch >= '0' && ch <= '9')
+ || ((ch|0x20) >= 'a' && (ch|0x20) <= 'z')
+ ) {
+ continue;
+ }
+ bb_error_msg_and_die("illegal character with code %u at position %u",
+ (unsigned)ch, (unsigned)(name - start));
+ } while (*++name);
+
+ /* The minimum size of the login name is one char or two if
+ * last char is the '$'. Violations of this are caught above.
+ * The maximum size of the login name is LOGIN_NAME_MAX
+ * including the terminating null byte.
+ */
+ if (name - start >= LOGIN_NAME_MAX)
+ bb_error_msg_and_die("name is too long");
+}
diff --git a/ap/app/busybox/src/libbb/dump.c b/ap/app/busybox/src/libbb/dump.c
new file mode 100644
index 0000000..7e43564
--- /dev/null
+++ b/ap/app/busybox/src/libbb/dump.c
@@ -0,0 +1,837 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Support code for the hexdump and od applets,
+ * based on code from util-linux v 2.11l
+ *
+ * Copyright (c) 1989
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ *
+ * Original copyright notice is retained at the end of this file.
+ */
+
+#include "libbb.h"
+#include "dump.h"
+
+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[] 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;
+
+dumper_t* FAST_FUNC alloc_dumper(void)
+{
+ 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;
+
+ /* figure out the data block bb_dump_size needed for each format unit */
+ for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->bcnt) {
+ cur_size += fu->bcnt * fu->reps;
+ continue;
+ }
+ for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
+ if (*fmt != '%')
+ continue;
+ /*
+ * skip any special chars -- save precision in
+ * case it's a %s format.
+ */
+ while (strchr(index_str + 1, *++fmt))
+ continue;
+ if (*fmt == '.' && isdigit(*++fmt)) {
+ prec = atoi(fmt);
+ while (isdigit(*++fmt))
+ continue;
+ }
+ p = strchr(size_conv_str + 12, *fmt);
+ if (!p) {
+ if (*fmt == 's') {
+ bcnt += prec;
+ } else if (*fmt == '_') {
+ ++fmt;
+ if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
+ bcnt += 1;
+ }
+ }
+ } else {
+ bcnt += size_conv_str[p - (size_conv_str + 12)];
+ }
+ }
+ cur_size += bcnt * fu->reps;
+ }
+ return cur_size;
+}
+
+static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
+{
+ enum { NOTOKAY, USEBCNT, USEPREC } sokay;
+ FU *fu;
+ PR *pr;
+ char *p1, *p2, *p3;
+ char savech, *fmtp;
+ const char *byte_count_str;
+ int nconv, prec = 0;
+
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ /*
+ * break each format unit into print units; each
+ * conversion character gets its own.
+ */
+ for (nconv = 0, fmtp = fu->fmt; *fmtp; ) {
+ /* NOSTRICT */
+ /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/
+ pr = xzalloc(sizeof(PR));
+ if (!fu->nextpr)
+ fu->nextpr = pr;
+
+ /* skip preceding text and up to the next % sign */
+ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1)
+ continue;
+
+ /* only text in the string */
+ if (!*p1) {
+ pr->fmt = fmtp;
+ pr->flags = F_TEXT;
+ break;
+ }
+
+ /*
+ * get precision for %s -- if have a byte count, don't
+ * need it.
+ */
+ if (fu->bcnt) {
+ sokay = USEBCNT;
+ /* skip to conversion character */
+ for (++p1; strchr(index_str, *p1); ++p1)
+ continue;
+ } else {
+ /* 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))
+ continue;
+ } else
+ sokay = NOTOKAY;
+ }
+
+ p2 = p1 + 1; /* set end pointer */
+
+ /*
+ * figure out the byte count for each conversion;
+ * rewrite the format as necessary, set up blank-
+ * pbb_dump_adding for end of data.
+ */
+ if (*p1 == 'c') {
+ pr->flags = F_CHAR;
+ DO_BYTE_COUNT_1:
+ byte_count_str = "\001";
+ DO_BYTE_COUNT:
+ if (fu->bcnt) {
+ do {
+ if (fu->bcnt == *byte_count_str) {
+ break;
+ }
+ } while (*++byte_count_str);
+ }
+ /* Unlike the original, output the remainder of the format string. */
+ if (!*byte_count_str) {
+ bb_error_msg_and_die("bad byte count for conversion character %s", p1);
+ }
+ pr->bcnt = *byte_count_str;
+ } else if (*p1 == 'l') {
+ ++p2;
+ ++p1;
+ DO_INT_CONV:
+ {
+ const char *e;
+ e = strchr(lcc, *p1);
+ if (!e) {
+ goto DO_BAD_CONV_CHAR;
+ }
+ pr->flags = F_INT;
+ if (e > lcc + 1) {
+ pr->flags = F_UINT;
+ }
+ byte_count_str = "\004\002\001";
+ goto DO_BYTE_COUNT;
+ }
+ /* NOTREACHED */
+ } else if (strchr(lcc, *p1)) {
+ goto DO_INT_CONV;
+ } else if (strchr("eEfgG", *p1)) {
+ pr->flags = F_DBL;
+ byte_count_str = "\010\004";
+ goto DO_BYTE_COUNT;
+ } else if (*p1 == 's') {
+ pr->flags = F_STR;
+ if (sokay == USEBCNT) {
+ pr->bcnt = fu->bcnt;
+ } else if (sokay == USEPREC) {
+ pr->bcnt = prec;
+ } else { /* NOTOKAY */
+ bb_error_msg_and_die("%%s requires a precision or a byte count");
+ }
+ } else if (*p1 == '_') {
+ ++p2;
+ switch (p1[1]) {
+ case 'A':
+ dumper->endfu = fu;
+ fu->flags |= F_IGNORE;
+ /* FALLTHROUGH */
+ case 'a':
+ pr->flags = F_ADDRESS;
+ ++p2;
+ if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
+ goto DO_BAD_CONV_CHAR;
+ }
+ *p1 = p1[2];
+ break;
+ case 'c':
+ pr->flags = F_C;
+ /* *p1 = 'c'; set in conv_c */
+ goto DO_BYTE_COUNT_1;
+ case 'p':
+ pr->flags = F_P;
+ *p1 = 'c';
+ goto DO_BYTE_COUNT_1;
+ case 'u':
+ pr->flags = F_U;
+ /* *p1 = 'c'; set in conv_u */
+ goto DO_BYTE_COUNT_1;
+ default:
+ goto DO_BAD_CONV_CHAR;
+ }
+ } else {
+ DO_BAD_CONV_CHAR:
+ bb_error_msg_and_die("bad conversion character %%%s", p1);
+ }
+
+ /*
+ * copy to PR format string, set conversion character
+ * pointer, update original.
+ */
+ savech = *p2;
+ p1[1] = '\0';
+ pr->fmt = xstrdup(fmtp);
+ *p2 = savech;
+ //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",
+ * we lose the " is a HEX number" part of fmt.
+ */
+ for (p3 = p2; *p3 && *p3 != '%'; p3++)
+ continue;
+ if (p3 > p2) {
+ savech = *p3;
+ *p3 = '\0';
+ 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");
+ }
+ }
+ /*
+ * if format unit byte count not specified, figure it out
+ * so can adjust rep count later.
+ */
+ if (!fu->bcnt)
+ for (pr = fu->nextpr; pr; pr = pr->nextpr)
+ fu->bcnt += pr->bcnt;
+ }
+ /*
+ * if the format string interprets any data at all, and it's
+ * not the same as the 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 = 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 && fu->nextpr) {
+ for (pr = fu->nextpr;; pr = pr->nextpr)
+ if (!pr->nextpr)
+ break;
+ for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
+ p2 = isspace(*p1) ? p1 : NULL;
+ if (p2)
+ pr->nospace = p2;
+ }
+ if (!fu->nextfu)
+ break;
+ }
+}
+
+static void do_skip(priv_dumper_t *dumper, const char *fname, int statok)
+{
+ struct stat sbuf;
+
+ if (statok) {
+ xfstat(STDIN_FILENO, &sbuf, fname);
+ 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, dumper->pub.dump_skip, SEEK_SET)) {
+ bb_simple_perror_msg_and_die(fname);
+ }
+ dumper->address += dumper->pub.dump_skip;
+ dumper->savaddress = dumper->address;
+ dumper->pub.dump_skip = 0;
+}
+
+static NOINLINE int next(priv_dumper_t *dumper)
+{
+ int statok;
+
+ for (;;) {
+ if (*dumper->argv) {
+ dumper->next__done = statok = 1;
+ if (!(freopen(*dumper->argv, "r", stdin))) {
+ bb_simple_perror_msg(*dumper->argv);
+ dumper->exitval = 1;
+ ++dumper->argv;
+ continue;
+ }
+ } else {
+ if (dumper->next__done)
+ return 0; /* no next file */
+ dumper->next__done = 1;
+ statok = 0;
+ }
+ 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 unsigned char *get(priv_dumper_t *dumper)
+{
+ int n;
+ int need, nread;
+ int blocksize = dumper->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 {
+ unsigned char *tmp = dumper->get__curp;
+ dumper->get__curp = dumper->get__savp;
+ dumper->get__savp = tmp;
+ dumper->savaddress += blocksize;
+ dumper->address = dumper->savaddress;
+ }
+ 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 (!dumper->pub.dump_length || (dumper->get__ateof && !next(dumper))) {
+ if (need == blocksize) {
+ return NULL;
+ }
+ if (dumper->pub.dump_vflag != ALL && !memcmp(dumper->get__curp, dumper->get__savp, nread)) {
+ if (dumper->pub.dump_vflag != DUP) {
+ puts("*");
+ }
+ return NULL;
+ }
+ memset(dumper->get__curp + nread, 0, need);
+ dumper->eaddress = dumper->address + nread;
+ return dumper->get__curp;
+ }
+ 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_simple_perror_msg(dumper->argv[-1]);
+ }
+ dumper->get__ateof = 1;
+ continue;
+ }
+ dumper->get__ateof = 0;
+ if (dumper->pub.dump_length != -1) {
+ dumper->pub.dump_length -= n;
+ }
+ 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 dumper->get__curp;
+ }
+ if (dumper->pub.dump_vflag == WAIT) {
+ puts("*");
+ }
+ dumper->pub.dump_vflag = DUP;
+ dumper->savaddress += blocksize;
+ dumper->address = dumper->savaddress;
+ need = blocksize;
+ nread = 0;
+ } else {
+ nread += n;
+ }
+ }
+}
+
+static void bpad(PR *pr)
+{
+ char *p1, *p2;
+
+ /*
+ * remove all conversion flags; '-' is the only one valid
+ * with %s, and it's not useful here.
+ */
+ pr->flags = F_BPAD;
+ *pr->cchar = 's';
+ for (p1 = pr->fmt; *p1 != '%'; ++p1)
+ continue;
+ for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
+ if (pr->nospace)
+ pr->nospace--;
+ while ((*p2++ = *p1++) != 0)
+ continue;
+}
+
+static const char conv_str[] ALIGN1 =
+ "\0\\0\0"
+ "\007\\a\0" /* \a */
+ "\b\\b\0"
+ "\f\\b\0"
+ "\n\\n\0"
+ "\r\\r\0"
+ "\t\\t\0"
+ "\v\\v\0"
+ ;
+
+
+static void conv_c(PR *pr, unsigned char *p)
+{
+ const char *str = conv_str;
+ char buf[10];
+
+ do {
+ if (*p == *str) {
+ ++str;
+ goto strpr;
+ }
+ str += 4;
+ } while (*str);
+
+ if (isprint_asciionly(*p)) {
+ *pr->cchar = 'c';
+ printf(pr->fmt, *p);
+ } else {
+ sprintf(buf, "%03o", (int) *p);
+ str = buf;
+ strpr:
+ *pr->cchar = 's';
+ printf(pr->fmt, str);
+ }
+}
+
+static void conv_u(PR *pr, unsigned char *p)
+{
+ 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"
+ "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
+
+ /* od used nl, not lf */
+ if (*p <= 0x1f) {
+ *pr->cchar = 's';
+ printf(pr->fmt, list + (4 * (int)*p));
+ } else if (*p == 0x7f) {
+ *pr->cchar = 's';
+ printf(pr->fmt, "del");
+ } else if (*p < 0x7f) { /* isprint() */
+ *pr->cchar = 'c';
+ printf(pr->fmt, *p);
+ } else {
+ *pr->cchar = 'x';
+ printf(pr->fmt, (int) *p);
+ }
+}
+
+static void display(priv_dumper_t* dumper)
+{
+ FS *fs;
+ FU *fu;
+ PR *pr;
+ int cnt;
+ unsigned char *bp, *savebp;
+ off_t saveaddress;
+ unsigned char savech = '\0';
+
+ 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; 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) {
+ savech = *pr->nospace;
+ *pr->nospace = '\0';
+ }
+/* PRINT; */
+ switch (pr->flags) {
+ case F_ADDRESS:
+ printf(pr->fmt, (unsigned) dumper->address);
+ break;
+ case F_BPAD:
+ printf(pr->fmt, "");
+ break;
+ case F_C:
+ conv_c(pr, bp);
+ break;
+ case F_CHAR:
+ printf(pr->fmt, *bp);
+ break;
+ case F_DBL: {
+ double dval;
+ float fval;
+
+ switch (pr->bcnt) {
+ case 4:
+ memcpy(&fval, bp, sizeof(fval));
+ printf(pr->fmt, fval);
+ break;
+ case 8:
+ memcpy(&dval, bp, sizeof(dval));
+ printf(pr->fmt, dval);
+ break;
+ }
+ break;
+ }
+ case F_INT: {
+ int ival;
+ short sval;
+
+ switch (pr->bcnt) {
+ case 1:
+ printf(pr->fmt, (int) *bp);
+ break;
+ case 2:
+ memcpy(&sval, bp, sizeof(sval));
+ printf(pr->fmt, (int) sval);
+ break;
+ case 4:
+ memcpy(&ival, bp, sizeof(ival));
+ printf(pr->fmt, ival);
+ break;
+ }
+ break;
+ }
+ case F_P:
+ printf(pr->fmt, isprint_asciionly(*bp) ? *bp : '.');
+ break;
+ case F_STR:
+ printf(pr->fmt, (char *) bp);
+ break;
+ case F_TEXT:
+ printf(pr->fmt);
+ break;
+ case F_U:
+ conv_u(pr, bp);
+ break;
+ case F_UINT: {
+ unsigned ival;
+ unsigned short sval;
+
+ switch (pr->bcnt) {
+ case 1:
+ printf(pr->fmt, (unsigned) *bp);
+ break;
+ case 2:
+ memcpy(&sval, bp, sizeof(sval));
+ printf(pr->fmt, (unsigned) sval);
+ break;
+ case 4:
+ memcpy(&ival, bp, sizeof(ival));
+ printf(pr->fmt, ival);
+ break;
+ }
+ break;
+ }
+ }
+ if (cnt == 1 && pr->nospace) {
+ *pr->nospace = savech;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (dumper->endfu) {
+ /*
+ * if eaddress not set, error or file size was multiple
+ * of blocksize, and no partial block ever found.
+ */
+ if (!dumper->eaddress) {
+ if (!dumper->address) {
+ return;
+ }
+ dumper->eaddress = dumper->address;
+ }
+ for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) {
+ switch (pr->flags) {
+ case F_ADDRESS:
+ printf(pr->fmt, (unsigned) dumper->eaddress);
+ break;
+ case F_TEXT:
+ printf(pr->fmt);
+ break;
+ }
+ }
+ }
+}
+
+#define dumper ((priv_dumper_t*)pub_dumper)
+int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv)
+{
+ FS *tfs;
+ int blocksize;
+
+ /* figure out the data block bb_dump_size */
+ blocksize = 0;
+ tfs = dumper->pub.fshead;
+ while (tfs) {
+ tfs->bcnt = bb_dump_size(tfs);
+ if (blocksize < tfs->bcnt) {
+ blocksize = tfs->bcnt;
+ }
+ tfs = tfs->nextfs;
+ }
+ dumper->blocksize = blocksize;
+
+ /* rewrite the rules, do syntax checking */
+ for (tfs = dumper->pub.fshead; tfs; tfs = tfs->nextfs) {
+ rewrite(dumper, tfs);
+ }
+
+ dumper->argv = argv;
+ display(dumper);
+
+ return dumper->exitval;
+}
+
+void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
+{
+ const char *p;
+ char *p1;
+ char *p2;
+ FS *tfs;
+ FU *tfu, **nextfupp;
+ const char *savep;
+
+ /* start new linked list of format units */
+ tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
+ if (!dumper->pub.fshead) {
+ dumper->pub.fshead = tfs;
+ } else {
+ FS *fslast = dumper->pub.fshead;
+ while (fslast->nextfs)
+ fslast = fslast->nextfs;
+ fslast->nextfs = tfs;
+ }
+ nextfupp = &tfs->nextfu;
+
+ /* take the format string and break it up into format units */
+ p = fmt;
+ for (;;) {
+ p = skip_whitespace(p);
+ if (*p == '\0') {
+ break;
+ }
+
+ /* allocate a new format unit and link it in */
+ /* NOSTRICT */
+ /* 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)
+ 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;
+ /* skip trailing white space */
+ p = skip_whitespace(++p);
+ }
+
+ /* skip slash and trailing white space */
+ if (*p == '/') {
+ p = skip_whitespace(p + 1);
+ }
+
+ /* byte count */
+ if (isdigit(*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);
+ /* skip trailing white space */
+ p = skip_whitespace(p + 1);
+ }
+
+ /* format */
+ if (*p != '"') {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ for (savep = ++p; *p != '"';) {
+ if (*p++ == '\0') {
+ bb_error_msg_and_die("bad format {%s}", fmt);
+ }
+ }
+ tfu->fmt = xstrndup(savep, p - savep);
+/* escape(tfu->fmt); */
+
+ p1 = tfu->fmt;
+
+ /* alphabetic escape sequences have to be done in place */
+ for (p2 = p1;; ++p1, ++p2) {
+ if (*p1 == '\0') {
+ *p2 = *p1;
+ break;
+ }
+ if (*p1 == '\\') {
+ const char *cs = conv_str + 4;
+ ++p1;
+ *p2 = *p1;
+ do {
+ if (*p1 == cs[2]) {
+ *p2 = cs[0];
+ break;
+ }
+ cs += 4;
+ } while (*cs);
+ }
+ }
+
+ p++;
+ }
+}
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
diff --git a/ap/app/busybox/src/libbb/execable.c b/ap/app/busybox/src/libbb/execable.c
new file mode 100644
index 0000000..178a00a
--- /dev/null
+++ b/ap/app/busybox/src/libbb/execable.c
@@ -0,0 +1,86 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2006 Gabriel Somlo <somlo at cmu.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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[])
+{
+ if (find_applet_by_name(file) >= 0)
+ execvp(bb_busybox_exec_path, argv);
+ return execvp(file, argv);
+}
+#endif
+
+int FAST_FUNC BB_EXECVP_or_die(char **argv)
+{
+ BB_EXECVP(argv[0], argv);
+ /* SUSv3-mandated exit codes */
+ xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
+ bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+}
diff --git a/ap/app/busybox/src/libbb/fclose_nonstdin.c b/ap/app/busybox/src/libbb/fclose_nonstdin.c
new file mode 100644
index 0000000..5ce9d5b
--- /dev/null
+++ b/ap/app/busybox/src/libbb/fclose_nonstdin.c
@@ -0,0 +1,25 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fclose_nonstdin implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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 "libbb.h"
+
+int FAST_FUNC fclose_if_not_stdin(FILE *f)
+{
+ /* 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/ap/app/busybox/src/libbb/fflush_stdout_and_exit.c b/ap/app/busybox/src/libbb/fflush_stdout_and_exit.c
new file mode 100644
index 0000000..9ad5dbf
--- /dev/null
+++ b/ap/app/busybox/src/libbb/fflush_stdout_and_exit.c
@@ -0,0 +1,29 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * fflush_stdout_and_exit implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* Attempt to fflush(stdout), and exit with an error code if stdout is
+ * in an error state.
+ */
+
+#include "libbb.h"
+
+void FAST_FUNC fflush_stdout_and_exit(int 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/ap/app/busybox/src/libbb/fgets_str.c b/ap/app/busybox/src/libbb/fgets_str.c
new file mode 100644
index 0000000..89210a3
--- /dev/null
+++ b/ap/app/busybox/src/libbb/fgets_str.c
@@ -0,0 +1,86 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+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);
+ int end_string_offset;
+ 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;
+ }
+
+ if (idx >= linebufsz) {
+ linebufsz += 200;
+ linebuf = xrealloc(linebuf, linebufsz);
+ if (idx >= maxsz) {
+ linebuf[idx] = ch;
+ idx++;
+ break;
+ }
+ }
+
+ linebuf[idx] = ch;
+ idx++;
+
+ /* Check for terminating string */
+ end_string_offset = idx - term_length;
+ if (end_string_offset >= 0
+ && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
+ ) {
+ if (chop_off)
+ idx -= term_length;
+ break;
+ }
+ }
+ /* Grow/shrink *first*, then store NUL */
+ linebuf = xrealloc(linebuf, idx + 1);
+ linebuf[idx] = '\0';
+ *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/ap/app/busybox/src/libbb/find_mount_point.c b/ap/app/busybox/src/libbb/find_mount_point.c
new file mode 100644
index 0000000..9676b5f
--- /dev/null
+++ b/ap/app/busybox/src/libbb/find_mount_point.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include <mntent.h>
+
+/*
+ * Given a block device, find the mount table entry if that block device
+ * is mounted.
+ *
+ * Given any other file (or directory), find the mount table entry for its
+ * filesystem.
+ */
+struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
+{
+ struct stat s;
+ FILE *mtab_fp;
+ struct mntent *mountEntry;
+ dev_t devno_of_name;
+ bool block_dev;
+
+ if (stat(name, &s) != 0)
+ return NULL;
+
+ devno_of_name = s.st_dev;
+ block_dev = 0;
+ /* Why S_ISCHR? - UBI volumes use char devices, not block */
+ if (S_ISBLK(s.st_mode) || S_ISCHR(s.st_mode)) {
+ devno_of_name = s.st_rdev;
+ block_dev = 1;
+ }
+
+ mtab_fp = setmntent(bb_path_mtab_file, "r");
+ if (!mtab_fp)
+ return NULL;
+
+ while ((mountEntry = getmntent(mtab_fp)) != 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 (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(mountEntry->mnt_fsname, "rootfs") == 0)
+ continue;
+
+ if (strcmp(name, mountEntry->mnt_dir) == 0
+ || strcmp(name, mountEntry->mnt_fsname) == 0
+ ) { /* String match. */
+ break;
+ }
+
+ if (!(subdir_too || block_dev))
+ continue;
+
+ /* Is device's dev_t == name's dev_t? */
+ if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == devno_of_name)
+ break;
+ /* Match the directory's mount point. */
+ if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == devno_of_name)
+ break;
+ }
+ endmntent(mtab_fp);
+
+ return mountEntry;
+}
diff --git a/ap/app/busybox/src/libbb/find_pid_by_name.c b/ap/app/busybox/src/libbb/find_pid_by_name.c
new file mode 100644
index 0000000..db823d0
--- /dev/null
+++ b/ap/app/busybox/src/libbb/find_pid_by_name.c
@@ -0,0 +1,120 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/*
+In Linux we have three ways to determine "process name":
+1. /proc/PID/stat has "...(name)...", among other things. It's so-called "comm" field.
+2. /proc/PID/cmdline's first NUL-terminated string. It's argv[0] from exec syscall.
+3. /proc/PID/exe symlink. Points to the running executable file.
+
+kernel threads:
+ comm: thread name
+ cmdline: empty
+ exe: <readlink fails>
+
+executable
+ comm: first 15 chars of base name
+ (if executable is a symlink, then first 15 chars of symlink name are used)
+ cmdline: argv[0] from exec syscall
+ exe: points to executable (resolves symlink, unlike comm)
+
+script (an executable with #!/path/to/interpreter):
+ comm: first 15 chars of script's base name (symlinks are not resolved)
+ cmdline: /path/to/interpreter (symlinks are not resolved)
+ (script name is in argv[1], args are pushed into argv[2] etc)
+ exe: points to interpreter's executable (symlinks are resolved)
+
+If FEATURE_PREFER_APPLETS=y (and more so if FEATURE_SH_STANDALONE=y),
+some commands started from busybox shell, xargs or find are started by
+execXXX("/proc/self/exe", applet_name, params....)
+and therefore comm field contains "exe".
+*/
+
+static int comm_match(procps_status_t *p, const char *procName)
+{
+ int argv1idx;
+ const char *argv1;
+
+ if (strncmp(p->comm, procName, 15) != 0)
+ return 0; /* comm does not match */
+
+ /* In Linux, if comm is 15 chars, it is truncated.
+ * (or maybe the name was exactly 15 chars, but there is
+ * no way to know that) */
+ if (p->comm[14] == '\0')
+ return 1; /* comm is not truncated - matches */
+
+ /* comm is truncated, but first 15 chars match.
+ * This can be crazily_long_script_name.sh!
+ * The telltale sign is basename(argv[1]) == procName */
+
+ if (!p->argv0)
+ return 0;
+
+ argv1idx = strlen(p->argv0) + 1;
+ if (argv1idx >= p->argv_len)
+ return 0;
+ argv1 = p->argv0 + argv1idx;
+
+ if (strcmp(bb_basename(argv1), procName) != 0)
+ return 0;
+
+ return 1;
+}
+
+/* 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
+ * It is the caller's duty to free the returned pidlist.
+ *
+ * Modified by Vladimir Oleynik for use with libbb/procps.c
+ */
+pid_t* FAST_FUNC find_pid_by_name(const char *procName)
+{
+ 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|PSSCAN_EXE))) {
+ 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)
+ /* or we require /proc/PID/exe link to match */
+ || (p->exe && strcmp(bb_basename(p->exe), procName) == 0)
+ ) {
+ pidList = xrealloc_vector(pidList, 2, i);
+ pidList[i++] = p->pid;
+ }
+ }
+
+ pidList[i] = 0;
+ return pidList;
+}
+
+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/ap/app/busybox/src/libbb/find_root_device.c b/ap/app/busybox/src/libbb/find_root_device.c
new file mode 100644
index 0000000..8436cd6
--- /dev/null
+++ b/ap/app/busybox/src/libbb/find_root_device.c
@@ -0,0 +1,75 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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];
+};
+
+static char *find_block_device_in_dir(struct arena *ap)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char *retpath = NULL;
+ int len, rem;
+
+ len = strlen(ap->devpath);
+ rem = DEVNAME_MAX-2 - len;
+ if (rem <= 0)
+ return NULL;
+
+ dir = opendir(ap->devpath);
+ if (!dir)
+ return NULL;
+
+ ap->devpath[len++] = '/';
+
+ 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;
+ }
+ }
+ closedir(dir);
+
+ return retpath;
+}
+
+char* FAST_FUNC find_block_device(const char *path)
+{
+ struct arena a;
+
+ 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/ap/app/busybox/src/libbb/full_write.c b/ap/app/busybox/src/libbb/full_write.c
new file mode 100644
index 0000000..777fbd9
--- /dev/null
+++ b/ap/app/busybox/src/libbb/full_write.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/*
+ * Write all of the supplied buffer out to a file.
+ * This does multiple writes as necessary.
+ * Returns the amount written, or -1 on an error.
+ */
+ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len) {
+ cc = safe_write(fd, buf, len);
+
+ 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. */
+ }
+
+ total += cc;
+ buf = ((const char *)buf) + cc;
+ len -= cc;
+ }
+
+ return total;
+}
diff --git a/ap/app/busybox/src/libbb/get_console.c b/ap/app/busybox/src/libbb/get_console.c
new file mode 100644
index 0000000..9b6407b
--- /dev/null
+++ b/ap/app/busybox/src/libbb/get_console.c
@@ -0,0 +1,80 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* From <linux/kd.h> */
+enum { KDGKBTYPE = 0x4B33 }; /* get keyboard type */
+
+static int open_a_console(const char *fnam)
+{
+ int fd;
+
+ /* try read-write */
+ fd = open(fnam, O_RDWR);
+
+ /* if failed, try read-only */
+ if (fd < 0 && errno == EACCES)
+ fd = open(fnam, O_RDONLY);
+
+ /* if failed, try write-only */
+ if (fd < 0 && errno == EACCES)
+ fd = open(fnam, O_WRONLY);
+
+ return fd;
+}
+
+/*
+ * Get an fd for use with kbd/console ioctls.
+ * We try several things because opening /dev/console will fail
+ * if someone else used X (which does a chown on /dev/console).
+ */
+int FAST_FUNC get_console_fd_or_die(void)
+{
+ static const char *const console_names[] = {
+ DEV_CONSOLE, CURRENT_VC, CURRENT_TTY
+ };
+
+ int 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;
+ }
+ }
+
+ bb_error_msg_and_die("can't open console");
+ /*return fd; - total failure */
+}
+
+/* From <linux/vt.h> */
+enum {
+ VT_ACTIVATE = 0x5606, /* make vt active */
+ VT_WAITACTIVE = 0x5607 /* wait for vt active */
+};
+
+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/ap/app/busybox/src/libbb/get_cpu_count.c b/ap/app/busybox/src/libbb/get_cpu_count.c
new file mode 100644
index 0000000..ab468af
--- /dev/null
+++ b/ap/app/busybox/src/libbb/get_cpu_count.c
@@ -0,0 +1,47 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Factored out of mpstat/iostat.
+ *
+ * Copyright (C) 2010 Marek Polacek <mmpolacek@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+/* Does str start with "cpu"? */
+int FAST_FUNC starts_with_cpu(const char *str)
+{
+ return ((str[0] - 'c') | (str[1] - 'p') | (str[2] - 'u')) == 0;
+}
+
+/*
+ * Get number of processors. Uses /proc/stat.
+ * Return value 0 means one CPU and non SMP kernel.
+ * Otherwise N means N processor(s) and SMP kernel.
+ */
+unsigned FAST_FUNC get_cpu_count(void)
+{
+ FILE *fp;
+ char line[256];
+ int proc_nr = -1;
+
+ fp = xfopen_for_read("/proc/stat");
+ while (fgets(line, sizeof(line), fp)) {
+ if (!starts_with_cpu(line)) {
+ if (proc_nr >= 0)
+ break; /* we are past "cpuN..." lines */
+ continue;
+ }
+ if (line[3] != ' ') { /* "cpuN" */
+ int num_proc;
+ if (sscanf(line + 3, "%u", &num_proc) == 1
+ && num_proc > proc_nr
+ ) {
+ proc_nr = num_proc;
+ }
+ }
+ }
+
+ fclose(fp);
+ return proc_nr + 1;
+}
diff --git a/ap/app/busybox/src/libbb/get_last_path_component.c b/ap/app/busybox/src/libbb/get_last_path_component.c
new file mode 100644
index 0000000..04fdf2a
--- /dev/null
+++ b/ap/app/busybox/src/libbb/get_last_path_component.c
@@ -0,0 +1,50 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_get_last_path_component implementation for busybox
+ *
+ * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+const char* FAST_FUNC bb_basename(const char *name)
+{
+ const char *cp = strrchr(name, '/');
+ if (cp)
+ return cp + 1;
+ return name;
+}
+
+/*
+ * "/" -> "/"
+ * "abc" -> "abc"
+ * "abc/def" -> "def"
+ * "abc/def/" -> ""
+ */
+char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path)
+{
+ char *slash = strrchr(path, '/');
+
+ if (!slash || (slash == path && !slash[1]))
+ return (char*)path;
+
+ return slash + 1;
+}
+
+/*
+ * "/" -> "/"
+ * "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/ap/app/busybox/src/libbb/get_line_from_file.c b/ap/app/busybox/src/libbb/get_line_from_file.c
new file mode 100644
index 0000000..a98dd35
--- /dev/null
+++ b/ap/app/busybox/src/libbb/get_line_from_file.c
@@ -0,0 +1,180 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2005, 2006 Rob Landley <rob@landley.net>
+ * Copyright (C) 2004 Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2001 Matt Krai
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end)
+{
+ int ch;
+ unsigned idx = 0;
+ char *linebuf = NULL;
+
+ while ((ch = getc(file)) != EOF) {
+ /* grow the line buffer as necessary */
+ if (!(idx & 0xff))
+ linebuf = xrealloc(linebuf, idx + 0x100);
+ linebuf[idx++] = (char) ch;
+ if (ch == '\0')
+ break;
+ if (end && ch == '\n')
+ break;
+ }
+ 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, 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;
+
+ while (1) {
+ 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;
+ }
+ /* 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;
+}
+
+/* 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);
+}
+
+/* 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/ap/app/busybox/src/libbb/get_shell_name.c b/ap/app/busybox/src/libbb/get_shell_name.c
new file mode 100644
index 0000000..5aebe9c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/get_shell_name.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011, Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//kbuild:lib-y += get_shell_name.o
+
+#include "libbb.h"
+
+const char* FAST_FUNC get_shell_name(void)
+{
+ struct passwd *pw;
+ char *shell;
+
+ shell = getenv("SHELL");
+ if (shell && shell[0])
+ return shell;
+
+ pw = getpwuid(getuid());
+ if (pw && pw->pw_shell && pw->pw_shell[0])
+ return pw->pw_shell;
+
+ return DEFAULT_SHELL;
+}
diff --git a/ap/app/busybox/src/libbb/get_volsize.c b/ap/app/busybox/src/libbb/get_volsize.c
new file mode 100644
index 0000000..241ceda
--- /dev/null
+++ b/ap/app/busybox/src/libbb/get_volsize.c
@@ -0,0 +1,48 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2010 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+uoff_t FAST_FUNC get_volume_size_in_bytes(int fd,
+ const char *override,
+ unsigned override_units,
+ int extend)
+{
+ uoff_t result;
+
+ if (override) {
+ result = XATOOFF(override);
+ if (result >= (uoff_t)(MAXINT(off_t)) / override_units)
+ bb_error_msg_and_die("image size is too big");
+ result *= override_units;
+ /* seek past end fails on block devices but works on files */
+ if (lseek(fd, result - 1, SEEK_SET) != (off_t)-1) {
+ if (extend)
+ xwrite(fd, "", 1); /* file grows if needed */
+ }
+ //else {
+ // bb_error_msg("warning, block device is smaller");
+ //}
+ } else {
+ /* more portable than BLKGETSIZE[64] */
+ result = xlseek(fd, 0, SEEK_END);
+ }
+
+ xlseek(fd, 0, SEEK_SET);
+
+ /* Prevent things like this:
+ * $ dd if=/dev/zero of=foo count=1 bs=1024
+ * $ mkswap foo
+ * Setting up swapspace version 1, size = 18446744073709548544 bytes
+ *
+ * Picked 16k arbitrarily: */
+ if (result < 16*1024)
+ bb_error_msg_and_die("image is too small");
+
+ return result;
+}
diff --git a/ap/app/busybox/src/libbb/getopt32.c b/ap/app/busybox/src/libbb/getopt32.c
new file mode 100644
index 0000000..d0e83d8
--- /dev/null
+++ b/ap/app/busybox/src/libbb/getopt32.c
@@ -0,0 +1,615 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * universal getopt32 implementation for busybox
+ *
+ * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG
+# include <getopt.h>
+#endif
+#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'.
+
+ "!" Report bad option, missing required options,
+ inconsistent options with all-ones return value (instead of abort).
+
+const char *applet_long_options
+
+ This struct allows you to define long options:
+
+ static const char applet_longopts[] ALIGN1 =
+ //"name\0" has_arg val
+ "verbose\0" No_argument "v"
+ ;
+ applet_long_options = applet_longopts;
+
+ The last member of struct option (val) typically is set to
+ matching short option from applet_opts. If there is no matching
+ char in applet_opts, then:
+ - return bit have next position after short options
+ - if has_arg is not "No_argument", use ptr for arg also
+ - opt_complementary affects it too
+
+ Note: a good applet will make long options configurable via the
+ config process and not a required feature. The current standard
+ is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
+
+const char *opt_complementary
+
+ ":" The colon (":") is used to separate groups of two or more chars
+ and/or groups of chars and special characters (stating some
+ conditions to be checked).
+
+ "abc" If groups of two or more chars are specified, the first char
+ is the main option and the other chars are secondary options.
+ Their flags will be turned on if the main option is found even
+ if they are not specifed on the command line. For example:
+
+ opt_complementary = "abc";
+ flags = getopt32(argv, "abcd")
+
+ If getopt() finds "-a" on the command line, then
+ getopt32's return value will be as if "-a -b -c" were
+ found.
+
+ "ww" Adjacent double options have a counter associated which indicates
+ the number of occurrences 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 group consisting of just a dash 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.
+ Example:
+
+ opt_complementary = "-:w-x:x-w"; // "-w-x:x-w" would also work,
+ getopt32(argv, "wx"); // but is less readable
+
+ This makes it possible to use options 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_positive() - 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_LONG_OPTS || ENABLE_FEATURE_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 */
+ char first_char;
+ int c;
+ const unsigned char *s;
+ t_complementary *on_off;
+ va_list p;
+#if ENABLE_LONG_OPTS || ENABLE_FEATURE_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 bbox extension */
+ first_char = applet_opts[0];
+ if (first_char == '!')
+ applet_opts++;
+
+ /* 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_LONG_OPTS || ENABLE_FEATURE_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: ;
+ }
+ /* Make it unnecessary to clear applet_long_options
+ * by hand after each call to getopt32
+ */
+ applet_long_options = NULL;
+ }
+#endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_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)
+ goto found_opt;
+ /* Without this, diagnostic of such bugs is not easy */
+ bb_error_msg_and_die("NO OPT %c!", *s);
+ found_opt:
+ if (c == ':' && s[2] == ':') {
+ on_off->param_type = PARAM_LIST;
+ continue;
+ }
+ if (c == '+' && (s[2] == ':' || s[2] == '\0')) {
+ on_off->param_type = PARAM_INT;
+ s++;
+ 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--;
+ }
+ opt_complementary = NULL;
+ 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() 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?? */
+
+ /* 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_LONG_OPTS || ENABLE_FEATURE_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" */
+ goto error;
+ }
+ }
+ if (flags & on_off->incongruously)
+ goto error;
+ 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 (optarg) {
+ if (on_off->param_type == PARAM_LIST) {
+ llist_add_to_end((llist_t **)(on_off->optarg), optarg);
+ } else if (on_off->param_type == PARAM_INT) {
+//TODO: xatoi_positive indirectly pulls in printf machinery
+ *(unsigned*)(on_off->optarg) = xatoi_positive(optarg);
+ } else if (on_off->optarg) {
+ *(char **)(on_off->optarg) = optarg;
+ }
+ }
+ }
+
+ /* 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
+ ) {
+ goto error;
+ }
+ }
+ if (requires && (flags & requires) == 0)
+ goto error;
+ argc -= optind;
+ if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
+ goto error;
+
+ option_mask32 = flags;
+ return flags;
+
+ error:
+ if (first_char != '!')
+ bb_show_usage();
+ return (int32_t)-1;
+}
diff --git a/ap/app/busybox/src/libbb/getpty.c b/ap/app/busybox/src/libbb/getpty.c
new file mode 100644
index 0000000..435e4d0
--- /dev/null
+++ b/ap/app/busybox/src/libbb/getpty.c
@@ -0,0 +1,66 @@
+/* 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 source tree.
+ */
+
+#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?) */
+# ifndef HAVE_PTSNAME_R
+ {
+ 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/ap/app/busybox/src/libbb/hash_md5_sha.c b/ap/app/busybox/src/libbb/hash_md5_sha.c
new file mode 100644
index 0000000..b4d955e
--- /dev/null
+++ b/ap/app/busybox/src/libbb/hash_md5_sha.c
@@ -0,0 +1,1168 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2010 Denys Vlasenko
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* gcc 4.2.1 optimizes rotr64 better with inline than with macro
+ * (for rotX32, there is no difference). Why? My guess is that
+ * macro requires clever common subexpression elimination heuristics
+ * in gcc, while inline basically forces it to happen.
+ */
+//#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n))))
+static ALWAYS_INLINE uint32_t rotl32(uint32_t x, unsigned n)
+{
+ return (x << n) | (x >> (32 - n));
+}
+//#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n))))
+static ALWAYS_INLINE uint32_t rotr32(uint32_t x, unsigned n)
+{
+ return (x >> n) | (x << (32 - n));
+}
+/* rotr64 in needed for sha512 only: */
+//#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n))))
+static ALWAYS_INLINE uint64_t rotr64(uint64_t x, unsigned n)
+{
+ return (x >> n) | (x << (64 - n));
+}
+
+/* rotl64 only used for sha3 currently */
+static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n)
+{
+ return (x << n) | (x >> (64 - n));
+}
+
+/* Feed data through a temporary buffer.
+ * The internal buffer remembers previous data until it has 64
+ * bytes worth to pass on.
+ */
+static void FAST_FUNC common64_hash(md5_ctx_t *ctx, const void *buffer, size_t len)
+{
+ unsigned bufpos = ctx->total64 & 63;
+
+ ctx->total64 += len;
+
+ while (1) {
+ unsigned remaining = 64 - bufpos;
+ if (remaining > len)
+ remaining = len;
+ /* Copy data into aligned buffer */
+ memcpy(ctx->wbuffer + bufpos, buffer, remaining);
+ len -= remaining;
+ buffer = (const char *)buffer + remaining;
+ bufpos += remaining;
+ /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */
+ bufpos -= 64;
+ if (bufpos != 0)
+ break;
+ /* Buffer is filled up, process it */
+ ctx->process_block(ctx);
+ /*bufpos = 0; - already is */
+ }
+}
+
+/* Process the remaining bytes in the buffer */
+static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
+{
+ unsigned bufpos = ctx->total64 & 63;
+ /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
+ ctx->wbuffer[bufpos++] = 0x80;
+
+ /* This loop iterates either once or twice, no more, no less */
+ while (1) {
+ unsigned remaining = 64 - bufpos;
+ memset(ctx->wbuffer + bufpos, 0, remaining);
+ /* Do we have enough space for the length count? */
+ if (remaining >= 8) {
+ /* Store the 64-bit counter of bits in the buffer */
+ uint64_t t = ctx->total64 << 3;
+ if (swap_needed)
+ t = bb_bswap_64(t);
+ /* wbuffer is suitably aligned for this */
+ *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t;
+ }
+ ctx->process_block(ctx);
+ if (remaining >= 8)
+ break;
+ bufpos = 0;
+ }
+}
+
+
+/*
+ * Compute MD5 checksum of strings according to the
+ * definition of MD5 in RFC 1321 from April 1992.
+ *
+ * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+ *
+ * Copyright (C) 1995-1999 Free Software Foundation, Inc.
+ * Copyright (C) 2001 Manuel Novoa III
+ * Copyright (C) 2003 Glenn L. McGrath
+ * Copyright (C) 2003 Erik Andersen
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 0: fastest, 3: smallest */
+#if CONFIG_MD5_SMALL < 0
+# define MD5_SMALL 0
+#elif CONFIG_MD5_SMALL > 3
+# define MD5_SMALL 3
+#else
+# define MD5_SMALL CONFIG_MD5_SMALL
+#endif
+
+/* 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))
+ */
+#undef FF
+#undef FG
+#undef FH
+#undef FI
+#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))
+
+/* Hash a single block, 64 bytes long and 4-byte aligned */
+static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
+{
+#if MD5_SMALL > 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
+ */
+ 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, 0x02441453, 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_SMALL > 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 */
+ };
+#endif
+ uint32_t *words = (void*) ctx->wbuffer;
+ uint32_t A = ctx->hash[0];
+ uint32_t B = ctx->hash[1];
+ uint32_t C = ctx->hash[2];
+ uint32_t D = ctx->hash[3];
+
+#if MD5_SMALL >= 2 /* 2 or 3 */
+
+ static const char S_array[] ALIGN1 = {
+ 7, 12, 17, 22,
+ 5, 9, 14, 20,
+ 4, 11, 16, 23,
+ 6, 10, 15, 21
+ };
+ const uint32_t *pc;
+ const char *pp;
+ const char *ps;
+ int i;
+ uint32_t temp;
+
+ if (BB_BIG_ENDIAN)
+ for (i = 0; i < 16; i++)
+ words[i] = SWAP_LE32(words[i]);
+
+# if MD5_SMALL == 3
+ 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 += words[(int) (*pp++)] + *pc++;
+ temp = rotl32(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+# else /* MD5_SMALL == 2 */
+ pc = C_array;
+ pp = P_array;
+ ps = S_array;
+
+ for (i = 0; i < 16; i++) {
+ temp = A + FF(B, C, D) + words[(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) + words[(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) + words[(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) + words[(int) (*pp++)] + *pc++;
+ temp = rotl32(temp, ps[i & 3]);
+ temp += B;
+ A = D;
+ D = C;
+ C = B;
+ B = temp;
+ }
+# endif
+ /* Add checksum to the starting values */
+ ctx->hash[0] += A;
+ ctx->hash[1] += B;
+ ctx->hash[2] += C;
+ ctx->hash[3] += D;
+
+#else /* MD5_SMALL == 0 or 1 */
+
+ uint32_t A_save = A;
+ uint32_t B_save = B;
+ uint32_t C_save = C;
+ uint32_t D_save = D;
+# if MD5_SMALL == 1
+ const uint32_t *pc;
+ const char *pp;
+ int i;
+# endif
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithm's 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 save swapped words in WORDS array. */
+# undef OP
+# define OP(a, b, c, d, s, T) \
+ do { \
+ a += FF(b, c, d) + (*words IF_BIG_ENDIAN(= SWAP_LE32(*words))) + T; \
+ words++; \
+ a = rotl32(a, s); \
+ a += b; \
+ } while (0)
+
+ /* Round 1 */
+# if MD5_SMALL == 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
+ words -= 16;
+
+ /* For the second to fourth round we have the possibly swapped words
+ in 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) + words[k] + T; \
+ a = rotl32(a, s); \
+ a += b; \
+ } while (0)
+
+ /* Round 2 */
+# if MD5_SMALL == 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
+
+ /* Round 3 */
+# if MD5_SMALL == 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
+
+ /* Round 4 */
+# if MD5_SMALL == 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);
+# undef OP
+# endif
+ /* Add checksum to the starting values */
+ ctx->hash[0] = A_save + A;
+ ctx->hash[1] = B_save + B;
+ ctx->hash[2] = C_save + C;
+ ctx->hash[3] = D_save + D;
+#endif
+}
+#undef FF
+#undef FG
+#undef FH
+#undef FI
+
+/* Initialize structure containing state of computation.
+ * (RFC 1321, 3.3: Step 3)
+ */
+void FAST_FUNC md5_begin(md5_ctx_t *ctx)
+{
+ ctx->hash[0] = 0x67452301;
+ ctx->hash[1] = 0xefcdab89;
+ ctx->hash[2] = 0x98badcfe;
+ ctx->hash[3] = 0x10325476;
+ ctx->total64 = 0;
+ ctx->process_block = md5_process_block64;
+}
+
+/* Used also for sha1 and sha256 */
+void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len)
+{
+ common64_hash(ctx, buffer, len);
+}
+
+/* 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.
+ */
+void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf)
+{
+ /* MD5 stores total in LE, need to swap on BE arches: */
+ common64_end(ctx, /*swap_needed:*/ BB_BIG_ENDIAN);
+
+ /* The MD5 result is in little endian byte order */
+ if (BB_BIG_ENDIAN) {
+ ctx->hash[0] = SWAP_LE32(ctx->hash[0]);
+ ctx->hash[1] = SWAP_LE32(ctx->hash[1]);
+ ctx->hash[2] = SWAP_LE32(ctx->hash[2]);
+ ctx->hash[3] = SWAP_LE32(ctx->hash[3]);
+ }
+
+ memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * 4);
+}
+
+
+/*
+ * SHA1 part is:
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * Based on the public domain SHA-1 in C by Steve Reid <steve@edmweb.com>
+ * from http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * SHA256 and SHA512 parts are:
+ * Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>.
+ * Shrank by Denys Vlasenko.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * The best way to test random blocksizes is to go to coreutils/md5_sha1_sum.c
+ * and replace "4096" with something like "2000 + time(NULL) % 2097",
+ * then rebuild and compare "shaNNNsum bigfile" results.
+ */
+
+static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx)
+{
+ static const uint32_t rconsts[] = {
+ 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
+ };
+ int i, j;
+ int cnt;
+ uint32_t W[16+16];
+ uint32_t a, b, c, d, e;
+
+ /* On-stack work buffer frees up one register in the main loop
+ * which otherwise will be needed to hold ctx pointer */
+ for (i = 0; i < 16; i++)
+ W[i] = W[i+16] = SWAP_BE32(((uint32_t*)ctx->wbuffer)[i]);
+
+ a = ctx->hash[0];
+ b = ctx->hash[1];
+ c = ctx->hash[2];
+ d = ctx->hash[3];
+ e = ctx->hash[4];
+
+ /* 4 rounds of 20 operations each */
+ cnt = 0;
+ for (i = 0; i < 4; i++) {
+ j = 19;
+ do {
+ uint32_t work;
+
+ work = c ^ d;
+ if (i == 0) {
+ work = (work & b) ^ d;
+ if (j <= 3)
+ goto ge16;
+ /* Used to do SWAP_BE32 here, but this
+ * requires ctx (see comment above) */
+ work += W[cnt];
+ } else {
+ if (i == 2)
+ work = ((b | c) & d) | (b & c);
+ else /* i = 1 or 3 */
+ work ^= b;
+ ge16:
+ W[cnt] = W[cnt+16] = rotl32(W[cnt+13] ^ W[cnt+8] ^ W[cnt+2] ^ W[cnt], 1);
+ work += W[cnt];
+ }
+ work += e + rotl32(a, 5) + rconsts[i];
+
+ /* Rotate by one for next time */
+ e = d;
+ d = c;
+ c = /* b = */ rotl32(b, 30);
+ b = a;
+ a = work;
+ cnt = (cnt + 1) & 15;
+ } while (--j >= 0);
+ }
+
+ 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
+};
+
+#undef Ch
+#undef Maj
+#undef S0
+#undef S1
+#undef R0
+#undef R1
+
+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] = SWAP_BE32(words[t]);
+ 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] = SWAP_BE64(words[t]);
+ 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[] = {
+ 0,
+ 0,
+ 0x6a09e667,
+ 0xbb67ae85,
+ 0x3c6ef372,
+ 0xa54ff53a,
+ 0x510e527f,
+ 0x9b05688c,
+ 0x1f83d9ab,
+ 0x5be0cd19,
+};
+static const uint32_t init512_lo[] = {
+ 0,
+ 0,
+ 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->total64, init256, sizeof(init256));
+ /*ctx->total64 = 0; - done by prepending two 32-bit zeros to init256 */
+ 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;
+ /* Two extra iterations zero out ctx->total64[2] */
+ uint64_t *tp = ctx->total64;
+ for (i = 0; i < 2+8; i++)
+ tp[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i];
+ /*ctx->total64[0] = ctx->total64[1] = 0; - already done */
+}
+
+void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len)
+{
+ unsigned bufpos = ctx->total64[0] & 127;
+ unsigned remaining;
+
+ /* 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]++;
+#if 0
+ remaining = 128 - bufpos;
+
+ /* Hash whole blocks */
+ while (len >= remaining) {
+ memcpy(ctx->wbuffer + bufpos, buffer, remaining);
+ buffer = (const char *)buffer + remaining;
+ len -= remaining;
+ remaining = 128;
+ bufpos = 0;
+ sha512_process_block128(ctx);
+ }
+
+ /* Save last, partial blosk */
+ memcpy(ctx->wbuffer + bufpos, buffer, len);
+#else
+ while (1) {
+ remaining = 128 - bufpos;
+ if (remaining > len)
+ remaining = len;
+ /* Copy data into aligned buffer */
+ memcpy(ctx->wbuffer + bufpos, buffer, remaining);
+ len -= remaining;
+ buffer = (const char *)buffer + remaining;
+ bufpos += remaining;
+ /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */
+ bufpos -= 128;
+ if (bufpos != 0)
+ break;
+ /* Buffer is filled up, process it */
+ sha512_process_block128(ctx);
+ /*bufpos = 0; - already is */
+ }
+#endif
+}
+
+/* Used also for sha256 */
+void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf)
+{
+ unsigned hash_size;
+
+ /* SHA stores total in BE, need to swap on LE arches: */
+ common64_end(ctx, /*swap_needed:*/ BB_LITTLE_ENDIAN);
+
+ hash_size = (ctx->process_block == sha1_process_block64) ? 5 : 8;
+ /* This way we do not impose alignment constraints on resbuf: */
+ if (BB_LITTLE_ENDIAN) {
+ unsigned i;
+ for (i = 0; i < hash_size; ++i)
+ ctx->hash[i] = SWAP_BE32(ctx->hash[i]);
+ }
+ memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * hash_size);
+}
+
+void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
+{
+ unsigned bufpos = ctx->total64[0] & 127;
+
+ /* Pad the buffer to the next 128-byte boundary with 0x80,0,0,0... */
+ ctx->wbuffer[bufpos++] = 0x80;
+
+ while (1) {
+ unsigned remaining = 128 - bufpos;
+ memset(ctx->wbuffer + bufpos, 0, remaining);
+ if (remaining >= 16) {
+ /* Store the 128-bit counter of bits in the buffer in BE format */
+ uint64_t t;
+ t = ctx->total64[0] << 3;
+ t = SWAP_BE64(t);
+ *(uint64_t *) (&ctx->wbuffer[128 - 8]) = t;
+ t = (ctx->total64[1] << 3) | (ctx->total64[0] >> 61);
+ t = SWAP_BE64(t);
+ *(uint64_t *) (&ctx->wbuffer[128 - 16]) = t;
+ }
+ sha512_process_block128(ctx);
+ if (remaining >= 16)
+ break;
+ bufpos = 0;
+ }
+
+ if (BB_LITTLE_ENDIAN) {
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i)
+ ctx->hash[i] = SWAP_BE64(ctx->hash[i]);
+ }
+ memcpy(resbuf, ctx->hash, sizeof(ctx->hash));
+}
+
+
+/*
+ * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
+ * Michael Peeters and Gilles Van Assche. For more information, feedback or
+ * questions, please refer to our website: http://keccak.noekeon.org/
+ *
+ * Implementation by Ronny Van Keer,
+ * hereby denoted as "the implementer".
+ *
+ * To the extent possible under law, the implementer has waived all copyright
+ * and related or neighboring rights to the source code in this file.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Busybox modifications (C) Lauri Kasanen, under the GPLv2.
+ */
+
+#if CONFIG_SHA3_SMALL < 0
+# define SHA3_SMALL 0
+#elif CONFIG_SHA3_SMALL > 1
+# define SHA3_SMALL 1
+#else
+# define SHA3_SMALL CONFIG_SHA3_SMALL
+#endif
+
+enum {
+ SHA3_IBLK_BYTES = 72, /* 576 bits / 8 */
+};
+
+/*
+ * In the crypto literature this function is usually called Keccak-f().
+ */
+static void sha3_process_block72(uint64_t *state)
+{
+ enum { NROUNDS = 24 };
+
+ /* Elements should be 64-bit, but top half is always zero or 0x80000000.
+ * We encode 63rd bits in a separate word below.
+ * Same is true for 31th bits, which lets us use 16-bit table instead of 64-bit.
+ * The speed penalty is lost in the noise.
+ */
+ static const uint16_t IOTA_CONST[NROUNDS] = {
+ 0x0001,
+ 0x8082,
+ 0x808a,
+ 0x8000,
+ 0x808b,
+ 0x0001,
+ 0x8081,
+ 0x8009,
+ 0x008a,
+ 0x0088,
+ 0x8009,
+ 0x000a,
+ 0x808b,
+ 0x008b,
+ 0x8089,
+ 0x8003,
+ 0x8002,
+ 0x0080,
+ 0x800a,
+ 0x000a,
+ 0x8081,
+ 0x8080,
+ 0x0001,
+ 0x8008,
+ };
+ /* bit for CONST[0] is in msb: 0011 0011 0000 0111 1101 1101 */
+ const uint32_t IOTA_CONST_bit63 = (uint32_t)(0x3307dd00);
+ /* bit for CONST[0] is in msb: 0001 0110 0011 1000 0001 1011 */
+ const uint32_t IOTA_CONST_bit31 = (uint32_t)(0x16381b00);
+
+ static const uint8_t ROT_CONST[24] = {
+ 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
+ 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
+ };
+ static const uint8_t PI_LANE[24] = {
+ 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
+ 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
+ };
+ /*static const uint8_t MOD5[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/
+
+ unsigned x, y;
+ unsigned round;
+
+ if (BB_BIG_ENDIAN) {
+ for (x = 0; x < 25; x++) {
+ state[x] = SWAP_LE64(state[x]);
+ }
+ }
+
+ for (round = 0; round < NROUNDS; ++round) {
+ /* Theta */
+ {
+ uint64_t BC[10];
+ for (x = 0; x < 5; ++x) {
+ BC[x + 5] = BC[x] = state[x]
+ ^ state[x + 5] ^ state[x + 10]
+ ^ state[x + 15] ^ state[x + 20];
+ }
+ /* Using 2x5 vector above eliminates the need to use
+ * BC[MOD5[x+N]] trick below to fetch BC[(x+N) % 5],
+ * and the code is a bit _smaller_.
+ */
+ for (x = 0; x < 5; ++x) {
+ uint64_t temp = BC[x + 4] ^ rotl64(BC[x + 1], 1);
+ state[x] ^= temp;
+ state[x + 5] ^= temp;
+ state[x + 10] ^= temp;
+ state[x + 15] ^= temp;
+ state[x + 20] ^= temp;
+ }
+ }
+
+ /* Rho Pi */
+ if (SHA3_SMALL) {
+ uint64_t t1 = state[1];
+ for (x = 0; x < 24; ++x) {
+ uint64_t t0 = state[PI_LANE[x]];
+ state[PI_LANE[x]] = rotl64(t1, ROT_CONST[x]);
+ t1 = t0;
+ }
+ } else {
+ /* Especially large benefit for 32-bit arch (75% faster):
+ * 64-bit rotations by non-constant usually are SLOW on those.
+ * We resort to unrolling here.
+ * This optimizes out PI_LANE[] and ROT_CONST[],
+ * but generates 300-500 more bytes of code.
+ */
+ uint64_t t0;
+ uint64_t t1 = state[1];
+#define RhoPi_twice(x) \
+ t0 = state[PI_LANE[x ]]; \
+ state[PI_LANE[x ]] = rotl64(t1, ROT_CONST[x ]); \
+ t1 = state[PI_LANE[x+1]]; \
+ state[PI_LANE[x+1]] = rotl64(t0, ROT_CONST[x+1]);
+ RhoPi_twice(0); RhoPi_twice(2);
+ RhoPi_twice(4); RhoPi_twice(6);
+ RhoPi_twice(8); RhoPi_twice(10);
+ RhoPi_twice(12); RhoPi_twice(14);
+ RhoPi_twice(16); RhoPi_twice(18);
+ RhoPi_twice(20); RhoPi_twice(22);
+#undef RhoPi_twice
+ }
+
+ /* Chi */
+ for (y = 0; y <= 20; y += 5) {
+ uint64_t BC0, BC1, BC2, BC3, BC4;
+ BC0 = state[y + 0];
+ BC1 = state[y + 1];
+ BC2 = state[y + 2];
+ state[y + 0] = BC0 ^ ((~BC1) & BC2);
+ BC3 = state[y + 3];
+ state[y + 1] = BC1 ^ ((~BC2) & BC3);
+ BC4 = state[y + 4];
+ state[y + 2] = BC2 ^ ((~BC3) & BC4);
+ state[y + 3] = BC3 ^ ((~BC4) & BC0);
+ state[y + 4] = BC4 ^ ((~BC0) & BC1);
+ }
+
+ /* Iota */
+ state[0] ^= IOTA_CONST[round]
+ | (uint32_t)((IOTA_CONST_bit31 << round) & 0x80000000)
+ | (uint64_t)((IOTA_CONST_bit63 << round) & 0x80000000) << 32;
+ }
+
+ if (BB_BIG_ENDIAN) {
+ for (x = 0; x < 25; x++) {
+ state[x] = SWAP_LE64(state[x]);
+ }
+ }
+}
+
+void FAST_FUNC sha3_begin(sha3_ctx_t *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len)
+{
+#if SHA3_SMALL
+ const uint8_t *data = buffer;
+ unsigned bufpos = ctx->bytes_queued;
+
+ while (1) {
+ unsigned remaining = SHA3_IBLK_BYTES - bufpos;
+ if (remaining > len)
+ remaining = len;
+ len -= remaining;
+ /* XOR data into buffer */
+ while (remaining != 0) {
+ uint8_t *buf = (uint8_t*)ctx->state;
+ buf[bufpos] ^= *data++;
+ bufpos++;
+ remaining--;
+ }
+ /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */
+ bufpos -= SHA3_IBLK_BYTES;
+ if (bufpos != 0)
+ break;
+ /* Buffer is filled up, process it */
+ sha3_process_block72(ctx->state);
+ /*bufpos = 0; - already is */
+ }
+ ctx->bytes_queued = bufpos + SHA3_IBLK_BYTES;
+#else
+ /* +50 bytes code size, but a bit faster because of long-sized XORs */
+ const uint8_t *data = buffer;
+ unsigned bufpos = ctx->bytes_queued;
+
+ /* If already data in queue, continue queuing first */
+ while (len != 0 && bufpos != 0) {
+ uint8_t *buf = (uint8_t*)ctx->state;
+ buf[bufpos] ^= *data++;
+ len--;
+ bufpos++;
+ if (bufpos == SHA3_IBLK_BYTES) {
+ bufpos = 0;
+ goto do_block;
+ }
+ }
+
+ /* Absorb complete blocks */
+ while (len >= SHA3_IBLK_BYTES) {
+ /* XOR data onto beginning of state[].
+ * We try to be efficient - operate one word at a time, not byte.
+ * Careful wrt unaligned access: can't just use "*(long*)data"!
+ */
+ unsigned count = SHA3_IBLK_BYTES / sizeof(long);
+ long *buf = (long*)ctx->state;
+ do {
+ long v;
+ move_from_unaligned_long(v, (long*)data);
+ *buf++ ^= v;
+ data += sizeof(long);
+ } while (--count);
+ len -= SHA3_IBLK_BYTES;
+ do_block:
+ sha3_process_block72(ctx->state);
+ }
+
+ /* Queue remaining data bytes */
+ while (len != 0) {
+ uint8_t *buf = (uint8_t*)ctx->state;
+ buf[bufpos] ^= *data++;
+ bufpos++;
+ len--;
+ }
+
+ ctx->bytes_queued = bufpos;
+#endif
+}
+
+void FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf)
+{
+ /* Padding */
+ uint8_t *buf = (uint8_t*)ctx->state;
+ buf[ctx->bytes_queued] ^= 1;
+ buf[SHA3_IBLK_BYTES - 1] ^= 0x80;
+
+ sha3_process_block72(ctx->state);
+
+ /* Output */
+ memcpy(resbuf, ctx->state, 64);
+}
diff --git a/ap/app/busybox/src/libbb/hash_md5prime.c b/ap/app/busybox/src/libbb/hash_md5prime.c
new file mode 100644
index 0000000..e089a15
--- /dev/null
+++ b/ap/app/busybox/src/libbb/hash_md5prime.c
@@ -0,0 +1,460 @@
+/* This file is not used by busybox right now.
+ * However, the code here seems to be a tiny bit smaller
+ * than one in md5.c. Need to investigate which one
+ * is better overall...
+ * Hint: grep for md5prime to find places where you can switch
+ * md5.c/md5prime.c
+ */
+
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
+ *
+ * This code is the same as the code published by RSA Inc. It has been
+ * edited for clarity and style only.
+ *
+ * ----------------------------------------------------------------------------
+ * The md5_crypt() function was taken from freeBSD's libcrypt and contains
+ * this license:
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ *
+ * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
+ *
+ * ----------------------------------------------------------------------------
+ * On April 19th, 2001 md5_crypt() was modified to make it reentrant
+ * by Erik Andersen <andersen@uclibc.org>
+ *
+ * June 28, 2001 Manuel Novoa III
+ *
+ * "Un-inlined" code using loops and static const tables in order to
+ * reduce generated code size (on i386 from approx 4k to approx 2.5k).
+ *
+ * June 29, 2001 Manuel Novoa III
+ *
+ * Completely removed static PADDING array.
+ *
+ * Reintroduced the loop unrolling in md5_transform and added the
+ * MD5_SMALL 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_SMALL < 1
+# define MD5_SMALL 1
+#elif CONFIG_MD5_SMALL > 3
+# define MD5_SMALL 3
+#else
+# define MD5_SMALL CONFIG_MD5_SMALL
+#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_SMALL > 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_SMALL > 1 */
+
+#if MD5_SMALL > 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_SMALL > 0 */
+
+ memcpy32_le2cpu(x, block, 64);
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+#if MD5_SMALL > 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_SMALL > 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_SMALL > 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/ap/app/busybox/src/libbb/herror_msg.c b/ap/app/busybox/src/libbb/herror_msg.c
new file mode 100644
index 0000000..d041076
--- /dev/null
+++ b/ap/app/busybox/src/libbb/herror_msg.c
@@ -0,0 +1,28 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+void FAST_FUNC bb_herror_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p, hstrerror(h_errno));
+ va_end(p);
+}
+
+void FAST_FUNC bb_herror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p, hstrerror(h_errno));
+ va_end(p);
+ xfunc_die();
+}
diff --git a/ap/app/busybox/src/libbb/human_readable.c b/ap/app/busybox/src/libbb/human_readable.c
new file mode 100644
index 0000000..8b22b0c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/human_readable.c
@@ -0,0 +1,197 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * June 30, 2001 Manuel Novoa III
+ *
+ * All-integer version (hey, not everyone has floating point) of
+ * make_human_readable_str, modified from similar code I had written
+ * for busybox several months ago.
+ *
+ * Notes:
+ * 1) I'm using an unsigned long long to hold the product size * block_size,
+ * as df (which calls this routine) could request a representation of a
+ * partition size in bytes > max of unsigned long. If long longs aren't
+ * available, it would be possible to do what's needed using polynomial
+ * representations (say, powers of 1024) and manipulating coefficients.
+ * The base ten "bytes" output could be handled similarly.
+ *
+ * 2) This routine always outputs a decimal point and a tenths digit when
+ * display_unit != 0. Hence, it isn't uncommon for the returned string
+ * to have a length of 5 or 6.
+ *
+ * It might be nice to add a flag to indicate no decimal digits in
+ * that case. This could be either an additional parameter, or a
+ * special value of display_unit. Such a flag would also be nice for du.
+ *
+ * Some code to omit the decimal point and tenths digit is sketched out
+ * and "#if 0"'d below.
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+const char* FAST_FUNC make_human_readable_str(unsigned long long val,
+ unsigned long block_size, unsigned long display_unit)
+{
+ static const char unit_chars[] ALIGN1 = {
+ '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'
+ };
+
+ static char *str;
+
+ unsigned frac; /* 0..9 - the fractional digit */
+ const char *u;
+ const char *fmt;
+
+ if (val == 0)
+ return "0";
+
+ fmt = "%llu";
+ if (block_size > 1)
+ val *= block_size;
+ frac = 0;
+ u = unit_chars;
+
+ if (display_unit) {
+ 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 {
+ while ((val >= 1024)
+ /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */
+ ) {
+ fmt = "%llu.%u%c";
+ u++;
+ frac = (((unsigned)val % 1024) * 10 + 1024/2) / 1024;
+ val /= 1024;
+ }
+ if (frac >= 10) { /* we need to round up here */
+ ++val;
+ frac = 0;
+ }
+#if 1
+ /* If block_size is 0, dont print fractional part */
+ if (block_size == 0) {
+ if (frac >= 5) {
+ ++val;
+ }
+ fmt = "%llu%*c";
+ frac = 1;
+ }
+#endif
+ }
+
+ if (!str) {
+ /* sufficient for any width of val */
+ str = xmalloc(sizeof(val)*3 + 2 + 3);
+ }
+ sprintf(str, fmt, val, frac, *u);
+ return str;
+}
+
+
+/* vda's implementations of the similar idea */
+
+/* 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[5], const char *scale)
+{
+ 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
+
+ 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..." */
+ }
+}
+
+/* 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[4], const char *scale)
+{
+ 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
+
+ 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..." */
+ }
+}
diff --git a/ap/app/busybox/src/libbb/inet_cksum.c b/ap/app/busybox/src/libbb/inet_cksum.c
new file mode 100644
index 0000000..3d5dc3a
--- /dev/null
+++ b/ap/app/busybox/src/libbb/inet_cksum.c
@@ -0,0 +1,36 @@
+/*
+ * Checksum routine for Internet Protocol family headers (C Version)
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft)
+{
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator,
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ unsigned sum = 0;
+ while (nleft > 1) {
+ sum += *addr++;
+ nleft -= 2;
+ }
+
+ /* Mop up an odd byte, if necessary */
+ if (nleft == 1) {
+ if (BB_LITTLE_ENDIAN)
+ sum += *(uint8_t*)addr;
+ else
+ sum += *(uint8_t*)addr << 8;
+ }
+
+ /* Add back carry outs from top 16 bits to low 16 bits */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+
+ return (uint16_t)~sum;
+}
diff --git a/ap/app/busybox/src/libbb/inet_common.c b/ap/app/busybox/src/libbb/inet_common.c
new file mode 100644
index 0000000..0f4fca1
--- /dev/null
+++ b/ap/app/busybox/src/libbb/inet_common.c
@@ -0,0 +1,224 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * stolen from net-tools-1.59 and stripped down for busybox by
+ * Erik Andersen <andersen@codepoet.org>
+ *
+ * Heavily modified by Manuel Novoa III Mar 12, 2001
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#include "inet_common.h"
+
+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, "default") == 0) {
+ s_in->sin_addr.s_addr = INADDR_ANY;
+ return 1;
+ }
+ /* Look to see if it's a dotted quad. */
+ if (inet_aton(name, &s_in->sin_addr)) {
+ return 0;
+ }
+ /* If we expect this to be a hostname, try hostname database first */
+#ifdef DEBUG
+ if (hostfirst) {
+ bb_error_msg("gethostbyname(%s)", name);
+ }
+#endif
+ if (hostfirst) {
+ hp = gethostbyname(name);
+ 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);
+#endif
+ 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 */
+ return -1;
+ }
+#ifdef DEBUG
+ res_init();
+ _res.options |= RES_DEBUG;
+ bb_error_msg("gethostbyname(%s)", name);
+#endif
+ hp = gethostbyname(name);
+ if (hp == NULL) {
+ return -1;
+ }
+ memcpy(&s_in->sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
+ return 0;
+}
+
+
+/* numeric: & 0x8000: default instead of *,
+ * & 0x4000: host instead of net,
+ * & 0x0fff: don't resolve
+ */
+char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask)
+{
+ /* 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;
+ char *name;
+ uint32_t ad, host_ad;
+ int host = 0;
+
+ if (s_in->sin_family != AF_INET) {
+#ifdef DEBUG
+ bb_error_msg("rresolve: unsupported address family %d!",
+ s_in->sin_family);
+#endif
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+ ad = s_in->sin_addr.s_addr;
+#ifdef DEBUG
+ 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)
+ return xstrdup("default");
+ return xstrdup("*");
+ }
+ }
+ if (numeric & 0x0FFF)
+ return xstrdup(inet_ntoa(s_in->sin_addr));
+
+ if ((ad & (~netmask)) != 0 || (numeric & 0x4000))
+ host = 1;
+ pn = cache;
+ while (pn) {
+ if (pn->addr.sin_addr.s_addr == ad && pn->host == host) {
+#ifdef DEBUG
+ bb_error_msg("rresolve: found %s %08x in cache",
+ (host ? "host" : "net"), (unsigned)ad);
+#endif
+ return xstrdup(pn->name);
+ }
+ pn = pn->next;
+ }
+
+ host_ad = ntohl(ad);
+ name = NULL;
+ if (host) {
+ struct hostent *ent;
+#ifdef DEBUG
+ bb_error_msg("gethostbyaddr (%08x)", (unsigned)ad);
+#endif
+ ent = gethostbyaddr((char *) &ad, 4, AF_INET);
+ if (ent)
+ name = xstrdup(ent->h_name);
+ } else if (ENABLE_FEATURE_ETC_NETWORKS) {
+ struct netent *np;
+#ifdef DEBUG
+ bb_error_msg("getnetbyaddr (%08x)", (unsigned)host_ad);
+#endif
+ np = getnetbyaddr(host_ad, AF_INET);
+ if (np)
+ name = xstrdup(np->n_name);
+ }
+ 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->host = host;
+ strcpy(pn->name, name);
+ cache = pn;
+ return name;
+}
+
+#if ENABLE_FEATURE_IPV6
+
+int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6)
+{
+ struct addrinfo req, *ai = NULL;
+ int s;
+
+ memset(&req, 0, sizeof(req));
+ req.ai_family = AF_INET6;
+ s = getaddrinfo(name, NULL, &req, &ai);
+ if (s != 0) {
+ bb_error_msg("getaddrinfo: %s: %d", name, s);
+ return -1;
+ }
+ memcpy(sin6, ai->ai_addr, sizeof(*sin6));
+ if (ai)
+ freeaddrinfo(ai);
+ return 0;
+}
+
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+# define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \
+ ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0)
+#endif
+
+
+char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric)
+{
+ char name[128];
+ int s;
+
+ if (sin6->sin6_family != AF_INET6) {
+#ifdef DEBUG
+ bb_error_msg("rresolve: unsupported address family %d!",
+ sin6->sin6_family);
+#endif
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+ if (numeric & 0x7FFF) {
+ inet_ntop(AF_INET6, &sin6->sin6_addr, name, sizeof(name));
+ return xstrdup(name);
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ if (numeric & 0x8000)
+ return xstrdup("default");
+ return xstrdup("*");
+ }
+
+ s = getnameinfo((struct sockaddr *) sin6, sizeof(*sin6),
+ name, sizeof(name),
+ /*serv,servlen:*/ NULL, 0,
+ 0);
+ if (s != 0) {
+ bb_error_msg("getnameinfo failed");
+ return NULL;
+ }
+ return xstrdup(name);
+}
+
+#endif /* CONFIG_FEATURE_IPV6 */
diff --git a/ap/app/busybox/src/libbb/info_msg.c b/ap/app/busybox/src/libbb/info_msg.c
new file mode 100644
index 0000000..56ca2ef
--- /dev/null
+++ b/ap/app/busybox/src/libbb/info_msg.c
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+#if ENABLE_FEATURE_SYSLOG
+# include <syslog.h>
+#endif
+
+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
+ if (logmode & LOGMODE_SYSLOG)
+ vsyslog(LOG_INFO, s, p2);
+# endif
+ 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);
+ va_end(p);
+ if (used < 0)
+ return;
+
+# if ENABLE_FEATURE_SYSLOG
+ if (logmode & LOGMODE_SYSLOG)
+ syslog(LOG_INFO, "%s", msg);
+# endif
+ if (logmode & LOGMODE_STDIO) {
+ fflush_all();
+ /* used = strlen(msg); - must be true already */
+ msg[used++] = '\n';
+ full_write(STDOUT_FILENO, msg, used);
+ }
+
+ free(msg);
+#endif
+}
diff --git a/ap/app/busybox/src/libbb/inode_hash.c b/ap/app/busybox/src/libbb/inode_hash.c
new file mode 100644
index 0000000..715535e
--- /dev/null
+++ b/ap/app/busybox/src/libbb/inode_hash.c
@@ -0,0 +1,87 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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)
+
+/* array of [HASH_SIZE] elements */
+static ino_dev_hashtable_bucket_t **ino_dev_hashtable;
+
+/*
+ * Return name if statbuf->st_ino && statbuf->st_dev are recorded in
+ * ino_dev_hashtable, else return NULL
+ */
+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)
+ ) {
+ return bucket->name;
+ }
+ bucket = bucket->next;
+ }
+ return NULL;
+}
+
+/* Add statbuf to statbuf hash table */
+void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
+{
+ int i;
+ ino_dev_hashtable_bucket_t *bucket;
+
+ i = hash_inode(statbuf->st_ino);
+ if (!name)
+ name = "";
+ bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name));
+ bucket->ino = statbuf->st_ino;
+ bucket->dev = statbuf->st_dev;
+ 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 FAST_FUNC reset_ino_dev_hashtable(void)
+{
+ int i;
+ ino_dev_hashtable_bucket_t *bucket;
+
+ 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;
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/isdirectory.c b/ap/app/busybox/src/libbb/isdirectory.c
new file mode 100644
index 0000000..ba6c52c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/isdirectory.c
@@ -0,0 +1,31 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under GPL.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include <sys/stat.h>
+#include "libbb.h"
+
+/*
+ * Return TRUE if fileName is a directory.
+ * Nonexistent files return FALSE.
+ */
+int FAST_FUNC is_directory(const char *fileName, int followLinks)
+{
+ int status;
+ struct stat statBuf;
+
+ if (followLinks)
+ status = stat(fileName, &statBuf);
+ else
+ status = lstat(fileName, &statBuf);
+
+ status = (status == 0 && S_ISDIR(statBuf.st_mode));
+
+ return status;
+}
diff --git a/ap/app/busybox/src/libbb/kernel_version.c b/ap/app/busybox/src/libbb/kernel_version.c
new file mode 100644
index 0000000..738ed02
--- /dev/null
+++ b/ap/app/busybox/src/libbb/kernel_version.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+/* After libbb.h, since it needs sys/types.h on some systems */
+#include <sys/utsname.h> /* for uname(2) */
+
+
+/* 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_linux_version_code() > KERNEL_VERSION(2,2,11)) { <stuff> }
+ */
+int FAST_FUNC get_linux_version_code(void)
+{
+ struct utsname name;
+ char *s, *t;
+ int i, r;
+
+ uname(&name); /* never fails */
+ s = name.release;
+ r = 0;
+ for (i = 0; i < 3; i++) {
+ t = strtok(s, ".");
+ r = r * 256 + (t ? atoi(t) : 0);
+ s = NULL;
+ }
+ return r;
+}
diff --git a/ap/app/busybox/src/libbb/last_char_is.c b/ap/app/busybox/src/libbb/last_char_is.c
new file mode 100644
index 0000000..65e6cdf
--- /dev/null
+++ b/ap/app/busybox/src/libbb/last_char_is.c
@@ -0,0 +1,24 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * busybox library eXtended function
+ *
+ * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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.
+ */
+char* FAST_FUNC last_char_is(const char *s, int c)
+{
+ if (s && *s) {
+ size_t sz = strlen(s) - 1;
+ s += sz;
+ if ( (unsigned char)*s == c)
+ return (char*)s;
+ }
+ return NULL;
+}
diff --git a/ap/app/busybox/src/libbb/lineedit.c b/ap/app/busybox/src/libbb/lineedit.c
new file mode 100755
index 0000000..61fe006
--- /dev/null
+++ b/ap/app/busybox/src/libbb/lineedit.c
@@ -0,0 +1,2787 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Command line editing.
+ *
+ * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
+ * Written by: Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Used ideas:
+ * Adam Rogoyski <rogoyski@cs.utexas.edu>
+ * Dave Cinege <dcinege@psychosis.com>
+ * Jakub Jelinek (c) 1995
+ * Erik Andersen <andersen@codepoet.org> (Majorly adjusted for busybox)
+ *
+ * This code is 'as is' with no warranty.
+ */
+
+/*
+ * Usage and known bugs:
+ * Terminal key codes are not extensive, more needs 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.
+ *
+ * The following readline-like commands are not implemented:
+ * ESC-b -- Move back one word
+ * ESC-f -- Move forward one word
+ * ESC-d -- Delete forward one word
+ * CTL-t -- Transpose two characters
+ *
+ * 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"
+#include "unicode.h"
+#ifndef _POSIX_VDISABLE
+# define _POSIX_VDISABLE '\0'
+#endif
+
+
+#ifdef TEST
+# define ENABLE_FEATURE_EDITING 0
+# define ENABLE_FEATURE_TAB_COMPLETION 0
+# define ENABLE_FEATURE_USERNAME_COMPLETION 0
+#endif
+
+
+/* Entire file (except TESTing part) sits inside this #if */
+#if ENABLE_FEATURE_EDITING
+
+
+#define ENABLE_USERNAME_OR_HOMEDIR \
+ (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
+#define IF_USERNAME_OR_HOMEDIR(...)
+#if ENABLE_USERNAME_OR_HOMEDIR
+# undef IF_USERNAME_OR_HOMEDIR
+# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__
+#endif
+
+
+#undef CHAR_T
+#if ENABLE_UNICODE_SUPPORT
+# define BB_NUL ((wchar_t)0)
+# define CHAR_T wchar_t
+static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); }
+# if ENABLE_FEATURE_EDITING_VI
+static bool BB_isalnum(CHAR_T c) { return ((unsigned)c < 256 && isalnum(c)); }
+# endif
+static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
+# undef isspace
+# undef isalnum
+# undef ispunct
+# undef isprint
+# define isspace isspace_must_not_be_used
+# define isalnum isalnum_must_not_be_used
+# define ispunct ispunct_must_not_be_used
+# define isprint isprint_must_not_be_used
+#else
+# define BB_NUL '\0'
+# define CHAR_T char
+# define BB_isspace(c) isspace(c)
+# define BB_isalnum(c) isalnum(c)
+# define BB_ispunct(c) ispunct(c)
+#endif
+#if ENABLE_UNICODE_PRESERVE_BROKEN
+# define unicode_mark_raw_byte(wc) ((wc) | 0x20000000)
+# define unicode_is_raw_byte(wc) ((wc) & 0x20000000)
+#else
+# define unicode_is_raw_byte(wc) 0
+#endif
+
+
+#define ESC "\033"
+
+#define SEQ_CLEAR_TILL_END_OF_SCREEN ESC"[J"
+//#define SEQ_CLEAR_TILL_END_OF_LINE ESC"[K"
+
+
+enum {
+ MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
+ ? CONFIG_FEATURE_EDITING_MAX_LEN
+ : 0x7ff0
+};
+
+#if ENABLE_USERNAME_OR_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 (col) terminal position */
+ unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
+ unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
+
+ unsigned cursor;
+ int command_len; /* must be signed */
+ /* signed maxsize: we want x in "if (x > S.maxsize)"
+ * to _not_ be promoted to unsigned */
+ int maxsize;
+ CHAR_T *command_ps;
+
+ const char *cmdedit_prompt;
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ int num_ok_lines; /* = 1; */
+#endif
+
+#if ENABLE_USERNAME_OR_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_T *delptr;
+ smallint newdelflag; /* whether delbuf should be reused yet */
+ CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */
+#endif
+#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
+ smallint sent_ESC_br6n;
+#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; \
+ IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
+ IF_USERNAME_OR_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_USERNAME_OR_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()
+
+
+#if ENABLE_UNICODE_SUPPORT
+static size_t load_string(const char *src)
+{
+ if (unicode_status == UNICODE_ON) {
+ ssize_t len = mbstowcs(command_ps, src, S.maxsize - 1);
+ if (len < 0)
+ len = 0;
+ command_ps[len] = BB_NUL;
+ return len;
+ } else {
+ unsigned i = 0;
+ while (src[i] && i < S.maxsize - 1) {
+ command_ps[i] = src[i];
+ i++;
+ }
+ command_ps[i] = BB_NUL;
+ return i;
+ }
+}
+static unsigned save_string(char *dst, unsigned maxsize)
+{
+ if (unicode_status == UNICODE_ON) {
+# if !ENABLE_UNICODE_PRESERVE_BROKEN
+ ssize_t len = wcstombs(dst, command_ps, maxsize - 1);
+ if (len < 0)
+ len = 0;
+ dst[len] = '\0';
+ return len;
+# else
+ unsigned dstpos = 0;
+ unsigned srcpos = 0;
+
+ maxsize--;
+ while (dstpos < maxsize) {
+ wchar_t wc;
+ int n = srcpos;
+
+ /* Convert up to 1st invalid byte (or up to end) */
+ while ((wc = command_ps[srcpos]) != BB_NUL
+ && !unicode_is_raw_byte(wc)
+ ) {
+ srcpos++;
+ }
+ command_ps[srcpos] = BB_NUL;
+ n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos);
+ if (n < 0) /* should not happen */
+ break;
+ dstpos += n;
+ if (wc == BB_NUL) /* usually is */
+ break;
+
+ /* We do have invalid byte here! */
+ command_ps[srcpos] = wc; /* restore it */
+ srcpos++;
+ if (dstpos == maxsize)
+ break;
+ dst[dstpos++] = (char) wc;
+ }
+ dst[dstpos] = '\0';
+ return dstpos;
+# endif
+ } else {
+ unsigned i = 0;
+ while ((dst[i] = command_ps[i]) != 0)
+ i++;
+ return i;
+ }
+}
+/* I thought just fputwc(c, stdout) would work. But no... */
+static void BB_PUTCHAR(wchar_t c)
+{
+ if (unicode_status == UNICODE_ON) {
+ char buf[MB_CUR_MAX + 1];
+ mbstate_t mbst = { 0 };
+ ssize_t len = wcrtomb(buf, c, &mbst);
+ if (len > 0) {
+ buf[len] = '\0';
+ fputs(buf, stdout);
+ }
+ } else {
+ /* In this case, c is always one byte */
+ putchar(c);
+ }
+}
+# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
+static wchar_t adjust_width_and_validate_wc(unsigned *width_adj, wchar_t wc)
+# else
+static wchar_t adjust_width_and_validate_wc(wchar_t wc)
+# define adjust_width_and_validate_wc(width_adj, wc) \
+ ((*(width_adj))++, adjust_width_and_validate_wc(wc))
+# endif
+{
+ int w = 1;
+
+ if (unicode_status == UNICODE_ON) {
+ if (wc > CONFIG_LAST_SUPPORTED_WCHAR) {
+ /* note: also true for unicode_is_raw_byte(wc) */
+ goto subst;
+ }
+ w = wcwidth(wc);
+ if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0)
+ || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
+ || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
+ ) {
+ subst:
+ w = 1;
+ wc = CONFIG_SUBST_WCHAR;
+ }
+ }
+
+# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
+ *width_adj += w;
+#endif
+ return wc;
+}
+#else /* !UNICODE */
+static size_t load_string(const char *src)
+{
+ safe_strncpy(command_ps, src, S.maxsize);
+ return strlen(command_ps);
+}
+# if ENABLE_FEATURE_TAB_COMPLETION
+static void save_string(char *dst, unsigned maxsize)
+{
+ safe_strncpy(dst, command_ps, maxsize);
+}
+# endif
+# define BB_PUTCHAR(c) bb_putchar(c)
+/* Should never be called: */
+int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
+#endif
+
+
+/* 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
+static void put_cur_glyph_and_inc_cursor(void)
+{
+ CHAR_T c = command_ps[cursor];
+ unsigned width = 0;
+ int ofs_to_right;
+
+ if (c == BB_NUL) {
+ /* erase character after end of input string */
+ c = ' ';
+ } else {
+ /* advance cursor only if we aren't at the end yet */
+ cursor++;
+ if (unicode_status == UNICODE_ON) {
+ IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
+ c = adjust_width_and_validate_wc(&cmdedit_x, c);
+ IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
+ } else {
+ cmdedit_x++;
+ }
+ }
+
+ ofs_to_right = cmdedit_x - cmdedit_termw;
+ if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
+ /* c fits on this line */
+ BB_PUTCHAR(c);
+ }
+
+ if (ofs_to_right >= 0) {
+ /* we go to the next line */
+#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
+ /* VT-10x terminals don't wrap cursor to next line when last char
+ * on the line is printed - cursor stays "over" this char.
+ * Need to print _next_ char too (first one to appear on next line)
+ * to make cursor move down to next line.
+ */
+ /* Works ok only if cmdedit_termw is correct. */
+ c = command_ps[cursor];
+ if (c == BB_NUL)
+ c = ' ';
+ BB_PUTCHAR(c);
+ bb_putchar('\b');
+#endif
+ cmdedit_y++;
+ if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
+ width = 0;
+ } else { /* ofs_to_right > 0 */
+ /* wide char c didn't fit on prev line */
+ BB_PUTCHAR(c);
+ }
+ cmdedit_x = width;
+ }
+}
+
+/* Move to end of line (by printing all chars till the end) */
+static void put_till_end_and_adv_cursor(void)
+{
+ while (cursor < command_len)
+ put_cur_glyph_and_inc_cursor();
+}
+
+/* Go to the next line */
+static void goto_new_line(void)
+{
+ put_till_end_and_adv_cursor();
+ if (cmdedit_x != 0)
+ bb_putchar('\n');
+}
+
+static void beep(void)
+{
+ bb_putchar('\007');
+}
+
+static void put_prompt(void)
+{
+ unsigned w;
+
+ fputs(cmdedit_prompt, stdout);
+ fflush_all();
+ cursor = 0;
+ w = cmdedit_termw; /* read volatile var once */
+ cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
+ cmdedit_x = cmdedit_prmt_len % w;
+}
+
+/* Move back one character */
+/* (optimized for slow terminals) */
+static void input_backward(unsigned num)
+{
+ if (num > cursor)
+ num = cursor;
+ if (num == 0)
+ return;
+ cursor -= num;
+
+ if ((ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS)
+ && unicode_status == UNICODE_ON
+ ) {
+ /* correct NUM to be equal to _screen_ width */
+ int n = num;
+ num = 0;
+ while (--n >= 0)
+ adjust_width_and_validate_wc(&num, command_ps[cursor + n]);
+ if (num == 0)
+ return;
+ }
+
+ 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(ESC"[%uD", num);
+ return;
+ }
+
+ /* Need to go one or more lines up */
+ if (ENABLE_UNICODE_WIDE_WCHARS) {
+ /* With wide chars, it is hard to "backtrack"
+ * and reliably figure out where to put cursor.
+ * Example (<> is a wide char; # is an ordinary char, _ cursor):
+ * |prompt: <><> |
+ * |<><><><><><> |
+ * |_ |
+ * and user presses left arrow. num = 1, cmdedit_x = 0,
+ * We need to go up one line, and then - how do we know that
+ * we need to go *10* positions to the right? Because
+ * |prompt: <>#<>|
+ * |<><><>#<><><>|
+ * |_ |
+ * in this situation we need to go *11* positions to the right.
+ *
+ * A simpler thing to do is to redraw everything from the start
+ * up to new cursor position (which is already known):
+ */
+ unsigned sv_cursor;
+ /* go to 1st column; go up to first line */
+ printf("\r" ESC"[%uA", cmdedit_y);
+ cmdedit_y = 0;
+ sv_cursor = cursor;
+ put_prompt(); /* sets cursor to 0 */
+ while (cursor < sv_cursor)
+ put_cur_glyph_and_inc_cursor();
+ } else {
+ int lines_up;
+ unsigned width;
+ /* num = chars to go back from the beginning of current line: */
+ num -= cmdedit_x;
+ width = cmdedit_termw; /* read volatile var once */
+ /* num=1...w: one line up, w+1...2w: two, etc: */
+ lines_up = 1 + (num - 1) / width;
+ cmdedit_x = (width * cmdedit_y - num) % width;
+ cmdedit_y -= lines_up;
+ /* go to 1st column; go up */
+ printf("\r" ESC"[%uA", lines_up);
+ /* go to correct column.
+ * xterm, konsole, Linux VT interpret 0 as 1 below! wow.
+ * need to *make sure* we skip it if cmdedit_x == 0 */
+ if (cmdedit_x)
+ printf(ESC"[%uC", cmdedit_x);
+ }
+}
+
+/* draw prompt, editor line, and clear tail */
+static void redraw(int y, int back_cursor)
+{
+ if (y > 0) /* up y lines */
+ printf(ESC"[%uA", y);
+ bb_putchar('\r');
+ put_prompt();
+ put_till_end_and_adv_cursor();
+ printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
+ 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
+
+ memmove(command_ps + j, command_ps + j + 1,
+ /* (command_len + 1 [because of NUL]) - (j + 1)
+ * simplified into (command_len - j) */
+ (command_len - j) * sizeof(command_ps[0]));
+ command_len--;
+ put_till_end_and_adv_cursor();
+ /* Last char is still visible, erase it (and more) */
+ printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
+ 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) * sizeof(command_ps[0]));
+ memcpy(command_ps + cursor, delbuf, j * sizeof(command_ps[0]));
+ command_len += j;
+ put_till_end_and_adv_cursor();
+ 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)
+ put_cur_glyph_and_inc_cursor();
+}
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+
+//FIXME:
+//needs to be more clever: currently it thinks that "foo\ b<TAB>
+//matches the file named "foo bar", which is untrue.
+//Also, perhaps "foo b<TAB> needs to complete to "foo bar" <cursor>,
+//not "foo bar <cursor>...
+
+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)
+{
+ /*CVE-2017-16544 https://git.busybox.net/busybox/commit/?id=c3797d40a1c57352192c6106cc0f435e7d9c11e8*/
+ unsigned char *p = (unsigned char*)matched;
+ while (*p) {
+ /* ESC attack fix: drop any string with control chars */
+ if (*p < ' '
+ || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f)
+ || (ENABLE_UNICODE_SUPPORT && *p == 0x7f)
+ ) {
+ free(matched);
+ return;
+ }
+ p++;
+ }
+ matches = xrealloc_vector(matches, 4, num_matches);
+ matches[num_matches] = matched;
+ num_matches++;
+}
+
+# if ENABLE_FEATURE_USERNAME_COMPLETION
+/* Replace "~user/..." with "/homedir/...".
+ * The parameter is malloced, free it or return it
+ * unchanged if no user is matched.
+ */
+static char *username_path_completion(char *ud)
+{
+ struct passwd *entry;
+ char *tilde_name = ud;
+ char *home = NULL;
+
+ ud++; /* skip ~ */
+ if (*ud == '/') { /* "~/..." */
+ home = home_pwd_buf;
+ } else {
+ /* "~user/..." */
+ ud = strchr(ud, '/');
+ *ud = '\0'; /* "~user" */
+ entry = getpwnam(tilde_name + 1);
+ *ud = '/'; /* restore "~user/..." */
+ if (entry)
+ home = entry->pw_dir;
+ }
+ if (home) {
+ ud = concat_path_file(home, ud);
+ free(tilde_name);
+ tilde_name = ud;
+ }
+ return tilde_name;
+}
+
+/* ~use<tab> - find all users with this prefix.
+ * Return the length of the prefix used for matching.
+ */
+static NOINLINE unsigned complete_username(const char *ud)
+{
+ /* Using _r function to avoid pulling in static buffers */
+ char line_buff[256];
+ struct passwd pwd;
+ struct passwd *result;
+ unsigned userlen;
+
+ ud++; /* skip ~ */
+ userlen = strlen(ud);
+
+ 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();
+
+ return 1 + userlen;
+}
+# endif /* FEATURE_USERNAME_COMPLETION */
+
+enum {
+ FIND_EXE_ONLY = 0,
+ FIND_DIR_ONLY = 1,
+ FIND_FILE_ONLY = 2,
+};
+
+static int path_parse(char ***p)
+{
+ int npth;
+ const char *pth;
+ char *tmp;
+ char **res;
+
+ 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;
+ tmp++;
+ if (*tmp == '\0')
+ break; /* :<empty> */
+ npth++;
+ }
+
+ *p = res = xmalloc(npth * sizeof(res[0]));
+ res[0] = tmp = xstrdup(pth);
+ npth = 1;
+ while (1) {
+ tmp = strchr(tmp, ':');
+ if (!tmp)
+ break;
+ *tmp++ = '\0'; /* ':' -> '\0' */
+ if (*tmp == '\0')
+ break; /* :<empty> */
+ res[npth++] = tmp;
+ }
+ return npth;
+}
+
+/* Complete command, directory or file name.
+ * Return the length of the prefix used for matching.
+ */
+static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
+{
+ char *path1[1];
+ char **paths = path1;
+ int npaths;
+ int i;
+ unsigned pf_len;
+ const char *pfind;
+ char *dirbuf = NULL;
+
+ npaths = 1;
+ path1[0] = (char*)".";
+
+ pfind = strrchr(command, '/');
+ if (!pfind) {
+ if (type == FIND_EXE_ONLY)
+ npaths = path_parse(&paths);
+ pfind = command;
+ } else {
+ /* point to 'l' in "..../last_component" */
+ pfind++;
+ /* dirbuf = ".../.../.../" */
+ dirbuf = xstrndup(command, pfind - command);
+# if ENABLE_FEATURE_USERNAME_COMPLETION
+ if (dirbuf[0] == '~') /* ~/... or ~user/... */
+ dirbuf = username_path_completion(dirbuf);
+# endif
+ path1[0] = dirbuf;
+ }
+ pf_len = strlen(pfind);
+
+ for (i = 0; i < npaths; i++) {
+ DIR *dir;
+ struct dirent *next;
+ struct stat st;
+ char *found;
+
+ dir = opendir(paths[i]);
+ if (!dir)
+ continue; /* don't print an error */
+
+ while ((next = readdir(dir)) != NULL) {
+ unsigned len;
+ const char *name_found = next->d_name;
+
+ /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */
+ if (!pfind[0] && DOT_OR_DOTDOT(name_found))
+ continue;
+ /* match? */
+ if (strncmp(name_found, pfind, pf_len) != 0)
+ continue; /* no */
+
+ found = concat_path_file(paths[i], name_found);
+ /* 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; /* hmm, remove in progress? */
+
+ /* Save only name */
+ len = strlen(name_found);
+ found = xrealloc(found, len + 2); /* +2: for slash and NUL */
+ strcpy(found, name_found);
+
+ if (S_ISDIR(st.st_mode)) {
+ /* name is a directory, add slash */
+ found[len] = '/';
+ found[len + 1] = '\0';
+ } else {
+ /* skip files if looking for dirs only (example: cd) */
+ if (type == FIND_DIR_ONLY)
+ goto cont;
+ }
+ /* add it to the list */
+ add_match(found);
+ continue;
+ cont:
+ free(found);
+ }
+ closedir(dir);
+ } /* for every path */
+
+ if (paths != path1) {
+ free(paths[0]); /* allocated memory is only in first member */
+ free(paths);
+ }
+ free(dirbuf);
+
+ return pf_len;
+}
+
+/* build_match_prefix:
+ * On entry, match_buf contains everything up to cursor at the moment <tab>
+ * was pressed. This function looks at it, figures out what part of it
+ * constitutes the command/file/directory prefix to use for completion,
+ * and rewrites match_buf to contain only that part.
+ */
+#define dbg_bmp 0
+/* Helpers: */
+/* QUOT is used on elements of int_buf[], which are bytes,
+ * not Unicode chars. Therefore it works correctly even in Unicode mode.
+ */
+#define QUOT (UCHAR_MAX+1)
+static void remove_chunk(int16_t *int_buf, int beg, int end)
+{
+ /* beg must be <= end */
+ if (beg == end)
+ return;
+
+ while ((int_buf[beg] = int_buf[end]) != 0)
+ beg++, end++;
+
+ if (dbg_bmp) {
+ int i;
+ for (i = 0; int_buf[i]; i++)
+ bb_putchar((unsigned char)int_buf[i]);
+ bb_putchar('\n');
+ }
+}
+/* Caller ensures that match_buf points to a malloced buffer
+ * big enough to hold strlen(match_buf)*2 + 2
+ */
+static NOINLINE int build_match_prefix(char *match_buf)
+{
+ int i, j;
+ int command_mode;
+ int16_t *int_buf = (int16_t*)match_buf;
+
+ if (dbg_bmp) printf("\n%s\n", match_buf);
+
+ /* Copy in reverse order, since they overlap */
+ i = strlen(match_buf);
+ do {
+ int_buf[i] = (unsigned char)match_buf[i];
+ i--;
+ } while (i >= 0);
+
+ /* Mark every \c as "quoted c" */
+ for (i = 0; int_buf[i]; i++) {
+ if (int_buf[i] == '\\') {
+ remove_chunk(int_buf, i, i + 1);
+ int_buf[i] |= QUOT;
+ }
+ }
+ /* Quote-mark "chars" and 'chars', drop delimiters */
+ {
+ int in_quote = 0;
+ i = 0;
+ while (int_buf[i]) {
+ int cur = int_buf[i];
+ if (!cur)
+ break;
+ if (cur == '\'' || cur == '"') {
+ if (!in_quote || (cur == in_quote)) {
+ in_quote ^= cur;
+ remove_chunk(int_buf, i, i + 1);
+ continue;
+ }
+ }
+ if (in_quote)
+ int_buf[i] = cur | QUOT;
+ i++;
+ }
+ }
+
+ /* Remove everything up to command delimiters:
+ * ';' ';;' '&' '|' '&&' '||',
+ * but careful with '>&' '<&' '>|'
+ */
+ for (i = 0; int_buf[i]; i++) {
+ int cur = int_buf[i];
+ if (cur == ';' || cur == '&' || cur == '|') {
+ int prev = i ? int_buf[i - 1] : 0;
+ if (cur == '&' && (prev == '>' || prev == '<')) {
+ continue;
+ } else if (cur == '|' && prev == '>') {
+ continue;
+ }
+ remove_chunk(int_buf, 0, i + 1 + (cur == int_buf[i + 1]));
+ i = -1; /* back to square 1 */
+ }
+ }
+ /* Remove all `cmd` */
+ for (i = 0; int_buf[i]; i++) {
+ if (int_buf[i] == '`') {
+ for (j = i + 1; int_buf[j]; j++) {
+ if (int_buf[j] == '`') {
+ /* `cmd` should count as a word:
+ * `cmd` c<tab> should search for files c*,
+ * not commands c*. Therefore we don't drop
+ * `cmd` entirely, we replace it with single `.
+ */
+ remove_chunk(int_buf, i, j);
+ goto next;
+ }
+ }
+ /* No closing ` - command mode, remove all up to ` */
+ remove_chunk(int_buf, 0, i + 1);
+ break;
+ next: ;
+ }
+ }
+
+ /* Remove "cmd (" and "cmd {"
+ * Example: "if { c<tab>"
+ * In this example, c should be matched as command pfx.
+ */
+ for (i = 0; int_buf[i]; i++) {
+ if (int_buf[i] == '(' || int_buf[i] == '{') {
+ remove_chunk(int_buf, 0, i + 1);
+ i = -1; /* back to square 1 */
+ }
+ }
+
+ /* Remove leading unquoted spaces */
+ for (i = 0; int_buf[i]; i++)
+ if (int_buf[i] != ' ')
+ break;
+ remove_chunk(int_buf, 0, i);
+
+ /* Determine completion mode */
+ 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
+ && (char)int_buf[0] == 'c'
+ && (char)int_buf[1] == 'd'
+ && i == 2 /* -> int_buf[2] == ' ' */
+ ) {
+ command_mode = FIND_DIR_ONLY;
+ } else {
+ command_mode = FIND_FILE_ONLY;
+ break;
+ }
+ }
+ }
+ if (dbg_bmp) printf("command_mode(0:exe/1:dir/2:file):%d\n", command_mode);
+
+ /* Remove everything except last word */
+ for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */
+ continue;
+ for (--i; i >= 0; i--) {
+ int cur = int_buf[i];
+ if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') {
+ remove_chunk(int_buf, 0, i + 1);
+ break;
+ }
+ }
+
+ /* Convert back to string of _chars_ */
+ i = 0;
+ while ((match_buf[i] = int_buf[i]) != '\0')
+ i++;
+
+ if (dbg_bmp) printf("final match_buf:'%s'\n", match_buf);
+
+ return command_mode;
+}
+
+/*
+ * Display by column (original idea from ls applet,
+ * very optimized by me [Vladimir] :)
+ */
+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 = unicode_strwidth(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 - unicode_strwidth(matches[n])), ""
+ );
+ }
+ if (ENABLE_UNICODE_SUPPORT)
+ puts(printable_string(NULL, matches[n]));
+ else
+ puts(matches[n]);
+ }
+}
+
+static const char *is_special_char(char c)
+{
+ return strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", c);
+}
+
+static char *quote_special_chars(char *found)
+{
+ int l = 0;
+ char *s = xzalloc((strlen(found) + 1) * 2);
+
+ while (*found) {
+ if (is_special_char(*found))
+ s[l++] = '\\';
+ s[l++] = *found++;
+ }
+ /* s[l] = '\0'; - already is */
+ return s;
+}
+
+/* Do TAB completion */
+static NOINLINE void input_tab(smallint *lastWasTab)
+{
+ char *chosen_match;
+ char *match_buf;
+ size_t len_found;
+ /* Length of string used for matching */
+ unsigned match_pfx_len = match_pfx_len;
+ int find_type;
+# if ENABLE_UNICODE_SUPPORT
+ /* cursor pos in command converted to multibyte form */
+ int cursor_mb;
+# endif
+ if (!(state->flags & TAB_COMPLETION))
+ return;
+
+ if (*lastWasTab) {
+ /* The last char was a TAB too.
+ * Print a list of all the available choices.
+ */
+ if (num_matches > 0) {
+ /* cursor will be changed by goto_new_line() */
+ int sav_cursor = cursor;
+ goto_new_line();
+ showfiles();
+ redraw(0, command_len - sav_cursor);
+ }
+ return;
+ }
+
+ *lastWasTab = 1;
+ chosen_match = NULL;
+
+ /* Make a local copy of the string up to the position of the cursor.
+ * build_match_prefix will expand it into int16_t's, need to allocate
+ * twice as much as the string_len+1.
+ * (we then also (ab)use this extra space later - see (**))
+ */
+ match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t));
+# if !ENABLE_UNICODE_SUPPORT
+ save_string(match_buf, cursor + 1); /* +1 for NUL */
+# else
+ {
+ CHAR_T wc = command_ps[cursor];
+ command_ps[cursor] = BB_NUL;
+ save_string(match_buf, MAX_LINELEN);
+ command_ps[cursor] = wc;
+ cursor_mb = strlen(match_buf);
+ }
+# endif
+ find_type = build_match_prefix(match_buf);
+
+ /* 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 (match_buf[0] == '~' && strchr(match_buf, '/') == NULL)
+ match_pfx_len = complete_username(match_buf);
+# endif
+ /* If complete_username() did not match,
+ * try to match a command in $PATH, or a directory, or a file */
+ if (!matches)
+ match_pfx_len = complete_cmd_dir_file(match_buf, find_type);
+
+ /* Account for backslashes which will be inserted
+ * by quote_special_chars() later */
+ {
+ const char *e = match_buf + strlen(match_buf);
+ const char *s = e - match_pfx_len;
+ while (s < e)
+ if (is_special_char(*s++))
+ match_pfx_len++;
+ }
+
+ /* Remove duplicates */
+ if (matches) {
+ unsigned i, 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;
+ }
+
+ /* Did we find exactly one match? */
+ if (num_matches != 1) { /* no */
+ char *cp;
+ beep();
+ if (!matches)
+ goto ret; /* no matches at all */
+ /* Find common prefix */
+ chosen_match = xstrdup(matches[0]);
+ for (cp = chosen_match; *cp; cp++) {
+ unsigned n;
+ for (n = 1; n < num_matches; n++) {
+ if (matches[n][cp - chosen_match] != *cp) {
+ goto stop;
+ }
+ }
+ }
+ stop:
+ if (cp == chosen_match) { /* have unique prefix? */
+ goto ret; /* no */
+ }
+ *cp = '\0';
+ cp = quote_special_chars(chosen_match);
+ free(chosen_match);
+ chosen_match = cp;
+ len_found = strlen(chosen_match);
+ } else { /* exactly one match */
+ /* Next <tab> is not a double-tab */
+ *lastWasTab = 0;
+
+ chosen_match = quote_special_chars(matches[0]);
+ len_found = strlen(chosen_match);
+ if (chosen_match[len_found-1] != '/') {
+ chosen_match[len_found] = ' ';
+ chosen_match[++len_found] = '\0';
+ }
+ }
+
+# if !ENABLE_UNICODE_SUPPORT
+ /* Have space to place the match? */
+ /* The result consists of three parts with these lengths: */
+ /* cursor + (len_found - match_pfx_len) + (command_len - cursor) */
+ /* it simplifies into: */
+ if ((int)(len_found - match_pfx_len + command_len) < S.maxsize) {
+ int pos;
+ /* save tail */
+ strcpy(match_buf, &command_ps[cursor]);
+ /* add match and tail */
+ sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf);
+ command_len = strlen(command_ps);
+ /* new pos */
+ pos = cursor + len_found - match_pfx_len;
+ /* write out the matched command */
+ redraw(cmdedit_y, command_len - pos);
+ }
+# else
+ {
+ /* Use 2nd half of match_buf as scratch space - see (**) */
+ char *command = match_buf + MAX_LINELEN;
+ int len = save_string(command, MAX_LINELEN);
+ /* Have space to place the match? */
+ /* cursor_mb + (len_found - match_pfx_len) + (len - cursor_mb) */
+ if ((int)(len_found - match_pfx_len + len) < MAX_LINELEN) {
+ int pos;
+ /* save tail */
+ strcpy(match_buf, &command[cursor_mb]);
+ /* where do we want to have cursor after all? */
+ strcpy(&command[cursor_mb], chosen_match + match_pfx_len);
+ len = load_string(command);
+ /* add match and tail */
+ sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf);
+ command_len = load_string(command);
+ /* write out the matched command */
+ /* paranoia: load_string can return 0 on conv error,
+ * prevent passing pos = (0 - 12) to redraw */
+ pos = command_len - len;
+ redraw(cmdedit_y, pos >= 0 ? pos : 0);
+ }
+ }
+# endif
+ ret:
+ free(chosen_match);
+ free(match_buf);
+}
+
+#endif /* FEATURE_TAB_COMPLETION */
+
+
+line_input_t* FAST_FUNC new_line_input_t(int flags)
+{
+ line_input_t *n = xzalloc(sizeof(*n));
+ n->flags = flags;
+ n->max_history = MAX_HISTORY;
+ return n;
+}
+
+
+#if MAX_HISTORY > 0
+
+unsigned size_from_HISTFILESIZE(const char *hp)
+{
+ int size = MAX_HISTORY;
+ if (hp) {
+ size = atoi(hp);
+ if (size <= 0)
+ return 1;
+ if (size > MAX_HISTORY)
+ return MAX_HISTORY;
+ }
+ return size;
+}
+
+static void save_command_ps_at_cur_history(void)
+{
+ if (command_ps[0] != BB_NUL) {
+ int cur = state->cur_history;
+ free(state->history[cur]);
+
+# if ENABLE_UNICODE_SUPPORT
+ {
+ char tbuf[MAX_LINELEN];
+ save_string(tbuf, sizeof(tbuf));
+ state->history[cur] = xstrdup(tbuf);
+ }
+# else
+ state->history[cur] = xstrdup(command_ps);
+# endif
+ }
+}
+
+/* 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));
+ idx = 0;
+ st_parm->cnt_history_in_file = 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 == st_parm->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 == st_parm->max_history)
+ idx = 0;
+ }
+ }
+
+ /* copy temp_h[] to st_parm->history[] */
+ for (i = 0; i < st_parm->max_history;) {
+ line = temp_h[idx];
+ if (!line)
+ break;
+ idx++;
+ if (idx == st_parm->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;
+ if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
+ st_parm->cnt_history_in_file = i;
+ }
+}
+
+# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
+void save_history(line_input_t *st)
+{
+ FILE *fp;
+
+ if (!st->hist_file)
+ return;
+ if (st->cnt_history <= st->cnt_history_in_file)
+ return;
+
+ fp = fopen(st->hist_file, "a");
+ if (fp) {
+ int i, fd;
+ char *new_name;
+ line_input_t *st_temp;
+
+ for (i = st->cnt_history_in_file; i < st->cnt_history; i++)
+ fprintf(fp, "%s\n", st->history[i]);
+ fclose(fp);
+
+ /* we may have concurrently written entries from others.
+ * load them */
+ st_temp = new_line_input_t(st->flags);
+ st_temp->hist_file = st->hist_file;
+ st_temp->max_history = st->max_history;
+ load_history(st_temp);
+
+ /* write out temp file and replace hist_file atomically */
+ new_name = xasprintf("%s.%u.new", st->hist_file, (int) getpid());
+ fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd >= 0) {
+ fp = xfdopen_for_write(fd);
+ for (i = 0; i < st_temp->cnt_history; i++)
+ fprintf(fp, "%s\n", st_temp->history[i]);
+ fclose(fp);
+ if (rename(new_name, st->hist_file) == 0)
+ st->cnt_history_in_file = st_temp->cnt_history;
+ }
+ free(new_name);
+ free_line_input_t(st_temp);
+ }
+}
+# else
+static void save_history(char *str)
+{
+ int fd;
+ int len, len2;
+
+ if (!state->hist_file)
+ return;
+
+ fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
+ 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 > state->max_history * 4) {
+ char *new_name;
+ line_input_t *st_temp;
+
+ /* 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;
+ st_temp->max_history = state->max_history;
+ load_history(st_temp);
+
+ /* write out temp file and replace hist_file atomically */
+ new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid());
+ fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd >= 0) {
+ FILE *fp;
+ int i;
+
+ fp = xfdopen_for_write(fd);
+ 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);
+ }
+}
+# endif
+# 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[state->max_history]); /* redundant, paranoia */
+ state->history[state->max_history] = NULL; /* redundant, paranoia */
+
+ /* If history[] is full, remove the oldest command */
+ /* we need to keep history[state->max_history] empty, hence >=, not > */
+ if (i >= state->max_history) {
+ free(state->history[0]);
+ for (i = 0; i < state->max_history-1; i++)
+ state->history[i] = state->history[i+1];
+ /* i == state->max_history-1 */
+# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
+ if (state->cnt_history_in_file)
+ state->cnt_history_in_file--;
+# endif
+ }
+ /* i <= state->max_history-1 */
+ state->history[i++] = xstrdup(str);
+ /* i <= state->max_history */
+ state->cur_history = i;
+ state->cnt_history = i;
+# if ENABLE_FEATURE_EDITING_SAVEHISTORY && !ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
+ save_history(str);
+# endif
+ IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
+}
+
+#else /* MAX_HISTORY == 0 */
+# define remember_in_history(a) ((void)0)
+#endif /* MAX_HISTORY */
+
+
+#if ENABLE_FEATURE_EDITING_VI
+/*
+ * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
+ */
+static void
+vi_Word_motion(int eat)
+{
+ CHAR_T *command = command_ps;
+
+ while (cursor < command_len && !BB_isspace(command[cursor]))
+ input_forward();
+ if (eat) while (cursor < command_len && BB_isspace(command[cursor]))
+ input_forward();
+}
+
+static void
+vi_word_motion(int eat)
+{
+ CHAR_T *command = command_ps;
+
+ if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor < command_len
+ && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_')
+ ) {
+ input_forward();
+ }
+ } else if (BB_ispunct(command[cursor])) {
+ while (cursor < command_len && BB_ispunct(command[cursor+1]))
+ input_forward();
+ }
+
+ if (cursor < command_len)
+ input_forward();
+
+ if (eat) {
+ while (cursor < command_len && BB_isspace(command[cursor]))
+ input_forward();
+ }
+}
+
+static void
+vi_End_motion(void)
+{
+ CHAR_T *command = command_ps;
+
+ input_forward();
+ while (cursor < command_len && BB_isspace(command[cursor]))
+ input_forward();
+ while (cursor < command_len-1 && !BB_isspace(command[cursor+1]))
+ input_forward();
+}
+
+static void
+vi_end_motion(void)
+{
+ CHAR_T *command = command_ps;
+
+ if (cursor >= command_len-1)
+ return;
+ input_forward();
+ while (cursor < command_len-1 && BB_isspace(command[cursor]))
+ input_forward();
+ if (cursor >= command_len-1)
+ return;
+ if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor < command_len-1
+ && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_')
+ ) {
+ input_forward();
+ }
+ } else if (BB_ispunct(command[cursor])) {
+ while (cursor < command_len-1 && BB_ispunct(command[cursor+1]))
+ input_forward();
+ }
+}
+
+static void
+vi_Back_motion(void)
+{
+ CHAR_T *command = command_ps;
+
+ while (cursor > 0 && BB_isspace(command[cursor-1]))
+ input_backward(1);
+ while (cursor > 0 && !BB_isspace(command[cursor-1]))
+ input_backward(1);
+}
+
+static void
+vi_back_motion(void)
+{
+ CHAR_T *command = command_ps;
+
+ if (cursor <= 0)
+ return;
+ input_backward(1);
+ while (cursor > 0 && BB_isspace(command[cursor]))
+ input_backward(1);
+ if (cursor <= 0)
+ return;
+ if (BB_isalnum(command[cursor]) || command[cursor] == '_') {
+ while (cursor > 0
+ && (BB_isalnum(command[cursor-1]) || command[cursor-1] == '_')
+ ) {
+ input_backward(1);
+ }
+ } else if (BB_ispunct(command[cursor])) {
+ while (cursor > 0 && BB_ispunct(command[cursor-1]))
+ input_backward(1);
+ }
+}
+#endif
+
+/* Modelled after bash 4.0 behavior of Ctrl-<arrow> */
+static void ctrl_left(void)
+{
+ CHAR_T *command = command_ps;
+
+ while (1) {
+ CHAR_T c;
+
+ input_backward(1);
+ if (cursor == 0)
+ break;
+ c = command[cursor];
+ if (c != ' ' && !BB_ispunct(c)) {
+ /* we reached a "word" delimited by spaces/punct.
+ * go to its beginning */
+ while (1) {
+ c = command[cursor - 1];
+ if (c == ' ' || BB_ispunct(c))
+ break;
+ input_backward(1);
+ if (cursor == 0)
+ break;
+ }
+ break;
+ }
+ }
+}
+static void ctrl_right(void)
+{
+ CHAR_T *command = command_ps;
+
+ while (1) {
+ CHAR_T c;
+
+ c = command[cursor];
+ if (c == BB_NUL)
+ break;
+ if (c != ' ' && !BB_ispunct(c)) {
+ /* we reached a "word" delimited by spaces/punct.
+ * go to its end + 1 */
+ while (1) {
+ input_forward();
+ c = command[cursor];
+ if (c == BB_NUL || c == ' ' || BB_ispunct(c))
+ break;
+ }
+ break;
+ }
+ input_forward();
+ }
+}
+
+
+/*
+ * read_line_input and its helpers
+ */
+
+#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
+static void ask_terminal(void)
+{
+ /* Ask terminal where is the cursor now.
+ * lineedit_read_key handles response and corrects
+ * our idea of current cursor position.
+ * Testcase: run "echo -n long_line_long_line_long_line",
+ * then type in a long, wrapping command and try to
+ * delete it using backspace key.
+ * Note: we print it _after_ prompt, because
+ * prompt may contain CR. Example: PS1='\[\r\n\]\w '
+ */
+ /* Problem: if there is buffered input on stdin,
+ * the response will be delivered later,
+ * possibly to an unsuspecting application.
+ * Testcase: "sleep 1; busybox ash" + press and hold [Enter].
+ * Result:
+ * ~/srcdevel/bbox/fix/busybox.t4 #
+ * ~/srcdevel/bbox/fix/busybox.t4 #
+ * ^[[59;34~/srcdevel/bbox/fix/busybox.t4 # <-- garbage
+ * ~/srcdevel/bbox/fix/busybox.t4 #
+ *
+ * Checking for input with poll only makes the race narrower,
+ * I still can trigger it. Strace:
+ *
+ * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33
+ * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists
+ * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick!
+ * poll([{fd=0, events=POLLIN}], 1, -1) = 1 ([{fd=0, revents=POLLIN}])
+ * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first
+ */
+ struct pollfd pfd;
+
+ pfd.fd = STDIN_FILENO;
+ pfd.events = POLLIN;
+ if (safe_poll(&pfd, 1, 0) == 0) {
+ S.sent_ESC_br6n = 1;
+ fputs(ESC"[6n", stdout);
+ fflush_all(); /* make terminal see it ASAP! */
+ }
+}
+#else
+#define ask_terminal() ((void)0)
+#endif
+
+#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_USERNAME_OR_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_USERNAME_OR_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_all();
+ }
+}
+
+static void win_changed(int nsig)
+{
+ int sv_errno = errno;
+ unsigned width;
+
+ get_terminal_width_height(0, &width, NULL);
+//FIXME: cmdedit_setwidth() -> redraw() -> printf() -> KABOOM! (we are in signal handler!)
+ cmdedit_setwidth(width, /*redraw_flg:*/ nsig);
+
+ errno = sv_errno;
+}
+
+static int lineedit_read_key(char *read_key_buffer, int timeout)
+{
+ int64_t ic;
+#if ENABLE_UNICODE_SUPPORT
+ char unicode_buf[MB_CUR_MAX + 1];
+ int unicode_idx = 0;
+#endif
+
+ while (1) {
+ /* Wait for input. TIMEOUT = -1 makes read_key wait even
+ * on nonblocking stdin, TIMEOUT = 50 makes sure we won't
+ * insist on full MB_CUR_MAX buffer to declare input like
+ * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls".
+ *
+ * Note: read_key sets errno to 0 on success.
+ */
+ ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
+ if (errno) {
+#if ENABLE_UNICODE_SUPPORT
+ if (errno == EAGAIN && unicode_idx != 0)
+ goto pushback;
+#endif
+ break;
+ }
+
+#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
+ if ((int32_t)ic == KEYCODE_CURSOR_POS
+ && S.sent_ESC_br6n
+ ) {
+ S.sent_ESC_br6n = 0;
+ if (cursor == 0) { /* otherwise it may be bogus */
+ int col = ((ic >> 32) & 0x7fff) - 1;
+ if (col > cmdedit_prmt_len) {
+ cmdedit_x += (col - cmdedit_prmt_len);
+ while (cmdedit_x >= cmdedit_termw) {
+ cmdedit_x -= cmdedit_termw;
+ cmdedit_y++;
+ }
+ }
+ }
+ continue;
+ }
+#endif
+
+#if ENABLE_UNICODE_SUPPORT
+ if (unicode_status == UNICODE_ON) {
+ wchar_t wc;
+
+ if ((int32_t)ic < 0) /* KEYCODE_xxx */
+ break;
+ // TODO: imagine sequence like: 0xff,<left-arrow>: we are currently losing 0xff...
+
+ unicode_buf[unicode_idx++] = ic;
+ unicode_buf[unicode_idx] = '\0';
+ if (mbstowcs(&wc, unicode_buf, 1) != 1) {
+ /* Not (yet?) a valid unicode char */
+ if (unicode_idx < MB_CUR_MAX) {
+ timeout = 50;
+ continue;
+ }
+ pushback:
+ /* Invalid sequence. Save all "bad bytes" except first */
+ read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1);
+# if !ENABLE_UNICODE_PRESERVE_BROKEN
+ ic = CONFIG_SUBST_WCHAR;
+# else
+ ic = unicode_mark_raw_byte(unicode_buf[0]);
+# endif
+ } else {
+ /* Valid unicode char, return its code */
+ ic = wc;
+ }
+ }
+#endif
+ break;
+ }
+
+ return ic;
+}
+
+#if ENABLE_UNICODE_BIDI_SUPPORT
+static int isrtl_str(void)
+{
+ int idx = cursor;
+
+ while (idx < command_len && unicode_bidi_is_neutral_wchar(command_ps[idx]))
+ idx++;
+ return unicode_bidi_isrtl(command_ps[idx]);
+}
+#else
+# define isrtl_str() 0
+#endif
+
+/* leave out the "vi-mode"-only case labels if vi editing isn't
+ * configured. */
+#define vi_case(caselabel) IF_FEATURE_EDITING_VI(case caselabel)
+
+/* convert uppercase ascii to equivalent control char, for readability */
+#undef CTRL
+#define CTRL(a) ((a) & ~0x40)
+
+enum {
+ VI_CMDMODE_BIT = 0x40000000,
+ /* 0x80000000 bit flags KEYCODE_xxx */
+};
+
+#if ENABLE_FEATURE_REVERSE_SEARCH
+/* Mimic readline Ctrl-R reverse history search.
+ * When invoked, it shows the following prompt:
+ * (reverse-i-search)'': user_input [cursor pos unchanged by Ctrl-R]
+ * and typing results in search being performed:
+ * (reverse-i-search)'tmp': cd /tmp [cursor under t in /tmp]
+ * Search is performed by looking at progressively older lines in history.
+ * Ctrl-R again searches for the next match in history.
+ * Backspace deletes last matched char.
+ * Control keys exit search and return to normal editing (at current history line).
+ */
+static int32_t reverse_i_search(void)
+{
+ char match_buf[128]; /* for user input */
+ char read_key_buffer[KEYCODE_BUFFER_SIZE];
+ const char *matched_history_line;
+ const char *saved_prompt;
+ int32_t ic;
+
+ matched_history_line = NULL;
+ read_key_buffer[0] = 0;
+ match_buf[0] = '\0';
+
+ /* Save and replace the prompt */
+ saved_prompt = cmdedit_prompt;
+ goto set_prompt;
+
+ while (1) {
+ int h;
+ unsigned match_buf_len = strlen(match_buf);
+
+ fflush_all();
+//FIXME: correct timeout?
+ ic = lineedit_read_key(read_key_buffer, -1);
+
+ switch (ic) {
+ case CTRL('R'): /* searching for the next match */
+ break;
+
+ case '\b':
+ case '\x7f':
+ /* Backspace */
+ if (unicode_status == UNICODE_ON) {
+ while (match_buf_len != 0) {
+ uint8_t c = match_buf[--match_buf_len];
+ if ((c & 0xc0) != 0x80) /* start of UTF-8 char? */
+ break; /* yes */
+ }
+ } else {
+ if (match_buf_len != 0)
+ match_buf_len--;
+ }
+ match_buf[match_buf_len] = '\0';
+ break;
+
+ default:
+ if (ic < ' '
+ || (!ENABLE_UNICODE_SUPPORT && ic >= 256)
+ || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT)
+ ) {
+ goto ret;
+ }
+
+ /* Append this char */
+#if ENABLE_UNICODE_SUPPORT
+ if (unicode_status == UNICODE_ON) {
+ mbstate_t mbstate = { 0 };
+ char buf[MB_CUR_MAX + 1];
+ int len = wcrtomb(buf, ic, &mbstate);
+ if (len > 0) {
+ buf[len] = '\0';
+ if (match_buf_len + len < sizeof(match_buf))
+ strcpy(match_buf + match_buf_len, buf);
+ }
+ } else
+#endif
+ if (match_buf_len < sizeof(match_buf) - 1) {
+ match_buf[match_buf_len] = ic;
+ match_buf[match_buf_len + 1] = '\0';
+ }
+ break;
+ } /* switch (ic) */
+
+ /* Search in history for match_buf */
+ h = state->cur_history;
+ if (ic == CTRL('R'))
+ h--;
+ while (h >= 0) {
+ if (state->history[h]) {
+ char *match = strstr(state->history[h], match_buf);
+ if (match) {
+ state->cur_history = h;
+ matched_history_line = state->history[h];
+ command_len = load_string(matched_history_line);
+ cursor = match - matched_history_line;
+//FIXME: cursor position for Unicode case
+
+ free((char*)cmdedit_prompt);
+ set_prompt:
+ cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf);
+ cmdedit_prmt_len = strlen(cmdedit_prompt);
+ goto do_redraw;
+ }
+ }
+ h--;
+ }
+
+ /* Not found */
+ match_buf[match_buf_len] = '\0';
+ beep();
+ continue;
+
+ do_redraw:
+ redraw(cmdedit_y, command_len - cursor);
+ } /* while (1) */
+
+ ret:
+ if (matched_history_line)
+ command_len = load_string(matched_history_line);
+
+ free((char*)cmdedit_prompt);
+ cmdedit_prompt = saved_prompt;
+ cmdedit_prmt_len = strlen(cmdedit_prompt);
+ redraw(cmdedit_y, command_len - cursor);
+
+ return ic;
+}
+#endif
+
+/* maxsize must be >= 2.
+ * 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(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout)
+{
+ int len;
+#if ENABLE_FEATURE_TAB_COMPLETION
+ smallint lastWasTab = 0;
+#endif
+ smallint break_out = 0;
+#if ENABLE_FEATURE_EDITING_VI
+ smallint vi_cmdmode = 0;
+#endif
+ struct termios initial_settings;
+ struct termios new_settings;
+ char read_key_buffer[KEYCODE_BUFFER_SIZE];
+
+ 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_all(); - done by parse_and_put_prompt */
+ if (fgets(command, maxsize, stdin) == NULL)
+ len = -1; /* EOF or error */
+ else
+ len = strlen(command);
+ DEINIT_S();
+ return len;
+ }
+
+ init_unicode();
+
+// FIXME: audit & improve this
+ if (maxsize > MAX_LINELEN)
+ maxsize = MAX_LINELEN;
+ S.maxsize = maxsize;
+
+ /* With zero flags, no other fields are ever used */
+ state = st ? st : (line_input_t*) &const_int_0;
+#if MAX_HISTORY > 0
+# if ENABLE_FEATURE_EDITING_SAVEHISTORY
+ if (state->hist_file)
+ if (state->cnt_history == 0)
+ load_history(state);
+# endif
+ if (state->flags & DO_HISTORY)
+ state->cur_history = state->cnt_history;
+#endif
+
+ /* prepare before init handlers */
+ cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
+ command_len = 0;
+#if ENABLE_UNICODE_SUPPORT
+ command_ps = xzalloc(maxsize * sizeof(command_ps[0]));
+#else
+ command_ps = command;
+ command[0] = '\0';
+#endif
+#define command command_must_not_be_used
+
+ new_settings = initial_settings;
+ /* ~ICANON: unbuffered input (most c_cc[] are disabled, VMIN/VTIME are enabled) */
+ /* ~ECHO, ~ECHONL: turn off echoing, including newline echoing */
+ /* ~ISIG: turn off INTR (ctrl-C), QUIT, SUSP */
+ new_settings.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG);
+ /* reads would block only if < 1 char is available */
+ new_settings.c_cc[VMIN] = 1;
+ /* no timeout (reads block forever) */
+ new_settings.c_cc[VTIME] = 0;
+ /* Should be not needed if ISIG is off: */
+ /* Turn off CTRL-C */
+ /* new_settings.c_cc[VINTR] = _POSIX_VDISABLE; */
+ tcsetattr_stdin_TCSANOW(&new_settings);
+
+#if ENABLE_USERNAME_OR_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 (i = 0; i <= state->max_history; i++)
+ bb_error_msg("history[%d]:'%s'", i, state->history[i]);
+ bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history);
+#endif
+
+ /* Print out the command prompt, optionally ask where cursor is */
+ parse_and_put_prompt(prompt);
+ ask_terminal();
+
+ /* Install window resize handler (NB: after *all* init is complete) */
+//FIXME: save entire sigaction!
+ previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
+ win_changed(0); /* get initial window size */
+
+ read_key_buffer[0] = 0;
+ while (1) {
+ /*
+ * 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.
+ */
+ int32_t ic, ic_raw;
+
+ fflush_all();
+ ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
+
+#if ENABLE_FEATURE_REVERSE_SEARCH
+ again:
+#endif
+#if ENABLE_FEATURE_EDITING_VI
+ newdelflag = 1;
+ if (vi_cmdmode) {
+ /* btw, since KEYCODE_xxx are all < 0, this doesn't
+ * change ic if it contains one of them: */
+ ic |= VI_CMDMODE_BIT;
+ }
+#endif
+
+ switch (ic) {
+ case '\n':
+ case '\r':
+ vi_case('\n'|VI_CMDMODE_BIT:)
+ vi_case('\r'|VI_CMDMODE_BIT:)
+ /* Enter */
+ goto_new_line();
+ break_out = 1;
+ break;
+ case CTRL('A'):
+ vi_case('0'|VI_CMDMODE_BIT:)
+ /* Control-a -- Beginning of line */
+ input_backward(cursor);
+ break;
+ case CTRL('B'):
+ vi_case('h'|VI_CMDMODE_BIT:)
+ vi_case('\b'|VI_CMDMODE_BIT:) /* ^H */
+ vi_case('\x7f'|VI_CMDMODE_BIT:) /* DEL */
+ input_backward(1); /* Move back one character */
+ break;
+ case CTRL('E'):
+ vi_case('$'|VI_CMDMODE_BIT:)
+ /* Control-e -- End of line */
+ put_till_end_and_adv_cursor();
+ break;
+ case CTRL('F'):
+ vi_case('l'|VI_CMDMODE_BIT:)
+ vi_case(' '|VI_CMDMODE_BIT:)
+ input_forward(); /* Move forward one character */
+ break;
+ case '\b': /* ^H */
+ case '\x7f': /* DEL */
+ if (!isrtl_str())
+ input_backspace();
+ else
+ input_delete(0);
+ break;
+ case KEYCODE_DELETE:
+ if (!isrtl_str())
+ input_delete(0);
+ else
+ 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_ps[cursor] = BB_NUL;
+ command_len = cursor;
+ printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
+ break;
+ case CTRL('L'):
+ vi_case(CTRL('L')|VI_CMDMODE_BIT:)
+ /* Control-l -- clear screen */
+ printf(ESC"[H"); /* cursor to top,left */
+ redraw(0, command_len - cursor);
+ break;
+#if MAX_HISTORY > 0
+ case CTRL('N'):
+ vi_case(CTRL('N')|VI_CMDMODE_BIT:)
+ vi_case('j'|VI_CMDMODE_BIT:)
+ /* Control-n -- Get next command in history */
+ if (get_next_history())
+ goto rewrite_line;
+ break;
+ case CTRL('P'):
+ vi_case(CTRL('P')|VI_CMDMODE_BIT:)
+ vi_case('k'|VI_CMDMODE_BIT:)
+ /* Control-p -- Get previous command from history */
+ if (get_previous_history())
+ goto rewrite_line;
+ break;
+#endif
+ case CTRL('U'):
+ vi_case(CTRL('U')|VI_CMDMODE_BIT:)
+ /* Control-U -- Clear line before cursor */
+ if (cursor) {
+ command_len -= cursor;
+ memmove(command_ps, command_ps + cursor,
+ (command_len + 1) * sizeof(command_ps[0]));
+ redraw(cmdedit_y, command_len);
+ }
+ break;
+ case CTRL('W'):
+ vi_case(CTRL('W')|VI_CMDMODE_BIT:)
+ /* Control-W -- Remove the last word */
+ while (cursor > 0 && BB_isspace(command_ps[cursor-1]))
+ input_backspace();
+ while (cursor > 0 && !BB_isspace(command_ps[cursor-1]))
+ input_backspace();
+ break;
+#if ENABLE_FEATURE_REVERSE_SEARCH
+ case CTRL('R'):
+ ic = ic_raw = reverse_i_search();
+ goto again;
+#endif
+
+#if ENABLE_FEATURE_EDITING_VI
+ case 'i'|VI_CMDMODE_BIT:
+ vi_cmdmode = 0;
+ break;
+ case 'I'|VI_CMDMODE_BIT:
+ input_backward(cursor);
+ vi_cmdmode = 0;
+ break;
+ case 'a'|VI_CMDMODE_BIT:
+ input_forward();
+ vi_cmdmode = 0;
+ break;
+ case 'A'|VI_CMDMODE_BIT:
+ put_till_end_and_adv_cursor();
+ vi_cmdmode = 0;
+ break;
+ case 'x'|VI_CMDMODE_BIT:
+ input_delete(1);
+ break;
+ case 'X'|VI_CMDMODE_BIT:
+ if (cursor > 0) {
+ input_backward(1);
+ input_delete(1);
+ }
+ break;
+ case 'W'|VI_CMDMODE_BIT:
+ vi_Word_motion(1);
+ break;
+ case 'w'|VI_CMDMODE_BIT:
+ vi_word_motion(1);
+ break;
+ case 'E'|VI_CMDMODE_BIT:
+ vi_End_motion();
+ break;
+ case 'e'|VI_CMDMODE_BIT:
+ vi_end_motion();
+ break;
+ case 'B'|VI_CMDMODE_BIT:
+ vi_Back_motion();
+ break;
+ case 'b'|VI_CMDMODE_BIT:
+ vi_back_motion();
+ break;
+ case 'C'|VI_CMDMODE_BIT:
+ vi_cmdmode = 0;
+ /* fall through */
+ case 'D'|VI_CMDMODE_BIT:
+ goto clear_to_eol;
+
+ case 'c'|VI_CMDMODE_BIT:
+ vi_cmdmode = 0;
+ /* fall through */
+ case 'd'|VI_CMDMODE_BIT: {
+ int nc, sc;
+
+ ic = lineedit_read_key(read_key_buffer, timeout);
+ if (errno) /* error */
+ goto return_error_indicator;
+ if (ic == ic_raw) { /* "cc", "dd" */
+ input_backward(cursor);
+ goto clear_to_eol;
+ break;
+ }
+
+ sc = cursor;
+ switch (ic) {
+ case 'w':
+ case 'W':
+ case 'e':
+ case 'E':
+ switch (ic) {
+ case 'w': /* "dw", "cw" */
+ vi_word_motion(vi_cmdmode);
+ break;
+ case 'W': /* 'dW', 'cW' */
+ vi_Word_motion(vi_cmdmode);
+ break;
+ case 'e': /* 'de', 'ce' */
+ vi_end_motion();
+ input_forward();
+ break;
+ case 'E': /* 'dE', 'cE' */
+ vi_End_motion();
+ 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 (ic == 'b')
+ vi_back_motion();
+ else
+ vi_Back_motion();
+ 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'|VI_CMDMODE_BIT:
+ input_forward();
+ /* fallthrough */
+ case 'P'|VI_CMDMODE_BIT:
+ put();
+ break;
+ case 'r'|VI_CMDMODE_BIT:
+//FIXME: unicode case?
+ ic = lineedit_read_key(read_key_buffer, timeout);
+ if (errno) /* error */
+ goto return_error_indicator;
+ if (ic < ' ' || ic > 255) {
+ beep();
+ } else {
+ command_ps[cursor] = ic;
+ bb_putchar(ic);
+ bb_putchar('\b');
+ }
+ break;
+ case '\x1b': /* ESC */
+ if (state->flags & VI_MODE) {
+ /* insert mode --> command mode */
+ vi_cmdmode = 1;
+ input_backward(1);
+ }
+ /* Handle a few ESC-<key> combinations the same way
+ * standard readline bindings (IOW: bash) do.
+ * Often, Alt-<key> generates ESC-<key>.
+ */
+ ic = lineedit_read_key(read_key_buffer, timeout);
+ switch (ic) {
+ //case KEYCODE_LEFT: - bash doesn't do this
+ case 'b':
+ ctrl_left();
+ break;
+ //case KEYCODE_RIGHT: - bash doesn't do this
+ case 'f':
+ ctrl_right();
+ break;
+ //case KEYCODE_DELETE: - bash doesn't do this
+ case 'd': /* Alt-D */
+ {
+ /* Delete word forward */
+ int nc, sc = cursor;
+ ctrl_right();
+ nc = cursor - sc;
+ input_backward(nc);
+ while (--nc >= 0)
+ input_delete(1);
+ break;
+ }
+ case '\b': /* Alt-Backspace(?) */
+ case '\x7f': /* Alt-Backspace(?) */
+ //case 'w': - bash doesn't do this
+ {
+ /* Delete word backward */
+ int sc = cursor;
+ ctrl_left();
+ while (sc-- > cursor)
+ input_delete(1);
+ break;
+ }
+ }
+ break;
+#endif /* FEATURE_COMMAND_EDITING_VI */
+
+#if MAX_HISTORY > 0
+ case KEYCODE_UP:
+ if (get_previous_history())
+ goto rewrite_line;
+ beep();
+ break;
+ case KEYCODE_DOWN:
+ if (!get_next_history())
+ break;
+ rewrite_line:
+ /* Rewrite the line with the selected history item */
+ /* change command */
+ command_len = load_string(state->history[state->cur_history] ?
+ 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 KEYCODE_RIGHT:
+ input_forward();
+ break;
+ case KEYCODE_LEFT:
+ input_backward(1);
+ break;
+ case KEYCODE_CTRL_LEFT:
+ case KEYCODE_ALT_LEFT: /* bash doesn't do it */
+ ctrl_left();
+ break;
+ case KEYCODE_CTRL_RIGHT:
+ case KEYCODE_ALT_RIGHT: /* bash doesn't do it */
+ ctrl_right();
+ break;
+ case KEYCODE_HOME:
+ input_backward(cursor);
+ break;
+ case KEYCODE_END:
+ put_till_end_and_adv_cursor();
+ break;
+
+ default:
+ if (initial_settings.c_cc[VINTR] != 0
+ && ic_raw == initial_settings.c_cc[VINTR]
+ ) {
+ /* Ctrl-C (usually) - stop gathering input */
+ goto_new_line();
+ command_len = 0;
+ break_out = -1; /* "do not append '\n'" */
+ break;
+ }
+ if (initial_settings.c_cc[VEOF] != 0
+ && ic_raw == initial_settings.c_cc[VEOF]
+ ) {
+ /* Ctrl-D (usually) - delete one character,
+ * or exit if len=0 and no chars to delete */
+ if (command_len == 0) {
+ errno = 0;
+
+ case -1: /* error (e.g. EIO when tty is destroyed) */
+ IF_FEATURE_EDITING_VI(return_error_indicator:)
+ break_out = command_len = -1;
+ break;
+ }
+ input_delete(0);
+ break;
+ }
+// /* Control-V -- force insert of next char */
+// if (c == CTRL('V')) {
+// if (safe_read(STDIN_FILENO, &c, 1) < 1)
+// goto return_error_indicator;
+// if (c == 0) {
+// beep();
+// break;
+// }
+// }
+ if (ic < ' '
+ || (!ENABLE_UNICODE_SUPPORT && ic >= 256)
+ || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT)
+ ) {
+ /* If VI_CMDMODE_BIT is set, ic is >= 256
+ * and vi mode ignores unexpected chars.
+ * Otherwise, we are here if ic is a
+ * control char or an unhandled ESC sequence,
+ * which is also ignored.
+ */
+ break;
+ }
+ if ((int)command_len >= (maxsize - 2)) {
+ /* Not enough space for the char and EOL */
+ break;
+ }
+
+ command_len++;
+ if (cursor == (command_len - 1)) {
+ /* We are at the end, append */
+ command_ps[cursor] = ic;
+ command_ps[cursor + 1] = BB_NUL;
+ put_cur_glyph_and_inc_cursor();
+ if (unicode_bidi_isrtl(ic))
+ input_backward(1);
+ } else {
+ /* In the middle, insert */
+ int sc = cursor;
+
+ memmove(command_ps + sc + 1, command_ps + sc,
+ (command_len - sc) * sizeof(command_ps[0]));
+ command_ps[sc] = ic;
+ /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */
+ if (!isrtl_str())
+ sc++; /* no */
+ put_till_end_and_adv_cursor();
+ /* to prev x pos + 1 */
+ input_backward(cursor - sc);
+ }
+ break;
+ } /* switch (ic) */
+
+ if (break_out)
+ break;
+
+#if ENABLE_FEATURE_TAB_COMPLETION
+ if (ic_raw != '\t')
+ lastWasTab = 0;
+#endif
+ } /* while (1) */
+
+#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
+ if (S.sent_ESC_br6n) {
+ /* "sleep 1; busybox ash" + hold [Enter] to trigger.
+ * We sent "ESC [ 6 n", but got '\n' first, and
+ * KEYCODE_CURSOR_POS response is now buffered from terminal.
+ * It's bad already and not much can be done with it
+ * (it _will_ be visible for the next process to read stdin),
+ * but without this delay it even shows up on the screen
+ * as garbage because we restore echo settings with tcsetattr
+ * before it comes in. UGLY!
+ */
+ usleep(20*1000);
+ }
+#endif
+
+/* End of bug-catching "command_must_not_be_used" trick */
+#undef command
+
+#if ENABLE_UNICODE_SUPPORT
+ command[0] = '\0';
+ if (command_len > 0)
+ command_len = save_string(command, maxsize - 1);
+ free(command_ps);
+#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_all();
+
+ len = command_len;
+ DEINIT_S();
+
+ return len; /* can't return command_len, DEINIT_S() destroys it */
+}
+
+#else /* !FEATURE_EDITING */
+
+#undef read_line_input
+int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize)
+{
+ fputs(prompt, stdout);
+ fflush_all();
+ if (!fgets(command, maxsize, stdin))
+ return -1;
+ return strlen(command);
+}
+
+#endif /* !FEATURE_EDITING */
+
+
+/*
+ * Testing
+ */
+
+#ifdef TEST
+
+#include <locale.h>
+
+const char *applet_name = "debug stuff usage";
+
+int main(int argc, char **argv)
+{
+ char buff[MAX_LINELEN];
+ char *prompt =
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:"
+ "\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] "
+ "\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
+#else
+ "% ";
+#endif
+
+ 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/ap/app/busybox/src/libbb/lineedit_ptr_hack.c b/ap/app/busybox/src/libbb/lineedit_ptr_hack.c
new file mode 100644
index 0000000..dc45855
--- /dev/null
+++ b/ap/app/busybox/src/libbb/lineedit_ptr_hack.c
@@ -0,0 +1,23 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+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/ap/app/busybox/src/libbb/llist.c b/ap/app/busybox/src/libbb/llist.c
new file mode 100644
index 0000000..032e9fa
--- /dev/null
+++ b/ap/app/busybox/src/libbb/llist.c
@@ -0,0 +1,98 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * linked list helper functions.
+ *
+ * Copyright (C) 2003 Glenn McGrath
+ * Copyright (C) 2005 Vladimir Oleynik
+ * Copyright (C) 2005 Bernhard Reutner-Fischer
+ * Copyright (C) 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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/ap/app/busybox/src/libbb/login.c b/ap/app/busybox/src/libbb/login.c
new file mode 100644
index 0000000..8a82c6a
--- /dev/null
+++ b/ap/app/busybox/src/libbb/login.c
@@ -0,0 +1,132 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * issue.c: issue printing code
+ *
+ * Copyright (C) 2003 Bastian Blank <waldi@tuxbox.org>
+ *
+ * Optimize and correcting OCRNL by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+/* After libbb.h, since it needs sys/types.h on some systems */
+#include <sys/utsname.h>
+
+#define LOGIN " login: "
+
+static const char fmtstr_d[] ALIGN1 = "%A, %d %B %Y";
+static const char fmtstr_t[] ALIGN1 = "%H:%M:%S";
+
+void FAST_FUNC print_login_issue(const char *issue_file, const char *tty)
+{
+ FILE *fp;
+ int c;
+ char buf[256+1];
+ const char *outbuf;
+ time_t t;
+ struct utsname uts;
+
+ time(&t);
+ uname(&uts);
+
+ puts("\r"); /* start a new line */
+
+ 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';
+ }
+ 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;
+/* The field domainname of struct utsname is Linux specific. */
+#if defined(__linux__)
+ case 'D':
+ case 'o':
+ outbuf = uts.domainname;
+ break;
+#endif
+ 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;
+ }
+ }
+ fputs(outbuf, stdout);
+ }
+ fclose(fp);
+ fflush_all();
+}
+
+void FAST_FUNC print_login_prompt(void)
+{
+ char *hostname = safe_gethostname();
+
+ fputs(hostname, stdout);
+ fputs(LOGIN, stdout);
+ fflush_all();
+ 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/ap/app/busybox/src/libbb/loop.c b/ap/app/busybox/src/libbb/loop.c
new file mode 100644
index 0000000..823fba0
--- /dev/null
+++ b/ap/app/busybox/src/libbb/loop.c
@@ -0,0 +1,174 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+
+/* For 2.6, use the cleaned up header to get the 64 bit API. */
+// Commented out per Rob's request
+//# include "fix_u32.h" /* some old toolchains need __u64 for linux/loop.h */
+# include <linux/loop.h>
+typedef struct loop_info64 bb_loop_info;
+# define BB_LOOP_SET_STATUS LOOP_SET_STATUS64
+# define BB_LOOP_GET_STATUS LOOP_GET_STATUS64
+
+#else
+
+/* For 2.4 and earlier, use the 32 bit API (and don't trust the headers) */
+/* Stuff stolen from linux/loop.h for 2.4 and earlier kernels */
+# include <linux/posix_types.h>
+# define LO_NAME_SIZE 64
+# define LO_KEY_SIZE 32
+# define LOOP_SET_FD 0x4C00
+# define LOOP_CLR_FD 0x4C01
+# define BB_LOOP_SET_STATUS 0x4C02
+# define BB_LOOP_GET_STATUS 0x4C03
+typedef struct {
+ int lo_number;
+ __kernel_dev_t lo_device;
+ unsigned long lo_inode;
+ __kernel_dev_t lo_rdevice;
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size;
+ int lo_flags;
+ char lo_file_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE];
+ unsigned long lo_init[2];
+ char reserved[4];
+} bb_loop_info;
+#endif
+
+char* FAST_FUNC query_loop(const char *device)
+{
+ int fd;
+ bb_loop_info loopinfo;
+ char *dev = NULL;
+
+ fd = open(device, O_RDONLY);
+ if (fd >= 0) {
+ if (ioctl(fd, BB_LOOP_GET_STATUS, &loopinfo) == 0) {
+ dev = xasprintf("%"OFF_FMT"u %s", (off_t) loopinfo.lo_offset,
+ (char *)loopinfo.lo_file_name);
+ }
+ close(fd);
+ }
+
+ return dev;
+}
+
+int FAST_FUNC del_loop(const char *device)
+{
+ int fd, rc;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ return 1;
+ rc = ioctl(fd, LOOP_CLR_FD, 0);
+ close(fd);
+
+ return rc;
+}
+
+/* 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, int ro)
+{
+ char dev[LOOP_NAMESIZE];
+ char *try;
+ bb_loop_info loopinfo;
+ struct stat statbuf;
+ int i, dfd, ffd, mode, rc = -1;
+
+ /* Open the file. Barf if this doesn't work. */
+ mode = ro ? O_RDONLY : O_RDWR;
+ ffd = open(file, mode);
+ if (ffd < 0) {
+ if (mode != O_RDONLY) {
+ mode = O_RDONLY;
+ ffd = open(file, mode);
+ }
+ if (ffd < 0)
+ return -errno;
+ }
+
+ /* Find a loop device. */
+ try = *device ? *device : dev;
+ /* 1048575 is a max possible minor number in Linux circa 2010 */
+ for (i = 0; rc && i < 1048576; i++) {
+ sprintf(dev, LOOP_FORMAT, i);
+
+ IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;)
+ if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) {
+ if (ENABLE_FEATURE_MOUNT_LOOP_CREATE
+ && errno == ENOENT
+ && try == dev
+ ) {
+ /* Node doesn't exist, try to create it. */
+ if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0)
+ goto try_to_open;
+ }
+ /* Ran out of block devices, return failure. */
+ rc = -ENOENT;
+ break;
+ }
+ try_to_open:
+ /* 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) == 0) {
+ if (ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo) == 0)
+ 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 == 0) {
+ if (!*device)
+ *device = xstrdup(dev);
+ return (mode == O_RDONLY); /* 1:ro, 0:rw */
+ }
+ return rc;
+}
diff --git a/ap/app/busybox/src/libbb/make_directory.c b/ap/app/busybox/src/libbb/make_directory.c
new file mode 100644
index 0000000..7826b90
--- /dev/null
+++ b/ap/app/busybox/src/libbb/make_directory.c
@@ -0,0 +1,134 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * parse_mode implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* Mar 5, 2003 Manuel Novoa III
+ *
+ * This is the main work function for the 'mkdir' applet. As such, it
+ * strives to be SUSv3 compliant in it's behaviour when recursively
+ * making missing parent dirs, and in it's mode setting of the final
+ * directory 'path'.
+ *
+ * To recursively build all missing intermediate directories, make
+ * sure that (flags & FILEUTILS_RECUR) is non-zero. Newly created
+ * intermediate directories will have at least u+wx perms.
+ *
+ * To set specific permissions on 'path', pass the appropriate 'mode'
+ * val. Otherwise, pass -1 to get default permissions.
+ */
+
+#include "libbb.h"
+
+/* This function is used from NOFORK applets. It must not allocate anything */
+
+int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
+{
+ mode_t cur_mask;
+ mode_t org_mask;
+ const char *fail_msg;
+ char *s;
+ char c;
+ struct stat st;
+
+ /* Happens on bb_make_directory(dirname("no_slashes"),...) */
+ if (LONE_CHAR(path, '.'))
+ return 0;
+
+ org_mask = cur_mask = (mode_t)-1L;
+ s = path;
+ 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;
+ }
+ }
+
+ if (c != '\0') {
+ /* Intermediate dirs: must have wx for user */
+ if (cur_mask == (mode_t)-1L) { /* wasn't done yet? */
+ mode_t new_mask;
+ org_mask = umask(0);
+ cur_mask = 0;
+ /* Clear u=wx in umask - this ensures
+ * they won't be cleared on mkdir */
+ new_mask = (org_mask & ~(mode_t)0300);
+ //bb_error_msg("org_mask:%o cur_mask:%o", org_mask, new_mask);
+ if (new_mask != cur_mask) {
+ cur_mask = new_mask;
+ umask(new_mask);
+ }
+ }
+ } else {
+ /* Last component: uses original umask */
+ //bb_error_msg("1 org_mask:%o", org_mask);
+ if (org_mask != cur_mask) {
+ cur_mask = org_mask;
+ umask(org_mask);
+ }
+ }
+
+ 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 && errno != EISDIR)
+ || !(flags & FILEUTILS_RECUR)
+ || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode))
+ ) {
+ fail_msg = "create";
+ 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) {
+ goto ret0;
+ }
+ }
+
+ 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";
+ if (flags & FILEUTILS_IGNORE_CHMOD_ERR) {
+ flags = 0;
+ goto print_err;
+ }
+ break;
+ }
+ goto ret0;
+ }
+
+ /* Remove any inserted nul from the path (recursive mode) */
+ *s = c;
+ } /* while (1) */
+
+ flags = -1;
+ print_err:
+ bb_perror_msg("can't %s directory '%s'", fail_msg, path);
+ goto ret;
+ ret0:
+ flags = 0;
+ ret:
+ //bb_error_msg("2 org_mask:%o", org_mask);
+ if (org_mask != cur_mask)
+ umask(org_mask);
+ return flags;
+}
diff --git a/ap/app/busybox/src/libbb/makedev.c b/ap/app/busybox/src/libbb/makedev.c
new file mode 100644
index 0000000..06c4039
--- /dev/null
+++ b/ap/app/busybox/src/libbb/makedev.c
@@ -0,0 +1,31 @@
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+/* We do not include libbb.h - #define makedev() is there! */
+#include "platform.h"
+
+/* Different Unixes want different headers for makedev */
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
+ || defined(__APPLE__)
+# include <sys/types.h>
+#else
+# include <features.h>
+# include <sys/sysmacros.h>
+#endif
+
+#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 major, unsigned minor);
+unsigned long long FAST_FUNC bb_makedev(unsigned major, unsigned minor)
+{
+ return makedev(major, minor);
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/match_fstype.c b/ap/app/busybox/src/libbb/match_fstype.c
new file mode 100644
index 0000000..32c3d7f
--- /dev/null
+++ b/ap/app/busybox/src/libbb/match_fstype.c
@@ -0,0 +1,46 @@
+/* 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 source tree.
+ */
+
+#include "libbb.h"
+
+#ifdef HAVE_MNTENT_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;
+}
+
+#endif /* HAVE_MNTENT_H */
diff --git a/ap/app/busybox/src/libbb/messages.c b/ap/app/busybox/src/libbb/messages.c
new file mode 100644
index 0000000..2545eed
--- /dev/null
+++ b/ap/app/busybox/src/libbb/messages.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* allow default system PATH to be extended via CFLAGS */
+#ifndef BB_ADDITIONAL_PATH
+#define BB_ADDITIONAL_PATH ""
+#endif
+
+/* allow version to be extended, via CFLAGS */
+#ifndef BB_EXTRA_VERSION
+#define BB_EXTRA_VERSION BB_BT
+#endif
+
+#define BANNER "BusyBox v" BB_VER " (" BB_EXTRA_VERSION ")"
+
+const char bb_banner[] ALIGN1 = BANNER;
+
+
+const char bb_msg_memory_exhausted[] ALIGN1 = "out of memory";
+const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'";
+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_you_must_be_root[] ALIGN1 = "you must be 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_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
+
+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 =
+#if ENABLE_INSTALL_TO_RECOVERY
+ "PATH=/recovery/sbin:/recovery/usr/sbin:/recovery/bin:/recovery/usr/bin" BB_ADDITIONAL_PATH;
+#else
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH;
+#endif
+
+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;
+
+#if ENABLE_FEATURE_WTMP
+/* 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
+#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/ap/app/busybox/src/libbb/missing_syscalls.c b/ap/app/busybox/src/libbb/missing_syscalls.c
new file mode 100644
index 0000000..dd430e3
--- /dev/null
+++ b/ap/app/busybox/src/libbb/missing_syscalls.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012, Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//kbuild:lib-y += missing_syscalls.o
+
+/*#include <linux/timex.h> - for struct timex, but may collide with <time.h> */
+#include <sys/syscall.h>
+#include "libbb.h"
+
+#if defined(ANDROID) || defined(__ANDROID__)
+pid_t getsid(pid_t pid)
+{
+ return syscall(__NR_getsid, pid);
+}
+
+int stime(const time_t *t)
+{
+ struct timeval tv;
+ tv.tv_sec = *t;
+ tv.tv_usec = 0;
+ return settimeofday(&tv, NULL);
+}
+
+int sethostname(const char *name, size_t len)
+{
+ return syscall(__NR_sethostname, name, len);
+}
+
+struct timex;
+int adjtimex(struct timex *buf)
+{
+ return syscall(__NR_adjtimex, buf);
+}
+
+int pivot_root(const char *new_root, const char *put_old)
+{
+ return syscall(__NR_pivot_root, new_root, put_old);
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/mode_string.c b/ap/app/busybox/src/libbb/mode_string.c
new file mode 100644
index 0000000..f1afe7d
--- /dev/null
+++ b/ap/app/busybox/src/libbb/mode_string.c
@@ -0,0 +1,128 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mode_string implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* Aug 13, 2003
+ * Fix a bug reported by junkio@cox.net involving the mode_chars index.
+ */
+
+
+#include <assert.h>
+#include <sys/stat.h>
+
+#include "libbb.h"
+
+#if ( S_ISUID != 04000 ) || ( S_ISGID != 02000 ) || ( S_ISVTX != 01000 ) \
+ || ( S_IRUSR != 00400 ) || ( S_IWUSR != 00200 ) || ( S_IXUSR != 00100 ) \
+ || ( S_IRGRP != 00040 ) || ( S_IWGRP != 00020 ) || ( S_IXGRP != 00010 ) \
+ || ( S_IROTH != 00004 ) || ( S_IWOTH != 00002 ) || ( S_IXOTH != 00001 )
+#error permission bitflag value assumption(s) violated!
+#endif
+
+#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \
+ || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 ) \
+ || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \
+ || ( S_IFIFO != 0010000 )
+#warning mode type bitflag value assumption(s) violated! falling back to larger version
+
+#if (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX) == 07777
+#undef mode_t
+#define mode_t unsigned short
+#endif
+
+static const mode_t mode_flags[] = {
+ S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID,
+ S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID,
+ S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX
+};
+
+/* The static const char arrays below are duplicated for the two cases
+ * because moving them ahead of the mode_flags declaration cause a text
+ * size increase with the gcc version I'm using. */
+
+/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
+ * and 'B' types don't appear to be available on linux. So I removed them. */
+static const char type_chars[16] ALIGN1 = "?pc?d?b?-?l?s???";
+/***************************************** 0123456789abcdef */
+static const char mode_chars[7] ALIGN1 = "rwxSTst";
+
+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);
+
+ /* Note: We don't bother with nul termination because bss initialization
+ * should have taken care of that for us. If the user scribbled in buf
+ * memory, they deserve whatever happens. But we'll at least assert. */
+ assert(buf[10] == 0);
+
+ return buf;
+}
+
+#else
+
+/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
+ * and 'B' types don't appear to be available on linux. So I removed them. */
+static const char type_chars[16] = "?pc?d?b?-?l?s???";
+/********************************** 0123456789abcdef */
+static const char mode_chars[7] = "rwxSTst";
+
+const char* 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/ap/app/busybox/src/libbb/mtab.c b/ap/app/busybox/src/libbb/mtab.c
new file mode 100644
index 0000000..22bff64
--- /dev/null
+++ b/ap/app/busybox/src/libbb/mtab.c
@@ -0,0 +1,55 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include <mntent.h>
+#include "libbb.h"
+
+#if ENABLE_FEATURE_MTAB_SUPPORT
+void FAST_FUNC erase_mtab(const char *name)
+{
+ struct mntent *entries;
+ int i, count;
+ FILE *mountTable;
+ struct mntent *m;
+
+ 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 = 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);
+
+//TODO: make update atomic
+ mountTable = setmntent(bb_path_mtab_file, "w");
+ if (mountTable) {
+ for (i = 0; i < count; i++) {
+ 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)
+ bb_perror_msg(bb_path_mtab_file);
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/obscure.c b/ap/app/busybox/src/libbb/obscure.c
new file mode 100644
index 0000000..9ecc1f6
--- /dev/null
+++ b/ap/app/busybox/src/libbb/obscure.c
@@ -0,0 +1,184 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini weak password checker implementation for busybox
+ *
+ * Copyright (C) 2006 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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 "libbb.h"
+
+static int string_checker_helper(const char *p1, const char *p2) __attribute__ ((__pure__));
+
+static int string_checker_helper(const char *p1, const char *p2)
+{
+ /* as sub-string */
+ if (strcasestr(p2, p1) != NULL
+ /* invert in case haystack is shorter than needle */
+ || strcasestr(p1, p2) != NULL
+ /* as-is or capitalized */
+ /* || strcasecmp(p1, p2) == 0 - 1st strcasestr should catch this too */
+ ) {
+ return 1;
+ }
+ return 0;
+}
+
+static int string_checker(const char *p1, const char *p2)
+{
+ int size, i;
+ /* check string */
+ int ret = string_checker_helper(p1, p2);
+ /* make our own copy */
+ char *p = xstrdup(p1);
+
+ /* reverse string */
+ i = size = strlen(p1);
+ while (--i >= 0) {
+ *p++ = p1[i];
+ }
+ p -= size; /* restore pointer */
+
+ /* check reversed string */
+ ret |= string_checker_helper(p, p2);
+
+ /* clean up */
+ memset(p, 0, size);
+ free(p);
+
+ return ret;
+}
+
+#define CATEGORIES 4
+
+#define LOWERCASE 1
+#define UPPERCASE 2
+#define NUMBERS 4
+#define SPECIAL 8
+
+#define LAST_CAT 8
+
+static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw)
+{
+ unsigned length;
+ unsigned size;
+ unsigned mixed;
+ unsigned c;
+ unsigned i;
+ const char *p;
+ char *hostname;
+
+ /* size */
+ if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN)
+ return "too short";
+
+ /* no username as-is, as sub-string, reversed, capitalized, doubled */
+ if (string_checker(new_p, pw->pw_name)) {
+ return "similar to username";
+ }
+#ifndef __BIONIC__
+ /* no gecos as-is, as sub-string, reversed, capitalized, doubled */
+ if (pw->pw_gecos[0] && string_checker(new_p, pw->pw_gecos)) {
+ return "similar to gecos";
+ }
+#endif
+ /* 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: */
+ mixed = 0;
+ 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;
+ }
+ /* Count i'th char */
+ c = 0;
+ p = new_p;
+ while (1) {
+ p = strchr(p, new_p[i]);
+ if (p == NULL) {
+ break;
+ }
+ c++;
+ p++;
+ if (!*p) {
+ break;
+ }
+ }
+ /* More than 50% similar characters ? */
+ if (c*2 >= length) {
+ return "too many similar characters";
+ }
+ }
+
+ size = CONFIG_PASSWORD_MINLEN + 2*CATEGORIES;
+ for (i = 1; i <= LAST_CAT; i <<= 1)
+ if (mixed & i)
+ size -= 2;
+ if (length < size)
+ return "too weak";
+
+ if (old_p && old_p[0]) {
+ /* check vs. old password */
+ if (string_checker(new_p, old_p)) {
+ return "similar to old password";
+ }
+ }
+
+ return NULL;
+}
+
+int FAST_FUNC obscure(const char *old, const char *newval, const struct passwd *pw)
+{
+ const char *msg;
+
+ msg = obscure_msg(old, newval, pw);
+ if (msg) {
+ printf("Bad password: %s\n", msg);
+ return 1;
+ }
+ return 0;
+}
diff --git a/ap/app/busybox/src/libbb/parse_config.c b/ap/app/busybox/src/libbb/parse_config.c
new file mode 100644
index 0000000..1590d9a
--- /dev/null
+++ b/ap/app/busybox/src/libbb/parse_config.c
@@ -0,0 +1,243 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * config file parser helper
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later.
+ */
+
+/* Uncomment to enable test applet */
+////config:config PARSE
+////config: bool "Uniform config file parser debugging applet: parse"
+////config: default n
+////config: help
+////config: Typical usage of parse API:
+////config: char *t[3];
+////config: parser_t *p = config_open(filename);
+////config: while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens
+////config: bb_error_msg("TOKENS: '%s''%s''%s'", t[0], t[1], t[2]);
+////config: }
+////config: config_close(p);
+
+////applet:IF_PARSE(APPLET(parse, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-y += parse_config.o
+
+//usage:#define parse_trivial_usage
+//usage: "[-x] [-n MAXTOKENS] [-m MINTOKENS] [-d DELIMS] [-f FLAGS] FILE..."
+//usage:#define parse_full_usage "\n\n"
+//usage: " -x Suppress output (for benchmarking)"
+
+#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";
+ char **t;
+ unsigned flags = PARSE_NORMAL;
+ int mintokens = 0, ntokens = 128;
+ unsigned noout;
+
+ opt_complementary = "-1:n+:m+:f+";
+ noout = 1 & getopt32(argv, "xn:m:d:f:", &ntokens, &mintokens, &delims, &flags);
+ //argc -= optind;
+ argv += optind;
+
+ t = xmalloc(sizeof(t[0]) * ntokens);
+ while (*argv) {
+ int n;
+ parser_t *p = config_open(*argv);
+ while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) {
+ if (!noout) {
+ for (int i = 0; i < n; ++i)
+ printf("[%s]", t[i]);
+ puts("");
+ }
+ }
+ config_close(p);
+ argv++;
+ }
+ return EXIT_SUCCESS;
+}
+#endif
+
+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);
+}
+
+void FAST_FUNC config_close(parser_t *parser)
+{
+ if (parser) {
+ if (PARSE_KEEP_COPY) /* compile-time constant */
+ free(parser->data);
+ fclose(parser->fp);
+ free(parser->line);
+ free(parser->nline);
+ free(parser);
+ }
+}
+
+/* This function reads an entire line from a text file,
+ * up to a newline, exclusive.
+ * Trailing '\' is recognized as line continuation.
+ * Returns -1 if EOF/error.
+ */
+static int get_line_with_continuation(parser_t *parser)
+{
+ ssize_t len, nlen;
+ char *line;
+
+ len = getline(&parser->line, &parser->line_alloc, parser->fp);
+ if (len <= 0)
+ return len;
+
+ line = parser->line;
+ for (;;) {
+ parser->lineno++;
+ if (line[len - 1] == '\n')
+ len--;
+ if (len == 0 || line[len - 1] != '\\')
+ break;
+ len--;
+
+ nlen = getline(&parser->nline, &parser->nline_alloc, parser->fp);
+ if (nlen <= 0)
+ break;
+
+ if (parser->line_alloc < len + nlen + 1) {
+ parser->line_alloc = len + nlen + 1;
+ line = parser->line = xrealloc(line, parser->line_alloc);
+ }
+ memcpy(&line[len], parser->nline, nlen);
+ len += nlen;
+ }
+
+ line[len] = '\0';
+ return len;
+}
+
+
+/*
+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 character.
+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;
+
+ if (!parser)
+ return 0;
+
+ ntokens = (uint8_t)flags;
+ mintokens = (uint8_t)(flags >> 8);
+
+ again:
+ memset(tokens, 0, sizeof(tokens[0]) * ntokens);
+
+ /* Read one line (handling continuations with backslash) */
+ if (get_line_with_continuation(parser) < 0)
+ return 0;
+
+ line = parser->line;
+
+ /* 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) {
+ free(parser->data);
+ parser->data = xstrdup(line);
+ }
+
+ /* Tokenize the line */
+ t = 0;
+ do {
+ /* 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, PARSE_EOL_COMMENTS ? delims[0] : '\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 == delims[0])
+ *line = '\0';
+ else if (*line != '\0')
+ *line++ = '\0';
+
+#if 0 /* unused so far */
+ if (flags & PARSE_ESCAPE) {
+ strcpy_and_process_escape_sequences(tokens[t], tokens[t]);
+ }
+#endif
+ /* Skip possible delimiters */
+ if (flags & PARSE_COLLAPSE)
+ line += strspn(line, delims + 1);
+
+ t++;
+ } while (*line && *line != delims[0] && t < ntokens);
+
+ 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/ap/app/busybox/src/libbb/parse_mode.c b/ap/app/busybox/src/libbb/parse_mode.c
new file mode 100644
index 0000000..5a4e1c5
--- /dev/null
+++ b/ap/app/busybox/src/libbb/parse_mode.c
@@ -0,0 +1,150 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * parse_mode implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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)
+
+int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode)
+{
+ static const mode_t who_mask[] = {
+ S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
+ S_ISUID | S_IRWXU, /* u */
+ S_ISGID | S_IRWXG, /* g */
+ S_IRWXO /* o */
+ };
+ static const mode_t perm_mask[] = {
+ S_IRUSR | S_IRGRP | S_IROTH, /* r */
+ S_IWUSR | S_IWGRP | S_IWOTH, /* w */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* x */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
+ S_ISUID | S_ISGID, /* s */
+ S_ISVTX /* t */
+ };
+ static const char who_chars[] ALIGN1 = "augo";
+ static const char perm_chars[] ALIGN1 = "rwxXst";
+
+ const char *p;
+ mode_t wholist;
+ mode_t permlist;
+ mode_t new_mode;
+ char op;
+
+ if ((unsigned char)(*s - '0') < 8) {
+ unsigned long tmp;
+ char *e;
+
+ tmp = strtoul(s, &e, 8);
+ if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
+ return 0;
+ }
+ *current_mode = tmp;
+ 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;
+ }
+
+ /* Get a wholist. */
+ wholist = 0;
+ WHO_LIST:
+ p = who_chars;
+ do {
+ if (*p == *s) {
+ wholist |= who_mask[(int)(p-who_chars)];
+ if (!*++s) {
+ return 0;
+ }
+ goto WHO_LIST;
+ }
+ } while (*++p);
+
+ do { /* Process action list. */
+ if ((*s != '+') && (*s != '-')) {
+ if (*s != '=') {
+ return 0;
+ }
+ /* Since op is '=', clear all bits corresponding to the
+ * wholist, or all file bits if wholist is empty. */
+ permlist = ~FILEMODEBITS;
+ if (wholist) {
+ permlist = ~wholist;
+ }
+ new_mode &= permlist;
+ }
+ op = *s++;
+
+ /* Check for permcopy. */
+ p = who_chars + 1; /* Skip 'a' entry. */
+ do {
+ if (*p == *s) {
+ int i = 0;
+ permlist = who_mask[(int)(p-who_chars)]
+ & (S_IRWXU | S_IRWXG | S_IRWXO)
+ & new_mode;
+ do {
+ if (permlist & perm_mask[i]) {
+ permlist |= perm_mask[i];
+ }
+ } while (++i < 3);
+ ++s;
+ goto GOT_ACTION;
+ }
+ } while (*++p);
+
+ /* It was not a permcopy, so get a permlist. */
+ permlist = 0;
+ PERM_LIST:
+ p = perm_chars;
+ do {
+ if (*p == *s) {
+ if ((*p != 'X')
+ || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
+ ) {
+ permlist |= perm_mask[(int)(p-perm_chars)];
+ }
+ if (!*++s) {
+ break;
+ }
+ goto PERM_LIST;
+ }
+ } while (*++p);
+ GOT_ACTION:
+ if (permlist) { /* The permlist was nonempty. */
+ mode_t tmp = 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 != ','));
+ }
+
+ *current_mode = new_mode;
+ return 1;
+}
diff --git a/ap/app/busybox/src/libbb/percent_decode.c b/ap/app/busybox/src/libbb/percent_decode.c
new file mode 100644
index 0000000..9a9d80c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/percent_decode.c
@@ -0,0 +1,69 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//kbuild:lib-y += percent_decode.o
+
+#include "libbb.h"
+
+static unsigned hex_to_bin(unsigned char c)
+{
+ unsigned v;
+
+ v = c - '0';
+ if (v <= 9)
+ return v;
+ /* c | 0x20: letters to lower case, non-letters
+ * to (potentially different) non-letters */
+ v = (unsigned)(c | 0x20) - 'a';
+ if (v <= 5)
+ return v + 10;
+ return ~0;
+/* For testing:
+void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
+int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');
+t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
+*/
+}
+
+char* FAST_FUNC percent_decode_in_place(char *str, int strict)
+{
+ /* note that decoded string is always shorter than original */
+ char *src = str;
+ char *dst = str;
+ char c;
+
+ while ((c = *src++) != '\0') {
+ unsigned v;
+
+ if (!strict && c == '+') {
+ *dst++ = ' ';
+ continue;
+ }
+ if (c != '%') {
+ *dst++ = c;
+ continue;
+ }
+ v = hex_to_bin(src[0]);
+ if (v > 15) {
+ bad_hex:
+ if (strict)
+ return NULL;
+ *dst++ = '%';
+ continue;
+ }
+ v = (v * 16) | hex_to_bin(src[1]);
+ if (v > 255)
+ goto bad_hex;
+ if (strict && (v == '/' || v == '\0')) {
+ /* caller takes it as indication of invalid
+ * (dangerous wrt exploits) chars */
+ return str + 1;
+ }
+ *dst++ = v;
+ src += 2;
+ }
+ *dst = '\0';
+ return str;
+}
diff --git a/ap/app/busybox/src/libbb/perror_msg.c b/ap/app/busybox/src/libbb/perror_msg.c
new file mode 100644
index 0000000..fa1f0d3
--- /dev/null
+++ b/ap/app/busybox/src/libbb/perror_msg.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+void FAST_FUNC bb_perror_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ /* Guard against "<error message>: Success" */
+ bb_verror_msg(s, p, errno ? strerror(errno) : NULL);
+ va_end(p);
+}
+
+void FAST_FUNC bb_perror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ /* Guard against "<error message>: Success" */
+ bb_verror_msg(s, p, errno ? strerror(errno) : NULL);
+ va_end(p);
+ xfunc_die();
+}
+
+void FAST_FUNC bb_simple_perror_msg(const char *s)
+{
+ bb_perror_msg("%s", s);
+}
+
+void FAST_FUNC bb_simple_perror_msg_and_die(const char *s)
+{
+ bb_perror_msg_and_die("%s", s);
+}
diff --git a/ap/app/busybox/src/libbb/perror_nomsg.c b/ap/app/busybox/src/libbb/perror_nomsg.c
new file mode 100644
index 0000000..a2a11cc
--- /dev/null
+++ b/ap/app/busybox/src/libbb/perror_nomsg.c
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_perror_nomsg implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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;
+
+/* suppress gcc "no previous prototype" warning */
+void FAST_FUNC bb_perror_nomsg(void);
+void FAST_FUNC bb_perror_nomsg(void)
+{
+ bb_perror_msg(0);
+}
diff --git a/ap/app/busybox/src/libbb/perror_nomsg_and_die.c b/ap/app/busybox/src/libbb/perror_nomsg_and_die.c
new file mode 100644
index 0000000..543ff51
--- /dev/null
+++ b/ap/app/busybox/src/libbb/perror_nomsg_and_die.c
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_perror_nomsg_and_die implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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;
+
+/* suppress gcc "no previous prototype" warning */
+void FAST_FUNC bb_perror_nomsg_and_die(void);
+void FAST_FUNC bb_perror_nomsg_and_die(void)
+{
+ bb_perror_msg_and_die(0);
+}
diff --git a/ap/app/busybox/src/libbb/pidfile.c b/ap/app/busybox/src/libbb/pidfile.c
new file mode 100644
index 0000000..a48dfc3
--- /dev/null
+++ b/ap/app/busybox/src/libbb/pidfile.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * pid file routines
+ *
+ * Copyright (C) 2007 by Stephane Billiart <stephane.billiart@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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/ap/app/busybox/src/libbb/platform.c b/ap/app/busybox/src/libbb/platform.c
new file mode 100644
index 0000000..2bf34f5
--- /dev/null
+++ b/ap/app/busybox/src/libbb/platform.c
@@ -0,0 +1,176 @@
+/*
+ * Replacements for common but usually nonstandard functions that aren't
+ * supplied by all platforms.
+ *
+ * Copyright (C) 2009 by Dan Fandrich <dan@coneharvesters.com>, et. al.
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+#ifndef HAVE_STRCHRNUL
+char* FAST_FUNC strchrnul(const char *s, int c)
+{
+ while (*s != '\0' && *s != c)
+ s++;
+ return (char*)s;
+}
+#endif
+
+#ifndef HAVE_VASPRINTF
+int FAST_FUNC vasprintf(char **string_ptr, const char *format, va_list p)
+{
+ int r;
+ va_list p2;
+ char buf[128];
+
+ va_copy(p2, p);
+ r = vsnprintf(buf, 128, format, p);
+ va_end(p);
+
+ if (r < 128) {
+ va_end(p2);
+ *string_ptr = xstrdup(buf);
+ return r;
+ }
+
+ *string_ptr = xmalloc(r+1);
+ r = vsnprintf(*string_ptr, r+1, format, p2);
+ va_end(p2);
+
+ return r;
+}
+#endif
+
+#ifndef HAVE_DPRINTF
+/* dprintf is now part of POSIX.1, but was only added in 2008 */
+int dprintf(int fd, const char *format, ...)
+{
+ va_list p;
+ int r;
+ char *string_ptr;
+
+ va_start(p, format);
+ r = vasprintf(&string_ptr, format, p);
+ va_end(p);
+ if (r >= 0) {
+ r = full_write(fd, string_ptr, r);
+ free(string_ptr);
+ }
+ return r;
+}
+#endif
+
+#ifndef HAVE_MEMRCHR
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+ * memrchr() is a GNU function that might not be available everywhere.
+ * It's basically the inverse of memchr() - search backwards in a
+ * memory block for a particular character.
+ */
+void* FAST_FUNC memrchr(const void *s, int c, size_t n)
+{
+ const char *start = s, *end = s;
+
+ end += n - 1;
+
+ while (end >= start) {
+ if (*end == (char)c)
+ return (void *) end;
+ end--;
+ }
+
+ return NULL;
+}
+#endif
+
+#ifndef HAVE_MKDTEMP
+/* This is now actually part of POSIX.1, but was only added in 2008 */
+char* FAST_FUNC mkdtemp(char *template)
+{
+ if (mktemp(template) == NULL || mkdir(template, 0700) != 0)
+ return NULL;
+ return template;
+}
+#endif
+
+#ifndef HAVE_STRCASESTR
+/* Copyright (c) 1999, 2000 The ht://Dig Group */
+char* FAST_FUNC strcasestr(const char *s, const char *pattern)
+{
+ int length = strlen(pattern);
+
+ while (*s) {
+ if (strncasecmp(s, pattern, length) == 0)
+ return (char *)s;
+ s++;
+ }
+ return 0;
+}
+#endif
+
+#ifndef HAVE_STRSEP
+/* Copyright (C) 2004 Free Software Foundation, Inc. */
+char* FAST_FUNC strsep(char **stringp, const char *delim)
+{
+ char *start = *stringp;
+ char *ptr;
+
+ if (!start)
+ return NULL;
+
+ if (!*delim)
+ ptr = start + strlen(start);
+ else {
+ ptr = strpbrk(start, delim);
+ if (!ptr) {
+ *stringp = NULL;
+ return start;
+ }
+ }
+
+ *ptr = '\0';
+ *stringp = ptr + 1;
+
+ return start;
+}
+#endif
+
+#ifndef HAVE_STPCPY
+char* FAST_FUNC stpcpy(char *p, const char *to_add)
+{
+ while ((*p = *to_add) != '\0') {
+ p++;
+ to_add++;
+ }
+ return p;
+}
+#endif
+
+#ifndef HAVE_GETLINE
+ssize_t FAST_FUNC getline(char **lineptr, size_t *n, FILE *stream)
+{
+ int ch;
+ char *line = *lineptr;
+ size_t alloced = *n;
+ size_t len = 0;
+
+ do {
+ ch = fgetc(stream);
+ if (ch == EOF)
+ break;
+ if (len + 1 >= alloced) {
+ alloced += alloced/4 + 64;
+ line = xrealloc(line, alloced);
+ }
+ line[len++] = ch;
+ } while (ch != '\n');
+
+ if (len == 0)
+ return -1;
+
+ line[len] = '\0';
+ *lineptr = line;
+ *n = alloced;
+ return len;
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/print_flags.c b/ap/app/busybox/src/libbb/print_flags.c
new file mode 100644
index 0000000..eaec731
--- /dev/null
+++ b/ap/app/busybox/src/libbb/print_flags.c
@@ -0,0 +1,31 @@
+/* vi: set sw=4 ts=4: */
+/* Print string that matches bit masked flags
+ *
+ * Copyright (C) 2008 Natanael Copa <natanael.copa@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+/* returns a set with the flags not printed */
+int FAST_FUNC print_flags_separated(const int *masks, const char *labels, int flags, const char *separator)
+{
+ const char *need_separator = NULL;
+ while (*labels) {
+ if (flags & *masks) {
+ printf("%s%s",
+ need_separator ? need_separator : "",
+ labels);
+ need_separator = separator;
+ flags &= ~ *masks;
+ }
+ masks++;
+ labels += strlen(labels) + 1;
+ }
+ return flags;
+}
+
+int FAST_FUNC print_flags(const masks_labels_t *ml, int flags)
+{
+ return print_flags_separated(ml->masks, ml->labels, flags, NULL);
+}
diff --git a/ap/app/busybox/src/libbb/printable.c b/ap/app/busybox/src/libbb/printable.c
new file mode 100644
index 0000000..f6ada49
--- /dev/null
+++ b/ap/app/busybox/src/libbb/printable.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#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/ap/app/busybox/src/libbb/printable_string.c b/ap/app/busybox/src/libbb/printable_string.c
new file mode 100644
index 0000000..a316f60
--- /dev/null
+++ b/ap/app/busybox/src/libbb/printable_string.c
@@ -0,0 +1,65 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Unicode support routines.
+ *
+ * Copyright (C) 2010 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include "unicode.h"
+
+const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
+{
+ static char *saved[4];
+ static unsigned cur_saved; /* = 0 */
+
+ char *dst;
+ const char *s;
+
+ s = str;
+ while (1) {
+ unsigned char c = *s;
+ if (c == '\0') {
+ /* 99+% of inputs do not need conversion */
+ if (stats) {
+ stats->byte_count = (s - str);
+ stats->unicode_count = (s - str);
+ stats->unicode_width = (s - str);
+ }
+ return str;
+ }
+ if (c < ' ')
+ break;
+ if (c >= 0x7f)
+ break;
+ s++;
+ }
+
+#if ENABLE_UNICODE_SUPPORT
+ dst = unicode_conv_to_printable(stats, str);
+#else
+ {
+ char *d = dst = xstrdup(str);
+ while (1) {
+ unsigned char c = *d;
+ if (c == '\0')
+ break;
+ if (c < ' ' || c >= 0x7f)
+ *d = '?';
+ d++;
+ }
+ if (stats) {
+ stats->byte_count = (d - dst);
+ stats->unicode_count = (d - dst);
+ stats->unicode_width = (d - dst);
+ }
+ }
+#endif
+
+ free(saved[cur_saved]);
+ saved[cur_saved] = dst;
+ cur_saved = (cur_saved + 1) & (ARRAY_SIZE(saved)-1);
+
+ return dst;
+}
diff --git a/ap/app/busybox/src/libbb/process_escape_sequence.c b/ap/app/busybox/src/libbb/process_escape_sequence.c
new file mode 100644
index 0000000..346ecfa
--- /dev/null
+++ b/ap/app/busybox/src/libbb/process_escape_sequence.c
@@ -0,0 +1,112 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) Manuel Novoa III <mjn3@codepoet.org>
+ * and Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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 FAST_FUNC bb_process_escape_sequence(const char **ptr)
+{
+ const char *q;
+ unsigned num_digits;
+ unsigned n;
+ unsigned base;
+
+ num_digits = n = 0;
+ base = 8;
+ q = *ptr;
+
+ if (WANT_HEX_ESCAPES && *q == 'x') {
+ ++q;
+ base = 16;
+ ++num_digits;
+ }
+
+ /* bash requires leading 0 in octal escapes:
+ * \02 works, \2 does not (prints \ and 2).
+ * We treat \2 as a valid octal escape sequence. */
+ do {
+ unsigned r;
+#if !WANT_HEX_ESCAPES
+ unsigned d = (unsigned char)(*q) - '0';
+#else
+ unsigned d = (unsigned char)_tolower(*q) - '0';
+ if (d >= 10)
+ d += ('0' - 'a' + 10);
+#endif
+ if (d >= base) {
+ if (WANT_HEX_ESCAPES && base == 16) {
+ --num_digits;
+ if (num_digits == 0) {
+ /* \x<bad_char>: return '\',
+ * leave ptr pointing to x */
+ return '\\';
+ }
+ }
+ break;
+ }
+
+ r = n * base + d;
+ if (r > UCHAR_MAX) {
+ break;
+ }
+
+ n = r;
+ ++q;
+ } while (++num_digits < 3);
+
+ if (num_digits == 0) {
+ /* Not octal or hex escape sequence.
+ * Is it one-letter one? */
+
+ /* bash builtin "echo -e '\ec'" interprets \e as ESC,
+ * but coreutils "/bin/echo -e '\ec'" does not.
+ * Manpages tend to support coreutils way.
+ * Update: coreutils added support for \e on 28 Oct 2009. */
+ 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 = charmap;
+ do {
+ if (*p == *q) {
+ q++;
+ break;
+ }
+ } while (*++p != '\0');
+ /* p points to found escape char or NUL,
+ * advance it and find what it translates to.
+ * Note that \NUL and unrecognized sequence \z return '\'
+ * and leave ptr pointing to NUL or z. */
+ n = p[sizeof(charmap) / 2];
+ }
+
+ *ptr = q;
+
+ return (char) n;
+}
+
+char* FAST_FUNC strcpy_and_process_escape_sequences(char *dst, const char *src)
+{
+ while (1) {
+ char c, c1;
+ c = c1 = *src++;
+ if (c1 == '\\')
+ c1 = bb_process_escape_sequence(&src);
+ *dst = c1;
+ if (c == '\0')
+ return dst;
+ dst++;
+ }
+}
diff --git a/ap/app/busybox/src/libbb/procps.c b/ap/app/busybox/src/libbb/procps.c
new file mode 100644
index 0000000..5b68d34
--- /dev/null
+++ b/ap/app/busybox/src/libbb/procps.c
@@ -0,0 +1,659 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright 1998 by Albert Cahalan; all rights reserved.
+ * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
+ * SELinux support: (c) 2007 by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+
+typedef struct id_to_name_map_t {
+ uid_t id;
+ char name[USERNAME_MAX_SIZE];
+} id_to_name_map_t;
+
+typedef struct cache_t {
+ id_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, uid_t 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, uid_t id,
+ char* FAST_FUNC x2x_utoa(uid_t 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);
+#if ENABLE_FEATURE_SHOW_THREADS
+ if (sp->task_dir)
+ closedir(sp->task_dir);
+#endif
+ free(sp->argv0);
+ free(sp->exe);
+ IF_SELINUX(free(sp->context);)
+ free(sp);
+}
+
+#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
+static unsigned long fast_strtoul_16(char **endptr)
+{
+ unsigned char c;
+ char *str = *endptr;
+ unsigned long n = 0;
+
+ /* Need to stop on both ' ' and '\n' */
+ 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;
+}
+#endif
+
+#if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
+/* We cut a lot of corners here for speed */
+static unsigned long fast_strtoul_10(char **endptr)
+{
+ unsigned char c;
+ char *str = *endptr;
+ unsigned long n = *str - '0';
+
+ /* Need to stop on both ' ' and '\n' */
+ while ((c = *++str) > ' ')
+ n = n*10 + (c - '0');
+
+ *endptr = str + 1; /* We skip trailing space! */
+ return n;
+}
+
+# if ENABLE_FEATURE_FAST_TOP
+static long fast_strtol_10(char **endptr)
+{
+ if (**endptr != '-')
+ return fast_strtoul_10(endptr);
+
+ (*endptr)++;
+ return - (long)fast_strtoul_10(endptr);
+}
+# endif
+
+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
+
+#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
+int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
+ void (*cb)(struct smaprec *, void *), void *data)
+{
+ FILE *file;
+ struct smaprec currec;
+ char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3];
+ char buf[PROCPS_BUFSIZE];
+#if !ENABLE_PMAP
+ void (*cb)(struct smaprec *, void *) = NULL;
+ void *data = NULL;
+#endif
+
+ sprintf(filename, "/proc/%u/smaps", (int)pid);
+
+ file = fopen_for_read(filename);
+ if (!file)
+ return 1;
+
+ memset(&currec, 0, sizeof(currec));
+ while (fgets(buf, PROCPS_BUFSIZE, file)) {
+ // Each mapping datum has this form:
+ // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
+ // Size: nnn kB
+ // Rss: nnn kB
+ // .....
+
+ char *tp = buf, *p;
+
+#define SCAN(S, X) \
+ if (strncmp(tp, S, sizeof(S)-1) == 0) { \
+ tp = skip_whitespace(tp + sizeof(S)-1); \
+ total->X += currec.X = fast_strtoul_10(&tp); \
+ continue; \
+ }
+ if (cb) {
+ SCAN("Pss:" , smap_pss );
+ SCAN("Swap:" , smap_swap );
+ }
+ SCAN("Private_Dirty:", private_dirty);
+ SCAN("Private_Clean:", private_clean);
+ SCAN("Shared_Dirty:" , shared_dirty );
+ SCAN("Shared_Clean:" , shared_clean );
+#undef SCAN
+ tp = strchr(buf, '-');
+ if (tp) {
+ // We reached next mapping - the line of this form:
+ // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
+
+ if (cb) {
+ /* If we have a previous record, there's nothing more
+ * for it, call the callback and clear currec
+ */
+ if (currec.smap_size)
+ cb(&currec, data);
+ free(currec.smap_name);
+ }
+ memset(&currec, 0, sizeof(currec));
+
+ *tp = ' ';
+ tp = buf;
+ currec.smap_start = fast_strtoul_16(&tp);
+ currec.smap_size = (fast_strtoul_16(&tp) - currec.smap_start) >> 10;
+
+ strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1);
+
+ // skipping "rw-s FILEOFS M:m INODE "
+ 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 (currec.smap_mode[1] == 'w') {
+ currec.mapped_rw = currec.smap_size;
+ total->mapped_rw += currec.smap_size;
+ } else if (currec.smap_mode[1] == '-') {
+ currec.mapped_ro = currec.smap_size;
+ total->mapped_ro += currec.smap_size;
+ }
+ }
+
+ if (strcmp(tp, "[stack]\n") == 0)
+ total->stack += currec.smap_size;
+ if (cb) {
+ p = skip_non_whitespace(tp);
+ if (p == tp) {
+ currec.smap_name = xstrdup(" [ anon ]");
+ } else {
+ *p = '\0';
+ currec.smap_name = xstrdup(tp);
+ }
+ }
+ total->smap_size += currec.smap_size;
+ }
+ }
+ fclose(file);
+
+ if (cb) {
+ if (currec.smap_size)
+ cb(&currec, data);
+ free(currec.smap_name);
+ }
+
+ return 0;
+}
+#endif
+
+void BUG_comm_size(void);
+procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
+{
+ if (!sp)
+ sp = alloc_procps_scan();
+
+ for (;;) {
+ struct dirent *entry;
+ char buf[PROCPS_BUFSIZE];
+ long tasknice;
+ unsigned pid;
+ int n;
+ char filename[sizeof("/proc/%u/task/%u/cmdline") + sizeof(int)*3 * 2];
+ char *filename_tail;
+
+#if ENABLE_FEATURE_SHOW_THREADS
+ if (sp->task_dir) {
+ entry = readdir(sp->task_dir);
+ if (entry)
+ goto got_entry;
+ closedir(sp->task_dir);
+ sp->task_dir = NULL;
+ }
+#endif
+ entry = readdir(sp->dir);
+ if (entry == NULL) {
+ free_procps_scan(sp);
+ return NULL;
+ }
+ IF_FEATURE_SHOW_THREADS(got_entry:)
+ pid = bb_strtou(entry->d_name, NULL, 10);
+ if (errno)
+ continue;
+#if ENABLE_FEATURE_SHOW_THREADS
+ if ((flags & PSSCAN_TASKS) && !sp->task_dir) {
+ /* We found another /proc/PID. Do not use it,
+ * there will be /proc/PID/task/PID (same PID!),
+ * so just go ahead and dive into /proc/PID/task. */
+ sprintf(filename, "/proc/%u/task", pid);
+ /* Note: if opendir fails, we just go to next /proc/XXX */
+ sp->task_dir = opendir(filename);
+ sp->main_thread_pid = pid;
+ continue;
+ }
+#endif
+
+ /* After this point we can:
+ * "break": stop parsing, return the data
+ * "continue": try next /proc/XXX
+ */
+
+ memset(&sp->vsz, 0, sizeof(*sp) - offsetof(procps_status_t, vsz));
+
+ sp->pid = pid;
+ if (!(flags & ~PSSCAN_PID))
+ break; /* we needed only pid, we got it */
+
+#if ENABLE_SELINUX
+ if (flags & PSSCAN_CONTEXT) {
+ if (getpidcon(sp->pid, &sp->context) < 0)
+ sp->context = NULL;
+ }
+#endif
+
+#if ENABLE_FEATURE_SHOW_THREADS
+ if (sp->task_dir)
+ filename_tail = filename + sprintf(filename, "/proc/%u/task/%u/", sp->main_thread_pid, pid);
+ else
+#endif
+ filename_tail = filename + sprintf(filename, "/proc/%u/", pid);
+
+ if (flags & PSSCAN_UIDGID) {
+ struct stat sb;
+ if (stat(filename, &sb))
+ continue; /* process probably exited */
+ /* Effective UID/GID, not real */
+ sp->uid = sb.st_uid;
+ sp->gid = sb.st_gid;
+ }
+
+ /* These are all retrieved from proc/NN/stat in one go: */
+ if (flags & (PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID
+ | PSSCAN_COMM | PSSCAN_STATE
+ | PSSCAN_VSZ | PSSCAN_RSS
+ | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME
+ | PSSCAN_TTY | PSSCAN_NICE
+ | PSSCAN_CPU)
+ ) {
+ 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)
+ continue; /* process probably exited */
+ cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
+ /*if (!cp || cp[1] != ' ')
+ continue;*/
+ 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
+ );
+
+ if (n < 11)
+ continue; /* bogus data, get next /proc/XXX */
+# if ENABLE_FEATURE_TOP_SMP_PROCESS
+ if (n == 11)
+ sp->last_seen_on_cpu = 0;
+# endif
+
+ /* 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
+/* 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_strtol_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
+#endif /* FEATURE_FAST_TOP */
+
+#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
+ sp->niceness = tasknice;
+#endif
+
+ 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)
+ procps_read_smaps(pid, &sp->smaps, NULL, NULL);
+#endif /* TOPMEM */
+#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
+ if (flags & PSSCAN_RUIDGID) {
+ FILE *file;
+
+ strcpy(filename_tail, "status");
+ file = fopen_for_read(filename);
+ if (file) {
+ while (fgets(buf, sizeof(buf), file)) {
+ char *tp;
+#define SCAN_TWO(str, name, statement) \
+ if (strncmp(buf, str, sizeof(str)-1) == 0) { \
+ tp = skip_whitespace(buf + sizeof(str)-1); \
+ sscanf(tp, "%u", &sp->name); \
+ statement; \
+ }
+ SCAN_TWO("Uid:", ruid, continue);
+ SCAN_TWO("Gid:", rgid, break);
+#undef SCAN_TWO
+ }
+ fclose(file);
+ }
+ }
+#endif /* PS_ADDITIONAL_COLUMNS */
+ if (flags & PSSCAN_EXE) {
+ strcpy(filename_tail, "exe");
+ free(sp->exe);
+ sp->exe = xmalloc_readlink(filename);
+ }
+ /* Note: if /proc/PID/cmdline is empty,
+ * code below "breaks". Therefore it must be
+ * the last code to parse /proc/PID/xxx data
+ * (we used to have /proc/PID/exe parsing after it
+ * and were getting stale sp->exe).
+ */
+#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);
+ }
+ }
+#endif
+ break;
+ } /* for (;;) */
+
+ return sp;
+}
+
+void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
+{
+ int sz;
+ char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
+
+ sprintf(filename, "/proc/%u/cmdline", pid);
+ sz = open_read_close(filename, buf, col - 1);
+ if (sz > 0) {
+ const char *base;
+ int comm_len;
+
+ buf[sz] = '\0';
+ while (--sz >= 0 && buf[sz] == '\0')
+ continue;
+ /* Prevent basename("process foo/bar") = "bar" */
+ strchrnul(buf, ' ')[0] = '\0';
+ base = bb_basename(buf); /* before we replace argv0's NUL with space */
+ while (sz >= 0) {
+ if ((unsigned char)(buf[sz]) < ' ')
+ buf[sz] = ' ';
+ sz--;
+ }
+
+ /* If comm differs from argv0, prepend "{comm} ".
+ * It allows to see thread names set by prctl(PR_SET_NAME).
+ */
+ if (base[0] == '-') /* "-sh" (login shell)? */
+ base++;
+ comm_len = strlen(comm);
+ /* Why compare up to comm_len, not COMM_LEN-1?
+ * Well, some processes rewrite argv, and use _spaces_ there
+ * while rewriting. (KDE is observed to do it).
+ * I prefer to still treat argv0 "process foo bar"
+ * as 'equal' to comm "process".
+ */
+ if (strncmp(base, comm, comm_len) != 0) {
+ comm_len += 3;
+ if (col > comm_len)
+ memmove(buf + comm_len, buf, col - comm_len);
+ snprintf(buf, col, "{%s}", comm);
+ if (col <= comm_len)
+ return;
+ buf[comm_len - 1] = ' ';
+ buf[col - 1] = '\0';
+ }
+
+ } 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/ap/app/busybox/src/libbb/progress.c b/ap/app/busybox/src/libbb/progress.c
new file mode 100644
index 0000000..372feb0
--- /dev/null
+++ b/ap/app/busybox/src/libbb/progress.c
@@ -0,0 +1,207 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Progress bar code.
+ */
+/* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
+ * much of which was blatantly stolen from openssh.
+ */
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. BSD Advertising Clause omitted per the July 22, 1999 licensing change
+ * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
+ *
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "libbb.h"
+#include "unicode.h"
+
+enum {
+ /* Seconds when xfer considered "stalled" */
+ STALLTIME = 5
+};
+
+static unsigned int get_tty2_width(void)
+{
+ unsigned width;
+ get_terminal_width_height(2, &width, NULL);
+ return width;
+}
+
+void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile)
+{
+#if ENABLE_UNICODE_SUPPORT
+ init_unicode();
+ p->curfile = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20);
+#else
+ p->curfile = curfile;
+#endif
+ p->start_sec = monotonic_sec();
+ p->last_update_sec = p->start_sec;
+ p->last_change_sec = p->start_sec;
+ p->last_size = 0;
+}
+
+/* File already had beg_size bytes.
+ * Then we started downloading.
+ * We downloaded "transferred" bytes so far.
+ * Download is expected to stop when total size (beg_size + transferred)
+ * will be "totalsize" bytes.
+ * If totalsize == 0, then it is unknown.
+ */
+void FAST_FUNC bb_progress_update(bb_progress_t *p,
+ uoff_t beg_size,
+ uoff_t transferred,
+ uoff_t totalsize)
+{
+ uoff_t beg_and_transferred;
+ unsigned since_last_update, elapsed;
+ int barlength;
+ int kiloscale;
+
+ //transferred = 1234; /* use for stall detection testing */
+ //totalsize = 0; /* use for unknown size download testing */
+
+ elapsed = monotonic_sec();
+ since_last_update = elapsed - p->last_update_sec;
+ p->last_update_sec = elapsed;
+
+ if (totalsize != 0 && transferred >= totalsize - beg_size) {
+ /* Last call. Do not skip this update */
+ transferred = totalsize - beg_size; /* sanitize just in case */
+ }
+ else if (since_last_update == 0) {
+ /*
+ * Do not update on every call
+ * (we can be called on every network read!)
+ */
+ return;
+ }
+
+ kiloscale = 0;
+ /*
+ * Scale sizes down if they are close to overflowing.
+ * This allows calculations like (100 * transferred / totalsize)
+ * without risking overflow: we guarantee 10 highest bits to be 0.
+ * Introduced error is less than 1 / 2^12 ~= 0.025%
+ */
+ if (ULONG_MAX > 0xffffffff || sizeof(off_t) == 4 || sizeof(off_t) != 8) {
+ /*
+ * 64-bit CPU || small off_t: in either case,
+ * >> is cheap, single-word operation.
+ * ... || strange off_t: also use this code
+ * (it is safe, just suboptimal wrt code size),
+ * because 32/64 optimized one works only for 64-bit off_t.
+ */
+ if (totalsize >= (1 << 22)) {
+ totalsize >>= 10;
+ beg_size >>= 10;
+ transferred >>= 10;
+ kiloscale = 1;
+ }
+ } else {
+ /* 32-bit CPU and 64-bit off_t.
+ * Use a 40-bit shift, it is easier to do on 32-bit CPU.
+ */
+/* ONE suppresses "warning: shift count >= width of type" */
+#define ONE (sizeof(off_t) > 4)
+ if (totalsize >= (uoff_t)(1ULL << 54*ONE)) {
+ totalsize = (uint32_t)(totalsize >> 32*ONE) >> 8;
+ beg_size = (uint32_t)(beg_size >> 32*ONE) >> 8;
+ transferred = (uint32_t)(transferred >> 32*ONE) >> 8;
+ kiloscale = 4;
+ }
+ }
+
+ if (ENABLE_UNICODE_SUPPORT)
+ fprintf(stderr, "\r%s", p->curfile);
+ else
+ fprintf(stderr, "\r%-20.20s", p->curfile);
+
+ beg_and_transferred = beg_size + transferred;
+
+ if (totalsize != 0) {
+ unsigned ratio = 100 * beg_and_transferred / totalsize;
+ fprintf(stderr, "%4u%%", ratio);
+
+ barlength = get_tty2_width() - 49;
+ if (barlength > 0) {
+ /* god bless gcc for variable arrays :) */
+ char buf[barlength + 1];
+ unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize;
+ memset(buf, ' ', barlength);
+ buf[barlength] = '\0';
+ memset(buf, '*', stars);
+ fprintf(stderr, " |%s|", buf);
+ }
+ }
+
+ while (beg_and_transferred >= 100000) {
+ beg_and_transferred >>= 10;
+ kiloscale++;
+ }
+ /* see http://en.wikipedia.org/wiki/Tera */
+ fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]);
+#define beg_and_transferred dont_use_beg_and_transferred_below()
+
+ since_last_update = elapsed - p->last_change_sec;
+ if ((unsigned)transferred != p->last_size) {
+ p->last_change_sec = elapsed;
+ p->last_size = (unsigned)transferred;
+ if (since_last_update >= STALLTIME) {
+ /* We "cut out" these seconds from elapsed time
+ * by adjusting start time */
+ p->start_sec += since_last_update;
+ }
+ since_last_update = 0; /* we are un-stalled now */
+ }
+
+ elapsed -= p->start_sec; /* now it's "elapsed since start" */
+
+ if (since_last_update >= STALLTIME) {
+ fprintf(stderr, " - stalled -");
+ } else if (!totalsize || !transferred || (int)elapsed < 0) {
+ fprintf(stderr, " --:--:-- ETA");
+ } else {
+ unsigned eta, secs, hours;
+
+ totalsize -= beg_size; /* now it's "total to upload" */
+
+ /* Estimated remaining time =
+ * estimated_sec_to_dl_totalsize_bytes - elapsed_sec =
+ * totalsize / average_bytes_sec_so_far - elapsed =
+ * totalsize / (transferred/elapsed) - elapsed =
+ * totalsize * elapsed / transferred - elapsed
+ */
+ eta = totalsize * elapsed / transferred - elapsed;
+ if (eta >= 1000*60*60)
+ eta = 1000*60*60 - 1;
+ secs = eta % 3600;
+ hours = eta / 3600;
+ fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60);
+ }
+}
diff --git a/ap/app/busybox/src/libbb/ptr_to_globals.c b/ap/app/busybox/src/libbb/ptr_to_globals.c
new file mode 100644
index 0000000..1074538
--- /dev/null
+++ b/ap/app/busybox/src/libbb/ptr_to_globals.c
@@ -0,0 +1,35 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include <errno.h>
+
+struct globals;
+
+#ifndef GCC_COMBINE
+
+/* We cheat here. It is declared as const ptr in libbb.h,
+ * but here we make it live in R/W memory */
+struct globals *ptr_to_globals;
+
+#ifdef __GLIBC__
+int *bb_errno;
+#endif
+
+
+#else
+
+
+/* gcc -combine will see through and complain */
+/* Using alternative method which is more likely to break
+ * on weird architectures, compilers, linkers and so on */
+struct globals *const ptr_to_globals __attribute__ ((section (".data")));
+
+#ifdef __GLIBC__
+int *const bb_errno __attribute__ ((section (".data")));
+#endif
+
+#endif
diff --git a/ap/app/busybox/src/libbb/pw_encrypt.c b/ap/app/busybox/src/libbb/pw_encrypt.c
new file mode 100644
index 0000000..39ffa08
--- /dev/null
+++ b/ap/app/busybox/src/libbb/pw_encrypt.c
@@ -0,0 +1,148 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* static const uint8_t ascii64[] =
+ * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ */
+
+static int i64c(int i)
+{
+ 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 */)
+{
+ /* was: x += ... */
+ int x = getpid() + monotonic_us();
+ 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;
+}
+
+char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo)
+{
+ int len = 2/2;
+ char *salt_ptr = salt;
+ if (algo[0] != 'd') { /* not des */
+ len = 8/2; /* so far assuming md5 */
+ *salt_ptr++ = '$';
+ *salt_ptr++ = '1';
+ *salt_ptr++ = '$';
+#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA
+ if (algo[0] == 's') { /* sha */
+ salt[1] = '5' + (strcmp(algo, "sha512") == 0);
+ len = 16/2;
+ }
+#endif
+ }
+ crypt_make_salt(salt_ptr, len);
+ return salt_ptr;
+}
+
+#if ENABLE_USE_BB_CRYPT
+
+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
+ }
+
+ 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/ap/app/busybox/src/libbb/pw_encrypt_des.c b/ap/app/busybox/src/libbb/pw_encrypt_des.c
new file mode 100644
index 0000000..c8e02dd
--- /dev/null
+++ b/ap/app/busybox/src/libbb/pw_encrypt_des.c
@@ -0,0 +1,820 @@
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * All rights reserved.
+ *
+ * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
+ * this file should now *only* export crypt(), in order to make
+ * binaries of libcrypt exportable from the USA
+ *
+ * Adapted for FreeBSD-4.0 by Mark R V Murray
+ * this file should now *only* export crypt_des(), in order to make
+ * a module that can be optionally included in libcrypt.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ * B. Schneier, Applied Cryptography: protocols, algorithms,
+ * and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author). A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * ARCHITECTURE ASSUMPTIONS:
+ * It is assumed that the 8-byte arrays passed by reference can be
+ * addressed as arrays of uint32_t's (ie. the CPU is not picky about
+ * alignment).
+ */
+
+
+/* Parts busybox doesn't need or had optimized */
+#define USE_PRECOMPUTED_u_sbox 1
+#define USE_REPETITIVE_SPEEDUP 0
+#define USE_ip_mask 0
+#define USE_de_keys 0
+
+
+/* A pile of data */
+static const uint8_t IP[64] = {
+ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+static const uint8_t key_perm[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+static const uint8_t key_shifts[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static const uint8_t comp_perm[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * No E box is used, as it's replaced by some ANDs, shifts, and ORs.
+ */
+#if !USE_PRECOMPUTED_u_sbox
+static const uint8_t sbox[8][64] = {
+ { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
+ },
+ { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
+ },
+ { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
+ },
+ { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
+ },
+ { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
+ },
+ { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
+ },
+ { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
+ },
+ { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
+ }
+};
+#else /* precomputed, with half-bytes packed into one byte */
+static const uint8_t u_sbox[8][32] = {
+ { 0x0e, 0xf4, 0x7d, 0x41, 0xe2, 0x2f, 0xdb, 0x18,
+ 0xa3, 0x6a, 0xc6, 0xbc, 0x95, 0x59, 0x30, 0x87,
+ 0xf4, 0xc1, 0x8e, 0x28, 0x4d, 0x96, 0x12, 0x7b,
+ 0x5f, 0xbc, 0x39, 0xe7, 0xa3, 0x0a, 0x65, 0xd0,
+ },
+ { 0x3f, 0xd1, 0x48, 0x7e, 0xf6, 0x2b, 0x83, 0xe4,
+ 0xc9, 0x07, 0x12, 0xad, 0x6c, 0x90, 0xb5, 0x5a,
+ 0xd0, 0x8e, 0xa7, 0x1b, 0x3a, 0xf4, 0x4d, 0x21,
+ 0xb5, 0x68, 0x7c, 0xc6, 0x09, 0x53, 0xe2, 0x9f,
+ },
+ { 0xda, 0x70, 0x09, 0x9e, 0x36, 0x43, 0x6f, 0xa5,
+ 0x21, 0x8d, 0x5c, 0xe7, 0xcb, 0xb4, 0xf2, 0x18,
+ 0x1d, 0xa6, 0xd4, 0x09, 0x68, 0x9f, 0x83, 0x70,
+ 0x4b, 0xf1, 0xe2, 0x3c, 0xb5, 0x5a, 0x2e, 0xc7,
+ },
+ { 0xd7, 0x8d, 0xbe, 0x53, 0x60, 0xf6, 0x09, 0x3a,
+ 0x41, 0x72, 0x28, 0xc5, 0x1b, 0xac, 0xe4, 0x9f,
+ 0x3a, 0xf6, 0x09, 0x60, 0xac, 0x1b, 0xd7, 0x8d,
+ 0x9f, 0x41, 0x53, 0xbe, 0xc5, 0x72, 0x28, 0xe4,
+ },
+ { 0xe2, 0xbc, 0x24, 0xc1, 0x47, 0x7a, 0xdb, 0x16,
+ 0x58, 0x05, 0xf3, 0xaf, 0x3d, 0x90, 0x8e, 0x69,
+ 0xb4, 0x82, 0xc1, 0x7b, 0x1a, 0xed, 0x27, 0xd8,
+ 0x6f, 0xf9, 0x0c, 0x95, 0xa6, 0x43, 0x50, 0x3e,
+ },
+ { 0xac, 0xf1, 0x4a, 0x2f, 0x79, 0xc2, 0x96, 0x58,
+ 0x60, 0x1d, 0xd3, 0xe4, 0x0e, 0xb7, 0x35, 0x8b,
+ 0x49, 0x3e, 0x2f, 0xc5, 0x92, 0x58, 0xfc, 0xa3,
+ 0xb7, 0xe0, 0x14, 0x7a, 0x61, 0x0d, 0x8b, 0xd6,
+ },
+ { 0xd4, 0x0b, 0xb2, 0x7e, 0x4f, 0x90, 0x18, 0xad,
+ 0xe3, 0x3c, 0x59, 0xc7, 0x25, 0xfa, 0x86, 0x61,
+ 0x61, 0xb4, 0xdb, 0x8d, 0x1c, 0x43, 0xa7, 0x7e,
+ 0x9a, 0x5f, 0x06, 0xf8, 0xe0, 0x25, 0x39, 0xc2,
+ },
+ { 0x1d, 0xf2, 0xd8, 0x84, 0xa6, 0x3f, 0x7b, 0x41,
+ 0xca, 0x59, 0x63, 0xbe, 0x05, 0xe0, 0x9c, 0x27,
+ 0x27, 0x1b, 0xe4, 0x71, 0x49, 0xac, 0x8e, 0xd2,
+ 0xf0, 0xc6, 0x9a, 0x0d, 0x3f, 0x53, 0x65, 0xb8,
+ },
+};
+#endif
+
+static const uint8_t pbox[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+static const uint32_t bits32[32] =
+{
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const uint8_t bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+
+static int
+ascii_to_bin(char ch)
+{
+ if (ch > 'z')
+ return 0;
+ if (ch >= 'a')
+ return (ch - 'a' + 38);
+ if (ch > 'Z')
+ return 0;
+ if (ch >= 'A')
+ return (ch - 'A' + 12);
+ if (ch > '9')
+ return 0;
+ if (ch >= '.')
+ return (ch - '.');
+ return 0;
+}
+
+
+/* Static stuff that stays resident and doesn't change after
+ * being initialized, and therefore doesn't need to be made
+ * reentrant. */
+struct const_des_ctx {
+#if USE_ip_mask
+ uint8_t init_perm[64]; /* referenced 2 times */
+#endif
+ uint8_t final_perm[64]; /* 2 times */
+ uint8_t m_sbox[4][4096]; /* 5 times */
+};
+#define C (*cctx)
+#define init_perm (C.init_perm )
+#define final_perm (C.final_perm)
+#define m_sbox (C.m_sbox )
+
+static struct const_des_ctx*
+const_des_init(void)
+{
+ unsigned i, j, b;
+ struct const_des_ctx *cctx;
+
+#if !USE_PRECOMPUTED_u_sbox
+ uint8_t u_sbox[8][64];
+
+ cctx = xmalloc(sizeof(*cctx));
+
+ /* Invert the S-boxes, reordering the input bits. */
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 64; j++) {
+ b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
+ u_sbox[i][j] = sbox[i][b];
+ }
+ }
+ for (i = 0; i < 8; i++) {
+ fprintf(stderr, "\t{\t");
+ for (j = 0; j < 64; j+=2)
+ fprintf(stderr, " 0x%02x,", u_sbox[i][j] + u_sbox[i][j+1]*16);
+ fprintf(stderr, "\n\t},\n");
+ }
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 64; i++)
+ for (j = 0; j < 64; j++)
+ m_sbox[b][(i << 6) | j] =
+ (uint8_t)((u_sbox[(b << 1)][i] << 4) |
+ u_sbox[(b << 1) + 1][j]);
+#else
+ cctx = xmalloc(sizeof(*cctx));
+
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 64; i++)
+ for (j = 0; j < 64; j++) {
+ uint8_t lo, hi;
+ hi = u_sbox[(b << 1)][i / 2];
+ if (!(i & 1))
+ hi <<= 4;
+ lo = u_sbox[(b << 1) + 1][j / 2];
+ if (j & 1)
+ lo >>= 4;
+ m_sbox[b][(i << 6) | j] = (hi & 0xf0) | (lo & 0x0f);
+ }
+#endif
+
+ /*
+ * Set up the initial & final permutations into a useful form.
+ */
+ for (i = 0; i < 64; i++) {
+ final_perm[i] = IP[i] - 1;
+#if USE_ip_mask
+ init_perm[final_perm[i]] = (uint8_t)i;
+#endif
+ }
+
+ return cctx;
+}
+
+
+struct des_ctx {
+ const struct const_des_ctx *const_ctx;
+ uint32_t saltbits; /* referenced 5 times */
+#if USE_REPETITIVE_SPEEDUP
+ uint32_t old_salt; /* 3 times */
+ uint32_t old_rawkey0, old_rawkey1; /* 3 times each */
+#endif
+ uint8_t un_pbox[32]; /* 2 times */
+ uint8_t inv_comp_perm[56]; /* 3 times */
+ uint8_t inv_key_perm[64]; /* 3 times */
+ uint32_t en_keysl[16], en_keysr[16]; /* 2 times each */
+#if USE_de_keys
+ uint32_t de_keysl[16], de_keysr[16]; /* 2 times each */
+#endif
+#if USE_ip_mask
+ uint32_t ip_maskl[8][256], ip_maskr[8][256]; /* 9 times each */
+#endif
+ uint32_t fp_maskl[8][256], fp_maskr[8][256]; /* 9 times each */
+ uint32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; /* 9 times */
+ uint32_t comp_maskl[8][128], comp_maskr[8][128]; /* 9 times each */
+ uint32_t psbox[4][256]; /* 5 times */
+};
+#define D (*ctx)
+#define const_ctx (D.const_ctx )
+#define saltbits (D.saltbits )
+#define old_salt (D.old_salt )
+#define old_rawkey0 (D.old_rawkey0 )
+#define old_rawkey1 (D.old_rawkey1 )
+#define un_pbox (D.un_pbox )
+#define inv_comp_perm (D.inv_comp_perm )
+#define inv_key_perm (D.inv_key_perm )
+#define en_keysl (D.en_keysl )
+#define en_keysr (D.en_keysr )
+#define de_keysl (D.de_keysl )
+#define de_keysr (D.de_keysr )
+#define ip_maskl (D.ip_maskl )
+#define ip_maskr (D.ip_maskr )
+#define fp_maskl (D.fp_maskl )
+#define fp_maskr (D.fp_maskr )
+#define key_perm_maskl (D.key_perm_maskl )
+#define key_perm_maskr (D.key_perm_maskr )
+#define comp_maskl (D.comp_maskl )
+#define comp_maskr (D.comp_maskr )
+#define psbox (D.psbox )
+
+static struct des_ctx*
+des_init(struct des_ctx *ctx, const struct const_des_ctx *cctx)
+{
+ int i, j, b, k, inbit, obit;
+ uint32_t p;
+ const uint32_t *bits28, *bits24;
+
+ if (!ctx)
+ ctx = xmalloc(sizeof(*ctx));
+ const_ctx = cctx;
+
+#if USE_REPETITIVE_SPEEDUP
+ old_rawkey0 = old_rawkey1 = 0;
+ old_salt = 0;
+#endif
+ saltbits = 0;
+ bits28 = bits32 + 4;
+ bits24 = bits28 + 4;
+
+ /* Initialise the inverted key permutation. */
+ for (i = 0; i < 64; i++) {
+ inv_key_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key permutation and initialise the inverted key
+ * compression permutation.
+ */
+ for (i = 0; i < 56; i++) {
+ inv_key_perm[key_perm[i] - 1] = (uint8_t)i;
+ inv_comp_perm[i] = 255;
+ }
+
+ /* Invert the key compression permutation. */
+ for (i = 0; i < 48; i++) {
+ inv_comp_perm[comp_perm[i] - 1] = (uint8_t)i;
+ }
+
+ /*
+ * Set up the OR-mask arrays for the initial and final permutations,
+ * and for the key initial and compression permutations.
+ */
+ for (k = 0; k < 8; k++) {
+ uint32_t il, ir;
+ uint32_t fl, fr;
+ for (i = 0; i < 256; i++) {
+#if USE_ip_mask
+ il = 0;
+ ir = 0;
+#endif
+ fl = 0;
+ fr = 0;
+ for (j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j]) {
+#if USE_ip_mask
+ obit = init_perm[inbit];
+ if (obit < 32)
+ il |= bits32[obit];
+ else
+ ir |= bits32[obit - 32];
+#endif
+ obit = final_perm[inbit];
+ if (obit < 32)
+ fl |= bits32[obit];
+ else
+ fr |= bits32[obit - 32];
+ }
+ }
+#if USE_ip_mask
+ ip_maskl[k][i] = il;
+ ip_maskr[k][i] = ir;
+#endif
+ fp_maskl[k][i] = fl;
+ fp_maskr[k][i] = fr;
+ }
+ for (i = 0; i < 128; i++) {
+ il = 0;
+ ir = 0;
+ for (j = 0; j < 7; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j + 1]) {
+ obit = inv_key_perm[inbit];
+ if (obit == 255)
+ continue;
+ if (obit < 28)
+ il |= bits28[obit];
+ else
+ ir |= bits28[obit - 28];
+ }
+ }
+ key_perm_maskl[k][i] = il;
+ key_perm_maskr[k][i] = ir;
+ il = 0;
+ ir = 0;
+ for (j = 0; j < 7; j++) {
+ inbit = 7 * k + j;
+ if (i & bits8[j + 1]) {
+ obit = inv_comp_perm[inbit];
+ if (obit == 255)
+ continue;
+ if (obit < 24)
+ il |= bits24[obit];
+ else
+ ir |= bits24[obit - 24];
+ }
+ }
+ comp_maskl[k][i] = il;
+ comp_maskr[k][i] = ir;
+ }
+ }
+
+ /*
+ * Invert the P-box permutation, and convert into OR-masks for
+ * handling the output of the S-box arrays setup above.
+ */
+ for (i = 0; i < 32; i++)
+ un_pbox[pbox[i] - 1] = (uint8_t)i;
+
+ for (b = 0; b < 4; b++) {
+ for (i = 0; i < 256; i++) {
+ p = 0;
+ for (j = 0; j < 8; j++) {
+ if (i & bits8[j])
+ p |= bits32[un_pbox[8 * b + j]];
+ }
+ psbox[b][i] = p;
+ }
+ }
+
+ return ctx;
+}
+
+
+static void
+setup_salt(struct des_ctx *ctx, uint32_t salt)
+{
+ uint32_t obit, saltbit;
+ int i;
+
+#if USE_REPETITIVE_SPEEDUP
+ if (salt == old_salt)
+ return;
+ old_salt = salt;
+#endif
+
+ saltbits = 0;
+ saltbit = 1;
+ obit = 0x800000;
+ for (i = 0; i < 24; i++) {
+ if (salt & saltbit)
+ saltbits |= obit;
+ saltbit <<= 1;
+ obit >>= 1;
+ }
+}
+
+static void
+des_setkey(struct des_ctx *ctx, const char *key)
+{
+ uint32_t k0, k1, rawkey0, rawkey1;
+ int shifts, round;
+
+ rawkey0 = ntohl(*(const uint32_t *) key);
+ rawkey1 = ntohl(*(const uint32_t *) (key + 4));
+
+#if USE_REPETITIVE_SPEEDUP
+ if ((rawkey0 | rawkey1)
+ && rawkey0 == old_rawkey0
+ && rawkey1 == old_rawkey1
+ ) {
+ /*
+ * Already setup for this key.
+ * This optimisation fails on a zero key (which is weak and
+ * has bad parity anyway) in order to simplify the starting
+ * conditions.
+ */
+ return;
+ }
+ old_rawkey0 = rawkey0;
+ old_rawkey1 = rawkey1;
+#endif
+
+ /*
+ * Do key permutation and split into two 28-bit subkeys.
+ */
+ k0 = key_perm_maskl[0][rawkey0 >> 25]
+ | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskl[4][rawkey1 >> 25]
+ | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+ k1 = key_perm_maskr[0][rawkey0 >> 25]
+ | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskr[4][rawkey1 >> 25]
+ | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+ /*
+ * Rotate subkeys and do compression permutation.
+ */
+ shifts = 0;
+ for (round = 0; round < 16; round++) {
+ uint32_t t0, t1;
+
+ shifts += key_shifts[round];
+
+ t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+ t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+#if USE_de_keys
+ de_keysl[15 - round] =
+#endif
+ en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+ | comp_maskl[1][(t0 >> 14) & 0x7f]
+ | comp_maskl[2][(t0 >> 7) & 0x7f]
+ | comp_maskl[3][t0 & 0x7f]
+ | comp_maskl[4][(t1 >> 21) & 0x7f]
+ | comp_maskl[5][(t1 >> 14) & 0x7f]
+ | comp_maskl[6][(t1 >> 7) & 0x7f]
+ | comp_maskl[7][t1 & 0x7f];
+
+#if USE_de_keys
+ de_keysr[15 - round] =
+#endif
+ en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]
+ | comp_maskr[1][(t0 >> 14) & 0x7f]
+ | comp_maskr[2][(t0 >> 7) & 0x7f]
+ | comp_maskr[3][t0 & 0x7f]
+ | comp_maskr[4][(t1 >> 21) & 0x7f]
+ | comp_maskr[5][(t1 >> 14) & 0x7f]
+ | comp_maskr[6][(t1 >> 7) & 0x7f]
+ | comp_maskr[7][t1 & 0x7f];
+ }
+}
+
+
+static void
+do_des(struct des_ctx *ctx, /*uint32_t l_in, uint32_t r_in,*/ uint32_t *l_out, uint32_t *r_out, int count)
+{
+ const struct const_des_ctx *cctx = const_ctx;
+ /*
+ * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+ */
+ uint32_t l, r, *kl, *kr;
+ uint32_t f = f; /* silence gcc */
+ uint32_t r48l, r48r;
+ int round;
+
+ /* Do initial permutation (IP). */
+#if USE_ip_mask
+ uint32_t l_in = 0;
+ uint32_t r_in = 0;
+ l = ip_maskl[0][l_in >> 24]
+ | ip_maskl[1][(l_in >> 16) & 0xff]
+ | ip_maskl[2][(l_in >> 8) & 0xff]
+ | ip_maskl[3][l_in & 0xff]
+ | ip_maskl[4][r_in >> 24]
+ | ip_maskl[5][(r_in >> 16) & 0xff]
+ | ip_maskl[6][(r_in >> 8) & 0xff]
+ | ip_maskl[7][r_in & 0xff];
+ r = ip_maskr[0][l_in >> 24]
+ | ip_maskr[1][(l_in >> 16) & 0xff]
+ | ip_maskr[2][(l_in >> 8) & 0xff]
+ | ip_maskr[3][l_in & 0xff]
+ | ip_maskr[4][r_in >> 24]
+ | ip_maskr[5][(r_in >> 16) & 0xff]
+ | ip_maskr[6][(r_in >> 8) & 0xff]
+ | ip_maskr[7][r_in & 0xff];
+#elif 0 /* -65 bytes (using the fact that l_in == r_in == 0) */
+ l = r = 0;
+ for (round = 0; round < 8; round++) {
+ l |= ip_maskl[round][0];
+ r |= ip_maskr[round][0];
+ }
+ bb_error_msg("l:%x r:%x", l, r); /* reports 0, 0 always! */
+#else /* using the fact that ip_maskX[] is constant (written to by des_init) */
+ l = r = 0;
+#endif
+
+ do {
+ /* Do each round. */
+ kl = en_keysl;
+ kr = en_keysr;
+ round = 16;
+ do {
+ /* Expand R to 48 bits (simulate the E-box). */
+ r48l = ((r & 0x00000001) << 23)
+ | ((r & 0xf8000000) >> 9)
+ | ((r & 0x1f800000) >> 11)
+ | ((r & 0x01f80000) >> 13)
+ | ((r & 0x001f8000) >> 15);
+
+ r48r = ((r & 0x0001f800) << 7)
+ | ((r & 0x00001f80) << 5)
+ | ((r & 0x000001f8) << 3)
+ | ((r & 0x0000001f) << 1)
+ | ((r & 0x80000000) >> 31);
+ /*
+ * Do salting for crypt() and friends, and
+ * XOR with the permuted key.
+ */
+ f = (r48l ^ r48r) & saltbits;
+ r48l ^= f ^ *kl++;
+ r48r ^= f ^ *kr++;
+ /*
+ * Do sbox lookups (which shrink it back to 32 bits)
+ * and do the pbox permutation at the same time.
+ */
+ f = psbox[0][m_sbox[0][r48l >> 12]]
+ | psbox[1][m_sbox[1][r48l & 0xfff]]
+ | psbox[2][m_sbox[2][r48r >> 12]]
+ | psbox[3][m_sbox[3][r48r & 0xfff]];
+ /* Now that we've permuted things, complete f(). */
+ f ^= l;
+ l = r;
+ r = f;
+ } while (--round);
+ r = l;
+ l = f;
+ } while (--count);
+
+ /* Do final permutation (inverse of IP). */
+ *l_out = fp_maskl[0][l >> 24]
+ | fp_maskl[1][(l >> 16) & 0xff]
+ | fp_maskl[2][(l >> 8) & 0xff]
+ | fp_maskl[3][l & 0xff]
+ | fp_maskl[4][r >> 24]
+ | fp_maskl[5][(r >> 16) & 0xff]
+ | fp_maskl[6][(r >> 8) & 0xff]
+ | fp_maskl[7][r & 0xff];
+ *r_out = fp_maskr[0][l >> 24]
+ | fp_maskr[1][(l >> 16) & 0xff]
+ | fp_maskr[2][(l >> 8) & 0xff]
+ | fp_maskr[3][l & 0xff]
+ | fp_maskr[4][r >> 24]
+ | fp_maskr[5][(r >> 16) & 0xff]
+ | fp_maskr[6][(r >> 8) & 0xff]
+ | fp_maskr[7][r & 0xff];
+}
+
+#define DES_OUT_BUFSIZE 21
+
+static void
+to64_msb_first(char *s, unsigned v)
+{
+#if 0
+ *s++ = ascii64[(v >> 18) & 0x3f]; /* bits 23..18 */
+ *s++ = ascii64[(v >> 12) & 0x3f]; /* bits 17..12 */
+ *s++ = ascii64[(v >> 6) & 0x3f]; /* bits 11..6 */
+ *s = ascii64[v & 0x3f]; /* bits 5..0 */
+#endif
+ *s++ = i64c(v >> 18); /* bits 23..18 */
+ *s++ = i64c(v >> 12); /* bits 17..12 */
+ *s++ = i64c(v >> 6); /* bits 11..6 */
+ *s = i64c(v); /* bits 5..0 */
+}
+
+static char *
+NOINLINE
+des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
+ const unsigned char *key, const unsigned char *setting)
+{
+ uint32_t salt, r0, r1, keybuf[2];
+ uint8_t *q;
+
+ /*
+ * Copy the key, shifting each character up by one bit
+ * and padding with zeros.
+ */
+ q = (uint8_t *)keybuf;
+ while (q - (uint8_t *)keybuf != 8) {
+ *q = *key << 1;
+ if (*q)
+ key++;
+ q++;
+ }
+ des_setkey(ctx, (char *)keybuf);
+
+ /*
+ * setting - 2 bytes of salt
+ * key - up to 8 characters
+ */
+ salt = (ascii_to_bin(setting[1]) << 6)
+ | ascii_to_bin(setting[0]);
+
+ output[0] = setting[0];
+ /*
+ * If the encrypted password that the salt was extracted from
+ * is only 1 character long, the salt will be corrupted. We
+ * need to ensure that the output string doesn't have an extra
+ * NUL in it!
+ */
+ output[1] = setting[1] ? setting[1] : output[0];
+
+ setup_salt(ctx, salt);
+ /* Do it. */
+ do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */);
+
+ /* Now encode the result. */
+#if 0
+{
+ uint32_t l = (r0 >> 8);
+ q = (uint8_t *)output + 2;
+ *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 31..26 of r0 */
+ *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 25..20 of r0 */
+ *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 19..14 of r0 */
+ *q++ = ascii64[l & 0x3f]; /* bits 13..8 of r0 */
+ l = ((r0 << 16) | (r1 >> 16));
+ *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 7..2 of r0 */
+ *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 1..2 of r0 and 31..28 of r1 */
+ *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 27..22 of r1 */
+ *q++ = ascii64[l & 0x3f]; /* bits 21..16 of r1 */
+ l = r1 << 2;
+ *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 15..10 of r1 */
+ *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 9..4 of r1 */
+ *q++ = ascii64[l & 0x3f]; /* bits 3..0 of r1 + 00 */
+ *q = 0;
+}
+#else
+ /* Each call takes low-order 24 bits and stores 4 chars */
+ /* bits 31..8 of r0 */
+ to64_msb_first(output + 2, (r0 >> 8));
+ /* bits 7..0 of r0 and 31..16 of r1 */
+ to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16));
+ /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */
+ to64_msb_first(output + 10, (r1 << 8));
+ /* extra zero byte is encoded as '.', fixing it */
+ output[13] = '\0';
+#endif
+
+ return output;
+}
+
+#undef USE_PRECOMPUTED_u_sbox
+#undef USE_REPETITIVE_SPEEDUP
+#undef USE_ip_mask
+#undef USE_de_keys
+
+#undef C
+#undef init_perm
+#undef final_perm
+#undef m_sbox
+#undef D
+#undef const_ctx
+#undef saltbits
+#undef old_salt
+#undef old_rawkey0
+#undef old_rawkey1
+#undef un_pbox
+#undef inv_comp_perm
+#undef inv_key_perm
+#undef en_keysl
+#undef en_keysr
+#undef de_keysl
+#undef de_keysr
+#undef ip_maskl
+#undef ip_maskr
+#undef fp_maskl
+#undef fp_maskr
+#undef key_perm_maskl
+#undef key_perm_maskr
+#undef comp_maskl
+#undef comp_maskr
+#undef psbox
diff --git a/ap/app/busybox/src/libbb/pw_encrypt_md5.c b/ap/app/busybox/src/libbb/pw_encrypt_md5.c
new file mode 100644
index 0000000..889e09c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/pw_encrypt_md5.c
@@ -0,0 +1,161 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
+ *
+ * This code is the same as the code published by RSA Inc. It has been
+ * edited for clarity and style only.
+ *
+ * ----------------------------------------------------------------------------
+ * The md5_crypt() function was taken from freeBSD's libcrypt and contains
+ * this license:
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ *
+ * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
+ *
+ * ----------------------------------------------------------------------------
+ * On April 19th, 2001 md5_crypt() was modified to make it reentrant
+ * by Erik Andersen <andersen@uclibc.org>
+ *
+ *
+ * June 28, 2001 Manuel Novoa III
+ *
+ * "Un-inlined" code using loops and static const tables in order to
+ * reduce generated code size (on i386 from approx 4k to approx 2.5k).
+ *
+ * June 29, 2001 Manuel Novoa III
+ *
+ * Completely removed static PADDING array.
+ *
+ * Reintroduced the loop unrolling in MD5_Transform and added the
+ * MD5_SIZE_OVER_SPEED option for configurability. Define below as:
+ * 0 fully unrolled loops
+ * 1 partially unrolled (4 ops per loop)
+ * 2 no unrolling -- introduces the need to swap 4 variables (slow)
+ * 3 no unrolling and all 4 loops merged into one with switch
+ * in each loop (glacial)
+ * On i386, sizes are roughly (-Os -fno-builtin):
+ * 0: 3k 1: 2.5k 2: 2.2k 3: 2k
+ *
+ * Since SuSv3 does not require crypt_r, modified again August 7, 2002
+ * by Erik Andersen to remove reentrance stuff...
+ */
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+#define MD5_OUT_BUFSIZE 36
+static char *
+NOINLINE
+md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt)
+{
+ char *p;
+ unsigned char final[17]; /* final[16] exists only to aid in looping */
+ int sl, pl, i, pw_len;
+ md5_ctx_t ctx, ctx1;
+
+ /* NB: in busybox, "$1$" in salt is always present */
+
+ /* Refine the Salt first */
+
+ /* Get the length of the salt including "$1$" */
+ sl = 3;
+ while (salt[sl] && salt[sl] != '$' && sl < (3 + 8))
+ sl++;
+
+ /* Hash. the password first, since that is what is most unknown */
+ md5_begin(&ctx);
+ pw_len = strlen((char*)pw);
+ md5_hash(&ctx, pw, pw_len);
+
+ /* Then the salt including "$1$" */
+ md5_hash(&ctx, salt, sl);
+
+ /* 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(&ctx1, pw, pw_len);
+ md5_hash(&ctx1, salt, sl);
+ md5_hash(&ctx1, pw, pw_len);
+ md5_end(&ctx1, final);
+ for (pl = pw_len; pl > 0; pl -= 16)
+ md5_hash(&ctx, final, pl > 16 ? 16 : pl);
+
+ /* Then something really weird... */
+ memset(final, 0, sizeof(final));
+ for (i = pw_len; i; i >>= 1) {
+ md5_hash(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1);
+ }
+ md5_end(&ctx, final);
+
+ /* 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(&ctx1, pw, pw_len);
+ else
+ md5_hash(&ctx1, final, 16);
+
+ if (i % 3)
+ md5_hash(&ctx1, salt, sl);
+
+ if (i % 7)
+ md5_hash(&ctx1, pw, pw_len);
+
+ if (i & 1)
+ md5_hash(&ctx1, final, 16);
+ else
+ md5_hash(&ctx1, pw, pw_len);
+ md5_end(&ctx1, final);
+ }
+
+ 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/ap/app/busybox/src/libbb/pw_encrypt_sha.c b/ap/app/busybox/src/libbb/pw_encrypt_sha.c
new file mode 100644
index 0000000..8aeaaca
--- /dev/null
+++ b/ap/app/busybox/src/libbb/pw_encrypt_sha.c
@@ -0,0 +1,286 @@
+/* SHA256 and SHA512-based Unix crypt implementation.
+ * Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>.
+ */
+
+/* Prefix for optional rounds specification. */
+static const char str_rounds[] ALIGN1 = "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)(void *ctx, const void *buffer, size_t len) FAST_FUNC;
+ void (*sha_end)(void *ctx, void *resbuf) 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(&ctx, key_data, key_len);
+ sha_hash(&ctx, salt_data, salt_len);
+
+ /* 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(&alt_ctx, key_data, key_len);
+ sha_hash(&alt_ctx, salt_data, salt_len);
+ sha_hash(&alt_ctx, key_data, key_len);
+ sha_end(&alt_ctx, alt_result);
+
+ /* 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(&ctx, alt_result, _32or64);
+ sha_hash(&ctx, alt_result, cnt);
+
+ /* 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(&ctx, alt_result, _32or64);
+ else
+ sha_hash(&ctx, key_data, key_len);
+
+ /* Create intermediate result. */
+ sha_end(&ctx, alt_result);
+
+ /* 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(&alt_ctx, key_data, key_len);
+ sha_end(&alt_ctx, temp_result);
+
+ /* 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(&alt_ctx, salt_data, salt_len);
+ sha_end(&alt_ctx, temp_result);
+
+ /* 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(&ctx, p_bytes, key_len);
+ else
+ sha_hash(&ctx, alt_result, _32or64);
+ /* Add salt for numbers not divisible by 3. */
+ if (cnt % 3 != 0)
+ sha_hash(&ctx, s_bytes, salt_len);
+ /* Add key for numbers not divisible by 7. */
+ if (cnt % 7 != 0)
+ sha_hash(&ctx, p_bytes, key_len);
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ sha_hash(&ctx, alt_result, _32or64);
+ else
+ sha_hash(&ctx, p_bytes, key_len);
+
+ sha_end(&ctx, alt_result);
+ }
+
+ /* 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/ap/app/busybox/src/libbb/read.c b/ap/app/busybox/src/libbb/read.c
new file mode 100644
index 0000000..5906bc2
--- /dev/null
+++ b/ap/app/busybox/src/libbb/read.c
@@ -0,0 +1,72 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+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;
+}
+
+/*
+ * 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;
+}
+
+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);
+}
diff --git a/ap/app/busybox/src/libbb/read_key.c b/ap/app/busybox/src/libbb/read_key.c
new file mode 100644
index 0000000..ace23de
--- /dev/null
+++ b/ap/app/busybox/src/libbb/read_key.c
@@ -0,0 +1,281 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 Rob Landley <rob@landley.net>
+ * Copyright (C) 2008 Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
+{
+ struct pollfd pfd;
+ const char *seq;
+ int n;
+
+ /* Known escape sequences for cursor and function keys.
+ * See "Xterm Control Sequences"
+ * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ */
+ 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 */
+ /* ESC [ O 1 ; 2 P - Shift-F1 */
+ /* ESC [ O 1 ; 3 P - Alt-F1 */
+ /* ESC [ O 1 ; 4 P - Alt-Shift-F1 */
+ /* ESC [ O 1 ; 5 P - Ctrl-F1 */
+ /* ESC [ O 1 ; 6 P - Ctrl-Shift-F1 */
+ '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 ,
+ /* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift-<arrow> */
+ /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt-<arrow> - implemented below */
+ /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */
+ /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */
+ /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */
+ /* ESC [ 1 ; 7 x, where x = A/B/C/D: Ctrl-Alt-<arrow> */
+ /* ESC [ 1 ; 8 x, where x = A/B/C/D: Ctrl-Alt-Shift-<arrow> */
+ '[','H' |0x80,KEYCODE_HOME , /* xterm */
+ '[','F' |0x80,KEYCODE_END , /* xterm */
+ /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home (End similarly?) */
+ /* '[','Z' |0x80,KEYCODE_SHIFT_TAB, */
+ '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */
+ '[','2','~' |0x80,KEYCODE_INSERT ,
+ /* ESC [ 2 ; 3 ~ - Alt-Insert */
+ '[','3','~' |0x80,KEYCODE_DELETE ,
+ /* [ESC] ESC [ 3 [;2] ~ - [Alt-][Shift-]Delete */
+ /* ESC [ 3 ; 3 ~ - Alt-Delete */
+ /* ESC [ 3 ; 5 ~ - Ctrl-Delete */
+ '[','4','~' |0x80,KEYCODE_END , /* vt100? linux vt? or what? */
+ '[','5','~' |0x80,KEYCODE_PAGEUP ,
+ /* ESC [ 5 ; 3 ~ - Alt-PgUp */
+ /* ESC [ 5 ; 5 ~ - Ctrl-PgUp */
+ /* ESC [ 5 ; 7 ~ - Ctrl-Alt-PgUp */
+ '[','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 , /* old xterm, deprecated by ESC O P */
+ '[','1','2','~'|0x80,KEYCODE_FUN2 , /* old xterm... */
+ '[','1','3','~'|0x80,KEYCODE_FUN3 , /* old xterm... */
+ '[','1','4','~'|0x80,KEYCODE_FUN4 , /* old xterm... */
+ '[','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 ,
+ /* ESC [ 2 4 ; 2 ~ - Shift-F12 */
+ /* ESC [ 2 4 ; 3 ~ - Alt-F12 */
+ /* ESC [ 2 4 ; 4 ~ - Alt-Shift-F12 */
+ /* ESC [ 2 4 ; 5 ~ - Ctrl-F12 */
+ /* ESC [ 2 4 ; 6 ~ - Ctrl-Shift-F12 */
+#endif
+ /* '[','1',';','5','A' |0x80,KEYCODE_CTRL_UP , - unused */
+ /* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */
+ '[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT,
+ '[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT ,
+ /* '[','1',';','3','A' |0x80,KEYCODE_ALT_UP , - unused */
+ /* '[','1',';','3','B' |0x80,KEYCODE_ALT_DOWN , - unused */
+ '[','1',';','3','C' |0x80,KEYCODE_ALT_RIGHT,
+ '[','1',';','3','D' |0x80,KEYCODE_ALT_LEFT ,
+ /* '[','3',';','3','~' |0x80,KEYCODE_ALT_DELETE, - unused */
+ 0
+ };
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+
+ buffer++; /* saved chars counter is in buffer[-1] now */
+
+ start_over:
+ errno = 0;
+ n = (unsigned char)buffer[-1];
+ if (n == 0) {
+ /* If no data, wait for input.
+ * If requested, wait TIMEOUT ms. TIMEOUT = -1 is useful
+ * if fd can be in non-blocking mode.
+ */
+ if (timeout >= -1) {
+ if (safe_poll(&pfd, 1, timeout) == 0) {
+ /* Timed out */
+ errno = EAGAIN;
+ return -1;
+ }
+ }
+ /* It is tempting to read more than one byte here,
+ * but it breaks pasting. Example: at shell prompt,
+ * user presses "c","a","t" and then pastes "\nline\n".
+ * When we were reading 3 bytes here, we were eating
+ * "li" too, and cat was getting wrong input.
+ */
+ n = safe_read(fd, buffer, 1);
+ if (n <= 0)
+ return -1;
+ }
+
+ {
+ unsigned char c = buffer[0];
+ n--;
+ if (n)
+ memmove(buffer, buffer + 1, n);
+ /* Only ESC starts ESC sequences */
+ if (c != 27) {
+ buffer[-1] = n;
+ return c;
+ }
+ }
+
+ /* Loop through known ESC sequences */
+ 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 -
+ * anything later is longer than this seq.
+ * Break out of both loops. */
+ goto got_all;
+ }
+ 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) {
+ /* otherwise: it's EOF/error */
+ buffer[-1] = 0;
+ return -1;
+ }
+ goto got_all;
+ }
+ 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 */
+ n = 0;
+ /* n -= i; memmove(...);
+ * would be more correct,
+ * but we never read ahead that much,
+ * and n == i here. */
+ buffer[-1] = 0;
+ return (signed char)seq[i+1];
+ }
+ i++;
+ }
+ }
+ /* We did not find matching sequence.
+ * We possibly read and stored more input in buffer[] by now.
+ * n = bytes read. Try to read more until we time out.
+ */
+ while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */
+ if (safe_poll(&pfd, 1, 50) == 0) {
+ /* No more data! */
+ break;
+ }
+ 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) {
+ /* otherwise: it's EOF/error */
+ buffer[-1] = 0;
+ return -1;
+ }
+ break;
+ }
+ n++;
+ /* Try to decipher "ESC [ NNN ; NNN R" sequence */
+ if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL
+ || ENABLE_FEATURE_VI_ASK_TERMINAL
+ || ENABLE_FEATURE_LESS_ASK_TERMINAL
+ )
+ && n >= 5
+ && buffer[0] == '['
+ && buffer[n-1] == 'R'
+ && isdigit(buffer[1])
+ ) {
+ char *end;
+ unsigned long row, col;
+
+ row = strtoul(buffer + 1, &end, 10);
+ if (*end != ';' || !isdigit(end[1]))
+ continue;
+ col = strtoul(end + 1, &end, 10);
+ if (*end != 'R')
+ continue;
+ if (row < 1 || col < 1 || (row | col) > 0x7fff)
+ continue;
+
+ buffer[-1] = 0;
+ /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
+ col |= (((-1 << 15) | row) << 16);
+ /* Return it in high-order word */
+ return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS;
+ }
+ }
+ got_all:
+
+ if (n <= 1) {
+ /* Alt-x is usually returned as ESC x.
+ * Report ESC, x is remembered for the next call.
+ */
+ buffer[-1] = n;
+ return 27;
+ }
+
+ /* We were doing "buffer[-1] = n; return c;" here, but this results
+ * in unknown key sequences being interpreted as ESC + garbage.
+ * This was not useful. Pretend there was no key pressed,
+ * go and wait for a new keypress:
+ */
+ buffer[-1] = 0;
+ goto start_over;
+}
+
+void FAST_FUNC read_key_ungets(char *buffer, const char *str, unsigned len)
+{
+ unsigned cur_len = (unsigned char)buffer[0];
+ if (len > KEYCODE_BUFFER_SIZE-1 - cur_len)
+ len = KEYCODE_BUFFER_SIZE-1 - cur_len;
+ memcpy(buffer + 1 + cur_len, str, len);
+ buffer[0] += len;
+}
diff --git a/ap/app/busybox/src/libbb/read_printf.c b/ap/app/busybox/src/libbb/read_printf.c
new file mode 100644
index 0000000..5ed6e36
--- /dev/null
+++ b/ap/app/busybox/src/libbb/read_printf.c
@@ -0,0 +1,236 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+
+/* 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) | 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) | 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) | 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_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR)
+{
+ struct pollfd pfd[1];
+ ssize_t n;
+
+ while (1) {
+ n = loop_on_EINTR ? safe_read(fd, buf, count) : 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;
+ /* note: safe_poll pulls in printf */
+ loop_on_EINTR ? safe_poll(pfd, 1, -1) : poll(pfd, 1, -1);
+ }
+}
+
+// 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, size_t *maxsz_p)
+{
+ char *p;
+ char *buf = NULL;
+ size_t sz = 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;
+ }
+ if (nonblock_immune_read(fd, p, 1, /*loop_on_EINTR:*/ 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);
+}
+
+// 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;
+}
+
+/* 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;
+}
+
+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;
+}
diff --git a/ap/app/busybox/src/libbb/recursive_action.c b/ap/app/busybox/src/libbb/recursive_action.c
new file mode 100644
index 0000000..b5cf7c0
--- /dev/null
+++ b/ap/app/busybox/src/libbb/recursive_action.c
@@ -0,0 +1,156 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+#undef DEBUG_RECURS_ACTION
+
+/*
+ * Walk down all the directories under the specified
+ * location, and do something (something specified
+ * by the fileAction and dirAction function pointers).
+ *
+ * Unfortunately, while nftw(3) could replace this and reduce
+ * code size a bit, nftw() wasn't supported before GNU libc 2.1,
+ * and so isn't sufficiently portable to take over since glibc2.1
+ * is so stinking huge.
+ */
+
+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)
+ *
+ * ACTION_FOLLOWLINKS mainly controls 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)
+{
+ struct stat statbuf;
+ unsigned follow;
+ int status;
+ DIR *dir;
+ struct dirent *next;
+
+ if (!fileAction) fileAction = true_action;
+ if (!dirAction) dirAction = true_action;
+
+ follow = ACTION_FOLLOWLINKS;
+ if (depth == 0)
+ follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
+ follow &= flags;
+ status = (follow ? stat : lstat)(fileName, &statbuf);
+ if (status < 0) {
+#ifdef DEBUG_RECURS_ACTION
+ bb_error_msg("status=%d flags=%x", status, flags);
+#endif
+ if ((flags & ACTION_DANGLING_OK)
+ && errno == ENOENT
+ && lstat(fileName, &statbuf) == 0
+ ) {
+ /* Dangling link */
+ return fileAction(fileName, &statbuf, userData, depth);
+ }
+ goto done_nak_warn;
+ }
+
+ /* 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);
+ }
+
+ /* It's a directory (or a link to one, and followLinks is set) */
+
+ if (!(flags & ACTION_RECURSE)) {
+ return dirAction(fileName, &statbuf, userData, depth);
+ }
+
+ if (!(flags & ACTION_DEPTHFIRST)) {
+ status = dirAction(fileName, &statbuf, userData, depth);
+ if (!status)
+ goto done_nak_warn;
+ if (status == SKIP)
+ 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;
+
+ 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/ap/app/busybox/src/libbb/remove_file.c b/ap/app/busybox/src/libbb/remove_file.c
new file mode 100644
index 0000000..5b75f7f
--- /dev/null
+++ b/ap/app/busybox/src/libbb/remove_file.c
@@ -0,0 +1,102 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini remove_file implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* Used from NOFORK applets. Must not allocate anything */
+
+int FAST_FUNC remove_file(const char *path, int flags)
+{
+ struct stat path_stat;
+
+ if (lstat(path, &path_stat) < 0) {
+ if (errno != ENOENT) {
+ bb_perror_msg("can't stat '%s'", path);
+ return -1;
+ }
+ if (!(flags & FILEUTILS_FORCE)) {
+ bb_perror_msg("can't remove '%s'", path);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (S_ISDIR(path_stat.st_mode)) {
+ DIR *dp;
+ struct dirent *d;
+ int status = 0;
+
+ if (!(flags & FILEUTILS_RECUR)) {
+ bb_error_msg("'%s' is a directory", path);
+ return -1;
+ }
+
+ if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && isatty(0))
+ || (flags & FILEUTILS_INTERACTIVE)
+ ) {
+ fprintf(stderr, "%s: descend into directory '%s'? ", applet_name,
+ path);
+ if (!bb_ask_confirmation())
+ return 0;
+ }
+
+ dp = opendir(path);
+ if (dp == NULL) {
+ return -1;
+ }
+
+ while ((d = readdir(dp)) != NULL) {
+ char *new_path;
+
+ new_path = concat_subpath_file(path, d->d_name);
+ if (new_path == NULL)
+ continue;
+ if (remove_file(new_path, flags) < 0)
+ status = -1;
+ free(new_path);
+ }
+
+ if (closedir(dp) < 0) {
+ bb_perror_msg("can't close '%s'", path);
+ return -1;
+ }
+
+ if (flags & FILEUTILS_INTERACTIVE) {
+ fprintf(stderr, "%s: remove directory '%s'? ", applet_name, path);
+ if (!bb_ask_confirmation())
+ return status;
+ }
+
+ if (rmdir(path) < 0) {
+ bb_perror_msg("can't remove '%s'", path);
+ return -1;
+ }
+
+ return status;
+ }
+
+ /* !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;
+ }
+
+ if (unlink(path) < 0) {
+ bb_perror_msg("can't remove '%s'", path);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/ap/app/busybox/src/libbb/rtc.c b/ap/app/busybox/src/libbb/rtc.c
new file mode 100644
index 0000000..97455e8
--- /dev/null
+++ b/ap/app/busybox/src/libbb/rtc.c
@@ -0,0 +1,83 @@
+/*
+ * Common RTC functions
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#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) {
+ char buffer[128];
+
+ while (fgets(buffer, sizeof(buffer), f)) {
+ if (strncmp(buffer, "UTC", 3) == 0) {
+ utc = 1;
+ break;
+ }
+ }
+ fclose(f);
+ }
+
+ 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);
+}
+
+void FAST_FUNC rtc_read_tm(struct tm *ptm, int fd)
+{
+ memset(ptm, 0, sizeof(*ptm));
+ xioctl(fd, RTC_RD_TIME, ptm);
+ ptm->tm_isdst = -1; /* "not known" */
+}
+
+time_t FAST_FUNC rtc_tm2time(struct tm *ptm, int utc)
+{
+ char *oldtz = oldtz; /* for compiler */
+ time_t t;
+
+ if (utc) {
+ oldtz = getenv("TZ");
+ putenv((char*)"TZ=UTC0");
+ tzset();
+ }
+
+ t = mktime(ptm);
+
+ if (utc) {
+ unsetenv("TZ");
+ if (oldtz)
+ putenv(oldtz - 3);
+ tzset();
+ }
+
+ return t;
+}
diff --git a/ap/app/busybox/src/libbb/run_shell.c b/ap/app/busybox/src/libbb/run_shell.c
new file mode 100644
index 0000000..4d92c3c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/run_shell.c
@@ -0,0 +1,92 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libbb.h"
+#if ENABLE_SELINUX
+#include <selinux/selinux.h> /* for setexeccon */
+#endif
+
+#if ENABLE_SELINUX
+static security_context_t current_sid;
+
+void FAST_FUNC renew_current_security_context(void)
+{
+ freecon(current_sid); /* Release old context */
+ getcon(¤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 "" or NULL.
+ * If COMMAND is nonzero, pass it to the shell with the -c option.
+ * If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
+ * arguments. */
+void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args)
+{
+ const char **args;
+ int argno;
+ int additional_args_cnt = 0;
+
+ for (args = additional_args; args && *args; args++)
+ additional_args_cnt++;
+
+ args = xmalloc(sizeof(char*) * (4 + additional_args_cnt));
+
+ if (!shell || !shell[0])
+ shell = DEFAULT_SHELL;
+
+ args[0] = bb_get_last_path_component_nostrip(shell);
+ if (loginshell)
+ args[0] = xasprintf("-%s", args[0]);
+ argno = 1;
+ if (command) {
+ args[argno++] = "-c";
+ args[argno++] = command;
+ }
+ if (additional_args) {
+ for (; *additional_args; ++additional_args)
+ args[argno++] = *additional_args;
+ }
+ 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("can't execute '%s'", shell);
+}
diff --git a/ap/app/busybox/src/libbb/safe_gethostname.c b/ap/app/busybox/src/libbb/safe_gethostname.c
new file mode 100644
index 0000000..cac99ae
--- /dev/null
+++ b/ap/app/busybox/src/libbb/safe_gethostname.c
@@ -0,0 +1,52 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Safe gethostname implementation for busybox
+ *
+ * Copyright (C) 2008 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/*
+ * SUSv2 guarantees that "Host names are limited to 255 bytes"
+ * POSIX.1-2001 guarantees that "Host names (not including the terminating
+ * null byte) are limited to HOST_NAME_MAX bytes" (64 bytes on my box).
+ *
+ * RFC1123 says:
+ *
+ * The syntax of a legal Internet host name was specified in RFC-952
+ * [DNS:4]. One aspect of host name syntax is hereby changed: the
+ * restriction on the first character is relaxed to allow either a
+ * letter or a digit. Host software MUST support this more liberal
+ * syntax.
+ *
+ * Host software MUST handle host names of up to 63 characters and
+ * SHOULD handle host names of up to 255 characters.
+ */
+
+#include "libbb.h"
+#include <sys/utsname.h>
+
+/*
+ * On success return the current malloced and NUL terminated hostname.
+ * On error return malloced and NUL terminated string "?".
+ * This is an illegal first character for a hostname.
+ * The returned malloced string must be freed by the caller.
+ */
+char* FAST_FUNC safe_gethostname(void)
+{
+ struct utsname uts;
+
+ /* The length of the arrays in a struct utsname is unspecified;
+ * the fields are terminated by a null byte.
+ * Note that there is no standard that says that the hostname
+ * set by sethostname(2) is the same string as the nodename field of the
+ * struct returned by uname (indeed, some systems allow a 256-byte host-
+ * name and an 8-byte nodename), but this is true on Linux. The same holds
+ * for setdomainname(2) and the domainname field.
+ */
+
+ /* Uname can fail only if you pass a bad pointer to it. */
+ uname(&uts);
+ return xstrndup(!uts.nodename[0] ? "?" : uts.nodename, sizeof(uts.nodename));
+}
diff --git a/ap/app/busybox/src/libbb/safe_poll.c b/ap/app/busybox/src/libbb/safe_poll.c
new file mode 100644
index 0000000..b492a81
--- /dev/null
+++ b/ap/app/busybox/src/libbb/safe_poll.c
@@ -0,0 +1,34 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#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/ap/app/busybox/src/libbb/safe_strncpy.c b/ap/app/busybox/src/libbb/safe_strncpy.c
new file mode 100644
index 0000000..5eb0db0
--- /dev/null
+++ b/ap/app/busybox/src/libbb/safe_strncpy.c
@@ -0,0 +1,32 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* 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);
+}
+
+/* Like strcpy but can copy overlapping strings. */
+void FAST_FUNC overlapping_strcpy(char *dst, const char *src)
+{
+ /* Cheap optimization for dst == src case -
+ * better to have it here than in many callers.
+ */
+ if (dst != src) {
+ while ((*dst = *src) != '\0') {
+ dst++;
+ src++;
+ }
+ }
+}
diff --git a/ap/app/busybox/src/libbb/safe_write.c b/ap/app/busybox/src/libbb/safe_write.c
new file mode 100644
index 0000000..8f76280
--- /dev/null
+++ b/ap/app/busybox/src/libbb/safe_write.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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/ap/app/busybox/src/libbb/selinux_common.c b/ap/app/busybox/src/libbb/selinux_common.c
new file mode 100644
index 0000000..c258555
--- /dev/null
+++ b/ap/app/busybox/src/libbb/selinux_common.c
@@ -0,0 +1,55 @@
+/*
+ * libbb/selinux_common.c
+ * -- common SELinux utility functions
+ *
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include <selinux/context.h>
+
+context_t FAST_FUNC set_security_context_component(security_context_t cur_context,
+ char *user, char *role, char *type, char *range)
+{
+ context_t con = context_new(cur_context);
+ if (!con)
+ return NULL;
+
+ if (user && context_user_set(con, user))
+ goto error;
+ if (type && context_type_set(con, type))
+ goto error;
+ if (range && context_range_set(con, range))
+ goto error;
+ if (role && context_role_set(con, role))
+ goto error;
+ return con;
+
+error:
+ context_free(con);
+ return NULL;
+}
+
+void FAST_FUNC setfscreatecon_or_die(security_context_t scontext)
+{
+ if (setfscreatecon(scontext) < 0) {
+ /* Can be NULL. All known printf implementations
+ * display "(null)", "<null>" etc */
+ bb_perror_msg_and_die("can't 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/ap/app/busybox/src/libbb/setup_environment.c b/ap/app/busybox/src/libbb/setup_environment.c
new file mode 100644
index 0000000..4258656
--- /dev/null
+++ b/ap/app/busybox/src/libbb/setup_environment.c
@@ -0,0 +1,74 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libbb.h"
+
+void FAST_FUNC setup_environment(const char *shell, int flags, const struct passwd *pw)
+{
+ if (!shell || !shell[0])
+ shell = DEFAULT_SHELL;
+
+ /* Change the current working directory to be the home directory
+ * of the user */
+ if (!(flags & SETUP_ENV_NO_CHDIR)) {
+ if (chdir(pw->pw_dir) != 0) {
+ bb_error_msg("can't change directory to '%s'", pw->pw_dir);
+ xchdir((flags & SETUP_ENV_TO_TMP) ? "/tmp" : "/");
+ }
+ }
+
+ if (flags & SETUP_ENV_CLEARENV) {
+ const char *term;
+
+ /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
+ * Unset all other environment variables. */
+ 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 (flags & SETUP_ENV_CHANGEENV) {
+ /* Set HOME, SHELL, and if not becoming a super-user,
+ * 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/ap/app/busybox/src/libbb/signals.c b/ap/app/busybox/src/libbb/signals.c
new file mode 100644
index 0000000..5651247
--- /dev/null
+++ b/ap/app/busybox/src/libbb/signals.c
@@ -0,0 +1,121 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#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(sig | 128); /* 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/ap/app/busybox/src/libbb/simplify_path.c b/ap/app/busybox/src/libbb/simplify_path.c
new file mode 100644
index 0000000..89dc5bd
--- /dev/null
+++ b/ap/app/busybox/src/libbb/simplify_path.c
@@ -0,0 +1,59 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * bb_simplify_path implementation for busybox
+ *
+ * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+char* FAST_FUNC bb_simplify_abs_path_inplace(char *start)
+{
+ char *s, *p;
+
+ p = s = start;
+ do {
+ if (*p == '/') {
+ if (*s == '/') { /* skip duplicate (or initial) slash */
+ continue;
+ }
+ if (*s == '.') {
+ if (s[1] == '/' || !s[1]) { /* remove extra '.' */
+ continue;
+ }
+ if ((s[1] == '.') && (s[2] == '/' || !s[2])) {
+ ++s;
+ if (p > start) {
+ while (*--p != '/') /* omit previous dir */
+ continue;
+ }
+ continue;
+ }
+ }
+ }
+ *++p = *s;
+ } while (*++s);
+
+ if ((p == start) || (*p != '/')) { /* not a trailing slash */
+ ++p; /* so keep last character */
+ }
+ *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);
+ }
+
+ bb_simplify_abs_path_inplace(s);
+ return s;
+}
diff --git a/ap/app/busybox/src/libbb/single_argv.c b/ap/app/busybox/src/libbb/single_argv.c
new file mode 100644
index 0000000..64844dd
--- /dev/null
+++ b/ap/app/busybox/src/libbb/single_argv.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2009 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+char* FAST_FUNC single_argv(char **argv)
+{
+ if (argv[1] && strcmp(argv[1], "--") == 0)
+ argv++;
+ if (!argv[1] || argv[2])
+ bb_show_usage();
+ return argv[1];
+}
diff --git a/ap/app/busybox/src/libbb/skip_whitespace.c b/ap/app/busybox/src/libbb/skip_whitespace.c
new file mode 100644
index 0000000..8c7b674
--- /dev/null
+++ b/ap/app/busybox/src/libbb/skip_whitespace.c
@@ -0,0 +1,39 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * skip_whitespace implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+char* FAST_FUNC skip_whitespace(const char *s)
+{
+ /* In POSIX/C locale (the only locale we care about: do we REALLY want
+ * to allow Unicode whitespace in, say, .conf files? nuts!)
+ * isspace is only these chars: "\t\n\v\f\r" and space.
+ * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
+ * Use that.
+ */
+ while (*s == ' ' || (unsigned char)(*s - 9) <= (13 - 9))
+ s++;
+
+ return (char *) s;
+}
+
+char* FAST_FUNC skip_non_whitespace(const char *s)
+{
+ while (*s != '\0' && *s != ' ' && (unsigned char)(*s - 9) > (13 - 9))
+ s++;
+
+ return (char *) s;
+}
+
+char* FAST_FUNC skip_dev_pfx(const char *tty_name)
+{
+ if (strncmp(tty_name, "/dev/", 5) == 0)
+ tty_name += 5;
+ return (char*)tty_name;
+}
diff --git a/ap/app/busybox/src/libbb/speed_table.c b/ap/app/busybox/src/libbb/speed_table.c
new file mode 100644
index 0000000..45159f1
--- /dev/null
+++ b/ap/app/busybox/src/libbb/speed_table.c
@@ -0,0 +1,119 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * compact speed_t <-> speed functions for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+struct speed_map {
+ unsigned short speed;
+ unsigned short value;
+};
+
+static const struct speed_map speeds[] = {
+ {B0, 0},
+ {B50, 50},
+ {B75, 75},
+ {B110, 110},
+ {B134, 134},
+ {B150, 150},
+ {B200, 200},
+ {B300, 300},
+ {B600, 600},
+ {B1200, 1200},
+ {B1800, 1800},
+ {B2400, 2400},
+ {B4800, 4800},
+ {B9600, 9600},
+#ifdef B19200
+ {B19200, 19200},
+#elif defined(EXTA)
+ {EXTA, 19200},
+#endif
+#ifdef B38400
+ {B38400, 38400/256 + 0x8000U},
+#elif defined(EXTB)
+ {EXTB, 38400/256 + 0x8000U},
+#endif
+#ifdef B57600
+ {B57600, 57600/256 + 0x8000U},
+#endif
+#ifdef B115200
+ {B115200, 115200/256 + 0x8000U},
+#endif
+#ifdef B230400
+ {B230400, 230400/256 + 0x8000U},
+#endif
+#ifdef B460800
+ {B460800, 460800/256 + 0x8000U},
+#endif
+#ifdef B921600
+ {B921600, 921600/256 + 0x8000U},
+#endif
+};
+
+enum { NUM_SPEEDS = ARRAY_SIZE(speeds) };
+
+unsigned FAST_FUNC tty_baud_to_value(speed_t speed)
+{
+ int i = 0;
+
+ do {
+ if (speed == speeds[i].speed) {
+ if (speeds[i].value & 0x8000U) {
+ return ((unsigned long) (speeds[i].value) & 0x7fffU) * 256;
+ }
+ return speeds[i].value;
+ }
+ } while (++i < NUM_SPEEDS);
+
+ return 0;
+}
+
+speed_t FAST_FUNC tty_value_to_baud(unsigned int value)
+{
+ int i = 0;
+
+ do {
+ if (value == tty_baud_to_value(speeds[i].speed)) {
+ return speeds[i].speed;
+ }
+ } while (++i < NUM_SPEEDS);
+
+ return (speed_t) - 1;
+}
+
+#if 0
+/* testing code */
+#include <stdio.h>
+
+int main(void)
+{
+ unsigned long v;
+ speed_t s;
+
+ for (v = 0 ; v < 1000000; v++) {
+ s = tty_value_to_baud(v);
+ if (s == (speed_t) -1) {
+ continue;
+ }
+ printf("v = %lu -- s = %0lo\n", v, (unsigned long) s);
+ }
+
+ printf("-------------------------------\n");
+
+ for (s = 0 ; s < 010017+1; s++) {
+ v = tty_baud_to_value(s);
+ if (!v) {
+ continue;
+ }
+ printf("v = %lu -- s = %0lo\n", v, (unsigned long) s);
+ }
+
+ return 0;
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/str_tolower.c b/ap/app/busybox/src/libbb/str_tolower.c
new file mode 100644
index 0000000..c2d5637
--- /dev/null
+++ b/ap/app/busybox/src/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 source tree.
+ */
+#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/ap/app/busybox/src/libbb/strrstr.c b/ap/app/busybox/src/libbb/strrstr.c
new file mode 100644
index 0000000..d8823fc
--- /dev/null
+++ b/ap/app/busybox/src/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 source tree.
+ */
+
+#ifdef __DO_STRRSTR_TEST
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#else
+#include "libbb.h"
+#endif
+
+/*
+ * The strrstr() function finds the last occurrence of the substring needle
+ * in the string haystack. The terminating nul characters are not compared.
+ */
+char* FAST_FUNC strrstr(const char *haystack, const char *needle)
+{
+ char *r = NULL;
+
+ if (!needle[0])
+ return (char*)haystack + strlen(haystack);
+ while (1) {
+ char *p = strstr(haystack, needle);
+ if (!p)
+ return r;
+ r = p;
+ haystack = p + 1;
+ }
+}
+
+#ifdef __DO_STRRSTR_TEST
+int main(int argc, char **argv)
+{
+ static const struct {
+ const char *h, *n;
+ int pos;
+ } test_array[] = {
+ /* 0123456789 */
+ { "baaabaaab", "aaa", 5 },
+ { "baaabaaaab", "aaa", 6 },
+ { "baaabaab", "aaa", 1 },
+ { "aaa", "aaa", 0 },
+ { "aaa", "a", 2 },
+ { "aaa", "bbb", -1 },
+ { "a", "aaa", -1 },
+ { "aaa", "", 3 },
+ { "", "aaa", -1 },
+ { "", "", 0 },
+ };
+
+ int i;
+
+ i = 0;
+ while (i < sizeof(test_array) / sizeof(test_array[0])) {
+ const char *r = strrstr(test_array[i].h, test_array[i].n);
+ printf("'%s' vs. '%s': '%s' - ", test_array[i].h, test_array[i].n, r);
+ if (r == NULL)
+ r = test_array[i].h - 1;
+ printf("%s\n", r == test_array[i].h + test_array[i].pos ? "PASSED" : "FAILED");
+ i++;
+ }
+
+ return 0;
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/systemd_support.c b/ap/app/busybox/src/libbb/systemd_support.c
new file mode 100644
index 0000000..542a3ef
--- /dev/null
+++ b/ap/app/busybox/src/libbb/systemd_support.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 Davide Cavalca <davide@geexbox.org>
+ *
+ * Based on http://cgit.freedesktop.org/systemd/tree/src/sd-daemon.c
+ * Copyright 2010 Lennart Poettering
+ *
+ * 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.
+ */
+#include "libbb.h"
+
+//config:config FEATURE_SYSTEMD
+//config: bool "Enable systemd support"
+//config: default y
+//config: help
+//config: If you plan to use busybox daemons on a system where daemons
+//config: are controlled by systemd, enable this option.
+//config: If you don't use systemd, it is still safe to enable it,
+//config: but the downside is increased code size.
+
+//kbuild:lib-$(CONFIG_FEATURE_SYSTEMD) += systemd_support.o
+
+int sd_listen_fds(void)
+{
+ const char *e;
+ int n;
+ int fd;
+
+ e = getenv("LISTEN_PID");
+ if (!e)
+ return 0;
+ n = xatoi_positive(e);
+ /* Is this for us? */
+ if (getpid() != (pid_t) n)
+ return 0;
+
+ e = getenv("LISTEN_FDS");
+ if (!e)
+ return 0;
+ n = xatoi_positive(e);
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++)
+ close_on_exec_on(fd);
+
+ return n;
+}
diff --git a/ap/app/busybox/src/libbb/time.c b/ap/app/busybox/src/libbb/time.c
new file mode 100644
index 0000000..e2b9384
--- /dev/null
+++ b/ap/app/busybox/src/libbb/time.c
@@ -0,0 +1,256 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
+{
+ char end = '\0';
+ const char *last_colon = strrchr(date_str, ':');
+
+ if (last_colon != NULL) {
+ /* Parse input and assign appropriately to ptm */
+#if ENABLE_DESKTOP
+ const char *endp;
+#endif
+
+ /* HH:MM */
+ if (sscanf(date_str, "%u:%u%c",
+ &ptm->tm_hour,
+ &ptm->tm_min,
+ &end) >= 2) {
+ /* no adjustments needed */
+ } else
+ /* mm.dd-HH:MM */
+ if (sscanf(date_str, "%u.%u-%u:%u%c",
+ &ptm->tm_mon, &ptm->tm_mday,
+ &ptm->tm_hour, &ptm->tm_min,
+ &end) >= 4) {
+ /* Adjust month from 1-12 to 0-11 */
+ ptm->tm_mon -= 1;
+ } else
+ /* yyyy.mm.dd-HH:MM */
+ if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &ptm->tm_year,
+ &ptm->tm_mon, &ptm->tm_mday,
+ &ptm->tm_hour, &ptm->tm_min,
+ &end) >= 5) {
+ ptm->tm_year -= 1900; /* Adjust years */
+ ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
+ } else
+ /* yyyy-mm-dd HH:MM */
+ if (sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year,
+ &ptm->tm_mon, &ptm->tm_mday,
+ &ptm->tm_hour, &ptm->tm_min,
+ &end) >= 5) {
+ ptm->tm_year -= 1900; /* Adjust years */
+ ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
+ } else
+#if ENABLE_DESKTOP /* strptime is BIG: ~1k in uclibc, ~10k in glibc */
+ /* month_name d HH:MM:SS YYYY. Supported by GNU date */
+ if ((endp = strptime(date_str, "%b %d %T %Y", ptm)) != NULL
+ && *endp == '\0'
+ ) {
+ return; /* don't fall through to end == ":" check */
+ } else
+#endif
+//TODO: coreutils 6.9 also accepts "yyyy-mm-dd HH" (no minutes)
+ {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
+ if (end == ':') {
+ /* xxx:SS */
+ if (sscanf(last_colon + 1, "%u%c", &ptm->tm_sec, &end) == 1)
+ end = '\0';
+ /* else end != NUL and we error out */
+ }
+ } else if (date_str[0] == '@') {
+ time_t t = bb_strtol(date_str + 1, NULL, 10);
+ if (!errno) {
+ struct tm *lt = localtime(&t);
+ if (lt) {
+ *ptm = *lt;
+ return;
+ }
+ }
+ end = '1';
+ } else {
+ /* Googled the following on an old date manpage:
+ *
+ * The canonical representation for setting the date/time is:
+ * cc Century (either 19 or 20)
+ * yy Year in abbreviated form (e.g. 89, 06)
+ * mm Numeric month, a number from 1 to 12
+ * dd Day, a number from 1 to 31
+ * HH Hour, a number from 0 to 23
+ * MM Minutes, a number from 0 to 59
+ * .SS Seconds, a number from 0 to 61 (with leap seconds)
+ * Everything but the minutes is optional
+ *
+ * "touch -t DATETIME" format: [[[[[YY]YY]MM]DD]hh]mm[.ss]
+ * Some, but not all, Unix "date DATETIME" commands
+ * move [[YY]YY] past minutes mm field (!).
+ * Coreutils date does it, and SUS mandates it.
+ * (date -s DATETIME does not support this format. lovely!)
+ * In bbox, this format is special-cased in date applet
+ * (IOW: this function assumes "touch -t" format).
+ */
+ unsigned cur_year = ptm->tm_year;
+ int len = strchrnul(date_str, '.') - date_str;
+
+ /* MM[.SS] */
+ if (len == 2 && sscanf(date_str, "%2u%2u%2u%2u""%2u%c" + 12,
+ &ptm->tm_min,
+ &end) >= 1) {
+ } else
+ /* HHMM[.SS] */
+ if (len == 4 && sscanf(date_str, "%2u%2u%2u""%2u%2u%c" + 9,
+ &ptm->tm_hour,
+ &ptm->tm_min,
+ &end) >= 2) {
+ } else
+ /* ddHHMM[.SS] */
+ if (len == 6 && sscanf(date_str, "%2u%2u""%2u%2u%2u%c" + 6,
+ &ptm->tm_mday,
+ &ptm->tm_hour,
+ &ptm->tm_min,
+ &end) >= 3) {
+ } else
+ /* mmddHHMM[.SS] */
+ if (len == 8 && sscanf(date_str, "%2u""%2u%2u%2u%2u%c" + 3,
+ &ptm->tm_mon,
+ &ptm->tm_mday,
+ &ptm->tm_hour,
+ &ptm->tm_min,
+ &end) >= 4) {
+ /* Adjust month from 1-12 to 0-11 */
+ ptm->tm_mon -= 1;
+ } else
+ /* yymmddHHMM[.SS] */
+ if (len == 10 && sscanf(date_str, "%2u%2u%2u%2u%2u%c",
+ &ptm->tm_year,
+ &ptm->tm_mon,
+ &ptm->tm_mday,
+ &ptm->tm_hour,
+ &ptm->tm_min,
+ &end) >= 5) {
+ /* Adjust month from 1-12 to 0-11 */
+ ptm->tm_mon -= 1;
+ if ((int)cur_year >= 50) { /* >= 1950 */
+ /* Adjust year: */
+ /* 1. Put it in the current century */
+ ptm->tm_year += (cur_year / 100) * 100;
+ /* 2. If too far in the past, +100 years */
+ if (ptm->tm_year < cur_year - 50)
+ ptm->tm_year += 100;
+ /* 3. If too far in the future, -100 years */
+ if (ptm->tm_year > cur_year + 50)
+ ptm->tm_year -= 100;
+ }
+ } else
+ /* ccyymmddHHMM[.SS] */
+ if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c",
+ &ptm->tm_year,
+ &ptm->tm_mon,
+ &ptm->tm_mday,
+ &ptm->tm_hour,
+ &ptm->tm_min,
+ &end) >= 5) {
+ ptm->tm_year -= 1900; /* Adjust years */
+ ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
+ } else {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
+ if (end == '.') {
+ /* xxx.SS */
+ if (sscanf(strchr(date_str, '.') + 1, "%u%c",
+ &ptm->tm_sec, &end) == 1)
+ end = '\0';
+ /* else end != NUL and we error out */
+ }
+ }
+ if (end != '\0') {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
+}
+
+time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm)
+{
+ time_t t = mktime(ptm);
+ if (t == (time_t) -1L) {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
+ return t;
+}
+
+#if ENABLE_MONOTONIC_SYSCALL
+
+#include <sys/syscall.h>
+/* Old glibc (< 2.3.4) does not provide this constant. We use syscall
+ * directly so this definition is safe. */
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 1
+#endif
+
+/* libc has incredibly messy way of doing this,
+ * typically requiring -lrt. We just skip all this mess */
+static void get_mono(struct timespec *ts)
+{
+ if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
+ bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
+}
+unsigned long long FAST_FUNC monotonic_ns(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+}
+unsigned long long FAST_FUNC monotonic_us(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
+}
+unsigned long long FAST_FUNC monotonic_ms(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec * 1000ULL + ts.tv_nsec/1000000;
+}
+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 long long FAST_FUNC monotonic_ms(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
+}
+unsigned FAST_FUNC monotonic_sec(void)
+{
+ return time(NULL);
+}
+
+#endif
diff --git a/ap/app/busybox/src/libbb/trim.c b/ap/app/busybox/src/libbb/trim.c
new file mode 100644
index 0000000..16cb4fb
--- /dev/null
+++ b/ap/app/busybox/src/libbb/trim.c
@@ -0,0 +1,30 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+void FAST_FUNC trim(char *s)
+{
+ size_t len = strlen(s);
+
+ /* trim trailing whitespace */
+ while (len && isspace(s[len-1]))
+ --len;
+
+ /* trim leading whitespace */
+ if (len) {
+ char *nws = skip_whitespace(s);
+ if ((nws - s) != 0) {
+ len -= (nws - s);
+ memmove(s, nws, len);
+ }
+ }
+ s[len] = '\0';
+}
diff --git a/ap/app/busybox/src/libbb/u_signal_names.c b/ap/app/busybox/src/libbb/u_signal_names.c
new file mode 100644
index 0000000..8c78f5e
--- /dev/null
+++ b/ap/app/busybox/src/libbb/u_signal_names.c
@@ -0,0 +1,236 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Signal name/number conversion routines.
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+//config:config FEATURE_RTMINMAX
+//config: bool "Support RTMIN[+n] and RTMAX[-n] signal names"
+//config: default y
+//config: help
+//config: Support RTMIN[+n] and RTMAX[-n] signal names
+//config: in kill, killall etc. This costs ~250 bytes.
+
+#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 SIGINT
+ [SIGINT ] = "INT",
+#endif
+#ifdef SIGQUIT
+ [SIGQUIT ] = "QUIT",
+#endif
+#ifdef SIGILL
+ [SIGILL ] = "ILL",
+#endif
+#ifdef SIGTRAP
+ [SIGTRAP ] = "TRAP",
+#endif
+#ifdef SIGABRT
+ [SIGABRT ] = "ABRT",
+#endif
+#ifdef SIGBUS
+ [SIGBUS ] = "BUS",
+#endif
+#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
+ [SIGSTKFLT] = "STKFLT",
+#endif
+#ifdef SIGCHLD
+ [SIGCHLD ] = "CHLD",
+#endif
+#ifdef SIGCONT
+ [SIGCONT ] = "CONT",
+#endif
+#ifdef SIGSTOP
+ [SIGSTOP ] = "STOP",
+#endif
+#ifdef SIGTSTP
+ [SIGTSTP ] = "TSTP",
+#endif
+#ifdef SIGTTIN
+ [SIGTTIN ] = "TTIN",
+#endif
+#ifdef SIGTTOU
+ [SIGTTOU ] = "TTOU",
+#endif
+#ifdef SIGURG
+ [SIGURG ] = "URG",
+#endif
+#ifdef SIGXCPU
+ [SIGXCPU ] = "XCPU",
+#endif
+#ifdef SIGXFSZ
+ [SIGXFSZ ] = "XFSZ",
+#endif
+#ifdef SIGVTALRM
+ [SIGVTALRM] = "VTALRM",
+#endif
+#ifdef SIGPROF
+ [SIGPROF ] = "PROF",
+#endif
+#ifdef SIGWINCH
+ [SIGWINCH ] = "WINCH",
+#endif
+#ifdef SIGPOLL
+ [SIGPOLL ] = "POLL",
+#endif
+#ifdef SIGPWR
+ [SIGPWR ] = "PWR",
+#endif
+#ifdef SIGSYS
+ [SIGSYS ] = "SYS",
+#endif
+#if ENABLE_FEATURE_RTMINMAX
+# ifdef __SIGRTMIN
+ [__SIGRTMIN] = "RTMIN",
+# endif
+// This makes array about x2 bigger.
+// More compact approach is to special-case SIGRTMAX in print_signames()
+//# ifdef __SIGRTMAX
+// [__SIGRTMAX] = "RTMAX",
+//# endif
+#endif
+};
+
+// 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
+# if 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 SIGIOT
+ if ((name[2] | 0x20) == 't' && !name[3])
+ return SIGIOT;
+# endif
+ }
+# endif
+#endif
+
+#if ENABLE_FEATURE_RTMINMAX
+# if defined(SIGRTMIN) && defined(SIGRTMAX)
+/* libc may use some rt sigs for pthreads and therefore "remap" SIGRTMIN/MAX,
+ * but we want to use "raw" SIGRTMIN/MAX. Underscored names, if exist, provide
+ * them. If they don't exist, fall back to non-underscored ones: */
+# if !defined(__SIGRTMIN)
+# define __SIGRTMIN SIGRTMIN
+# endif
+# if !defined(__SIGRTMAX)
+# define __SIGRTMAX SIGRTMAX
+# endif
+ if (strncasecmp(name, "RTMIN", 5) == 0) {
+ if (!name[5])
+ return __SIGRTMIN;
+ if (name[5] == '+') {
+ i = bb_strtou(name + 6, NULL, 10);
+ if (!errno && i <= __SIGRTMAX - __SIGRTMIN)
+ return __SIGRTMIN + i;
+ }
+ }
+ else if (strncasecmp(name, "RTMAX", 5) == 0) {
+ if (!name[5])
+ return __SIGRTMAX;
+ if (name[5] == '-') {
+ i = bb_strtou(name + 6, NULL, 10);
+ if (!errno && i <= __SIGRTMAX - __SIGRTMIN)
+ return __SIGRTMAX - i;
+ }
+ }
+# endif
+#endif
+
+ 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);
+}
+
+
+// Print the whole signal list
+
+void FAST_FUNC print_signames(void)
+{
+ unsigned signo;
+
+ for (signo = 1; signo < ARRAY_SIZE(signals); signo++) {
+ const char *name = signals[signo];
+ if (name[0])
+ printf("%2u) %s\n", signo, name);
+ }
+#if ENABLE_FEATURE_RTMINMAX
+# ifdef __SIGRTMAX
+ printf("%2u) %s\n", __SIGRTMAX, "RTMAX");
+# endif
+#endif
+}
diff --git a/ap/app/busybox/src/libbb/udp_io.c b/ap/app/busybox/src/libbb/udp_io.c
new file mode 100644
index 0000000..7985a97
--- /dev/null
+++ b/ap/app/busybox/src/libbb/udp_io.c
@@ -0,0 +1,179 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2007 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#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 UNUSED_PARAM)
+{
+#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
+ (void)from; /* suppress "unused from" warning */
+ 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(u...) */
+ /* In general, CMSG_DATA() can be unaligned, but in this case
+ * we know for sure it is sufficiently aligned:
+ * CMSG_FIRSTHDR simply returns &u above,
+ * and CMSG_DATA returns &u + size_t + int + int.
+ * Thus direct assignment is ok:
+ */
+ 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(u...) */
+ 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
+ (void)to; /* suppress "unused to" warning */
+ 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;
+
+# define to4 ((struct sockaddr_in*)to)
+# define to6 ((struct sockaddr_in6*)to)
+ /* 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
+ ) {
+ const int IPI_ADDR_OFF = offsetof(struct in_pktinfo, ipi_addr);
+ to->sa_family = AF_INET;
+ /*# define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) )*/
+ /*to4->sin_addr = pktinfo(cmsgptr)->ipi_addr; - may be unaligned */
+ memcpy(&to4->sin_addr, (char*)(CMSG_DATA(cmsgptr)) + IPI_ADDR_OFF, sizeof(to4->sin_addr));
+ /*to4->sin_port = 123; - this data is not supplied by kernel */
+ break;
+ }
+# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+ if (cmsgptr->cmsg_level == IPPROTO_IPV6
+ && cmsgptr->cmsg_type == IPV6_PKTINFO
+ ) {
+ const int IPI6_ADDR_OFF = offsetof(struct in6_pktinfo, ipi6_addr);
+ to->sa_family = AF_INET6;
+ /*# define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) )*/
+ /*to6->sin6_addr = pktinfo(cmsgptr)->ipi6_addr; - may be unaligned */
+ memcpy(&to6->sin6_addr, (char*)(CMSG_DATA(cmsgptr)) + IPI6_ADDR_OFF, sizeof(to6->sin6_addr));
+ /*to6->sin6_port = 123; */
+ break;
+ }
+# endif
+ }
+ return recv_length;
+#endif
+}
diff --git a/ap/app/busybox/src/libbb/unicode.c b/ap/app/busybox/src/libbb/unicode.c
new file mode 100644
index 0000000..99dc1df
--- /dev/null
+++ b/ap/app/busybox/src/libbb/unicode.c
@@ -0,0 +1,1158 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Unicode support routines.
+ *
+ * Copyright (C) 2009 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#include "unicode.h"
+
+/* If it's not #defined as a constant in unicode.h... */
+#ifndef unicode_status
+uint8_t unicode_status;
+#endif
+
+/* This file is compiled only if UNICODE_SUPPORT is on.
+ * We check other options and decide whether to use libc support
+ * via locale, or use our own logic:
+ */
+
+#if ENABLE_UNICODE_USING_LOCALE
+
+/* Unicode support using libc locale support. */
+
+void FAST_FUNC reinit_unicode(const char *LANG)
+{
+ static const char unicode_0x394[] = { 0xce, 0x94, 0 };
+ size_t width;
+
+//TODO: avoid repeated calls by caching last string?
+ setlocale(LC_ALL, (LANG && LANG[0]) ? LANG : "C");
+
+ /* In unicode, this is a one character string */
+// can use unicode_strlen(string) too, but otherwise unicode_strlen() is unused
+ width = mbstowcs(NULL, unicode_0x394, INT_MAX);
+ unicode_status = (width == 1 ? UNICODE_ON : UNICODE_OFF);
+}
+
+void FAST_FUNC init_unicode(void)
+{
+ if (unicode_status == UNICODE_UNKNOWN)
+ reinit_unicode(getenv("LANG"));
+}
+
+#else
+
+/* Homegrown Unicode support. It knows only C and Unicode locales. */
+
+# if ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
+void FAST_FUNC reinit_unicode(const char *LANG)
+{
+ unicode_status = UNICODE_OFF;
+ if (!LANG || !(strstr(LANG, ".utf") || strstr(LANG, ".UTF")))
+ return;
+ unicode_status = UNICODE_ON;
+}
+
+void FAST_FUNC init_unicode(void)
+{
+ if (unicode_status == UNICODE_UNKNOWN)
+ reinit_unicode(getenv("LANG"));
+}
+# endif
+
+static size_t wcrtomb_internal(char *s, wchar_t wc)
+{
+ int n, i;
+ uint32_t v = wc;
+
+ if (v <= 0x7f) {
+ *s = v;
+ return 1;
+ }
+
+ /* RFC 3629 says that Unicode ends at 10FFFF,
+ * but we cover entire 32 bits */
+
+ /* 4000000-FFFFFFFF -> 111111tt 10tttttt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */
+ /* 200000-3FFFFFF -> 111110tt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */
+ /* 10000-1FFFFF -> 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx */
+ /* 800-FFFF -> 1110yyyy 10yyyyxx 10xxxxxx */
+ /* 80-7FF -> 110yyyxx 10xxxxxx */
+
+ /* How many bytes do we need? */
+ n = 2;
+ /* (0x80000000+ would result in n = 7, limiting n to 6) */
+ while (v >= 0x800 && n < 6) {
+ v >>= 5;
+ n++;
+ }
+ /* Fill bytes n-1..1 */
+ i = n;
+ while (--i) {
+ s[i] = (wc & 0x3f) | 0x80;
+ wc >>= 6;
+ }
+ /* Fill byte 0 */
+ s[0] = wc | (uint8_t)(0x3f00 >> n);
+ return n;
+}
+size_t FAST_FUNC wcrtomb(char *s, wchar_t wc, mbstate_t *ps UNUSED_PARAM)
+{
+ if (unicode_status != UNICODE_ON) {
+ *s = wc;
+ return 1;
+ }
+
+ return wcrtomb_internal(s, wc);
+}
+size_t FAST_FUNC wcstombs(char *dest, const wchar_t *src, size_t n)
+{
+ size_t org_n = n;
+
+ if (unicode_status != UNICODE_ON) {
+ while (n) {
+ wchar_t c = *src++;
+ *dest++ = c;
+ if (c == 0)
+ break;
+ n--;
+ }
+ return org_n - n;
+ }
+
+ while (n >= MB_CUR_MAX) {
+ wchar_t wc = *src++;
+ size_t len = wcrtomb_internal(dest, wc);
+
+ if (wc == L'\0')
+ return org_n - n;
+ dest += len;
+ n -= len;
+ }
+ while (n) {
+ char tbuf[MB_CUR_MAX];
+ wchar_t wc = *src++;
+ size_t len = wcrtomb_internal(tbuf, wc);
+
+ if (len > n)
+ break;
+ memcpy(dest, tbuf, len);
+ if (wc == L'\0')
+ return org_n - n;
+ dest += len;
+ n -= len;
+ }
+ return org_n - n;
+}
+
+# define ERROR_WCHAR (~(wchar_t)0)
+
+static const char *mbstowc_internal(wchar_t *res, const char *src)
+{
+ int bytes;
+ unsigned c = (unsigned char) *src++;
+
+ if (c <= 0x7f) {
+ *res = c;
+ return src;
+ }
+
+ /* 80-7FF -> 110yyyxx 10xxxxxx */
+ /* 800-FFFF -> 1110yyyy 10yyyyxx 10xxxxxx */
+ /* 10000-1FFFFF -> 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx */
+ /* 200000-3FFFFFF -> 111110tt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */
+ /* 4000000-FFFFFFFF -> 111111tt 10tttttt 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx */
+ bytes = 0;
+ do {
+ c <<= 1;
+ bytes++;
+ } while ((c & 0x80) && bytes < 6);
+ if (bytes == 1) {
+ /* A bare "continuation" byte. Say, 80 */
+ *res = ERROR_WCHAR;
+ return src;
+ }
+ c = (uint8_t)(c) >> bytes;
+
+ while (--bytes) {
+ unsigned ch = (unsigned char) *src;
+ if ((ch & 0xc0) != 0x80) {
+ /* Missing "continuation" byte. Example: e0 80 */
+ *res = ERROR_WCHAR;
+ return src;
+ }
+ c = (c << 6) + (ch & 0x3f);
+ src++;
+ }
+
+ /* TODO */
+ /* Need to check that c isn't produced by overlong encoding */
+ /* Example: 11000000 10000000 converts to NUL */
+ /* 11110000 10000000 10000100 10000000 converts to 0x100 */
+ /* correct encoding: 11000100 10000000 */
+ if (c <= 0x7f) { /* crude check */
+ *res = ERROR_WCHAR;
+ return src;
+ }
+
+ *res = c;
+ return src;
+}
+size_t FAST_FUNC mbstowcs(wchar_t *dest, const char *src, size_t n)
+{
+ size_t org_n = n;
+
+ if (unicode_status != UNICODE_ON) {
+ while (n) {
+ unsigned char c = *src++;
+
+ if (dest)
+ *dest++ = c;
+ if (c == 0)
+ break;
+ n--;
+ }
+ return org_n - n;
+ }
+
+ while (n) {
+ wchar_t wc;
+ src = mbstowc_internal(&wc, src);
+ if (wc == ERROR_WCHAR) /* error */
+ return (size_t) -1L;
+ if (dest)
+ *dest++ = wc;
+ if (wc == 0) /* end-of-string */
+ break;
+ n--;
+ }
+
+ return org_n - n;
+}
+
+int FAST_FUNC iswspace(wint_t wc)
+{
+ return (unsigned)wc <= 0x7f && isspace(wc);
+}
+
+int FAST_FUNC iswalnum(wint_t wc)
+{
+ return (unsigned)wc <= 0x7f && isalnum(wc);
+}
+
+int FAST_FUNC iswpunct(wint_t wc)
+{
+ return (unsigned)wc <= 0x7f && ispunct(wc);
+}
+
+
+# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300
+struct interval {
+ uint16_t first;
+ uint16_t last;
+};
+
+/* auxiliary function for binary search in interval table */
+static int in_interval_table(unsigned ucs, const struct interval *table, unsigned max)
+{
+ unsigned min;
+ unsigned mid;
+
+ if (ucs < table[0].first || ucs > table[max].last)
+ return 0;
+
+ min = 0;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (ucs > table[mid].last)
+ min = mid + 1;
+ else if (ucs < table[mid].first)
+ max = mid - 1;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max)
+{
+ unsigned min;
+ unsigned mid;
+ unsigned first, last;
+
+ first = table[0] >> 2;
+ last = first + (table[0] & 3);
+ if (ucs < first || ucs > last)
+ return 0;
+
+ min = 0;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ first = table[mid] >> 2;
+ last = first + (table[mid] & 3);
+ if (ucs > last)
+ min = mid + 1;
+ else if (ucs < first)
+ max = mid - 1;
+ else
+ return 1;
+ }
+ return 0;
+}
+# endif
+
+
+/*
+ * This is an implementation of wcwidth() and wcswidth() (defined in
+ * IEEE Std 1002.1-2001) for Unicode.
+ *
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
+ * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
+ *
+ * In fixed-width output devices, Latin characters all occupy a single
+ * "cell" position of equal width, whereas ideographic CJK characters
+ * occupy two such cells. Interoperability between terminal-line
+ * applications and (teletype-style) character terminals using the
+ * UTF-8 encoding requires agreement on which character should advance
+ * the cursor by how many cell positions. No established formal
+ * standards exist at present on which Unicode character shall occupy
+ * how many cell positions on character terminals. These routines are
+ * a first attempt of defining such behavior based on simple rules
+ * applied to data provided by the Unicode Consortium.
+ *
+ * For some graphical characters, the Unicode standard explicitly
+ * defines a character-cell width via the definition of the East Asian
+ * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
+ * In all these cases, there is no ambiguity about which width a
+ * terminal shall use. For characters in the East Asian Ambiguous (A)
+ * class, the width choice depends purely on a preference of backward
+ * compatibility with either historic CJK or Western practice.
+ * Choosing single-width for these characters is easy to justify as
+ * the appropriate long-term solution, as the CJK practice of
+ * displaying these characters as double-width comes from historic
+ * implementation simplicity (8-bit encoded characters were displayed
+ * single-width and 16-bit ones double-width, even for Greek,
+ * Cyrillic, etc.) and not any typographic considerations.
+ *
+ * Much less clear is the choice of width for the Not East Asian
+ * (Neutral) class. Existing practice does not dictate a width for any
+ * of these characters. It would nevertheless make sense
+ * typographically to allocate two character cells to characters such
+ * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
+ * represented adequately with a single-width glyph. The following
+ * routines at present merely assign a single-cell width to all
+ * neutral characters, in the interest of simplicity. This is not
+ * entirely satisfactory and should be reconsidered before
+ * establishing a formal standard in this area. At the moment, the
+ * decision which Not East Asian (Neutral) characters should be
+ * represented by double-width glyphs cannot yet be answered by
+ * applying a simple rule from the Unicode database content. Setting
+ * up a proper standard for the behavior of UTF-8 character terminals
+ * will require a careful analysis not only of each Unicode character,
+ * but also of each presentation form, something the author of these
+ * routines has avoided to do so far.
+ *
+ * http://www.unicode.org/unicode/reports/tr11/
+ *
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * for any purpose and without fee is hereby granted. The author
+ * disclaims all warranties with regard to this software.
+ *
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+
+/* Assigned Unicode character ranges:
+ * Plane Range
+ * 0 0000–FFFF Basic Multilingual Plane
+ * 1 10000–1FFFF Supplementary Multilingual Plane
+ * 2 20000–2FFFF Supplementary Ideographic Plane
+ * 3 30000-3FFFF Tertiary Ideographic Plane (no chars assigned yet)
+ * 4-13 40000–DFFFF currently unassigned
+ * 14 E0000–EFFFF Supplementary Special-purpose Plane
+ * 15 F0000–FFFFF Supplementary Private Use Area-A
+ * 16 100000–10FFFF Supplementary Private Use Area-B
+ *
+ * "Supplementary Special-purpose Plane currently contains non-graphical
+ * characters in two blocks of 128 and 240 characters. The first block
+ * is for language tag characters for use when language cannot be indicated
+ * through other protocols (such as the xml:lang attribute in XML).
+ * The other block contains glyph variation selectors to indicate
+ * an alternate glyph for a character that cannot be determined by context."
+ *
+ * In simpler terms: it is a tool to fix the "Han unification" mess
+ * created by Unicode committee, to select Chinese/Japanese/Korean/Taiwan
+ * version of a character. (They forgot that the whole purpose of the Unicode
+ * was to be able to write all chars in one charset without such tricks).
+ * Until East Asian users say it is actually necessary to support these
+ * code points in console applications like busybox
+ * (i.e. do these chars ever appear in filenames, hostnames, text files
+ * and such?), we are treating these code points as invalid.
+ *
+ * Tertiary Ideographic Plane is also ignored for now,
+ * until Unicode committee assigns something there.
+ */
+/* The following two functions define the column width of an ISO 10646
+ * character as follows:
+ *
+ * - The null character (U+0000) has a column width of 0.
+ *
+ * - Other C0/C1 control characters and DEL will lead to a return
+ * value of -1.
+ *
+ * - Non-spacing and enclosing combining characters (general
+ * category code Mn or Me in the Unicode database) have a
+ * column width of 0.
+ *
+ * - SOFT HYPHEN (U+00AD) has a column width of 1.
+ *
+ * - Other format characters (general category code Cf in the Unicode
+ * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+ *
+ * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+ * have a column width of 0.
+ *
+ * - Spacing characters in the East Asian Wide (W) or East Asian
+ * Full-width (F) category as defined in Unicode Technical
+ * Report #11 have a column width of 2.
+ *
+ * - All remaining characters (including all printable
+ * ISO 8859-1 and WGL4 characters, Unicode control characters,
+ * etc.) have a column width of 1.
+ *
+ * This implementation assumes that wchar_t characters are encoded
+ * in ISO 10646.
+ */
+int FAST_FUNC wcwidth(unsigned ucs)
+{
+# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300
+ /* sorted list of non-overlapping intervals of non-spacing characters */
+ /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
+# define BIG_(a,b) { a, b },
+# define PAIR(a,b)
+# define ARRAY /* PAIR if < 0x4000 and no more than 4 chars big */ \
+ BIG_(0x0300, 0x036F) \
+ PAIR(0x0483, 0x0486) \
+ PAIR(0x0488, 0x0489) \
+ BIG_(0x0591, 0x05BD) \
+ PAIR(0x05BF, 0x05BF) \
+ PAIR(0x05C1, 0x05C2) \
+ PAIR(0x05C4, 0x05C5) \
+ PAIR(0x05C7, 0x05C7) \
+ PAIR(0x0600, 0x0603) \
+ BIG_(0x0610, 0x0615) \
+ BIG_(0x064B, 0x065E) \
+ PAIR(0x0670, 0x0670) \
+ BIG_(0x06D6, 0x06E4) \
+ PAIR(0x06E7, 0x06E8) \
+ PAIR(0x06EA, 0x06ED) \
+ PAIR(0x070F, 0x070F) \
+ PAIR(0x0711, 0x0711) \
+ BIG_(0x0730, 0x074A) \
+ BIG_(0x07A6, 0x07B0) \
+ BIG_(0x07EB, 0x07F3) \
+ PAIR(0x0901, 0x0902) \
+ PAIR(0x093C, 0x093C) \
+ BIG_(0x0941, 0x0948) \
+ PAIR(0x094D, 0x094D) \
+ PAIR(0x0951, 0x0954) \
+ PAIR(0x0962, 0x0963) \
+ PAIR(0x0981, 0x0981) \
+ PAIR(0x09BC, 0x09BC) \
+ PAIR(0x09C1, 0x09C4) \
+ PAIR(0x09CD, 0x09CD) \
+ PAIR(0x09E2, 0x09E3) \
+ PAIR(0x0A01, 0x0A02) \
+ PAIR(0x0A3C, 0x0A3C) \
+ PAIR(0x0A41, 0x0A42) \
+ PAIR(0x0A47, 0x0A48) \
+ PAIR(0x0A4B, 0x0A4D) \
+ PAIR(0x0A70, 0x0A71) \
+ PAIR(0x0A81, 0x0A82) \
+ PAIR(0x0ABC, 0x0ABC) \
+ BIG_(0x0AC1, 0x0AC5) \
+ PAIR(0x0AC7, 0x0AC8) \
+ PAIR(0x0ACD, 0x0ACD) \
+ PAIR(0x0AE2, 0x0AE3) \
+ PAIR(0x0B01, 0x0B01) \
+ PAIR(0x0B3C, 0x0B3C) \
+ PAIR(0x0B3F, 0x0B3F) \
+ PAIR(0x0B41, 0x0B43) \
+ PAIR(0x0B4D, 0x0B4D) \
+ PAIR(0x0B56, 0x0B56) \
+ PAIR(0x0B82, 0x0B82) \
+ PAIR(0x0BC0, 0x0BC0) \
+ PAIR(0x0BCD, 0x0BCD) \
+ PAIR(0x0C3E, 0x0C40) \
+ PAIR(0x0C46, 0x0C48) \
+ PAIR(0x0C4A, 0x0C4D) \
+ PAIR(0x0C55, 0x0C56) \
+ PAIR(0x0CBC, 0x0CBC) \
+ PAIR(0x0CBF, 0x0CBF) \
+ PAIR(0x0CC6, 0x0CC6) \
+ PAIR(0x0CCC, 0x0CCD) \
+ PAIR(0x0CE2, 0x0CE3) \
+ PAIR(0x0D41, 0x0D43) \
+ PAIR(0x0D4D, 0x0D4D) \
+ PAIR(0x0DCA, 0x0DCA) \
+ PAIR(0x0DD2, 0x0DD4) \
+ PAIR(0x0DD6, 0x0DD6) \
+ PAIR(0x0E31, 0x0E31) \
+ BIG_(0x0E34, 0x0E3A) \
+ BIG_(0x0E47, 0x0E4E) \
+ PAIR(0x0EB1, 0x0EB1) \
+ BIG_(0x0EB4, 0x0EB9) \
+ PAIR(0x0EBB, 0x0EBC) \
+ BIG_(0x0EC8, 0x0ECD) \
+ PAIR(0x0F18, 0x0F19) \
+ PAIR(0x0F35, 0x0F35) \
+ PAIR(0x0F37, 0x0F37) \
+ PAIR(0x0F39, 0x0F39) \
+ BIG_(0x0F71, 0x0F7E) \
+ BIG_(0x0F80, 0x0F84) \
+ PAIR(0x0F86, 0x0F87) \
+ PAIR(0x0FC6, 0x0FC6) \
+ BIG_(0x0F90, 0x0F97) \
+ BIG_(0x0F99, 0x0FBC) \
+ PAIR(0x102D, 0x1030) \
+ PAIR(0x1032, 0x1032) \
+ PAIR(0x1036, 0x1037) \
+ PAIR(0x1039, 0x1039) \
+ PAIR(0x1058, 0x1059) \
+ BIG_(0x1160, 0x11FF) \
+ PAIR(0x135F, 0x135F) \
+ PAIR(0x1712, 0x1714) \
+ PAIR(0x1732, 0x1734) \
+ PAIR(0x1752, 0x1753) \
+ PAIR(0x1772, 0x1773) \
+ PAIR(0x17B4, 0x17B5) \
+ BIG_(0x17B7, 0x17BD) \
+ PAIR(0x17C6, 0x17C6) \
+ BIG_(0x17C9, 0x17D3) \
+ PAIR(0x17DD, 0x17DD) \
+ PAIR(0x180B, 0x180D) \
+ PAIR(0x18A9, 0x18A9) \
+ PAIR(0x1920, 0x1922) \
+ PAIR(0x1927, 0x1928) \
+ PAIR(0x1932, 0x1932) \
+ PAIR(0x1939, 0x193B) \
+ PAIR(0x1A17, 0x1A18) \
+ PAIR(0x1B00, 0x1B03) \
+ PAIR(0x1B34, 0x1B34) \
+ BIG_(0x1B36, 0x1B3A) \
+ PAIR(0x1B3C, 0x1B3C) \
+ PAIR(0x1B42, 0x1B42) \
+ BIG_(0x1B6B, 0x1B73) \
+ BIG_(0x1DC0, 0x1DCA) \
+ PAIR(0x1DFE, 0x1DFF) \
+ BIG_(0x200B, 0x200F) \
+ BIG_(0x202A, 0x202E) \
+ PAIR(0x2060, 0x2063) \
+ BIG_(0x206A, 0x206F) \
+ BIG_(0x20D0, 0x20EF) \
+ BIG_(0x302A, 0x302F) \
+ PAIR(0x3099, 0x309A) \
+ /* Too big to be packed in PAIRs: */ \
+ BIG_(0xA806, 0xA806) \
+ BIG_(0xA80B, 0xA80B) \
+ BIG_(0xA825, 0xA826) \
+ BIG_(0xFB1E, 0xFB1E) \
+ BIG_(0xFE00, 0xFE0F) \
+ BIG_(0xFE20, 0xFE23) \
+ BIG_(0xFEFF, 0xFEFF) \
+ BIG_(0xFFF9, 0xFFFB)
+ static const struct interval combining[] = { ARRAY };
+# undef BIG_
+# undef PAIR
+# define BIG_(a,b)
+# define PAIR(a,b) (a << 2) | (b-a),
+ static const uint16_t combining1[] = { ARRAY };
+# undef BIG_
+# undef PAIR
+# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
+# define PAIR(a,b) char pair##a[b >= 0x4000 || b-a > 3 ? -1 : 1];
+ struct CHECK { ARRAY };
+# undef BIG_
+# undef PAIR
+# undef ARRAY
+# endif
+
+ if (ucs == 0)
+ return 0;
+
+ /* Test for 8-bit control characters (00-1f, 80-9f, 7f) */
+ if ((ucs & ~0x80) < 0x20 || ucs == 0x7f)
+ return -1;
+ /* Quick abort if it is an obviously invalid char */
+ if (ucs > CONFIG_LAST_SUPPORTED_WCHAR)
+ return -1;
+
+ /* Optimization: no combining chars below 0x300 */
+ if (CONFIG_LAST_SUPPORTED_WCHAR < 0x300 || ucs < 0x300)
+ return 1;
+
+# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300
+ /* Binary search in table of non-spacing characters */
+ if (in_interval_table(ucs, combining, ARRAY_SIZE(combining) - 1))
+ return 0;
+ if (in_uint16_table(ucs, combining1, ARRAY_SIZE(combining1) - 1))
+ return 0;
+
+ /* Optimization: all chars below 0x1100 are not double-width */
+ if (CONFIG_LAST_SUPPORTED_WCHAR < 0x1100 || ucs < 0x1100)
+ return 1;
+
+# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x1100
+ /* Invalid code points: */
+ /* High (d800..dbff) and low (dc00..dfff) surrogates (valid only in UTF16) */
+ /* Private Use Area (e000..f8ff) */
+ /* Noncharacters fdd0..fdef */
+ if ((CONFIG_LAST_SUPPORTED_WCHAR >= 0xd800 && ucs >= 0xd800 && ucs <= 0xf8ff)
+ || (CONFIG_LAST_SUPPORTED_WCHAR >= 0xfdd0 && ucs >= 0xfdd0 && ucs <= 0xfdef)
+ ) {
+ return -1;
+ }
+ /* 0xfffe and 0xffff in every plane are invalid */
+ if (CONFIG_LAST_SUPPORTED_WCHAR >= 0xfffe && ((ucs & 0xfffe) == 0xfffe)) {
+ return -1;
+ }
+
+# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x10000
+ if (ucs >= 0x10000) {
+ /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */
+ static const struct interval combining0x10000[] = {
+ { 0x0A01, 0x0A03 }, { 0x0A05, 0x0A06 }, { 0x0A0C, 0x0A0F },
+ { 0x0A38, 0x0A3A }, { 0x0A3F, 0x0A3F }, { 0xD167, 0xD169 },
+ { 0xD173, 0xD182 }, { 0xD185, 0xD18B }, { 0xD1AA, 0xD1AD },
+ { 0xD242, 0xD244 }
+ };
+ /* Binary search in table of non-spacing characters in Supplementary Multilingual Plane */
+ if (in_interval_table(ucs ^ 0x10000, combining0x10000, ARRAY_SIZE(combining0x10000) - 1))
+ return 0;
+ /* Check a few non-spacing chars in Supplementary Special-purpose Plane 0xExxxx */
+ if (CONFIG_LAST_SUPPORTED_WCHAR >= 0xE0001
+ && ( ucs == 0xE0001
+ || (ucs >= 0xE0020 && ucs <= 0xE007F)
+ || (ucs >= 0xE0100 && ucs <= 0xE01EF)
+ )
+ ) {
+ return 0;
+ }
+ }
+# endif
+
+ /* If we arrive here, ucs is not a combining or C0/C1 control character.
+ * Check whether it's 1 char or 2-shar wide.
+ */
+ return 1 +
+ ( (/*ucs >= 0x1100 &&*/ ucs <= 0x115f) /* Hangul Jamo init. consonants */
+ || ucs == 0x2329 /* left-pointing angle bracket; also CJK punct. char */
+ || ucs == 0x232a /* right-pointing angle bracket; also CJK punct. char */
+ || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) /* CJK ... Yi */
+# if CONFIG_LAST_SUPPORTED_WCHAR >= 0xac00
+ || (ucs >= 0xac00 && ucs <= 0xd7a3) /* Hangul Syllables */
+ || (ucs >= 0xf900 && ucs <= 0xfaff) /* CJK Compatibility Ideographs */
+ || (ucs >= 0xfe10 && ucs <= 0xfe19) /* Vertical forms */
+ || (ucs >= 0xfe30 && ucs <= 0xfe6f) /* CJK Compatibility Forms */
+ || (ucs >= 0xff00 && ucs <= 0xff60) /* Fullwidth Forms */
+ || (ucs >= 0xffe0 && ucs <= 0xffe6)
+ || ((ucs >> 17) == (2 >> 1)) /* 20000..3ffff: Supplementary and Tertiary Ideographic Planes */
+# endif
+ );
+# endif /* >= 0x1100 */
+# endif /* >= 0x300 */
+}
+
+
+# if ENABLE_UNICODE_BIDI_SUPPORT
+int FAST_FUNC unicode_bidi_isrtl(wint_t wc)
+{
+ /* ranges taken from
+ * http://www.unicode.org/Public/5.2.0/ucd/extracted/DerivedBidiClass.txt
+ * Bidi_Class=Left_To_Right | Bidi_Class=Arabic_Letter
+ */
+# define BIG_(a,b) { a, b },
+# define PAIR(a,b)
+# define ARRAY \
+ PAIR(0x0590, 0x0590) \
+ PAIR(0x05BE, 0x05BE) \
+ PAIR(0x05C0, 0x05C0) \
+ PAIR(0x05C3, 0x05C3) \
+ PAIR(0x05C6, 0x05C6) \
+ BIG_(0x05C8, 0x05FF) \
+ PAIR(0x0604, 0x0605) \
+ PAIR(0x0608, 0x0608) \
+ PAIR(0x060B, 0x060B) \
+ PAIR(0x060D, 0x060D) \
+ BIG_(0x061B, 0x064A) \
+ PAIR(0x065F, 0x065F) \
+ PAIR(0x066D, 0x066F) \
+ BIG_(0x0671, 0x06D5) \
+ PAIR(0x06E5, 0x06E6) \
+ PAIR(0x06EE, 0x06EF) \
+ BIG_(0x06FA, 0x070E) \
+ PAIR(0x0710, 0x0710) \
+ BIG_(0x0712, 0x072F) \
+ BIG_(0x074B, 0x07A5) \
+ BIG_(0x07B1, 0x07EA) \
+ PAIR(0x07F4, 0x07F5) \
+ BIG_(0x07FA, 0x0815) \
+ PAIR(0x081A, 0x081A) \
+ PAIR(0x0824, 0x0824) \
+ PAIR(0x0828, 0x0828) \
+ BIG_(0x082E, 0x08FF) \
+ PAIR(0x200F, 0x200F) \
+ PAIR(0x202B, 0x202B) \
+ PAIR(0x202E, 0x202E) \
+ BIG_(0xFB1D, 0xFB1D) \
+ BIG_(0xFB1F, 0xFB28) \
+ BIG_(0xFB2A, 0xFD3D) \
+ BIG_(0xFD40, 0xFDCF) \
+ BIG_(0xFDC8, 0xFDCF) \
+ BIG_(0xFDF0, 0xFDFC) \
+ BIG_(0xFDFE, 0xFDFF) \
+ BIG_(0xFE70, 0xFEFE)
+ /* Probably not necessary
+ {0x10800, 0x1091E},
+ {0x10920, 0x10A00},
+ {0x10A04, 0x10A04},
+ {0x10A07, 0x10A0B},
+ {0x10A10, 0x10A37},
+ {0x10A3B, 0x10A3E},
+ {0x10A40, 0x10A7F},
+ {0x10B36, 0x10B38},
+ {0x10B40, 0x10E5F},
+ {0x10E7F, 0x10FFF},
+ {0x1E800, 0x1EFFF}
+ */
+ static const struct interval rtl_b[] = { ARRAY };
+# undef BIG_
+# undef PAIR
+# define BIG_(a,b)
+# define PAIR(a,b) (a << 2) | (b-a),
+ static const uint16_t rtl_p[] = { ARRAY };
+# undef BIG_
+# undef PAIR
+# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
+# define PAIR(a,b) char pair##a[b >= 0x4000 || b-a > 3 ? -1 : 1];
+ struct CHECK { ARRAY };
+# undef BIG_
+# undef PAIR
+# undef ARRAY
+
+ if (in_interval_table(wc, rtl_b, ARRAY_SIZE(rtl_b) - 1))
+ return 1;
+ if (in_uint16_table(wc, rtl_p, ARRAY_SIZE(rtl_p) - 1))
+ return 1;
+ return 0;
+}
+
+# if ENABLE_UNICODE_NEUTRAL_TABLE
+int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc)
+{
+ /* ranges taken from
+ * http://www.unicode.org/Public/5.2.0/ucd/extracted/DerivedBidiClass.txt
+ * Bidi_Classes: Paragraph_Separator, Segment_Separator,
+ * White_Space, Other_Neutral, European_Number, European_Separator,
+ * European_Terminator, Arabic_Number, Common_Separator
+ */
+# define BIG_(a,b) { a, b },
+# define PAIR(a,b)
+# define ARRAY \
+ BIG_(0x0009, 0x000D) \
+ BIG_(0x001C, 0x0040) \
+ BIG_(0x005B, 0x0060) \
+ PAIR(0x007B, 0x007E) \
+ PAIR(0x0085, 0x0085) \
+ BIG_(0x00A0, 0x00A9) \
+ PAIR(0x00AB, 0x00AC) \
+ BIG_(0x00AE, 0x00B4) \
+ PAIR(0x00B6, 0x00B9) \
+ BIG_(0x00BB, 0x00BF) \
+ PAIR(0x00D7, 0x00D7) \
+ PAIR(0x00F7, 0x00F7) \
+ PAIR(0x02B9, 0x02BA) \
+ BIG_(0x02C2, 0x02CF) \
+ BIG_(0x02D2, 0x02DF) \
+ BIG_(0x02E5, 0x02FF) \
+ PAIR(0x0374, 0x0375) \
+ PAIR(0x037E, 0x037E) \
+ PAIR(0x0384, 0x0385) \
+ PAIR(0x0387, 0x0387) \
+ PAIR(0x03F6, 0x03F6) \
+ PAIR(0x058A, 0x058A) \
+ PAIR(0x0600, 0x0603) \
+ PAIR(0x0606, 0x0607) \
+ PAIR(0x0609, 0x060A) \
+ PAIR(0x060C, 0x060C) \
+ PAIR(0x060E, 0x060F) \
+ BIG_(0x0660, 0x066C) \
+ PAIR(0x06DD, 0x06DD) \
+ PAIR(0x06E9, 0x06E9) \
+ BIG_(0x06F0, 0x06F9) \
+ PAIR(0x07F6, 0x07F9) \
+ PAIR(0x09F2, 0x09F3) \
+ PAIR(0x09FB, 0x09FB) \
+ PAIR(0x0AF1, 0x0AF1) \
+ BIG_(0x0BF3, 0x0BFA) \
+ BIG_(0x0C78, 0x0C7E) \
+ PAIR(0x0CF1, 0x0CF2) \
+ PAIR(0x0E3F, 0x0E3F) \
+ PAIR(0x0F3A, 0x0F3D) \
+ BIG_(0x1390, 0x1400) \
+ PAIR(0x1680, 0x1680) \
+ PAIR(0x169B, 0x169C) \
+ PAIR(0x17DB, 0x17DB) \
+ BIG_(0x17F0, 0x17F9) \
+ BIG_(0x1800, 0x180A) \
+ PAIR(0x180E, 0x180E) \
+ PAIR(0x1940, 0x1940) \
+ PAIR(0x1944, 0x1945) \
+ BIG_(0x19DE, 0x19FF) \
+ PAIR(0x1FBD, 0x1FBD) \
+ PAIR(0x1FBF, 0x1FC1) \
+ PAIR(0x1FCD, 0x1FCF) \
+ PAIR(0x1FDD, 0x1FDF) \
+ PAIR(0x1FED, 0x1FEF) \
+ PAIR(0x1FFD, 0x1FFE) \
+ BIG_(0x2000, 0x200A) \
+ BIG_(0x2010, 0x2029) \
+ BIG_(0x202F, 0x205F) \
+ PAIR(0x2070, 0x2070) \
+ BIG_(0x2074, 0x207E) \
+ BIG_(0x2080, 0x208E) \
+ BIG_(0x20A0, 0x20B8) \
+ PAIR(0x2100, 0x2101) \
+ PAIR(0x2103, 0x2106) \
+ PAIR(0x2108, 0x2109) \
+ PAIR(0x2114, 0x2114) \
+ PAIR(0x2116, 0x2118) \
+ BIG_(0x211E, 0x2123) \
+ PAIR(0x2125, 0x2125) \
+ PAIR(0x2127, 0x2127) \
+ PAIR(0x2129, 0x2129) \
+ PAIR(0x212E, 0x212E) \
+ PAIR(0x213A, 0x213B) \
+ BIG_(0x2140, 0x2144) \
+ PAIR(0x214A, 0x214D) \
+ BIG_(0x2150, 0x215F) \
+ PAIR(0x2189, 0x2189) \
+ BIG_(0x2190, 0x2335) \
+ BIG_(0x237B, 0x2394) \
+ BIG_(0x2396, 0x23E8) \
+ BIG_(0x2400, 0x2426) \
+ BIG_(0x2440, 0x244A) \
+ BIG_(0x2460, 0x249B) \
+ BIG_(0x24EA, 0x26AB) \
+ BIG_(0x26AD, 0x26CD) \
+ BIG_(0x26CF, 0x26E1) \
+ PAIR(0x26E3, 0x26E3) \
+ BIG_(0x26E8, 0x26FF) \
+ PAIR(0x2701, 0x2704) \
+ PAIR(0x2706, 0x2709) \
+ BIG_(0x270C, 0x2727) \
+ BIG_(0x2729, 0x274B) \
+ PAIR(0x274D, 0x274D) \
+ PAIR(0x274F, 0x2752) \
+ BIG_(0x2756, 0x275E) \
+ BIG_(0x2761, 0x2794) \
+ BIG_(0x2798, 0x27AF) \
+ BIG_(0x27B1, 0x27BE) \
+ BIG_(0x27C0, 0x27CA) \
+ PAIR(0x27CC, 0x27CC) \
+ BIG_(0x27D0, 0x27FF) \
+ BIG_(0x2900, 0x2B4C) \
+ BIG_(0x2B50, 0x2B59) \
+ BIG_(0x2CE5, 0x2CEA) \
+ BIG_(0x2CF9, 0x2CFF) \
+ BIG_(0x2E00, 0x2E99) \
+ BIG_(0x2E9B, 0x2EF3) \
+ BIG_(0x2F00, 0x2FD5) \
+ BIG_(0x2FF0, 0x2FFB) \
+ BIG_(0x3000, 0x3004) \
+ BIG_(0x3008, 0x3020) \
+ PAIR(0x3030, 0x3030) \
+ PAIR(0x3036, 0x3037) \
+ PAIR(0x303D, 0x303D) \
+ PAIR(0x303E, 0x303F) \
+ PAIR(0x309B, 0x309C) \
+ PAIR(0x30A0, 0x30A0) \
+ PAIR(0x30FB, 0x30FB) \
+ BIG_(0x31C0, 0x31E3) \
+ PAIR(0x321D, 0x321E) \
+ BIG_(0x3250, 0x325F) \
+ PAIR(0x327C, 0x327E) \
+ BIG_(0x32B1, 0x32BF) \
+ PAIR(0x32CC, 0x32CF) \
+ PAIR(0x3377, 0x337A) \
+ PAIR(0x33DE, 0x33DF) \
+ PAIR(0x33FF, 0x33FF) \
+ BIG_(0x4DC0, 0x4DFF) \
+ BIG_(0xA490, 0xA4C6) \
+ BIG_(0xA60D, 0xA60F) \
+ BIG_(0xA673, 0xA673) \
+ BIG_(0xA67E, 0xA67F) \
+ BIG_(0xA700, 0xA721) \
+ BIG_(0xA788, 0xA788) \
+ BIG_(0xA828, 0xA82B) \
+ BIG_(0xA838, 0xA839) \
+ BIG_(0xA874, 0xA877) \
+ BIG_(0xFB29, 0xFB29) \
+ BIG_(0xFD3E, 0xFD3F) \
+ BIG_(0xFDFD, 0xFDFD) \
+ BIG_(0xFE10, 0xFE19) \
+ BIG_(0xFE30, 0xFE52) \
+ BIG_(0xFE54, 0xFE66) \
+ BIG_(0xFE68, 0xFE6B) \
+ BIG_(0xFF01, 0xFF20) \
+ BIG_(0xFF3B, 0xFF40) \
+ BIG_(0xFF5B, 0xFF65) \
+ BIG_(0xFFE0, 0xFFE6) \
+ BIG_(0xFFE8, 0xFFEE) \
+ BIG_(0xFFF9, 0xFFFD)
+ /*
+ {0x10101, 0x10101},
+ {0x10140, 0x1019B},
+ {0x1091F, 0x1091F},
+ {0x10B39, 0x10B3F},
+ {0x10E60, 0x10E7E},
+ {0x1D200, 0x1D241},
+ {0x1D245, 0x1D245},
+ {0x1D300, 0x1D356},
+ {0x1D6DB, 0x1D6DB},
+ {0x1D715, 0x1D715},
+ {0x1D74F, 0x1D74F},
+ {0x1D789, 0x1D789},
+ {0x1D7C3, 0x1D7C3},
+ {0x1D7CE, 0x1D7FF},
+ {0x1F000, 0x1F02B},
+ {0x1F030, 0x1F093},
+ {0x1F100, 0x1F10A}
+ */
+ static const struct interval neutral_b[] = { ARRAY };
+# undef BIG_
+# undef PAIR
+# define BIG_(a,b)
+# define PAIR(a,b) (a << 2) | (b-a),
+ static const uint16_t neutral_p[] = { ARRAY };
+# undef BIG_
+# undef PAIR
+# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
+# define PAIR(a,b) char pair##a[b >= 0x4000 || b-a > 3 ? -1 : 1];
+ struct CHECK { ARRAY };
+# undef BIG_
+# undef PAIR
+# undef ARRAY
+
+ if (in_interval_table(wc, neutral_b, ARRAY_SIZE(neutral_b) - 1))
+ return 1;
+ if (in_uint16_table(wc, neutral_p, ARRAY_SIZE(neutral_p) - 1))
+ return 1;
+ return 0;
+}
+# endif
+
+# endif /* UNICODE_BIDI_SUPPORT */
+
+#endif /* Homegrown Unicode support */
+
+
+/* The rest is mostly same for libc and for "homegrown" support */
+
+#if 0 // UNUSED
+size_t FAST_FUNC unicode_strlen(const char *string)
+{
+ size_t width = mbstowcs(NULL, string, INT_MAX);
+ if (width == (size_t)-1L)
+ return strlen(string);
+ return width;
+}
+#endif
+
+size_t FAST_FUNC unicode_strwidth(const char *string)
+{
+ uni_stat_t uni_stat;
+ printable_string(&uni_stat, string);
+ return uni_stat.unicode_width;
+}
+
+static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
+{
+ char *dst;
+ unsigned dst_len;
+ unsigned uni_count;
+ unsigned uni_width;
+
+ if (unicode_status != UNICODE_ON) {
+ char *d;
+ if (flags & UNI_FLAG_PAD) {
+ d = dst = xmalloc(width + 1);
+ while ((int)--width >= 0) {
+ unsigned char c = *src;
+ if (c == '\0') {
+ do
+ *d++ = ' ';
+ while ((int)--width >= 0);
+ break;
+ }
+ *d++ = (c >= ' ' && c < 0x7f) ? c : '?';
+ src++;
+ }
+ *d = '\0';
+ } else {
+ d = dst = xstrndup(src, width);
+ while (*d) {
+ unsigned char c = *d;
+ if (c < ' ' || c >= 0x7f)
+ *d = '?';
+ d++;
+ }
+ }
+ if (stats) {
+ stats->byte_count = (d - dst);
+ stats->unicode_count = (d - dst);
+ stats->unicode_width = (d - dst);
+ }
+ return dst;
+ }
+
+ dst = NULL;
+ uni_count = uni_width = 0;
+ dst_len = 0;
+ while (1) {
+ int w;
+ wchar_t wc;
+
+#if ENABLE_UNICODE_USING_LOCALE
+ {
+ mbstate_t mbst = { 0 };
+ ssize_t rc = mbsrtowcs(&wc, &src, 1, &mbst);
+ /* If invalid sequence is seen: -1 is returned,
+ * src points to the invalid sequence, errno = EILSEQ.
+ * Else number of wchars (excluding terminating L'\0')
+ * written to dest is returned.
+ * If len (here: 1) non-L'\0' wchars stored at dest,
+ * src points to the next char to be converted.
+ * If string is completely converted: src = NULL.
+ */
+ if (rc == 0) /* end-of-string */
+ break;
+ if (rc < 0) { /* error */
+ src++;
+ goto subst;
+ }
+ if (!iswprint(wc))
+ goto subst;
+ }
+#else
+ src = mbstowc_internal(&wc, src);
+ /* src is advanced to next mb char
+ * wc == ERROR_WCHAR: invalid sequence is seen
+ * else: wc is set
+ */
+ if (wc == ERROR_WCHAR) /* error */
+ goto subst;
+ if (wc == 0) /* end-of-string */
+ break;
+#endif
+ if (CONFIG_LAST_SUPPORTED_WCHAR && wc > CONFIG_LAST_SUPPORTED_WCHAR)
+ goto subst;
+ w = wcwidth(wc);
+ if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0) /* non-printable wchar */
+ || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
+ || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
+ ) {
+ subst:
+ wc = CONFIG_SUBST_WCHAR;
+ w = 1;
+ }
+ width -= w;
+ /* Note: if width == 0, we still may add more chars,
+ * they may be zero-width or combining ones */
+ if ((int)width < 0) {
+ /* can't add this wc, string would become longer than width */
+ width += w;
+ break;
+ }
+
+ uni_count++;
+ uni_width += w;
+ dst = xrealloc(dst, dst_len + MB_CUR_MAX);
+#if ENABLE_UNICODE_USING_LOCALE
+ {
+ mbstate_t mbst = { 0 };
+ dst_len += wcrtomb(&dst[dst_len], wc, &mbst);
+ }
+#else
+ dst_len += wcrtomb_internal(&dst[dst_len], wc);
+#endif
+ }
+
+ /* Pad to remaining width */
+ if (flags & UNI_FLAG_PAD) {
+ dst = xrealloc(dst, dst_len + width + 1);
+ uni_count += width;
+ uni_width += width;
+ while ((int)--width >= 0) {
+ dst[dst_len++] = ' ';
+ }
+ }
+ dst[dst_len] = '\0';
+ if (stats) {
+ stats->byte_count = dst_len;
+ stats->unicode_count = uni_count;
+ stats->unicode_width = uni_width;
+ }
+
+ return dst;
+}
+char* FAST_FUNC unicode_conv_to_printable(uni_stat_t *stats, const char *src)
+{
+ return unicode_conv_to_printable2(stats, src, INT_MAX, 0);
+}
+char* FAST_FUNC unicode_conv_to_printable_fixedwidth(/*uni_stat_t *stats,*/ const char *src, unsigned width)
+{
+ return unicode_conv_to_printable2(/*stats:*/ NULL, src, width, UNI_FLAG_PAD);
+}
+
+#ifdef UNUSED
+char* FAST_FUNC unicode_conv_to_printable_maxwidth(uni_stat_t *stats, const char *src, unsigned maxwidth)
+{
+ return unicode_conv_to_printable2(stats, src, maxwidth, 0);
+}
+
+unsigned FAST_FUNC unicode_padding_to_width(unsigned width, const char *src)
+{
+ if (unicode_status != UNICODE_ON) {
+ return width - strnlen(src, width);
+ }
+
+ while (1) {
+ int w;
+ wchar_t wc;
+
+#if ENABLE_UNICODE_USING_LOCALE
+ {
+ mbstate_t mbst = { 0 };
+ ssize_t rc = mbsrtowcs(&wc, &src, 1, &mbst);
+ if (rc <= 0) /* error, or end-of-string */
+ return width;
+ }
+#else
+ src = mbstowc_internal(&wc, src);
+ if (wc == ERROR_WCHAR || wc == 0) /* error, or end-of-string */
+ return width;
+#endif
+ w = wcwidth(wc);
+ if (w < 0) /* non-printable wchar */
+ return width;
+ width -= w;
+ if ((int)width <= 0) /* string is longer than width */
+ return 0;
+ }
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/update_passwd.c b/ap/app/busybox/src/libbb/update_passwd.c
new file mode 100644
index 0000000..a30af6f
--- /dev/null
+++ b/ap/app/busybox/src/libbb/update_passwd.c
@@ -0,0 +1,285 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * update_passwd
+ *
+ * update_passwd is a common function for passwd and chpasswd applets;
+ * it is responsible for updating password file (i.e. /etc/passwd or
+ * /etc/shadow) for a given user and password.
+ *
+ * Moved from loginutils/passwd.c by Alexander Shishkin <virtuoso@slind.org>
+ *
+ * Modified to be able to add or delete users, groups and users to/from groups
+ * by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#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 password: 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;
+ char *name_colon;
+ unsigned user_len;
+ int old_fd;
+ int new_fd;
+ int i;
+ int changed_lines;
+ int ret = -1; /* failure */
+ /* used as a bool: "are we modifying /etc/shadow?" */
+#if ENABLE_FEATURE_SHADOWPASSWDS
+ const char *shadow = strstr(filename, "shadow");
+#else
+# define shadow NULL
+#endif
+
+ 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_colon = xasprintf("%s:", name);
+ user_len = strlen(name_colon);
+
+ if (shadow)
+ old_fp = fopen(filename, "r+");
+ else
+ old_fp = fopen_or_warn(filename, "r+");
+ if (!old_fp) {
+ if (shadow)
+ ret = 0; /* missing shadow is not an error */
+ 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) == 0) {
+ fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
+ fchown(new_fd, sb.st_uid, sb.st_gid);
+ }
+ errno = 0;
+ new_fp = xfdopen_for_write(new_fd);
+
+ /* 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_colon, 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 */
+
+ if (shadow && *cp == ':') {
+ /* /etc/shadow's field 3 (passwd change date) needs updating */
+ /* move past old change date */
+ cp = strchrnul(cp + 1, ':');
+ /* "name:" + "new_passwd" + ":" + "change date" + ":rest of line" */
+ fprintf(new_fp, "%s%s:%u%s\n", name_colon, new_passwd,
+ (unsigned)(time(NULL)) / (24*60*60), cp);
+ } else {
+ /* "name:" + "new_passwd" + ":rest of line" */
+ fprintf(new_fp, "%s%s%s\n", name_colon, new_passwd, cp);
+ }
+ changed_lines++;
+ } /* else delete user or group: skip the line */
+ next:
+ free(line);
+ }
+
+ if (changed_lines == 0) {
+#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
+ if (member) {
+ if (ENABLE_ADDGROUP && applet_name[0] == 'a')
+ bb_error_msg("can't find %s in %s", name, filename);
+ if (ENABLE_DELGROUP && applet_name[0] == 'd')
+ 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_colon, 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(name_colon);
+ return ret;
+}
diff --git a/ap/app/busybox/src/libbb/utmp.c b/ap/app/busybox/src/libbb/utmp.c
new file mode 100644
index 0000000..09443fb
--- /dev/null
+++ b/ap/app/busybox/src/libbb/utmp.c
@@ -0,0 +1,132 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * utmp/wtmp support routines.
+ *
+ * Copyright (C) 2010 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+static void touch(const char *filename)
+{
+ if (access(filename, R_OK | W_OK) == -1)
+ close(open(filename, O_WRONLY | O_CREAT, 0664));
+}
+
+void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname)
+{
+ struct utmp utent;
+ char *id;
+ unsigned width;
+
+ memset(&utent, 0, sizeof(utent));
+ utent.ut_pid = pid;
+ utent.ut_type = new_type;
+ tty_name = skip_dev_pfx(tty_name);
+ safe_strncpy(utent.ut_line, tty_name, sizeof(utent.ut_line));
+ if (username)
+ safe_strncpy(utent.ut_user, username, sizeof(utent.ut_user));
+ if (hostname)
+ safe_strncpy(utent.ut_host, hostname, sizeof(utent.ut_host));
+ utent.ut_tv.tv_sec = time(NULL);
+
+ /* Invent our own ut_id. ut_id is only 4 chars wide.
+ * Try to fit something remotely meaningful... */
+ id = utent.ut_id;
+ width = sizeof(utent.ut_id);
+ if (tty_name[0] == 'p') {
+ /* if "ptyXXX", map to "pXXX" */
+ /* if "pts/XX", map to "p/XX" */
+ *id++ = 'p';
+ width--;
+ } /* else: usually it's "ttyXXXX", map to "XXXX" */
+ if (strlen(tty_name) > 3)
+ tty_name += 3;
+ strncpy(id, tty_name, width);
+
+ touch(_PATH_UTMP);
+ //utmpname(_PATH_UTMP);
+ setutent();
+ /* Append new one (hopefully, unless we collide on ut_id) */
+ pututline(&utent);
+ endutent();
+
+#if ENABLE_FEATURE_WTMP
+ /* "man utmp" says wtmp file should *not* be created automagically */
+ /*touch(bb_path_wtmp_file);*/
+ updwtmp(bb_path_wtmp_file, &utent);
+#endif
+}
+
+/*
+ * Read "man utmp" to make sense out of it.
+ */
+void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname)
+{
+ struct utmp utent;
+ struct utmp *utp;
+
+ touch(_PATH_UTMP);
+ //utmpname(_PATH_UTMP);
+ setutent();
+
+ /* Did init/getty/telnetd/sshd/... create an entry for us?
+ * It should be (new_type-1), but we'd also reuse
+ * any other potentially stale xxx_PROCESS entry */
+ while ((utp = getutent()) != NULL) {
+ if (utp->ut_pid == pid
+ // && ut->ut_line[0]
+ && utp->ut_id[0] /* must have nonzero id */
+ && ( utp->ut_type == INIT_PROCESS
+ || utp->ut_type == LOGIN_PROCESS
+ || utp->ut_type == USER_PROCESS
+ || utp->ut_type == DEAD_PROCESS
+ )
+ ) {
+ if (utp->ut_type >= new_type) {
+ /* Stale record. Nuke hostname */
+ memset(utp->ut_host, 0, sizeof(utp->ut_host));
+ }
+ /* NB: pututline (see later) searches for matching utent
+ * using getutid(utent) - we must not change ut_id
+ * if we want *exactly this* record to be overwritten!
+ */
+ break;
+ }
+ }
+ //endutent(); - no need, pututline can deal with (and actually likes)
+ //the situation when utmp file is positioned on found record
+
+ if (!utp) {
+ if (new_type != DEAD_PROCESS)
+ write_new_utmp(pid, new_type, tty_name, username, hostname);
+ else
+ endutent();
+ return;
+ }
+
+ /* Make a copy. We can't use *utp, pututline's internal getutid
+ * will overwrite it before it is used! */
+ utent = *utp;
+
+ utent.ut_type = new_type;
+ if (tty_name)
+ safe_strncpy(utent.ut_line, skip_dev_pfx(tty_name), sizeof(utent.ut_line));
+ if (username)
+ safe_strncpy(utent.ut_user, username, sizeof(utent.ut_user));
+ if (hostname)
+ safe_strncpy(utent.ut_host, hostname, sizeof(utent.ut_host));
+ utent.ut_tv.tv_sec = time(NULL);
+
+ /* Update, or append new one */
+ //setutent();
+ pututline(&utent);
+ endutent();
+
+#if ENABLE_FEATURE_WTMP
+ /* "man utmp" says wtmp file should *not* be created automagically */
+ /*touch(bb_path_wtmp_file);*/
+ updwtmp(bb_path_wtmp_file, &utent);
+#endif
+}
diff --git a/ap/app/busybox/src/libbb/uuencode.c b/ap/app/busybox/src/libbb/uuencode.c
new file mode 100644
index 0000000..f7b2484
--- /dev/null
+++ b/ap/app/busybox/src/libbb/uuencode.c
@@ -0,0 +1,224 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 2003, Glenn McGrath
+ * Copyright 2006, Rob Landley <rob@landley.net>
+ * Copyright 2010, Denys Vlasenko
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* Conversion table. for base 64 */
+const char bb_uuenc_tbl_base64[65 + 1] 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 */,
+ '\0' /* needed for uudecode.c only */
+};
+
+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++;
+ }
+}
+
+/*
+ * Decode base64 encoded string. Stops on '\0'.
+ *
+ * Returns: pointer to the undecoded part of source.
+ * If points to '\0', then the source was fully decoded.
+ * (*pp_dst): advanced past the last written byte.
+ */
+const char* FAST_FUNC decode_base64(char **pp_dst, const char *src)
+{
+ char *dst = *pp_dst;
+ const char *src_tail;
+
+ while (1) {
+ unsigned char six_bit[4];
+ int count = 0;
+
+ /* Fetch up to four 6-bit values */
+ src_tail = src;
+ while (count < 4) {
+ char *table_ptr;
+ int ch;
+
+ /* Get next _valid_ character.
+ * bb_uuenc_tbl_base64[] contains this string:
+ * 0 1 2 3 4 5 6
+ * 01234567890123456789012345678901234567890123456789012345678901234
+ * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
+ */
+ do {
+ ch = *src;
+ if (ch == '\0') {
+ if (count == 0) {
+ /* Example:
+ * If we decode "QUJD <NUL>", we want
+ * to return ptr to NUL, not to ' ',
+ * because we did fully decode
+ * the string (to "ABC").
+ */
+ src_tail = src;
+ }
+ goto ret;
+ }
+ src++;
+ table_ptr = strchr(bb_uuenc_tbl_base64, ch);
+//TODO: add BASE64_FLAG_foo to die on bad char?
+ } while (!table_ptr);
+
+ /* Convert encoded character to decimal */
+ ch = table_ptr - bb_uuenc_tbl_base64;
+
+ /* ch is 64 if char was '=', otherwise 0..63 */
+ if (ch == 64)
+ break;
+ six_bit[count] = ch;
+ count++;
+ }
+
+ /* Transform 6-bit values to 8-bit ones.
+ * count can be < 4 when we decode the tail:
+ * "eQ==" -> "y", not "y NUL NUL".
+ * Note that (count > 1) is always true,
+ * "x===" encoding is not valid:
+ * even a single zero byte encodes as "AA==".
+ * However, with current logic we come here with count == 1
+ * when we decode "==" tail.
+ */
+ if (count > 1)
+ *dst++ = six_bit[0] << 2 | six_bit[1] >> 4;
+ if (count > 2)
+ *dst++ = six_bit[1] << 4 | six_bit[2] >> 2;
+ if (count > 3)
+ *dst++ = six_bit[2] << 6 | six_bit[3];
+ /* Note that if we decode "AA==" and ate first '=',
+ * we just decoded one char (count == 2) and now we'll
+ * do the loop once more to decode second '='.
+ */
+ } /* while (1) */
+ ret:
+ *pp_dst = dst;
+ return src_tail;
+}
+
+/*
+ * Decode base64 encoded stream.
+ * Can stop on EOF, specified char, or on uuencode-style "====" line:
+ * flags argument controls it.
+ */
+void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
+{
+/* Note that EOF _can_ be passed as exit_char too */
+#define exit_char ((int)(signed char)flags)
+#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
+
+ /* uuencoded files have 61 byte lines. Use 64 byte buffer
+ * to process line at a time.
+ */
+ enum { BUFFER_SIZE = 64 };
+
+ char in_buf[BUFFER_SIZE + 2];
+ char out_buf[BUFFER_SIZE / 4 * 3 + 2];
+ char *out_tail;
+ const char *in_tail;
+ int term_seen = 0;
+ int in_count = 0;
+
+ while (1) {
+ while (in_count < BUFFER_SIZE) {
+ int ch = fgetc(src_stream);
+ if (ch == exit_char) {
+ if (in_count == 0)
+ return;
+ term_seen = 1;
+ break;
+ }
+ if (ch == EOF) {
+ term_seen = 1;
+ break;
+ }
+ /* Prevent "====" line to be split: stop if we see '\n'.
+ * We can also skip other whitespace and skirt the problem
+ * of files with NULs by stopping on any control char or space:
+ */
+ if (ch <= ' ')
+ break;
+ in_buf[in_count++] = ch;
+ }
+ in_buf[in_count] = '\0';
+
+ /* Did we encounter "====" line? */
+ if (uu_style_end && strcmp(in_buf, "====") == 0)
+ return;
+
+ out_tail = out_buf;
+ in_tail = decode_base64(&out_tail, in_buf);
+
+ fwrite(out_buf, (out_tail - out_buf), 1, dst_stream);
+
+ if (term_seen) {
+ /* Did we consume ALL characters? */
+ if (*in_tail == '\0')
+ return;
+ /* No */
+ bb_error_msg_and_die("truncated base64 input");
+ }
+
+ /* It was partial decode */
+ in_count = strlen(in_tail);
+ memmove(in_buf, in_tail, in_count);
+ }
+}
diff --git a/ap/app/busybox/src/libbb/vdprintf.c b/ap/app/busybox/src/libbb/vdprintf.c
new file mode 100644
index 0000000..0542687
--- /dev/null
+++ b/ap/app/busybox/src/libbb/vdprintf.c
@@ -0,0 +1,21 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+#if defined(__GLIBC__) && __GLIBC__ < 2
+int FAST_FUNC vdprintf(int d, const char *format, va_list ap)
+{
+ char buf[8 * 1024];
+ int len;
+
+ len = vsnprintf(buf, sizeof(buf), format, ap);
+ return write(d, buf, len);
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/verror_msg.c b/ap/app/busybox/src/libbb/verror_msg.c
new file mode 100644
index 0000000..ee95be3
--- /dev/null
+++ b/ap/app/busybox/src/libbb/verror_msg.c
@@ -0,0 +1,158 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+#if ENABLE_FEATURE_SYSLOG
+# include <syslog.h>
+#endif
+
+smallint logmode = LOGMODE_STDIO;
+const char *msg_eol = "\n";
+
+void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
+{
+ char *msg, *msg1;
+ 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);
+ /* can't use xrealloc: it calls error_msg on failure,
+ * that may result in a recursion */
+ /* +3 is for ": " before strerr and for terminating NUL */
+ msg1 = realloc(msg, applet_len + used + strerr_len + msgeol_len + 3);
+ if (!msg1) {
+ msg[used++] = '\n'; /* overwrites NUL */
+ applet_len = 0;
+ } else {
+ msg = msg1;
+ /* 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);
+ used += msgeol_len;
+ }
+
+ if (logmode & LOGMODE_STDIO) {
+ fflush_all();
+ full_write(STDERR_FILENO, msg, used);
+ }
+#if ENABLE_FEATURE_SYSLOG
+ if (logmode & LOGMODE_SYSLOG) {
+ syslog(LOG_ERR, "%s", msg + applet_len);
+ }
+#endif
+ free(msg);
+}
+
+#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_all();
+ writev(STDERR_FILENO, iov, 3);
+ }
+# if ENABLE_FEATURE_SYSLOG
+ if (logmode & LOGMODE_SYSLOG) {
+ syslog(LOG_ERR, "%s", msgc);
+ }
+# endif
+ free(msgc);
+}
+#endif
+
+
+void FAST_FUNC bb_error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p, NULL);
+ va_end(p);
+ xfunc_die();
+}
+
+void FAST_FUNC bb_error_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ bb_verror_msg(s, p, NULL);
+ va_end(p);
+}
diff --git a/ap/app/busybox/src/libbb/vfork_daemon_rexec.c b/ap/app/busybox/src/libbb/vfork_daemon_rexec.c
new file mode 100644
index 0000000..ed1f86f
--- /dev/null
+++ b/ap/app/busybox/src/libbb/vfork_daemon_rexec.c
@@ -0,0 +1,281 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Rexec program for system have fork() as vfork() with foreground option
+ *
+ * Copyright (C) Vladimir N. Oleynik <dzo@simtreas.ru>
+ * Copyright (C) 2003 Russ Dill <Russ.Dill@asu.edu>
+ *
+ * daemon() portion taken from uClibc:
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Modified for uClibc by Erik Andersen <andersee@debian.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#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;
+
+ fflush_all();
+
+ /* 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;
+ /* mount, for example, does not want the message */
+ /*bb_perror_msg("can't execute '%s'", argv[0]);*/
+ _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) {
+ safe_waitpid(pid, NULL, 0); /* prevent zombie */
+ 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;
+}
+
+#if ENABLE_FEATURE_PREFER_APPLETS
+struct nofork_save_area {
+ jmp_buf die_jmp;
+ const char *applet_name;
+ uint32_t option_mask32;
+ int die_sleep;
+ uint8_t xfunc_error_retval;
+};
+static void 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;
+}
+static void 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;
+}
+
+int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
+{
+ int rc, argc;
+ struct nofork_save_area old;
+
+ save_nofork_data(&old);
+
+ applet_name = APPLET_NAME(applet_no);
+
+ xfunc_error_retval = EXIT_FAILURE;
+
+ /* 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 */
+
+ argc = 1;
+ while (argv[argc])
+ argc++;
+
+ /* 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;
+
+ 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);
+ } else { /* xfunc died in NOFORK applet */
+ /* in case they meant to return 0... */
+ if (rc == -2222)
+ rc = 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 */
+}
+#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("can't execute '%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;
+ pid = xvfork();
+ if (pid) /* parent */
+ return pid;
+ /* child - re-exec ourself */
+ re_exec(argv);
+}
+#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, detach from stdio & ctty */
+ setsid();
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ if (flags & DAEMON_DOUBLE_FORK) {
+ /* On Linux, session leader can acquire ctty
+ * unknowingly, by opening a tty.
+ * Prevent this: stop being a session leader.
+ */
+ if (fork_or_rexec(argv))
+ exit(EXIT_SUCCESS); /* parent */
+ }
+ }
+ 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);
+}
diff --git a/ap/app/busybox/src/libbb/warn_ignoring_args.c b/ap/app/busybox/src/libbb/warn_ignoring_args.c
new file mode 100644
index 0000000..3f3025c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/warn_ignoring_args.c
@@ -0,0 +1,18 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * warn_ignoring_args implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+#if ENABLE_DESKTOP
+void FAST_FUNC bb_warn_ignoring_args(char *arg)
+{
+ if (arg) {
+ bb_error_msg("ignoring all arguments");
+ }
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/wfopen.c b/ap/app/busybox/src/libbb/wfopen.c
new file mode 100644
index 0000000..76dc8b8
--- /dev/null
+++ b/ap/app/busybox/src/libbb/wfopen.c
@@ -0,0 +1,56 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+FILE* FAST_FUNC fopen_or_warn(const char *path, const char *mode)
+{
+ 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");
+}
+
+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");
+}
+
+static FILE* xfdopen_helper(unsigned fd_and_rw_bit)
+{
+ FILE* fp = fdopen(fd_and_rw_bit >> 1, fd_and_rw_bit & 1 ? "w" : "r");
+ if (!fp)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return fp;
+}
+FILE* FAST_FUNC xfdopen_for_read(int fd)
+{
+ return xfdopen_helper(fd << 1);
+}
+FILE* FAST_FUNC xfdopen_for_write(int fd)
+{
+ return xfdopen_helper((fd << 1) + 1);
+}
diff --git a/ap/app/busybox/src/libbb/wfopen_input.c b/ap/app/busybox/src/libbb/wfopen_input.c
new file mode 100644
index 0000000..d8b1c4a
--- /dev/null
+++ b/ap/app/busybox/src/libbb/wfopen_input.c
@@ -0,0 +1,56 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * wfopen_input implementation for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* 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.
+ */
+
+#include "libbb.h"
+
+FILE* FAST_FUNC fopen_or_warn_stdin(const char *filename)
+{
+ FILE *fp = stdin;
+
+ if (filename != bb_msg_standard_input
+ && NOT_LONE_DASH(filename)
+ ) {
+ 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;
+}
+
+int FAST_FUNC xopen_stdin(const char *filename)
+{
+ int fd = open_or_warn_stdin(filename);
+ if (fd >= 0)
+ return fd;
+ xfunc_die(); /* We already output an error message. */
+}
diff --git a/ap/app/busybox/src/libbb/write.c b/ap/app/busybox/src/libbb/write.c
new file mode 100644
index 0000000..2d67a72
--- /dev/null
+++ b/ap/app/busybox/src/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 source tree.
+ */
+
+#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/ap/app/busybox/src/libbb/xatonum.c b/ap/app/busybox/src/libbb/xatonum.c
new file mode 100644
index 0000000..62bbe53
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xatonum.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ascii-to-numbers implementations for busybox
+ *
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#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_positive(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/ap/app/busybox/src/libbb/xatonum_template.c b/ap/app/busybox/src/libbb/xatonum_template.c
new file mode 100644
index 0000000..e047198
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xatonum_template.c
@@ -0,0 +1,195 @@
+/*
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+/*
+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. */
+ if (*numstr == '-' || *numstr == '+' || isspace(*numstr))
+ goto inval;
+
+ /* Since this is a lib function, we're not allowed to reset errno to 0.
+ * Doing so could break an app that is deferring checking of errno.
+ * So, save the old value so that we can restore it if successful. */
+ old_errno = errno;
+ errno = 0;
+ r = XSTR_STRTOU(numstr, &e, base);
+ /* Do the initial validity check. Note: The standards do not
+ * guarantee that errno is set if no digits were found. So we
+ * must test for this explicitly. */
+ if (errno || numstr == e)
+ goto inval; /* error / no digits / illegal trailing chars */
+
+ errno = old_errno; /* Ok. So restore errno. */
+
+ /* Do optional suffix parsing. Allow 'empty' suffix tables.
+ * Note that we also allow nul suffixes with associated multipliers,
+ * to allow for scaling of the numstr by some default multiplier. */
+ if (suffixes) {
+ while (suffixes->mult) {
+ if (strcmp(suffixes->suffix, e) == 0) {
+ if (XSTR_UTYPE_MAX / suffixes->mult < r)
+ goto range; /* overflow! */
+ r *= suffixes->mult;
+ goto chk_range;
+ }
+ ++suffixes;
+ }
+ }
+
+ /* Note: trailing space is an error.
+ * It would be easy enough to allow though if desired. */
+ if (*e)
+ goto inval;
+ chk_range:
+ /* Finally, check for range limits. */
+ if (r >= lower && r <= upper)
+ return r;
+ range:
+ bb_error_msg_and_die("number %s is not in %llu..%llu range",
+ numstr, (unsigned long long)lower,
+ (unsigned long long)upper);
+ inval:
+ bb_error_msg_and_die("invalid number '%s'", numstr);
+}
+
+unsigned type FAST_FUNC xstrtou(_range)(const char *numstr, int base,
+ unsigned type lower,
+ unsigned type upper)
+{
+ return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL);
+}
+
+unsigned type FAST_FUNC xstrtou(_sfx)(const char *numstr, int base,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes);
+}
+
+unsigned type FAST_FUNC xstrtou()(const char *numstr, int base)
+{
+ return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL);
+}
+
+unsigned type FAST_FUNC xatou(_range_sfx)(const char *numstr,
+ unsigned type lower,
+ unsigned type upper,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes);
+}
+
+unsigned type FAST_FUNC xatou(_range)(const char *numstr,
+ unsigned type lower,
+ unsigned type upper)
+{
+ return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL);
+}
+
+unsigned type FAST_FUNC xatou(_sfx)(const char *numstr,
+ const struct suffix_mult *suffixes)
+{
+ return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes);
+}
+
+unsigned type FAST_FUNC xatou()(const char *numstr)
+{
+ return xatou(_sfx)(numstr, NULL);
+}
+
+/* Signed ones */
+
+type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base,
+ type lower,
+ type upper,
+ const struct suffix_mult *suffixes)
+{
+ unsigned type u = XSTR_TYPE_MAX;
+ type r;
+ const char *p = numstr;
+
+ /* NB: if you'll decide to disallow '+':
+ * at least renice applet needs to allow it */
+ if (p[0] == '+' || p[0] == '-') {
+ ++p;
+ if (p[0] == '-')
+ ++u; /* = <type>_MIN (01111... + 1 == 10000...) */
+ }
+
+ r = xstrtou(_range_sfx)(p, base, 0, u, suffixes);
+
+ if (*numstr == '-') {
+ r = -r;
+ }
+
+ if (r < lower || r > upper) {
+ bb_error_msg_and_die("number %s is not in %lld..%lld range",
+ numstr, (long long)lower, (long long)upper);
+ }
+
+ return r;
+}
+
+type FAST_FUNC xstrto(_range)(const char *numstr, int base, type lower, type upper)
+{
+ return xstrto(_range_sfx)(numstr, base, lower, upper, NULL);
+}
+
+type FAST_FUNC xstrto()(const char *numstr, int base)
+{
+ return xstrto(_range_sfx)(numstr, base, XSTR_TYPE_MIN, XSTR_TYPE_MAX, 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/ap/app/busybox/src/libbb/xconnect.c b/ap/app/busybox/src/libbb/xconnect.c
new file mode 100644
index 0000000..1c8bb2b
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xconnect.c
@@ -0,0 +1,486 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Connect to host at port using address resolution from getaddrinfo
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h> /* netinet/in.h needs it */
+#include <netinet/in.h>
+#include <net/if.h>
+#include <sys/un.h>
+#include "libbb.h"
+
+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));
+}
+
+#ifdef SO_BINDTODEVICE
+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;
+}
+#else
+int FAST_FUNC setsockopt_bindtodevice(int fd UNUSED_PARAM,
+ const char *iface UNUSED_PARAM)
+{
+ bb_error_msg("SO_BINDTODEVICE is not supported on this system");
+ return -1;
+}
+#endif
+
+static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen))
+{
+ len_and_sockaddr lsa;
+ len_and_sockaddr *lsa_ptr;
+
+ lsa.len = LSA_SIZEOF_SA;
+ if (get_name(fd, &lsa.u.sa, &lsa.len) != 0)
+ return NULL;
+
+ lsa_ptr = xzalloc(LSA_LEN_SIZE + lsa.len);
+ if (lsa.len > LSA_SIZEOF_SA) { /* rarely (if ever) happens */
+ lsa_ptr->len = lsa.len;
+ get_name(fd, &lsa_ptr->u.sa, &lsa_ptr->len);
+ } else {
+ memcpy(lsa_ptr, &lsa, LSA_LEN_SIZE + lsa.len);
+ }
+ return lsa_ptr;
+}
+
+len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd)
+{
+ return get_lsa(fd, getsockname);
+}
+
+len_and_sockaddr* FAST_FUNC get_peer_lsa(int fd)
+{
+ return get_lsa(fd, getpeername);
+}
+
+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)",
+ "can't connect to remote host",
+ inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
+ bb_perror_msg_and_die("can't connect to remote 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;
+}
+
+
+/* "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(struct sockaddr *sa, unsigned port)
+{
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (void*) sa;
+ sin6->sin6_port = port;
+ return;
+ }
+#endif
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (void*) sa;
+ 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,
+IF_FEATURE_IPV6(sa_family_t af,)
+ int ai_flags)
+{
+IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;)
+ int rc;
+ len_and_sockaddr *r;
+ struct addrinfo *result = NULL;
+ struct addrinfo *used_res;
+ const char *org_host = host; /* only for error msg */
+ const char *cp;
+ struct addrinfo hint;
+
+ if (ENABLE_FEATURE_UNIX_LOCAL && strncmp(host, "local:", 6) == 0) {
+ struct sockaddr_un *sun;
+
+ r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
+ r->len = sizeof(struct sockaddr_un);
+ r->u.sa.sa_family = AF_UNIX;
+ sun = (struct sockaddr_un *)&r->u.sa;
+ safe_strncpy(sun->sun_path, host + 6, sizeof(sun->sun_path));
+ return r;
+ }
+
+ r = NULL;
+
+ /* 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: ;
+ }
+
+ /* Next two if blocks allow to skip getaddrinfo()
+ * in case host name is a numeric IP(v6) address.
+ * getaddrinfo() initializes DNS resolution machinery,
+ * scans network config and such - tens of syscalls.
+ */
+ /* If we were not asked specifically for IPv6,
+ * check whether this is a numeric IPv4 */
+ IF_FEATURE_IPV6(if(af != AF_INET6)) {
+ struct in_addr in4;
+ if (inet_aton(host, &in4) != 0) {
+ r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in));
+ r->len = sizeof(struct sockaddr_in);
+ r->u.sa.sa_family = AF_INET;
+ r->u.sin.sin_addr = in4;
+ goto set_port;
+ }
+ }
+#if ENABLE_FEATURE_IPV6
+ /* If we were not asked specifically for IPv4,
+ * check whether this is a numeric IPv6 */
+ if (af != AF_INET) {
+ struct in6_addr in6;
+ if (inet_pton(AF_INET6, host, &in6) > 0) {
+ r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in6));
+ r->len = sizeof(struct sockaddr_in6);
+ r->u.sa.sa_family = AF_INET6;
+ r->u.sin6.sin6_addr = in6;
+ goto set_port;
+ }
+ }
+#endif
+
+ memset(&hint, 0 , sizeof(hint));
+ hint.ai_family = af;
+ /* Need SOCK_STREAM, or else we 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(LSA_LEN_SIZE + used_res->ai_addrlen);
+ r->len = used_res->ai_addrlen;
+ memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
+
+ set_port:
+ set_nport(&r->u.sa, htons(port));
+ ret:
+ if (result)
+ freeaddrinfo(result);
+ return r;
+}
+#if !ENABLE_FEATURE_IPV6
+#define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
+#endif
+
+#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);
+}
+
+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
+
+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);
+}
+
+len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
+}
+
+int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type)
+{
+ len_and_sockaddr *lsa;
+ int fd;
+ int len;
+
+ if (family == AF_UNSPEC) {
+#if ENABLE_FEATURE_IPV6
+ fd = socket(AF_INET6, sock_type, 0);
+ if (fd >= 0) {
+ family = AF_INET6;
+ goto done;
+ }
+#endif
+ family = AF_INET;
+ }
+
+ fd = xsocket(family, sock_type, 0);
+
+ len = sizeof(struct sockaddr_in);
+ if (family == AF_UNIX)
+ len = sizeof(struct sockaddr_un);
+#if ENABLE_FEATURE_IPV6
+ if (family == AF_INET6) {
+ done:
+ len = sizeof(struct sockaddr_in6);
+ }
+#endif
+ lsa = xzalloc(LSA_LEN_SIZE + 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, 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, AF_UNSPEC, sock_type);
+ set_nport(&lsa->u.sa, 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;
+
+ if (ENABLE_FEATURE_UNIX_LOCAL && sa->sa_family == AF_UNIX) {
+ struct sockaddr_un *sun = (struct sockaddr_un *)sa;
+ return xasprintf("local:%.*s",
+ (int) sizeof(sun->sun_path),
+ sun->sun_path);
+ }
+
+ 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/ap/app/busybox/src/libbb/xfunc_die.c b/ap/app/busybox/src/libbb/xfunc_die.c
new file mode 100644
index 0000000..204e5e4
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xfunc_die.c
@@ -0,0 +1,40 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+/* 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/ap/app/busybox/src/libbb/xfuncs.c b/ap/app/busybox/src/libbb/xfuncs.c
new file mode 100644
index 0000000..23f2751
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xfuncs.c
@@ -0,0 +1,310 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+/* 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.
+ *
+ * TODO: move xmalloc() and xatonum() here.
+ */
+
+#include "libbb.h"
+
+/* Turn on nonblocking I/O on a fd */
+void FAST_FUNC ndelay_on(int fd)
+{
+ int flags = fcntl(fd, F_GETFL);
+ if (flags & O_NONBLOCK)
+ return;
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+void FAST_FUNC ndelay_off(int fd)
+{
+ int flags = fcntl(fd, F_GETFL);
+ if (!(flags & O_NONBLOCK))
+ return;
+ fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+void FAST_FUNC close_on_exec_on(int fd)
+{
+ 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);
+}
+
+
+/* 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(void);
+char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen)
+{
+ unsigned i, out, res;
+
+ if (buflen) {
+ out = 0;
+ if (sizeof(n) == 4)
+ // 2^32-1 = 4294967295
+ i = 1000000000;
+#if UINT_MAX > 4294967295 /* prevents warning about "const too large" */
+ else
+ if (sizeof(n) == 8)
+ // 2^64-1 = 18446744073709551615
+ i = 10000000000000000000;
+#endif
+ else
+ BUG_sizeof();
+ for (; i; i /= 10) {
+ res = n / i;
+ n = n % i;
+ if (res || out || i == 1) {
+ if (--buflen == 0)
+ break;
+ out++;
+ *buf++ = '0' + res;
+ }
+ }
+ }
+ return buf;
+}
+
+/* Convert signed integer to ascii, like utoa_to_buf() */
+char* FAST_FUNC itoa_to_buf(int n, char *buf, unsigned buflen)
+{
+ if (!buflen)
+ return buf;
+ if (n < 0) {
+ n = -n;
+ *buf++ = '-';
+ buflen--;
+ }
+ return utoa_to_buf((unsigned)n, buf, buflen);
+}
+
+// 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 NUL, or 1+10+1=12 bytes.
+// It so happens that sizeof(int) * 3 is enough for 32+ bit ints.
+// (sizeof(int) * 3 + 2 is correct for any width, even 8-bit)
+
+static char local_buf[sizeof(int) * 3];
+
+/* 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) - 1)) = '\0';
+
+ return local_buf;
+}
+
+/* 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) - 1)) = '\0';
+
+ return local_buf;
+}
+
+/* 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;
+}
+
+/* Convert "[x]x[:][x]x[:][x]x[:][x]x" hex string to binary, no more than COUNT bytes */
+char* FAST_FUNC hex2bin(char *dst, const char *str, int count)
+{
+ errno = EINVAL;
+ while (*str && count) {
+ uint8_t val;
+ uint8_t c = *str++;
+ if (isdigit(c))
+ val = c - '0';
+ else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
+ val = (c|0x20) - ('a' - 10);
+ else
+ return NULL;
+ val <<= 4;
+ c = *str;
+ if (isdigit(c))
+ val |= c - '0';
+ else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
+ val |= (c|0x20) - ('a' - 10);
+ else if (c == ':' || c == '\0')
+ val >>= 4;
+ else
+ return NULL;
+
+ *dst++ = val;
+ if (c != '\0')
+ str++;
+ if (*str == ':')
+ str++;
+ count--;
+ }
+ errno = (*str ? ERANGE : 0);
+ return dst;
+}
+
+/* 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)
+{
+ 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
+
+int FAST_FUNC bb_putchar_stderr(char ch)
+{
+ return write(STDERR_FILENO, &ch, 1);
+}
+
+ssize_t FAST_FUNC full_write1_str(const char *str)
+{
+ return full_write(STDOUT_FILENO, str, strlen(str));
+}
+
+ssize_t FAST_FUNC full_write2_str(const char *str)
+{
+ return full_write(STDERR_FILENO, str, strlen(str));
+}
+
+static int wh_helper(int value, int def_val, const char *env_name, int *err)
+{
+ if (value == 0) {
+ char *s = getenv(env_name);
+ if (s) {
+ value = atoi(s);
+ /* If LINES/COLUMNS are set, pretend that there is
+ * no error getting w/h, this prevents some ugly
+ * cursor tricks by our callers */
+ *err = 0;
+ }
+ }
+ if (value <= 1 || value >= 30000)
+ value = def_val;
+ return value;
+}
+
+/* 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;
+ int err;
+
+ win.ws_row = 0;
+ win.ws_col = 0;
+ /* I've seen ioctl returning 0, but row/col is (still?) 0.
+ * We treat that as an error too. */
+ err = ioctl(fd, TIOCGWINSZ, &win) != 0 || win.ws_row == 0;
+ if (height)
+ *height = wh_helper(win.ws_row, 24, "LINES", &err);
+ if (width)
+ *width = wh_helper(win.ws_col, 80, "COLUMNS", &err);
+ return err;
+}
+
+int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
+{
+ return tcsetattr(STDIN_FILENO, TCSANOW, tp);
+}
+
+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) + 0x180;
+ return 0;
+}
diff --git a/ap/app/busybox/src/libbb/xfuncs_printf.c b/ap/app/busybox/src/libbb/xfuncs_printf.c
new file mode 100644
index 0000000..05aa07c
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xfuncs_printf.c
@@ -0,0 +1,625 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2006 Rob Landley
+ * Copyright (C) 2006 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+/* 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 a file and return a fd.
+int FAST_FUNC xopen(const char *pathname, int flags)
+{
+ return xopen3(pathname, flags, 0666);
+}
+
+/* Die if we can't open an existing file readonly with O_NONBLOCK
+ * and return the fd.
+ * Note that for ioctl O_RDONLY is sufficient.
+ */
+int FAST_FUNC xopen_nonblocking(const char *pathname)
+{
+ return xopen(pathname, O_RDONLY | O_NONBLOCK);
+}
+
+// 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));
+}
+
+void FAST_FUNC xclose(int fd)
+{
+ if (close(fd))
+ bb_perror_msg_and_die("close failed");
+}
+
+// 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;
+}
+
+int FAST_FUNC xmkstemp(char *template)
+{
+ int fd = mkstemp(template);
+ if (fd < 0)
+ bb_perror_msg_and_die("can't create temp file '%s'", template);
+ return fd;
+}
+
+// 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);
+}
+
+int FAST_FUNC fflush_all(void)
+{
+ return fflush(NULL);
+}
+
+
+int FAST_FUNC bb_putchar(int ch)
+{
+ return putchar(ch);
+}
+
+/* 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_all();
+ // copyfd outputs error messages for us.
+ if (bb_copyfd_eof(fileno(file), STDOUT_FILENO) == -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;
+
+ va_start(p, format);
+ r = vasprintf(&string_ptr, format, p);
+ va_end(p);
+
+ if (r < 0)
+ bb_error_msg_and_die(bb_msg_memory_exhausted);
+ return string_ptr;
+}
+
+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);
+}
+
+void FAST_FUNC bb_unsetenv_and_free(char *var)
+{
+ bb_unsetenv(var);
+ free(var);
+}
+
+// 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("can't change directory to '%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);
+ xchdir("/");
+}
+
+// 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";
+# ifdef AF_PACKET
+ if (domain == AF_PACKET) s = "PACKET";
+# endif
+# ifdef AF_NETLINK
+ if (domain == AF_NETLINK) s = "NETLINK";
+# endif
+IF_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
+ bb_perror_msg_and_die("socket(AF_%s,%d,%d)", s, type, protocol);
+#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);
+}
+
+void FAST_FUNC xfstat(int fd, struct stat *stat_buf, const char *errmsg)
+{
+ /* errmsg is usually a file name, but not always:
+ * xfstat may be called in a spot where file name is no longer
+ * available, and caller may give e.g. "can't stat input file" string.
+ */
+ if (fstat(fd, stat_buf))
+ bb_simple_perror_msg_and_die(errmsg);
+}
+
+// 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
+
+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;
+}
+
+void FAST_FUNC generate_uuid(uint8_t *buf)
+{
+ /* http://www.ietf.org/rfc/rfc4122.txt
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | time_low |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | time_mid | time_hi_and_version |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |clk_seq_and_variant | node (0-1) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | node (2-5) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * IOW, uuid has this layout:
+ * uint32_t time_low (big endian)
+ * uint16_t time_mid (big endian)
+ * uint16_t time_hi_and_version (big endian)
+ * version is a 4-bit field:
+ * 1 Time-based
+ * 2 DCE Security, with embedded POSIX UIDs
+ * 3 Name-based (MD5)
+ * 4 Randomly generated
+ * 5 Name-based (SHA-1)
+ * uint16_t clk_seq_and_variant (big endian)
+ * variant is a 3-bit field:
+ * 0xx Reserved, NCS backward compatibility
+ * 10x The variant specified in rfc4122
+ * 110 Reserved, Microsoft backward compatibility
+ * 111 Reserved for future definition
+ * uint8_t node[6]
+ *
+ * For version 4, these bits are set/cleared:
+ * time_hi_and_version & 0x0fff | 0x4000
+ * clk_seq_and_variant & 0x3fff | 0x8000
+ */
+ pid_t pid;
+ int i;
+
+ i = open("/dev/urandom", O_RDONLY);
+ if (i >= 0) {
+ read(i, buf, 16);
+ close(i);
+ }
+ /* Paranoia. /dev/urandom may be missing.
+ * rand() is guaranteed to generate at least [0, 2^15) range,
+ * but lowest bits in some libc are not so "random". */
+ srand(monotonic_us()); /* pulls in printf */
+ pid = getpid();
+ while (1) {
+ for (i = 0; i < 16; i++)
+ buf[i] ^= rand() >> 5;
+ if (pid == 0)
+ break;
+ srand(pid);
+ pid = 0;
+ }
+
+ /* version = 4 */
+ buf[4 + 2 ] = (buf[4 + 2 ] & 0x0f) | 0x40;
+ /* variant = 10x */
+ buf[4 + 2 + 2] = (buf[4 + 2 + 2] & 0x3f) | 0x80;
+}
+
+#if BB_MMU
+pid_t FAST_FUNC xfork(void)
+{
+ pid_t pid;
+ pid = fork();
+ if (pid < 0) /* wtf? */
+ bb_perror_msg_and_die("vfork"+1);
+ return pid;
+}
+#endif
diff --git a/ap/app/busybox/src/libbb/xgetcwd.c b/ap/app/busybox/src/libbb/xgetcwd.c
new file mode 100644
index 0000000..71720d3
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xgetcwd.c
@@ -0,0 +1,43 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * xgetcwd.c -- return current directory with unlimited length
+ * Copyright (C) 1992, 1996 Free Software Foundation, Inc.
+ * Written by David MacKenzie <djm@gnu.ai.mit.edu>.
+ *
+ * Special function for busybox written by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/* 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* FAST_FUNC
+xrealloc_getcwd_or_warn(char *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/ap/app/busybox/src/libbb/xgethostbyname.c b/ap/app/busybox/src/libbb/xgethostbyname.c
new file mode 100644
index 0000000..89d0329
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xgethostbyname.c
@@ -0,0 +1,17 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini xgethostbyname implementation.
+ *
+ * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include "libbb.h"
+
+struct hostent* FAST_FUNC xgethostbyname(const char *name)
+{
+ struct hostent *retval = gethostbyname(name);
+ if (!retval)
+ bb_herror_msg_and_die("%s", name);
+ return retval;
+}
diff --git a/ap/app/busybox/src/libbb/xreadlink.c b/ap/app/busybox/src/libbb/xreadlink.c
new file mode 100644
index 0000000..ec95af2
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xreadlink.c
@@ -0,0 +1,115 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * xreadlink.c - safe implementation of readlink.
+ * Returns a NULL on failure...
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+/*
+ * NOTE: This function returns a malloced char* that you will have to free
+ * yourself.
+ */
+char* FAST_FUNC xmalloc_readlink(const char *path)
+{
+ enum { GROWBY = 80 }; /* how large we will grow strings by */
+
+ char *buf = NULL;
+ int bufsize = 0, readsize = 0;
+
+ do {
+ bufsize += GROWBY;
+ buf = xrealloc(buf, bufsize);
+ readsize = readlink(path, buf, bufsize);
+ if (readsize == -1) {
+ free(buf);
+ return NULL;
+ }
+ } 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;
+}
+
+char* FAST_FUNC xmalloc_realpath(const char *path)
+{
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+ /* glibc provides a non-standard extension */
+ /* new: POSIX.1-2008 specifies this behavior as well */
+ return realpath(path, NULL);
+#else
+ char buf[PATH_MAX+1];
+
+ /* on error returns NULL (xstrdup(NULL) == NULL) */
+ return xstrdup(realpath(path, buf));
+#endif
+}
diff --git a/ap/app/busybox/src/libbb/xrealloc_vector.c b/ap/app/busybox/src/libbb/xrealloc_vector.c
new file mode 100644
index 0000000..e8d31b7
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xrealloc_vector.c
@@ -0,0 +1,46 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2008 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+#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), with any idx,
+ * it's ok to use at least v[idx] and v[idx+1].
+ * v[idx+2] etc generally are not ok.
+ *
+ * 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/ap/app/busybox/src/libbb/xregcomp.c b/ap/app/busybox/src/libbb/xregcomp.c
new file mode 100644
index 0000000..d106f85
--- /dev/null
+++ b/ap/app/busybox/src/libbb/xregcomp.c
@@ -0,0 +1,64 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "libbb.h"
+
+#if defined(__UC_LIBC__USE_REGEXP_H__)
+
+#include <regexp.h>
+
+void xregcomp(regex_t *preg, const char *reg, int cflags)
+{
+ regexp *ret;
+ const char *r;
+ r = reg;
+ if (cflags)
+ bb_error_msg_and_die("xregcomp: no support for -i");
+ ret = regcomp(r);
+ if (ret == NULL) {
+ regerror("cannot compile expression");
+ exit(1);
+ }
+ *preg = ret;
+}
+
+#else
+
+#include "xregex.h"
+
+char* FAST_FUNC regcomp_or_errmsg(regex_t *preg, const char *regex, int cflags)
+{
+ int ret = regcomp(preg, regex, cflags);
+ if (ret) {
+ int errmsgsz = regerror(ret, preg, NULL, 0);
+ char *errmsg = xmalloc(errmsgsz);
+ regerror(ret, preg, errmsg, errmsgsz);
+ return errmsg;
+ }
+ return NULL;
+}
+
+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);
+ }
+}
+#endif
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/