[PATCH] ash: allow a profile script to be embedded in the binary

Ron Yorston rmy at pobox.com
Sun Nov 18 10:57:17 UTC 2018


If the file embed/.profile exists at build time it is placed at the
start of the block of compressed scripts.  Its name isn't included
in the list of scripts so it can't be run directly by the user.
Instead it is executed when a login shell is started, before
/etc/profile.

With no embed/.profile the binary is unchanged; with an empty script:

function                                             old     new   delta
scripted_main                                         55      57      +2
ash_main                                            1346    1301     -45
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 2/-45)             Total: -43 bytes

Signed-off-by: Ron Yorston <rmy at pobox.com>
---
 Makefile                 |  2 +-
 libbb/appletlib.c        |  9 ++++++---
 scripts/embedded_scripts | 10 +++++++++-
 shell/ash.c              | 20 ++++++++++++++++++++
 4 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/Makefile b/Makefile
index f0b4da234..a9c3c3996 100644
--- a/Makefile
+++ b/Makefile
@@ -853,7 +853,7 @@ quiet_cmd_split_autoconf   = SPLIT   include/autoconf.h -> include/config/*
 quiet_cmd_gen_embedded_scripts = GEN     include/embedded_scripts.h
       cmd_gen_embedded_scripts = $(srctree)/scripts/embedded_scripts include/embedded_scripts.h $(srctree)/embed $(srctree)/applets_sh
 #bbox# piggybacked generation of few .h files
-include/config/MARKER: scripts/basic/split-include include/autoconf.h $(wildcard $(srctree)/embed/*) $(wildcard $(srctree)/applets_sh/*) $(srctree)/scripts/embedded_scripts
+include/config/MARKER: scripts/basic/split-include include/autoconf.h $(wildcard $(srctree)/embed/*) $(if $(wildcard $(srctree)/embed/.profile),$(srctree)/embed/.profile,) $(wildcard $(srctree)/applets_sh/*) $(srctree)/scripts/embedded_scripts
 	$(call cmd,split_autoconf)
 	$(call cmd,gen_bbconfigopts)
 	$(call cmd,gen_common_bufsiz)
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index a0ebaca29..e0a402031 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -55,8 +55,9 @@
 # include "embedded_scripts.h"
 #else
 # define NUM_SCRIPTS 0
+# define HAS_PROFILE 0
 #endif
-#if NUM_SCRIPTS > 0
+#if NUM_SCRIPTS > 0 || HAS_PROFILE
 # include "bb_archive.h"
 static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS };
 #endif
@@ -948,7 +949,7 @@ static int find_script_by_name(const char *name)
 	if (applet >= 0) {
 		for (i = 0; i < NUM_SCRIPTS; ++i)
 			if (applet_numbers[i] == applet)
-				return i;
+				return i + HAS_PROFILE;
 	}
 	return -1;
 }
@@ -960,7 +961,9 @@ int scripted_main(int argc UNUSED_PARAM, char **argv)
 		exit(ash_main(-script - 1, argv));
 	return 0;
 }
+# endif /* NUM_SCRIPTS > 0 */
 
+# if NUM_SCRIPTS > 0 || HAS_PROFILE
 char* FAST_FUNC
 get_script_content(unsigned n)
 {
@@ -975,7 +978,7 @@ get_script_content(unsigned n)
 	}
 	return t;
 }
-# endif /* NUM_SCRIPTS > 0 */
+# endif /* NUM_SCRIPTS > 0 || HAS_PROFILE */
 
 # if ENABLE_BUSYBOX || NUM_APPLETS > 0
 static NORETURN void run_applet_and_exit(const char *name, char **argv)
diff --git a/scripts/embedded_scripts b/scripts/embedded_scripts
index b419bcb1f..9e137ca1d 100755
--- a/scripts/embedded_scripts
+++ b/scripts/embedded_scripts
@@ -86,7 +86,7 @@ concatenate_scripts() {
 
 exec >"$target.$$"
 
-if [ $n -ne 0 ]
+if [ $n -ne 0 -o -f $custom_loc/.profile ]
 then
 	printf '#ifdef DEFINE_SCRIPT_DATA\n'
 	if [ $n -ne 0 ]
@@ -109,6 +109,14 @@ fi
 
 printf "\n"
 printf '#define NUM_SCRIPTS %d\n' $n
+if [ -f $custom_loc/.profile ]
+then
+	# order is important: .profile must be first
+	custom_scripts=".profile $custom_scripts"
+	printf "#define HAS_PROFILE 1\n"
+else
+	printf "#define HAS_PROFILE 0\n"
+fi
 printf "\n"
 
 if [ $n -ne 0 ]
diff --git a/shell/ash.c b/shell/ash.c
index 44b3569dc..8233efb04 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -199,6 +199,7 @@
 # include "embedded_scripts.h"
 #else
 # define NUM_SCRIPTS 0
+# define HAS_PROFILE 0
 #endif
 
 /* So far, all bash compat is controlled by one config option */
@@ -14163,6 +14164,9 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
 	struct jmploc jmploc;
 	struct stackmark smark;
 	int login_sh;
+#if HAS_PROFILE
+	char *profile;
+#endif
 
 	/* Initialize global data */
 	INIT_G_misc();
@@ -14198,6 +14202,10 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
 
 		popstackmark(&smark);
 		FORCE_INT_ON; /* enable interrupts */
+#if HAS_PROFILE
+		if (s == 0x1a)
+			goto state1a;
+#endif
 		if (s == 1)
 			goto state1;
 		if (s == 2)
@@ -14226,6 +14234,18 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
 	if (login_sh) {
 		const char *hp;
 
+#if HAS_PROFILE
+		state = 0x1a;
+		profile = get_script_content(0);
+		if (profile) {
+			setinputstring(profile);
+			cmdloop(0);
+			popfile();
+		}
+ state1a:
+		free(profile);
+#endif
+
 		state = 1;
 		read_profile("/etc/profile");
  state1:
-- 
2.19.1



More information about the busybox mailing list