aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/crypto/c_src/crypto.c26
-rw-r--r--lib/kernel/doc/src/inet.xml60
-rw-r--r--lib/kernel/doc/src/kernel_app.xml20
-rw-r--r--lib/kernel/src/inet.erl5
-rw-r--r--lib/observer/src/cdv_detail_wx.erl11
-rw-r--r--lib/observer/src/cdv_info_wx.erl4
-rw-r--r--lib/observer/src/crashdump_viewer.erl134
-rw-r--r--lib/observer/src/observer_lib.erl67
-rw-r--r--lib/observer/src/observer_port_wx.erl4
-rw-r--r--lib/observer/src/observer_procinfo.erl4
-rw-r--r--lib/observer/test/crashdump_helper.erl1
-rw-r--r--lib/runtime_tools/src/system_information.erl232
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl5
-rw-r--r--lib/stdlib/doc/src/filelib.xml4
-rw-r--r--lib/stdlib/doc/src/filename.xml19
-rw-r--r--lib/stdlib/src/filelib.erl21
-rw-r--r--lib/stdlib/test/filelib_SUITE.erl35
17 files changed, 454 insertions, 198 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 6957d25774..9a3ea07c97 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -179,6 +179,12 @@
# define HAVE_ECB_IVEC_BUG
#endif
+#define HAVE_RSA_SSLV23_PADDING
+#if defined(HAS_LIBRESSL) \
+ && LIBRESSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(2,6,1)
+# undef HAVE_RSA_SSLV23_PADDING
+#endif
+
#if defined(HAVE_CMAC)
#include <openssl/cmac.h>
#endif
@@ -659,7 +665,9 @@ static ERL_NIF_TERM atom_rsa_oaep_md;
static ERL_NIF_TERM atom_rsa_pad; /* backwards compatibility */
static ERL_NIF_TERM atom_rsa_padding;
static ERL_NIF_TERM atom_rsa_pkcs1_pss_padding;
+#ifdef HAVE_RSA_SSLV23_PADDING
static ERL_NIF_TERM atom_rsa_sslv23_padding;
+#endif
static ERL_NIF_TERM atom_rsa_x931_padding;
static ERL_NIF_TERM atom_rsa_pss_saltlen;
static ERL_NIF_TERM atom_sha224;
@@ -1064,7 +1072,9 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_rsa_pad = enif_make_atom(env,"rsa_pad"); /* backwards compatibility */
atom_rsa_padding = enif_make_atom(env,"rsa_padding");
atom_rsa_pkcs1_pss_padding = enif_make_atom(env,"rsa_pkcs1_pss_padding");
+#ifdef HAVE_RSA_SSLV23_PADDING
atom_rsa_sslv23_padding = enif_make_atom(env,"rsa_sslv23_padding");
+#endif
atom_rsa_x931_padding = enif_make_atom(env,"rsa_x931_padding");
atom_rsa_pss_saltlen = enif_make_atom(env,"rsa_pss_saltlen");
atom_sha224 = enif_make_atom(env,"sha224");
@@ -4449,8 +4459,10 @@ static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NI
opt->rsa_padding = RSA_PKCS1_PADDING;
} else if (tpl_terms[1] == atom_rsa_pkcs1_oaep_padding) {
opt->rsa_padding = RSA_PKCS1_OAEP_PADDING;
+#ifdef HAVE_RSA_SSLV23_PADDING
} else if (tpl_terms[1] == atom_rsa_sslv23_padding) {
opt->rsa_padding = RSA_SSLV23_PADDING;
+#endif
} else if (tpl_terms[1] == atom_rsa_x931_padding) {
opt->rsa_padding = RSA_X931_PADDING;
} else if (tpl_terms[1] == atom_rsa_no_padding) {
@@ -4516,7 +4528,10 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
#endif
PKeyCryptOptions crypt_opt;
ErlNifBinary in_bin, out_bin, tmp_bin;
- size_t outlen, tmplen;
+ size_t outlen;
+#ifdef HAVE_RSA_SSLV23_PADDING
+ size_t tmplen;
+#endif
int is_private = (argv[4] == atom_true),
is_encrypt = (argv[5] == atom_true);
int algo_init = 0;
@@ -4596,6 +4611,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
if (crypt_opt.signature_md != NULL
&& EVP_PKEY_CTX_set_signature_md(ctx, crypt_opt.signature_md) <= 0)
goto badarg;
+#ifdef HAVE_RSA_SSLV23_PADDING
if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) {
if (is_encrypt) {
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
@@ -4607,9 +4623,11 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
in_bin = tmp_bin;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0) goto badarg;
- } else {
+ } else
+#endif
+ {
if (EVP_PKEY_CTX_set_rsa_padding(ctx, crypt_opt.rsa_padding) <= 0) goto badarg;
- }
+ }
#ifdef HAVE_RSA_OAEP_MD
if (crypt_opt.rsa_padding == RSA_PKCS1_OAEP_PADDING) {
if (crypt_opt.rsa_oaep_md != NULL
@@ -4728,6 +4746,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
#endif
if ((i > 0) && argv[0] == atom_rsa && !is_encrypt) {
+#ifdef HAVE_RSA_SSLV23_PADDING
if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) {
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
unsigned char *p;
@@ -4745,6 +4764,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
i = 1;
}
}
+#endif
}
if (tmp_bin.data != NULL) {
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 169a76463b..abb045b744 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -197,6 +197,9 @@ fe80::204:acff:fe17:bf38
<datatype>
<name name="address_family"/>
</datatype>
+ <datatype>
+ <name name="socket_protocol"/>
+ </datatype>
</datatypes>
<funcs>
@@ -461,6 +464,61 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
+ <name name="i" arity="0" />
+ <name name="i" arity="1" />
+ <name name="i" arity="2" />
+ <fsummary>Displays information and statistics about sockets on the terminal</fsummary>
+ <desc>
+ <p>
+ Lists all TCP, UDP and SCTP sockets, including those that the Erlang runtime system uses as well as
+ those created by the application.
+ </p>
+ <p>
+ The following options are available:
+ </p>
+
+ <taglist>
+ <tag><c>port</c></tag>
+ <item>
+ <p>The internal index of the port.</p>
+ </item>
+ <tag><c>module</c></tag>
+ <item>
+ <p>The callback module of the socket.</p>
+ </item>
+ <tag><c>recv</c></tag>
+ <item>
+ <p>Number of bytes received by the socket.</p>
+ </item>
+ <tag><c>sent</c></tag>
+ <item>
+ <p>Number of bytes sent from the socket.</p>
+ </item>
+ <tag><c>owner</c></tag>
+ <item>
+ <p>The socket owner process.</p>
+ </item>
+ <tag><c>local_address</c></tag>
+ <item>
+ <p>The local address of the socket.</p>
+ </item>
+ <tag><c>foreign_address</c></tag>
+ <item>
+ <p>The address and port of the other end of the connection.</p>
+ </item>
+ <tag><c>state</c></tag>
+ <item>
+ <p>The connection state.</p>
+ </item>
+ <tag><c>type</c></tag>
+ <item>
+ <p>STREAM or DGRAM or SEQPACKET.</p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
<name name="ntoa" arity="1" />
<fsummary>Convert IPv6/IPV4 address to ASCII.</fsummary>
<desc>
@@ -1214,7 +1272,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
For one-to-many style sockets, the special value <c>0</c>
is defined to mean that the returned addresses must be
without any particular association.
- How different SCTP implementations interprets this varies somewhat.
+ How different SCTP implementations interpret this varies somewhat.
</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index e5ac031539..0762cebc94 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -469,8 +469,12 @@ MaxT = TickTime + TickTime / 4</code>
<item><c>ObjSuffix = string()</c></item>
<item><c>SrcSuffix = string()</c></item>
</list>
- <p>Specifies a list of rules for use by <c>filelib:find_file/2</c> and
- <c>filelib:find_source/2</c>. If this is set to some other value
+ <p>Specifies a list of rules for use by
+ <seealso marker="stdlib:filelib#find_file/2">
+ <c>filelib:find_file/2</c></seealso>
+ <seealso marker="stdlib:filelib#find_source/2">
+ <c>filelib:find_source/2</c></seealso>
+ If this is set to some other value
than the empty list, it replaces the default rules. Rules can be
simple pairs of directory suffixes, such as <c>{"ebin",
"src"}</c>, which are used by <c>filelib:find_file/2</c>, or
@@ -478,6 +482,16 @@ MaxT = TickTime + TickTime / 4</code>
file name extensions, for example <c>[{".beam", ".erl", [{"ebin",
"src"}]}</c>, which are used by <c>filelib:find_source/2</c>. Both
kinds of rules can be mixed in the list.</p>
+ <p>The interpretation of <c>ObjDirSuffix</c> and <c>SrcDirSuffix</c>
+ is as follows: if the end of the directory name where an
+ object is located matches <c>ObjDirSuffix</c>, then the
+ name created by replacing <c>ObjDirSuffix</c> with
+ <c>SrcDirSuffix</c> is expanded by calling
+ <seealso marker="stdlib:filelib#wildcard/1">
+ <c>filelib:wildcard/1</c></seealso>, and the first regular
+ file found among the matches is the source file.
+ </p>
+
</item>
</taglist>
</section>
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index dc20c21c77..fe91b0d33e 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -72,7 +72,7 @@
%% timer interface
-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
--export_type([address_family/0, hostent/0, hostname/0, ip4_address/0,
+-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
ip6_address/0, ip_address/0, port_number/0,
local_address/0, socket_address/0, returned_non_ip_address/0,
socket_setopt/0, socket_getopt/0,
@@ -1452,11 +1452,14 @@ fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) ->
%% socket stat
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec i() -> ok.
i() -> i(tcp), i(udp), i(sctp).
+-spec i(socket_protocol()) -> ok.
i(Proto) -> i(Proto, [port, module, recv, sent, owner,
local_address, foreign_address, state, type]).
+-spec i(socket_protocol(), [atom()]) -> ok.
i(tcp, Fs) ->
ii(tcp_sockets(), Fs, tcp);
i(udp, Fs) ->
diff --git a/lib/observer/src/cdv_detail_wx.erl b/lib/observer/src/cdv_detail_wx.erl
index f6d282638a..6c4739042b 100644
--- a/lib/observer/src/cdv_detail_wx.erl
+++ b/lib/observer/src/cdv_detail_wx.erl
@@ -48,6 +48,7 @@ init([Id, Data, ParentFrame, Callback, App, Parent]) ->
display_progress(ParentFrame,App),
case Callback:get_details(Id, Data) of
{ok,Details} ->
+ display_progress_pulse(Callback,Id),
init(Id,ParentFrame,Callback,App,Parent,Details);
{yes_no, Info, Fun} ->
destroy_progress(App),
@@ -69,8 +70,16 @@ display_progress(ParentFrame,cdv) ->
"Reading data");
display_progress(_,_) ->
ok.
+
+%% Display pulse while creating process detail page with much data
+display_progress_pulse(cdv_proc_cb,Pid) ->
+ observer_lib:report_progress({ok,"Displaying data for "++Pid}),
+ observer_lib:report_progress({ok,start_pulse});
+display_progress_pulse(_,_) ->
+ ok.
+
destroy_progress(cdv) ->
- observer_lib:destroy_progress_dialog();
+ observer_lib:sync_destroy_progress_dialog();
destroy_progress(_) ->
ok.
diff --git a/lib/observer/src/cdv_info_wx.erl b/lib/observer/src/cdv_info_wx.erl
index 7e416dd11a..07c28610e2 100644
--- a/lib/observer/src/cdv_info_wx.erl
+++ b/lib/observer/src/cdv_info_wx.erl
@@ -95,6 +95,10 @@ handle_cast(Msg, State) ->
io:format("~p~p: Unhandled cast ~tp~n",[?MODULE, ?LINE, Msg]),
{noreply, State}.
+handle_event(#wx{obj=MoreEntry,event=#wxMouse{type=left_down},userData={more,More}}, State) ->
+ observer_lib:add_scroll_entries(MoreEntry,More),
+ {noreply, State};
+
handle_event(#wx{event=#wxMouse{type=left_down},userData=Target}, State) ->
cdv_virtual_list_wx:start_detail_win(Target),
{noreply, State};
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index d578639f1a..bba97624a7 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -1240,7 +1240,7 @@ all_procinfo(Fd,Fun,Proc,WS,LineHead) ->
"Last calls" ->
get_procinfo(Fd,Fun,Proc#proc{last_calls=get_last_calls(Fd)},WS);
"Link list" ->
- {Links,Monitors,MonitoredBy} = parse_link_list(bytes(Fd),[],[],[]),
+ {Links,Monitors,MonitoredBy} = get_link_list(Fd),
get_procinfo(Fd,Fun,Proc#proc{links=Links,
monitors=Monitors,
mon_by=MonitoredBy},WS);
@@ -1322,86 +1322,64 @@ get_last_calls(Fd,<<>>,Acc,Lines) ->
lists:reverse(Lines,[byte_list_to_string(lists:reverse(Acc))])
end.
-parse_link_list([SB|Str],Links,Monitors,MonitoredBy) when SB==$[; SB==$] ->
- parse_link_list(Str,Links,Monitors,MonitoredBy);
-parse_link_list("#Port"++_=Str,Links,Monitors,MonitoredBy) ->
- {Link,Rest} = parse_port(Str),
- parse_link_list(Rest,[Link|Links],Monitors,MonitoredBy);
-parse_link_list("<"++_=Str,Links,Monitors,MonitoredBy) ->
- {Link,Rest} = parse_pid(Str),
- parse_link_list(Rest,[Link|Links],Monitors,MonitoredBy);
-parse_link_list("{to,"++Str,Links,Monitors,MonitoredBy) ->
- {Mon,Rest} = parse_monitor(Str),
- parse_link_list(Rest,Links,[Mon|Monitors],MonitoredBy);
-parse_link_list("{from,"++Str,Links,Monitors,MonitoredBy) ->
- {Mon,Rest} = parse_monitor(Str),
- parse_link_list(Rest,Links,Monitors,[Mon|MonitoredBy]);
-parse_link_list(", "++Rest,Links,Monitors,MonitoredBy) ->
- parse_link_list(Rest,Links,Monitors,MonitoredBy);
-parse_link_list([],Links,Monitors,MonitoredBy) ->
- {lists:reverse(Links),lists:reverse(Monitors),lists:reverse(MonitoredBy)};
-parse_link_list(Unexpected,Links,Monitors,MonitoredBy) ->
- io:format("WARNING: found unexpected data in link list:~n~ts~n",[Unexpected]),
- parse_link_list([],Links,Monitors,MonitoredBy).
-
-
-parse_port(Str) ->
- {Port,Rest} = parse_link(Str,[]),
- {{Port,Port},Rest}.
-
-parse_pid(Str) ->
- {Pid,Rest} = parse_link(Str,[]),
- {{Pid,Pid},Rest}.
-
-parse_monitor("{"++Str) ->
- %% Named process
- {Name,Node,Rest1} = parse_name_node(Str,[]),
- Pid = get_pid_from_name(Name,Node),
- case parse_link(string:trim(Rest1,leading,","),[]) of
- {Ref,"}"++Rest2} ->
- %% Bug in break.c - prints an extra "}" for remote
- %% nodes... thus the strip
- {{Pid,"{"++Name++","++Node++"} ("++Ref++")"},
- string:trim(Rest2,leading,"}")};
- {Ref,[]} ->
- {{Pid,"{"++Name++","++Node++"} ("++Ref++")"},[]}
- end;
-parse_monitor(Str) ->
- case parse_link(Str,[]) of
- {Pid,","++Rest1} ->
- case parse_link(Rest1,[]) of
- {Ref,"}"++Rest2} ->
- {{Pid,Pid++" ("++Ref++")"},Rest2};
- {Ref,[]} ->
- {{Pid,Pid++" ("++Ref++")"},[]}
- end;
- {Pid,[]} ->
- {{Pid,Pid++" (unknown_ref)"},[]}
+get_link_list(Fd) ->
+ case get_chunk(Fd) of
+ {ok,<<"[",Bin/binary>>} ->
+ #{links:=Links,
+ mons:=Monitors,
+ mon_by:=MonitoredBy} =
+ get_link_list(Fd,Bin,#{links=>[],mons=>[],mon_by=>[]}),
+ {lists:reverse(Links),
+ lists:reverse(Monitors),
+ lists:reverse(MonitoredBy)};
+ eof ->
+ {[],[],[]}
end.
-parse_link(">"++Rest,Acc) ->
- {lists:reverse(Acc,">"),Rest};
-parse_link([H|T],Acc) ->
- parse_link(T,[H|Acc]);
-parse_link([],Acc) ->
- %% truncated
- {lists:reverse(Acc),[]}.
+get_link_list(Fd,<<NL:8,_/binary>>=Bin,Acc) when NL=:=$\r; NL=:=$\n->
+ skip(Fd,Bin),
+ Acc;
+get_link_list(Fd,Bin,Acc) ->
+ case binary:split(Bin,[<<", ">>,<<"]">>]) of
+ [Link,Rest] ->
+ get_link_list(Fd,Rest,get_link(Link,Acc));
+ [Incomplete] ->
+ case get_chunk(Fd) of
+ {ok,More} ->
+ get_link_list(Fd,<<Incomplete/binary,More/binary>>,Acc);
+ eof ->
+ Acc
+ end
+ end.
-parse_name_node(","++Rest,Name) ->
- parse_name_node(Rest,Name,[]);
-parse_name_node([H|T],Name) ->
- parse_name_node(T,[H|Name]);
-parse_name_node([],Name) ->
- %% truncated
- {lists:reverse(Name),[],[]}.
-
-parse_name_node("}"++Rest,Name,Node) ->
- {lists:reverse(Name),lists:reverse(Node),Rest};
-parse_name_node([H|T],Name,Node) ->
- parse_name_node(T,Name,[H|Node]);
-parse_name_node([],Name,Node) ->
- %% truncated
- {lists:reverse(Name),lists:reverse(Node),[]}.
+get_link(<<"#Port",_/binary>>=PortBin,#{links:=Links}=Acc) ->
+ PortStr = binary_to_list(PortBin),
+ Acc#{links=>[{PortStr,PortStr}|Links]};
+get_link(<<"<",_/binary>>=PidBin,#{links:=Links}=Acc) ->
+ PidStr = binary_to_list(PidBin),
+ Acc#{links=>[{PidStr,PidStr}|Links]};
+get_link(<<"{to,",Bin/binary>>,#{mons:=Monitors}=Acc) ->
+ Acc#{mons=>[parse_monitor(Bin)|Monitors]};
+get_link(<<"{from,",Bin/binary>>,#{mon_by:=MonitoredBy}=Acc) ->
+ Acc#{mon_by=>[parse_monitor(Bin)|MonitoredBy]};
+get_link(Unexpected,Acc) ->
+ io:format("WARNING: found unexpected data in link list:~n~ts~n",[Unexpected]),
+ Acc.
+
+parse_monitor(MonBin) ->
+ case binary:split(MonBin,[<<",">>,<<"{">>,<<"}">>],[global]) of
+ [PidBin,RefBin,<<>>] ->
+ PidStr = binary_to_list(PidBin),
+ RefStr = binary_to_list(RefBin),
+ {PidStr,PidStr++" ("++RefStr++")"};
+ [<<>>,NameBin,NodeBin,<<>>,RefBin,<<>>] ->
+ %% Named process
+ NameStr = binary_to_list(NameBin),
+ NodeStr = binary_to_list(NodeBin),
+ PidStr = get_pid_from_name(NameStr,NodeStr),
+ RefStr = binary_to_list(RefBin),
+ {PidStr,"{"++NameStr++","++NodeStr++"} ("++RefStr++")"}
+ end.
get_pid_from_name(Name,Node) ->
case ets:lookup(cdv_reg_proc_table,cdv_dump_node_name) of
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 52e6c3e52a..0678b64134 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -21,7 +21,8 @@
-export([get_wx_parent/1,
display_info_dialog/2, display_yes_no_dialog/1,
- display_progress_dialog/3, destroy_progress_dialog/0,
+ display_progress_dialog/3,
+ destroy_progress_dialog/0, sync_destroy_progress_dialog/0,
wait_for_progress/0, report_progress/1,
user_term/3, user_term_multiline/3,
interval_dialog/4, start_timer/1, start_timer/2, stop_timer/1, timer_config/1,
@@ -31,7 +32,8 @@
set_listctrl_col_size/2,
create_status_bar/1,
html_window/1, html_window/2,
- make_obsbin/2
+ make_obsbin/2,
+ add_scroll_entries/2
]).
-include_lib("wx/include/wx.hrl").
@@ -40,6 +42,8 @@
-define(SINGLE_LINE_STYLE, ?wxBORDER_NONE bor ?wxTE_READONLY bor ?wxTE_RICH2).
-define(MULTI_LINE_STYLE, ?SINGLE_LINE_STYLE bor ?wxTE_MULTILINE).
+-define(NUM_SCROLL_ITEMS,8).
+
-define(pulse_timeout,50).
get_wx_parent(Window) ->
@@ -397,17 +401,18 @@ get_box_info({Title, left, List}) -> {Title, ?wxALIGN_LEFT, List};
get_box_info({Title, right, List}) -> {Title, ?wxALIGN_RIGHT, List}.
add_box(Panel, OuterBox, Cursor, Title, Proportion, {Format, List}) ->
- Box = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, Title}]),
+ NumStr = " ("++integer_to_list(length(List))++")",
+ Box = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, Title ++ NumStr}]),
Scroll = wxScrolledWindow:new(Panel),
wxScrolledWindow:enableScrolling(Scroll,true,true),
wxScrolledWindow:setScrollbars(Scroll,1,1,0,0),
ScrollSizer = wxBoxSizer:new(?wxVERTICAL),
wxScrolledWindow:setSizer(Scroll, ScrollSizer),
wxWindow:setBackgroundStyle(Scroll, ?wxBG_STYLE_SYSTEM),
- add_entries(Format, List, Scroll, ScrollSizer, Cursor),
+ Entries = add_entries(Format, List, Scroll, ScrollSizer, Cursor),
wxSizer:add(Box,Scroll,[{proportion,1},{flag,?wxEXPAND}]),
wxSizer:add(OuterBox,Box,[{proportion,Proportion},{flag,?wxEXPAND}]),
- {Scroll,ScrollSizer,length(List)}.
+ {Scroll,ScrollSizer,length(Entries)}.
add_entries(click, List, Scroll, ScrollSizer, Cursor) ->
Add = fun(Link) ->
@@ -415,7 +420,20 @@ add_entries(click, List, Scroll, ScrollSizer, Cursor) ->
wxWindow:setBackgroundStyle(TC, ?wxBG_STYLE_SYSTEM),
wxSizer:add(ScrollSizer,TC, [{flag,?wxEXPAND}])
end,
- [Add(Link) || Link <- List];
+ if length(List) > ?NUM_SCROLL_ITEMS ->
+ {List1,Rest} = lists:split(?NUM_SCROLL_ITEMS,List),
+ LinkEntries = [Add(Link) || Link <- List1],
+ NStr = integer_to_list(length(Rest)),
+ TC = link_entry2(Scroll,
+ {{more,{Rest,Scroll,ScrollSizer}},"more..."},
+ Cursor,
+ "Click to see " ++ NStr ++ " more entries"),
+ wxWindow:setBackgroundStyle(TC, ?wxBG_STYLE_SYSTEM),
+ E = wxSizer:add(ScrollSizer,TC, [{flag,?wxEXPAND}]),
+ LinkEntries ++ [E];
+ true ->
+ [Add(Link) || Link <- List]
+ end;
add_entries(plain, List, Scroll, ScrollSizer, _) ->
Add = fun(String) ->
TC = wxStaticText:new(Scroll, ?wxID_ANY, String),
@@ -423,6 +441,23 @@ add_entries(plain, List, Scroll, ScrollSizer, _) ->
end,
[Add(String) || String <- List].
+add_scroll_entries(MoreEntry,{List, Scroll, ScrollSizer}) ->
+ wx:batch(
+ fun() ->
+ wxSizer:remove(ScrollSizer,?NUM_SCROLL_ITEMS),
+ wxStaticText:destroy(MoreEntry),
+ Cursor = wxCursor:new(?wxCURSOR_HAND),
+ Add = fun(Link) ->
+ TC = link_entry(Scroll, Link, Cursor),
+ wxWindow:setBackgroundStyle(TC, ?wxBG_STYLE_SYSTEM),
+ wxSizer:add(ScrollSizer,TC, [{flag,?wxEXPAND}])
+ end,
+ Entries = [Add(Link) || Link <- List],
+ wxCursor:destroy(Cursor),
+ wxSizer:layout(ScrollSizer),
+ wxSizer:setVirtualSizeHints(ScrollSizer,Scroll),
+ Entries
+ end).
create_box(_Panel, {scroll_boxes,[]}) ->
undefined;
@@ -449,7 +484,7 @@ create_box(Panel, {scroll_boxes,Data}) ->
{_,H} = wxWindow:getSize(Dummy),
wxTextCtrl:destroy(Dummy),
- MaxH = if MaxL > 8 -> 8*H;
+ MaxH = if MaxL > ?NUM_SCROLL_ITEMS -> ?NUM_SCROLL_ITEMS*H;
true -> MaxL*H
end,
[wxWindow:setMinSize(B,{0,MaxH}) || {B,_,_} <- Boxes],
@@ -504,20 +539,22 @@ create_box(Parent, Data) ->
link_entry(Panel, Link) ->
Cursor = wxCursor:new(?wxCURSOR_HAND),
- TC = link_entry2(Panel, to_link(Link), Cursor),
+ TC = link_entry(Panel, Link, Cursor),
wxCursor:destroy(Cursor),
TC.
link_entry(Panel, Link, Cursor) ->
- link_entry2(Panel, to_link(Link), Cursor).
+ link_entry2(Panel,to_link(Link),Cursor).
link_entry2(Panel,{Target,Str},Cursor) ->
+ link_entry2(Panel,{Target,Str},Cursor,"Click to see properties for " ++ Str).
+link_entry2(Panel,{Target,Str},Cursor,ToolTipText) ->
TC = wxStaticText:new(Panel, ?wxID_ANY, Str),
wxWindow:setForegroundColour(TC,?wxBLUE),
wxWindow:setCursor(TC, Cursor),
wxWindow:connect(TC, left_down, [{userData,Target}]),
wxWindow:connect(TC, enter_window),
wxWindow:connect(TC, leave_window),
- ToolTip = wxToolTip:new("Click to see properties for " ++ Str),
+ ToolTip = wxToolTip:new(ToolTipText),
wxWindow:setToolTip(TC, ToolTip),
TC.
@@ -708,6 +745,11 @@ wait_for_progress() ->
destroy_progress_dialog() ->
report_progress(finish).
+sync_destroy_progress_dialog() ->
+ Ref = erlang:monitor(process,?progress_handler),
+ destroy_progress_dialog(),
+ receive {'DOWN',Ref,process,_,_} -> ok end.
+
report_progress(Progress) ->
case whereis(?progress_handler) of
Pid when is_pid(Pid) ->
@@ -787,9 +829,8 @@ progress_dialog_new(Parent,Title,Str) ->
[{style,?wxDEFAULT_DIALOG_STYLE}]),
Panel = wxPanel:new(Dialog),
Sizer = wxBoxSizer:new(?wxVERTICAL),
- Message = wxStaticText:new(Panel, 1, Str),
- Gauge = wxGauge:new(Panel, 2, 100, [{size, {170, -1}},
- {style, ?wxGA_HORIZONTAL}]),
+ Message = wxStaticText:new(Panel, 1, Str,[{size,{220,-1}}]),
+ Gauge = wxGauge:new(Panel, 2, 100, [{style, ?wxGA_HORIZONTAL}]),
SizerFlags = ?wxEXPAND bor ?wxLEFT bor ?wxRIGHT bor ?wxTOP,
wxSizer:add(Sizer, Message, [{flag,SizerFlags},{border,15}]),
wxSizer:add(Sizer, Gauge, [{flag, SizerFlags bor ?wxBOTTOM},{border,15}]),
diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl
index 5908e99e36..f7ae07fb85 100644
--- a/lib/observer/src/observer_port_wx.erl
+++ b/lib/observer/src/observer_port_wx.erl
@@ -242,6 +242,10 @@ handle_event(#wx{id=?ID_REFRESH_INTERVAL},
Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60),
{noreply, State#state{timer=Timer}};
+handle_event(#wx{obj=MoreEntry,event=#wxMouse{type=left_down},userData={more,More}}, State) ->
+ observer_lib:add_scroll_entries(MoreEntry,More),
+ {noreply, State};
+
handle_event(#wx{event=#wxMouse{type=left_down}, userData=TargetPid}, State) ->
observer ! {open_link, TargetPid},
{noreply, State};
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 4ce38e439d..4d3f306a0a 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -120,6 +120,10 @@ handle_event(#wx{id=?REFRESH}, #state{frame=Frame, pid=Pid, pages=Pages, expand_
end,
{noreply, State};
+handle_event(#wx{obj=MoreEntry,event=#wxMouse{type=left_down},userData={more,More}}, State) ->
+ observer_lib:add_scroll_entries(MoreEntry,More),
+ {noreply, State};
+
handle_event(#wx{event=#wxMouse{type=left_down}, userData=TargetPid}, State) ->
observer ! {open_link, TargetPid},
{noreply, State};
diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl
index bb1755f530..b5e94a893a 100644
--- a/lib/observer/test/crashdump_helper.erl
+++ b/lib/observer/test/crashdump_helper.erl
@@ -83,6 +83,7 @@ n1_proc(Creator,_N2,Pid2,Port2,_L) ->
link(OtherPid), % own node
link(Pid2), % external node
erlang:monitor(process,OtherPid),
+ erlang:monitor(process,init), % named process
erlang:monitor(process,Pid2),
code:load_file(?MODULE),
diff --git a/lib/runtime_tools/src/system_information.erl b/lib/runtime_tools/src/system_information.erl
index 92109c9a74..119d7cc3d4 100644
--- a/lib/runtime_tools/src/system_information.erl
+++ b/lib/runtime_tools/src/system_information.erl
@@ -75,43 +75,37 @@ load_report(file, File) -> load_report(data, from_file(File));
load_report(data, Report) ->
ok = start_internal(), gen_server:call(?SERVER, {load_report, Report}, infinity).
-report() -> [
- {init_arguments, init:get_arguments()},
- {code_paths, code:get_path()},
- {code, code()},
- {system_info, erlang_system_info()},
- {erts_compile_info, erlang:system_info(compile_info)},
- {beam_dynamic_libraries, get_dynamic_libraries()},
- {environment_erts, os_getenv_erts_specific()},
- {environment, [split_env(Env) || Env <- os:getenv()]},
- {sanity_check, sanity_check()}
- ].
+report() ->
+ %% This is ugly but beats having to maintain two distinct implementations,
+ %% and we don't really care about memory use since it's internal and
+ %% undocumented.
+ {ok, Fd} = file:open([], [ram, read, write]),
+ to_fd(Fd),
+ {ok, _} = file:position(Fd, bof),
+ from_fd(Fd).
-spec to_file(FileName) -> ok | {error, Reason} when
FileName :: file:name_all(),
Reason :: file:posix() | badarg | terminated | system_limit.
to_file(File) ->
- file:write_file(File, iolist_to_binary([
- io_lib:format("{system_information_version, ~p}.~n", [
- ?REPORT_FILE_VSN
- ]),
- io_lib:format("{system_information, ~p}.~n", [
- report()
- ])
- ])).
+ case file:open(File, [raw, write, binary, delayed_write]) of
+ {ok, Fd} ->
+ try
+ to_fd(Fd)
+ after
+ file:close(Fd)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
from_file(File) ->
- case file:consult(File) of
- {ok, Data} ->
- case get_value([system_information_version], Data) of
- ?REPORT_FILE_VSN ->
- get_value([system_information], Data);
- Vsn ->
- erlang:error({unknown_version, Vsn})
- end;
- _ ->
- erlang:error(bad_report_file)
+ {ok, Fd} = file:open(File, [raw, read]),
+ try
+ from_fd(Fd)
+ after
+ file:close(Fd)
end.
applications() -> applications([]).
@@ -457,61 +451,151 @@ split_env([$=|Vs], Key) -> {lists:reverse(Key), Vs};
split_env([I|Vs], Key) -> split_env(Vs, [I|Key]);
split_env([], KV) -> lists:reverse(KV). % should not happen.
-%% get applications
+from_fd(Fd) ->
+ try
+ [{system_information_version, "1.0"},
+ {system_information, Data}] = consult_fd(Fd),
+ Data
+ catch
+ _:_ -> erlang:error(bad_report_file)
+ end.
-code() ->
- % order is important
- get_code_from_paths(code:get_path()).
+consult_fd(Fd) ->
+ consult_fd_1(Fd, [], {ok, []}).
+consult_fd_1(Fd, Cont0, ReadResult) ->
+ Data =
+ case ReadResult of
+ {ok, Characters} -> Characters;
+ eof -> eof
+ end,
+ case erl_scan:tokens(Cont0, Data, 1) of
+ {done, {ok, Tokens, _}, Next} ->
+ {ok, Term} = erl_parse:parse_term(Tokens),
+ [Term | consult_fd_1(Fd, [], {ok, Next})];
+ {more, Cont} ->
+ consult_fd_1(Fd, Cont, file:read(Fd, 1 bsl 20));
+ {done, {eof, _}, eof} -> []
+ end.
-get_code_from_paths([]) -> [];
-get_code_from_paths([Path|Paths]) ->
- case is_application_path(Path) of
- true ->
- [{application, get_application_from_path(Path)}|get_code_from_paths(Paths)];
- false ->
- [{code, [
- {path, Path},
- {modules, get_modules_from_path(Path)}
- ]}|get_code_from_paths(Paths)]
+%%
+%% Dumps a system_information tuple to the given Fd, writing the term in chunks
+%% to avoid eating too much memory on large systems.
+%%
+
+to_fd(Fd) ->
+ EmitChunk =
+ fun(Format, Args) ->
+ ok = file:write(Fd, io_lib:format(Format, Args))
+ end,
+
+ EmitChunk("{system_information_version, ~p}.~n"
+ "{system_information,["
+ "{init_arguments,~p},"
+ "{code_paths,~p},",
+ [?REPORT_FILE_VSN,
+ init:get_arguments(),
+ code:get_path()]),
+
+ emit_code_info(EmitChunk),
+
+ EmitChunk( "," %% Note the leading comma!
+ "{system_info,~p},"
+ "{erts_compile_info,~p},"
+ "{beam_dynamic_libraries,~p},"
+ "{environment_erts,~p},"
+ "{environment,~p},"
+ "{sanity_check,~p}"
+ "]}.~n",
+ [erlang_system_info(),
+ erlang:system_info(compile_info),
+ get_dynamic_libraries(),
+ os_getenv_erts_specific(),
+ [split_env(Env) || Env <- os:getenv()],
+ sanity_check()]).
+
+%% Emits all modules/applications in the *code path order*
+emit_code_info(EmitChunk) ->
+ EmitChunk("{code, [", []),
+ comma_separated_foreach(EmitChunk,
+ fun(Path) ->
+ case is_application_path(Path) of
+ true -> emit_application_info(EmitChunk, Path);
+ false -> emit_code_path_info(EmitChunk, Path)
+ end
+ end, code:get_path()),
+ EmitChunk("]}", []).
+
+emit_application_info(EmitChunk, Path) ->
+ [Appfile|_] = filelib:wildcard(filename:join(Path, "*.app")),
+ case file:consult(Appfile) of
+ {ok, [{application, App, Info}]} ->
+ RtDeps = proplists:get_value(runtime_dependencies, Info, []),
+ Description = proplists:get_value(description, Info, []),
+ Version = proplists:get_value(vsn, Info, []),
+
+ EmitChunk("{application, {~p,["
+ "{description,~p},"
+ "{vsn,~p},"
+ "{path,~p},"
+ "{runtime_dependencies,~p},",
+ [App, Description, Version, Path, RtDeps]),
+ emit_module_info_from_path(EmitChunk, Path),
+ EmitChunk("]}}", [])
end.
+emit_code_path_info(EmitChunk, Path) ->
+ EmitChunk("{code, ["
+ "{path, ~p},", [Path]),
+ emit_module_info_from_path(EmitChunk, Path),
+ EmitChunk("]}", []).
+
+emit_module_info_from_path(EmitChunk, Path) ->
+ BeamFiles = filelib:wildcard(filename:join(Path, "*.beam")),
+
+ EmitChunk("{modules, [", []),
+ comma_separated_foreach(EmitChunk,
+ fun(Beam) ->
+ emit_module_info(EmitChunk, Beam)
+ end, BeamFiles),
+ EmitChunk("]}", []).
+
+emit_module_info(EmitChunk, Beam) ->
+ %% FIXME: The next three calls load *all* significant chunks onto the heap,
+ %% which may cause us to run out of memory if there's a huge module in the
+ %% code path.
+ {ok,{Mod, Md5}} = beam_lib:md5(Beam),
+
+ CompilerVersion = get_compiler_version(Beam),
+ Native = beam_is_native_compiled(Beam),
+
+ Loaded = case code:is_loaded(Mod) of
+ false -> false;
+ _ -> true
+ end,
+
+ EmitChunk("{~p,["
+ "{loaded,~p},"
+ "{native,~p},"
+ "{compiler,~p},"
+ "{md5,~p}"
+ "]}",
+ [Mod, Loaded, Native, CompilerVersion, hexstring(Md5)]).
+
+comma_separated_foreach(_EmitChunk, _Fun, []) ->
+ ok;
+comma_separated_foreach(_EmitChunk, Fun, [H]) ->
+ Fun(H);
+comma_separated_foreach(EmitChunk, Fun, [H | T]) ->
+ Fun(H),
+ EmitChunk(",", []),
+ comma_separated_foreach(EmitChunk, Fun, T).
+
is_application_path(Path) ->
case filelib:wildcard(filename:join(Path, "*.app")) of
[] -> false;
_ -> true
end.
-get_application_from_path(Path) ->
- [Appfile|_] = filelib:wildcard(filename:join(Path, "*.app")),
- case file:consult(Appfile) of
- {ok, [{application, App, Info}]} ->
- {App, [
- {description, proplists:get_value(description, Info, [])},
- {vsn, proplists:get_value(vsn, Info, [])},
- {path, Path},
- {runtime_dependencies,
- proplists:get_value(runtime_dependencies, Info, [])},
- {modules, get_modules_from_path(Path)}
- ]}
- end.
-
-get_modules_from_path(Path) ->
- [
- begin
- {ok,{Mod, Md5}} = beam_lib:md5(Beam),
- Loaded = case code:is_loaded(Mod) of
- false -> false;
- _ -> true
- end,
- {Mod, [
- {loaded, Loaded},
- {native, beam_is_native_compiled(Beam)},
- {compiler, get_compiler_version(Beam)},
- {md5, hexstring(Md5)}
- ]}
- end || Beam <- filelib:wildcard(filename:join(Path, "*.beam"))
- ].
-
hexstring(Bin) when is_binary(Bin) ->
lists:flatten([io_lib:format("~2.16.0b", [V]) || <<V>> <= Bin]).
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 9258fa011b..179d1562cd 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -280,8 +280,11 @@ end_per_suite(_Config) ->
init_per_group(GroupName, Config) when GroupName == basic_tls;
GroupName == options_tls;
+ GroupName == options;
GroupName == basic;
- GroupName == options ->
+ GroupName == session;
+ GroupName == error_handling_tests_tls
+ ->
ssl_test_lib:clean_tls_version(Config);
init_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml
index 5e631aac21..3b5be75bc0 100644
--- a/lib/stdlib/doc/src/filelib.xml
+++ b/lib/stdlib/doc/src/filelib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -296,7 +296,7 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code>
for a file with the extension <c>.beam</c>, the default rule is to
look for a file with a corresponding extension <c>.erl</c> by
replacing the suffix <c>"ebin"</c> of the object directory path with
- <c>"src"</c>.
+ <c>"src"</c> or <c>"src/*"</c>.
The file search is done through <seealso
marker="#find_file/3"><c>find_file/3</c></seealso>. The directory of
the object file is always tried before any other directory specified
diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml
index d2608ad542..ce19f70df0 100644
--- a/lib/stdlib/doc/src/filename.xml
+++ b/lib/stdlib/doc/src/filename.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -399,15 +399,18 @@ true
tuples <c>{<anno>BinSuffix</anno>, <anno>SourceSuffix</anno>}</c> and
is interpreted as follows: if the end of the directory name where the
object is located matches <c><anno>BinSuffix</anno></c>, then the
- source code directory has the same name, but with
- <c><anno>BinSuffix</anno></c> replaced by
- <c><anno>SourceSuffix</anno></c>. <c><anno>Rules</anno></c> defaults
+ name created by replacing <c><anno>BinSuffix</anno></c> with
+ <c><anno>SourceSuffix</anno></c> is expanded by calling
+ <seealso marker="filelib#wildcard/1">
+ <c>filelib:wildcard/1</c></seealso>.
+ If a regular file is found among the matches, the function
+ returns that location together with <c><anno>Options</anno></c>.
+ Otherwise the next rule is tried, and so on.</p>
+ <p><c><anno>Rules</anno></c> defaults
to:</p>
<code type="none">
-[{"", ""}, {"ebin", "src"}, {"ebin", "esrc"}]</code>
- <p>If the source file is found in the resulting directory, the function
- returns that location together with <c><anno>Options</anno></c>.
- Otherwise the next rule is tried, and so on.</p>
+[{"", ""}, {"ebin", "src"}, {"ebin", "esrc"},
+ {"ebin", "src/*"}, {"ebin", "esrc/*"}]</code>
<p>The function returns <c>{<anno>SourceFile</anno>,
<anno>Options</anno>}</c> if it succeeds.
<c><anno>SourceFile</anno></c> is the absolute path to the source
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index 0f90b3fc33..de839be5cf 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -582,17 +582,16 @@ default_search_rules() ->
{"", ".c", c_source_search_rules()},
{"", ".in", basic_source_search_rules()},
%% plain old directory rules, backwards compatible
- {"", ""},
- {"ebin","src"},
- {"ebin","esrc"}
- ].
+ {"", ""}] ++ erl_source_search_rules().
basic_source_search_rules() ->
(erl_source_search_rules()
++ c_source_search_rules()).
erl_source_search_rules() ->
- [{"ebin","src"}, {"ebin","esrc"}].
+ [{"ebin","src"}, {"ebin","esrc"},
+ {"ebin",filename:join("src", "*")},
+ {"ebin",filename:join("esrc", "*")}].
c_source_search_rules() ->
[{"priv","c_src"}, {"priv","src"}, {"bin","c_src"}, {"bin","src"}, {"", "src"}].
@@ -672,8 +671,16 @@ try_dir_rule(Dir, Filename, From, To) ->
Src = filename:join(NewDir, Filename),
case is_regular(Src) of
true -> {ok, Src};
- false -> error
+ false -> find_regular_file(wildcard(Src))
end;
false ->
error
end.
+
+find_regular_file([]) ->
+ error;
+find_regular_file([File|Files]) ->
+ case is_regular(File) of
+ true -> {ok, File};
+ false -> find_regular_file(Files)
+ end.
diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl
index 930cea347f..7403d52881 100644
--- a/lib/stdlib/test/filelib_SUITE.erl
+++ b/lib/stdlib/test/filelib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
wildcard_one/1,wildcard_two/1,wildcard_errors/1,
fold_files/1,otp_5960/1,ensure_dir_eexist/1,ensure_dir_symlink/1,
wildcard_symlink/1, is_file_symlink/1, file_props_symlink/1,
- find_source/1]).
+ find_source/1, find_source_subdir/1]).
-import(lists, [foreach/2]).
@@ -49,7 +49,7 @@ all() ->
[wildcard_one, wildcard_two, wildcard_errors,
fold_files, otp_5960, ensure_dir_eexist, ensure_dir_symlink,
wildcard_symlink, is_file_symlink, file_props_symlink,
- find_source].
+ find_source, find_source_subdir].
groups() ->
[].
@@ -567,16 +567,18 @@ find_source(Config) when is_list(Config) ->
[{".erl",".yrl",[{"",""}]}]),
{ok, ParserErl} = filelib:find_source(code:which(core_parse)),
+ ParserErlName = filename:basename(ParserErl),
+ ParserErlDir = filename:dirname(ParserErl),
{ok, ParserYrl} = filelib:find_source(ParserErl),
"lry." ++ _ = lists:reverse(ParserYrl),
- {ok, ParserYrl} = filelib:find_source(ParserErl,
+ {ok, ParserYrl} = filelib:find_source(ParserErlName, ParserErlDir,
[{".beam",".erl",[{"ebin","src"}]},
{".erl",".yrl",[{"",""}]}]),
%% find_source automatically checks the local directory regardless of rules
{ok, ParserYrl} = filelib:find_source(ParserErl),
- {ok, ParserYrl} = filelib:find_source(ParserErl,
- [{".beam",".erl",[{"ebin","src"}]}]),
+ {ok, ParserYrl} = filelib:find_source(ParserErlName, ParserErlDir,
+ [{".erl",".yrl",[{"ebin","src"}]}]),
%% find_file does not check the local directory unless in the rules
ParserYrlName = filename:basename(ParserYrl),
@@ -590,3 +592,24 @@ find_source(Config) when is_list(Config) ->
{ok, ParserYrl} = filelib:find_file(ParserYrlName, ParserYrlDir),
{ok, ParserYrl} = filelib:find_file(ParserYrlName, ParserYrlDir, []),
ok.
+
+find_source_subdir(Config) when is_list(Config) ->
+ BeamFile = code:which(inets), % Located in lib/inets/src/inets_app/
+ BeamName = filename:basename(BeamFile),
+ BeamDir = filename:dirname(BeamFile),
+ SrcName = filename:basename(BeamFile, ".beam") ++ ".erl",
+
+ {ok, SrcFile} = filelib:find_source(BeamName, BeamDir),
+ SrcName = filename:basename(SrcFile),
+
+ {error, not_found} =
+ filelib:find_source(BeamName, BeamDir,
+ [{".beam",".erl",[{"ebin","src"}]}]),
+ {ok, SrcFile} =
+ filelib:find_source(BeamName, BeamDir,
+ [{".beam",".erl",
+ [{"ebin",filename:join("src", "*")}]}]),
+
+ {ok, SrcFile} = filelib:find_file(SrcName, BeamDir),
+
+ ok.