1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2004-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(snmpm).
22
23%%----------------------------------------------------------------------
24%% This module implements a simple SNMP manager for Erlang.
25%%----------------------------------------------------------------------
26
27%% User interface
28%% Avoid warning for local function demonitor/1 clashing with autoimported BIF.
29-compile({no_auto_import,[demonitor/1]}).
30-export([
31	 %%
32	 %% Management API
33	 start/0, start/1,
34	 start_link/0, start_link/1,
35	 stop/0, stop/1,
36
37	 monitor/0, demonitor/1,
38	 notify_started/1, cancel_notify_started/1,
39
40	 backup/1,
41
42	 load_mib/1, unload_mib/1,
43	 which_mibs/0,
44	 name_to_oid/1, oid_to_name/1, oid_to_type/1,
45
46	 register_user/3, register_user/4,
47	 register_user_monitor/3, register_user_monitor/4,
48	 unregister_user/1,
49	 which_users/0,
50
51	 register_agent/2, register_agent/3, register_agent/4,
52	 unregister_agent/2, unregister_agent/3,
53	 which_agents/0, which_agents/1,
54	 agent_info/2, update_agent_info/3, update_agent_info/4,
55
56	 register_usm_user/3, unregister_usm_user/2,
57	 which_usm_users/0, which_usm_users/1,
58	 usm_user_info/3, update_usm_user_info/4,
59
60	 %%
61	 %% Basic SNMP API (version "3").
62	 sync_get2/3, sync_get2/4,
63	 async_get2/3, async_get2/4,
64	 sync_get_next2/3, sync_get_next2/4,
65	 async_get_next2/3, async_get_next2/4,
66	 sync_set2/3, sync_set2/4,
67	 async_set2/3, async_set2/4,
68	 sync_get_bulk2/5, sync_get_bulk2/6,
69	 async_get_bulk2/5, async_get_bulk2/6,
70
71	 cancel_async_request/2,
72
73	 %%
74	 %% Extended SNMP API
75	 %% discovery/2, discovery/3, discovery/4, discovery/5, discovery/6,
76
77	 %%
78	 %% Logging
79	 log_to_txt/1, log_to_txt/2, log_to_txt/3, log_to_txt/4,
80	 log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_txt/8,
81	 log_to_io/1,  log_to_io/2,  log_to_io/3,  log_to_io/4,
82	 log_to_io/5,  log_to_io/6,  log_to_io/7,
83	 change_log_size/1,
84	 get_log_type/0,
85	 set_log_type/1,
86
87	 reconfigure/0,
88
89	 system_start_time/0,
90	 sys_up_time/0,
91
92	 info/0, info/1,
93	 verbosity/2,
94         restart/1
95	]).
96
97-export([format_reason/1, format_reason/2]).
98
99%% Backward compatibility exports (API version "2")
100-export([
101	 sync_get/3, sync_get/4, sync_get/5, sync_get/6,
102	 async_get/3, async_get/4, async_get/5, async_get/6,
103	 sync_get_next/3, sync_get_next/4, sync_get_next/5, sync_get_next/6,
104	 async_get_next/3, async_get_next/4, async_get_next/5, async_get_next/6,
105	 sync_set/3, sync_set/4, sync_set/5, sync_set/6,
106	 async_set/3, async_set/4, async_set/5, async_set/6,
107	 sync_get_bulk/5, sync_get_bulk/6, sync_get_bulk/7, sync_get_bulk/8,
108	 async_get_bulk/5, async_get_bulk/6, async_get_bulk/7, async_get_bulk/8
109	]).
110
111%% Application internal export
112-export([start_link/3, snmpm_start_verify/2, snmpm_start_verify/3]).
113-export([target_name/1, target_name/2]).
114
115-export_type([
116	      register_timeout/0,
117	      agent_config/0,
118	      target_name/0
119	     ]).
120
121
122-include_lib("snmp/src/misc/snmp_debug.hrl").
123-include_lib("snmp/include/snmp_types.hrl").
124-include("snmpm_atl.hrl").
125-include("snmpm_internal.hrl").
126-include("snmp_verbosity.hrl").
127
128-define(DEFAULT_AGENT_PORT, 161).
129-define(ATL_BLOCK_DEFAULT,  true).
130
131
132%%-----------------------------------------------------------------
133%% Types
134%%-----------------------------------------------------------------
135
136-type register_timeout() :: pos_integer() | snmp:snmp_timer().
137-type agent_config() :: {engine_id,        snmp:engine_id()}   | % Mandatory
138			{address,          inet:ip_address()}  | % Mandatory
139			{port,             inet:port_number()} | % Optional
140			{tdomain,          snmp:tdomain()}     | % Optional
141			{community,        snmp:community()}   | % Optional
142			{timeout,          register_timeout()} | % Optional
143			{max_message_size, snmp:mms()}         | % Optional
144			{version,          snmp:version()}     | % Optional
145			{sec_moduel,       snmp:sec_model()}   | % Optional
146			{sec_name,         snmp:sec_name()}    | % Optional
147			{sec_level,        snmp:sec_level()}.    % Optional
148-type target_name() :: string().
149
150
151%% This function is called when the snmp application
152%% starts.
153start_link(Opts, normal, []) ->
154    start_link(Opts).
155
156
157simple_conf() ->
158    Vsns      = [v1, v2, v3],
159    {ok, Cwd} = file:get_cwd(),
160    %% Check if the manager config file exist, if not create it
161    MgrConf = filename:join(Cwd, "manager.conf"),
162    case file:read_file_info(MgrConf) of
163	{ok, _} ->
164	    ok;
165	_ ->
166	    ok = snmp_config:write_manager_config(Cwd, "",
167						  [{port, 5000},
168						   {engine_id, "mgrEngine"},
169						   {max_message_size, 484}])
170    end,
171    Conf = [{dir, Cwd}, {db_dir, Cwd}],
172    [{versions, Vsns}, {config, Conf}].
173
174%% Simple start. Start a manager with default values.
175start_link() ->
176    start_link(simple_conf()).
177
178%% This function is normally not used. Instead the manager is
179%% started as a consequence of a call to application:start(snmp)
180%% when {snmp, [{manager, Options}]} is present in the
181%% node config file.
182start_link(Opts) ->
183    %% This start the manager top supervisor, which in turn
184    %% starts the other processes.
185    {ok, _} = snmpm_supervisor:start_link(normal, Opts),
186    ok.
187
188%% Simple start. Start a manager with default values.
189start() ->
190    start(simple_conf()).
191
192start(Opts) ->
193    %% This start the manager top supervisor, which in turn
194    %% starts the other processes.
195    {ok, Pid} = snmpm_supervisor:start_link(normal, Opts),
196    unlink(Pid),
197    ok.
198
199stop() ->
200    stop(0).
201
202stop(Timeout) when (Timeout =:= infinity) orelse
203                   (is_integer(Timeout) andalso (Timeout >= 0)) ->
204    snmpm_supervisor:stop(Timeout).
205
206
207
208monitor() ->
209    erlang:monitor(process, snmpm_supervisor).
210
211demonitor(Ref) ->
212    erlang:demonitor(Ref).
213
214
215-define(NOTIFY_START_TICK_TIME, 500).
216
217notify_started(To) when is_integer(To) andalso (To > 0) ->
218    spawn_link(?MODULE, snmpm_start_verify, [self(), To]).
219
220cancel_notify_started(Pid) ->
221    Pid ! {cancel, self()},
222    ok.
223
224snmpm_start_verify(Parent, To) ->
225    ?d("starting", []),
226    snmpm_start_verify(Parent, monitor(), To).
227
228snmpm_start_verify(Parent, _Ref, To) when (To =< 0) ->
229    ?d("timeout", []),
230    unlink(Parent),
231    Parent ! {snmpm_start_timeout, self()};
232snmpm_start_verify(Parent, Ref, To) ->
233    T0 = t(),
234    receive
235	{cancel, Parent} ->
236	    ?d("cancel", []),
237	    demonitor(Ref),
238	    unlink(Parent),
239	    exit(normal);
240	{'EXIT', Parent, _} ->
241	    exit(normal);
242	{'DOWN', Ref, process, _Object, _Info} ->
243	    ?d("down", []),
244	    sleep(?NOTIFY_START_TICK_TIME),
245	    ?MODULE:snmpm_start_verify(Parent, monitor(), t(T0, To))
246    after ?NOTIFY_START_TICK_TIME ->
247	    ?d("down timeout", []),
248	    demonitor(Ref),
249	    case snmpm_server:is_started() of
250		true ->
251		    unlink(Parent),
252		    Parent ! {snmpm_started, self()};
253		_ ->
254		    ?MODULE:snmpm_start_verify(Parent, monitor(), t(T0, To))
255	    end
256    end.
257
258t(T0, T)  -> T - (t() - T0).
259t()       -> snmp_misc:now(ms).
260sleep(To) -> snmp_misc:sleep(To).
261
262
263%% -- Misc --
264
265backup(BackupDir) ->
266    snmpm_config:backup(BackupDir).
267
268
269%% -- Mibs --
270
271%% Load a mib into the manager
272load_mib(MibFile) ->
273    snmpm_server:load_mib(MibFile).
274
275%% Unload a mib from the manager
276unload_mib(Mib) ->
277    snmpm_server:unload_mib(Mib).
278
279%% Which mib's are loaded
280which_mibs() ->
281    snmpm_config:which_mibs().
282
283%% Get all the possible oid's for the aliasname
284name_to_oid(Name) ->
285    snmpm_config:name_to_oid(Name).
286
287%% Get the aliasname for an oid
288oid_to_name(Oid) ->
289    snmpm_config:oid_to_name(Oid).
290
291%% Get the type for an oid
292oid_to_type(Oid) ->
293    snmpm_config:oid_to_type(Oid).
294
295
296%% -- Info --
297
298info() ->
299    snmpm_server:info().
300
301info(Key) ->
302    proplists:get_value(Key, info(), {error, not_found}).
303
304
305%% -- Verbosity --
306
307%% Change the verbosity of a process in the manager
308verbosity(config, V) ->
309    snmpm_config:verbosity(V);
310verbosity(server, V) ->
311    snmpm_server:verbosity(V);
312verbosity(net_if, V) ->
313    snmpm_server:verbosity(net_if, V);
314verbosity(note_store, V) ->
315    snmpm_server:verbosity(note_store, V);
316verbosity(all, V) ->
317    snmpm_config:verbosity(V),
318    snmpm_server:verbosity(V),
319    snmpm_server:verbosity(net_if, V),
320    snmpm_server:verbosity(note_store, V).
321
322
323%% -- Restart --
324
325%% Restart various component processes in the manager
326%% Note that the effects of this is diffiult to
327%% predict, so it should be use with *caution*!
328
329restart(net_if = What) ->
330    snmpm_server:restart(What).
331
332
333%% -- Users --
334
335%% Register the 'user'.
336%% The manager entity responsible for a specific agent.
337%% Module is the callback module (snmpm_user behaviour) which
338%% will be called whenever something happens (detected
339%% agent, incomming reply or incomming trap/notification).
340%% Note that this could have already been done as a
341%% consequence of the node config.
342register_user(Id, Module, Data) ->
343    register_user(Id, Module, Data, []).
344
345%% Default config for agents registered by this user
346register_user(Id, Module, Data, DefaultAgentConfig) ->
347    snmpm_server:register_user(Id, Module, Data, DefaultAgentConfig).
348
349register_user_monitor(Id, Module, Data) ->
350    register_user_monitor(Id, Module, Data, []).
351
352register_user_monitor(Id, Module, Data, DefaultAgentConfig) ->
353    snmpm_server:register_user_monitor(Id, Module, Data, DefaultAgentConfig).
354
355unregister_user(Id) ->
356    snmpm_server:unregister_user(Id).
357
358which_users() ->
359    snmpm_config:which_users().
360
361
362%% -- Agents --
363
364%% Explicitly instruct the manager to handle this agent.
365%% Called to instruct the manager that this agent
366%% shall be handled. These functions is used when
367%% the user know's in advance which agents the
368%% manager shall handle.
369%% Note that there is an alternate way to do the same thing:
370%% Add the agent to the manager config files.
371%%
372%% UserId     -> Id of the user responsible for this agent: term()
373%% TargetName -> Unique name for the agent: (string())
374%% Config     -> Agent configuration: [config()]
375
376do_register_agent(UserId, TargetName, Config) ->
377    snmpm_config:register_agent(UserId, TargetName, Config).
378
379register_agent(UserId, TargetName, Config)
380  when (is_list(TargetName) andalso
381	(length(TargetName) > 0) andalso
382	is_list(Config)) ->
383    do_register_agent(UserId, TargetName, [{reg_type, target_name} | Config]);
384
385%% Backward compatibility
386%% Note that the agent engine id is a mandatory config option,
387%% so this function *will* fail!
388register_agent(UserId, Addr, Port) when is_integer(Port) ->
389    register_agent(UserId, Addr, Port, []);
390
391%% Backward compatibility
392register_agent(UserId, Addr, Config) when is_list(Config) ->
393    register_agent(UserId, Addr, ?DEFAULT_AGENT_PORT, Config).
394
395%% Backward compatibility
396%% Note that the agent engine id is a mandatory config option,
397%% so this function *will* fail!
398register_agent(UserId, Addr) ->
399    register_agent(UserId, Addr, ?DEFAULT_AGENT_PORT, []).
400
401%% Backward compatibility
402register_agent(UserId, Domain, Addr, Config0) when is_atom(Domain) ->
403    case lists:keymember(target_name, 1, Config0) of
404	false ->
405	    TargetName = mk_target_name(Domain, Addr, Config0),
406	    Config =
407		[{reg_type, addr_port},
408		 {tdomain, Domain}, {taddress, Addr} | Config0],
409	    do_register_agent(UserId, TargetName, ensure_engine_id(Config));
410	true ->
411	    {value, {_, TargetName}} =
412		lists:keysearch(target_name, 1, Config0),
413	    Config1 = lists:keydelete(target_name, 1, Config0),
414	    Config2 =
415		[{reg_type, addr_port},
416		 {tdomain, Domain}, {taddress, Addr} | Config1],
417	    register_agent(UserId, TargetName, ensure_engine_id(Config2))
418    end;
419register_agent(UserId, Ip, Port, Config) when is_integer(Port) ->
420    Domain = snmpm_config:default_transport_domain(),
421    Addr =
422	case snmp_conf:check_address(Domain, {Ip, Port}) of
423	    ok ->
424		{Ip, Port};
425	    {ok, FixedAddr} ->
426		FixedAddr
427	end,
428    register_agent(UserId, Domain, Addr, Config).
429
430unregister_agent(UserId, TargetName) when is_list(TargetName) ->
431    snmpm_config:unregister_agent(UserId, TargetName);
432
433%% Backward compatibility functions
434unregister_agent(UserId, Addr) ->
435    unregister_agent(UserId, Addr, ?DEFAULT_AGENT_PORT).
436
437unregister_agent(UserId, DomainIp, AddressPort) ->
438    case target_name(DomainIp, AddressPort) of
439	{ok, TargetName} ->
440	    unregister_agent(UserId, TargetName);
441	Error ->
442	    Error
443    end.
444
445
446agent_info(TargetName, Item) ->
447    snmpm_config:agent_info(TargetName, Item).
448
449update_agent_info(UserId, TargetName, Info) when is_list(Info) ->
450    snmpm_config:update_agent_info(UserId, TargetName, Info).
451
452update_agent_info(UserId, TargetName, Item, Val) ->
453    update_agent_info(UserId, TargetName, [{Item, Val}]).
454
455
456which_agents() ->
457    snmpm_config:which_agents().
458
459which_agents(UserId) ->
460    snmpm_config:which_agents(UserId).
461
462
463%% -- USM users --
464
465register_usm_user(EngineID, UserName, Conf)
466  when is_list(EngineID) andalso is_list(UserName) andalso is_list(Conf) ->
467    snmpm_config:register_usm_user(EngineID, UserName, Conf).
468
469unregister_usm_user(EngineID, UserName)
470  when is_list(EngineID) andalso is_list(UserName) ->
471    snmpm_config:unregister_usm_user(EngineID, UserName).
472
473usm_user_info(EngineID, UserName, Item)
474  when is_list(EngineID) andalso is_list(UserName) andalso is_atom(Item) ->
475    snmpm_config:usm_user_info(EngineID, UserName, Item).
476
477update_usm_user_info(EngineID, UserName, Item, Val)
478  when is_list(EngineID) andalso is_list(UserName) andalso is_atom(Item) ->
479    snmpm_config:update_usm_user_info(EngineID, UserName, Item, Val).
480
481which_usm_users() ->
482    snmpm_config:which_usm_users().
483
484which_usm_users(EngineID) when is_list(EngineID) ->
485    snmpm_config:which_usm_users(EngineID).
486
487
488%% -- Discovery --
489
490%% Start a discovery process
491%% discovery(UserId, BAddr) ->
492%%     snmpm_server:discovery(UserId, BAddr).
493
494%% discovery(UserId, BAddr, ExpireOrConfig) ->
495%%     snmpm_server:discovery(UserId, BAddr, ExpireOrConfig).
496
497%% discovery(UserId, BAddr, Config, Expire) ->
498%%     snmpm_server:discovery(UserId, BAddr, Config, Expire).
499
500%% discovery(UserId, BAddr, Port, Config, Expire) ->
501%%     snmpm_server:discovery(UserId, BAddr, Port, Config, Expire).
502
503%% discovery(UserId, BAddr, Port, Config, Expire, ExtraInfo) ->
504%%     snmpm_server:discovery(UserId, BAddr, Port, Config, Expire, ExtraInfo).
505
506
507%% -- Requests --
508
509%% --- synchroneous get-request ---
510%%
511
512sync_get2(UserId, TargetName, Oids) ->
513    sync_get2(UserId, TargetName, Oids, []).
514
515sync_get2(UserId, TargetName, Oids, SendOpts)
516  when is_list(Oids) andalso is_list(SendOpts) ->
517    snmpm_server:sync_get2(UserId, TargetName, Oids, SendOpts).
518
519%% <BACKWARD-COMPAT>
520sync_get(UserId, TargetName, Oids) ->
521    sync_get2(UserId, TargetName, Oids).
522
523sync_get(UserId, TargetName, Oids, Timeout)
524  when is_list(Oids) andalso is_integer(Timeout) ->
525    SendOpts = [{timeout, Timeout}],
526    sync_get2(UserId, TargetName, Oids, SendOpts);
527sync_get(UserId, TargetName, Context, [OH|_] = Oids)
528  when is_list(Context) andalso is_list(OH) ->
529    SendOpts = [{context, Context}],
530    sync_get2(UserId, TargetName, Oids, SendOpts).
531
532sync_get(UserId, TargetName, Context, Oids, Timeout) ->
533    SendOpts = [{context, Context}, {timeout, Timeout}],
534    sync_get2(UserId, TargetName, Oids, SendOpts).
535
536sync_get(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
537    SendOpts = [{context, Context}, {timeout, Timeout}, {extra, ExtraInfo}],
538    sync_get2(UserId, TargetName, Oids, SendOpts).
539%% </BACKWARD-COMPAT>
540
541
542
543%% --- asynchronous get-request ---
544%%
545%% The reply will be delivered to the user
546%% through a call to handle_pdu/5
547%%
548
549async_get2(UserId, TargetName, Oids) ->
550    async_get2(UserId, TargetName, Oids, []).
551
552async_get2(UserId, TargetName, Oids, SendOpts)
553  when is_list(Oids) andalso is_list(SendOpts) ->
554    snmpm_server:async_get2(UserId, TargetName, Oids, SendOpts).
555
556%% <BACKWARD-COMPAT>
557async_get(UserId, TargetName, Oids) ->
558    async_get2(UserId, TargetName, Oids).
559
560async_get(UserId, TargetName, Oids, Expire) when is_integer(Expire) ->
561    SendOpts = [{timeout, Expire}],
562    async_get2(UserId, TargetName, Oids, SendOpts);
563async_get(UserId, TargetName, Context, Oids)
564  when is_list(Context) andalso is_list(Oids) ->
565    SendOpts = [{context, Context}],
566    async_get2(UserId, TargetName, Oids, SendOpts).
567
568async_get(UserId, TargetName, Context, Oids, Expire) ->
569    SendOpts = [{timeout, Expire}, {context, Context}],
570    async_get2(UserId, TargetName, Oids, SendOpts).
571
572async_get(UserId, TargetName, Context, Oids, Expire, ExtraInfo) ->
573    SendOpts = [{timeout, Expire}, {context, Context}, {extra, ExtraInfo}],
574    async_get2(UserId, TargetName, Oids, SendOpts).
575%% </BACKWARD-COMPAT>
576
577
578%% --- synchroneous get_next-request ---
579%%
580
581sync_get_next2(UserId, TargetName, Oids) ->
582    sync_get_next2(UserId, TargetName, Oids, []).
583
584sync_get_next2(UserId, TargetName, Oids, SendOpts)
585  when is_list(Oids) andalso is_list(SendOpts) ->
586    snmpm_server:sync_get_next2(UserId, TargetName, Oids, SendOpts).
587
588%% <BACKWARD-COMPAT>
589sync_get_next(UserId, TargetName, Oids) ->
590    sync_get_next2(UserId, TargetName, Oids).
591
592sync_get_next(UserId, TargetName, Oids, Timeout)
593  when is_list(Oids) andalso is_integer(Timeout) ->
594    SendOpts = [{timeout, Timeout}],
595    sync_get_next2(UserId, TargetName, Oids, SendOpts);
596sync_get_next(UserId, TargetName, Context, Oids)
597  when is_list(Context) andalso is_list(Oids) ->
598    SendOpts = [{context, Context}],
599    sync_get_next2(UserId, TargetName, Oids, SendOpts).
600
601sync_get_next(UserId, TargetName, Context, Oids, Timeout) ->
602    SendOpts = [{timeout, Timeout}, {context, Context}],
603    sync_get_next2(UserId, TargetName, Oids, SendOpts).
604
605sync_get_next(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
606    SendOpts = [{timeout, Timeout}, {context, Context}, {extra, ExtraInfo}],
607    sync_get_next2(UserId, TargetName, Oids, SendOpts).
608%% </BACKWARD-COMPAT>
609
610
611%% --- asynchronous get_next-request ---
612%%
613
614async_get_next2(UserId, TargetName, Oids) ->
615    async_get_next2(UserId, TargetName, Oids, []).
616
617async_get_next2(UserId, TargetName, Oids, SendOpts)
618  when is_list(Oids) andalso is_list(SendOpts) ->
619    snmpm_server:async_get_next2(UserId, TargetName, Oids, SendOpts).
620
621%% <BACKWARD-COMPAT>
622async_get_next(UserId, TargetName, Oids) ->
623    async_get_next2(UserId, TargetName, Oids).
624
625async_get_next(UserId, TargetName, Oids, Expire)
626  when is_list(Oids) andalso is_integer(Expire) ->
627    SendOpts = [{timeout, Expire}],
628    async_get_next2(UserId, TargetName, Oids, SendOpts);
629async_get_next(UserId, TargetName, Context, Oids)
630  when is_list(Context) andalso is_list(Oids) ->
631    SendOpts = [{context, Context}],
632    async_get_next2(UserId, TargetName, Oids, SendOpts).
633
634async_get_next(UserId, TargetName, Context, Oids, Expire) ->
635    SendOpts = [{timeout, Expire}, {context, Context}],
636    async_get_next2(UserId, TargetName, Oids, SendOpts).
637
638async_get_next(UserId, TargetName, Context, Oids, Expire, ExtraInfo) ->
639    SendOpts = [{timeout, Expire}, {context, Context}, {extra, ExtraInfo}],
640    async_get_next2(UserId, TargetName, Oids, SendOpts).
641%% </BACKWARD-COMPAT>
642
643
644%% --- synchroneous set-request ---
645%%
646
647sync_set2(UserId, TargetName, VarsAndVals) ->
648    sync_set2(UserId, TargetName, VarsAndVals, []).
649
650sync_set2(UserId, TargetName, VarsAndVals, SendOpts)
651  when is_list(VarsAndVals) andalso is_list(SendOpts) ->
652    snmpm_server:sync_set2(UserId, TargetName, VarsAndVals, SendOpts).
653
654%% <BACKWARD-COMPAT>
655sync_set(UserId, TargetName, VarsAndVals) ->
656    sync_set2(UserId, TargetName, VarsAndVals).
657
658sync_set(UserId, TargetName, VarsAndVals, Timeout)
659  when is_list(VarsAndVals) andalso is_integer(Timeout) ->
660    SendOpts = [{timeout, Timeout}],
661    sync_set2(UserId, TargetName, VarsAndVals, SendOpts);
662sync_set(UserId, TargetName, Context, VarsAndVals)
663  when is_list(Context) andalso is_list(VarsAndVals) ->
664    SendOpts = [{context, Context}],
665    sync_set2(UserId, TargetName, VarsAndVals, SendOpts).
666
667sync_set(UserId, TargetName, Context, VarsAndVals, Timeout) ->
668    SendOpts = [{timeout, Timeout}, {context, Context}],
669    sync_set2(UserId, TargetName, VarsAndVals, SendOpts).
670
671sync_set(UserId, TargetName, Context, VarsAndVals, Timeout, ExtraInfo) ->
672    SendOpts = [{timeout, Timeout}, {context, Context}, {extra, ExtraInfo}],
673    sync_set2(UserId, TargetName, VarsAndVals, SendOpts).
674%% </BACKWARD-COMPAT>
675
676
677%% --- asynchronous set-request ---
678%%
679
680async_set2(UserId, TargetName, VarsAndVals) ->
681    async_set2(UserId, TargetName, VarsAndVals, []).
682
683async_set2(UserId, TargetName, VarsAndVals, SendOpts)
684  when is_list(VarsAndVals) andalso is_list(SendOpts) ->
685    snmpm_server:async_set2(UserId, TargetName, VarsAndVals, SendOpts).
686
687%% <BACKWARD-COMPAT>
688async_set(UserId, TargetName, VarsAndVals) ->
689    async_set2(UserId, TargetName, VarsAndVals).
690
691async_set(UserId, TargetName, VarsAndVals, Expire)
692  when is_list(VarsAndVals) andalso is_integer(Expire) ->
693    SendOpts = [{timeout, Expire}],
694    async_set2(UserId, TargetName, VarsAndVals, SendOpts);
695async_set(UserId, TargetName, Context, VarsAndVals)
696  when is_list(Context) andalso is_list(VarsAndVals) ->
697    SendOpts = [{context, Context}],
698    async_set2(UserId, TargetName, VarsAndVals, SendOpts).
699
700async_set(UserId, TargetName, Context, VarsAndVals, Expire) ->
701    SendOpts = [{timeout, Expire}, {context, Context}],
702    async_set2(UserId, TargetName, VarsAndVals, SendOpts).
703
704async_set(UserId, TargetName, Context, VarsAndVals, Expire, ExtraInfo) ->
705    SendOpts = [{timeout, Expire}, {context, Context}, {extra, ExtraInfo}],
706    async_set2(UserId, TargetName, VarsAndVals, SendOpts).
707%% </BACKWARD-COMPAT>
708
709
710%% --- synchroneous get-bulk ---
711%%
712
713sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) ->
714    sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, []).
715
716sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts)
717  when is_integer(NonRep) andalso
718       is_integer(MaxRep) andalso
719       is_list(Oids) andalso
720       is_list(SendOpts) ->
721    %% p("sync_get_bulk -> entry with"
722    %%   "~n   UserId:     ~p"
723    %%   "~n   TargetName: ~p"
724    %%   "~n   NonRep:     ~p"
725    %%   "~n   MaxRep:     ~p"
726    %%   "~n   Oids:       ~p"
727    %%   "~n   SendOpts:   ~p",
728    %%   [UserId, TargetName, NonRep, MaxRep, Oids, SendOpts]),
729    snmpm_server:sync_get_bulk2(UserId, TargetName,
730				NonRep, MaxRep, Oids, SendOpts).
731
732%% <BACKWARD-COMPAT>
733sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) ->
734    sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids).
735
736sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Timeout)
737  when is_integer(NonRep) andalso
738       is_integer(MaxRep) andalso
739       is_list(Oids) andalso
740       is_integer(Timeout) ->
741    SendOpts = [{timeout, Timeout}],
742    sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts);
743sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids)
744  when is_integer(NonRep) andalso
745       is_integer(MaxRep) andalso
746       is_list(Context) andalso
747       is_list(Oids) ->
748    %% p("sync_get_bulk -> entry with"
749    %%   "~n   UserId: ~p"
750    %%   "~n   TargetName: ~p"
751    %%   "~n   NonRep: ~p"
752    %%   "~n   MaxRep: ~p"
753    %%   "~n   Context: ~p"
754    %%   "~n   Oids: ~p", [UserId, TargetName, NonRep, MaxRep, Context, Oids]),
755    SendOpts = [{context, Context}],
756    sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts).
757
758sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Timeout) ->
759    SendOpts = [{timeout, Timeout}, {context, Context}],
760    sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts).
761
762sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Timeout,
763	      ExtraInfo) ->
764    SendOpts = [{timeout, Timeout}, {context, Context}, {extra, ExtraInfo}],
765    sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts).
766%% </BACKWARD-COMPAT>
767
768
769%% --- asynchronous get-bulk ---
770%%
771
772async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) ->
773    async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, []).
774
775async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts)
776  when is_integer(NonRep) andalso
777       is_integer(MaxRep) andalso
778       is_list(Oids) andalso
779       is_list(SendOpts) ->
780    snmpm_server:async_get_bulk2(UserId, TargetName,
781				 NonRep, MaxRep, Oids, SendOpts).
782
783%% <BACKWARD-COMPAT>
784async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) ->
785    async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids).
786
787async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Expire)
788  when is_integer(NonRep) andalso
789       is_integer(MaxRep) andalso
790       is_list(Oids) andalso
791       is_integer(Expire) ->
792    SendOpts = [{timeout, Expire}],
793    async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts);
794async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids)
795  when is_integer(NonRep) andalso
796       is_integer(MaxRep) andalso
797       is_list(Context) andalso
798       is_list(Oids) ->
799    SendOpts = [{context, Context}],
800    async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts).
801
802async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Expire) ->
803    SendOpts = [{timeout, Expire}, {context, Context}],
804    async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts).
805
806async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Expire,
807	       ExtraInfo) ->
808    SendOpts = [{timeout, Expire}, {context, Context}, {extra, ExtraInfo}],
809    async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts).
810%% </BACKWARD-COMPAT>
811
812
813
814cancel_async_request(UserId, ReqId) ->
815    snmpm_server:cancel_async_request(UserId, ReqId).
816
817
818%%%-----------------------------------------------------------------
819%%% Audit Trail Log functions (for backward compatibility)
820%%%-----------------------------------------------------------------
821
822-spec log_to_txt(LogDir :: snmp:dir()) ->
823    snmp:void().
824
825log_to_txt(LogDir) ->
826    log_to_txt(LogDir, []).
827
828-spec log_to_txt(LogDir :: snmp:dir(),
829		 Block  :: boolean()) ->
830    snmp:void();
831                (LogDir :: snmp:dir(),
832		 Mibs   :: [snmp:mib_name()]) ->
833    snmp:void().
834
835log_to_txt(LogDir, Block)
836  when ((Block =:= true) orelse (Block =:= false)) ->
837    Mibs    = [],
838    OutFile = "snmpm_log.txt",
839    LogName = ?audit_trail_log_name,
840    LogFile = ?audit_trail_log_file,
841    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
842log_to_txt(LogDir, Mibs) ->
843    Block   = ?ATL_BLOCK_DEFAULT,
844    OutFile = "snmpm_log.txt",
845    LogName = ?audit_trail_log_name,
846    LogFile = ?audit_trail_log_file,
847    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
848
849-spec log_to_txt(LogDir :: snmp:dir(),
850		 Mibs   :: [snmp:mib_name()],
851		 Block  :: boolean()) ->
852    snmp:void();
853                (LogDir  :: snmp:dir(),
854		 Mibs    :: [snmp:mib_name()],
855		 OutFile :: file:filename()) ->
856    snmp:void().
857
858log_to_txt(LogDir, Mibs, Block)
859  when ((Block =:= true) orelse (Block =:= false)) ->
860    OutFile = "snmpm_log.txt",
861    LogName = ?audit_trail_log_name,
862    LogFile = ?audit_trail_log_file,
863    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
864log_to_txt(LogDir, Mibs, OutFile) ->
865    Block   = ?ATL_BLOCK_DEFAULT,
866    LogName = ?audit_trail_log_name,
867    LogFile = ?audit_trail_log_file,
868    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
869
870-spec log_to_txt(LogDir  :: snmp:dir(),
871		 Mibs    :: [snmp:mib_name()],
872		 OutFile :: file:filename(),
873		 Block   :: boolean()) ->
874    snmp:void();
875                (LogDir  :: snmp:dir(),
876		 Mibs    :: [snmp:mib_name()],
877		 OutFile :: file:filename(),
878		 LogName :: string()) ->
879    snmp:void().
880
881log_to_txt(LogDir, Mibs, OutFile, Block)
882  when ((Block =:= true) orelse (Block =:= false)) ->
883    LogName = ?audit_trail_log_name,
884    LogFile = ?audit_trail_log_file,
885    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
886log_to_txt(LogDir, Mibs, OutFile, LogName) ->
887    Block   = ?ATL_BLOCK_DEFAULT,
888    LogFile = ?audit_trail_log_file,
889    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
890
891-spec log_to_txt(LogDir  :: snmp:dir(),
892		 Mibs    :: [snmp:mib_name()],
893		 OutFile :: file:filename(),
894		 LogName :: string(),
895		 Block   :: boolean()) ->
896    snmp:void();
897                (LogDir  :: snmp:dir(),
898		 Mibs    :: [snmp:mib_name()],
899		 OutFile :: file:filename(),
900		 LogName :: string(),
901		 LogFile :: string()) ->
902    snmp:void().
903
904log_to_txt(LogDir, Mibs, OutFile, LogName, Block)
905  when ((Block =:= true) orelse (Block =:= false)) ->
906    LogFile = ?audit_trail_log_file,
907    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
908log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) ->
909    Block = ?ATL_BLOCK_DEFAULT,
910    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block).
911
912-spec log_to_txt(LogDir  :: snmp:dir(),
913		 Mibs    :: [snmp:mib_name()],
914		 OutFile :: file:filename(),
915		 LogName :: string(),
916		 LogFile :: string(),
917		 Block   :: boolean()) ->
918    snmp:void();
919                (LogDir  :: snmp:dir(),
920		 Mibs    :: [snmp:mib_name()],
921		 OutFile :: file:filename(),
922		 LogName :: string(),
923		 LogFile :: string(),
924		 Start   :: snmp_log:log_time()) ->
925    snmp:void().
926
927log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block)
928  when ((Block =:= true) orelse (Block =:= false)) ->
929    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block);
930log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) ->
931    Block = ?ATL_BLOCK_DEFAULT,
932    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start).
933
934-spec log_to_txt(LogDir  :: snmp:dir(),
935		 Mibs    :: [snmp:mib_name()],
936		 OutFile :: file:filename(),
937		 LogName :: string(),
938		 LogFile :: string(),
939		 Block   :: boolean(),
940		 Start   :: snmp_log:log_time()) ->
941    snmp:void();
942                (LogDir  :: snmp:dir(),
943		 Mibs    :: [snmp:mib_name()],
944		 OutFile :: file:filename(),
945		 LogName :: string(),
946		 LogFile :: string(),
947		 Start   :: snmp_log:log_time(),
948		 Stop    :: snmp_log:log_time()) ->
949    snmp:void().
950
951log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start)
952  when ((Block =:= true) orelse (Block =:= false)) ->
953    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start);
954log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) ->
955    Block = ?ATL_BLOCK_DEFAULT,
956    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
957
958-spec log_to_txt(LogDir  :: snmp:dir(),
959		 Mibs    :: [snmp:mib_name()],
960		 OutFile :: file:filename(),
961		 LogName :: string(),
962		 LogFile :: string(),
963		 Block   :: boolean(),
964		 Start   :: snmp_log:log_time(),
965		 Stop    :: snmp_log:log_time()) ->
966    snmp:void().
967
968log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) ->
969    snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
970
971
972log_to_io(LogDir) ->
973    log_to_io(LogDir, []).
974
975log_to_io(LogDir, Block)
976  when ((Block =:= true) orelse (Block =:= false)) ->
977    Mibs    = [],
978    LogName = ?audit_trail_log_name,
979    LogFile = ?audit_trail_log_file,
980    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
981log_to_io(LogDir, Mibs) ->
982    LogName = ?audit_trail_log_name,
983    LogFile = ?audit_trail_log_file,
984    snmp:log_to_io(LogDir, Mibs, LogName, LogFile).
985
986log_to_io(LogDir, Mibs, Block)
987  when ((Block =:= true) orelse (Block =:= false)) ->
988    LogName = ?audit_trail_log_name,
989    LogFile = ?audit_trail_log_file,
990    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
991log_to_io(LogDir, Mibs, LogName) ->
992    Block   = ?ATL_BLOCK_DEFAULT,
993    LogFile = ?audit_trail_log_file,
994    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block).
995
996log_to_io(LogDir, Mibs, LogName, Block)
997  when ((Block =:= true) orelse (Block =:= false)) ->
998    LogFile = ?audit_trail_log_file,
999    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
1000log_to_io(LogDir, Mibs, LogName, LogFile) ->
1001    Block = ?ATL_BLOCK_DEFAULT,
1002    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block).
1003
1004log_to_io(LogDir, Mibs, LogName, LogFile, Block)
1005  when ((Block =:= true) orelse (Block =:= false)) ->
1006    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block);
1007log_to_io(LogDir, Mibs, LogName, LogFile, Start) ->
1008    Block = ?ATL_BLOCK_DEFAULT,
1009    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start).
1010
1011log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start)
1012  when ((Block =:= true) orelse (Block =:= false)) ->
1013    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start);
1014log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) ->
1015    Block = ?ATL_BLOCK_DEFAULT,
1016    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
1017
1018log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) ->
1019    snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
1020
1021
1022change_log_size(NewSize) ->
1023    LogName = ?audit_trail_log_name,
1024    snmp:change_log_size(LogName, NewSize).
1025
1026
1027get_log_type() ->
1028    snmpm_server:get_log_type().
1029
1030%% NewType -> atl_type()
1031set_log_type(NewType) ->
1032    snmpm_server:set_log_type(NewType).
1033
1034
1035reconfigure() ->
1036    snmpm_server:reconfigure().
1037
1038
1039%%%-----------------------------------------------------------------
1040
1041system_start_time() ->
1042    {ok, Time} = snmpm_config:system_start_time(),
1043    Time.
1044
1045sys_up_time() ->
1046    % time in 0.01 seconds.
1047    StartTime = system_start_time(),
1048    (snmp_misc:now(cs) - StartTime) rem (2 bsl 31).
1049
1050
1051%%%-----------------------------------------------------------------
1052%%% This is just some simple utility functions to create a pretty-
1053%%% printable string of the error reason received from either:
1054%%%
1055%%%    * If any of the sync/async get/get-next/set/get-bulk
1056%%%      returnes {error, Reason}
1057%%%    * The Reason parameter in the handle_error user callback
1058%%%      function
1059%%%
1060%%%-----------------------------------------------------------------
1061
1062format_reason(Reason) ->
1063    format_reason("", Reason).
1064
1065format_reason(Prefix, Reason) when is_integer(Prefix) andalso (Prefix >= 0) ->
1066    format_reason(lists:duplicate(Prefix, $ ), Reason);
1067format_reason(Prefix, Reason) when is_list(Prefix) ->
1068    case (catch do_format_reason(Prefix, Reason)) of
1069	FL when is_list(FL) ->
1070	    FL;
1071	_ ->
1072	    %% Crap, try it without any fancy formatting
1073	    case (catch io_lib:format("~sInternal manager error: ~n"
1074				      "~s   ~p~n",
1075				      [Prefix, Prefix, Reason])) of
1076		L1 when is_list(L1) ->
1077		    lists:flatten(L1);
1078		_ ->
1079		    %% Really crap, try it without the prefix
1080		    case (catch io_lib:format("Internal manager error: ~n"
1081					      "   ~p~n",
1082					      [Reason])) of
1083			L2 when is_list(L2) ->
1084			    lists:flatten(L2);
1085			_ ->
1086			    %% Ok, I give up
1087			    "Illegal input. Unable to format error reason"
1088		    end
1089	    end
1090    end.
1091
1092
1093do_format_reason(Prefix, {failed_generating_response, {RePdu, Reason}}) ->
1094    FmtPdu = format_pdu(Prefix ++ "   ", RePdu),
1095    lists:flatten(io_lib:format("~sFailed generating response: ~n"
1096				"~s"
1097				"~s   ~p~n",
1098				[Prefix, FmtPdu, Prefix, Reason]));
1099do_format_reason(Prefix, {failed_processing_message, Reason})  ->
1100    lists:flatten(io_lib:format("~sFailed processing message: ~n"
1101				"~s   ~p~n",
1102				[Prefix, Prefix, Reason]));
1103do_format_reason(Prefix, {unexpected_pdu, SnmpInfo})  ->
1104    FmtSnmpInfo = format_snmp_info(Prefix ++ "   ", SnmpInfo),
1105    lists:flatten(io_lib:format("~sUnexpected PDU: ~n~s",
1106				[Prefix, FmtSnmpInfo]));
1107do_format_reason(Prefix, {send_failed, ReqId, Reason})  ->
1108    lists:flatten(io_lib:format("~sSend failed: ~n"
1109				"~s   Request id: ~w~n"
1110				"~s   Reason:     ~p~n",
1111				[Prefix, Prefix, ReqId, Prefix, Reason]));
1112do_format_reason(Prefix, {invalid_sec_info, SecInfo, SnmpInfo})  ->
1113    FmtSecInfo  = format_sec_info(Prefix ++ "   ", SecInfo),
1114    FmtSnmpInfo = format_snmp_info(Prefix ++ "   ", SnmpInfo),
1115    lists:flatten(io_lib:format("~sInvalid security info: ~n"
1116				"~s"
1117				"~s",
1118				[Prefix, FmtSecInfo, FmtSnmpInfo]));
1119do_format_reason(Prefix, Reason)  ->
1120    lists:flatten(io_lib:format("~sInternal manager error: ~n"
1121				"~s   ~p~n", [Prefix, Prefix, Reason])).
1122
1123format_pdu(Prefix, #pdu{type         = Type,
1124			request_id   = ReqId,
1125			error_status = ES,
1126			error_index  = EI,
1127			varbinds     = VBs}) ->
1128    FmtPdyType   = format_pdu_type(Type),
1129    FmtErrStatus = format_error_status(ES),
1130    FmtErrIdx    = format_error_index(EI),
1131    FmtVBs       = format_varbinds(Prefix ++ "   ", VBs),
1132    lists:flatten(io_lib:format("~s~s: ~n"
1133				"~s   Request-id:   ~w~n"
1134				"~s   Error-status: ~s~n"
1135				"~s   Error-index:  ~s~n"
1136				"~s",
1137				[Prefix, FmtPdyType,
1138				 Prefix, ReqId,
1139				 Prefix, FmtErrStatus,
1140				 Prefix, FmtErrIdx,
1141				 FmtVBs]));
1142format_pdu(Prefix, #trappdu{enterprise    = E,
1143			    agent_addr    = AA,
1144			    generic_trap  = GT,
1145			    specific_trap = ST,
1146			    time_stamp    = TS,
1147			    varbinds      = VBs}) ->
1148    FmtVBs = format_varbinds(Prefix ++ "   ", VBs),
1149    lists:flatten(io_lib:format("~sTrap PDU: ~n"
1150				"~s   Enterprise:    ~p~n"
1151				"~s   Agent address: ~p~n"
1152				"~s   Generic trap:  ~p~n"
1153				"~s   Specific trap: ~p~n"
1154				"~s   Time stamp:    ~p~n"
1155				"~s",
1156				[Prefix,
1157				 Prefix, E,
1158				 Prefix, AA,
1159				 Prefix, GT,
1160				 Prefix, ST,
1161				 Prefix, TS,
1162				 FmtVBs]));
1163format_pdu(Prefix, PDU) ->
1164    lists:flatten(io_lib:format("~s~p~n", [Prefix, PDU])).
1165
1166format_pdu_type('get-request') ->
1167    "GetRequest-PDU";
1168format_pdu_type('get-next-request') ->
1169    "GetNextRequest-PDU";
1170format_pdu_type('get-response') ->
1171    "Response-PDU";
1172format_pdu_type('set-request') ->
1173    "SetRequest-PDU";
1174format_pdu_type('get-bulk-request') ->
1175    "GetBulkRequest-PDU";
1176format_pdu_type('inform-request') ->
1177    "InformRequest-PDU";
1178format_pdu_type('snmpv2-trap') ->
1179    "SNMPv2-Trap-PDU";
1180format_pdu_type(report) ->
1181    "Report-PDU";
1182format_pdu_type(T) ->
1183    lists:flatten(io_lib:format("~p", [T])).
1184
1185format_snmp_info(Prefix, {ES, EI, VBs}) ->
1186    lists:flatten(io_lib:format("~sSNMP info: ~n"
1187				"~s   Error-status: ~s~n"
1188				"~s   Error-index:  ~s~n"
1189				"~s",
1190				[Prefix,
1191				 Prefix, format_error_status(ES),
1192				 Prefix, format_error_index(EI),
1193				 format_varbinds(Prefix ++ "   ", VBs)]));
1194format_snmp_info(Prefix, JunkSnmpInfo) ->
1195    lists:flatten(io_lib:format("~sJunk SNMP info: ~n"
1196				"~s   ~p~n",
1197				[Prefix, Prefix, JunkSnmpInfo])).
1198
1199format_error_status(ES) ->
1200    lists:flatten(io_lib:format("~p", [ES])).
1201
1202format_error_index(EI) ->
1203    lists:flatten(io_lib:format("~p", [EI])).
1204
1205format_sec_info(Prefix, Info) ->
1206    FmtSecInfo = do_format_sec_info(Prefix ++ "   ", Info),
1207    lists:flatten(io_lib:format("~sSecurity info: ~n~s",
1208				[Prefix, FmtSecInfo])).
1209
1210do_format_sec_info(_Prefix, []) ->
1211    "";
1212do_format_sec_info(Prefix, [{Tag, ExpVal, Val}|T]) ->
1213    format_sec_info(Prefix, Tag, ExpVal, Val) ++
1214	do_format_sec_info(Prefix, T).
1215
1216
1217format_sec_info(_Prefix, _Tag, Val, Val) ->
1218    "";
1219format_sec_info(Prefix, Tag, ExpVal, Val) ->
1220    lists:flatten(io_lib:format("~s~s:~n"
1221				"~s   Expected value: ~p~n"
1222				"~s   Actual value:   ~p~n",
1223				[Prefix, format_sec_info_tag(Tag),
1224				 Prefix, ExpVal,
1225				 Prefix, Val])).
1226
1227format_sec_info_tag(sec_engine_id) ->
1228    "Sec engine id";
1229format_sec_info_tag(msg_sec_model) ->
1230    "Msg sec model";
1231format_sec_info_tag(sec_name) ->
1232    "Sec name";
1233format_sec_info_tag(sec_level) ->
1234    "Sec level";
1235format_sec_info_tag(ctx_engine_id) ->
1236    "Context engine id";
1237format_sec_info_tag(ctx_name) ->
1238    "Context name";
1239format_sec_info_tag(request_id) ->
1240    "Request id";
1241format_sec_info_tag(T) ->
1242    lists:flatten(io_lib:format("~p", [T])).
1243
1244format_varbinds(Prefix, []) ->
1245    lists:flatten(io_lib:format("~sVarbinds:    []~n", [Prefix]));
1246format_varbinds(Prefix, VBs) when is_list(VBs) ->
1247    lists:flatten(io_lib:format("~sVarbinds: ~n~s",
1248				[Prefix, format_vbs(Prefix ++ "   ", VBs)]));
1249format_varbinds(Prefix, VBs) ->
1250    lists:flatten(io_lib:format("~sInvalid varbinds: ~n"
1251				"~s   ~p~n",
1252				[Prefix, Prefix, VBs])).
1253
1254format_vbs(_Prefix, []) ->
1255    "";
1256format_vbs(Prefix, [VB|VBs]) ->
1257    format_vb(Prefix, VB) ++ format_vbs(Prefix, VBs).
1258
1259format_vb(Prefix, #varbind{oid          = Oid0,
1260			   variabletype = Type,
1261			   value        = Val,
1262			   org_index    = Idx}) ->
1263    Oid =
1264	case snmpm:oid_to_name(Oid0) of
1265	    {ok, O} ->
1266		O;
1267	    _ ->
1268		Oid0
1269	end,
1270    FmtVT  = format_vb_variabletype(Prefix ++ "   ", Type),
1271    FmtVal = format_vb_value(Prefix ++ "   ", Type, Val),
1272    lists:flatten(io_lib:format("~s~w:~n"
1273				"~s"
1274				"~s"
1275				"~s   Org-index:     ~p~n",
1276				[Prefix, Oid,
1277				 FmtVT,
1278				 FmtVal,
1279				 Prefix, Idx]));
1280format_vb(Prefix, JunkVB) ->
1281    lists:flatten(io_lib:format("~sJunk varbind:~n"
1282				"~s   ~p~n", [Prefix, Prefix, JunkVB])).
1283
1284format_vb_variabletype(Prefix, Type) when is_atom(Type) ->
1285    lists:flatten(io_lib:format("~sVariable-type: ~s~n",
1286				[Prefix, atom_to_list(Type)]));
1287format_vb_variabletype(Prefix, Type) ->
1288    lists:flatten(io_lib:format("~sVariable-type: ~p~n", [Prefix, Type])).
1289
1290format_vb_value(Prefix, _Type, Val) ->
1291    lists:flatten(io_lib:format("~sValue:         ~p~n", [Prefix, Val])).
1292
1293
1294%% ---------------------------------------------------------------------------
1295%%
1296%% --- Internal utility functions ---
1297%%
1298
1299target_name(Ip) ->
1300    target_name(Ip, ?DEFAULT_AGENT_PORT).
1301
1302target_name(DomainIp, AddressPort) ->
1303    snmpm_config:agent_info(DomainIp, AddressPort, target_name).
1304
1305mk_target_name(Addr, Port, Config) ->
1306    R = snmpm_config:mk_target_name(Addr, Port, Config),
1307    p(?MODULE_STRING":mk_target_name(~p, ~p, ~p) -> ~p.~n",
1308      [Addr, Port, Config, R]),
1309    R.
1310
1311ensure_engine_id(Config) ->
1312    case lists:keymember(engine_id, 1, Config) of
1313	true ->
1314	    Config;
1315	false ->
1316	    DefaultEngineId = "agentEngine-default",
1317	    [{engine_id, DefaultEngineId} | Config]
1318    end.
1319
1320
1321
1322%% p(F) ->
1323%%     p(F, []).
1324
1325p(F, A) ->
1326    io:format("~w:" ++ F ++ "~n", [?MODULE | A]).
1327