From cbfa58d56c3ca59538bf23e30105ce27ed5ef948 Mon Sep 17 00:00:00 2001 From: Ron Yorston <rmy@pobox.com> Date: Wed, 4 Sep 2024 12:47:03 +0100 Subject: ash: optimise running of scripts (2) Commit 4b7b4a960 (ash: optimise running of scripts) avoided creation of a process when running a script. There's another case where we can do the same: if the script is being run from a FS_SHELLEXEC shell. - Check the necessary conditions for this to happen. - Allocate two extra slots in the argv array for FS_SHELLEXEC. - Set the index of the script file in the argv array. Without this the test 'pidof this' failed because the command name hadn't been correctly set. Adds 80-96 bytes. --- include/mingw.h | 1 + libbb/appletlib.c | 7 +++++++ shell/ash.c | 26 ++++++++++++++++++-------- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/include/mingw.h b/include/mingw.h index ed7884e39..65940b40b 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -667,3 +667,4 @@ enum { ADMIN_ENABLED = 2 }; int elevation_state(void); +void set_interp(int i) FAST_FUNC; diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 97dfb3df8..1ff7fe6c8 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -394,6 +394,13 @@ bool re_execed; static int interp = 0; char bb_comm[COMM_LEN]; char bb_command_line[128]; + +# if ENABLE_FEATURE_SH_STANDALONE +void FAST_FUNC set_interp(int i) +{ + interp = i; +} +# endif #endif diff --git a/shell/ash.c b/shell/ash.c index 2e4181b3f..d9a7bee83 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9099,6 +9099,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c #endif { #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE + struct forkshell *fs = (struct forkshell *)sticky_mem_start; interp_t interp; #endif #if ENABLE_FEATURE_SH_STANDALONE @@ -9106,7 +9107,6 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c # if ENABLE_PLATFORM_MINGW32 /* Treat all applets as NOEXEC, including the shell itself if * this is a FS_SHELLEXEC shell. */ - struct forkshell *fs = (struct forkshell *)sticky_mem_start; if (applet_main[applet_no] != ash_main || (fs && fs->fpid == FS_SHELLEXEC)) { run_noexec: @@ -9152,21 +9152,28 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c add_win32_extension((char *)cmd); # if ENABLE_FEATURE_SH_STANDALONE - /* If nfpath is non-NULL, evalcommand() has determined this - * command doesn't need a fork(). If the command is a script - * with an interpreter which is an applet we can run it as if - * it were a noexec applet. */ + /* If nfpath is non-NULL evalcommand() has determined this + * command doesn't need a fork(). Even it's NULL we can + * possibly avoid a fork if this is a FS_SHELLEXEC shell. */ + if (nfpath == NULL && (fs && fs->fpid == FS_SHELLEXEC)) + nfpath = pathval(); + + /* If nfpath is non-NULL and the command is a script with an + * interpreter which is an applet, we can run it as if it + * were a noexec applet. */ if (nfpath && parse_interpreter(cmd, &interp)) { applet_no = find_applet_by_name_for_sh(interp.name, nfpath); if (applet_no >= 0) { argv[0] = (char *)cmd; - /* evalcommand() has added two elements before argv */ + /* evalcommand()/spawn_forkshell() add two elements before argv */ if (interp.opts) { argv--; argv[0] = (char *)interp.opts; } argv--; cmd = argv[0] = (char *)interp.name; + /* Identify the index of the script file in argv */ + set_interp(1 + (interp.opts != NULL)); goto run_noexec; } } @@ -16842,7 +16849,8 @@ argv_size(struct datasize ds, char **p) ds.funcstringsize += align_len(*p); p++; } - ds.funcblocksize += sizeof(char *); + // Allow two extra elements for tryexec(). + ds.funcblocksize += 3 * sizeof(char *); } return ds; } @@ -16856,6 +16864,8 @@ argv_copy(char **p) #endif if (p) { + // Allow two extra elements for tryexec(). + funcblock = (char *) funcblock + 2 * sizeof(char *); while (*p) { new = funcblock; funcblock = (char *) funcblock + sizeof(char *); @@ -16866,7 +16876,7 @@ argv_copy(char **p) new = funcblock; funcblock = (char *) funcblock + sizeof(char *); *new = NULL; - return start; + return start + 2; } return NULL; } -- cgit v1.2.3-55-g6feb