aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/beam_utils.erl11
-rw-r--r--lib/compiler/src/sys_core_fold.erl6
-rw-r--r--lib/compiler/test/Makefile1
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl27
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl7
-rw-r--r--lib/compiler/test/compilation_SUITE.erl32
-rw-r--r--lib/compiler/test/compile_SUITE.erl37
-rw-r--r--lib/compiler/test/compile_SUITE_data/attributes.erl23
-rw-r--r--lib/compiler/test/compiler.cover2
-rw-r--r--lib/compiler/test/core_SUITE.erl34
-rw-r--r--lib/compiler/test/core_SUITE_data/eval_is_boolean.core22
-rw-r--r--lib/compiler/test/core_SUITE_data/make_effect_seq.core51
-rw-r--r--lib/compiler/test/core_SUITE_data/nomatch_shadow.core28
-rw-r--r--lib/compiler/test/core_SUITE_data/reversed_annos.core49
-rw-r--r--lib/compiler/test/core_SUITE_data/unsafe_case.core25
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl14
-rw-r--r--lib/compiler/test/parteval_SUITE.erl66
-rw-r--r--lib/compiler/test/parteval_SUITE_data/t1.erl140
-rw-r--r--lib/compiler/test/test_lib.erl9
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl18
-rw-r--r--lib/hipe/flow/Makefile2
-rw-r--r--lib/hipe/flow/cfg.hrl5
-rw-r--r--lib/hipe/icode/Makefile2
-rw-r--r--lib/hipe/opt/Makefile2
-rw-r--r--lib/hipe/rtl/Makefile52
-rw-r--r--lib/inets/doc/src/notes.xml54
-rw-r--r--lib/inets/src/ftp/ftp.erl7
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl140
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl36
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl90
-rw-r--r--lib/inets/src/inets_app/inets.appup.src20
-rw-r--r--lib/inets/test/httpc_SUITE.erl330
-rw-r--r--lib/inets/test/httpd_SUITE.erl1
-rw-r--r--lib/inets/test/httpd_test_lib.erl33
-rw-r--r--lib/inets/vsn.mk4
-rw-r--r--lib/kernel/src/code_server.erl10
-rw-r--r--lib/kernel/src/gen_sctp.erl6
-rw-r--r--lib/kernel/test/code_SUITE.erl49
-rw-r--r--lib/kernel/test/file_SUITE.erl167
-rwxr-xr-xlib/kernel/test/inet_res_SUITE_data/run-named10
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl109
-rw-r--r--lib/observer/src/observer_lib.erl36
-rw-r--r--lib/observer/src/observer_procinfo.erl101
-rw-r--r--lib/observer/src/observer_tv_table.erl109
-rw-r--r--lib/observer/src/observer_tv_wx.erl4
-rw-r--r--lib/os_mon/src/cpu_sup.erl5
-rw-r--r--lib/os_mon/src/memsup.erl3
-rw-r--r--lib/os_mon/src/os_mon.erl20
-rw-r--r--lib/os_mon/src/os_mon_sysinfo.erl6
-rw-r--r--lib/public_key/.gitignore10
-rw-r--r--lib/snmp/doc/src/notes.xml479
-rw-r--r--lib/snmp/doc/src/notes_history.xml351
-rw-r--r--lib/snmp/doc/src/snmp_app.xml109
-rw-r--r--lib/snmp/doc/src/snmp_config.xml104
-rw-r--r--lib/snmp/src/agent/depend.mk2
-rw-r--r--lib/snmp/src/agent/snmp_generic_mnesia.erl5
-rw-r--r--lib/snmp/src/agent/snmp_target_mib.erl16
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl29
-rw-r--r--lib/snmp/src/agent/snmpa.erl4
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl619
-rw-r--r--lib/snmp/src/agent/snmpa_internal.hrl9
-rw-r--r--lib/snmp/src/agent/snmpa_mib_lib.erl20
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl40
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl21
-rw-r--r--lib/snmp/src/agent/snmpa_vacm.erl52
-rw-r--r--lib/snmp/src/app/snmp.appup.src287
-rw-r--r--lib/snmp/test/snmp_agent_test.erl7
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl15
-rw-r--r--lib/snmp/test/snmp_manager_config_test.erl15
-rw-r--r--lib/snmp/test/snmp_manager_test.erl18
-rw-r--r--lib/snmp/test/snmp_test_lib.erl11
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl15
-rw-r--r--lib/snmp/test/snmp_test_mgr_misc.erl15
-rw-r--r--lib/snmp/vsn.mk9
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl69
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_dsa13
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub1
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_rsa16
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub1
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key16
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE.erl6
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/id_rsa15
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub1
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE.erl24
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl26
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_test_lib.erl490
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl76
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/stdlib/src/erl_expand_records.erl17
-rw-r--r--lib/stdlib/src/erl_lint.erl23
-rw-r--r--lib/stdlib/src/error_logger_file_h.erl23
-rw-r--r--lib/stdlib/src/error_logger_tty_h.erl23
-rw-r--r--lib/stdlib/test/erl_expand_records_SUITE.erl12
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl30
-rw-r--r--lib/stdlib/test/ets_SUITE.erl16
-rw-r--r--lib/syntax_tools/src/Makefile2
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl6
-rw-r--r--lib/tools/c_src/Makefile.in27
-rw-r--r--lib/wx/doc/src/Makefile2
105 files changed, 3401 insertions, 1896 deletions
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index a631b8cd69..116ede0bc9 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -474,8 +474,15 @@ check_liveness(R, [{make_fun2,_,_,_,NumFree}|Is], St) ->
end;
check_liveness(R, [{try_end,Y}|Is], St) ->
case R of
- Y -> {killed,St};
- _ -> check_liveness(R, Is, St)
+ Y ->
+ {killed,St};
+ {y,_} ->
+ %% y registers will be used if an exception occurs and
+ %% control transfers to the label given in the previous
+ %% try/2 instruction.
+ {used,St};
+ _ ->
+ check_liveness(R, Is, St)
end;
check_liveness(R, [{catch_end,Y}|Is], St) ->
case R of
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 6ea67741fa..5b155398dc 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2641,9 +2641,9 @@ bsm_leftmost_2([_|Ps], Cs, N, Pos) ->
bsm_leftmost_2([], Cs, _, Pos) ->
bsm_leftmost_1(Cs, Pos).
-%% bsm_notempty(Cs, Pos) -> true|false
+%% bsm_nonempty(Cs, Pos) -> true|false
%% Check if at least one of the clauses matches a non-empty
-%% binary in the given argumet position.
+%% binary in the given argument position.
%%
bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) ->
case nth(Pos, Ps) of
@@ -2704,7 +2704,7 @@ bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) ->
%%
%% But if the clauses can't be freely rearranged, as in
%%
- %% b(Var, <<>>) -> ...
+ %% b(Var, <<X>>) -> ...
%% b(1, 2) -> ...
%%
%% we do have a problem.
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index 2ea50b9112..e13ad4ae90 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -30,7 +30,6 @@ MODULES= \
misc_SUITE \
num_bif_SUITE \
pmod_SUITE \
- parteval_SUITE \
receive_SUITE \
record_SUITE \
trycatch_SUITE \
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 556dc54a8f..902867bc19 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -79,21 +79,18 @@ beam_files(Config) when is_list(Config) ->
%% a grammatical error in the output of the io:format/2 call below. ;-)
?line [_,_|_] = Fs = filelib:wildcard(Wc),
?line io:format("~p files\n", [length(Fs)]),
- beam_files_1(Fs, 0).
-
-beam_files_1([F|Fs], Errors) ->
- ?line case beam_validator:file(F) of
- ok ->
- beam_files_1(Fs, Errors);
- {error,Es} ->
- io:format("File: ~s", [F]),
- io:format("Error: ~p\n", [Es]),
- beam_files_1(Fs, Errors+1)
- end;
-beam_files_1([], 0) -> ok;
-beam_files_1([], Errors) ->
- ?line io:format("~p error(s)", [Errors]),
- ?line ?t:fail().
+ test_lib:p_run(fun do_beam_file/1, Fs).
+
+
+do_beam_file(F) ->
+ case beam_validator:file(F) of
+ ok ->
+ ok;
+ {error,Es} ->
+ io:format("File: ~s", [F]),
+ io:format("Error: ~p\n", [Es]),
+ error
+ end.
compiler_bug(Config) when is_list(Config) ->
%% Check that the compiler returns an error if we try to
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index f8c71a0257..01b7568122 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -342,6 +342,10 @@ partitioned_bs_match(Config) when is_list(Config) ->
?line fc(partitioned_bs_match_2, [4,<<0:17>>],
catch partitioned_bs_match_2(4, <<0:17>>)),
+
+ anything = partitioned_bs_match_3(anything, <<42>>),
+ ok = partitioned_bs_match_3(1, 2),
+
ok.
partitioned_bs_match(_, <<42:8,T/binary>>) ->
@@ -356,6 +360,9 @@ partitioned_bs_match_2(1, <<B:8,T/binary>>) ->
partitioned_bs_match_2(Len, <<_:8,T/binary>>) ->
{Len,T}.
+partitioned_bs_match_3(Var, <<_>>) -> Var;
+partitioned_bs_match_3(1, 2) -> ok.
+
function_clause(Config) when is_list(Config) ->
?line ok = function_clause_1(<<0,7,0,7,42>>),
?line fc(function_clause_1, [<<0,1,2,3>>],
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index 1f17664b54..664582a3a8 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -427,9 +427,9 @@ self_compile_1(Config, Prefix, Opts) ->
%% Compile the compiler again using the newly compiled compiler.
%% (In another node because reloading the compiler would disturb cover.)
CompilerB = Prefix++"compiler_b",
- ?line CompB = make_compiler_dir(Priv, Prefix++"compiler_b"),
+ CompB = make_compiler_dir(Priv, CompilerB),
?line VsnB = VsnA ++ ".0",
- ?line self_compile_node(CompilerB, CompA, CompB, VsnB, Opts),
+ self_compile_node(CompA, CompB, VsnB, Opts),
%% Compare compiler directories.
?line compare_compilers(CompA, CompB),
@@ -438,21 +438,26 @@ self_compile_1(Config, Prefix, Opts) ->
?line CompilerC = Prefix++"compiler_c",
?line CompC = make_compiler_dir(Priv, CompilerC),
?line VsnC = VsnB ++ ".0",
- ?line self_compile_node(CompilerC, CompB, CompC, VsnC, Opts),
+ self_compile_node(CompB, CompC, VsnC, Opts),
?line compare_compilers(CompB, CompC),
?line test_server:timetrap_cancel(Dog),
ok.
-self_compile_node(NodeName0, CompilerDir, OutDir, Version, Opts) ->
- ?line NodeName = list_to_atom(NodeName0),
- ?line Dog = test_server:timetrap(test_server:minutes(10)),
+self_compile_node(CompilerDir, OutDir, Version, Opts) ->
+ ?line Dog = test_server:timetrap(test_server:minutes(15)),
?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)) ++
" -pa " ++ CompilerDir,
- ?line {ok,Node} = start_node(NodeName, Pa),
?line Files = compiler_src(),
- ?line ok = rpc:call(Node, ?MODULE, compile_compiler, [Files,OutDir,Version,Opts]),
- ?line test_server:stop_node(Node),
+
+ %% We don't want the cover server started on the other node,
+ %% because it will load the same cover-compiled code as on this
+ %% node. Use a shielded node to prevent the cover server from
+ %% being started.
+ ?t:run_on_shielded_node(
+ fun() ->
+ compile_compiler(Files, OutDir, Version, Opts)
+ end, Pa),
?line test_server:timetrap_cancel(Dog),
ok.
@@ -465,9 +470,12 @@ compile_compiler(Files, OutDir, Version, InlineOpts) ->
{d,'COMPILER_VSN',"\""++Version++"\""},
nowarn_shadow_vars,
{i,filename:join(code:lib_dir(stdlib), "include")}|InlineOpts],
- lists:foreach(fun(File) ->
- {ok,_} = compile:file(File, Opts)
- end, Files).
+ test_lib:p_run(fun(File) ->
+ case compile:file(File, Opts) of
+ {ok,_} -> ok;
+ _ -> error
+ end
+ end, Files).
compiler_src() ->
filelib:wildcard(filename:join([code:lib_dir(compiler), "src", "*.erl"])).
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index fedbd98f71..640849f2ec 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -29,7 +29,8 @@
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
other_output/1, package_forms/1, encrypted_abstr/1,
bad_record_use1/1, bad_record_use2/1, strict_record/1,
- missing_testheap/1, cover/1, env/1, core/1, asm/1]).
+ missing_testheap/1, cover/1, env/1, core/1, asm/1,
+ sys_pre_attributes/1]).
-export([init/3]).
@@ -45,7 +46,8 @@ all() ->
binary, makedep, cond_and_ifdef, listings, listings_big,
other_output, package_forms, encrypted_abstr,
{group, bad_record_use}, strict_record,
- missing_testheap, cover, env, core, asm].
+ missing_testheap, cover, env, core, asm,
+ sys_pre_attributes].
groups() ->
[{bad_record_use, [],
@@ -785,6 +787,37 @@ do_asm(Beam, Outdir) ->
error
end.
+sys_pre_attributes(Config) ->
+ DataDir = ?config(data_dir, Config),
+ File = filename:join(DataDir, "attributes.erl"),
+ Mod = attributes,
+ CommonOpts = [binary,report,verbose,
+ {parse_transform,sys_pre_attributes}],
+ PreOpts = [{attribute,delete,deleted}],
+ PostOpts = [{attribute,insert,inserted,"value"}],
+ PrePostOpts = [{attribute,replace,replaced,42},
+ {attribute,replace,replace_nonexisting,new}],
+ {ok,Mod,Code} = compile:file(File, PrePostOpts ++ PreOpts ++
+ PostOpts ++ CommonOpts),
+ code:load_binary(Mod, File, Code),
+ Attr = Mod:module_info(attributes),
+ io:format("~p", [Attr]),
+ {inserted,"value"} = lists:keyfind(inserted, 1, Attr),
+ {replaced,[42]} = lists:keyfind(replaced, 1, Attr),
+ {replace_nonexisting,[new]} = lists:keyfind(replace_nonexisting, 1, Attr),
+ false = lists:keymember(deleted, 1, Attr),
+
+ %% Cover more code.
+ {ok,Mod,_} = compile:file(File, PostOpts ++ CommonOpts),
+ {ok,Mod,_} = compile:file(File, CommonOpts -- [verbose]),
+ {ok,Mod,_} = compile:file(File, PreOpts ++ CommonOpts),
+ {ok,Mod,_} = compile:file(File,
+ [{attribute,replace,replaced,42}|CommonOpts]),
+ {ok,Mod,_} = compile:file(File, PrePostOpts ++ PreOpts ++
+ PostOpts ++ CommonOpts --
+ [report,verbose]),
+ ok.
+
%%%
%%% Utilities.
%%%
diff --git a/lib/compiler/test/compile_SUITE_data/attributes.erl b/lib/compiler/test/compile_SUITE_data/attributes.erl
new file mode 100644
index 0000000000..9c3451d272
--- /dev/null
+++ b/lib/compiler/test/compile_SUITE_data/attributes.erl
@@ -0,0 +1,23 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(attributes).
+-deleted(dummy).
+-replaced(dummy).
+
diff --git a/lib/compiler/test/compiler.cover b/lib/compiler/test/compiler.cover
index 9fc4c7dd43..3fd7fc1937 100644
--- a/lib/compiler/test/compiler.cover
+++ b/lib/compiler/test/compiler.cover
@@ -1,5 +1,5 @@
{incl_app,compiler,details}.
%% -*- erlang -*-
-{excl_mods,[sys_pre_attributes,core_scan,core_parse]}.
+{excl_mods,compiler,[core_scan,core_parse]}.
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 26173c62b8..874e02803d 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -21,7 +21,9 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
- dehydrated_itracer/1,nested_tries/1]).
+ dehydrated_itracer/1,nested_tries/1,
+ make_effect_seq/1,eval_is_boolean/1,
+ unsafe_case/1,nomatch_shadow/1,reversed_annos/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -41,7 +43,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [dehydrated_itracer, nested_tries].
+ [dehydrated_itracer,nested_tries,make_effect_seq,
+ eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos].
groups() ->
[].
@@ -61,19 +64,18 @@ end_per_group(_GroupName, Config) ->
?comp(dehydrated_itracer).
?comp(nested_tries).
+?comp(make_effect_seq).
+?comp(eval_is_boolean).
+?comp(unsafe_case).
+?comp(nomatch_shadow).
+?comp(reversed_annos).
try_it(Mod, Conf) ->
- ?line Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)),
- ?line Out = ?config(priv_dir,Conf),
- ?line io:format("Compiling: ~s\n", [Src]),
- ?line CompRc0 = compile:file(Src, [from_core,{outdir,Out},report,time]),
- ?line io:format("Result: ~p\n",[CompRc0]),
- ?line {ok,Mod} = CompRc0,
-
- ?line {module,Mod} = code:load_abs(filename:join(Out, Mod)),
- ?line ok = Mod:Mod(),
- ok.
-
-
-
-
+ Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)),
+ compile_and_load(Src, []),
+ compile_and_load(Src, [no_copt]).
+
+compile_and_load(Src, Opts) ->
+ {ok,Mod,Bin} = compile:file(Src, [from_core,report,time,binary|Opts]),
+ {module,Mod} = code:load_binary(Mod, Mod, Bin),
+ ok = Mod:Mod().
diff --git a/lib/compiler/test/core_SUITE_data/eval_is_boolean.core b/lib/compiler/test/core_SUITE_data/eval_is_boolean.core
new file mode 100644
index 0000000000..6a68b1414d
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/eval_is_boolean.core
@@ -0,0 +1,22 @@
+module 'eval_is_boolean' ['eval_is_boolean'/0]
+ attributes []
+'eval_is_boolean'/0 =
+ %% Line 4
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ case call 'erlang':'is_boolean'(call 'erlang':'make_ref'()) of
+ <'false'> when 'true' ->
+ 'ok'
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'eval_is_boolean',0}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/make_effect_seq.core b/lib/compiler/test/core_SUITE_data/make_effect_seq.core
new file mode 100644
index 0000000000..9941e63b76
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/make_effect_seq.core
@@ -0,0 +1,51 @@
+module 'make_effect_seq' ['make_effect_seq'/0]
+ attributes []
+'make_effect_seq'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ let <_cor0> =
+ catch
+ apply 't'/1
+ ('a')
+ in
+ case _cor0 of
+ <{'EXIT',{'badarg',_cor3}}> when 'true' ->
+ let <_cor4> =
+ apply 't'/1
+ ({'a','b','c'})
+ in
+ case _cor4 of
+ <'ok'> when 'true' ->
+ ( _cor4
+ -| ['compiler_generated'] )
+ ( <_cor2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor2})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'make_effect_seq',0}}] )
+ -| ['compiler_generated'] )
+ end
+'t'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <T> when 'true' ->
+ do
+ {'ok',call 'erlang':'element'(2, T)}
+ 'ok'
+ ( <_cor2> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor2})
+ -| [{'function_name',{'t',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/nomatch_shadow.core b/lib/compiler/test/core_SUITE_data/nomatch_shadow.core
new file mode 100644
index 0000000000..565d9dc0f3
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/nomatch_shadow.core
@@ -0,0 +1,28 @@
+module 'nomatch_shadow' ['nomatch_shadow'/0]
+ attributes []
+'nomatch_shadow'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ apply 't'/1
+ (42)
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'nomatch_shadow',0}}] )
+ -| ['compiler_generated'] )
+ end
+'t'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <42> when 'true' ->
+ 'ok'
+ <42> when 'true' ->
+ 'ok'
+ ( <_cor1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor1})
+ -| [{'function_name',{'t',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/reversed_annos.core b/lib/compiler/test/core_SUITE_data/reversed_annos.core
new file mode 100644
index 0000000000..95b3cd52d6
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/reversed_annos.core
@@ -0,0 +1,49 @@
+module 'reversed_annos' ['reversed_annos'/0]
+ attributes []
+'reversed_annos'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ case apply 't'/1
+ (['a']) of
+ <'ok'> when 'true' ->
+ let <_cor2> =
+ apply 't'/1
+ (['a'|['b']])
+ in
+ case _cor2 of
+ <'ok'> when 'true' ->
+ ( _cor2
+ -| ['compiler_generated'] )
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor0})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'reversed_annos',0}}] )
+ -| ['compiler_generated'] )
+ end
+'t'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <[_cor2|_cor3]> when 'true' ->
+ 'ok'
+ %% Cover v3_kernel:get_line/1.
+ ( <['a']> when 'true' ->
+ 'error'
+ -| [{'file',"reversed_annos.erl"},11] )
+ ( <_cor1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor1})
+ -| [{'function_name',{'t',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/unsafe_case.core b/lib/compiler/test/core_SUITE_data/unsafe_case.core
new file mode 100644
index 0000000000..84cb2c310a
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/unsafe_case.core
@@ -0,0 +1,25 @@
+module 'unsafe_case' ['unsafe_case'/0]
+ attributes []
+'unsafe_case'/0 =
+ fun () ->
+ case apply 't'/1
+ (42) of
+ <{'ok',42}> when 'true' ->
+ 'ok'
+ ( <_cor0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor0})
+ -| ['compiler_generated'] )
+ end
+'t'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <X>
+ when call 'erlang':'>'
+ (_cor0,
+ 0) ->
+ {'ok',X}
+ %% The default case is intentionally missing
+ %% to cover v3_kernel:build_match/2.
+ end
+end
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index ac14d36e82..fb5ec88c9f 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -214,6 +214,7 @@ coverage(Config) when is_list(Config) ->
(catch cover_will_match_list_type({a,b,c,d})),
?line a = cover_remove_non_vars_alias({a,b,c}),
?line error = cover_will_match_lit_list(),
+ {ok,[a]} = cover_is_safe_bool_expr(a),
%% Make sure that we don't attempt to make literals
%% out of pids. (Putting a pid into a #c_literal{}
@@ -249,4 +250,17 @@ cover_will_match_lit_list() ->
error
end.
+cover_is_safe_bool_expr(X) ->
+ %% Use a try...catch that looks like a try...catch in a guard.
+ try
+ %% let V = [X] in {ok,V}
+ %% is_safe_simple([X]) ==> true
+ %% is_safe_bool_expr([X]) ==> false
+ V = [X],
+ {ok,V}
+ catch
+ _:_ ->
+ false
+ end.
+
id(I) -> I.
diff --git a/lib/compiler/test/parteval_SUITE.erl b/lib/compiler/test/parteval_SUITE.erl
deleted file mode 100644
index 6b1ae38c1b..0000000000
--- a/lib/compiler/test/parteval_SUITE.erl
+++ /dev/null
@@ -1,66 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(parteval_SUITE).
-
--include_lib("test_server/include/test_server.hrl").
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2, pe2/1]).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [pe2].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% (This is more general than needed, since we once compiled the same
-%% source code with and without a certain option.)
-compile_and_load(Srcname, Outdir, Module, Options) ->
- ?line Objname = filename:join(Outdir, "t1") ++ code:objfile_extension(),
- ?line {ok, Module} =
- compile:file(Srcname,
- [{d, 'M', Module}, {outdir, Outdir}] ++ Options),
- ?line {ok, B} = file:read_file(Objname),
- ?line {module, Module} = code:load_binary(Module, Objname, B),
- B.
-
-pe2(Config) when is_list(Config) ->
- ?line DataDir = ?config(data_dir, Config),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Srcname = filename:join(DataDir, "t1.erl"),
- ?line compile_and_load(Srcname, PrivDir, t1, []),
-
- ?line {Correct, Actual} = t1:run(),
- ?line Correct = Actual,
- ok.
diff --git a/lib/compiler/test/parteval_SUITE_data/t1.erl b/lib/compiler/test/parteval_SUITE_data/t1.erl
deleted file mode 100644
index 5e4a40f103..0000000000
--- a/lib/compiler/test/parteval_SUITE_data/t1.erl
+++ /dev/null
@@ -1,140 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(?M).
-
--compile(export_all).
-
-%%% The arity-0 functions are all called from the test suite.
-
-f2() ->
- size({1,2}).
-
-i() ->
- case [] of
- [] ->
- ok;
- X ->
- hopp
- end.
-
-e() ->
- case 4+5 of
-% X when X>10 -> kvock; % not removed by BEAM opt.
- {X,X} when list(X) ->
- kvack;
- 9 ->
- ok;
- _ ->
- ko
- end.
-
-f() ->
- element(2,{a,b,c,d}),
- erlang:element(2,{a,b,c,d}),
- "hej" ++ "hopp".
-
-g(X) ->
- if
- float(3.4) ->
- hej;
- X == 5, 4==4 ->
- japp;
- 4 == 4, size({1,2}) == 1 ->
- ok
- end.
-
-g() ->
- {g(3),g(5)}.
-
-bliff() ->
- if
- 3==4 ->
- himm
- end.
-
-fi() ->
- case 4 of
- X when 4==3 ->
- {X};
- 4 ->
- 4;
- _ ->
- ok
- end.
-
-iff() when 3==2 ->
- if
- 3 == 4 ->
- baff;
- 3 == 3 ->
- nipp
- end.
-
-sleep(I) -> receive after I -> ok end.
-
-sleep() ->
- sleep(45).
-
-s() ->
- case 4 of
- 3 ->
- ok
- end.
-
-error_reason(R) when atom(R) ->
- R;
-error_reason(R) when tuple(R) ->
- error_reason(element(1, R)).
-
-plusplus() ->
- ?MODULE ++ " -> mindre snygg felhantering".
-
-call_it(F) ->
- case (catch apply(?MODULE, F, [])) of
- {'EXIT', R0} ->
- {'EXIT', error_reason(R0)};
- V ->
- V
- end.
-
-run() ->
- L = [{f2, 2},
- {i, ok},
- {e, ok},
- {f, "hejhopp"},
- {g, {hej, hej}},
- {bliff, {'EXIT', if_clause}},
- {fi, 4},
- {iff, {'EXIT', function_clause}},
- {sleep, ok},
- {s, {'EXIT', case_clause},
- {plusplus, {'EXIT', badarg}}}],
- Actual = [call_it(F) || {F, _} <- L],
- Correct = [C || {_, C} <- L],
- {Correct, Actual}.
-
-
-%%% Don't call, only compile.
-t(A) ->
- receive
- A when 1==2 ->
- ok;
- B ->
- B
- end.
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 53d8c04169..2295592a38 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -77,7 +77,14 @@ get_data_dir(Config) ->
%% Will fail the test case if there were any errors.
p_run(Test, List) ->
- N = erlang:system_info(schedulers) + 1,
+ N = case ?t:is_cover() of
+ false ->
+ erlang:system_info(schedulers);
+ true ->
+ %% Cover is running. Using more than one process
+ %% will probably only slow down compilation.
+ 1
+ end,
p_run_loop(Test, List, N, [], 0, 0).
p_run_loop(_, [], _, [], Errors, Ws) ->
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index 760cf17225..09a23724fe 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -24,7 +24,7 @@
catch_oops/1,after_oops/1,eclectic/1,rethrow/1,
nested_of/1,nested_catch/1,nested_after/1,
nested_horrid/1,last_call_optimization/1,bool/1,
- plain_catch_coverage/1,andalso_orelse/1]).
+ plain_catch_coverage/1,andalso_orelse/1,get_in_try/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -35,7 +35,7 @@ all() ->
[basic, lean_throw, try_of, try_after, catch_oops,
after_oops, eclectic, rethrow, nested_of, nested_catch,
nested_after, nested_horrid, last_call_optimization,
- bool, plain_catch_coverage, andalso_orelse].
+ bool, plain_catch_coverage, andalso_orelse, get_in_try].
groups() ->
[].
@@ -928,3 +928,17 @@ andalso_orelse_2({Type,Keyval}) ->
zero() ->
0.0.
+
+get_in_try(_) ->
+ undefined = get_valid_line([a], []),
+ ok.
+
+get_valid_line([_|T]=Path, Annotations) ->
+ try
+ get(Path)
+ %% beam_dead used to optimize away an assignment to {y,1}
+ %% because it didn't appear to be used.
+ catch
+ _:not_found ->
+ get_valid_line(T, Annotations)
+ end.
diff --git a/lib/hipe/flow/Makefile b/lib/hipe/flow/Makefile
index 02f610587b..bbe8ef8666 100644
--- a/lib/hipe/flow/Makefile
+++ b/lib/hipe/flow/Makefile
@@ -65,7 +65,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec # +warn_untyped_record
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/flow/cfg.hrl b/lib/hipe/flow/cfg.hrl
index 79fe6162ad..62f47a707a 100644
--- a/lib/hipe/flow/cfg.hrl
+++ b/lib/hipe/flow/cfg.hrl
@@ -36,9 +36,8 @@
is_closure :: boolean(),
closure_arity :: arity(),
is_leaf :: boolean(),
- params :: any(), %% any() since type information is missing?
- info = [] :: list() %% this field seems not needed; take out??
- }).
+ params, % :: list()
+ info = []}). %% this field seems not needed; take out??
%%
%% Data is a triple with a dict of constants, a list of labels and an integer
diff --git a/lib/hipe/icode/Makefile b/lib/hipe/icode/Makefile
index eced90b0ec..bd6436c8b3 100644
--- a/lib/hipe/icode/Makefile
+++ b/lib/hipe/icode/Makefile
@@ -83,7 +83,7 @@ DOC_FILES= $(DOC_MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec # +warn_untyped_record
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/opt/Makefile b/lib/hipe/opt/Makefile
index 74fde26c0b..4596201801 100644
--- a/lib/hipe/opt/Makefile
+++ b/lib/hipe/opt/Makefile
@@ -63,7 +63,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec # +warn_untyped_record
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index 690045b978..48086ec79f 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2011. All Rights Reserved.
+# Copyright Ericsson AB 2001-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -139,27 +139,35 @@ hipe_literals.hrl: $(HIPE_MKLITERALS)
../main/hipe.hrl: ../vsn.mk ../main/hipe.hrl.src
(cd ../main && $(MAKE) hipe.hrl)
-$(EBIN)/hipe_rtl.beam: hipe_rtl.hrl ../main/hipe.hrl
-$(EBIN)/hipe_rtl_arch.beam: hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_binary.beam: hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_bin_util.beam: hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_cfg.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc ../main/hipe.hrl
-$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl
-$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc
-$(EBIN)/hipe_icode2rtl.beam: hipe_literals.hrl ../main/hipe.hrl ../icode/hipe_icode.hrl
-$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_primops.beam: hipe_rtl.hrl ../icode/hipe_icode_primops.hrl hipe_literals.hrl ../main/hipe.hrl
+# 2012-02-24. Please keep these dependencies up to date. They tend to rot.
+# grep ^-include *.erl says a lot, but you need to dig further, e.g:
+# grep ^-include ../flow/*.{hrl,inc}
+$(EBIN)/hipe_icode2rtl.beam: \
+ ../main/hipe.hrl ../icode/hipe_icode.hrl hipe_literals.hrl
+$(EBIN)/hipe_rtl_arch.beam: hipe_literals.hrl
$(EBIN)/hipe_rtl_arith_32.beam: ../main/hipe.hrl hipe_rtl_arith.inc
$(EBIN)/hipe_rtl_arith_64.beam: ../main/hipe.hrl hipe_rtl_arith.inc
-$(EBIN)/hipe_rtl_bs_ops.beam: hipe_literals.hrl ../main/hipe.hrl
-$(EBIN)/hipe_rtl_cerl_bs_ops.beam: ../main/hipe.hrl hipe_literals.hrl hipe_rtl.hrl
-$(EBIN)/hipe_rtl_exceptions.beam: hipe_literals.hrl ../main/hipe.hrl
-$(EBIN)/hipe_rtl_inline_bs_ops.beam: hipe_rtl.hrl hipe_literals.hrl ../main/hipe.hrl
+$(EBIN)/hipe_rtl_binary_construct.beam: \
+ ../main/hipe.hrl hipe_rtl.hrl hipe_literals.hrl
+$(EBIN)/hipe_rtl_binary_match.beam: hipe_literals.hrl
+$(EBIN)/hipe_rtl_cfg.beam: \
+ ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc
+$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl
+$(EBIN)/hipe_rtl.beam: ../main/hipe.hrl hipe_rtl.hrl
+$(EBIN)/hipe_rtl_exceptions.beam: ../main/hipe.hrl hipe_literals.hrl
+$(EBIN)/hipe_rtl_lcm.beam: ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl
+$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc
$(EBIN)/hipe_rtl_mk_switch.beam: ../main/hipe.hrl
-$(EBIN)/hipe_rtl_lcm.beam: ../flow/cfg.hrl hipe_rtl.hrl
-$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl ../flow/cfg.hrl ../icode/hipe_icode_primops.hrl
-$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl ../icode/hipe_icode.hrl
-
-$(EBIN)/hipe_rtl_ssa.beam: ../ssa/hipe_ssa.inc ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc hipe_rtl.hrl
-$(EBIN)/hipe_rtl_ssa_const_prop.beam: hipe_rtl.hrl ../main/hipe.hrl ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc
-$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl ../flow/cfg.hrl hipe_rtl.hrl
+$(EBIN)/hipe_rtl_primops.beam: ../main/hipe.hrl \
+ ../icode/hipe_icode_primops.hrl hipe_rtl.hrl hipe_literals.hrl
+$(EBIN)/hipe_rtl_ssa_avail_expr.beam: ../main/hipe.hrl hipe_rtl.hrl
+$(EBIN)/hipe_rtl_ssa_const_prop.beam: ../main/hipe.hrl hipe_rtl.hrl \
+ ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc
+$(EBIN)/hipe_rtl_ssa.beam: hipe_rtl.hrl \
+ ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc ../ssa/hipe_ssa.inc
+$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl hipe_rtl.hrl
+$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl \
+ ../icode/hipe_icode_primops.hrl
+$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl \
+ ../misc/hipe_consttab.hrl ../icode/hipe_icode.hrl
+$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 369762d0c6..cfc58b8ddb 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2011</year>
+ <year>2002</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,58 @@
<file>notes.xml</file>
</header>
+
+ <section><title>Inets 5.8.1</title>
+ <section><title>Improvements and New Features</title>
+ <p>-</p>
+
+<!--
+ <list>
+ <item>
+ <p>[httpc|httpd] Added support for IPv6 with ssl. </p>
+ <p>Own Id: OTP-5566</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>[ftp] Fails to open IPv6 connection due to badly formatted
+ IPv6 address in EPRT command. The address part of the command
+ incorrectly contained decimal elements instead of hexadecimal. </p>
+ <p>Own Id: OTP-9827</p>
+ <p>Aux Id: Seq 11970 </p>
+ </item>
+
+ <item>
+ <p>[httpc] Bad Keep Alive Mode. When selecting a session,
+ the "state" of the session (specifically if the server has
+ responded) was not taken into account. </p>
+ <p>Own Id: OTP-9847</p>
+ </item>
+
+ <item>
+ <p>[httpc] The client incorrectly streams 404 responses.
+ The documentation specifies that only 200 and 206 responses
+ shall be streamed. </p>
+ <p>Shane Evens</p>
+ <p>Own Id: OTP-9860</p>
+ </item>
+
+ </list>
+ </section>
+
+ </section> <!-- 5.8.1 -->
+
+
<section><title>Inets 5.8</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index b6da92947c..560ee55271 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -1987,17 +1987,14 @@ setup_ctrl_connection(Host, Port, Timeout, State) ->
setup_data_connection(#state{mode = active,
caller = Caller,
csock = CSock} = State) ->
- IntToString = fun(Element) -> integer_to_list(Element) end,
-
case (catch inet:sockname(CSock)) of
{ok, {{_, _, _, _, _, _, _, _} = IP, _}} ->
{ok, LSock} =
gen_tcp:listen(0, [{ip, IP}, {active, false},
inet6, binary, {packet, 0}]),
{ok, Port} = inet:port(LSock),
- Cmd = mk_cmd("EPRT |2|~s:~s:~s:~s:~s:~s:~s:~s|~s|",
- lists:map(IntToString,
- tuple_to_list(IP) ++ [Port])),
+ IpAddress = inet_parse:ntoa(IP),
+ Cmd = mk_cmd("EPRT |2|~s|~p|", [IpAddress, Port]),
send_ctrl_message(State, Cmd),
activate_ctrl_connection(State),
{noreply, State#state{caller = {setup_data_connection,
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 587e24cc8d..bfe9b14ef6 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -157,12 +157,12 @@ info(Pid) ->
%% memory in vain.)
%%--------------------------------------------------------------------
%% Request should not be streamed
-stream(BodyPart, Request = #request{stream = none}, _) ->
+stream(BodyPart, #request{stream = none} = Request, _) ->
?hcrt("stream - none", []),
{BodyPart, Request};
%% Stream to caller
-stream(BodyPart, Request = #request{stream = Self}, Code)
+stream(BodyPart, #request{stream = Self} = Request, Code)
when ((Code =:= 200) orelse (Code =:= 206)) andalso
((Self =:= self) orelse (Self =:= {self, once})) ->
?hcrt("stream - self", [{stream, Self}, {code, Code}]),
@@ -170,17 +170,10 @@ stream(BodyPart, Request = #request{stream = Self}, Code)
{Request#request.id, stream, BodyPart}),
{<<>>, Request};
-stream(BodyPart, Request = #request{stream = Self}, 404)
- when (Self =:= self) orelse (Self =:= {self, once}) ->
- ?hcrt("stream - self with 404", [{stream, Self}]),
- httpc_response:send(Request#request.from,
- {Request#request.id, stream, BodyPart}),
- {<<>>, Request};
-
%% Stream to file
%% This has been moved to start_stream/3
%% We keep this for backward compatibillity...
-stream(BodyPart, Request = #request{stream = Filename}, Code)
+stream(BodyPart, #request{stream = Filename} = Request, Code)
when ((Code =:= 200) orelse (Code =:= 206)) andalso is_list(Filename) ->
?hcrt("stream - filename", [{stream, Filename}, {code, Code}]),
case file:open(Filename, [write, raw, append, delayed_write]) of
@@ -192,7 +185,7 @@ stream(BodyPart, Request = #request{stream = Filename}, Code)
end;
%% Stream to file
-stream(BodyPart, Request = #request{stream = Fd}, Code)
+stream(BodyPart, #request{stream = Fd} = Request, Code)
when ((Code =:= 200) orelse (Code =:= 206)) ->
?hcrt("stream to file", [{stream, Fd}, {code, Code}]),
case file:write(Fd, BodyPart) of
@@ -295,7 +288,7 @@ handle_call(#request{address = Addr} = Request, _,
%% Queue + current
queue:len(NewPipeline) + 1,
client_close = ClientClose},
- httpc_manager:insert_session(NewSession, ProfileName),
+ insert_session(NewSession, ProfileName),
?hcrd("session updated", []),
{reply, ok, State#state{pipeline = NewPipeline,
session = NewSession,
@@ -363,7 +356,7 @@ handle_call(#request{address = Addr} = Request, _,
%% Queue + current
queue:len(NewKeepAlive) + 1,
client_close = ClientClose},
- httpc_manager:insert_session(NewSession, ProfileName),
+ insert_session(NewSession, ProfileName),
?hcrd("session updated", []),
{reply, ok, State#state{keep_alive = NewKeepAlive,
session = NewSession,
@@ -377,7 +370,7 @@ handle_call(#request{address = Addr} = Request, _,
NewSession =
Session#session{queue_length = 1,
client_close = ClientClose},
- httpc_manager:insert_session(NewSession, ProfileName),
+ insert_session(NewSession, ProfileName),
Relaxed =
(Request#request.settings)#http_options.relaxed,
MFA = {httpc_response, parse,
@@ -766,23 +759,52 @@ deliver_answer(Request) ->
%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
%% Purpose: Convert process state when code is changed
%%--------------------------------------------------------------------
-%% code_change(_, #state{request = Request, pipeline = Queue} = State,
-%% [{from, '5.0.1'}, {to, '5.0.2'}]) ->
-%% Settings = new_http_options(Request#request.settings),
-%% NewRequest = Request#request{settings = Settings},
-%% NewQueue = new_queue(Queue, fun new_http_options/1),
-%% {ok, State#state{request = NewRequest, pipeline = NewQueue}};
-
-%% code_change(_, #state{request = Request, pipeline = Queue} = State,
-%% [{from, '5.0.2'}, {to, '5.0.1'}]) ->
-%% Settings = old_http_options(Request#request.settings),
-%% NewRequest = Request#request{settings = Settings},
-%% NewQueue = new_queue(Queue, fun old_http_options/1),
-%% {ok, State#state{request = NewRequest, pipeline = NewQueue}};
+
+code_change(_,
+ #state{session = OldSession,
+ profile_name = ProfileName} = State,
+ upgrade_from_pre_5_8_1) ->
+ case OldSession of
+ {session,
+ Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type} ->
+ NewSession = #session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type},
+ insert_session(NewSession, ProfileName),
+ {ok, State#state{session = NewSession}};
+ _ ->
+ {ok, State}
+ end;
+
+code_change(_,
+ #state{session = OldSession,
+ profile_name = ProfileName} = State,
+ downgrade_to_pre_5_8_1) ->
+ case OldSession of
+ #session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type} ->
+ NewSession = {session,
+ Id, ClientClose, Scheme, Socket, SocketType,
+ QueueLen, Type},
+ insert_session(NewSession, ProfileName),
+ {ok, State#state{session = NewSession}};
+ _ ->
+ {ok, State}
+ end;
code_change(_, State, _) ->
{ok, State}.
+
%% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
%% Auth, Relaxed}) ->
%% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
@@ -1181,7 +1203,7 @@ handle_pipeline(#state{status = pipeline,
case queue:out(State#state.pipeline) of
{empty, _} ->
- ?hcrd("epmty pipeline queue", []),
+ ?hcrd("pipeline queue empty", []),
%% The server may choose too teminate an idle pipeline
%% in this case we want to receive the close message
@@ -1191,9 +1213,8 @@ handle_pipeline(#state{status = pipeline,
%% If a pipeline that has been idle for some time is not
%% closed by the server, the client may want to close it.
- NewState = activate_queue_timeout(TimeOut, State),
- NewSession = Session#session{queue_length = 0},
- httpc_manager:insert_session(NewSession, ProfileName),
+ NewState = activate_queue_timeout(TimeOut, State),
+ update_session(ProfileName, Session, #session.queue_length, 0),
%% Note mfa will be initilized when a new request
%% arrives.
{noreply,
@@ -1203,6 +1224,7 @@ handle_pipeline(#state{status = pipeline,
headers = undefined,
body = undefined}};
{{value, NextRequest}, Pipeline} ->
+ ?hcrd("pipeline queue non-empty", []),
case lists:member(NextRequest#request.id,
State#state.canceled) of
true ->
@@ -1218,7 +1240,7 @@ handle_pipeline(#state{status = pipeline,
Session#session{queue_length =
%% Queue + current
queue:len(Pipeline) + 1},
- httpc_manager:insert_session(NewSession, ProfileName),
+ insert_session(NewSession, ProfileName),
Relaxed =
(NextRequest#request.settings)#http_options.relaxed,
MFA = {httpc_response,
@@ -1257,7 +1279,7 @@ handle_keep_alive_queue(
case queue:out(State#state.keep_alive) of
{empty, _} ->
- ?hcrd("empty keep_alive queue", []),
+ ?hcrd("keep_alive queue empty", []),
%% The server may choose too terminate an idle keep_alive session
%% in this case we want to receive the close message
%% at once and not when trying to send the next
@@ -1266,8 +1288,7 @@ handle_keep_alive_queue(
%% If a keep_alive session has been idle for some time is not
%% closed by the server, the client may want to close it.
NewState = activate_queue_timeout(TimeOut, State),
- NewSession = Session#session{queue_length = 0},
- httpc_manager:insert_session(NewSession, ProfileName),
+ update_session(ProfileName, Session, #session.queue_length, 0),
%% Note mfa will be initilized when a new request
%% arrives.
{noreply,
@@ -1279,6 +1300,7 @@ handle_keep_alive_queue(
}
};
{{value, NextRequest}, KeepAlive} ->
+ ?hcrd("keep_alive queue non-empty", []),
case lists:member(NextRequest#request.id,
State#state.canceled) of
true ->
@@ -1388,10 +1410,10 @@ try_to_enable_pipeline_or_keep_alive(
case (is_pipeline_enabled_client(Session) andalso
httpc_request:is_idempotent(Method)) of
true ->
- httpc_manager:insert_session(Session, ProfileName),
+ insert_session(Session, ProfileName),
State#state{status = pipeline};
false ->
- httpc_manager:insert_session(Session, ProfileName),
+ insert_session(Session, ProfileName),
%% Make sure type is keep_alive in session
%% as it in this case might be pipeline
NewSession = Session#session{type = keep_alive},
@@ -1403,7 +1425,9 @@ try_to_enable_pipeline_or_keep_alive(
end.
answer_request(#request{id = RequestId, from = From} = Request, Msg,
- #state{timers = Timers, profile_name = ProfileName} = State) ->
+ #state{session = Session,
+ timers = Timers,
+ profile_name = ProfileName} = State) ->
?hcrt("answer request", [{request, Request}, {msg, Msg}]),
httpc_response:send(From, Msg),
RequestTimers = Timers#timers.request_timers,
@@ -1412,12 +1436,20 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
Timer = {RequestId, TimerRef},
cancel_timer(TimerRef, {timeout, Request#request.id}),
httpc_manager:request_done(RequestId, ProfileName),
-
+ NewSession = maybe_make_session_available(ProfileName, Session),
+ Timers2 = Timers#timers{request_timers = lists:delete(Timer,
+ RequestTimers)},
State#state{request = Request#request{from = answer_sent},
- timers =
- Timers#timers{request_timers =
- lists:delete(Timer, RequestTimers)}}.
-
+ session = NewSession,
+ timers = Timers2}.
+
+maybe_make_session_available(ProfileName,
+ #session{available = false} = Session) ->
+ update_session(ProfileName, Session, #session.available, true),
+ Session#session{available = true};
+maybe_make_session_available(_ProfileName, Session) ->
+ Session.
+
cancel_timers(#timers{request_timers = ReqTmrs, queue_timer = QTmr}) ->
cancel_timer(QTmr, timeout_queue),
CancelTimer = fun({_, Timer}) -> cancel_timer(Timer, timeout) end,
@@ -1656,6 +1688,28 @@ send_raw(SocketType, Socket, ProcessBody, Acc) ->
end.
+%% ---------------------------------------------------------------------
+%% Session wrappers
+%% ---------------------------------------------------------------------
+
+insert_session(Session, ProfileName) ->
+ httpc_manager:insert_session(Session, ProfileName).
+
+
+update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
+ try
+ begin
+ httpc_manager:update_session(ProfileName, SessionId, Pos, Value)
+ end
+ catch
+ error:undef -> % This could happen during code upgrade
+ Session2 = erlang:setelement(Pos, Session, Value),
+ insert_session(Session2, ProfileName)
+ end.
+
+
+%% ---------------------------------------------------------------------
+
call(Msg, Pid) ->
Timeout = infinity,
call(Msg, Pid, Timeout).
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 1fbbaa8d13..8af752546c 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -115,17 +115,37 @@
}
).
+
-record(session,
{
- id, % {{Host, Port}, HandlerPid}
- client_close, % true | false
- scheme, % http (HTTP/TCP) | https (HTTP/SSL/TCP)
- socket, % Open socket, used by connection
- socket_type, % socket-type, used by connection
- queue_length = 1, % Current length of pipeline or keep-alive queue
- type % pipeline | keep_alive (wait for response before sending new request)
+ %% {{Host, Port}, HandlerPid}
+ id,
+
+ %% true | false
+ client_close,
+
+ %% http (HTTP/TCP) | https (HTTP/SSL/TCP)
+ scheme,
+
+ %% Open socket, used by connection
+ socket,
+
+ %% socket-type, used by connection
+ socket_type,
+
+ %% Current length of pipeline or keep-alive queue
+ queue_length = 1,
+
+ %% pipeline | keep_alive (wait for response before sending new request)
+ type,
+
+ %% true | false
+ %% This will be true, when a response has been received for
+ %% the first request. See type above.
+ available = false
}).
+
-record(http_cookie,
{
domain,
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index a97cbb83f1..453081da21 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,6 +34,7 @@
retry_request/2,
redirect_request/2,
insert_session/2,
+ update_session/4,
delete_session/2,
set_options/2,
store_cookies/3,
@@ -193,6 +194,27 @@ insert_session(Session, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: update_session(ProfileName, SessionId, Pos, Value) -> _
+%% Session - #session{}
+%% ProfileName - atom()
+%%
+%% Description: Update, only one field (Pos) of the session record
+%% identified by the SessionId, the session information
+%% of the httpc manager table <ProfileName>_session_db.
+%% Intended to be called by the httpc request handler process.
+%%--------------------------------------------------------------------
+
+update_session(ProfileName, SessionId, Pos, Value) ->
+ SessionDbName = session_db_name(ProfileName),
+ ?hcrt("update session",
+ [{id, SessionId},
+ {pos, Pos},
+ {value, Value},
+ {profile, ProfileName}]),
+ ets:update_element(SessionDbName, SessionId, {Pos, Value}).
+
+
+%%--------------------------------------------------------------------
%% Function: delete_session(SessionId, ProfileName) -> _
%% SessionId - {{Host, Port}, HandlerPid}
%% ProfileName - atom()
@@ -559,9 +581,70 @@ terminate(_, State) ->
%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
%% Purpose: Convert process state when code is changed
%%--------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
+code_change(_,
+ #state{session_db = SessionDB} = State,
+ upgrade_from_pre_5_8_1) ->
+ Upgrade =
+ fun({session,
+ Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type}) ->
+ {ok, #session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type}};
+ (_) -> % Already upgraded (by handler)
+ ignore
+ end,
+ (catch update_session_table(SessionDB, Upgrade)),
+ {ok, State};
+
+code_change(_,
+ #state{session_db = SessionDB} = State,
+ downgrade_to_pre_5_8_1) ->
+ Downgrade =
+ fun(#session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type}) ->
+ {ok, {session,
+ Id, ClientClose, Scheme, Socket, SocketType,
+ QueueLen, Type}};
+ (_) -> % Already downgraded (by handler)
+ ignore
+ end,
+ (catch update_session_table(SessionDB, Downgrade)),
+ {ok, State};
+
+code_change(_, State, _) ->
{ok, State}.
+%% This function is to catch everything that calls through the cracks...
+update_session_table(SessionDB, Transform) ->
+ ets:safe_fixtable(SessionDB, true),
+ update_session_table(SessionDB, ets:first(SessionDB), Transform),
+ ets:safe_fixtable(SessionDB, false).
+
+update_session_table(_SessionDB, '$end_of_table', _Transform) ->
+ ok;
+update_session_table(SessionDB, Key, Transform) ->
+ case ets:lookup(SessionDB, Key) of
+ [OldSession] ->
+ case Transform(OldSession) of
+ {ok, NewSession} ->
+ ets:insert(SessionDB, NewSession);
+ ignore ->
+ ok
+ end;
+ _ ->
+ ok
+ end,
+ update_session_table(SessionDB, ets:next(SessionDB, Key), Transform).
+
%%--------------------------------------------------------------------
%% Internal functions
@@ -690,6 +773,7 @@ select_session(Method, HostPort, Scheme, SessionType,
scheme = Scheme,
queue_length = '$2',
type = SessionType,
+ available = true,
_ = '_'},
%% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp},
Candidates = ets:match(SessionDb, Pattern),
@@ -727,7 +811,7 @@ pipeline_or_keep_alive(Request, HandlerPid, State) ->
ets:insert(State#state.handler_db, {Request#request.id,
HandlerPid,
Request#request.from});
- _ -> %timeout pipelining failed
+ _ -> % timeout pipelining failed
start_handler(Request, State)
end.
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 779dd8e439..e80cb2a23b 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -1,7 +1,7 @@
%% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,6 +18,15 @@
{"%VSN%",
[
+ {"5.8",
+ [
+ {load_module, ftp, soft_purge, soft_purge, []},
+ {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1},
+ soft_purge, soft_purge, []},
+ {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1},
+ soft_purge, soft_purge, [httpc_handler]}
+ ]
+ },
{"5.7.2",
[
{restart_application, inets}
@@ -40,6 +49,15 @@
}
],
[
+ {"5.8",
+ [
+ {load_module, ftp, soft_purge, soft_purge, []},
+ {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1},
+ soft_purge, soft_purge, []},
+ {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1},
+ soft_purge, soft_purge, [httpc_handler]}
+ ]
+ },
{"5.7.2",
[
{restart_application, inets}
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 6e69c9a469..881266b70a 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -90,6 +90,7 @@ all() ->
parse_url,
options,
headers_as_is,
+ selecting_session,
{group, proxy},
{group, ssl},
{group, stream},
@@ -252,7 +253,7 @@ init_per_testcase(Case, Timeout, Config) ->
%% inets:enable_trace(max, io, httpd),
%% inets:enable_trace(max, io, httpc),
- inets:enable_trace(max, io, all),
+ %% inets:enable_trace(max, io, all),
NewConfig =
case atom_to_list(Case) of
@@ -1765,6 +1766,7 @@ http_stream(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+
http_stream_once(doc) ->
["Test the option stream for asynchrony requests"];
http_stream_once(suite) ->
@@ -1772,12 +1774,12 @@ http_stream_once(suite) ->
http_stream_once(Config) when is_list(Config) ->
p("http_stream_once -> entry with"
"~n Config: ~p", [Config]),
-
+
p("http_stream_once -> set ipfamily to inet", []),
ok = httpc:set_options([{ipfamily, inet}]),
p("http_stream_once -> start dummy server", []),
{DummyServerPid, Port} = dummy_server(ipv4),
-
+
PortStr = integer_to_list(Port),
p("http_stream_once -> once", []),
once(?URL_START ++ PortStr ++ "/once.html"),
@@ -1785,14 +1787,14 @@ http_stream_once(Config) when is_list(Config) ->
once(?URL_START ++ PortStr ++ "/once_chunked.html"),
p("http_stream_once -> dummy", []),
once(?URL_START ++ PortStr ++ "/dummy.html"),
-
+
p("http_stream_once -> stop dummy server", []),
DummyServerPid ! stop,
p("http_stream_once -> set ipfamily to inet6fb4", []),
ok = httpc:set_options([{ipfamily, inet6fb4}]),
p("http_stream_once -> done", []),
ok.
-
+
once(URL) ->
p("once -> issue sync request for ~p", [URL]),
{ok, {{_,200,_}, [_ | _], Body}} =
@@ -2001,6 +2003,7 @@ ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) ->
%%-------------------------------------------------------------------------
+
headers_as_is(doc) ->
["Test the option headers_as_is"];
headers_as_is(suite) ->
@@ -2018,6 +2021,321 @@ headers_as_is(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+
+selecting_session(doc) ->
+ ["Test selection of sessions - OTP-9847"];
+selecting_session(suite) ->
+ [];
+selecting_session(Config) when is_list(Config) ->
+ tsp("selecting_session -> entry with"
+ "~n Config: ~p", [Config]),
+
+ tsp("selecting_session -> set ipfamily to inet"),
+ ok = httpc:set_options([{ipfamily, inet}]),
+
+ tsp("selecting_session -> start server"),
+ {ServerPid, Port} = otp_9847_server(),
+
+ PortStr = integer_to_list(Port),
+ URL = ?URL_START ++ PortStr ++ "/index.html",
+
+ tsp("selecting_session -> issue the first batch (three) requests"),
+ lists:foreach(fun(P) ->
+ tsp("selecting_session:fun1 -> "
+ "send stop request to ~p", [P]),
+ P ! stop
+ end,
+ reqs(URL, ServerPid, 3, 3, false)),
+ tsp("selecting_session -> sleep some (1) to make sure nothing lingers"),
+ ?SLEEP(5000),
+ tsp("selecting_session -> "
+ "instruct the server to reply to the first request"),
+ ServerPid ! {answer, true},
+ receive
+ {answer, true} ->
+ tsp("selecting_session -> "
+ "received ack from server to reply to the first request"),
+ ok
+ end,
+ tsp("selecting_session -> issue the second batch (four) requests"),
+ lists:foreach(fun(P) ->
+ tsp("selecting_session:fun2 -> "
+ "send stop request to ~p", [P]),
+ P ! stop
+ end,
+ reqs(URL, ServerPid, 4, 1, true)),
+ tsp("selecting_session -> sleep some (2) to make sure nothing lingers"),
+ ?SLEEP(5000),
+
+ tsp("selecting_session -> stop server"),
+ ServerPid ! stop,
+ tsp("selecting_session -> set ipfamily (back) to inet6fb4"),
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
+ tsp("selecting_session -> done"),
+ ok.
+
+reqs(URL, ServerPid, NumReqs, NumHandlers, InitialSync) ->
+ tsp("reqs -> entry with"
+ "~n URL: ~p"
+ "~n ServerPid: ~w"
+ "~n NumReqs: ~w"
+ "~n NumHandlers: ~w"
+ "~n InitialSync: ~w",
+ [URL, ServerPid, NumReqs, NumHandlers, InitialSync]),
+ Handlers = reqs2(URL, NumReqs, [], InitialSync),
+ tsp("reqs -> "
+ "~n Handlers: ~w", [Handlers]),
+ case length(Handlers) of
+ NumHandlers ->
+ tsp("reqs -> "
+ "~n NumHandlers: ~w", [NumHandlers]),
+ ServerPid ! num_handlers,
+ receive
+ {num_handlers, NumHandlers} ->
+ tsp("reqs -> received num_handlers with"
+ "~n NumHandlers: ~w", [NumHandlers]),
+ Handlers;
+ {num_handlers, WrongNumHandlers} ->
+ tsp("reqs -> received num_handlers with"
+ "~n WrongNumHandlers: ~w", [WrongNumHandlers]),
+ exit({wrong_num_handlers1, WrongNumHandlers, NumHandlers})
+ end;
+ WrongNumHandlers ->
+ tsp("reqs -> "
+ "~n WrongNumHandlers: ~w", [WrongNumHandlers]),
+ exit({wrong_num_handlers2, WrongNumHandlers, NumHandlers})
+ end.
+
+
+reqs2(_URL, 0, Acc, _Sync) ->
+ lists:reverse(Acc);
+reqs2(URL, Num, Acc, Sync) ->
+ tsp("reqs2 -> entry with"
+ "~n Num: ~w"
+ "~n Sync: ~w", [Num, Sync]),
+ case httpc:request(get, {URL, []}, [], [{sync, Sync}]) of
+ {ok, _Reply} ->
+ tsp("reqs2 -> successful request: ~p", [_Reply]),
+ receive
+ {handler, Handler, _Manager} ->
+ %% This is when a new handler is created
+ tsp("reqs2 -> received handler: ~p", [Handler]),
+ case lists:member(Handler, Acc) of
+ true ->
+ tsp("reqs2 -> duplicate handler"),
+ exit({duplicate_handler, Handler, Num, Acc});
+ false ->
+ tsp("reqs2 -> wait for data ack"),
+ receive
+ {data_received, Handler} ->
+ tsp("reqs2 -> "
+ "received data ack from ~p", [Handler]),
+ case Sync of
+ true ->
+ reqs2(URL, Num-1, [Handler|Acc],
+ false);
+ false ->
+ reqs2(URL, Num-1, [Handler|Acc],
+ Sync)
+ end
+ end
+ end;
+
+ {data_received, Handler} ->
+ tsp("reqs2 -> "
+ "received data ack from ~p", [Handler]),
+ reqs2(URL, Num-1, Acc, false)
+
+ end;
+
+ {error, Reason} ->
+ tsp("reqs2 -> request ~w failed: ~p", [Num, Reason]),
+ exit({request_failed, Reason, Num, Acc})
+ end.
+
+otp_9847_server() ->
+ TC = self(),
+ Pid = spawn_link(fun() -> otp_9847_server_init(TC) end),
+ receive
+ {port, Port} ->
+ {Pid, Port}
+ end.
+
+otp_9847_server_init(TC) ->
+ tsp("otp_9847_server_init -> entry with"
+ "~n TC: ~p", [TC]),
+ {ok, ListenSocket} =
+ gen_tcp:listen(0, [binary, inet, {packet, 0},
+ {reuseaddr,true},
+ {active, false}]),
+ tsp("otp_9847_server_init -> listen socket created: "
+ "~n ListenSocket: ~p", [ListenSocket]),
+ {ok, Port} = inet:port(ListenSocket),
+ tsp("otp_9847_server_init -> Port: ~p", [Port]),
+ TC ! {port, Port},
+ otp_9847_server_main(TC, ListenSocket, false, []).
+
+otp_9847_server_main(TC, ListenSocket, Answer, Handlers) ->
+ tsp("otp_9847_server_main -> entry with"
+ "~n TC: ~p"
+ "~n ListenSocket: ~p"
+ "~n Answer: ~p"
+ "~n Handlers: ~p", [TC, ListenSocket, Answer, Handlers]),
+ case gen_tcp:accept(ListenSocket, 1000) of
+ {ok, Sock} ->
+ tsp("otp_9847_server_main -> accepted"
+ "~n Sock: ~p", [Sock]),
+ {Handler, Mon, Port} = otp_9847_handler(TC, Sock, Answer),
+ tsp("otp_9847_server_main -> handler ~p created for ~w",
+ [Handler, Port]),
+ gen_tcp:controlling_process(Sock, Handler),
+ tsp("otp_9847_server_main -> control transfer"),
+ Handler ! owner,
+ tsp("otp_9847_server_main -> "
+ "handler ~p informed of owner transfer", [Handler]),
+ TC ! {handler, Handler, self()},
+ tsp("otp_9847_server_main -> "
+ "TC ~p informed of handler ~p", [TC, Handler]),
+ otp_9847_server_main(TC, ListenSocket, Answer,
+ [{Handler, Mon, Sock, Port}|Handlers]);
+
+ {error, timeout} ->
+ tsp("otp_9847_server_main -> timeout"),
+ receive
+ {answer, true} ->
+ tsp("otp_9847_server_main -> received answer request"),
+ TC ! {answer, true},
+ otp_9847_server_main(TC, ListenSocket, true, Handlers);
+
+ {'DOWN', _Mon, process, Pid, _Reason} ->
+ %% Could be one of the handlers
+ tsp("otp_9847_server_main -> received DOWN for ~p", [Pid]),
+ otp_9847_server_main(TC, ListenSocket, Answer,
+ lists:keydelete(Pid, 1, Handlers));
+
+ num_handlers ->
+ tsp("otp_9847_server_main -> "
+ "received request for number of handlers (~w)",
+ [length(Handlers)]),
+ TC ! {num_handlers, length(Handlers)},
+ otp_9847_server_main(TC, ListenSocket, Answer, Handlers);
+
+ stop ->
+ tsp("otp_9847_server_main -> received stop request"),
+ %% Stop all handlers (just in case)
+ Pids = [Handler || {Handler, _, _} <- Handlers],
+ lists:foreach(fun(Pid) -> Pid ! stop end, Pids),
+ exit(normal);
+
+ Any ->
+ tsp("otp_9847_server_main -> received"
+ "~n Any: ~p", [Any]),
+ exit({crap, Any})
+
+ after 0 ->
+ tsp("otp_9847_server_main -> nothing in queue"),
+ otp_9847_server_main(TC, ListenSocket, Answer, Handlers)
+ end;
+
+ Error ->
+ exit(Error)
+ end.
+
+
+otp_9847_handler(TC, Sock, Answer) ->
+ tsp("otp_9847_handler -> entry with"
+ "~n TC: ~p"
+ "~n Sock: ~p"
+ "~n Answer: ~p", [TC, Sock, Answer]),
+ Self = self(),
+ {Pid, Mon} =
+ spawn_opt(fun() ->
+ otp_9847_handler_init(TC, Self, Sock, Answer)
+ end,
+ [monitor]),
+ receive
+ {port, Port} ->
+ tsp("otp_9847_handler -> received port message (from ~p)"
+ "~n Port: ~p", [Pid, Port]),
+ {Pid, Mon, Port}
+ end.
+
+
+otp_9847_handler_init(TC, Server, Sock, Answer) ->
+ tsp("otp_9847_handler_init -> entry with"
+ "~n TC: ~p"
+ "~n Server: ~p"
+ "~n Sock: ~p"
+ "~n Answer: ~p", [TC, Server, Sock, Answer]),
+ {ok, Port} = inet:port(Sock),
+ Server ! {port, Port},
+ receive
+ owner ->
+ tsp("otp_9847_handler_init -> "
+ "received owner message - activate socket"),
+ inet:setopts(Sock, [{active, true}]),
+ otp_9847_handler_main(TC, Server, Sock, Answer, [?HTTP_MAX_HEADER_SIZE])
+ end.
+
+otp_9847_handler_main(TC, Server, Sock, Answer, ParseArgs) ->
+ tsp("otp_9847_handler_main -> entry with"
+ "~n TC: ~p"
+ "~n Server: ~p"
+ "~n Sock: ~p"
+ "~n Answer: ~p"
+ "~n ParseArgs: ~p", [TC, Server, Sock, Answer, ParseArgs]),
+ receive
+ stop ->
+ tsp("otp_9847_handler_main -> received stop request"),
+ exit(normal);
+
+ {tcp, Sock, _Data} when Answer =:= false ->
+ tsp("otp_9847_handler_main -> received tcp data - no answer"),
+ TC ! {data_received, self()},
+ inet:setopts(Sock, [{active, true}]),
+ %% Ignore all data
+ otp_9847_handler_main(TC, Server, Sock, Answer, ParseArgs);
+
+ {tcp, Sock, Data} when Answer =:= true ->
+ tsp("otp_9847_handler_main -> received tcp data - answer"),
+ TC ! {data_received, self()},
+ inet:setopts(Sock, [{active, true}]),
+ NewParseArgs = otp_9847_handler_request(Sock, [Data|ParseArgs]),
+ otp_9847_handler_main(TC, Server, Sock, Answer, NewParseArgs);
+
+ {tcp_closed, Sock} ->
+ tsp("otp_9847_handler_main -> received tcp socket closed"),
+ exit(normal);
+
+ {tcp_error, Sock, Reason} ->
+ tsp("otp_9847_handler_main -> socket error: ~p", [Reason]),
+ (catch gen_tcp:close(Sock)),
+ exit(normal)
+
+ %% after 30000 ->
+ %% gen_tcp:close(Sock),
+ %% exit(normal)
+ end.
+
+otp_9847_handler_request(Sock, Args) ->
+ Msg =
+ case httpd_request:parse(Args) of
+ {ok, {_, "/index.html" = _RelUrl, _, _, _}} ->
+ B =
+ "<HTML><BODY>" ++
+ "...some body part..." ++
+ "</BODY></HTML>",
+ Len = integer_to_list(length(B)),
+ "HTTP/1.1 200 ok\r\n" ++
+ "Content-Length:" ++ Len ++ "\r\n\r\n" ++ B
+ end,
+ gen_tcp:send(Sock, Msg),
+ [?HTTP_MAX_HEADER_SIZE].
+
+
+
+%%-------------------------------------------------------------------------
+
options(doc) ->
["Test the option parameters."];
options(suite) ->
@@ -2042,6 +2360,7 @@ options(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+
http_invalid_http(doc) ->
["Test parse error"];
http_invalid_http(suite) ->
@@ -2855,6 +3174,7 @@ otp_8739_dummy_server_main(_Parent, ListenSocket) ->
exit(Error)
end.
+
%%-------------------------------------------------------------------------
initial_server_connect(doc) ->
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 5b571a9649..a4bb8f7159 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -2227,6 +2227,7 @@ ticket_5865(doc) ->
ticket_5865(suite) ->
[];
ticket_5865(Config) ->
+ ?SKIP(as_of_r15_behaviour_of_calendar_has_changed),
Host = ?config(host,Config),
ServerRoot = ?config(server_root, Config),
DocRoot = filename:join([ServerRoot, "htdocs"]),
diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl
index 1c7bb512cc..2f5867559a 100644
--- a/lib/inets/test/httpd_test_lib.erl
+++ b/lib/inets/test/httpd_test_lib.erl
@@ -80,14 +80,18 @@
%% API
%%------------------------------------------------------------------
verify_request(SocketType, Host, Port, Node, RequestStr, Options) ->
- verify_request(SocketType, Host, Port, Node, RequestStr, Options, 30000).
+ verify_request(SocketType, Host, Port, Node, RequestStr,
+ Options, 30000).
verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options)
when is_list(TranspOpts) ->
- verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, 30000);
+ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr,
+ Options, 30000);
verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut)
when (is_integer(TimeOut) orelse (TimeOut =:= infinity)) ->
- verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut).
-verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, TimeOut) ->
+ verify_request(SocketType, Host, Port, [], Node, RequestStr,
+ Options, TimeOut).
+verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr,
+ Options, TimeOut) ->
tsp("verify_request -> entry with"
"~n SocketType: ~p"
"~n Host: ~p"
@@ -259,10 +263,10 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _},
headers = Headers,
body = Body}, Options, N, P) ->
- %% tsp("validate -> entry with"
- %% "~n StatusCode: ~p"
- %% "~n Headers: ~p"
- %% "~n Body: ~p", [StatusCode, Headers, Body]),
+ tsp("validate -> entry with"
+ "~n StatusCode: ~p"
+ "~n Headers: ~p"
+ "~n Body: ~p", [StatusCode, Headers, Body]),
check_version(Version, Options),
case lists:keysearch(statuscode, 1, Options) of
@@ -320,9 +324,9 @@ do_validate(Header, [{header, HeaderField}|Rest], N, P) ->
{value, {LowerHeaderField, _Value}} ->
ok;
false ->
- test_server:fail({missing_header_field, LowerHeaderField, Header});
+ tsf({missing_header_field, LowerHeaderField, Header});
_ ->
- test_server:fail({missing_header_field, LowerHeaderField, Header})
+ tsf({missing_header_field, LowerHeaderField, Header})
end,
do_validate(Header, Rest, N, P);
do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) ->
@@ -331,18 +335,15 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) ->
{value, {LowerHeaderField, Value}} ->
ok;
false ->
- test_server:fail({wrong_header_field_value, LowerHeaderField,
- Header});
+ tsf({wrong_header_field_value, LowerHeaderField, Header});
_ ->
- test_server:fail({wrong_header_field_value, LowerHeaderField,
- Header})
+ tsf({wrong_header_field_value, LowerHeaderField, Header})
end,
do_validate(Header, Rest, N, P);
do_validate(Header,[{no_last_modified, HeaderField}|Rest],N,P) ->
case lists:keysearch(HeaderField,1,Header) of
{value,_} ->
- test_server:fail({wrong_header_field_value, HeaderField,
- Header});
+ tsf({wrong_header_field_value, HeaderField, Header});
_ ->
ok
end,
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 1df4558e45..77eb43a7ed 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2011. All Rights Reserved.
+# Copyright Ericsson AB 2001-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.8
+INETS_VSN = 5.8.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 32a12e2b52..5d4f2eb70c 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1317,15 +1317,21 @@ int_list([H|T]) when is_integer(H) -> int_list(T);
int_list([_|_]) -> false;
int_list([]) -> true.
+load_file(Mod0, {From,_}=Caller, St0) ->
+ Mod = to_atom(Mod0),
+ case pending_on_load(Mod, From, St0) of
+ no -> load_file_1(Mod, Caller, St0);
+ {yes,St} -> {noreply,St}
+ end.
-load_file(Mod, Caller, #state{path=Path,cache=no_cache}=St) ->
+load_file_1(Mod, Caller, #state{path=Path,cache=no_cache}=St) ->
case mod_to_bin(Path, Mod) of
error ->
{reply,{error,nofile},St};
{Mod,Binary,File} ->
try_load_module(File, Mod, Binary, Caller, St)
end;
-load_file(Mod, Caller, #state{cache=Cache}=St0) ->
+load_file_1(Mod, Caller, #state{cache=Cache}=St0) ->
Key = {obj,Mod},
case ets:lookup(Cache, Key) of
[] ->
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 77ca26b845..d8954f0cf7 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -314,7 +314,7 @@ eof_or_abort(S, AssocId, Action) ->
-spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when
Socket :: sctp_socket(),
SndRcvInfo :: #sctp_sndrcvinfo{},
- Data :: binary | iolist(),
+ Data :: binary() | iolist(),
Reason :: term().
%% Full-featured send. Rarely needed.
@@ -331,7 +331,7 @@ send(S, SRI, Data) ->
Socket :: sctp_socket(),
Assoc :: #sctp_assoc_change{} | assoc_id(),
Stream :: integer(),
- Data :: binary | iolist(),
+ Data :: binary() | iolist(),
Reason :: term().
send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data)
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 10ab3e4370..99b0cd2ffb 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -30,9 +30,9 @@
load_cached/1, start_node_with_cache/1, add_and_rehash/1,
where_is_file_cached/1, where_is_file_no_cache/1,
purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1,
- code_archive/1, code_archive2/1, on_load/1,
- big_boot_embedded/1,
- on_load_embedded/1, on_load_errors/1, native_early_modules/1]).
+ code_archive/1, code_archive2/1, on_load/1, on_load_binary/1,
+ on_load_embedded/1, on_load_errors/1, big_boot_embedded/1,
+ native_early_modules/1]).
-export([init_per_testcase/2, end_per_testcase/2,
init_per_suite/1, end_per_suite/1,
@@ -55,8 +55,8 @@ all() ->
add_and_rehash, where_is_file_no_cache,
where_is_file_cached, purge_stacktrace, mult_lib_roots,
bad_erl_libs, code_archive, code_archive2, on_load,
- on_load_embedded, big_boot_embedded, on_load_errors,
- native_early_modules].
+ on_load_binary, on_load_embedded, on_load_errors,
+ big_boot_embedded, native_early_modules].
groups() ->
[].
@@ -1286,6 +1286,45 @@ on_load_wait_for_all([Ref|T]) ->
end;
on_load_wait_for_all([]) -> ok.
+on_load_binary(_) ->
+ Master = on_load_binary_test_case_process,
+ register(Master, self()),
+
+ %% Construct, compile and pretty-print.
+ Mod = on_load_binary,
+ File = atom_to_list(Mod) ++ ".erl",
+ Forms = [{attribute,1,file,{File,1}},
+ {attribute,1,module,Mod},
+ {attribute,2,export,[{ok,0}]},
+ {attribute,3,on_load,{init,0}},
+ {function,5,init,0,
+ [{clause,5,[],[],
+ [{op,6,'!',
+ {atom,6,Master},
+ {tuple,6,[{atom,6,Mod},{call,6,{atom,6,self},[]}]}},
+ {'receive',7,[{clause,8,[{atom,8,go}],[],[{atom,8,ok}]}]}]}]},
+ {function,11,ok,0,[{clause,11,[],[],[{atom,11,true}]}]}],
+ {ok,Mod,Bin} = compile:forms(Forms, [report]),
+ [io:put_chars(erl_pp:form(F)) || F <- Forms],
+
+ {Pid1,Ref1} = spawn_monitor(fun() ->
+ code:load_binary(Mod, File, Bin),
+ true = on_load_binary:ok()
+ end),
+ receive {Mod,OnLoadPid} -> ok end,
+ {Pid2,Ref2} = spawn_monitor(fun() ->
+ true = on_load_binary:ok()
+ end),
+ erlang:yield(),
+ OnLoadPid ! go,
+ receive {'DOWN',Ref1,process,Pid1,Exit1} -> ok end,
+ receive {'DOWN',Ref2,process,Pid2,Exit2} -> ok end,
+ normal = Exit1,
+ normal = Exit2,
+ true = code:delete(on_load_binary),
+ false = code:purge(on_load_binary),
+ ok.
+
on_load_embedded(Config) when is_list(Config) ->
try
on_load_embedded_1(Config)
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 85346762ac..2b6af7e1fb 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -78,7 +78,7 @@
-export([altname/1]).
--export([large_file/1]).
+-export([large_file/1, large_write/1]).
-export([read_line_1/1, read_line_2/1, read_line_3/1,read_line_4/1]).
@@ -92,6 +92,8 @@
-export([bytes/2, iterate/3]).
+%% System probe functions that might be handy to check from the shell
+-export([disc_free/1, memsize/0]).
-include_lib("test_server/include/test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -106,7 +108,7 @@ all() ->
{group, compression}, {group, links}, copy,
delayed_write, read_ahead, segment_read, segment_write,
ipread, pid2name, interleaved_read_write, otp_5814,
- large_file, read_line_1, read_line_2, read_line_3,
+ large_file, large_write, read_line_1, read_line_2, read_line_3,
read_line_4, standard_io].
groups() ->
@@ -143,6 +145,13 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config) when is_list(Config) ->
+ SaslConfig = case application:start(sasl) of
+ {error, {already_started, sasl}} ->
+ [];
+ ok ->
+ [{sasl,started}]
+ end,
+ ok = application:start(os_mon),
case os:type() of
{win32, _} ->
Priv = ?config(priv_dir, Config),
@@ -154,9 +163,9 @@ init_per_suite(Config) when is_list(Config) ->
{ok, _} ->
[]
end,
- ?FILE_INIT(HasAccessTime++Config);
+ ?FILE_INIT(HasAccessTime++Config++SaslConfig);
_ ->
- ?FILE_INIT(Config)
+ ?FILE_INIT(Config++SaslConfig)
end.
end_per_suite(Config) when is_list(Config) ->
@@ -166,6 +175,13 @@ end_per_suite(Config) when is_list(Config) ->
_ ->
ok
end,
+ application:stop(os_mon),
+ case proplists:get_value(sasl, Config) of
+ started ->
+ application:stop(sasl);
+ _Else ->
+ ok
+ end,
?FILE_FINI(Config).
init_per_testcase(_Func, Config) ->
@@ -394,6 +410,7 @@ make_del_dir(Config) when is_list(Config) ->
%% Don't worry ;-) the parent directory should never be empty, right?
?line case ?FILE_MODULE:del_dir('..') of
{error, eexist} -> ok;
+ {error, eacces} -> ok; %OpenBSD
{error, einval} -> ok %FreeBSD
end,
?line {error, enoent} = ?FILE_MODULE:del_dir(""),
@@ -3287,50 +3304,13 @@ large_file(suite) ->
large_file(doc) ->
["Tests positioning in large files (> 4G)"];
large_file(Config) when is_list(Config) ->
- case {os:type(),os:version()} of
- {{win32,nt},_} ->
- do_large_file(Config);
- {{unix,sunos},{A,B,C}}
- when A == 5, B == 5, C >= 1; A == 5, B >= 6; A >= 6 ->
- do_large_file(Config);
- {{unix,Unix},_} when Unix =/= sunos ->
- N = unix_free(Config),
- io:format("Free: ~w KByte~n", [N]),
- if N < 5 * (1 bsl 20) ->
- %% Less than 5 GByte free
- {skipped,"Less than 5 GByte free"};
- true ->
- do_large_file(Config)
- end;
- _ ->
- {skipped,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
- end.
+ run_large_file_test(Config,
+ fun(Name) -> do_large_file(Name) end,
+ "_large_file").
-unix_free(Config) ->
- Cmd = ["df -k '",?config(priv_dir, Config),"'"],
- DF0 = os:cmd(Cmd),
- io:format("$ ~s~n~s", [Cmd,DF0]),
- [$\n|DF1] = lists:dropwhile(fun ($\n) -> false; (_) -> true end, DF0),
- {ok,[N],_} = io_lib:fread(" ~*s ~d", DF1),
- N.
+do_large_file(Name) ->
+ ?line Watchdog = ?t:timetrap(?t:minutes(20)),
-do_large_file(Config) ->
- ?line Watchdog = ?t:timetrap(?t:minutes(5)),
- %%
- ?line Name = filename:join(?config(priv_dir, Config),
- ?MODULE_STRING ++ "_large_file"),
- ?line Tester = self(),
- Deleter =
- spawn(
- fun() ->
- Mref = erlang:monitor(process, Tester),
- receive
- {'DOWN',Mref,_,_,_} -> ok;
- {Tester,done} -> ok
- end,
- ?FILE_MODULE:delete(Name)
- end),
- %%
?line S = "1234567890",
L = length(S),
R = lists:reverse(S),
@@ -3366,15 +3346,36 @@ do_large_file(Config) ->
?line {ok,R} = ?FILE_MODULE:read(F1, L+1),
?line ok = ?FILE_MODULE:close(F1),
%%
- ?line Mref = erlang:monitor(process, Deleter),
- ?line Deleter ! {Tester,done},
- ?line receive {'DOWN',Mref,_,_,_} -> ok end,
- %%
?line ?t:timetrap_cancel(Watchdog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+large_write(Config) when is_list(Config) ->
+ run_large_file_test(Config,
+ fun(Name) -> do_large_write(Name) end,
+ "_large_write").
+
+do_large_write(Name) ->
+ Memsize = memsize(),
+ io:format("Memsize = ~w Bytes~n", [Memsize]),
+ case {erlang:system_info(wordsize),Memsize} of
+ {4,_} ->
+ {skip,"Needs a 64-bit emulator"};
+ {8,N} when N < 6 bsl 30 ->
+ {skip,
+ "This machine has < 6 GB memory: "
+ ++integer_to_list(N)};
+ {8,_} ->
+ Size = 4*1024*1024*1024+1,
+ Bin = <<0:Size/unit:8>>,
+ ok = file:write_file(Name, Bin),
+ {ok,#file_info{size=Size}} = file:read_file_info(Name),
+ ok
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
response_analysis(Module, Function, Arguments) ->
@@ -3950,3 +3951,67 @@ flush(Msgs) ->
after 0 ->
lists:reverse(Msgs)
end.
+
+%%%
+%%% Support for testing large files.
+%%%
+
+run_large_file_test(Config, Run, Name) ->
+ case {os:type(),os:version()} of
+ {{win32,nt},_} ->
+ do_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 = disc_free(?config(priv_dir, Config)),
+ io:format("Free disk: ~w KByte~n", [N]),
+ if N < 5 * (1 bsl 20) ->
+ %% Less than 5 GByte free
+ {skip,"Less than 5 GByte free"};
+ true ->
+ do_run_large_file_test(Config, Run, Name)
+ end;
+ _ ->
+ {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
+ end.
+
+
+do_run_large_file_test(Config, Run, Name0) ->
+ Name = filename:join(?config(priv_dir, Config),
+ ?MODULE_STRING ++ Name0),
+
+ %% Set up a process that will delete this file.
+ Tester = self(),
+ Deleter =
+ spawn(
+ fun() ->
+ Mref = erlang:monitor(process, Tester),
+ receive
+ {'DOWN',Mref,_,_,_} -> ok;
+ {Tester,done} -> ok
+ end,
+ ?FILE_MODULE:delete(Name)
+ end),
+
+ %% Run the test case.
+ Res = Run(Name),
+
+ %% Delete file and finish deleter process.
+ Mref = erlang:monitor(process, Deleter),
+ Deleter ! {Tester,done},
+ receive {'DOWN',Mref,_,_,_} -> ok end,
+
+ Res.
+
+disc_free(Path) ->
+ Data = disksup:get_disk_data(),
+ {_,Tot,Perc} = hd(lists:filter(
+ fun({P,_Size,_Full}) ->
+ lists:prefix(filename:nativename(P),
+ filename:nativename(Path))
+ end, lists:reverse(lists:sort(Data)))),
+ round(Tot * (1-(Perc/100))).
+
+memsize() ->
+ {Tot,_Used,_} = memsup:get_memory_data(),
+ Tot.
diff --git a/lib/kernel/test/inet_res_SUITE_data/run-named b/lib/kernel/test/inet_res_SUITE_data/run-named
index 619e456b3f..211d2c7af7 100755
--- a/lib/kernel/test/inet_res_SUITE_data/run-named
+++ b/lib/kernel/test/inet_res_SUITE_data/run-named
@@ -2,7 +2,7 @@
##
## %CopyrightBegin%
##
-## Copyright Ericsson AB 2009-2011. All Rights Reserved.
+## Copyright Ericsson AB 2009-2012. All Rights Reserved.
##
## The contents of this file are subject to the Erlang Public License,
## Version 1.1, (the "License"); you may not use this file except in
@@ -159,17 +159,17 @@ echo "Command: $NAMED $NAMED_FG -c $CONF_FILE"
$NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null &
NAMED_PID=$!
echo "Pid: $NAMED_PID"
-trap "kill -TERM $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \
+trap "kill $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \
0 1 2 3 15
sleep 5 # Give name server time to load its zone files
-if ps p $NAMED_PID; then
+if ps -p $NAMED_PID >/dev/null 2>&1 || ps p $NAMED_PID >/dev/null 2>&1; then
echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED_PID]..."
while read LINE; do
test :"$LINE" = :'quit' && break
done
+ echo "Closing: Terminating nameserver..."
else
- wait $NAMED_PID; error "$NAMED failed to start"
+ error "$NAMED failed to start"
fi
-echo "Closing: Terminating nameserver..."
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index ccf26ee034..3e2202922c 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -52,6 +52,10 @@
list_dir_limit/1]).
-export([advise/1]).
+-export([large_write/1]).
+
+%% System probe functions that might be handy to check from the shell
+-export([unix_free/1]).
-include_lib("test_server/include/test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -83,7 +87,7 @@ groups() ->
cur_dir_1a, cur_dir_1b]},
{files, [],
[{group, open}, {group, pos}, {group, file_info},
- truncate, sync, datasync, advise]},
+ truncate, sync, datasync, advise, large_write]},
{open, [],
[open1, modes, close, access, read_write, pread_write,
append, exclusive]},
@@ -290,6 +294,7 @@ make_del_dir(Config, Handle, Suffix) ->
%% Don't worry ;-) the parent directory should never be empty, right?
?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of
{error, eexist} -> ok;
+ {error, eacces} -> ok; %OpenBSD
{error, einval} -> ok %FreeBSD
end,
?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]),
@@ -1322,6 +1327,41 @@ advise(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+large_write(Config) when is_list(Config) ->
+ run_large_file_test(Config,
+ fun(Name) -> do_large_write(Name) end,
+ "_large_write").
+
+do_large_write(Name) ->
+ Dog = test_server:timetrap(test_server:minutes(60)),
+ ChunkSize = (256 bsl 20) + 1, % 256 M + 1
+ Chunks = 16, % times 16 -> 4 G + 16
+ Base = 100,
+ Interleave = lists:seq(Base+1, Base+Chunks),
+ Chunk = <<0:ChunkSize/unit:8>>,
+ Data = zip_data(lists:duplicate(Chunks, Chunk), Interleave),
+ Size = Chunks * ChunkSize + Chunks, % 4 G + 32
+ Wordsize = erlang:system_info(wordsize),
+ case prim_file:write_file(Name, Data) of
+ ok when Wordsize =:= 8 ->
+ {ok,#file_info{size=Size}} = file:read_file_info(Name),
+ {ok,Fd} = prim_file:open(Name, [read]),
+ check_large_write(Dog, Fd, ChunkSize, 0, Interleave);
+ {error,einval} when Wordsize =:= 4 ->
+ ok
+ end.
+
+check_large_write(Dog, Fd, ChunkSize, Pos, [X|Interleave]) ->
+ Pos1 = Pos + ChunkSize,
+ {ok,Pos1} = prim_file:position(Fd, {cur,ChunkSize}),
+ {ok,[X]} = prim_file:read(Fd, 1),
+ check_large_write(Dog, Fd, ChunkSize, Pos1+1, Interleave);
+check_large_write(Dog, Fd, _, _, []) ->
+ eof = prim_file:read(Fd, 1),
+ test_server:timetrap_cancel(Dog),
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2044,3 +2084,70 @@ list_dir_limit_cleanup(Dir, Handle, N, Cnt) ->
?PRIM_FILE:delete(Handle, filename:join(Dir, Name)),
list_dir_limit_cleanup(Dir, Handle, N, Cnt+1).
+%%%
+%%% Support for testing large files.
+%%%
+
+run_large_file_test(Config, Run, Name) ->
+ case {os:type(),os:version()} of
+ {{win32,nt},_} ->
+ do_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(?config(priv_dir, Config)),
+ io:format("Free disk: ~w KByte~n", [N]),
+ if N < 5 bsl 20 ->
+ %% Less than 5 GByte free
+ {skip,"Less than 5 GByte free disk"};
+ true ->
+ do_run_large_file_test(Config, Run, Name)
+ end;
+ _ ->
+ {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
+ end.
+
+
+do_run_large_file_test(Config, Run, Name0) ->
+ Name = filename:join(?config(priv_dir, Config),
+ ?MODULE_STRING ++ Name0),
+
+ %% Set up a process that will delete this file.
+ Tester = self(),
+ Deleter =
+ spawn(
+ fun() ->
+ Mref = erlang:monitor(process, Tester),
+ receive
+ {'DOWN',Mref,_,_,_} -> ok;
+ {Tester,done} -> ok
+ end,
+ prim_file:delete(Name)
+ end),
+
+ %% Run the test case.
+ Res = Run(Name),
+
+ %% Delete file and finish deleter process.
+ Mref = erlang:monitor(process, Deleter),
+ Deleter ! {Tester,done},
+ receive {'DOWN',Mref,_,_,_} -> ok end,
+
+ Res.
+
+unix_free(Path) ->
+ Cmd = ["df -k '",Path,"'"],
+ DF0 = os:cmd(Cmd),
+ io:format("$ ~s~n~s", [Cmd,DF0]),
+ Lines = re:split(DF0, "\n", [trim,{return,list}]),
+ Last = lists:last(Lines),
+ RE = "^[^\\s]*\\s+\\d+\\s+\\d+\\s+(\\d+)",
+ {match,[Avail]} = re:run(Last, RE, [{capture,all_but_first,list}]),
+ list_to_integer(Avail).
+
+zip_data([A|As], [B|Bs]) ->
+ [[A,B]|zip_data(As, Bs)];
+zip_data([], Bs) ->
+ Bs;
+zip_data(As, []) ->
+ As.
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 967baa5c7a..5260861497 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -339,17 +339,37 @@ user_term(Parent, Title, Default) ->
?wxID_OK ->
Str = wxTextEntryDialog:getValue(Dialog),
wxTextEntryDialog:destroy(Dialog),
- parse_string(Str);
+ parse_string(ensure_last_is_dot(Str));
?wxID_CANCEL ->
- wxTextEntryDialog:destroy(Dialog)
+ wxTextEntryDialog:destroy(Dialog),
+ cancel
end.
parse_string(Str) ->
try
- {ok, Tokens, _} = erl_scan:string(Str),
- erl_parse:parse_term(Tokens)
- catch _:{badmatch, {error, {_, _, Err}}} ->
- {error, ["Parse error: ", Err]};
- _Err ->
+ Tokens = case erl_scan:string(Str) of
+ {ok, Ts, _} -> Ts;
+ {error, {_SLine, SMod, SError}, _} ->
+ throw(io_lib:format("~s", [SMod:format_error(SError)]))
+ end,
+ case erl_parse:parse_term(Tokens) of
+ {error, {_PLine, PMod, PError}} ->
+ throw(io_lib:format("~s", [PMod:format_error(PError)]));
+ Res -> Res
+ end
+ catch
+ throw:ErrStr ->
+ {error, ErrStr};
+ _:_Err ->
{error, ["Syntax error in: ", Str]}
end.
+
+ensure_last_is_dot([]) ->
+ ".";
+ensure_last_is_dot(String) ->
+ case lists:last(String) =:= $. of
+ true ->
+ String;
+ false ->
+ String ++ "."
+ end.
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index a4c5914c49..ec08d3aff1 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -124,9 +124,14 @@ code_change(_, _, State) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_process_page(Panel, Pid) ->
- Fields = process_info_fields(Pid),
- {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields),
- {FPanel, fun() -> observer_lib:update_info(UpFields, process_info_fields(Pid)) end}.
+ Fields0 = process_info_fields(Pid),
+ {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields0),
+ {FPanel, fun() -> case process_info_fields(Pid) of
+ Fields when is_list(Fields) ->
+ observer_lib:update_info(UpFields, Fields);
+ _ -> ok
+ end
+ end}.
init_text_page(Parent) ->
Style = ?wxTE_MULTILINE bor ?wxTE_RICH2 bor ?wxTE_READONLY,
@@ -144,16 +149,20 @@ init_message_page(Parent, Pid) ->
Number+1}
end,
Update = fun() ->
- {messages,RawMessages} =
- observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, messages]),
- {Messages,_} = lists:mapfoldl(Format, 1, RawMessages),
- Last = wxTextCtrl:getLastPosition(Text),
- wxTextCtrl:remove(Text, 0, Last),
- case Messages =:= [] of
- true ->
- wxTextCtrl:writeText(Text, "No messages");
- false ->
- wxTextCtrl:writeText(Text, Messages)
+ case observer_wx:try_rpc(node(Pid), erlang, process_info,
+ [Pid, messages])
+ of
+ {messages,RawMessages} ->
+ {Messages,_} = lists:mapfoldl(Format, 1, RawMessages),
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ case Messages =:= [] of
+ true ->
+ wxTextCtrl:writeText(Text, "No messages");
+ false ->
+ wxTextCtrl:writeText(Text, Messages)
+ end;
+ _ -> ok
end
end,
Update(),
@@ -162,12 +171,15 @@ init_message_page(Parent, Pid) ->
init_dict_page(Parent, Pid) ->
Text = init_text_page(Parent),
Update = fun() ->
- {dictionary,RawDict} =
- observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]),
- Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict],
- Last = wxTextCtrl:getLastPosition(Text),
- wxTextCtrl:remove(Text, 0, Last),
- wxTextCtrl:writeText(Text, Dict)
+ case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary])
+ of
+ {dictionary,RawDict} ->
+ Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict],
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ wxTextCtrl:writeText(Text, Dict);
+ _ -> ok
+ end
end,
Update(),
{Text, Update}.
@@ -183,24 +195,29 @@ init_stack_page(Parent, Pid) ->
wxListCtrl:setColumnWidth(LCtrl, 1, 300),
wxListItem:destroy(Li),
Update = fun() ->
- {current_stacktrace,RawBt} =
- observer_wx:try_rpc(node(Pid), erlang, process_info,
- [Pid, current_stacktrace]),
- wxListCtrl:deleteAllItems(LCtrl),
- wx:foldl(fun({M, F, A, Info}, Row) ->
- _Item = wxListCtrl:insertItem(LCtrl, Row, ""),
- ?EVEN(Row) andalso
- wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN),
- wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})),
- FileLine = case Info of
- [{file,File},{line,Line}] ->
- io_lib:format("~s:~w", [File,Line]);
- _ ->
- []
- end,
- wxListCtrl:setItem(LCtrl, Row, 1, FileLine),
- Row+1
- end, 0, RawBt)
+ case observer_wx:try_rpc(node(Pid), erlang, process_info,
+ [Pid, current_stacktrace])
+ of
+ {current_stacktrace,RawBt} ->
+ observer_wx:try_rpc(node(Pid), erlang, process_info,
+ [Pid, current_stacktrace]),
+ wxListCtrl:deleteAllItems(LCtrl),
+ wx:foldl(fun({M, F, A, Info}, Row) ->
+ _Item = wxListCtrl:insertItem(LCtrl, Row, ""),
+ ?EVEN(Row) andalso
+ wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN),
+ wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})),
+ FileLine = case Info of
+ [{file,File},{line,Line}] ->
+ io_lib:format("~s:~w", [File,Line]);
+ _ ->
+ []
+ end,
+ wxListCtrl:setItem(LCtrl, Row, 1, FileLine),
+ Row+1
+ end, 0, RawBt);
+ _ -> ok
+ end
end,
Resize = fun(#wx{event=#wxSize{size={W,_}}},Ev) ->
wxEvent:skip(Ev),
@@ -216,7 +233,6 @@ create_menus(MenuBar) ->
observer_lib:create_menus(Menus, MenuBar, new_window).
process_info_fields(Pid) ->
- RawInfo = observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]),
Struct = [{"Overview",
[{"Initial Call", initial_call},
{"Current Function", current_function},
@@ -246,7 +262,12 @@ process_info_fields(Pid) ->
{"GC Min Heap Size", {bytes, get_gc_info(min_heap_size)}},
{"GC FullSweep After", get_gc_info(fullsweep_after)}
]}],
- observer_lib:fill_info(Struct, RawInfo).
+ case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]) of
+ RawInfo when is_list(RawInfo) ->
+ observer_lib:fill_info(Struct, RawInfo);
+ _ ->
+ ok
+ end.
item_list() ->
[ %% backtrace,
diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl
index 31d5f3d632..f432173f57 100644
--- a/lib/observer/src/observer_tv_table.erl
+++ b/lib/observer/src/observer_tv_table.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -58,7 +58,7 @@
source,
tab,
attrs,
- timer
+ timer={false, 30}
}).
-record(opt,
@@ -268,8 +268,8 @@ handle_event(#wx{id=?ID_DELETE},
handle_event(#wx{id=?wxID_CLOSE}, State) ->
{stop, normal, State};
-handle_event(Help = #wx{id=?wxID_HELP}, State = #state{parent=Parent}) ->
- Parent ! Help,
+handle_event(Help = #wx{id=?wxID_HELP}, State) ->
+ observer ! Help,
{noreply, State};
handle_event(#wx{id=?GOTO_ENTRY, event=#wxCommand{cmdString=Str}},
@@ -374,40 +374,51 @@ handle_event(#wx{id=?ID_REFRESH_INTERVAL},
Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60),
{noreply, State#state{timer=Timer}};
-handle_event(Event, State) ->
- io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]),
+handle_event(_Event, State) ->
+ %io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]),
{noreply, State}.
-handle_sync_event(Event, _Obj, _State) ->
- io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]),
+handle_sync_event(_Event, _Obj, _State) ->
+ %io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]),
ok.
-handle_call(Event, From, State) ->
- io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]),
+handle_call(_Event, _From, State) ->
+ %io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]),
{noreply, State}.
-handle_cast(Event, State) ->
- io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]),
+handle_cast(_Event, State) ->
+ %io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]),
{noreply, State}.
handle_info({no_rows, N}, State = #state{grid=Grid, status=StatusBar}) ->
wxListCtrl:setItemCount(Grid, N),
wxStatusBar:setStatusText(StatusBar, io_lib:format("Objects: ~w",[N])),
{noreply, State};
+
handle_info({new_cols, New}, State = #state{grid=Grid, columns=Cols0}) ->
Cols = add_columns(Grid, Cols0, New),
{noreply, State#state{columns=Cols}};
+
handle_info({refresh, Min, Max}, State = #state{grid=Grid}) ->
wxListCtrl:refreshItems(Grid, Min, Max),
{noreply, State};
+
+handle_info(refresh_interval, State = #state{pid=Pid}) ->
+ Pid ! refresh,
+ {noreply, State};
+
handle_info({error, Error}, State = #state{frame=Frame}) ->
- Dlg = wxMessageDialog:new(Frame, Error),
+ ErrorStr =
+ try io_lib:format("~ts", [Error]), Error
+ catch _:_ -> io_lib:format("~p", [Error])
+ end,
+ Dlg = wxMessageDialog:new(Frame, ErrorStr),
wxMessageDialog:showModal(Dlg),
wxMessageDialog:destroy(Dlg),
{noreply, State};
-handle_info(Event, State) ->
- io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, Event]),
+handle_info(_Event, State) ->
+ %% io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, _Event]),
{noreply, State}.
terminate(_Event, #state{pid=Pid, attrs=Attrs}) ->
@@ -588,19 +599,22 @@ search([Str, Row, Dir0, CaseSens],
true -> [];
false -> [caseless]
end,
- {ok, Re} = re:compile(Str, Opt),
Dir = case Dir0 of
true -> 1;
false -> -1
end,
- Res = search(Row, Dir, Re, Table),
+ Res = case re:compile(Str, Opt) of
+ {ok, Re} ->
+ search(Row, Dir, Re, Table);
+ {error, _} -> false
+ end,
Parent ! {self(), Res},
S#holder{search=Res}.
search(Row, Dir, Re, Table) ->
Res = try lists:nth(Row+1, Table) of
Term ->
- Str = io_lib:format("~w", [Term]),
+ Str = format(Term),
re:run(Str, Re)
catch _:_ -> no_more
end,
@@ -613,9 +627,9 @@ search(Row, Dir, Re, Table) ->
get_row(From, Row, Col, Table) ->
case lists:nth(Row+1, Table) of
[Object|_] when Col =:= all ->
- From ! {self(), io_lib:format("~w", [Object])};
+ From ! {self(), format(Object)};
[Object|_] when tuple_size(Object) >= Col ->
- From ! {self(), io_lib:format("~w", [element(Col, Object)])};
+ From ! {self(), format(element(Col, Object))};
_ ->
From ! {self(), ""}
end.
@@ -724,3 +738,58 @@ key_pos(Node, ets, TabId) ->
KeyPos = rpc:call(Node, ets, info, [TabId, keypos]),
is_integer(KeyPos) orelse throw(node_or_table_down),
KeyPos.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+format(Tuple) when is_tuple(Tuple) ->
+ [${ |format_tuple(Tuple, 1, tuple_size(Tuple))];
+format(List) when is_list(List) ->
+ format_list(List);
+format(Bin) when is_binary(Bin), byte_size(Bin) > 100 ->
+ io_lib:format("<<#Bin:~w>>", [byte_size(Bin)]);
+format(Float) when is_float(Float) ->
+ io_lib:format("~.3g", [Float]);
+format(Term) ->
+ io_lib:format("~w", [Term]).
+
+format_tuple(Tuple, I, Max) when I < Max ->
+ [format(element(I, Tuple)), $,|format_tuple(Tuple, I+1, Max)];
+format_tuple(Tuple, Max, Max) ->
+ [format(element(Max, Tuple)), $}];
+format_tuple(_Tuple, 1, 0) ->
+ [$}].
+
+format_list([]) -> "[]";
+format_list(List) ->
+ case printable_list(List) of
+ true -> io_lib:format("\"~ts\"", [List]);
+ false -> [$[ | make_list(List)]
+ end.
+
+make_list([Last]) ->
+ [format(Last), $]];
+make_list([Head|Tail]) ->
+ [format(Head), $,|make_list(Tail)].
+
+%% printable_list([Char]) -> bool()
+%% Return true if CharList is a list of printable characters, else
+%% false.
+
+printable_list([C|Cs]) when is_integer(C), C >= $ , C =< 255 ->
+ printable_list(Cs);
+printable_list([$\n|Cs]) ->
+ printable_list(Cs);
+printable_list([$\r|Cs]) ->
+ printable_list(Cs);
+printable_list([$\t|Cs]) ->
+ printable_list(Cs);
+printable_list([$\v|Cs]) ->
+ printable_list(Cs);
+printable_list([$\b|Cs]) ->
+ printable_list(Cs);
+printable_list([$\f|Cs]) ->
+ printable_list(Cs);
+printable_list([$\e|Cs]) ->
+ printable_list(Cs);
+printable_list([]) -> true;
+printable_list(_Other) -> false. %Everything else is false
diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl
index ad3e8c14ab..b276965f83 100644
--- a/lib/observer/src/observer_tv_wx.erl
+++ b/lib/observer/src/observer_tv_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -313,7 +313,7 @@ display_table_info(Parent0, Node, Source, Table) ->
list_to_strings([]) -> "None";
list_to_strings([A]) -> integer_to_list(A);
-list_to_strings([A,B]) ->
+list_to_strings([A|B]) ->
integer_to_list(A) ++ " ," ++ list_to_strings(B).
handle_error(Foo) ->
diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl
index e414e2c10b..34251178ee 100644
--- a/lib/os_mon/src/cpu_sup.erl
+++ b/lib/os_mon/src/cpu_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -764,8 +764,7 @@ port_receive_cpu_util_entries(_, _, Data) ->
exit({data_mismatch, Data}).
start_portprogram() ->
- Command = filename:join([code:priv_dir(os_mon), "bin", "cpu_sup"]),
- Port = open_port({spawn, Command}, [stream]),
+ Port = os_mon:open_port("cpu_sup", [stream]),
port_command(Port, ?ping),
4711 = port_receive_uint32(Port, 5000),
Port.
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index ba07a529bc..49533da1f7 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -802,8 +802,7 @@ port_init() ->
port_idle(Port).
start_portprogram() ->
- Command = filename:join([code:priv_dir(os_mon), "bin", "memsup"]),
- open_port({spawn, Command}, [{packet, 1}]).
+ os_mon:open_port("memsup",[{packet,1}]).
%% The connected process loops are a bit awkward (several different
%% functions doing almost the same thing) as
diff --git a/lib/os_mon/src/os_mon.erl b/lib/os_mon/src/os_mon.erl
index ef368571db..3098c38808 100644
--- a/lib/os_mon/src/os_mon.erl
+++ b/lib/os_mon/src/os_mon.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
-behaviour(supervisor).
%% API
--export([call/2, call/3, get_env/2]).
+-export([call/2, call/3, get_env/2, open_port/2]).
%% Application callbacks
-export([start/2, stop/1]).
@@ -79,6 +79,22 @@ get_env(Service, Param) ->
Service:param_default(Param)
end.
+open_port(Name, Opts) ->
+ PrivDir = code:priv_dir(os_mon),
+ ReleasedPath = filename:join([PrivDir,"bin",Name]),
+ %% Check os_mon*/priv/bin/Name
+ case filelib:is_regular(ReleasedPath) of
+ true ->
+ erlang:open_port({spawn, ReleasedPath}, Opts);
+ false ->
+ %% Use os_mon*/priv/bin/Arch/Name
+ ArchPath =
+ filename:join(
+ [PrivDir,"bin",erlang:system_info(system_architecture),Name]),
+ erlang:open_port({spawn, ArchPath}, Opts)
+ end.
+
+
%%%-----------------------------------------------------------------
%%% Application callbacks
%%%-----------------------------------------------------------------
diff --git a/lib/os_mon/src/os_mon_sysinfo.erl b/lib/os_mon/src/os_mon_sysinfo.erl
index 5d12bd95d1..080885d5d6 100644
--- a/lib/os_mon/src/os_mon_sysinfo.erl
+++ b/lib/os_mon/src/os_mon_sysinfo.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -108,9 +108,7 @@ code_change(_OldVsn, State, _Extra) ->
%%----------------------------------------------------------------------
start_portprogram() ->
- Command =
- filename:join([code:priv_dir(os_mon),"bin","win32sysinfo.exe"]),
- Port = open_port({spawn,Command}, [{packet,1}]),
+ Port = os_mon:open_port("win32sysinfo.exe", [{packet,1}]),
receive
{Port, {data, [?OK]}} ->
Port;
diff --git a/lib/public_key/.gitignore b/lib/public_key/.gitignore
index db24906676..d30fe62c9d 100644
--- a/lib/public_key/.gitignore
+++ b/lib/public_key/.gitignore
@@ -1,7 +1,7 @@
# public_key
-/lib/public_key/asn1/*.asn1db
-/lib/public_key/asn1/*.erl
-/lib/public_key/asn1/*.hrl
-/lib/public_key/include/OTP-PUB-KEY.hrl
-/lib/public_key/include/PKCS-FRAME.hrl
+asn1/*.asn1db
+asn1/*.erl
+asn1/*.hrl
+include/OTP-PUB-KEY.hrl
+include/PKCS-FRAME.hrl
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 64a0d1a13f..942d943c3c 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,130 @@
<section>
+ <title>SNMP Development Toolkit 4.21.6</title>
+ <p>Version 4.21.6 supports code replacement in runtime from/to
+ version 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and
+ 4.20. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] DoS attack using GET-BULK with large value of
+ MaxRepetitions.
+ A preventive method has been implementing by simply
+ limit the number of varbinds that can be included in
+ a Get-BULK response message. This is specified by the
+ new config option,
+ <seealso marker="snmp_app#agent_gb_max_vbs">gb_max_vbs</seealso>.
+ </p>
+ <p>Own Id: OTP-9700</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Mib server cache gclimit update function incorrectly calls
+ age update function.
+ The gclimit update function,
+ <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1</seealso>,
+ <em>incorrectly</em> called the age update function,
+ <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/2</seealso>. </p>
+ <p>Johan Claesson</p>
+ <p>Own Id: OTP-9868</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ </section> <!-- 4.21.6 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.21.5</title>
+ <p>Version 4.21.5 supports code replacement in runtime from/to
+ version 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and 4.20. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Removed (more) use of old style tuple funs. </p>
+ <p>Own Id: OTP-9783</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Repeated vacm table dumping fails due to file name
+ conflict. When dumping the vacm table to disk, a temoporary
+ file with a fixed name was used. If the table dumping
+ (snmpa_vacm:dump_table/0) was initiated from several different
+ processes in rapid succesion, the dumping could fail because the
+ different processes was simultaniously trying to write to the
+ same file. This problem has been eliminated by creating a unique
+ name for the temporary file. </p>
+ <p>Own Id: OTP-9851</p>
+ <p>Aux Id: Seq 11980</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>foo. </p>
+ <p>Own Id: OTP-9718</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ </section> <!-- 4.21.5 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.21.4</title>
+ <p>This version has never been released for R14B.</p>
<p>Version 4.21.4 supports code replacement in runtime from/to
version 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1, 4.20 and 4.19. </p>
@@ -46,7 +169,7 @@
<list type="bulleted">
<item>
<p>[compiler] Improved version info printout from the
- <seealso marker="snmpc(command)#">MIB compiler frontend escript</seealso>. </p>
+ <seealso marker="snmpc(command)#">MIB compiler frontend escript</seealso>. </p>
<p>Own Id: OTP-9618</p>
</item>
@@ -70,7 +193,6 @@
</list>
</section>
-
<section>
<title>Incompatibilities</title>
<p>-</p>
@@ -78,7 +200,7 @@
<!--
<list type="bulleted">
<item>
- <p>foo. </p>
+ <p>foo. </p>
<p>Own Id: OTP-9718</p>
</item>
@@ -641,355 +763,6 @@ snmp_view_basec_acm_mib:vacmAccessTable(set, RowIndex, Cols).
</section> <!-- 4.18 -->
- <section>
- <title>SNMP Development Toolkit 4.17.1</title>
- <p>Version 4.17.1 supports code replacement in runtime from/to
- version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>When the function FilterMod:accept_recv/2
- returned false the SNMP agent stopped collecting
- messages from UDP.</p>
- <p>Own Id: OTP-8761</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.17.1 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.17</title>
- <p>Version 4.17 supports code replacement in runtime from/to
- version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] Added very basic support for multiple SNMPv3
- EngineIDs in a single agent. See
- <seealso marker="snmpa#send_notification">send_notification/7</seealso>,
- <seealso marker="snmpa_mpd#process_packet">process_packet/7</seealso>,
- <seealso marker="snmpa_mpd#generate_response_msg">generate_response_msg/6</seealso> or
- <seealso marker="snmpa_mpd#generate_msg">generate_msg/6</seealso>
- for more info. </p>
-
- <p>Own Id: OTP-8478</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <p>-</p>
-
- <!--
- <list type="bulleted">
- <item>
- <p>The config utility
- (<seealso marker="snmp#config">snmp:config/0</seealso>)
- generated a default notify.conf
- with a bad name for the standard trap entry (was "stadard trap",
- but should have been "standard trap"). This has been corrected. </p>
- <p>Kenji Rikitake</p>
- <p>Own Id: OTP-8433</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.17 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.16.2</title>
- <p>Version 4.16.2 supports code replacement in runtime from/to
- version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[compiler] The SMI specifies that a table row OID should be
- named: { &lt;tableIdentifier&gt; "1" }. </p>
- <p>A new option has been introduced,
- <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>,
- that allows for a more liberal numbering scheme</p>
- <p>Own Id: OTP-8574</p>
- </item>
-
- <item>
- <p>[agent|manager] Changes to make snmp (forward) compatible with
- the new version of the crypto application (released in R14).
- As of R14, crypto is implemented using NIFs. Also,
- the API is more strict. </p>
- <p>Own Id: OTP-8594</p>
- </item>
-
- <item>
- <p>Auto [agent] Changed default value for the MIB server cache.
- GC is now on by default. </p>
- <p>Own Id: OTP-8648</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>Encode/decode of Counter64 values larger than
- 16#7fffffffffffffff (9223372036854775807) failed. </p>
- <p>Own Id: OTP-8563</p>
- </item>
-
- <item>
- <p>[compiler] Fails to compile non-contiguous BITS. </p>
- <p>Per Hedeland</p>
- <p>Own Id: OTP-8595</p>
- </item>
-
- <item>
- <p>[manager] Raise condition causing the manager server process to
- crash. Unregistering an agent while traffic (set/get-operations)
- is ongoing could cause a crash in the manager server process
- (raise condition). </p>
- <p>Own Id: OTP-8646</p>
- <p>Aux Id: Seq 11585</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.16.2 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.16.1</title>
- <p>Version 4.16.1 supports code replacement in runtime from/to
- version 4.16, 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
- <!--
- <list type="bulleted">
- <item>
- <p>[agent|manager] Entries in the audit trail log can now be
- augmented by a sequence number. </p>
- <p>This is enabled by the <c>seqno</c> option, which is part of the
- <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso>
- config option. </p>
- <p>See the
- <seealso marker="snmp_app#configuration_params">reference manual</seealso>
- or the
- <seealso marker="snmp_config#configuration_params">Configuring the application</seealso>
- chapter of the User's Guide for further info. </p>
-
- <p>Own Id: OTP-8395</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>[manager] Fixed an upgrade/downgrade problem. </p>
- <p>Upgrade/downgrade from/to 4.13.5 did not work for the net-if
- process. This has now been fixed. </p>
- <p>Own Id: OTP-8481</p>
- </item>
-
- <item>
- <p>[agent] A minor mnesia related performance improvement. </p>
- <p>Own Id: OTP-8480</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.16.1 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.16</title>
- <p>Version 4.16 supports code replacement in runtime from/to
- version 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent|manager] Entries in the audit trail log can now be
- augmented by a sequence number. </p>
- <p>This is enabled by the <c>seqno</c> option, which is part of the
- <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso>
- config option. </p>
- <p>See the
- <seealso marker="snmp_app#configuration_params">reference manual</seealso>
- or the
- <seealso marker="snmp_config#configuration_params">Configuring the application</seealso>
- chapter of the User's Guide for further info. </p>
-
- <p>Own Id: OTP-8395</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>[manager] Registration of agents using the config file,
- <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>,
- does not work. This has now been corrected. </p>
- <p>Per Hedeland</p>
- <p>Own Id: OTP-8442</p>
- </item>
-
- <item>
- <p>The config utility
- (<seealso marker="snmp#config">snmp:config/0</seealso>)
- generated a default notify.conf
- with a bad name for the standard trap entry (was "stadard trap",
- but should have been "standard trap"). This has been corrected. </p>
- <p>Kenji Rikitake</p>
- <p>Own Id: OTP-8433</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.16 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.15</title>
-
- <p>Version 4.15 supports code replacement in runtime from/to
- version 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>The documentation is now built with open source tools
- (<em>xsltproc</em> and <em>fop</em>) that exists on most
- platforms. One visible change is that the frames are removed.</p>
- <p>Own Id: OTP-8249</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[manager] When information from an unknown agent is received,
- it was previously delivered to the default user via calls to all
- the functions of the callback API depending on the info type
- (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>).
- The problem was that the <c>TargetName</c> argument was useless
- in this case (only an already known agent has a known/valid
- <c>TargetName</c>, but the <c>TargetName</c> used in these calls
- was generated "on the fly"). </p>
- <p>This has now been changed so that when a message is received
- from an unknown agent, then only
- <seealso marker="snmpm_user#handle_agent">handle_agent</seealso>
- (for the default user) is called, but now this call also has a
- <c>Type</c> argument, which is
- <c>pdu | trap | report | inform</c>, depending on what kind of
- message was actually received, thus making it possible for the
- user to properly analyze the data received. </p>
- <p>To handle this, the
- <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has
- been updated. </p>
- <p>*** POTENTIAL INCOMPATIBILITY ***</p>
- <p>Own Id: OTP-8229</p>
- <!-- <p>Aux Id: Seq 11312</p> -->
- </item>
-
- </list>
-
- </section>
-
- </section> <!-- 4.15 -->
-
-
<!-- section>
<title>Release notes history</title>
<p>For information about older versions see
diff --git a/lib/snmp/doc/src/notes_history.xml b/lib/snmp/doc/src/notes_history.xml
index e833335ffb..023717cd7c 100644
--- a/lib/snmp/doc/src/notes_history.xml
+++ b/lib/snmp/doc/src/notes_history.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2011</year>
+ <year>2004</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,6 +33,355 @@
</header>
<section>
+ <title>SNMP Development Toolkit 4.17.1</title>
+ <p>Version 4.17.1 supports code replacement in runtime from/to
+ version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>When the function FilterMod:accept_recv/2
+ returned false the SNMP agent stopped collecting
+ messages from UDP.</p>
+ <p>Own Id: OTP-8761</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.17.1 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.17</title>
+ <p>Version 4.17 supports code replacement in runtime from/to
+ version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Added very basic support for multiple SNMPv3
+ EngineIDs in a single agent. See
+ <seealso marker="snmpa#send_notification">send_notification/7</seealso>,
+ <seealso marker="snmpa_mpd#process_packet">process_packet/7</seealso>,
+ <seealso marker="snmpa_mpd#generate_response_msg">generate_response_msg/6</seealso> or
+ <seealso marker="snmpa_mpd#generate_msg">generate_msg/6</seealso>
+ for more info. </p>
+
+ <p>Own Id: OTP-8478</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>The config utility
+ (<seealso marker="snmp#config">snmp:config/0</seealso>)
+ generated a default notify.conf
+ with a bad name for the standard trap entry (was "stadard trap",
+ but should have been "standard trap"). This has been corrected. </p>
+ <p>Kenji Rikitake</p>
+ <p>Own Id: OTP-8433</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.17 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.16.2</title>
+ <p>Version 4.16.2 supports code replacement in runtime from/to
+ version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[compiler] The SMI specifies that a table row OID should be
+ named: { &lt;tableIdentifier&gt; "1" }. </p>
+ <p>A new option has been introduced,
+ <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>,
+ that allows for a more liberal numbering scheme</p>
+ <p>Own Id: OTP-8574</p>
+ </item>
+
+ <item>
+ <p>[agent|manager] Changes to make snmp (forward) compatible with
+ the new version of the crypto application (released in R14).
+ As of R14, crypto is implemented using NIFs. Also,
+ the API is more strict. </p>
+ <p>Own Id: OTP-8594</p>
+ </item>
+
+ <item>
+ <p>Auto [agent] Changed default value for the MIB server cache.
+ GC is now on by default. </p>
+ <p>Own Id: OTP-8648</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>Encode/decode of Counter64 values larger than
+ 16#7fffffffffffffff (9223372036854775807) failed. </p>
+ <p>Own Id: OTP-8563</p>
+ </item>
+
+ <item>
+ <p>[compiler] Fails to compile non-contiguous BITS. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-8595</p>
+ </item>
+
+ <item>
+ <p>[manager] Raise condition causing the manager server process to
+ crash. Unregistering an agent while traffic (set/get-operations)
+ is ongoing could cause a crash in the manager server process
+ (raise condition). </p>
+ <p>Own Id: OTP-8646</p>
+ <p>Aux Id: Seq 11585</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.16.2 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.16.1</title>
+ <p>Version 4.16.1 supports code replacement in runtime from/to
+ version 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent|manager] Entries in the audit trail log can now be
+ augmented by a sequence number. </p>
+ <p>This is enabled by the <c>seqno</c> option, which is part of the
+ <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso>
+ config option. </p>
+ <p>See the
+ <seealso marker="snmp_app#configuration_params">reference manual</seealso>
+ or the
+ <seealso marker="snmp_config#configuration_params">Configuring the application</seealso>
+ chapter of the User's Guide for further info. </p>
+
+ <p>Own Id: OTP-8395</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[manager] Fixed an upgrade/downgrade problem. </p>
+ <p>Upgrade/downgrade from/to 4.13.5 did not work for the net-if
+ process. This has now been fixed. </p>
+ <p>Own Id: OTP-8481</p>
+ </item>
+
+ <item>
+ <p>[agent] A minor mnesia related performance improvement. </p>
+ <p>Own Id: OTP-8480</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.16.1 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.16</title>
+ <p>Version 4.16 supports code replacement in runtime from/to
+ version 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent|manager] Entries in the audit trail log can now be
+ augmented by a sequence number. </p>
+ <p>This is enabled by the <c>seqno</c> option, which is part of the
+ <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso>
+ config option. </p>
+ <p>See the
+ <seealso marker="snmp_app#configuration_params">reference manual</seealso>
+ or the
+ <seealso marker="snmp_config#configuration_params">Configuring the application</seealso>
+ chapter of the User's Guide for further info. </p>
+
+ <p>Own Id: OTP-8395</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[manager] Registration of agents using the config file,
+ <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>,
+ does not work. This has now been corrected. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-8442</p>
+ </item>
+
+ <item>
+ <p>The config utility
+ (<seealso marker="snmp#config">snmp:config/0</seealso>)
+ generated a default notify.conf
+ with a bad name for the standard trap entry (was "stadard trap",
+ but should have been "standard trap"). This has been corrected. </p>
+ <p>Kenji Rikitake</p>
+ <p>Own Id: OTP-8433</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.16 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.15</title>
+
+ <p>Version 4.15 supports code replacement in runtime from/to
+ version 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>The documentation is now built with open source tools
+ (<em>xsltproc</em> and <em>fop</em>) that exists on most
+ platforms. One visible change is that the frames are removed.</p>
+ <p>Own Id: OTP-8249</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] When information from an unknown agent is received,
+ it was previously delivered to the default user via calls to all
+ the functions of the callback API depending on the info type
+ (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>).
+ The problem was that the <c>TargetName</c> argument was useless
+ in this case (only an already known agent has a known/valid
+ <c>TargetName</c>, but the <c>TargetName</c> used in these calls
+ was generated "on the fly"). </p>
+ <p>This has now been changed so that when a message is received
+ from an unknown agent, then only
+ <seealso marker="snmpm_user#handle_agent">handle_agent</seealso>
+ (for the default user) is called, but now this call also has a
+ <c>Type</c> argument, which is
+ <c>pdu | trap | report | inform</c>, depending on what kind of
+ message was actually received, thus making it possible for the
+ user to properly analyze the data received. </p>
+ <p>To handle this, the
+ <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has
+ been updated. </p>
+ <p>*** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>Own Id: OTP-8229</p>
+ <!-- <p>Aux Id: Seq 11312</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ </section> <!-- 4.15 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.14</title>
<p>Version 4.14 supports code replacement in runtime from/to
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml
index 694e619da1..f6abe783b3 100644
--- a/lib/snmp/doc/src/snmp_app.xml
+++ b/lib/snmp/doc/src/snmp_app.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -78,7 +78,15 @@
].
</pre>
- <!-- The info below is also found in the snmp_config.xml file -->
+
+ <!--
+ ********************************************************
+
+ The info below is also found in the snmp_config.xml file
+
+ ********************************************************
+ -->
+
<p>Each snmp component has its own set of configuration parameters,
even though some of the types are common to both components. </p>
@@ -92,6 +100,7 @@
{agent_verbosity, verbosity()} |
{discovery, agent_discovery()} |
{versions, versions()} |
+ {gb_max_vbs, gb_max_vbs()} |
{priority, priority()} |
{multi_threaded, multi_threaded()} |
{db_dir, db_dir()} |
@@ -122,8 +131,10 @@
{def_user_data, def_user_data()}
</pre>
+ <marker id="agent_opts_and_types"></marker>
<p>Agent specific config options and types:</p>
<taglist>
+ <marker id="agent_type"></marker>
<tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag>
<item>
<p>If <c>master</c>, one master agent is
@@ -131,6 +142,7 @@
<p>Default is <c>master</c>.</p>
</item>
+ <marker id="agent_disco"></marker>
<tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_discovery_opt() =
@@ -143,6 +155,7 @@
<p>For defaults see the options in <c>agent_discovery_opt()</c>.</p>
</item>
+ <marker id="agent_term_disco_opts"></marker>
<tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_terminating_discovery_opt() =
@@ -160,6 +173,7 @@
</list>
</item>
+ <marker id="agent_orig_disco_opts"></marker>
<tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_originating_discovery_opt() =
@@ -173,6 +187,7 @@
</list>
</item>
+ <marker id="agent_mt"></marker>
<tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, the agent is multi-threaded, with one
@@ -180,11 +195,21 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_data_dir"></marker>
<tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP agent internal db files are stored.</p>
</item>
+ <marker id="agent_gb_max_vbs"></marker>
+ <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>Defines the maximum number of varbinds allowed
+ in a Get-BULK response.</p>
+ <p>Default is <c>1000</c>.</p>
+ </item>
+
+ <marker id="agent_local_db"></marker>
<tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag>
<item>
<p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p>
@@ -192,6 +217,7 @@
<p>For defaults see the options in <c>local_db_opt()</c>.</p>
</item>
+ <marker id="agent_ldb_repair"></marker>
<tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag>
<item>
<p>When starting snmpa_local_db it always tries to open an
@@ -202,6 +228,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="agent_ldb_auto_save"></marker>
<tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag>
<item>
<p>The auto save interval. The table is flushed to disk
@@ -209,6 +236,7 @@
<p>Default is <c>5000</c>.</p>
</item>
+ <marker id="agent_net_if"></marker>
<tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_opt() = {module, agent_net_if_module()} | {verbosity, verbosity()} | {options, agent_net_if_options()}</c></p>
@@ -217,6 +245,7 @@
<p>For defaults see the options in <c>agent_net_if_opt()</c>.</p>
</item>
+ <marker id="agent_ni_module"></marker>
<tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface part for the
@@ -225,6 +254,7 @@
<p>Default is <c>snmpa_net_if</c>.</p>
</item>
+ <marker id="agent_ni_opts"></marker>
<tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_option() = {bind_to, bind_to()} |
@@ -239,12 +269,14 @@
<p>For defaults see the options in <c>agent_net_if_option()</c>.</p>
</item>
+ <marker id="agent_ni_req_limit"></marker>
<tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag>
<item>
<p>Max number of simultaneous requests handled by the agent.</p>
<p>Default is <c>infinity</c>.</p>
</item>
+ <marker id="agent_ni_filter_opts"></marker>
<tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_filter_option() = {module, agent_net_if_filter_module()}</c></p>
@@ -255,6 +287,7 @@
<c>agent_net_if_filter_option()</c>.</p>
</item>
+ <marker id="agent_ni_filter_module"></marker>
<tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface filter part for the
@@ -263,6 +296,7 @@
<p>Default is <c>snmpa_net_if_filter</c>.</p>
</item>
+ <marker id="agent_mibs"></marker>
<tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag>
<item>
<p>Specifies a list of MIBs (including path) that defines which MIBs
@@ -277,6 +311,7 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="agent_mib_storage"></marker>
<tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag>
<item>
<p>Specifies how info retrieved from the mibs will be stored.</p>
@@ -302,6 +337,7 @@
mnesia/dets table already exist.</p>
</item>
+ <marker id="agent_mib_server"></marker>
<tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
<item>
<p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p>
@@ -309,6 +345,7 @@
<p>For defaults see the options in <c>mib_server_opt()</c>.</p>
</item>
+ <marker id="agent_ms_meo"></marker>
<tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag>
<item>
<p>If this value is false, then when loading a mib each mib-
@@ -318,6 +355,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_teo"></marker>
<tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag>
<item>
<p>If this value is false, then when loading a mib each trap
@@ -327,6 +365,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_cache"></marker>
<tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag>
<item>
<p>Shall the agent utilize the mib server lookup cache or not.</p>
@@ -334,6 +373,7 @@
default values apply).</p>
</item>
+ <marker id="agent_ms_cache_opts"></marker>
<tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag>
<item>
<p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p>
@@ -341,6 +381,7 @@
<p>For defaults see the options in <c>mibs_cache_opt()</c>.</p>
</item>
+ <marker id="agent_ms_cache_autogc"></marker>
<tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag>
<item>
<p>Defines if the mib server shall perform cache gc automatically or
@@ -349,6 +390,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="agent_ms_cache_age"></marker>
<tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag>
<item>
<p>Defines how old the entries in the cache will be allowed before
@@ -358,6 +400,7 @@
<p>Default is <c>10 timutes</c>.</p>
</item>
+ <marker id="agent_ms_cache_gclimit"></marker>
<tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag>
<item>
<p>When performing a GC, this is the max number of cache entries
@@ -368,6 +411,7 @@
<p>Default is <c>100</c>.</p>
</item>
+ <marker id="agent_error_report_mod"></marker>
<tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag>
<item>
<p>Defines an error report module, implementing the
@@ -377,6 +421,7 @@
<p>Default is <c>snmpa_error_logger</c>.</p>
</item>
+ <marker id="agent_symbolic_store"></marker>
<tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag>
<item>
<p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p>
@@ -384,23 +429,29 @@
<p>For defaults see the options in <c>symbolic_store_opt()</c>.</p>
</item>
+ <marker id="agent_target_cache"></marker>
<tag><c>target_cache() = [target_cache_opt()]</c></tag>
<item>
<p><c>target_cache_opt() = {verbosity, verbosity()}</c></p>
<p>Defines options specific for the SNMP agent target cache. </p>
<p>For defaults see the options in <c>target_cache_opt()</c>.</p>
</item>
+
+ <marker id="agent_config"></marker>
<tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag>
<item>
<p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p>
<p>Defines specific config related options for the SNMP agent. </p>
<p>For defaults see the options in <c>agent_config_opt()</c>.</p>
</item>
+
+ <marker id="agent_config_dir"></marker>
<tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP agent configuration files are stored.</p>
</item>
+ <marker id="agent_force_load"></marker>
<tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c> the configuration files are re-read
@@ -412,14 +463,18 @@
</item>
</taglist>
+ <marker id="manager_opts_and_types"></marker>
<p>Manager specific config options and types:</p>
<taglist>
+ <marker id="manager_server"></marker>
<tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag>
<item>
<p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p>
<p>Specifies the options for the manager server process.</p>
<p>Default is <c>silence</c>.</p>
</item>
+
+ <marker id="manager_server_timeout"></marker>
<tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag>
<item>
<p>Asynchroneous request cleanup time. For every requests,
@@ -440,6 +495,7 @@
<p>Default is <c>30000</c>.</p>
</item>
+ <marker id="manager_config"></marker>
<tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag>
<item>
<p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p>
@@ -447,16 +503,19 @@
<p>For defaults see the options in <c>manager_config_opt()</c>.</p>
</item>
+ <marker id="manager_config_dir"></marker>
<tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP manager configuration files are stored.</p>
</item>
+ <marker id="manager_config_db_dir"></marker>
<tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP manager store persistent data.</p>
</item>
+ <marker id="manager_config_repair"></marker>
<tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag>
<item>
<p>Defines the repair option for the persistent database (if
@@ -464,6 +523,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="manager_config_auto_save"></marker>
<tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag>
<item>
<p>The auto save interval. The table is flushed to disk
@@ -471,6 +531,7 @@
<p>Default is <c>5000</c>.</p>
</item>
+ <marker id="manager_irb"></marker>
<tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag>
<item>
<p>This option defines how the manager will handle the sending of
@@ -500,6 +561,7 @@
<p>Default is <c>auto</c>.</p>
</item>
+ <marker id="manager_mibs"></marker>
<tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag>
<item>
<p>Specifies a list of MIBs (including path) and defines which MIBs
@@ -507,6 +569,7 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="manager_net_if"></marker>
<tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_opt() = {module, manager_net_if_module()} |
@@ -517,6 +580,7 @@
<p>For defaults see the options in <c>manager_net_if_opt()</c>.</p>
</item>
+ <marker id="manager_ni_opts"></marker>
<tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_option() = {bind_to, bind_to()} |
@@ -530,6 +594,7 @@
<p>For defaults see the options in <c>manager_net_if_option()</c>.</p>
</item>
+ <marker id="manager_ni_module"></marker>
<tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface part for the
@@ -538,6 +603,7 @@
<p>Default is <c>snmpm_net_if</c>.</p>
</item>
+ <marker id="manager_ni_filter_opts"></marker>
<tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p>
@@ -548,6 +614,7 @@
<c>manager_net_if_filter_option()</c>.</p>
</item>
+ <marker id="manager_ni_filter_module"></marker>
<tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface filter part for the
@@ -556,6 +623,7 @@
<p>Default is <c>snmpm_net_if_filter</c>.</p>
</item>
+ <marker id="manager_def_user_module"></marker>
<tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag>
<item>
<p>The module implementing the default user. See the
@@ -563,6 +631,7 @@
<p>Default is <c>snmpm_user_default</c>.</p>
</item>
+ <marker id="manager_def_user_data"></marker>
<tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag>
<item>
<p>Data for the default user. Passed to the user module when
@@ -571,8 +640,10 @@
</item>
</taglist>
+ <marker id="common_types"></marker>
<p>Common config types:</p>
<taglist>
+ <marker id="restart_type"></marker>
<tag><c>restart_type() = permanent | transient | temporary</c></tag>
<item>
<p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso>
@@ -580,6 +651,8 @@
<p>Default is <c>permanent</c> for the agent and <c>transient</c>
for the manager.</p>
</item>
+
+ <marker id="db_init_error"></marker>
<tag><c>db_init_error() = terminate | create</c></tag>
<item>
<p>Defines what to do if the agent or manager is unable to open an
@@ -588,23 +661,31 @@
agent/manager will remove the faulty file(s) and create new ones.</p>
<p>Default is <c>terminate</c>.</p>
</item>
+
+ <marker id="prio"></marker>
<tag><c><![CDATA[priority() = atom() <optional>]]></c></tag>
<item>
<p>Defines the Erlang priority for all SNMP processes.</p>
<p>Default is <c>normal</c>.</p>
</item>
+
+ <marker id="versions"></marker>
<tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag>
<item>
<p><c>version() = v1 | v2 | v3</c></p>
<p>Which SNMP versions shall be accepted/used.</p>
<p>Default is <c>[v1,v2,v3]</c>.</p>
</item>
+
+ <marker id="verbosity"></marker>
<tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag>
<item>
<p>Verbosity for a SNMP process. This specifies now much debug info
is printed.</p>
<p>Default is <c>silence</c>.</p>
</item>
+
+ <marker id="bind_to"></marker>
<tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, net_if binds to the IP address.
@@ -612,6 +693,8 @@
where it is running. </p>
<p>Default is <c>false</c>.</p>
</item>
+
+ <marker id="no_reuse"></marker>
<tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, net_if does not specify that the IP
@@ -619,22 +702,30 @@
the address is set to reusable. </p>
<p>Default is <c>false</c>.</p>
</item>
+
+ <marker id="recbuf"></marker>
<tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag>
<item>
<p>Receive buffer size. </p>
<p>Default value is defined by <c>gen_udp</c>.</p>
</item>
+
+ <marker id="sndbuf"></marker>
<tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag>
<item>
<p>Send buffer size. </p>
<p>Default value is defined by <c>gen_udp</c>.</p>
</item>
+
+ <marker id="note_store"></marker>
<tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag>
<item>
<p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p>
<p>Specifies the start-up verbosity for the SNMP note store.</p>
<p>For defaults see the options in <c>note_store_opt()</c>.</p>
</item>
+
+ <marker id="ns_timeout"></marker>
<tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag>
<item>
<p>Note cleanup time. When storing a note in the note store,
@@ -643,9 +734,9 @@
milli-seconds.</p>
<p>Default is <c>30000</c>.</p>
- <marker id="audit_trail_log"></marker>
</item>
+ <marker id="audit_trail_log"></marker>
<tag><c><![CDATA[audit_trail_log() = [audit_trail_log_opt()] <optional>]]></c></tag>
<item>
<p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p>
@@ -655,6 +746,8 @@
<c>size</c> options are mandatory.</p>
<p>If not present, audit trail logging is not used.</p>
</item>
+
+ <marker id="atl_type"></marker>
<tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag>
<item>
<p>Specifies what type of an audit trail log should be used.
@@ -675,12 +768,16 @@
</list>
<p>Default is <c>read_write</c>.</p>
</item>
+
+ <marker id="atl_dir"></marker>
<tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Specifies where the audit trail log should be stored.</p>
<p>If <c>audit_trail_log</c> specifies that logging should take
place, this parameter <em>must</em> be defined.</p>
</item>
+
+ <marker id="atl_size"></marker>
<tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag>
<item>
<p>Specifies the size of the audit
@@ -688,6 +785,8 @@
<p>If <c>audit_trail_log</c> specifies that logging should
take place, this parameter <em>must</em> be defined.</p>
</item>
+
+ <marker id="atl_repair"></marker>
<tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag>
<item>
<p>Specifies if and how the audit trail log shall be repaired
@@ -699,6 +798,8 @@
analysis.</p>
<p>Default is <c>true</c>.</p>
</item>
+
+ <marker id="atl_seqno"></marker>
<tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag>
<item>
<p>Specifies if the audit trail log entries will be (sequence)
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
index fc8562b638..0a49b7a62e 100644
--- a/lib/snmp/doc/src/snmp_config.xml
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -40,6 +40,7 @@
<item>starting the application (agent and/or manager)</item>
<item>debugging the application (agent and/or manager)</item>
</list>
+
<p>Refer also to the chapter(s)
<seealso marker="snmp_agent_config_files">Definition of Agent Configuration Files</seealso> and
<seealso marker="snmp_manager_config_files">Definition of Manager Configuration Files</seealso> which contains more detailed information
@@ -73,7 +74,14 @@
</item>
</list>
- <!-- The info below is also found in the snmp_app.xml file -->
+
+ <!--
+ *****************************************************
+
+ The info below is also found in the snmp_app.xml file
+
+ *****************************************************
+ -->
<p>The agent and manager uses (application) configuration parameters to
find out where these directories are located. The parameters should be
@@ -87,6 +95,7 @@
{agent_verbosity, verbosity()} |
{versions, versions()} |
{discovery, agent_discovery()} |
+ {gb_max_vbs, gb_max_vbs()} |
{priority, priority()} |
{multi_threaded, multi_threaded()} |
{db_dir, db_dir()} |
@@ -117,8 +126,10 @@
{def_user_data, def_user_data()}
</pre>
+ <marker id="agent_opts_and_types"></marker>
<p>Agent specific config options and types:</p>
<taglist>
+ <marker id="agent_type"></marker>
<tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag>
<item>
<p>If <c>master</c>, one master agent is
@@ -126,6 +137,7 @@
<p>Default is <c>master</c>.</p>
</item>
+ <marker id="agent_disco"></marker>
<tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_discovery_opt() =
@@ -138,6 +150,7 @@
<p>For defaults see the options in <c>agent_discovery_opt()</c>.</p>
</item>
+ <marker id="agent_term_disco_opts"></marker>
<tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_terminating_discovery_opt() =
@@ -155,6 +168,7 @@
</list>
</item>
+ <marker id="agent_orig_disco_opts"></marker>
<tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_originating_discovery_opt() =
@@ -168,6 +182,7 @@
</list>
</item>
+ <marker id="agent_mt"></marker>
<tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, the agent is multi-threaded, with one
@@ -175,11 +190,21 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_data_dir"></marker>
<tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP agent internal db files are stored.</p>
</item>
+ <marker id="agent_gb_max_vbs"></marker>
+ <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>Defines the maximum number of varbinds allowed
+ in a Get-BULK response.</p>
+ <p>Default is <c>1000</c>.</p>
+ </item>
+
+ <marker id="agent_local_db"></marker>
<tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag>
<item>
<p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p>
@@ -187,6 +212,7 @@
<p>For defaults see the options in <c>local_db_opt()</c>.</p>
</item>
+ <marker id="agent_ldb_repair"></marker>
<tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag>
<item>
<p>When starting snmpa_local_db it always tries to open an
@@ -197,6 +223,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="agent_ldb_auto_save"></marker>
<tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag>
<item>
<p>The auto save interval. The table is flushed to disk
@@ -204,6 +231,7 @@
<p>Default is <c>5000</c>.</p>
</item>
+ <marker id="agent_net_if"></marker>
<tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_option() = {module, agent_net_if_module()} |
@@ -214,6 +242,7 @@
<p>For defaults see the options in <c>agent_net_if_opt()</c>.</p>
</item>
+ <marker id="agent_ni_module"></marker>
<tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface part for the
@@ -222,6 +251,7 @@
<p>Default is <c>snmpa_net_if</c>.</p>
</item>
+ <marker id="agent_ni_opts"></marker>
<tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_option() = {bind_to, bind_to()} |
@@ -236,6 +266,14 @@
<p>For defaults see the options in <c>agent_net_if_option()</c>.</p>
</item>
+ <marker id="agent_ni_req_limit"></marker>
+ <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>Max number of simultaneous requests handled by the agent.</p>
+ <p>Default is <c>infinity</c>.</p>
+ </item>
+
+ <marker id="agent_ni_filter_opts"></marker>
<tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag>
<item>
<p><c><![CDATA[agent_net_if_filter_option() = {module, agent_net_if_filter_module()}]]></c></p>
@@ -245,6 +283,7 @@
<p>For defaults see the options in <c>agent_net_if_filter_option()</c>.</p>
</item>
+ <marker id="agent_ni_filter_module"></marker>
<tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface filter part for the
@@ -254,12 +293,7 @@
<p>Default is <c>snmpa_net_if_filter</c>.</p>
</item>
- <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag>
- <item>
- <p>Max number of simultaneous requests handled by the agent.</p>
- <p>Default is <c>infinity</c>.</p>
- </item>
-
+ <marker id="agent_mibs"></marker>
<tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag>
<item>
<p>Specifies a list of MIBs (including path) that defines which MIBs
@@ -274,6 +308,7 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="agent_mib_storage"></marker>
<tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag>
<item>
<p>Specifies how info retrieved from the mibs will be stored.</p>
@@ -299,6 +334,7 @@
mnesia/dets table already exist.</p>
</item>
+ <marker id="agent_mib_server"></marker>
<tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
<item>
<p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p>
@@ -306,6 +342,7 @@
<p>For defaults see the options in <c>mib_server_opt()</c>.</p>
</item>
+ <marker id="agent_ms_meo"></marker>
<tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag>
<item>
<p>If this value is false, then when loading a mib each mib-
@@ -315,6 +352,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_teo"></marker>
<tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag>
<item>
<p>If this value is false, then when loading a mib each trap
@@ -324,6 +362,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_cache"></marker>
<tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag>
<item>
<p>Shall the agent utilize the mib server lookup cache or not.</p>
@@ -331,6 +370,7 @@
default values apply).</p>
</item>
+ <marker id="agent_ms_cache_opts"></marker>
<tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag>
<item>
<p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p>
@@ -338,6 +378,7 @@
<p>For defaults see the options in <c>mibs_cache_opt()</c>.</p>
</item>
+ <marker id="agent_ms_cache_autogc"></marker>
<tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag>
<item>
<p>Defines if the mib server shall perform cache gc automatically or
@@ -346,6 +387,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="agent_ms_cache_age"></marker>
<tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag>
<item>
<p>Defines how old the entries in the cache will be allowed before
@@ -355,6 +397,7 @@
<p>Default is <c>10 timutes</c>.</p>
</item>
+ <marker id="agent_ms_cache_gclimit"></marker>
<tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag>
<item>
<p>When performing a GC, this is the max number of cache entries
@@ -365,6 +408,7 @@
<p>Default is <c>100</c>.</p>
</item>
+ <marker id="agent_error_report_mod"></marker>
<tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag>
<item>
<p>Defines an error report module, implementing the
@@ -374,6 +418,7 @@
<p>Default is <c>snmpa_error_logger</c>.</p>
</item>
+ <marker id="agent_symbolic_store"></marker>
<tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag>
<item>
<p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p>
@@ -381,12 +426,15 @@
<p>For defaults see the options in <c>symbolic_store_opt()</c>.</p>
</item>
+ <marker id="agent_target_cache"></marker>
<tag><c>target_cache() = [target_cache_opt()]</c></tag>
<item>
<p><c>target_cache_opt() = {verbosity, verbosity()}</c></p>
<p>Defines options specific for the SNMP agent target cache. </p>
<p>For defaults see the options in <c>target_cache_opt()</c>.</p>
</item>
+
+ <marker id="agent_config"></marker>
<tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag>
<item>
<p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p>
@@ -394,11 +442,13 @@
<p>For defaults see the options in <c>agent_config_opt()</c>.</p>
</item>
+ <marker id="agent_config_dir"></marker>
<tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP agent configuration files are stored.</p>
</item>
+ <marker id="agent_force_load"></marker>
<tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c> the configuration files are re-read
@@ -410,14 +460,18 @@
</item>
</taglist>
+ <marker id="manager_opts_and_types"></marker>
<p>Manager specific config options and types:</p>
<taglist>
+ <marker id="manager_server"></marker>
<tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag>
<item>
<p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p>
<p>Specifies the options for the manager server process.</p>
<p>Default is <c>silence</c>.</p>
</item>
+
+ <marker id="manager_server_timeout"></marker>
<tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag>
<item>
<p>Asynchroneous request cleanup time. For every requests,
@@ -438,6 +492,7 @@
<p>Default is <c>30000</c>.</p>
</item>
+ <marker id="manager_config"></marker>
<tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag>
<item>
<p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p>
@@ -445,16 +500,19 @@
<p>For defaults see the options in <c>manager_config_opt()</c>.</p>
</item>
+ <marker id="manager_config_dir"></marker>
<tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP manager configuration files are stored.</p>
</item>
+ <marker id="manager_config_db_dir"></marker>
<tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP manager store persistent data.</p>
</item>
+ <marker id="manager_config_repair"></marker>
<tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag>
<item>
<p>Defines the repair option for the persistent database (if
@@ -462,6 +520,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="manager_config_auto_save"></marker>
<tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag>
<item>
<p>The auto save interval. The table is flushed to disk
@@ -469,6 +528,7 @@
<p>Default is <c>5000</c>.</p>
</item>
+ <marker id="manager_irb"></marker>
<tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag>
<item>
<p>This option defines how the manager will handle the sending of
@@ -498,6 +558,7 @@
<p>Default is <c>auto</c>.</p>
</item>
+ <marker id="manager_mibs"></marker>
<tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag>
<item>
<p>Specifies a list of MIBs (including path) and defines which MIBs
@@ -505,6 +566,7 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="manager_net_if"></marker>
<tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_opt() = {module, manager_net_if_module()} |
@@ -515,6 +577,7 @@
<p>For defaults see the options in <c>manager_net_if_opt()</c>.</p>
</item>
+ <marker id="manager_ni_opts"></marker>
<tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_option() = {bind_to, bind_to()} |
@@ -528,6 +591,7 @@
<p>For defaults see the options in <c>manager_net_if_option()</c>.</p>
</item>
+ <marker id="manager_ni_module"></marker>
<tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface part for the
@@ -536,6 +600,7 @@
<p>Default is <c>snmpm_net_if</c>.</p>
</item>
+ <marker id="manager_ni_filter_opts"></marker>
<tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p>
@@ -546,6 +611,7 @@
<c>manager_net_if_filter_option()</c>.</p>
</item>
+ <marker id="manager_ni_filter_module"></marker>
<tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface filter part for the
@@ -554,6 +620,7 @@
<p>Default is <c>snmpm_net_if_filter</c>.</p>
</item>
+ <marker id="manager_def_user_module"></marker>
<tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag>
<item>
<p>The module implementing the default user. See the
@@ -561,6 +628,7 @@
<p>Default is <c>snmpm_user_default</c>.</p>
</item>
+ <marker id="manager_def_user_data"></marker>
<tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag>
<item>
<p>Data for the default user. Passed to the user when calling
@@ -569,8 +637,10 @@
</item>
</taglist>
+ <marker id="common_types"></marker>
<p>Common config types:</p>
<taglist>
+ <marker id="restart_type"></marker>
<tag><c>restart_type() = permanent | transient | temporary</c></tag>
<item>
<p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso>
@@ -579,6 +649,7 @@
for the manager.</p>
</item>
+ <marker id="db_init_error"></marker>
<tag><c>db_init_error() = terminate | create</c></tag>
<item>
<p>Defines what to do if the agent is unable to open an
@@ -588,12 +659,14 @@
<p>Default is <c>terminate</c>.</p>
</item>
+ <marker id="prio"></marker>
<tag><c><![CDATA[priority() = atom() <optional>]]></c></tag>
<item>
<p>Defines the Erlang priority for all SNMP processes.</p>
<p>Default is <c>normal</c>.</p>
</item>
+ <marker id="versions"></marker>
<tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag>
<item>
<p><c>version() = v1 | v2 | v3</c></p>
@@ -601,6 +674,7 @@
<p>Default is <c>[v1,v2,v3]</c>.</p>
</item>
+ <marker id="verbosity"></marker>
<tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag>
<item>
<p>Verbosity for a SNMP process. This specifies now much debug info
@@ -608,6 +682,7 @@
<p>Default is <c>silence</c>.</p>
</item>
+ <marker id="bind_to"></marker>
<tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, net_if binds to the IP address.
@@ -616,6 +691,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="no_reuse"></marker>
<tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, net_if does not specify that the IP
@@ -624,17 +700,21 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="recbuf"></marker>
<tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag>
<item>
<p>Receive buffer size. </p>
<p>Default value is defined by <c>gen_udp</c>.</p>
</item>
+
+ <marker id="sndbuf"></marker>
<tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag>
<item>
<p>Send buffer size. </p>
<p>Default value is defined by <c>gen_udp</c>.</p>
</item>
+ <marker id="note_store"></marker>
<tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag>
<item>
<p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p>
@@ -642,6 +722,7 @@
<p>For defaults see the options in <c>note_store_opt()</c>.</p>
</item>
+ <marker id="ns_timeout"></marker>
<tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag>
<item>
<p>Note cleanup time. When storing a note in the note store,
@@ -649,10 +730,9 @@
process performs a GC to remove the expired note's. Time in
milli-seconds.</p>
<p>Default is <c>30000</c>.</p>
-
- <marker id="audit_trail_log"></marker>
</item>
+ <marker id="audit_trail_log"></marker>
<tag><c><![CDATA[audit_trail_log() [audit_trail_log_opt()] <optional>]]></c></tag>
<item>
<p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p>
@@ -663,6 +743,7 @@
<p>If not present, audit trail logging is not used.</p>
</item>
+ <marker id="atl_type"></marker>
<tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag>
<item>
<p>Specifies what type of an audit trail log should be used.
@@ -684,6 +765,7 @@
<p>Default is <c>read_write</c>.</p>
</item>
+ <marker id="atl_dir"></marker>
<tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Specifies where the audit trail log should be stored.</p>
@@ -691,6 +773,7 @@
place, this parameter <em>must</em> be defined.</p>
</item>
+ <marker id="atl_size"></marker>
<tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag>
<item>
<p>Specifies the size of the audit
@@ -699,6 +782,7 @@
take place, this parameter <em>must</em> be defined.</p>
</item>
+ <marker id="atl_repair"></marker>
<tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag>
<item>
<p>Specifies if and how the audit trail log shall be repaired
@@ -710,6 +794,8 @@
analysis.</p>
<p>Default is <c>true</c>.</p>
</item>
+
+ <marker id="atl_seqno"></marker>
<tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag>
<item>
<p>Specifies if the audit trail log entries will be (sequence)
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index bc39e1fa35..078ef15821 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -52,6 +52,7 @@ $(EBIN)/snmpa_acm.$(EMULATOR): \
$(EBIN)/snmpa_agent.$(EMULATOR): \
snmpa_agent.erl \
+ snmpa_internal.hrl \
../misc/snmp_debug.hrl \
../misc/snmp_verbosity.hrl \
../../include/snmp_types.hrl
@@ -136,6 +137,7 @@ $(EBIN)/snmpa_set_lib.$(EMULATOR): \
$(EBIN)/snmpa_supervisor.$(EMULATOR): \
snmpa_supervisor.erl \
+ snmpa_internal.hrl \
../misc/snmp_debug.hrl \
../misc/snmp_verbosity.hrl
diff --git a/lib/snmp/src/agent/snmp_generic_mnesia.erl b/lib/snmp/src/agent/snmp_generic_mnesia.erl
index a73aad5b33..ce42af404b 100644
--- a/lib/snmp/src/agent/snmp_generic_mnesia.erl
+++ b/lib/snmp/src/agent/snmp_generic_mnesia.erl
@@ -121,7 +121,7 @@ table_func(set, RowIndex, Cols, Name) ->
fun() ->
snmp_generic:table_set_row(
{Name, mnesia}, nofunc,
- {snmp_generic_mnesia, table_try_make_consistent},
+ fun table_try_make_consistent/2,
RowIndex, Cols)
end) of
{atomic, Value} ->
@@ -368,7 +368,8 @@ table_set_elements(Name, RowIndex, Cols) ->
_ -> false
end.
table_set_elements(Name, RowIndex, Cols, ConsFunc) ->
- #table_info{index_types = Indexes, first_own_index = FirstOwnIndex} =
+ #table_info{index_types = Indexes,
+ first_own_index = FirstOwnIndex} =
snmp_generic:table_info(Name),
AddCol = if
FirstOwnIndex == 0 -> 2;
diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl
index 60bd3e0912..a45db89c09 100644
--- a/lib/snmp/src/agent/snmp_target_mib.erl
+++ b/lib/snmp/src/agent/snmp_target_mib.erl
@@ -46,8 +46,14 @@
%% Column not accessible via SNMP - needed when the agent sends informs
-define(snmpTargetAddrEngineId, 10).
%% Extra comlumns for the augmented table snmpTargetAddrExtTable
--define(snmpTargetAddrTMask, 11).
--define(snmpTargetAddrMMS, 12).
+-define(snmpTargetAddrTMask, 11).
+-define(snmpTargetAddrMMS, 12).
+
+-ifdef(snmp_extended_verbosity).
+-define(vt(F,A), ?vtrace(F, A)).
+-else.
+-define(vt(_F, _A), ok).
+-endif.
%%-----------------------------------------------------------------
@@ -459,10 +465,16 @@ get_target_addrs() ->
get_target_addrs(Key, {Tab, _} = TabDb, Acc) ->
+ ?vt("get_target_addrs -> entry with"
+ "~n Key: ~p", [Key]),
case table_next(Tab, Key) of
endOfTable ->
+ ?vt("get_target_addrs -> endOfTable when"
+ "~n Acc: ~p", [Acc]),
Acc;
NextKey ->
+ ?vt("get_target_addrs -> next ok: "
+ "~n NextKey: ~p", [NextKey]),
case get_target_addr(TabDb, NextKey) of
{ok, Targ} ->
get_target_addrs(NextKey, TabDb, [Targ| Acc]);
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index 37f6dd3f26..2cee91b081 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -203,18 +203,16 @@ init_sec2group_table([Row | T]) ->
init_sec2group_table(T);
init_sec2group_table([]) -> true.
-init_access_table([{GN, Prefix, Model, Level, Row} | T]) ->
-%% ?vtrace("init access table: "
-%% "~n GN: ~p"
-%% "~n Prefix: ~p"
-%% "~n Model: ~p"
-%% "~n Level: ~p"
-%% "~n Row: ~p",[GN, Prefix, Model, Level, Row]),
- Key = [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level],
- snmpa_vacm:insert([{Key, Row}], false),
- init_access_table(T);
-init_access_table([]) ->
- snmpa_vacm:dump_table().
+make_access_key(GN, Prefix, Model, Level) ->
+ [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level].
+
+make_access_entry({GN, Prefix, Model, Level, Row}) ->
+ Key = make_access_key(GN, Prefix, Model, Level),
+ {Key, Row}.
+
+init_access_table(TableData) ->
+ TableData2 = [make_access_entry(E) || E <- TableData],
+ snmpa_vacm:insert(TableData2, true).
init_view_table([Row | T]) ->
%% ?vtrace("init view table: "
@@ -276,10 +274,7 @@ add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) ->
Match, RV, WV, NV},
case (catch check_vacm(Access)) of
{ok, {vacmAccess, {GN, Pref, SM, SL, Row}}} ->
- Key1 = [length(GN) | GN],
- Key2 = [length(Pref) | Pref],
- Key3 = [SM, SL],
- Key = Key1 ++ Key2 ++ Key3,
+ Key = make_access_key(GN, Pref, SM, SL),
snmpa_vacm:insert([{Key, Row}], false),
snmpa_agent:invalidate_ca_cache(),
{ok, Key};
diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl
index 50b169e4e7..c400aaddf7 100644
--- a/lib/snmp/src/agent/snmpa.erl
+++ b/lib/snmp/src/agent/snmpa.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -547,7 +547,7 @@ update_mibs_cache_age(Agent, Age) ->
update_mibs_cache_gclimit(GcLimit) ->
- update_mibs_cache_age(snmp_master_agent, GcLimit).
+ update_mibs_cache_gclimit(snmp_master_agent, GcLimit).
update_mibs_cache_gclimit(Agent, GcLimit) ->
snmpa_agent:update_mibs_cache_gclimit(Agent, GcLimit).
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 46c634969d..17cb9c9fe3 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -68,8 +68,11 @@
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3, tr_var/2, tr_varbind/1,
- handle_pdu/7, worker/2, worker_loop/1,
+ handle_pdu/8, worker/2, worker_loop/1,
do_send_trap/7, do_send_trap/8]).
+%% <BACKWARD-COMPAT>
+-export([handle_pdu/7]).
+%% </BACKWARD-COMPAT>
-include("snmpa_internal.hrl").
@@ -87,7 +90,6 @@
-define(DISCO_TERMINATING_TRIGGER_USERNAME, "").
-
-ifdef(snmp_debug).
-define(GS_START_LINK3(Prio, Parent, Ref, Opts),
gen_server:start_link(?MODULE, [Prio, Parent, Ref, Opts],
@@ -103,13 +105,49 @@
gen_server:start_link({local, Name}, ?MODULE,
[Prio, Parent, Ref, Opts],[])).
-endif.
-
+
+%% Increment this whenever a change is made to the worker interface
+-define(WORKER_INTERFACE_VERSION, 1).
+
+%% -- Utility macros for creating worker commands --
+-define(mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
+ #wrequest{cmd = handle_pdu,
+ info = [{vsn, Vsn},
+ {pdu, Pdu},
+ {pdu_ms, PduMS},
+ {acm_data, ACMData},
+ {addr, Address},
+ {gb_max_vbs, GbMaxVBs},
+ {extra, Extra}]}).
+-define(mk_send_trap_wreq(TrapRec, NotifyName, ContextName,
+ Recv, Vbs, LocalEngineID, Extra),
+ #wrequest{cmd = send_trap,
+ info = [{trap_rec, TrapRec},
+ {notify_name, NotifyName},
+ {context_name, ContextName},
+ {receiver, Recv},
+ {varbinds, Vbs},
+ {local_engine_id, LocalEngineID},
+ {extra, Extra}]}).
+-define(mk_terminate_wreq(), #wrequest{cmd = terminate, info = []}).
+-define(mk_verbosity_wreq(V), #wrequest{cmd = verbosity,
+ info = [{verbosity, V}]}).
+
-record(notification_filter, {id, mod, data}).
-record(disco,
{from, rec, sender, target, engine_id,
sec_level, ctx, ivbs, stage, handler, extra}).
+%% This record is used when sending requests to the worker processes
+-record(wrequest,
+ {
+ version = ?WORKER_INTERFACE_VERSION,
+ cmd,
+ info
+ }
+ ).
+
%%-----------------------------------------------------------------
%% The agent is multi-threaded, i.e. each request is handled
@@ -142,7 +180,8 @@
net_if_mod,
backup,
disco,
- mibs_cache_request}).
+ mibs_cache_request,
+ gb_max_vbs}).
%%%-----------------------------------------------------------------
@@ -330,6 +369,8 @@ do_init(Prio, Parent, Ref, Options) ->
MultiT = get_multi_threaded(Options),
Vsns = get_versions(Options),
+ GbMaxVbs = get_gb_max_vbs(Options),
+
NS = start_note_store(Prio, Ref, Options),
{Type, NetIfPid, NetIfMod} =
start_net_if(Parent, Prio, Ref, Vsns, NS, Options),
@@ -348,7 +389,8 @@ do_init(Prio, Parent, Ref, Options) ->
ref = Ref,
vsns = Vsns,
note_store = NS,
- net_if_mod = NetIfMod}}.
+ net_if_mod = NetIfMod,
+ gb_max_vbs = GbMaxVbs}}.
start_note_store(Prio, Ref, Options) ->
@@ -410,7 +452,8 @@ start_net_if(Parent, _Prio, _Ref, _Vsns, _NoteStore, _Options)
start_mib_server(Prio, Ref, Mibs, Options) ->
?vdebug("start_mib_server -> with Prio: ~p", [Prio]),
MibStorage = get_mib_storage(Options),
- MibsOpts = [{mib_storage, MibStorage}|get_option(mib_server, Options, [])],
+ MibsOpts = [{mib_storage, MibStorage} |
+ get_option(mib_server, Options, [])],
?vtrace("start_mib_server -> "
"~n Mibs: ~p"
@@ -751,7 +794,8 @@ handle_info({snmp_pdu, Vsn, Pdu, PduMS, ACMData, Address, Extra}, S) ->
?vdebug("handle_info(snmp_pdu) -> entry with"
"~n Vsn: ~p"
"~n Pdu: ~p"
- "~n Address: ~p", [Vsn, Pdu, Address]),
+ "~n Address: ~p"
+ "~n Extra: ~p", [Vsn, Pdu, Address, Extra]),
NewS = handle_snmp_pdu(is_valid_pdu_type(Pdu#pdu.type),
Vsn, Pdu, PduMS, ACMData, Address, Extra, S),
@@ -934,6 +978,7 @@ handle_info({'EXIT', Pid, Reason}, S) ->
end,
{noreply, S}
end;
+
handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}},
#state{mibs_cache_request = {Pid, Ref, From}} = S) ->
?vlog("reply from the mibs cache request handler (~p): ~n~p",
@@ -1075,7 +1120,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) ->
"~n PduData: ~p",
[MibView,Varbinds,PduData]),
put_pdu_data(PduData),
- {reply, do_get_next(MibView, Varbinds), S};
+ {reply, do_get_next(MibView, Varbinds, infinity), S};
handle_call({subagent_set, Arguments, PduData}, _From, S) ->
?vlog("[handle_call] subagent set:"
"~n Arguments: ~p"
@@ -1116,7 +1161,7 @@ handle_call({get_next, Vars, Context}, _From, S) ->
?vdebug("Varbinds: ~p",[Varbinds]),
MibView = snmpa_acm:get_root_mib_view(),
Reply =
- case do_get_next(MibView, Varbinds) of
+ case do_get_next(MibView, Varbinds, infinity) of
{noError, 0, NewVarbinds} ->
Vbs = lists:keysort(#varbind.org_index, NewVarbinds),
[{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs];
@@ -1283,27 +1328,27 @@ handle_call({me_of, Oid}, _From, S) ->
{reply, Reply, S};
handle_call(get_log_type, _From, S) ->
- ?vlog("get_log_type", []),
+ ?vlog("handle_call(get_log_type) -> entry with", []),
Reply = handle_get_log_type(S),
{reply, Reply, S};
handle_call({set_log_type, NewType}, _From, S) ->
- ?vlog("set_log_type -> "
+ ?vlog("handle_call(set_log_type) -> entry with"
"~n NewType: ~p", [NewType]),
Reply = handle_set_log_type(S, NewType),
{reply, Reply, S};
handle_call(get_request_limit, _From, S) ->
- ?vlog("get_request_limit", []),
+ ?vlog("handle_call(get_request_limit) -> entry with", []),
Reply = handle_get_request_limit(S),
{reply, Reply, S};
handle_call({set_request_limit, NewLimit}, _From, S) ->
- ?vlog("set_request_limit -> "
+ ?vlog("handle_call(set_request_limit) -> entry with"
"~n NewLimit: ~p", [NewLimit]),
Reply = handle_set_request_limit(S, NewLimit),
{reply, Reply, S};
-
+
handle_call(stop, _From, S) ->
{stop, normal, ok, S};
@@ -1312,15 +1357,15 @@ handle_call(Req, _From, S) ->
Reply = {error, {unknown, Req}},
{reply, Reply, S}.
-handle_cast({verbosity,Verbosity}, S) ->
- ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+handle_cast({verbosity, Verbosity}, S) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity), Verbosity]),
put(verbosity,snmp_verbosity:validate(Verbosity)),
case S#state.worker of
- Pid when is_pid(Pid) -> Pid ! {verbosity,Verbosity};
+ Pid when is_pid(Pid) -> Pid ! ?mk_verbosity_wreq(Verbosity);
_ -> ok
end,
case S#state.set_worker of
- Pid2 when is_pid(Pid2) -> Pid2 ! {verbosity,Verbosity};
+ Pid2 when is_pid(Pid2) -> Pid2 ! ?mk_verbosity_wreq(Verbosity);
_ -> ok
end,
{noreply, S};
@@ -1407,13 +1452,80 @@ handle_mibs_cache_request(MibServer, Req) ->
%% Downgrade
%%
-%% code_change({down, _Vsn}, S, downgrade_to_pre_4_13) ->
-%% {ok, S2};
+code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) ->
+ #state{type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR} = S1,
+ S2 = {state,
+ type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR},
+ {ok, S2};
%% Upgrade
%%
-%% code_change(_Vsn, S, upgrade_from_pre_4_13) ->
-%% {ok, S2};
+code_change(_Vsn, S1, upgrade_from_pre_4_17_3) ->
+ {state,
+ type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR} = S1,
+ S2 = #state{type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR,
+ gb_max_vbs = ?DEFAULT_GB_MAX_VBS},
+ {ok, S2};
code_change(_Vsn, S, _Extra) ->
{ok, S}.
@@ -1453,7 +1565,7 @@ worker_start(Dict) ->
%% worker_stop(Pid, infinity).
worker_stop(Pid, Timeout) when is_pid(Pid) ->
- Pid ! terminate,
+ Pid ! ?mk_terminate_wreq(),
receive
{'EXIT', Pid, normal} ->
ok
@@ -1590,9 +1702,11 @@ invalidate_ca_cache() ->
%%
%%-----------------------------------------------------------------
-spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
+%% This functions spawns a temporary worker process,
+%% that evaluates one request and then silently exits.
+spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) ->
Dict = get(),
- Args = [Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict],
+ Args = [Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict],
proc_lib:spawn_link(?MODULE, handle_pdu, Args).
spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs,
@@ -1610,7 +1724,7 @@ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, Dict) ->
lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
- put(sname,trap_sender_short_name(get(sname))),
+ put(sname, trap_sender_short_name(get(sname))),
?vlog("starting",[]),
snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, get(net_if)).
@@ -1622,58 +1736,122 @@ worker(Master, Dict) ->
worker_loop(Master).
worker_loop(Master) ->
- receive
- {Vsn, Pdu, PduMS, ACMData, Address, Extra} ->
- ?vtrace("worker_loop -> received request", []),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
- Master ! worker_available;
-
- %% We don't trap EXITs!
- {TrapRec, NotifyName, ContextName, Recv, Vbs} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- ?DEFAULT_NOTIF_EXTRA_INFO,
- get(net_if)),
- Master ! worker_available;
-
- %% We don't trap EXITs!
- {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- LocalEngineID, ?DEFAULT_NOTIF_EXTRA_INFO,
- get(net_if)),
- Master ! worker_available;
-
- {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo,
- get(net_if)),
- Master ! worker_available;
-
- {verbosity, Verbosity} ->
- put(verbosity,snmp_verbosity:validate(Verbosity));
-
- terminate ->
- exit(normal);
-
- _X ->
- %% ignore
- ok
-
- after 30000 ->
- %% This is to assure that the worker process leaves a
- %% possibly old version of this module.
- ok
- end,
+ Res =
+ receive
+ #wrequest{cmd = handle_pdu,
+ info = Info} = Req ->
+ ?vtrace("worker_loop -> received handle_pdu request with"
+ "~n Info: ~p", [Info]),
+ Vsn = proplists:get_value(vsn, Info),
+ Pdu = proplists:get_value(pdu, Info),
+ PduMS = proplists:get_value(pdu_ms, Info),
+ ACMData = proplists:get_value(acm_data, Info),
+ Address = proplists:get_value(addr, Info),
+ GbMaxVBs = proplists:get_value(gb_max_vbs, Info),
+ Extra = proplists:get_value(extra, Info),
+ HandlePduRes =
+ try
+ begin
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address,
+ GbMaxVBs, Extra)
+ end
+ catch
+ T:E ->
+ exit({worker_crash, Req, T, E,
+ erlang:get_stacktrace()})
+ end,
+ Master ! worker_available,
+ HandlePduRes; % For debugging...
+
+
+ #wrequest{cmd = send_trap,
+ info = Info} = Req ->
+ ?vtrace("worker_loop -> received send_trap request with"
+ "~n Info: ~p", [Info]),
+ TrapRec = proplists:get_value(trap_rec, Info),
+ NotifyName = proplists:get_value(notify_name, Info),
+ ContextName = proplists:get_value(context_name, Info),
+ Recv = proplists:get_value(receiver, Info),
+ Vbs = proplists:get_value(varbinds, Info),
+ LocalEngineID = proplists:get_value(local_engine_id, Info),
+ Extra = proplists:get_value(extra, Info),
+ SendTrapRes =
+ try
+ begin
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, Extra,
+ get(net_if))
+ end
+ catch
+ T:E ->
+ exit({worker_crash, Req, T, E,
+ erlang:get_stacktrace()})
+ end,
+ Master ! worker_available,
+ SendTrapRes; % For debugging...
+
+
+ #wrequest{cmd = verbosity,
+ info = Info} ->
+ Verbosity = proplists:get_value(verbosity, Info),
+ put(verbosity, snmp_verbosity:validate(Verbosity));
+
+
+ #wrequest{cmd = terminate} ->
+ ?vtrace("worker_loop -> received terminate request", []),
+ exit(normal);
+
+
+ %% *************************************************************
+ %%
+ %% Kept for backward compatibillity reasons
+ %%
+ %% *************************************************************
+
+ {Vsn, Pdu, PduMS, ACMData, Address, Extra} ->
+ ?vtrace("worker_loop -> received request", []),
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address,
+ ?DEFAULT_GB_MAX_VBS, Extra),
+ Master ! worker_available;
+
+ %% We don't trap exits!
+ {TrapRec, NotifyName, ContextName, Recv, Vbs} ->
+ ?vtrace("worker_loop -> send trap:"
+ "~n ~p", [TrapRec]),
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs, get(net_if)),
+ Master ! worker_available;
+
+ %% We don't trap exits!
+ {send_trap,
+ TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
+ ExtraInfo} ->
+ ?vtrace("worker_loop -> send trap:"
+ "~n ~p", [TrapRec]),
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo,
+ get(net_if)),
+ Master ! worker_available;
+
+ {verbosity, Verbosity} ->
+ put(verbosity, snmp_verbosity:validate(Verbosity));
+
+ terminate ->
+ exit(normal);
+
+ _X ->
+ %% ignore
+ ignore_unknown
+
+ after 30000 ->
+ %% This is to assure that the worker process leaves a
+ %% possibly old version of this module.
+ ok
+ end,
+ ?vtrace("worker_loop -> wrap with"
+ "~n ~p", [Res]),
?MODULE:worker_loop(Master).
@@ -1681,42 +1859,52 @@ worker_loop(Master) ->
%%-----------------------------------------------------------------
handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra,
- #state{multi_threaded = false} = S) ->
+ #state{multi_threaded = false,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> single-thread agent",[]),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
S;
handle_snmp_pdu(true, Vsn, #pdu{type = 'set-request'} = Pdu, PduMS,
ACMData, Address, Extra,
#state{set_worker = Worker} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"send set-request to main worker",[]),
- Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra},
+ WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, infinity, Extra),
+ Worker ! WRequest,
S#state{worker_state = busy};
handle_snmp_pdu(true, Vsn, Pdu, PduMS,
ACMData, Address, Extra,
- #state{worker_state = busy} = S) ->
+ #state{worker_state = busy,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"main worker busy - create new worker",[]),
- spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
S;
handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra,
- #state{worker = Worker} = S) ->
+ #state{worker = Worker,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"send to main worker",[]),
- Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra},
+ WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
+ Worker ! WRequest,
S#state{worker_state = busy};
handle_snmp_pdu(_, _Vsn, _Pdu, _PduMS, _ACMData, _Address, _Extra, S) ->
S.
%% Called via the spawn_thread function
+%% <BACKWARD-COMPAT>
handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict) ->
+ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, ?DEFAULT_GB_MAX_VBS, Extra,
+ Dict).
+%% </BACKWARD-COMPAT>
+handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict) ->
lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
put(sname, pdu_handler_short_name(get(sname))),
?vlog("new worker starting",[]),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra).
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra).
-handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
+handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) ->
%% OTP-3324
AuthMod = get(auth_module),
case AuthMod:init_check_access(Pdu, ACMData) of
@@ -1725,7 +1913,8 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
"~n MibView: ~p"
"~n ContextName: ~p", [MibView, ContextName]),
AgentData = cheat(ACMData, Address, ContextName),
- do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra);
+ do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData,
+ GbMaxVBs, Extra);
{error, Reason} ->
?vlog("handle_pdu -> error:"
"~n Reason: ~p", [Reason]),
@@ -1739,16 +1928,19 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
end.
do_handle_pdu(MibView, Vsn, Pdu, PduMS,
- ACMData, {Community, Address, ContextName}, Extra) ->
+ ACMData, {Community, Address, ContextName},
+ GbMaxVBs, Extra) ->
put(net_if_data, Extra),
+
RePdu = process_msg(MibView, Vsn, Pdu, PduMS, Community,
- Address, ContextName),
+ Address, ContextName, GbMaxVBs),
?vtrace("do_handle_pdu -> processed:"
"~n RePdu: ~p", [RePdu]),
- get(net_if) ! {snmp_response, Vsn, RePdu,
- RePdu#pdu.type, ACMData, Address, Extra}.
+ NetIf = get(net_if),
+ NetIf ! {snmp_response, Vsn, RePdu,
+ RePdu#pdu.type, ACMData, Address, Extra}.
handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) ->
@@ -1949,9 +2141,9 @@ do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds,
master_agent ->
%% Send to main worker
?vtrace("do_handle_send_trap -> send to main worker",[]),
- S#state.worker ! {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo},
+ S#state.worker ! ?mk_send_trap_wreq(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo),
{ok, S#state{worker_state = busy}}
end.
@@ -2291,17 +2483,18 @@ handle_mib_of(MibServer, Oid) ->
%% Func: process_msg/7
%% Returns: RePdu
%%-----------------------------------------------------------------
-process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName) ->
+process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName,
+ GbMaxVBs) ->
#pdu{request_id = ReqId} = Pdu,
put(snmp_address, {tuple_to_list(Ip), Udp}),
put(snmp_request_id, ReqId),
put(snmp_community, Community),
put(snmp_context, ContextName),
?vtrace("process ~p",[Pdu#pdu.type]),
- process_pdu(Pdu, PduMS, Vsn, MibView).
+ process_pdu(Pdu, PduMS, Vsn, MibView, GbMaxVBs).
process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
- _PduMS, Vsn, MibView) ->
+ _PduMS, Vsn, MibView, _GbMaxVBs) ->
?vtrace("get ~p",[ReqId]),
Res = get_err(do_get(MibView, Vbs, false)),
?vtrace("get result: "
@@ -2322,12 +2515,12 @@ process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
- _PduMS, Vsn, MibView) ->
+ _PduMS, Vsn, MibView, _GbMaxVBs) ->
?vtrace("process get-next-request -> entry with"
"~n ReqId: ~p"
"~n Vbs: ~p"
"~n MibView: ~p",[ReqId, Vbs, MibView]),
- Res = get_err(do_get_next(MibView, Vbs)),
+ Res = get_err(do_get_next(MibView, Vbs, infinity)),
?vtrace("get-next result: "
"~n ~p",[Res]),
{ErrStatus, ErrIndex, ResVarbinds} =
@@ -2344,11 +2537,15 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
"~n ~p",[ResponseVarbinds]),
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
-process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs,
- error_status = NonRepeaters, error_index = MaxRepetitions},
- PduMS, _Vsn, MibView)->
+process_pdu(#pdu{type = 'get-bulk-request',
+ request_id = ReqId,
+ varbinds = Vbs,
+ error_status = NonRepeaters,
+ error_index = MaxRepetitions},
+ PduMS, _Vsn, MibView, GbMaxVBs) ->
{ErrStatus, ErrIndex, ResponseVarbinds} =
- get_err(do_get_bulk(MibView,NonRepeaters,MaxRepetitions,PduMS,Vbs)),
+ get_err(do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs,
+ GbMaxVBs)),
?vtrace("get-bulk final result: "
"~n Error status: ~p"
"~n Error index: ~p"
@@ -2357,7 +2554,7 @@ process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs,
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs},
- _PduMS, Vsn, MibView)->
+ _PduMS, Vsn, MibView, _GbMaxVbs)->
Res = do_set(MibView, Vbs),
?vtrace("set result: "
"~n ~p",[Res]),
@@ -2414,7 +2611,8 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res)
{noSuchName, Vb#varbind.org_index};
validate_next_v1_2([Vb | Vbs], MibView, Res)
when Vb#varbind.variabletype =:= 'Counter64' ->
- case validate_next_v1(do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of
+ case validate_next_v1(
+ do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of
{noError, 0, [NVb]} ->
validate_next_v1_2(Vbs, MibView, [NVb | Res]);
{Error, Index, _OrgVb} ->
@@ -2887,59 +3085,97 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
%% that this really matters, since many nexts across the same
%% subagent must be considered to be very rare.
%%-----------------------------------------------------------------
-do_get_next(MibView, UnsortedVarbinds) ->
- SortedVarbinds = oid_sort_varbindlist(UnsortedVarbinds),
- next_loop_varbinds([], SortedVarbinds, MibView, [], []).
-oid_sort_varbindlist(Vbs) ->
+%% It may be a bit agressive to check this already,
+%% but since it is a security measure, it makes sense.
+do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+do_get_next(MibView, UnsortedVBs, GbMaxVBs) ->
+ ?vt("do_get_next -> entry when"
+ "~n MibView: ~p"
+ "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
+ SortedVBs = oid_sort_vbs(UnsortedVBs),
+ ?vt("do_get_next -> "
+ "~n SortedVBs: ~p", [SortedVBs]),
+ next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
+
+oid_sort_vbs(Vbs) ->
lists:keysort(#varbind.oid, Vbs).
+next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso
+ ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+
%% LAVb is Last Accessible Vb
-next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb) ->
+next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds -> entry when"
"~n Vb: ~p"
"~n MibView: ~p", [Vb, MibView]),
case varbind_next(Vb, MibView) of
endOfMibView ->
+ ?vt("next_loop_varbind -> endOfMibView", []),
RVb = if LAVb =:= [] -> Vb;
true -> LAVb
end,
NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []);
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
+
{variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
(ME#me.access =/= 'write-only') andalso
(ME#me.access =/= 'accessible-for-notify')) ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n ME: ~p"
+ "~n VarOid: ~p", [ME, VarOid]),
case try_get_instance(Vb, ME) of
{value, noValue, _NoSuchSomething} ->
+ ?vt("next_loop_varbind -> noValue", []),
%% Try next one
- NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, []);
+ NewVb = Vb#varbind{oid = VarOid,
+ value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
+ GbMaxVBs);
{value, Type, Value} ->
- NewVb = Vb#varbind{oid = VarOid, variabletype = Type,
- value = Value},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []);
+ ?vt("next_loop_varbind -> value"
+ "~n Type: ~p"
+ "~n Value: ~p", [Type, Value]),
+ NewVb = Vb#varbind{oid = VarOid,
+ variabletype = Type,
+ value = Value},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
+ GbMaxVBs);
{error, ErrorStatus} ->
?vdebug("next loop varbinds:"
"~n ErrorStatus: ~p",[ErrorStatus]),
{ErrorStatus, Vb#varbind.org_index, []}
end;
{variable, _ME, VarOid} ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n VarOid: ~p", [VarOid]),
RVb = if LAVb =:= [] -> Vb;
true -> LAVb
end,
NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb);
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
{table, TableOid, TableRestOid, ME} ->
+ ?vt("next_loop_varbind -> table: "
+ "~n TableOid: ~p"
+ "~n TableRestOid: ~p"
+ "~n ME: ~p", [TableOid, TableRestOid, ME]),
next_loop_varbinds({table, TableOid, ME,
[{tab_oid(TableRestOid), Vb}]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
{subagent, SubAgentPid, SAOid} ->
+ ?vt("next_loop_varbind -> subagent: "
+ "~n SubAgentPid: ~p"
+ "~n SAOid: ~p", [SubAgentPid, SAOid]),
NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
- Vbs, MibView, Res, [])
+ Vbs, MibView, Res, [], GbMaxVBs)
end;
next_loop_varbinds({table, TableOid, ME, TabOids},
- [Vb | Vbs], MibView, Res, _LAVb) ->
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(table) -> entry with"
"~n TableOid: ~p"
"~n Vb: ~p", [TableOid, Vb]),
@@ -2947,13 +3183,14 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
{table, TableOid, TableRestOid, _ME} ->
next_loop_varbinds({table, TableOid, ME,
[{tab_oid(TableRestOid), Vb} | TabOids]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
_ ->
case get_next_table(ME, TableOid, TabOids, MibView) of
{ok, TabRes, TabEndOfTabVbs} ->
NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{ErrorStatus, OrgIndex} ->
?vdebug("next loop varbinds: next varbind"
"~n ErrorStatus: ~p"
@@ -2963,7 +3200,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
end
end;
next_loop_varbinds({table, TableOid, ME, TabOids},
- [], MibView, Res, _LAVb) ->
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(table) -> entry with"
"~n TableOid: ~p", [TableOid]),
case get_next_table(ME, TableOid, TabOids, MibView) of
@@ -2972,7 +3209,8 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
"~n TabRes: ~p"
"~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, []);
+ next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
+ GbMaxVBs);
{ErrorStatus, OrgIndex} ->
?vdebug("next loop varbinds: next table"
"~n ErrorStatus: ~p"
@@ -2981,7 +3219,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
{ErrorStatus, OrgIndex, []}
end;
next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [Vb | Vbs], MibView, Res, _LAVb) ->
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(subagent) -> entry with"
"~n SAPid: ~p"
"~n SAOid: ~p"
@@ -2990,13 +3228,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
{subagent, _SubAgentPid, SAOid} ->
next_loop_varbinds({subagent, SAPid, SAOid,
[Vb | SAVbs]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
_ ->
case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
{ok, SARes, SAEndOfMibViewVbs} ->
NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{noSuchName, OrgIndex} ->
%% v1 reply, treat this Vb as endOfMibView, and try again
%% for the others.
@@ -3009,12 +3248,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
case lists:delete(EVb, SAVbs) of
[] ->
next_loop_varbinds([], [EndOfVb, Vb | Vbs],
- MibView, Res, []);
+ MibView, Res, [],
+ GbMaxVBs);
TryAgainVbs ->
next_loop_varbinds({subagent, SAPid, SAOid,
TryAgainVbs},
[EndOfVb, Vb | Vbs],
- MibView, Res, [])
+ MibView, Res, [],
+ GbMaxVBs)
end;
false ->
%% bad index from subagent
@@ -3030,14 +3271,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
end
end;
next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [], MibView, Res, _LAVb) ->
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(subagent) -> entry with"
"~n SAPid: ~p"
"~n SAOid: ~p", [SAPid, SAOid]),
case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
{ok, SARes, SAEndOfMibViewVbs} ->
NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{noSuchName, OrgIndex} ->
%% v1 reply, treat this Vb as endOfMibView, and try again for
%% the others.
@@ -3048,11 +3290,13 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
value = {endOfMibView, NextOid}},
case lists:delete(EVb, SAVbs) of
[] ->
- next_loop_varbinds([], [EndOfVb], MibView, Res, []);
+ next_loop_varbinds([], [EndOfVb], MibView, Res, [],
+ GbMaxVBs);
TryAgainVbs ->
next_loop_varbinds({subagent, SAPid, SAOid,
TryAgainVbs},
- [EndOfVb], MibView, Res, [])
+ [EndOfVb], MibView, Res, [],
+ GbMaxVBs)
end;
false ->
%% bad index from subagent
@@ -3065,12 +3309,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
[ErrorStatus,OrgIndex]),
{ErrorStatus, OrgIndex, []}
end;
-next_loop_varbinds([], [], _MibView, Res, _LAVb) ->
+next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
?vt("next_loop_varbinds -> entry when done", []),
{noError, 0, Res}.
try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
- ?vtrace("try get instance from <~p,~p,~p>",[M,F,A]),
+ ?vtrace("try_get_instance -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [M,F,A]),
Result = (catch dbg_apply(M, F, [get | A])),
% mib shall return {value, <a-nice-value-within-range>} |
% {noValue, noSuchName} (v1) |
@@ -3081,6 +3328,7 @@ try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
tab_oid([]) -> [0];
tab_oid(X) -> X.
+
%%-----------------------------------------------------------------
%% Perform a next, using the varbinds Oid if value is simple
%% value. If value is {endOf<something>, NextOid}, use NextOid.
@@ -3327,22 +3575,30 @@ next_oid(Oid) ->
%%%-----------------------------------------------------------------
%%% 5. GET-BULK REQUEST
+%%%
+%%% In order to prevent excesses in reply sizes there are two
+%%% preventive methods in place. One is to check that the encode
+%%% size does not exceed Max PDU size (this is mentioned in the
+%%% standard). The other is a simple VBs limit. That is, the
+%%% resulting response cannot contain more then this number of VBs.
%%%-----------------------------------------------------------------
-do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
- ?vtrace("do get bulk: start with"
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) ->
+ ?vtrace("do_get_bulk -> entry with"
"~n MibView: ~p"
"~n NonRepeaters: ~p"
"~n MaxRepetitions: ~p"
"~n PduMS: ~p"
- "~n Varbinds: ~p",
- [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds]),
+ "~n Varbinds: ~p"
+ "~n GbMaxVBs: ~p",
+ [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
{NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []),
- ?vt("do get bulk -> split: "
+ ?vt("do_get_bulk -> split: "
"~n NonRepVbs: ~p"
"~n RestVbs: ~p", [NonRepVbs, RestVbs]),
- case do_get_next(MibView, NonRepVbs) of
- {noError, 0, UResNonRepVbs} ->
- ?vt("do get bulk -> next: "
+ case do_get_next(MibView, NonRepVbs, GbMaxVBs) of
+ {noError, 0, UResNonRepVbs} ->
+ ?vt("do_get_bulk -> next noError: "
"~n UResNonRepVbs: ~p", [UResNonRepVbs]),
ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
%% Decode the first varbinds, produce a reversed list of
@@ -3352,11 +3608,12 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
{genErr, Idx, []};
{SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
- ?vtrace("do get bulk -> encoded: "
+ ?vtrace("do_get_bulk -> encoded: "
"~n SizeLeft: ~p"
"~n Res: ~w", [SizeLeft, Res]),
case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
- RestVbs, Res)) of
+ RestVbs, Res,
+ length(UResNonRepVbs), GbMaxVBs)) of
{error, Idx, Reason} ->
user_err("failed encoding varbind ~w:~n~p",
[Idx, Reason]),
@@ -3365,6 +3622,10 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
?vtrace("do get bulk -> Res: "
"~n ~w", [Res]),
{noError, 0, conv_res(Res)};
+ {noError, 0, Data} = OK ->
+ ?vtrace("do get bulk -> OK: "
+ "~n length(Data): ~w", [length(Data)]),
+ OK;
Else ->
?vtrace("do get bulk -> Else: "
"~n ~w", [Else]),
@@ -3373,6 +3634,7 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
Res when is_list(Res) ->
{noError, 0, conv_res(Res)}
end;
+
{ErrorStatus, Index, _} ->
?vdebug("do get bulk: "
"~n ErrorStatus: ~p"
@@ -3422,11 +3684,12 @@ enc_vbs(SizeLeft, Vbs) ->
end,
lists:foldl(Fun, {SizeLeft, []}, Vbs).
-do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res)
+do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
when MaxRepetitions >= 0 ->
- do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res);
-do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res) ->
- do_get_rep(Sz, MibView, 0, 0, Varbinds, Res).
+ do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
+ GbNumVBs, GbMaxVBs);
+do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
conv_res(ResVarbinds) ->
conv_res(ResVarbinds, []).
@@ -3435,22 +3698,30 @@ conv_res([VbListOfBytes | T], Bytes) ->
conv_res([], Bytes) ->
Bytes.
-do_get_rep(_Sz, _MibView, Max, Max, _, Res) ->
+%% The only other value, then a positive integer, is infinity.
+do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
+ ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
+ "~n Count: ~p"
+ "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
+ {tooBig, 0, []};
+do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
?vt("do_get_rep -> done when: "
"~n Res: ~p", [Res]),
{noError, 0, conv_res(Res)};
-do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) ->
+do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
?vt("do_get_rep -> entry when: "
"~n Sz: ~p"
"~n Count: ~p"
"~n Res: ~w", [Sz, Count, Res]),
- case try_get_bulk(Sz, MibView, Varbinds) of
+ case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
{noError, NextVarbinds, SizeLeft, Res2} ->
?vt("do_get_rep -> noError: "
"~n SizeLeft: ~p"
"~n Res2: ~p", [SizeLeft, Res2]),
do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
- Res2 ++ Res);
+ Res2 ++ Res,
+ GbNumVBs + length(Varbinds), GbMaxVBs);
{endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
?vt("do_get_rep -> endOfMibView: "
"~n Res2: ~p", [Res2]),
@@ -3462,22 +3733,29 @@ do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) ->
{ErrorStatus, Index, []}
end.
-try_get_bulk(Sz, MibView, Varbinds) ->
+org_index_sort_vbs(Vbs) ->
+ lists:keysort(#varbind.org_index, Vbs).
+
+try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
?vt("try_get_bulk -> entry with"
- "~n Sz: ~w", [Sz]),
- case do_get_next(MibView, Varbinds) of
+ "~n Sz: ~w"
+ "~n MibView: ~w"
+ "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
+ case do_get_next(MibView, Varbinds, GbMaxVBs) of
{noError, 0, UNextVarbinds} ->
- ?vt("try_get_bulk -> noError", []),
- NextVarbinds = lists:keysort(#varbind.org_index, UNextVarbinds),
+ ?vt("try_get_bulk -> noError: "
+ "~n UNextVarbinds: ~p", [UNextVarbinds]),
+ NextVarbinds = org_index_sort_vbs(UNextVarbinds),
case (catch enc_vbs(Sz, NextVarbinds)) of
{error, Idx, Reason} ->
user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- ?vtrace("try_get_bulk -> error: "
+ ?vtrace("try_get_bulk -> encode error: "
"~n Idx: ~p"
"~n Reason: ~p", [Idx, Reason]),
{genErr, Idx};
- {SizeLeft, Res} when is_integer(SizeLeft) andalso is_list(Res) ->
- ?vt("try get bulk -> "
+ {SizeLeft, Res} when is_integer(SizeLeft) andalso
+ is_list(Res) ->
+ ?vt("try get bulk -> encode ok: "
"~n SizeLeft: ~w"
"~n Res: ~w", [SizeLeft, Res]),
{check_end_of_mibview(NextVarbinds),
@@ -3488,9 +3766,9 @@ try_get_bulk(Sz, MibView, Varbinds) ->
{endOfMibView, [], 0, Res}
end;
{ErrorStatus, Index, _} ->
- ?vt("try get bulk: "
+ ?vt("try_get_bulk -> error: "
"~n ErrorStatus: ~p"
- "~n Index: ~p",[ErrorStatus, Index]),
+ "~n Index: ~p", [ErrorStatus, Index]),
{ErrorStatus, Index}
end.
@@ -3631,9 +3909,8 @@ get_err({ErrC, ErrI, Vbs}) ->
{get_err_i(ErrC), ErrI, Vbs}.
get_err_i(noError) -> noError;
-get_err_i(S) ->
- ?vtrace("convert '~p' to 'genErr'",[S]),
- genErr.
+get_err_i(tooBig) -> tooBig; % OTP-9700
+get_err_i(ES) -> ?vtrace("convert ErrorStatus '~p' to 'genErr'", [ES]), genErr.
v2err_to_v1err(noError) -> noError;
v2err_to_v1err(noAccess) -> noSuchName;
@@ -3859,6 +4136,7 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) ->
{Accu2,[R|Rs]};
mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}.
+
%%-----------------------------------------------------------------
%% Runtime debugging of the agent.
%%-----------------------------------------------------------------
@@ -3983,7 +4261,7 @@ handle_set_request_limit(_, _) ->
{error, not_supported}.
-agent_info(#state{worker = W, set_worker = SW}) ->
+agent_info(#state{worker = W, set_worker = SW}) ->
case (catch get_agent_info(W, SW)) of
Info when is_list(Info) ->
Info;
@@ -4142,6 +4420,9 @@ get_multi_threaded(Opts) ->
get_versions(Opts) ->
get_option(versions, Opts, [v1,v2,v3]).
+get_gb_max_vbs(Opts) ->
+ get_option(gb_max_vbs, Opts, infinity).
+
get_note_store_opt(Opts) ->
get_option(note_store, Opts, []).
diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl
index 20a36cc118..c435b519d9 100644
--- a/lib/snmp/src/agent/snmpa_internal.hrl
+++ b/lib/snmp/src/agent/snmpa_internal.hrl
@@ -26,6 +26,15 @@
-define(DEFAULT_LOCAL_ENGINE_ID, snmp_framework_mib:get_engine_id()).
-define(DEFAULT_NOTIF_EXTRA_INFO, {snmpa_default_notification_extra_info}).
+%% -- Max number of VBs in a Get-BULK response --
+%% (( The default value, 1000, is *way* more ))
+%% (( then there is room for in a normal pdu ))
+%% (( (unless the max pdu size has been ))
+%% (( cranked way up), so this value should ))
+%% (( suffice as "infinity" without actually ))
+%% (( causing memory issues for the VM ... ))
+-define(DEFAULT_GB_MAX_VBS, 1000).
+
-define(snmpa_info(F, A), ?snmp_info("agent", F, A)).
-define(snmpa_warning(F, A), ?snmp_warning("agent", F, A)).
-define(snmpa_error(F, A), ?snmp_error("agent", F, A)).
diff --git a/lib/snmp/src/agent/snmpa_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl
index 078e681945..3c94cc8095 100644
--- a/lib/snmp/src/agent/snmpa_mib_lib.erl
+++ b/lib/snmp/src/agent/snmpa_mib_lib.erl
@@ -61,23 +61,23 @@ table_del_row({Tab, Db} = TabDb, Key) ->
get_table(NameDb, FOI) ->
(catch get_table(NameDb, FOI, [], [])).
-get_table(NameDb, FOI, Oid, Acc) ->
- case table_next(NameDb, Oid) of
+get_table(NameDb, FOI, Key, Acc) ->
+ case table_next(NameDb, Key) of
endOfTable ->
?vdebug("end of table",[]),
{ok, lists:reverse(Acc)};
- Oid ->
+ Key ->
%% Crap, circular ref
- ?vinfo("cyclic reference: ~w -> ~w", [Oid,Oid]),
- throw({error, {cyclic_db_reference, Oid, Acc}});
- NextOid ->
- ?vtrace("get row for oid ~w", [NextOid]),
- case table_get_row(NameDb, NextOid, FOI) of
+ ?vinfo("cyclic reference: ~w -> ~w", [Key, Key]),
+ throw({error, {cyclic_db_reference, Key, Acc}});
+ NextKey ->
+ ?vtrace("get row for key ~w", [NextKey]),
+ case table_get_row(NameDb, NextKey, FOI) of
undefined ->
- throw({error, {invalid_rowindex, NextOid, Acc}});
+ throw({error, {invalid_rowindex, NextKey, Acc}});
Row ->
?vtrace("row: ~w", [Row]),
- get_table(NameDb, FOI, NextOid, [{NextOid, Row}|Acc])
+ get_table(NameDb, FOI, NextKey, [{NextKey, Row}|Acc])
end
end.
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index 5ef5914e18..7a9c214e0d 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -176,8 +176,8 @@ init([AgentType, Opts]) ->
"~n AgentType: ~p"
"~n Opts: ~p", [AgentType, Opts]),
- put(sname, asup),
- put(verbosity,get_verbosity(Opts)),
+ put(sname, asup),
+ put(verbosity, get_verbosity(Opts)),
?vlog("starting",[]),
@@ -203,7 +203,12 @@ init([AgentType, Opts]) ->
Vsns = get_opt(versions, Opts, [v1,v2,v3]),
?vdebug("[agent table] store versions: ~p",[Vsns]),
ets:insert(snmp_agent_table, {versions, Vsns}),
-
+
+ %% -- Max number of VBs in a Get-BULK response --
+ GbMaxVBs = get_gb_max_vbs(Opts),
+ ?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]),
+ ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}),
+
%% -- DB-directory --
DbDir = get_opt(db_dir, Opts),
?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]),
@@ -377,7 +382,8 @@ init([AgentType, Opts]) ->
{versions, Vsns},
{net_if, NiOpts},
{mib_server, MibsOpts},
- {note_store, NsOpts}|
+ {note_store, NsOpts},
+ {gb_max_vbs, GbMaxVBs} |
get_opt(master_agent_options, Opts, [])],
AgentSpec =
@@ -542,6 +548,32 @@ get_verbosity(Opts) ->
get_agent_type(Opts) ->
get_opt(agent_type, Opts, master).
+
+%% We validate this option! This should really be done for all
+%% options, but it is beyond the scope of this ticket, OTP-9700.
+
+get_gb_max_vbs(Opts) ->
+ Validate =
+ fun(GbMaxVBs)
+ when ((is_integer(GbMaxVBs) andalso (GbMaxVBs > 0)) orelse
+ (GbMaxVBs =:= infinity)) ->
+ ok;
+ (_) ->
+ error
+ end,
+ get_option(gb_max_vbs, ?DEFAULT_GB_MAX_VBS, Validate, Opts).
+
+get_option(Key, Default, Validate, Opts)
+ when is_list(Opts) andalso is_function(Validate) ->
+ Value = get_opt(Key, Opts, Default),
+ case Validate(Value) of
+ ok ->
+ Value;
+ error ->
+ exit({bad_option, Key, Value})
+ end.
+
+
get_opt(Key, Opts) ->
snmp_misc:get_option(Key, Opts).
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index 5b579efc13..994d926224 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -352,11 +352,26 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, ExtraInfo, NetIf) ->
send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, NetIf).
+%% The agent normally does not care about the result,
+%% but since it can be usefull when debugging, add
+%% some info when we fail to send the trap(s).
send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
ExtraInfo, NetIf) ->
- (catch do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo, NetIf)).
-
+ try
+ begin
+ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo, NetIf)
+ end
+ catch
+ T:E ->
+ Info = [{args, [TrapRec, NotifyName, ContextName,
+ Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]},
+ {tag, T},
+ {err, E},
+ {stacktrace, erlang:get_stacktrace()}],
+ {error, {failed_sending_trap, Info}}
+ end.
+
do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, NetIf) ->
VarbindList = make_varbind_list(Vbs),
diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl
index 892dc265f1..dadcf32543 100644
--- a/lib/snmp/src/agent/snmpa_vacm.erl
+++ b/lib/snmp/src/agent/snmpa_vacm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -62,6 +62,13 @@ get_mib_view(ViewType, SecModel, SecName, SecLevel, ContextName) ->
%% Follows the procedure in rfc2275
auth(ViewType, SecModel, SecName, SecLevel, ContextName) ->
+ ?vtrace("auth -> entry with"
+ "~n ViewType: ~p"
+ "~n SecModel: ~p"
+ "~n SecName: ~p"
+ "~n SecLevel: ~p"
+ "~n ContextName: ~p",
+ [ViewType, SecModel, SecName, SecLevel, ContextName]),
% 3.2.1 - Check that the context is known to us
?vdebug("check that the context (~p) is known to us",[ContextName]),
case snmp_view_based_acm_mib:vacmContextTable(get, ContextName,
@@ -74,7 +81,7 @@ auth(ViewType, SecModel, SecName, SecLevel, ContextName) ->
end,
% 3.2.2 - Check that the SecModel and SecName is valid
?vdebug("check that SecModel (~p) and SecName (~p) is valid",
- [SecModel,SecName]),
+ [SecModel, SecName]),
GroupName =
case snmp_view_based_acm_mib:get(vacmSecurityToGroupTable,
[SecModel, length(SecName) | SecName],
@@ -111,6 +118,8 @@ check_auth(Res) -> {ok, Res}.
%% key in the table >= ViewIndex.
%%-----------------------------------------------------------------
get_mib_view(ViewName) ->
+ ?vtrace("get_mib_view -> entry with"
+ "~n ViewName: ~p", [ViewName]),
ViewKey = [length(ViewName) | ViewName],
case snmp_view_based_acm_mib:table_next(vacmViewTreeFamilyTable,
ViewKey) of
@@ -202,6 +211,13 @@ backup(BackupDir) ->
%% Ret: {ok, ViewName} | {error, Reason}
get_view_name(ViewType, GroupName, ContextName, SecModel, SecLevel) ->
+ ?vtrace("get_view_name -> entry with"
+ "~n ViewType: ~p"
+ "~n GroupName: ~p"
+ "~n ContextName: ~p"
+ "~n SecModel: ~p"
+ "~n SecLevel: ~p",
+ [ViewType, GroupName, ContextName, SecModel, SecLevel]),
GroupKey = [length(GroupName) | GroupName],
case get_access_row(GroupKey, ContextName, SecModel, SecLevel) of
undefined ->
@@ -266,9 +282,10 @@ dump_table(true) ->
dump_table(_) ->
ok.
+
dump_table() ->
[{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file),
- TmpName = FName ++ ".tmp",
+ TmpName = unique_table_name(FName),
case ets:tab2file(snmpa_vacm, TmpName) of
ok ->
case file:rename(TmpName, FName) of
@@ -283,6 +300,35 @@ dump_table() ->
[FName, Reason])
end.
+%% This little thing is an attempt to create a "unique" filename
+%% in order to minimize the risk of two processes at the same
+%% time dumping the table.
+unique_table_name(Pre) ->
+ %% We want something that is guaranteed to be unique,
+ %% therefor we use erlang:now() instead of os:timestamp()
+ unique_table_name(Pre, erlang:now()).
+
+unique_table_name(Pre, {_A, _B, C} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY, MM, DD} = Date,
+ {Hour, Min, Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w~.2.0w~.2.0w_~.2.0w~.2.0w~.2.0w_~w",
+ [YYYY, MM, DD, Hour, Min, Sec, round(C/1000)]),
+ unique_table_name2(Pre, FormatDate).
+
+unique_table_name2(Pre, FormatedDate) ->
+ PidPart = unique_table_name_pid(),
+ lists:flatten(io_lib:format("~s.~s~s.tmp", [Pre, PidPart, FormatedDate])).
+
+unique_table_name_pid() ->
+ case string:tokens(pid_to_list(self()), [$<,$.,$>]) of
+ [A, B, C] ->
+ A ++ B ++ C ++ ".";
+ _ ->
+ ""
+ end.
+
%%-----------------------------------------------------------------
%% Alg.
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 219ac62a73..254e697039 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,46 +22,109 @@
%% ----- U p g r a d e -------------------------------------------------------
[
+ {"4.21.5",
+ [
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"4.21.4",
+ [
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21.3",
[
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.2",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.1",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []}
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
{"4.21",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []}
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
{"4.20.1",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
{load_module, snmpm, soft_purge, soft_purge,
[snmpm_server, snmpm_config, snmp_config]},
@@ -73,21 +136,28 @@
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
+ {update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
+ {update, snmpm_net_if, soft, soft_purge, soft_purge,
[snmp_conf, snmpm_mpd, snmpm_config]}
]
},
{"4.20",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
+ {load_module, snmp_target_mib, soft_purge, soft_purge,
+ [snmpa_mib_lib, snmp_conf]},
{load_module, snmpm, soft_purge, soft_purge,
[snmpm_server, snmpm_config, snmp_config]},
{load_module, snmp_conf, soft_purge, soft_purge, []},
@@ -98,101 +168,121 @@
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
+ {update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
+ {update, snmpm_net_if, soft, soft_purge, soft_purge,
[snmp_conf, snmpm_mpd, snmpm_config]}
]
- },
- {"4.19",
- [
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmpa_usm, soft_purge, soft_purge, []},
- {load_module, snmpm_usm, soft_purge, soft_purge, []},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmp_misc, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_trap, soft_purge, soft_purge,
- [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]},
- {load_module, snmpa_acm, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd, snmp_target_mib]},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_config, snmp_notification_mib]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_notification_mib, soft_purge, soft_purge,
- [snmp_conf, snmp_target_mib]},
- {load_module, snmp_community_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd]},
- {update, snmpa_agent, soft, soft_purge, soft_purge,
- [snmpa_acm, snmpa_mpd, snmpa_trap]}
- ]
}
],
%% ------D o w n g r a d e ---------------------------------------------------
[
+ {"4.21.5",
+ [
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"4.21.4",
+ [
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21.3",
[
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.2",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.1",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, []},
{update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
{"4.21",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_target_mib, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, []},
{update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
{"4.20.1",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_target_mib, soft_purge, soft_purge, []},
@@ -207,7 +297,8 @@
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
@@ -218,6 +309,11 @@
},
{"4.20",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
@@ -232,7 +328,8 @@
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
@@ -240,50 +337,6 @@
{update, snmpm_net_if, soft, soft_purge, soft_purge,
[snmp_conf, snmpm_mpd, snmpm_config]}
]
- },
- {"4.19",
- [
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmpa_usm, soft_purge, soft_purge, []},
- {load_module, snmpm_usm, soft_purge, soft_purge, []},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmp_misc, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_trap, soft_purge, soft_purge,
- [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]},
- {load_module, snmpa_acm, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd, snmp_target_mib]},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_config, snmp_notification_mib]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_notification_mib, soft_purge, soft_purge,
- [snmp_conf, snmp_target_mib]},
- {load_module, snmp_community_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd]},
- {update, snmpa_agent, soft, soft_purge, soft_purge,
- [snmpa_acm, snmpa_mpd, snmpa_trap]}
- ]
}
]
}.
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index c95346b5a6..abfd528639 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -1321,8 +1321,11 @@ finish_v3(Config) when is_list(Config) ->
lists:keydelete(vsn, 1, C1).
-mt_cases() ->
- [multi_threaded, mt_trap].
+mt_cases() ->
+ [
+ multi_threaded,
+ mt_trap
+ ].
init_mt(Config) when is_list(Config) ->
SaNode = ?config(snmp_sa, Config),
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
index c964b08168..0a147130b0 100644
--- a/lib/snmp/test/snmp_compiler_test.erl
+++ b/lib/snmp/test/snmp_compiler_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -566,14 +566,7 @@ p(F, A) ->
p(TName, F, A) ->
io:format("*** [~w][~s] ***"
- "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]).
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl
index 4498d506f3..3192fe1b40 100644
--- a/lib/snmp/test/snmp_manager_config_test.erl
+++ b/lib/snmp/test/snmp_manager_config_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -2726,14 +2726,7 @@ p(F, A) ->
p(TName, F, A) ->
io:format("*** [~s] ***"
- " ~w -> " ++ F ++ "~n", [format_timestamp(now()),TName|A]).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ " ~w -> " ++ F ++ "~n", [formated_timestamp(),TName|A]).
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index d18f20d359..75c9f7b277 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -6064,7 +6064,7 @@ rcall(Node, Mod, Func, Args) ->
%% Time in milli sec
%% t() ->
-%% {A,B,C} = erlang:now(),
+%% {A,B,C} = os:timestamp(),
%% A*1000000000+B*1000+(C div 1000).
@@ -6078,16 +6078,10 @@ p(F, A) ->
p(TName, F, A) ->
io:format("*** [~w][~s] ***"
- "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]).
+
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
%% p(TName, F, A) ->
%% io:format("~w -> " ++ F ++ "~n", [TName|A]).
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index 54839d989b..e4d58a1253 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,7 +37,7 @@
-export([watchdog/3, watchdog_start/1, watchdog_start/2, watchdog_stop/1]).
-export([del_dir/1]).
-export([cover/1]).
--export([p/2, print/5]).
+-export([p/2, print/5, formated_timestamp/0]).
%% ----------------------------------------------------------------------
@@ -521,15 +521,18 @@ p(F, A) when is_list(F) andalso is_list(A) ->
print(Prefix, Module, Line, Format, Args) ->
io:format("*** [~s] ~s ~p ~p ~p:~p *** " ++ Format ++ "~n",
- [format_timestamp(now()),
+ [formated_timestamp(),
Prefix, node(), self(), Module, Line|Args]).
+formated_timestamp() ->
+ format_timestamp(os:timestamp()).
+
format_timestamp({_N1, _N2, N3} = Now) ->
{Date, Time} = calendar:now_to_datetime(Now),
{YYYY,MM,DD} = Date,
{Hour,Min,Sec} = Time,
FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w ~w",
[YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
lists:flatten(FormatDate).
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index 84bdc6b04f..499cf7abcf 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1124,16 +1124,11 @@ d(F,A) -> d(get(debug),F,A).
d(true,F,A) ->
io:format("*** [~s] MGR_DBG *** " ++ F ++ "~n",
- [format_timestamp(now())|A]);
+ [formated_timestamp()|A]);
d(_,_F,_A) ->
ok.
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl
index fc6dedd96d..5525c5c3ec 100644
--- a/lib/snmp/test/snmp_test_mgr_misc.erl
+++ b/lib/snmp/test/snmp_test_mgr_misc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -779,16 +779,9 @@ d(F,A) -> d(get(debug),F,A).
d(true,F,A) ->
io:format("*** [~s] MGR_PS_DBG *** " ++ F ++ "~n",
- [format_timestamp(now())|A]);
+ [formated_timestamp()|A]);
d(_,_F,_A) ->
ok.
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
-
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index ee2e633c69..1fbad654f7 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2011. All Rights Reserved.
+# Copyright Ericsson AB 1997-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -18,6 +18,7 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 4.21.4
-PRE_VSN =
-APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
+SNMP_VSN = 4.21.6
+PRE_VSN =
+APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
+
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 5ea0d98980..73b60057cc 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -41,9 +41,20 @@
init_per_suite(Config) ->
case catch crypto:start() of
ok ->
- Dir = ?config(priv_dir, Config),
- {ok, _} = ssh_test_lib:get_id_keys(Dir),
- ssh_test_lib:make_dsa_files(Config),
+ DataDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:copyfile(DataDir, UserDir, "id_rsa"),
+ ssh_test_lib:copyfile(DataDir, UserDir, "id_dsa"),
+ RSAFile = filename:join(DataDir, "id_rsa.pub"),
+ DSAFile = filename:join(DataDir, "id_dsa.pub"),
+ {ok, Ssh1} = file:read_file(RSAFile),
+ {ok, Ssh2} = file:read_file(DSAFile),
+ [{RSA, _}] = public_key:ssh_decode(Ssh1,public_key),
+ [{DSA, _}] = public_key:ssh_decode(Ssh2,public_key),
+ AuthKeys = public_key:ssh_encode([{RSA, [{comment, "Test"}]},
+ {DSA,[{comment, "Test"}]}], auth_keys),
+ AuthKeysFile = filename:join(UserDir, "authorized_keys"),
+ file:write_file(AuthKeysFile, AuthKeys),
Config;
_Else ->
{skip, "Crypto could not be started!"}
@@ -56,9 +67,7 @@ init_per_suite(Config) ->
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
end_per_suite(Config) ->
- Dir = ?config(priv_dir, Config),
crypto:stop(),
- ssh_test_lib:remove_id_keys(Dir),
ok.
%%--------------------------------------------------------------------
@@ -75,7 +84,6 @@ end_per_suite(Config) ->
%% Description: Initialization before each test case
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
- ssh_test_lib:known_hosts(backup),
ssh:start(),
Config.
@@ -87,9 +95,16 @@ init_per_testcase(_TestCase, Config) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, _Config) ->
+
+end_per_testcase(TestCase, Config) when TestCase == server_password_option;
+ TestCase == server_userpassword_option ->
+ UserDir = filename:join(?config(priv_dir, Config), nopubkey),
+ file:del_dir(UserDir),
+ end_per_testcase(Config);
+end_per_testcase(_TestCase, Config) ->
+ end_per_testcase(Config).
+end_per_testcase(Config) ->
ssh:stop(),
- ssh_test_lib:known_hosts(restore),
ok.
%%--------------------------------------------------------------------
@@ -101,9 +116,8 @@ end_per_testcase(_TestCase, _Config) ->
%% Description: Returns a list of all test cases in this test suite
%%--------------------------------------------------------------------
all() ->
- [exec, exec_compressed, shell, daemon_already_started,
- server_password_option, server_userpassword_option,
- known_hosts].
+ [exec, exec_compressed, shell, daemon_already_started,
+ server_password_option, server_userpassword_option, known_hosts].
groups() ->
[].
@@ -136,10 +150,14 @@ exec(suite) ->
exec(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
ConnectionRef =
ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
{user_interaction, false}]),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
success = ssh_connection:exec(ConnectionRef, ChannelId0,
@@ -178,12 +196,15 @@ exec_compressed(suite) ->
exec_compressed(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = ?config(data_dir, Config),
- {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ UserDir = ?config(priv_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
{compression, zlib},
{failfun, fun ssh_test_lib:failfun/2}]),
ConnectionRef =
ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
{user_interaction, false}]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
success = ssh_connection:exec(ConnectionRef, ChannelId,
@@ -209,12 +230,14 @@ shell(suite) ->
shell(Config) when is_list(Config) ->
process_flag(trap_exit, true),
SystemDir = ?config(data_dir, Config),
- {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ UserDir = ?config(priv_dir, Config),
+
+ {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
test_server:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO),
+ Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
receive
ErlShellStart ->
test_server:format("Erlang shell start: ~p~n", [ErlShellStart])
@@ -291,8 +314,9 @@ server_password_option(doc) ->
server_password_option(suite) ->
[];
server_password_option(Config) when is_list(Config) ->
- UserDir = ?config(data_dir, Config), % to make sure we don't use
- SysDir = ?config(data_dir, Config), % public-key-auth
+ UserDir = filename:join(?config(priv_dir, Config), nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
{password, "morot"}]),
@@ -321,8 +345,9 @@ server_userpassword_option(doc) ->
server_userpassword_option(suite) ->
[];
server_userpassword_option(Config) when is_list(Config) ->
- UserDir = ?config(data_dir, Config), % to make sure we don't use
- SysDir = ?config(data_dir, Config), % public-key-auth
+ UserDir = filename:join(?config(priv_dir, Config), nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
{user_passwords, [{"vego", "morot"}]}]),
@@ -361,10 +386,10 @@ known_hosts(doc) ->
known_hosts(suite) ->
[];
known_hosts(Config) when is_list(Config) ->
- SystemDir = ?config(data_dir, Config),
+ DataDir = ?config(data_dir, Config),
UserDir = ?config(priv_dir, Config),
-
- {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{user_dir, UserDir},{system_dir, DataDir},
{failfun, fun ssh_test_lib:failfun/2}]),
KnownHosts = filename:join(UserDir, "known_hosts"),
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_dsa b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa
new file mode 100644
index 0000000000..d306f8b26e
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
+APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
+/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
+kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
+JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
+OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
+uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
+Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
+ZU8w8Q+H7z0j+a+70x2iAw==
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub
new file mode 100644
index 0000000000..9406116777
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAN+LZ+VJNlmh/BPjJBPQ2KRf8sY1PtQ94H9cRZ7/Gi8RgISV9pAA8WLFe8SBfCiiOZnmSJBErMszf3AE/SM8REtudld844PQ8OfDSFoyHt0PtcpUyh38SKBWAd/+oF0zYzzLPWz+tEXufVSktLKnOIqOTMKbsmhJDbNtYg92YEhfAAAAFQDID5Ka+0qtzu7B3W/A+tNQ0Y6BMQAAAIAw5DEN8HYV3yi7Pob3p/9Q7NEwj8p2/yRhgpYkgZj6lFiss/JjNR4nOfBmt44mCtzMBf6W4ecoVYnYOeTkLJ5eTrtayvukn/gwEwM4p4hLRLyqhIE3z4qunv1+AD7JLch+puQku0u7gQFoJfiYpAhfj76Tjh3hTmVzym372GUQjwAAAIEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+euEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AXCy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34= Dsa
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub
new file mode 100644
index 0000000000..95bce6bc61
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== ingela@dain
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..d306f8b26e
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
+APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
+/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
+kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
+JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
+OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
+uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
+Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
+ZU8w8Q+H7z0j+a+70x2iAw==
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index c96b6de3ea..a9a568ced6 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,7 +50,6 @@ init_per_suite(Config) ->
{ok,ok} ->
Dir = ?config(priv_dir, Config),
{ok, _} = ssh_test_lib:get_id_keys(Dir),
- ssh_test_lib:make_dsa_files(Config),
Config;
{ok,_} ->
{skip,"Could not start ssh!"};
@@ -94,13 +93,14 @@ init_per_testcase(_Case, Config) ->
SysDir = ?config(data_dir, Config),
Host = ssh_test_lib:hostname(),
+ %% Run test against openssh server if available
Sftp = case (catch ssh_sftp:start_channel(Host,
[{user_dir, Dir},
{user_interaction, false},
{silently_accept_hosts, true}])) of
{ok, ChannelPid, Connection} ->
{ChannelPid, Connection};
- _Error ->
+ _Error -> %% Start own sftp server
{_Sftpd, _Host, _Port} =
ssh_test_lib:daemon(Host, ?SFPD_PORT,
[{system_dir, SysDir},
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa
deleted file mode 100644
index 7e3f885f5d..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICWwIBAAKBgQDLKYTdRnGzphcN+pF8UuI3sYB7rxZUHbOT87K3vh8XOLkDOsS3
-8VREtNS8Wb3uYXsRtyDoUvrLIDnyllOfJSDupWLr4ibckUZd/nhFAaC6WryVmH6k
-GlQLLp9KU+vcn2DwYeo14gbwHYDB3pmv4CWAlnO1m/BkX4aLz1zC314OkQIBIwKB
-gD/Z2UzboBPjvhpWEHeHw3CW3zzQoJ4X9pw2peH57IOkHOPCA0/A3/hWFvleCH4e
-owWRU3w3ViKVGYbBh/7RJ5rllN+ENUmVn536srJTxLKUtvb5jRGj3W6EWgAGHSUB
-hm83Kt9Lb5hprL7dPrNGvSseBm/LQSfBQ4vUUyiVRKGPAkEA/rPxWoLdBBP+FZtE
-fGzz9izPM6Fe6o8ZGNZIlRBProOhgEvvIqdgzQWObgLVVrw+M/YApPpiYS3PEmWj
-b2b+jwJBAMwyYeL6coKTl8swDu8HvLnshgUFJFTtHhOTXsKtXQNI1b24xhUrB3Sb
-X8fmoByyRNRpOfvg4Jdqi3Z6KfIcsN8CQQDEfC83McBw3DkJWoVKCugVrYnmACSm
-USH9N5cT6AL0VupNB2C0VTwL37cEaJXyc/V4ipLIaWHV8CNl9qKmZWVJAkEAurG4
-lQI8zyfbPW3EgsU+1d+QeZ5NGnJkpC73jWtNudwxIn0M4CdXRgpmMxwAGjyWs5No
-Nr75OfsDKn5SPHIAywJAKrtONlOizgDiG3EvAXZlwFtOb+HkQ7lrFwczrQu9m7yi
-brSAcnTrLKI6CrR33b/QJLvb9C/HTEZojFABGq8M7A==
------END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub
deleted file mode 100644
index 77f57de4af..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAyymE3UZxs6YXDfqRfFLiN7GAe68WVB2zk/Oyt74fFzi5AzrEt/FURLTUvFm97mF7Ebcg6FL6yyA58pZTnyUg7qVi6+Im3JFGXf54RQGgulq8lZh+pBpUCy6fSlPr3J9g8GHqNeIG8B2Awd6Zr+AlgJZztZvwZF+Gi89cwt9eDpE= jakob@balin
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index bfe54a3e75..0873348be0 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -53,16 +53,15 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- case {catch ssh:stop(),catch crypto:start()} of
- {ok,ok} ->
- ssh_test_lib:make_dsa_files(Config),
+ case (catch crypto:start()) of
+ ok ->
+ ssh:start(),
+ DataDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa(UserDir, DataDir),
Config;
- {ok,_} ->
- {skip,"Could not start ssh!"};
- {_,ok} ->
- {skip,"Could not start crypto!"};
- {_,_} ->
- {skip,"Could not start crypto and ssh!"}
+ _ ->
+ {skip,"Could not start ssh!"}
end.
%%--------------------------------------------------------------------
@@ -71,7 +70,10 @@ init_per_suite(Config) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(UserDir),
+ ssh:stop(),
crypto:stop(),
ok.
diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
index 2209af05d5..c63ad7de73 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -48,13 +48,14 @@ init_per_suite(Config) ->
case catch crypto:start() of
ok ->
DataDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"),
c:c(FileAlt),
FileName = filename:join(DataDir, "test.txt"),
{ok, FileInfo} = file:read_file_info(FileName),
ok = file:write_file_info(FileName,
FileInfo#file_info{mode = 8#400}),
- ssh_test_lib:make_dsa_files(Config),
+ ssh_test_lib:setup_dsa(DataDir, UserDir),
Config;
_Else ->
{skip,"Could not start ssh!"}
@@ -66,7 +67,9 @@ init_per_suite(Config) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(UserDir),
crypto:stop(),
ok.
@@ -85,7 +88,7 @@ end_per_suite(_Config) ->
%%--------------------------------------------------------------------
init_per_testcase(TestCase, Config) ->
ssh:start(),
- DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
Options =
case atom_to_list(TestCase) of
@@ -95,8 +98,7 @@ init_per_testcase(TestCase, Config) ->
ssh_sftpd_file_alt}]),
[{user_passwords,[{?USER, ?PASSWD}]},
{pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ {system_dir, PrivDir},
{subsystems, [Spec]}];
"root_dir" ->
Privdir = ?config(priv_dir, Config),
@@ -105,23 +107,20 @@ init_per_testcase(TestCase, Config) ->
Spec = ssh_sftpd:subsystem_spec([{root,Root}]),
[{user_passwords,[{?USER, ?PASSWD}]},
{pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ {system_dir, PrivDir},
{subsystems, [Spec]}];
"list_dir_limited" ->
Spec =
ssh_sftpd:subsystem_spec([{max_files,1}]),
[{user_passwords,[{?USER, ?PASSWD}]},
{pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ {system_dir, PrivDir},
{subsystems, [Spec]}];
_ ->
[{user_passwords,[{?USER, ?PASSWD}]},
{pwdfun, fun(_,_) -> true end},
- {user_dir, DataDir},
- {system_dir, DataDir}]
+ {system_dir, PrivDir}]
end,
{Sftpd, Host, _Port} = ssh_test_lib:daemon(any, ?SSHD_PORT, Options),
@@ -131,8 +130,7 @@ init_per_testcase(TestCase, Config) ->
[{silently_accept_hosts, true},
{user, ?USER}, {password, ?PASSWD},
{pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ {user_dir, PrivDir},
{timeout, 30000}]),
TmpConfig = lists:keydelete(sftp, 1, Config),
NewConfig = lists:keydelete(sftpd, 1, TmpConfig),
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 425fae22c1..f4e95f9bfb 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -68,15 +68,11 @@ daemon(Host, Port, Options) ->
Error
end.
+start_shell(Port, IOServer, UserDir) ->
+ spawn_link(?MODULE, init_shell, [Port, IOServer, [{user_dir, UserDir}]]).
-
-
-start_shell(Port, IOServer) ->
- spawn_link(?MODULE, init_shell, [Port, IOServer]).
-
-init_shell(Port, IOServer) ->
+init_shell(Port, IOServer, UserDir) ->
Host = hostname(),
- UserDir = get_user_dir(),
Options = [{user_interaction, false}, {silently_accept_hosts,
true}] ++ UserDir,
group_leader(IOServer, self()),
@@ -139,12 +135,18 @@ reply(TestCase, Result) ->
receive_exec_result(Msg) ->
test_server:format("Expect data! ~p", [Msg]),
receive
+ {ssh_cm,_,{data,_,1, Data}} ->
+ test_server:format("StdErr: ~p~n", [Data]),
+ receive_exec_result(Msg);
Msg ->
test_server:format("1: Collected data ~p", [Msg]),
expected;
Other ->
+ test_server:format("Other ~p", [Other]),
{unexpected_msg, Other}
end.
+
+
receive_exec_end(ConnectionRef, ChannelId) ->
Eof = {ssh_cm, ConnectionRef, {eof, ChannelId}},
ExitStatus = {ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}},
@@ -198,9 +200,16 @@ remove_id_keys(Dir) ->
file:delete(filename:join(Dir, "id_rsa")),
file:delete(filename:join(Dir, "id_dsa")).
-copyfile(SrcDir, DstDir, Fn) ->
- file:copy(filename:join(SrcDir, Fn),
- filename:join(DstDir, Fn)).
+copyfile(SrcDir, DstDir, FileName) ->
+ Dest = filename:join(DstDir, FileName),
+ Result = file:copy(filename:join(SrcDir, FileName), Dest),
+ {ok, Pem} = file:read_file(Dest),
+ case public_key:pem_decode(Pem) of
+ [{_,_, not_encrypted}] ->
+ Result;
+ _ ->
+ {error, "Has pass phrase can not be used by automated test case"}
+ end.
failfun(_User, {authmethod,none}) ->
ok;
@@ -222,39 +231,11 @@ known_hosts(BR) ->
file:rename(B, KnownHosts)
end.
-
-get_user_dir() ->
- case os:type() of
- {win32, _} ->
- [{user_dir, filename:join([os:getenv("HOME"), ".ssh"])}];
- _ ->
- []
- end.
-
-
-make_dsa_cert_files(Config) ->
- make_dsa_cert_files("", Config).
-
-make_dsa_cert_files(RoleStr, Config) ->
-
- CaInfo = {CaCert, _} = make_cert([{key, dsa}]),
- {Cert, CertKey} = make_cert([{key, dsa}, {issuer, CaInfo}]),
- CaCertFile = filename:join([?config(data_dir, Config),
- RoleStr, "dsa_cacerts.pem"]),
- CertFile = filename:join([?config(data_dir, Config),
- RoleStr, "dsa_cert.pem"]),
- KeyFile = filename:join([?config(data_dir, Config),
- RoleStr, "dsa_key.pem"]),
-
- der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]),
- der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]),
- der_to_pem(KeyFile, [CertKey]),
- {CaCertFile, CertFile, KeyFile}.
-
-make_dsa_files(Config) ->
- make_dsa_files(Config, rfc4716_public_key).
-make_dsa_files(Config, Type) ->
- {DSA, EncodedKey} = ssh_test_lib:gen_dsa(128, 20),
+setup_dsa(DataDir, UserDir) ->
+ ssh_test_lib:copyfile(DataDir, UserDir, "ssh_host_dsa_key"),
+ ssh_test_lib:copyfile(DataDir, UserDir, "ssh_host_dsa_key.pub"),
+ {ok, Pem} = file:read_file(filename:join(UserDir, "ssh_host_dsa_key")),
+ DSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))),
PKey = DSA#'DSAPrivateKey'.y,
P = DSA#'DSAPrivateKey'.p,
Q = DSA#'DSAPrivateKey'.q,
@@ -263,422 +244,13 @@ make_dsa_files(Config, Type) ->
{ok, Hostname} = inet:gethostname(),
{ok, {A, B, C, D}} = inet:getaddr(Hostname, inet),
IP = lists:concat([A, ".", B, ".", C, ".", D]),
- Attributes = [], % Could be [{comment,"user@" ++ Hostname}],
HostNames = [{hostnames,[IP, IP]}],
- PublicKey = [{{PKey, Dss}, Attributes}],
KnownHosts = [{{PKey, Dss}, HostNames}],
-
KnownHostsEnc = public_key:ssh_encode(KnownHosts, known_hosts),
- KnownHosts = public_key:ssh_decode(KnownHostsEnc, known_hosts),
-
- PublicKeyEnc = public_key:ssh_encode(PublicKey, Type),
-% PublicKey = public_key:ssh_decode(PublicKeyEnc, Type),
-
- SystemTmpDir = ?config(data_dir, Config),
- filelib:ensure_dir(SystemTmpDir),
- file:make_dir(SystemTmpDir),
-
- DSAFile = filename:join(SystemTmpDir, "ssh_host_dsa_key.pub"),
- file:delete(DSAFile),
-
- DSAPrivateFile = filename:join(SystemTmpDir, "ssh_host_dsa_key"),
- file:delete(DSAPrivateFile),
-
- KHFile = filename:join(SystemTmpDir, "known_hosts"),
- file:delete(KHFile),
-
- PemBin = public_key:pem_encode([EncodedKey]),
-
- file:write_file(DSAFile, PublicKeyEnc),
- file:write_file(KHFile, KnownHostsEnc),
- file:write_file(DSAPrivateFile, PemBin),
- ok.
-
-%%--------------------------------------------------------------------
-%% Create and return a der encoded certificate
-%% Option Default
-%% -------------------------------------------------------
-%% digest sha1
-%% validity {date(), date() + week()}
-%% version 3
-%% subject [] list of the following content
-%% {name, Name}
-%% {email, Email}
-%% {city, City}
-%% {state, State}
-%% {org, Org}
-%% {org_unit, OrgUnit}
-%% {country, Country}
-%% {serial, Serial}
-%% {title, Title}
-%% {dnQualifer, DnQ}
-%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
-%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
-%%
-%%
-%% (OBS: The generated keys are for testing only)
-%% make_cert([{::atom(), ::term()}]) -> {Cert::binary(), Key::binary()}
-%%--------------------------------------------------------------------
-make_cert(Opts) ->
- SubjectPrivateKey = get_key(Opts),
- {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts),
- Cert = public_key:pkix_sign(TBSCert, IssuerKey),
- true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok
- {Cert, encode_key(SubjectPrivateKey)}.
-
-%%--------------------------------------------------------------------
-%% Writes cert files in Dir with FileName and FileName ++ Suffix
-%% write_cert(::string(), ::string(), {Cert,Key}) -> ok
-%%--------------------------------------------------------------------
-write_cert(Dir, FileName, Suffix, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) ->
- ok = der_to_pem(filename:join(Dir, FileName),
- [{'Certificate', Cert, not_encrypted}]),
- ok = der_to_pem(filename:join(Dir, FileName ++ Suffix), [Key]).
-
-%%--------------------------------------------------------------------
-%% Creates a rsa key (OBS: for testing only)
-%% the size are in bytes
-%% gen_rsa(::integer()) -> {::atom(), ::binary(), ::opaque()}
-%%--------------------------------------------------------------------
-gen_rsa(Size) when is_integer(Size) ->
- Key = gen_rsa2(Size),
- {Key, encode_key(Key)}.
-
-%%--------------------------------------------------------------------
-%% Creates a dsa key (OBS: for testing only)
-%% the sizes are in bytes
-%% gen_dsa(::integer()) -> {::atom(), ::binary(), ::opaque()}
-%%--------------------------------------------------------------------
-gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
- Key = gen_dsa2(LSize, NSize),
- {Key, encode_key(Key)}.
-
-%%--------------------------------------------------------------------
-%% Verifies cert signatures
-%% verify_signature(::binary(), ::tuple()) -> ::boolean()
-%%--------------------------------------------------------------------
-verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
- Key = decode_key(DerKey),
- case Key of
- #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} ->
- public_key:pkix_verify(DerEncodedCert,
- #'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
- #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-get_key(Opts) ->
- case proplists:get_value(key, Opts) of
- undefined -> make_key(rsa, Opts);
- rsa -> make_key(rsa, Opts);
- dsa -> make_key(dsa, Opts);
- Key ->
- Password = proplists:get_value(password, Opts, no_passwd),
- decode_key(Key, Password)
- end.
-
-decode_key({Key, Pw}) ->
- decode_key(Key, Pw);
-decode_key(Key) ->
- decode_key(Key, no_passwd).
-
-
-decode_key(#'RSAPublicKey'{} = Key,_) ->
- Key;
-decode_key(#'RSAPrivateKey'{} = Key,_) ->
- Key;
-decode_key(#'DSAPrivateKey'{} = Key,_) ->
- Key;
-decode_key(PemEntry = {_,_,_}, Pw) ->
- public_key:pem_entry_decode(PemEntry, Pw);
-decode_key(PemBin, Pw) ->
- [KeyInfo] = public_key:pem_decode(PemBin),
- decode_key(KeyInfo, Pw).
-
-encode_key(Key = #'RSAPrivateKey'{}) ->
- {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
-encode_key(Key = #'DSAPrivateKey'{}) ->
- {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
-
-make_tbs(SubjectKey, Opts) ->
- Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
-
- IssuerProp = proplists:get_value(issuer, Opts, true),
- {Issuer, IssuerKey} = issuer(IssuerProp, Opts, SubjectKey),
-
- {Algo, Parameters} = sign_algorithm(IssuerKey, Opts),
-
- SignAlgo = #'SignatureAlgorithm'{algorithm = Algo,
- parameters = Parameters},
- Subject = case IssuerProp of
- true -> %% Is a Root Ca
- Issuer;
- _ ->
- subject(proplists:get_value(subject, Opts),false)
- end,
-
- {#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1,
- signature = SignAlgo,
- issuer = Issuer,
- validity = validity(Opts),
- subject = Subject,
- subjectPublicKeyInfo = publickey(SubjectKey),
- version = Version,
- extensions = extensions(Opts)
- }, IssuerKey}.
-
-issuer(true, Opts, SubjectKey) ->
- %% Self signed
- {subject(proplists:get_value(subject, Opts), true), SubjectKey};
-issuer({Issuer, IssuerKey}, _Opts, _SubjectKey) when is_binary(Issuer) ->
- {issuer_der(Issuer), decode_key(IssuerKey)};
-issuer({File, IssuerKey}, _Opts, _SubjectKey) when is_list(File) ->
- {ok, [{cert, Cert, _}|_]} = pem_to_der(File),
- {issuer_der(Cert), decode_key(IssuerKey)}.
-
-issuer_der(Issuer) ->
- Decoded = public_key:pkix_decode_cert(Issuer, otp),
- #'OTPCertificate'{tbsCertificate=Tbs} = Decoded,
- #'OTPTBSCertificate'{subject=Subject} = Tbs,
- Subject.
-
-subject(undefined, IsRootCA) ->
- User = if IsRootCA -> "RootCA"; true -> os:getenv("USER") end,
- Opts = [{email, User ++ "@erlang.org"},
- {name, User},
- {city, "Stockholm"},
- {country, "SE"},
- {org, "erlang"},
- {org_unit, "testing dep"}],
- subject(Opts);
-subject(Opts, _) ->
- subject(Opts).
-
-subject(SubjectOpts) when is_list(SubjectOpts) ->
- Encode = fun(Opt) ->
- {Type,Value} = subject_enc(Opt),
- [#'AttributeTypeAndValue'{type=Type, value=Value}]
- end,
- {rdnSequence, [Encode(Opt) || Opt <- SubjectOpts]}.
-
-%% Fill in the blanks
-subject_enc({name, Name}) -> {?'id-at-commonName', {printableString, Name}};
-subject_enc({email, Email}) -> {?'id-emailAddress', Email};
-subject_enc({city, City}) -> {?'id-at-localityName', {printableString, City}};
-subject_enc({state, State}) -> {?'id-at-stateOrProvinceName', {printableString, State}};
-subject_enc({org, Org}) -> {?'id-at-organizationName', {printableString, Org}};
-subject_enc({org_unit, OrgUnit}) -> {?'id-at-organizationalUnitName', {printableString, OrgUnit}};
-subject_enc({country, Country}) -> {?'id-at-countryName', Country};
-subject_enc({serial, Serial}) -> {?'id-at-serialNumber', Serial};
-subject_enc({title, Title}) -> {?'id-at-title', {printableString, Title}};
-subject_enc({dnQualifer, DnQ}) -> {?'id-at-dnQualifier', DnQ};
-subject_enc(Other) -> Other.
-
-
-extensions(Opts) ->
- case proplists:get_value(extensions, Opts, []) of
- false ->
- asn1_NOVALUE;
- Exts ->
- lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)])
- end.
-
-default_extensions(Exts) ->
- Def = [{key_usage,undefined},
- {subject_altname, undefined},
- {issuer_altname, undefined},
- {basic_constraints, default},
- {name_constraints, undefined},
- {policy_constraints, undefined},
- {ext_key_usage, undefined},
- {inhibit_any, undefined},
- {auth_key_id, undefined},
- {subject_key_id, undefined},
- {policy_mapping, undefined}],
- Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end,
- Exts ++ lists:foldl(Filter, Def, Exts).
-
-extension({_, undefined}) -> [];
-extension({basic_constraints, Data}) ->
- case Data of
- default ->
- #'Extension'{extnID = ?'id-ce-basicConstraints',
- extnValue = #'BasicConstraints'{cA=true},
- critical=true};
- false ->
- [];
- Len when is_integer(Len) ->
- #'Extension'{extnID = ?'id-ce-basicConstraints',
- extnValue = #'BasicConstraints'{cA=true, pathLenConstraint=Len},
- critical=true};
- _ ->
- #'Extension'{extnID = ?'id-ce-basicConstraints',
- extnValue = Data}
- end;
-extension({Id, Data, Critical}) ->
- #'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
-
-
-publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
- Public = #'RSAPublicKey'{modulus=N, publicExponent=E},
- Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
- subjectPublicKey = Public};
-publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
- Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
- parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
-
-validity(Opts) ->
- DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
- DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7),
- {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}),
- Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end,
- #'Validity'{notBefore={generalTime, Format(DefFrom)},
- notAfter ={generalTime, Format(DefTo)}}.
-
-sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
- Type = case proplists:get_value(digest, Opts, sha1) of
- sha1 -> ?'sha1WithRSAEncryption';
- sha512 -> ?'sha512WithRSAEncryption';
- sha384 -> ?'sha384WithRSAEncryption';
- sha256 -> ?'sha256WithRSAEncryption';
- md5 -> ?'md5WithRSAEncryption';
- md2 -> ?'md2WithRSAEncryption'
- end,
- {Type, 'NULL'};
-sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
-
-make_key(rsa, _Opts) ->
- %% (OBS: for testing only)
- gen_rsa2(64);
-make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% RSA key generation (OBS: for testing only)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53,
- 47,43,41,37,31,29,23,19,17,13,11,7,5,3]).
-
-gen_rsa2(Size) ->
- P = prime(Size),
- Q = prime(Size),
- N = P*Q,
- Tot = (P - 1) * (Q - 1),
- [E|_] = lists:dropwhile(fun(Candidate) -> (Tot rem Candidate) == 0 end, ?SMALL_PRIMES),
- {D1,D2} = extended_gcd(E, Tot),
- D = erlang:max(D1,D2),
- case D < E of
- true ->
- gen_rsa2(Size);
- false ->
- {Co1,Co2} = extended_gcd(Q, P),
- Co = erlang:max(Co1,Co2),
- #'RSAPrivateKey'{version = 'two-prime',
- modulus = N,
- publicExponent = E,
- privateExponent = D,
- prime1 = P,
- prime2 = Q,
- exponent1 = D rem (P-1),
- exponent2 = D rem (Q-1),
- coefficient = Co
- }
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% DSA key generation (OBS: for testing only)
-%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm
-%% and the fips_186-3.pdf
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-gen_dsa2(LSize, NSize) ->
- Q = prime(NSize), %% Choose N-bit prime Q
- X0 = prime(LSize),
- P0 = prime((LSize div 2) +1),
-
- %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
- case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
- error ->
- gen_dsa2(LSize, NSize);
- P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
- %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
-
- X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
-
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
- end.
-
-%% See fips_186-3.pdf
-dsa_search(T, P0, Q, Iter) when Iter > 0 ->
- P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
- true -> P;
- false -> dsa_search(T+1, P0, Q, Iter-1)
- end;
-dsa_search(_,_,_,_) ->
- error.
-
-
-%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-prime(ByteSize) ->
- Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
-
-prime_odd(Rand, N) ->
- case is_prime(Rand, 50) of
- true ->
- Rand;
- false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
- end.
-
-%% see http://en.wikipedia.org/wiki/Fermat_primality_test
-is_prime(_, 0) -> true;
-is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
-
-odd_rand(Size) ->
- Min = 1 bsl (Size*8-1),
- Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
-
-odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
- end.
-
-extended_gcd(A, B) ->
- case A rem B of
- 0 ->
- {0, 1};
- N ->
- {X, Y} = extended_gcd(B, N),
- {Y, X-Y*(A div B)}
- end.
-
-pem_to_der(File) ->
- {ok, PemBin} = file:read_file(File),
- public_key:pem_decode(PemBin).
+ KHFile = filename:join(UserDir, "known_hosts"),
+ file:write_file(KHFile, KnownHostsEnc).
-der_to_pem(File, Entries) ->
- PemBin = public_key:pem_encode(Entries),
- file:write_file(File, PemBin).
+clean_dsa(UserDir) ->
+ file:delete(filename:join(UserDir, "ssh_host_dsa_key")),
+ file:delete(filename:join(UserDir, "ssh_host_dsa_key.pub")),
+ file:delete(filename:join(UserDir, "known_hosts")).
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index f959d50484..53d04620c5 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -42,8 +42,12 @@
init_per_suite(Config) ->
case catch crypto:start() of
ok ->
- ssh_test_lib:make_dsa_files(Config),
- Config;
+ case gen_tcp:connect("localhost", 22, []) of
+ {error,econnrefused} ->
+ {skip,"No openssh deamon"};
+ _ ->
+ Config
+ end;
_Else ->
{skip,"Could not start crypto!"}
end.
@@ -100,26 +104,43 @@ all() ->
false ->
{skip, "openSSH not installed on host"};
_ ->
- [erlang_shell_client_openssh_server,
- erlang_client_openssh_server_exec,
- erlang_client_openssh_server_exec_compressed,
- erlang_server_openssh_client_exec,
- erlang_server_openssh_client_exec_compressed,
- erlang_client_openssh_server_setenv,
- erlang_client_openssh_server_publickey_rsa,
- erlang_client_openssh_server_publickey_dsa,
- erlang_server_openssh_client_pulic_key_dsa,
- erlang_client_openssh_server_password]
+ [{group, erlang_client},
+ {group, erlang_server}
+ ]
end.
groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
+ [{erlang_client, [], [erlang_shell_client_openssh_server,
+ erlang_client_openssh_server_exec,
+ erlang_client_openssh_server_exec_compressed,
+ erlang_client_openssh_server_setenv,
+ erlang_client_openssh_server_publickey_rsa,
+ erlang_client_openssh_server_publickey_dsa,
+ erlang_client_openssh_server_password]},
+ {erlang_server, [], [erlang_server_openssh_client_exec,
+ erlang_server_openssh_client_exec_compressed,
+ erlang_server_openssh_client_pulic_key_dsa,
+ erlang_client_openssh_server_password]}
+ ].
+
+init_per_group(erlang_server, Config) ->
+ DataDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa(DataDir, UserDir),
+ Config;
+init_per_group(_, Config) ->
+ Dir = ?config(priv_dir, Config),
+ {ok, _} = ssh_test_lib:get_id_keys(Dir),
+ Config.
-end_per_group(_GroupName, Config) ->
- Config.
+end_per_group(erlang_server, Config) ->
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(UserDir),
+ Config;
+end_per_group(_, Config) ->
+ Dir = ?config(priv_dir, Config),
+ ssh_test_lib:remove_id_keys(Dir),
+ Config.
%% TEST cases starts here.
%%--------------------------------------------------------------------
@@ -131,8 +152,9 @@ erlang_shell_client_openssh_server(suite) ->
erlang_shell_client_openssh_server(Config) when is_list(Config) ->
process_flag(trap_exit, true),
+ UserDir = ?config(priv_dir, Config),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO),
+ Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO, UserDir),
IO ! {input, self(), "echo Hej\n"},
receive_hej(),
IO ! {input, self(), "exit\n"},
@@ -228,7 +250,7 @@ erlang_server_openssh_client_exec(suite) ->
[];
erlang_server_openssh_client_exec(Config) when is_list(Config) ->
- SystemDir = ?config(data_dir, Config),
+ SystemDir = ?config(priv_dir, Config),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{failfun, fun ssh_test_lib:failfun/2}]),
@@ -257,7 +279,7 @@ erlang_server_openssh_client_exec_compressed(suite) ->
[];
erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) ->
- SystemDir = ?config(data_dir, Config),
+ SystemDir = ?config(priv_dir, Config),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{compression, zlib},
{failfun, fun ssh_test_lib:failfun/2}]),
@@ -346,7 +368,9 @@ erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) ->
ok = ssh:close(ConnectionRef),
ok = file:delete(filename:join(UserDir, "id_rsa"));
{error, enoent} ->
- {skip, "no ~/.ssh/id_rsa"}
+ {skip, "no ~/.ssh/id_rsa"};
+ {error, Reason} ->
+ {skip, Reason}
end.
%%--------------------------------------------------------------------
@@ -372,7 +396,9 @@ erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) ->
ok = ssh:close(ConnectionRef),
ok = file:delete(filename:join(UserDir, "id_dsa"));
{error, enoent} ->
- {skip, "no ~/.ssh/id_dsa"}
+ {skip, "no ~/.ssh/id_dsa"};
+ {error, Reason} ->
+ {skip, Reason}
end.
%%--------------------------------------------------------------------
@@ -383,7 +409,7 @@ erlang_server_openssh_client_pulic_key_dsa(suite) ->
[];
erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) ->
- SystemDir = ?config(data_dir, Config),
+ SystemDir = ?config(priv_dir, Config),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{public_key_alg, ssh_dsa},
{failfun, fun ssh_test_lib:failfun/2}]),
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index 20fd247cea..1c69a131f9 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -452,8 +452,10 @@ conj([], _E) ->
conj([{{Name,_Rp},L,R,Sz} | AL], E) ->
NL = neg_line(L),
T1 = {op,NL,'orelse',
- {call,NL,{atom,NL,is_record},[R,{atom,NL,Name},{integer,NL,Sz}]},
- {atom,NL,fail}},
+ {call,NL,
+ {remote,NL,{atom,NL,erlang},{atom,NL,is_record}},
+ [R,{atom,NL,Name},{integer,NL,Sz}]},
+ {atom,NL,fail}},
T2 = case conj(AL, none) of
empty -> T1;
C -> {op,NL,'and',C,T1}
@@ -581,7 +583,9 @@ strict_get_record_field(Line, R, {atom,_,F}=Index, Name, St0) ->
ExpRp = erl_lint:modify_line(ExpR, fun(_L) -> 0 end),
RA = {{Name,ExpRp},Line,ExpR,length(Fs)+1},
St2 = St1#exprec{strict_ra = [RA | St1#exprec.strict_ra]},
- {{call,Line,{atom,Line,element},[I,ExpR]},St2}
+ {{call,Line,
+ {remote,Line,{atom,Line,erlang},{atom,Line,element}},
+ [I,ExpR]},St2}
end.
record_pattern(I, I, Var, Sz, Line, Acc) ->
@@ -593,7 +597,9 @@ record_pattern(_, _, _, _, _, Acc) -> reverse(Acc).
sloppy_get_record_field(Line, R, Index, Name, St) ->
Fs = record_fields(Name, St),
I = index_expr(Line, Index, Name, Fs),
- expr({call,Line,{atom,Line,element},[I,R]}, St).
+ expr({call,Line,
+ {remote,Line,{atom,Line,erlang},{atom,Line,element}},
+ [I,R]}, St).
strict_record_tests([strict_record_tests | _]) -> true;
strict_record_tests([no_strict_record_tests | _]) -> false;
@@ -710,7 +716,8 @@ record_setel(R, Name, Fs, Us0) ->
{'case',Lr,R,
[{clause,Lr,[{tuple,Lr,[{atom,Lr,Name} | Wildcards]}],[],
[foldr(fun ({I,Lf,Val}, Acc) ->
- {call,Lf,{atom,Lf,setelement},[I,Acc,Val]} end,
+ {call,Lf,{remote,Lf,{atom,Lf,erlang},
+ {atom,Lf,setelement}},[I,Acc,Val]} end,
R, Us)]},
{clause,NLr,[{var,NLr,'_'}],[],
[call_error(NLr, {tuple,NLr,[{atom,NLr,badrecord},{atom,NLr,Name}]})]}]}.
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index e5adb84932..cfbcf54d95 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -1804,12 +1804,19 @@ guard_test(G, Vt, St0) ->
%% Specially handle record type test here.
guard_test2({call,Line,{atom,Lr,record},[E,A]}, Vt, St0) ->
gexpr({call,Line,{atom,Lr,is_record},[E,A]}, Vt, St0);
-guard_test2({call,_Line,{atom,_La,F},As}=G, Vt, St0) ->
+guard_test2({call,Line,{atom,_La,F},As}=G, Vt, St0) ->
{Asvt,St1} = gexpr_list(As, Vt, St0), %Always check this.
A = length(As),
case erl_internal:type_test(F, A) of
- true when F =/= is_record -> {Asvt,St1};
- _ -> gexpr(G, Vt, St0)
+ true when F =/= is_record, A =/= 2 ->
+ case no_guard_bif_clash(St1, {F,A}) of
+ false ->
+ {Asvt,add_error(Line, {illegal_guard_local_call,{F,A}}, St1)};
+ true ->
+ {Asvt,St1}
+ end;
+ _ ->
+ gexpr(G, Vt, St0)
end;
guard_test2(G, Vt, St) ->
%% Everything else is a guard expression.
@@ -1865,9 +1872,15 @@ gexpr({call,Line,{atom,_Lr,is_record},[E,R]}, Vt, St0) ->
gexpr({call,Line,{remote,_Lr,{atom,_Lm,erlang},{atom,Lf,is_record}},[E,A]},
Vt, St0) ->
gexpr({call,Line,{atom,Lf,is_record},[E,A]}, Vt, St0);
-gexpr({call,_Line,{atom,_Lr,is_record},[E,{atom,_,_Name},{integer,_,_}]},
+gexpr({call,Line,{atom,_Lr,is_record},[E0,{atom,_,_Name},{integer,_,_}]},
Vt, St0) ->
- gexpr(E, Vt, St0);
+ {E,St1} = gexpr(E0, Vt, St0),
+ case no_guard_bif_clash(St0, {is_record,3}) of
+ true ->
+ {E,St1};
+ false ->
+ {E,add_error(Line, {illegal_guard_local_call,{is_record,3}}, St1)}
+ end;
gexpr({call,Line,{atom,_Lr,is_record},[_,_,_]=Asvt0}, Vt, St0) ->
{Asvt,St1} = gexpr_list(Asvt0, Vt, St0),
{Asvt,add_error(Line, illegal_guard_expr, St1)};
diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl
index ee4f0b3a51..08f1873803 100644
--- a/lib/stdlib/src/error_logger_file_h.erl
+++ b/lib/stdlib/src/error_logger_file_h.erl
@@ -104,7 +104,7 @@ code_change(_OldVsn, State, _Extra) ->
%%% ------------------------------------------------------
tag_event(Event) ->
- {erlang:localtime(), Event}.
+ {erlang:universaltime(), Event}.
write_events(Fd, Events) -> write_events1(Fd, lists:reverse(Events)).
@@ -169,23 +169,18 @@ write_event(_, _) ->
maybe_utc(Time) ->
UTC = case application:get_env(sasl, utc_log) of
- {ok, Val} ->
- Val;
+ {ok, Val} -> Val;
undefined ->
%% Backwards compatible:
case application:get_env(stdlib, utc_log) of
- {ok, Val} ->
- Val;
- undefined ->
- false
+ {ok, Val} -> Val;
+ undefined -> false
end
end,
- if
- UTC =:= true ->
- {utc, calendar:local_time_to_universal_time(Time)};
- true ->
- Time
- end.
+ maybe_utc(Time, UTC).
+
+maybe_utc(Time, true) -> {utc, Time};
+maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}.
format_report(Rep) when is_list(Rep) ->
case string_p(Rep) of
@@ -238,7 +233,7 @@ write_time(Time) -> write_time(Time, "ERROR REPORT").
write_time({utc,{{Y,Mo,D},{H,Mi,S}}}, Type) ->
io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
[Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
-write_time({{Y,Mo,D},{H,Mi,S}}, Type) ->
+write_time({local, {{Y,Mo,D},{H,Mi,S}}}, Type) ->
io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n",
[Type,D,month(Mo),Y,t(H),t(Mi),t(S)]).
diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl
index fa13fbb2bd..48e069a407 100644
--- a/lib/stdlib/src/error_logger_tty_h.erl
+++ b/lib/stdlib/src/error_logger_tty_h.erl
@@ -97,7 +97,7 @@ set_group_leader() ->
end.
tag_event(Event) ->
- {erlang:localtime(), Event}.
+ {erlang:universaltime(), Event}.
write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod).
@@ -162,23 +162,18 @@ write_event({_Time, _Error},_IOMod) ->
maybe_utc(Time) ->
UTC = case application:get_env(sasl, utc_log) of
- {ok, Val} ->
- Val;
+ {ok, Val} -> Val;
undefined ->
%% Backwards compatible:
case application:get_env(stdlib, utc_log) of
- {ok, Val} ->
- Val;
- undefined ->
- false
+ {ok, Val} -> Val;
+ undefined -> false
end
end,
- if
- UTC =:= true ->
- {utc, calendar:local_time_to_universal_time(Time)};
- true ->
- Time
- end.
+ maybe_utc(Time, UTC).
+
+maybe_utc(Time, true) -> {utc, Time};
+maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}.
format(IOMod, String) -> format(IOMod, String, []).
format(io_lib, String, Args) -> io_lib:format(String, Args);
@@ -234,7 +229,7 @@ write_time(Time) -> write_time(Time, "ERROR REPORT").
write_time({utc,{{Y,Mo,D},{H,Mi,S}}},Type) ->
io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
[Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
-write_time({{Y,Mo,D},{H,Mi,S}},Type) ->
+write_time({local, {{Y,Mo,D},{H,Mi,S}}},Type) ->
io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n",
[Type,D,month(Mo),Y,t(H),t(Mi),t(S)]).
diff --git a/lib/stdlib/test/erl_expand_records_SUITE.erl b/lib/stdlib/test/erl_expand_records_SUITE.erl
index f8c1ad783c..8b162cfda0 100644
--- a/lib/stdlib/test/erl_expand_records_SUITE.erl
+++ b/lib/stdlib/test/erl_expand_records_SUITE.erl
@@ -178,6 +178,9 @@ expr(Config) when is_list(Config) ->
true ->
not_ok
end.
+
+ is_record(_, _, _) ->
+ error(wrong_is_record).
">>
],
@@ -366,6 +369,8 @@ strict(Config) when is_list(Config) ->
end
catch error:_ -> ok
end.
+ element(_, _) ->
+ error(wrong_element).
">>
],
?line run(Config, Ts1, [strict_record_tests]),
@@ -380,6 +385,8 @@ strict(Config) when is_list(Config) ->
case foo of
_ when A#r2.a =:= 1 -> ok
end.
+ element(_, _) ->
+ error(wrong_element).
">>
],
?line run(Config, Ts2, [no_strict_record_tests]),
@@ -415,6 +422,11 @@ update(Config) when is_list(Config) ->
t2() ->
R0 = #r{},
#r{_ = R0#r{a = ok}}.
+
+ %% Implicit calls to setelement/3 must go to the BIF,
+ %% not to this function.
+ setelement(_, _, _) ->
+ erlang:error(wrong_setelement_called).
">>
],
?line run(Config, Ts),
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 9041adbe5c..4e93f056ad 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -2631,7 +2631,35 @@ bif_clash(Config) when is_list(Config) ->
binary_part(A,B,C).
">>,
[warn_unused_import],
- {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}}
+ {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}},
+ %% Don't accept call to a guard BIF if there is a local definition
+ %% or an import with the same name. Note: is_record/2 is an
+ %% exception, since it is more of syntatic sugar than a real BIF.
+ {clash21,
+ <<"-export([is_list/1]).
+ -import(x, [is_tuple/1]).
+ -record(r, {a,b}).
+ x(T) when is_tuple(T) -> ok;
+ x(T) when is_list(T) -> ok.
+ y(T) when is_tuple(T) =:= true -> ok;
+ y(T) when is_list(T) =:= true -> ok;
+ y(T) when is_record(T, r, 3) -> ok;
+ y(T) when is_record(T, r, 3) =:= true -> ok;
+ y(T) when is_record(T, r) =:= true -> ok.
+ is_list(_) ->
+ ok.
+ is_record(_, _) ->
+ ok.
+ is_record(_, _, _) ->
+ ok.
+ ">>,
+ [{no_auto_import,[{is_tuple,1}]}],
+ {errors,[{4,erl_lint,{illegal_guard_local_call,{is_tuple,1}}},
+ {5,erl_lint,{illegal_guard_local_call,{is_list,1}}},
+ {6,erl_lint,{illegal_guard_local_call,{is_tuple,1}}},
+ {7,erl_lint,{illegal_guard_local_call,{is_list,1}}},
+ {8,erl_lint,{illegal_guard_local_call,{is_record,3}}},
+ {9,erl_lint,{illegal_guard_local_call,{is_record,3}}}],[]}}
],
?line [] = run(Config, Ts),
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 0e8849b5b3..101828fdef 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -74,7 +74,7 @@
-export([bad_table/1, types/1]).
-export([otp_9423/1]).
--export([init_per_testcase/2]).
+-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
-export([random_test/0]).
@@ -2385,6 +2385,8 @@ setopts_do(Opts) ->
?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{protection,private,false})),
?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,protection)),
?line ets:delete(T),
+ unlink(Heir),
+ exit(Heir, bang),
ok.
bad_table(doc) -> ["All kinds of operations with bad table argument"];
@@ -5645,7 +5647,8 @@ spawn_logger(Procs) ->
true -> exit(Proc, kill);
_ -> ok
end,
- erlang:display(process_info(Proc)),
+ erlang:display({"Waiting for 'DOWN' from", Proc,
+ process_info(Proc), pid_status(Proc)}),
receive
{'DOWN', Mon, _, _, _} ->
ok
@@ -5656,6 +5659,15 @@ spawn_logger(Procs) ->
spawn_logger([From])
end.
+pid_status(Pid) ->
+ try
+ erts_debug:get_internal_state({process_status, Pid})
+ catch
+ error:undef ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ pid_status(Pid)
+ end.
+
start_spawn_logger() ->
case whereis(ets_test_spawn_logger) of
Pid when is_pid(Pid) -> true;
diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile
index 50369e633e..bac138e95a 100644
--- a/lib/syntax_tools/src/Makefile
+++ b/lib/syntax_tools/src/Makefile
@@ -26,7 +26,7 @@ EBIN = ../ebin
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
endif
-ERL_COMPILE_FLAGS += +warn_unused_vars +nowarn_shadow_vars +warn_unused_import +warn_missing_spec +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_unused_vars +nowarn_shadow_vars +warn_unused_import # +warn_missing_spec +warn_untyped_record
SOURCES=erl_syntax.erl erl_prettypr.erl erl_syntax_lib.erl \
erl_comment_scan.erl erl_recomment.erl erl_tidy.erl \
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 4e2235d552..32fd3722d6 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -3523,10 +3523,7 @@ qualified_name_segments(Node) ->
%% @see is_form/1
%% @see rule/2
--record(function, {
- name :: atom(),
- clauses :: list()
- }).
+-record(function, {name, clauses}).
%% XXX: This one is problematic because there is a tuple with the same
%% tag and size that comes from 'erl_parse'
%% -record(function, {name :: syntaxTree(), clauses :: [syntaxTree()]}).
@@ -6105,6 +6102,7 @@ implicit_fun_name(Node) ->
set_pos(integer(Arity), Pos)));
{'fun', _Pos, {function, Module, Atom, Arity}} ->
%% New in R15: fun M:F/A.
+ %% XXX: Perhaps set position for this as well?
module_qualifier(Module, arity_qualifier(Atom, Arity));
Node1 ->
data(Node1)
diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in
index 604332a91e..b8c4aed6e2 100644
--- a/lib/tools/c_src/Makefile.in
+++ b/lib/tools/c_src/Makefile.in
@@ -1,19 +1,20 @@
-# ``The contents of this file are subject to the Erlang Public License,
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2009-2012. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
-# retrieved via the world wide web at http://www.erlang.org/.
-#
+# retrieved online at http://www.erlang.org/.
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
+#
+# %CopyrightEnd%
#
include $(ERL_TOP)/make/target.mk
@@ -138,15 +139,17 @@ EMEM_LIBS = $(LIBS) \
EMEM_OBJS = $(addprefix $(EMEM_OBJ_DIR)/,$(notdir $(EMEM_SRCS:.c=.o)))
+ERTS_LIB = $(ERL_TOP/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE
+
#
# Misc targets
#
_create_dirs := $(shell mkdir -p $(CREATE_DIRS))
-all: erts_lib $(PROGS) $(DRIVERS)
+all: $(PROGS) $(DRIVERS)
-erts_lib:
+$(ERTS_LIB):
cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
@@ -174,7 +177,7 @@ $(EMEM_OBJ_DIR)/%.o: %.c
# Program targets
#
-$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS)
+$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS) $(ERTS_LIB)
$(PRE_LD) $(LD) $(EMEM_LDFLAGS) -o $@ $(EMEM_OBJS) $(EMEM_LIBS)
#
diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile
index c8eb6174c4..03e9f1e1bb 100644
--- a/lib/wx/doc/src/Makefile
+++ b/lib/wx/doc/src/Makefile
@@ -22,7 +22,7 @@
# ----------------------------------------------------
include ../../vsn.mk
include ../../config.mk
-APPLICATION=wxErlang
+APPLICATION=wx
ErlMods = wx.erl wx_object.erl