aboutsummaryrefslogblamecommitdiffstats
path: root/lib/snmp/src/compile/snmpc.src
blob: 5f9b154bfadac38d586a6ff58d57f4e183e481aa (plain) (tree)
1
2
3
4
5
6


                      

                   
                                                        

















                                                                         
 
                                        

                                            
 

               
                            
              
                                                             



                               







                                     
                



                                                              

                                   

           


                                                                           


                             
        





                                 

       




                
             




                                                   
                           








                                       
                 
                                         




















                                                                       

        











                                                        
                                     









                                                                                  
 


















                                                                           

























                                                              





                                                
                   
                       
                     


                                               
    
                                                                       
















                                                                 

                                         

                                                                                   











                                                                                  





























































                                                                                        
















                                                                                         

                                                                 





                                          


                                                                            






                                                                                                

                                                                                


                                                                                                
                                                                                             




                                                                                                        
                                                                                                 
                                                                     





                                                                                                            

                                                                                         






                                                                                                   
                                                           

                                                                                               
                                                              
                                                                                                        


                                                                                                      


                                                                                                     
                                                                                                         


                                                                                                       
                                                                    






                           
 
#!/usr/bin/env escript
%% -*- erlang -*-
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 2008-2011. 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%
%%
%% SNMP MIB compiler frontend
%% 

-mode(compile).

-include_lib("kernel/include/file.hrl").
-include_lib("snmp/include/snmp_types.hrl").


-record(state, 
        {
	 version = "%VSN%", 
         mfv, 
         file, % .mib or .bin depending on which are compiled
         outdir = "./",
         db = volatile,
	 include_dirs = ["./"],
         include_lib_dirs = [],
	 deprecated         = false,
	 group_check        = true,
	 description        = false,
	 reference          = false,
	 imports            = false,
	 module_identity    = false,
	 module_compliance  = false, 
	 agent_capabilities = false,
	 module,
	 no_defaults        = false,
	 relaxed_row_name_assigne_check = false,
	 %% The default verbosity (silence) will be filled in 
	 %% during argument processing.
	 verbosity, 
	 warnings           = false
        }).


%% ------------------------------------------------------------------------
%% Valid arguments: 
%% --o Dir [defaults to "./"]
%% --i Dir [defaults to "./"]
%% --il Dir
%% --sgc
%% --db DB [defaults to volatile]
%% --dep
%% --desc
%% --ref
%% --imp
%% --mi
%% --mc
%% --ac
%% --mod Mod
%% --nd
%% --rrnac
%% --version
%% --verbosity V
%% --warnings
main(Args) when is_list(Args) ->
    case (catch process_args(Args)) of
	ok ->
	    usage();
        {ok, State} when is_record(State, state) ->
	    compile(State);
        {ok, Str} when is_list(Str) ->
            io:format("~s~n~n", [Str]),
            halt(1);
        {error, ReasonStr} ->
            usage(ReasonStr)
    end;
main(_) ->
    usage().

compile(State) ->
    %% io:format("snmpc: ~p~n", [State]),
    case mk_file(State) of
	{mib, File} ->
	    Options = mk_mib_options(State),
	    case mib2bin(File, Options) of
		{ok, _BinFileName} ->
		    ok;
		{error, Reason} ->
		    io:format("ERROR: Failed compiling mib: "
			      "~n   ~p~n", [Reason]),
		    halt(1)
	    end;
	{bin, File} ->
	    Options = mk_hrl_options(State),
	    case bin2hrl(File, Options) of
		ok ->
		    ok;
		{error, Reason} ->
		    io:format("ERROR: Failed generating hrl from mib: "
			      "~n   ~p~n", [Reason]),
		    halt(1)
	    end
    end.

mib2bin(MibFileName, Options) ->
    snmpc:compile(MibFileName, Options).

