aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/src/agent/snmpa_symbolic_store.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/src/agent/snmpa_symbolic_store.erl')
-rw-r--r--lib/snmp/src/agent/snmpa_symbolic_store.erl711
1 files changed, 711 insertions, 0 deletions
diff --git a/lib/snmp/src/agent/snmpa_symbolic_store.erl b/lib/snmp/src/agent/snmpa_symbolic_store.erl
new file mode 100644
index 0000000000..6c58ffde41
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_symbolic_store.erl
@@ -0,0 +1,711 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(snmpa_symbolic_store).
+
+%%----------------------------------------------------------------------
+%% This module implements a multipurpose symbolic store.
+%% 1) For internal and use from application: aliasname_to_value/1.
+%% If this was stored in the mib, deadlock would occur.
+%% 2 table_info/1. Getting information about a table. Used by default
+%% implementation of tables.
+%% 3) variable_info/1. Used by default implementation of variables.
+%% 4) notification storage. Used by snmpa_trap.
+%% There is one symbolic store per node and it uses the ets table
+%% snmp_agent_table, owned by the snmpa_supervisor.
+%%
+%%----------------------------------------------------------------------
+
+-include_lib("kernel/include/file.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+-include("SNMPv2-MIB.hrl").
+
+
+%% API
+-export([start_link/2,
+ stop/0,
+ info/0,
+ backup/1,
+ aliasname_to_oid/1, oid_to_aliasname/1,
+ add_aliasnames/2, delete_aliasnames/1,
+ which_aliasnames/0,
+ which_tables/0,
+ which_variables/0,
+ enum_to_int/2, int_to_enum/2,
+ table_info/1, add_table_infos/2, delete_table_infos/1,
+ variable_info/1, add_variable_infos/2, delete_variable_infos/1,
+ get_notification/1, set_notification/2,
+ delete_notifications/1, which_notifications/0,
+ add_types/2, delete_types/1]).
+
+%% API (for quick access to the db, note that this is only reads).
+-export([get_db/0,
+ aliasname_to_oid/2, oid_to_aliasname/2,
+ enum_to_int/3, int_to_enum/3]).
+
+
+%% Internal exports
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+
+-export([verbosity/1]).
+
+-define(SERVER, ?MODULE).
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Prio, Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts],
+ [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Prio, Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts], [])).
+-endif.
+
+-record(state, {db, backup}).
+-record(symbol, {key, mib_name, info}).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Args: Prio is priority of mib-server
+%% Opts is a list of options
+%% Purpose: starts the mib server synchronized
+%% Returns: {ok, Pid} | {error, Reason}
+%%-----------------------------------------------------------------
+start_link(Prio, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n Opts: ~p", [Prio,Opts]),
+ ?GS_START_LINK(Prio,Opts).
+
+stop() ->
+ call(stop).
+
+info() ->
+ call(info).
+
+backup(BackupDir) ->
+ call({backup, BackupDir}).
+
+
+%%----------------------------------------------------------------------
+%% Returns: Db
+%%----------------------------------------------------------------------
+
+get_db() ->
+ call(get_db).
+
+
+%%----------------------------------------------------------------------
+%% Returns: {value, Oid} | false
+%%----------------------------------------------------------------------
+aliasname_to_oid(Aliasname) ->
+ call({aliasname_to_oid, Aliasname}).
+
+oid_to_aliasname(OID) ->
+ call({oid_to_aliasname, OID}).
+
+int_to_enum(TypeOrObjName, Int) ->
+ call({int_to_enum,TypeOrObjName,Int}).
+
+enum_to_int(TypeOrObjName, Enum) ->
+ call({enum_to_int,TypeOrObjName,Enum}).
+
+add_types(MibName, Types) ->
+ cast({add_types, MibName, Types}).
+
+delete_types(MibName) ->
+ cast({delete_types, MibName}).
+
+add_aliasnames(MibName, MEs) ->
+ cast({add_aliasnames, MibName, MEs}).
+
+delete_aliasnames(MibName) ->
+ cast({delete_aliasname, MibName}).
+
+which_aliasnames() ->
+ call(which_aliasnames).
+
+which_tables() ->
+ call(which_tables).
+
+which_variables() ->
+ call(which_variables).
+
+
+%%----------------------------------------------------------------------
+%% Returns: false|{value, Info}
+%%----------------------------------------------------------------------
+table_info(TableName) ->
+ call({table_info, TableName}).
+
+
+%%----------------------------------------------------------------------
+%% Returns: false|{value, Info}
+%%----------------------------------------------------------------------
+variable_info(VariableName) ->
+ call({variable_info, VariableName}).
+
+add_table_infos(MibName, TableInfos) ->
+ cast({add_table_infos, MibName, TableInfos}).
+
+delete_table_infos(MibName) ->
+ cast({delete_table_infos, MibName}).
+
+add_variable_infos(MibName, VariableInfos) ->
+ cast({add_variable_infos, MibName, VariableInfos}).
+
+delete_variable_infos(MibName) ->
+ cast({delete_variable_infos, MibName}).
+
+
+%%-----------------------------------------------------------------
+%% Store traps
+%%-----------------------------------------------------------------
+%% A notification is stored as {Key, Value}, where
+%% Key is the symbolic trap name, and Value is
+%% a #trap record.
+%%-----------------------------------------------------------------
+%% Returns: {value, Val} | undefined
+%%-----------------------------------------------------------------
+get_notification(Key) ->
+ call({get_notification, Key}).
+set_notification(Trap, MibName) ->
+ call({set_notification, MibName, Trap}).
+delete_notifications(MibName) ->
+ call({delete_notifications, MibName}).
+which_notifications() ->
+ call(which_notifications).
+
+
+verbosity(Verbosity) ->
+ cast({verbosity,Verbosity}).
+
+
+%%----------------------------------------------------------------------
+%% DB access (read) functions: Returns: {value, Oid} | false
+%%----------------------------------------------------------------------
+aliasname_to_oid(Db, Aliasname) ->
+ case snmpa_general_db:read(Db, {alias, Aliasname}) of
+ {value,#symbol{info = {Oid, _Enums}}} -> {value, Oid};
+ false -> false
+ end.
+
+oid_to_aliasname(Db,Oid) ->
+ case snmpa_general_db:read(Db, {oid, Oid}) of
+ {value,#symbol{info = Aliasname}} -> {value, Aliasname};
+ _ -> false
+ end.
+
+which_notifications(Db) ->
+ Pattern = #symbol{key = {trap, '_'}, _ = '_'},
+ Symbols = snmpa_general_db:match_object(Db, Pattern),
+ [{Name, Mib, Rec} || #symbol{key = {trap, Name},
+ mib_name = Mib,
+ info = Rec} <- Symbols].
+
+which_aliasnames(Db) ->
+ Pattern = #symbol{key = {alias, '_'}, _ = '_'},
+ Symbols = snmpa_general_db:match_object(Db, Pattern),
+ [Alias || #symbol{key = {alias, Alias}} <- Symbols].
+
+which_tables(Db) ->
+ Pattern = #symbol{key = {table_info, '_'}, _ = '_'},
+ Symbols = snmpa_general_db:match_object(Db, Pattern),
+ [Name || #symbol{key = {table_info, Name}} <- Symbols].
+
+which_variables(Db) ->
+ Pattern = #symbol{key = {variable_info, '_'}, _ = '_'},
+ Symbols = snmpa_general_db:match_object(Db, Pattern),
+ [Name || #symbol{key = {variable_info, Name}} <- Symbols].
+
+int_to_enum(Db,TypeOrObjName,Int) ->
+ case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+ {value,#symbol{info = {_Oid, Enums}}} ->
+ case lists:keysearch(Int, 2, Enums) of
+ {value, {Enum, _Int}} -> {value, Enum};
+ false -> false
+ end;
+ false -> % Not an Aliasname ->
+ case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ {value,#symbol{info = Enums}} ->
+ case lists:keysearch(Int, 2, Enums) of
+ {value, {Enum, _Int}} -> {value, Enum};
+ false -> false
+ end;
+ false ->
+ false
+ end
+ end.
+
+enum_to_int(Db, TypeOrObjName, Enum) ->
+ case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+ {value,#symbol{info = {_Oid, Enums}}} ->
+ case lists:keysearch(Enum, 1, Enums) of
+ {value, {_Enum, Int}} -> {value, Int};
+ false -> false
+ end;
+ false -> % Not an Aliasname
+ case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ {value,#symbol{info = Enums}} ->
+ case lists:keysearch(Enum, 1, Enums) of
+ {value, {_Enum, Int}} -> {value, Int};
+ false -> false
+ end;
+ false ->
+ false
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% DB access (read) functions: Returns: false|{value, Info}
+%%----------------------------------------------------------------------
+table_info(Db,TableName) ->
+ case snmpa_general_db:read(Db, {table_info, TableName}) of
+ {value,#symbol{info = Info}} -> {value, Info};
+ false -> false
+ end.
+
+
+%%----------------------------------------------------------------------
+%% DB access (read) functions: Returns: false|{value, Info}
+%%----------------------------------------------------------------------
+variable_info(Db,VariableName) ->
+ case snmpa_general_db:read(Db, {variable_info, VariableName}) of
+ {value,#symbol{info = Info}} -> {value, Info};
+ false -> false
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Implementation
+%%----------------------------------------------------------------------
+
+init([Prio,Opts]) ->
+ ?d("init -> entry with"
+ "~n Prio: ~p"
+ "~n Opts: ~p", [Prio,Opts]),
+ case (catch do_init(Prio, Opts)) of
+ {ok, State} ->
+ {ok, State};
+ Error ->
+ config_err("failed starting symbolic-store: ~n~p", [Error]),
+ {stop, {error, Error}}
+ end.
+
+do_init(Prio, Opts) ->
+ process_flag(priority, Prio),
+ process_flag(trap_exit, true),
+ put(sname,ss),
+ put(verbosity,get_verbosity(Opts)),
+ ?vlog("starting",[]),
+ Storage = get_mib_storage(Opts),
+ %% type = bag solves the problem with import and multiple
+ %% object/type definitions.
+ Db = snmpa_general_db:open(Storage, snmpa_symbolic_store,
+ symbol, record_info(fields,symbol), bag),
+ S = #state{db = Db},
+ ?vdebug("started",[]),
+ {ok, S}.
+
+
+handle_call(get_db, _From, #state{db = DB} = S) ->
+ ?vlog("get db",[]),
+ {reply, DB, S};
+
+handle_call({table_info, TableName}, _From, #state{db = DB} = S) ->
+ ?vlog("table info: ~p",[TableName]),
+ Res = table_info(DB, TableName),
+ ?vdebug("table info result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({variable_info, VariableName}, _From, #state{db = DB} = S) ->
+ ?vlog("variable info: ~p",[VariableName]),
+ Res = variable_info(DB, VariableName),
+ ?vdebug("variable info result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({aliasname_to_oid, Aliasname}, _From, #state{db = DB} = S) ->
+ ?vlog("aliasname to oid: ~p",[Aliasname]),
+ Res = aliasname_to_oid(DB,Aliasname),
+ ?vdebug("aliasname to oid result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({oid_to_aliasname, Oid}, _From, #state{db = DB} = S) ->
+ ?vlog("oid to aliasname: ~p",[Oid]),
+ Res = oid_to_aliasname(DB, Oid),
+ ?vdebug("oid to aliasname result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call(which_aliasnames, _From, #state{db = DB} = S) ->
+ ?vlog("which aliasnames",[]),
+ Res = which_aliasnames(DB),
+ ?vdebug("which aliasnames: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call(which_tables, _From, #state{db = DB} = S) ->
+ ?vlog("which tables",[]),
+ Res = which_tables(DB),
+ ?vdebug("which tables: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call(which_variables, _From, #state{db = DB} = S) ->
+ ?vlog("which variables",[]),
+ Res = which_variables(DB),
+ ?vdebug("which variables: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({enum_to_int, TypeOrObjName, Enum}, _From, #state{db = DB} = S) ->
+ ?vlog("enum to int: ~p, ~p",[TypeOrObjName,Enum]),
+ Res = enum_to_int(DB, TypeOrObjName, Enum),
+ ?vdebug("enum to int result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({int_to_enum, TypeOrObjName, Int}, _From, #state{db = DB} = S) ->
+ ?vlog("int to enum: ~p, ~p",[TypeOrObjName,Int]),
+ Res = int_to_enum(DB, TypeOrObjName, Int),
+ ?vdebug("int to enum result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({set_notification, MibName, Trap}, _From, #state{db = DB} = S) ->
+ ?vlog("set notification:"
+ "~n ~p~n ~p", [MibName,Trap]),
+ set_notif(DB, MibName, Trap),
+ {reply, true, S};
+
+handle_call({delete_notifications, MibName}, _From, #state{db = DB} = S) ->
+ ?vlog("delete notification: ~p",[MibName]),
+ delete_notif(DB, MibName),
+ {reply, true, S};
+
+handle_call(which_notifications, _From, #state{db = DB} = S) ->
+ ?vlog("which notifications", []),
+ Reply = which_notifications(DB),
+ {reply, Reply, S};
+
+handle_call({get_notification, Key}, _From, #state{db = DB} = S) ->
+ ?vlog("get notification: ~p",[Key]),
+ Res = get_notif(DB, Key),
+ ?vdebug("get notification result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call(info, _From, #state{db = DB} = S) ->
+ ?vlog("info",[]),
+ Info = get_info(DB),
+ {reply, Info, S};
+
+handle_call({backup, BackupDir}, From, #state{db = DB} = S) ->
+ ?vlog("info to ~p",[BackupDir]),
+ Pid = self(),
+ V = get(verbosity),
+ case file:read_file_info(BackupDir) of
+ {ok, #file_info{type = directory}} ->
+ BackupServer =
+ erlang:spawn_link(
+ fun() ->
+ put(sname, albs),
+ put(verbosity, V),
+ Dir = filename:join([BackupDir]),
+ Reply = snmpa_general_db:backup(DB, Dir),
+ Pid ! {backup_done, Reply},
+ unlink(Pid)
+ end),
+ ?vtrace("backup server: ~p", [BackupServer]),
+ {noreply, S#state{backup = {BackupServer, From}}};
+ {ok, _} ->
+ {reply, {error, not_a_directory}, S};
+ Error ->
+ {reply, Error, S}
+ end;
+
+handle_call(stop, _From, S) ->
+ ?vlog("stop",[]),
+ {stop, normal, ok, S};
+
+handle_call(Req, _From, S) ->
+ info_msg("received unknown request: ~n~p", [Req]),
+ Reply = {error, {unknown, Req}},
+ {reply, Reply, S}.
+
+
+handle_cast({add_types, MibName, Types}, #state{db = DB} = S) ->
+ ?vlog("add types for ~p:",[MibName]),
+ F = fun(#asn1_type{assocList = Alist, aliasname = Name}) ->
+ case snmp_misc:assq(enums, Alist) of
+ {value, Es} ->
+ ?vlog("add type~n ~p -> ~p",[Name,Es]),
+ Rec = #symbol{key = {type, Name},
+ mib_name = MibName,
+ info = Es},
+ snmpa_general_db:write(DB, Rec);
+ false -> done
+ end
+ end,
+ lists:foreach(F, Types),
+ {noreply, S};
+
+handle_cast({delete_types, MibName}, #state{db = DB} = S) ->
+ ?vlog("delete types: ~p",[MibName]),
+ Pattern = #symbol{key = {type, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern),
+ {noreply, S};
+
+handle_cast({add_aliasnames, MibName, MEs}, #state{db = DB} = S) ->
+ ?vlog("add aliasnames for ~p:",[MibName]),
+ F = fun(#me{aliasname = AN, oid = Oid, asn1_type = AT}) ->
+ Enums =
+ case AT of
+ #asn1_type{assocList = Alist} ->
+ case lists:keysearch(enums, 1, Alist) of
+ {value, {enums, Es}} -> Es;
+ _ -> []
+ end;
+ _ -> []
+ end,
+ write_alias(AN, DB, Enums, MibName, Oid)
+ end,
+ lists:foreach(F, MEs),
+ {noreply, S};
+
+handle_cast({delete_aliasname, MibName}, #state{db = DB} = S) ->
+ ?vlog("delete aliasname: ~p",[MibName]),
+ Pattern1 = #symbol{key = {alias, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern1),
+ Pattern2 = #symbol{key = {oid, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern2),
+ {noreply, S};
+
+handle_cast({add_table_infos, MibName, TableInfos}, #state{db = DB} = S) ->
+ ?vlog("add table infos for ~p:",[MibName]),
+ F = fun({Name, TableInfo}) ->
+ ?vlog("add table info~n ~p -> ~p",
+ [Name, TableInfo]),
+ Rec = #symbol{key = {table_info, Name},
+ mib_name = MibName,
+ info = TableInfo},
+ snmpa_general_db:write(DB, Rec)
+ end,
+ lists:foreach(F, TableInfos),
+ {noreply, S};
+
+handle_cast({delete_table_infos, MibName}, #state{db = DB} = S) ->
+ ?vlog("delete table infos: ~p",[MibName]),
+ Pattern = #symbol{key = {table_info, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern),
+ {noreply, S};
+
+handle_cast({add_variable_infos, MibName, VariableInfos},
+ #state{db = DB} = S) ->
+ ?vlog("add variable infos for ~p:",[MibName]),
+ F = fun({Name, VariableInfo}) ->
+ ?vlog("add variable info~n ~p -> ~p",
+ [Name,VariableInfo]),
+ Rec = #symbol{key = {variable_info, Name},
+ mib_name = MibName,
+ info = VariableInfo},
+ snmpa_general_db:write(DB, Rec)
+ end,
+ lists:foreach(F, VariableInfos),
+ {noreply, S};
+
+handle_cast({delete_variable_infos, MibName}, #state{db = DB} = S) ->
+ ?vlog("delete variable infos: ~p",[MibName]),
+ Pattern = #symbol{key = {variable_info,'_'},
+ mib_name = MibName,
+ info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern),
+ {noreply, S};
+
+handle_cast({verbosity,Verbosity}, State) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+ put(verbosity,snmp_verbosity:validate(Verbosity)),
+ {noreply, State};
+
+handle_cast(Msg, S) ->
+ info_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, S}.
+
+
+handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) ->
+ ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]),
+ gen_server:reply(From, {error, Reason}),
+ {noreply, S#state{backup = undefined}};
+
+handle_info({'EXIT', Pid, Reason}, S) ->
+ %% The only other processes we should be linked to are
+ %% either the master agent or our supervisor, so die...
+ {stop, {received_exit, Pid, Reason}, S};
+
+handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) ->
+ ?vlog("backup done:"
+ "~n Reply: ~p", [Reply]),
+ gen_server:reply(From, Reply),
+ {noreply, S#state{backup = undefined}};
+
+handle_info(Info, S) ->
+ info_msg("received unknown info: ~n~p", [Info]),
+ {noreply, S}.
+
+
+terminate(Reason, S) ->
+ ?vlog("terminate: ~p",[Reason]),
+ snmpa_general_db:close(S#state.db).
+
+
+%%----------------------------------------------------------
+%% Code change
+%%----------------------------------------------------------
+
+% downgrade
+code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
+ ?d("code_change(down) -> entry", []),
+ stop_backup_server(B),
+ S = {state, DB},
+ {ok, S};
+
+% upgrade
+code_change(_Vsn, S, upgrade_from_pre_4_7) ->
+ ?d("code_change(up) -> entry", []),
+ {state, DB} = S,
+ S1 = #state{db = DB},
+ {ok, S1};
+
+code_change(_Vsn, S, _Extra) ->
+ ?d("code_change -> entry [do nothing]", []),
+ {ok, S}.
+
+
+stop_backup_server(undefined) ->
+ ok;
+stop_backup_server({Pid, _}) when is_pid(Pid) ->
+ exit(Pid, kill).
+
+
+
+%%-----------------------------------------------------------------
+%% Trap operations (write, read, delete)
+%%-----------------------------------------------------------------
+%% A notification is stored as {Key, Value}, where
+%% Key is the symbolic trap name, and Value is
+%% a #trap or a #notification record.
+%%-----------------------------------------------------------------
+%% Returns: {value, Value} | undefined
+%%-----------------------------------------------------------------
+get_notif(Db, Key) ->
+ case snmpa_general_db:read(Db, {trap, Key}) of
+ {value,#symbol{info = Value}} -> {value, Value};
+ false -> undefined
+ end.
+
+set_notif(Db, MibName, Trap) when is_record(Trap, trap) ->
+ #trap{trapname = Name} = Trap,
+ Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
+ %% convert old v1 trap to oid
+ Oid = case Trap#trap.enterpriseoid of
+ ?snmp ->
+ ?snmpTraps ++ [Trap#trap.specificcode + 1];
+ Oid0 ->
+ Oid0 ++ [0, Trap#trap.specificcode]
+ end,
+ write_alias(Name, Db, MibName, Oid),
+ snmpa_general_db:write(Db, Rec);
+set_notif(Db, MibName, Trap) ->
+ #notification{trapname = Name, oid = Oid} = Trap,
+ Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
+ write_alias(Name, Db, MibName, Oid),
+ snmpa_general_db:write(Db, Rec).
+
+delete_notif(Db, MibName) ->
+ Pattern = #symbol{key = {trap, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(Db, Pattern).
+
+
+write_alias(AN, DB, MibName, Oid) ->
+ write_alias(AN, DB, [], MibName, Oid).
+
+write_alias(AN, DB, Enums, MibName, Oid) ->
+ ?vlog("add alias~n ~p -> {~p,~p}",[AN, Oid, Enums]),
+ Rec1 = #symbol{key = {alias, AN},
+ mib_name = MibName,
+ info = {Oid,Enums}},
+ snmpa_general_db:write(DB, Rec1),
+ ?vlog("add oid~n ~p -> ~p",[Oid, AN]),
+ Rec2 = #symbol{key = {oid, Oid},
+ mib_name = MibName,
+ info = AN},
+ snmpa_general_db:write(DB, Rec2).
+
+%% -------------------------------------
+
+get_info(DB) ->
+ ProcSize = proc_mem(self()),
+ DbSz = tab_size(DB),
+ [{process_memory, ProcSize}, {db_memory, DbSz}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+%% proc_mem(_) ->
+%% undefined.
+
+tab_size(DB) ->
+ case (catch snmpa_general_db:info(DB, memory)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+
+
+
+%% -------------------------------------
+
+get_verbosity(L) ->
+ snmp_misc:get_option(verbosity,L,?default_verbosity).
+
+get_mib_storage(L) ->
+ snmp_misc:get_option(mib_storage,L,ets).
+
+
+%% -------------------------------------
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, Timeout) ->
+ gen_server:call(?SERVER, Req, Timeout).
+
+cast(Msg) ->
+ gen_server:cast(?SERVER, Msg).
+
+
+%% ----------------------------------------------------------------
+
+info_msg(F, A) ->
+ error_logger:info_msg("~w: " ++ F ++ "~n", [?MODULE|A]).
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
+