%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
%% Note that most of these functions *assume* that they are executed
%% by the agent. If they are not they may note work as they require
%% some properties to be set in the process dictionary!
%%
-module(snmpa_get_lib).
-export([
split_vbs/1, split_vbs/3,
split_vbs_view/2,
split_vbs_gb/2,
agent_sort_vbs/1,
oid_sort_vbs/1, org_index_sort_vbs/1,
sa_split/1,
delete_prefixes/2,
dbg_apply/3,
user_err/2
]).
-include("snmpa_internal.hrl").
-include("snmp_types.hrl").
-include("snmp_debug.hrl").
-include("snmp_verbosity.hrl").
%%-----------------------------------------------------------------
%% split_vbs/1,3
%%
%% Splits the list of varbinds (basically) into two lists. One
%% of 'end of'-varbinds (mib view and tables) and then the rest
%% of the varbinds.
%%-----------------------------------------------------------------
-spec split_vbs(VBs :: [snmp:varbind()]) ->
{ResVBs :: [snmp:varbind()],
EndOfVBs :: [snmp:varbind()]}.
split_vbs(VBs) ->
split_vbs(VBs, [], []).
-spec split_vbs(VBs :: [snmp:varbind()],
Res :: [snmp:varbind()],
EndOfs :: [snmp:varbind()]) ->
{ResVBs :: [snmp:varbind()],
EndOfVBs :: [snmp:varbind()]}.
split_vbs([], ResVBs, EndOfVBs) ->
{ResVBs, EndOfVBs};
split_vbs([VB | VBs], Res, EndOfs) ->
case VB#varbind.value of
{endOfMibView, _} -> split_vbs(VBs, Res, [VB | EndOfs]);
{endOfTable, _} -> split_vbs(VBs, Res, [VB | EndOfs]);
_ -> split_vbs(VBs, [VB | Res], EndOfs)
end.
%%-----------------------------------------------------------------
%% split_vbs_view/2
%%
%% Splits a list of varbinds into two lists based on the provided
%% MibView. One list of varbinds inside the MibView and one of
%% varbinds outside the MibView.
%%-----------------------------------------------------------------
-spec split_vbs_view(VBs :: [snmp:varbind()],
MibView :: snmp_view_based_acm_mib:mibview()) ->
{OutSideView :: [snmp:varbind()],
InSideView :: [snmp:varbind()]}.
split_vbs_view(VBs, MibView) ->
?vtrace("split the varbinds view", []),
split_vbs_view(VBs, MibView, [], []).
split_vbs_view([], _MibView, Out, In) ->
{Out, In};
split_vbs_view([VB | VBs], MibView, Out, In) ->
case snmpa_acm:validate_mib_view(VB#varbind.oid, MibView) of
true ->
split_vbs_view(VBs, MibView, Out, [VB | In]);
false ->
VB2 = VB#varbind{value = noSuchObject},
split_vbs_view(VBs, MibView, [VB2 | Out], In)
end.
%%-----------------------------------------------------------------
%% split_vbs_gb/2
%%
%% Performs a get-bulk split of the varbinds
%%-----------------------------------------------------------------
-spec split_vbs_gb(NonRepeaters :: integer(),
VBs :: [snmp:varbind()]) ->
{NonRepVBs :: [snmp:varbind()],
RestVBs :: [snmp:varbind()]}.
split_vbs_gb(N, VBs) ->
split_vbs_gb(N, VBs, []).
split_vbs_gb(N, Varbinds, Res) when N =< 0 ->
{Res, Varbinds};
split_vbs_gb(N, [H | T], Res) ->
split_vbs_gb(N-1, T, [H | Res]);
split_vbs_gb(_N, [], Res) ->
{Res, []}.
%%-----------------------------------------------------------------
%% agent_sort_vbs/1
%%
%% Sorts the varbinds into two categories. The first is varbinds
%% belonging to "our" agent and the other is varbinds for
%% subagents.
%%-----------------------------------------------------------------
-spec agent_sort_vbs(VBs :: [snmp:varbind()]) ->
{AgentVBs :: [snmp:varbind()],
SubAgentVBs :: [snmp:varbind()]}.
agent_sort_vbs(VBs) ->
snmpa_svbl:sort_varbindlist(get(mibserver), VBs).
%%-----------------------------------------------------------------
%% oid_sort_vbs/1
%%
%% Sorts the varbinds based on their oid.
%%-----------------------------------------------------------------
-spec oid_sort_vbs(VBs :: [snmp:varbind()]) -> SortedVBs :: [snmp:varbind()].
oid_sort_vbs(VBs) ->
lists:keysort(#varbind.oid, VBs).
%%-----------------------------------------------------------------
%% org_index_sort_vbs/1
%%
%% Sorts the varbinds based on their org_index.
%%-----------------------------------------------------------------
-spec org_index_sort_vbs(VBs :: [snmp:varbind()]) -> SortedVBs :: [snmp:varbind()].
org_index_sort_vbs(Vbs) ->
lists:keysort(#varbind.org_index, Vbs).
%%-----------------------------------------------------------------
%% sa_split/1
%%
%% Splits a list of {oid(), varbind()} into two lists of oid()
%% and varbind. The resulting lists are reversed!
%%-----------------------------------------------------------------
-spec sa_split(SAVBs :: [{SAOid :: snmp:oid(), snmp:varbind()}]) ->
{Oids :: [snmp:oid()], VBs :: [snmp:varbind()]}.
sa_split(SAVBs) ->
snmpa_svbl:sa_split(SAVBs).
%%-----------------------------------------------------------------
%% delete_prefixes/2
%%
%% Takes an Oid prefix and a list of ivarbinds and produces a list
%% of {ShortOid, ASN1Type}. The ShortOid is basically the oid with
%% the OidPrefix removed.
%%-----------------------------------------------------------------
-spec delete_prefixes(OidPrefix :: snmp:oid(),
VBs :: [snmp:ivarbind()]) ->
[{ShortOid :: snmp:oid(),
ASN1Type :: snmp:asn1_type()}].
delete_prefixes(OidPrefix, IVBs) ->
[{snmp_misc:diff(Oid, OidPrefix), ME#me.asn1_type} ||
#ivarbind{varbind = #varbind{oid = Oid}, mibentry = ME} <- IVBs].
%%-----------------------------------------------------------------
%% dbg_apply/3
%%
%% Call instrumentation functions, but allow for debug printing
%% of useful debug info.
%%-----------------------------------------------------------------
-spec dbg_apply(M :: atom(), F :: atom(), A :: list()) ->
any().
dbg_apply(M, F, A) ->
case get(verbosity) of
silence ->
apply(M,F,A);
_ ->
?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
Res = (catch apply(M,F,A)),
case Res of
{'EXIT', Reason} ->
?vinfo("Call to: "
"~n Module: ~p"
"~n Function: ~p"
"~n Args: ~p"
"~n"
"~nresulted in an exit"
"~n"
"~n ~p", [M, F, A, Reason]);
_ ->
?vlog("~n returned: ~p", [Res])
end,
Res
end.
%% ---------------------------------------------------------------------
user_err(F, A) ->
snmpa_error:user_err(F, A).