%%
%% %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, [email protected]
-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.
%% -----------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%