aboutsummaryrefslogtreecommitdiffstats
path: root/lib/os_mon/src/os_sup.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/os_mon/src/os_sup.erl')
-rw-r--r--lib/os_mon/src/os_sup.erl258
1 files changed, 258 insertions, 0 deletions
diff --git a/lib/os_mon/src/os_sup.erl b/lib/os_mon/src/os_sup.erl
new file mode 100644
index 0000000000..f5c6c138ba
--- /dev/null
+++ b/lib/os_mon/src/os_sup.erl
@@ -0,0 +1,258 @@
+%%
+%% %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(os_sup).
+-behaviour(gen_server).
+
+%% API
+-export([start_link/1, start/0, stop/0]).
+-export([error_report/2]).
+-export([enable/0, enable/2, disable/0, disable/2]).
+-export([param_type/2, param_default/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-record(state, {port, mfa, config, path, conf}).
+
+%%----------------------------------------------------------------------
+%% API
+%%----------------------------------------------------------------------
+
+start_link({win32, _OSname}) ->
+ Identifier = os_sup,
+ MFA = os_mon:get_env(os_sup, os_sup_mfa),
+ gen_server:start_link({local, os_sup_server}, nteventlog,
+ [Identifier, MFA], []);
+start_link(_OS) ->
+ gen_server:start_link({local, os_sup_server}, os_sup, [], []).
+
+start() -> % for testing
+ gen_server:start({local, os_sup_server}, os_sup, [], []).
+
+stop() ->
+ gen_server:call(os_sup_server, stop).
+
+error_report(LogData, Tag) ->
+ error_logger:error_report(Tag, LogData).
+
+enable() ->
+ command(enable).
+enable(Path, Conf) ->
+ command(enable, Path, Conf).
+
+disable() ->
+ command(disable).
+disable(Path, Conf) ->
+ command(disable, Path, Conf).
+
+param_type(os_sup_errortag, Val) when is_atom(Val) -> true;
+param_type(os_sup_own, Val) -> io_lib:printable_list(Val);
+param_type(os_sup_syslogconf, Val) -> io_lib:printable_list(Val);
+param_type(os_sup_enable, Val) when Val==true; Val==false -> true;
+param_type(os_sup_mfa, {Mod,Func,Args}) when is_atom(Mod),
+ is_atom(Func),
+ is_list(Args) -> true;
+param_type(_Param, _Val) -> false.
+
+param_default(os_sup_errortag) -> std_error;
+param_default(os_sup_own) -> "/etc";
+param_default(os_sup_syslogconf) -> "/etc/syslog.conf";
+param_default(os_sup_enable) -> true;
+param_default(os_sup_mfa) -> {os_sup, error_report, [std_error]}.
+
+%%----------------------------------------------------------------------
+%% gen_server callbacks
+%%----------------------------------------------------------------------
+
+init([]) ->
+ process_flag(trap_exit, true),
+ process_flag(priority, low),
+
+ case os:type() of
+ {unix, sunos} ->
+ init2();
+ OS -> {stop, {unsupported_os, OS}}
+ end.
+
+init2() -> % Enable service if configured to do so
+ ConfigP = os_mon:get_env(os_sup, os_sup_enable),
+ case ConfigP of
+ true -> % ..yes -- do enable
+ Path = os_mon:get_env(os_sup, os_sup_own),
+ Conf = os_mon:get_env(os_sup, os_sup_syslogconf),
+ case enable(Path, Conf) of
+ ok ->
+ init3(#state{config=ConfigP, path=Path, conf=Conf});
+ {error, Error} ->
+ {stop, {mod_syslog, Error}}
+ end;
+ false -> % ..no -- skip directly to init3/1
+ init3(#state{config=ConfigP})
+ end.
+
+init3(State0) ->
+ Port = start_portprogram(),
+
+ %% Read the values of some configuration parameters
+ MFA = case os_mon:get_env(os_sup, os_sup_mfa) of
+ {os_sup, error_report, _} ->
+ Tag = os_mon:get_env(os_sup, os_sup_errortag),
+ {os_sup, error_report, [Tag]};
+ MFA0 ->
+ MFA0
+ end,
+
+ {ok, State0#state{port=Port, mfa=MFA}}.
+
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info({_Port, {data, Data}}, #state{mfa={M,F,A}} = State) ->
+ apply(M, F, [Data | A]),
+ {noreply, State};
+handle_info({'EXIT', _Port, Reason}, State) ->
+ {stop, {port_died, Reason}, State#state{port=not_used}};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, #state{port=Port} = State) ->
+ case State#state.config of
+ true when is_port(Port) ->
+ Port ! {self(), {command, "only_stdin"}},
+ Res = disable(State#state.path, State#state.conf),
+ port_close(Port),
+ if
+ Res/="0" -> exit({mod_syslog, Res});
+ true -> ok
+ end;
+ true ->
+ Res = disable(State#state.path, State#state.conf),
+ if
+ Res/="0" -> exit({mod_syslog, Res});
+ true -> ok
+ end;
+ false when is_port(Port) ->
+ Port ! {self(), {command, "only_stdin"}},
+ port_close(Port);
+ false ->
+ ok
+ end.
+
+%% os_mon-2.0
+%% For live downgrade to/upgrade from os_mon-1.8[.1]
+code_change(Vsn, PrevState, "1.8") ->
+ case Vsn of
+
+ %% Downgrade from this version
+ {down, _Vsn} ->
+
+ %% Find out the error tag used
+ {DefM, DefF, _} = param_default(os_sup_mfa),
+ Tag = case PrevState#state.mfa of
+
+ %% Default callback function is used, then use
+ %% the corresponding tag
+ {DefM, DefF, [Tag0]} ->
+ Tag0;
+
+ %% Default callback function is *not* used
+ %% (before the downgrade, that is)
+ %% -- check the configuration parameter
+ _ ->
+ case application:get_env(os_mon,
+ os_sup_errortag) of
+ {ok, Tag1} ->
+ Tag1;
+
+ %% (actually, if it has no value,
+ %% the process should terminate
+ %% according to 1.8.1 version, but that
+ %% seems too harsh here)
+ _ ->
+ std_error
+ end
+ end,
+
+ %% Downgrade to old state record
+ State = {state, PrevState#state.port, Tag},
+ {ok, State};
+
+ %% Upgrade to this version
+ _Vsn ->
+
+ {state, Port, Tag} = PrevState,
+
+ {DefM, DefF, _} = param_default(os_sup_mfa),
+ MFA = {DefM, DefF, [Tag]},
+
+ %% We can safely assume the following configuration
+ %% parameters are defined, otherwise os_sup would never had
+ %% started in the first place.
+ %% (We can *not* safely assume they haven't been changed,
+ %% but that's a weakness inherited from the 1.8.1 version)
+ Path = application:get_env(os_mon, os_sup_own),
+ Conf = application:get_env(os_mon, os_sup_syslogconf),
+
+ %% Upgrade to this state record
+ State = #state{port=Port, mfa=MFA, config=true,
+ path=Path, conf=Conf},
+ {ok, State}
+ end;
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%----------------------------------------------------------------------
+%% Internal functions
+%%----------------------------------------------------------------------
+
+start_portprogram() ->
+ OwnPath = os_mon:get_env(os_sup, os_sup_own),
+ Command =
+ filename:join([code:priv_dir(os_mon), "bin", "ferrule"]) ++
+ " " ++ OwnPath,
+ open_port({spawn, Command}, [{packet, 2}]).
+
+%% os:cmd(cmd_str(enable)) should be done BEFORE starting os_sup
+%% os:cmd(cmd_str(disable)) should be done AFTER os_sup is terminated
+%% Both commands return "0" if successful
+command(Mode) ->
+ command(Mode, "/etc", "/etc/syslog.conf").
+command(Mode, Path, Conf) ->
+ case os:cmd(cmd_str(Mode, Path, Conf)) of
+ "0" ->
+ ok;
+ Error ->
+ {error, Error}
+ end.
+
+cmd_str(Mode, Path, Conf) ->
+ %% modpgm modesw ownpath syslogconf
+ PrivDir = code:priv_dir(os_mon),
+ ModeSw =
+ case Mode of
+ enable ->
+ " otp ";
+ disable ->
+ " nootp "
+ end,
+ PrivDir ++ "/bin/mod_syslog" ++ ModeSw ++ Path ++ " " ++ Conf.