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 similarity index 100% rename from applets_sh/nologin rename to 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 +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 #include /* 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: "));