bin2hrl(BinFileName, {OutDir, Verbosity}) ->
    MibName = filename:basename(BinFileName), 
    BinFile = BinFileName ++ ".bin",
    HrlFile = filename:join(OutDir, MibName) ++ ".hrl",
    put(verbosity, Verbosity),
    snmpc_mib_to_hrl:convert(BinFile, HrlFile, MibName).
	    

mk_file(#state{file = MIB}) ->
    DirName  = filename:dirname(MIB),
    case filename:extension(MIB) of
	".mib" ->
	    BaseName = filename:basename(MIB, ".mib"),
	    {mib, filename:join(DirName, BaseName)};
	".bin"  ->
	    BaseName = filename:basename(MIB, ".bin"),
	    {bin, filename:join(DirName, BaseName)};
	BadExt ->
	    e(lists:flatten(io_lib:format("Unsupported file type: ~s", [BadExt])))
    end.

mk_mib_options(#state{outdir             = OutDir, 
		      db                 = DB,
		      include_dirs       = IDs,
		      include_lib_dirs   = ILDs,
		      deprecated         = Dep,
		      group_check        = GC,
		      description        = Desc,
		      reference          = Ref,
		      imports            = Imp,
		      module_identity    = MI,
		      module_compliance  = MC, 
		      agent_capabilities = AC,
		      module             = Mod,
		      no_defaults        = ND,
		      relaxed_row_name_assigne_check = RRNAC,
		      %% The default verbosity (silence) will be filled in 
		      %% during argument processing.
		      verbosity          = V, 
		      warnings           = W}) ->
    [{outdir,                        OutDir}, 
     {db,                            DB},
     {i,                             IDs},
     {il,                            ILDs},
     {group_check,                   GC},
     {verbosity,                     V}, 
     {warnings,                      W}, 
     {deprecated,                    Dep}] ++ 
	if
	    (Mod =/= undefined) ->
		[{module, Mod}];
	    true ->
		[]
	end ++ 
	maybe_option(ND,    no_defs) ++ 
	maybe_option(RRNAC, relaxed_row_name_assign_check) ++ 
	maybe_option(Desc,  description) ++ 
	maybe_option(Ref,   reference) ++ 
	maybe_option(Imp,   imports) ++ 
	maybe_option(MI,    module_identity) ++ 
	maybe_option(MC,    module_compliance) ++ 
	maybe_option(AC,    agent_capabilities).

maybe_option(true, Opt) -> [Opt];
maybe_option(_,    _)   -> [].
    

mk_hrl_options(#state{outdir    = OutDir, 
		      verbosity = Verbosity}) ->
    {OutDir, Verbosity}.


process_args([]) ->
    e("No input file");
