[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:", &param);
+
+ "a::"  A double colon after a char in opt_complementary means that the
+        option can occur multiple times. Each occurrence will be saved as
+        a llist_t element instead of char*.
+
+        For example:
+        The grep applet can have one or more "-e pattern" arguments.
+        In this case you should use getopt32() as follows:
+
+        llist_t *patterns = NULL;
+
+        (this pointer must be initializated to NULL if the list is empty
+        as required by llist_add_to_end(llist_t **old_head, char *new_item).)
+
+        opt_complementary = "e::";
+
+        getopt32(argv, "e:", &patterns);
+        $ grep -e user -e root /etc/passwd
+        root:x:0:0:root:/root:/bin/bash
+        user:x:500:500::/home/user:/bin/bash
+
+ "a?b"  A "?" between an option and a group of options means that
+        at least one of them is required to occur if the first option
+        occurs in preceding command line arguments.
+
+        For example from "id" applet:
+
+        // Don't allow -n -r -rn -ug -rug -nug -rnug
+        opt_complementary = "r?ug:n?ug:u--g:g--u";
+        flags = getopt32(argv, "rnug");
+
+        This example allowed only:
+        $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
+
+ "X"    A opt_complementary group with just a single letter means
+        that this option is required. If more than one such group exists,
+        at least one option is required to occur (not all of them).
+        For example from "start-stop-daemon" applet:
+
+        // Don't allow -KS -SK, but -S or -K is required
+        opt_complementary = "K:S:K--S:S--K";
+        flags = getopt32(argv, "KS...);
+
+
+        Don't forget to use ':'. For example, "?322-22-23X-x-a"
+        is interpreted as "?3:22:-2:2-2:2-3Xa:2--x" -
+        max 3 args; count uses of '-2'; min 2 args; if there is
+        a '-2' option then unset '-3', '-X' and '-a'; if there is
+        a '-2' and after it a '-x' then error out.
+        But it's far too obfuscated. Use ':' to separate groups.
+*/
+
+/* Code here assumes that 'unsigned' is at least 32 bits wide */
+
+const char *const bb_argv_dash[] = { "-", NULL };
+
+const char *opt_complementary;
+
+enum {
+	PARAM_STRING,
+	PARAM_LIST,
+	PARAM_INT,
+};
+
+typedef struct {
+	unsigned char opt_char;
+	smallint param_type;
+	unsigned switch_on;
+	unsigned switch_off;
+	unsigned incongruously;
+	unsigned requires;
+	void **optarg;  /* char**, llist_t** or int *. */
+	int *counter;
+} t_complementary;
+
+/* You can set applet_long_options for parse called long options */
+#if ENABLE_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(&current_sid);  /* update */
+}
+void FAST_FUNC set_current_security_context(security_context_t sid)
+{
+	freecon(current_sid);  /* Release old context  */
+	current_sid = sid;
+}
+
+#endif
+
+/* Run SHELL, or DEFAULT_SHELL if SHELL is "" 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:
+*/