1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2019. 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-module(snmp).
21
22
23%%----------------------------------------------------------------------
24%% This module contains the user interface to the snmp toolkit.
25%%----------------------------------------------------------------------
26
27%% Application exports
28-export([start/0, start/1, stop/0,
29	 start_agent/0,   start_agent/1,
30	 start_manager/0, start_manager/1,
31	 config/0,
32
33         versions1/0,      versions2/0,
34	 print_versions/1, print_versions/2,
35	 print_version_info/0, print_version_info/1,
36
37	 date_and_time/0,
38	 universal_time_to_date_and_time/1,
39	 local_time_to_date_and_time_dst/1,
40	 date_and_time_to_universal_time_dst/1,
41	 validate_date_and_time/1, validate_date_and_time/2,
42	 date_and_time_to_string/1, date_and_time_to_string/2,
43	 date_and_time_to_string2/1,
44
45	 str_apply/1,
46
47	 sys_up_time/1, system_start_time/1,
48
49         passwd2localized_key/3, localize_key/3,
50
51	 read_mib/1,
52
53	 log_to_txt/5, log_to_txt/6, log_to_txt/7, log_to_txt/8,
54	 log_to_io/4,  log_to_io/5,  log_to_io/6,  log_to_io/7,
55	 change_log_size/2,
56
57	 octet_string_to_bits/1, bits_to_octet_string/1,
58
59	 enable_trace/0, disable_trace/0,
60	 set_trace/1, reset_trace/1,
61	 set_trace/2, set_trace/3]).
62
63%% Compiler exports
64-export([c/1, c/2, is_consistent/1, mib_to_hrl/1,
65	 compile/3]).
66
67%% Agent exports (Dont use these, they will be removed eventually)
68-export([current_request_id/0, current_community/0, current_address/0,
69	 current_context/0, current_net_if_data/0,
70
71	 get_symbolic_store_db/0,
72	 name_to_oid/1, name_to_oid/2,
73	 oid_to_name/1, oid_to_name/2,
74	 int_to_enum/2, int_to_enum/3,
75	 enum_to_int/2, enum_to_int/3,
76
77	 get/2,
78	 info/1,
79	 load_mibs/2, unload_mibs/2, dump_mibs/0, dump_mibs/1,
80
81	 register_subagent/3, unregister_subagent/2,
82
83	 send_notification/3, send_notification/4, send_notification/5,
84	 send_notification/6,
85	 send_trap/3, send_trap/4,
86
87	 add_agent_caps/2, del_agent_caps/1, get_agent_caps/0,
88
89	 log_to_txt/2, log_to_txt/3, log_to_txt/4,
90	 change_log_size/1
91
92	]).
93
94-export_type([
95	      dir/0,
96	      snmp_timer/0,
97
98              atl_type/0,
99              verbosity/0,
100
101	      engine_id/0,
102	      tdomain/0,
103	      community/0,
104	      mms/0,
105	      version/0,
106	      sec_model/0,
107	      sec_name/0,
108	      sec_level/0,
109
110	      oid/0,
111	      varbind/0,
112	      ivarbind/0,
113	      asn1_type/0,
114	      table_info/0,
115	      variable_info/0,
116	      me/0,
117	      trap/0,
118	      notification/0,
119	      pdu/0,
120	      trappdu/0,
121	      mib/0,
122	      mib_name/0,
123
124              error_status/0,
125              error_index/0,
126
127	      void/0
128	     ]).
129
130
131%% This is for XREF
132-deprecated([{c,                     1, eventually},
133	     {c,                     2, eventually},
134	     {compile,               3, eventually},
135	     {is_consistent,         1, eventually},
136	     {mib_to_hrl,            1, eventually},
137
138	     {change_log_size,       1, eventually},
139	     {log_to_txt,            2, eventually},
140	     {log_to_txt,            3, eventually},
141	     {log_to_txt,            4, eventually},
142
143	     {current_request_id,    0, eventually},
144	     {current_community,     0, eventually},
145	     {current_address,       0, eventually},
146	     {current_context,       0, eventually},
147	     {current_net_if_data,   0, eventually},
148
149	     {get_symbolic_store_db, 0, eventually},
150	     {name_to_oid,           1, eventually},
151	     {name_to_oid,           2, eventually},
152	     {oid_to_name,           1, eventually},
153	     {oid_to_name,           2, eventually},
154	     {int_to_enum,           2, eventually},
155	     {int_to_enum,           3, eventually},
156	     {enum_to_int,           2, eventually},
157	     {enum_to_int,           3, eventually},
158
159	     {get,                   2, eventually},
160	     {info,                  1, eventually},
161	     {load_mibs,             2, eventually},
162	     {unload_mibs,           2, eventually},
163	     {dump_mibs,             0, eventually},
164	     {dump_mibs,             1, eventually},
165
166	     {register_subagent,     3, eventually},
167	     {unregister_subagent,   2, eventually},
168
169	     {send_notification,     3, eventually},
170	     {send_notification,     4, eventually},
171	     {send_notification,     5, eventually},
172	     {send_notification,     6, eventually},
173	     {send_trap,             3, eventually},
174	     {send_trap,             4, eventually},
175
176	     {add_agent_caps,        2, eventually},
177	     {del_agent_caps,        1, eventually},
178	     {get_agent_caps,        0, eventually}]).
179
180
181-define(APPLICATION, snmp).
182-define(ATL_BLOCK_DEFAULT, true).
183
184-include_lib("snmp/include/snmp_types.hrl").
185
186
187%%-----------------------------------------------------------------
188%% Types
189%%-----------------------------------------------------------------
190
191-type dir()           :: string().
192-type snmp_timer()    :: #snmp_incr_timer{}.
193
194-type atl_type()      :: read | write | read_write.
195-type verbosity()     :: info | log | debug | trace | silence.
196
197-type engine_id()     :: string().
198-type tdomain()       :: transportDomainUdpIpv4 | transportDomainUdpIpv6.
199-type community()     :: string().
200-type mms()           :: non_neg_integer().
201-type version()       :: v1 | v2 | v3.
202-type sec_model()     :: any | v1 | v2c | usm.
203-type sec_name()      :: string().
204-type sec_level()     :: noAuthNoPriv | authNoPriv | authPriv.
205
206-type oid()           :: [non_neg_integer()].
207-type varbind()       :: #varbind{}.
208-type ivarbind()      :: #ivarbind{}.
209-type asn1_type()     :: #asn1_type{}.
210-type table_info()    :: #table_info{}.
211-type variable_info() :: #variable_info{}.
212-type me()            :: #me{}.
213-type trap()          :: #trap{}.
214-type notification()  :: #notification{}.
215-type mib()           :: #mib{}.
216-type mib_name()      :: string().
217-type pdu()           :: #pdu{}.
218-type trappdu()       :: #trappdu{}.
219
220%% We should really specify all of these, but they are so numerous...
221%% See the validate_err/1 function in the snmpa_agent.
222%% Here are a number of them:
223%% badValue |
224%% commitFailed |
225%% genErr |
226%% inconsistentName | inconsistentValue |
227%% noAccess | noCreation |
228%% noSuchInstance | noSuchName | noSuchObject |
229%% notWritable |
230%% resourceUnavailable |
231%% undoFailed |
232%% wrongValue
233
234-type error_status()  :: atom().
235-type error_index()   :: pos_integer().
236
237-type void()          :: term().
238
239
240%%-----------------------------------------------------------------
241%% Application
242%%-----------------------------------------------------------------
243
244start() ->
245    application:start(?APPLICATION).
246
247stop() ->
248    application:stop(?APPLICATION).
249
250start(p) ->
251    start(permanent);
252start(tr) ->
253    start(transient);
254start(te) ->
255    start(temporary);
256start(Type) ->
257    application:start(?APPLICATION, Type).
258
259
260start_agent() ->
261    snmp_app:start_agent().
262
263start_agent(Type) ->
264    snmp_app:start_agent(Type).
265
266start_manager() ->
267    snmp_app:start_manager().
268
269start_manager(Type) ->
270    snmp_app:start_manager(Type).
271
272
273config() -> snmp_config:config().
274
275
276%%-----------------------------------------------------------------
277
278enable_trace() ->
279    HandleSpec = {fun handle_trace_event/2, dummy},
280    dbg:tracer(process, HandleSpec).
281
282disable_trace() ->
283    dbg:stop().
284
285set_trace(Module) when is_atom(Module) ->
286    set_trace([Module]);
287set_trace(Modules) when is_list(Modules) ->
288    Opts = [], % Use default values for all options
289    set_trace(Modules, Opts).
290
291reset_trace(Module) when is_atom(Module) ->
292    set_trace(Module, disable);
293reset_trace(Modules) when is_list(Modules) ->
294    set_trace(Modules, disable).
295
296set_trace(Module, disable) when is_atom(Module) ->
297    dbg:ctp(Module);
298set_trace(Module, Opts) when is_atom(Module) andalso is_list(Opts) ->
299    (catch set_trace(all, Module, Opts));
300set_trace(Modules, Opts) when is_list(Modules) ->
301    (catch set_trace(all, Modules, Opts)).
302
303set_trace(Item, Module, Opts) when is_atom(Module) ->
304    set_trace(Item, [{Module, []}], Opts);
305set_trace(_Item, Modules, disable) when is_list(Modules) ->
306    DisableTrace =
307	fun(Module) when is_atom(Module) ->
308		dbg:ctp(Module);
309	   (_) ->
310		ok
311	end,
312    lists:foreach(DisableTrace, Modules);
313set_trace(Item, Modules, Opts) when is_list(Modules) ->
314    Mods = parse_modules(Modules, Opts),
315    SetTrace =
316	fun({Module, ModOpts}) ->
317		set_module_trace(Module, ModOpts)
318	end,
319    lists:foreach(SetTrace, Mods),
320    Flags =
321	case lists:keysearch(timestamp, 1, Opts) of
322	    {value, {timestamp, false}} ->
323		[call];
324	    _ ->
325		[call, timestamp]
326	end,
327    case dbg:p(Item, Flags) of
328	{ok, _} ->
329	    ok;
330	Error ->
331	    Error
332    end.
333
334set_module_trace(Module, disable) ->
335    dbg:ctp(Module);
336set_module_trace(Module, Opts) ->
337    ReturnTrace =
338	case lists:keysearch(return_trace, 1, Opts) of
339	    {value, {return_trace, false}} ->
340		[];
341	    _ ->
342		%% Default is allways  to include return values
343		[{return_trace}]
344	end,
345    TraceRes =
346	case lists:keysearch(scope, 1, Opts) of
347	    {value, {scope, all_functions}} ->
348		dbg:tpl(Module, [{'_', [], ReturnTrace}]);
349	    {value, {scope, exported_functions}}  ->
350		dbg:tp(Module, [{'_', [], ReturnTrace}]);
351	    {value, {scope, Func}}  when is_atom(Func) ->
352		dbg:tpl(Module, Func, [{'_', [], ReturnTrace}]);
353	    {value, {scope, {Func, Arity}}}  when is_atom(Func) andalso
354						  is_integer(Arity) ->
355		dbg:tpl(Module, Func, Arity, [{'_', [], ReturnTrace}]);
356	    false ->
357	    %% Default scope is exported functions
358		dbg:tp(Module, [{'_', [], ReturnTrace}])
359	end,
360    case TraceRes of
361	{error, Reason} ->
362	    throw({error, {failed_enabling_trace, Module, Opts, Reason}});
363	_ ->
364	    ok
365    end.
366
367
368parse_modules(Modules, Opts) ->
369    parse_modules(Modules, Opts, []).
370
371parse_modules([], _Opts, Acc) ->
372    lists:reverse(Acc);
373
374parse_modules([Module|Modules], Opts, Acc)
375  when is_atom(Module) andalso is_list(Opts) ->
376    parse_modules(Modules, Opts, [{Module, Opts}|Acc]);
377
378parse_modules([{Module, ModOpts}|Modules], Opts, Acc)
379  when is_atom(Module) andalso is_list(ModOpts) andalso is_list(Opts) ->
380    NewModOpts = update_trace_options(Opts, ModOpts),
381    parse_modules(Modules, Opts, [{Module, NewModOpts}|Acc]);
382
383parse_modules([_|Modules], Opts, Acc) ->
384    parse_modules(Modules, Opts, Acc).
385
386
387update_trace_options([], Opts) ->
388    Opts;
389update_trace_options([{Key, _} = Opt|Opts], ModOpts) ->
390    case lists:keysearch(Key, 1, ModOpts) of
391	{value, _} ->
392	    update_trace_options(Opts, ModOpts);
393	_ ->
394	    update_trace_options(Opts, [Opt|ModOpts])
395    end;
396update_trace_options([_|Opts], ModOpts) ->
397    update_trace_options(Opts, ModOpts).
398
399
400handle_trace_event({trace, Who, call, Event}, Data) ->
401    io:format("*** call trace event *** "
402	      "~n   Who:   ~p"
403	      "~n   Event: ~p"
404	      "~n", [Who, Event]),
405    Data;
406handle_trace_event({trace, Who, return_from, Func, Value}, Data) ->
407    io:format("*** return trace event *** "
408	      "~n   Who:      ~p"
409	      "~n   Function: ~p"
410	      "~n   Value:    ~p"
411	      "~n", [Who, Func, Value]),
412    Data;
413handle_trace_event({trace_ts, Who, call, {Mod, Func, Args}, Ts}, Data)
414  when is_atom(Mod) andalso is_atom(Func) andalso is_list(Args) ->
415    io:format("*** call trace event ~s *** "
416	      "~n   Who:  ~p"
417	      "~n   Mod:  ~p"
418	      "~n   Func: ~p"
419	      "~n   Args: ~p"
420	      "~n", [format_timestamp(Ts), Who, Mod, Func, Args]),
421    Data;
422handle_trace_event({trace_ts, Who, call, Event, Ts}, Data) ->
423    io:format("*** call trace event ~s *** "
424	      "~n   Who:   ~p"
425	      "~n   Event: ~p"
426	      "~n", [format_timestamp(Ts), Who, Event]),
427    Data;
428handle_trace_event({trace_ts, Who, return_from, {Mod, Func, Arity}, Value, Ts},
429		   Data)
430  when is_atom(Mod) andalso is_atom(Func) andalso is_integer(Arity) ->
431    io:format("*** return trace event ~s *** "
432	      "~n   Who:   ~p"
433	      "~n   Mod:   ~p"
434	      "~n   Func:  ~p"
435	      "~n   Arity: ~p"
436	      "~n   Value: ~p"
437	      "~n", [format_timestamp(Ts), Who, Mod, Func, Arity, Value]),
438    Data;
439handle_trace_event({trace_ts, Who, return_from, Func, Value, Ts}, Data) ->
440    io:format("*** return trace event ~s *** "
441	      "~n   Who:      ~p"
442	      "~n   Function: ~p"
443	      "~n   Value:    ~p"
444	      "~n", [format_timestamp(Ts), Who, Func, Value]),
445    Data;
446handle_trace_event(TraceEvent, Data) ->
447    io:format("*** trace event *** "
448	      "~n   TraceEvent: ~p"
449	      "~n", [TraceEvent]),
450    Data.
451
452format_timestamp({_N1, _N2, N3} = Now) ->
453    {Date, Time}   = calendar:now_to_datetime(Now),
454    {YYYY,MM,DD}   = Date,
455    {Hour,Min,Sec} = Time,
456    FormatDate =
457        io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
458                      [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
459    lists:flatten(FormatDate).
460
461
462%%-----------------------------------------------------------------
463%% {ok, Vs} = snmp:versions1(), snmp:print_versions(Vs).
464
465print_version_info() ->
466    {ok, Vs} = versions1(),
467    print_versions(Vs).
468
469print_version_info(Prefix) ->
470    {ok, Vs} = versions1(),
471    print_versions(Prefix, Vs).
472
473print_versions(Versions) ->
474    print_versions("", Versions).
475
476print_versions(Prefix, Versions)
477  when is_list(Prefix) andalso is_list(Versions) ->
478    do_print_versions(Prefix, Versions);
479print_versions(Prefix, Versions)
480  when (is_integer(Prefix) andalso (Prefix >= 0)) andalso is_list(Versions) ->
481    do_print_versions(lists:duplicate(Prefix, $ ), Versions);
482print_versions(Prefix, BadVersions)
483  when is_list(Prefix) orelse (is_integer(Prefix) andalso (Prefix >= 0)) ->
484    {error, {bad_versions, BadVersions}};
485print_versions(Prefix, BadVersions)
486  when is_list(BadVersions) ->
487    {error, {bad_prefix, Prefix}};
488print_versions(Prefix, BadVersions) ->
489    {error, {bad_args, Prefix, BadVersions}}.
490
491do_print_versions(Prefix, Versions) ->
492    print_sys_info(Prefix, Versions),
493    print_os_info(Prefix, Versions),
494    print_mods_info(Prefix, Versions).
495
496print_sys_info(Prefix, Versions) ->
497    case key1search(sys_info, Versions) of
498        {value, SysInfo} when is_list(SysInfo) ->
499            {value, Arch} = key1search(arch, SysInfo, "Not found"),
500            {value, Ver}  = key1search(ver, SysInfo, "Not found"),
501            io:format("~sSystem info: "
502                      "~n~s   Arch: ~s"
503                      "~n~s   Ver:  ~s"
504                      "~n", [Prefix,
505			     Prefix, Arch,
506			     Prefix, Ver]),
507            ok;
508        _ ->
509            io:format("System info: Not found~n", []),
510            not_found
511    end.
512
513print_os_info(Prefix, Versions) ->
514    case key1search(os_info, Versions) of
515        {value, OsInfo} when is_list(OsInfo) ->
516            Fam =
517                case key1search(fam, OsInfo, "Not found") of
518                    {value, F} when is_atom(F) ->
519                        atom_to_list(F);
520                    {value, LF} when is_list(LF) ->
521                        LF;
522                    {value, XF} ->
523                        lists:flatten(io_lib:format("~p", [XF]))
524                end,
525            Name =
526                case key1search(name, OsInfo) of
527                    {value, N} when is_atom(N) ->
528                        "[" ++ atom_to_list(N) ++ "]";
529                    {value, LN} when is_list(LN) ->
530                        "[" ++ LN ++ "]";
531                    not_found ->
532                        ""
533                end,
534            Ver =
535                case key1search(ver, OsInfo, "Not found") of
536                    {value, T} when is_tuple(T) ->
537                        tversion(T);
538                    {value, LV} when is_list(LV) ->
539                        LV;
540                    {value, XV} ->
541                        lists:flatten(io_lib:format("~p", [XV]))
542                end,
543            io:format("~sOS info: "
544                      "~n~s   Family: ~s ~s"
545                      "~n~s   Ver:    ~s"
546                      "~n", [Prefix,
547			     Prefix, Fam, Name,
548			     Prefix, Ver]),
549            ok;
550        _ ->
551            io:format("~sOS info:     Not found~n", [Prefix]),
552            not_found
553    end.
554
555tversion(T) ->
556    L = tuple_to_list(T),
557    lversion(L).
558
559lversion([]) ->
560    "";
561lversion([A]) ->
562    integer_to_list(A);
563lversion([A|R]) ->
564    integer_to_list(A) ++ "." ++ lversion(R).
565
566print_mods_info(Prefix, Versions) ->
567    case key1search(mod_info, Versions) of
568        {value, ModsInfo} when is_list(ModsInfo) ->
569            io:format("~sModule info: ~n", [Prefix]),
570	    F = fun(MI) -> print_mod_info(Prefix, MI) end,
571            lists:foreach(F, ModsInfo);
572        _ ->
573            io:format("~sModule info: Not found~n", [Prefix]),
574            not_found
575    end.
576
577print_mod_info(Prefix, {Module, Info}) ->
578    Vsn =
579        case key1search(vsn, Info) of
580            {value, I} when is_integer(I) ->
581                integer_to_list(I);
582            _ ->
583                "Not found"
584        end,
585    AppVsn =
586        case key1search(app_vsn, Info) of
587            {value, S1} when is_list(S1) ->
588                S1;
589            _ ->
590                "Not found"
591        end,
592    CompVer =
593        case key1search(compiler_version, Info) of
594            {value, S2} when is_list(S2) ->
595                S2;
596            _ ->
597                "Not found"
598        end,
599    Digest =
600        case key1search(md5, Info) of
601            {value, MD5} when is_binary(MD5) ->
602		[io_lib:format("~2.16.0b", [Byte]) || <<Byte>> <= MD5];
603            _ ->
604                "Not found"
605        end,
606    io:format("~s   ~w:~n"
607              "~s      Vsn:          ~s~n"
608              "~s      App vsn:      ~s~n"
609              "~s      Compiler ver: ~s~n"
610              "~s      MD5 digest:   ~s~n",
611              [Prefix, Module,
612	       Prefix, Vsn,
613	       Prefix, AppVsn,
614	       Prefix, CompVer,
615	       Prefix, Digest]),
616    ok.
617
618key1search(Key, Vals) ->
619    case lists:keysearch(Key, 1, Vals) of
620        {value, {Key, Val}} ->
621            {value, Val};
622        false ->
623            not_found
624    end.
625
626key1search(Key, Vals, Def) ->
627    case key1search(Key, Vals) of
628	not_found ->
629	    {value, Def};
630	Value ->
631	    Value
632    end.
633
634
635%%-----------------------------------------------------------------
636
637versions1() ->
638    case ms1() of
639        {ok, Mods} ->
640            {ok, version_info(Mods)};
641        Error ->
642            Error
643    end.
644
645versions2() ->
646    case ms2() of
647        {ok, Mods} ->
648            {ok, version_info(Mods)};
649        Error ->
650            Error
651    end.
652
653version_info(Mods) ->
654    SysInfo = sys_info(),
655    OsInfo  = os_info(),
656    ModInfo = [mod_version_info(Mod) || Mod <- Mods],
657    [{sys_info, SysInfo}, {os_info, OsInfo}, {mod_info, ModInfo}].
658
659mod_version_info(Mod) ->
660    Info = Mod:module_info(),
661    {Mod,
662     case key1search(attributes, Info) of
663	 {value, Attr} ->
664	     case key1search(vsn, Attr) of
665		 {value, [Vsn]} ->
666		     [{vsn, Vsn}];
667		 not_found ->
668		     []
669	     end ++
670		 case key1search(app_vsn, Attr) of
671		     {value, AppVsn} ->
672			 [{app_vsn, AppVsn}];
673		     not_found ->
674			 []
675		 end;
676	 not_found ->
677	     []
678     end ++
679	 case key1search(compile, Info) of
680	     {value, Comp} ->
681		 case key1search(version, Comp) of
682		     {value, Ver} ->
683			 [{compiler_version, Ver}];
684		     not_found ->
685			 []
686		 end ++
687		     case key1search(time, Comp) of
688			 {value, Ver} ->
689			     [{compile_time, Ver}];
690			 not_found ->
691			     []
692		     end;
693	     not_found ->
694		 []
695	 end ++
696	 case key1search(md5, Info) of
697	     {value, Bin} ->
698		 [{md5, Bin}];
699	     not_found ->
700		 []
701	 end}.
702
703sys_info() ->
704    SysArch = string:strip(erlang:system_info(system_architecture),right,$\n),
705    SysVer  = string:strip(erlang:system_info(system_version),right,$\n),
706    [{arch, SysArch}, {ver, SysVer}].
707
708os_info() ->
709    {OsFam, OsName} = os:type(),
710    [{fam, OsFam}, {name, OsName}, {ver, os:version()}].
711
712ms1() ->
713    App    = ?APPLICATION,
714    LibDir = code:lib_dir(App),
715    File   = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
716    case file:consult(File) of
717        {ok, [{application, App, AppFile}]} ->
718            case lists:keysearch(modules, 1, AppFile) of
719                {value, {modules, Mods}} ->
720                    {ok, Mods};
721                _ ->
722                    {error, {invalid_format, modules}}
723            end;
724        Error ->
725            {error, {invalid_format, Error}}
726    end.
727
728ms2() ->
729    application:get_key(?APPLICATION, modules).
730
731
732%%-----------------------------------------------------------------
733%% Returns: current time as a DateAndTime type (defined in rfc1903)
734%%-----------------------------------------------------------------
735date_and_time() ->
736    UTC   = calendar:universal_time(),
737    Local = calendar:universal_time_to_local_time(UTC),
738    date_and_time(Local, UTC).
739
740date_and_time(Local, UTC) ->
741    DiffSecs = calendar:datetime_to_gregorian_seconds(Local) -
742	calendar:datetime_to_gregorian_seconds(UTC),
743    short_time(Local) ++ diff(DiffSecs).
744
745short_time({{Y,M,D},{H,Mi,S}}) ->
746    [y1(Y), y2(Y), M, D, H, Mi, S, 0].
747
748%% This function will only be called if there has been some
749%% validation error, and as it is strict, it allways returns
750%% false.
751strict_validation(_What, _Data) ->
752    false.
753
754kiribati_validation(diff, Diff) ->
755    check_kiribati_diff(Diff);
756kiribati_validation(_What, _Data) ->
757    false.
758
759check_kiribati_diff([$+, H, M])
760  when ((0 =< H) andalso (H < 14) andalso (0 =< M) andalso (M < 60)) orelse
761       ((H =:= 14) andalso (M =:= 0)) ->
762    true;
763check_kiribati_diff([$-, H, M])
764  when ((0 =< H) andalso (H < 14) andalso (0 =< M) andalso (M < 60)) orelse
765       ((H =:= 14) andalso (M =:= 0)) ->
766    true;
767check_kiribati_diff(_) ->
768    false.
769
770
771date_and_time_to_string2(DAT) ->
772    Validate = fun(What, Data) -> kiribati_validation(What, Data) end,
773    date_and_time_to_string(DAT, Validate).
774
775date_and_time_to_string(DAT) ->
776    Validate = fun(What, Data) -> strict_validation(What, Data) end,
777    date_and_time_to_string(DAT, Validate).
778date_and_time_to_string(DAT, Validate) when is_function(Validate) ->
779    case validate_date_and_time(DAT, Validate) of
780	true ->
781	        dat2str(DAT);
782	false ->
783	        exit({badarg, {?MODULE, date_and_time_to_string, [DAT]}})
784    end.
785
786dat2str([Y1,Y2, Mo, D, H, M, S, Ds | Diff]) ->
787    lists:flatten(io_lib:format("~w-~w-~w,~w:~w:~w.~w",
788				[y(Y1,Y2),Mo,D,H,M,S,Ds]) ++
789		    case Diff of
790			      [Sign,Hd,Md] ->
791			      io_lib:format(",~c~w:~w",
792					    [Sign,Hd,Md]);
793			      _ -> []
794		      end).
795
796
797y1(Y) -> (Y bsr 8) band 255.
798y2(Y) -> Y band 255.
799
800y(Y1, Y2) -> 256 * Y1 + Y2.
801
802diff(Secs) ->
803    case calendar:seconds_to_daystime(Secs) of
804	{0, {H, M,_}} ->
805	        [$+, H, M];
806	{-1, _} ->
807	        {0, {H, M, _}} = calendar:seconds_to_daystime(-Secs),
808	        [$-, H, M]
809    end.
810
811universal_time_to_date_and_time(UTC) ->
812    short_time(UTC) ++ [$+, 0, 0].
813
814local_time_to_date_and_time_dst(Local) ->
815    case calendar:local_time_to_universal_time_dst(Local) of
816	[] ->
817	    [];
818	[UTC] ->
819	    [date_and_time(Local, UTC)];
820	[UTC1, UTC2] ->
821	    [date_and_time(Local, UTC1), date_and_time(Local, UTC2)]
822    end.
823
824date_and_time_to_universal_time_dst([Y1, Y2, Mo, D, H, M, S, _Ds]) ->
825    %% Local time specified, convert to UTC
826    Local = {{y(Y1,Y2), Mo, D}, {H, M, S}},
827    calendar:local_time_to_universal_time_dst(Local);
828date_and_time_to_universal_time_dst([Y1, Y2, Mo, D, H, M, S, _Ds, Sign, Hd, Md]) ->
829     %% Time specified as local time + diff from UTC. Conv to UTC.
830    Local = {{y(Y1,Y2), Mo, D}, {H, M, S}},
831    LocalSecs = calendar:datetime_to_gregorian_seconds(Local),
832    Diff = (Hd*60 + Md)*60,
833    UTCSecs = if Sign == $+ -> LocalSecs - Diff;
834		 Sign == $- -> LocalSecs + Diff
835	      end,
836    [calendar:gregorian_seconds_to_datetime(UTCSecs)].
837
838
839validate_date_and_time(DateAndTime) ->
840    Validate = fun(What, Data) -> strict_validation(What, Data) end,
841    validate_date_and_time(DateAndTime, Validate).
842
843validate_date_and_time(DateAndTime, Validate) when is_function(Validate) ->
844    do_validate_date_and_time(DateAndTime, Validate).
845
846do_validate_date_and_time([Y1,Y2, Mo, D, H, M, S, Ds | Diff], Validate)
847  when ((0 =< Y1) andalso (0 =< Y2)) andalso
848       ((0 < Mo) andalso (Mo < 13)) andalso
849       ((0 < D) andalso (D < 32) andalso (0 =< H)) andalso
850       (H < 24) andalso
851       ((0 =< M) andalso (M < 60)) andalso
852       ((0 =< S) andalso (S < 61)) andalso
853       ((0 =< Ds) andalso (Ds < 10)) ->
854    case check_diff(Diff, Validate) of
855	true ->
856	    Year = y(Y1,Y2),
857	    case calendar:valid_date(Year, Mo, D) of
858		true ->
859		    true;
860		_ ->
861		    Validate(valid_date, {Year, Mo, D})
862	    end;
863	false ->
864	    false
865    end;
866do_validate_date_and_time([Y1,Y2, Mo, D, H, M, S, Ds | Diff], Validate) ->
867    Valid =
868	Validate(year,         {Y1, Y2}) andalso
869	Validate(month,        Mo)       andalso
870	Validate(day,          D)        andalso
871	Validate(hour,         H)        andalso
872	Validate(minute,       M)        andalso
873	Validate(seconds,      S)        andalso
874	Validate(deci_seconds, Ds),
875    if
876	Valid =:= true ->
877	    case check_diff(Diff, Validate) of
878		true ->
879		    Year = y(Y1,Y2),
880		    case calendar:valid_date(Year, Mo, D) of
881			true ->
882			    true;
883			_ ->
884			    Validate(valid_date, {Year, Mo, D})
885		    end;
886		false ->
887		    false
888	    end;
889	true ->
890	    false
891    end;
892do_validate_date_and_time(_, _) ->
893    false.
894
895%% OTP-4206 (now according to RFC-2579)
896check_diff([], _) ->
897    true;
898check_diff([$+, H, M], _)
899  when (0 =< H) andalso (H < 14) andalso (0 =< M) andalso (M < 60) ->
900    true;
901check_diff([$-, H, M], _)
902  when (0 =< H) andalso (H < 14) andalso (0 =< M) andalso (M < 60) ->
903    true;
904check_diff(Diff, Validate) ->
905    Validate(diff, Diff).
906
907
908%%-----------------------------------------------------------------
909%% System start- and up-time
910%%-----------------------------------------------------------------
911
912system_start_time(agent) ->
913    snmpa:system_start_time();
914system_start_time(manager) ->
915    snmpm:system_start_time().
916
917sys_up_time(agent) ->
918    snmpa:sys_up_time();
919sys_up_time(manager) ->
920    snmpm:sys_up_time().
921
922
923
924%%-----------------------------------------------------------------
925%% Utility functions for OCTET-STRING / BITS conversion.
926%%-----------------------------------------------------------------
927
928octet_string_to_bits(S) ->
929    snmp_pdus:octet_str_to_bits(S).
930
931bits_to_octet_string(B) ->
932    snmp_pdus:bits_to_str(B).
933
934
935%%%-----------------------------------------------------------------
936%%% USM functions
937%%%-----------------------------------------------------------------
938
939passwd2localized_key(Alg, Passwd, EngineID) ->
940    snmp_usm:passwd2localized_key(Alg, Passwd, EngineID).
941
942localize_key(Alg, Key, EngineID) ->
943    snmp_usm:localize_key(Alg, Key, EngineID).
944
945
946%%%-----------------------------------------------------------------
947%%% Read a mib
948%%%-----------------------------------------------------------------
949
950read_mib(FileName) ->
951    snmp_misc:read_mib(FileName).
952
953
954%%%-----------------------------------------------------------------
955%%% Audit Trail Log functions
956%%%-----------------------------------------------------------------
957
958log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) ->
959    Block = ?ATL_BLOCK_DEFAULT,
960    Start = null,
961    Stop  = null,
962    log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
963
964log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block)
965  when ((Block =:= true) orelse (Block =:= false)) ->
966    Start = null,
967    Stop  = null,
968    log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop);
969log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) ->
970    Block = ?ATL_BLOCK_DEFAULT,
971    Stop  = null,
972    log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
973
974log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start)
975  when ((Block =:= true) orelse (Block =:= false)) ->
976    Stop  = null,
977    log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop);
978log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) ->
979    Block = ?ATL_BLOCK_DEFAULT,
980    log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop).
981
982log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) ->
983    snmp_log:log_to_txt(LogName, Block, LogFile, LogDir, Mibs, OutFile,
984			Start, Stop).
985
986
987log_to_io(LogDir, Mibs, LogName, LogFile) ->
988    Block = ?ATL_BLOCK_DEFAULT,
989    Start = null,
990    Stop  = null,
991    log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
992
993log_to_io(LogDir, Mibs, LogName, LogFile, Block)
994  when ((Block =:= true) orelse (Block =:= false)) ->
995    Start = null,
996    Stop  = null,
997    log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop);
998log_to_io(LogDir, Mibs, LogName, LogFile, Start) ->
999    Block = ?ATL_BLOCK_DEFAULT,
1000    Stop  = null,
1001    log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
1002
1003log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start)
1004  when ((Block =:= true) orelse (Block =:= false)) ->
1005    Stop  = null,
1006    log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop);
1007log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) ->
1008    Block = ?ATL_BLOCK_DEFAULT,
1009    log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop).
1010
1011log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) ->
1012    snmp_log:log_to_io(LogName, Block, LogFile, LogDir, Mibs, Start, Stop).
1013
1014change_log_size(LogName, NewSize) ->
1015    snmp_log:change_size(LogName, NewSize).
1016
1017
1018%%%-----------------------------------------------------------------
1019%%% Misc
1020%%%-----------------------------------------------------------------
1021
1022%% Usage: erl -s snmp str_apply '{Mod,Func,ArgList}'
1023str_apply([Atom]) ->
1024    Str = atom_to_list(Atom),
1025    {Mod, Func, Args} = to_erlang_term(Str),
1026    apply(Mod, Func, Args).
1027
1028to_erlang_term(String) ->
1029    {ok, Tokens, _} = erl_scan:string(lists:append([String, ". "])),
1030    {ok, Term}      = erl_parse:parse_term(Tokens),
1031    Term.
1032
1033
1034%%%-----------------------------------------------------------------
1035%%% BACKWARD COMPATIBILLITY CRAP
1036%%%-----------------------------------------------------------------
1037
1038c(File) -> snmpc:compile(File).
1039c(File, Options) -> snmpc:compile(File, Options).
1040
1041is_consistent(Filenames) ->
1042    snmpc:is_consistent(Filenames).
1043
1044mib_to_hrl(MibName) ->
1045    snmpc:mib_to_hrl(MibName).
1046
1047compile(Input, Output, Options) ->
1048    snmpc:compile(Input, Output, Options).
1049
1050get_symbolic_store_db() -> snmpa:get_symbolic_store_db().
1051
1052name_to_oid(Name)           -> snmpa:name_to_oid(Name).
1053name_to_oid(Db, Name)       -> snmpa:name_to_oid(Db, Name).
1054oid_to_name(OID)            -> snmpa:oid_to_name(OID).
1055oid_to_name(Db, OID)        -> snmpa:oid_to_name(Db, OID).
1056enum_to_int(Name, Enum)     -> snmpa:enum_to_int(Name, Enum).
1057enum_to_int(Db, Name, Enum) -> snmpa:enum_to_int(Db, Name, Enum).
1058int_to_enum(Name, Int)      -> snmpa:int_to_enum(Name, Int).
1059int_to_enum(Db, Name, Int)  -> snmpa:int_to_enum(Db, Name, Int).
1060
1061current_request_id()  -> snmpa:current_request_id().
1062current_context()     -> snmpa:current_context().
1063current_community()   -> snmpa:current_community().
1064current_address()     -> snmpa:current_address().
1065current_net_if_data() -> snmpa:current_net_if_data().
1066
1067get(Agent, Vars) -> snmpa:get(Agent, Vars).
1068info(Agent) -> snmpa:info(Agent).
1069dump_mibs()     -> snmpa:dump_mibs().
1070dump_mibs(File) -> snmpa:dump_mibs(File).
1071load_mibs(Agent, Mibs) -> snmpa:load_mibs(Agent, Mibs).
1072unload_mibs(Agent, Mibs) -> snmpa:unload_mibs(Agent, Mibs).
1073send_notification(Agent, Notification, Recv) ->
1074    snmpa:send_notification(Agent, Notification, Recv).
1075send_notification(Agent, Notification, Recv, Varbinds) ->
1076    snmpa:send_notification(Agent, Notification, Recv, Varbinds).
1077send_notification(Agent, Notification, Recv, NotifyName, Varbinds) ->
1078    snmpa:send_notification(Agent, Notification, Recv, NotifyName, Varbinds).
1079send_notification(Agent, Notification, Recv, NotifyName,
1080		  ContextName, Varbinds) ->
1081    snmpa:send_notification(Agent, Notification, Recv, NotifyName,
1082			    ContextName, Varbinds).
1083send_trap(Agent, Trap, Community) ->
1084    snmpa:send_trap(Agent, Trap, Community).
1085send_trap(Agent, Trap, Community, Varbinds) ->
1086    snmpa:send_trap(Agent, Trap, Community, Varbinds).
1087register_subagent(Agent, SubTree, SubAgent) ->
1088    snmpa:register_subagent(Agent, SubTree, SubAgent).
1089unregister_subagent(Agent, SubOidOrPid) ->
1090    snmpa:unregister_subagent(Agent, SubOidOrPid).
1091
1092add_agent_caps(Oid, Descr) -> snmpa:add_agent_caps(Oid, Descr).
1093del_agent_caps(Index) -> snmpa:del_agent_caps(Index).
1094get_agent_caps() -> snmpa:get_agent_caps().
1095
1096log_to_txt(LogDir, Mibs) ->
1097    snmpa:log_to_txt(LogDir, Mibs).
1098log_to_txt(LogDir, Mibs, OutFile) ->
1099    snmpa:log_to_txt(LogDir, Mibs, OutFile).
1100log_to_txt(LogDir, Mibs, OutFile, LogName) ->
1101    snmpa:log_to_txt(LogDir, Mibs, OutFile, LogName).
1102change_log_size(NewSize) ->
1103    snmpa:change_log_size(NewSize).
1104
1105
1106
1107