process_args(Args) ->
    #mib{mib_format_version = MFV} = #mib{},
    State = #state{}, 
    process_args(Args, State#state{mfv = MFV}).
    
process_args([], #state{verbosity = Verbosity0, file = MIB} = State) ->
    if 
	(MIB =:= undefined) ->
	    e("No input file");
	true ->
	    Verbosity = 
		case Verbosity0 of
		    undefined ->
			silence;
		    _ ->
			Verbosity0
		end,
	    IPath  = lists:reverse(State#state.include_dirs),
	    IlPath = lists:reverse(State#state.include_lib_dirs),
	    {ok, State#state{verbosity        = Verbosity,
			     include_dirs     = IPath,
			     include_lib_dirs = IlPath}}
    end;
process_args(["--help"|_Args], _State) ->
    ok;
process_args(["--version"|_Args], #state{version = Version, mfv = MFV} = _State) ->
    {ok, lists:flatten(io_lib:format("snmpc ~s (~s)", [Version, MFV]))};
process_args(["--verbosity", Verbosity0|Args], #state{verbosity = V} = State) 
  when (V =:= undefined) ->
    Verbosity = list_to_atom(Verbosity0),
    case lists:member(Verbosity, [trace,debug,log,info,silence]) of
	true ->
	    process_args(Args, State#state{verbosity = Verbosity});
	false ->
	    e(lists:flatten(io_lib:format("Unknown verbosity: ~s", [Verbosity0])))
    end;
process_args(["--verbosity"|_Args], #state{verbosity = V}) 
  when (V =/= undefined) ->
    e(lists:flatten(io_lib:format("Verbosity already set to ~w", [V])));
process_args(["--warnings"|Args], State) ->
    process_args(Args, State#state{warnings = true});
process_args(["--o", Dir|Args], State) ->
    case (catch file:read_file_info(Dir)) of
        {ok, #file_info{type = directory}} ->
            process_args(Args, State#state{outdir = Dir});
        {ok, #file_info{type = BadType}} ->
            e(lists:flatten(io_lib:format("Not a directory: ~p (~w)", [Dir, BadType])));
        _ ->
            e(lists:flatten(io_lib:format("Bad directory: ~p", [Dir])))
    end;
process_args(["--i", Dir|Args], State) ->
    case (catch file:read_file_info(Dir)) of
        {ok, #file_info{type = directory}} ->
	    IPath = [Dir | State#state.include_dirs], 
            process_args(Args, State#state{include_dirs = IPath});
        {ok, #file_info{type = BadType}} ->
            e(lists:flatten(io_lib:format("Not a directory: ~p (~w)", [Dir, BadType])));
        _ ->
            e(lists:flatten(io_lib:format("Bad directory: ~p", [Dir])))
    end;
process_args(["--il", Dir|Args], State) ->
    case (catch file:read_file_info(Dir)) of
        {ok, #file_info{type = directory}} ->
	    IlPath = [Dir | State#state.include_lib_dirs], 
            process_args(Args, State#state{include_lib_dirs = IlPath});
        {ok, #file_info{type = BadType}} ->
            e(lists:flatten(io_lib:format("Not a directory: ~p (~w)", [Dir, BadType])));
        _ ->
            e(lists:flatten(io_lib:format("Bad directory: ~p", [Dir])))
    end;
process_args(["--db", DB0|Args], State) ->
    DB = list_to_atom(DB0),
    case lists:member(DB, [volatile,persistent,mnesia]) of
	true ->
	    process_args(Args, State#state{db = DB});
	false ->
            e(lists:flatten(io_lib:format("Invalid db: ~s", [DB0])))
    end;
process_args(["--dep"|Args], State) ->
    process_args(Args, State#state{deprecated = true});
process_args(["--sgc"|Args], State) ->
    process_args(Args, State#state{group_check = false});
process_args(["--desc"|Args], State) ->
    process_args(Args, State#state{description = true});
process_args(["--ref"|Args], State) ->
    process_args(Args, State#state{reference = true});
process_args(["--imp"|Args], State) ->
    process_args(Args, State#state{imports = true});
process_args(["--mi"|Args], State) ->
    process_args(Args, State#state{module_identity = true});
process_args(["--mod", Module0|Args], #state{module = M} = State) 
  when (M =:= undefined) ->
    Module = list_to_atom(Module0),
    process_args(Args, State#state{module = Module});
process_args(["--mod"|_Args], #state{module = M}) 
  when (M =/= undefined) ->
    e(lists:flatten(io_lib:format("Module already set to ~w", [M])));
process_args(["--nd"|Args], State) ->
    process_args(Args, State#state{no_defaults = true});
process_args(["--rrnac"|Args], State) ->
    process_args(Args, State#state{relaxed_row_name_assigne_check = true});
process_args([MIB], State) ->
    Ext = filename:extension(MIB),
    if 
	((Ext =:= ".mib") orelse (Ext =:= ".bin")) ->
	    case (catch file:read_file_info(MIB)) of
		{ok, #file_info{type = regular}} ->
		    process_args([], State#state{file = MIB});
		{ok, #file_info{type = BadType}} ->
		    e(lists:flatten(io_lib:format("~s not a file: ~w", [MIB, BadType])));
		{error, enoent} ->
		    e(lists:flatten(io_lib:format("No such file: ~s", [MIB])));
		_ ->
		    e(lists:flatten(io_lib:format("Bad file: ~s", [MIB])))
	    end; 
	true ->
	    e(lists:flatten(io_lib:format("Unknown option: ~s", [MIB])))
    end;
process_args([Arg|Args], _State) when Args =/= [] ->
    e(lists:flatten(io_lib:format("Unknown option: ~s", [Arg]))).

usage(ReasonStr) ->
    io:format("ERROR: ~s~n", [ReasonStr]),
    usage().

usage() ->
    io:format("Usage: snmpc [options] MIB.mib|MIB.bin"
	      "~nCompile a MIB (.mib -> .bin) or generate an erlang header "
	      "~nfile from a compiled MIB file (.bin -> .hrl)"
	      "~nOptions:"
	      "~n   --help                   - Prints this info."
	      "~n   --version                - Prints compiler version."
	      "~n   --verbosity <verbosity>  - Print debug info."
	      "~n                              verbosity = trace | debug | log | info | silence"
	      "~n                              Defaults to silence."
	      "~n   --warnings               - Print warning messages."
	      "~n   --o <output dir>         - The output dir."
	      "~n                              Defaults to current working dir."
	      "~n   --i <include dir>        - Add this dir to the list of dirs that will be"
	      "~n                              searched for imported (compiled) MIB files."
	      "~n                              The current workin dir will always be included. "
	      "~n   --il <include_lib dir>   - Add this dir to the list of dirs that will be"
	      "~n                              searched for imported (compiled) MIB files."
	      "~n                              It assumes that the first element in the dir name"
	      "~n                              correspond to an OTP application. For example snmp/mibs/"
	      "~n                              The current workin dir and the <snmp-home>/priv/mibs "
	      "~n                              are always listed last the includ path. "
	      "~n   --db <DB>                - Database to used for the default instrumentation."
	      "~n                              Defaults to volatile."
	      "~n   --sgc                    - This option (skip group check), if present, disables "
	      "~n                              the \"group check\" of the mib compiler. "
	      "~n                              That is, should the OBJECT-GROUP and the NOTIFICATION-GROUP "
	      "~n                              macro(s) be checked for correctness or not. "
	      "~n                              By default the check is done. "
	      "~n   --dep                    - Keep deprecated definition(s)."
	      "~n                              If not specified the compiler will ignore"
	      "~n                              deprecated definitions."
	      "~n   --desc                   - The DESCRIPTION field will be included."
	      "~n   --ref                    - The REFERENCE field will be included."
	      "~n   --imp                    - The IMPORTS field will be included."
	      "~n   --mi                     - The MODULE-IDENTITY field will be included."
	      "~n   --mc                     - The MODULE-COMPLIANCE field will be included."
	      "~n   --ac                     - The AGENT-CAPABILITIES field will be included."
	      "~n   --mod <module>           - The module which implements all the instrumentation"
	      "~n                              functions. "
	      "~n                              The name of all instrumentation functions must"
	      "~n                              be the same as the corresponding managed object"
	      "~n                              it implements."
	      "~n   --nd                     - The default instrumentation functions will *not* be used"
	      "~n                              if a managed object have no instrumentation function. "
	      "~n                              Instead this will be reported as an error, and the "
	      "~n                              compilation aborts. "
	      "~n   --rrnac                  - This option, if present, specifies that the row name "
	      "~n                              assign check shall not be done strictly according to"
	      "~n                              the SMI (which allows only the value 1). "
	      "~n                              With this option, all values greater than zero is allowed"
	      "~n                              (>= 1). This means that the error will be converted to "
	      "~n                              a warning. "
	      "~n                              By default it is not included, but if this option is "
	      "~n                              present it will be. "
	      "~n   "
	      "~n", []),
    halt(1).


e(Reason) ->
    throw({error, Reason}).