aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-11-01 09:53:25 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-11-01 10:15:13 +0100
commit4f2ef4a836be37b25808c94f41c7c85895db6f93 (patch)
treee224e4f3b8513b35655da80b26369d42bd62d24d
parent552796791f8c5aa12dfb790e3a94c2d905f367ee (diff)
downloadbusybox-w32-4f2ef4a836be37b25808c94f41c7c85895db6f93.tar.gz
busybox-w32-4f2ef4a836be37b25808c94f41c7c85895db6f93.tar.bz2
busybox-w32-4f2ef4a836be37b25808c94f41c7c85895db6f93.zip
ash: 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. '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. When scripts are embedded in the binary, scripts can be run as 'busybox SCRIPT [ARGS]' or by usual (sym)link mechanism. embed/nologin is provided as an example. function old new delta packed_scripts - 123 +123 unpack_scripts - 87 +87 ash_main 1103 1171 +68 run_applet_and_exit 78 128 +50 get_script_content - 32 +32 script_names - 10 +10 expmeta 663 659 -4 ------------------------------------------------------------------------------ (add/remove: 4/0 grow/shrink: 2/1 up/down: 370/-4) Total: 366 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-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
850 cmd_gen_common_bufsiz = $(srctree)/scripts/generate_BUFSIZ.sh include/common_bufsiz.h 850 cmd_gen_common_bufsiz = $(srctree)/scripts/generate_BUFSIZ.sh include/common_bufsiz.h
851quiet_cmd_split_autoconf = SPLIT include/autoconf.h -> include/config/* 851quiet_cmd_split_autoconf = SPLIT include/autoconf.h -> include/config/*
852 cmd_split_autoconf = scripts/basic/split-include include/autoconf.h include/config 852 cmd_split_autoconf = scripts/basic/split-include include/autoconf.h include/config
853quiet_cmd_gen_embedded_scripts = GEN include/embedded_scripts.h
854 cmd_gen_embedded_scripts = scripts/embedded_scripts include/embedded_scripts.h embed
853#bbox# piggybacked generation of few .h files 855#bbox# piggybacked generation of few .h files
854include/config/MARKER: scripts/basic/split-include include/autoconf.h 856include/config/MARKER: scripts/basic/split-include include/autoconf.h $(wildcard embed/*) scripts/embedded_scripts
855 $(call cmd,split_autoconf) 857 $(call cmd,split_autoconf)
856 $(call cmd,gen_bbconfigopts) 858 $(call cmd,gen_bbconfigopts)
857 $(call cmd,gen_common_bufsiz) 859 $(call cmd,gen_common_bufsiz)
860 $(call cmd,gen_embedded_scripts)
858 @touch $@ 861 @touch $@
859 862
860# Generate some files 863# Generate some files
@@ -974,6 +977,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \
974 include/autoconf.h \ 977 include/autoconf.h \
975 include/bbconfigopts.h \ 978 include/bbconfigopts.h \
976 include/bbconfigopts_bz2.h \ 979 include/bbconfigopts_bz2.h \
980 include/embedded_scripts.h \
977 include/usage_compressed.h \ 981 include/usage_compressed.h \
978 include/applet_tables.h \ 982 include/applet_tables.h \
979 include/applets.h \ 983 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.
91lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o 91lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o
92lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o 92lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o
93lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o 93lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o
94lib-$(CONFIG_ASH_EMBEDDED_SCRIPTS) += open_transformer.o decompress_bunzip2.o
94 95
95ifneq ($(lib-y),) 96ifneq ($(lib-y),)
96lib-y += $(COMMON_FILES) 97lib-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 @@
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/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;
1321#define MAIN_EXTERNALLY_VISIBLE 1321#define MAIN_EXTERNALLY_VISIBLE
1322#endif 1322#endif
1323 1323
1324/* Embedded script support */
1325//int find_script_by_name(const char *arg IF_FEATURE_SH_STANDALONE(, int offset)) FAST_FUNC;
1326char *get_script_content(unsigned n) FAST_FUNC;
1324 1327
1325/* Applets which are useful from another applets */ 1328/* Applets which are useful from another applets */
1326int bb_cat(char** argv) FAST_FUNC; 1329int bb_cat(char** argv) FAST_FUNC;
1330int ash_main(int argc, char** argv)
1331#if ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH
1332 MAIN_EXTERNALLY_VISIBLE
1333#endif
1334;
1327/* If shell needs them, they exist even if not enabled as applets */ 1335/* If shell needs them, they exist even if not enabled as applets */
1328int echo_main(int argc, char** argv) IF_ECHO(MAIN_EXTERNALLY_VISIBLE); 1336int echo_main(int argc, char** argv) IF_ECHO(MAIN_EXTERNALLY_VISIBLE);
1329int printf_main(int argc, char **argv) IF_PRINTF(MAIN_EXTERNALLY_VISIBLE); 1337int 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 @@
50 50
51#include "usage_compressed.h" 51#include "usage_compressed.h"
52 52
53#if ENABLE_ASH_EMBEDDED_SCRIPTS
54# define DEFINE_script_names 1
55# include "embedded_scripts.h"
56#else
57# define NUM_SCRIPTS 0
58#endif
59#if NUM_SCRIPTS > 0
60# include "bb_archive.h"
61static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS };
62#endif
53 63
54/* "Do not compress usage text if uncompressed text is small 64/* "Do not compress usage text if uncompressed text is small
55 * and we don't include bunzip2 code for other reasons" 65 * 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
953} 963}
954# endif /* NUM_APPLETS > 0 */ 964# endif /* NUM_APPLETS > 0 */
955 965
956# if ENABLE_BUSYBOX || NUM_APPLETS > 0 966# if NUM_SCRIPTS > 0
967static char *
968unpack_scripts(void)
969{
970 char *outbuf = NULL;
971 bunzip_data *bd;
972 int i;
973 jmp_buf jmpbuf;
974
975 /* Setup for I/O error handling via longjmp */
976 i = setjmp(jmpbuf);
977 if (i == 0) {
978 i = start_bunzip(&jmpbuf,
979 &bd,
980 /* src_fd: */ -1,
981 /* inbuf: */ packed_scripts,
982 /* len: */ sizeof(packed_scripts)
983 );
984 }
985 /* read_bunzip can longjmp and end up here with i != 0
986 * on read data errors! Not trivial */
987 if (i == 0) {
988 outbuf = xmalloc(UNPACKED_SCRIPTS_LENGTH);
989 read_bunzip(bd, outbuf, UNPACKED_SCRIPTS_LENGTH);
990 }
991 dealloc_bunzip(bd);
992 return outbuf;
993}
994
995/*
996 * In standalone shell mode we sometimes want the index of the script
997 * and sometimes the index offset by NUM_APPLETS.
998 */
999static int
1000find_script_by_name(const char *arg)
1001{
1002 const char *s = script_names;
1003 int i = 0;
1004
1005 while (*s) {
1006 if (strcmp(arg, s) == 0)
1007 return i;
1008 i++;
1009 while (*s++ != '\0')
1010 continue;
1011 }
1012 return -1;
1013}
1014
1015char* FAST_FUNC
1016get_script_content(unsigned n)
1017{
1018 char *t = unpack_scripts();
1019 if (t) {
1020 while (n != 0) {
1021 while (*t++ != '\0')
1022 continue;
1023 n--;
1024 }
1025 }
1026 return t;
1027}
1028# endif /* NUM_SCRIPTS > 0 */
1029
1030# if ENABLE_BUSYBOX || NUM_APPLETS > 0 || NUM_SCRIPTS > 0
957static NORETURN void run_applet_and_exit(const char *name, char **argv) 1031static NORETURN void run_applet_and_exit(const char *name, char **argv)
958{ 1032{
959# if ENABLE_BUSYBOX 1033# if ENABLE_BUSYBOX
@@ -968,6 +1042,13 @@ static NORETURN void run_applet_and_exit(const char *name, char **argv)
968 run_applet_no_and_exit(applet, name, argv); 1042 run_applet_no_and_exit(applet, name, argv);
969 } 1043 }
970# endif 1044# endif
1045# if NUM_SCRIPTS > 0
1046 {
1047 int script = find_script_by_name(name);
1048 if (script >= 0)
1049 exit(ash_main(-script - 1, argv));
1050 }
1051# endif
971 1052
972 /*bb_error_msg_and_die("applet not found"); - links in printf */ 1053 /*bb_error_msg_and_die("applet not found"); - links in printf */
973 full_write2_str(applet_name); 1054 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 @@
41#include "busybox.h" 41#include "busybox.h"
42#include "NUM_APPLETS.h" 42#include "NUM_APPLETS.h"
43#include "unicode.h" 43#include "unicode.h"
44#if ENABLE_ASH_EMBEDDED_SCRIPTS
45# include "embedded_scripts.h"
46#else
47# define NUM_SCRIPTS 0
48#endif
49
44#ifndef _POSIX_VDISABLE 50#ifndef _POSIX_VDISABLE
45# define _POSIX_VDISABLE '\0' 51# define _POSIX_VDISABLE '\0'
46#endif 52#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 @@
1#!/bin/sh
2
3target="$1"
4loc="$2"
5
6test "$target" || exit 1
7test "$SED" || SED=sed
8test "$DD" || DD=dd
9
10# Some people were bitten by their system lacking a (proper) od
11od -v -b </dev/null >/dev/null
12if test $? != 0; then
13 echo 'od tool is not installed or cannot accept "-v -b" options'
14 exit 1
15fi
16
17exec >"$target.$$"
18
19scripts=""
20if [ -d "$loc" ]
21then
22 scripts=$(cd $loc; ls * 2>/dev/null)
23fi
24
25n=$(echo $scripts | wc -w)
26
27if [ $n -ne 0 ]
28then
29 printf '#ifdef DEFINE_script_names\n'
30 printf 'const char script_names[] ALIGN1 = '
31 for i in $scripts
32 do
33 printf '"%s\\0"' $i
34 done
35 printf '"\\0";\n'
36 printf '#else\n'
37 printf 'extern const char script_names[] ALIGN1;\n'
38 printf '#endif\n'
39fi
40printf "#define NUM_SCRIPTS $n\n\n"
41
42if [ $n -ne 0 ]
43then
44 printf '#define UNPACKED_SCRIPTS_LENGTH '
45 for i in $scripts
46 do
47 cat $loc/$i
48 printf '\000'
49 done | wc -c
50
51 printf '#define PACKED_SCRIPTS \\\n'
52 for i in $scripts
53 do
54 cat $loc/$i
55 printf '\000'
56 done | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \
57 | grep -v '^ ' \
58 | $SED -e 's/^[^ ]*//' \
59 -e 's/ //g' \
60 -e '/^$/d' \
61 -e 's/\(...\)/0\1,/g' \
62 -e 's/$/ \\/'
63 printf '\n'
64fi
65
66mv -- "$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 @@
148//config: you to run the specified command or builtin, 148//config: you to run the specified command or builtin,
149//config: even when there is a function with the same name. 149//config: even when there is a function with the same name.
150//config: 150//config:
151//config:config ASH_EMBEDDED_SCRIPTS
152//config: bool "Embed scripts in the binary"
153//config: default y
154//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
155//config: help
156//config: Allow scripts to be compressed and embedded in the BusyBox
157//config: binary. The scripts should be placed in the 'embed' directory
158//config: at build time. In standalone shell mode such scripts can be
159//config: run directly and are subject to tab completion; otherwise they
160//config: can be run by giving their name as an argument to the shell.
161//config: For convenience shell aliases are created. The '-L' shell
162//config: argument lists the names of the scripts. Like applets scripts
163//config: can be run as 'busybox name ...' or by linking their name to
164//config: the binary.
165//config:
151//config:endif # ash options 166//config:endif # ash options
152 167
153//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 168//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
@@ -181,6 +196,11 @@
181#include <sys/times.h> 196#include <sys/times.h>
182#include <sys/utsname.h> /* for setting $HOSTNAME */ 197#include <sys/utsname.h> /* for setting $HOSTNAME */
183#include "busybox.h" /* for applet_names */ 198#include "busybox.h" /* for applet_names */
199#if ENABLE_ASH_EMBEDDED_SCRIPTS
200# include "embedded_scripts.h"
201#else
202# define NUM_SCRIPTS 0
203#endif
184 204
185/* So far, all bash compat is controlled by one config option */ 205/* So far, all bash compat is controlled by one config option */
186/* Separate defines document which part of code implements what */ 206/* Separate defines document which part of code implements what */
@@ -14021,13 +14041,17 @@ procargs(char **argv)
14021 int login_sh; 14041 int login_sh;
14022 14042
14023 xargv = argv; 14043 xargv = argv;
14044#if NUM_SCRIPTS > 0
14045 if (minusc)
14046 goto setarg0;
14047#endif
14024 login_sh = xargv[0] && xargv[0][0] == '-'; 14048 login_sh = xargv[0] && xargv[0][0] == '-';
14025 arg0 = xargv[0]; 14049 arg0 = xargv[0];
14026 /* if (xargv[0]) - mmm, this is always true! */ 14050 /* if (xargv[0]) - mmm, this is always true! */
14027 xargv++; 14051 xargv++;
14052 argptr = xargv;
14028 for (i = 0; i < NOPTS; i++) 14053 for (i = 0; i < NOPTS; i++)
14029 optlist[i] = 2; 14054 optlist[i] = 2;
14030 argptr = xargv;
14031 if (options(/*cmdline:*/ 1, &login_sh)) { 14055 if (options(/*cmdline:*/ 1, &login_sh)) {
14032 /* it already printed err message */ 14056 /* it already printed err message */
14033 raise_exception(EXERROR); 14057 raise_exception(EXERROR);
@@ -14130,6 +14154,7 @@ extern int etext();
14130 */ 14154 */
14131int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 14155int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14132int ash_main(int argc UNUSED_PARAM, char **argv) 14156int ash_main(int argc UNUSED_PARAM, char **argv)
14157/* note: 'argc' is used only if embedded scripts are enabled */
14133{ 14158{
14134 volatile smallint state; 14159 volatile smallint state;
14135 struct jmploc jmploc; 14160 struct jmploc jmploc;
@@ -14183,6 +14208,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
14183 14208
14184 init(); 14209 init();
14185 setstackmark(&smark); 14210 setstackmark(&smark);
14211
14212#if NUM_SCRIPTS > 0
14213 if (argc < 0)
14214 /* Non-NULL minusc tells procargs that an embedded script is being run */
14215 minusc = get_script_content(-argc - 1);
14216#endif
14186 login_sh = procargs(argv); 14217 login_sh = procargs(argv);
14187#if DEBUG 14218#if DEBUG
14188 TRACE(("Shell args: ")); 14219 TRACE(("Shell args: "));