aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml17
-rw-r--r--lib/kernel/doc/src/inet.xml28
-rw-r--r--lib/kernel/src/dist_util.erl49
-rw-r--r--lib/kernel/src/inet.erl8
-rw-r--r--lib/kernel/src/inet_int.hrl1
-rw-r--r--lib/kernel/src/kernel.erl244
-rw-r--r--lib/kernel/src/net_kernel.erl38
-rw-r--r--lib/kernel/test/code_SUITE.erl14
-rw-r--r--lib/kernel/test/disk_log_SUITE.erl50
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl99
-rw-r--r--lib/kernel/test/erl_distribution_wb_SUITE.erl6
-rw-r--r--lib/kernel/test/file_name_SUITE.erl2
-rw-r--r--lib/kernel/test/inet_SUITE.erl70
-rw-r--r--lib/kernel/test/pg2_SUITE.erl27
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl47
15 files changed, 512 insertions, 188 deletions
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index e97db20062..bef8096aed 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -140,6 +140,23 @@ do_recv(Sock, Bs) ->
<fsummary>Close a TCP socket.</fsummary>
<desc>
<p>Closes a TCP socket.</p>
+ <p>Note that in most implementations of TCP, doing a <c>close</c> does
+ not guarantee that any data sent is delivered to the recipient before
+ the close is detected at the remote side. If you want to guarantee
+ delivery of the data to the recipient there are two common ways to
+ achieve this.</p>
+ <list type="ordered">
+ <item><p>Use <seealso marker="#shutdown/2">
+ <c>gen_tcp:shutdown(Sock, write)</c></seealso> to signal that
+ no more data is to be sent and wait for the read side of the
+ socket to be closed.</p>
+ </item>
+ <item><p>Use the socket option <seealso marker="inet#packet">
+ <c>{packet, N}</c></seealso> (or something similar) to make
+ it possible for the receiver to close the connection when it
+ knowns it has received all the data.</p>
+ </item>
+ </list>
</desc>
</func>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index d557efb6a8..947e4d4560 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -897,6 +897,32 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
<seealso marker="file#native_name_encoding/0"><c>file:native_name_encoding/0</c></seealso>.</p></item>
</list>
</item>
+ <tag><c>{bind_to_device, Ifname :: binary()}</c></tag>
+ <item>
+ <p>Binds a socket to a specific network interface. This option
+ must be used in a function call that creates a socket, that is,
+ <seealso marker="gen_tcp#connect/3"><c>gen_tcp:connect/3,4</c></seealso>,
+ <seealso marker="gen_tcp#listen/2"><c>gen_tcp:listen/2</c></seealso>,
+ <seealso marker="gen_udp#open/1"><c>gen_udp:open/1,2</c></seealso>, or
+ <seealso marker="gen_sctp#open/0"><c>gen_sctp:open/0,1,2</c></seealso>.</p>
+ <p>Unlike <seealso marker="#getifaddrs/0"><c>getifaddrs/0</c></seealso>, Ifname
+ is encoded a binary. In the unlikely case that a system is using
+ non-7-bit-ASCII characters in network device names, special care
+ has to be taken when encoding this argument.</p>
+ <p>This option uses the Linux-specific socket option
+ <c>SO_BINDTODEVICE</c>, such as in Linux kernel 2.0.30 or later,
+ and therefore only exists when the runtime system
+ is compiled for such an operating system.</p>
+ <p>Before Linux 3.8, this socket option could be set, but could not retrieved
+ with <seealso marker="#getopts/2"><c>getopts/2</c></seealso>. Since Linux 3.8,
+ it is readable.</p>
+ <p>The virtual machine also needs elevated privileges, either
+ running as superuser or (for Linux) having capability
+ <c>CAP_NET_RAW</c>.</p>
+ <p>The primary use case for this option is to bind sockets into
+ <url href="http://www.kernel.org/doc/Documentation/networking/vrf.txt">Linux VRF instances</url>.
+ </p>
+ </item>
<tag><c>list</c></tag>
<item>
<p>Received <c>Packet</c> is delivered as a list.</p>
@@ -913,7 +939,7 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
</item>
<tag><c>{packet, PacketType}</c>(TCP/IP sockets)</tag>
<item>
- <p>Defines the type of packets to use for a socket.
+ <p><marker id="packet"/>Defines the type of packets to use for a socket.
Possible values:</p>
<taglist>
<tag><c>raw | 0</c></tag>
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index 8d2fc4d4b7..d929179715 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -131,7 +131,7 @@ handshake_other_started(#hs_data{request_type=ReqType}=HSData0) ->
other_version=Version,
other_node=Node,
other_started=true},
- check_dflag_xnc(HSData),
+ check_dflags(HSData),
is_allowed(HSData),
?debug({"MD5 connection from ~p (V~p)~n",
[Node, HSData#hs_data.other_version]}),
@@ -168,27 +168,24 @@ is_allowed(#hs_data{other_node = Node,
%% Check that both nodes can handle the same types of extended
%% node containers. If they can not, abort the connection.
%%
-check_dflag_xnc(#hs_data{other_node = Node,
- other_flags = OtherFlags,
- other_started = OtherStarted} = HSData) ->
- XRFlg = ?DFLAG_EXTENDED_REFERENCES,
- XPPFlg = case erlang:system_info(compat_rel) of
- R when R >= 10 ->
- ?DFLAG_EXTENDED_PIDS_PORTS;
- _ ->
- 0
- end,
- ReqXncFlags = XRFlg bor XPPFlg,
- case OtherFlags band ReqXncFlags =:= ReqXncFlags of
- true ->
- ok;
- false ->
- What = case {OtherFlags band XRFlg =:= XRFlg,
- OtherFlags band XPPFlg =:= XPPFlg} of
- {false, false} -> "references, pids and ports";
- {true, false} -> "pids and ports";
- {false, true} -> "references"
- end,
+check_dflags(#hs_data{other_node = Node,
+ other_flags = OtherFlags,
+ other_started = OtherStarted} = HSData) ->
+
+ Mandatory = [{?DFLAG_EXTENDED_REFERENCES, "EXTENDED_REFERENCES"},
+ {?DFLAG_EXTENDED_PIDS_PORTS, "EXTENDED_PIDS_PORTS"},
+ {?DFLAG_UTF8_ATOMS, "UTF8_ATOMS"}],
+ Missing = lists:filtermap(fun({Bit, Str}) ->
+ case Bit band OtherFlags of
+ Bit -> false;
+ 0 -> {true, Str}
+ end
+ end,
+ Mandatory),
+ case Missing of
+ [] ->
+ ok;
+ _ ->
case OtherStarted of
true ->
send_status(HSData, not_allowed),
@@ -199,9 +196,9 @@ check_dflag_xnc(#hs_data{other_node = Node,
How = "aborted"
end,
error_msg("** ~w: Connection attempt ~s node ~w ~s "
- "since it cannot handle extended ~s. "
- "**~n", [node(), Dir, Node, How, What]),
- ?shutdown2(Node, {check_dflag_xnc_failed, What})
+ "since it cannot handle ~p."
+ "**~n", [node(), Dir, Node, How, Missing]),
+ ?shutdown2(Node, {check_dflags_failed, Missing})
end.
@@ -327,7 +324,7 @@ handshake_we_started(#hs_data{request_type=ReqType,
NewHSData = HSData#hs_data{this_flags = ThisFlags,
other_flags = OtherFlags,
other_started = false},
- check_dflag_xnc(NewHSData),
+ check_dflags(NewHSData),
MyChallenge = gen_challenge(),
{MyCookie,HisCookie} = get_cookies(Node),
send_challenge_reply(NewHSData,MyChallenge,
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index f5c13ecdd7..5be790b7d9 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -702,7 +702,7 @@ connect_options() ->
header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
- show_econnreset].
+ show_econnreset, bind_to_device].
connect_options(Opts, Mod) ->
BaseOpts =
@@ -770,7 +770,7 @@ listen_options() ->
header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
- packet_size, raw, show_econnreset].
+ packet_size, raw, show_econnreset, bind_to_device].
listen_options(Opts, Mod) ->
BaseOpts =
@@ -850,7 +850,7 @@ udp_options() ->
deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
add_membership, drop_membership, read_packets,raw,
- high_msgq_watermark, low_msgq_watermark].
+ high_msgq_watermark, low_msgq_watermark, bind_to_device].
udp_options(Opts, Mod) ->
@@ -919,6 +919,7 @@ sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
mode, active, buffer, tos, tclass, priority, dontroute, reuseaddr, linger, sndbuf,
recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
+ bind_to_device,
% Other options are SCTP-specific (though they may be similar to their
% TCP and UDP counter-parts):
@@ -1055,7 +1056,6 @@ binary2filename(Bin) ->
Bin
end.
-
translate_ip(any, inet) -> {0,0,0,0};
translate_ip(loopback, inet) -> {127,0,0,1};
translate_ip(any, inet6) -> {0,0,0,0,0,0,0,0};
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 4e8f59a3b9..e6cd48935a 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -154,6 +154,7 @@
-define(INET_LOPT_TCP_SHOW_ECONNRESET, 39).
-define(INET_LOPT_LINE_DELIM, 40).
-define(INET_OPT_TCLASS, 41).
+-define(INET_OPT_BIND_TO_DEVICE, 42).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index 59eca242b1..b901da95b8 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -100,63 +100,112 @@ get_error_logger_type() ->
%%%-----------------------------------------------------------------
init([]) ->
- SupFlags = {one_for_all, 0, 1},
-
- Config = {kernel_config,
- {kernel_config, start_link, []},
- permanent, 2000, worker, [kernel_config]},
- Code = {code_server,
- {code, start_link, []},
- permanent, 2000, worker, [code]},
- File = {file_server_2,
- {file_server, start_link, []},
- permanent, 2000, worker,
- [file, file_server, file_io_server, prim_file]},
- StdError = {standard_error,
- {standard_error, start_link, []},
- temporary, 2000, supervisor, [user_sup]},
- User = {user,
- {user_sup, start, []},
- temporary, 2000, supervisor, [user_sup]},
-
+ SupFlags = #{strategy => one_for_all,
+ intensity => 0,
+ period => 1},
+
+ Config = #{id => kernel_config,
+ start => {kernel_config, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [kernel_config]},
+
+ Code = #{id => code_server,
+ start => {code, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [code]},
+
+ File = #{id => file_server_2,
+ start => {file_server, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modeules => [file, file_server, file_io_server, prim_file]},
+
+ StdError = #{id => standard_error,
+ start => {standard_error, start_link, []},
+ restart => temporary,
+ shutdown => 2000,
+ type => supervisor,
+ modules => [user_sup]},
+
+ User = #{id => user,
+ start => {user_sup, start, []},
+ restart => temporary,
+ shutdown => 2000,
+ type => supervisor,
+ modules => [user_sup]},
+
+ SafeSup = #{id => kernel_safe_sup,
+ start =>{supervisor, start_link, [{local, kernel_safe_sup}, ?MODULE, safe]},
+ restart => permanent,
+ shutdown => infinity,
+ type => supervisor,
+ modules => [?MODULE]},
+
case init:get_argument(mode) of
- {ok, [["minimal"]]} ->
- SafeSupervisor = {kernel_safe_sup,
- {supervisor, start_link,
- [{local, kernel_safe_sup}, ?MODULE, safe]},
- permanent, infinity, supervisor, [?MODULE]},
- {ok, {SupFlags,
- [Code, File, StdError, User,
- Config, SafeSupervisor]}};
- _ ->
- Rpc = {rex, {rpc, start_link, []},
- permanent, 2000, worker, [rpc]},
- Global = {global_name_server, {global, start_link, []},
- permanent, 2000, worker, [global]},
- Glo_grp = {global_group, {global_group,start_link,[]},
- permanent, 2000, worker, [global_group]},
- InetDb = {inet_db, {inet_db, start_link, []},
- permanent, 2000, worker, [inet_db]},
- NetSup = {net_sup, {erl_distribution, start_link, []},
- permanent, infinity, supervisor,[erl_distribution]},
+ {ok, [["minimal"]]} ->
+ {ok, {SupFlags, [Code, File, StdError, User, Config, SafeSup]}};
+ _ ->
+ Rpc = #{id => rex,
+ start => {rpc, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [rpc]},
+
+ Global = #{id => global_name_server,
+ start => {global, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [global]},
+
+ GlGroup = #{id => global_group,
+ start => {global_group,start_link,[]},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [global_group]},
+
+ InetDb = #{id => inet_db,
+ start => {inet_db, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [inet_db]},
+
+ NetSup = #{id => net_sup,
+ start => {erl_distribution, start_link, []},
+ restart => permanent,
+ shutdown => infinity,
+ type => supervisor,
+ modules => [erl_distribution]},
+
SigSrv = #{id => erl_signal_server,
start => {gen_event, start_link, [{local, erl_signal_server}]},
- type => worker, restart => permanent, shutdown => 2000, modules => dynamic},
- DistAC = start_dist_ac(),
-
- Timer = start_timer(),
-
- SafeSupervisor = {kernel_safe_sup,
- {supervisor, start_link,
- [{local, kernel_safe_sup}, ?MODULE, safe]},
- permanent, infinity, supervisor, [?MODULE]},
- {ok, {SupFlags,
- [Code, Rpc, Global, InetDb | DistAC] ++
- [NetSup, Glo_grp, File, SigSrv,
- StdError, User, Config, SafeSupervisor] ++ Timer}}
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => dynamic},
+
+ DistAC = start_dist_ac(),
+
+ Timer = start_timer(),
+
+ {ok, {SupFlags,
+ [Code, Rpc, Global, InetDb | DistAC] ++
+ [NetSup, GlGroup, File, SigSrv,
+ StdError, User, Config, SafeSup] ++ Timer}}
end;
init(safe) ->
- SupFlags = {one_for_one, 4, 3600},
+ SupFlags = #{strategy => one_for_one,
+ intensity => 4,
+ period => 3600},
+
Boot = start_boot_server(),
DiskLog = start_disk_log(),
Pg2 = start_pg2(),
@@ -170,60 +219,85 @@ init(safe) ->
{ok, {SupFlags, Boot ++ DiskLog ++ Pg2}}.
start_dist_ac() ->
- Spec = [{dist_ac,{dist_ac,start_link,[]},permanent,2000,worker,[dist_ac]}],
+ Spec = [#{id => dist_ac,
+ start => {dist_ac,start_link,[]},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [dist_ac]}],
case application:get_env(kernel, start_dist_ac) of
- {ok, true} -> Spec;
- {ok, false} -> [];
- undefined ->
- case application:get_env(kernel, distributed) of
- {ok, _} -> Spec;
- _ -> []
- end
+ {ok, true} -> Spec;
+ {ok, false} -> [];
+ undefined ->
+ case application:get_env(kernel, distributed) of
+ {ok, _} -> Spec;
+ _ -> []
+ end
end.
start_boot_server() ->
case application:get_env(kernel, start_boot_server) of
- {ok, true} ->
- Args = get_boot_args(),
- [{boot_server, {erl_boot_server, start_link, [Args]}, permanent,
- 1000, worker, [erl_boot_server]}];
- _ ->
- []
+ {ok, true} ->
+ Args = get_boot_args(),
+ [#{id => boot_server,
+ start => {erl_boot_server, start_link, [Args]},
+ restart => permanent,
+ shutdown => 1000,
+ type => worker,
+ modules => [erl_boot_server]}];
+ _ ->
+ []
end.
get_boot_args() ->
case application:get_env(kernel, boot_server_slaves) of
- {ok, Slaves} -> Slaves;
- _ -> []
+ {ok, Slaves} -> Slaves;
+ _ -> []
end.
start_disk_log() ->
case application:get_env(kernel, start_disk_log) of
- {ok, true} ->
- [{disk_log_server,
- {disk_log_server, start_link, []},
- permanent, 2000, worker, [disk_log_server]},
- {disk_log_sup, {disk_log_sup, start_link, []}, permanent,
- 1000, supervisor, [disk_log_sup]}];
- _ ->
- []
+ {ok, true} ->
+ [#{id => disk_log_server,
+ start => {disk_log_server, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [disk_log_server]},
+ #{id => disk_log_sup,
+ start => {disk_log_sup, start_link, []},
+ restart => permanent,
+ shutdown => 1000,
+ type => supervisor,
+ modules => [disk_log_sup]}];
+ _ ->
+ []
end.
start_pg2() ->
case application:get_env(kernel, start_pg2) of
- {ok, true} ->
- [{pg2, {pg2, start_link, []}, permanent, 1000, worker, [pg2]}];
- _ ->
- []
+ {ok, true} ->
+ [#{id => pg2,
+ start => {pg2, start_link, []},
+ restart => permanent,
+ shutdown => 1000,
+ type => worker,
+ modules => [pg2]}];
+ _ ->
+ []
end.
start_timer() ->
case application:get_env(kernel, start_timer) of
- {ok, true} ->
- [{timer_server, {timer, start_link, []}, permanent, 1000, worker,
- [timer]}];
- _ ->
- []
+ {ok, true} ->
+ [#{id => timer_server,
+ start => {timer, start_link, []},
+ restart => permanent,
+ shutdown => 1000,
+ type => worker,
+ modules => [timer]}];
+ _ ->
+ []
end.
%%-----------------------------------------------------------------
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index 0a9f9316b0..9921a0adfd 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -1262,11 +1262,22 @@ create_name(Name, LongOrShortNames, Try) ->
{Head,Host1} = create_hostpart(Name, LongOrShortNames),
case Host1 of
{ok,HostPart} ->
- {ok,list_to_atom(Head ++ HostPart)};
+ case valid_name_head(Head) of
+ true ->
+ {ok,list_to_atom(Head ++ HostPart)};
+ false ->
+ error_logger:info_msg("Invalid node name!\n"
+ "Please check your configuration\n"),
+ {error, badarg}
+ end;
{error,long} when Try =:= 1 ->
%% It could be we haven't read domain name from resolv file yet
inet_config:do_load_resolv(os:type(), longnames),
create_name(Name, LongOrShortNames, 0);
+ {error, hostname_not_allowed} ->
+ error_logger:info_msg("Invalid node name!\n"
+ "Please check your configuration\n"),
+ {error, badarg};
{error,Type} ->
error_logger:info_msg(
lists:concat(["Can\'t set ",
@@ -1279,12 +1290,13 @@ create_name(Name, LongOrShortNames, Try) ->
create_hostpart(Name, LongOrShortNames) ->
{Head,Host} = split_node(Name),
Host1 = case {Host,LongOrShortNames} of
- {[$@,_|_],longnames} ->
- {ok,Host};
+ {[$@,_|_] = Host,longnames} ->
+ validate_hostname(Host);
{[$@,_|_],shortnames} ->
case lists:member($.,Host) of
true -> {error,short};
- _ -> {ok,Host}
+ _ ->
+ validate_hostname(Host)
end;
{_,shortnames} ->
case inet_db:gethostname() of
@@ -1304,6 +1316,24 @@ create_hostpart(Name, LongOrShortNames) ->
end,
{Head,Host1}.
+validate_hostname([$@|HostPart] = Host) ->
+ {ok, MP} = re:compile("^[!-ÿ]*$", [unicode]),
+ case re:run(HostPart, MP) of
+ {match, _} ->
+ {ok, Host};
+ nomatch ->
+ {error, hostname_not_allowed}
+ end.
+
+valid_name_head(Head) ->
+ {ok, MP} = re:compile("^[0-9A-Za-z_\\-]*$", [unicode]),
+ case re:run(Head, MP) of
+ {match, _} ->
+ true;
+ nomatch ->
+ false
+ end.
+
split_node(Name) ->
lists:splitwith(fun(C) -> C =/= $@ end, atom_to_list(Name)).
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 19d36a7613..088d851b09 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -107,6 +107,10 @@ init_per_testcase(big_boot_embedded, Config) ->
_Else ->
{skip, "Needs crypto!"}
end;
+init_per_testcase(on_load_embedded, Config) ->
+ LibRoot = code:lib_dir(),
+ LinkName = filename:join(LibRoot, "on_load_app-1.0"),
+ [{link_name,LinkName}|Config];
init_per_testcase(_Func, Config) ->
P = code:get_path(),
[{code_path, P}|Config].
@@ -124,6 +128,10 @@ end_per_testcase(TC, Config) when TC == mult_lib_roots;
NodeName = list_to_atom(atom_to_list(TC)++"@"++HostName),
test_server:stop_node(NodeName),
end_per_testcase(Config);
+end_per_testcase(on_load_embedded, Config) ->
+ LinkName = proplists:get_value(link_name, Config),
+ _ = del_link(LinkName),
+ end_per_testcase(Config);
end_per_testcase(_Func, Config) ->
end_per_testcase(Config).
@@ -1271,10 +1279,9 @@ on_load_embedded(Config) when is_list(Config) ->
on_load_embedded_1(Config) ->
DataDir = proplists:get_value(data_dir, Config),
+ LinkName = proplists:get_value(link_name, Config),
%% Link the on_load_app application into the lib directory.
- LibRoot = code:lib_dir(),
- LinkName = filename:join(LibRoot, "on_load_app-1.0"),
OnLoadApp = filename:join(DataDir, "on_load_app-1.0"),
del_link(LinkName),
io:format("LinkName :~p, OnLoadApp: ~p~n",[LinkName,OnLoadApp]),
@@ -1308,8 +1315,7 @@ on_load_embedded_1(Config) ->
ok = rpc:call(Node, on_load_embedded, status, []),
%% Clean up.
- stop_node(Node),
- ok = del_link(LinkName).
+ stop_node(Node).
del_link(LinkName) ->
case file:delete(LinkName) of
diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl
index 23fe975ef7..079cc2f90f 100644
--- a/lib/kernel/test/disk_log_SUITE.erl
+++ b/lib/kernel/test/disk_log_SUITE.erl
@@ -481,7 +481,7 @@ halt_ro_crash(Conf) when is_list(Conf) ->
%% This is how it was before R6B:
%% {C1,T1,15} = disk_log:chunk(a,start),
%% {C2,T2} = disk_log:chunk(a,C1),
- {C1,_OneItem,7478} = disk_log:chunk(a,start),
+ {C1,_OneItem,7476} = disk_log:chunk(a,start),
{C2, [], 7} = disk_log:chunk(a,C1),
eof = disk_log:chunk(a,C2),
ok = disk_log:close(a),
@@ -2502,8 +2502,8 @@ error_repair(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
BadFile = add_ext(File, 2), % current file
set_opened(BadFile),
- crash(BadFile, 28), % the binary is now invalid
- {repaired,n,{recovered,0},{badbytes,26}} =
+ crash(BadFile, 26), % the binary is now invalid
+ {repaired,n,{recovered,0},{badbytes,24}} =
disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, internal}, {size, {40,No}}]),
ok = disk_log:close(n),
@@ -2518,8 +2518,8 @@ error_repair(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
BadFile2 = add_ext(File, 1), % current file
set_opened(BadFile2),
- crash(BadFile2, 51), % the second binary is now invalid
- {repaired,n,{recovered,1},{badbytes,26}} =
+ crash(BadFile2, 47), % the second binary is now invalid
+ {repaired,n,{recovered,1},{badbytes,24}} =
disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, internal}, {size, {4000,No}}]),
ok = disk_log:close(n),
@@ -2571,7 +2571,7 @@ error_repair(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
set_opened(File),
crash(File, 30),
- {repaired,n,{recovered,3},{badbytes,16}} =
+ {repaired,n,{recovered,3},{badbytes,15}} =
disk_log:open([{name, n}, {file, File}, {type, halt},
{format, internal},{repair,true},
{head_func, {?MODULE, head_fun, [{ok,"head"}]}}]),
@@ -2797,7 +2797,7 @@ chunk(Conf) when is_list(Conf) ->
ok = disk_log:log_terms(n, [{some,terms}]), % second file full
2 = curf(n),
BadFile = add_ext(File, 1),
- crash(BadFile, 28), % the _binary_ is now invalid
+ crash(BadFile, 26), % the _binary_ is now invalid
{error, {corrupt_log_file, BFile}} = disk_log:chunk(n, start, 1),
BadFile = BFile,
ok = disk_log:close(n),
@@ -2807,7 +2807,7 @@ chunk(Conf) when is_list(Conf) ->
{format, internal}]),
ok = disk_log:log_terms(n, [{this,is}]),
ok = disk_log:sync(n),
- crash(File, 28), % the _binary_ is now invalid
+ crash(File, 26), % the _binary_ is now invalid
{error, {corrupt_log_file, File2}} = disk_log:chunk(n, start, 1),
crash(File, 10),
{error,{corrupt_log_file,_}} = disk_log:bchunk(n, start, 1),
@@ -2901,8 +2901,8 @@ chunk(Conf) when is_list(Conf) ->
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, internal}, {mode, read_only}]),
CrashFile = add_ext(File, 1),
- crash(CrashFile, 51), % the binary term {some,terms} is now bad
- {H1, [{this,is}], 18} = disk_log:chunk(n, start, 10),
+ crash(CrashFile, 46), % the binary term {some,terms} is now bad
+ {H1, [{this,is}], 16} = disk_log:chunk(n, start, 10),
{H2, [{on,a},{wrap,file}]} = disk_log:chunk(n, H1),
eof = disk_log:chunk(n, H2),
ok = disk_log:close(n),
@@ -2916,8 +2916,8 @@ chunk(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt},
{format, internal}, {mode, read_only}]),
- crash(File, 51), % the binary term {some,terms} is now bad
- {J1, [{this,is}], 18} = disk_log:chunk(n, start, 10),
+ crash(File, 46), % the binary term {some,terms} is now bad
+ {J1, [{this,is}], 16} = disk_log:chunk(n, start, 10),
{J2, [{on,a},{halt,file}]} = disk_log:chunk(n, J1),
eof = disk_log:chunk(n, J2),
ok = disk_log:close(n),
@@ -2932,8 +2932,8 @@ chunk(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt},
{format, internal}, {mode, read_only}]),
- crash(File, 44), % the binary term {s} is now bad
- {J11, [{this,is}], 7} = disk_log:chunk(n, start, 10),
+ crash(File, 40), % the binary term {s} is now bad
+ {J11, [{this,is}], 6} = disk_log:chunk(n, start, 10),
{J21, [{on,a},{halt,file}]} = disk_log:chunk(n, J11),
eof = disk_log:chunk(n, J21),
ok = disk_log:close(n),
@@ -3052,7 +3052,7 @@ truncate(Conf) when is_list(Conf) ->
ok = disk_log:truncate(n, apa),
rec(1, {disk_log, node(), n, {truncated, 6}}),
{0, 0} = no_overflows(n),
- 23 = curb(n),
+ 22 = curb(n),
1 = curf(n),
1 = cur_cnt(n),
true = (Size == sz(n)),
@@ -3072,7 +3072,7 @@ truncate(Conf) when is_list(Conf) ->
ok = disk_log:truncate(n, apa),
rec(1, {disk_log, node(), n, {truncated, 3}}),
{0, 0} = no_overflows(n),
- 23 = curb(n),
+ 22 = curb(n),
1 = curf(n),
1 = cur_cnt(n),
true = (Size == sz(n)),
@@ -3181,45 +3181,45 @@ info_current(Conf) when is_list(Conf) ->
%% Internal with header.
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap},
{head, header}, {size, {100,No}}]),
- {26, 1} = {curb(n), cur_cnt(n)},
+ {25, 1} = {curb(n), cur_cnt(n)},
{1, 1} = {no_written_items(n), no_items(n)},
ok = disk_log:log(n, B),
- {94, 2} = {curb(n), cur_cnt(n)},
+ {93, 2} = {curb(n), cur_cnt(n)},
{2, 2} = {no_written_items(n), no_items(n)},
ok = disk_log:close(n),
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap},
{notify, true},
{head, header}, {size, {100,No}}]),
- {94, 2} = {curb(n), cur_cnt(n)},
+ {93, 2} = {curb(n), cur_cnt(n)},
{0, 2} = {no_written_items(n), no_items(n)},
ok = disk_log:log(n, B),
rec(1, {disk_log, node(), n, {wrap, 0}}),
- {94, 2} = {curb(n), cur_cnt(n)},
+ {93, 2} = {curb(n), cur_cnt(n)},
{2, 4} = {no_written_items(n), no_items(n)},
disk_log:inc_wrap_file(n),
rec(1, {disk_log, node(), n, {wrap, 0}}),
- {26, 1} = {curb(n), cur_cnt(n)},
+ {25, 1} = {curb(n), cur_cnt(n)},
{3, 4} = {no_written_items(n), no_items(n)},
ok = disk_log:log_terms(n, [B,B,B]),
%% Used to be one message, but now one per wrapped file.
rec(1, {disk_log, node(), n, {wrap, 0}}),
rec(1, {disk_log, node(), n, {wrap, 2}}),
- {94, 2} = {curb(n), cur_cnt(n)},
+ {93, 2} = {curb(n), cur_cnt(n)},
{8, 7} = {no_written_items(n), no_items(n)},
ok = disk_log:log_terms(n, [B]),
rec(1, {disk_log, node(), n, {wrap, 2}}),
ok = disk_log:log_terms(n, [B]),
rec(1, {disk_log, node(), n, {wrap, 2}}),
- {94, 2} = {curb(n), cur_cnt(n)},
+ {93, 2} = {curb(n), cur_cnt(n)},
{12, 7} = {no_written_items(n), no_items(n)},
ok = disk_log:log_terms(n, [BB,BB]),
%% Used to be one message, but now one per wrapped file.
rec(2, {disk_log, node(), n, {wrap, 2}}),
- {194, 2} = {curb(n), cur_cnt(n)},
+ {193, 2} = {curb(n), cur_cnt(n)},
{16, 7} = {no_written_items(n), no_items(n)},
ok = disk_log:log_terms(n, [SB,SB,SB]),
rec(1, {disk_log, node(), n, {wrap, 2}}),
- {80, 4} = {curb(n), cur_cnt(n)},
+ {79, 4} = {curb(n), cur_cnt(n)},
{20, 9} = {no_written_items(n), no_items(n)},
ok = disk_log:close(n),
del(File, No),
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index 09c80a0956..ecfa3d6cdb 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -24,7 +24,9 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([tick/1, tick_change/1, illegal_nodenames/1, hidden_node/1,
+-export([tick/1, tick_change/1,
+ nodenames/1, hostnames/1,
+ illegal_nodenames/1, hidden_node/1,
setopts/1,
table_waste/1, net_setuptime/1,
inet_dist_options_options/1,
@@ -53,7 +55,6 @@
-export([pinger/1]).
-
-define(DUMMY_NODE,dummy@test01).
%%-----------------------------------------------------------------
@@ -68,8 +69,8 @@ suite() ->
{timetrap,{minutes,4}}].
all() ->
- [tick, tick_change, illegal_nodenames, hidden_node,
- setopts,
+ [tick, tick_change, nodenames, hostnames, illegal_nodenames,
+ hidden_node, setopts,
table_waste, net_setuptime, inet_dist_options_options,
{group, monitor_nodes}].
@@ -179,7 +180,97 @@ table_waste(Config) when is_list(Config) ->
stop_node(N),
ok.
+%% Test that starting nodes with different legal name part works, and that illegal
+%% ones are filtered
+nodenames(Config) when is_list(Config) ->
+ legal("a1@b"),
+ legal("a-1@b"),
+ legal("a_1@b"),
+
+ illegal("cdé@a"),
+ illegal("te欢st@a").
+
+%% Test that starting nodes with different legal host part works, and that illegal
+%% ones are filtered
+hostnames(Config) when is_list(Config) ->
+ Host = gethostname(),
+ legal([$a,$@|atom_to_list(Host)]),
+ legal("1@b1"),
+ legal("b@b1-c"),
+ legal("c@b1_c"),
+ legal("d@b1#c"),
+ legal("f@::1"),
+ legal("g@1:bc3:4e3f:f20:0:1"),
+
+ case file:native_name_encoding() of
+ latin1 -> ignore;
+ _ -> legal("e@b1é")
+ end,
+ long_hostnames(net_kernel:longnames()),
+
+ illegal("h@testالع"),
+ illegal("i@языtest"),
+ illegal("j@te欢st").
+
+long_hostnames(true) ->
+ legal("[email protected]"),
+ legal("[email protected]"),
+ legal("[email protected]_c.d"),
+ legal("[email protected]"),
+ legal("[email protected]");
+long_hostnames(false) ->
+ illegal("[email protected]").
+
+legal(Name) ->
+ case test_node(Name) of
+ started ->
+ ok;
+ not_started ->
+ ct:fail("no ~p node started", [Name])
+ end.
+
+illegal(Name) ->
+ case test_node(Name) of
+ not_started ->
+ ok;
+ started ->
+ ct:fail("~p node started with illegal name", [Name])
+ end.
+test_node(Name) ->
+ ProgName = atom_to_list(lib:progname()),
+ Command = ProgName ++ " -noinput " ++ long_or_short() ++ Name ++
+ " -eval \"net_adm:ping('" ++ atom_to_list(node()) ++ "')\"",
+ net_kernel:monitor_nodes(true),
+ BinCommand = unicode:characters_to_binary(Command, utf8),
+ open_port({spawn, BinCommand}, [stream]),
+ Node = list_to_atom(Name),
+ receive
+ {nodeup, Node} ->
+ net_kernel:monitor_nodes(false),
+ slave:stop(Node),
+ started
+ after 5000 ->
+ net_kernel:monitor_nodes(false),
+ not_started
+ end.
+
+long_or_short() ->
+ case net_kernel:longnames() of
+ true -> " -name ";
+ false -> " -sname "
+ end.
+
+% get the localhost's name, depending on the using name policy
+gethostname() ->
+ Hostname = case net_kernel:longnames() of
+ true->
+ net_adm:localhost();
+ _->
+ {ok, Name}=inet:gethostname(),
+ Name
+ end,
+ list_to_atom(Hostname).
%% Test that pinging an illegal nodename does not kill the node.
illegal_nodenames(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/erl_distribution_wb_SUITE.erl b/lib/kernel/test/erl_distribution_wb_SUITE.erl
index 61aa3b32ee..c1dc208cc1 100644
--- a/lib/kernel/test/erl_distribution_wb_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_wb_SUITE.erl
@@ -56,10 +56,14 @@
-define(DFLAG_HIDDEN_ATOM_CACHE,16#40).
-define(DFLAG_NEW_FUN_TAGS,16#80).
-define(DFLAG_EXTENDED_PIDS_PORTS,16#100).
+-define(DFLAG_UTF8_ATOMS, 16#10000).
%% From R9 and forward extended references is compulsory
%% From R10 and forward extended pids and ports are compulsory
--define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor ?DFLAG_EXTENDED_PIDS_PORTS)).
+%% From R20 and forward UTF8 atoms are compulsory
+-define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor
+ ?DFLAG_EXTENDED_PIDS_PORTS bor
+ ?DFLAG_UTF8_ATOMS)).
-define(shutdown(X), exit(X)).
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index 10b6b105d0..b2051af050 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -383,7 +383,7 @@ check_icky(Mod) ->
ok
end,
- _ = make_icky_dir(Mod, treat_icky(<<"åäö_dir">>)),
+ _ = make_icky_dir(Mod, treat_icky(<<"åäö_dir"/utf8>>)),
if
UniMode and (OS =/= win32) ->
{error,enoent} = Mod:set_cwd("åäö_dir");
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index f60c13d2e3..86f6b95fb9 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -40,7 +40,8 @@
lookup_bad_search_option/1,
getif/1,
getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1,
- parse_strict_address/1, simple_netns/1, simple_netns_open/1]).
+ parse_strict_address/1, simple_netns/1, simple_netns_open/1,
+ simple_bind_to_device/1, simple_bind_to_device_open/1]).
-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
kill_gethost/0, parallell_gethost/0, test_netns/0]).
@@ -58,7 +59,8 @@ all() ->
gethostnative_debug_level, gethostnative_soft_restart,
lookup_bad_search_option,
getif, getif_ifr_name_overflow, getservbyname_overflow,
- getifaddrs, parse_strict_address, simple_netns, simple_netns_open].
+ getifaddrs, parse_strict_address, simple_netns, simple_netns_open,
+ simple_bind_to_device, simple_bind_to_device_open].
groups() ->
[{parse, [], [parse_hosts, parse_address]}].
@@ -1247,3 +1249,67 @@ cmd(CmdString) ->
io:put_chars(["# ",CmdString,io_lib:nl()]),
io:put_chars([os:cmd(CmdString++" ; echo ' =>' $?")]),
ok.
+
+-define(CAP_NET_RAW, 13). %% from /usr/include/linux/capability.h
+
+can_bind_to_device({unix, linux}, {Major, _, _})
+ when Major > 2 ->
+ Status = os:cmd("cat /proc/self/status | grep CapEff"),
+ [_, CapEffStr] = string:tokens(Status, [$\n, $\t]),
+ CapEff = list_to_integer(CapEffStr, 16),
+ if CapEff band (1 bsl ?CAP_NET_RAW) =/= 0 ->
+ ok;
+ true ->
+ {skip,"insufficient capabilities, CAP_NET_RAW not granted"}
+ end;
+can_bind_to_device(_OS, _Version) ->
+ {skip,"socket option bind_to_device not supported on this OS or version"}.
+
+simple_bind_to_device(Config) when is_list(Config) ->
+ case can_bind_to_device(os:type(), os:version()) of
+ ok ->
+ {ok,U} = gen_udp:open(0),
+ jog_bind_to_device_opt(U),
+ ok = gen_udp:close(U),
+ %%
+ {ok,L} = gen_tcp:listen(0, []),
+ jog_bind_to_device_opt(L),
+ ok = gen_tcp:close(L),
+ %%
+ case gen_sctp:open() of
+ {ok,S} ->
+ jog_bind_to_device_opt(S),
+ ok = gen_sctp:close(S);
+ {error,eprotonosupport} ->
+ ok
+ end;
+ Other ->
+ Other
+ end.
+
+%% Smoke test bind_to_device support.
+simple_bind_to_device_open(Config) when is_list(Config) ->
+ case can_bind_to_device(os:type(), os:version()) of
+ ok ->
+ {ok,U} = gen_udp:open(0, [binary,{bind_to_device,<<"lo">>},inet]),
+ ok = gen_udp:close(U),
+ {ok,T} = gen_tcp:listen(0, [binary,{bind_to_device,<<"lo">>},inet]),
+ ok = gen_tcp:close(T),
+
+ case gen_sctp:open(0, [binary,{bind_to_device,<<"lo">>},inet]) of
+ {ok,S} ->
+ ok = gen_sctp:close(S);
+ {error,eprotonosupport} ->
+ ok
+ end;
+ Other ->
+ Other
+ end.
+
+jog_bind_to_device_opt(S) ->
+ %% This is just jogging the option mechanics
+ ok = inet:setopts(S, [{bind_to_device,<<>>}]),
+ {ok,[{bind_to_device,<<>>}]} = inet:getopts(S, [bind_to_device]),
+ ok = inet:setopts(S, [{bind_to_device,<<"lo">>}]),
+ {ok,[{bind_to_device,<<"lo">>}]} = inet:getopts(S, [bind_to_device]),
+ ok.
diff --git a/lib/kernel/test/pg2_SUITE.erl b/lib/kernel/test/pg2_SUITE.erl
index fdc268cb5a..9460608a3e 100644
--- a/lib/kernel/test/pg2_SUITE.erl
+++ b/lib/kernel/test/pg2_SUITE.erl
@@ -31,7 +31,7 @@
-export([
otp_7277/1, otp_8259/1, otp_8653/1,
- compat/1, basic/1]).
+ basic/1]).
-define(TESTCASE, testcase_name).
-define(testcase, proplists:get_value(?TESTCASE, Config)).
@@ -56,7 +56,7 @@ all() ->
groups() ->
[{tickets, [],
- [otp_7277, otp_8259, otp_8653, compat, basic]}].
+ [otp_7277, otp_8259, otp_8653, basic]}].
init_per_suite(Config) ->
Config.
@@ -218,29 +218,6 @@ loop() ->
exit(normal)
end.
-%% OTP-8259. Check that 'exchange' and 'del_member' work.
-compat(Config) when is_list(Config) ->
- case test_server:is_release_available("r13b") of
- true ->
- Pid = spawn(forever()),
- G = a,
- ok = pg2:create(G),
- ok = pg2:join(G, Pid),
- ok = pg2:join(G, Pid),
- {ok, A} = start_node_rel(r13, r13b, slave),
- pong = net_adm:ping(A),
- wait_for_ready_net(Config),
- {ok, _} = rpc:call(A, pg2, start, []),
- ?UNTIL([Pid,Pid] =:= rpc:call(A, pg2, get_members, [a])),
- true = exit(Pid, kill),
- ?UNTIL([] =:= pg2:get_members(a)),
- ?UNTIL([] =:= rpc:call(A, pg2, get_members, [a])),
- test_server:stop_node(A),
- ok;
- false ->
- {skipped, "No support for old node"}
- end.
-
%% OTP-8259. Some basic tests.
basic(Config) when is_list(Config) ->
_ = [pg2:delete(G) || G <- pg2:which_groups()],
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index 8be94f1e57..0c84a7d1cc 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -19,8 +19,8 @@
%%
-module(prim_file_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- read_write_file/1]).
+ init_per_group/2,end_per_group/2, init_per_testcase/2, end_per_testcase/2,
+ read_write_file/1, free_memory/0]).
-export([cur_dir_0a/1, cur_dir_0b/1,
cur_dir_1a/1, cur_dir_1b/1,
make_del_dir_a/1, make_del_dir_b/1,
@@ -115,6 +115,18 @@ groups() ->
[make_link_a, make_link_b, read_link_info_for_non_link,
symlinks_a, symlinks_b, list_dir_error]}].
+init_per_testcase(large_write, Config) ->
+ {ok, Started} = application:ensure_all_started(os_mon),
+ [{started, Started}|Config];
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(large_write, Config) ->
+ [application:stop(App) || App <- lists:reverse(proplists:get_value(started, Config))],
+ ok;
+end_per_testcase(_, _Config) ->
+ ok.
+
init_per_group(_GroupName, Config) ->
Config.
@@ -2022,11 +2034,13 @@ run_large_file_test(Config, Run, Name) ->
{{unix,sunos},OsVersion} when OsVersion < {5,5,1} ->
{skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"};
{{unix,_},_} ->
- N = unix_free(proplists:get_value(priv_dir, Config)),
- io:format("Free disk: ~w KByte~n", [N]),
- if N < 5 bsl 20 ->
+ DiscFree = unix_free(proplists:get_value(priv_dir, Config)),
+ MemFree = free_memory(),
+ io:format("Free disk: ~w KByte~n", [DiscFree]),
+ io:format("Free mem: ~w MByte~n", [MemFree]),
+ if DiscFree < 5 bsl 20; MemFree < 5 bsl 10 ->
%% Less than 5 GByte free
- {skip,"Less than 5 GByte free disk"};
+ {skip,"Less than 5 GByte free disk/mem"};
true ->
do_run_large_file_test(Config, Run, Name)
end;
@@ -2079,6 +2093,27 @@ zip_data([], Bs) ->
zip_data(As, []) ->
As.
+%% Stolen from emulator -> alloc_SUITE
+free_memory() ->
+ %% Free memory in MB.
+ try
+ SMD = memsup:get_system_memory_data(),
+ {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD),
+ TotFree = (Free +
+ case lists:keysearch(cached_memory, 1, SMD) of
+ {value, {cached_memory, Cached}} -> Cached;
+ false -> 0
+ end +
+ case lists:keysearch(buffered_memory, 1, SMD) of
+ {value, {buffered_memory, Buffed}} -> Buffed;
+ false -> 0
+ end),
+ TotFree div (1024*1024)
+ catch
+ error : undef ->
+ ct:fail({"os_mon not built"})
+ end.
+
%%%-----------------------------------------------------------------
%%% Utilities
rm_rf(Mod,Dir) ->