%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2004-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_mib_lib).
-export([table_cre_row/3, table_del_row/2]).
-export([get_table/2]).
-export([print_variables/1, print_table/3, print_table/4, print_tables/1]).
-export([gc_tab/3, gc_tab/5]).
-include("SNMPv2-TC.hrl").
-include("snmp_types.hrl").
-define(VMODULE,"MIB-LIB").
-include("snmp_verbosity.hrl").
-ifndef(default_verbosity).
-define(default_verbosity,silence).
-endif.
%%%-----------------------------------------------------------------
%%%-----------------------------------------------------------------
%% returns: bool()
table_cre_row({Tab, mnesia}, Key, _Row) ->
?vtrace("create mnesia table ~w row with Key: ~w",[Tab, Key]),
{error, mnesia_not_supported};
table_cre_row({Tab, Db} = TabDb, Key, Row) ->
?vtrace("create ~w table ~w row with Key: ~w",[Db, Tab, Key]),
snmpa_local_db:table_create_row(TabDb, Key, Row).
%% returns: bool()
table_del_row({Tab, mnesia}, Key) ->
?vtrace("delete mnesia table ~w row with Key: ~w",[Tab, Key]),
{error, mnesia_not_supported};
table_del_row({Tab, Db} = TabDb, Key) ->
?vtrace("delete ~w table ~w row with Key: ~w", [Db, Tab, Key]),
snmpa_local_db:table_delete_row(TabDb, Key).
%%%-----------------------------------------------------------------
%%% Retreives the entire table. Used for debugging
%%%-----------------------------------------------------------------
get_table(NameDb, FOI) ->
(catch get_table(NameDb, FOI, [], [])).
get_table(NameDb, FOI, Oid, Acc) ->
case table_next(NameDb, Oid) of
endOfTable ->
?vdebug("end of table",[]),
{ok, lists:reverse(Acc)};
Oid ->
%% Crap, circular ref
?vinfo("cyclic reference: ~w -> ~w", [Oid,Oid]),
throw({error, {cyclic_db_reference, Oid, Acc}});
NextOid ->
?vtrace("get row for oid ~w", [NextOid]),
case table_get_row(NameDb, NextOid, FOI) of
undefined ->
throw({error, {invalid_rowindex, NextOid, Acc}});
Row ->
?vtrace("row: ~w", [Row]),
get_table(NameDb, FOI, NextOid, [{NextOid, Row}|Acc])
end
end.
print_variables(Variables) when is_list(Variables) ->
Variables2 = print_variables_prefixify(Variables),
lists:foreach(fun({Variable, ValueResult, Prefix}) ->
print_variable(Variable, ValueResult, Prefix)
end, Variables2),
ok.
print_variable(Variable, {value, Val}, Prefix) when is_atom(Variable) ->
io:format("~w~s => ~p~n", [Variable, Prefix, Val]);
print_variable(Variable, Error, Prefix) when is_atom(Variable) ->
io:format("~w~s => ERROR: ~p~n", [Variable, Prefix, Error]).
print_variables_prefixify(Variables) ->
MaxVarLength = print_variables_maxlength(Variables),
print_variables_prefixify(Variables, MaxVarLength, []).
print_variables_prefixify([], _MaxVarLength, Acc) ->
lists:reverse(Acc);
print_variables_prefixify([{Var, Res}|Variables], MaxVarLength, Acc) ->
Prefix = make_variable_print_prefix(Var, MaxVarLength),
print_variables_prefixify(Variables, MaxVarLength,
[{Var, Res, Prefix}|Acc]).
make_variable_print_prefix(Var, MaxVarLength) ->
lists:duplicate(MaxVarLength - length(atom_to_list(Var)) + 1, $ ).
print_variables_maxlength(Variables) ->
print_variables_maxlength(Variables, 0).
print_variables_maxlength([], MaxLength) ->
MaxLength;
print_variables_maxlength([{Var, _}|Variables], MaxLength) when is_atom(Var) ->
VarLen = length(atom_to_list(Var)),
if
VarLen > MaxLength ->
print_variables_maxlength(Variables, VarLen);
true ->
print_variables_maxlength(Variables, MaxLength)
end.
print_tables(Tables) when is_list(Tables) ->
lists:foreach(fun({Table, DB, FOI, PrintRow}) ->
print_table(Table, DB, FOI, PrintRow)
end, Tables),
ok.
%% print_table(Table, DB, FOI, PrintRow) ->
%% TableInfo = get_table(DB(Table), FOI(Table)),
%% print_table(Table, TableInfo, PrintRow),
%% ok.
print_table(Table, DB, FOI, PrintRow) ->
TableInfo = get_table(DB, FOI),
print_table(Table, TableInfo, PrintRow).
print_table(Table, TableInfo, PrintRow) when is_function(PrintRow, 2) ->
io:format("~w => ~n", [Table]),
do_print_table(TableInfo, PrintRow).
do_print_table({ok, TableInfo}, PrintRow) when is_function(PrintRow, 2) ->
lists:foreach(fun({RowIdx, Row}) ->
io:format(" ~w => ~n~s~n",
[RowIdx, PrintRow(" ", Row)])
end, TableInfo),
io:format("~n", []);
do_print_table({error, {invalid_rowindex, BadRowIndex, []}}, _PrintRow) ->
io:format("Error: Bad rowindex ~w~n", [BadRowIndex]);
do_print_table({error, {invalid_rowindex, BadRowIndex, TableInfo}}, PrintRow) ->
io:format("Error: Bad rowindex ~w", [BadRowIndex]),
do_print_table(TableInfo, PrintRow);
do_print_table(Error, _PrintRow) ->
io:format("Error: ~p~n", [Error]).
%%%-----------------------------------------------------------------
%%%
%%%-----------------------------------------------------------------
table_next({Name, mnesia}, RestOid) ->
snmp_generic_mnesia:table_next(Name, RestOid);
table_next(NameDb, RestOid) ->
snmpa_local_db:table_next(NameDb, RestOid).
table_get_row({Name, mnesia}, RowIndex) ->
snmp_generic_mnesia:table_get_row(Name, RowIndex);
table_get_row(NameDb, RowIndex) ->
snmpa_local_db:table_get_row(NameDb, RowIndex).
table_get_row(NameDb, RowIndex, undefined) ->
table_get_row(NameDb, RowIndex);
table_get_row({Name, mnesia}, RowIndex, FOI) ->
snmp_generic_mnesia:table_get_row(Name, RowIndex, FOI);
table_get_row(NameDb, RowIndex, _FOI) ->
snmpa_local_db:table_get_row(NameDb, RowIndex).
%%%-----------------------------------------------------------------
%%% Utility module for the mib-implementation modules (such as
%%% snmp_target_mib).
%%%-----------------------------------------------------------------
gc_tab(TabDb, STC, FOI) ->
InvalidateRow = fun(_) -> ok end,
UpdateRow = fun(_) -> ok end,
gc_tab(TabDb, STC, FOI, InvalidateRow, UpdateRow).
gc_tab({Tab,mnesia} = TabDb, STC, FOI, InvalidateRow, UpdateRow) ->
F = fun(RowIndex, Row) ->
case element(STC, Row) of
?'StorageType_volatile' ->
snmp_generic_mnesia:table_delete_row(Tab, RowIndex),
InvalidateRow(RowIndex);
_ ->
UpdateRow(RowIndex)
end
end,
gc_tab1(F, TabDb, FOI);
gc_tab(TabDb, STC, FOI, InvalidateRow, UpdateRow) ->
F = fun(RowIndex, Row) ->
case element(STC, Row) of
?'StorageType_volatile' ->
snmpa_local_db:table_delete_row(TabDb, RowIndex),
InvalidateRow(RowIndex);
_ ->
UpdateRow(RowIndex),
ok
end
end,
gc_tab1(F, TabDb, FOI).
gc_tab1(F, {Tab,_} = TabDb, FOI) ->
case (catch snmp_generic:table_foreach(TabDb, F, FOI)) of
{'EXIT',{cyclic_db_reference,Oid}} ->
%% Remove the row regardless of storage type since this
%% is a major error. This row must be removed.
case table_delete_row(TabDb, Oid) of
true ->
?vlog("deleted cyclic ref row for: ~w;~w",
[Tab, Oid]),
config_err("cyclic reference in table ~w: "
"~w -> ~w. Row deleted",
[Tab, Oid, Oid]),
gc_tab1(F, TabDb, FOI);
false ->
?vlog("unable to remove faulty row from table ~w",
[Tab]),
config_err("failed removing faulty row. "
"Giving up on table ~w cleanup", [Tab])
end;
_ ->
ok
end.
table_delete_row({Tab, mnesia}, Oid) ->
snmp_generic_mnesia:table_delete_row(Tab, Oid),
true;
table_delete_row(TabDb, Oid) ->
snmpa_local_db:table_delete_row(TabDb, Oid).
config_err(F, A) ->
snmpa_error:config_err(F, A).