File 6041-Add-the-os_cmd_shell-kernel-config-parameter-to-poin.patch of Package erlang

From 66fac5cbab8a9ff4528e70adff8c6cd0e867624f Mon Sep 17 00:00:00 2001
From: Yaroslav Maslennikov <ymaslenn@cisco.com>
Date: Tue, 22 Oct 2024 12:52:48 +0200
Subject: [PATCH 1/3] Add the os_cmd_shell kernel config parameter to point to
 system shell for os:cmd/2

Initialize the parameter at startup

Fix the test - restore the old shell after the test
Add initialization to other tests that use os:cmd/2
Update os:cmd/2 description
---
 lib/kernel/doc/kernel_app.md               |  4 ++
 lib/kernel/src/kernel.erl                  |  1 +
 lib/kernel/src/os.erl                      | 70 ++++++++++++++--------
 lib/kernel/test/os_SUITE.erl               | 34 ++++++++++-
 lib/kernel/test/os_SUITE_data/Makefile.src |  8 ++-
 lib/kernel/test/os_SUITE_data/sys_shell.c  |  6 ++
 6 files changed, 95 insertions(+), 28 deletions(-)
 create mode 100644 lib/kernel/test/os_SUITE_data/sys_shell.c

diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index 4984a350ab..0428b911de 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -623,6 +623,11 @@ MaxT = NetTickTime + NetTickTime / NetTi
 	</p>
 
       </item>
+      <tag><marker id="os_cmd_shell"/><c>os_cmd_shell =  string()</c></tag>
+      <item>
+        <p>Specifies which shell to use when invoking system commands via `os:cmd/2`.
+          By default the shell is detected automatically.</p>
+      </item>
     </taglist>
   </section>
 
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index 021676c33e..f53f3b1071 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -33,6 +33,7 @@
 start(_, []) ->
     %% Setup the logger and configure the kernel logger environment
     ok = logger:internal_init_logger(),
+    ok = os:internal_init_cmd_shell(),
     case supervisor:start_link({local, kernel_sup}, kernel, []) of
 	{ok, Pid} ->
             ok = erl_signal_handler:start(),
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index adb31bd678..3f0895167a 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -37,6 +37,8 @@ a program to run on most platforms.
 
 -export([type/0, version/0, cmd/1, cmd/2, find_executable/1, find_executable/2]).
 
+-export([internal_init_cmd_shell/0]).
+
 -include("file.hrl").
 
 -export_type([env_var_name/0, env_var_value/0, env_var_name_value/0]).
@@ -581,35 +587,14 @@ get_option(Opt, Options, Default) ->
         _ -> throw(badopt)
     end.
 
-mk_cmd({win32,Wtype}, Cmd) ->
-    Command = case {os:getenv("COMSPEC"),Wtype} of
-                  {false,windows} -> lists:concat(["command.com /c", Cmd]);
-                  {false,_} -> lists:concat(["cmd /c", Cmd]);
-                  {Cspec,_} -> lists:concat([Cspec," /c",Cmd])
-              end,
+mk_cmd({win32,_}, Cmd) ->
+    {ok, Shell} = application:get_env(kernel, os_cmd_shell),
+    Command = lists:concat([Shell, " /c", Cmd]),
     {Command, [], [], <<>>};
 mk_cmd(_,Cmd) ->
     %% Have to send command in like this in order to make sh commands like
     %% cd and ulimit available.
-    %%
-    %% We use an absolute path here because we do not want the path to be
-    %% searched in case a stale NFS handle is somewhere in the path before
-    %% the sh command.
-    %%
-    %% Check if the default shell is located in /bin/sh as expected usually
-    %% or in /system/bin/sh as implemented on Android. The raw option is
-    %% used to bypass the file server and speed up the file access.
-    Shell = case file:read_file_info("/bin/sh",[raw]) of
-                {ok,#file_info{type=regular}} ->
-                    "/bin/sh";
-                _ ->
-                    case file:read_file_info("/system/bin/sh",[raw]) of
-                        {ok,#file_info{type=regular}} ->
-                            "/system/bin/sh";
-                        _ ->
-                            "/bin/sh"
-                    end
-            end,
+    {ok, Shell} = application:get_env(kernel, os_cmd_shell),
     {Shell ++ " -s unix:cmd", [out],
      %% We insert a new line after the command, in case the command
      %% contains a comment character.
@@ -628,6 +613,40 @@ mk_cmd(_,Cmd) ->
      ["(", unicode:characters_to_binary(Cmd), "\n) </dev/null; echo \"\^D\"\n"],
      <<$\^D>>}.
 
+internal_init_cmd_shell() ->
+    case application:get_env(kernel, os_cmd_shell) of
+        undefined ->
+            application:set_env(kernel, os_cmd_shell,
+            internal_init_cmd_shell(os:type()));
+        _ ->
+            ok
+    end.
+internal_init_cmd_shell({win32,Wtype}) ->
+    case {os:getenv("COMSPEC"),Wtype} of
+        {false,windows} -> "command.com";
+        {false,_} -> "cmd";
+        {Cspec,_} -> Cspec
+    end;
+internal_init_cmd_shell(_) ->
+    %% We use an absolute path here because we do not want the path to be
+    %% searched in case a stale NFS handle is somewhere in the path before
+    %% the sh command.
+    %%
+    %% Check if the default shell is located in /bin/sh as expected usually
+    %% or in /system/bin/sh as implemented on Android. The raw option is
+    %% used to bypass the file server.
+    case file:read_file_info("/bin/sh",[raw]) of
+        {ok,#file_info{type=regular}} ->
+            "/bin/sh";
+        _ ->
+            case file:read_file_info("/system/bin/sh",[raw]) of
+                {ok,#file_info{type=regular}} ->
+                    "/system/bin/sh";
+                _ ->
+                    "/bin/sh"
+            end
+    end.
+
 validate(Term) ->
     try validate1(Term)
     catch error:_ -> throw(badarg)
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 6d6ed337a0..8a5691bef7 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -28,7 +28,7 @@
 	 find_executable/1, unix_comment_in_command/1, deep_list_command/1,
          large_output_command/1, background_command/0, background_command/1,
          message_leak/1, close_stdin/0, close_stdin/1, max_size_command/1,
-         perf_counter_api/1, error_info/1]).
+         perf_counter_api/1, error_info/1, os_cmd_shell/1,os_cmd_shell_peer/1]).
 
 -include_lib("common_test/include/ct.hrl").
 
