aboutsummaryrefslogtreecommitdiffstats
path: root/erts/preloaded/src
diff options
context:
space:
mode:
Diffstat (limited to 'erts/preloaded/src')
-rw-r--r--erts/preloaded/src/erl_prim_loader.erl10
-rw-r--r--erts/preloaded/src/erlang.erl2
-rw-r--r--erts/preloaded/src/prim_file.erl30
-rw-r--r--erts/preloaded/src/prim_inet.erl180
4 files changed, 132 insertions, 90 deletions
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl
index 0b4db3d9d0..14a7a2bf20 100644
--- a/erts/preloaded/src/erl_prim_loader.erl
+++ b/erts/preloaded/src/erl_prim_loader.erl
@@ -129,7 +129,7 @@ start(Id, Pgm0, Hosts) ->
{error,Reason}
end.
-%% Hosts must be a list on form ['1.2.3.4' ...]
+%% Hosts must be a list of form ['1.2.3.4' ...]
start_it("inet", Id, Pid, Hosts) ->
process_flag(trap_exit, true),
?dbg(inet, {Id,Pid,Hosts}),
@@ -729,7 +729,7 @@ udp_options() ->
%% INET version IPv4 addresses
%%
ll_tcp_connect(LocalPort, IP, RemotePort) ->
- case ll_open_set_bind(tcp, ?INET_FAMILY, tcp_options(),
+ case ll_open_set_bind(tcp, ?INET_FAMILY, stream, tcp_options(),
?INET_ADDRESS, LocalPort) of
{ok,S} ->
case prim_inet:connect(S, IP, RemotePort, tcp_timeout()) of
@@ -743,11 +743,11 @@ ll_tcp_connect(LocalPort, IP, RemotePort) ->
%% Open and initialize an udp port for broadcast
%%
ll_udp_open(P) ->
- ll_open_set_bind(udp, ?INET_FAMILY, udp_options(), ?INET_ADDRESS, P).
+ ll_open_set_bind(udp, ?INET_FAMILY, dgram, udp_options(), ?INET_ADDRESS, P).
-ll_open_set_bind(Protocol, Family, SOpts, IP, Port) ->
- case prim_inet:open(Protocol, Family) of
+ll_open_set_bind(Protocol, Family, Type, SOpts, IP, Port) ->
+ case prim_inet:open(Protocol, Family, Type) of
{ok, S} ->
case prim_inet:setopts(S, SOpts) of
ok ->
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index e9a59a7aaf..4affc9bffe 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -1091,8 +1091,6 @@ receive_emd(Ref, EMD, N) ->
receive_emd(Ref) ->
receive_emd(Ref, #memory{}, erlang:system_info(schedulers)).
-aa_mem_data(notsup, _) ->
- notsup;
aa_mem_data(#memory{} = Mem,
[{maximum, Max} | Rest]) ->
aa_mem_data(Mem#memory{maximum = Max},
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 30b7a5246a..7316e0be99 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -26,7 +26,8 @@
%% Generic file contents operations
-export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1,
- write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3, copy/3]).
+ write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3,
+ copy/3, sendfile/10]).
%% Specialized file operations
-export([open/1, open/3]).
@@ -98,6 +99,7 @@
-define(FILE_READ_LINE, 29).
-define(FILE_FDATASYNC, 30).
-define(FILE_ADVISE, 31).
+-define(FILE_SENDFILE, 32).
%% Driver responses
-define(FILE_RESP_OK, 0).
@@ -537,7 +539,31 @@ write_file(File, Bin) when (is_list(File) orelse is_binary(File)) ->
end;
write_file(_, _) ->
{error, badarg}.
-
+
+
+%% Returns {error, Reason} | {ok, BytesCopied}
+%sendfile(_,_,_,_,_,_,_,_,_,_) ->
+% {error, enotsup};
+sendfile(#file_descriptor{module = ?MODULE, data = {Port, _}},
+ Dest, Offset, Bytes, _ChunkSize, Headers, Trailers,
+ _Nodiskio, _MNowait, _Sync) ->
+ case erlang:port_get_data(Dest) of
+ Data when Data == inet_tcp; Data == inet6_tcp ->
+ ok = inet:lock_socket(Dest,true),
+ {ok, DestFD} = prim_inet:getfd(Dest),
+ try drv_command(Port, [<<?FILE_SENDFILE, DestFD:32,
+ 0:8,
+ Offset:64/unsigned,
+ Bytes:64/unsigned,
+ (iolist_size(Headers)):32/unsigned,
+ (iolist_size(Trailers)):32/unsigned>>,
+ Headers,Trailers])
+ after
+ ok = inet:lock_socket(Dest,false)
+ end;
+ _Else ->
+ {error,badarg}
+ end.
%%%-----------------------------------------------------------------
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 8f2e845b4f..0cedd284db 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -25,8 +25,8 @@
%% Primitive inet_drv interface
--export([open/1, open/2, fdopen/2, fdopen/3, close/1]).
--export([bind/3, listen/1, listen/2]).
+-export([open/3, fdopen/4, close/1]).
+-export([bind/3, listen/1, listen/2, peeloff/2]).
-export([connect/3, connect/4, async_connect/4]).
-export([accept/1, accept/2, async_accept/2]).
-export([shutdown/2]).
@@ -36,7 +36,8 @@
-export([recvfrom/2, recvfrom/3]).
-export([setopt/3, setopts/2, getopt/2, getopts/2, is_sockopt_val/2]).
-export([chgopt/3, chgopts/2]).
--export([getstat/2, getfd/1, getindex/1, getstatus/1, gettype/1,
+-export([getstat/2, getfd/1, ignorefd/2,
+ getindex/1, getstatus/1, gettype/1,
getifaddrs/1, getiflist/1, ifget/3, ifset/3,
gethostname/1]).
-export([getservbyname/3, getservbyport/3]).
@@ -56,58 +57,46 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
-%% OPEN(tcp | udp | sctp, inet | inet6) ->
+%% OPEN(tcp | udp | sctp, inet | inet6, stream | dgram | seqpacket) ->
%% {ok, insock()} |
%% {error, Reason}
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-open(Protocol) -> open1(Protocol, ?INET_AF_INET).
+open(Protocol, Family, Type) ->
+ open(Protocol, Family, Type, ?INET_REQ_OPEN, []).
-open(Protocol, inet) -> open1(Protocol, ?INET_AF_INET);
-open(Protocol, inet6) -> open1(Protocol, ?INET_AF_INET6);
-open(_, _) -> {error, einval}.
+fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) ->
+ open(Protocol, Family, Type, ?INET_REQ_FDOPEN, ?int32(Fd)).
-fdopen(Protocol, Fd) -> fdopen1(Protocol, ?INET_AF_INET, Fd).
-
-fdopen(Protocol, Fd, inet) -> fdopen1(Protocol, ?INET_AF_INET, Fd);
-fdopen(Protocol, Fd, inet6) -> fdopen1(Protocol, ?INET_AF_INET6, Fd);
-fdopen(_, _, _) -> {error, einval}.
-
-open1(Protocol, Family) ->
- case open0(Protocol) of
- {ok, S} ->
- case ctl_cmd(S, ?INET_REQ_OPEN, [Family]) of
- {ok, _} ->
- {ok,S};
- Error ->
- close(S), Error
- end;
- Error -> Error
+open(Protocol, Family, Type, Req, Data) ->
+ Drv = protocol2drv(Protocol),
+ AF = enc_family(Family),
+ T = enc_type(Type),
+ try erlang:open_port({spawn_driver,Drv}, [binary]) of
+ S ->
+ case ctl_cmd(S, Req, [AF,T,Data]) of
+ {ok,_} -> {ok,S};
+ {error,_}=Error ->
+ close(S),
+ Error
+ end
+ catch
+ %% The only (?) way to get here is to try to open
+ %% the sctp driver when it does not exist
+ error:badarg -> {error,eprotonosupport}
end.
-fdopen1(Protocol, Family, Fd) when is_integer(Fd) ->
- case open0(Protocol) of
- {ok, S} ->
- case ctl_cmd(S,?INET_REQ_FDOPEN,[Family,?int32(Fd)]) of
- {ok, _} -> {ok,S};
- Error -> close(S), Error
- end;
- Error -> Error
- end.
+enc_family(inet) -> ?INET_AF_INET;
+enc_family(inet6) -> ?INET_AF_INET6.
-open0(Protocol) ->
- try erlang:open_port({spawn_driver,protocol2drv(Protocol)}, [binary]) of
- Port -> {ok,Port}
- catch
- error:Reason -> {error,Reason}
- end.
+enc_type(stream) -> ?INET_TYPE_STREAM;
+enc_type(dgram) -> ?INET_TYPE_DGRAM;
+enc_type(seqpacket) -> ?INET_TYPE_SEQPACKET.
protocol2drv(tcp) -> "tcp_inet";
protocol2drv(udp) -> "udp_inet";
-protocol2drv(sctp) -> "sctp_inet";
-protocol2drv(_) ->
- erlang:error(eprotonosupport).
+protocol2drv(sctp) -> "sctp_inet".
drv2protocol("tcp_inet") -> tcp;
drv2protocol("udp_inet") -> udp;
@@ -139,7 +128,7 @@ shutdown_1(S, How) ->
shutdown_2(S, How) ->
case ctl_cmd(S, ?TCP_REQ_SHUTDOWN, [How]) of
{ok, []} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
end.
shutdown_pend_loop(S, N0) ->
@@ -195,7 +184,7 @@ close_pend_loop(S, N) ->
bind(S,IP,Port) when is_port(S), is_integer(Port), Port >= 0, Port =< 65535 ->
case ctl_cmd(S,?INET_REQ_BIND,[?int16(Port),ip_to_bytes(IP)]) of
{ok, [P1,P0]} -> {ok, ?u16(P1, P0)};
- Error -> Error
+ {error,_}=Error -> Error
end;
%% Multi-homed "bind": sctp_bindx(). The Op is 'add' or 'remove'.
@@ -222,7 +211,7 @@ bindx(S, AddFlag, Addrs) ->
{IP, Port} <- Addrs]],
case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
{ok,_} -> {ok, S};
- Error -> Error
+ {error,_}=Error -> Error
end;
_ -> {error, einval}
end.
@@ -265,7 +254,7 @@ async_connect(S, IP, Port, Time) ->
case ctl_cmd(S, ?INET_REQ_CONNECT,
[enc_time(Time),?int16(Port),ip_to_bytes(IP)]) of
{ok, [R1,R0]} -> {ok, S, ?u16(R1,R0)};
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -318,9 +307,9 @@ accept_opts(L, S) ->
end.
async_accept(L, Time) ->
- case ctl_cmd(L,?TCP_REQ_ACCEPT, [enc_time(Time)]) of
+ case ctl_cmd(L,?INET_REQ_ACCEPT, [enc_time(Time)]) of
{ok, [R1,R0]} -> {ok, ?u16(R1,R0)};
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -334,16 +323,30 @@ async_accept(L, Time) ->
%% listening) is also accepted:
listen(S) -> listen(S, ?LISTEN_BACKLOG).
-
+
+listen(S, true) -> listen(S, ?LISTEN_BACKLOG);
+listen(S, false) -> listen(S, 0);
listen(S, BackLog) when is_port(S), is_integer(BackLog) ->
- case ctl_cmd(S, ?TCP_REQ_LISTEN, [?int16(BackLog)]) of
+ case ctl_cmd(S, ?INET_REQ_LISTEN, [?int16(BackLog)]) of
{ok, _} -> ok;
- Error -> Error
- end;
-listen(S, Flag) when is_port(S), is_boolean(Flag) ->
- case ctl_cmd(S, ?SCTP_REQ_LISTEN, enc_value(set, bool8, Flag)) of
- {ok,_} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% PEELOFF(insock(), AssocId) -> {ok,outsock()} | {error, Reason}
+%%
+%% SCTP: Peel off one association into a type stream socket
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+peeloff(S, AssocId) ->
+ case ctl_cmd(S, ?SCTP_REQ_PEELOFF, [?int32(AssocId)]) of
+ inet_reply ->
+ receive
+ {inet_reply,S,Res} -> Res
+ end;
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -395,12 +398,12 @@ sendto(S, IP, Port, Data) when is_port(S), Port >= 0, Port =< 65535 ->
true ->
receive
{inet_reply,S,Reply} ->
- ?DBG_FORMAT("prim_inet:send() -> ~p~n", [Reply]),
+ ?DBG_FORMAT("prim_inet:sendto() -> ~p~n", [Reply]),
Reply
end
catch
error:_ ->
- ?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []),
+ ?DBG_FORMAT("prim_inet:sendto() -> {error,einval}~n", []),
{error,einval}
end.
@@ -455,7 +458,7 @@ recv0(S, Length, Time) when is_port(S), is_integer(Length), Length >= 0 ->
async_recv(S, Length, Time) ->
case ctl_cmd(S, ?TCP_REQ_RECV, [enc_time(Time), ?int32(Length)]) of
{ok,[R1,R0]} -> {ok, ?u16(R1,R0)};
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -501,7 +504,7 @@ recvfrom0(S, Length, Time)
{inet_async, S, Ref, Error={error, _}} ->
Error
end;
- Error ->
+ {error,_}=Error ->
Error % Front-end error
end;
recvfrom0(_, _, _) -> {error,einval}.
@@ -517,18 +520,18 @@ peername(S) when is_port(S) ->
{ok, [F, P1,P0 | Addr]} ->
{IP, _} = get_ip(F, Addr),
{ok, { IP, ?u16(P1, P0) }};
- Error -> Error
+ {error,_}=Error -> Error
end.
setpeername(S, {IP,Port}) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_SETPEER, [?int16(Port),ip_to_bytes(IP)]) of
{ok,[]} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
end;
setpeername(S, undefined) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_SETPEER, []) of
{ok,[]} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -542,18 +545,18 @@ sockname(S) when is_port(S) ->
{ok, [F, P1, P0 | Addr]} ->
{IP, _} = get_ip(F, Addr),
{ok, { IP, ?u16(P1, P0) }};
- Error -> Error
+ {error,_}=Error -> Error
end.
setsockname(S, {IP,Port}) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_SETNAME, [?int16(Port),ip_to_bytes(IP)]) of
{ok,[]} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
end;
setsockname(S, undefined) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_SETNAME, []) of
{ok,[]} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -573,7 +576,7 @@ setopts(S, Opts) when is_port(S) ->
{ok, Buf} ->
case ctl_cmd(S, ?INET_REQ_SETOPTS, Buf) of
{ok, _} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
end;
Error -> Error
end.
@@ -599,12 +602,12 @@ getopts(S, Opts) when is_port(S), is_list(Opts) ->
{ok,Rep} ->
%% Non-SCTP: "Rep" contains the encoded option vals:
decode_opt_val(Rep);
- {error,sctp_reply} ->
+ inet_reply ->
%% SCTP: Need to receive the full value:
receive
{inet_reply,S,Res} -> Res
end;
- Error -> Error
+ {error,_}=Error -> Error
end;
Error -> Error
end.
@@ -733,7 +736,7 @@ getifaddrs_ifget(S, IFs, IF, FlagsVals, Opts) ->
getiflist(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_GETIFLIST, []) of
{ok, Data} -> {ok, build_iflist(Data)};
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -751,7 +754,7 @@ ifget(S, Name, Opts) ->
{ok, Buf2} ->
case ctl_cmd(S, ?INET_REQ_IFGET, [Buf1,Buf2]) of
{ok, Data} -> decode_ifopts(Data,[]);
- Error -> Error
+ {error,_}=Error -> Error
end;
Error -> Error
end;
@@ -773,7 +776,7 @@ ifset(S, Name, Opts) ->
{ok, Buf2} ->
case ctl_cmd(S, ?INET_REQ_IFSET, [Buf1,Buf2]) of
{ok, _} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
end;
Error -> Error
end;
@@ -801,7 +804,7 @@ subscribe(S, Sub) when is_port(S), is_list(Sub) ->
{ok, Bytes} ->
case ctl_cmd(S, ?INET_REQ_SUBSCRIBE, Bytes) of
{ok, Data} -> decode_subs(Data);
- Error -> Error
+ {error,_}=Error -> Error
end;
Error -> Error
end.
@@ -819,7 +822,7 @@ getstat(S, Stats) when is_port(S), is_list(Stats) ->
{ok, Bytes} ->
case ctl_cmd(S, ?INET_REQ_GETSTAT, Bytes) of
{ok, Data} -> decode_stats(Data);
- Error -> Error
+ {error,_}=Error -> Error
end;
Error -> Error
end.
@@ -835,11 +838,26 @@ getstat(S, Stats) when is_port(S), is_list(Stats) ->
getfd(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_GETFD, []) of
{ok, [S3,S2,S1,S0]} -> {ok, ?u32(S3,S2,S1,S0)};
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
+%% IGNOREFD(insock(),boolean()) -> {ok,integer()} | {error, Reason}
+%%
+%% steal internal file descriptor
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ignorefd(S,Bool) when is_port(S) ->
+ Val = if Bool -> 1; true -> 0 end,
+ case ctl_cmd(S, ?INET_REQ_IGNOREFD, [Val]) of
+ {ok, _} -> ok;
+ Error -> Error
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
%% GETIX(insock()) -> {ok,integer()} | {error, Reason}
%%
%% get internal socket index
@@ -873,7 +891,7 @@ gettype(S) when is_port(S) ->
_ -> undefined
end,
{ok, {Family, Type}};
- Error -> Error
+ {error,_}=Error -> Error
end.
getprotocol(S) when is_port(S) ->
@@ -901,7 +919,7 @@ getstatus(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_GETSTATUS, []) of
{ok, [S3,S2,S1,S0]} ->
{ok, dec_status(?u32(S3,S2,S1,S0))};
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -943,7 +961,7 @@ getservbyname1(S,Name,Proto) ->
case ctl_cmd(S, ?INET_REQ_GETSERVBYNAME, [L1,Name,L2,Proto]) of
{ok, [P1,P0]} ->
{ok, ?u16(P1,P0)};
- Error ->
+ {error,_}=Error ->
Error
end
end.
@@ -971,7 +989,7 @@ getservbyport1(S,Port,Proto) ->
true ->
case ctl_cmd(S, ?INET_REQ_GETSERVBYPORT, [?int16(Port),L,Proto]) of
{ok, Name} -> {ok, Name};
- Error -> Error
+ {error,_}=Error -> Error
end
end.
@@ -985,7 +1003,7 @@ getservbyport1(S,Port,Proto) ->
unrecv(S, Data) ->
case ctl_cmd(S, ?TCP_REQ_UNRECV, Data) of
{ok, _} -> ok;
- Error -> Error
+ {error,_}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2163,7 +2181,7 @@ ctl_cmd(Port, Cmd, Args) ->
Result =
try erlang:port_control(Port, Cmd, Args) of
[?INET_REP_OK|Reply] -> {ok,Reply};
- [?INET_REP_SCTP] -> {error,sctp_reply};
+ [?INET_REP] -> inet_reply;
[?INET_REP_ERROR|Err] -> {error,list_to_atom(Err)}
catch
error:_ -> {error,einval}