File 0861-Support-long-PATH-values-in-erlexec.patch of Package erlang
From 3c11286c800029d9d71493832e516ea576cd5d6a Mon Sep 17 00:00:00 2001
From: Rin Kuryloski <rin.kuryloski@mechanical-orchard.com>
Date: Wed, 22 Jan 2025 11:49:59 +0100
Subject: [PATCH 1/6] Support long PATH values in erlexec
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Previously a finite 10240 buffer was used. Long paths can fail
semi-silently, while long paths that already contain the erlang bindir
at the end can cause a crash.
Co-authored-by: Eric Meadows-Jönsson <eric.meadows.jonsson@mechanical-orchard.com>
---
erts/etc/common/erlexec.c | 46 +++++++++++++-------
erts/test/erlexec_SUITE.erl | 86 ++++++++++++++++++++++---------------
2 files changed, 83 insertions(+), 49 deletions(-)
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index ef29181f6b..aecfe2cac1 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -555,37 +555,53 @@ int main(int argc, char **argv)
if (s == NULL) {
erts_snprintf(tmpStr, sizeof(tmpStr),
"%s" PATHSEP "%s" DIRSEP "bin" PATHSEP, bindir, rootdir);
+ set_env("PATH", tmpStr);
} else if (strstr(s, rootdir) == NULL) {
erts_snprintf(tmpStr, sizeof(tmpStr),
"%s" PATHSEP "%s" DIRSEP "bin" PATHSEP "%s", bindir, rootdir, s);
+ set_env("PATH", tmpStr);
} else {
- const char *bindir_slug, *bindir_slug_index;
- int bindir_slug_length;
+ char *pathBuf = NULL;
+ int pathBufLen = 0;
+
+ char *sep_index;
+ int sep_length = strlen(PATHSEP);
+ int bindir_length = strlen(bindir);
const char *in_index;
char *out_index;
- erts_snprintf(tmpStr, sizeof(tmpStr), "%s" PATHSEP, bindir);
+ pathBufLen = strlen(s) + strlen(bindir) + strlen(PATHSEP);
+ pathBuf = emalloc(pathBufLen);
- bindir_slug = strsave(tmpStr);
- bindir_slug_length = strlen(bindir_slug);
+ strcpy(pathBuf, bindir);
- out_index = &tmpStr[bindir_slug_length];
+ out_index = &pathBuf[bindir_length];
in_index = s;
- while ((bindir_slug_index = strstr(in_index, bindir_slug))) {
- int block_length = (bindir_slug_index - in_index);
+ while ((sep_index = strstr(in_index, PATHSEP))) {
+ int elem_length = (sep_index - in_index);
- memcpy(out_index, in_index, block_length);
+ if (bindir_length != elem_length ||
+ 0 != strncmp(in_index, bindir, elem_length)) {
+ strcpy(out_index, PATHSEP);
+ out_index += sep_length;
+ memcpy(out_index, in_index, elem_length);
+ out_index += elem_length;
+ }
- in_index = bindir_slug_index + bindir_slug_length;
- out_index += block_length;
+ in_index = sep_index + sep_length;
}
- efree((void*)bindir_slug);
- strcpy(out_index, in_index);
- }
+ if (0 != strcmp(in_index, bindir)) {
+ strcpy(out_index, PATHSEP);
+ out_index += sep_length;
+ strcpy(out_index, in_index);
+ }
+
+ set_env("PATH", pathBuf);
+ efree(pathBuf);
+ }
free_env_val(s);
- set_env("PATH", tmpStr);
i = 1;
diff --git a/erts/test/erlexec_SUITE.erl b/erts/test/erlexec_SUITE.erl
index ab2439be09..18ec4e2d37 100644
--- a/erts/test/erlexec_SUITE.erl
+++ b/erts/test/erlexec_SUITE.erl
@@ -32,7 +32,7 @@
-export([args_file/1, evil_args_file/1, missing_args_file/1, env/1, args_file_env/1,
otp_7461/1, otp_7461_remote/1, argument_separation/1, argument_with_option/1,
- zdbbl_dist_buf_busy_limit/1]).
+ zdbbl_dist_buf_busy_limit/1, long_path_env/1]).
-include_lib("common_test/include/ct.hrl").
@@ -40,9 +40,10 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {minutes, 1}}].
-all() ->
+all() ->
[args_file, evil_args_file, missing_args_file, env, args_file_env,
- otp_7461, argument_separation, argument_with_option, zdbbl_dist_buf_busy_limit].
+ otp_7461, argument_separation, argument_with_option, zdbbl_dist_buf_busy_limit,
+ long_path_env].
init_per_suite(Config) ->
[{suite_erl_flags, save_env()} | Config].
@@ -108,9 +109,9 @@ loop_ping(_,0) ->
loop_ping(Node,N) ->
case net_adm:ping(Node) of
pang ->
- receive
+ receive
after 500 ->
- ok
+ ok
end,
loop_ping(Node, N-1);
pong ->
@@ -147,7 +148,7 @@ argument_with_option(Config) when is_list(Config) ->
ok
end
end,
-
+
[begin
MissingCheck(CmdLine,"-",""),
@@ -172,7 +173,7 @@ argument_with_option(Config) when is_list(Config) ->
end || CmdLine <- EmuSingle],
ErlDouble = ["env"],
-
+
[begin
MissingCheck(CmdLine,"-",""),
MissingCheck(CmdLine,"-"," a"),
@@ -354,16 +355,16 @@ args_file_env(Config) when is_list(Config) ->
ok.
%% Make sure "erl -detached" survives when parent process group gets killed
-otp_7461(Config) when is_list(Config) ->
+otp_7461(Config) when is_list(Config) ->
case os:type() of
{unix,_} ->
{NetStarted, _} = net_kernel:start([test_server, shortnames]),
try
net_kernel:monitor_nodes(true),
- register(otp_7461, self()),
+ register(otp_7461, self()),
- otp_7461_do(Config)
- after
+ otp_7461_do(Config)
+ after
catch unregister(otp_7461),
catch net_kernel:monitor_nodes(false),
case NetStarted of
@@ -374,7 +375,7 @@ otp_7461(Config) when is_list(Config) ->
_ ->
{skip,"Only on Unix."}
end.
-
+
otp_7461_do(Config) ->
io:format("alive=~p node=~p\n",[is_alive(), node()]),
TestProg = filename:join([proplists:get_value(data_dir, Config), "erlexec_tests"]),
@@ -384,32 +385,32 @@ otp_7461_do(Config) ->
" -setcookie " ++ atom_to_list(erlang:get_cookie()) ++
" -pa " ++ filename:dirname(code:which(?MODULE)) ++
" -s erlexec_SUITE otp_7461_remote init " ++ atom_to_list(node()),
-
+
%% otp_7461 --------> erlexec_tests.c --------> cerl -detached
%% open_port fork+exec
-
+
io:format("spawn port prog ~p\n",[Cmd]),
Port = open_port({spawn, Cmd}, [eof]),
-
- io:format("Wait for node to connect...\n",[]),
+
+ io:format("Wait for node to connect...\n",[]),
{nodeup, Slave} = receive Msg -> Msg
after 20*1000 -> timeout end,
io:format("Node alive: ~p\n", [Slave]),
-
+
pong = net_adm:ping(Slave),
io:format("Ping ok towards ~p\n", [Slave]),
-
+
Port ! { self(), {command, "K"}}, % Kill child process group
{Port, {data, "K"}} = receive Msg2 -> Msg2 end,
port_close(Port),
-
+
%% Now the actual test. Detached node should still be alive.
pong = net_adm:ping(Slave),
io:format("Ping still ok towards ~p\n", [Slave]),
-
+
%% Halt node
rpc:cast(Slave, ?MODULE, otp_7461_remote, [[halt, self()]]),
-
+
{nodedown, Slave} = receive
Msg3 -> Msg3
after 20*1000 -> timeout
@@ -417,7 +418,7 @@ otp_7461_do(Config) ->
io:format("Node dead: ~p\n", [Slave]),
ok.
-
+
%% Executed on slave node
otp_7461_remote([init, Master]) ->
io:format("otp_7461_remote(init,~p) at ~p\n",[Master, node()]),
@@ -442,7 +443,22 @@ zdbbl_dist_buf_busy_limit(Config) when is_list(Config) ->
LimB = rpc:call(SName,erlang,system_info,[dist_buf_busy_limit]),
ok = cleanup_node(SNameS, 10),
ok.
-
+
+long_path_env(Config) when is_list(Config) ->
+ OriginalPath = os:getenv("PATH"),
+ [BinPath, _RestPath] = string:split(OriginalPath, ":"),
+ LongPath = lists:duplicate(10240, "x"),
+ TestPath = OriginalPath ++ ":" ++ LongPath ++ ":" ++ BinPath,
+ AssertPath = OriginalPath ++ ":" ++ LongPath,
+ os:putenv("PATH", TestPath),
+
+ {ok, [[PName]]} = init:get_argument(progname),
+ Cmd = PName ++ " -noshell -eval 'io:format(\"~ts\", [os:getenv(\"PATH\")]),erlang:halt()'",
+ Output = os:cmd(Cmd),
+
+ true = string:equal(AssertPath, Output),
+ ok.
+
%%
%% Utils
@@ -452,29 +468,31 @@ save_env() ->
{erl_flags,
os:getenv("ERL_AFLAGS"),
os:getenv("ERL_FLAGS"),
- os:getenv("ERL_"++erlang:system_info(otp_release)++"_FLAGS"),
- os:getenv("ERL_ZFLAGS")}.
+ os:getenv("ERL_" ++ erlang:system_info(otp_release) ++ "_FLAGS"),
+ os:getenv("ERL_ZFLAGS"),
+ os:getenv("PATH")}.
restore_env(EVar, false) when is_list(EVar) ->
restore_env(EVar, "");
restore_env(EVar, "") when is_list(EVar) ->
case os:getenv(EVar) of
- false -> ok;
- "" -> ok;
- " " -> ok;
- _ -> os:putenv(EVar, " ")
+ false -> ok;
+ "" -> ok;
+ " " -> ok;
+ _ -> os:putenv(EVar, " ")
end;
restore_env(EVar, Value) when is_list(EVar), is_list(Value) ->
case os:getenv(EVar) of
- Value -> ok;
- _ -> os:putenv(EVar, Value)
+ Value -> ok;
+ _ -> os:putenv(EVar, Value)
end.
-restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs}) ->
+restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs, Path}) ->
restore_env("ERL_AFLAGS", AFlgs),
restore_env("ERL_FLAGS", Flgs),
- restore_env("ERL_"++erlang:system_info(otp_release)++"_FLAGS", RFlgs),
+ restore_env("ERL_"++erlang:system_info(otp_release) ++ "_FLAGS", RFlgs),
restore_env("ERL_ZFLAGS", ZFlgs),
+ restore_env("PATH", Path),
ok.
privfile(Name, Config) ->
@@ -544,7 +562,7 @@ split_emu_clt([A|As], Emu, Misc, Extra, misc = Type) ->
split_emu_clt([A|As], Emu, Misc, Extra, extra = Type) ->
split_emu_clt(As, Emu, Misc, [A|Extra], Type).
-
+
get_nodename(T) ->
atom_to_list(T)
--
2.43.0