Discussion:
[PATCH] ash: allow a profile script to be embedded in the binary
Ron Yorston
2018-11-03 10:56:23 UTC
Permalink
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, after /etc/profile
but before ~/.profile.

If an empty .profile is present bloatcheck reports:

function old new delta
ash_main 1346 1398 +52
.rodata 168516 168528 +12
find_script_by_name 57 60 +3
packed_scripts 123 122 -1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/1 up/down: 67/-1) Total: 66 bytes

Signed-off-by: Ron Yorston <***@pobox.com>
---
.gitignore | 1 +
Makefile | 2 +-
libbb/appletlib.c | 9 ++++++---
libbb/lineedit.c | 1 +
scripts/embedded_scripts | 12 ++++++++++--
shell/ash.c | 14 +++++++++++++-
6 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/.gitignore b/.gitignore
index c03c2e8a6..d8b02f13b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ Config.in
# Never ignore these
#
!.gitignore
+!embed/.profile

#
# Normal output
diff --git a/Makefile b/Makefile
index 8a0dbdf49..5d9be032f 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 = 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 $(wildcard embed/*) scripts/embedded_scripts
+include/config/MARKER: scripts/basic/split-include include/autoconf.h $(wildcard embed/*) $(if $(wildcard embed/.profile),embed/.profile,) 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 6dfaf1f41..afdee39d6 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
@@ -950,7 +951,7 @@ int FAST_FUNC
find_script_by_name(const char *name)
{
const char *s = script_names;
- int i = 0;
+ int i = HAS_PROFILE;

while (*s) {
if (strcmp(name, s) == 0)
@@ -961,7 +962,9 @@ find_script_by_name(const char *name)
}
return -0x10000; /* make it so that NUM_APPLETS + <error> is still < 0 */
}
+# endif /* NUM_SCRIPTS > 0 */

+# if NUM_SCRIPTS > 0 || HAS_PROFILE
char* FAST_FUNC
get_script_content(unsigned n)
{
@@ -976,7 +979,7 @@ get_script_content(unsigned n)
}
return t;
}
-# endif /* NUM_SCRIPTS > 0 */
+# endif /* NUM_SCRIPTS > 0 || HAS_PROFILE */

# if ENABLE_BUSYBOX || NUM_APPLETS > 0 || NUM_SCRIPTS > 0
static NORETURN void run_applet_and_exit(const char *name, char **argv)
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 618e7c221..3561f3d85 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -45,6 +45,7 @@
# include "embedded_scripts.h"
#else
# define NUM_SCRIPTS 0
+# define HAS_PROFILE 0
#endif

#ifndef _POSIX_VDISABLE
diff --git a/scripts/embedded_scripts b/scripts/embedded_scripts
index 7245ba6e0..09f050d1b 100755
--- a/scripts/embedded_scripts
+++ b/scripts/embedded_scripts
@@ -37,9 +37,17 @@ then
printf 'extern const char script_names[] ALIGN1;\n'
printf '#endif\n'
fi
-printf "#define NUM_SCRIPTS $n\n\n"
+printf "#define NUM_SCRIPTS $n\n"

-if [ $n -ne 0 ]
+if [ -f $loc/.profile ]
+then
+ scripts=".profile $scripts"
+ printf "#define HAS_PROFILE 1\n\n"
+else
+ printf "#define HAS_PROFILE 0\n\n"
+fi
+
+if [ $n -ne 0 -o -f $loc/.profile ]
then
printf '#define UNPACKED_SCRIPTS_LENGTH '
for i in $scripts
diff --git a/shell/ash.c b/shell/ash.c
index 88f2b5bd6..39d5b5b1b 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -195,6 +195,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 */
@@ -14235,7 +14236,18 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
const char *hp;

state = 1;
- read_profile("/etc/profile");
+ read_profile("/etc/Profile");
+#if HAS_PROFILE
+ {
+ char *profile = get_script_content(0);
+ if (profile) {
+ setinputstring(profile);
+ cmdloop(0);
+ free(profile);
+ popfile();
+ }
+ }
+#endif
state1:
state = 2;
hp = lookupvar("HOME");
--
2.19.1
Ron Yorston
2018-11-03 11:07:54 UTC
Permalink
Gah! Scratch that last patch, I left in the renamed /etc/profile I
was using during testing to avoid bashisms in my real /etc/profile.

Ron
Denys Vlasenko
2018-11-03 17:06:30 UTC
Permalink
Post by Ron Yorston
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, after /etc/profile
but before ~/.profile.
As I see it, the purpose of EMBEDDED_SCRIPTS is to have some applets
written in shell: sometimes that cat be smaller than C code.

What is the purpose of embedded profile script?
Ron Yorston
2018-11-03 18:10:41 UTC
Permalink
Denys,
Post by Denys Vlasenko
As I see it, the purpose of EMBEDDED_SCRIPTS is to have some applets
written in shell: sometimes that cat be smaller than C code.
What is the purpose of embedded profile script?
The idea is to allow users [to] ship application scripts as part of the
binary so there's less chance of them getting lost. It also allows
them to extend BusyBox without having to write full-blown applets.
The plan was to make it easy for developers to ship customised BusyBox
binaries with application-specific scripts included. Things that might
not make sense as general-purpose applets.

In that context I think it's reasonable to allow for a profile script.

It's also why, for example, I included the 'embed' directory in
.gitignore: it was intended for customisation, not for standard applets
implemented as scripts, which already have the 'applets_sh' directory.

Likewise, the embedded scripts have a separate namespace and no mechanism
for installing them. My view was that applets implemented as scripts
would live in the same namespace as C applets and have their usage
messages and installation directories integrated in the same way.
Post by Denys Vlasenko
I consider what I've done here orthogonal to the idea of implementing
actual applets as scripts. I'd expect the latter to set much higher
standards in terms of usage documentation and integration. I'd expect
script applets to be separately configured at build time and to ensure
that any other applets required by the script were included. It'd be
a whole lot more work to implement.
Ron

Loading...