diff options
author | Ron Yorston <rmy@pobox.com> | 2018-10-22 09:12:07 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2018-10-22 09:20:19 +0100 |
commit | 3994d5a52b8fa70637bffe4173f165267e6169fb (patch) | |
tree | 33268801c1adaa10797e6bee98ef737293fe6711 | |
parent | eee3722fd32c8c0929cfbacdbe0b6524e1fd645c (diff) | |
download | busybox-w32-3994d5a52b8fa70637bffe4173f165267e6169fb.tar.gz busybox-w32-3994d5a52b8fa70637bffe4173f165267e6169fb.tar.bz2 busybox-w32-3994d5a52b8fa70637bffe4173f165267e6169fb.zip |
Allow shell scripts to be embedded in the binary
To assist in the deployment of shell scripts it may be convenient
to embed them in the BusyBox binary.
This patch adds two configuration options to the shell:
- 'Embed scripts in the binary' takes any files in the directory
'embed', concatenates them with null separators, compresses them
and embeds them in the binary.
- 'Allow the contents of embedded scripts to be listed' makes the
shell argument '-L name' list the contents of the named script.
Both options are off by default.
When scripts are embedded in the binary:
- The shell argument '-L' lists the names of the scripts.
- Scripts can be run as 'sh name arg...'.
- An alias is added for each script, equivalent to "alias name='sh name'".
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | archival/libarchive/Kbuild.src | 1 | ||||
-rw-r--r-- | include/.gitignore | 1 | ||||
-rw-r--r-- | shell/Kbuild.src | 10 | ||||
-rw-r--r-- | shell/ash.c | 140 | ||||
-rwxr-xr-x | shell/embedded_scripts | 62 |
6 files changed, 218 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore index 517e750c1..cc485189e 100644 --- a/.gitignore +++ b/.gitignore | |||
@@ -58,3 +58,8 @@ cscope.po.out | |||
58 | # | 58 | # |
59 | tags | 59 | tags |
60 | TAGS | 60 | TAGS |
61 | |||
62 | # | ||
63 | # user-supplied scripts | ||
64 | # | ||
65 | /embed | ||
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. | |||
91 | lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o | 91 | lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o |
92 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o | 92 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o |
93 | lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o | 93 | lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o |
94 | lib-$(CONFIG_ASH_EMBEDDED_SCRIPTS) += open_transformer.o decompress_bunzip2.o | ||
94 | 95 | ||
95 | ifneq ($(lib-y),) | 96 | ifneq ($(lib-y),) |
96 | lib-y += $(COMMON_FILES) | 97 | lib-y += $(COMMON_FILES) |
diff --git a/include/.gitignore b/include/.gitignore index 75afff9ca..13a96e018 100644 --- a/include/.gitignore +++ b/include/.gitignore | |||
@@ -5,6 +5,7 @@ | |||
5 | /autoconf.h | 5 | /autoconf.h |
6 | /bbconfigopts_bz2.h | 6 | /bbconfigopts_bz2.h |
7 | /bbconfigopts.h | 7 | /bbconfigopts.h |
8 | /embedded_scripts.h | ||
8 | /NUM_APPLETS.h | 9 | /NUM_APPLETS.h |
9 | /usage_compressed.h | 10 | /usage_compressed.h |
10 | /usage.h | 11 | /usage.h |
diff --git a/shell/Kbuild.src b/shell/Kbuild.src index a287fce4e..34dd93d48 100644 --- a/shell/Kbuild.src +++ b/shell/Kbuild.src | |||
@@ -10,3 +10,13 @@ INSERT | |||
10 | 10 | ||
11 | lib-$(CONFIG_FEATURE_SH_MATH) += math.o | 11 | lib-$(CONFIG_FEATURE_SH_MATH) += math.o |
12 | lib-$(CONFIG_FEATURE_PRNG_SHELL) += random.o | 12 | lib-$(CONFIG_FEATURE_PRNG_SHELL) += random.o |
13 | |||
14 | quiet_cmd_gen_embedded_scripts = GEN include/embedded_scripts.h | ||
15 | cmd_gen_embedded_scripts = $(srctree_slash)shell/embedded_scripts include/embedded_scripts.h embed | ||
16 | |||
17 | ifdef CONFIG_ASH_EMBEDDED_SCRIPTS | ||
18 | shell/ash.o: include/embedded_scripts.h | ||
19 | endif | ||
20 | |||
21 | include/embedded_scripts.h: $(wildcard embed/*) shell/embedded_scripts | ||
22 | $(call cmd,gen_embedded_scripts) | ||
diff --git a/shell/ash.c b/shell/ash.c index 7131609e4..9d7ef032c 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -175,6 +175,25 @@ | |||
175 | //config: from a GUI application. Disable this if your platform doesn't | 175 | //config: from a GUI application. Disable this if your platform doesn't |
176 | //config: support the required APIs. | 176 | //config: support the required APIs. |
177 | //config: | 177 | //config: |
178 | //config:config ASH_EMBEDDED_SCRIPTS | ||
179 | //config: bool "Embed scripts in the binary" | ||
180 | //config: default n | ||
181 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | ||
182 | //config: help | ||
183 | //config: Allow scripts to be compressed and embedded in the BusyBox | ||
184 | //config: binary. The scripts should be placed in the 'embed' directory. | ||
185 | //config: Such scripts can only be run by giving their name as an | ||
186 | //config: argument to the shell, though aliases are set up to do this. | ||
187 | //config: The names of the scripts are listed by the '-L' shell argument. | ||
188 | //config: | ||
189 | //config:config ASH_LIST_EMBEDDED_SCRIPTS | ||
190 | //config: bool "Allow the contents of embedded scripts to be listed" | ||
191 | //config: default n | ||
192 | //config: depends on ASH_EMBEDDED_SCRIPTS | ||
193 | //config: help | ||
194 | //config: Allow the contents of embedded script to be listed using | ||
195 | //config: the '-L name' shell argument. | ||
196 | //config: | ||
178 | //config:endif # ash options | 197 | //config:endif # ash options |
179 | 198 | ||
180 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) | 199 | //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) |
@@ -209,6 +228,16 @@ | |||
209 | #include <sys/utsname.h> /* for setting $HOSTNAME */ | 228 | #include <sys/utsname.h> /* for setting $HOSTNAME */ |
210 | #include "busybox.h" /* for applet_names */ | 229 | #include "busybox.h" /* for applet_names */ |
211 | 230 | ||
231 | #if ENABLE_ASH_EMBEDDED_SCRIPTS | ||
232 | #include "embedded_scripts.h" | ||
233 | #else | ||
234 | #define NUM_SCRIPTS 0 | ||
235 | #endif | ||
236 | |||
237 | #if NUM_SCRIPTS | ||
238 | static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS }; | ||
239 | #endif | ||
240 | |||
212 | /* So far, all bash compat is controlled by one config option */ | 241 | /* So far, all bash compat is controlled by one config option */ |
213 | /* Separate defines document which part of code implements what */ | 242 | /* Separate defines document which part of code implements what */ |
214 | /* function keyword */ | 243 | /* function keyword */ |
@@ -11490,6 +11519,76 @@ setparam(char **argv) | |||
11490 | #endif | 11519 | #endif |
11491 | } | 11520 | } |
11492 | 11521 | ||
11522 | #if NUM_SCRIPTS | ||
11523 | #define BB_ARCHIVE_PUBLIC | ||
11524 | # include "bb_archive.h" | ||
11525 | static char *unpack_scripts(void) | ||
11526 | { | ||
11527 | char *outbuf = NULL; | ||
11528 | bunzip_data *bd; | ||
11529 | int i; | ||
11530 | jmp_buf jmpbuf; | ||
11531 | |||
11532 | /* Setup for I/O error handling via longjmp */ | ||
11533 | i = setjmp(jmpbuf); | ||
11534 | if (i == 0) { | ||
11535 | i = start_bunzip(&jmpbuf, | ||
11536 | &bd, | ||
11537 | /* src_fd: */ -1, | ||
11538 | /* inbuf: */ packed_scripts, | ||
11539 | /* len: */ sizeof(packed_scripts) | ||
11540 | ); | ||
11541 | } | ||
11542 | /* read_bunzip can longjmp and end up here with i != 0 | ||
11543 | * on read data errors! Not trivial */ | ||
11544 | if (i == 0) { | ||
11545 | /* Cannot use xmalloc: will leak bd in NOFORK case! */ | ||
11546 | outbuf = malloc_or_warn(UNPACKED_SCRIPTS_LENGTH); | ||
11547 | if (outbuf) | ||
11548 | read_bunzip(bd, outbuf, UNPACKED_SCRIPTS_LENGTH); | ||
11549 | } | ||
11550 | dealloc_bunzip(bd); | ||
11551 | return outbuf; | ||
11552 | } | ||
11553 | |||
11554 | static char * | ||
11555 | check_embedded(const char *arg) | ||
11556 | { | ||
11557 | int i; | ||
11558 | char *scripts; | ||
11559 | const char *s; | ||
11560 | |||
11561 | i = 0; | ||
11562 | for (s=script_names; *s; s+=strlen(s)+1) { | ||
11563 | if (strcmp(arg, s) == 0) { | ||
11564 | break; | ||
11565 | } | ||
11566 | ++i; | ||
11567 | } | ||
11568 | |||
11569 | if (i != NUM_SCRIPTS && (scripts=unpack_scripts()) != NULL) { | ||
11570 | char *t = scripts; | ||
11571 | while (i != 0) { | ||
11572 | t += strlen(t) + 1; | ||
11573 | --i; | ||
11574 | } | ||
11575 | return t; | ||
11576 | } | ||
11577 | |||
11578 | return NULL; | ||
11579 | } | ||
11580 | |||
11581 | static void | ||
11582 | alias_embedded(void) | ||
11583 | { | ||
11584 | const char *s; | ||
11585 | |||
11586 | for (s=script_names; *s; s+=strlen(s)+1) { | ||
11587 | setalias(s, auto_string(xasprintf("sh %s", s))); | ||
11588 | } | ||
11589 | } | ||
11590 | #endif | ||
11591 | |||
11493 | /* | 11592 | /* |
11494 | * Process shell options. The global variable argptr contains a pointer | 11593 | * Process shell options. The global variable argptr contains a pointer |
11495 | * to the argument list; we advance it past the options. | 11594 | * to the argument list; we advance it past the options. |
@@ -11600,6 +11699,26 @@ options(int cmdline, int *login_sh) | |||
11600 | *login_sh = 1; | 11699 | *login_sh = 1; |
11601 | } | 11700 | } |
11602 | break; | 11701 | break; |
11702 | #if NUM_SCRIPTS | ||
11703 | } else if (cmdline && (c == 'L')) { | ||
11704 | #if ENABLE_ASH_LIST_EMBEDDED_SCRIPTS | ||
11705 | if (*argptr) { | ||
11706 | char *script; | ||
11707 | |||
11708 | if ((script=check_embedded(*argptr)) != NULL) { | ||
11709 | printf(script); | ||
11710 | } | ||
11711 | } else | ||
11712 | #endif | ||
11713 | { | ||
11714 | const char *s; | ||
11715 | |||
11716 | for (s=script_names; *s; s+=strlen(s)+1) { | ||
11717 | printf("%s\n", s); | ||
11718 | } | ||
11719 | } | ||
11720 | exit(0); | ||
11721 | #endif | ||
11603 | } else { | 11722 | } else { |
11604 | setoption(c, val); | 11723 | setoption(c, val); |
11605 | } | 11724 | } |
@@ -14643,9 +14762,17 @@ init(void) | |||
14643 | } | 14762 | } |
14644 | } | 14763 | } |
14645 | 14764 | ||
14646 | |||
14647 | //usage:#define ash_trivial_usage | 14765 | //usage:#define ash_trivial_usage |
14648 | //usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]" | 14766 | //usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]" |
14767 | //usage: IF_ASH_EMBEDDED_SCRIPTS( | ||
14768 | //usage: " [-L" | ||
14769 | //usage: ) | ||
14770 | //usage: IF_ASH_LIST_EMBEDDED_SCRIPTS( | ||
14771 | //usage: " [name]" | ||
14772 | //usage: ) | ||
14773 | //usage: IF_ASH_EMBEDDED_SCRIPTS( | ||
14774 | //usage: "]" | ||
14775 | //usage: ) | ||
14649 | //usage:#define ash_full_usage "\n\n" | 14776 | //usage:#define ash_full_usage "\n\n" |
14650 | //usage: "Unix shell interpreter" | 14777 | //usage: "Unix shell interpreter" |
14651 | 14778 | ||
@@ -14689,12 +14816,23 @@ procargs(char **argv) | |||
14689 | #if DEBUG == 2 | 14816 | #if DEBUG == 2 |
14690 | debug = 1; | 14817 | debug = 1; |
14691 | #endif | 14818 | #endif |
14819 | #if NUM_SCRIPTS | ||
14820 | alias_embedded(); | ||
14821 | #endif | ||
14692 | /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */ | 14822 | /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */ |
14693 | if (xminusc) { | 14823 | if (xminusc) { |
14694 | minusc = *xargv++; | 14824 | minusc = *xargv++; |
14695 | if (*xargv) | 14825 | if (*xargv) |
14696 | goto setarg0; | 14826 | goto setarg0; |
14697 | } else if (!sflag) { | 14827 | } else if (!sflag) { |
14828 | #if NUM_SCRIPTS | ||
14829 | char *script; | ||
14830 | if ((script=check_embedded(*xargv)) != NULL) { | ||
14831 | setinputstring(script); | ||
14832 | xflag = 0; | ||
14833 | goto setarg0; | ||
14834 | } | ||
14835 | #endif | ||
14698 | setinputfile(*xargv, 0); | 14836 | setinputfile(*xargv, 0); |
14699 | #if ENABLE_PLATFORM_MINGW32 | 14837 | #if ENABLE_PLATFORM_MINGW32 |
14700 | convert_slashes(*xargv); | 14838 | convert_slashes(*xargv); |
diff --git a/shell/embedded_scripts b/shell/embedded_scripts new file mode 100755 index 000000000..0ca89b91e --- /dev/null +++ b/shell/embedded_scripts | |||
@@ -0,0 +1,62 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | target="$1" | ||
4 | loc="$2" | ||
5 | |||
6 | test "$target" || exit 1 | ||
7 | test "$SED" || SED=sed | ||
8 | test "$DD" || DD=dd | ||
9 | |||
10 | # Some people were bitten by their system lacking a (proper) od | ||
11 | od -v -b </dev/null >/dev/null | ||
12 | if test $? != 0; then | ||
13 | echo 'od tool is not installed or cannot accept "-v -b" options' | ||
14 | exit 1 | ||
15 | fi | ||
16 | |||
17 | exec >"$target.$$" | ||
18 | |||
19 | scripts="" | ||
20 | if [ -d "$loc" ] | ||
21 | then | ||
22 | scripts=$(cd $loc; ls * 2>/dev/null) | ||
23 | fi | ||
24 | |||
25 | n=$(echo $scripts | wc -w) | ||
26 | |||
27 | if [ $n -ne 0 ] | ||
28 | then | ||
29 | printf 'static const char script_names[] ALIGN1 = ' | ||
30 | for i in $scripts | ||
31 | do | ||
32 | printf '"%s\\0"' $i | ||
33 | done | ||
34 | printf '"\\0";\n' | ||
35 | fi | ||
36 | printf "#define NUM_SCRIPTS $n\n\n" | ||
37 | |||
38 | if [ $n -ne 0 ] | ||
39 | then | ||
40 | printf '#define UNPACKED_SCRIPTS_LENGTH ' | ||
41 | for i in $scripts | ||
42 | do | ||
43 | cat $loc/$i | ||
44 | printf '\000' | ||
45 | done | wc -c | ||
46 | |||
47 | printf '#define PACKED_SCRIPTS \\\n' | ||
48 | for i in $scripts | ||
49 | do | ||
50 | cat $loc/$i | ||
51 | printf '\000' | ||
52 | done | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \ | ||
53 | | grep -v '^ ' \ | ||
54 | | $SED -e 's/^[^ ]*//' \ | ||
55 | -e 's/ //g' \ | ||
56 | -e '/^$/d' \ | ||
57 | -e 's/\(...\)/0\1,/g' \ | ||
58 | -e 's/$/ \\/' | ||
59 | printf '\n' | ||
60 | fi | ||
61 | |||
62 | mv -- "$target.$$" "$target" | ||