%%
%% %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(user_sup).
%% ---------------------------------------------
%% This is a supervisor bridge hiding the process
%% details of the user/group implementation.
%% ---------------------------------------------
-behaviour(supervisor_bridge).
-export([start/0]).
%% Internal exports.
-export([init/1, terminate/2, relay/1]).
-spec start() -> {'error', {'already_started', pid()}} | {'ok', pid()}.
start() ->
supervisor_bridge:start_link(user_sup, []).
-spec init([]) -> 'ignore' | {'error', 'nouser'} | {'ok', pid(), pid()}.
init([]) ->
case get_user() of
nouser ->
ignore;
{master, Master} ->
Pid = start_slave(Master),
{ok, Pid, Pid};
{M, F, A} ->
case start_user(M, F, A) of
{ok, Pid} ->
{ok, Pid, Pid};
Error ->
Error
end
end.
start_slave(Master) ->
case rpc:call(Master, erlang, whereis, [user]) of
User when is_pid(User) ->
spawn(?MODULE, relay, [User]);
_ ->
error_logger:error_msg("Cannot get remote user", []),
receive after 1000 -> true end,
halt()
end.
-spec relay(pid()) -> no_return().
relay(Pid) ->
register(user, self()),
relay1(Pid).
relay1(Pid) ->
receive
X ->
Pid ! X,
relay1(Pid)
end.
%%-----------------------------------------------------------------
%% Sleep a while in order to let user write all (some) buffered
%% information before termination.
%%-----------------------------------------------------------------
-spec terminate(term(), pid()) -> 'ok'.
terminate(_Reason, UserPid) ->
receive after 1000 -> ok end,
exit(UserPid, kill),
ok.
%%-----------------------------------------------------------------
%% If there is a user, wait for it to register itself. (But wait
%% no more than 10 seconds). This is so the application_controller
%% is guaranteed that the user is started.
%%-----------------------------------------------------------------
start_user(Mod, Func, A) ->
apply(Mod, Func, A),
wait_for_user_p(100).
wait_for_user_p(0) ->
{error, nouser};
wait_for_user_p(N) ->
case whereis(user) of
Pid when is_pid(Pid) ->
link(Pid),
{ok, Pid};
_ ->
receive after 100 -> ok end,
wait_for_user_p(N-1)
end.
get_user() ->
Flags = init:get_arguments(),
check_flags(Flags, {user_drv, start, []}).
%% These flags depend upon what arguments the erl script passes on
%% to erl91.
check_flags([{nouser, []} |T], _) -> check_flags(T, nouser);
check_flags([{user, [User]} | T], _) ->
check_flags(T, {list_to_atom(User), start, []});
check_flags([{noshell, []} | T], _) -> check_flags(T, {user, start, []});
check_flags([{oldshell, []} | T], _) -> check_flags(T, {user, start, []});
check_flags([{noinput, []} | T], _) -> check_flags(T, {user, start_out, []});
check_flags([{master, [Node]} | T], _) ->
check_flags(T, {master, list_to_atom(Node)});
check_flags([_H | T], User) -> check_flags(T, User);
check_flags([], User) -> User.