]> granicus.if.org Git - ejabberd/commitdiff
Add code for handling deprecations of get_stacktrace()
authorPaweł Chmielowski <pchmielowski@process-one.net>
Thu, 13 Dec 2018 10:45:45 +0000 (11:45 +0100)
committerPaweł Chmielowski <pchmielowski@process-one.net>
Thu, 13 Dec 2018 10:46:53 +0000 (11:46 +0100)
19 files changed:
include/ejabberd_stacktrace.hrl [new file with mode: 0644]
mix.exs
rebar.config
src/ejabberd_acme.erl
src/ejabberd_ctl.erl
src/ejabberd_hooks.erl
src/ejabberd_local.erl
src/ejabberd_mnesia.erl
src/ejabberd_redis.erl
src/ejabberd_router.erl
src/ejabberd_router_sql.erl
src/ejabberd_s2s.erl
src/ejabberd_sm.erl
src/ejabberd_sql.erl
src/gen_iq_handler.erl
src/gen_mod.erl
src/mod_http_api.erl
src/mod_muc_room.erl
src/mod_roster.erl

diff --git a/include/ejabberd_stacktrace.hrl b/include/ejabberd_stacktrace.hrl
new file mode 100644 (file)
index 0000000..470abed
--- /dev/null
@@ -0,0 +1,27 @@
+%%%----------------------------------------------------------------------
+%%%
+%%% ejabberd, Copyright (C) 2002-2018   ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%----------------------------------------------------------------------
+
+-ifdef(DEPRECATED_GET_STACKTRACE).
+-define(EX_RULE(Class, Reason, Stack), Class:Reason:Stack).
+-define(EX_STACK(Stack), Stack).
+-else.
+-define(EX_RULE(Class, Reason, _), Class:Reason).
+-define(EX_STACK(_), erlang:get_stacktrace()).
+-endif.
diff --git a/mix.exs b/mix.exs
index 176e229f6c98504514f50ed64d9fcb0f0bd096fa..92e4ca876ec1a3abc189c7dea1750a531a332c82 100644 (file)
--- a/mix.exs
+++ b/mix.exs
@@ -42,10 +42,19 @@ defmodule Ejabberd.Mixfile do
     end
   end
 
+  defp if_version_above(ver, okResult) do
+    if :erlang.system_info(:otp_release) > ver do
+      okResult
+    else
+      []
+    end
+  end
+
   defp erlc_options do
     # Use our own includes + includes from all dependencies
     includes = ["include"] ++ deps_include(["fast_xml", "xmpp", "p1_utils"])
     [:debug_info, {:d, :ELIXIR_ENABLED}] ++ cond_options() ++ Enum.map(includes, fn(path) -> {:i, path} end) ++
+    if_version_above('20', [{:d, :DEPRECATED_GET_STACKTRACE}]) ++
     if_function_exported(:crypto, :strong_rand_bytes, 1, [{:d, :STRONG_RAND_BYTES}]) ++
     if_function_exported(:rand, :uniform, 1, [{:d, :RAND_UNIFORM}]) ++
     if_function_exported(:gb_sets, :iterator_from, 2, [{:d, :GB_SETS_ITERATOR_FROM}]) ++
index b2de1bd0eba1aed921e3074921d9da856bcd4c7b..4c61cc4a475f7f8ae9f93ed36d3fae9eb8c1960a 100644 (file)
@@ -92,6 +92,7 @@
             {if_var_true, debug, debug_info},
             {if_var_true, sip, {d, 'SIP'}},
             {if_var_true, stun, {d, 'STUN'}},
