summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--archival/libarchive/Kbuild.src1
-rwxr-xr-xembed/nologin (renamed from applets_sh/nologin)0
-rw-r--r--include/.gitignore1
-rw-r--r--include/libbb.h8
-rw-r--r--libbb/appletlib.c83
-rw-r--r--libbb/lineedit.c6
-rwxr-xr-xscripts/embedded_scripts66
-rw-r--r--shell/ash.c33
9 files changed, 201 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 59ec83a6a..8a0dbdf49 100644
--- a/Makefile
+++ b/Makefile
@@ -850,11 +850,14 @@ quiet_cmd_gen_common_bufsiz = GEN include/common_bufsiz.h
cmd_gen_common_bufsiz = $(srctree)/scripts/generate_BUFSIZ.sh include/common_bufsiz.h
quiet_cmd_split_autoconf = SPLIT include/autoconf.h -> include/config/*
cmd_split_autoconf = scripts/basic/split-include include/autoconf.h include/config
+quiet_cmd_gen_embedded_scripts = GEN include/embedded_scripts.h
+ cmd_gen_embedded_scripts = scripts/embedded_scripts include/embedded_scripts.h embed
#bbox# piggybacked generation of few .h files
-include/config/MARKER: scripts/basic/split-include include/autoconf.h
+include/config/MARKER: scripts/basic/split-include include/autoconf.h $(wildcard embed/*) scripts/embedded_scripts
$(call cmd,split_autoconf)
$(call cmd,gen_bbconfigopts)
$(call cmd,gen_common_bufsiz)
+ $(call cmd,gen_embedded_scripts)
@touch $@
# Generate some files
@@ -974,6 +977,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \
include/autoconf.h \
include/bbconfigopts.h \
include/bbconfigopts_bz2.h \
+ include/embedded_scripts.h \
include/usage_compressed.h \
include/applet_tables.h \
include/applets.h \
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index e1a8a7529..12e66a88b 100644
--- a/archival/libarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -91,6 +91,7 @@ lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.
lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o
lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o
lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o
+lib-$(CONFIG_ASH_EMBEDDED_SCRIPTS) += open_transformer.o decompress_bunzip2.o
ifneq ($(lib-y),)
lib-y += $(COMMON_FILES)
diff --git a/applets_sh/nologin b/embed/nologin
index 3768eaaa7..3768eaaa7 100755
--- a/applets_sh/nologin
+++ b/embed/nologin
diff --git a/include/.gitignore b/include/.gitignore
index 75afff9ca..13a96e018 100644
--- a/include/.gitignore
+++ b/include/.gitignore
@@ -5,6 +5,7 @@
/autoconf.h
/bbconfigopts_bz2.h
/bbconfigopts.h
+/embedded_scripts.h
/NUM_APPLETS.h
/usage_compressed.h
/usage.h
diff --git a/include/libbb.h b/include/libbb.h
index 140404ff5..affff5874 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1321,9 +1321,17 @@ void bb_logenv_override(void) FAST_FUNC;
#define MAIN_EXTERNALLY_VISIBLE
#endif
+/* Embedded script support */
+//int find_script_by_name(const char *arg IF_FEATURE_SH_STANDALONE(, int offset)) FAST_FUNC;
+char *get_script_content(unsigned n) FAST_FUNC;
/* Applets which are useful from another applets */
int bb_cat(char** argv) FAST_FUNC;
+int ash_main(int argc, char** argv)
+#if ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH
+ MAIN_EXTERNALLY_VISIBLE
+#endif
+;
/* If shell needs them, they exist even if not enabled as applets */
int echo_main(int argc, char** argv) IF_ECHO(MAIN_EXTERNALLY_VISIBLE);
int printf_main(int argc, char **argv) IF_PRINTF(MAIN_EXTERNALLY_VISIBLE);
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 319bcc263..08720082e 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -50,6 +50,16 @@
#include "usage_compressed.h"
+#if ENABLE_ASH_EMBEDDED_SCRIPTS
+# define DEFINE_script_names 1
+# include "embedded_scripts.h"
+#else
+# define NUM_SCRIPTS 0
+#endif
+#if NUM_SCRIPTS > 0
+# include "bb_archive.h"
+static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS };
+#endif
/* "Do not compress usage text if uncompressed text is small
* and we don't include bunzip2 code for other reasons"
@@ -953,7 +963,71 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **ar
}
# endif /* NUM_APPLETS > 0 */
-# if ENABLE_BUSYBOX || NUM_APPLETS > 0
+# if NUM_SCRIPTS > 0
+static char *
+unpack_scripts(void)
+{
+ char *outbuf = NULL;
+ bunzip_data *bd;
+ int i;
+ jmp_buf jmpbuf;
+
+ /* Setup for I/O error handling via longjmp */
+ i = setjmp(jmpbuf);
+ if (i == 0) {
+ i = start_bunzip(&jmpbuf,
+ &bd,
+ /* src_fd: */ -1,
+ /* inbuf: */ packed_scripts,
+ /* len: */ sizeof(packed_scripts)
+ );
+ }
+ /* read_bunzip can longjmp and end up here with i != 0
+ * on read data errors! Not trivial */
+ if (i == 0) {
+ outbuf = xmalloc(UNPACKED_SCRIPTS_LENGTH);
+ read_bunzip(bd, outbuf, UNPACKED_SCRIPTS_LENGTH);
+ }
+ dealloc_bunzip(bd);
+ return outbuf;
+}
+
+/*
+ * In standalone shell mode we sometimes want the index of the script
+ * and sometimes the index offset by NUM_APPLETS.
+ */
+static int
+find_script_by_name(const char *arg)
+{
+ const char *s = script_names;
+ int i = 0;
+
+ while (*s) {
+ if (strcmp(arg, s) == 0)
+ return i;
+ i++;
+ while (*s++ != '\0')
+ continue;
+ }
+ return -1;
+}
+
+char* FAST_FUNC
+get_script_content(unsigned n)
+{
+ char *t = unpack_scripts();
+ if (t) {
+ while (n != 0) {
+ while (*t++ != '\0')
+ continue;
+ n--;
+ }
+ }
+ return t;
+}
+# endif /* NUM_SCRIPTS > 0 */
+
+# if ENABLE_BUSYBOX || NUM_APPLETS > 0 || NUM_SCRIPTS > 0
static NORETURN void run_applet_and_exit(const char *name, char **argv)
{
# if ENABLE_BUSYBOX
@@ -968,6 +1042,13 @@ static NORETURN void run_applet_and_exit(const char *name, char **argv)
run_applet_no_and_exit(applet, name, argv);
}
# endif
+# if NUM_SCRIPTS > 0
+ {
+ int script = find_script_by_name(name);
+ if (script >= 0)
+ exit(ash_main(-script - 1, argv));
+ }
+# endif
/*bb_error_msg_and_die("applet not found"); - links in printf */
full_write2_str(applet_name);
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index b1e971f88..aef1911d9 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -41,6 +41,12 @@
#include "busybox.h"
#include "NUM_APPLETS.h"
#include "unicode.h"
+#if ENABLE_ASH_EMBEDDED_SCRIPTS
+# include "embedded_scripts.h"
+#else
+# define NUM_SCRIPTS 0
+#endif
+
#ifndef _POSIX_VDISABLE
# define _POSIX_VDISABLE '\0'
#endif
diff --git a/scripts/embedded_scripts b/scripts/embedded_scripts
new file mode 100755
index 000000000..986e85160
--- /dev/null
+++ b/scripts/embedded_scripts
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+target="$1"
+loc="$2"
+
+test "$target" || exit 1
+test "$SED" || SED=sed
+test "$DD" || DD=dd
+
+# Some people were bitten by their system lacking a (proper) od
+od -v -b </dev/null >/dev/null
+if test $? != 0; then
+ echo 'od tool is not installed or cannot accept "-v -b" options'
+ exit 1
+fi
+
+exec >"$target.$$"
+
+scripts=""
+if [ -d "$loc" ]
+then
+ scripts=$(cd $loc; ls * 2>/dev/null)
+fi
+
+n=$(echo $scripts | wc -w)
+
+if [ $n -ne 0 ]
+then
+ printf '#ifdef DEFINE_script_names\n'
+ printf 'const char script_names[] ALIGN1 = '
+ for i in $scripts
+ do
+ printf '"%s\\0"' $i
+ done
+ printf '"\\0";\n'
+ printf '#else\n'
+ printf 'extern const char script_names[] ALIGN1;\n'
+ printf '#endif\n'
+fi
+printf "#define NUM_SCRIPTS $n\n\n"
+
+if [ $n -ne 0 ]
+then
+ printf '#define UNPACKED_SCRIPTS_LENGTH '
+ for i in $scripts
+ do
+ cat $loc/$i
+ printf '\000'
+ done | wc -c
+
+ printf '#define PACKED_SCRIPTS \\\n'
+ for i in $scripts
+ do
+ cat $loc/$i
+ printf '\000'
+ done | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \
+ | grep -v '^ ' \
+ | $SED -e 's/^[^ ]*//' \
+ -e 's/ //g' \
+ -e '/^$/d' \
+ -e 's/\(...\)/0\1,/g' \
+ -e 's/$/ \\/'
+ printf '\n'
+fi
+
+mv -- "$target.$$" "$target"
diff --git a/shell/ash.c b/shell/ash.c
index dc1a55a6b..25468d796 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -148,6 +148,21 @@
//config: you to run the specified command or builtin,
//config: even when there is a function with the same name.
//config:
+//config:config ASH_EMBEDDED_SCRIPTS
+//config: bool "Embed scripts in the binary"
+//config: default y
+//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: help
+//config: Allow scripts to be compressed and embedded in the BusyBox
+//config: binary. The scripts should be placed in the 'embed' directory
+//config: at build time. In standalone shell mode such scripts can be
+//config: run directly and are subject to tab completion; otherwise they
+//config: can be run by giving their name as an argument to the shell.
+//config: For convenience shell aliases are created. The '-L' shell
+//config: argument lists the names of the scripts. Like applets scripts
+//config: can be run as 'busybox name ...' or by linking their name to
+//config: the binary.
+//config:
//config:endif # ash options
//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
@@ -181,6 +196,11 @@
#include <sys/times.h>
#include <sys/utsname.h> /* for setting $HOSTNAME */
#include "busybox.h" /* for applet_names */
+#if ENABLE_ASH_EMBEDDED_SCRIPTS
+# include "embedded_scripts.h"
+#else
+# define NUM_SCRIPTS 0
+#endif
/* So far, all bash compat is controlled by one config option */
/* Separate defines document which part of code implements what */
@@ -14021,13 +14041,17 @@ procargs(char **argv)
int login_sh;
xargv = argv;
+#if NUM_SCRIPTS > 0
+ if (minusc)
+ goto setarg0;
+#endif
login_sh = xargv[0] && xargv[0][0] == '-';
arg0 = xargv[0];
/* if (xargv[0]) - mmm, this is always true! */
xargv++;
+ argptr = xargv;
for (i = 0; i < NOPTS; i++)
optlist[i] = 2;
- argptr = xargv;
if (options(/*cmdline:*/ 1, &login_sh)) {
/* it already printed err message */
raise_exception(EXERROR);
@@ -14130,6 +14154,7 @@ extern int etext();
*/
int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int ash_main(int argc UNUSED_PARAM, char **argv)
+/* note: 'argc' is used only if embedded scripts are enabled */
{
volatile smallint state;
struct jmploc jmploc;
@@ -14183,6 +14208,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
init();
setstackmark(&smark);
+
+#if NUM_SCRIPTS > 0
+ if (argc < 0)
+ /* Non-NULL minusc tells procargs that an embedded script is being run */
+ minusc = get_script_content(-argc - 1);
+#endif
login_sh = procargs(argv);
#if DEBUG
TRACE(("Shell args: "));