aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/src/misc/snmp_config.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/src/misc/snmp_config.erl')
-rw-r--r--lib/snmp/src/misc/snmp_config.erl565
1 files changed, 389 insertions, 176 deletions
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
index a222f842e5..17dfcd70b4 100644
--- a/lib/snmp/src/misc/snmp_config.erl
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -26,24 +26,29 @@
-compile({no_auto_import,[error/1]}).
-export([config/0]).
--export([write_config_file/4, append_config_file/4, read_config_file/3]).
+%%-export([write_config_file/4, append_config_file/4, read_config_file/4]).
+
+-export([write_config_file/6, append_config_file/6, read_config_file/4]).
-export([write_agent_snmp_files/7, write_agent_snmp_files/12,
+ write_agent_snmp_files/6, write_agent_snmp_files/11,
- write_agent_snmp_conf/5,
+ write_agent_snmp_conf/4, write_agent_snmp_conf/5,
write_agent_snmp_context_conf/1,
write_agent_snmp_community_conf/1,
write_agent_snmp_standard_conf/2,
- write_agent_snmp_target_addr_conf/4,
- write_agent_snmp_target_addr_conf/6,
+ write_agent_snmp_target_addr_conf/3,
+ write_agent_snmp_target_addr_conf/4,
+ write_agent_snmp_target_addr_conf/5,
+ write_agent_snmp_target_addr_conf/6,
write_agent_snmp_target_params_conf/2,
write_agent_snmp_notify_conf/2,
write_agent_snmp_usm_conf/5,
write_agent_snmp_vacm_conf/3,
write_manager_snmp_files/8,
- write_manager_snmp_conf/5,
- write_manager_snmp_users_conf/2,
+ write_manager_snmp_conf/4, write_manager_snmp_conf/5,
+ write_manager_snmp_users_conf/2,
write_manager_snmp_agents_conf/2,
write_manager_snmp_usm_conf/2
@@ -90,9 +95,9 @@
]).
--export_type([void/0,
- verify_config_entry_function/0,
- verify_config_function/0,
+-export_type([void/0,
+ order_config_entry_function/0,
+ check_config_entry_function/0,
write_config_function/0]).
@@ -567,11 +572,9 @@ config_agent_snmp(Dir, Vsns) ->
end,
NT
end,
- case (catch write_agent_snmp_files(Dir,
- Vsns, ManagerIP, TrapUdp,
- AgentIP, AgentUDP,
- SysName, NotifType, SecType,
- Passwd, EngineID, MMS)) of
+ case (catch write_agent_snmp_files(
+ Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP, SysName,
+ NotifType, SecType, Passwd, EngineID, MMS)) of
ok ->
i("~n- - - - - - - - - - - - -"),
i("Info: 1. SecurityName \"initial\" has noAuthNoPriv read access~n"
@@ -1580,35 +1583,63 @@ remove_newline(Str) ->
%% File generation
%%======================================================================
+write_agent_snmp_files(
+ Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName)
+ when is_list(Dir),
+ is_list(Vsns),
+ is_atom(Domain),
+ is_list(SysName) ->
+ write_agent_snmp_files(
+ Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName,
+ trap, none, "", "agentEngine", 484).
+
%%----------------------------------------------------------------------
%% Dir: string() (ex: "../conf/")
%% ManagerIP, AgentIP: [int(),int(),int(),int()]
%% TrapUdp, AgentUDP: integer()
%% SysName: string()
%%----------------------------------------------------------------------
-write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp,
- AgentIP, AgentUDP, SysName)
- when is_list(Dir) andalso
- is_list(Vsns) andalso
- is_list(ManagerIP) andalso
- is_integer(TrapUdp) andalso
- is_list(AgentIP) andalso
- is_integer(AgentUDP) andalso
+write_agent_snmp_files(
+ Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName)
+ when is_list(Dir) andalso
+ is_list(Vsns) andalso
+ is_list(ManagerIP) andalso
+ is_integer(TrapUDP) andalso
+ is_list(AgentIP) andalso
+ is_integer(AgentUDP) andalso
is_list(SysName) ->
- write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP,
- SysName, "trap", none, "", "agentEngine", 484).
+ write_agent_snmp_files(
+ Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName,
+ trap, none, "", "agentEngine", 484).
%%
%% ----- Agent config files generator functions -----
%%
-write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP,
- SysName, NotifType, SecType, Passwd, EngineID, MMS) ->
+write_agent_snmp_files(
+ Dir, Vsns, Domain, ManagerAddr, AgentAddr, SysName,
+ NotifType, SecType, Passwd, EngineID, MMS) ->
+ write_agent_snmp_conf(Dir, Domain, AgentAddr, EngineID, MMS),
+ write_agent_snmp_context_conf(Dir),
+ write_agent_snmp_community_conf(Dir),
+ write_agent_snmp_standard_conf(Dir, SysName),
+ write_agent_snmp_target_addr_conf(Dir, Domain, ManagerAddr, Vsns),
+ write_agent_snmp_target_params_conf(Dir, Vsns),
+ write_agent_snmp_notify_conf(Dir, NotifType),
+ write_agent_snmp_usm_conf(Dir, Vsns, EngineID, SecType, Passwd),
+ write_agent_snmp_vacm_conf(Dir, Vsns, SecType),
+ ok.
+
+write_agent_snmp_files(
+ Dir, Vsns, ManagerIP, TrapUDP, AgentIP, AgentUDP, SysName,
+ NotifType, SecType, Passwd, EngineID, MMS) ->
+ Domain = snmp_target_mib:default_domain(),
+ ManagerAddr = {ManagerIP, TrapUDP},
write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS),
write_agent_snmp_context_conf(Dir),
write_agent_snmp_community_conf(Dir),
write_agent_snmp_standard_conf(Dir, SysName),
- write_agent_snmp_target_addr_conf(Dir, ManagerIP, TrapUdp, Vsns),
+ write_agent_snmp_target_addr_conf(Dir, Domain, ManagerAddr, Vsns),
write_agent_snmp_target_params_conf(Dir, Vsns),
write_agent_snmp_notify_conf(Dir, NotifType),
write_agent_snmp_usm_conf(Dir, Vsns, EngineID, SecType, Passwd),
@@ -1616,11 +1647,40 @@ write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP,
ok.
+
%%
%% ------ [agent] agent.conf ------
%%
-write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS) ->
+write_agent_snmp_conf(Dir, Transports, EngineID, MMS) ->
+ Conf =
+ [{intAgentTransports, Transports},
+ {snmpEngineID, EngineID},
+ {snmpEngineMaxMessageSize, MMS}],
+ do_write_agent_snmp_conf(Dir, Conf).
+
+write_agent_snmp_conf(Dir, Domain, AgentAddr, EngineID, MMS)
+ when is_atom(Domain) ->
+ {AgentIP, AgentUDP} = AgentAddr,
+ Conf =
+ [{intAgentTransportDomain, Domain},
+ {intAgentUDPPort, AgentUDP},
+ {intAgentIpAddress, AgentIP},
+ {snmpEngineID, EngineID},
+ {snmpEngineMaxMessageSize, MMS}],
+ do_write_agent_snmp_conf(Dir, Conf);
+write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS)
+ when is_integer(AgentUDP) ->
+ Conf =
+ [{intAgentUDPPort, AgentUDP},
+ {intAgentIpAddress, AgentIP},
+ {snmpEngineID, EngineID},
+ {snmpEngineMaxMessageSize, MMS}],
+ do_write_agent_snmp_conf(Dir, Conf);
+write_agent_snmp_conf(_Dir, Domain, AgentAddr, _EngineID, _MMS) ->
+ error({bad_address, {Domain, AgentAddr}}).
+
+do_write_agent_snmp_conf(Dir, Conf) ->
Comment =
"%% This file defines the Agent local configuration info\n"
"%% The data is inserted into the snmpEngine* variables defined\n"
@@ -1635,11 +1695,7 @@ write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS) ->
"%% {snmpEngineID, \"agentEngine\"}.\n"
"%% {snmpEngineMaxMessageSize, 484}.\n"
"%%\n\n",
- Hdr = header() ++ Comment,
- Conf = [{intAgentUDPPort, AgentUDP},
- {intAgentIpAddress, AgentIP},
- {snmpEngineID, EngineID},
- {snmpEngineMaxMessageSize, MMS}],
+ Hdr = header() ++ Comment,
write_agent_config(Dir, Hdr, Conf).
write_agent_config(Dir, Hdr, Conf) ->
@@ -1745,17 +1801,19 @@ update_agent_standard_config(Dir, Conf) ->
%% ------ target_addr.conf ------
%%
-write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
- Timeout = 1500,
- RetryCount = 3,
- write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP,
- Timeout, RetryCount,
- Vsns).
+write_agent_snmp_target_addr_conf(Dir, Addresses, Vsns) ->
+ Timeout = 1500,
+ RetryCount = 3,
+ write_agent_snmp_target_addr_conf(
+ Dir, Addresses, Timeout, RetryCount, Vsns).
-write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP,
- Timeout, RetryCount,
- Vsns) ->
- Comment =
+write_agent_snmp_target_addr_conf(Dir, Domain_or_Ip, Addr_or_Port, Vsns) ->
+ Addresses = [{Domain_or_Ip, Addr_or_Port}],
+ write_agent_snmp_target_addr_conf(Dir, Addresses, Vsns).
+
+write_agent_snmp_target_addr_conf(
+ Dir, Addresses, Timeout, RetryCount, Vsns) ->
+ Comment =
"%% This file defines the target address parameters.\n"
"%% The data is inserted into the snmpTargetAddrTable defined\n"
"%% in SNMP-TARGET-MIB, and in the snmpTargetAddrExtTable defined\n"
@@ -1774,36 +1832,59 @@ write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP,
"%% [127,0,0,0], 2048}.\n"
"%%\n\n",
Hdr = header() ++ Comment,
- F = fun(v1 = Vsn, Acc) ->
- [{mk_ip(ManagerIp, Vsn),
- snmp_target_mib:default_domain(),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_trap", mk_param(Vsn), "", [], 2048}| Acc];
- (v2 = Vsn, Acc) ->
- [{mk_ip(ManagerIp, Vsn),
- snmp_target_mib:default_domain(),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_trap", mk_param(Vsn), "", [], 2048},
- {lists:flatten(io_lib:format("~s.2",[mk_ip(ManagerIp, Vsn)])),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_inform", mk_param(Vsn), "", [], 2048}| Acc];
- (v3 = Vsn, Acc) ->
- [{mk_ip(ManagerIp, Vsn),
- snmp_target_mib:default_domain(),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_trap", mk_param(Vsn), "", [], 2048},
- {lists:flatten(io_lib:format("~s.3",[mk_ip(ManagerIp, Vsn)])),
- ManagerIp, UDP, Timeout, RetryCount,
- "std_inform", mk_param(Vsn), "mgrEngine", [], 2048}| Acc]
- end,
- Conf = lists:foldl(F, [], Vsns),
+ Conf =
+ lists:foldl(
+ fun ({Domain_or_Ip, Addr_or_Port} = Address, OuterAcc) ->
+ lists:foldl(
+ fun(v1 = Vsn, Acc) ->
+ [{mk_name(Address, Vsn),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "",
+ [], 2048}| Acc];
+ (v2 = Vsn, Acc) ->
+ [{mk_name(Address, Vsn),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "",
+ [], 2048},
+ {lists:flatten(
+ io_lib:format(
+ "~s.2", [mk_name(Address, Vsn)])),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_inform", mk_param(Vsn), "",
+ [], 2048}| Acc];
+ (v3 = Vsn, Acc) ->
+ [{mk_name(Address, Vsn),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "",
+ [], 2048},
+ {lists:flatten(
+ io_lib:format(
+ "~s.3", [mk_name(Address, Vsn)])),
+ Domain_or_Ip, Addr_or_Port,
+ Timeout, RetryCount,
+ "std_inform", mk_param(Vsn), "mgrEngine",
+ [], 2048} | Acc]
+ end, OuterAcc, Vsns)
+ end, [], Addresses),
write_agent_target_addr_config(Dir, Hdr, Conf).
+write_agent_snmp_target_addr_conf(
+ Dir, Domain_or_Ip, Addr_or_Port, Timeout, RetryCount, Vsns) ->
+ Addresses = [{Domain_or_Ip, Addr_or_Port}],
+ write_agent_snmp_target_addr_conf(
+ Dir, Addresses, Timeout, RetryCount, Vsns).
+
mk_param(Vsn) ->
lists:flatten(io_lib:format("target_~w", [Vsn])).
-mk_ip([A,B,C,D], Vsn) ->
- lists:flatten(io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn])).
+mk_name(Address, Vsn) ->
+ lists:flatten(
+ io_lib:format(
+ "~s ~w", [snmp_conf:mk_addr_string(Address), Vsn])).
write_agent_target_addr_config(Dir, Hdr, Conf) ->
snmpa_conf:write_target_addr_config(Dir, Hdr, Conf).
@@ -2037,7 +2118,24 @@ write_manager_snmp_files(Dir, IP, Port, MMS, EngineID,
%% ------ manager.conf ------
%%
-write_manager_snmp_conf(Dir, IP, Port, MMS, EngineID) ->
+write_manager_snmp_conf(Dir, Transports, MMS, EngineID) ->
+ Comment =
+"%% This file defines the Manager local configuration info\n"
+"%% Each row is a 2-tuple:\n"
+"%% {Variable, Value}.\n"
+"%% For example\n"
+"%% {transports, [{transportDomainUdpIpv4, {{127,42,17,5}, 5000}}]}.\n"
+"%% {engine_id, \"managerEngine\"}.\n"
+"%% {max_message_size, 484}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf =
+ [{transports, Transports},
+ {engine_id, EngineID},
+ {max_message_size, MMS}],
+ write_manager_config(Dir, Hdr, Conf).
+
+write_manager_snmp_conf(Dir, Domain_or_IP, Addr_or_Port, MMS, EngineID) ->
Comment =
"%% This file defines the Manager local configuration info\n"
"%% Each row is a 2-tuple:\n"
@@ -2049,10 +2147,20 @@ write_manager_snmp_conf(Dir, IP, Port, MMS, EngineID) ->
"%% {max_message_size, 484}.\n"
"%%\n\n",
Hdr = header() ++ Comment,
- Conf = [{port, Port},
- {address, IP},
- {engine_id, EngineID},
- {max_message_size, MMS}],
+ Conf =
+ case Addr_or_Port of
+ {IP, Port} when is_integer(Port), is_atom(Domain_or_IP) ->
+ [{domain, Domain_or_IP},
+ {port, Port},
+ {address, IP}];
+ _ when is_integer(Addr_or_Port) ->
+ [{port, Addr_or_Port},
+ {address, Domain_or_IP}];
+ _ ->
+ error({bad_address, {Domain_or_IP, Addr_or_Port}})
+ end ++
+ [{engine_id, EngineID},
+ {max_message_size, MMS}],
write_manager_config(Dir, Hdr, Conf).
write_manager_config(Dir, Hdr, Conf) ->
@@ -2410,83 +2518,92 @@ header() ->
[?MODULE, ?version, Y, Mo, D, H, Mi, S]).
-%% *If* these functions are successfull, they successfully return anything
-%% (which is ignored), but they fail with either a throw or an exit or
-%% something similar.
-
-%% Verification of one config entry read from a file
--type(verify_config_entry_function() ::
- fun((Entry :: term()) -> ok | {error, Reason :: term()})).
-
-%% Verification of config to be written
--type(verify_config_function() ::
- fun(() -> void())).
-
-%% Write config to file (as defined by Fd)
--type(write_config_function() ::
- fun((Fd :: file:io_device()) -> void())).
-
--spec write_config_file(Dir :: string(),
- FileName :: string(),
- Verify :: verify_config_function(),
- Write :: write_config_function()) ->
- ok | {error, Reason :: term()}.
-
-write_config_file(Dir, FileName, Verify, Write)
- when (is_list(Dir) andalso
- is_list(FileName) andalso
- is_function(Verify) andalso
- is_function(Write)) ->
+%% *If* these functions are successfull, they successfully return
+%% (value is ignored), but they fail preferably with
+%% throw({error, Reason}). Other exceptions are also handled.
+
+%% Sorting order for config entries (see lists:sort/2)
+-type(order_config_entry_function() ::
+ fun((term(), term()) -> boolean())).
+
+%% Check of config entries. Initial State is 'undefined'
+-type(check_config_entry_function() ::
+ fun((Entry :: term(), State :: undefined | term()) ->
+ {ok | {ok, NewEntry :: term()}, NewState :: term()})).
+
+%% Write configuration entries to file descriptor Fd
+-type(write_config_function() ::
+ fun((Fd :: file:io_device(), [Entry :: term()]) -> ok)).
+
+-spec write_config_file(
+ Dir :: string(),
+ FileName :: string(),
+ Order :: order_config_entry_function(),
+ Check :: check_config_entry_function(),
+ Write :: write_config_function(),
+ Entries :: [term()]) ->
+ ok | {error, term()}.
+
+write_config_file(Dir, FileName, Order, Check, Write, Entries)
+ when is_list(Dir), is_list(FileName),
+ is_function(Order), is_function(Check), is_function(Write),
+ is_list(Entries) ->
try
- begin
- do_write_config_file(Dir, FileName, Verify, Write)
- end
+ SortedEntries = lists:sort(Order, Entries),
+ _ =
+ lists:foldl(
+ fun (Entry, State) ->
+ case Check(Entry, State) of
+ {Ok, NewState} when is_list(Ok) ->
+ NewState;
+ {ok, NewState} ->
+ NewState;
+ {{ok, _}, NewState} ->
+ NewState
+ end
+ end, undefined, SortedEntries),
+ ok
+ of
+ _ ->
+ case file:open(filename:join(Dir, FileName), [write]) of
+ {ok, Fd} ->
+ write_config_file(Dir, FileName, Write, Entries, Fd);
+ Error ->
+ Error
+ end
catch
- throw:Error ->
- Error;
- T:E ->
- {error, {failed_write, Dir, FileName, T, E}}
- end.
-
-
-do_write_config_file(Dir, FileName, Verify, Write) ->
- Verify(),
- case file:open(filename:join(Dir, FileName), [write]) of
- {ok, Fd} ->
- file_write_and_close(Write, Fd, Dir, FileName);
Error ->
- Error
- end.
-
-append_config_file(Dir, FileName, Verify, Write)
- when (is_list(Dir) andalso
- is_list(FileName) andalso
- is_function(Verify) andalso
- is_function(Write)) ->
- try
- begin
- do_append_config_file(Dir, FileName, Verify, Write)
- end
- catch
- throw:Error ->
+ S = erlang:get_stacktrace(),
+ d("File write of ~s throwed: ~p~n ~p~n",
+ [FileName, Error, S]),
Error;
- T:E ->
- {error, {failed_append, Dir, FileName, T, E}}
+ C:E ->
+ S = erlang:get_stacktrace(),
+ d("File write of ~s exception: ~p:~p~n ~p~n",
+ [FileName,C,E,S]),
+ {error, {failed_write, Dir, FileName, {C, E, S}}}
end.
-do_append_config_file(Dir, FileName, Verify, Write) ->
- Verify(),
- case file:open(filename:join(Dir, FileName), [read, write]) of
- {ok, Fd} ->
- file:position(Fd, eof),
- file_write_and_close(Write, Fd, Dir, FileName);
+write_config_file(Dir, FileName, Write, Entries, Fd) ->
+ try Write(Fd, Entries) of
+ ok ->
+ close_config_file(Dir, FileName, Fd)
+ catch
Error ->
- Error
+ S = erlang:get_stacktrace(),
+ d("File write of ~s throwed: ~p~n ~p~n",
+ [FileName, Error, S]),
+ close_config_file(Dir, FileName, Fd),
+ Error;
+ C:E ->
+ S = erlang:get_stacktrace(),
+ d("File write of ~s exception: ~p:~p~n ~p~n",
+ [FileName,C,E,S]),
+ close_config_file(Dir, FileName, Fd),
+ {error, {failed_write, Dir, FileName, {C, E, S}}}
end.
-
-file_write_and_close(Write, Fd, Dir, FileName) ->
- ok = Write(Fd),
+close_config_file(Dir, FileName, Fd) ->
case file:sync(Fd) of
ok ->
case file:close(Fd) of
@@ -2496,63 +2613,159 @@ file_write_and_close(Write, Fd, Dir, FileName) ->
{error, {failed_closing, Dir, FileName, Reason}}
end;
{error, Reason} ->
+ _ = file:close(Fd),
{error, {failed_syncing, Dir, FileName, Reason}}
end.
--spec read_config_file(Dir :: string(),
- FileName :: string(),
- Verify :: verify_config_entry_function()) ->
- {ok, Config :: list()} | {error, Reason :: term()}.
-read_config_file(Dir, FileName, Verify)
- when is_list(Dir) andalso is_list(FileName) andalso is_function(Verify) ->
- (catch do_read_config_file(Dir, FileName, Verify)).
+-spec append_config_file(
+ Dir :: string(),
+ FileName :: string(),
+ Order :: order_config_entry_function(),
+ Check :: check_config_entry_function(),
+ Write :: write_config_function(),
+ Entries :: [term()]) ->
+ ok | {error, term()}.
+
+append_config_file(Dir, FileName, Order, Check, Write, Entries)
+ when is_list(Dir), is_list(FileName),
+ is_function(Order), is_function(Check), is_function(Write),
+ is_list(Entries) ->
+ case file:open(filename:join(Dir, FileName), [read, write]) of
+ {ok, Fd} ->
+ append_config_file(
+ Dir, FileName, Order, Check, Write, Entries, Fd);
+ Error ->
+ Error
+ end.
+
+append_config_file(Dir, FileName, Order, Check, Write, Entries, Fd) ->
+ try
+ %% Verify the entries together with the file content
+ LinesInFileR = read_lines(Fd, [], 1),
+ StartLine =
+ case LinesInFileR of
+ [] ->
+ 1;
+ [{_, _, EndLine} | _] ->
+ EndLine
+ end,
+ LinesR = prepend_lines(LinesInFileR, Entries, StartLine),
+ SortedLines = sort_lines(lists:reverse(LinesR), Order),
+ _ = verify_lines(SortedLines, Check, undefined, []),
+ %% Append to the file
+ Write(Fd, Entries)
+ of
+ ok ->
+ close_config_file(Dir, FileName, Fd)
+ catch
+ Error ->
+ S = erlang:get_stacktrace(),
+ d("File append of ~s throwed: ~p~n ~p~n",
+ [FileName, Error, S]),
+ close_config_file(Dir, FileName, Fd),
+ Error;
+ C:E ->
+ S = erlang:get_stacktrace(),
+ d("File append of ~s exception: ~p:~p~n ~p~n",
+ [FileName,C,E,S]),
+ close_config_file(Dir, FileName, Fd),
+ {error, {failed_append, Dir, FileName, {C, E, S}}}
+ end.
+
+%% Fake line numbers, one per entry
+prepend_lines(Lines, [], _) ->
+ Lines;
+prepend_lines(Lines, [Entry | Entries], StartLine) ->
+ EndLine = StartLine + 1,
+ prepend_lines([{StartLine, Entry, EndLine} | Lines], Entries, EndLine).
+
+
-do_read_config_file(Dir, FileName, Verify) ->
+-spec read_config_file(
+ Dir :: string(),
+ FileName :: string(),
+ Order :: order_config_entry_function(),
+ Check :: check_config_entry_function()) ->
+ {ok, Config :: [Entry :: term()]} |
+ {error, Reason :: term()}.
+
+read_config_file(Dir, FileName, Order, Check)
+ when is_list(Dir), is_list(FileName),
+ is_function(Order), is_function(Check) ->
case file:open(filename:join(Dir, FileName), [read]) of
{ok, Fd} ->
- Result = read_loop(Fd, [], Verify, 1),
- file:close(Fd),
- Result;
+ try
+ Lines = lists:reverse(read_lines(Fd, [], 1)),
+ SortedLines = sort_lines(Lines, Order),
+ {ok, verify_lines(SortedLines, Check, undefined, [])}
+ catch
+ Error ->
+ S = erlang:get_stacktrace(),
+ d("File read of ~s throwed: ~p~n ~p~n",
+ [FileName, Error, S]),
+ {error, Error};
+ T:E ->
+ S = erlang:get_stacktrace(),
+ d("File read of ~s exception: ~p:~p~n ~p~n",
+ [FileName,T,E,S]),
+ {error, {failed_read, Dir, FileName, {T, E, S}}}
+ after
+ file:close(Fd)
+ end;
{error, Reason} ->
{error, {Reason, FileName}}
end.
-read_loop(Fd, Acc, Check, StartLine) ->
- case read_term(Fd, StartLine) of
+read_lines(Fd, Acc, StartLine) ->
+ case read_and_parse_term(Fd, StartLine) of
{ok, Term, EndLine} ->
- case (catch Check(Term)) of
- ok ->
- read_loop(Fd, [Term | Acc], Check, EndLine);
- {error, Reason} ->
- {error, {failed_check, StartLine, EndLine, Reason}};
- Error ->
- {error, {failed_check, StartLine, EndLine, Error}}
- end;
- {error, EndLine, Error} ->
- {error, {failed_reading, StartLine, EndLine, Error}};
- eof ->
- {ok, lists:reverse(Acc)}
+ read_lines(Fd, [{StartLine, Term, EndLine}|Acc], EndLine);
+ {error, Error, EndLine} ->
+ throw({failed_reading, StartLine, EndLine, Error});
+ {eof, _EndLine} ->
+ Acc
end.
-
-read_term(Fd, StartLine) ->
+
+read_and_parse_term(Fd, StartLine) ->
case io:request(Fd, {get_until, "", erl_scan, tokens, [StartLine]}) of
{ok, Tokens, EndLine} ->
case erl_parse:parse_term(Tokens) of
{ok, Term} ->
{ok, Term, EndLine};
{error, {Line, erl_parse, Error}} ->
- {error, Line, {parse_error, Error}}
+ {error, {parse_error, Error}, Line}
end;
- {error, E, EndLine} ->
- {error, EndLine, E};
- {eof, _EndLine} ->
- eof;
Other ->
Other
end.
+sort_lines(Lines, Order) ->
+ lists:sort(
+ fun ({_, T1, _}, {_, T2, _}) ->
+ Order(T1, T2)
+ end, Lines).
+
+verify_lines([], _, _, Acc) ->
+ lists:reverse(Acc);
+verify_lines(
+ [{StartLine, Term, EndLine}|Lines], Check, State, Acc) ->
+ try Check(Term, State) of
+ {Terms, NewState} when is_list(Terms) ->
+ verify_lines(Lines, Check, NewState, Terms ++ Acc);
+ {ok, NewState} ->
+ verify_lines(Lines, Check, NewState, [Term|Acc]);
+ {{ok, NewTerm}, NewState} ->
+ verify_lines(Lines, Check, NewState, [NewTerm|Acc])
+ catch
+ {error, Reason} ->
+ throw({failed_check, StartLine, EndLine, Reason});
+ C:R ->
+ S = erlang:get_stacktrace(),
+ throw({failed_check, StartLine, EndLine, {C, R, S}})
+ end.
+
agent_snmp_mk_secret(Alg, Passwd, EngineID) ->
snmp_usm:passwd2localized_key(Alg, Passwd, EngineID).
@@ -2575,8 +2788,8 @@ ensure_started(App) ->
%% -------------------------------------------------------------------------
-% d(F, A) ->
-% i("DBG: " ++ F, A).
+d(F, A) ->
+ i("DBG: " ++ F, A).
i(F) ->
i(F, []).