1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2016. 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(snmpa_symbolic_store).
21
22%%----------------------------------------------------------------------
23%% This module implements a multipurpose symbolic store.
24%% 1) For internal and use from application: aliasname_to_value/1.
25%%    If this was stored in the mib, deadlock would occur.
26%% 2 table_info/1. Getting information about a table. Used by default
27%%    implementation of tables.
28%% 3) variable_info/1. Used by default implementation of variables.
29%% 4) notification storage. Used by snmpa_trap.
30%% There is one symbolic store per node and it uses the ets table
31%% snmp_agent_table, owned by the snmpa_supervisor.
32%%
33%%----------------------------------------------------------------------
34
35-include_lib("kernel/include/file.hrl").
36-include("snmp_types.hrl").
37-include("snmp_debug.hrl").
38-include("snmp_verbosity.hrl").
39-include("SNMPv2-MIB.hrl").
40
41
42%% API
43-export([start_link/2,
44	 stop/0,
45	 info/0,
46	 backup/1,
47	 aliasname_to_oid/1, oid_to_aliasname/1,
48	 add_aliasnames/2, delete_aliasnames/1,
49	 which_aliasnames/0,
50	 which_tables/0,
51	 which_variables/0,
52	 enum_to_int/2, int_to_enum/2,
53	 table_info/1, add_table_infos/2, delete_table_infos/1,
54	 variable_info/1, add_variable_infos/2, delete_variable_infos/1,
55	 get_notification/1, set_notification/2,
56	 delete_notifications/1, which_notifications/0,
57	 add_types/2, delete_types/1]).
58
59%% API (for quick access to the db, note that this is only reads).
60-export([get_db/0,
61	 aliasname_to_oid/2, oid_to_aliasname/2,
62	 enum_to_int/3, int_to_enum/3]).
63
64
65%% Internal exports
66-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
67	code_change/3]).
68
69-export([verbosity/1]).
70
71-define(SERVER, ?MODULE).
72
73-ifdef(snmp_debug).
74-define(GS_START_LINK(Prio, Opts),
75        gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts],
76			      [{debug,[trace]}])).
77-else.
78-define(GS_START_LINK(Prio, Opts),
79        gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts], [])).
80-endif.
81
82-record(state,  {module, db, backup}).
83-record(symbol, {key, mib_name, info}).
84
85
86%%-----------------------------------------------------------------
87%% Func: start_link/1
88%% Args: Prio is priority of mib-server
89%%       Opts is a list of options
90%% Purpose: starts the mib server synchronized
91%% Returns: {ok, Pid} | {error, Reason}
92%%-----------------------------------------------------------------
93start_link(Prio, Opts) ->
94    ?d("start_link -> entry with"
95	"~n   Prio: ~p"
96	"~n   Opts: ~p", [Prio,Opts]),
97    ?GS_START_LINK(Prio,Opts).
98
99stop() ->
100    call(stop).
101
102info() ->
103    call(info).
104
105backup(BackupDir) ->
106    call({backup, BackupDir}).
107
108
109%%----------------------------------------------------------------------
110%% Returns: Db
111%%----------------------------------------------------------------------
112
113get_db() ->
114    call(get_db).
115
116which_module() ->
117    call(which_module).
118
119
120%%----------------------------------------------------------------------
121%% Returns: {value, Oid} | false
122%%----------------------------------------------------------------------
123aliasname_to_oid(Aliasname) ->
124    call({aliasname_to_oid, Aliasname}).
125
126oid_to_aliasname(OID) ->
127    call({oid_to_aliasname, OID}).
128
129int_to_enum(TypeOrObjName, Int) ->
130    call({int_to_enum,TypeOrObjName,Int}).
131
132enum_to_int(TypeOrObjName, Enum) ->
133    call({enum_to_int,TypeOrObjName,Enum}).
134
135add_types(MibName, Types) ->
136    cast({add_types, MibName, Types}).
137
138delete_types(MibName) ->
139    cast({delete_types, MibName}).
140
141add_aliasnames(MibName, MEs) ->
142    cast({add_aliasnames, MibName, MEs}).
143
144delete_aliasnames(MibName) ->
145    cast({delete_aliasname, MibName}).
146
147which_aliasnames() ->
148    call(which_aliasnames).
149
150which_tables() ->
151    call(which_tables).
152
153which_variables() ->
154    call(which_variables).
155
156
157%%----------------------------------------------------------------------
158%% Returns: false|{value, Info}
159%%----------------------------------------------------------------------
160table_info(TableName) ->
161    call({table_info, TableName}).
162
163
164%%----------------------------------------------------------------------
165%% Returns: false|{value, Info}
166%%----------------------------------------------------------------------
167variable_info(VariableName) ->
168    call({variable_info, VariableName}).
169
170add_table_infos(MibName, TableInfos) ->
171    cast({add_table_infos, MibName, TableInfos}).
172
173delete_table_infos(MibName) ->
174    cast({delete_table_infos, MibName}).
175
176add_variable_infos(MibName, VariableInfos) ->
177    cast({add_variable_infos, MibName, VariableInfos}).
178
179delete_variable_infos(MibName) ->
180    cast({delete_variable_infos, MibName}).
181
182
183%%-----------------------------------------------------------------
184%% Store traps
185%%-----------------------------------------------------------------
186%% A notification is stored as {Key, Value}, where
187%% Key is the symbolic trap name, and Value is
188%% a #trap record.
189%%-----------------------------------------------------------------
190%% Returns: {value, Val} | undefined
191%%-----------------------------------------------------------------
192get_notification(Key) ->
193    call({get_notification, Key}).
194set_notification(Trap, MibName) ->
195    call({set_notification, MibName, Trap}).
196delete_notifications(MibName) ->
197    call({delete_notifications, MibName}).
198which_notifications() ->
199    call(which_notifications).
200
201
202verbosity(Verbosity) ->
203    cast({verbosity,Verbosity}).
204
205
206%%----------------------------------------------------------------------
207%% DB access (read) functions: Returns: {value, Oid} | false
208%%----------------------------------------------------------------------
209
210aliasname_to_oid(Db, Aliasname) ->
211    Mod = which_module(),
212    aliasname_to_oid(Mod, Db, Aliasname).
213
214aliasname_to_oid(Mod, Db, Aliasname) ->
215    case Mod:read(Db, {alias, Aliasname}) of
216	{value,#symbol{info = {Oid, _Enums}}} -> {value, Oid};
217	false -> false
218    end.
219
220oid_to_aliasname(Db, Oid) ->
221    Mod = which_module(),
222    oid_to_aliasname(Mod, Db, Oid).
223
224oid_to_aliasname(Mod, Db, Oid) ->
225    case Mod:read(Db, {oid, Oid}) of
226	{value,#symbol{info = Aliasname}} -> {value, Aliasname};
227	_ -> false
228    end.
229
230which_notifications(Mod, Db) ->
231    Pattern = #symbol{key = {trap, '_'}, _ = '_'},
232    Symbols = Mod:match_object(Db, Pattern),
233    [{Name, Mib, Rec} || #symbol{key      = {trap, Name},
234				 mib_name = Mib,
235				 info     = Rec} <- Symbols].
236
237which_aliasnames(Mod, Db) ->
238    Pattern = #symbol{key = {alias, '_'}, _ = '_'},
239    Symbols = Mod:match_object(Db, Pattern),
240    [Alias || #symbol{key = {alias, Alias}} <- Symbols].
241
242which_tables(Mod, Db) ->
243    Pattern = #symbol{key = {table_info, '_'}, _ = '_'},
244    Symbols = Mod:match_object(Db, Pattern),
245    [Name || #symbol{key = {table_info, Name}} <- Symbols].
246
247which_variables(Mod, Db) ->
248    Pattern = #symbol{key = {variable_info, '_'}, _ = '_'},
249    Symbols = Mod:match_object(Db, Pattern),
250    [Name || #symbol{key = {variable_info, Name}} <- Symbols].
251
252
253int_to_enum(Db, TypeOrObjName, Int) ->
254    Mod = which_module(),
255    int_to_enum(Mod, Db, TypeOrObjName, Int).
256
257int_to_enum(Mod, Db, TypeOrObjName, Int) ->
258    case Mod:read(Db, {alias, TypeOrObjName}) of
259	{value,#symbol{info = {_Oid, Enums}}} ->
260	    case lists:keysearch(Int, 2, Enums) of
261		{value, {Enum, _Int}} -> {value, Enum};
262		false -> false
263	    end;
264	false -> % Not an Aliasname ->
265	    case Mod:read(Db, {type, TypeOrObjName}) of
266		{value,#symbol{info = Enums}} ->
267		    case lists:keysearch(Int, 2, Enums) of
268			{value, {Enum, _Int}} -> {value, Enum};
269			false -> false
270		    end;
271		false ->
272		    false
273	    end
274    end.
275
276enum_to_int(Db, TypeOrObjName, Enum) ->
277    Mod = which_module(),
278    enum_to_int(Mod, Db, TypeOrObjName, Enum).
279
280enum_to_int(Mod, Db, TypeOrObjName, Enum) ->
281    case Mod:read(Db, {alias, TypeOrObjName}) of
282	{value,#symbol{info = {_Oid, Enums}}} ->
283	    case lists:keysearch(Enum, 1, Enums) of
284		{value, {_Enum, Int}} -> {value, Int};
285		false -> false
286	    end;
287	false -> % Not an Aliasname
288	    case Mod:read(Db, {type, TypeOrObjName}) of
289		{value,#symbol{info = Enums}} ->
290		    case lists:keysearch(Enum, 1, Enums) of
291			{value, {_Enum, Int}} -> {value, Int};
292			false -> false
293		    end;
294		false ->
295		    false
296	    end
297    end.
298
299
300%%----------------------------------------------------------------------
301%% DB access (read) functions: Returns: false|{value, Info}
302%%----------------------------------------------------------------------
303
304table_info(Mod, Db, TableName) ->
305    case Mod:read(Db, {table_info, TableName}) of
306	{value,#symbol{info = Info}} -> {value, Info};
307	false -> false
308    end.
309
310
311%%----------------------------------------------------------------------
312%% DB access (read) functions: Returns: false|{value, Info}
313%%----------------------------------------------------------------------
314variable_info(Mod, Db, VariableName) ->
315    case Mod:read(Db, {variable_info, VariableName}) of
316	{value,#symbol{info = Info}} -> {value, Info};
317	false -> false
318    end.
319
320
321%%----------------------------------------------------------------------
322%% Implementation
323%%----------------------------------------------------------------------
324
325init([Prio, Opts]) ->
326    ?d("init -> entry with"
327	"~n   Prio: ~p"
328	"~n   Opts: ~p", [Prio,Opts]),
329    case (catch do_init(Prio, Opts)) of
330	{ok, State} ->
331	    {ok, State};
332	Error ->
333	    config_err("failed starting symbolic-store: ~n~p", [Error]),
334	    {stop, {error, Error}}
335    end.
336
337do_init(Prio, Opts) ->
338    process_flag(priority, Prio),
339    process_flag(trap_exit, true),
340    put(sname,ss),
341    put(verbosity,get_verbosity(Opts)),
342    ?vlog("starting",[]),
343    MibStorage = get_mib_storage(Opts),
344    Mod        = snmp_misc:get_option(module,  MibStorage),
345    MsOpts     = snmp_misc:get_option(options, MibStorage, []),
346
347    %% type = bag solves the problem with import and multiple
348    %% object/type definitions.
349    case Mod:open(?MODULE, symbol, record_info(fields, symbol), bag, MsOpts) of
350	{ok, Db} ->
351	    S  = #state{module = Mod, db = Db},
352	    ?vdebug("started",[]),
353	    {ok, S};
354	{error, _} = ERROR ->
355	    ERROR
356    end.
357
358
359handle_call(get_db, _From, #state{db = DB} = S) ->
360    ?vlog("get db",[]),
361    {reply, DB, S};
362
363handle_call(which_module, _From, #state{module = Mod} = S) ->
364    ?vlog("which module",[]),
365    {reply, Mod, S};
366
367handle_call({table_info, TableName}, _From,
368	    #state{module = Mod, db = DB} = S) ->
369    ?vlog("table info: ~p",[TableName]),
370    Res = table_info(Mod, DB, TableName),
371    ?vdebug("table info result: ~p",[Res]),
372    {reply, Res, S};
373
374handle_call({variable_info, VariableName}, _From,
375	    #state{module = Mod, db = DB} = S) ->
376    ?vlog("variable info: ~p",[VariableName]),
377    Res = variable_info(Mod, DB, VariableName),
378    ?vdebug("variable info result: ~p",[Res]),
379    {reply, Res, S};
380
381handle_call({aliasname_to_oid, Aliasname}, _From,
382	    #state{module = Mod, db = DB} = S) ->
383    ?vlog("aliasname to oid: ~p",[Aliasname]),
384    Res = aliasname_to_oid(Mod, DB, Aliasname),
385    ?vdebug("aliasname to oid result: ~p",[Res]),
386    {reply, Res, S};
387
388handle_call({oid_to_aliasname, Oid}, _From,
389	    #state{module = Mod, db = DB} = S) ->
390    ?vlog("oid to aliasname: ~p",[Oid]),
391    Res = oid_to_aliasname(Mod, DB, Oid),
392    ?vdebug("oid to aliasname result: ~p",[Res]),
393    {reply, Res, S};
394
395handle_call(which_aliasnames, _From,
396	    #state{module = Mod, db = DB} = S) ->
397    ?vlog("which aliasnames",[]),
398    Res = which_aliasnames(Mod, DB),
399    ?vdebug("which aliasnames: ~p",[Res]),
400    {reply, Res, S};
401
402handle_call(which_tables, _From,
403	    #state{module = Mod, db = DB} = S) ->
404    ?vlog("which tables",[]),
405    Res = which_tables(Mod, DB),
406    ?vdebug("which tables: ~p",[Res]),
407    {reply, Res, S};
408
409handle_call(which_variables, _From,
410	    #state{module = Mod, db = DB} = S) ->
411    ?vlog("which variables",[]),
412    Res = which_variables(Mod, DB),
413    ?vdebug("which variables: ~p",[Res]),
414    {reply, Res, S};
415
416handle_call({enum_to_int, TypeOrObjName, Enum}, _From,
417	    #state{module = Mod, db = DB} = S) ->
418    ?vlog("enum to int: ~p, ~p",[TypeOrObjName,Enum]),
419    Res = enum_to_int(Mod, DB, TypeOrObjName, Enum),
420    ?vdebug("enum to int result: ~p",[Res]),
421    {reply, Res, S};
422
423handle_call({int_to_enum, TypeOrObjName, Int}, _From,
424	    #state{module = Mod, db = DB} = S) ->
425    ?vlog("int to enum: ~p, ~p",[TypeOrObjName,Int]),
426    Res = int_to_enum(Mod, DB, TypeOrObjName, Int),
427    ?vdebug("int to enum result: ~p",[Res]),
428    {reply, Res, S};
429
430handle_call({set_notification, MibName, Trap}, _From,
431	    #state{module = Mod, db = DB} = S) ->
432    ?vlog("set notification:"
433	  "~n   ~p~n   ~p", [MibName,Trap]),
434    set_notif(Mod, DB, MibName, Trap),
435    {reply, true, S};
436
437handle_call({delete_notifications, MibName}, _From,
438	    #state{module = Mod, db = DB} = S) ->
439    ?vlog("delete notification: ~p",[MibName]),
440    delete_notif(Mod, DB, MibName),
441    {reply, true, S};
442
443handle_call(which_notifications, _From,
444	    #state{module = Mod, db = DB} = S) ->
445    ?vlog("which notifications", []),
446    Reply = which_notifications(Mod, DB),
447    {reply, Reply, S};
448
449handle_call({get_notification, Key}, _From,
450	    #state{module = Mod, db = DB} = S) ->
451    ?vlog("get notification: ~p",[Key]),
452    Res = get_notif(Mod, DB, Key),
453    ?vdebug("get notification result: ~p",[Res]),
454    {reply, Res, S};
455
456handle_call(info, _From, #state{module = Mod, db = DB} = S) ->
457    ?vlog("info",[]),
458    Info = get_info(Mod, DB),
459    {reply, Info, S};
460
461handle_call({backup, BackupDir}, From, #state{module = Mod, db = DB} = S) ->
462    ?vlog("info to ~p",[BackupDir]),
463    Pid = self(),
464    V   = get(verbosity),
465    case file:read_file_info(BackupDir) of
466	{ok, #file_info{type = directory}} ->
467	    BackupServer =
468		erlang:spawn_link(
469		  fun() ->
470			  put(sname, albs),
471			  put(verbosity, V),
472			  Dir   = filename:join([BackupDir]),
473			  Reply = Mod:backup(DB, Dir),
474			  Pid ! {backup_done, Reply},
475			  unlink(Pid)
476		  end),
477	    ?vtrace("backup server: ~p", [BackupServer]),
478	    {noreply, S#state{backup = {BackupServer, From}}};
479	{ok, _} ->
480	    {reply, {error, not_a_directory}, S};
481	Error ->
482	    {reply, Error, S}
483    end;
484
485handle_call(stop, _From, S) ->
486    ?vlog("stop",[]),
487    {stop, normal, ok, S};
488
489handle_call(Req, _From, S) ->
490    info_msg("received unknown request: ~n~p", [Req]),
491    Reply = {error, {unknown, Req}},
492    {reply, Reply, S}.
493
494
495handle_cast({add_types, MibName, Types}, #state{module = Mod, db = DB} = S) ->
496    ?vlog("add types for ~p:",[MibName]),
497    F = fun(#asn1_type{assocList = Alist, aliasname = Name}) ->
498		case snmp_misc:assq(enums, Alist) of
499		    {value, Es} ->
500			?vlog("add type~n   ~p -> ~p",[Name,Es]),
501			Rec = #symbol{key      = {type, Name},
502				      mib_name = MibName,
503				      info     = Es},
504			Mod:write(DB, Rec);
505		    false -> done
506		end
507	end,
508    lists:foreach(F, Types),
509    {noreply, S};
510
511handle_cast({delete_types, MibName}, #state{module = Mod, db = DB} = S) ->
512    ?vlog("delete types: ~p",[MibName]),
513    Pattern = #symbol{key = {type, '_'}, mib_name = MibName, info = '_'},
514    Mod:match_delete(DB, Pattern),
515    {noreply, S};
516
517handle_cast({add_aliasnames, MibName, MEs},
518	    #state{module = Mod, db = DB} = S) ->
519    ?vlog("add aliasnames for ~p:",[MibName]),
520    F = fun(#me{aliasname = AN, oid = Oid, asn1_type = AT}) ->
521		Enums =
522		    case AT of
523			#asn1_type{assocList = Alist} ->
524			    case lists:keysearch(enums, 1, Alist) of
525				{value, {enums, Es}} -> Es;
526				_ -> []
527			    end;
528			_ -> []
529		    end,
530		write_alias(Mod, AN, DB, Enums, MibName, Oid)
531	end,
532    lists:foreach(F, MEs),
533    {noreply, S};
534
535handle_cast({delete_aliasname, MibName}, #state{module = Mod, db = DB} = S) ->
536    ?vlog("delete aliasname: ~p",[MibName]),
537    Pattern1 = #symbol{key = {alias, '_'}, mib_name = MibName, info = '_'},
538    Mod:match_delete(DB, Pattern1),
539    Pattern2 = #symbol{key = {oid, '_'}, mib_name = MibName, info = '_'},
540    Mod:match_delete(DB, Pattern2),
541    {noreply, S};
542
543handle_cast({add_table_infos, MibName, TableInfos},
544	    #state{module = Mod, db = DB} = S) ->
545    ?vlog("add table infos for ~p:",[MibName]),
546    F = fun({Name, TableInfo}) ->
547		?vlog("add table info~n   ~p -> ~p",
548		      [Name, TableInfo]),
549		Rec = #symbol{key      = {table_info, Name},
550			      mib_name = MibName,
551			      info     = TableInfo},
552		Mod:write(DB, Rec)
553	end,
554    lists:foreach(F, TableInfos),
555    {noreply, S};
556
557handle_cast({delete_table_infos, MibName},
558	    #state{module = Mod, db = DB} = S) ->
559    ?vlog("delete table infos: ~p",[MibName]),
560    Pattern = #symbol{key = {table_info, '_'}, mib_name = MibName, info = '_'},
561    Mod:match_delete(DB, Pattern),
562    {noreply, S};
563
564handle_cast({add_variable_infos, MibName, VariableInfos},
565	    #state{module = Mod, db = DB} = S) ->
566    ?vlog("add variable infos for ~p:",[MibName]),
567    F = fun({Name, VariableInfo}) ->
568		?vlog("add variable info~n   ~p -> ~p",
569		      [Name,VariableInfo]),
570		Rec = #symbol{key      = {variable_info, Name},
571			      mib_name = MibName,
572			      info     = VariableInfo},
573		Mod:write(DB, Rec)
574	end,
575    lists:foreach(F, VariableInfos),
576    {noreply, S};
577
578handle_cast({delete_variable_infos, MibName},
579	    #state{module = Mod, db = DB} = S) ->
580    ?vlog("delete variable infos: ~p",[MibName]),
581    Pattern = #symbol{key      = {variable_info,'_'},
582		      mib_name = MibName,
583		      info     = '_'},
584    Mod:match_delete(DB, Pattern),
585    {noreply, S};
586
587handle_cast({verbosity,Verbosity}, State) ->
588    ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
589    put(verbosity,snmp_verbosity:validate(Verbosity)),
590    {noreply, State};
591
592handle_cast(Msg, S) ->
593    info_msg("received unknown message: ~n~p", [Msg]),
594    {noreply, S}.
595
596
597handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) ->
598    ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]),
599    gen_server:reply(From, {error, Reason}),
600    {noreply, S#state{backup = undefined}};
601
602handle_info({'EXIT', Pid, Reason}, S) ->
603    %% The only other processes we should be linked to are
604    %% either the master agent or our supervisor, so die...
605    {stop, {received_exit, Pid, Reason}, S};
606
607handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) ->
608    ?vlog("backup done:"
609	  "~n   Reply: ~p", [Reply]),
610    gen_server:reply(From, Reply),
611    {noreply, S#state{backup = undefined}};
612
613handle_info(Info, S) ->
614    info_msg("received unknown info: ~n~p", [Info]),
615    {noreply, S}.
616
617
618terminate(Reason, #state{module = Mod, db = DB}) ->
619    ?vlog("terminate: ~p", [Reason]),
620    Mod:close(DB).
621
622
623%%----------------------------------------------------------
624%% Code change
625%%----------------------------------------------------------
626
627% downgrade
628%% code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
629%%     ?d("code_change(down) -> entry", []),
630%%     stop_backup_server(B),
631%%     S = {state, DB},
632%%     {ok, S};
633
634%% % upgrade
635%% code_change(_Vsn, S, upgrade_from_pre_4_7) ->
636%%     ?d("code_change(up) -> entry", []),
637%%     {state, DB} = S,
638%%     S1 = #state{db = DB},
639%%     {ok, S1};
640
641code_change(_Vsn, S, _Extra) ->
642    ?d("code_change -> entry [do nothing]", []),
643    {ok, S}.
644
645
646%% stop_backup_server(undefined) ->
647%%     ok;
648%% stop_backup_server({Pid, _}) when is_pid(Pid) ->
649%%     exit(Pid, kill).
650
651
652
653%%-----------------------------------------------------------------
654%% Trap operations (write, read, delete)
655%%-----------------------------------------------------------------
656%% A notification is stored as {Key, Value}, where
657%% Key is the symbolic trap name, and Value is
658%% a #trap or a #notification record.
659%%-----------------------------------------------------------------
660%% Returns: {value, Value} | undefined
661%%-----------------------------------------------------------------
662get_notif(Mod, Db, Key) ->
663    case Mod:read(Db, {trap, Key}) of
664	{value,#symbol{info = Value}} -> {value, Value};
665	false -> undefined
666    end.
667
668set_notif(Mod, Db, MibName, Trap) when is_record(Trap, trap) ->
669    #trap{trapname = Name} = Trap,
670    Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
671    %% convert old v1 trap to oid
672    Oid = case Trap#trap.enterpriseoid of
673	      ?snmp ->
674		  ?snmpTraps ++ [Trap#trap.specificcode + 1];
675	      Oid0 ->
676		  Oid0 ++ [0, Trap#trap.specificcode]
677	  end,
678    write_alias(Mod, Name, Db, MibName, Oid),
679    Mod:write(Db, Rec);
680set_notif(Mod, Db, MibName, Trap) ->
681    #notification{trapname = Name, oid = Oid} = Trap,
682    Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
683    write_alias(Mod, Name, Db, MibName, Oid),
684    Mod:write(Db, Rec).
685
686delete_notif(Mod, Db, MibName) ->
687    Pattern = #symbol{key = {trap, '_'}, mib_name = MibName, info = '_'},
688    Mod:match_delete(Db, Pattern).
689
690
691write_alias(Mod, AN, DB, MibName, Oid) ->
692    write_alias(Mod, AN, DB, [], MibName, Oid).
693
694write_alias(Mod, AN, DB, Enums, MibName, Oid) ->
695    ?vlog("add alias~n   ~p -> {~p,~p}",[AN, Oid, Enums]),
696    Rec1 = #symbol{key      = {alias, AN},
697		   mib_name = MibName,
698		   info     = {Oid,Enums}},
699    Mod:write(DB, Rec1),
700    ?vlog("add oid~n   ~p -> ~p",[Oid, AN]),
701    Rec2 = #symbol{key      = {oid, Oid},
702		   mib_name = MibName,
703		   info     = AN},
704    Mod:write(DB, Rec2).
705
706
707%% -------------------------------------
708
709get_info(Mod, DB) ->
710    ProcSize = proc_mem(self()),
711    DbMemory = Mod:info(DB, memory),
712    [{process_memory, ProcSize}, {db_memory, DbMemory}].
713
714proc_mem(P) when is_pid(P) ->
715    case (catch erlang:process_info(P, memory)) of
716	{memory, Sz} when is_integer(Sz) ->
717	    Sz;
718	_ ->
719	    undefined
720    end.
721
722
723%% -------------------------------------
724
725get_verbosity(L) ->
726    snmp_misc:get_option(verbosity, L, ?default_verbosity).
727
728get_mib_storage(L) ->
729    snmp_misc:get_option(mib_storage, L).
730
731
732%% -------------------------------------
733
734call(Req) ->
735    call(Req, infinity).
736
737call(Req, Timeout) ->
738    gen_server:call(?SERVER, Req, Timeout).
739
740cast(Msg) ->
741    gen_server:cast(?SERVER, Msg).
742
743
744%% ----------------------------------------------------------------
745
746info_msg(F, A) ->
747    error_logger:info_msg("~w: " ++ F ++ "~n", [?MODULE|A]).
748
749config_err(F, A) ->
750    snmpa_error:config_err(F, A).
751
752