@@ -43,7 +43,7 @@ all() ->
      find_executable, unix_comment_in_command, deep_list_command,
      large_output_command, background_command, message_leak,
      close_stdin, max_size_command, perf_counter_api,
-     error_info].
+     error_info, os_cmd_shell, os_cmd_shell_peer].
 
 groups() ->
     [].
@@ -469,6 +469,36 @@ error_info(Config) ->
         ],
     error_info_lib:test_error_info(os, L).
 
+os_cmd_shell(Config) ->
+    DataDir = proplists:get_value(data_dir, Config),
+    SysShell = filename:join(DataDir, "sys_shell"),
+
+    {ok, OldShell} = application:get_env(kernel, os_cmd_shell),
+    try
+        application:set_env(kernel, os_cmd_shell, SysShell),
+
+        %% os:cmd should not try to detect the shell location rather than use
+        %% the value from kernel:os_cmd_shell parameter
+        comp("sys_shell", os:cmd("ls"))
+    after
+        application:set_env(kernel, os_cmd_shell, OldShell)
+    end.
+
+os_cmd_shell_peer(Config) ->
+    DataDir = proplists:get_value(data_dir, Config),
+    SysShell = "\"" ++ filename:join(DataDir, "sys_shell") ++ "\"",
+    {ok, Peer, Node} = ?CT_PEER(["-kernel","os_cmd_shell", SysShell]),
+    try erpc:call(Node, os, cmd, ["ls"], rtnode:timeout(normal)) of
+        "sys_shell" -> ok;
+        Other -> ct:fail({unexpected, Other})
+    catch
+        C:R:Stk ->
+            io:format("~p\n~p\n~p\n", [C,R,Stk]),
+            ct:fail(failed)
+    after
+        peer:stop(Peer)
+    end.
+
 no_limit_for_opened_files() ->
     case os:type() of
         {unix, freebsd} ->
diff --git a/lib/kernel/test/os_SUITE_data/Makefile.src b/lib/kernel/test/os_SUITE_data/Makefile.src
index f83f781411..2141b320bb 100644
--- a/lib/kernel/test/os_SUITE_data/Makefile.src
+++ b/lib/kernel/test/os_SUITE_data/Makefile.src
@@ -3,7 +3,7 @@ LD = @LD@
 CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@
 CROSSLDFLAGS = @CROSSLDFLAGS@
 
-PROGS = my_echo@exe@ my_fds@exe@
+PROGS = my_echo@exe@ my_fds@exe@ sys_shell@exe@
 
 all: $(PROGS)
 
@@ -18,3 +18,9 @@ my_fds@exe@: my_fds@obj@
 
 my_fds@obj@: my_fds.c
 	$(CC) -c -o my_fds@obj@ $(CFLAGS) my_fds.c
+
+sys_shell@exe@: sys_shell@obj@
+	$(LD) $(CROSSLDFLAGS) -o sys_shell sys_shell@obj@ @LIBS@
+
+sys_shell@obj@: sys_shell.c
+	$(CC) -c -o sys_shell@obj@ $(CFLAGS) sys_shell.c
diff --git a/lib/kernel/test/os_SUITE_data/sys_shell.c b/lib/kernel/test/os_SUITE_data/sys_shell.c
new file mode 100644
index 0000000000..73a8c03450
--- /dev/null
+++ b/lib/kernel/test/os_SUITE_data/sys_shell.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+int main(void)
+{
+    printf("sys_shell");
+    return 0;
+}
-- 
2.43.0

openSUSE Build Service is sponsored by