1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2005-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(snmp_agent_test_lib).
22
23
24-export([
25	 start_v1_agent/1,        start_v1_agent/2,
26	 start_v2_agent/1,        start_v2_agent/2,
27	 start_v3_agent/1,        start_v3_agent/2,
28	 start_bilingual_agent/1, start_bilingual_agent/2,
29	 start_mt_agent/1,        start_mt_agent/2,         start_mt_agent/3,
30	 stop_agent/1,
31
32	 %% start_sup/0,      stop_sup/2,
33	 start_subagent/3, stop_subagent/1,
34	 start_sub_sup/1,  start_sub_sup/2,
35
36	 start_node/1, stop_node/1,
37
38	 load_master/1, load_master_std/1, unload_master/1,
39	 loaded_mibs/0, unload_mibs/1,
40
41	 get_req/2, get_next_req/1,
42
43	 config/5, config/6,
44	 delete_files/1,
45	 copy_file/2,
46	 update_usm/2,
47	 update_usm_mgr/2, rewrite_usm_mgr/3, reset_usm_mgr/1,
48	 update_community/2,
49	 update_vacm/2,
50	 write_community_conf/2,
51	 write_target_addr_conf/2, write_target_addr_conf/4,
52	 rewrite_target_addr_conf/2, reset_target_addr_conf/1,
53	 write_target_params_conf/2, rewrite_target_params_conf/3,
54	 reset_target_params_conf/1,
55	 write_notify_conf/1, write_view_conf/1,
56
57	 display_memory_usage/0,
58
59	 init_all/1, finish_all/1,
60	 init_case/1,
61	 try_test/2, try_test/3, try_test/4,
62	 expect/3, expect/4, expect/5, expect/7,
63
64	 regs/0,
65	 rpc/3
66	]).
67
68%% Internal exports
69-export([tc_wait/5, tc_run/4]).
70
71-include_lib("kernel/include/file.hrl").
72-include_lib("common_test/include/ct.hrl").
73-include("snmp_test_lib.hrl").
74-define(SNMP_USE_V3, true).
75-include_lib("snmp/include/snmp_types.hrl").
76
77-define(TRAP_UDP, 5000).
78
79-define(v1_2(V1,V2),
80	case get(vsn) of
81	    v1 -> V1;
82	    _  -> V2
83	end).
84
85-define(v1_2_3(V1,V2,V3),
86	case get(vsn) of
87	    v1 -> V1;
88	    v2 -> V2;
89	    _  -> V3
90	end).
91
92
93%%%-----------------------------------------------------------------
94%%% The test case structure is as follows:
95%%%
96%%% init_all - starts mnesia,
97%%%
98%%%    init_v1 - starts agent
99%%%       simple
100%%%       big  - e.g. starts/stops subagent, load/unloads mibs
101%%%       init_mul
102%%%          mul_get
103%%%          mul_set
104%%%          <etc>
105%%%       finish_mul
106%%%       <etc>
107%%%    finish_v1
108%%%
109%%%    init_v2 - starts agent
110%%%    finish_v2
111%%%
112%%%    init_bilingual - starts agent
113%%%    finish_bilingual
114%%%
115%%% finish_all
116%%%
117%%% There is still one problem with these testsuites.  If one test
118%%% fails, it may not be possible to run some other cases, as it
119%%% may have e.g. created some row or loaded some table, that it
120%%% didn't undo (since it failed).
121%%%-----------------------------------------------------------------
122
123init_all(Config) when is_list(Config) ->
124
125    ?IPRINT("init_all -> entry with"
126            "~n   Config: ~p",[Config]),
127
128    %% --
129    %% Start nodes
130    %%
131
132    ?line {ok, SaNode}  = start_node(snmp_sa),
133    ?line {ok, MgrNode} = start_node(snmp_mgr),
134
135
136    %% --
137    %% Create necessary files ( and dirs )
138    %%
139
140    SuiteTopDir = ?config(snmp_suite_top_dir, Config),
141    ?DBG("init_all -> SuiteTopDir ~p", [SuiteTopDir]),
142
143    AgentDir = join(SuiteTopDir, "agent/"),
144    ?line ok = file:make_dir(AgentDir),
145    ?DBG("init_all -> AgentDir ~p", [AgentDir]),
146
147    AgentDbDir = join(AgentDir, "db/"),
148    ?line ok   = file:make_dir(AgentDbDir),
149    ?DBG("init_all -> AgentDbDir ~p", [AgentDbDir]),
150
151    AgentLogDir = join(AgentDir, "log/"),
152    ?line ok    = file:make_dir(AgentLogDir),
153    ?DBG("init_all -> AgentLogDir ~p", [AgentLogDir]),
154
155    AgentConfDir = join(AgentDir, "conf/"),
156    ?line ok     = file:make_dir(AgentConfDir),
157    ?DBG("init_all -> AgentConfDir ~p", [AgentConfDir]),
158
159    MgrDir   = join(SuiteTopDir, "mgr/"),
160    ?line ok = file:make_dir(MgrDir),
161    ?DBG("init_all -> MgrDir ~p", [MgrDir]),
162
163    SaDir    = join(SuiteTopDir, "sa/"),
164    ?line ok = file:make_dir(SaDir),
165    ?DBG("init_all -> SaDir ~p", [SaDir]),
166
167    SaDbDir  = join(SaDir, "db/"),
168    ?line ok = file:make_dir(SaDbDir),
169    ?DBG("init_all -> SaDbDir ~p", [SaDbDir]),
170
171    %% MibDir = ?config(mib_dir, Config),
172    %% ?DBG("init_all -> MibDir ~p", [DataDir]),
173
174
175    %% --
176    %% Start and initiate mnesia
177    %%
178
179    ?DBG("init_all -> load application mnesia", []),
180    ?line ok = application:load(mnesia),
181
182    ?DBG("init_all -> load application mnesia on node ~p", [SaNode]),
183    ?line ok = rpc:call(SaNode, application, load, [mnesia]),
184
185    ?DBG("init_all -> application mnesia: set_env dir",[]),
186    ?line application_controller:set_env(mnesia, dir,
187					 join(AgentDbDir, "Mnesia1")),
188
189    ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]),
190    ?line rpc:call(SaNode, application_controller, set_env,
191		   [mnesia, dir,  join(SaDir, "Mnesia2")]),
192
193    ?DBG("init_all -> create mnesia schema",[]),
194    ?line ok = mnesia:create_schema([SaNode, node()]),
195
196    ?DBG("init_all -> start application mnesia",[]),
197    ?line ok = application:start(mnesia),
198
199    ?DBG("init_all -> start application mnesia on ~p",[SaNode]),
200    ?line ok = rpc:call(SaNode, application, start, [mnesia]),
201    Ip = ?LOCALHOST(),
202    [{snmp_sa,        SaNode},
203     {snmp_mgr,       MgrNode},
204     {snmp_master,    node()},
205     {agent_dir,      AgentDir ++ "/"},
206     {agent_db_dir,   AgentDbDir ++ "/"},
207     {agent_log_dir,  AgentLogDir ++ "/"},
208     {agent_conf_dir, AgentConfDir ++ "/"},
209     {sa_dir,         SaDir ++ "/"},
210     {sa_db_dir,      SaDbDir ++ "/"},
211     {mgr_dir,        MgrDir ++ "/"},
212     %% {mib_dir,        DataDir},
213     {ip,             Ip} |
214     Config].
215
216
217finish_all(Config) when is_list(Config) ->
218    SaNode = ?config(snmp_sa, Config),
219    MgrNode = ?config(snmp_mgr, Config),
220    stop_node(SaNode),
221    stop_node(MgrNode),
222    application:stop(mnesia).
223
224
225%% --- This one *must* be run first in each case ---
226
227init_case(Config) when is_list(Config) ->
228
229    ?DBG("init_case -> entry with"
230	 "~n   Config: ~p", [Config]),
231
232    SaNode     = ?config(snmp_sa,     Config),
233    MgrNode    = ?config(snmp_mgr,    Config),
234    MasterNode = ?config(snmp_master, Config),
235    %% MasterNode = node(),
236    IpFamily  = proplists:get_value(ipfamily, Config, inet),
237
238    SaHost         = ?HOSTNAME(SaNode),
239    MgrHost        = ?HOSTNAME(MgrNode),
240    MasterHost     = ?HOSTNAME(MasterNode),
241    {ok, MasterIP} = snmp_misc:ip(MasterHost, IpFamily),
242    {ok, MIP}      = snmp_misc:ip(MgrHost, IpFamily),
243    {ok, SIP}      = snmp_misc:ip(SaHost, IpFamily),
244
245
246    put(mgr_node,    MgrNode),
247    put(sa_node,     SaNode),
248    put(master_node, MasterNode),
249    put(sa_host,     SaHost),
250    put(mgr_host,    MgrHost),
251    put(master_host, MasterHost),
252    put(mip,         tuple_to_list(MIP)),
253    put(masterip,    tuple_to_list(MasterIP)),
254    put(sip,         tuple_to_list(SIP)),
255    put(ipfamily,    IpFamily),
256
257    MibDir = ?config(mib_dir, Config),
258    put(mib_dir, MibDir),
259    StdM = join(code:priv_dir(snmp), "mibs") ++ "/",
260    put(std_mib_dir, StdM),
261
262    MgrDir = ?config(mgr_dir, Config),
263    put(mgr_dir, MgrDir),
264
265    put(vsn, ?config(vsn, Config)),
266    ?DBG("init_case -> exit with"
267	"~n   MasterNode: ~p"
268	"~n   SaNode:     ~p"
269	"~n   MgrNode:    ~p"
270	"~n   MibDir:     ~p", [MasterNode, SaNode, MgrNode, MibDir]),
271    {SaNode, MgrNode, MibDir}.
272
273
274%%%--------------------------------------------------
275%%% Used to test the standard mib with our
276%%% configuration.
277%%%--------------------------------------------------
278
279try_test(TcRunMod, TcRunFunc) ->
280    try_test(TcRunMod, TcRunFunc, []).
281
282try_test(TcRunMod, TcRunFunc, TcRunArgs) ->
283    try_test(TcRunMod, TcRunFunc, TcRunArgs, []).
284
285try_test(TcRunMod, TcRunFunc, TcRunArgs, TcRunOpts) ->
286    Node      = get(mgr_node),
287    Mod       = ?MODULE,
288    Func      = tc_run,
289    Args      = [TcRunMod, TcRunFunc, TcRunArgs, TcRunOpts],
290    tc_try(Node, Mod, Func, Args).
291
292%% We spawn a test case runner process on the manager node.
293%% The assumption is that the manager shall do something, but
294%% not all test cases have the manager perform actions.
295%% In some cases we make a rpc call back to the agent node directly
296%% and call something in the agent... (for example the info_test
297%% test case).
298%% We should use link (instead of monitor) in order for the test case
299%% timeout cleanup (kills) should have effect on the test case runner
300%% process as well.
301
302tc_try(N, M, F, A) ->
303    ?IPRINT("tc_try -> entry with"
304            "~n      N:     ~p"
305            "~n      M:     ~p"
306            "~n      F:     ~p"
307            "~n      A:     ~p"
308            "~n   when"
309            "~n      get(): ~p"
310            "~n", [N,
311                   M, F, A,
312                   get()]),
313    case net_adm:ping(N) of
314        pong ->
315            ?IPRINT("tc_try -> ~p still running - start runner~n", [N]),
316            OldFlag = trap_exit(true), % Make sure we catch it
317            Runner  = spawn_link(N, ?MODULE, tc_wait, [self(), get(), M, F, A]),
318            await_tc_runner_started(Runner, OldFlag),
319            await_tc_runner_done(Runner, OldFlag);
320        pang ->
321            ?WPRINT("tc_try -> ~p *not* running~n", [N]),
322            skip({node_not_running, N})
323    end.
324
325await_tc_runner_started(Runner, OldFlag) ->
326    ?IPRINT("await tc-runner (~p) start ack~n", [Runner]),
327    receive
328        {'EXIT', Runner, Reason} ->
329            ?EPRINT("TC runner start failed: "
330                    "~n   ~p~n", [Reason]),
331            exit({tx_runner_start_failed, Reason});
332        {tc_runner_started, Runner} ->
333            ?IPRINT("TC runner start acknowledged~n"),
334            ok
335    after 10000 -> %% We should *really* not have to wait this long, but...
336            trap_exit(OldFlag),
337            unlink_and_flush_exit(Runner),
338            RunnerInfo = ?PINFO(Runner),
339            ?EPRINT("TC runner start timeout: "
340                    "~n   ~p", [RunnerInfo]),
341            %% If we don't get a start ack within 10 seconds, we are f*ed
342            exit(Runner, kill),
343            exit({tc_runner_start, timeout, RunnerInfo})
344    end.
345
346await_tc_runner_done(Runner, OldFlag) ->
347    receive
348        {'EXIT', Runner, Reason} ->
349            %% This is not a normal (tc) failure (that is the clause below).
350            %% Instead the tc runner process crashed, for some reason. So
351            %% check if have got any system events, and if so, skip.
352            SysEvs = snmp_test_global_sys_monitor:events(),
353            if
354                (SysEvs =:= []) ->
355                    ?EPRINT("TC runner failed: "
356                            "~n   ~p~n", [Reason]),
357                    exit({tx_runner_failed, Reason});
358                true ->
359                    ?WPRINT("TC runner failed when we got system events: "
360                            "~n   Reason:     ~p"
361                            "~n   Sys Events: ~p"
362                            "~n", [Reason, SysEvs]),
363                    skip([{reason, Reason}, {system_events, SysEvs}])
364            end;
365	{tc_runner_done, Runner, {'EXIT', {skip, Reason}}, Loc} ->
366	    ?WPRINT("call -> done with skip: "
367                    "~n   Reason: ~p"
368                    "~n   Loc:    ~p"
369                    "~n", [Reason, Loc]),
370            trap_exit(OldFlag),
371            unlink_and_flush_exit(Runner),
372	    put(test_server_loc, Loc),
373	    skip(Reason);
374	{tc_runner_done, Runner, {'EXIT', Rn}, Loc} ->
375	    ?EPRINT("call -> done with exit: "
376                    "~n   Rn:  ~p"
377                    "~n   Loc: ~p"
378                    "~n", [Rn, Loc]),
379            trap_exit(OldFlag),
380            unlink_and_flush_exit(Runner),
381	    put(test_server_loc, Loc),
382	    exit(Rn);
383	{tc_runner_done, Runner, Ret, _Zed} ->
384	    ?DBG("call -> done:"
385		 "~n   Ret: ~p"
386		 "~n   Zed: ~p", [Ret, _Zed]),
387            trap_exit(OldFlag),
388            unlink_and_flush_exit(Runner),
389	    case Ret of
390		{error, Reason} ->
391		    exit(Reason);
392		{skip, Reason} ->
393		    skip(Reason);
394		OK ->
395		    OK
396	    end
397    end.
398
399trap_exit(Flag) when is_boolean(Flag) ->
400    erlang:process_flag(trap_exit, Flag).
401
402unlink_and_flush_exit(Pid) ->
403    unlink(Pid),
404    receive
405        {'EXIT', Pid, _} ->
406            ok
407    after 0 ->
408            ok
409    end.
410
411tc_wait(From, Env, M, F, A) ->
412    ?IPRINT("tc_wait -> entry with"
413            "~n   From: ~p"
414            "~n   Env:  ~p"
415            "~n   M:    ~p"
416            "~n   F:    ~p"
417            "~n   A:    ~p", [From, Env, M, F, A]),
418    From ! {tc_runner_started, self()},
419    lists:foreach(fun({K,V}) -> put(K,V) end, Env),
420    ?IPRINT("tc_wait -> env set - now run tc~n"),
421    Res = (catch apply(M, F, A)),
422    ?IPRINT("tc_wait -> tc run done: "
423            "~n   ~p"
424            "~n", [Res]),
425    From ! {tc_runner_done, self(), Res, get(test_server_loc)},
426    %% The point of this is that in some cases we have seen that the
427    %% exit signal having been "passed on" to the CT, which consider any
428    %% exit a fail (even if its {'EXIT', ok}).
429    %% So, just to be on the safe side, convert an 'ok' to a 'normal'.
430    case Res of
431        ok ->
432            exit(normal);
433        {ok, _} ->
434            exit(normal);
435        _ ->
436            exit(Res)
437    end.
438
439tc_run(Mod, Func, Args, Opts) ->
440    ?IPRINT("tc_run -> entry with"
441            "~n   Mod:  ~p"
442            "~n   Func: ~p"
443            "~n   Args: ~p"
444            "~n   Opts: ~p"
445            "~n", [Mod, Func, Args, Opts]),
446    (catch snmp_test_mgr:stop()), % If we had a running mgr from a failed case
447    M           = get(mib_dir),
448    Dir         = get(mgr_dir),
449    User        = snmp_misc:get_option(user, Opts, "all-rights"),
450    SecLevel    = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
451    EngineID    = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
452    CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
453    Community   = snmp_misc:get_option(community, Opts, "all-rights"),
454    ?DBG("tc_run -> start crypto app",[]),
455    _CryptoRes  = ?CRYPTO_START(),
456    ?DBG("tc_run -> Crypto: ~p", [_CryptoRes]),
457    StdM        = join(code:priv_dir(snmp), "mibs") ++ "/",
458    Vsn         = get(vsn),
459    ?IPRINT("tc_run -> config:"
460            "~n   M:           ~p"
461            "~n   Vsn:         ~p"
462            "~n   Dir:         ~p"
463            "~n   User:        ~p"
464            "~n   SecLevel:    ~p"
465            "~n   EngineID:    ~p"
466            "~n   CtxEngineID: ~p"
467            "~n   Community:   ~p"
468            "~n   StdM:        ~p"
469            "~n", [M,Vsn,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
470    case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
471			      {packet_server_debug, true},
472			      {debug,               false},
473			      {agent,               get(master_host)},
474			      {ipfamily,            get(ipfamily)},
475			      {agent_udp,           4000},
476			      {trap_udp,            5000},
477			      {recbuf,              65535},
478			      quiet,
479			      Vsn,
480			      {community,           Community},
481			      {user,                User},
482			      {sec_level,           SecLevel},
483			      {engine_id,           EngineID},
484			      {context_engine_id,   CtxEngineID},
485			      {dir,                 Dir},
486			      {mibs,                mibs(StdM, M)}]) of
487	{ok, _Pid} ->
488	    case (catch apply(Mod, Func, Args)) of
489		{'EXIT', {skip, Reason}} ->
490                    ?WPRINT("apply skip detected: "
491                             "~n   ~p", [Reason]),
492		    (catch snmp_test_mgr:stop()),
493		    ?SKIP(Reason);
494		{'EXIT', Reason} ->
495                    %% We have hosts (mostly *very* slooow VMs) that
496                    %% can timeout anything. Since we are basically
497                    %% testing communication, we therefor must check
498                    %% for system events at every failure. Grrr!
499                    SysEvs = snmp_test_global_sys_monitor:events(),
500		    (catch snmp_test_mgr:stop()),
501                    if
502                        (SysEvs =:= []) ->
503                            ?EPRINT("TC runner failed: "
504                                    "~n   ~p~n", [Reason]),
505                            ?FAIL({apply_failed, {Mod, Func, Args}, Reason});
506                        true ->
507                            ?WPRINT("apply exit catched when we got system events: "
508                                     "~n   Reason:     ~p"
509                                     "~n   Sys Events: ~p"
510                                     "~n", [Reason, SysEvs]),
511                            ?SKIP([{reason, Reason}, {system_events, SysEvs}])
512                    end;
513		Res ->
514		    (catch snmp_test_mgr:stop()),
515		    Res
516	    end;
517
518	{error, Reason} ->
519	    ?EPRINT("Failed starting (test) manager: "
520                    "~n   ~p", [Reason]),
521	    (catch snmp_test_mgr:stop()),
522	    ?line ?FAIL({mgr_start_error, Reason});
523
524	Err ->
525	    ?EPRINT("Failed starting (test) manager: "
526                    "~n   ~p", [Err]),
527	    (catch snmp_test_mgr:stop()),
528	    ?line ?FAIL({mgr_start_failure, Err})
529    end.
530
531
532%% ---------------------------------------------------------------
533%% ---                                                         ---
534%% ---                   Start the agent                       ---
535%% ---                                                         ---
536%% ---------------------------------------------------------------
537
538start_v1_agent(Config) when is_list(Config) ->
539    start_agent(Config, [v1]).
540
541start_v1_agent(Config, Opts) when is_list(Config) andalso is_list(Opts)  ->
542    start_agent(Config, [v1], Opts).
543
544start_v2_agent(Config) when is_list(Config) ->
545    start_agent(Config, [v2]).
546
547start_v2_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
548    start_agent(Config, [v2], Opts).
549
550start_v3_agent(Config) when is_list(Config) ->
551    start_agent(Config, [v3]).
552
553start_v3_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
554    start_agent(Config, [v3], Opts).
555
556start_bilingual_agent(Config) when is_list(Config) ->
557    start_agent(Config, [v1,v2]).
558
559start_bilingual_agent(Config, Opts)
560  when is_list(Config) andalso is_list(Opts) ->
561    start_agent(Config, [v1,v2], Opts).
562
563start_mt_agent(Config) ->
564    start_mt_agent(Config, true, []).
565
566start_mt_agent(Config, MT) ->
567    start_mt_agent(Config, MT, []).
568
569start_mt_agent(Config, MT, Opts)
570  when is_list(Config) andalso
571       ((MT =:= true) orelse (MT =:= extended)) andalso
572       is_list(Opts) ->
573    start_agent(Config, [v2], [{multi_threaded, MT} | Opts]).
574
575start_agent(Config, Vsns) ->
576    start_agent(Config, Vsns, []).
577start_agent(Config, Vsns, Opts) ->
578
579    ?IPRINT("start_agent -> entry (~p) with"
580            "~n   Config: ~p"
581            "~n   Vsns:   ~p"
582            "~n   Opts:   ~p", [node(), Config, Vsns, Opts]),
583
584    ?line AgentLogDir  = ?config(agent_log_dir,  Config),
585    ?line AgentConfDir = ?config(agent_conf_dir, Config),
586    ?line AgentDbDir   = ?config(agent_db_dir,   Config),
587    ?line SaNode       = ?config(snmp_sa,        Config),
588
589    Env = app_agent_env_init(
590	    [{versions,         Vsns},
591	     {agent_type,       master},
592	     {agent_verbosity,  trace},
593             {get_mechanism,    snmp_agent_test_get},
594	     {db_dir,           AgentDbDir},
595	     {audit_trail_log,  [{type, read_write},
596				 {dir,  AgentLogDir},
597				 {size, {10240, 10}}]},
598	     {config,           [{dir, AgentConfDir},
599				 {force_load, false},
600				 {verbosity,  trace}]},
601	     {local_db,         [{repair,    true},
602				 {verbosity, log}]},
603	     {mib_server,       [{verbosity, log}]},
604	     {symbolic_store,   [{verbosity, log}]},
605	     {note_store,       [{verbosity, log}]},
606	     {net_if,           [{verbosity, trace}]}],
607	    Opts),
608
609
610    process_flag(trap_exit,true),
611
612    ?IPRINT("start_agent -> try start snmp app supervisor", []),
613    {ok, AppSup} = snmp_app_sup:start_link(),
614    unlink(AppSup),
615    ?DBG("start_agent -> snmp app supervisor: ~p", [AppSup]),
616
617    ?IPRINT("start_agent -> try start master agent",[]),
618    ?line Sup = start_sup(Env),
619    ?line unlink(Sup),
620    ?DBG("start_agent -> snmp supervisor: ~p", [Sup]),
621
622    ?IPRINT("start_agent -> try (rpc) start sub agent on ~p", [SaNode]),
623    ?line SaDir = ?config(sa_dir, Config),
624    ?line {ok, Sub} = start_sub_sup(SaNode, SaDir),
625    ?DBG("start_agent -> done", []),
626
627    ?line [{snmp_app_sup, AppSup},
628           {snmp_sup,     {Sup, self()}},
629           {snmp_sub,     Sub} | Config].
630
631
632app_agent_env_init(Env0, Opts) ->
633    ?DBG("app_agent_env_init -> unload snmp",[]),
634    ?line application:unload(snmp),
635
636    ?DBG("app_agent_env_init -> load snmp",[]),
637    ?line application:load(snmp),
638
639    ?DBG("app_agent_env_init -> "
640	 "merge or maybe replace (snmp agent) app env",[]),
641    Env = add_or_maybe_merge_agent_env(Opts, Env0),
642    ?DBG("app_agent_env_init -> merged env: "
643	 "~n   ~p", [Env]),
644
645    %% We put it into the app environment just as
646    %% a precaution, since when starting normally,
647    %% this is where the environment is extracted from.
648    app_agent_set_env(Env),
649    Env.
650
651app_agent_set_env(Value) ->
652    application_controller:set_env(snmp, agent, Value).
653
654add_or_maybe_merge_agent_env([], Env) ->
655    ?DBG("merging agent env -> merged", []),
656    lists:keysort(1, Env);
657add_or_maybe_merge_agent_env([{Key, Value1}|Opts], Env) ->
658    ?DBG("merging agent env -> add, replace or merge ~p", [Key]),
659    case lists:keysearch(Key, 1, Env) of
660	{value, {Key, Value1}} ->
661	    %% Identical, move on
662	    ?DBG("merging agent env -> "
663		 "no need to merge ~p - identical - keep: "
664		 "~n   ~p", [Key, Value1]),
665	    add_or_maybe_merge_agent_env(Opts, Env);
666	{value, {Key, Value2}} ->
667	    %% Another value, merge or replace
668	    NewValue = merge_or_replace_agent_env(Key, Value1, Value2),
669	    Env2 = lists:keyreplace(Key, 1, Env, {Key, NewValue}),
670	    add_or_maybe_merge_agent_env(Opts, Env2);
671	false ->
672	    ?DBG("merging agent env -> no old ~p to merge with - add: "
673		 "~n   ~p", [Key, Value1]),
674	    add_or_maybe_merge_agent_env(Opts, [{Key, Value1}|Env])
675    end.
676
677merge_or_replace_agent_env(versions, NewVersions, _OldVersions) ->
678    ?DBG("merging agent env -> versions replaced: ~p -> ~p",
679	 [NewVersions, _OldVersions]),
680    NewVersions;
681merge_or_replace_agent_env(agent_type, NewType, _OldType) ->
682    ?DBG("merging agent env -> agent type replaced: ~p -> ~p",
683	 [NewType, _OldType]),
684    NewType;
685merge_or_replace_agent_env(agent_verbosity, NewVerbosity, _OldVerbosity) ->
686    ?DBG("merging agent env -> agent verbosity replaced: ~p -> ~p",
687	 [NewVerbosity, _OldVerbosity]),
688    NewVerbosity;
689merge_or_replace_agent_env(db_dir, NewDbDir, _OldDbDir) ->
690    ?DBG("merging agent env -> db-dir replaced: ~p -> ~p",
691	 [NewDbDir, _OldDbDir]),
692    NewDbDir;
693merge_or_replace_agent_env(audit_trail_log, NewATL, OldATL) ->
694    merge_or_replace_agent_env_atl(NewATL, OldATL);
695merge_or_replace_agent_env(config, NewConfig, OldConfig) ->
696    merge_or_replace_agent_env_config(NewConfig, OldConfig);
697merge_or_replace_agent_env(local_db, NewLdb, OldLdb) ->
698    merge_or_replace_agent_env_ldb(NewLdb, OldLdb);
699merge_or_replace_agent_env(mib_storage, NewMst, OldMst) ->
700    merge_or_replace_agent_env_mib_storage(NewMst, OldMst);
701merge_or_replace_agent_env(mib_server, NewMibs, OldMibs) ->
702    merge_or_replace_agent_env_mib_server(NewMibs, OldMibs);
703merge_or_replace_agent_env(symbolic_store, NewSymStore, OldSymStore) ->
704    merge_or_replace_agent_env_symbolic_store(NewSymStore, OldSymStore);
705merge_or_replace_agent_env(note_store, NewNoteStore, OldNoteStore) ->
706    merge_or_replace_agent_env_note_store(NewNoteStore, OldNoteStore);
707merge_or_replace_agent_env(net_if, NewNetIf, OldNetIf) ->
708    merge_or_replace_agent_env_net_if(NewNetIf, OldNetIf);
709merge_or_replace_agent_env(Key, NewValue, OldValue) ->
710    ?FAIL({not_implemented_merge_or_replace,
711	   Key, NewValue, OldValue}).
712
713merge_or_replace_agent_env_atl(New, Old) ->
714    ATL = merge_agent_options(New, Old),
715    ?DBG("merging agent env -> audit-trail-log merged: "
716	 "~n   ~p | ~p -> ~p", [New, Old, ATL]),
717    ATL.
718
719merge_or_replace_agent_env_config(New, Old) ->
720    Config = merge_agent_options(New, Old),
721    case lists:keymember(dir, 1, Config) of
722	true ->
723	    ?DBG("merging agent env -> config merged: "
724		 "~n   ~p | ~p -> ~p", [New, Old, Config]),
725	    Config;
726	false ->
727	    ?FAIL({missing_mandatory_option, {config, dir}})
728    end.
729
730merge_or_replace_agent_env_ldb(New, Old) ->
731    LDB = merge_agent_options(New, Old),
732    ?DBG("merging agent env -> local-db merged: "
733	 "~n   ~p | ~p -> ~p", [New, Old, LDB]),
734    LDB.
735
736merge_or_replace_agent_env_mib_storage(NewMibStorage, OldMibStorage) ->
737    %% Shall we merge or replace?
738    %% module is mandatory. We will only merge if NewModule is
739    %% equal to OldModule.
740    NewModule =
741	case lists:keysearch(module, 1, NewMibStorage) of
742	    {value, {module, M}} ->
743		M;
744	    false ->
745		?FAIL({missing_mandatory_option, {mib_storage, module}})
746	end,
747    case lists:keysearch(module, 1, OldMibStorage) of
748	{value, {module, NewModule}} ->
749	    %% Same module => merge
750	    %% Non-ex new options => remove
751	    %% Ex new options and non-ex old options => replace
752	    %% Otherwise merge
753	    case lists:keysearch(options, 1, NewMibStorage) of
754		false ->
755		    ?DBG("merging agent env -> "
756			 "no mib-storage ~p merge needed - "
757			 "no new options (= remove old options)", [NewModule]),
758		    NewMibStorage;
759		{value, {options, NewOptions}} ->
760		    case lists:keysearch(options, 1, OldMibStorage) of
761			false ->
762			    ?DBG("merging agent env -> "
763				 "no mib-storage ~p merge needed - "
764				 "no old options", [NewModule]),
765			    NewMibStorage;
766			{value, {options, OldOptions}} ->
767			    MergedOptions =
768				merge_agent_options(NewOptions, OldOptions),
769			    ?DBG("merging agent env -> mib-storage ~p merged: "
770				 "~n   Options: ~p | ~p -> ~p",
771				 [NewModule,
772				  NewOptions, OldOptions, MergedOptions]),
773			    [{module,  NewModule},
774			     {options, MergedOptions}]
775		    end
776	    end;
777	_ ->
778	    %% Diff module => replace
779	    ?DBG("merging agent env -> "
780		 "no mib-storage ~p merge needed - "
781		 "new module", [NewModule]),
782	    NewMibStorage
783    end.
784
785merge_or_replace_agent_env_mib_server(New, Old) ->
786    MibServer = merge_agent_options(New, Old),
787    ?DBG("merging agent env -> mib-server merged: "
788	 "~n   ~p | ~p -> ~p", [New, Old, MibServer]),
789    MibServer.
790
791merge_or_replace_agent_env_symbolic_store(New, Old) ->
792    SymbolicStore = merge_agent_options(New, Old),
793    ?DBG("merging agent env -> symbolic-store merged: "
794	 "~n   ~p | ~p -> ~p", [New, Old, SymbolicStore]),
795    SymbolicStore.
796
797merge_or_replace_agent_env_note_store(New, Old) ->
798    NoteStore = merge_agent_options(New, Old),
799    ?DBG("merging agent env -> note-store merged: "
800	 "~n   ~p | ~p -> ~p", [New, Old, NoteStore]),
801    NoteStore.
802
803merge_or_replace_agent_env_net_if(New, Old) ->
804    NetIf = merge_agent_options(New, Old),
805    ?DBG("merging agent env -> net-if merged: "
806	 "~n   ~p | ~p -> ~p", [New, Old, NetIf]),
807    NetIf.
808
809merge_agent_options([], Options) ->
810    lists:keysort(1, Options);
811merge_agent_options([{Key, _Value} = Opt|Opts], Options) ->
812    case lists:keysearch(Key, 1, Options) of
813	{value, _} ->
814	    NewOptions = lists:keyreplace(Key, 1, Options, Opt),
815	    merge_agent_options(Opts, NewOptions);
816	false ->
817	    merge_agent_options(Opts, [Opt|Options])
818    end.
819
820
821stop_agent(Config) when is_list(Config) ->
822    ?IPRINT("stop_agent -> entry with"
823            "~n   Config: ~p",[Config]),
824
825
826    %% Stop the sub-agent (the agent supervisor)
827    {SubSup, SubPar} = ?config(snmp_sub, Config),
828    ?IPRINT("stop_agent -> attempt to stop sub agent (~p)"
829            "~n   Sub Sup info: "
830            "~n      ~p"
831            "~n   Sub Par info: "
832            "~n      ~p",
833            [SubSup, ?PINFO(SubSup), ?PINFO(SubPar)]),
834    stop_sup(SubSup, SubPar),
835    Config2 = lists:keydelete(snmp_sub, 1, Config),
836
837
838    %% Stop the master-agent (the top agent supervisor)
839    {MasterSup, MasterPar} = ?config(snmp_sup, Config),
840    ?IPRINT("stop_agent -> attempt to stop master agent (~p)"
841            "~n   Master Sup: "
842            "~n      ~p"
843            "~n   Master Par: "
844            "~n      ~p"
845            "~n   Agent Info: "
846            "~n      ~p",
847            [MasterSup,
848             ?PINFO(MasterSup), ?PINFO(MasterPar),
849             agent_info(MasterSup)]),
850    stop_sup(MasterSup, MasterPar),
851    Config3 = lists:keydelete(snmp_sup, 1, Config2),
852
853
854    %% Stop the top supervisor (of the snmp app)
855    AppSup = ?config(snmp_app_sup, Config),
856    ?IPRINT("stop_agent -> attempt to app sup ~p"
857            "~n   App Sup: ~p",
858            [AppSup, ?PINFO(AppSup)]),
859    Config4 = lists:keydelete(snmp_app_sup, 1, Config3),
860
861
862    ?IPRINT("stop_agent -> done", []),
863    Config4.
864
865
866start_sup(Env) ->
867    case (catch snmp_app_sup:start_agent(normal, Env)) of
868	{ok, S} ->
869	    ?DBG("start_agent -> started, Sup: ~p", [S]),
870	    S;
871
872	Else ->
873	    ?EPRINT("start_agent -> unknown result: ~n~p", [Else]),
874	    %% Get info about the apps we depend on
875	    ?FAIL({start_failed, Else, ?IS_MNESIA_RUNNING()})
876    end.
877
878stop_sup(Pid, _) when (node(Pid) =:= node()) ->
879    case (catch process_info(Pid)) of
880	PI when is_list(PI) ->
881	    ?IPRINT("stop_sup -> attempt to stop ~p", [Pid]),
882	    Ref = erlang:monitor(process, Pid),
883	    exit(Pid, kill),
884	    await_stopped(Pid, Ref);
885	{'EXIT', _Reason} ->
886	    ?IPRINT("stop_sup -> ~p not running", [Pid]),
887	    ok
888    end;
889stop_sup(Pid, _) ->
890    ?IPRINT("stop_sup -> attempt to stop ~p", [Pid]),
891    Ref = erlang:monitor(process, Pid),
892    ?IPRINT("stop_sup -> Ref: ~p", [Ref]),
893    exit(Pid, kill),
894    await_stopped(Pid, Ref).
895
896await_stopped(Pid, Ref) ->
897    receive
898        {'DOWN', Ref, process, Pid, _Reason} ->
899            ?DBG("received down message for ~p", [Pid]),
900            ok
901    after 10000 ->
902	    ?EPRINT("await_stopped -> timeout for ~p",[Pid]),
903	    erlang:demonitor(Ref),
904	    ?FAIL({failed_stop,Pid})
905    end.
906
907
908%% --- start subagent supervisor ---
909
910start_sub_sup(Node, Dir) ->
911    rpc:call(Node, ?MODULE, start_sub_sup, [Dir]).
912
913start_sub_sup(Dir) ->
914    ?DBG("start_sub -> entry",[]),
915    Opts = [{db_dir,     Dir},
916            {supervisor, [{verbosity, trace}]}],
917    {ok, P} = snmpa_supervisor:start_sub_sup(Opts),
918    unlink(P),
919    {ok, {P, self()}}.
920
921
922%% --- start and stop subagents ---
923
924start_subagent(SaNode, RegTree, Mib) ->
925    ?DBG("start_subagent -> entry with"
926	"~n   SaNode:  ~p"
927	"~n   RegTree: ~p"
928	"~n   Mib:     ~p", [SaNode, RegTree, Mib]),
929    MA = whereis(snmp_master_agent),
930    ?DBG("start_subagent -> MA: ~p", [MA]),
931    MibDir = get(mib_dir),
932    Mib1   = join(MibDir, Mib),
933    Mod    = snmpa_supervisor,
934    Func   = start_sub_agent,
935    Args   = [MA, RegTree, [Mib1]],
936    case rpc:call(SaNode, Mod, Func, Args) of
937	{ok, SA} ->
938	    ?DBG("start_subagent -> SA: ~p", [SA]),
939	    {ok, SA};
940	Error ->
941	    ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]})
942    end.
943
944stop_subagent(SA) ->
945    ?DBG("stop_subagent -> entry with"
946	 "~n   SA: ~p", [SA]),
947    rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]).
948
949
950mibs(StdMibDir,MibDir) ->
951    [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")),
952     join(MibDir, "OLD-SNMPEA-MIB.bin"),
953     join(StdMibDir, "SNMP-FRAMEWORK-MIB"),
954     join(StdMibDir, "SNMP-MPD-MIB"),
955     join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"),
956     join(StdMibDir, "SNMP-USER-BASED-SM-MIB"),
957     join(StdMibDir, "SNMP-TARGET-MIB"),
958     join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
959     join(MibDir, "Klas1.bin"),
960     join(MibDir, "Klas2.bin"),
961     join(MibDir, "Klas3.bin"),
962     join(MibDir, "Klas4.bin"),
963     join(MibDir, "SA-MIB.bin"),
964     join(MibDir, "TestTrap.bin"),
965     join(MibDir, "Test1.bin"),
966     join(MibDir, "Test2.bin"),
967     join(MibDir, "TestTrapv2.bin")].
968
969
970%% --- various mib load/unload functions ---
971
972load_master(Mib) ->
973    ?DBG("load_master -> entry with"
974	"~n   Mib: ~p", [Mib]),
975    snmpa:unload_mib(snmp_master_agent, Mib),	% Unload for safety
976    ok = snmpa:load_mib(snmp_master_agent, join(get(mib_dir), Mib)).
977
978load_master_std(Mib) ->
979    ?DBG("load_master_std -> entry with"
980	"~n   Mib: ~p", [Mib]),
981    snmpa:unload_mib(snmp_master_agent, Mib),	% Unload for safety
982    ok = snmpa:load_mibs(snmp_master_agent, join(get(std_mib_dir), Mib)).
983
984unload_master(Mib) ->
985    ?DBG("unload_master -> entry with"
986	"~n   Mib: ~p", [Mib]),
987    ok = snmpa:unload_mib(snmp_master_agent, Mib).
988
989loaded_mibs() ->
990    ?DBG("loaded_mibs -> entry",[]),
991    Info = snmpa:info(snmp_master_agent),
992    {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info),
993    [atom_to_list(Mib) || {Mib,_,_} <- Mibs].
994
995unload_mibs(Mibs) ->
996    ?DBG("unload_mibs -> entry with"
997	"~n   Mibs: ~p", [Mibs]),
998    ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
999
1000
1001agent_info(Sup) ->
1002    ?DBG("agent_info -> entry with"
1003	 "~n   Sup: ~p", [Sup]),
1004    rpc:call(node(Sup), snmpa, info, []).
1005
1006
1007%% ---
1008%% The first two arguments are simple to be able to find where in the
1009%% (test) code this call is made.
1010
1011expect(Mod, Line, What) ->
1012    Fun = fun() -> do_expect(What) end,
1013    expect2(Mod, Line, Fun).
1014
1015expect(Mod, Line, What, ExpVBs) ->
1016    Fun = fun() -> do_expect(What, ExpVBs) end,
1017    expect2(Mod, Line, Fun).
1018
1019expect(Mod, Line, Error, Index, ExpVBS) ->
1020    Fun = fun() -> do_expect(Error, Index, ExpVBS) end,
1021    expect2(Mod, Line, Fun).
1022
1023expect(Mod, Line, Type, Enterp, Generic, Specific, ExpVBs) ->
1024    Fun = fun() -> do_expect(Type, Enterp, Generic, Specific, ExpVBs) end,
1025    expect2(Mod, Line, Fun).
1026
1027expect2(Mod, Line, F) ->
1028    io_format_expect("for ~w:~w", [Mod, Line]),
1029    case F() of
1030	{error, Reason} ->
1031	    io_format_expect("failed at ~w:~w => "
1032                             "~n      ~p", [Mod, Line, Reason]),
1033	    throw({error, {expect, Mod, Line, Reason}});
1034	Else ->
1035	    io_format_expect("result for ~w:~w => "
1036                             "~n      ~p", [Mod, Line, Else]),
1037	    Else
1038    end.
1039
1040
1041%% ----------------------------------------------------------------------
1042
1043-define(BASE_REQ_TIMEOUT, 3500).
1044
1045get_timeout() ->
1046    %% Try to figure out how "fast" a machine is.
1047    %% We assume that the number of schedulers
1048    %% (which depends on the number of core:s)
1049    %% effect the performance of the host...
1050    %% This is obviously not enough. The network
1051    %% also matterns, clock freq or the CPU, ...
1052    %% But its better than what we had before...
1053    case erlang:system_info(schedulers) of
1054        N when is_integer(N) ->
1055            ?BASE_REQ_TIMEOUT + timer:seconds(10 div N);
1056        _ ->
1057            ?BASE_REQ_TIMEOUT
1058    end.
1059
1060receive_pdu(To) ->
1061    receive
1062	{snmp_pdu, PDU} when is_record(PDU, pdu) ->
1063	    PDU
1064    after To ->
1065	    {error, timeout}
1066    end.
1067
1068receive_trap(To) ->
1069    receive
1070	{snmp_pdu, PDU} when is_record(PDU, trappdu) ->
1071	    PDU
1072    after To ->
1073	    {error, timeout}
1074    end.
1075
1076
1077io_format_expect(F) ->
1078    io_format_expect(F, []).
1079
1080io_format_expect(F, A) ->
1081    ?IPRINT("EXPECT " ++ F, A).
1082
1083
1084do_expect(Expect) when is_atom(Expect) ->
1085    do_expect({Expect, get_timeout()});
1086
1087do_expect({any_pdu, To})
1088  when is_integer(To) orelse (To =:= infinity) ->
1089    io_format_expect("any PDU"),
1090    receive_pdu(To);
1091
1092do_expect({any_trap, To}) ->
1093    io_format_expect("any TRAP within ~w", [To]),
1094    receive_trap(To);
1095
1096do_expect({timeout, To}) ->
1097    io_format_expect("nothing within ~w", [To]),
1098    receive
1099	X ->
1100	    {error, {unexpected, X}}
1101    after
1102	To ->
1103	    ok
1104    end;
1105
1106do_expect({Err, To})
1107  when (is_atom(Err) andalso
1108	((is_integer(To) andalso To > 0) orelse (To =:= infinity))) ->
1109    io_format_expect("error ~w within ~w", [Err, To]),
1110    do_expect({{error, Err}, To});
1111
1112do_expect({error, Err}) when is_atom(Err) ->
1113    Check = fun(_, R) -> R end,
1114    io_format_expect("error ~w", [Err]),
1115    do_expect2(Check, any, Err, any, any, get_timeout());
1116do_expect({{error, Err}, To}) ->
1117    Check = fun(_, R) -> R end,
1118    io_format_expect("error ~w within ~w", [Err, To]),
1119    do_expect2(Check, any, Err, any, any, To);
1120
1121%% exp_varbinds() -> [exp_varbind()]
1122%% exp_varbind()  -> any | {Oid, any} | {Oid, Value}
1123%% Oid            -> [integer()]
1124%% Value          -> term()
1125%% ExpVBs         -> exp_varbinds() | {VbsCondition, exp_varbinds()}
1126do_expect(ExpVBs) ->
1127    Check = fun(_, R) -> R end,
1128    io_format_expect("'get-response'"
1129                     "~n   with"
1130                     "~n      Varbinds: ~p", [ExpVBs]),
1131    do_expect2(Check, 'get-response', noError, 0, ExpVBs, get_timeout()).
1132
1133
1134do_expect(v2trap, ExpVBs) ->
1135    Check = fun(_, R) -> R end,
1136    io_format_expect("'snmpv2-trap' with"
1137                     "~n      Varbinds: ~p", [ExpVBs]),
1138    do_expect2(Check, 'snmpv2-trap', noError, 0, ExpVBs, get_timeout());
1139
1140
1141do_expect(report, ExpVBs) ->
1142    Check = fun(_, R) -> R end,
1143    io_format_expect("'report' with"
1144                     "~n      Varbinds: ~p", [ExpVBs]),
1145    do_expect2(Check, 'report', noError, 0, ExpVBs, get_timeout());
1146
1147
1148do_expect(inform, ExpVBs) ->
1149    do_expect({inform, true}, ExpVBs);
1150
1151do_expect({inform, false}, ExpVBs) ->
1152    Check = fun(_, R) -> R end,
1153    io_format_expect("'inform-request' (false) with"
1154                     "~n      Varbinds: ~p", [ExpVBs]),
1155    do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout());
1156
1157do_expect({inform, true}, ExpVBs) ->
1158    Check =
1159	fun(PDU, ok) ->
1160		RespPDU = PDU#pdu{type         = 'get-response',
1161				  error_status = noError,
1162				  error_index  = 0},
1163		snmp_test_mgr:rpl(RespPDU),
1164		ok;
1165	   (_, Err) ->
1166		Err
1167	end,
1168    io_format_expect("'inform-request' (true) with"
1169                     "~n      Varbinds: ~p", [ExpVBs]),
1170    do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout());
1171
1172do_expect({inform, {error, EStat, EIdx}}, ExpVBs)
1173  when is_atom(EStat) andalso is_integer(EIdx) ->
1174    Check =
1175	fun(PDU, ok) ->
1176		RespPDU = PDU#pdu{type         = 'get-response',
1177				  error_status = EStat,
1178				  error_index  = EIdx},
1179		snmp_test_mgr:rpl(RespPDU),
1180		ok;
1181	   (_, Err) ->
1182		Err
1183	end,
1184    io_format_expect("'inform-request' (error) with"
1185                     "~n      Error Status: ~p"
1186                     "~n      Error Index:  ~p"
1187                     "~n      Varbinds:     ~p", [EStat, EIdx, ExpVBs]),
1188    do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()).
1189
1190
1191do_expect(Err, Idx, ExpVBs) ->
1192    do_expect(Err, Idx, ExpVBs, get_timeout()).
1193
1194do_expect(Err, Idx, ExpVBs, To)
1195  when is_atom(Err) andalso
1196       (is_integer(Idx) orelse is_list(Idx) orelse (Idx == any)) ->
1197    Check = fun(_, R) -> R end,
1198    io_format_expect("'get-response' withing ~w ms with"
1199                     "~n      Error:    ~p"
1200                     "~n      Index:    ~p"
1201                     "~n      Varbinds: ~p", [To, Err, Idx, ExpVBs]),
1202    do_expect2(Check, 'get-response', Err, Idx, ExpVBs, To).
1203
1204
1205do_expect(Type, Enterp, Generic, Specific, ExpVBs) ->
1206    do_expect(Type, Enterp, Generic, Specific, ExpVBs, get_timeout()).
1207
1208do_expect(trap, Enterp, Generic, Specific, ExpVBs, To) ->
1209    io_format_expect("trap within ~w ms with"
1210                     "~n      Enterp:   ~w"
1211                     "~n      Generic:  ~w"
1212                     "~n      Specific: ~w"
1213                     "~n      Varbinds: ~w",
1214                     [To, Enterp, Generic, Specific, ExpVBs]),
1215    PureE = purify_oid(Enterp),
1216    case receive_trap(To) of
1217	#trappdu{enterprise    = PureE,
1218		 generic_trap  = Generic,
1219		 specific_trap = Specific,
1220		 varbinds      = VBs} ->
1221	    check_vbs(purify_oids(ExpVBs), VBs);
1222
1223	#trappdu{enterprise    = Ent2,
1224		 generic_trap  = G2,
1225		 specific_trap = Spec2,
1226		 varbinds      = VBs} ->
1227	    {error, {unexpected_trap,
1228		     {PureE, Generic, Specific, ExpVBs},
1229		     {Ent2, G2, Spec2, VBs}}};
1230
1231	{error, timeout} = Error ->
1232            SysEvs = snmp_test_global_sys_monitor:events(),
1233	    io_format_expect("[expecting trap] got timeout when system events:"
1234                             "~n   ~p", [SysEvs]),
1235            if
1236                (SysEvs =:= []) ->
1237                    Error;
1238                true ->
1239                    skip({system_events, SysEvs})
1240            end;
1241
1242
1243	Error ->
1244	    Error
1245    end.
1246
1247
1248do_expect2(Check, Type, Err, Idx, ExpVBs, To)
1249  when is_function(Check) andalso
1250       is_atom(Type) andalso
1251       is_atom(Err) andalso
1252       (is_integer(Idx) orelse is_list(Idx) orelse (Idx =:= any)) andalso
1253       (is_list(ExpVBs) orelse (ExpVBs =:= any)) andalso
1254       (is_integer(To) orelse (To =:= infinity)) ->
1255
1256    case receive_pdu(To) of
1257
1258	#pdu{type         = Type,
1259	     error_status = Err,
1260	     error_index  = Idx} when ExpVBs =:= any ->
1261	    io_format_expect("received expected pdu (1)"),
1262	    ok;
1263
1264	#pdu{type         = Type,
1265	     request_id   = ReqId,
1266	     error_status = Err2,
1267	     error_index  = Idx} when ExpVBs =:= any ->
1268	    io_format_expect("received expected pdu with "
1269                             "unexpected error status (2): "
1270                             "~n   Error Status: ~p", [Err2]),
1271	    {error, {unexpected_error_status, Err, Err2, ReqId}};
1272
1273	#pdu{error_status = Err} when (Type   =:= any) andalso
1274				      (Idx    =:= any) andalso
1275				      (ExpVBs =:= any) ->
1276	    io_format_expect("received expected pdu (3)"),
1277	    ok;
1278
1279	#pdu{request_id   = ReqId,
1280	     error_status = Err2} when (Type   =:= any) andalso
1281				       (Idx    =:= any) andalso
1282				       (ExpVBs =:= any) ->
1283	    io_format_expect("received expected pdu with "
1284                             "unexpected error status (4): "
1285                             "~n   Error Status: ~p", [Err2]),
1286	    {error, {unexpected_error_status, Err, Err2, ReqId}};
1287
1288	#pdu{type         = Type,
1289	     error_status = Err} when (Idx =:= any) andalso
1290				      (ExpVBs =:= any) ->
1291	    io_format_expect("received expected pdu (5)", []),
1292	    ok;
1293
1294	#pdu{type         = Type,
1295	     request_id   = ReqId,
1296	     error_status = Err2} when (Idx =:= any) andalso
1297				       (ExpVBs =:= any) ->
1298	    io_format_expect("received expected pdu with "
1299                             "unexpected error status (6): "
1300                             "~n   Error Status: ~p", [Err2]),
1301	    {error, {unexpected_error_status, Err, Err2, ReqId}};
1302
1303	#pdu{type         = Type,
1304	     request_id   = ReqId,
1305	     error_status = Err,
1306	     error_index  = EI} when is_list(Idx) andalso (ExpVBs =:= any) ->
1307	    case lists:member(EI, Idx) of
1308		true ->
1309		    io_format_expect("received expected pdu with "
1310                                     "expected error index (7)"),
1311		    ok;
1312		false ->
1313		    io_format_expect("received expected pdu with "
1314                                     "unexpected error index (8): "
1315                                     "~n   Error Index: ~p", [EI]),
1316		    {error, {unexpected_error_index, EI, Idx, ReqId}}
1317	    end;
1318
1319	#pdu{type         = Type,
1320	     request_id   = ReqId,
1321	     error_status = Err2,
1322	     error_index  = EI} when is_list(Idx) andalso (ExpVBs =:= any) ->
1323	    case lists:member(EI, Idx) of
1324		true ->
1325		    io_format_expect("received expected pdu with "
1326                                     "unexpected error status (9): "
1327                                     "~n   Error Status: ~p", [Err2]),
1328		    {error, {unexpected_error_status, Err, Err2, ReqId}};
1329		false ->
1330		    io_format_expect("received expected pdu with "
1331                                     "unexpected error (10): "
1332                                     "~n   Error Status: ~p"
1333                                     "~n   Error index:  ~p", [Err2, EI]),
1334		    {error, {unexpected_error, {Err, Idx}, {Err2, EI}, ReqId}}
1335	    end;
1336
1337	#pdu{type         = Type2,
1338	     request_id   = ReqId,
1339	     error_status = Err2,
1340	     error_index  = Idx2} when ExpVBs =:= any ->
1341	    io_format_expect("received unexpected pdu with (11) "
1342                             "~n   Type:         ~p"
1343                             "~n   ReqId:        ~p"
1344                             "~n   Error status: ~p"
1345                             "~n   Error index:  ~p",
1346                             [Type2, ReqId, Err2, Idx2]),
1347	    {error,
1348	     {unexpected_pdu,
1349	      {Type, Err, Idx}, {Type2, Err2, Idx2}, ReqId}};
1350
1351	#pdu{type         = Type,
1352	     error_status = Err,
1353	     error_index  = Idx,
1354	     varbinds     = VBs} = PDU ->
1355	    io_format_expect("received pdu (12): "
1356                             "~n   [exp] Type:         ~p"
1357                             "~n   [exp] Error Status: ~p"
1358                             "~n   [exp] Error Index:  ~p"
1359                             "~n   VBs:                ~p"
1360                             "~nwhen"
1361                             "~n   ExpVBs:             ~p",
1362                             [Type, Err, Idx, VBs, ExpVBs]),
1363	    Check(PDU, check_vbs(purify_oids(ExpVBs), VBs));
1364
1365	#pdu{type         = Type,
1366	     error_status = Err,
1367	     varbinds     = VBs} = PDU when Idx =:= any ->
1368	    io_format_expect("received pdu (13): "
1369                             "~n   [exp] Type:         ~p"
1370                             "~n   [exp] Error Status: ~p"
1371                             "~n   VBs:                ~p"
1372                             "~nwhen"
1373                             "~n   ExpVBs:             ~p",
1374                             [Type, Err, VBs, ExpVBs]),
1375	    Check(PDU, check_vbs(purify_oids(ExpVBs), VBs));
1376
1377	#pdu{type         = Type,
1378	     request_id   = ReqId,
1379	     error_status = Err,
1380	     error_index  = EI,
1381	     varbinds     = VBs} = PDU when is_list(Idx) ->
1382	    io_format_expect("received pdu (14): "
1383                             "~n   [exp] Type:         ~p"
1384                             "~n   ReqId:              ~p"
1385                             "~n   [exp] Error Status: ~p"
1386                             "~n   [exp] Error Index:  ~p"
1387                             "~n   VBs:                ~p"
1388                             "~nwhen"
1389                             "~n   ExpVBs:             ~p",
1390                             [Type, ReqId, Err, EI, VBs, ExpVBs]),
1391	    PureVBs = purify_oids(ExpVBs),
1392	    case lists:member(EI, Idx) of
1393		true ->
1394		    Check(PDU, check_vbs(PureVBs, VBs));
1395		false ->
1396		    {error, {unexpected_error_index, Idx, EI, ReqId}}
1397	    end;
1398
1399	#pdu{type         = Type2,
1400	     request_id   = ReqId,
1401	     error_status = Err2,
1402	     error_index  = Idx2,
1403	     varbinds     = VBs2} ->
1404	    io_format_expect("received unexpected pdu with (15) "
1405                             "~n   Type:         ~p"
1406                             "~n   ReqId:        ~p"
1407                             "~n   Error status: ~p"
1408                             "~n   Error index:  ~p"
1409                             "~n   Varbinds:     ~p",
1410                             [Type2, ReqId, Err2, Idx2, VBs2]),
1411	    {error,
1412	     {unexpected_pdu,
1413	      {Type,  Err,  Idx, purify_oids(ExpVBs)},
1414	      {Type2, Err2, Idx2, VBs2},
1415	      ReqId}};
1416
1417
1418	{error, timeout} = Error ->
1419            SysEvs = snmp_test_global_sys_monitor:events(),
1420	    io_format_expect("got timeout (16) when system events:"
1421                             "~n   ~p", [SysEvs]),
1422            if
1423                (SysEvs =:= []) ->
1424                    Error;
1425                true ->
1426                    skip({system_events, SysEvs})
1427            end;
1428
1429
1430        Error ->
1431            io_format_expect("received error (17):  "
1432                             "~n   Error: ~p", [Error]),
1433            Error
1434    end.
1435
1436
1437
1438check_vbs([], []) ->
1439    ok;
1440check_vbs(Exp, []) ->
1441    {error, {to_few_vbs, Exp}};
1442check_vbs([], VBs) ->
1443    {error, {to_many_vbs, VBs}};
1444check_vbs([any|Exp], [_|VBs]) ->
1445    check_vbs(Exp, VBs);
1446check_vbs([{Oid, any}|Exp], [#varbind{oid = Oid}|VBs]) ->
1447    check_vbs(Exp, VBs);
1448check_vbs([{Oid, Val}|Exp], [#varbind{oid = Oid, value = Val}|VBs]) ->
1449    check_vbs(Exp, VBs);
1450check_vbs([{Oid, Val1}|_], [#varbind{oid = Oid, value = Val2}|_]) ->
1451    {error, {unexpected_vb_value, Oid, Val1, Val2}};
1452check_vbs([{Oid1, _}|_], [#varbind{oid = Oid2}|_]) ->
1453    {error, {unexpected_vb_oid, Oid1, Oid2}}.
1454
1455
1456purify_oids({VbsCondition, VBs})
1457  when ((VbsCondition =:= true) orelse (VbsCondition =:= false)) andalso
1458       is_list(VBs) ->
1459    {VbsCondition, do_purify_oids(VBs)};
1460purify_oids(VBs) when is_list(VBs) ->
1461    do_purify_oids(VBs).
1462
1463do_purify_oids([]) ->
1464    [];
1465do_purify_oids([{XOid, Q}|T]) ->
1466    [{purify_oid(XOid), Q} | do_purify_oids(T)].
1467
1468
1469purify_oid(Oid) ->
1470    io:format("~w:purify_oid -> entry with"
1471	      "~n   Oid:      ~w"
1472	      "~n",
1473	      [?MODULE, Oid]),
1474    case (catch snmp_test_mgr:purify_oid(Oid)) of
1475	{error, Reason} ->
1476	    io:format("~w:purify_oid -> error: "
1477		      "~n   Reason: ~p"
1478		      "~n",
1479		      [?MODULE, Reason]),
1480	    exit({malformed_oid, Reason});
1481	{ok, Oid2} when is_list(Oid2) ->
1482	    io:format("~w:purify_oid -> ok: "
1483		      "~n   Oid2: ~p"
1484		      "~n",
1485		      [?MODULE, Oid2]),
1486	    Oid2;
1487	Error ->
1488	    io:format("~w:purify_oid -> unexpected return value: "
1489		      "~n   Error: ~p"
1490		      "~n",
1491		      [?MODULE, Error]),
1492	    exit({unexpected_purify_result, Error})
1493
1494    end.
1495
1496
1497%% ----------------------------------------------------------------------
1498
1499get_req(Id, Vars) ->
1500    ?DBG("get_req -> entry with"
1501	   "~n   Id:   ~p"
1502	   "~n   Vars: ~p",[Id,Vars]),
1503    snmp_test_mgr:g(Vars),
1504    ?DBG("get_req -> await response",[]),
1505    case snmp_test_mgr:get_response(Id, Vars) of
1506	{ok, Val} ->
1507	    ?DBG("get_req -> response: ~p",[Val]),
1508	    Val;
1509	{error, _, {_ExpFmt, ExpArg}, {_ActFmt, ActArg}} ->
1510	    ?DBG("get_req -> error for ~p: "
1511		 "~n   " ++ _ExpFmt ++
1512		 "~n   " ++ _ActFmt,
1513		 [Id] ++ ExpArg ++ ActArg),
1514	    exit({unexpected_response, ExpArg, ActArg});
1515	Error ->
1516	    ?DBG("get_req -> error: ~n~p",[Error]),
1517	    exit({unknown, Error})
1518    end.
1519
1520
1521get_next_req(Vars) ->
1522    ?DBG("get_next_req -> entry with"
1523	 "~n   Vars: ~p", [Vars]),
1524    snmp_test_mgr:gn(Vars),
1525    ?DBG("get_next_req -> await response",[]),
1526    Response = snmp_test_mgr:receive_response(),
1527    ?DBG("get_next_req -> response: ~p",[Response]),
1528    Response.
1529
1530
1531%% --- start and stop nodes ---
1532
1533start_node(Name) ->
1534    ?IPRINT("start_node -> entry with"
1535            "~n   Name: ~p"
1536            "~n when"
1537            "~n   hostname of this node: ~p",
1538            [Name, list_to_atom(?HOSTNAME(node()))]),
1539
1540    Pa = filename:dirname(code:which(?MODULE)),
1541    ?DBG("start_node -> Pa: ~p", [Pa]),
1542
1543    A = " -pa " ++ Pa ++
1544        " -s " ++ atom_to_list(snmp_test_sys_monitor) ++ " start" ++
1545        " -s global sync",
1546    case ?START_NODE(Name, A) of
1547	{ok, Node} ->
1548	    ?DBG("start_node -> Node: ~p", [Node]),
1549            global:sync(),
1550	    {ok, Node};
1551	{error, Reason}  ->
1552	    ?WPRINT("start_node -> failed starting node ~p:"
1553                    "~n      Reason: ~p", [Name, Reason]),
1554	    ?line ?SKIP({failed_start_node, Reason});
1555	Else  ->
1556	    ?EPRINT("start_node -> failed starting node ~p:"
1557                    "~n      ~p", [Name, Else]),
1558	    ?line ?FAIL(Else)
1559    end.
1560
1561
1562stop_node(Node) ->
1563    ?IPRINT("stop_node -> Node: ~p", [Node]),
1564    ?STOP_NODE(Node).
1565
1566
1567%%%-----------------------------------------------------------------
1568%%% Configuration
1569%%%-----------------------------------------------------------------
1570
1571config(Vsns, MgrDir, AgentConfDir, MIp, AIp) ->
1572    config(Vsns, MgrDir, AgentConfDir, MIp, AIp, inet).
1573
1574config(Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily) ->
1575    ?IPRINT("config -> entry with"
1576            "~n   Vsns:         ~p"
1577            "~n   MgrDir:       ~p"
1578            "~n   AgentConfDir: ~p"
1579            "~n   MIp:          ~p"
1580            "~n   AIp:          ~p"
1581            "~n   IpFamily:     ~p",
1582            [Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily]),
1583    ?line {Domain, ManagerAddr} =
1584	case IpFamily of
1585	    inet6 ->
1586		Ipv6Domain = transportDomainUdpIpv6,
1587		AgentIpv6Addr = {AIp, 4000},
1588		ManagerIpv6Addr = {MIp, ?TRAP_UDP},
1589		?line ok =
1590		    snmp_config:write_agent_snmp_files(
1591		      AgentConfDir, Vsns,
1592		      Ipv6Domain, ManagerIpv6Addr, AgentIpv6Addr, "test"),
1593		{Ipv6Domain, ManagerIpv6Addr};
1594	    _ ->
1595		?line ok =
1596		    snmp_config:write_agent_snmp_files(
1597		      AgentConfDir, Vsns, MIp, ?TRAP_UDP, AIp, 4000, "test"),
1598		{snmpUDPDomain, {MIp, ?TRAP_UDP}}
1599	  end,
1600
1601    ?line case update_usm(Vsns, AgentConfDir) of
1602	      true ->
1603		  ?line copy_file(join(AgentConfDir, "usm.conf"),
1604				  join(MgrDir, "usm.conf")),
1605		  ?line update_usm_mgr(Vsns, MgrDir);
1606	      false ->
1607		  ?line ok
1608	  end,
1609    ?line update_community(Vsns, AgentConfDir),
1610    ?line update_vacm(Vsns, AgentConfDir),
1611    ?line write_target_addr_conf(AgentConfDir, Domain, ManagerAddr, Vsns),
1612    ?line write_target_params_conf(AgentConfDir, Vsns),
1613    ?line write_notify_conf(AgentConfDir),
1614    ok.
1615
1616delete_files(Config) ->
1617    AgentDir = ?config(agent_dir, Config),
1618    delete_files(AgentDir, [db, conf]).
1619
1620delete_files(_AgentFiles, []) ->
1621    ok;
1622delete_files(AgentDir, [DirName|DirNames]) ->
1623    Dir = join(AgentDir, DirName),
1624    {ok, Files} = file:list_dir(Dir),
1625    lists:foreach(fun(FName) -> file:delete(join(Dir, FName)) end,
1626		  Files),
1627    delete_files(AgentDir, DirNames).
1628
1629update_usm(Vsns, Dir) ->
1630    case lists:member(v3, Vsns) of
1631	true ->
1632	    Conf = [{"agentEngine", "all-rights", "all-rights", zeroDotZero,
1633		     usmNoAuthProtocol, "", "",
1634		     usmNoPrivProtocol, "", "", "", "", ""},
1635
1636		    {"agentEngine", "no-rights", "no-rights", zeroDotZero,
1637		     usmNoAuthProtocol, "", "",
1638		     usmNoPrivProtocol, "", "", "", "", ""},
1639
1640		    {"agentEngine", "authMD5", "authMD5", zeroDotZero,
1641		     usmHMACMD5AuthProtocol, "", "",
1642		     usmNoPrivProtocol, "", "", "", "passwd_md5xxxxxx", ""},
1643
1644		    {"agentEngine", "authSHA", "authSHA", zeroDotZero,
1645		     usmHMACSHAAuthProtocol, "", "",
1646		     usmNoPrivProtocol, "", "", "",
1647		     "passwd_shaxxxxxxxxxx", ""},
1648
1649		    {"agentEngine", "privDES", "privDES", zeroDotZero,
1650		     usmHMACSHAAuthProtocol, "", "",
1651		     usmDESPrivProtocol, "", "", "",
1652		     "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"},
1653
1654		    {"mgrEngine", "all-rights", "all-rights", zeroDotZero,
1655		     usmNoAuthProtocol, "", "",
1656		     usmNoPrivProtocol, "", "", "", "", ""},
1657
1658		    {"mgrEngine", "no-rights", "no-rights", zeroDotZero,
1659		     usmNoAuthProtocol, "", "",
1660		     usmNoPrivProtocol, "", "", "", "", ""},
1661
1662		    {"mgrEngine", "authMD5", "authMD5", zeroDotZero,
1663		     usmHMACMD5AuthProtocol, "", "",
1664		     usmNoPrivProtocol, "", "", "", "passwd_md5xxxxxx", ""},
1665
1666		    {"mgrEngine", "authSHA", "authSHA", zeroDotZero,
1667		     usmHMACSHAAuthProtocol, "", "",
1668		     usmNoPrivProtocol, "", "", "",
1669		     "passwd_shaxxxxxxxxxx", ""},
1670
1671		    {"mgrEngine", "privDES", "privDES", zeroDotZero,
1672		     usmHMACSHAAuthProtocol, "", "",
1673		     usmDESPrivProtocol, "", "", "",
1674		     "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"}],
1675	    ?line ok = snmp_config:update_agent_usm_config(Dir, Conf),
1676	    true;
1677	false ->
1678	    false
1679    end.
1680
1681update_usm_mgr(Vsns, Dir) ->
1682    case lists:member(v3, Vsns) of
1683	true ->
1684	    Conf = [{"agentEngine", "newUser", "newUser", zeroDotZero,
1685		     usmHMACSHAAuthProtocol, "", "",
1686		     usmDESPrivProtocol, "", "", "",
1687		     "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"},
1688
1689		    {"mgrEngine", "newUser", "newUser", zeroDotZero,
1690		     usmHMACSHAAuthProtocol, "", "",
1691		     usmDESPrivProtocol, "", "", "",
1692		     "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"}],
1693
1694	    ?line ok = snmp_config:update_agent_usm_config(Dir, Conf),
1695	    true;
1696	false ->
1697	    false
1698    end.
1699
1700rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
1701    ?line ok = file:rename(join(Dir,"usm.conf"),
1702			   join(Dir,"usm.old")),
1703    Conf = [{"agentEngine", "newUser", "newUser", zeroDotZero,
1704	     usmHMACSHAAuthProtocol, "", "",
1705	     usmDESPrivProtocol, "", "", "", ShaKey, DesKey},
1706	    {"mgrEngine", "newUser", "newUser", zeroDotZero,
1707	     usmHMACSHAAuthProtocol, "", "",
1708	     usmDESPrivProtocol, "", "", "", ShaKey, DesKey}],
1709    ?line ok = snmp_config:write_agent_usm_config(Dir, "", Conf).
1710
1711reset_usm_mgr(Dir) ->
1712    ?line ok = file:rename(join(Dir,"usm.old"),
1713			   join(Dir,"usm.conf")).
1714
1715
1716update_community([v3], _Dir) ->
1717    ok;
1718update_community(_, Dir) ->
1719    Conf = [{"no-rights", "no-rights", "no-rights", "", ""}],
1720    ?line ok = snmp_config:update_agent_community_config(Dir, Conf).
1721
1722
1723-define(tDescr_instance, [1,3,6,1,2,1,16,1,0]).
1724update_vacm(_Vsn, Dir) ->
1725    Conf = [{vacmSecurityToGroup, usm, "authMD5", "initial"},
1726	    {vacmSecurityToGroup, usm, "authSHA", "initial"},
1727	    {vacmSecurityToGroup, usm, "privDES", "initial"},
1728	    {vacmSecurityToGroup, usm, "newUser", "initial"},
1729	    {vacmViewTreeFamily, "internet", ?tDescr_instance,
1730	     excluded, null}],
1731    ?line ok = snmp_config:update_agent_vacm_config(Dir, Conf).
1732
1733
1734write_community_conf(Dir, Conf) ->
1735    ?line ok = snmp_config:write_agent_community_config(Dir, "", Conf).
1736
1737write_target_addr_conf(Dir, Conf) ->
1738    ?line ok = snmp_config:write_agent_target_addr_config(Dir, "", Conf).
1739
1740write_target_addr_conf(Dir, Ip_or_Domain, Port_or_Addr, Vsns) ->
1741    ?line ok =
1742	snmp_config:write_agent_snmp_target_addr_conf(
1743	  Dir, Ip_or_Domain, Port_or_Addr, Vsns).
1744
1745rewrite_target_addr_conf(Dir, NewPort) ->
1746    ?DBG("rewrite_target_addr_conf -> entry with"
1747	 "~n   NewPort: ~p", [NewPort]),
1748    TAFile = join(Dir, "target_addr.conf"),
1749    case file:read_file_info(TAFile) of
1750	{ok, _} ->
1751	    ok;
1752	{error, _R} ->
1753	    ?WPRINT("failure reading file info of "
1754                    "target address config file: ~p", [_R]),
1755	    ok
1756    end,
1757
1758    ?line [TrapAddr|Addrs] =
1759	snmp_conf:read(TAFile, fun rewrite_target_addr_conf_check/1),
1760
1761    ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]),
1762
1763    NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs],
1764
1765    ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]),
1766
1767    ?line ok = file:rename(join(Dir,"target_addr.conf"),
1768			   join(Dir,"target_addr.old")),
1769
1770    ?line ok = snmp_config:write_agent_target_addr_config(Dir, "", NewAddrs).
1771
1772rewrite_target_addr_conf_check(O) ->
1773    {ok,O}.
1774
1775rewrite_target_addr_conf2(NewPort,
1776			  {Name, Ip, _Port, Timeout, Retry,
1777			   "std_trap", EngineId}) ->
1778    ?IPRINT("rewrite_target_addr_conf2 -> entry with std_trap",[]),
1779    {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId};
1780rewrite_target_addr_conf2(_NewPort,O) ->
1781    ?IPRINT("rewrite_target_addr_conf2 -> entry with "
1782	 "~n   O: ~p",[O]),
1783    O.
1784
1785reset_target_addr_conf(Dir) ->
1786    ?line ok = file:rename(join(Dir, "target_addr.old"),
1787			   join(Dir, "target_addr.conf")).
1788
1789write_target_params_conf(Dir, Vsns) ->
1790    F = fun(v1) -> {"target_v1", v1,  v1,  "all-rights", noAuthNoPriv};
1791	   (v2) -> {"target_v2", v2c, v2c, "all-rights", noAuthNoPriv};
1792	   (v3) -> {"target_v3", v3,  usm, "all-rights", noAuthNoPriv}
1793	end,
1794    Conf = [F(Vsn) || Vsn <- Vsns],
1795    ?line ok = snmp_config:write_agent_target_params_config(Dir, "", Conf).
1796
1797rewrite_target_params_conf(Dir, SecName, SecLevel)
1798  when is_list(SecName) andalso is_atom(SecLevel) ->
1799    ?line ok = file:rename(join(Dir,"target_params.conf"),
1800			   join(Dir,"target_params.old")),
1801    Conf = [{"target_v3", v3, usm, SecName, SecLevel}],
1802    ?line ok = snmp_config:write_agent_target_params_config(Dir, "", Conf).
1803
1804reset_target_params_conf(Dir) ->
1805    ?line ok = file:rename(join(Dir,"target_params.old"),
1806			   join(Dir,"target_params.conf")).
1807
1808write_notify_conf(Dir) ->
1809    Conf = [{"standard trap",   "std_trap",   trap},
1810	    {"standard inform", "std_inform", inform}],
1811    ?line ok = snmp_config:write_agent_notify_config(Dir, "", Conf).
1812
1813write_view_conf(Dir) ->
1814    Conf = [{2, [1,3,6], included, null},
1815	    {2, ?tDescr_instance, excluded, null}],
1816    ?line ok = snmp_config:write_agent_view_config(Dir, "", Conf).
1817
1818
1819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1820
1821copy_file(From, To) ->
1822    {ok, Bin} = file:read_file(From),
1823    ok = file:write_file(To, Bin).
1824
1825
1826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1827
1828display_memory_usage() ->
1829    Info       = snmpa:info(snmp_master_agent),
1830    TreeSize   = key1search(tree_size_bytes,  Info),
1831    ProcMem    = key1search(process_memory,   Info),
1832    MibDbSize  = key1search([db_memory,mib],  Info),
1833    NodeDbSize = key1search([db_memory,node], Info),
1834    TreeDbSize = key1search([db_memory,tree], Info),
1835    ?IPRINT("Memory usage: "
1836            "~n   Tree size:           ~p"
1837            "~n   Process memory size: ~p"
1838            "~n   Mib db size:         ~p"
1839            "~n   Node db size:        ~p"
1840            "~n   Tree db size:        ~p",
1841    [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
1842
1843key1search([], Res) ->
1844    Res;
1845key1search([Key|Keys], List) when is_atom(Key) andalso is_list(List) ->
1846    case lists:keysearch(Key, 1, List) of
1847	{value, {Key, Val}} ->
1848	    key1search(Keys, Val);
1849	false ->
1850	    undefined
1851    end;
1852key1search(Key, List) when is_atom(Key) ->
1853    case lists:keysearch(Key, 1, List) of
1854	{value, {Key, Val}} ->
1855	    Val;
1856	false ->
1857	    undefined
1858    end.
1859
1860
1861regs() ->
1862    lists:sort(registered()).
1863
1864
1865rpc(Node, F, A) ->
1866    rpc:call(Node, snmpa, F, A).
1867
1868
1869join(Dir, File) ->
1870    filename:join(Dir, File).
1871
1872
1873skip(R) ->
1874    exit({skip, R}).
1875
1876