summaryrefslogtreecommitdiff
path: root/lib/kernel/src/user_sup.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src/user_sup.erl')
-rw-r--r--lib/kernel/src/user_sup.erl129
1 files changed, 129 insertions, 0 deletions
diff --git a/lib/kernel/src/user_sup.erl b/lib/kernel/src/user_sup.erl
new file mode 100644
index 0000000000..35b7ff0cfe
--- /dev/null
+++ b/lib/kernel/src/user_sup.erl
@@ -0,0 +1,129 @@
+%%
+%% %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(Func,A) ->
+ apply(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.