aboutsummaryrefslogtreecommitdiffstats
path: root/lib/sasl/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sasl/src')
-rw-r--r--lib/sasl/src/release_handler_1.erl107
-rw-r--r--lib/sasl/src/systools_lib.erl7
-rw-r--r--lib/sasl/src/systools_make.erl174
-rw-r--r--lib/sasl/src/systools_relup.erl68
4 files changed, 235 insertions, 121 deletions
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index ef95606bb5..8d0baf3ab1 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.erl
@@ -21,7 +21,7 @@
%% External exports
-export([eval_script/1, eval_script/5,
check_script/2, check_old_processes/2]).
--export([get_current_vsn/1]). %% exported because used in a test case
+-export([get_current_vsn/1, get_supervised_procs/0]). %% exported because used in a test case
-record(eval_state, {bins = [], stopped = [], suspended = [], apps = [],
libdirs, unpurged = [], vsns = [], newlibs = [],
@@ -493,6 +493,19 @@ start(Procs) ->
%% supervisor module, we should load the new version, and then
%% delete the old. Then we should perform the start changes
%% manually, by adding/deleting children.
+%%
+%% Recent changes to this code cause the upgrade error out and
+%% log the case where a suspended supervisor has which_children
+%% called against it. This retains the behavior of causing a VM
+%% restart to the *old* version of a release but has the
+%% advantage of logging the pid and supervisor that had the
+%% issue.
+%%
+%% A second case where this can occur is if a child spec is
+%% incorrect and get_modules is called against a process that
+%% can't respond to the gen:call. Again an error is logged,
+%% an error returned and a VM restart is issued.
+%%
%% Returns: [{SuperPid, ChildName, ChildPid, Mods}]
%%-----------------------------------------------------------------
%% OTP-3452. For each application the first item contains the pid
@@ -502,49 +515,81 @@ start(Procs) ->
get_supervised_procs() ->
lists:foldl(
fun(Application, Procs) ->
- case application_controller:get_master(Application) of
- Pid when is_pid(Pid) ->
- {Root, _AppMod} = application_master:get_child(Pid),
- case get_supervisor_module(Root) of
- {ok, SupMod} ->
- get_procs(supervisor:which_children(Root),
- Root) ++
- [{undefined, undefined, Root, [SupMod]} |
- Procs];
- {error, _} ->
- error_logger:error_msg("release_handler: "
- "cannot find top "
- "supervisor for "
- "application ~w~n",
- [Application]),
- get_procs(supervisor:which_children(Root),
- Root) ++ Procs
- end;
- _ -> Procs
- end
+ get_master_procs(Application,
+ Procs,
+ application_controller:get_master(Application))
end,
[],
- lists:map(fun({Application, _Name, _Vsn}) ->
- Application
- end,
- application:which_applications())).
+ get_application_names()).
+
+get_supervised_procs(_, Root, Procs, {ok, SupMod}) ->
+ get_procs(maybe_supervisor_which_children(get_proc_state(Root), SupMod, Root), Root) ++
+ [{undefined, undefined, Root, [SupMod]} | Procs];
+get_supervised_procs(Application, Root, Procs, {error, _}) ->
+ error_logger:error_msg("release_handler: cannot find top supervisor for "
+ "application ~w~n", [Application]),
+ get_procs(maybe_supervisor_which_children(get_proc_state(Root), Application, Root), Root) ++ Procs.
+
+get_application_names() ->
+ lists:map(fun({Application, _Name, _Vsn}) ->
+ Application
+ end,
+ application:which_applications()).
+
+get_master_procs(Application, Procs, Pid) when is_pid(Pid) ->
+ {Root, _AppMod} = application_master:get_child(Pid),
+ get_supervised_procs(Application, Root, Procs, get_supervisor_module(Root));
+get_master_procs(_, Procs, _) ->
+ Procs.
get_procs([{Name, Pid, worker, dynamic} | T], Sup) when is_pid(Pid) ->
- Mods = get_dynamic_mods(Pid),
+ Mods = maybe_get_dynamic_mods(Name, Pid),
[{Sup, Name, Pid, Mods} | get_procs(T, Sup)];
get_procs([{Name, Pid, worker, Mods} | T], Sup) when is_pid(Pid), is_list(Mods) ->
[{Sup, Name, Pid, Mods} | get_procs(T, Sup)];
get_procs([{Name, Pid, supervisor, Mods} | T], Sup) when is_pid(Pid) ->
- [{Sup, Name, Pid, Mods} | get_procs(T, Sup)] ++
- get_procs(supervisor:which_children(Pid), Pid);
+ [{Sup, Name, Pid, Mods} | get_procs(T, Sup)] ++
+ get_procs(maybe_supervisor_which_children(get_proc_state(Pid), Name, Pid), Pid);
get_procs([_H | T], Sup) ->
get_procs(T, Sup);
get_procs(_, _Sup) ->
[].
-get_dynamic_mods(Pid) ->
- {ok,Res} = gen:call(Pid, self(), get_modules),
- Res.
+get_proc_state(Proc) ->
+ {status, _, {module, _}, [_, State, _, _, _]} = sys:get_status(Proc),
+ State.
+
+maybe_supervisor_which_children(suspended, Name, Pid) ->
+ error_logger:error_msg("release_handler: a which_children call"
+ " to ~p (~p) was avoided. This supervisor"
+ " is suspended and should likely be upgraded"
+ " differently. Exiting ...~n", [Name, Pid]),
+ error(suspended_supervisor);
+
+maybe_supervisor_which_children(State, Name, Pid) ->
+ case catch supervisor:which_children(Pid) of
+ Res when is_list(Res) ->
+ Res;
+ Other ->
+ error_logger:error_msg("release_handler: ~p~nerror during"
+ " a which_children call to ~p (~p)."
+ " [State: ~p] Exiting ... ~n",
+ [Other, Name, Pid, State]),
+ error(which_children_failed)
+ end.
+
+maybe_get_dynamic_mods(Name, Pid) ->
+ case catch gen:call(Pid, self(), get_modules) of
+ {ok, Res} ->
+ Res;
+ Other ->
+ error_logger:error_msg("release_handler: ~p~nerror during a"
+ " get_modules call to ~p (~p),"
+ " there may be an error in it's"
+ " childspec. Exiting ...~n",
+ [Other, Name, Pid]),
+ error(get_modules_failed)
+ end.
%% XXXX
%% Note: The following is a terrible hack done in order to resolve the
diff --git a/lib/sasl/src/systools_lib.erl b/lib/sasl/src/systools_lib.erl
index f951647b79..1b6ea125d9 100644
--- a/lib/sasl/src/systools_lib.erl
+++ b/lib/sasl/src/systools_lib.erl
@@ -24,7 +24,7 @@
%%
-export([file_term2binary/2, read_term/1, read_term_from_stream/2,
- get_dirs/1, get_path/1]).
+ get_dirs/1, get_path/1, werror/2]).
-include_lib("kernel/include/file.hrl").
@@ -219,6 +219,7 @@ flat([H|T], Ack) ->
flat(T, [H|Ack]);
flat([], Ack) ->
lists:reverse(Ack).
-
-
+
+werror(Options, Warnings) ->
+ lists:member(warnings_as_errors, Options) andalso Warnings =/= [].
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 5dc83e7b2a..7f400f5cce 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -44,10 +44,12 @@
%%-----------------------------------------------------------------
%% Create a boot script from a release file.
-%% Options is a list of {path, Path} | silent | local where path sets
-%% the search path, silent supresses error message printing on console,
-%% local generates a script with references to the directories there
-%% the applications are found.
+%% Options is a list of {path, Path} | silent | local
+%% | warnings_as_errors
+%% where path sets the search path, silent supresses error message
+%% printing on console, local generates a script with references
+%% to the directories there the applications are found,
+%% and warnings_as_errors treats warnings as errors.
%%
%% New options: {path,Path} can contain wildcards
%% src_tests
@@ -85,11 +87,16 @@ make_script(RelName, Output, Flags) when is_list(RelName),
ModTestP = {member(src_tests, Flags),xref_p(Flags)},
case get_release(RelName, Path, ModTestP, machine(Flags)) of
{ok, Release, Appls, Warnings} ->
- case generate_script(Output,Release,Appls,Flags) of
- ok ->
+ case systools_lib:werror(Flags, Warnings) of
+ true ->
return(ok,Warnings,Flags);
- Error ->
- return(Error,Warnings,Flags)
+ false ->
+ case generate_script(Output,Release,Appls,Flags) of
+ ok ->
+ return(ok,Warnings,Flags);
+ Error ->
+ return(Error,Warnings,Flags)
+ end
end;
Error ->
return(Error,[],Flags)
@@ -130,10 +137,21 @@ get_outdir(Flags) ->
return(ok,Warnings,Flags) ->
case member(silent,Flags) of
true ->
- {ok,?MODULE,Warnings};
+ case systools_lib:werror(Flags, Warnings) of
+ true ->
+ error;
+ false ->
+ {ok,?MODULE,Warnings}
+ end;
_ ->
- io:format("~s",[format_warning(Warnings)]),
- ok
+ case member(warnings_as_errors,Flags) of
+ true ->
+ io:format("~s",[format_warning(Warnings, true)]),
+ error;
+ false ->
+ io:format("~s",[format_warning(Warnings)]),
+ ok
+ end
end;
return({error,Mod,Error},_,Flags) ->
case member(silent,Flags) of
@@ -1833,78 +1851,89 @@ get_flag(_,_) -> false.
%% Check Options for make_script
check_args_script(Args) ->
cas(Args,
- {undef, undef, undef, undef, undef, undef, undef, undef, []}).
+ {undef, undef, undef, undef, undef, undef, undef, undef,
+ undef, []}).
-cas([], {_Path,_Sil,_Loc,_Test,_Var,_Mach,_Xref,_XrefApps, X}) ->
+cas([], {_Path,_Sil,_Loc,_Test,_Var,_Mach,_Xref,_XrefApps,_Werror, X}) ->
X;
%%% path ---------------------------------------------------------------
-cas([{path, P} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_list(P) ->
+cas([{path, P} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_list(P) ->
case check_path(P) of
ok ->
- cas(Args, {P, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X});
+ cas(Args, {P, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
+ Werror, X});
error ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- X++[{path,P}]})
+ Werror, X++[{path,P}]})
end;
%%% silent -------------------------------------------------------------
-cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) ->
- cas(Args, {Path, silent, Loc, Test, Var, Mach, Xref, XrefApps, X});
+cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, silent, Loc, Test, Var, Mach, Xref, XrefApps,
+ Werror, X});
%%% local --------------------------------------------------------------
-cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach,
- Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps, X});
+cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps,
+ Werror, X});
%%% src_tests -------------------------------------------------------
-cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach,
- Xref, XrefApps, X}) ->
+cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
cas(Args,
- {Path, Sil, Loc, src_tests, Var, Mach, Xref, XrefApps,X});
+ {Path, Sil, Loc, src_tests, Var, Mach, Xref, Werror, XrefApps,X});
%%% variables ----------------------------------------------------------
-cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_list(V) ->
+cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_list(V) ->
case check_vars(V) of
ok ->
cas(Args,
- {Path, Sil, Loc, Test, V, Mach, Xref, XrefApps, X});
+ {Path, Sil, Loc, Test, V, Mach, Xref, XrefApps, Werror, X});
error ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- X++[{variables, V}]})
+ Werror, X++[{variables, V}]})
end;
%%% machine ------------------------------------------------------------
-cas([{machine, M} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_atom(M) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X});
+cas([{machine, M} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_atom(M) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
%%% exref --------------------------------------------------------------
-cas([exref | Args], {Path, Sil, Loc, Test, Var, Mach,
- _Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, exref, XrefApps, X});
+cas([exref | Args], {Path, Sil, Loc, Test, Var, Mach, _Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, exref, XrefApps, Werror, X});
%%% exref Apps ---------------------------------------------------------
-cas([{exref, Apps} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_list(Apps) ->
+cas([{exref, Apps} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_list(Apps) ->
case check_apps(Apps) of
ok ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach,
- Xref, Apps, X});
+ Xref, Apps, Werror, X});
error ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X++[{exref, Apps}]})
+ Xref, XrefApps, Werror, X++[{exref, Apps}]})
end;
%%% outdir Dir ---------------------------------------------------------
-cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_list(Dir) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X});
+cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_list(Dir) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
%%% otp_build (secret, not documented) ---------------------------------
-cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X});
+cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
%%% no_module_tests (kept for backwards compatibility, but ignored) ----
-cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X});
+cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
+%%% warnings_as_errors (kept for backwards compatibility, but ignored) ----
+cas([warnings_as_errors | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, _Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
+ warnings_as_errors, X});
%%% ERROR --------------------------------------------------------------
-cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X++[Y]}).
+cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
+ Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror,
+ X++[Y]}).
@@ -2030,7 +2059,6 @@ check_apps([H|T]) when is_atom(H) ->
check_apps(_) ->
error.
-
%% Format error
format_error(badly_formatted_release) ->
@@ -2144,21 +2172,31 @@ form_tar_err({add, File, Error}) ->
%% Format warning
format_warning(Warnings) ->
- map(fun({warning,W}) -> form_warn(W) end, Warnings).
-
-form_warn({source_not_found,{Mod,_,App,_,_}}) ->
- io_lib:format("*WARNING* ~p: Source code not found: ~p.erl~n",
- [App,Mod]);
-form_warn({{parse_error, File},{_,_,App,_,_}}) ->
- io_lib:format("*WARNING* ~p: Parse error: ~p~n",
- [App,File]);
-form_warn({obj_out_of_date,{Mod,_,App,_,_}}) ->
- io_lib:format("*WARNING* ~p: Object code (~p) out of date~n",[App,Mod]);
-form_warn({exref_undef, Undef}) ->
- F = fun({M,F,A}) ->
- io_lib:format("*WARNING* Undefined function ~p:~p/~p~n",
- [M,F,A])
+ format_warning(Warnings, false).
+
+format_warning(Warnings, Werror) ->
+ Prefix = case Werror of
+ true ->
+ "";
+ false ->
+ "*WARNING* "
+ end,
+ map(fun({warning,W}) -> form_warn(Prefix, W) end, Warnings).
+
+form_warn(Prefix, {source_not_found,{Mod,_,App,_,_}}) ->
+ io_lib:format("~s~p: Source code not found: ~p.erl~n",
+ [Prefix,App,Mod]);
+form_warn(Prefix, {{parse_error, File},{_,_,App,_,_}}) ->
+ io_lib:format("~s~p: Parse error: ~p~n",
+ [Prefix,App,File]);
+form_warn(Prefix, {obj_out_of_date,{Mod,_,App,_,_}}) ->
+ io_lib:format("~s~p: Object code (~p) out of date~n",
+ [Prefix,App,Mod]);
+form_warn(Prefix, {exref_undef, Undef}) ->
+ F = fun({M,F,A}) ->
+ io_lib:format("~sUndefined function ~p:~p/~p~n",
+ [Prefix,M,F,A])
end,
map(F, Undef);
-form_warn(What) ->
- io_lib:format("*WARNING* ~p~n", [What]).
+form_warn(Prefix, What) ->
+ io_lib:format("~s ~p~n", [Prefix,What]).
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl
index ec5486226c..6d9e922900 100644
--- a/lib/sasl/src/systools_relup.erl
+++ b/lib/sasl/src/systools_relup.erl
@@ -122,7 +122,7 @@
%% rel_filename() = description() = string()
%% Opts = [opt()]
%% opt() = {path, [path()]} | silent | noexec | restart_emulator
-%% | {outdir, string()}
+%% | {outdir, string()} | warnings_as_errors
%% path() = [string()]
%% Ret = ok | error | {ok, Relup, Module, Warnings} | {error, Module, Error}
%%
@@ -139,8 +139,9 @@
%%
%% The option `path' sets search path, `silent' suppresses printing of
%% error messages to the console, `noexec' inhibits the creation of
-%% the output "relup" file, and restart_emulator ensures that the new
-%% emulator is restarted (as the final step).
+%% the output "relup" file, restart_emulator ensures that the new
+%% emulator is restarted (as the final step), and `warnings_as_errors'
+%% treats warnings as errors.
%% ----------------------------------------------------------------
mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs) ->
mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, []).
@@ -153,14 +154,29 @@ mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Opts) ->
{false, false} ->
case R of
{ok, _Res, _Mod, Ws} ->
- print_warnings(Ws),
- ok;
+ print_warnings(Ws, Opts),
+ case systools_lib:werror(Opts, Ws) of
+ true ->
+ error;
+ false ->
+ ok
+ end;
Other ->
print_error(Other),
error
end;
- _ ->
- R
+ _ ->
+ case R of
+ {ok, _Res, _Mod, Ws} ->
+ case systools_lib:werror(Opts, Ws) of
+ true ->
+ error;
+ false ->
+ R
+ end;
+ R ->
+ R
+ end
end;
BadArg ->
erlang:error({badarg, BadArg})
@@ -195,7 +211,12 @@ do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) ->
{Dn, Ws2} = foreach_baserel_dn(TopRel, TopApps, BaseDnRelDcs,
Path, Opts, Ws1),
Relup = {TopRel#release.vsn, Up, Dn},
- write_relup_file(Relup, Opts),
+ case systools_lib:werror(Opts, Ws2) of
+ true ->
+ ok;
+ false ->
+ write_relup_file(Relup, Opts)
+ end,
{ok, Relup, ?MODULE, Ws2};
Other ->
throw(Other)
@@ -527,20 +548,29 @@ format_error(Error) ->
io:format("~p~n", [Error]).
-print_warnings(Ws) when is_list(Ws) ->
- lists:foreach(fun(W) -> print_warning(W) end, Ws);
-print_warnings(W) ->
- print_warning(W).
+print_warnings(Ws, Opts) when is_list(Ws) ->
+ lists:foreach(fun(W) -> print_warning(W, Opts) end, Ws);
+print_warnings(W, Opts) ->
+ print_warning(W, Opts).
-print_warning(W) ->
- S = format_warning(W),
+print_warning(W, Opts) ->
+ Prefix = case lists:member(warnings_as_errors, Opts) of
+ true ->
+ "";
+ false ->
+ "*WARNING* "
+ end,
+ S = format_warning(Prefix, W),
io:format("~s", [S]).
-format_warning({erts_vsn_changed, {Rel1, Rel2}}) ->
- io_lib:format("*WARNING* The ERTS version changed between ~p and ~p~n",
- [Rel1, Rel2]);
-format_warning(What) ->
- io_lib:format("*WARNING* ~p~n",[What]).
+format_warning(W) ->
+ format_warning("*WARNING* ", W).
+
+format_warning(Prefix, {erts_vsn_changed, {Rel1, Rel2}}) ->
+ io_lib:format("~sThe ERTS version changed between ~p and ~p~n",
+ [Prefix, Rel1, Rel2]);
+format_warning(Prefix, What) ->
+ io_lib:format("~s~p~n",[Prefix, What]).
get_reason({error, {open, _, _}}) -> open;