diff options
Diffstat (limited to 'lib/snmp/src/compile/snmpc_mib_to_hrl.erl')
-rw-r--r-- | lib/snmp/src/compile/snmpc_mib_to_hrl.erl | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/lib/snmp/src/compile/snmpc_mib_to_hrl.erl b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl new file mode 100644 index 0000000000..07bd29231b --- /dev/null +++ b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl @@ -0,0 +1,391 @@ +%% +%% %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(snmpc_mib_to_hrl). + +-include_lib("stdlib/include/erl_compile.hrl"). +-include("snmp_types.hrl"). +-include("snmpc_lib.hrl"). + +%% External exports +-export([convert/1, compile/3]). + +%%----------------------------------------------------------------- +%% Func: convert/1 +%% Args: MibName = string() without extension. +%% Purpose: Produce a .hrl file with oid for tables and variables, +%% column numbers for columns and values for enums. +%% Writes only the first occurence of a name. Prints a +%% warning if a duplicate name is found. +%% Returns: ok | {error, Reason} +%% Note: The Mib must be compiled. +%%----------------------------------------------------------------- +convert(MibName) -> + MibFile = MibName ++ ".bin", + HrlFile = MibName ++ ".hrl", + put(verbosity, trace), + convert(MibFile, HrlFile, MibName). + +convert(MibFile, HrlFile, MibName) -> + ?vtrace("convert -> entry with" + "~n MibFile: ~s" + "~n HrlFile: ~s" + "~n MibName: ~s", [MibFile, HrlFile, MibName]), + case snmpc_misc:read_mib(MibFile) of + {ok, #mib{asn1_types = Types, mes = MEs, traps = Traps}} -> + ?vdebug("mib successfully read", []), + resolve(Types, MEs, Traps, HrlFile, + filename:basename(MibName)), + ok; + {error, Reason} -> + ?vinfo("failed reading mib: " + "~n Reason: ~p", [Reason]), + {error, Reason} + end. + +resolve(Types, MEs, Traps, HrlFile, MibName) -> + ?vtrace("resolve -> entry", []), + case file:open(HrlFile, [write]) of + {ok, Fd} -> + insert_header(Fd), + insert_begin(Fd, MibName), + insert_notifs(Traps, Fd), + insert_oids(MEs, Fd), + insert_range(MEs, Fd), + insert_enums(Types, MEs, Fd), + insert_defvals(MEs, Fd), + insert_end(Fd), + file:close(Fd), + ?vlog("~s written", [HrlFile]); + {error, Reason} -> + ?vinfo("failed opening output file: " + "~n Reason: ~p", [Reason]), + {error, Reason} + end. + +insert_header(Fd) -> + ?vdebug("insert file header", []), + io:format(Fd, "%%% This file was automatically generated by " + "snmpc_mib_to_hrl version ~s~n", [?version]), + {Y,Mo,D} = date(), + {H,Mi,S} = time(), + io:format(Fd, "%%% Date: ~2.2.0w-~s-~w::~2.2.0w:~2.2.0w:~2.2.0w~n", + [D,month(Mo),Y,H,Mi,S]). + +insert_begin(Fd, MibName) -> + ?vdebug("insert file begin", []), + io:format(Fd, + "-ifndef('~s').~n" + "-define('~s', true).~n", [MibName, MibName]). + +insert_end(Fd) -> + ?vdebug("insert file end", []), + io:format(Fd, "-endif.~n", []). + +insert_oids(MEs, Fd) -> + ?vdebug("insert oids", []), + io:format(Fd, "~n%% Oids~n", []), + insert_oids2(MEs, Fd), + io:format(Fd, "~n", []). + +insert_oids2([#me{imported = true} | T], Fd) -> + insert_oids2(T, Fd); +insert_oids2([#me{entrytype = table_column, oid = Oid, aliasname = Name} | T], + Fd) -> + ?vtrace("insert oid [table column]: ~p - ~w", [Name, Oid]), + io:format(Fd, "-define(~w, ~w).~n", [Name, lists:last(Oid)]), + insert_oids2(T, Fd); +insert_oids2([#me{entrytype = variable, oid = Oid, aliasname = Name} | T], + Fd) -> + ?vtrace("insert oid [variable]: ~p - ~w", [Name, Oid]), + io:format(Fd, "-define(~w, ~w).~n", [Name, Oid]), + io:format(Fd, "-define(~w, ~w).~n", [merge_atoms(Name, instance), + Oid ++ [0]]), + insert_oids2(T, Fd); +insert_oids2([#me{oid = Oid, aliasname = Name} | T], Fd) -> + ?vtrace("insert oid: ~p - ~w", [Name, Oid]), + io:format(Fd, "~n-define(~w, ~w).~n", [Name, Oid]), + insert_oids2(T, Fd); +insert_oids2([], _Fd) -> + ok. + + +insert_notifs(Traps, Fd) -> + ?vdebug("insert notifications", []), + Notifs = [Notif || Notif <- Traps, is_record(Notif, notification)], + case Notifs of + [] -> + ok; + _ -> + io:format(Fd, "~n%% Notifications~n", []), + insert_notifs2(Notifs, Fd) + end. + +insert_notifs2([], _Fd) -> + ok; +insert_notifs2([#notification{trapname = Name, oid = Oid}|T], Fd) -> + ?vtrace("insert notification ~p - ~w", [Name, Oid]), + io:format(Fd, "-define(~w, ~w).~n", [Name, Oid]), + insert_notifs2(T, Fd). + + +%%----------------------------------------------------------------- +%% There's nothing strange with this function! Enums can be +%% defined in types and in mibentries; therefore, we first call +%% ins_types and then ins_mes to insert enums from different places. +%%----------------------------------------------------------------- +insert_enums(Types, MEs, Fd) -> + ?vdebug("insert enums", []), + T = ins_types(Types, Fd, []), + ins_mes(MEs, T, Fd). + +%% Insert all types, but not the imported. Ret the names of inserted +%% types. +ins_types([#asn1_type{aliasname = Name, + assocList = Alist, + imported = false} | T], + Fd, Res) + when is_list(Alist) -> + case lists:keysearch(enums, 1, Alist) of + {value, {enums, Enums}} when Enums =/= [] -> + case Enums of + [] -> ins_types(T, Fd, Res); + NewEnums -> + io:format(Fd, "~n%% Definitions from ~w~n", [Name]), + ins_enums(NewEnums, Name, Fd), + ins_types(T, Fd, [Name | Res]) + end; + _ -> ins_types(T, Fd, Res) + end; +ins_types([_ | T], Fd, Res) -> + ins_types(T, Fd, Res); +ins_types([], _Fd, Res) -> Res. + +ins_mes([#me{entrytype = internal} | T], Types, Fd) -> + ins_mes(T, Types, Fd); +ins_mes([#me{entrytype = table} | T], Types, Fd) -> + ins_mes(T, Types, Fd); +ins_mes([#me{aliasname = Name, + asn1_type = #asn1_type{assocList = Alist, + aliasname = Aname}, + imported = false} | T], + Types, Fd) + when is_list(Alist) -> + case lists:keysearch(enums, 1, Alist) of + {value, {enums, Enums}} when Enums =/= [] -> + case Enums of + [] -> ins_mes(T, Types, Fd); + NewEnums -> + %% Now, check if the type is already inserted + %% (by ins_types). + case lists:member(Aname, Types) of + false -> + io:format(Fd, "~n%% Enum definitions from ~w~n", + [Name]), + ins_enums(NewEnums, Name, Fd), + ins_mes(T, Types, Fd); + _ -> ins_mes(T, Types, Fd) + end + end; + _ -> ins_mes(T, Types, Fd) + end; +ins_mes([_ | T], Types, Fd) -> + ins_mes(T, Types, Fd); +ins_mes([], _Types, _Fd) -> ok. + +ins_enums([{Name, Val} | T], Origin, Fd) -> + EnumName = merge_atoms(Origin, Name), + io:format(Fd, "-define(~w, ~w).~n", [EnumName, Val]), + ins_enums(T, Origin, Fd); +ins_enums([], _Origin, _Fd) -> + ok. + +%%---------------------------------------------------------------------- +%% Solves the problem with placing '' around some atoms. +%% You can't write two atoms using ~w_~w. +%%---------------------------------------------------------------------- +merge_atoms(TypeOrigin, Name) -> + list_to_atom(lists:append([atom_to_list(TypeOrigin), "_", + atom_to_list(Name)])). + +insert_defvals(Mes, Fd) -> + ?vdebug("insert default values", []), + io:format(Fd, "~n%% Default values~n", []), + insert_defvals2(Mes, Fd), + io:format(Fd, "~n", []). + +insert_defvals2([#me{imported = true} | T], Fd) -> + insert_defvals2(T, Fd); +insert_defvals2([#me{entrytype = table_column, assocList = Alist, + aliasname = Name} | T], + Fd) -> + case snmpc_misc:assq(defval, Alist) of + {value, Val} -> + Atom = merge_atoms('default', Name), + io:format(Fd, "-define(~w, ~w).~n", [Atom, Val]); + _ -> ok + end, + insert_defvals2(T, Fd); +insert_defvals2([#me{entrytype = variable, assocList = Alist, aliasname = Name} + | T], + Fd) -> + case snmpc_misc:assq(variable_info, Alist) of + {value, VarInfo} -> + case VarInfo#variable_info.defval of + undefined -> ok; + Val -> + Atom = merge_atoms('default', Name), + io:format(Fd, "-define(~w, ~w).~n", [Atom, Val]) + end; + _ -> ok + end, + insert_defvals2(T, Fd); +insert_defvals2([_ | T], Fd) -> + insert_defvals2(T, Fd); +insert_defvals2([], _Fd) -> ok. + +insert_range(Mes, Fd) -> + ?vdebug("insert range", []), + io:format(Fd, "~n%% Range values~n", []), + insert_range2(Mes, Fd), + io:format(Fd, "~n", []). + +insert_range2([#me{imported = true} | T], Fd)-> + insert_range2(T,Fd); +insert_range2([#me{asn1_type=#asn1_type{bertype='OCTET STRING',lo=Low,hi=High},aliasname=Name}|T],Fd)-> + case Low =:= undefined of + true-> + insert_range2(T,Fd); + false-> + AtomLow = merge_atoms('low', Name), + AtomHigh = merge_atoms('high', Name), + io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]), + io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]), + insert_range2(T,Fd) + end; +insert_range2([#me{asn1_type=#asn1_type{bertype='Unsigned32',lo=Low,hi=High},aliasname=Name}|T],Fd)-> + AtomLow = merge_atoms('low', Name), + AtomHigh = merge_atoms('high', Name), + io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]), + io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]), + insert_range2(T,Fd); +insert_range2([#me{asn1_type=#asn1_type{bertype='Counter32',lo=Low,hi=High},aliasname=Name}|T],Fd)-> + AtomLow = merge_atoms('low', Name), + AtomHigh = merge_atoms('high', Name), + io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]), + io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]), + insert_range2(T,Fd); +insert_range2([#me{asn1_type=#asn1_type{bertype='INTEGER',lo=Low,hi=High},aliasname=Name}|T],Fd)-> + case Low =:= undefined of + true-> + insert_range2(T,Fd); + false-> + AtomLow = merge_atoms('low', Name), + AtomHigh = merge_atoms('high', Name), + io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]), + io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]), + insert_range2(T,Fd) + end; +insert_range2([_|T],Fd) -> + insert_range2(T,Fd); +insert_range2([],_Fd) -> + ok. + +month(1) -> "Jan"; +month(2) -> "Feb"; +month(3) -> "Mar"; +month(4) -> "Apr"; +month(5) -> "May"; +month(6) -> "Jun"; +month(7) -> "Jul"; +month(8) -> "Aug"; +month(9) -> "Sep"; +month(10) -> "Oct"; +month(11) -> "Nov"; +month(12) -> "Dec". + +%%%----------------------------------------------------------------- +%%% Interface for erl_compile. +%%%----------------------------------------------------------------- + +%% Opts#options.specific +compile(Input, Output, Opts) -> + set_verbosity(Opts), + set_filename(Input), + ?vtrace("compile -> entry with" + "~n Input: ~s" + "~n Output: ~s" + "~n Opts: ~p", [Input, Output, Opts]), + case convert(Input++".bin", Output++".hrl", Input) of + ok -> + ok; + {error, Reason} -> + io:format("~p", [Reason]), + error + end. + +set_verbosity(#options{verbose = Verbose, specific = Spec}) -> + set_verbosity(Verbose, Spec). + +set_verbosity(Verbose, Spec) -> + Verbosity = + case lists:keysearch(verbosity, 1, Spec) of + {value, {verbosity, V}} -> + case (catch snmpc_lib:vvalidate(V)) of + ok -> + case Verbose of + true -> + case V of + silence -> + log; + info -> + log; + _ -> + V + end; + _ -> + V + end; + _ -> + case Verbose of + true -> + log; + false -> + silence + end + end; + false -> + case Verbose of + true -> + log; + false -> + silence + end + end, + put(verbosity, Verbosity). + + +set_filename(Filename) -> + Rootname = filename:rootname(Filename), + Basename = filename:basename(Rootname ++ ".mib"), + put(filename, Basename). + + + + |