diff options
Diffstat (limited to 'lib/kernel/src')
-rw-r--r-- | lib/kernel/src/application.erl | 6 | ||||
-rw-r--r-- | lib/kernel/src/code.erl | 129 | ||||
-rw-r--r-- | lib/kernel/src/disk_log_1.erl | 8 | ||||
-rw-r--r-- | lib/kernel/src/erl_ddll.erl | 33 | ||||
-rw-r--r-- | lib/kernel/src/error_handler.erl | 6 | ||||
-rw-r--r-- | lib/kernel/src/file.erl | 4 | ||||
-rw-r--r-- | lib/kernel/src/global.erl | 30 | ||||
-rw-r--r-- | lib/kernel/src/hipe_unified_loader.erl | 11 | ||||
-rw-r--r-- | lib/kernel/src/inet6_tcp_dist.erl | 6 | ||||
-rw-r--r-- | lib/kernel/src/inet_res.erl | 203 | ||||
-rw-r--r-- | lib/kernel/src/net_kernel.erl | 35 | ||||
-rw-r--r-- | lib/kernel/src/os.erl | 33 |
12 files changed, 283 insertions, 221 deletions
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index d9db23d652..2a193affd4 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 @@ -204,12 +204,12 @@ get_env(Key) -> get_env(Application, Key) -> application_controller:get_env(Application, Key). --spec get_all_env() -> [] | [{atom(), any()}]. +-spec get_all_env() -> [{atom(), any()}]. get_all_env() -> application_controller:get_pid_all_env(group_leader()). --spec get_all_env(atom()) -> [] | [{atom(), any()}]. +-spec get_all_env(atom()) -> [{atom(), any()}]. get_all_env(Application) -> application_controller:get_all_env(Application). diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index feb5131aad..b0f99305f2 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 @@ -72,39 +72,42 @@ %% User interface. %% -%% objfile_extension() -> ".beam" -%% set_path(Dir*) -> true -%% get_path() -> Dir* -%% add_path(Dir) -> true | {error, What} -%% add_patha(Dir) -> true | {error, What} -%% add_pathz(Dir) -> true | {error, What} -%% add_paths(DirList) -> true | {error, What} -%% add_pathsa(DirList) -> true | {error, What} -%% add_pathsz(DirList) -> true | {error, What} -%% del_path(Dir) -> true | {error, What} -%% replace_path(Name,Dir) -> true | {error, What} -%% load_file(File) -> {error,What} | {module, Mod} -%% load_abs(File) -> {error,What} | {module, Mod} -%% load_abs(File,Mod) -> {error,What} | {module, Mod} -%% load_binary(Mod,File,Bin) -> {error,What} | {module,Mod} -%% ensure_loaded(Module) -> {error,What} | {module, Mod} -%% delete(Module) -%% purge(Module) kills all procs running old code -%% soft_purge(Module) -> true | false -%% is_loaded(Module) -> {file, File} | false -%% all_loaded() -> {Module, File}* -%% get_object_code(Mod) -> error | {Mod, Bin, Filename} -%% stop() -> true -%% root_dir() -%% compiler_dir() -%% lib_dir() -%% priv_dir(Name) -%% stick_dir(Dir) -> ok | error -%% unstick_dir(Dir) -> ok | error -%% is_sticky(Module) -> true | false -%% which(Module) -> Filename -%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason} -%% clash() -> -> print out +%% objfile_extension() -> ".beam" +%% get_path() -> [Dir] +%% set_path([Dir]) -> true | {error, bad_directory | bad_path} +%% add_path(Dir) -> true | {error, bad_directory} +%% add_patha(Dir) -> true | {error, bad_directory} +%% add_pathz(Dir) -> true | {error, bad_directory} +%% add_paths([Dir]) -> ok +%% add_pathsa([Dir]) -> ok +%% add_pathsz([Dir]) -> ok +%% del_path(Dir) -> boolean() | {error, bad_name} +%% replace_path(Name, Dir) -> true | replace_path_error() +%% load_file(Module) -> {module, Module} | {error, What :: atom()} +%% load_abs(File) -> {module, Module} | {error, What :: atom()} +%% load_abs(File, Module) -> {module, Module} | {error, What :: atom()} +%% load_binary(Module, File, Bin)-> {module, Module} | {error, What :: atom()} +%% ensure_loaded(Module) -> {module, Module} | {error, What :: atom()} +%% delete(Module) -> boolean() +%% purge(Module) -> boolean() kills all procs running old code +%% soft_purge(Module) -> boolean() +%% is_loaded(Module) -> {file, loaded_filename()} | false +%% all_loaded() -> [{Module, loaded_filename()}] +%% get_object_code(Module) -> {Module, Bin, Filename} | error +%% stop() -> no_return() +%% root_dir() -> Dir +%% compiler_dir() -> Dir +%% lib_dir() -> Dir +%% lib_dir(Application) -> Dir | {error, bad_name} +%% priv_dir(Application) -> Dir | {error, bad_name} +%% stick_dir(Dir) -> ok | error +%% unstick_dir(Dir) -> ok | error +%% stick_mod(Module) -> true +%% unstick_mod(Module) -> true +%% is_sticky(Module) -> boolean() +%% which(Module) -> Filename | loaded_ret_atoms() | non_existing +%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason} +%% clash() -> ok prints out number of clashes %%---------------------------------------------------------------------------- %% Some types for basic exported functions of this module @@ -120,7 +123,7 @@ %% User interface %%---------------------------------------------------------------------------- --spec objfile_extension() -> file:filename(). +-spec objfile_extension() -> nonempty_string(). objfile_extension() -> init:objfile_extension(). @@ -138,21 +141,21 @@ load_abs(File) when is_list(File); is_atom(File) -> call({load_abs,File,[]}). %% XXX Filename is also an atom(), e.g. 'cover_compiled' -spec load_abs(Filename :: loaded_filename(), Module :: atom()) -> load_ret(). -load_abs(File,M) when (is_list(File) orelse is_atom(File)), is_atom(M) -> +load_abs(File, M) when (is_list(File) orelse is_atom(File)), is_atom(M) -> call({load_abs,File,M}). %% XXX Filename is also an atom(), e.g. 'cover_compiled' -spec load_binary(Module :: atom(), Filename :: loaded_filename(), Binary :: binary()) -> load_ret(). -load_binary(Mod,File,Bin) +load_binary(Mod, File, Bin) when is_atom(Mod), (is_list(File) orelse is_atom(File)), is_binary(Bin) -> call({load_binary,Mod,File,Bin}). -spec load_native_partial(Module :: atom(), Binary :: binary()) -> load_ret(). -load_native_partial(Mod,Bin) when is_atom(Mod), is_binary(Bin) -> +load_native_partial(Mod, Bin) when is_atom(Mod), is_binary(Bin) -> call({load_native_partial,Mod,Bin}). -spec load_native_sticky(Module :: atom(), Binary :: binary(), WholeModule :: 'false' | binary()) -> load_ret(). -load_native_sticky(Mod,Bin,WholeModule) +load_native_sticky(Mod, Bin, WholeModule) when is_atom(Mod), is_binary(Bin), (is_binary(WholeModule) orelse WholeModule =:= false) -> call({load_native_sticky,Mod,Bin,WholeModule}). @@ -160,7 +163,7 @@ load_native_sticky(Mod,Bin,WholeModule) -spec delete(Module :: atom()) -> boolean(). delete(Mod) when is_atom(Mod) -> call({delete,Mod}). --spec purge/1 :: (Module :: atom()) -> boolean(). +-spec purge(Module :: atom()) -> boolean(). purge(Mod) when is_atom(Mod) -> call({purge,Mod}). -spec soft_purge(Module :: atom()) -> boolean(). @@ -195,7 +198,7 @@ lib_dir(App, SubDir) when is_atom(App), is_atom(SubDir) -> call({dir,{lib_dir,Ap compiler_dir() -> call({dir,compiler_dir}). %% XXX is_list() is for backwards compatibility -- take out in future version --spec priv_dir(Appl :: atom()) -> file:filename() | {'error', 'bad_name'}. +-spec priv_dir(App :: atom()) -> file:filename() | {'error', 'bad_name'}. priv_dir(App) when is_atom(App) ; is_list(App) -> call({dir,{priv_dir,App}}). -spec stick_dir(Directory :: file:filename()) -> 'ok' | 'error'. @@ -220,13 +223,14 @@ 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', 'bad_directory'}. +-type add_path_ret() :: 'true' | {'error', 'bad_directory'}. +-spec add_path(Directory :: file:filename()) -> add_path_ret(). add_path(Dir) when is_list(Dir) -> call({add_path,last,Dir}). --spec add_pathz(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}. +-spec add_pathz(Directory :: file:filename()) -> add_path_ret(). add_pathz(Dir) when is_list(Dir) -> call({add_path,last,Dir}). --spec add_patha(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}. +-spec add_patha(Directory :: file:filename()) -> add_path_ret(). add_patha(Dir) when is_list(Dir) -> call({add_path,first,Dir}). -spec add_paths(Directories :: [file:filename()]) -> 'ok'. @@ -243,8 +247,8 @@ del_path(Name) when is_list(Name) ; is_atom(Name) -> call({del_path,Name}). -type replace_path_error() :: {'error', 'bad_directory' | 'bad_name' | {'badarg',_}}. -spec replace_path(Name:: atom(), Dir :: file:filename()) -> 'true' | replace_path_error(). -replace_path(Name, Dir) when (is_atom(Name) or is_list(Name)) and - (is_atom(Dir) or is_list(Dir)) -> +replace_path(Name, Dir) when (is_atom(Name) orelse is_list(Name)), + (is_atom(Dir) orelse is_list(Dir)) -> call({replace_path,Name,Dir}). -spec rehash() -> 'ok'. @@ -275,21 +279,14 @@ start_link(Flags) -> do_start(Flags) -> %% The following module_info/1 calls are here to ensure - %% that the modules are loaded prior to their use elsewhere in + %% that these modules are loaded prior to their use elsewhere in %% the code_server. %% Otherwise a deadlock may occur when the code_server is starting. - code_server:module_info(module), - packages:module_info(module), + code_server = code_server:module_info(module), + packages = packages:module_info(module), catch hipe_unified_loader:load_hipe_modules(), - gb_sets:module_info(module), - gb_trees:module_info(module), - - ets:module_info(module), - os:module_info(module), - binary:module_info(module), - unicode:module_info(module), - filename:module_info(module), - lists:module_info(module), + Modules2 = [gb_sets, gb_trees, ets, os, binary, unicode, filename, lists], + lists:foreach(fun (M) -> M = M:module_info(module) end, Modules2), Mode = get_mode(Flags), case init:get_argument(root) of @@ -297,7 +294,7 @@ do_start(Flags) -> Root = filename:join([Root0]), % Normalize. Use filename case code_server:start_link([Root,Mode]) of {ok,_Pid} = Ok2 -> - if + if Mode =:= interactive -> case lists:member(stick, Flags) of true -> do_stick_dirs(); @@ -306,14 +303,14 @@ do_start(Flags) -> true -> ok end, - % Quietly load the native code for all modules loaded so far. + %% Quietly load native code for all modules loaded so far catch load_native_code_for_all_loaded(), Ok2; Other -> Other end; Other -> - error_logger:error_msg("Can not start code server ~w ~n",[Other]), + error_logger:error_msg("Can not start code server ~w ~n", [Other]), {error, crash} end. @@ -330,7 +327,7 @@ do_s(Lib) -> %% The return value is intentionally ignored. Missing %% directories is not a fatal error. (In embedded systems, %% there is usually no compiler directory.) - stick_dir(filename:append(Dir, "ebin")), + _ = stick_dir(filename:append(Dir, "ebin")), ok end. @@ -428,7 +425,7 @@ where_is_file(Path, File) when is_list(Path), is_list(File) -> -spec set_primary_archive(ArchiveFile :: file:filename(), ArchiveBin :: binary(), - FileInfo :: #file_info{}) + FileInfo :: file:file_info()) -> 'ok' | {'error', atom()}. set_primary_archive(ArchiveFile0, ArchiveBin, #file_info{} = FileInfo) @@ -485,13 +482,13 @@ filter(Ext, _, {ok,Files}) -> filter2(Ext, length(Ext), Files). filter2(_Ext, _Extlen, []) -> []; -filter2(Ext, Extlen,[File|Tail]) -> - case has_ext(Ext,Extlen, File) of +filter2(Ext, Extlen, [File|Tail]) -> + case has_ext(Ext, Extlen, File) of true -> [File | filter2(Ext, Extlen, Tail)]; false -> filter2(Ext, Extlen, Tail) end. -has_ext(Ext, Extlen,File) -> +has_ext(Ext, Extlen, File) -> L = length(File), case catch lists:nthtail(L - Extlen, File) of Ext -> true; diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl index 8ccdb88d12..266df84a03 100644 --- a/lib/kernel/src/disk_log_1.erl +++ b/lib/kernel/src/disk_log_1.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 @@ -581,11 +581,13 @@ done_scan(In, Out, OutName, FName, RecoveredTerms, BadChars) -> file:delete(OutName), throw(Error) end. - + +-spec repair_err(file:io_device(), #cache{}, file:filename(), + file:filename(), {'error', file:posix()}) -> no_return(). repair_err(In, Out, OutName, ErrFileName, Error) -> file:close(In), catch fclose(Out, OutName), - % OutName is often the culprit, try to remove it anyway... + %% OutName is often the culprit, try to remove it anyway... file:delete(OutName), file_error(ErrFileName, Error). diff --git a/lib/kernel/src/erl_ddll.erl b/lib/kernel/src/erl_ddll.erl index 88f91de24f..ce64589a29 100644 --- a/lib/kernel/src/erl_ddll.erl +++ b/lib/kernel/src/erl_ddll.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2011. 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% %% %% Dynamic Driver Loader and Linker @@ -29,6 +29,11 @@ %%---------------------------------------------------------------------------- +-type path() :: string() | atom(). +-type driver() :: string() | atom(). + +%%---------------------------------------------------------------------------- + -spec start() -> {'error', {'already_started', 'undefined'}}. start() -> @@ -39,13 +44,13 @@ start() -> stop() -> ok. --spec load_driver(Path :: string() | atom(), Driver :: string() | atom()) -> +-spec load_driver(Path :: path(), Driver :: driver()) -> 'ok' | {'error', any()}. load_driver(Path, Driver) -> do_load_driver(Path, Driver, [{driver_options,[kill_ports]}]). --spec load(Path :: string() | atom(), Driver :: string() | atom()) -> +-spec load(Path :: path(), Driver :: driver()) -> 'ok' | {'error', any()}. load(Path, Driver) -> @@ -95,23 +100,23 @@ do_unload_driver(Driver,Flags) -> end end. --spec unload_driver(Driver :: string() | atom()) -> 'ok' | {'error', any()}. +-spec unload_driver(Driver :: driver()) -> 'ok' | {'error', any()}. unload_driver(Driver) -> do_unload_driver(Driver,[{monitor,pending_driver},kill_ports]). --spec unload(Driver :: string() | atom()) -> 'ok' | {'error', any()}. +-spec unload(Driver :: driver()) -> 'ok' | {'error', any()}. unload(Driver) -> do_unload_driver(Driver,[]). --spec reload(Path :: string() | atom(), Driver :: string() | atom()) -> +-spec reload(Path :: path(), Driver :: driver()) -> 'ok' | {'error', any()}. reload(Path,Driver) -> do_load_driver(Path, Driver, [{reload,pending_driver}]). --spec reload_driver(Path :: string() | atom(), Driver :: string() | atom()) -> +-spec reload_driver(Path :: path(), Driver :: driver()) -> 'ok' | {'error', any()}. reload_driver(Path,Driver) -> @@ -122,15 +127,15 @@ reload_driver(Path,Driver) -> format_error(Code) -> case Code of - % This is the only error code returned only from erlang code... - % 'permanent' has a translation in the emulator, even though the erlang code uses it to... + %% This is the only error code returned only from erlang code... + %% 'permanent' has a translation in the emulator, even though the erlang code uses it to... load_cancelled -> "Loading was cancelled from other process"; _ -> erl_ddll:format_error_int(Code) end. --spec info(Driver :: string() | atom()) -> [{atom(), any()}]. +-spec info(Driver :: driver()) -> [{atom(), any()}, ...]. info(Driver) -> [{processes, erl_ddll:info(Driver,processes)}, diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl index 885eeb2b0f..6f69f4ccb9 100644 --- a/lib/kernel/src/error_handler.erl +++ b/lib/kernel/src/error_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 @@ -80,9 +80,13 @@ int() -> int. %% %% Crash providing a beautiful stack backtrace. %% +-spec crash(atom(), [term()]) -> no_return(). + crash(Fun, Args) -> crash({Fun,Args}). +-spec crash(atom(), atom(), arity()) -> no_return(). + crash(M, F, A) -> crash({M,F,A}). diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index bc95359986..88bcf9a9cc 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 @@ -240,7 +240,7 @@ write_file(Name, Bin) -> %% when it is time to change file server protocol again. %% Meanwhile, it is implemented here, slightly less efficient. --spec write_file(Name :: name(), Bin :: binary(), Modes :: [mode()]) -> +-spec write_file(Name :: name(), Bin :: iodata(), Modes :: [mode()]) -> 'ok' | {'error', posix()}. write_file(Name, Bin, ModeList) when is_list(ModeList) -> diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl index 081e7e2f93..6343acd000 100644 --- a/lib/kernel/src/global.erl +++ b/lib/kernel/src/global.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 @@ -113,8 +113,9 @@ syncers = [] :: [pid()], node_name = node() :: node(), the_locker, the_registrar, trace, - global_lock_down = false + global_lock_down = false :: boolean() }). +-type state() :: #state{}. %%% There are also ETS tables used for bookkeeping of locks and names %%% (the first position is the key): @@ -399,6 +400,9 @@ info() -> %%%----------------------------------------------------------------- %%% Call-back functions from gen_server %%%----------------------------------------------------------------- + +-spec init([]) -> {'ok', state()}. + init([]) -> process_flag(trap_exit, true), _ = ets:new(global_locks, [set, named_table, protected]), @@ -542,6 +546,11 @@ init([]) -> %% sent by each node to all new nodes (Node becomes known to them) %%----------------------------------------------------------------- +-spec handle_call(term(), {pid(), term()}, state()) -> + {'noreply', state()} | + {'reply', term(), state()} | + {'stop', 'normal', 'stopped', state()}. + handle_call({whereis, Name}, From, S) -> do_whereis(Name, From), {noreply, S}; @@ -621,6 +630,9 @@ handle_call(Request, From, S) -> %% init_connect %% %%======================================================================== + +-spec handle_cast(term(), state()) -> {'noreply', state()}. + handle_cast({init_connect, Vsn, Node, InitMsg}, S) -> %% Sent from global_name_server at Node. ?trace({'####', init_connect, {vsn, Vsn}, {node,Node},{initmsg,InitMsg}}), @@ -782,6 +794,11 @@ handle_cast(Request, S) -> "handle_cast(~p, _)\n", [Request]), {noreply, S}. +%%======================================================================== + +-spec handle_info(term(), state()) -> + {'noreply', state()} | {'stop', term(), state()}. + handle_info({'EXIT', Locker, _Reason}=Exit, #state{the_locker=Locker}=S) -> {stop, {locker_died,Exit}, S#state{the_locker=undefined}}; handle_info({'EXIT', Registrar, _}=Exit, #state{the_registrar=Registrar}=S) -> @@ -1122,12 +1139,17 @@ do_whereis(Name, From) -> send_again({whereis, Name, From}) end. +-spec terminate(term(), state()) -> 'ok'. + terminate(_Reason, _S) -> true = ets:delete(global_names), true = ets:delete(global_names_ext), true = ets:delete(global_locks), true = ets:delete(global_pid_names), - true = ets:delete(global_pid_ids). + true = ets:delete(global_pid_ids), + ok. + +-spec code_change(term(), state(), term()) -> {'ok', state()}. code_change(_OldVsn, S, _Extra) -> {ok, S}. @@ -1955,7 +1977,7 @@ delete_lock(Ref, S0) -> Locks = pid_locks(Ref), F = fun({ResourceId, LockRequesterId, PidRefs}, S) -> {Pid, _RPid, Ref} = lists:keyfind(Ref, 3, PidRefs), - remove_lock(ResourceId, LockRequesterId, Pid, PidRefs, true,S) + remove_lock(ResourceId, LockRequesterId, Pid, PidRefs, true, S) end, lists:foldl(F, S0, Locks). diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index f289b8110d..1d3eb926ca 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -258,7 +258,7 @@ find_callee_mfas(Patches) when is_list(Patches) -> amd64 -> []; arm -> find_callee_mfas(Patches, gb_sets:empty(), false); powerpc -> find_callee_mfas(Patches, gb_sets:empty(), true); - %% ppc64 -> find_callee_mfas(Patches, gb_sets:empty(), true); + ppc64 -> find_callee_mfas(Patches, gb_sets:empty(), true); ultrasparc -> []; x86 -> [] end. @@ -301,6 +301,7 @@ mk_trampoline_map(CalleeMFAs, Trampolines) -> SizeofLong = case erlang:system_info(hipe_architecture) of amd64 -> 8; + ppc64 -> 8; _ -> 4 end, mk_trampoline_map(tuple_size(CalleeMFAs), CalleeMFAs, @@ -625,15 +626,15 @@ patch_instr(Address, Value, Type) -> %% %% XXX: It appears this is used for inserting both code addresses %% and other data. In HiPE, code addresses are still 32-bit on -%% 64-bit machines. +%% some 64-bit machines. write_word(DataAddress, DataWord) -> case erlang:system_info(hipe_architecture) of amd64 -> hipe_bifs:write_u64(DataAddress, DataWord), DataAddress+8; - %% ppc64 -> - %% hipe_bifs:write_u64(DataAddress, DataWord), - %% DataAddress+8; + ppc64 -> + hipe_bifs:write_u64(DataAddress, DataWord), + DataAddress+8; _ -> hipe_bifs:write_u32(DataAddress, DataWord), DataAddress+4 diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl index fab00bbb9f..b9c4fa607c 100644 --- a/lib/kernel/src/inet6_tcp_dist.erl +++ b/lib/kernel/src/inet6_tcp_dist.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 @@ -162,8 +162,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> inet:getll(S) end, f_address = fun get_remote_id/2, - mf_tick = {?MODULE, tick}, - mf_getstat = {?MODULE,getstat} + mf_tick = fun ?MODULE:tick/1, + mf_getstat = fun ?MODULE:getstat/1 }, dist_util:handshake_other_started(HSData); {false,IP} -> diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl index de0f23bf24..93563c6011 100644 --- a/lib/kernel/src/inet_res.erl +++ b/lib/kernel/src/inet_res.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 @@ -539,27 +539,41 @@ udp_send(#sock{inet=I}, {A,B,C,D}=IP, Port, Buffer) when ?ip(A,B,C,D), ?port(Port) -> gen_udp:send(I, IP, Port, Buffer). -udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout) +udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout, Decode) when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) -> - do_udp_recv(fun(T) -> gen_udp:recv(I, 0, T) end, IP, Port, Timeout); -udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout) + do_udp_recv(I, IP, Port, Timeout, Decode, erlang:now(), Timeout); +udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout, Decode) when ?ip(A,B,C,D), ?port(Port) -> - do_udp_recv(fun(T) -> gen_udp:recv(I, 0, T) end, IP, Port, Timeout). - -do_udp_recv(Recv, IP, Port, Timeout) -> - do_udp_recv(Recv, IP, Port, Timeout, - if Timeout =/= 0 -> erlang:now(); true -> undefined end). - -do_udp_recv(Recv, IP, Port, Timeout, Then) -> - case Recv(Timeout) of - {ok,{IP,Port,Answer}} -> - {ok,Answer,erlang:max(0, Timeout - now_ms(erlang:now(), Then))}; - {ok,_} when Timeout =:= 0 -> - {error,timeout}; - {ok,_} -> - Now = erlang:now(), - T = erlang:max(0, Timeout - now_ms(Now, Then)), - do_udp_recv(Recv, IP, Port, T, Now); + do_udp_recv(I, IP, Port, Timeout, Decode, erlang:now(), Timeout). + +do_udp_recv(_I, _IP, _Port, 0, _Decode, _Start, _T) -> + timeout; +do_udp_recv(I, IP, Port, Timeout, Decode, Start, T) -> + case gen_udp:recv(I, 0, T) of + {ok,Reply} -> + case Decode(Reply) of + false when T =:= 0 -> + %% This is a compromize between the hard way i.e + %% in the clause below if NewT becomes 0 bailout + %% immediately and risk that the right reply lies + %% ahead after some bad id replies, and the + %% forgiving way i.e go on with Timeout 0 until + %% the right reply comes or no reply (timeout) + %% which opens for a DOS attack by a malicious + %% DNS server flooding with bad id replies causing + %% an infinite loop here. + %% + %% Timeout is used as a sanity limit counter + %% just to put an end to the loop. + NewTimeout = erlang:max(0, Timeout - 50), + do_udp_recv(I, IP, Port, NewTimeout, Decode, Start, T); + false -> + Now = erlang:now(), + NewT = erlang:max(0, Timeout - now_ms(Now, Start)), + do_udp_recv(I, IP, Port, Timeout, Decode, Start, NewT); + Result -> + Result + end; Error -> Error end. @@ -580,6 +594,17 @@ udp_close(#sock{inet=I,inet6=I6}) -> %% end %% end %% +%% But that man page also says dig always use num_servers = 1. +%% +%% Our man page says: timeout/retry, then double for next retry, i.e +%% for i = 0 to retry - 1 +%% foreach nameserver +%% send query +%% wait((time * (2**i)) / retry) +%% end +%% end +%% +%% And that is what the code seems to do, now fixed, hopefully... do_query(_Q, [], _Timer) -> {error,nxdomain}; @@ -589,19 +614,16 @@ do_query(#q{options=#options{retry=Retry}}=Q, NSs, Timer) -> query_retries(_Q, _NSs, _Timer, Retry, Retry, S) -> udp_close(S), {error,timeout}; +query_retries(_Q, [], _Timer, _Retry, _I, S) -> + udp_close(S), + {error,timeout}; 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 - {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers - query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S); - {S,Result} -> - udp_close(S), - Result - end + case query_nss(Q, NSs, Timer, Retry, I, S0, []) of + {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers + query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S); + {S,Result} -> + udp_close(S), + Result end. query_nss(_Q, [], _Timer, _Retry, _I, S, ErrNSs) -> @@ -611,13 +633,13 @@ query_nss(#q{edns=undefined}=Q, NSs, Timer, Retry, I, S, ErrNSs) -> query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs) -> query_nss_edns(Q, NSs, Timer, Retry, I, S, ErrNSs). -query_nss_edns(#q{options=#options{udp_payload_size=PSz}=Options, - edns={Id,Buffer}}=Q, - [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) -> - {S,Res}=Reply = query_ns(S0, Id, Buffer, IP, Port, Timer, - Retry, I, Options, PSz), +query_nss_edns( + #q{options=#options{udp_payload_size=PSz}=Options,edns={Id,Buffer}}=Q, + [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) -> + {S,Res}=Reply = + query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, PSz), case Res of - timeout -> {S,{error,timeout}}; + timeout -> {S,{error,timeout}}; % Bailout timeout {ok,_} -> Reply; {error,{nxdomain,_}} -> Reply; {error,{E,_}} when E =:= qfmterror; E =:= notimp; E =:= servfail; @@ -629,17 +651,19 @@ query_nss_edns(#q{options=#options{udp_payload_size=PSz}=Options, query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs) end. -query_nss_dns(#q{dns=Qdns}=Q0, [{IP,Port}=NS|NSs], - Timer, Retry, I, S0, ErrNSs) -> +query_nss_dns( + #q{dns=Qdns}=Q0, + [{IP,Port}=NS|NSs], Timer, Retry, I, S0, ErrNSs) -> #q{options=Options,dns={Id,Buffer}}=Q = if is_function(Qdns, 0) -> Q0#q{dns=Qdns()}; true -> Q0 end, - {S,Res}=Reply = query_ns(S0, Id, Buffer, IP, Port, Timer, - Retry, I, Options, ?PACKETSZ), + {S,Res}=Reply = + query_ns( + S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, ?PACKETSZ), case Res of - timeout -> {S,{error,timeout}}; + timeout -> {S,{error,timeout}}; % Bailout timeout {ok,_} -> Reply; {error,{E,_}} when E =:= nxdomain; E =:= qfmterror -> Reply; {error,E} when E =:= fmt; E =:= enetunreach; E =:= econnrefused -> @@ -653,48 +677,66 @@ query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, PSz) -> case UseVC orelse iolist_size(Buffer) > PSz of true -> - {S0,query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose)}; + TcpTimeout = inet:timeout(Tm*5, Timer), + {S0,query_tcp(TcpTimeout, Id, Buffer, IP, Port, Verbose)}; false -> case udp_open(S0, IP) of {ok,S} -> - {S,case query_udp(S, Id, Buffer, IP, Port, Timer, - Retry, I, Tm, Verbose) of - {ok,#dns_rec{header=H}} when H#dns_header.tc -> - query_tcp(Tm, Id, Buffer, - IP, Port, Timer, Verbose); - Reply -> Reply - end}; + Timeout = + inet:timeout( (Tm * (1 bsl I)) div Retry, Timer), + {S, + case query_udp( + S, Id, Buffer, IP, Port, Timeout, Verbose) of + {ok,#dns_rec{header=H}} when H#dns_header.tc -> + TcpTimeout = inet:timeout(Tm*5, Timer), + query_tcp( + TcpTimeout, Id, Buffer, IP, Port, Verbose); + Reply -> Reply + end}; Error -> {S0,Error} end end. -query_udp(S, Id, Buffer, IP, Port, Timer, Retry, I, Tm, Verbose) -> - Timeout = inet:timeout( (Tm * (1 bsl I)) div Retry, Timer), +query_udp(_S, _Id, _Buffer, _IP, _Port, 0, Verbose) -> + timeout; +query_udp(S, Id, Buffer, IP, Port, Timeout, Verbose) -> ?verbose(Verbose, "Try UDP server : ~p:~p (timeout=~w)\n", - [IP, Port, Timeout]), - udp_connect(S, IP, Port), - udp_send(S, IP, Port, Buffer), - query_udp_recv(S, IP, Port, Id, Timeout, Verbose). - -query_udp_recv(S, IP, Port, Id, Timeout, Verbose) -> - case udp_recv(S, IP, Port, Timeout) of - {ok,Answer,T} -> - case decode_answer(Answer, Id, Verbose) of - {error, badid} -> - query_udp_recv(S, IP, Port, Id, T, Verbose); - Reply -> Reply + [IP,Port,Timeout]), + case + case udp_connect(S, IP, Port) of + ok -> + udp_send(S, IP, Port, Buffer); + E1 -> + E1 end of + ok -> + Decode = + fun ({RecIP,RecPort,Answer}) + when RecIP =:= IP, RecPort =:= Port -> + case decode_answer(Answer, Id, Verbose) of + {error,badid} -> + false; + Reply -> + Reply + end; + ({_,_,_}) -> + false + end, + case udp_recv(S, IP, Port, Timeout, Decode) of + {ok,_}=Result -> + Result; + E2 -> + ?verbose(Verbose, "UDP server error: ~p\n", [E2]), + E2 end; - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "UDP server timeout\n", []), - timeout; - Error -> - ?verbose(Verbose, "UDP server error: ~p\n", [Error]), - Error + E3 -> + ?verbose(Verbose, "UDP send failed: ~p\n", [E3]), + {error,econnrefused} end. -query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose) -> - Timeout = inet:timeout(Tm*5, Timer), +query_tcp(0, _Id, _Buffer, _IP, _Port, Verbose) -> + timeout; +query_tcp(Timeout, Id, Buffer, IP, Port, Verbose) -> ?verbose(Verbose, "Try TCP server : ~p:~p (timeout=~w)\n", [IP, Port, Timeout]), Family = case IP of @@ -716,19 +758,10 @@ query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose) -> end; Error -> gen_tcp:close(S), - case Error of - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "TCP server recv timeout\n", []), - timeout; - _ -> - ?verbose(Verbose, "TCP server recv error: ~p\n", - [Error]), - Error - end + ?verbose(Verbose, "TCP server recv error: ~p\n", + [Error]), + Error end; - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "TCP server connect timeout\n", []), - timeout; Error -> ?verbose(Verbose, "TCP server error: ~p\n", [Error]), Error diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index f5e2820bbe..5228d4fe01 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. 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 @@ -322,24 +322,19 @@ init({Name, LongOrShortNames, TickT}) -> process_flag(priority, max), Ticktime = to_integer(TickT), Ticker = spawn_link(net_kernel, ticker, [self(), Ticktime]), - case auth:get_cookie(Node) of - Cookie when is_atom(Cookie) -> - {ok, #state{name = Name, - node = Node, - type = LongOrShortNames, - tick = #tick{ticker = Ticker, time = Ticktime}, - connecttime = connecttime(), - connections = - ets:new(sys_dist,[named_table, - protected, - {keypos, 2}]), - listen = Listeners, - allowed = [], - verbose = 0 - }}; - _ELSE -> - {stop, {error,{bad_cookie, Node}}} - end; + {ok, #state{name = Name, + node = Node, + type = LongOrShortNames, + tick = #tick{ticker = Ticker, time = Ticktime}, + connecttime = connecttime(), + connections = + ets:new(sys_dist,[named_table, + protected, + {keypos, 2}]), + listen = Listeners, + allowed = [], + verbose = 0 + }}; Error -> {stop, Error} end. @@ -1254,7 +1249,7 @@ protocol_childspecs([H|T]) -> epmd_module() -> case init:get_argument(epmd_module) of {ok,[[Module]]} -> - Module; + list_to_atom(Module); _ -> erl_epmd end. diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index 75a11a8afd..d1feae771d 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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,8 +82,9 @@ verify_executable(Name0, [Ext|Rest], OrigExtensions) -> end; _ -> case file:read_file_info(Name1) of - {ok, #file_info{mode=Mode}} when Mode band 8#111 =/= 0 -> - %% XXX This test for execution permission is not full-proof + {ok, #file_info{type=regular,mode=Mode}} + when Mode band 8#111 =/= 0 -> + %% XXX This test for execution permission is not fool-proof %% on Unix, since we test if any execution bit is set. {ok, Name1}; _ -> @@ -136,7 +137,7 @@ reverse_element([$"|T]) -> %" reverse_element(List) -> lists:reverse(List). --spec extensions() -> [string()]. +-spec extensions() -> [string(),...]. %% Extensions in lower case extensions() -> case type() of @@ -230,9 +231,13 @@ start_port_srv(Request) -> catch error:_ -> false end, - start_port_srv_loop(Request, StayAlive). + start_port_srv_handle(Request), + case StayAlive of + true -> start_port_srv_loop(); + false -> exiting + end. -start_port_srv_loop({Ref,Client}, StayAlive) -> +start_port_srv_handle({Ref,Client}) -> Reply = try open_port({spawn, ?SHELL},[stream]) of Port when is_port(Port) -> (catch port_connect(Port, Client)), @@ -242,20 +247,18 @@ start_port_srv_loop({Ref,Client}, StayAlive) -> error:Reason -> {Reason,erlang:get_stacktrace()} end, - Client ! {Ref,Reply}, - case StayAlive of - true -> start_port_srv_loop(get_open_port_request(), true); - false -> exiting - end. + Client ! {Ref,Reply}. -get_open_port_request() -> + +start_port_srv_loop() -> receive {Ref, Client} = Request when is_reference(Ref), is_pid(Client) -> - Request; + start_port_srv_handle(Request); _Junk -> - get_open_port_request() - end. + ignore + end, + start_port_srv_loop(). %% %% unix_get_data(Port) -> Result |