+            {if_version_above, "20", {d, 'DEPRECATED_GET_STACKTRACE'}},
             {if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
             {if_var_match, db_type, mssql, {d, 'mssql'}},
             {if_var_true, elixir, {d, 'ELIXIR_ENABLED'}},
index bd4f22418f4fe352aab51271be70e7a767b0b378..9e25ed4e6cbb6028db5e63d095c707a3bddd2aa2 100644 (file)
@@ -25,6 +25,7 @@
 -include("ejabberd_commands.hrl").
 -include("ejabberd_acme.hrl").
 -include_lib("public_key/include/public_key.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -define(DEFAULT_CONFIG_CONTACT, <<"mailto:example-admin@example.com">>).
 -define(DEFAULT_CONFIG_CA_URL, "https://acme-v01.api.letsencrypt.org").
@@ -100,10 +101,10 @@ is_valid_domain_opt(DomainString) ->
     end.
 
 -spec is_valid_revoke_cert(string()) -> boolean().
-is_valid_revoke_cert(DomainOrFile) ->      
+is_valid_revoke_cert(DomainOrFile) ->
     lists:prefix("file:", DomainOrFile) orelse
        lists:prefix("domain:", DomainOrFile).
-           
+
 %% Commands
 get_commands_spec() ->
     [#ejabberd_commands{name = get_certificates, tags = [acme],
@@ -142,7 +143,7 @@ get_commands_spec() ->
 %%
 -spec get_certificates(domains_opt()) -> string() | {'error', _}.
 get_certificates(Domains) ->
-    case is_valid_domain_opt(Domains) of 
+    case is_valid_domain_opt(Domains) of
        true ->
            try
                CAUrl = get_config_ca_url(),
@@ -150,9 +151,8 @@ get_certificates(Domains) ->
            catch
                throw:Throw ->
                    Throw;
-               E:R ->
-                    St = erlang:get_stacktrace(),
-                   ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
+               ?EX_RULE(E, R, St) ->
+                   ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
                    {error, get_certificates}
            end;
        false ->
@@ -171,7 +171,7 @@ retrieve_or_create_account(CAUrl) ->
     case read_account_persistent() of
        none ->
            create_save_new_account(CAUrl);
-       
+
        {ok, AccId, CAUrl, PrivateKey} ->
            {ok, AccId, PrivateKey};
        {ok, _AccId, _, _PrivateKey} ->
@@ -199,7 +199,7 @@ get_certificates2(CAUrl, PrivateKey, Hosts) ->
     %% Format the result to send back to ejabberdctl
     format_get_certificates_result(SavedCerts).
 
--spec format_get_certificates_result([{'ok', bitstring(), _} | 
+-spec format_get_certificates_result([{'ok', bitstring(), _} |
                                      {'error', bitstring(), _}]) ->
                                            string().
 format_get_certificates_result(Certs) ->
@@ -211,26 +211,26 @@ format_get_certificates_result(Certs) ->
     case Cond of
        true ->
            Result = io_lib:format("Success:~n~s", [FormattedCerts]),
-           lists:flatten(Result); 
+           lists:flatten(Result);
        _ ->
            Result = io_lib:format("Error with one or more certificates~n~s", [FormattedCerts]),
            lists:flatten(Result)
     end.
 
--spec format_get_certificate({'ok', bitstring(), _} | 
+-spec format_get_certificate({'ok', bitstring(), _} |
                             {'error', bitstring(), _}) ->
                                    string().
-format_get_certificate({ok, Domain, saved}) ->    
+format_get_certificate({ok, Domain, saved}) ->
     io_lib:format("  Certificate for domain: \"~s\" acquired and saved", [Domain]);
-format_get_certificate({ok, Domain, not_found}) ->    
+format_get_certificate({ok, Domain, not_found}) ->
     io_lib:format("  Certificate for domain: \"~s\" not found, so it was not renewed", [Domain]);
 format_get_certificate({ok, Domain, no_expire}) ->
     io_lib:format("  Certificate for domain: \"~s\" is not close to expiring", [Domain]);
 format_get_certificate({error, Domain, Reason}) ->
     io_lib:format("  Error for domain: \"~s\",  with reason: \'~s\'", [Domain, Reason]).
 
--spec get_certificate(url(), bitstring(), jose_jwk:key()) -> 
-                            {'ok', bitstring(), pem()} | 
+-spec get_certificate(url(), bitstring(), jose_jwk:key()) ->
+                            {'ok', bitstring(), pem()} |
                             {'error', bitstring(), _}.
 get_certificate(CAUrl, DomainName, PrivateKey) ->
     try
@@ -243,9 +243,8 @@ get_certificate(CAUrl, DomainName, PrivateKey) ->
     catch
        throw:Throw ->
            Throw;
-       E:R ->
-            St = erlang:get_stacktrace(),
-           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
+       ?EX_RULE(E, R, St) ->
+           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
            {error, DomainName, get_certificate}
     end.
 
@@ -267,23 +266,23 @@ create_save_new_account(CAUrl) ->
 
 %% TODO:
 %% Find a way to ask the user if he accepts the TOS
--spec create_new_account(url(), bitstring(), jose_jwk:key()) -> {'ok', string()} | 
+-spec create_new_account(url(), bitstring(), jose_jwk:key()) -> {'ok', string()} |
                                                                no_return().
 create_new_account(CAUrl, Contact, PrivateKey) ->
     try
        {ok, Dirs, Nonce0} = ejabberd_acme_comm:directory(CAUrl),
        Req0 = [{ <<"contact">>, [Contact]}],
-       {ok, {TOS, Account}, Nonce1} = 
+       {ok, {TOS, Account}, Nonce1} =
            ejabberd_acme_comm:new_account(Dirs, PrivateKey, Req0, Nonce0),
        {<<"id">>, AccIdInt} = lists:keyfind(<<"id">>, 1, Account),
        AccId = integer_to_list(AccIdInt),
        Req1 = [{ <<"agreement">>, list_to_bitstring(TOS)}],
-       {ok, _Account2, _Nonce2} = 
+       {ok, _Account2, _Nonce2} =
            ejabberd_acme_comm:update_account({CAUrl, AccId}, PrivateKey, Req1, Nonce1),
        {ok, AccId}
     catch
        E:R ->
-           ?ERROR_MSG("Error: ~p creating an account for contact: ~p", 
+           ?ERROR_MSG("Error: ~p creating an account for contact: ~p",
                       [{E,R}, Contact]),
            throw({error,create_new_account})
     end.
@@ -298,7 +297,7 @@ create_new_authorization(CAUrl, DomainName, PrivateKey) ->
                 {[{<<"type">>, <<"dns">>},
                   {<<"value">>, DomainName}]}},
                {<<"existing">>, <<"accept">>}],
-       {ok, {AuthzUrl, Authz}, Nonce1} = 
+       {ok, {AuthzUrl, Authz}, Nonce1} =
            ejabberd_acme_comm:new_authz(Dirs, PrivateKey, Req0, Nonce0),
        {ok, AuthzId} = location_to_id(AuthzUrl),
 
@@ -321,7 +320,7 @@ create_new_authorization(CAUrl, DomainName, PrivateKey) ->
        acme_challenge:unregister_hooks(DomainName)
     end.
 
--spec create_new_certificate(url(), {bitstring(), [bitstring()]}, jose_jwk:key()) -> 
+-spec create_new_certificate(url(), {bitstring(), [bitstring()]}, jose_jwk:key()) ->
                                    {ok, bitstring(), pem()}.
 create_new_certificate(CAUrl, {DomainName, AllSubDomains}, PrivateKey) ->
     try
@@ -338,7 +337,7 @@ create_new_certificate(CAUrl, {DomainName, AllSubDomains}, PrivateKey) ->
        {ok, {IssuerCertLink, Certificate}, _Nonce1} =
            ejabberd_acme_comm:new_cert(Dirs, PrivateKey, Req, Nonce0),
 
-       DecodedCert = public_key:pkix_decode_cert(list_to_binary(Certificate), plain),  
+       DecodedCert = public_key:pkix_decode_cert(list_to_binary(Certificate), plain),
        PemEntryCert = public_key:pem_entry_encode('Certificate', DecodedCert),
 
        {ok, IssuerCert, _Nonce2} = ejabberd_acme_comm:get_issuer_cert(IssuerCertLink),
@@ -351,7 +350,7 @@ create_new_certificate(CAUrl, {DomainName, AllSubDomains}, PrivateKey) ->
        PemCertKey = public_key:pem_encode([PemEntryKey, PemEntryCert, PemEntryIssuerCert]),
 
        {ok, DomainName, PemCertKey}
-    catch                   
+    catch
        E:R ->
            ?ERROR_MSG("Error: ~p getting an authorization for domain: ~p~n",
                       [{E,R}, DomainName]),
@@ -383,9 +382,8 @@ renew_certificates() ->
     catch
        throw:Throw ->
            Throw;
-       E:R ->
-            St = erlang:get_stacktrace(),
-           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
+       ?EX_RULE(E, R, St) ->
+           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
            {error, get_certificates}
     end.
 
@@ -406,8 +404,8 @@ renew_certificates0(CAUrl) ->
     %% Format the result to send back to ejabberdctl
     format_get_certificates_result(SavedCerts).
 
--spec renew_certificate(url(), {bitstring(), data_cert()}, jose_jwk:key()) -> 
-                              {'ok', bitstring(), _} | 
+-spec renew_certificate(url(), {bitstring(), data_cert()}, jose_jwk:key()) ->
+                              {'ok', bitstring(), _} |
                               {'error', bitstring(), _}.
 renew_certificate(CAUrl, {DomainName, _} = Cert, PrivateKey) ->
     case cert_to_expire(Cert) of
@@ -449,9 +447,8 @@ list_certificates(Verbose) ->
            catch
                throw:Throw ->
                    Throw;
-               E:R ->
-                    St = erlang:get_stacktrace(),
-                   ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
+               ?EX_RULE(E, R, St) ->
+                   ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
                    {error, list_certificates}
            end;
        false ->
@@ -492,34 +489,33 @@ format_certificate(DataCert, Verbose) ->
                format_certificate_verbose(DomainName, SANs, NotAfter, PemCert)
        end
     catch
-       E:R ->
-            St = erlang:get_stacktrace(),
-           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
+       ?EX_RULE(E, R, St) ->
+           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
            fail_format_certificate(DomainName)
     end.
 
--spec format_certificate_plain(bitstring(), [string()], {expired | ok, string()}, string()) 
+-spec format_certificate_plain(bitstring(), [string()], {expired | ok, string()}, string())
                              -> string().
 format_certificate_plain(DomainName, SANs, NotAfter, Path) ->
     Result = lists:flatten(io_lib:format(
-                            "  Domain: ~s~n" 
+                            "  Domain: ~s~n"
                             "~s"
-                            "    ~s~n" 
-                            "    Path: ~s", 
+                            "    ~s~n"
+                            "    Path: ~s",
                             [DomainName,
                              lists:flatten([io_lib:format("    SAN: ~s~n", [SAN]) || SAN <- SANs]),
                              format_validity(NotAfter), Path])),
     Result.
 
--spec format_certificate_verbose(bitstring(), [string()], {expired | ok, string()}, bitstring()) 
+-spec format_certificate_verbose(bitstring(), [string()], {expired | ok, string()}, bitstring())
                                -> string().
 format_certificate_verbose(DomainName, SANs, NotAfter, PemCert) ->
     Result = lists:flatten(io_lib:format(
                             "  Domain: ~s~n"
-                            "~s" 
-                            "    ~s~n" 
-                            "    Certificate In PEM format: ~n~s", 
-                            [DomainName, 
+                            "~s"
+                            "    ~s~n"
+                            "    Certificate In PEM format: ~n~s",
+                            [DomainName,
                              lists:flatten([io_lib:format("    SAN: ~s~n", [SAN]) || SAN <- SANs]),
                              format_validity(NotAfter), PemCert])),
     Result.
@@ -533,8 +529,8 @@ format_validity({ok, NotAfter}) ->
 -spec fail_format_certificate(bitstring()) -> string().
 fail_format_certificate(DomainName) ->
     Result = lists:flatten(io_lib:format(
-                            "  Domain: ~s~n" 
-                            "    Failed to format Certificate", 
+                            "  Domain: ~s~n"
+                            "    Failed to format Certificate",
                             [DomainName])),
     Result.
 
@@ -542,7 +538,7 @@ fail_format_certificate(DomainName) ->
 get_commonName(#'Certificate'{tbsCertificate = TbsCertificate}) ->
     #'TBSCertificate'{
        subject = {rdnSequence, SubjectList}
-      } = TbsCertificate, 
+      } = TbsCertificate,
 
     %% TODO: Not the best way to find the commonName
     ShallowSubjectList = [Attribute || [Attribute] <- SubjectList],
@@ -560,9 +556,9 @@ get_notAfter(Certificate) ->
               true -> "19" ++ [Y1,Y2];
               _ -> "20" ++ [Y1,Y2]
           end,
-    NotAfter = lists:flatten(io_lib:format("~s-~s-~s ~s:~s:~s", 
+    NotAfter = lists:flatten(io_lib:format("~s-~s-~s ~s:~s:~s",
                                           [YEAR, [MO1,MO2], [D1,D2],
-                                           [H1,H2], [MI1,MI2], [S1,S2]])), 
+                                           [H1,H2], [MI1,MI2], [S1,S2]])),
 
     case close_to_expire(UtcTime, 0) of
        true ->
@@ -577,7 +573,7 @@ get_subjectAltNames(#'Certificate'{tbsCertificate = TbsCertificate}) ->
        extensions = Exts
       } = TbsCertificate,
 
-    EncodedSANs = [Val || #'Extension'{extnID = Oid, extnValue = Val} <- Exts, 
+    EncodedSANs = [Val || #'Extension'{extnID = Oid, extnValue = Val} <- Exts,
                          Oid =:= attribute_oid(subjectAltName)],
 
     lists:flatmap(
@@ -586,7 +582,7 @@ get_subjectAltNames(#'Certificate'{tbsCertificate = TbsCertificate}) ->
              [Name || {dNSName, Name} <- SANs0]
       end, EncodedSANs).
 
-    
+
 
 -spec get_utc_validity(#'Certificate'{}) -> string().
 get_utc_validity(#'Certificate'{tbsCertificate = TbsCertificate}) ->
@@ -618,18 +614,17 @@ revoke_certificates(DomainOrFile) ->
     catch
        throw:Throw ->
            Throw;
-       E:R ->
-            St = erlang:get_stacktrace(),
-           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
+       ?EX_RULE(E, R, St) ->
+           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
            {error, revoke_certificate}
-    end.       
+    end.
 
 -spec revoke_certificate0(url(), string()) -> {ok, deleted}.
 revoke_certificate0(CAUrl, DomainOrFile) ->
     ParsedCert = parse_revoke_cert_argument(DomainOrFile),
     revoke_certificate1(CAUrl, ParsedCert).
 
--spec revoke_certificate1(url(), {domain, bitstring()} | {file, file:filename()}) -> 
+-spec revoke_certificate1(url(), {domain, bitstring()} | {file, file:filename()}) ->
                                 {ok, deleted}.
 revoke_certificate1(CAUrl, {domain, Domain}) ->
     case domain_certificate_exists(Domain) of
@@ -650,7 +645,7 @@ revoke_certificate1(CAUrl, {file, File}) ->
            ?ERROR_MSG("Error: ~p reading pem certificate-key file: ~p", [Reason, File]),
            throw({error, Reason})
     end.
-       
+
 
 -spec revoke_certificate2(url(), pem()) -> ok.
 revoke_certificate2(CAUrl, PemEncodedCert) ->
@@ -676,10 +671,10 @@ prepare_certificate_revoke(PemEncodedCert) ->
     DerCert = public_key:der_encode('Certificate', PemCert),
     Base64Cert = base64url:encode(DerCert),
 
-    {ok, Key} = find_private_key_in_pem(PemEncodedCert),    
+    {ok, Key} = find_private_key_in_pem(PemEncodedCert),
     {Base64Cert, Key}.
 
--spec domain_certificate_exists(bitstring()) -> {bitstring(), data_cert()} | false.    
+-spec domain_certificate_exists(bitstring()) -> {bitstring(), data_cert()} | false.
 domain_certificate_exists(Domain) ->
     Certs = read_certificates_persistent(),
     lists:keyfind(Domain, 1, Certs).
@@ -693,7 +688,7 @@ domain_certificate_exists(Domain) ->
 %% For now we accept only generating a key of
 %% specific type for signing the csr
 
--spec make_csr(proplist(), [{dNSName, bitstring()}]) 
+-spec make_csr(proplist(), [{dNSName, bitstring()}])
              -> {binary(), jose_jwk:key()}.
 make_csr(Attributes, SANs) ->
     Key = generate_key(),
@@ -749,9 +744,9 @@ extension(SANs) ->
 extension_request(SANs) ->
     #'AttributePKCS-10'{
        type = ?'pkcs-9-at-extensionRequest',
-       values = [{'asn1_OPENTYPE', 
+       values = [{'asn1_OPENTYPE',
                  public_key:der_encode(
-                   'ExtensionRequest', 
+                   'ExtensionRequest',
                    [extension(SANs)])}]
       }.
 
@@ -918,7 +913,7 @@ find_private_key_in_pem(Pem) ->
            JoseKey = jose_jwk:from_key(Key),
            {ok, JoseKey}
     end.
-           
+
 
 -spec find_private_key_in_pem1([public_key:pki_asn1_type()],
                               [public_key:pem_entry()]) ->
@@ -948,10 +943,10 @@ private_key_types() ->
 find_all_sub_domains(DomainName) ->
     AllRoutes = ejabberd_router:get_all_routes(),
     DomainLen = size(DomainName),
-    [Route || Route <- AllRoutes,  
-             binary:longest_common_suffix([DomainName, Route]) 
+    [Route || Route <- AllRoutes,
+             binary:longest_common_suffix([DomainName, Route])
                  =:= DomainLen].
-    
+
 
 -spec is_error(_) -> boolean().
 is_error({error, _}) -> true;
@@ -981,13 +976,13 @@ data_get_account(Data) ->
     end.
 
 -spec data_set_account(acme_data(), {list(), url(), jose_jwk:key()}) -> acme_data().
-data_set_account(Data, {AccId, CAUrl, PrivateKey}) -> 
+data_set_account(Data, {AccId, CAUrl, PrivateKey}) ->
     NewAcc = {account, #data_acc{id = AccId, ca_url = CAUrl, key = PrivateKey}},
     lists:keystore(account, 1, Data, NewAcc).
 
 %%
 %% Certificates
-%% 
+%%
 
 -spec data_get_certificates(acme_data()) -> data_certs().
 data_get_certificates(Data) ->
@@ -999,7 +994,7 @@ data_get_certificates(Data) ->
     end.
 
 -spec data_set_certificates(acme_data(), data_certs()) -> acme_data().
-data_set_certificates(Data, NewCerts) -> 
+data_set_certificates(Data, NewCerts) ->
     lists:keystore(certs, 1, Data, {certs, NewCerts}).
 
 %% ATM we preserve one certificate for each domain
@@ -1053,7 +1048,7 @@ write_persistent(Data) ->
        {error, Reason} ->
            ?ERROR_MSG("Error: ~p writing acme data file", [Reason]),
            throw({error, Reason})
-    end.    
+    end.
 
 -spec create_persistent() -> ok | no_return().
 create_persistent() ->
@@ -1069,7 +1064,7 @@ create_persistent() ->
        {error, Reason} ->
            ?ERROR_MSG("Error: ~p creating acme data file", [Reason]),
            throw({error, Reason})
-    end.        
+    end.
 
 -spec write_account_persistent({list(), url(), jose_jwk:key()}) -> ok | no_return().
 write_account_persistent({AccId, CAUrl, PrivateKey}) ->
@@ -1099,7 +1094,7 @@ remove_certificate_persistent(DataCert) ->
     NewData = data_remove_certificate(Data, DataCert),
     ok = write_persistent(NewData).
 
--spec save_certificate({ok, bitstring(), binary()} | {error, _, _}) -> 
+-spec save_certificate({ok, bitstring(), binary()} | {error, _, _}) ->
                              {ok, bitstring(), saved} | {error, bitstring(), _}.
 save_certificate({error, _, _} = Error) ->
     Error;
@@ -1123,13 +1118,12 @@ save_certificate({ok, DomainName, Cert}) ->
     catch
        throw:Throw ->
            Throw;
-       E:R ->
-            St = erlang:get_stacktrace(),
-           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
+       ?EX_RULE(E, R, St) ->
+           ?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
            {error, DomainName, saving}
     end.
 
--spec save_renewed_certificate({ok, bitstring(), _} | {error, _, _}) -> 
+-spec save_renewed_certificate({ok, bitstring(), _} | {error, _, _}) ->
                                      {ok, bitstring(), _} | {error, bitstring(), _}.
 save_renewed_certificate({error, _, _} = Error) ->
     Error;
index c716495629e56f588d949d11aac355e2df9afc96..3930d8865b48644efce2003d3d46455f5c8374ec 100644 (file)
@@ -59,6 +59,7 @@
 -include("ejabberd_ctl.hrl").
 -include("ejabberd_commands.hrl").
 -include("logger.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -define(DEFAULT_VERSION, 1000000).
 
@@ -327,9 +328,9 @@ try_call_command(Args, Auth, AccessCommands, Version) ->
     catch
        throw:Error ->
            {io_lib:format("~p", [Error]), ?STATUS_ERROR};
-       A:Why ->
-           Stack = erlang:get_stacktrace(),
-           {io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p", [A, Why, Stack]), ?STATUS_ERROR}
+       ?EX_RULE(A, Why, Stack) ->
+           {io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p",
+                          [A, Why, ?EX_STACK(Stack)]), ?STATUS_ERROR}
     end.
 
 %% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} | {error, ErrorType}
index bc67b4c67aa92e0f63bc961269a8d7a635579998..383f203cc3cc55cbfc4f5939b8357afd189cecff 100644 (file)
@@ -57,6 +57,7 @@
         terminate/2]).
 
 -include("logger.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -record(state, {}).
 -type local_hook() :: { Seq :: integer(), Module :: atom(), Function :: atom()}.
@@ -129,14 +130,14 @@ delete_dist(Hook, Node, Module, Function, Seq) ->
 delete_dist(Hook, Host, Node, Module, Function, Seq) ->
     gen_server:call(ejabberd_hooks, {delete, Hook, Host, Node, Module, Function, Seq}).
 
--spec delete_all_hooks() -> true. 
+-spec delete_all_hooks() -> true.
 
 %% @doc Primarily for testing / instrumentation
 delete_all_hooks() ->
     gen_server:call(ejabberd_hooks, {delete_all}).
 
 -spec get_handlers(atom(), binary() | global) -> [local_hook() | distributed_hook()].
-%% @doc Returns currently set handler for hook name 
+%% @doc Returns currently set handler for hook name
 get_handlers(Hookname, Host) ->
     gen_server:call(ejabberd_hooks, {get_handlers, Hookname, Host}).
 
@@ -264,7 +265,7 @@ handle_delete(Hook, Host, El) ->
             ok;
         [] ->
             ok
-    end. 
+    end.
 
 %%----------------------------------------------------------------------
 %% Func: handle_cast/2
@@ -379,15 +380,11 @@ safe_apply(Hook, Module, Function, Args) ->
        true ->
                apply(Module, Function, Args)
        end
-    catch E:R when E /= exit; R /= normal ->
-            St = get_stacktrace(),
+    catch ?EX_RULE(E, R, St) when E /= exit; R /= normal ->
            ?ERROR_MSG("Hook ~p crashed when running ~p:~p/~p:~n"
                       "** Reason = ~p~n"
                       "** Arguments = ~p",
                       [Hook, Module, Function, length(Args),
-                       {E, R, St}, Args]),
+                       {E, R, ?EX_STACK(St)}, Args]),
            'EXIT'
     end.
-
-get_stacktrace() ->
-    [{Mod, Fun, Loc, Args} || {Mod, Fun, Args, Loc} <- erlang:get_stacktrace()].
index d9ef971299d18f13361cec702a7f03402cfdd1c6..2a1b532e01c6a63412ae9be62470dc2195330569 100644 (file)
@@ -48,6 +48,7 @@
 -include("logger.hrl").
 -include_lib("stdlib/include/ms_transform.hrl").
 -include("xmpp.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -record(state, {}).
 
@@ -70,10 +71,9 @@ start_link() ->
 -spec route(stanza()) -> any().
 route(Packet) ->
     try do_route(Packet)
-    catch E:R ->
-            St = erlang:get_stacktrace(),
+    catch ?EX_RULE(E, R, St) ->
            ?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
-                      [xmpp:pp(Packet), {E, {R, St}}])
+                      [xmpp:pp(Packet), {E, {R, ?EX_STACK(St)}}])
     end.
 
 -spec route_iq(iq(), function()) -> ok.
index 48bc6db5c2fabfbc071e9179dd8597a94bfd86ec..882f95041c3ba42ddf97a0b6e782860a9ec4958c 100644 (file)
@@ -43,6 +43,7 @@
 -define(NEED_RESET, [local_content, type]).
 
 -include("logger.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -record(state, {tables = #{} :: map(),
                schema = [] :: [{atom(), [{atom(), any()}]}]}).
@@ -385,8 +386,8 @@ do_transform(OldAttrs, Attrs, Old) ->
 transform_fun(Module, Name) ->
     fun(Obj) ->
            try Module:transform(Obj)
-           catch E:R ->
-                   StackTrace = erlang:get_stacktrace(),
+           catch ?EX_RULE(E, R, St) ->
+                   StackTrace = ?EX_STACK(St),
                    ?ERROR_MSG("Failed to transform Mnesia table ~s:~n"
                               "** Record: ~p~n"
                               "** Reason: ~p~n"
index 857bece0e119132228307703181db05d785686cd..ac4421588f1f286238b798d68c0277a08f76a478 100644 (file)
@@ -50,6 +50,7 @@
 -define(CALL_TIMEOUT, 60*1000). %% 60 seconds
 
 -include("logger.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -record(state, {connection :: pid() | undefined,
                num :: pos_integer(),
@@ -106,9 +107,9 @@ multi(F) ->
                        {error, _} = Err -> Err;
                        Result -> get_result(Result)
                    end
-           catch E:R ->
+           catch ?EX_RULE(E, R, St) ->
                    erlang:erase(?TR_STACK),
-                   erlang:raise(E, R, erlang:get_stacktrace())
+                   erlang:raise(E, R, ?EX_STACK(St))
            end;
        _ ->
            erlang:error(nested_transaction)
index bd9a87ce27108fd2959ca45f47907718db798516..edfcf932a560dabba32eb9f4f507cf005a54b8a8 100644 (file)
@@ -71,6 +71,7 @@
 -include("logger.hrl").
 -include("ejabberd_router.hrl").
 -include("xmpp.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -callback init() -> any().
 -callback register_route(binary(), binary(), local_hint(),
@@ -90,10 +91,9 @@ start_link() ->
 -spec route(stanza()) -> ok.
 route(Packet) ->
     try do_route(Packet)
-    catch E:R ->
-            St = erlang:get_stacktrace(),
+    catch ?EX_RULE(E, R, St) ->
            ?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
-                      [xmpp:pp(Packet), {E, {R, St}}])
+                      [xmpp:pp(Packet), {E, {R, ?EX_STACK(St)}}])
     end.
 
 -spec route(jid(), jid(), xmlel() | stanza()) -> ok.
index edf06dfe0e26f9d946603c95344fb82149696b23..fa6579ce40fbc48f0145185b9f5dc9e3c8918614 100644 (file)
@@ -32,6 +32,7 @@
 -include("logger.hrl").
 -include("ejabberd_sql_pt.hrl").
 -include("ejabberd_router.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 %%%===================================================================
 %%% API
@@ -121,12 +122,11 @@ row_to_route(Domain, {ServerHost, NodeS, PidS, LocalHintS} = Row) ->
                local_hint = dec_local_hint(LocalHintS)}]
     catch _:{bad_node, _} ->
            [];
-         E:R ->
-            St = erlang:get_stacktrace(),
+         ?EX_RULE(E, R, St) ->
            ?ERROR_MSG("failed to decode row from 'route' table:~n"
                       "Row = ~p~n"
                       "Domain = ~s~n"
                       "Reason = ~p",
-                      [Row, Domain, {E, {R, St}}]),
+                      [Row, Domain, {E, {R, ?EX_STACK(St)}}]),
            []
     end.
index a33d477e5898629714f3bef9acdfa133d000e1c0..b721ca1e7a54db068d0cd89f1ac58e0301709601 100644 (file)
         transform_options/1, opt_type/1]).
 
 -include("logger.hrl").
-
 -include("xmpp.hrl").
-
 -include("ejabberd_commands.hrl").
-
 -include_lib("public_key/include/public_key.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -define(PKIXEXPLICIT, 'OTP-PUB-KEY').
 
@@ -94,10 +92,9 @@ start_link() ->
 
 route(Packet) ->
     try do_route(Packet)
-    catch E:R ->
-            St = erlang:get_stacktrace(),
+    catch ?EX_RULE(E, R, St) ->
             ?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
-                       [xmpp:pp(Packet), {E, {R, St}}])
+                       [xmpp:pp(Packet), {E, {R, ?EX_STACK(St)}}])
     end.
 
 clean_temporarily_blocked_table() ->
index 6c00815d54986c012c6112ea3f33296c74ae2ab2..873c32da0ccda55c9be09d91a1c665002fb0b7e7 100644 (file)
@@ -90,6 +90,7 @@
 
 -include("ejabberd_commands.hrl").
 -include("ejabberd_sm.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -callback init() -> ok | {error, any()}.
 -callback set_session(#session{}) -> ok | {error, any()}.
@@ -140,11 +141,10 @@ route(Packet) ->
            ?DEBUG("hook dropped stanza:~n~s", [xmpp:pp(Packet)]);
        Packet1 ->
            try do_route(Packet1), ok
-           catch E:R ->
-                    St = erlang:get_stacktrace(),
+           catch ?EX_RULE(E, R, St) ->
                    ?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
                               [xmpp:pp(Packet1),
-                               {E, {R, St}}])
+                               {E, {R, ?EX_STACK(St)}}])
            end
     end.
 
index 9e088f211ff0effd618482ae2d7729ed27212b78..5e35e344c144b44aa4140f2a030025a30906dede 100644 (file)
@@ -69,6 +69,7 @@
 
 -include("logger.hrl").
 -include("ejabberd_sql_pt.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -record(state,
        {db_ref = self()                     :: pid(),
@@ -516,24 +517,26 @@ outer_transaction(F, NRestarts, _Reason) ->
     end,
     sql_query_internal([<<"begin;">>]),
     put(?NESTING_KEY, PreviousNestingLevel + 1),
-    Result = (catch F()),
-    put(?NESTING_KEY, PreviousNestingLevel),
-    case Result of
-      {aborted, Reason} when NRestarts > 0 ->
-         sql_query_internal([<<"rollback;">>]),
-         outer_transaction(F, NRestarts - 1, Reason);
-      {aborted, Reason} when NRestarts =:= 0 ->
-         ?ERROR_MSG("SQL transaction restarts exceeded~n** "
-                    "Restarts: ~p~n** Last abort reason: "
-                    "~p~n** Stacktrace: ~p~n** When State "
-                    "== ~p",
-                    [?MAX_TRANSACTION_RESTARTS, Reason,
-                     erlang:get_stacktrace(), get(?STATE_KEY)]),
-         sql_query_internal([<<"rollback;">>]),
-         {aborted, Reason};
-      {'EXIT', Reason} ->
-         sql_query_internal([<<"rollback;">>]), {aborted, Reason};
-      Res -> sql_query_internal([<<"commit;">>]), {atomic, Res}
+    try F() of
+       Res ->
+           sql_query_internal([<<"commit;">>]),
+           {atomic, Res}
+    catch
+       ?EX_RULE(throw, {aborted, Reason}, _) when NRestarts > 0 ->
+           sql_query_internal([<<"rollback;">>]),
+           outer_transaction(F, NRestarts - 1, Reason);
+       ?EX_RULE(throw, {aborted, Reason}, Stack) when NRestarts =:= 0 ->
+           ?ERROR_MSG("SQL transaction restarts exceeded~n** "
+                      "Restarts: ~p~n** Last abort reason: "
+                      "~p~n** Stacktrace: ~p~n** When State "
+                      "== ~p",
+                      [?MAX_TRANSACTION_RESTARTS, Reason,
+                       ?EX_STACK(Stack), get(?STATE_KEY)]),
+           sql_query_internal([<<"rollback;">>]),
+           {aborted, Reason};
+       ?EX_RULE(exit, Reason, _) ->
+           sql_query_internal([<<"rollback;">>]),
+           {aborted, Reason}
     end.
 
 execute_bloc(F) ->
@@ -599,10 +602,9 @@ sql_query_internal(#sql_query{} = Query) ->
                {error, <<"killed">>};
              exit:{normal, _} ->
                {error, <<"terminated unexpectedly">>};
-             Class:Reason ->
-                ST = erlang:get_stacktrace(),
+             ?EX_RULE(Class, Reason, Stack) ->
                 ?ERROR_MSG("Internal error while processing SQL query: ~p",
-                           [{Class, Reason, ST}]),
+                           [{Class, Reason, ?EX_STACK(Stack)}]),
                 {error, <<"internal error">>}
         end,
     check_error(Res, Query);
@@ -737,12 +739,11 @@ sql_query_format_res({selected, _, Rows}, SQLQuery) ->
                   try
                       [(SQLQuery#sql_query.format_res)(Row)]
                   catch
-                      Class:Reason ->
-                          ST = erlang:get_stacktrace(),
+                     ?EX_RULE(Class, Reason, Stack) ->
                           ?ERROR_MSG("Error while processing "
                                      "SQL query result: ~p~n"
                                      "row: ~p",
-                                     [{Class, Reason, ST}, Row]),
+                                     [{Class, Reason, ?EX_STACK(Stack)}, Row]),
                           []
                   end
           end, Rows),
index f6a6744fde81342718c2b0c0e2a45c719bd1f192..9e7b5640615ac0aef90b063127c2152fb6abafff 100644 (file)
@@ -40,6 +40,7 @@
 -include("logger.hrl").
 -include("xmpp.hrl").
 -include("translate.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -type component() :: ejabberd_sm | ejabberd_local.
 
@@ -113,10 +114,9 @@ process_iq(_Host, Module, Function, IQ) ->
            ejabberd_router:route(ResIQ);
        ignore ->
            ok
-    catch E:R ->
-            St = erlang:get_stacktrace(),
+    catch ?EX_RULE(E, R, St) ->
            ?ERROR_MSG("failed to process iq:~n~s~nReason = ~p",
-                      [xmpp:pp(IQ), {E, {R, St}}]),
+                      [xmpp:pp(IQ), {E, {R, ?EX_STACK(St)}}]),
            Txt = <<"Module failed to handle the query">>,
            Err = xmpp:err_internal_server_error(Txt, IQ#iq.lang),
            ejabberd_router:route_error(IQ, Err)
index cf107f7b0bb9289eff8ac7b38f38964f7d81ecdb..d225beeffee648700948e464ca682240a7dd433c 100644 (file)
@@ -58,6 +58,7 @@
 
 -include("logger.hrl").
 -include_lib("stdlib/include/ms_transform.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -record(ejabberd_module,
         {module_host = {undefined, <<"">>} :: {atom(), binary()},
@@ -217,8 +218,8 @@ start_module(Host, Module, Opts0, Order, NeedValidation) ->
                    {ok, Pid} when is_pid(Pid) -> {ok, Pid};
                    Err -> erlang:error({bad_return, Module, Err})
                end
-           catch Class:Reason ->
-                   StackTrace = erlang:get_stacktrace(),
+           catch ?EX_RULE(Class, Reason, Stack) ->
+                   StackTrace = ?EX_STACK(Stack),
                    ets:delete(ejabberd_modules, {Module, Host}),
                    ErrorText = format_module_error(
                                  Module, start, 2,
@@ -282,8 +283,8 @@ reload_module(Host, Module, NewOpts, OldOpts, Order) ->
                    {ok, Pid} when is_pid(Pid) -> {ok, Pid};
                    Err -> erlang:error({bad_return, Module, Err})
                end
-           catch Class:Reason ->
-                   StackTrace = erlang:get_stacktrace(),
+           catch ?EX_RULE(Class, Reason, Stack) ->
+                   StackTrace = ?EX_STACK(Stack),
                    ErrorText = format_module_error(
                                   Module, reload, 3,
                                   NewOpts, Class, Reason,
index 3fb0d5981bc29581e652c978b19f91c3c5fb047f..e6e618bd0ba5a469999d724de2c43fc955bc599b 100644 (file)
@@ -80,6 +80,7 @@
 -include("xmpp.hrl").
 -include("logger.hrl").
 -include("ejabberd_http.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -define(DEFAULT_API_VERSION, 0).
 
@@ -192,9 +193,8 @@ process([Call], #request{method = 'POST', data = Data, ip = IPPort} = Req) ->
         _:{error,{_,invalid_json}} = _Err ->
            ?DEBUG("Bad Request: ~p", [_Err]),
            badrequest_response(<<"Invalid JSON input">>);
-         _:_Error ->
-            St = erlang:get_stacktrace(),
-            ?DEBUG("Bad Request: ~p ~p", [_Error, St]),
+       ?EX_RULE(_Class, _Error, Stack) ->
+            ?DEBUG("Bad Request: ~p ~p", [_Error, ?EX_STACK(Stack)]),
             badrequest_response()
     end;
 process([Call], #request{method = 'GET', q = Data, ip = {IP, _}} = Req) ->
@@ -210,9 +210,8 @@ process([Call], #request{method = 'GET', q = Data, ip = {IP, _}} = Req) ->
         %% TODO We need to refactor to remove redundant error return formatting
         throw:{error, unknown_command} ->
             json_format({404, 44, <<"Command not found.">>});
-        _:_Error ->
-            St = erlang:get_stacktrace(),
-            ?DEBUG("Bad Request: ~p ~p", [_Error, St]),
+        ?EX_RULE(_, _Error, Stack) ->
+            ?DEBUG("Bad Request: ~p ~p", [_Error, ?EX_STACK(Stack)]),
             badrequest_response()
     end;
 process([_Call], #request{method = 'OPTIONS', data = <<>>}) ->
@@ -302,9 +301,8 @@ handle(Call, Auth, Args, Version) when is_atom(Call), is_list(Args) ->
                    {400, misc:atom_to_binary(Error)};
                  throw:Msg when is_list(Msg); is_binary(Msg) ->
                    {400, iolist_to_binary(Msg)};
-                 _Error ->
-                    St = erlang:get_stacktrace(),
-                   ?ERROR_MSG("REST API Error: ~p ~p", [_Error, St]),
+                 ?EX_RULE(Class, Error, Stack) ->
+                   ?ERROR_MSG("REST API Error: ~p:~p ~p", [Class, Error, ?EX_STACK(Stack)]),
                    {500, <<"internal_error">>}
            end;
         {error, Msg} ->
index 39f72711150581b001bb37c64e2379141af4a9e6..a52b3d55ad5160a30271f48c13ec4ef2388472c4 100644 (file)
@@ -54,6 +54,7 @@
 -include("xmpp.hrl").
 -include("translate.hrl").
 -include("mod_muc_room.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -define(MAX_USERS_DEFAULT_LIST,
        [5, 10, 20, 30, 50, 100, 200, 500, 1000, 2000, 5000]).
@@ -2765,7 +2766,7 @@ process_item_change(Item, SD, UJID) ->
                maybe_send_affiliation(JID, A, SD1),
                SD1
        end
-    catch E:R ->
+    catch ?EX_RULE(E, R, St) ->
                FromSuffix = case UJID of
                        #jid{} ->
                                JidString = jid:encode(UJID),
@@ -2773,9 +2774,8 @@ process_item_change(Item, SD, UJID) ->
                        undefined ->
                                <<"">>
                end,
-                St = erlang:get_stacktrace(),
                ?ERROR_MSG("failed to set item ~p~s: ~p",
-                      [Item, FromSuffix, {E, {R, St}}]),
+                      [Item, FromSuffix, {E, {R, ?EX_STACK(St)}}]),
            {error, xmpp:err_internal_server_error()}
     end.
 
index 8d3fde6d1c4572905ff708f83f1f25bb85219b8e..f97b8ea5f7cd047e49cc0549b588e68e7f08e70a 100644 (file)
         depends/2]).
 
 -include("logger.hrl").
-
 -include("xmpp.hrl").
-
 -include("mod_roster.hrl").
-
 -include("ejabberd_http.hrl").
-
 -include("ejabberd_web_admin.hrl").
+-include("ejabberd_stacktrace.hrl").
 
 -define(ROSTER_CACHE, roster_cache).
 -define(ROSTER_ITEM_CACHE, roster_item_cache).
@@ -320,10 +317,9 @@ process_iq_get(#iq{to = To, lang = Lang,
                   #roster_query{items = Items,
                                 ver = Version}
           end)
-    catch E:R ->
-            St = erlang:get_stacktrace(),
+    catch ?EX_RULE(E, R, St) ->
            ?ERROR_MSG("failed to process roster get for ~s: ~p",
-                      [jid:encode(To), {E, {R, St}}]),
+                      [jid:encode(To), {E, {R, ?EX_STACK(St)}}]),
            Txt = <<"Roster module has failed">>,
            xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang))
     end.