ash: allow shell scripts to be embedded in the binary
No binary (build failed)
—
(log yok)
| @@ -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 \ | |
| @@ -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) | |
| @@ -5,6 +5,7 @@ | |
| /autoconf.h | |
| /bbconfigopts_bz2.h | |
| /bbconfigopts.h | |
| + | /embedded_scripts.h |
| /NUM_APPLETS.h | |
| /usage_compressed.h | |
| /usage.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); | |
| @@ -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); | |
| @@ -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 | |
| @@ -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" |
| @@ -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: ")); | |