%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2006-2010. 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% %% %% Author: Lennart Öhman, lennart.ohman@st.se -module(inviso_autostart). -export([autostart/1,which_config_file/0]). %% This module implements the default autostart module for the inviso runtime %% component. %% It will: %% (1) Open the autostart configuration file (either the default or the one %% pointed out by the runtime_tools application parameter inviso_autostart_config). %% (2) Check that the incarnation counter has not reached 0. If so, we do not %% allow (yet) one autostart. %% (3) Rewrite the configuration file if there was an incarnation counter. %% (With the counter decreased). %% (4) Inspect the content of the configuration file and pass paramters in the %% return value (which is interpreted by the runtime component). %% %% CONTENT OF A CONFIGURATION FILE: %% A plain text file containing erlang tuple terms, each ended with a period(.). %% The following parameters are recognized: %% {repeat,N} N=interger(), %% The number of remaining allowed autostart incarnations of inviso. %% {options,Options} Options=list() %% The options which controls the runtime component, such as overload and %% dependency. %% {mfa,{Mod,Func,Args}} Args=list() %% Controls how a spy process initiating tracing, patterns and flags shall %% be started. %% {tag,Tag} %% The tag identifying the runtime component to control components. %% ============================================================================= %% This function is run in the runtime component's context during autostart %% to determine whether to continue and if, then how. autostart(_AutoModArgs) -> ConfigFile= case application:get_env(inviso_autostart_conf) of {ok,FileName} when is_list(FileName) -> % Use this filename then. FileName; {ok,{load,FileNames,{M,F}}} -> % First load the module, then... case try_load_module(FileNames) of ok -> autostart_apply(M,F); false -> % No such module available "inviso_autostart.config" end; {ok,{M,F}} -> % Use M:F(node()) autostart_apply(M,F); {ok,no_autostart} -> false; _ -> % Use a default name, in CWD! "inviso_autostart.config" end, if is_list(ConfigFile) -> case file:consult(ConfigFile) of {ok,Terms} -> % There is a configuration. case handle_repeat(ConfigFile,Terms) of ok -> % Handled or not, we shall continue. {get_mfa(Terms),get_options(Terms),get_tag(Terms)}; stop -> % We are out of allowed starts. true % Then no autostart. end; {error,_} -> % There is no config file true % Then no autostart! end; true -> % Skip it then. true end. autostart_apply(M,F) -> case catch M:F(node()) of FileName when is_list(FileName) -> FileName; no_autostart -> % No autostart after all. false; _ -> "inviso_autostart.config" end. %% This function is necessary since it is not always the case that all code-paths %% are set at the time of an autostart. try_load_module([AbsFileName|Rest]) when is_list(AbsFileName) -> case catch code:load_abs(AbsFileName) of % May not be a proper filename. {module,_Mod} -> try_load_module(Rest); _ -> false end; try_load_module([]) -> % Load all beam files successfully. ok; try_load_module(AbsFileName) when is_list(AbsFileName) -> try_load_module([AbsFileName]). %% ----------------------------------------------------------------------------- %% Function returning the filename probably used as autostart config file. %% Note that this function must be executed at the node in question. which_config_file() -> case application:get_env(runtime_tools,inviso_autostart_conf) of {ok,FileName} when is_list(FileName) -> % Use this filename then. FileName; {ok,{M,F}} -> % Use M:F(node()) case catch M:F(node()) of FileName when is_list(FileName) -> FileName; _ -> {ok,CWD}=file:get_cwd(), filename:join(CWD,"inviso_autostart.config") end; _ -> % Use a default name, in CWD! {ok,CWD}=file:get_cwd(), filename:join(CWD,"inviso_autostart.config") end. %% ----------------------------------------------------------------------------- %% Help function which finds out if there is a limit on the number of times %% we shall autostart. If there is a repeat parameter and it is greater than %% zero, the file must be rewritten with the parameter decreased with one. %% Returns 'ok' or 'stop'. handle_repeat(FileName,Terms) -> case lists:keysearch(repeat,1,Terms) of {value,{_,N}} when N>0 -> % Controlls how many time more. handle_repeat_rewritefile(FileName,Terms,N-1), ok; % Indicate that we shall continue. {value,_} -> % No we have reached the limit. stop; false -> % There is no repeat parameter. ok % No restrictions then! end. %% Help function which writes the configuration file again, but with the %% repeat parameter set to NewN. %% Returns nothing significant. handle_repeat_rewritefile(FileName,Term,NewN) -> case file:open(FileName,[write]) of {ok,FD} -> NewTerm=lists:keyreplace(repeat,1,Term,{repeat,NewN}), handle_repeat_rewritefile_2(FD,NewTerm), file:close(FD); {error,_Reason} -> % Not much we can do then?! error end. handle_repeat_rewritefile_2(FD,[Tuple|Rest]) -> io:format(FD,"~w.~n",[Tuple]), handle_repeat_rewritefile_2(FD,Rest); handle_repeat_rewritefile_2(_,[]) -> true. %% ----------------------------------------------------------------------------- %% Three help functions finding the parameters possible to give to the runtime %% component. Note that some of them have default values, should the parameter %% not exist. get_mfa(Terms) -> case lists:keysearch(mfa,1,Terms) of {value,{_,MFA}} -> MFA; false -> false end. get_options(Terms) -> case lists:keysearch(options,1,Terms) of {value,{_,Options}} -> Options; false -> [] end. get_tag(Terms) -> case lists:keysearch(tag,1,Terms) of {value,{_,Tag}} -> Tag; false -> default_tag end. %% ----------------------------------------------------------------------------- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%