[RFC PATCH 1/1] Allow applets to be implemented as scripts
Ron Yorston
rmy at pobox.com
Mon Nov 5 14:00:46 UTC 2018
Now that scripts can be embedded in the BusyBox binary it's possible
to implement applets as scripts.
Such scripts should be placed in the 'applets_sh' directory. A stub
C program should be written to provide the usual applet configuration
details and placed in a suitable subsystem directory.
This patch implements the 'nologin' applet as a script.
The 'embed' directory can be used for scripts that aren't intended
to be treated as applets.
Signed-off-by: Ron Yorston <rmy at pobox.com>
---
.gitignore | 5 +++
applets/busybox.mkscripts | 16 +++++++++
{embed => applets_sh}/nologin | 0
include/applets.src.h | 15 +++++++++
include/libbb.h | 1 +
libbb/appletlib.c | 54 +++++++++++++++---------------
scripts/embedded_scripts | 62 +++++++++++++++++++++++++----------
shell/ash.c | 9 ++++-
util-linux/nologin.c | 15 +++++++++
9 files changed, 132 insertions(+), 45 deletions(-)
create mode 100755 applets/busybox.mkscripts
rename {embed => applets_sh}/nologin (100%)
create mode 100644 util-linux/nologin.c
diff --git a/.gitignore b/.gitignore
index c03c2e8a6..becd9bf6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,3 +56,8 @@ cscope.po.out
#
tags
TAGS
+
+#
+# user-supplied scripts
+#
+/embed
diff --git a/applets/busybox.mkscripts b/applets/busybox.mkscripts
new file mode 100755
index 000000000..935685cba
--- /dev/null
+++ b/applets/busybox.mkscripts
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Make busybox scripted applet list file.
+
+# input $1: full path to Config.h
+# input $2: full path to applets.h
+# output (stdout): list of pathnames that should be linked to busybox
+
+export LC_ALL=POSIX
+export LC_CTYPE=POSIX
+
+CONFIG_H=${1:-include/autoconf.h}
+APPLETS_H=${2:-include/applets.h}
+$HOSTCC -E -DMAKE_SCRIPTS -include $CONFIG_H $APPLETS_H |
+ awk '/^[ \t]*SCRIPT/{
+ print $2
+ }'
diff --git a/embed/nologin b/applets_sh/nologin
similarity index 100%
rename from embed/nologin
rename to applets_sh/nologin
diff --git a/include/applets.src.h b/include/applets.src.h
index 2ddf120ad..161a97ee8 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -27,36 +27,49 @@ s - suid type:
# define APPLET_ODDNAME(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
# define APPLET_NOEXEC(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
# define APPLET_NOFORK(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+# define APPLET_SCRIPTED(name,main,l,s,help)
#elif defined(NAME_MAIN)
# define APPLET(name,l,s) name name##_main
# define APPLET_ODDNAME(name,main,l,s,help) name main##_main
# define APPLET_NOEXEC(name,main,l,s,help) name main##_main
# define APPLET_NOFORK(name,main,l,s,help) name main##_main
+# define APPLET_SCRIPTED(name,main,l,s,help) name scripted_main
#elif defined(MAKE_USAGE) && ENABLE_FEATURE_VERBOSE_USAGE
# define APPLET(name,l,s) MAKE_USAGE(#name, name##_trivial_usage name##_full_usage)
# define APPLET_ODDNAME(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage)
# define APPLET_NOEXEC(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage)
# define APPLET_NOFORK(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage)
+# define APPLET_SCRIPTED(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage)
#elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE
# define APPLET(name,l,s) MAKE_USAGE(#name, name##_trivial_usage)
# define APPLET_ODDNAME(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage)
# define APPLET_NOEXEC(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage)
# define APPLET_NOFORK(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage)
+# define APPLET_SCRIPTED(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage)
#elif defined(MAKE_LINKS)
# define APPLET(name,l,c) LINK l name
# define APPLET_ODDNAME(name,main,l,s,help) LINK l name
# define APPLET_NOEXEC(name,main,l,s,help) LINK l name
# define APPLET_NOFORK(name,main,l,s,help) LINK l name
+# define APPLET_SCRIPTED(name,main,l,s,help) LINK l name
#elif defined(MAKE_SUID)
# define APPLET(name,l,s) SUID s l name
# define APPLET_ODDNAME(name,main,l,s,help) SUID s l name
# define APPLET_NOEXEC(name,main,l,s,help) SUID s l name
# define APPLET_NOFORK(name,main,l,s,help) SUID s l name
+# define APPLET_SCRIPTED(name,main,l,s,help) SUID s l name
+
+#elif defined(MAKE_SCRIPTS)
+# define APPLET(name,l,s)
+# define APPLET_ODDNAME(name,main,l,s,help)
+# define APPLET_NOEXEC(name,main,l,s,help)
+# define APPLET_NOFORK(name,main,l,s,help)
+# define APPLET_SCRIPTED(name,main,l,s,help) SCRIPT name
#else
static struct bb_applet applets[] = { /* name, main, location, need_suid */
@@ -64,6 +77,7 @@ s - suid type:
# define APPLET_ODDNAME(name,main,l,s,help) { #name, #main, l, s },
# define APPLET_NOEXEC(name,main,l,s,help) { #name, #main, l, s, 1 },
# define APPLET_NOFORK(name,main,l,s,help) { #name, #main, l, s, 1, 1 },
+# define APPLET_SCRIPTED(name,main,l,s,help) { #name, #main, l, 0, 1, 1 },
#endif
#if ENABLE_INSTALL_NO_USR
@@ -84,3 +98,4 @@ INSERT
#undef APPLET_ODDNAME
#undef APPLET_NOEXEC
#undef APPLET_NOFORK
+#undef APPLET_SCRIPTED
diff --git a/include/libbb.h b/include/libbb.h
index a32608ebd..3fcff421b 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1324,6 +1324,7 @@ void bb_logenv_override(void) FAST_FUNC;
/* Embedded script support */
int find_script_by_name(const char *name) FAST_FUNC;
char *get_script_content(unsigned n) FAST_FUNC;
+int scripted_main(int argc UNUSED_PARAM, char** argv) FAST_FUNC;
/* Applets which are useful from another applets */
int bb_cat(char** argv) FAST_FUNC;
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 6dfaf1f41..7cc98a6aa 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -55,6 +55,7 @@
# include "embedded_scripts.h"
#else
# define NUM_SCRIPTS 0
+# define NUM_EMBEDDED_SCRIPTS 0
#endif
#if NUM_SCRIPTS > 0
# include "bb_archive.h"
@@ -754,6 +755,14 @@ static void install_links(const char *busybox UNUSED_PARAM,
}
# endif
+int FAST_FUNC scripted_main(int argc UNUSED_PARAM, char **argv)
+{
+ int script = find_script_by_name(applet_name);
+ if (script >= 0)
+ exit(ash_main(-script - 1, argv));
+ return 0;
+}
+
static void run_applet_and_exit(const char *name, char **argv) NORETURN;
# if ENABLE_BUSYBOX
@@ -815,30 +824,24 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
"Currently defined functions:\n"
);
col = 0;
+ a = applet_names;
/* prevent last comma to be in the very last pos */
output_width--;
- a = applet_names;
- {
-# if NUM_SCRIPTS > 0
- int i;
- for (i = 0; i < 2; i++, a = script_names)
-# endif
- while (*a) {
- int len2 = strlen(a) + 2;
- if (col >= (int)output_width - len2) {
- full_write2_str(",\n");
- col = 0;
- }
- if (col == 0) {
- col = 6;
- full_write2_str("\t");
- } else {
- full_write2_str(", ");
- }
- full_write2_str(a);
- col += len2;
- a += len2 - 1;
+ while (*a) {
+ int len2 = strlen(a) + 2;
+ if (col >= (int)output_width - len2) {
+ full_write2_str(",\n");
+ col = 0;
+ }
+ if (col == 0) {
+ col = 6;
+ full_write2_str("\t");
+ } else {
+ full_write2_str(", ");
}
+ full_write2_str(a);
+ col += len2;
+ a += len2 - 1;
}
full_write2_str("\n");
return 0;
@@ -993,12 +996,9 @@ 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));
- }
+# if NUM_EMBEDDED_SCRIPTS > 0
+ /* returns if script is not found */
+ scripted_main(0, argv);
# endif
/*bb_error_msg_and_die("applet not found"); - links in printf */
diff --git a/scripts/embedded_scripts b/scripts/embedded_scripts
index 7245ba6e0..2d82ba0b9 100755
--- a/scripts/embedded_scripts
+++ b/scripts/embedded_scripts
@@ -14,21 +14,33 @@ if test $? != 0; then
exit 1
fi
-exec >"$target.$$"
-
-scripts=""
+embedded_scripts=""
if [ -d "$loc" ]
then
- scripts=$(cd $loc; ls * 2>/dev/null)
+ embedded_scripts=$(cd $loc; ls * 2>/dev/null)
fi
+applet_scripts=$(applets/busybox.mkscripts)
+
+for i in $applet_scripts
+do
+ if [ ! -f applets_sh/$i ]
+ then
+ echo "missing applet script $i"
+ exit 1
+ fi
+done
+
+n=$(echo $embedded_scripts $applet_scripts | wc -w)
+num_escripts=$(echo $embedded_scripts | wc -w)
+num_ascripts=$(echo $applet_scripts | wc -w)
-n=$(echo $scripts | wc -w)
+exec >"$target.$$"
if [ $n -ne 0 ]
then
printf '#ifdef DEFINE_script_names\n'
printf 'const char script_names[] ALIGN1 = '
- for i in $scripts
+ for i in $embedded_scripts $applet_scripts
do
printf '"%s\\0"' $i
done
@@ -37,23 +49,39 @@ 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"
+printf "#define NUM_EMBEDDED_SCRIPTS $num_escripts\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
+ (
+ for i in $embedded_scripts
+ do
+ cat $loc/$i
+ printf '\000'
+ done
+ for i in $applet_scripts
+ do
+ cat applets_sh/$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 \
+ (
+ for i in $embedded_scripts
+ do
+ cat $loc/$i
+ printf '\000'
+ done
+ for i in $applet_scripts
+ do
+ cat applets_sh/$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' \
diff --git a/shell/ash.c b/shell/ash.c
index 88f2b5bd6..26ae38755 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -157,6 +157,9 @@
//config: binary. The scripts should be placed in the 'embed' directory
//config: at build time. Like applets, scripts can be run as
//config: 'busybox SCRIPT ...' or by linking their name to the binary.
+//config: This also allows applets to be implemented as scripts: place
+//config: the script in 'applets_sh' and a stub C file containing
+//config: configuration in the appropriate subsystem directory.
//config:
//config:endif # ash options
@@ -14052,11 +14055,11 @@ procargs(char **argv)
int login_sh;
xargv = argv;
+ login_sh = xargv[0] && xargv[0][0] == '-';
#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++;
@@ -14164,7 +14167,11 @@ extern int etext();
* is used to figure out how far we had gotten.
*/
int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+#if NUM_SCRIPTS > 0
+int ash_main(int argc, char **argv)
+#else
int ash_main(int argc UNUSED_PARAM, char **argv)
+#endif
/* note: 'argc' is used only if embedded scripts are enabled */
{
volatile smallint state;
diff --git a/util-linux/nologin.c b/util-linux/nologin.c
new file mode 100644
index 000000000..afa044984
--- /dev/null
+++ b/util-linux/nologin.c
@@ -0,0 +1,15 @@
+//config:config NOLOGIN
+//config: bool "nologin"
+//config: default y
+//config: depends on ASH_EMBEDDED_SCRIPTS
+//config: help
+//config: politely refuse a login
+
+//applet:IF_NOLOGIN(APPLET_SCRIPTED(nologin, scripted, BB_DIR_USR_SBIN, BB_SUID_DROP, nologin))
+
+//kbuild:lib-$(CONFIG_NOLOGIN) += nologin.o
+
+//usage:#define nologin_trivial_usage
+//usage: ""
+//usage:#define nologin_full_usage "\n\n"
+//usage: "Display a message that an account is not available and exit non-zero."
--
2.19.1
More information about the busybox
mailing list