1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2007-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%%%------------------------------------------------------------------- 22%%% File : erlexec_SUITE.erl 23%%% Author : Rickard Green <rickard.s.green@ericsson.com> 24%%% Description : Test erlexec's command line parsing 25%%% 26%%% Created : 22 May 2007 by Rickard Green <rickard.s.green@ericsson.com> 27%%%------------------------------------------------------------------- 28-module(erlexec_SUITE). 29 30-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]). 31 32-export([args_file/1, evil_args_file/1, env/1, args_file_env/1, 33 otp_7461/1, otp_7461_remote/1, argument_separation/1, 34 zdbbl_dist_buf_busy_limit/1]). 35 36-include_lib("common_test/include/ct.hrl"). 37 38init_per_testcase(Case, Config) -> 39 SavedEnv = save_env(), 40 [{testcase, Case},{erl_flags_env, SavedEnv}|Config]. 41 42end_per_testcase(_Case, Config) -> 43 SavedEnv = proplists:get_value(erl_flags_env, Config), 44 restore_env(SavedEnv), 45 cleanup_nodes(), 46 ok. 47 48suite() -> 49 [{ct_hooks,[ts_install_cth]}, 50 {timetrap, {minutes, 1}}]. 51 52all() -> 53 [args_file, evil_args_file, env, args_file_env, 54 otp_7461, argument_separation, zdbbl_dist_buf_busy_limit]. 55 56%% Test that plain first argument does not 57%% destroy -home switch [OTP-8209] or interact with environments 58argument_separation(Config) when is_list(Config) -> 59 {ok,[[PName]]} = init:get_argument(progname), 60 SNameS = "erlexec_test_01", 61 SName = list_to_atom(SNameS++"@"++ 62 hd(tl(string:lexemes(atom_to_list(node()),"@")))), 63 Cmd = PName ++ " cmd_param -sname "++SNameS++" -setcookie "++ 64 atom_to_list(erlang:get_cookie()) ++ " -cmd_test", 65 open_port({spawn,Cmd},[{env,[{"ERL_AFLAGS","-atest"}, 66 {"ERL_FLAGS","env_param -test"}, 67 {"ERL_ZFLAGS","zenv_param"}]}]), 68 pong = loop_ping(SName,40), 69 ct:log("emu_args: ~p",[rpc:call(SName,erlang,system_info,[emu_args])]), 70 {ok,[[_]]} = rpc:call(SName,init,get_argument,[home]), 71 {ok,[[]]} = rpc:call(SName,init,get_argument,[atest]), 72 {ok,[[]]} = rpc:call(SName,init,get_argument,[cmd_test]), 73 {ok,[[]]} = rpc:call(SName,init,get_argument,[test]), 74 error = rpc:call(SName,init,get_argument,[unkown]), 75 ["cmd_param","env_param","zenv_param"] = rpc:call(SName,init,get_plain_arguments,[]), 76 ok = cleanup_nodes(), 77 ok. 78 79cleanup_nodes() -> 80 cleanup_node("erlexec_test_01",20). 81cleanup_node(SNameS,0) -> 82 {error, {would_not_die,list_to_atom(SNameS)}}; 83cleanup_node(SNameS,N) -> 84 SName = list_to_atom(SNameS++"@"++ 85 hd(tl(string:lexemes(atom_to_list(node()),"@")))), 86 case rpc:call(SName,init,stop,[]) of 87 {badrpc,_} -> 88 ok; 89 ok -> 90 receive after 500 -> ok end, 91 cleanup_node(SNameS,N-1) 92 end. 93 94loop_ping(_,0) -> 95 flush(), 96 pang; 97loop_ping(Node,N) -> 98 case net_adm:ping(Node) of 99 pang -> 100 receive 101 after 500 -> 102 ok 103 end, 104 loop_ping(Node, N-1); 105 pong -> 106 pong 107 end. 108 109flush() -> 110 receive M -> 111 ct:pal("~p",[M]), 112 flush() 113 after 10 -> 114 ok 115 end. 116 117args_file(Config) when is_list(Config) -> 118 AFN1 = privfile("1", Config), 119 AFN2 = privfile("2", Config), 120 AFN3 = privfile("3", Config), 121 AFN4 = privfile("4", Config), 122 AFN5 = privfile("5", Config), 123 AFN6 = privfile("6", Config), 124 write_file(AFN1, "-MiscArg2~n" 125 "# a comment +\\#1000~n" 126 "+\\#200 # another comment~n" 127 "~n" 128 "# another config file to read~n" 129 " -args_file ~s#acomment~n" 130 "~n" 131 "-MiscArg7~n" 132 "#~n" 133 "+\\#700~n" 134 "-extra +XtraArg6~n", 135 [AFN2]), 136 write_file(AFN2, 137 "-MiscArg3~n" 138 "+\\#300~n" 139 "-args_file ~s~n" 140 "-MiscArg5~n" 141 "+\\#500#anothercomment -MiscArg10~n" 142 "-args_file ~s~n" 143 "-args_file ~s~n" 144 "-args_file ~s~n" 145 "-extra +XtraArg5~n", 146 [AFN3, AFN4, AFN5, AFN6]), 147 write_file(AFN3, 148 "# comment again~n" 149 " -MiscArg4 +\\#400 -extra +XtraArg1"), 150 write_file(AFN4, 151 " -MiscArg6 +\\#600 -extra +XtraArg2~n" 152 "+XtraArg3~n" 153 "+XtraArg4~n" 154 "# comment again~n"), 155 write_file(AFN5, ""), 156 write_file(AFN6, "-extra # +XtraArg10~n"), 157 CmdLine = "+#100 -MiscArg1 " 158 ++ "-args_file " ++ AFN1 159 ++ " +#800 -MiscArg8 -extra +XtraArg7 +XtraArg8", 160 {Emu, Misc, Extra} = emu_args(CmdLine), 161 verify_args(["-#100", "-#200", "-#300", "-#400", 162 "-#500", "-#600", "-#700", "-#800"], Emu), 163 verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", 164 "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"], 165 Misc), 166 verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 167 "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], 168 Extra), 169 verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", 170 "-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", 171 "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8", 172 "+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 173 "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], 174 Emu), 175 verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", 176 "-#100", "-#200", "-#300", "-#400", 177 "-#500", "-#600", "-#700", "-#800", 178 "+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 179 "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], 180 Misc), 181 verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", 182 "-#100", "-#200", "-#300", "-#400", 183 "-#500", "-#600", "-#700", "-#800", 184 "-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", 185 "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"], 186 Extra), 187 ok. 188 189evil_args_file(Config) when is_list(Config) -> 190 Lim = 300, 191 FNums = lists:seq(1, Lim), 192 lists:foreach(fun (End) when End == Lim -> 193 AFN = privfile(integer_to_list(End), Config), 194 write_file(AFN, 195 "-MiscArg~p ", 196 [End]); 197 (I) -> 198 AFNX = privfile(integer_to_list(I), Config), 199 AFNY = privfile(integer_to_list(I+1), Config), 200 {Frmt, Args} = 201 case I rem 2 of 202 0 -> 203 {"-MiscArg~p -args_file ~s -MiscArg~p", 204 [I, AFNY, I]}; 205 _ -> 206 {"-MiscArg~p -args_file ~s", 207 [I, AFNY]} 208 end, 209 write_file(AFNX, Frmt, Args) 210 end, 211 FNums), 212 {_Emu, Misc, _Extra} = emu_args("-args_file " 213 ++ privfile("1", Config)), 214 ANums = FNums 215 ++ lists:reverse(lists:filter(fun (I) when I == Lim -> false; 216 (I) when I rem 2 == 0 -> true; 217 (_) -> false 218 end, FNums)), 219 verify_args(lists:map(fun (I) -> "-MiscArg"++integer_to_list(I) end, 220 ANums), 221 Misc), 222 ok. 223 224 225 226env(Config) when is_list(Config) -> 227 os:putenv("ERL_AFLAGS", "-MiscArg1 +#100 -extra +XtraArg1 +XtraArg2"), 228 CmdLine = "+#200 -MiscArg2 -extra +XtraArg3 +XtraArg4", 229 os:putenv("ERL_FLAGS", "-MiscArg3 +#300 -extra +XtraArg5"), 230 os:putenv("ERL_ZFLAGS", "-MiscArg4 +#400 -extra +XtraArg6"), 231 {Emu, Misc, Extra} = emu_args(CmdLine), 232 verify_args(["-#100", "-#200", "-#300", "-#400"], Emu), 233 verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4"], 234 Misc), 235 verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 236 "+XtraArg5", "+XtraArg6"], 237 Extra), 238 ok. 239 240args_file_env(Config) when is_list(Config) -> 241 AFN1 = privfile("1", Config), 242 AFN2 = privfile("2", Config), 243 write_file(AFN1, "-MiscArg2 +\\#200 -extra +XtraArg1"), 244 write_file(AFN2, "-MiscArg3 +\\#400 -extra +XtraArg3"), 245 os:putenv("ERL_AFLAGS", 246 "-MiscArg1 +#100 -args_file "++AFN1++ " -extra +XtraArg2"), 247 CmdLine = "+#300 -args_file "++AFN2++" -MiscArg4 -extra +XtraArg4", 248 os:putenv("ERL_FLAGS", "-MiscArg5 +#500 -extra +XtraArg5"), 249 os:putenv("ERL_ZFLAGS", "-MiscArg6 +#600 -extra +XtraArg6"), 250 {Emu, Misc, Extra} = emu_args(CmdLine), 251 verify_args(["-#100", "-#200", "-#300", "-#400", 252 "-#500", "-#600"], Emu), 253 verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", 254 "-MiscArg5", "-MiscArg6"], 255 Misc), 256 verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 257 "+XtraArg5", "+XtraArg6"], 258 Extra), 259 ok. 260 261%% Make sure "erl -detached" survives when parent process group gets killed 262otp_7461(Config) when is_list(Config) -> 263 case os:type() of 264 {unix,_} -> 265 {NetStarted, _} = net_kernel:start([test_server, shortnames]), 266 try 267 net_kernel:monitor_nodes(true), 268 register(otp_7461, self()), 269 270 otp_7461_do(Config) 271 after 272 catch unregister(otp_7461), 273 catch net_kernel:monitor_nodes(false), 274 case NetStarted of 275 ok -> net_kernel:stop(); 276 _ -> ok 277 end 278 end; 279 _ -> 280 {skip,"Only on Unix."} 281 end. 282 283otp_7461_do(Config) -> 284 io:format("alive=~p node=~p\n",[is_alive(), node()]), 285 TestProg = filename:join([proplists:get_value(data_dir, Config), "erlexec_tests"]), 286 {ok, [[ErlProg]]} = init:get_argument(progname), 287 Cmd = TestProg ++ " " ++ ErlProg ++ 288 " -detached -sname " ++ get_nodename(otp_7461) ++ 289 " -setcookie " ++ atom_to_list(erlang:get_cookie()) ++ 290 " -pa " ++ filename:dirname(code:which(?MODULE)) ++ 291 " -s erlexec_SUITE otp_7461_remote init " ++ atom_to_list(node()), 292 293 %% otp_7461 --------> erlexec_tests.c --------> cerl -detached 294 %% open_port fork+exec 295 296 io:format("spawn port prog ~p\n",[Cmd]), 297 Port = open_port({spawn, Cmd}, [eof]), 298 299 io:format("Wait for node to connect...\n",[]), 300 {nodeup, Slave} = receive Msg -> Msg 301 after 20*1000 -> timeout end, 302 io:format("Node alive: ~p\n", [Slave]), 303 304 pong = net_adm:ping(Slave), 305 io:format("Ping ok towards ~p\n", [Slave]), 306 307 Port ! { self(), {command, "K"}}, % Kill child process group 308 {Port, {data, "K"}} = receive Msg2 -> Msg2 end, 309 port_close(Port), 310 311 %% Now the actual test. Detached node should still be alive. 312 pong = net_adm:ping(Slave), 313 io:format("Ping still ok towards ~p\n", [Slave]), 314 315 %% Halt node 316 rpc:cast(Slave, ?MODULE, otp_7461_remote, [[halt, self()]]), 317 318 {nodedown, Slave} = receive 319 Msg3 -> Msg3 320 after 20*1000 -> timeout 321 end, 322 io:format("Node dead: ~p\n", [Slave]), 323 ok. 324 325 326%% Executed on slave node 327otp_7461_remote([init, Master]) -> 328 io:format("otp_7461_remote(init,~p) at ~p\n",[Master, node()]), 329 net_kernel:connect_node(Master); 330otp_7461_remote([halt, Pid]) -> 331 io:format("halt order from ~p to node ~p\n",[Pid,node()]), 332 halt(). 333 334%% Check +zdbbl flag 335zdbbl_dist_buf_busy_limit(Config) when is_list(Config) -> 336 LimKB = 1122233, 337 LimB = LimKB*1024, 338 {ok,[[PName]]} = init:get_argument(progname), 339 SNameS = "erlexec_test_02", 340 SName = list_to_atom(SNameS++"@"++ 341 hd(tl(string:lexemes(atom_to_list(node()),"@")))), 342 Cmd = PName ++ " -sname "++SNameS++" -setcookie "++ 343 atom_to_list(erlang:get_cookie()) ++ 344 " +zdbbl " ++ integer_to_list(LimKB), 345 open_port({spawn,Cmd},[]), 346 pong = loop_ping(SName,40), 347 LimB = rpc:call(SName,erlang,system_info,[dist_buf_busy_limit]), 348 ok = cleanup_node(SNameS, 10), 349 ok. 350 351 352%% 353%% Utils 354%% 355 356save_env() -> 357 {erl_flags, 358 os:getenv("ERL_AFLAGS"), 359 os:getenv("ERL_FLAGS"), 360 os:getenv("ERL_"++erlang:system_info(otp_release)++"_FLAGS"), 361 os:getenv("ERL_ZFLAGS")}. 362 363restore_env(EVar, false) when is_list(EVar) -> 364 restore_env(EVar, ""); 365restore_env(EVar, "") when is_list(EVar) -> 366 case os:getenv(EVar) of 367 false -> ok; 368 "" -> ok; 369 " " -> ok; 370 _ -> os:putenv(EVar, " ") 371 end; 372restore_env(EVar, Value) when is_list(EVar), is_list(Value) -> 373 case os:getenv(EVar) of 374 Value -> ok; 375 _ -> os:putenv(EVar, Value) 376 end. 377 378restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs}) -> 379 restore_env("ERL_AFLAGS", AFlgs), 380 restore_env("ERL_FLAGS", Flgs), 381 restore_env("ERL_"++erlang:system_info(otp_release)++"_FLAGS", RFlgs), 382 restore_env("ERL_ZFLAGS", ZFlgs), 383 ok. 384 385privfile(Name, Config) -> 386 filename:join([proplists:get_value(priv_dir, Config), 387 atom_to_list(proplists:get_value(testcase, Config)) ++ "." ++ Name]). 388 389write_file(FileName, Frmt) -> 390 write_file(FileName, Frmt, []). 391 392write_file(FileName, Frmt, Args) -> 393 {ok, File} = file:open(FileName, [write]), 394 io:format(File, Frmt, Args), 395 ok = file:close(File). 396 397verify_args([], _Ys) -> 398 ok; 399verify_args(Xs, []) -> 400 exit({args_not_found_in_order, Xs}); 401verify_args([X|Xs], [X|Ys]) -> 402 verify_args(Xs, Ys); 403verify_args(Xs, [_Y|Ys]) -> 404 verify_args(Xs, Ys). 405 406verify_not_args(Xs, Ys) -> 407 lists:foreach(fun (X) -> 408 case lists:member(X, Ys) of 409 true -> exit({arg_present, X}); 410 false -> ok 411 end 412 end, Xs). 413 414emu_args(CmdLineArgs) -> 415 io:format("CmdLineArgs = ~ts~n", [CmdLineArgs]), 416 {ok,[[Erl]]} = init:get_argument(progname), 417 EmuCL = os:cmd(Erl ++ " -emu_args_exit " ++ CmdLineArgs), 418 io:format("EmuCL = ~ts", [EmuCL]), 419 split_emu_clt(string:lexemes(EmuCL, [$ ,$\t,$\n,[$\r,$\n]])). 420 421split_emu_clt(EmuCLT) -> 422 split_emu_clt(EmuCLT, [], [], [], emu). 423 424split_emu_clt([], _Emu, _Misc, _Extra, emu) -> 425 exit(bad_cmd_line); 426split_emu_clt([], Emu, Misc, Extra, _Type) -> 427 {lists:reverse(Emu), lists:reverse(Misc), lists:reverse(Extra)}; 428 429split_emu_clt(["--"|As], Emu, Misc, Extra, emu) -> 430 split_emu_clt(As, Emu, Misc, Extra, misc); 431split_emu_clt([A|As], Emu, Misc, Extra, emu = Type) -> 432 split_emu_clt(As, [A|Emu], Misc, Extra, Type); 433 434split_emu_clt(["-extra"|As], Emu, Misc, Extra, misc) -> 435 split_emu_clt(As, Emu, Misc, Extra, extra); 436split_emu_clt([A|As], Emu, Misc, Extra, misc = Type) -> 437 split_emu_clt(As, Emu, [A|Misc], Extra, Type); 438 439split_emu_clt([A|As], Emu, Misc, Extra, extra = Type) -> 440 split_emu_clt(As, Emu, Misc, [A|Extra], Type). 441 442 443get_nodename(T) -> 444 atom_to_list(T) 445 ++ "-" 446 ++ atom_to_list(?MODULE) 447 ++ "-" 448 ++ integer_to_list(erlang:system_time(seconds)) 449 ++ "-" 450 ++ integer_to_list(erlang:unique_integer([positive])). 451