aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src')
-rw-r--r--lib/kernel/src/auth.erl6
-rw-r--r--lib/kernel/src/code.erl32
-rw-r--r--lib/kernel/src/dist_util.erl15
-rw-r--r--lib/kernel/src/erl_epmd.erl86
-rw-r--r--lib/kernel/src/erl_epmd.hrl17
-rw-r--r--lib/kernel/src/error_handler.erl5
-rw-r--r--lib/kernel/src/file.erl107
-rw-r--r--lib/kernel/src/file_io_server.erl20
-rw-r--r--lib/kernel/src/gen_sctp.erl38
-rw-r--r--lib/kernel/src/gen_tcp.erl36
-rw-r--r--lib/kernel/src/gen_udp.erl34
-rw-r--r--lib/kernel/src/group.erl48
-rw-r--r--lib/kernel/src/inet.erl14
-rw-r--r--lib/kernel/src/inet6_sctp.erl23
-rw-r--r--lib/kernel/src/inet_config.erl2
-rw-r--r--lib/kernel/src/inet_dns.erl44
-rw-r--r--lib/kernel/src/inet_int.hrl3
-rw-r--r--lib/kernel/src/inet_parse.erl2
-rw-r--r--lib/kernel/src/inet_res.erl11
-rw-r--r--lib/kernel/src/inet_sctp.erl21
-rw-r--r--lib/kernel/src/kernel.erl9
-rw-r--r--lib/kernel/src/net_kernel.erl203
-rw-r--r--lib/kernel/src/os.erl31
-rw-r--r--lib/kernel/src/pg2.erl4
-rw-r--r--lib/kernel/src/ram_file.erl48
25 files changed, 534 insertions, 325 deletions
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index 7fe30ae828..5c7fe2421d 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -50,6 +50,8 @@
%% Exported functions
%%----------------------------------------------------------------------
+-spec start_link() -> {'ok',pid()} | {'error', term()} | 'ignore'.
+
start_link() ->
gen_server:start_link({local, auth}, auth, [], []).
@@ -134,7 +136,9 @@ init([]) ->
%% The net kernel will let all message to the auth server
%% through as is
--type calls() :: 'echo' | 'sync_cookie' | {'set_cookie', node(), term()}.
+-type calls() :: 'echo' | 'sync_cookie'
+ | {'get_cookie', node()}
+ | {'set_cookie', node(), term()}.
-spec handle_call(calls(), {pid(), term()}, state()) ->
{'reply', 'hello' | 'true' | 'nocookie' | cookie(), state()}.
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index affa5fc0fd..feb5131aad 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -66,6 +66,8 @@
set_primary_archive/3,
clash/0]).
+-export_type([load_error_rsn/0, load_ret/0]).
+
-include_lib("kernel/include/file.hrl").
%% User interface.
@@ -211,19 +213,20 @@ unstick_mod(Mod) when is_atom(Mod) -> call({unstick_mod,Mod}).
-spec is_sticky(Module :: atom()) -> boolean().
is_sticky(Mod) when is_atom(Mod) -> call({is_sticky,Mod}).
--spec set_path(Directories :: [file:filename()]) -> 'true' | {'error', term()}.
+-spec set_path(Directories :: [file:filename()]) ->
+ 'true' | {'error', 'bad_directory' | 'bad_path'}.
set_path(PathList) when is_list(PathList) -> call({set_path,PathList}).
-spec get_path() -> [file:filename()].
get_path() -> call(get_path).
--spec add_path(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-spec add_path(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}.
add_path(Dir) when is_list(Dir) -> call({add_path,last,Dir}).
--spec add_pathz(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-spec add_pathz(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}.
add_pathz(Dir) when is_list(Dir) -> call({add_path,last,Dir}).
--spec add_patha(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-spec add_patha(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}.
add_patha(Dir) when is_list(Dir) -> call({add_path,first,Dir}).
-spec add_paths(Directories :: [file:filename()]) -> 'ok'.
@@ -235,7 +238,6 @@ add_pathsz(Dirs) when is_list(Dirs) -> call({add_paths,last,Dirs}).
-spec add_pathsa(Directories :: [file:filename()]) -> 'ok'.
add_pathsa(Dirs) when is_list(Dirs) -> call({add_paths,first,Dirs}).
-%% XXX Contract's input argument differs from add_path/1 -- why?
-spec del_path(Name :: file:filename() | atom()) -> boolean() | {'error', 'bad_name'}.
del_path(Name) when is_list(Name) ; is_atom(Name) -> call({del_path,Name}).
@@ -284,6 +286,8 @@ do_start(Flags) ->
ets:module_info(module),
os:module_info(module),
+ binary:module_info(module),
+ unicode:module_info(module),
filename:module_info(module),
lists:module_info(module),
@@ -302,6 +306,8 @@ do_start(Flags) ->
true ->
ok
end,
+ % Quietly load the native code for all modules loaded so far.
+ catch load_native_code_for_all_loaded(),
Ok2;
Other ->
Other
@@ -494,3 +500,19 @@ has_ext(Ext, Extlen,File) ->
to_path(X) ->
filename:join(packages:split(X)).
+
+-spec load_native_code_for_all_loaded() -> ok.
+load_native_code_for_all_loaded() ->
+ Architecture = erlang:system_info(hipe_architecture),
+ ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ lists:foreach(fun({Module, BeamFilename}) ->
+ case code:is_module_native(Module) of
+ false ->
+ case beam_lib:chunks(BeamFilename, [ChunkName]) of
+ {ok,{_,[{_,Bin}]}} when is_binary(Bin) ->
+ load_native_partial(Module, Bin);
+ {error, beam_lib, _} -> ok
+ end;
+ true -> ok
+ end
+ end, all_loaded()).
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index a2937d60b8..f0d54a2f3e 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2010. 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%
%%
%%%----------------------------------------------------------------------
@@ -564,7 +564,7 @@ recv_challenge(#hs_data{socket=Socket,other_node=Node,
case Recv(Socket, 0, infinity) of
{ok,[$n,V1,V0,Fl1,Fl2,Fl3,Fl4,CA3,CA2,CA1,CA0 | Ns]} ->
Flags = ?u32(Fl1,Fl2,Fl3,Fl4),
- case {list_to_existing_atom(Ns),?u16(V1,V0)} of
+ try {list_to_existing_atom(Ns),?u16(V1,V0)} of
{Node,Version} ->
Challenge = ?u32(CA3,CA2,CA1,CA0),
?trace("recv: node=~w, challenge=~w version=~w\n",
@@ -572,6 +572,9 @@ recv_challenge(#hs_data{socket=Socket,other_node=Node,
{Flags,Challenge};
_ ->
?shutdown(no_node)
+ catch
+ error:badarg ->
+ ?shutdown(no_node)
end;
_ ->
?shutdown(no_node)
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index 4a22637304..91af49f303 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -210,19 +210,6 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) ->
close(Socket) ->
gen_tcp:close(Socket).
-
-do_register_node_v0(NodeName, TcpPort) ->
- case open() of
- {ok, Socket} ->
- Name = cstring(NodeName),
- Len = 1+2+length(Name),
- gen_tcp:send(Socket, [?int16(Len), ?EPMD_ALIVE,
- ?int16(TcpPort), Name]),
- wait_for_reg_reply_v0(Socket, []);
- Error ->
- Error
- end.
-
do_register_node(NodeName, TcpPort) ->
case open() of
{ok, Socket} ->
@@ -240,14 +227,7 @@ do_register_node(NodeName, TcpPort) ->
Name,
?int16(Elen),
Extra]),
- case wait_for_reg_reply(Socket, []) of
- {error, epmd_close} ->
- %% could be old epmd; try old protocol
-% erlang:display('trying old'),
- do_register_node_v0(NodeName, TcpPort);
- Other ->
- Other
- end;
+ wait_for_reg_reply(Socket, []);
Error ->
Error
end.
@@ -305,41 +285,9 @@ wait_for_reg_reply(Socket, SoFar) ->
{error, no_reg_reply_from_epmd}
end.
-wait_for_reg_reply_v0(Socket, SoFar) ->
- receive
- {tcp, Socket, Data0} ->
- case SoFar ++ Data0 of
- [$Y, A, B] ->
- {alive, Socket, ?u16(A, B)};
- Data when length(Data) < 3 ->
- wait_for_reg_reply(Socket, Data);
- Garbage ->
- {error, {garbage_from_epmd, Garbage}}
- end;
- {tcp_closed, Socket} ->
- {error, duplicate_name} % A guess -- the most likely reason.
- after 10000 ->
- gen_tcp:close(Socket),
- {error, no_reg_reply_from_epmd}
- end.
%%
%% Lookup a node "Name" at Host
%%
-get_port_v0(Node, EpmdAddress) ->
- case open(EpmdAddress) of
- {ok, Socket} ->
- Name = cstring(Node),
- Len = 1+length(Name),
- gen_tcp:send(Socket, [?int16(Len),?EPMD_PORT_PLEASE, Name]),
- wait_for_port_reply_v0(Socket, []);
- _Error ->
- ?port_please_failure(),
- noport
- end.
-
-%%% Not used anymore
-%%% get_port(Node, EpmdAddress) ->
-%%% get_port(Node, EpmdAddress, infinity).
get_port(Node, EpmdAddress, Timeout) ->
case open(EpmdAddress, Timeout) of
@@ -347,40 +295,12 @@ get_port(Node, EpmdAddress, Timeout) ->
Name = to_string(Node),
Len = 1+length(Name),
gen_tcp:send(Socket, [?int16(Len),?EPMD_PORT_PLEASE2_REQ, Name]),
- Reply = wait_for_port_reply(Socket, []),
- case Reply of
- closed ->
- get_port_v0(Node, EpmdAddress);
- Other ->
- Other
- end;
+ wait_for_port_reply(Socket, []);
_Error ->
?port_please_failure2(_Error),
noport
end.
-wait_for_port_reply_v0(Socket, SoFar) ->
- receive
- {tcp, Socket, Data0} ->
-% io:format("got ~p~n", [Data0]),
- case SoFar ++ Data0 of
- [A, B] ->
- wait_for_close(Socket, {port, ?u16(A, B), 0});
-% wait_for_close(Socket, {port, ?u16(A, B)});
- Data when length(Data) < 2 ->
- wait_for_port_reply_v0(Socket, Data);
- Garbage ->
- ?port_please_failure(),
- {error, {garbage_from_epmd, Garbage}}
- end;
- {tcp_closed, Socket} ->
- ?port_please_failure(),
- noport
- after 10000 ->
- ?port_please_failure(),
- gen_tcp:close(Socket),
- noport
- end.
wait_for_port_reply(Socket, SoFar) ->
receive
@@ -487,8 +407,6 @@ wait_for_close(Socket, Reply) ->
%%
%% Creates a (flat) null terminated string from atom or list.
%%
-cstring(S) when is_atom(S) -> cstring(atom_to_list(S));
-cstring(S) when is_list(S) -> S ++ [0].
to_string(S) when is_atom(S) -> atom_to_list(S);
to_string(S) when is_list(S) -> S.
diff --git a/lib/kernel/src/erl_epmd.hrl b/lib/kernel/src/erl_epmd.hrl
index 47ab6195d8..5a50fda508 100644
--- a/lib/kernel/src/erl_epmd.hrl
+++ b/lib/kernel/src/erl_epmd.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2010. 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
@@ -17,16 +17,13 @@
%% %CopyrightEnd%
%%
--define(EPMD_ALIVE, $a).
--define(EPMD_PORT_PLEASE, $p).
--define(EPMD_NAMES, $n).
--define(EPMD_DUMP, $d).
--define(EPMD_KILL, $k).
--define(EPMD_STOP, $s).
-
--define(EPMD_ALIVE_OK, $Y).
-
-define(EPMD_ALIVE2_REQ, $x).
-define(EPMD_PORT_PLEASE2_REQ, $z).
-define(EPMD_ALIVE2_RESP, $y).
-define(EPMD_PORT2_RESP, $w).
+-define(EPMD_NAMES, $n).
+
+%% Commands used only by interactive client
+-define(EPMD_DUMP, $d).
+-define(EPMD_KILL, $k).
+-define(EPMD_STOP, $s).
diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index 17dd02acd4..885eeb2b0f 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
-module(error_handler).
+%% FIXME: remove no_native directive after HiPE has been changed to make
+%% remote calls link to the target's Export* like BEAM does.
+%% For a detailed explanation see the commit titled
+%% "error_handler: add no_native compiler directive"
+-compile(no_native).
%% A simple error handler.
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 46ffa9d708..bc95359986 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -36,11 +36,11 @@
%% Specialized
-export([ipread_s32bu_p32bu/3]).
%% Generic file contents.
--export([open/2, close/1,
+-export([open/2, close/1, advise/4,
read/2, write/2,
pread/2, pread/3, pwrite/2, pwrite/3,
read_line/1,
- position/2, truncate/1, sync/1,
+ position/2, truncate/1, datasync/1, sync/1,
copy/2, copy/3]).
%% High level operations
-export([consult/1, path_consult/2]).
@@ -61,6 +61,9 @@
-export([ipread_s32bu_p32bu_int/3]).
+%% Types that can be used from other modules -- alphabetically ordered.
+-export_type([date_time/0, fd/0, file_info/0, filename/0, io_device/0,
+ name/0, posix/0]).
%%% Includes and defines
-include("file.hrl").
@@ -72,23 +75,34 @@
-define(RAM_FILE, ram_file). % Module
%% data types
--type filename() :: string().
+-type filename() :: string() | binary().
-type file_info() :: #file_info{}.
-type fd() :: #file_descriptor{}.
-type io_device() :: pid() | fd().
-type location() :: integer() | {'bof', integer()} | {'cur', integer()}
| {'eof', integer()} | 'bof' | 'cur' | 'eof'.
--type mode() :: 'read' | 'write' | 'append' | 'raw' | 'binary' |
- {'delayed_write', non_neg_integer(), non_neg_integer()} |
- 'delayed_write' | {'read_ahead', pos_integer()} |
- 'read_ahead' | 'compressed'.
--type name() :: string() | atom() | [name()].
--type posix() :: atom().
+-type mode() :: 'read' | 'write' | 'append'
+ | 'exclusive' | 'raw' | 'binary'
+ | {'delayed_write', non_neg_integer(), non_neg_integer()}
+ | 'delayed_write' | {'read_ahead', pos_integer()}
+ | 'read_ahead' | 'compressed'
+ | {'encoding', unicode:encoding()}.
+-type name() :: string() | atom() | [name()] | binary().
+-type posix() :: 'eacces' | 'eagain' | 'ebadf' | 'ebusy' | 'edquot'
+ | 'eexist' | 'efault' | 'efbig' | 'eintr' | 'einval'
+ | 'eio' | 'eisdir' | 'eloop' | 'emfile' | 'emlink'
+ | 'enametoolong'
+ | 'enfile' | 'enodev' | 'enoent' | 'enomem' | 'enospc'
+ | 'enotblk' | 'enotdir' | 'enotsup' | 'enxio' | 'eperm'
+ | 'epipe' | 'erofs' | 'espipe' | 'esrch' | 'estale'
+ | 'exdev'.
-type bindings() :: any().
-type date() :: {pos_integer(), pos_integer(), pos_integer()}.
-type time() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
-type date_time() :: {date(), time()}.
+-type posix_file_advise() :: 'normal' | 'sequential' | 'random'
+ | 'no_reuse' | 'will_need' | 'dont_need'.
%%%-----------------------------------------------------------------
%%% General functions
@@ -169,7 +183,7 @@ make_dir(Name) ->
del_dir(Name) ->
check_and_call(del_dir, [file_name(Name)]).
--spec read_file_info(Name :: name()) -> {'ok', #file_info{}} | {'error', posix()}.
+-spec read_file_info(Name :: name()) -> {'ok', file_info()} | {'error', posix()}.
read_file_info(Name) ->
check_and_call(read_file_info, [file_name(Name)]).
@@ -179,7 +193,7 @@ read_file_info(Name) ->
altname(Name) ->
check_and_call(altname, [file_name(Name)]).
--spec read_link_info(Name :: name()) -> {'ok', #file_info{}} | {'error', posix()}.
+-spec read_link_info(Name :: name()) -> {'ok', file_info()} | {'error', posix()}.
read_link_info(Name) ->
check_and_call(read_link_info, [file_name(Name)]).
@@ -189,7 +203,7 @@ read_link_info(Name) ->
read_link(Name) ->
check_and_call(read_link, [file_name(Name)]).
--spec write_file_info(Name :: name(), Info :: #file_info{}) ->
+-spec write_file_info(Name :: name(), Info :: file_info()) ->
'ok' | {'error', posix()}.
write_file_info(Name, Info = #file_info{}) ->
@@ -200,7 +214,8 @@ write_file_info(Name, Info = #file_info{}) ->
list_dir(Name) ->
check_and_call(list_dir, [file_name(Name)]).
--spec read_file(Name :: name()) -> {'ok', binary()} | {'error', posix()}.
+-spec read_file(Name :: name()) ->
+ {'ok', binary()} | {'error', posix() | 'terminated' | 'system_limit'}.
read_file(Name) ->
check_and_call(read_file, [file_name(Name)]).
@@ -215,15 +230,15 @@ make_link(Old, New) ->
make_symlink(Old, New) ->
check_and_call(make_symlink, [file_name(Old), file_name(New)]).
--spec write_file(Name :: name(), Bin :: binary()) -> 'ok' | {'error', posix()}.
+-spec write_file(Name :: name(), Bin :: iodata()) ->
+ 'ok' | {'error', posix() | 'terminated' | 'system_limit'}.
write_file(Name, Bin) ->
check_and_call(write_file, [file_name(Name), make_binary(Bin)]).
%% This whole operation should be moved to the file_server and prim_file
%% when it is time to change file server protocol again.
-%% Meanwhile, it is implemented here, slihtly less efficient.
-%%
+%% Meanwhile, it is implemented here, slightly less efficient.
-spec write_file(Name :: name(), Bin :: binary(), Modes :: [mode()]) ->
'ok' | {'error', posix()}.
@@ -281,7 +296,7 @@ raw_write_file_info(Name, #file_info{} = Info) ->
%% Contemporary mode specification - list of options
-spec open(Name :: name(), Modes :: [mode()]) ->
- {'ok', io_device()} | {'error', posix()}.
+ {'ok', io_device()} | {'error', posix() | 'system_limit'}.
open(Item, ModeList) when is_list(ModeList) ->
case lists:member(raw, ModeList) of
@@ -334,7 +349,7 @@ open(Item, Mode) ->
%%% The File argument must be either a Pid or a handle
%%% returned from ?PRIM_FILE:open.
--spec close(File :: io_device()) -> 'ok' | {'error', posix()}.
+-spec close(File :: io_device()) -> 'ok' | {'error', posix() | 'terminated'}.
close(File) when is_pid(File) ->
R = file_request(File, close),
@@ -352,10 +367,22 @@ close(#file_descriptor{module = Module} = Handle) ->
close(_) ->
{error, badarg}.
--spec read(File :: io_device(), Size :: non_neg_integer()) ->
+-spec advise(File :: io_device(), Offset :: integer(),
+ Length :: integer(), Advise :: posix_file_advise()) ->
+ 'ok' | {'error', posix()}.
+
+advise(File, Offset, Length, Advise) when is_pid(File) ->
+ R = file_request(File, {advise, Offset, Length, Advise}),
+ wait_file_reply(File, R);
+advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
+ Module:advise(Handle, Offset, Length, Advise);
+advise(_, _, _, _) ->
+ {error, badarg}.
+
+-spec read(File :: io_device() | atom(), Size :: non_neg_integer()) ->
'eof' | {'ok', [char()] | binary()} | {'error', posix()}.
-read(File, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 ->
+read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 ->
case io:request(File, {get_chars, '', Sz}) of
Data when is_list(Data); is_binary(Data) ->
{ok, Data};
@@ -368,10 +395,10 @@ read(#file_descriptor{module = Module} = Handle, Sz)
read(_, _) ->
{error, badarg}.
--spec read_line(File :: io_device()) ->
+-spec read_line(File :: io_device() | atom()) ->
'eof' | {'ok', [char()] | binary()} | {'error', posix()}.
-read_line(File) when is_pid(File) ->
+read_line(File) when (is_pid(File) orelse is_atom(File)) ->
case io:request(File, {get_line, ''}) of
Data when is_list(Data); is_binary(Data) ->
{ok, Data};
@@ -422,10 +449,10 @@ pread(#file_descriptor{module = Module} = Handle, Offs, Sz)
pread(_, _, _) ->
{error, badarg}.
--spec write(File :: io_device(), Byte :: iodata()) ->
- 'ok' | {'error', posix()}.
+-spec write(File :: io_device() | atom(), Byte :: iodata()) ->
+ 'ok' | {'error', posix() | 'terminated'}.
-write(File, Bytes) when is_pid(File) ->
+write(File, Bytes) when (is_pid(File) orelse is_atom(File)) ->
case make_binary(Bytes) of
Bin when is_binary(Bin) ->
io:request(File, {put_chars,Bin});
@@ -472,6 +499,16 @@ pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) ->
pwrite(_, _, _) ->
{error, badarg}.
+-spec datasync(File :: io_device()) -> 'ok' | {'error', posix()}.
+
+datasync(File) when is_pid(File) ->
+ R = file_request(File, datasync),
+ wait_file_reply(File, R);
+datasync(#file_descriptor{module = Module} = Handle) ->
+ Module:datasync(Handle);
+datasync(_) ->
+ {error, badarg}.
+
-spec sync(File :: io_device()) -> 'ok' | {'error', posix()}.
sync(File) when is_pid(File) ->
@@ -997,22 +1034,26 @@ path_open_first([], _Name, _Mode, LastError) ->
%% Generates a flat file name from a deep list of atoms and
%% characters (integers).
+file_name(N) when is_binary(N) ->
+ N;
file_name(N) ->
try
- file_name_1(N)
+ file_name_1(N,file:native_name_encoding())
catch Reason ->
{error, Reason}
end.
-file_name_1([C|T]) when is_integer(C), C > 0, C =< 255 ->
- [C|file_name_1(T)];
-file_name_1([H|T]) ->
- file_name_1(H) ++ file_name_1(T);
-file_name_1([]) ->
+file_name_1([C|T],latin1) when is_integer(C), C < 256->
+ [C|file_name_1(T,latin1)];
+file_name_1([C|T],utf8) when is_integer(C) ->
+ [C|file_name_1(T,utf8)];
+file_name_1([H|T],E) ->
+ file_name_1(H,E) ++ file_name_1(T,E);
+file_name_1([],_) ->
[];
-file_name_1(N) when is_atom(N) ->
+file_name_1(N,_) when is_atom(N) ->
atom_to_list(N);
-file_name_1(_) ->
+file_name_1(_,_) ->
throw(badarg).
make_binary(Bin) when is_binary(Bin) ->
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index 3ac35a209d..14da9c1a55 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -44,11 +44,11 @@ format_error(ErrorId) ->
erl_posix_msg:message(ErrorId).
start(Owner, FileName, ModeList)
- when is_pid(Owner), is_list(FileName), is_list(ModeList) ->
+ when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) ->
do_start(spawn, Owner, FileName, ModeList).
start_link(Owner, FileName, ModeList)
- when is_pid(Owner), is_list(FileName), is_list(ModeList) ->
+ when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) ->
do_start(spawn_link, Owner, FileName, ModeList).
%%%-----------------------------------------------------------------
@@ -198,6 +198,14 @@ io_reply(From, ReplyAs, Reply) ->
%%%-----------------------------------------------------------------
%%% file requests
+file_request({advise,Offset,Length,Advise},
+ #state{handle=Handle}=State) ->
+ case ?PRIM_FILE:advise(Handle, Offset, Length, Advise) of
+ {error,_}=Reply ->
+ {stop,normal,Reply,State};
+ Reply ->
+ {reply,Reply,State}
+ end;
file_request({pread,At,Sz},
#state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) ->
case position(Handle, At, Buf) of
@@ -219,6 +227,14 @@ file_request({pwrite,At,Data},
Reply ->
std_reply(Reply, State)
end;
+file_request(datasync,
+ #state{handle=Handle}=State) ->
+ case ?PRIM_FILE:datasync(Handle) of
+ {error,_}=Reply ->
+ {stop,normal,Reply,State};
+ Reply ->
+ {reply,Reply,State}
+ end;
file_request(sync,
#state{handle=Handle}=State) ->
case ?PRIM_FILE:sync(Handle) of
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 5a31e3976f..cccfa75005 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -39,7 +39,7 @@ open() ->
open([]).
open(Opts) when is_list(Opts) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, undefined),
case Mod:open(Opts) of
{error,badarg} ->
erlang:error(badarg, [Opts]);
@@ -166,18 +166,14 @@ send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data)
when is_port(S), is_integer(Stream) ->
case inet_db:lookup_socket(S) of
{ok,Mod} ->
- Mod:sendmsg(S, #sctp_sndrcvinfo{
- stream = Stream,
- assoc_id = AssocId}, Data);
+ Mod:send(S, AssocId, Stream, Data);
Error -> Error
end;
send(S, AssocId, Stream, Data)
when is_port(S), is_integer(AssocId), is_integer(Stream) ->
case inet_db:lookup_socket(S) of
{ok,Mod} ->
- Mod:sendmsg(S, #sctp_sndrcvinfo{
- stream = Stream,
- assoc_id = AssocId}, Data);
+ Mod:send(S, AssocId, Stream, Data);
Error -> Error
end;
send(S, AssocChange, Stream, Data) ->
@@ -238,17 +234,27 @@ controlling_process(S, Pid) ->
%% Utilites
%%
-%% Get the SCTP moudule
-mod() -> inet_db:sctp_module().
+%% Get the SCTP module, but IPv6 address overrides default IPv4
+mod(Address) ->
+ case inet_db:sctp_module() of
+ inet_sctp when tuple_size(Address) =:= 8 ->
+ inet6_sctp;
+ Mod ->
+ Mod
+ end.
%% Get the SCTP module, but option sctp_module|inet|inet6 overrides
-mod([{sctp_module,Mod}|_]) ->
+mod([{sctp_module,Mod}|_], _Address) ->
Mod;
-mod([inet|_]) ->
+mod([inet|_], _Address) ->
inet_sctp;
-mod([inet6|_]) ->
+mod([inet6|_], _Address) ->
inet6_sctp;
-mod([_|Opts]) ->
- mod(Opts);
-mod([]) ->
- mod().
+mod([{ip, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([{ifaddr, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([_|Opts], Address) ->
+ mod(Opts, Address);
+mod([], Address) ->
+ mod(Address).
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 7401b06a64..16a87d71b6 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2010. 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
@@ -46,7 +46,7 @@ connect(Address, Port, Opts, Time) ->
end.
connect1(Address,Port,Opts,Timer) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, Address),
case Mod:getaddrs(Address,Timer) of
{ok,IPs} ->
case Mod:getserv(Port) of
@@ -73,7 +73,7 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) ->
%% Listen on a tcp port
%%
listen(Port, Opts) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, undefined),
case Mod:getserv(Port) of
{ok,TP} ->
Mod:listen(TP, Opts);
@@ -173,20 +173,30 @@ controlling_process(S, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, undefined),
Mod:fdopen(Fd, Opts).
-%% Get the tcp_module
-mod() -> inet_db:tcp_module().
+%% Get the tcp_module, but IPv6 address overrides default IPv4
+mod(Address) ->
+ case inet_db:tcp_module() of
+ inet_tcp when tuple_size(Address) =:= 8 ->
+ inet6_tcp;
+ Mod ->
+ Mod
+ end.
%% Get the tcp_module, but option tcp_module|inet|inet6 overrides
-mod([{tcp_module,Mod}|_]) ->
+mod([{tcp_module,Mod}|_], _Address) ->
Mod;
-mod([inet|_]) ->
+mod([inet|_], _Address) ->
inet_tcp;
-mod([inet6|_]) ->
+mod([inet6|_], _Address) ->
inet6_tcp;
-mod([_|Opts]) ->
- mod(Opts);
-mod([]) ->
- mod().
+mod([{ip, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([{ifaddr, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([_|Opts], Address) ->
+ mod(Opts, Address);
+mod([], Address) ->
+ mod(Address).
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 6bded4bda6..99020c7b6c 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2010. 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
@@ -29,7 +29,7 @@ open(Port) ->
open(Port, []).
open(Port, Opts) ->
- Mod = mod(Opts),
+ Mod = mod(Opts, undefined),
{ok,UP} = Mod:getserv(Port),
Mod:open(UP, Opts).
@@ -97,21 +97,31 @@ controlling_process(S, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- Mod = mod(),
+ Mod = mod(Opts, undefined),
Mod:fdopen(Fd, Opts).
-%% Get the udp_module
-mod() -> inet_db:udp_module().
+%% Get the udp_module, but IPv6 address overrides default IPv4
+mod(Address) ->
+ case inet_db:udp_module() of
+ inet_udp when tuple_size(Address) =:= 8 ->
+ inet6_udp;
+ Mod ->
+ Mod
+ end.
%% Get the udp_module, but option udp_module|inet|inet6 overrides
-mod([{udp_module,Mod}|_]) ->
+mod([{udp_module,Mod}|_], _Address) ->
Mod;
-mod([inet|_]) ->
+mod([inet|_], _Address) ->
inet_udp;
-mod([inet6|_]) ->
+mod([inet6|_], _Address) ->
inet6_udp;
-mod([_|Opts]) ->
- mod(Opts);
-mod([]) ->
- mod().
+mod([{ip, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([{ifaddr, Address}|Opts], _) ->
+ mod(Opts, Address);
+mod([_|Opts], Address) ->
+ mod(Opts, Address);
+mod([], Address) ->
+ mod(Address).
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index a45ba34eae..f92c6f7208 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. 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(group).
@@ -477,15 +477,15 @@ get_line(Chars, Pbs, Drv, Encoding) ->
get_line1(edlin:edit_line(Chars, Cont), Drv, new_stack(get(line_buffer)),
Encoding).
-get_line1({done,Line,Rest,Rs}, Drv, _Ls, _Encoding) ->
+get_line1({done,Line,Rest,Rs}, Drv, Ls, _Encoding) ->
send_drv_reqs(Drv, Rs),
- put(line_buffer, [Line|lists:delete(Line, get(line_buffer))]),
+ save_line_buffer(Line, get_lines(Ls)),
{done,Line,Rest};
get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
when ((Mode =:= none) and (Char =:= $\^P))
or ((Mode =:= meta_left_sq_bracket) and (Char =:= $A)) ->
send_drv_reqs(Drv, Rs),
- case up_stack(Ls0) of
+ case up_stack(save_line(Ls0, edlin:current_line(Cont))) of
{none,_Ls} ->
send_drv(Drv, beep),
get_line1(edlin:edit_line(Cs, Cont), Drv, Ls0, Encoding);
@@ -498,14 +498,14 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
Drv,
Ls, Encoding)
end;
-get_line1({undefined,{_A,Mode,Char},_Cs,Cont,Rs}, Drv, Ls0, Encoding)
+get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
when ((Mode =:= none) and (Char =:= $\^N))
or ((Mode =:= meta_left_sq_bracket) and (Char =:= $B)) ->
send_drv_reqs(Drv, Rs),
- case down_stack(Ls0) of
- {none,Ls} ->
- send_drv_reqs(Drv, edlin:erase_line(Cont)),
- get_line1(edlin:start(edlin:prompt(Cont)), Drv, Ls, Encoding);
+ case down_stack(save_line(Ls0, edlin:current_line(Cont))) of
+ {none,_Ls} ->
+ send_drv(Drv, beep),
+ get_line1(edlin:edit_line(Cs, Cont), Drv, Ls0, Encoding);
{Lcs,Ls} ->
send_drv_reqs(Drv, edlin:erase_line(Cont)),
{more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)),
@@ -627,6 +627,28 @@ down_stack({stack,U,{},[]}) ->
down_stack({stack,U,C,D}) ->
down_stack({stack,[C|U],{},D}).
+save_line({stack, U, {}, []}, Line) ->
+ {stack, U, {}, [Line]};
+save_line({stack, U, _L, D}, Line) ->
+ {stack, U, Line, D}.
+
+get_lines({stack, U, {}, []}) ->
+ U;
+get_lines({stack, U, {}, D}) ->
+ tl(lists:reverse(D, U));
+get_lines({stack, U, L, D}) ->
+ get_lines({stack, U, {}, [L|D]}).
+
+save_line_buffer("\n", Lines) ->
+ save_line_buffer(Lines);
+save_line_buffer(Line, [Line|_Lines]=Lines) ->
+ save_line_buffer(Lines);
+save_line_buffer(Line, Lines) ->
+ save_line_buffer([Line|Lines]).
+
+save_line_buffer(Lines) ->
+ put(line_buffer, Lines).
+
%% This is get_line without line editing (except for backspace) and
%% without echo.
get_password_line(Chars, Drv) ->
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index eb503235d8..327e0f93f1 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -25,6 +25,7 @@
%% socket
-export([peername/1, sockname/1, port/1, send/2,
setopts/2, getopts/2,
+ getifaddrs/0, getifaddrs/1,
getif/1, getif/0, getiflist/0, getiflist/1,
ifget/3, ifget/2, ifset/3, ifset/2,
getstat/1, getstat/2,
@@ -62,6 +63,8 @@
%% timer interface
-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
+-export_type([ip_address/0, socket/0]).
+
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -263,6 +266,17 @@ setopts(Socket, Opts) ->
getopts(Socket, Opts) ->
prim_inet:getopts(Socket, Opts).
+-spec getifaddrs(Socket :: socket()) ->
+ {'ok', [string()]} | {'error', posix()}.
+
+getifaddrs(Socket) ->
+ prim_inet:getifaddrs(Socket).
+
+-spec getifaddrs() -> {'ok', [string()]} | {'error', posix()}.
+
+getifaddrs() ->
+ withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
+
-spec getiflist(Socket :: socket()) ->
{'ok', [string()]} | {'error', posix()}.
diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl
index 5c49c4fec3..5bf3fca647 100644
--- a/lib/kernel/src/inet6_sctp.erl
+++ b/lib/kernel/src/inet6_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2010. 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
@@ -32,7 +32,7 @@
-define(FAMILY, inet6).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
--export([open/1,close/1,listen/2,connect/5,sendmsg/3,recv/2]).
+-export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]).
@@ -71,5 +71,24 @@ connect(S, Addr, Port, Opts, Timer) ->
sendmsg(S, SRI, Data) ->
prim_inet:sendmsg(S, SRI, Data).
+send(S, AssocId, Stream, Data) ->
+ case prim_inet:getopts(
+ S,
+ [{sctp_default_send_param,#sctp_sndrcvinfo{assoc_id=AssocId}}]) of
+ {ok,
+ [{sctp_default_send_param,
+ #sctp_sndrcvinfo{
+ flags=Flags, context=Context, ppid=PPID, timetolive=TTL}}]} ->
+ prim_inet:sendmsg(
+ S,
+ #sctp_sndrcvinfo{
+ flags=Flags, context=Context, ppid=PPID, timetolive=TTL,
+ assoc_id=AssocId, stream=Stream},
+ Data);
+ _ ->
+ prim_inet:sendmsg(
+ S, #sctp_sndrcvinfo{assoc_id=AssocId, stream=Stream}, Data)
+ end.
+
recv(S, Timeout) ->
prim_inet:recvfrom(S, 0, Timeout).
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 311e6bc9f9..2458876326 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -23,6 +23,8 @@
-import(lists, [foreach/2, member/2, reverse/1]).
+%% Avoid warning for local function error/2 clashing with autoimported BIF.
+-compile({no_auto_import,[error/2]}).
-export([init/0]).
-export([do_load_resolv/2]).
diff --git a/lib/kernel/src/inet_dns.erl b/lib/kernel/src/inet_dns.erl
index 669a361c9d..1289e176c7 100644
--- a/lib/kernel/src/inet_dns.erl
+++ b/lib/kernel/src/inet_dns.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. 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(inet_dns).
@@ -129,27 +129,33 @@ do_decode(<<Id:16,
RA:1,PR:1,_:2,Rcode:4,
QdCount:16,AnCount:16,NsCount:16,ArCount:16,
QdBuf/binary>>=Buffer) ->
- {AnBuf,QdList} = decode_query_section(QdBuf,QdCount,Buffer),
- {NsBuf,AnList} = decode_rr_section(AnBuf,AnCount,Buffer),
- {ArBuf,NsList} = decode_rr_section(NsBuf,NsCount,Buffer),
- {Rest,ArList} = decode_rr_section(ArBuf,ArCount,Buffer),
+ {AnBuf,QdList,QdTC} = decode_query_section(QdBuf,QdCount,Buffer),
+ {NsBuf,AnList,AnTC} = decode_rr_section(AnBuf,AnCount,Buffer),
+ {ArBuf,NsList,NsTC} = decode_rr_section(NsBuf,NsCount,Buffer),
+ {Rest,ArList,ArTC} = decode_rr_section(ArBuf,ArCount,Buffer),
case Rest of
<<>> ->
+ HdrTC = decode_boolean(TC),
DnsHdr =
#dns_header{id=Id,
qr=decode_boolean(QR),
opcode=decode_opcode(Opcode),
aa=decode_boolean(AA),
- tc=decode_boolean(TC),
+ tc=HdrTC,
rd=decode_boolean(RD),
ra=decode_boolean(RA),
pr=decode_boolean(PR),
rcode=Rcode},
- #dns_rec{header=DnsHdr,
- qdlist=QdList,
- anlist=AnList,
- nslist=NsList,
- arlist=ArList};
+ case QdTC or AnTC or NsTC or ArTC of
+ true when not HdrTC ->
+ throw(?DECODE_ERROR);
+ _ ->
+ #dns_rec{header=DnsHdr,
+ qdlist=QdList,
+ anlist=AnList,
+ nslist=NsList,
+ arlist=ArList}
+ end;
_ ->
%% Garbage data after DNS message
throw(?DECODE_ERROR)
@@ -161,8 +167,10 @@ do_decode(_) ->
decode_query_section(Bin, N, Buffer) ->
decode_query_section(Bin, N, Buffer, []).
+decode_query_section(<<>>=Rest, N, _Buffer, Qs) ->
+ {Rest,reverse(Qs),N =/= 0};
decode_query_section(Rest, 0, _Buffer, Qs) ->
- {Rest,reverse(Qs)};
+ {Rest,reverse(Qs),false};
decode_query_section(Bin, N, Buffer, Qs) ->
case decode_name(Bin, Buffer) of
{<<Type:16,Class:16,Rest/binary>>,Name} ->
@@ -179,8 +187,10 @@ decode_query_section(Bin, N, Buffer, Qs) ->
decode_rr_section(Bin, N, Buffer) ->
decode_rr_section(Bin, N, Buffer, []).
+decode_rr_section(<<>>=Rest, N, _Buffer, RRs) ->
+ {Rest,reverse(RRs),N =/= 0};
decode_rr_section(Rest, 0, _Buffer, RRs) ->
- {Rest,reverse(RRs)};
+ {Rest,reverse(RRs),false};
decode_rr_section(Bin, N, Buffer, RRs) ->
case decode_name(Bin, Buffer) of
{<<T:16/unsigned,C:16/unsigned,TTL:4/binary,
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index cf357b7fba..6f1688c6a2 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2010. 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
@@ -82,6 +82,7 @@
-define(INET_REQ_IFGET, 22).
-define(INET_REQ_IFSET, 23).
-define(INET_REQ_SUBSCRIBE, 24).
+-define(INET_REQ_GETIFADDRS, 25).
%% TCP requests
-define(TCP_REQ_ACCEPT, 40).
-define(TCP_REQ_LISTEN, 41).
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index 3bd5fa0958..65edddcb46 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -20,6 +20,8 @@
%% Parser for all kinds of ineternet configuration files
+%% Avoid warning for local function error/2 clashing with autoimported BIF.
+-compile({no_auto_import,[error/2]}).
-export([hosts/1, hosts/2]).
-export([hosts_vxworks/1]).
-export([protocols/1, protocols/2]).
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index 9b9e078898..de0f23bf24 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. 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%
%%
%% RFC 1035, 2671, 2782, 2915.
@@ -592,6 +592,7 @@ query_retries(_Q, _NSs, _Timer, Retry, Retry, S) ->
query_retries(Q, NSs, Timer, Retry, I, S0) ->
Num = length(NSs),
if Num =:= 0 ->
+ udp_close(S0),
{error,timeout};
true ->
case query_nss(Q, NSs, Timer, Retry, I, S0, []) of
diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl
index 795bf83807..de74b573bd 100644
--- a/lib/kernel/src/inet_sctp.erl
+++ b/lib/kernel/src/inet_sctp.erl
@@ -31,7 +31,7 @@
-define(FAMILY, inet).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
--export([open/1,close/1,listen/2,connect/5,sendmsg/3,recv/2]).
+-export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]).
@@ -141,5 +141,24 @@ connect_get_assoc(S, Addr, Port, Active, Timer) ->
sendmsg(S, SRI, Data) ->
prim_inet:sendmsg(S, SRI, Data).
+send(S, AssocId, Stream, Data) ->
+ case prim_inet:getopts(
+ S,
+ [{sctp_default_send_param,#sctp_sndrcvinfo{assoc_id=AssocId}}]) of
+ {ok,
+ [{sctp_default_send_param,
+ #sctp_sndrcvinfo{
+ flags=Flags, context=Context, ppid=PPID, timetolive=TTL}}]} ->
+ prim_inet:sendmsg(
+ S,
+ #sctp_sndrcvinfo{
+ flags=Flags, context=Context, ppid=PPID, timetolive=TTL,
+ assoc_id=AssocId, stream=Stream},
+ Data);
+ _ ->
+ prim_inet:sendmsg(
+ S, #sctp_sndrcvinfo{assoc_id=AssocId, stream=Stream}, Data)
+ end.
+
recv(S, Timeout) ->
prim_inet:recvfrom(S, 0, Timeout).
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index 92ee7b441a..1e07620a3e 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2010. 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
@@ -143,6 +143,13 @@ init(safe) ->
Boot = start_boot_server(),
DiskLog = start_disk_log(),
Pg2 = start_pg2(),
+
+ %% Run the on_load handlers for all modules that have been
+ %% loaded so far. Running them at this point means that
+ %% on_load handlers can safely call kernel processes
+ %% (and in particular call code:priv_dir/1 or code:lib_dir/1).
+ init:run_on_load_handlers(),
+
{ok, {SupFlags, Boot ++ DiskLog ++ Pg2}}.
get_code_args() ->
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index 3afaedf274..f5e2820bbe 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. 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(net_kernel).
@@ -72,7 +72,7 @@
-export([publish_on_node/1, update_publish_nodes/1]).
-%% Internal Exports
+%% Internal Exports
-export([do_spawn/3,
spawn_func/6,
ticker/2,
@@ -94,7 +94,7 @@
connecttime, %% the connection setuptime.
connections, %% table of connections
conn_owners = [], %% List of connection owner pids,
- pend_owners = [], %% List of potential owners
+ pend_owners = [], %% List of potential owners
listen, %% list of #listen
allowed, %% list of allowed nodes in a restricted system
verbose = 0, %% level of verboseness
@@ -232,7 +232,7 @@ do_connect(Node, Type, WaitForBarred) -> %% Type = normal | hidden
%% "connected from other end.~n",[Node]),
true;
{Pid, false} ->
- ?connect_failure(Node,{barred_connection,
+ ?connect_failure(Node,{barred_connection,
ets:lookup(sys_dist, Node)}),
%%io:format("Net Kernel: barred connection (~p) "
%% "- failure.~n",[Node]),
@@ -244,12 +244,12 @@ do_connect(Node, Type, WaitForBarred) -> %% Type = normal | hidden
{ok, never} ->
?connect_failure(Node,{dist_auto_connect,never}),
false;
- % This might happen due to connection close
+ % This might happen due to connection close
% not beeing propagated to user space yet.
- % Save the day by just not connecting...
+ % Save the day by just not connecting...
{ok, once} when Else =/= [],
(hd(Else))#connection.state =:= up ->
- ?connect_failure(Node,{barred_connection,
+ ?connect_failure(Node,{barred_connection,
ets:lookup(sys_dist, Node)}),
false;
_ ->
@@ -276,8 +276,8 @@ passive_connect_monitor(Parent, Node) ->
Parent ! {self(),true}
end
end.
-
-%% If the net_kernel isn't running we ignore all requests to the
+
+%% If the net_kernel isn't running we ignore all requests to the
%% kernel, thus basically accepting them :-)
request(Req) ->
case whereis(net_kernel) of
@@ -302,7 +302,7 @@ start_link([Name, LongOrShortNames]) ->
start_link([Name, LongOrShortNames, 15000]);
start_link([Name, LongOrShortNames, Ticktime]) ->
- case gen_server:start_link({local, net_kernel}, net_kernel,
+ case gen_server:start_link({local, net_kernel}, net_kernel,
{Name, LongOrShortNames, Ticktime}, []) of
{ok, Pid} ->
{ok, Pid};
@@ -313,7 +313,7 @@ start_link([Name, LongOrShortNames, Ticktime]) ->
end.
%% auth:get_cookie should only be able to return an atom
-%% tuple cookies are unknowns
+%% tuple cookies are unknowns
init({Name, LongOrShortNames, TickT}) ->
process_flag(trap_exit,true),
@@ -354,13 +354,13 @@ init({Name, LongOrShortNames, TickT}) ->
%% The response is delayed until the connection is up and
%% running.
%%
-handle_call({connect, _, Node}, _From, State) when Node =:= node() ->
- {reply, true, State};
+handle_call({connect, _, Node}, From, State) when Node =:= node() ->
+ async_reply({reply, true, State}, From);
handle_call({connect, Type, Node}, From, State) ->
verbose({connect, Type, Node}, 1, State),
case ets:lookup(sys_dist, Node) of
[Conn] when Conn#connection.state =:= up ->
- {reply, true, State};
+ async_reply({reply, true, State}, From);
[Conn] when Conn#connection.state =:= pending ->
Waiting = Conn#connection.waiting,
ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]}),
@@ -376,74 +376,75 @@ handle_call({connect, Type, Node}, From, State) ->
{noreply,State#state{conn_owners=Owners}};
_ ->
?connect_failure(Node, {setup_call, failed}),
- {reply, false, State}
+ async_reply({reply, false, State}, From)
end
end;
%%
%% Close the connection to Node.
%%
-handle_call({disconnect, Node}, _From, State) when Node =:= node() ->
- {reply, false, State};
-handle_call({disconnect, Node}, _From, State) ->
+handle_call({disconnect, Node}, From, State) when Node =:= node() ->
+ async_reply({reply, false, State}, From);
+handle_call({disconnect, Node}, From, State) ->
verbose({disconnect, Node}, 1, State),
{Reply, State1} = do_disconnect(Node, State),
- {reply, Reply, State1};
+ async_reply({reply, Reply, State1}, From);
-%%
+%%
%% The spawn/4 BIF ends up here.
-%%
+%%
handle_call({spawn,M,F,A,Gleader},{From,Tag},State) when is_pid(From) ->
do_spawn([no_link,{From,Tag},M,F,A,Gleader],[],State);
-%%
+%%
%% The spawn_link/4 BIF ends up here.
-%%
+%%
handle_call({spawn_link,M,F,A,Gleader},{From,Tag},State) when is_pid(From) ->
do_spawn([link,{From,Tag},M,F,A,Gleader],[],State);
-%%
+%%
%% The spawn_opt/5 BIF ends up here.
-%%
+%%
handle_call({spawn_opt,M,F,A,O,L,Gleader},{From,Tag},State) when is_pid(From) ->
do_spawn([L,{From,Tag},M,F,A,Gleader],O,State);
-%%
+%%
%% Only allow certain nodes.
-%%
-handle_call({allow, Nodes}, _From, State) ->
+%%
+handle_call({allow, Nodes}, From, State) ->
case all_atoms(Nodes) of
true ->
Allowed = State#state.allowed,
- {reply,ok,State#state{allowed = Allowed ++ Nodes}};
+ async_reply({reply,ok,State#state{allowed = Allowed ++ Nodes}},
+ From);
false ->
- {reply,error,State}
+ async_reply({reply,error,State}, From)
end;
-%%
+%%
%% authentication, used by auth. Simply works as this:
%% if the message comes through, the other node IS authorized.
-%%
-handle_call({is_auth, _Node}, _From, State) ->
- {reply,yes,State};
+%%
+handle_call({is_auth, _Node}, From, State) ->
+ async_reply({reply,yes,State}, From);
-%%
+%%
%% Not applicable any longer !?
-%%
-handle_call({apply,_Mod,_Fun,_Args}, {From,Tag}, State)
+%%
+handle_call({apply,_Mod,_Fun,_Args}, {From,Tag}, State)
when is_pid(From), node(From) =:= node() ->
- gen_server:reply({From,Tag}, not_implemented),
+ async_gen_server_reply({From,Tag}, not_implemented),
% Port = State#state.port,
% catch apply(Mod,Fun,[Port|Args]),
{noreply,State};
-handle_call(longnames, _From, State) ->
- {reply, get(longnames), State};
+handle_call(longnames, From, State) ->
+ async_reply({reply, get(longnames), State}, From);
-handle_call({update_publish_nodes, Ns}, _From, State) ->
- {reply, ok, State#state{publish_on_nodes = Ns}};
+handle_call({update_publish_nodes, Ns}, From, State) ->
+ async_reply({reply, ok, State#state{publish_on_nodes = Ns}}, From);
-handle_call({publish_on_node, Node}, _From, State) ->
+handle_call({publish_on_node, Node}, From, State) ->
NewState = case State#state.publish_on_nodes of
undefined ->
State#state{publish_on_nodes =
@@ -457,11 +458,12 @@ handle_call({publish_on_node, Node}, _From, State) ->
Nodes ->
lists:member(Node, Nodes)
end,
- {reply, Publish, NewState};
+ async_reply({reply, Publish, NewState}, From);
-handle_call({verbose, Level}, _From, State) ->
- {reply, State#state.verbose, State#state{verbose = Level}};
+handle_call({verbose, Level}, From, State) ->
+ async_reply({reply, State#state.verbose, State#state{verbose = Level}},
+ From);
%%
%% Set new ticktime
@@ -471,16 +473,16 @@ handle_call({verbose, Level}, _From, State) ->
%% #tick_change{} record if the ticker process has been upgraded;
%% otherwise, an integer or an atom.
-handle_call(ticktime, _, #state{tick = #tick{time = T}} = State) ->
- {reply, T, State};
-handle_call(ticktime, _, #state{tick = #tick_change{time = T}} = State) ->
- {reply, {ongoing_change_to, T}, State};
+handle_call(ticktime, From, #state{tick = #tick{time = T}} = State) ->
+ async_reply({reply, T, State}, From);
+handle_call(ticktime, From, #state{tick = #tick_change{time = T}} = State) ->
+ async_reply({reply, {ongoing_change_to, T}, State}, From);
-handle_call({new_ticktime,T,_TP}, _, #state{tick = #tick{time = T}} = State) ->
+handle_call({new_ticktime,T,_TP}, From, #state{tick = #tick{time = T}} = State) ->
?tckr_dbg(no_tick_change),
- {reply, unchanged, State};
+ async_reply({reply, unchanged, State}, From);
-handle_call({new_ticktime,T,TP}, _, #state{tick = #tick{ticker = Tckr,
+handle_call({new_ticktime,T,TP}, From, #state{tick = #tick{ticker = Tckr,
time = OT}} = State) ->
?tckr_dbg(initiating_tick_change),
start_aux_ticker(T, OT, TP),
@@ -493,14 +495,18 @@ handle_call({new_ticktime,T,TP}, _, #state{tick = #tick{ticker = Tckr,
?tckr_dbg(shorter_ticktime),
shorter
end,
- {reply, change_initiated, State#state{tick = #tick_change{ticker = Tckr,
- time = T,
- how = How}}};
+ async_reply({reply, change_initiated,
+ State#state{tick = #tick_change{ticker = Tckr,
+ time = T,
+ how = How}}}, From);
-handle_call({new_ticktime,_,_},
- _,
+handle_call({new_ticktime,_T,_TP},
+ From,
#state{tick = #tick_change{time = T}} = State) ->
- {reply, {ongoing_change_to, T}, State}.
+ async_reply({reply, {ongoing_change_to, T}, State}, From);
+
+handle_call(_Msg, _From, State) ->
+ {noreply, State}.
%% ------------------------------------------------------------
%% handle_cast.
@@ -568,7 +574,7 @@ handle_info({accept,AcceptPid,Socket,Family,Proto}, State) ->
%%
%% A node has successfully been connected.
%%
-handle_info({SetupPid, {nodeup,Node,Address,Type,Immediate}},
+handle_info({SetupPid, {nodeup,Node,Address,Type,Immediate}},
State) ->
case {Immediate, ets:lookup(sys_dist, Node)} of
{true, [Conn]} when Conn#connection.state =:= pending,
@@ -656,7 +662,7 @@ handle_info({From,registered_send,To,Mess},State) ->
send(From,To,Mess),
{noreply,State};
-%% badcookies SHOULD not be sent
+%% badcookies SHOULD not be sent
%% (if someone does erlang:set_cookie(node(),foo) this may be)
handle_info({From,badcookie,_To,_Mess}, State) ->
error_logger:error_msg("~n** Got OLD cookie from ~w~n",
@@ -704,7 +710,7 @@ handle_info(X, State) ->
%% 4. The ticker process.
%% (5. Garbage pid.)
%%
-%% The process type function that handled the process throws
+%% The process type function that handled the process throws
%% the handle_info return value !
%% -----------------------------------------------------------
@@ -994,9 +1000,9 @@ ticker(Kernel, Tick) when is_integer(Tick) ->
ticker_loop(Kernel, Tick).
to_integer(T) when is_integer(T) -> T;
-to_integer(T) when is_atom(T) ->
+to_integer(T) when is_atom(T) ->
list_to_integer(atom_to_list(T));
-to_integer(T) when is_list(T) ->
+to_integer(T) when is_list(T) ->
list_to_integer(T).
ticker_loop(Kernel, Tick) ->
@@ -1004,7 +1010,7 @@ ticker_loop(Kernel, Tick) ->
{new_ticktime, NewTick} ->
?tckr_dbg({ticker_changed_time, Tick, NewTick}),
?MODULE:ticker_loop(Kernel, NewTick)
- after Tick ->
+ after Tick ->
Kernel ! tick,
?MODULE:ticker_loop(Kernel, Tick)
end.
@@ -1052,7 +1058,7 @@ send(_From,To,Mess) ->
-ifdef(UNUSED).
safesend(Name,Mess) when is_atom(Name) ->
- case whereis(Name) of
+ case whereis(Name) of
undefined ->
Mess;
P when is_pid(P) ->
@@ -1063,11 +1069,12 @@ safesend(Pid, Mess) -> Pid ! Mess.
-endif.
do_spawn(SpawnFuncArgs, SpawnOpts, State) ->
+ [_,From|_] = SpawnFuncArgs,
case catch spawn_opt(?MODULE, spawn_func, SpawnFuncArgs, SpawnOpts) of
- {'EXIT', {Reason,_}} ->
- {reply, {'EXIT', {Reason,[]}}, State};
- {'EXIT', Reason} ->
- {reply, {'EXIT', {Reason,[]}}, State};
+ {'EXIT', {Reason,_}} ->
+ async_reply({reply, {'EXIT', {Reason,[]}}, State}, From);
+ {'EXIT', Reason} ->
+ async_reply({reply, {'EXIT', {Reason,[]}}, State}, From);
_ ->
{noreply,State}
end.
@@ -1145,7 +1152,7 @@ get_proto_mod(Family,Protocol,[L|Ls]) ->
true ->
get_proto_mod(Family,Protocol,Ls)
end;
-get_proto_mod(_Family, _Protocol, []) ->
+get_proto_mod(_Family, _Protocol, []) ->
error.
%% -------- Initialisation functions ------------------------
@@ -1156,9 +1163,9 @@ init_node(Name, LongOrShortNames) ->
case create_name(Name, LongOrShortNames, 1) of
{ok,Node} ->
case start_protos(list_to_atom(NameWithoutHost),Node) of
- {ok, Ls} ->
+ {ok, Ls} ->
{ok, Node, Ls};
- Error ->
+ Error ->
Error
end;
Error ->
@@ -1167,9 +1174,9 @@ init_node(Name, LongOrShortNames) ->
%% Create the node name
create_name(Name, LongOrShortNames, Try) ->
- put(longnames, case LongOrShortNames of
- shortnames -> false;
- longnames -> true
+ put(longnames, case LongOrShortNames of
+ shortnames -> false;
+ longnames -> true
end),
{Head,Host1} = create_hostpart(Name, LongOrShortNames),
case Host1 of
@@ -1218,7 +1225,7 @@ create_hostpart(Name, LongOrShortNames) ->
{Head,Host1}.
%%
-%%
+%%
%%
protocol_childspecs() ->
case init:get_argument(proto_dist) of
@@ -1228,7 +1235,7 @@ protocol_childspecs() ->
protocol_childspecs(["inet_tcp"])
end.
-protocol_childspecs([]) ->
+protocol_childspecs([]) ->
[];
protocol_childspecs([H|T]) ->
Mod = list_to_atom(H ++ "_dist"),
@@ -1238,15 +1245,15 @@ protocol_childspecs([H|T]) ->
_ ->
protocol_childspecs(T)
end.
-
-
+
+
%%
%% epmd_module() -> module_name of erl_epmd or similar gen_server_module.
%%
epmd_module() ->
case init:get_argument(epmd_module) of
- {ok,[[Module]]} ->
+ {ok,[[Module]]} ->
Module;
_ ->
erl_epmd
@@ -1293,7 +1300,7 @@ start_protos(Name, [Proto | Ps], Node, Ls) ->
error_logger:info_msg("Protocol: ~p: not supported~n", [Proto]),
start_protos(Name,Ps, Node, Ls);
{'EXIT', Reason} ->
- error_logger:info_msg("Protocol: ~p: register error: ~p~n",
+ error_logger:info_msg("Protocol: ~p: register error: ~p~n",
[Proto, Reason]),
start_protos(Name,Ps, Node, Ls);
{error, duplicate_name} ->
@@ -1303,7 +1310,7 @@ start_protos(Name, [Proto | Ps], Node, Ls) ->
[Proto]),
start_protos(Name,Ps, Node, Ls);
{error, Reason} ->
- error_logger:info_msg("Protocol: ~p: register/listen error: ~p~n",
+ error_logger:info_msg("Protocol: ~p: register/listen error: ~p~n",
[Proto, Reason]),
start_protos(Name,Ps, Node, Ls)
end;
@@ -1409,7 +1416,7 @@ reply_waiting(_Node, Waiting, Rep) ->
reply_waiting1(lists:reverse(Waiting), Rep).
reply_waiting1([From|W], Rep) ->
- gen_server:reply(From, Rep),
+ async_gen_server_reply(From, Rep),
reply_waiting1(W, Rep);
reply_waiting1([], _) ->
ok.
@@ -1455,7 +1462,7 @@ display_info({Node, Info}, {I,O}) ->
integer_to_list(In), integer_to_list(Out), Address),
{I+In,O+Out}.
-fmt_address(undefined) ->
+fmt_address(undefined) ->
"-";
fmt_address(A) ->
case A#net_address.family of
@@ -1511,3 +1518,21 @@ verbose(_, _, _) ->
getnode(P) when is_pid(P) -> node(P);
getnode(P) -> P.
+
+async_reply({reply, Msg, State}, From) ->
+ async_gen_server_reply(From, Msg),
+ {noreply, State}.
+
+async_gen_server_reply(From, Msg) ->
+ {Pid, Tag} = From,
+ M = {Tag, Msg},
+ case catch erlang:send(Pid, M, [nosuspend, noconnect]) of
+ ok ->
+ ok;
+ nosuspend ->
+ spawn(fun() -> catch erlang:send(Pid, M, [noconnect]) end);
+ noconnect ->
+ ok; % The gen module takes care of this case.
+ {'EXIT', _}=EXIT ->
+ EXIT
+ end.
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index d0b498edc9..75a11a8afd 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -50,7 +50,7 @@ find_executable(Name, Path) ->
relative ->
find_executable1(Name, split_path(Path), Extensions);
_ ->
- case verify_executable(Name, Extensions) of
+ case verify_executable(Name, Extensions, Extensions) of
{ok, Complete} ->
Complete;
error ->
@@ -60,7 +60,7 @@ find_executable(Name, Path) ->
find_executable1(Name, [Base|Rest], Extensions) ->
Complete0 = filename:join(Base, Name),
- case verify_executable(Complete0, Extensions) of
+ case verify_executable(Complete0, Extensions, Extensions) of
{ok, Complete} ->
Complete;
error ->
@@ -69,7 +69,7 @@ find_executable1(Name, [Base|Rest], Extensions) ->
find_executable1(_Name, [], _Extensions) ->
false.
-verify_executable(Name0, [Ext|Rest]) ->
+verify_executable(Name0, [Ext|Rest], OrigExtensions) ->
Name1 = Name0 ++ Ext,
case os:type() of
vxworks ->
@@ -78,7 +78,7 @@ verify_executable(Name0, [Ext|Rest]) ->
{ok, _} ->
{ok, Name1};
_ ->
- verify_executable(Name0, Rest)
+ verify_executable(Name0, Rest, OrigExtensions)
end;
_ ->
case file:read_file_info(Name1) of
@@ -87,12 +87,30 @@ verify_executable(Name0, [Ext|Rest]) ->
%% on Unix, since we test if any execution bit is set.
{ok, Name1};
_ ->
- verify_executable(Name0, Rest)
+ verify_executable(Name0, Rest, OrigExtensions)
end
end;
-verify_executable(_, []) ->
+verify_executable(Name, [], OrigExtensions) when OrigExtensions =/= [""] -> %% Windows
+ %% Will only happen on windows, hence case insensitivity
+ case can_be_full_name(string:to_lower(Name),OrigExtensions) of
+ true ->
+ verify_executable(Name,[""],[""]);
+ _ ->
+ error
+ end;
+verify_executable(_, [], _) ->
error.
+can_be_full_name(_Name,[]) ->
+ false;
+can_be_full_name(Name,[H|T]) ->
+ case lists:suffix(H,Name) of %% Name is in lowercase, cause this is a windows thing
+ true ->
+ true;
+ _ ->
+ can_be_full_name(Name,T)
+ end.
+
split_path(Path) ->
case type() of
{win32, _} ->
@@ -119,6 +137,7 @@ reverse_element(List) ->
lists:reverse(List).
-spec extensions() -> [string()].
+%% Extensions in lower case
extensions() ->
case type() of
{win32, _} -> [".exe",".com",".cmd",".bat"];
diff --git a/lib/kernel/src/pg2.erl b/lib/kernel/src/pg2.erl
index cb9fec2ffe..956a900adc 100644
--- a/lib/kernel/src/pg2.erl
+++ b/lib/kernel/src/pg2.erl
@@ -251,7 +251,9 @@ terminate(_Reason, _S) ->
%%% Pid is a member of group Name.
store(List) ->
- _ = [assure_group(Name) andalso [join_group(Name, P) || P <- Members] ||
+ _ = [(assure_group(Name)
+ andalso
+ [join_group(Name, P) || P <- Members -- group_members(Name)]) ||
[Name, Members] <- List],
ok.
diff --git a/lib/kernel/src/ram_file.erl b/lib/kernel/src/ram_file.erl
index d996650948..48ea871433 100644
--- a/lib/kernel/src/ram_file.erl
+++ b/lib/kernel/src/ram_file.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. 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(ram_file).
@@ -24,11 +24,11 @@
-export([open/2, close/1]).
-export([write/2, read/2, copy/3,
pread/2, pread/3, pwrite/2, pwrite/3,
- position/2, truncate/1, sync/1]).
+ position/2, truncate/1, datasync/1, sync/1]).
%% Specialized file operations
-export([get_size/1, get_file/1, set_file/2, get_file_close/1]).
--export([compress/1, uncompress/1, uuencode/1, uudecode/1]).
+-export([compress/1, uncompress/1, uuencode/1, uudecode/1, advise/4]).
-export([open_mode/1]). %% used by ftp-file
@@ -60,6 +60,7 @@
-define(RAM_FILE_TRUNCATE, 14).
-define(RAM_FILE_PREAD, 17).
-define(RAM_FILE_PWRITE, 18).
+-define(RAM_FILE_FDATASYNC, 19).
%% Other operations
-define(RAM_FILE_GET, 30).
@@ -70,6 +71,7 @@
-define(RAM_FILE_UUENCODE, 35).
-define(RAM_FILE_UUDECODE, 36).
-define(RAM_FILE_SIZE, 37).
+-define(RAM_FILE_ADVISE, 38).
%% Open modes for RAM_FILE_OPEN
-define(RAM_FILE_MODE_READ, 1).
@@ -90,6 +92,14 @@
-define(RAM_FILE_RESP_NUMBER, 3).
-define(RAM_FILE_RESP_INFO, 4).
+%% POSIX file advises
+-define(POSIX_FADV_NORMAL, 0).
+-define(POSIX_FADV_RANDOM, 1).
+-define(POSIX_FADV_SEQUENTIAL, 2).
+-define(POSIX_FADV_WILLNEED, 3).
+-define(POSIX_FADV_DONTNEED, 4).
+-define(POSIX_FADV_NOREUSE, 5).
+
%% --------------------------------------------------------------------------
%% Generic file contents operations.
%%
@@ -167,6 +177,8 @@ copy(#file_descriptor{module = ?MODULE} = Source,
%% XXX Should be moved down to the driver for optimization.
file:copy_opened(Source, Dest, Length).
+datasync(#file_descriptor{module = ?MODULE, data = Port}) ->
+ call_port(Port, <<?RAM_FILE_FDATASYNC>>).
sync(#file_descriptor{module = ?MODULE, data = Port}) ->
call_port(Port, <<?RAM_FILE_FSYNC>>).
@@ -349,6 +361,28 @@ uudecode(#file_descriptor{module = ?MODULE, data = Port}) ->
uudecode(#file_descriptor{}) ->
{error, enotsup}.
+advise(#file_descriptor{module = ?MODULE, data = Port}, Offset,
+ Length, Advise) ->
+ Cmd0 = <<?RAM_FILE_ADVISE, Offset:64/signed, Length:64/signed>>,
+ case Advise of
+ normal ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_NORMAL:32/signed>>);
+ random ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_RANDOM:32/signed>>);
+ sequential ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_SEQUENTIAL:32/signed>>);
+ will_need ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_WILLNEED:32/signed>>);
+ dont_need ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_DONTNEED:32/signed>>);
+ no_reuse ->
+ call_port(Port, <<Cmd0/binary, ?POSIX_FADV_NOREUSE:32/signed>>);
+ _ ->
+ {error, einval}
+ end;
+advise(#file_descriptor{}, _Offset, _Length, _Advise) ->
+ {error, enotsup}.
+
%%%-----------------------------------------------------------------