summaryrefslogtreecommitdiff
path: root/src/gen_mod.erl
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2018-05-09 11:44:24 +0300
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2018-05-09 11:44:24 +0300
commit35a076c2517bf36ff5afb5bb38a674291a1ec607 (patch)
tree5dc611e5be47e5d049d6d7653f390bb495645b19 /src/gen_mod.erl
parentReduce IQ handler code copying (diff)
Stop ejabberd initialization on invalid/unknown options
Since now, ejabberd doesn't ignore unknown options and doesn't allow to have options with malformed values. The rationale for this is to avoid unexpected behaviour during runtime, i.e. to conform to "fail early" approach. Note that it's safe to reload a configuration with potentialy invalid and/or unknown options: this will not halt ejabberd, but will only prevent the configuration from loading. ***NOTE FOR PACKAGE BUILDERS*** This new behaviour should be documented in the upgrade notes.
Diffstat (limited to 'src/gen_mod.erl')
-rw-r--r--src/gen_mod.erl109
1 files changed, 55 insertions, 54 deletions
diff --git a/src/gen_mod.erl b/src/gen_mod.erl
index 1e069be7..ed04767c 100644
--- a/src/gen_mod.erl
+++ b/src/gen_mod.erl
@@ -546,89 +546,94 @@ validate_opts(Host, Module, Opts0) ->
catch _:undef -> []
end
end, [Module|SubMods]),
- Required = lists:filter(fun is_atom/1, DefaultOpts),
try
Opts = merge_opts(Opts0, DefaultOpts, Module),
{ok, case get_validators(Host, {Module, SubMods}) of
undef ->
Opts;
Validators ->
- Opts1 = validate_opts(Host, Module, Opts, Required, Validators),
+ Opts1 = validate_opts(Host, Module, Opts, Validators),
remove_duplicated_opts(Opts1)
end}
catch _:{missing_required_option, Opt} ->
ErrTxt = io_lib:format("Module '~s' is missing required option '~s'",
[Module, Opt]),
- ?ERROR_MSG(ErrTxt, []),
- {error, ErrTxt}
+ module_error(ErrTxt);
+ _:{invalid_option, Opt, Val} ->
+ ErrTxt = io_lib:format("Invalid value '~p' for option '~s' of "
+ "module '~s'", [Val, Opt, Module]),
+ module_error(ErrTxt);
+ _:{invalid_option, Opt, Val, Reason} ->
+ ErrTxt = io_lib:format("Invalid value '~p' for option '~s' of "
+ "module '~s': ~s", [Val, Opt, Module, Reason]),
+ module_error(ErrTxt);
+ _:{unknown_option, Opt, []} ->
+ ErrTxt = io_lib:format("Unknown option '~s' of module '~s': "
+ "the module doesn't have any options",
+ [Opt, Module]),
+ module_error(ErrTxt);
+ _:{unknown_option, Opt, KnownOpts} ->
+ ErrTxt = io_lib:format("Unknown option '~s' of module '~s',"
+ " available options are: ~s",
+ [Opt, Module,
+ misc:join_atoms(KnownOpts, <<", ">>)]),
+ module_error(ErrTxt)
end.
-validate_opts(Host, Module, Opts, Required, Validators) when is_list(Opts) ->
+-spec module_error(iolist()) -> {error, iolist()}.
+module_error(ErrTxt) ->
+ ?ERROR_MSG(ErrTxt, []),
+ {error, ErrTxt}.
+
+-spec err_invalid_option(atom(), any()) -> no_return().
+err_invalid_option(Opt, Val) ->
+ erlang:error({invalid_option, Opt, Val}).
+
+-spec err_invalid_option(atom(), any(), iolist()) -> no_return().
+err_invalid_option(Opt, Val, Reason) ->
+ erlang:error({invalid_option, Opt, Val, Reason}).
+
+-spec err_unknown_option(atom(), [atom()]) -> no_return().
+err_unknown_option(Opt, KnownOpts) ->
+ erlang:error({unknown_option, Opt, KnownOpts}).
+
+-spec err_missing_required_option(atom()) -> no_return().
+err_missing_required_option(Opt) ->
+ erlang:error({missing_required_option, Opt}).
+
+validate_opts(Host, Module, Opts, Validators) when is_list(Opts) ->
lists:flatmap(
fun({Opt, Val}) when is_atom(Opt) ->
case lists:keyfind(Opt, 1, Validators) of
{_, L} ->
case lists:partition(fun is_function/1, L) of
{[VFun|_], []} ->
- validate_opt(Module, Opt, Val, Required, VFun);
+ validate_opt(Opt, Val, VFun);
{[VFun|_], SubValidators} ->
- try validate_opts(Host, Module, Val, Required, SubValidators) of
+ try validate_opts(Host, Module, Val, SubValidators) of
SubOpts ->
- validate_opt(Module, Opt, SubOpts, Required, VFun)
+ validate_opt(Opt, SubOpts, VFun)
catch _:bad_option ->
- ?ERROR_MSG("Ignoring invalid value '~p' for "
- "option '~s' of module '~s'",
- [Val, Opt, Module]),
- fail_if_option_is_required(Opt, Required),
- []
+ err_invalid_option(Opt, Val)
end
end;
false ->
- case Validators of
- [] ->
- ?ERROR_MSG("Ignoring unknown option '~s' of '~s':"
- " the module doesn't have any options",
- [Opt, Module]);
- _ ->
- ?ERROR_MSG("Ignoring unknown option '~s' of '~s',"
- " available options are: ~s",
- [Opt, Module,
- misc:join_atoms(
- [K || {K, _} <- Validators],
- <<", ">>)])
- end,
- []
+ err_unknown_option(Opt, [K || {K, _} <- Validators])
end;
(_) ->
erlang:error(bad_option)
end, Opts);
-validate_opts(_, _, _, _, _) ->
+validate_opts(_, _, _, _) ->
erlang:error(bad_option).
--spec validate_opt(module(), atom(), any(), [atom()],
- [{atom(), check_fun(), any()}]) -> [{atom(), any()}].
-validate_opt(Module, Opt, Val, Required, VFun) ->
+-spec validate_opt(atom(), any(), check_fun()) -> [{atom(), any()}].
+validate_opt(Opt, Val, VFun) ->
try VFun(Val) of
NewVal -> [{Opt, NewVal}]
catch {invalid_syntax, Error} ->
- ?ERROR_MSG("Ignoring invalid value '~p' for "
- "option '~s' of module '~s': ~s",
- [Val, Opt, Module, Error]),
- fail_if_option_is_required(Opt, Required),
- [];
+ err_invalid_option(Opt, Val, Error);
_:_ ->
- ?ERROR_MSG("Ignoring invalid value '~p' for "
- "option '~s' of module '~s'",
- [Val, Opt, Module]),
- fail_if_option_is_required(Opt, Required),
- []
- end.
-
--spec fail_if_option_is_required(atom(), [atom()]) -> ok | no_return().
-fail_if_option_is_required(Opt, Required) ->
- case lists:member(Opt, Required) of
- true -> erlang:error({missing_required_option, Opt});
- false -> ok
+ err_invalid_option(Opt, Val)
end.
-spec list_known_opts(binary(), module()) -> [atom() | {atom(), atom()}].
@@ -658,11 +663,7 @@ merge_opts(Opts, DefaultOpts, Module) ->
true ->
[{Opt, merge_opts(Val, Default, Module)}|Acc];
false ->
- ?ERROR_MSG(
- "Ignoring invalid value '~p' for "
- "option '~s' of module '~s'",
- [Val, Opt, Module]),
- [{Opt, Default}|Acc]
+ err_invalid_option(Opt, Val)
end;
Val ->
[{Opt, Default}|Acc];
@@ -677,7 +678,7 @@ merge_opts(Opts, DefaultOpts, Module) ->
{_, Val} ->
[{Opt, Val}|Acc];
false ->
- erlang:error({missing_required_option, Opt})
+ err_missing_required_option(Opt)
end
end, [], DefaultOpts),
lists:foldl(