%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions 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.