1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2004-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_mib_lib).
21
22-export([table_cre_row/3, table_del_row/2]).
23-export([get_table/2]).
24-export([print_variables/1, print_table/3, print_table/4, print_tables/1]).
25-export([gc_tab/3, gc_tab/5]).
26
27-include("SNMPv2-TC.hrl").
28-include("snmp_types.hrl").
29
30-define(VMODULE,"MIB-LIB").
31-include("snmp_verbosity.hrl").
32
33-ifndef(default_verbosity).
34-define(default_verbosity,silence).
35-endif.
36
37
38%%%-----------------------------------------------------------------
39%%%-----------------------------------------------------------------
40
41%% returns: bool()
42table_cre_row({Tab, mnesia}, Key, _Row) ->
43    ?vtrace("create mnesia table ~w row with Key: ~w",[Tab, Key]),
44    {error, mnesia_not_supported};
45table_cre_row({Tab, Db} = TabDb, Key, Row) ->
46    ?vtrace("create ~w table ~w row with Key: ~w",[Db, Tab, Key]),
47    snmpa_local_db:table_create_row(TabDb, Key, Row).
48
49%% returns: bool()
50table_del_row({Tab, mnesia}, Key) ->
51    ?vtrace("delete mnesia table ~w row with Key: ~w",[Tab, Key]),
52    {error, mnesia_not_supported};
53table_del_row({Tab, Db} = TabDb, Key) ->
54    ?vtrace("delete ~w table ~w row with Key: ~w", [Db, Tab, Key]),
55    snmpa_local_db:table_delete_row(TabDb, Key).
56
57
58%%%-----------------------------------------------------------------
59%%% Retreives the entire table. Used for debugging
60%%%-----------------------------------------------------------------
61
62get_table(NameDb, FOI) ->
63    (catch get_table(NameDb, FOI, [], [])).
64
65get_table(NameDb, FOI, Key, Acc) ->
66    case table_next(NameDb, Key) of
67        endOfTable ->
68            ?vdebug("end of table",[]),
69            {ok, lists:reverse(Acc)};
70        Key ->
71            %% Crap, circular ref
72            ?vinfo("cyclic reference: ~w -> ~w", [Key, Key]),
73            throw({error, {cyclic_db_reference, Key, Acc}});
74        NextKey ->
75            ?vtrace("get row for key ~w", [NextKey]),
76            case table_get_row(NameDb, NextKey, FOI) of
77                undefined ->
78		    throw({error, {invalid_rowindex, NextKey, Acc}});
79                Row ->
80                    ?vtrace("row: ~w", [Row]),
81		    get_table(NameDb, FOI, NextKey, [{NextKey, Row}|Acc])
82            end
83    end.
84
85
86print_variables(Variables) when is_list(Variables) ->
87    Variables2 = print_variables_prefixify(Variables),
88    lists:foreach(fun({Variable, ValueResult, Prefix}) ->
89			  print_variable(Variable, ValueResult, Prefix)
90		  end, Variables2),
91    ok.
92
93print_variable(Variable, {value, Val}, Prefix) when is_atom(Variable) ->
94    io:format("~w~s=> ~p~n", [Variable, Prefix, Val]);
95print_variable(Variable, Error, Prefix) when is_atom(Variable) ->
96    io:format("~w~s=> [e] ~p~n", [Variable, Prefix, Error]).
97
98print_variables_prefixify(Variables) ->
99    MaxVarLength = print_variables_maxlength(Variables),
100    print_variables_prefixify(Variables, MaxVarLength, []).
101
102print_variables_prefixify([], _MaxVarLength, Acc) ->
103    lists:reverse(Acc);
104print_variables_prefixify([{Var, Res}|Variables], MaxVarLength, Acc) ->
105    Prefix = make_variable_print_prefix(Var, MaxVarLength),
106    print_variables_prefixify(Variables, MaxVarLength,
107			      [{Var, Res, Prefix}|Acc]).
108
109make_variable_print_prefix(Var, MaxVarLength) ->
110    lists:duplicate(MaxVarLength - length(atom_to_list(Var)) + 1, $ ).
111
112print_variables_maxlength(Variables) ->
113    print_variables_maxlength(Variables, 0).
114
115print_variables_maxlength([], MaxLength) ->
116    MaxLength;
117print_variables_maxlength([{Var, _}|Variables], MaxLength) when is_atom(Var) ->
118    VarLen = length(atom_to_list(Var)),
119    if
120	VarLen > MaxLength ->
121	    print_variables_maxlength(Variables, VarLen);
122	true ->
123	    print_variables_maxlength(Variables, MaxLength)
124    end.
125
126
127print_tables(Tables) when is_list(Tables) ->
128    lists:foreach(fun({Table, DB, FOI, PrintRow}) ->
129			  print_table(Table, DB, FOI, PrintRow)
130		  end, Tables),
131    ok.
132
133print_table(Table, DB, FOI, PrintRow) ->
134    TableInfo = get_table(DB, FOI),
135    print_table(Table, TableInfo, PrintRow).
136
137print_table(Table, TableInfo, PrintRow) when is_function(PrintRow, 2) ->
138    io:format("~w =>", [Table]),
139    do_print_table(TableInfo, PrintRow).
140
141do_print_table({ok, [] = _TableInfo}, _PrintRow) ->
142    io:format(" -~n", []);
143do_print_table({ok, TableInfo}, PrintRow) when is_function(PrintRow, 2) ->
144    io:format("~n", []),
145    lists:foreach(fun({RowIdx, Row}) ->
146			  io:format("   ~w => ~n~s~n",
147				    [RowIdx, PrintRow("      ", Row)])
148		  end, TableInfo);
149do_print_table({error, {invalid_rowindex, BadRowIndex, []}}, _PrintRow) ->
150    io:format("Error: Bad rowindex ~w~n", [BadRowIndex]);
151do_print_table({error, {invalid_rowindex, BadRowIndex, TableInfo}}, PrintRow) ->
152    io:format("Error: Bad rowindex ~w", [BadRowIndex]),
153    do_print_table(TableInfo, PrintRow);
154do_print_table(Error, _PrintRow) ->
155    io:format("Error: ~p~n", [Error]).
156
157
158%%%-----------------------------------------------------------------
159%%%
160%%%-----------------------------------------------------------------
161
162table_next({Name, mnesia}, RestOid) ->
163    snmp_generic_mnesia:table_next(Name, RestOid);
164table_next(NameDb, RestOid) ->
165    snmpa_local_db:table_next(NameDb, RestOid).
166
167
168table_get_row({Name, mnesia}, RowIndex) ->
169    snmp_generic_mnesia:table_get_row(Name, RowIndex);
170table_get_row(NameDb, RowIndex) ->
171    snmpa_local_db:table_get_row(NameDb, RowIndex).
172
173table_get_row(NameDb, RowIndex, undefined) ->
174    table_get_row(NameDb, RowIndex);
175table_get_row({Name, mnesia}, RowIndex, FOI) ->
176    snmp_generic_mnesia:table_get_row(Name, RowIndex, FOI);
177table_get_row(NameDb, RowIndex, _FOI) ->
178    snmpa_local_db:table_get_row(NameDb, RowIndex).
179
180
181%%%-----------------------------------------------------------------
182%%% Utility module for the mib-implementation modules (such as
183%%% snmp_target_mib).
184%%%-----------------------------------------------------------------
185
186gc_tab(TabDb, STC, FOI) ->
187    InvalidateRow = fun(_) -> ok end,
188    UpdateRow     = fun(_) -> ok end,
189    gc_tab(TabDb, STC, FOI, InvalidateRow, UpdateRow).
190
191gc_tab({Tab,mnesia} = TabDb, STC, FOI, InvalidateRow, UpdateRow) ->
192    F = fun(RowIndex, Row) ->
193		case element(STC, Row) of
194                    ?'StorageType_volatile' ->
195			snmp_generic_mnesia:table_delete_row(Tab, RowIndex),
196                        InvalidateRow(RowIndex);
197		    _ ->
198			UpdateRow(RowIndex)
199		end
200	end,
201    gc_tab1(F, TabDb, FOI);
202
203gc_tab(TabDb, STC, FOI, InvalidateRow, UpdateRow) ->
204    F = fun(RowIndex, Row) ->
205		case element(STC, Row) of
206 		    ?'StorageType_volatile' ->
207			snmpa_local_db:table_delete_row(TabDb, RowIndex),
208			InvalidateRow(RowIndex);
209		    _ ->
210			UpdateRow(RowIndex),
211			ok
212		end
213	end,
214    gc_tab1(F, TabDb, FOI).
215
216
217gc_tab1(F, {Tab,_} = TabDb, FOI) ->
218    case (catch snmp_generic:table_foreach(TabDb, F, FOI)) of
219	{'EXIT',{cyclic_db_reference,Oid}} ->
220	    %% Remove the row regardless of storage type since this
221	    %% is a major error. This row must be removed.
222	    case table_delete_row(TabDb, Oid) of
223		true ->
224		    ?vlog("deleted cyclic ref row for: ~w;~w",
225			  [Tab, Oid]),
226		    config_err("cyclic reference in table ~w: "
227			       "~w -> ~w. Row deleted",
228			       [Tab, Oid, Oid]),
229		    gc_tab1(F, TabDb, FOI);
230		false ->
231		    ?vlog("unable to remove faulty row from table ~w",
232			  [Tab]),
233		    config_err("failed removing faulty row. "
234			       "Giving up on table ~w cleanup", [Tab])
235	    end;
236	_ ->
237	    ok
238    end.
239
240table_delete_row({Tab, mnesia}, Oid) ->
241    snmp_generic_mnesia:table_delete_row(Tab, Oid),
242    true;
243table_delete_row(TabDb, Oid) ->
244    snmpa_local_db:table_delete_row(TabDb, Oid).
245
246config_err(F, A) ->
247    snmpa_error:config_err(F, A).
248