aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/doc/src/application.xml2
-rw-r--r--lib/kernel/doc/src/error_handler.xml15
-rw-r--r--lib/kernel/doc/src/global.xml2
-rw-r--r--lib/kernel/doc/src/inet.xml2
-rw-r--r--lib/kernel/doc/src/ref_man.xml2
-rw-r--r--lib/kernel/include/dist.hrl3
-rw-r--r--lib/kernel/internal_doc/distribution_handshake.txt216
-rw-r--r--lib/kernel/src/Makefile4
-rw-r--r--lib/kernel/src/application.erl2
-rw-r--r--lib/kernel/src/application_controller.erl71
-rw-r--r--lib/kernel/src/auth.erl4
-rw-r--r--lib/kernel/src/code.erl6
-rw-r--r--lib/kernel/src/code_server.erl6
-rw-r--r--lib/kernel/src/disk_log.erl48
-rw-r--r--lib/kernel/src/disk_log_1.erl8
-rw-r--r--lib/kernel/src/dist_util.erl5
-rw-r--r--lib/kernel/src/error_handler.erl2
-rw-r--r--lib/kernel/src/file.erl8
-rw-r--r--lib/kernel/src/group.erl147
-rw-r--r--lib/kernel/src/inet_config.erl37
-rw-r--r--lib/kernel/src/inet_parse.erl4
-rw-r--r--lib/kernel/src/kernel.app.src2
-rw-r--r--lib/kernel/src/kernel_config.erl4
-rw-r--r--lib/kernel/src/net_kernel.erl10
-rw-r--r--lib/kernel/src/os.erl4
-rw-r--r--lib/kernel/src/user.erl172
-rw-r--r--lib/kernel/src/user_drv.erl4
-rw-r--r--lib/kernel/test/Makefile2
-rw-r--r--lib/kernel/test/application_SUITE.erl2
-rw-r--r--lib/kernel/test/file_SUITE.erl61
-rw-r--r--lib/kernel/test/gen_tcp_echo_SUITE.erl2
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl72
-rw-r--r--lib/kernel/test/ignore_cores.erl2
-rw-r--r--lib/kernel/test/inet_SUITE.erl2
-rw-r--r--lib/kernel/test/os_SUITE.erl2
-rw-r--r--lib/kernel/test/pdict_SUITE.erl2
36 files changed, 534 insertions, 403 deletions
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 9f19efc793..697de6681f 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/error_handler.xml b/lib/kernel/doc/src/error_handler.xml
index 610b65f0a2..84ec3927c8 100644
--- a/lib/kernel/doc/src/error_handler.xml
+++ b/lib/kernel/doc/src/error_handler.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1996</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -62,6 +62,19 @@
<c>'$handle_undefined_function'(</c><anno>Function</anno>,
<anno>Args</anno>).
</p>
+ <warning>
+ <p>Defining <c>'$handle_undefined_function'/2</c> in
+ ordinary application code is highly discouraged. It is very
+ easy to make subtle errors that can take a long time to
+ debug. Furthermore, none of the tools for static code
+ analysis (such as Dialyzer and Xref) supports the use of
+ <c>'$handle_undefined_function'/2</c> and no such support
+ will be added. Only use this function after having carefully
+ considered other, less dangerous, solutions. One example of
+ potential legitimate use is creating stubs for other
+ sub-systems during testing and debugging.
+ </p>
+ </warning>
<p>Otherwise an <c>undef</c> exception will be raised.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml
index 9c50049503..53958c47c2 100644
--- a/lib/kernel/doc/src/global.xml
+++ b/lib/kernel/doc/src/global.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 3d929a772e..541500a300 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2012</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml
index 67d91ba585..96604a2fa2 100644
--- a/lib/kernel/doc/src/ref_man.xml
+++ b/lib/kernel/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/include/dist.hrl b/lib/kernel/include/dist.hrl
index 5b52f6f294..e32c112e63 100644
--- a/lib/kernel/include/dist.hrl
+++ b/lib/kernel/include/dist.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. 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
@@ -36,3 +36,4 @@
-define(DFLAG_UNICODE_IO,16#1000).
-define(DFLAG_DIST_HDR_ATOM_CACHE,16#2000).
-define(DFLAG_SMALL_ATOM_TAGS, 16#4000).
+-define(DFLAG_UTF8_ATOMS, 16#10000).
diff --git a/lib/kernel/internal_doc/distribution_handshake.txt b/lib/kernel/internal_doc/distribution_handshake.txt
index 6a3ee22ed3..d00c4ceb02 100644
--- a/lib/kernel/internal_doc/distribution_handshake.txt
+++ b/lib/kernel/internal_doc/distribution_handshake.txt
@@ -1,215 +1 @@
-HOW THE DISTRIBUTION HANDSHAKE WORKS
-------------------------------------
-
-This document describes the distribution handshake introduced in
-the R6 release of Erlang/OTP.
-
-GENERAL
--------
-
-The TCP/IP distribution uses a handshake which expects a
-connection based protocol, i.e. the protocol does not include
-any authentication after the handshake procedure.
-
-This is not entirely safe, as it is vulnerable against takeover
-attacks, but it is a tradeoff between fair safety and performance.
-
-The cookies are never sent in cleartext and the handshake procedure
-expects the client (called A) to be the first one to prove that it can
-generate a sufficient digest. The digest is generated with the
-MD5 message digest algorithm and the challenges are expected to be very
-random numbers.
-
-DEFINITIONS
------------
-
-A challenge is a 32 bit integer number in big endian order. Below the function
-gen_challenge() returns a random 32 bit integer used as a challenge.
-
-A digest is a (16 bytes) MD5 hash of [the Challenge (as text) concatenated
-with the cookie (as text)]. Below, the function gen_digest(Challenge, Cookie)
-generates a digest as described above.
-
-An out_cookie is the cookie used in outgoing communication to a certain node,
-so that A's out_cookie for B should correspond with B's in_cookie for A and
-the other way around. A's out_cookie for B and A's in_cookie for B need *NOT*
-be the same. Below the function out_cookie(Node) returns the current
-node's out_cookie for Node.
-
-An in_cookie is the cookie expected to be used by another node when
-communicating with us, so that A's in_cookie for B corresponds with B's
-out_cookie for A. Below the function in_cookie(Node) returns the current
-node's in_cookie for Node.
-
-The cookies are text strings that can be viewed as passwords.
-
-Every message in the handshake starts with a 16 bit big endian integer
-which contains the length of the message (not counting the two initial bytes).
-In erlang this corresponds to the gen_tcp option {packet, 2}. Note that after
-the handshake, the distribution switches to 4 byte packet headers.
-
-THE HANDSHAKE IN DETAIL
------------------------
-
-Imagine two nodes, node A, which initiates the handshake and node B, which
-accepts the connection.
-
-1) connect/accept: A connects to B via TCP/IP and B accepts the connection.
-
-2) send_name/receive_name: A sends an initial identification to B.
-B receives the message. The message looks
-like this (every "square" being one byte and the packet header removed):
-
-+---+--------+--------+-----+-----+-----+-----+-----+-----+-...-+-----+
-|'n'|Version0|Version1|Flag0|Flag1|Flag2|Flag3|Name0|Name1| ... |NameN|
-+---+--------+--------+-----+-----+-----+-----+-----+-----+-... +-----+
-
-The 'n' is just a message tag,
-Version0 & Version1 is the distribution version selected by node A,
- based on information from EPMD. (16 bit big endian)
-Flag0 ... Flag3 are capability flags, the capabilities defined in dist.hrl.
- (32 bit big endian)
-Name0 ... NameN is the full nodename of A, as a string of bytes (the
- packet length denotes how long it is).
-
-3) recv_status/send_status: B sends a status message to A, which indicates
-if the connection is allowed. Four different status codes are defined:
-ok: The handshake will continue.
-ok_simultaneous: The handshake will continue, but A is informed that B
- has another ongoing connection attempt that will be
- shut down (simultaneous connect where A's name is
- greater than B's name, compared literally),
-nok: The handshake will not continue, as B already has an ongoing handshake
- which it itself has initiated. (simultaneous connect where B's name is
- greater than A's)
-not_allowed: The connection is disallowed for some (unspecified) security
- reason.
-alive: A connection to the node is already active, which either means
- that node A is confused or that the TCP connection breakdown
- of a previous node with this name has not yet reached node B.
- See 3B below.
-
-This is the format of the status message:
-
-+---+-------+-------+-...-+-------+
-|'s'|Status0|Status1| ... |StatusN|
-+---+-------+-------+-...-+-------+
-
-'s' is the message tag
-Status0 ... StatusN is the status as a string (not terminated)
-
-3B) send_status/recv_status: If status was 'alive', node A will answer with
-another status message containing either 'true' which means that the
-connection should continue (The old connection from this node is broken), or
-'false', which simply means that the connection should be closed, the
-connection attempt was a mistake.
-
-4) recv_challenge/send_challenge: If the status was 'ok' or 'ok_simultaneous',
-The handshake continues with B sending A another message, the challenge.
-The challenge contains the same type of information as the "name" message
-initially sent from A to B, with the addition of a 32 bit challenge:
-
-+---+--------+--------+-----+-----+-----+-----+-----+-----+-----+-----+---
-|'n'|Version0|Version1|Flag0|Flag1|Flag2|Flag3|Chal0|Chal1|Chal2|Chal3|
-+---+--------+--------+-----+-----+-----+-----+-----+-----+-----+-----+---
- ------+-----+-...-+-----+
- Name0|Name1| ... |NameN|
- ------+-----+-... +-----+
-
-Where Chal0 ... Chal3 is the challenge as a 32 bit big endian integer
-and the other fields are B's version, flags and full nodename.
-
-5) send_challenge_reply/recv_challenge_reply: Now A has generated
-a digest and its own challenge. Those are sent together in a package
-to B:
-
-+---+-----+-----+-----+-----+-----+-----+-----+-----+-...-+------+
-|'r'|Chal0|Chal1|Chal2|Chal3|Dige0|Dige1|Dige2|Dige3| ... |Dige15|
-+---+-----+-----+-----+-----+-----+-----+-----+-----+-...-+------+
-
-Where 'r' is the tag, Chal0 ... Chal3 is A's challenge for B to handle and
-Dige0 ... Dige15 is the digest that A constructed from the challenge B sent
-in the previous step.
-
-6) recv_challenge_ack/send_challenge_ack: B checks that the digest received
-from A is correct and generates a digest from the challenge received from
-A. The digest is then sent to A. The message looks like this:
-
-+---+-----+-----+-----+-----+-...-+------+
-|'a'|Dige0|Dige1|Dige2|Dige3| ... |Dige15|
-+---+-----+-----+-----+-----+-...-+------+
-
-Where 'a' is the tag and Dige0 ... Dige15 is the digest calculated by B
-for A's challenge.
-
-7) A checks the digest from B and the connection is up.
-
-SEMIGRAPHIC VIEW
-----------------
-
-A (initiator) B (acceptor)
-
-TCP connect ----------------------------------------->
- TCP accept
-
-send_name ----------------------------------------->
- recv_name
-
- <---------------------------------------- send_status
-recv_status
-(if status was 'alive'
- send_status - - - - - - - - - - - - - - - - - - - ->
- recv_status)
- ChB = gen_challenge()
- (ChB)
- <---------------------------------------- send_challenge
-recv_challenge
-
-ChA = gen_challenge(),
-OCA = out_cookie(B),
-DiA = gen_digest(ChB,OCA)
- (ChA, DiA)
-send_challenge_reply -------------------------------->
- recv_challenge_reply
- ICB = in_cookie(A),
- check:
- DiA == gen_digest
- (ChB, ICB) ?
- - if OK:
- OCB = out_cookie(A),
- DiB = gen_digest
- (DiB) (ChA, OCB)
- <----------------------------------------- send_challenge_ack
-recv_challenge_ack DONE
-ICA = in_cookie(B), - else
-check: CLOSE
-DiB == gen_digest(ChA,ICA) ?
-- if OK
- DONE
-- else
- CLOSE
-
-
-THE CURRENTLY DEFINED FLAGS
----------------------------
-Currently the following capability flags are defined:
-
-%% The node should be published and part of the global namespace
--define(DFLAG_PUBLISHED,1).
-
-%% The node implements an atom cache
--define(DFLAG_ATOM_CACHE,2).
-
-%% The node implements extended (3 * 32 bits) references
--define(DFLAG_EXTENDED_REFERENCES,4).
-
-%% The node implements distributed process monitoring.
--define(DFLAG_DIST_MONITOR,8).
-
-%% The node uses separate tag for fun's (lambdas) in the distribution protocol.
--define(DFLAG_FUN_TAGS,16).
-
-An R6 erlang node implements all of the above, while a C or Java node only
-implements DFLAG_EXTENDED_REFERENCES.
-
-Last modified 1999-11-08 -- Patrik Nyblom, OTP
+This information has been moved to the "Distribution Protocol" chapter of "ERTS User's Guide".
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index eaced4861a..cb3c0a49f4 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-2013. 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
@@ -148,7 +148,7 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
endif
-ERL_COMPILE_FLAGS += -I../include
+ERL_COMPILE_FLAGS += -I../include -Werror
# ----------------------------------------------------
# Targets
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index 4e65883be7..6efc1b4499 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 75ce852001..3c860af48e 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -247,7 +247,7 @@ start_boot_application(Application, RestartType) ->
{{error, {already_loaded, AppName}}, _} ->
gen_server:call(?AC, {start_application, AppName, RestartType}, infinity);
{{error,{bad_environment_value,Env}}, permanent} ->
- Txt = io_lib:format("Bad environment variable: ~p Application: ~p",
+ Txt = io_lib:format("Bad environment variable: ~tp Application: ~p",
[Env, Application]),
exit({error, list_to_atom(lists:flatten(Txt))});
{Error, _} ->
@@ -501,13 +501,13 @@ init(Init, Kernel) ->
{local, ?AC})
end;
{error, ErrorStr} ->
- Str = lists:flatten(io_lib:format("invalid config data: ~s", [ErrorStr])),
+ Str = lists:flatten(io_lib:format("invalid config data: ~ts", [ErrorStr])),
Init ! {ack, self(), {error, to_string(Str)}}
end;
{error, {File, Line, Str}} ->
ReasonStr =
lists:flatten(io_lib:format("error in config file "
- "~p (~w): ~s",
+ "~tp (~w): ~ts",
[File, Line, Str])),
Init ! {ack, self(), {error, to_string(ReasonStr)}}
end.
@@ -537,17 +537,17 @@ check_conf_data(ConfData) when is_list(ConfData) ->
end;
{AppName, List} when is_list(List) ->
ErrMsg = "application: "
- ++ lists:flatten(io_lib:format("~p",[AppName]))
+ ++ lists:flatten(io_lib:format("~tp",[AppName]))
++ "; application name must be an atom",
{error, ErrMsg};
{AppName, _List} ->
ErrMsg = "application: "
- ++ lists:flatten(io_lib:format("~p",[AppName]))
+ ++ lists:flatten(io_lib:format("~tp",[AppName]))
++ "; parameters must be a list",
{error, ErrMsg};
Else ->
ErrMsg = "invalid application name: " ++
- lists:flatten(io_lib:format(" ~p",[Else])),
+ lists:flatten(io_lib:format(" ~tp",[Else])),
{error, ErrMsg}
end;
check_conf_data(_ConfData) ->
@@ -570,10 +570,10 @@ check_para_kernel([{Para, _Val} | ParaList]) when is_atom(Para) ->
check_para_kernel(ParaList);
check_para_kernel([{Para, _Val} | _ParaList]) ->
{error, "application: kernel; invalid parameter: " ++
- lists:flatten(io_lib:format("~p",[Para]))};
+ lists:flatten(io_lib:format("~tp",[Para]))};
check_para_kernel(Else) ->
{error, "application: kernel; invalid parameter list: " ++
- lists:flatten(io_lib:format("~p",[Else]))}.
+ lists:flatten(io_lib:format("~tp",[Else]))}.
check_distributed([]) ->
@@ -594,10 +594,10 @@ check_para([{Para, _Val} | ParaList], AppName) when is_atom(Para) ->
check_para(ParaList, AppName);
check_para([{Para, _Val} | _ParaList], AppName) ->
{error, "application: " ++ AppName ++ "; invalid parameter: " ++
- lists:flatten(io_lib:format("~p",[Para]))};
+ lists:flatten(io_lib:format("~tp",[Para]))};
check_para([Else | _ParaList], AppName) ->
{error, "application: " ++ AppName ++ "; invalid parameter: " ++
- lists:flatten(io_lib:format("~p",[Else]))}.
+ lists:flatten(io_lib:format("~tp",[Else]))}.
-type calls() :: 'info' | 'prep_config_change' | 'which_applications'
@@ -1434,7 +1434,9 @@ make_appl(Name) when is_atom(Name) ->
{ok, [Application]} ->
{ok, make_appl_i(Application)};
{error, Reason} ->
- {error, {file:format_error(Reason), FName}}
+ {error, {file:format_error(Reason), FName}};
+ error ->
+ {error, "bad encoding"}
end
end;
make_appl(Application) ->
@@ -1443,12 +1445,17 @@ make_appl(Application) ->
prim_consult(FullName) ->
case erl_prim_loader:get_file(FullName) of
{ok, Bin, _} ->
- case erl_scan:string(binary_to_list(Bin)) of
- {ok, Tokens, _EndLine} ->
- prim_parse(Tokens, []);
- {error, Reason, _EndLine} ->
- {error, Reason}
- end;
+ case file_binary_to_list(Bin) of
+ {ok, String} ->
+ case erl_scan:string(String, 1, [unicode]) of
+ {ok, Tokens, _EndLine} ->
+ prim_parse(Tokens, []);
+ {error, Reason, _EndLine} ->
+ {error, Reason}
+ end;
+ error ->
+ error
+ end;
error ->
{error, enoent}
end.
@@ -1521,7 +1528,7 @@ do_change_apps(Applications, Config, OldAppls) ->
%% Report errors, but do not terminate
%% (backwards compatible behaviour)
lists:foreach(fun({error, {SysFName, Line, Str}}) ->
- Str2 = lists:flatten(io_lib:format("~p: ~w: ~s~n",
+ Str2 = lists:flatten(io_lib:format("~tp: ~w: ~ts~n",
[SysFName, Line, Str])),
error_logger:format(Str2, [])
end,
@@ -1593,18 +1600,18 @@ conv(_) -> [].
%%% Fix some day: eliminate the duplicated code here
make_term(Str) ->
- case erl_scan:string(Str) of
+ case erl_scan:string(Str, 1, [unicode]) of
{ok, Tokens, _} ->
case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of
{ok, Term} ->
Term;
{error, {_,M,Reason}} ->
- error_logger:format("application_controller: ~s: ~s~n",
+ error_logger:format("application_controller: ~ts: ~ts~n",
[M:format_error(Reason), Str]),
throw({error, {bad_environment_value, Str}})
end;
{error, {_,M,Reason}, _} ->
- error_logger:format("application_controller: ~s: ~s~n",
+ error_logger:format("application_controller: ~ts: ~ts~n",
[M:format_error(Reason), Str]),
throw({error, {bad_environment_value, Str}})
end.
@@ -1828,8 +1835,12 @@ load_file(File) ->
{ok, Bin, _FileName} ->
%% Make sure that there is some whitespace at the end of the string
%% (so that reading a file with no NL following the "." will work).
- Str = binary_to_list(Bin) ++ " ",
- scan_file(Str);
+ case file_binary_to_list(Bin) of
+ {ok, String} ->
+ scan_file(String ++ " ");
+ error ->
+ {error, {none, scan_file, "bad encoding"}}
+ end;
error ->
{error, {none, open_file, "configuration file not found"}}
end.
@@ -1947,6 +1958,18 @@ test_make_apps([], Res) ->
test_make_apps([A|Apps], Res) ->
test_make_apps(Apps, [make_appl(A) | Res]).
+file_binary_to_list(Bin) ->
+ Enc = case epp:read_encoding_from_binary(Bin) of
+ none -> epp:default_encoding();
+ Encoding -> Encoding
+ end,
+ case catch unicode:characters_to_list(Bin, Enc) of
+ String when is_list(String) ->
+ {ok, String};
+ _ ->
+ error
+ end.
+
%%-----------------------------------------------------------------
%% String conversion
%% Exit reason needs to be a printable string
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index 6ae786ebd9..1e12a647d7 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -384,7 +384,7 @@ create_cookie(Name) ->
{{error,Reason}, _} ->
{error,
lists:flatten(
- io_lib:format("Failed to write to cookie file '~s': ~p", [Name, Reason]))};
+ io_lib:format("Failed to write to cookie file '~ts': ~p", [Name, Reason]))};
{ok, {error, Reason}} ->
{error, "Failed to change mode: " ++ atom_to_list(Reason)}
end;
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 361f2bdf8a..8a543abd6f 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -511,7 +511,7 @@ search([{Dir, File} | Tail]) ->
false ->
search(Tail);
{Dir2, File} ->
- io:format("** ~s hides ~s~n",
+ io:format("** ~ts hides ~ts~n",
[filename:join(Dir, File),
filename:join(Dir2, File)]),
[clash | search(Tail)]
@@ -528,7 +528,7 @@ decorate([File|Tail], Dir) ->
[{Dir, File} | decorate(Tail, Dir)].
filter(_Ext, Dir, error) ->
- io:format("** Bad path can't read ~s~n", [Dir]), [];
+ io:format("** Bad path can't read ~ts~n", [Dir]), [];
filter(Ext, _, {ok,Files}) ->
filter2(Ext, length(Ext), Files).
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index b2d2c19f78..b770fce887 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. 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
@@ -1266,11 +1266,11 @@ try_load_module_1(File, Mod, Bin, Caller, #state{moddb=Db}=St) ->
{error,on_load} ->
handle_on_load(Mod, File, Caller, St);
{error,What} = Error ->
- error_msg("Loading of ~s failed: ~p\n", [File, What]),
+ error_msg("Loading of ~ts failed: ~p\n", [File, What]),
{reply,Error,St}
end;
Error ->
- error_msg("Native loading of ~s failed: ~p\n",
+ error_msg("Native loading of ~ts failed: ~p\n",
[File,Error]),
{reply,ok,St}
end
diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl
index 1513fdaec0..0c5af2857e 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
@@ -1527,48 +1527,48 @@ do_format_error({size_mismatch, OldSize, ArgSize}) ->
io_lib:format("The given size ~p does not match the size ~p found on "
"the disk log size file~n", [ArgSize, OldSize]);
do_format_error({read_only_mode, Log}) ->
- io_lib:format("The disk log ~p has been opened read-only, but the "
+ io_lib:format("The disk log ~tp has been opened read-only, but the "
"requested operation needs read-write access~n", [Log]);
do_format_error({format_external, Log}) ->
io_lib:format("The requested operation can only be applied on internally "
- "formatted disk logs, but ~p is externally formatted~n",
+ "formatted disk logs, but ~tp is externally formatted~n",
[Log]);
do_format_error({blocked_log, Log}) ->
- io_lib:format("The blocked disk log ~p does not queue requests, or "
+ io_lib:format("The blocked disk log ~tp does not queue requests, or "
"the log has been blocked by the calling process~n", [Log]);
do_format_error({full, Log}) ->
- io_lib:format("The halt log ~p is full~n", [Log]);
+ io_lib:format("The halt log ~tp is full~n", [Log]);
do_format_error({not_blocked, Log}) ->
- io_lib:format("The disk log ~p is not blocked~n", [Log]);
+ io_lib:format("The disk log ~tp is not blocked~n", [Log]);
do_format_error({not_owner, Pid}) ->
- io_lib:format("The pid ~p is not an owner of the disk log~n", [Pid]);
+ io_lib:format("The pid ~tp is not an owner of the disk log~n", [Pid]);
do_format_error({not_blocked_by_pid, Log}) ->
- io_lib:format("The disk log ~p is blocked, but only the blocking pid "
+ io_lib:format("The disk log ~tp is blocked, but only the blocking pid "
"can unblock a disk log~n", [Log]);
do_format_error({new_size_too_small, Log, CurrentSize}) ->
- io_lib:format("The current size ~p of the halt log ~p is greater than the "
+ io_lib:format("The current size ~p of the halt log ~tp is greater than the "
"requested new size~n", [CurrentSize, Log]);
do_format_error({halt_log, Log}) ->
- io_lib:format("The halt log ~p cannot be wrapped~n", [Log]);
+ io_lib:format("The halt log ~tp cannot be wrapped~n", [Log]);
do_format_error({same_file_name, Log}) ->
- io_lib:format("Current and new file name of the disk log ~p "
+ io_lib:format("Current and new file name of the disk log ~tp "
"are the same~n", [Log]);
do_format_error({arg_mismatch, Option, FirstValue, ArgValue}) ->
- io_lib:format("The value ~p of the disk log option ~p does not match "
- "the current value ~p~n", [ArgValue, Option, FirstValue]);
+ io_lib:format("The value ~tp of the disk log option ~p does not match "
+ "the current value ~tp~n", [ArgValue, Option, FirstValue]);
do_format_error({name_already_open, Log}) ->
- io_lib:format("The disk log ~p has already opened another file~n", [Log]);
+ io_lib:format("The disk log ~tp has already opened another file~n", [Log]);
do_format_error({node_already_open, Log}) ->
- io_lib:format("The distribution option of the disk log ~p does not match "
+ io_lib:format("The distribution option of the disk log ~tp does not match "
"already open log~n", [Log]);
do_format_error({open_read_write, Log}) ->
- io_lib:format("The disk log ~p has already been opened read-write~n",
+ io_lib:format("The disk log ~tp has already been opened read-write~n",
[Log]);
do_format_error({open_read_only, Log}) ->
- io_lib:format("The disk log ~p has already been opened read-only~n",
+ io_lib:format("The disk log ~tp has already been opened read-only~n",
[Log]);
do_format_error({not_internal_wrap, Log}) ->
- io_lib:format("The requested operation cannot be applied since ~p is not "
+ io_lib:format("The requested operation cannot be applied since ~tp is not "
"an internally formatted disk log~n", [Log]);
do_format_error(no_such_log) ->
io_lib:format("There is no disk log with the given name~n", []);
@@ -1579,13 +1579,13 @@ do_format_error(nodedown) ->
io_lib:format("There seems to be no node up that can handle "
"the request~n", []);
do_format_error({corrupt_log_file, FileName}) ->
- io_lib:format("The disk log file \"~s\" contains corrupt data~n",
+ io_lib:format("The disk log file \"~ts\" contains corrupt data~n",
[FileName]);
do_format_error({need_repair, FileName}) ->
- io_lib:format("The disk log file \"~s\" has not been closed properly and "
+ io_lib:format("The disk log file \"~ts\" has not been closed properly and "
"needs repair~n", [FileName]);
do_format_error({not_a_log_file, FileName}) ->
- io_lib:format("The file \"~s\" is not a wrap log file~n", [FileName]);
+ io_lib:format("The file \"~ts\" is not a wrap log file~n", [FileName]);
do_format_error({invalid_header, InvalidHeader}) ->
io_lib:format("The disk log header is not wellformed: ~p~n",
[InvalidHeader]);
@@ -1593,14 +1593,14 @@ do_format_error(end_of_log) ->
io_lib:format("An attempt was made to step outside a not yet "
"full wrap log~n", []);
do_format_error({invalid_index_file, FileName}) ->
- io_lib:format("The wrap log index file \"~s\" cannot be used~n",
+ io_lib:format("The wrap log index file \"~ts\" cannot be used~n",
[FileName]);
do_format_error({no_continuation, BadCont}) ->
io_lib:format("The term ~p is not a chunk continuation~n", [BadCont]);
do_format_error({file_error, FileName, Reason}) ->
- io_lib:format("\"~s\": ~p~n", [FileName, file:format_error(Reason)]);
+ io_lib:format("\"~ts\": ~tp~n", [FileName, file:format_error(Reason)]);
do_format_error(E) ->
- io_lib:format("~p~n", [E]).
+ io_lib:format("~tp~n", [E]).
do_info(L, Cnt) ->
#log{name = Name, type = Type, mode = Mode, filename = File,
diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl
index 0cb1ed579a..9d431bdd30 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-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
@@ -489,7 +489,7 @@ lh(H, _F) -> % cannot happen
repair(In, File) ->
FSz = file_size(File),
- error_logger:info_msg("disk_log: repairing ~p ...\n", [File]),
+ error_logger:info_msg("disk_log: repairing ~tp ...\n", [File]),
Tmp = add_ext(File, "TMP"),
{ok, {_Alloc, Out, {0, _}, _FileSize}} = new_int_file(Tmp, none),
scan_f_read(<<>>, In, Out, File, FSz, Tmp, ?MAX_CHUNK_SIZE, 0, 0).
@@ -758,7 +758,7 @@ mf_int_chunk(Handle, {FileNo, Pos}, Bin, N) ->
NFileNo = inc(FileNo, Handle#handle.maxF),
case catch int_open(FName, true, read_only, any) of
{error, _Reason} ->
- error_logger:info_msg("disk_log: chunk error. File ~p missing.\n\n",
+ error_logger:info_msg("disk_log: chunk error. File ~tp missing.\n\n",
[FName]),
mf_int_chunk(Handle, {NFileNo, 0}, [], N);
{ok, {_Alloc, FdC, _HeadSize, _FileSize}} ->
@@ -786,7 +786,7 @@ mf_int_chunk_read_only(Handle, {FileNo, Pos}, Bin, N) ->
NFileNo = inc(FileNo, Handle#handle.maxF),
case catch int_open(FName, true, read_only, any) of
{error, _Reason} ->
- error_logger:info_msg("disk_log: chunk error. File ~p missing.\n\n",
+ error_logger:info_msg("disk_log: chunk error. File ~tp missing.\n\n",
[FName]),
mf_int_chunk_read_only(Handle, {NFileNo, 0}, [], N);
{ok, {_Alloc, FdC, _HeadSize, _FileSize}} ->
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index e3511988a6..fc50ec6717 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. 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
@@ -115,7 +115,8 @@ make_this_flags(RequestType, OtherNode) ->
?DFLAG_NEW_FLOATS bor
?DFLAG_UNICODE_IO bor
?DFLAG_DIST_HDR_ATOM_CACHE bor
- ?DFLAG_SMALL_ATOM_TAGS).
+ ?DFLAG_SMALL_ATOM_TAGS bor
+ ?DFLAG_UTF8_ATOMS).
handshake_other_started(#hs_data{request_type=ReqType}=HSData0) ->
{PreOtherFlags,Node,Version} = recv_name(HSData0),
diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index a3aa1f1dcf..40aabba803 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 16f2dde464..70c4583ad2 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -148,7 +148,7 @@ format_error({Line, ?MODULE, {Reason, Stacktrace}}) ->
io_lib:format("~w: evaluation failed with reason ~w and stacktrace ~w",
[Line, Reason, Stacktrace]);
format_error({Line, Mod, Reason}) ->
- io_lib:format("~w: ~s", [Line, Mod:format_error(Reason)]);
+ io_lib:format("~w: ~ts", [Line, Mod:format_error(Reason)]);
format_error(badarg) ->
"bad argument";
format_error(system_limit) ->
@@ -591,7 +591,7 @@ pread(_, _, _) ->
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});
+ io:request(File, {put_chars,latin1,Bin});
Error ->
Error
end;
@@ -1345,7 +1345,7 @@ eval_stream(Fd, Handling, Bs) ->
eval_stream(Fd, Handling, 1, undefined, [], Bs).
eval_stream(Fd, H, Line, Last, E, Bs) ->
- eval_stream2(io:parse_erl_exprs(Fd, '', Line), Fd, H, Last, E, Bs).
+ eval_stream2(io:parse_erl_exprs(Fd, '', Line, [unicode]), Fd, H, Last, E, Bs).
eval_stream2({ok,Form,EndLine}, Fd, H, Last, E, Bs0) ->
try erl_eval:exprs(Form, Bs0) of
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index 4d2e31a429..ff835e1047 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -227,7 +227,7 @@ io_request({put_chars,latin1,Chars}, Drv, Buf) ->
send_drv(Drv, {put_chars, unicode,Binary}),
{ok,ok,Buf};
_ ->
- {error,{error,{put_chars,Chars}},Buf}
+ {error,{error,{put_chars,latin1,Chars}},Buf}
end;
io_request({put_chars,latin1,M,F,As}, Drv, Buf) ->
case catch apply(M, F, As) of
@@ -446,7 +446,6 @@ get_chars_loop(Pbs, M, F, Xa, Drv, Buf0, State, Encoding) ->
end.
get_chars_apply(Pbs, M, F, Xa, Drv, Buf, State0, Line, Encoding) ->
- id(M,F),
case catch M:F(State0, cast(Line,get(read_mode), Encoding), Encoding, Xa) of
{stop,Result,Rest} ->
{ok,Result,append(Rest, Buf, Encoding)};
@@ -456,8 +455,6 @@ get_chars_apply(Pbs, M, F, Xa, Drv, Buf, State0, Line, Encoding) ->
get_chars_loop(Pbs, M, F, Xa, Drv, Buf, State1, Encoding)
end.
-id(M,F) ->
- {M,F}.
%% Convert error code to make it look as before
err_func(io_lib, get_until, {_,F,_}) ->
F;
@@ -515,6 +512,27 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
Drv,
Ls, Encoding)
end;
+%% ^R = backward search, ^S = forward search.
+%% Search is tricky to implement and does a lot of back-and-forth
+%% work with edlin.erl (from stdlib). Edlin takes care of writing
+%% and handling lines and escape characters to get out of search,
+%% whereas this module does the actual searching and appending to lines.
+%% Erlang's shell wasn't exactly meant to traverse the wall between
+%% line and line stack, so we at least restrict it by introducing
+%% new modes: search, search_quit, search_found. These are added to
+%% the regular ones (none, meta_left_sq_bracket) and handle special
+%% cases of history search.
+get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls, Encoding)
+ when ((Mode =:= none) and (Char =:= $\^R)) ->
+ send_drv_reqs(Drv, Rs),
+ %% drop current line, move to search mode. We store the current
+ %% prompt ('N>') and substitute it with the search prompt.
+ send_drv_reqs(Drv, edlin:erase_line(Cont)),
+ put(search_quit_prompt, edlin:prompt(Cont)),
+ Pbs = prompt_bytes("(search)`': ", Encoding),
+ {more_chars,Ncont,Nrs} = edlin:start(Pbs, search),
+ send_drv_reqs(Drv, Nrs),
+ get_line1(edlin:edit_line1(Cs, Ncont), Drv, Ls, Encoding);
get_line1({expand, Before, Cs0, Cont,Rs}, Drv, Ls0, Encoding) ->
send_drv_reqs(Drv, Rs),
ExpandFun = get(expand_fun),
@@ -535,8 +553,59 @@ get_line1({undefined,_Char,Cs,Cont,Rs}, Drv, Ls, Encoding) ->
send_drv_reqs(Drv, Rs),
send_drv(Drv, beep),
get_line1(edlin:edit_line(Cs, Cont), Drv, Ls, Encoding);
+%% The search item was found and accepted (new line entered on the exact
+%% result found)
+get_line1({_What,Cont={line,_Prompt,_Chars,search_found},Rs}, Drv, Ls0, Encoding) ->
+ Line = edlin:current_line(Cont),
+ %% this may create duplicate entries.
+ Ls = save_line(new_stack(get_lines(Ls0)), Line),
+ get_line1({done, Line, "", Rs}, Drv, Ls, Encoding);
+%% The search mode has been exited, but the user wants to remain in line
+%% editing mode wherever that was, but editing the search result.
+get_line1({What,Cont={line,_Prompt,_Chars,search_quit},Rs}, Drv, Ls, Encoding) ->
+ Line = edlin:current_chars(Cont),
+ %% Load back the old prompt with the correct line number.
+ case get(search_quit_prompt) of
+ undefined -> % should not happen. Fallback.
+ LsFallback = save_line(new_stack(get_lines(Ls)), Line),
+ get_line1({done, "\n", Line, Rs}, Drv, LsFallback, Encoding);
+ Prompt -> % redraw the line and keep going with the same stack position
+ NCont = {line,Prompt,{lists:reverse(Line),[]},none},
+ send_drv_reqs(Drv, Rs),
+ send_drv_reqs(Drv, edlin:erase_line(Cont)),
+ send_drv_reqs(Drv, edlin:redraw_line(NCont)),
+ get_line1({What, NCont ,[]}, Drv, pad_stack(Ls), Encoding)
+ end;
+%% Search mode is entered.
+get_line1({What,{line,Prompt,{RevCmd0,_Aft},search},Rs},
+ Drv, Ls0, Encoding) ->
+ send_drv_reqs(Drv, Rs),
+ %% Figure out search direction. ^S and ^R are returned through edlin
+ %% whenever we received a search while being already in search mode.
+ {Search, Ls1, RevCmd} = case RevCmd0 of
+ [$\^S|RevCmd1] ->
+ {fun search_down_stack/2, Ls0, RevCmd1};
+ [$\^R|RevCmd1] ->
+ {fun search_up_stack/2, Ls0, RevCmd1};
+ _ -> % new search, rewind stack for a proper search.
+ {fun search_up_stack/2, new_stack(get_lines(Ls0)), RevCmd0}
+ end,
+ Cmd = lists:reverse(RevCmd),
+ {Ls, NewStack} = case Search(Ls1, Cmd) of
+ {none, Ls2} ->
+ send_drv(Drv, beep),
+ {Ls2, {RevCmd, "': "}};
+ {Line, Ls2} -> % found. Complete the output edlin couldn't have done.
+ send_drv_reqs(Drv, [{put_chars, Encoding, Line}]),
+ {Ls2, {RevCmd, "': "++Line}}
+ end,
+ Cont = {line,Prompt,NewStack,search},
+ more_data(What, Cont, Drv, Ls, Encoding);
get_line1({What,Cont0,Rs}, Drv, Ls, Encoding) ->
send_drv_reqs(Drv, Rs),
+ more_data(What, Cont0, Drv, Ls, Encoding).
+
+more_data(What, Cont0, Drv, Ls, Encoding) ->
receive
{Drv,{data,Cs}} ->
get_line1(edlin:edit_line(Cs, Cont0), Drv, Ls, Encoding);
@@ -557,7 +626,6 @@ get_line1({What,Cont0,Rs}, Drv, Ls, Encoding) ->
get_line1(edlin:edit_line([], Cont0), Drv, Ls, Encoding)
end.
-
get_line_echo_off(Chars, Pbs, Drv) ->
send_drv_reqs(Drv, [{put_chars, unicode,Pbs}]),
get_line_echo_off1(edit_line(Chars,[]), Drv).
@@ -632,12 +700,46 @@ save_line({stack, U, {}, []}, Line) ->
save_line({stack, U, _L, D}, Line) ->
{stack, U, Line, D}.
-get_lines({stack, U, {}, []}) ->
+get_lines(Ls) -> get_all_lines(Ls).
+%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]}).
+
+%% There's a funny behaviour whenever the line stack doesn't have a "\n"
+%% at its end -- get_lines() seemed to work on the assumption it *will* be
+%% there, but the manipulations done with search history do not require it.
+%%
+%% It is an assumption because the function was built with either the full
+%% stack being on the 'Up' side (we're on the new line) where it isn't
+%% stripped. The only other case when it isn't on the 'Up' side is when
+%% someone has used the up/down arrows (or ^P and ^N) to navigate lines,
+%% in which case, a line with only a \n is stored at the end of the stack
+%% (the \n is returned by edlin:current_line/1).
+%%
+%% get_all_lines works the same as get_lines, but only strips the trailing
+%% character if it's a linebreak. Otherwise it's kept the same. This is
+%% because traversing the stack due to search history will *not* insert
+%% said empty line in the stack at the same time as other commands do,
+%% and thus it should not always be stripped unless we know a new line
+%% is the last entry.
+get_all_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]}).
+get_all_lines({stack, U, {}, D}) ->
+ case lists:reverse(D, U) of
+ ["\n"|Lines] -> Lines;
+ Lines -> Lines
+ end;
+get_all_lines({stack, U, L, D}) ->
+ get_all_lines({stack, U, {}, [L|D]}).
+
+%% For the same reason as above, though, we need to expand the stack
+%% in some cases to make sure we play nice with up/down arrows. We need
+%% to insert newlines, but not always.
+pad_stack({stack, U, L, D}) ->
+ {stack, U, L, D++["\n"]}.
save_line_buffer("\n", Lines) ->
save_line_buffer(Lines);
@@ -649,6 +751,27 @@ save_line_buffer(Line, Lines) ->
save_line_buffer(Lines) ->
put(line_buffer, Lines).
+search_up_stack(Stack, Substr) ->
+ case up_stack(Stack) of
+ {none,NewStack} -> {none,NewStack};
+ {L, NewStack} ->
+ case string:str(L, Substr) of
+ 0 -> search_up_stack(NewStack, Substr);
+ _ -> {string:strip(L,right,$\n), NewStack}
+ end
+ end.
+
+search_down_stack(Stack, Substr) ->
+ case down_stack(Stack) of
+ {none,NewStack} -> {none,NewStack};
+ {L, NewStack} ->
+ case string:str(L, Substr) of
+ 0 -> search_down_stack(NewStack, Substr);
+ _ -> {string:strip(L,right,$\n), NewStack}
+ end
+ end.
+
+
%% This is get_line without line editing (except for backspace) and
%% without echo.
get_password_line(Chars, Drv) ->
@@ -687,7 +810,7 @@ edit_password([$\177|Cs],[_|Chars]) ->%% is backspace enough?
edit_password([Char|Cs],Chars) ->
edit_password(Cs,[Char|Chars]).
-%% prompt_bytes(Prompt)
+%% prompt_bytes(Prompt, Encoding)
%% Return a flat list of characters for the Prompt.
prompt_bytes(Prompt, Encoding) ->
lists:flatten(io_lib:format_prompt(Prompt, Encoding)).
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 526baca335..2461f3ff25 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
@@ -104,7 +104,7 @@ init() ->
%% Add inetrc config entries
case inet_db:add_rc_list(CfgList) of
ok -> ok;
- _ -> error("syntax error in ~s~n", [RcFile])
+ _ -> error("syntax error in ~ts~n", [RcFile])
end,
%% Set up a resolver configuration file for inet_res,
@@ -266,10 +266,10 @@ load_resolv(File, Func) ->
{ok, Ls} ->
inet_db:add_rc_list(Ls);
{error, Reason} ->
- error("parse error in file ~s: ~p", [File, Reason])
+ error("parse error in file ~ts: ~p", [File, Reason])
end;
Error ->
- warning("file not found ~s: ~p~n", [File, Error])
+ warning("file not found ~ts: ~p~n", [File, Error])
end.
%%
@@ -285,12 +285,12 @@ load_hosts(File,Os) ->
inet_db:add_host(IP, [Name|Aliases]) end,
Ls);
{error, Reason} ->
- error("parse error in file ~s: ~p", [File, Reason])
+ error("parse error in file ~ts: ~p", [File, Reason])
end;
Error ->
case Os of
unix ->
- error("file not found ~s: ~p~n", [File, Error]);
+ error("file not found ~ts: ~p~n", [File, Error]);
_ ->
%% for windows or nt the hosts file is not always there
%% and we don't require it
@@ -462,11 +462,11 @@ get_rc(File) ->
{ok,Ls} ->
Ls;
_Error ->
- error("parse error in ~s~n", [File]),
+ error("parse error in ~ts~n", [File]),
error
end;
_Error ->
- error("file ~s not found~n", [File]),
+ error("file ~ts not found~n", [File]),
error
end.
@@ -495,8 +495,12 @@ warning(Fmt, Args) ->
%% Ignore leading whitespace before a token (due to bug in erl_scan) !
%%
parse_inetrc(Bin) ->
- Str = binary_to_list(Bin) ++ "\n",
- parse_inetrc(Str, 1, []).
+ case file_binary_to_list(Bin) of
+ {ok, String} ->
+ parse_inetrc(String ++ "\n", 1, []);
+ error ->
+ {error, 'bad_encoding'}
+ end.
parse_inetrc_skip_line([], _Line, Ack) ->
{ok, reverse(Ack)};
@@ -535,3 +539,16 @@ parse_inetrc(Str, Line, Ack) ->
{more, _} -> %% Bug in erl_scan !!
{error, {'scan_inetrc', {eof, Line}}}
end.
+
+file_binary_to_list(Bin) ->
+ Enc = case epp:read_encoding_from_binary(Bin) of
+ none -> epp:default_encoding();
+ Encoding -> Encoding
+ end,
+ case catch unicode:characters_to_list(Bin, Enc) of
+ String when is_list(String) ->
+ {ok, String};
+ _ ->
+ error
+ end.
+
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index 3551e701b6..619c78a6ca 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
@@ -464,7 +464,7 @@ strict_address(Cs) when is_list(Cs) ->
_ ->
ipv6strict_address(Cs)
end;
-strict_address(Cs) ->
+strict_address(_) ->
{error, einval}.
%%
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 9a20baf8d0..cb8c98ab06 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
diff --git a/lib/kernel/src/kernel_config.erl b/lib/kernel/src/kernel_config.erl
index b1daf655c9..48141cfa03 100644
--- a/lib/kernel/src/kernel_config.erl
+++ b/lib/kernel/src/kernel_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -93,7 +93,7 @@ code_change(_OldVsn, State, _Extra) ->
sync_nodes() ->
case catch get_sync_data() of
{error, Reason} = Error ->
- error_logger:format("~p", [Reason]),
+ error_logger:format("~tp", [Reason]),
Error;
{infinity, MandatoryNodes, OptionalNodes} ->
case wait_nodes(MandatoryNodes, OptionalNodes) of
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index 0d59e7af67..dd0071b914 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -1340,20 +1340,20 @@ start_protos(Name, [Proto | Ps], Node, Ls) ->
start_protos(Name, Ps, Node, Ls)
end;
{'EXIT', {undef,_}} ->
- error_logger:info_msg("Protocol: ~p: not supported~n", [Proto]),
+ error_logger:info_msg("Protocol: ~tp: 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: ~tp: register error: ~tp~n",
[Proto, Reason]),
start_protos(Name,Ps, Node, Ls);
{error, duplicate_name} ->
- error_logger:info_msg("Protocol: ~p: the name " ++
+ error_logger:info_msg("Protocol: ~tp: the name " ++
atom_to_list(Node) ++
" seems to be in use by another Erlang node",
[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: ~tp: register/listen error: ~tp~n",
[Proto, Reason]),
start_protos(Name,Ps, Node, Ls)
end;
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index e20a2434b4..742c000cc1 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
@@ -334,7 +334,7 @@ mk_cmd(Cmd) when is_atom(Cmd) -> % backward comp.
mk_cmd(Cmd) ->
%% We insert a new line after the command, in case the command
%% contains a comment character.
- io_lib:format("(~s\n) </dev/null; echo \"\^D\"\n", [Cmd]).
+ io_lib:format("(~ts\n) </dev/null; echo \"\^D\"\n", [Cmd]).
validate(Atom) when is_atom(Atom) ->
diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl
index d6449d9e5e..c897d46bc2 100644
--- a/lib/kernel/src/user.erl
+++ b/lib/kernel/src/user.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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,7 +17,7 @@
%% %CopyrightEnd%
%%
-module(user).
--compile( [ inline, { inline_size, 100 } ] ).
+-compile(inline).
%% Basic standard i/o server for user interface port.
@@ -184,38 +184,52 @@ do_io_request(Req, From, ReplyAs, Port, Q0) ->
io_reply(From, ReplyAs, Reply),
Q1;
{exit,What} ->
- send_port(Port, close),
+ ok = send_port(Port, close),
exit(What)
end.
%% New in R13B
%% Encoding option (unicode/latin1)
io_request({put_chars,unicode,Chars}, Port, Q) -> % Binary new in R9C
- put_chars(wrap_characters_to_binary(Chars,unicode, get(encoding)), Port, Q);
+ case wrap_characters_to_binary(Chars, unicode, get(encoding)) of
+ error ->
+ {error,{error,put_chars},Q};
+ Bin ->
+ put_chars(Bin, Port, Q)
+ end;
io_request({put_chars,unicode,Mod,Func,Args}, Port, Q) ->
- Result = case catch apply(Mod,Func,Args) of
- Data when is_list(Data); is_binary(Data) ->
- wrap_characters_to_binary(Data,unicode,get(encoding));
- Undef ->
- Undef
- end,
- put_chars(Result, Port, Q);
+ case catch apply(Mod,Func,Args) of
+ Data when is_list(Data); is_binary(Data) ->
+ case wrap_characters_to_binary(Data, unicode, get(encoding)) of
+ Bin when is_binary(Bin) ->
+ put_chars(Bin, Port, Q);
+ error ->
+ {error,{error,put_chars},Q}
+ end;
+ Undef ->
+ put_chars(Undef, Port, Q)
+ end;
io_request({put_chars,latin1,Chars}, Port, Q) -> % Binary new in R9C
- Data = case get(encoding) of
- unicode ->
- unicode:characters_to_binary(Chars,latin1,unicode);
- latin1 ->
- erlang:iolist_to_binary(Chars)
- end,
- put_chars(Data, Port, Q);
+ case catch unicode:characters_to_binary(Chars, latin1, get(encoding)) of
+ Data when is_binary(Data) ->
+ put_chars(Data, Port, Q);
+ _ ->
+ {error,{error,put_chars},Q}
+ end;
io_request({put_chars,latin1,Mod,Func,Args}, Port, Q) ->
- Result = case catch apply(Mod,Func,Args) of
- Data when is_list(Data); is_binary(Data) ->
- unicode:characters_to_binary(Data,latin1,get(encoding));
- Undef ->
- Undef
- end,
- put_chars(Result, Port, Q);
+ case catch apply(Mod,Func,Args) of
+ Data when is_list(Data); is_binary(Data) ->
+ case
+ catch unicode:characters_to_binary(Data,latin1,get(encoding))
+ of
+ Bin when is_binary(Bin) ->
+ put_chars(Bin, Port, Q);
+ _ ->
+ {error,{error,put_chars},Q}
+ end;
+ Undef ->
+ put_chars(Undef, Port, Q)
+ end;
io_request({get_chars,Enc,Prompt,N}, Port, Q) -> % New in R9C
get_chars(Prompt, io_lib, collect_chars, N, Port, Q, Enc);
io_request({get_line,Enc,Prompt}, Port, Q) ->
@@ -285,7 +299,8 @@ put_port(List, Port) ->
%% send_port(Port, Command)
send_port(Port, Command) ->
- Port ! {self(),Command}.
+ Port ! {self(),Command},
+ ok.
%% io_reply(From, ReplyAs, Reply)
%% The function for sending i/o command acknowledgement.
@@ -296,7 +311,7 @@ io_reply(From, ReplyAs, Reply) ->
%% put_chars
put_chars(Chars, Port, Q) when is_binary(Chars) ->
- put_port(Chars, Port),
+ ok = put_port(Chars, Port),
{ok,ok,Q};
put_chars(Chars, Port, Q) ->
case catch list_to_binary(Chars) of
@@ -360,16 +375,20 @@ getopts(_Port,Q) ->
Bin = {binary, get(read_mode) =:= binary},
Uni = {encoding, get(encoding)},
{ok,[Bin,Uni],Q}.
-
get_line_bin(Prompt,Port,Q, Enc) ->
- prompt(Port, Prompt),
- case {get(eof),queue:is_empty(Q)} of
- {true,true} ->
- {ok,eof,Q};
- _ ->
- get_line(Prompt,Port, Q, [], Enc)
+ case prompt(Port, Prompt) of
+ error ->
+ {error,{error,get_line},Q};
+ ok ->
+ case {get(eof),queue:is_empty(Q)} of
+ {true,true} ->
+ {ok,eof,Q};
+ _ ->
+ get_line(Prompt,Port, Q, [], Enc)
+ end
end.
+
get_line(Prompt, Port, Q, Acc, Enc) ->
case queue:is_empty(Q) of
true ->
@@ -386,8 +405,12 @@ get_line(Prompt, Port, Q, Acc, Enc) ->
get_line(Prompt, Port, Q, Acc, Enc);
{io_request,From,ReplyAs,Request} when is_pid(From) ->
do_io_request(Request, From, ReplyAs, Port, queue:new()),
- prompt(Port, Prompt),
- get_line(Prompt, Port, Q, Acc, Enc);
+ case prompt(Port, Prompt) of
+ error ->
+ {error,{error,get_line},Q};
+ ok ->
+ get_line(Prompt, Port, Q, Acc, Enc)
+ end;
{'EXIT',From,What} when node(From) =:= node() ->
{exit,What}
end;
@@ -420,6 +443,7 @@ srch(<<X:8,_/binary>>,X,N) ->
{match,[{N,1}]};
srch(<<_:8,T/binary>>,X,N) ->
srch(T,X,N+1).
+
get_line_doit(Prompt, Port, Q, Accu, Enc) ->
case queue:is_empty(Q) of
true ->
@@ -569,12 +593,16 @@ binrev(L, T) ->
%% Entry function.
get_chars(Prompt, M, F, Xa, Port, Q, Enc) ->
- prompt(Port, Prompt),
- case {get(eof),queue:is_empty(Q)} of
- {true,true} ->
- {ok,eof,Q};
- _ ->
- get_chars(Prompt, M, F, Xa, Port, Q, start, Enc)
+ case prompt(Port, Prompt) of
+ error ->
+ {error,{error,get_chars},Q};
+ ok ->
+ case {get(eof),queue:is_empty(Q)} of
+ {true,true} ->
+ {ok,eof,Q};
+ _ ->
+ get_chars(Prompt, M, F, Xa, Port, Q, start, Enc)
+ end
end.
%% First loop. Wait for port data. Respond to output requests.
@@ -608,8 +636,12 @@ get_chars(Prompt, M, F, Xa, Port, Q, State, Enc) ->
get_chars_req(Prompt, M, F, XtraArg, Port, Q, State,
Req, From, ReplyAs, Enc) ->
do_io_request(Req, From, ReplyAs, Port, queue:new()), %Keep Q over this call
- prompt(Port, Prompt),
- get_chars(Prompt, M, F, XtraArg, Port, Q, State, Enc).
+ case prompt(Port, Prompt) of
+ error ->
+ {error,{error,get_chars},Q};
+ ok ->
+ get_chars(Prompt, M, F, XtraArg, Port, Q, State, Enc)
+ end.
%% Second loop. Pass data to client as long as it wants more.
%% A ^G in data interrupts loop if 'noshell' is not undefined.
@@ -671,12 +703,15 @@ get_chars_more(State, M, F, Xa, Port, Q, Enc) ->
%% common case, reduces execution time by 20%
prompt(_Port, '') -> ok;
-
prompt(Port, Prompt) ->
Encoding = get(encoding),
- put_port(wrap_characters_to_binary(io_lib:format_prompt(Prompt, Encoding),
- unicode, Encoding),
- Port).
+ PromptString = io_lib:format_prompt(Prompt, Encoding),
+ case wrap_characters_to_binary(PromptString, unicode, Encoding) of
+ Bin when is_binary(Bin) ->
+ put_port(Bin, Port);
+ error ->
+ error
+ end.
%% Convert error code to make it look as before
err_func(io_lib, get_until, {_,F,_}) ->
@@ -753,21 +788,30 @@ cast(Data, list, unicode, unicode) when is_binary(Data); is_list(Data) ->
_ -> exit({no_translation, unicode, unicode})
end.
-wrap_characters_to_binary(Chars,unicode,latin1) ->
- case unicode:characters_to_binary(Chars,unicode,latin1) of
- {error,_,_} ->
- list_to_binary(
- [ case X of
- High when High > 255 ->
- ["\\x{",erlang:integer_to_list(X, 16),$}];
- Low ->
- Low
- end || X <- unicode:characters_to_list(Chars,unicode) ]);
- Bin ->
- Bin
+wrap_characters_to_binary(Chars, unicode, latin1) ->
+ case catch unicode:characters_to_binary(Chars, unicode, latin1) of
+ Bin when is_binary(Bin) ->
+ Bin;
+ _ ->
+ case catch unicode:characters_to_list(Chars, unicode) of
+ L when is_list(L) ->
+ list_to_binary(
+ [ case X of
+ High when High > 255 ->
+ ["\\x{",erlang:integer_to_list(X, 16),$}];
+ Low ->
+ Low
+ end || X <- L ]);
+ _ ->
+ error
+ end
end;
-
-wrap_characters_to_binary(Bin,From,From) when is_binary(Bin) ->
+wrap_characters_to_binary(Bin, From, From) when is_binary(Bin) ->
Bin;
-wrap_characters_to_binary(Chars,From,To) ->
- unicode:characters_to_binary(Chars,From,To).
+wrap_characters_to_binary(Chars, From, To) ->
+ case catch unicode:characters_to_binary(Chars, From, To) of
+ Bin when is_binary(Bin) ->
+ Bin;
+ _ ->
+ error
+ end.
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index 8f2ca28f56..bb654495d3 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -129,7 +129,7 @@ server1(Iport, Oport, Shell) ->
Gr = gr_add_cur(Gr1, Curr, Shell1),
%% Print some information.
io_request({put_chars, unicode,
- flatten(io_lib:format("~s\n",
+ flatten(io_lib:format("~ts\n",
[erlang:system_info(system_version)]))},
Iport, Oport),
%% Enter the server loop.
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index 8d2d55777b..cb11d4e899 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2012. All Rights Reserved.
+# Copyright Ericsson AB 1997-2013. 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
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index 2ca8840e1f..0452202467 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 914f0d6127..ac991b1111 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -60,7 +60,8 @@
-export([ read_not_really_compressed/1,
read_compressed_cooked/1, read_compressed_cooked_binary/1,
read_cooked_tar_problem/1,
- write_compressed/1, compress_errors/1, catenated_gzips/1]).
+ write_compressed/1, compress_errors/1, catenated_gzips/1,
+ compress_async_crash/1]).
-export([ make_link/1, read_link_info_for_non_link/1, symlinks/1]).
@@ -135,7 +136,8 @@ groups() ->
{compression, [],
[read_compressed_cooked, read_compressed_cooked_binary,
read_cooked_tar_problem, read_not_really_compressed,
- write_compressed, compress_errors, catenated_gzips]},
+ write_compressed, compress_errors, catenated_gzips,
+ compress_async_crash]},
{links, [],
[make_link, read_link_info_for_non_link, symlinks]}].
@@ -230,7 +232,7 @@ mini_server(Parent) ->
receive
die ->
ok;
- {io_request,From,To,{put_chars,Data}} ->
+ {io_request,From,To,{put_chars,_Encoding,Data}} ->
Parent ! {io_request,From,To,{put_chars,Data}},
From ! {io_reply, To, ok},
mini_server(Parent);
@@ -2312,6 +2314,57 @@ compress_errors(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+compress_async_crash(suite) -> [];
+compress_async_crash(doc) -> [];
+compress_async_crash(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line Path = filename:join(DataDir, "test.gz"),
+ ExpectedData = <<"qwerty">>,
+
+ ?line _ = ?FILE_MODULE:delete(Path),
+ ?line {ok, Fd} = ?FILE_MODULE:open(Path, [write, binary, compressed]),
+ ?line ok = ?FILE_MODULE:write(Fd, ExpectedData),
+ ?line ok = ?FILE_MODULE:close(Fd),
+
+ % Test that when using async thread pool, the emulator doesn't crash
+ % when the efile port driver is stopped while a compressed file operation
+ % is in progress (being carried by an async thread).
+ ?line ok = compress_async_crash_loop(10000, Path, ExpectedData),
+ ?line ok = ?FILE_MODULE:delete(Path),
+ ok.
+
+compress_async_crash_loop(0, _Path, _ExpectedData) ->
+ ok;
+compress_async_crash_loop(N, Path, ExpectedData) ->
+ Parent = self(),
+ {Pid, Ref} = spawn_monitor(
+ fun() ->
+ ?line {ok, Fd} = ?FILE_MODULE:open(
+ Path, [read, compressed, raw, binary]),
+ Len = byte_size(ExpectedData),
+ Parent ! {self(), continue},
+ ?line {ok, ExpectedData} = ?FILE_MODULE:read(Fd, Len),
+ ?line ok = ?FILE_MODULE:close(Fd),
+ receive foobar -> ok end
+ end),
+ receive
+ {Pid, continue} ->
+ exit(Pid, shutdown),
+ receive
+ {'DOWN', Ref, _, _, Reason} ->
+ ?line shutdown = Reason
+ end;
+ {'DOWN', Ref, _, _, Reason2} ->
+ test_server:fail({worker_exited, Reason2})
+ after 60000 ->
+ exit(Pid, shutdown),
+ erlang:demonitor(Ref, [flush]),
+ test_server:fail(worker_timeout)
+ end,
+ compress_async_crash_loop(N - 1, Path, ExpectedData).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
altname(doc) ->
"Test the file:altname/1 function";
altname(suite) ->
diff --git a/lib/kernel/test/gen_tcp_echo_SUITE.erl b/lib/kernel/test/gen_tcp_echo_SUITE.erl
index 94f95798a0..9bc66dbae0 100644
--- a/lib/kernel/test/gen_tcp_echo_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_echo_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 93dc2a69d1..a72e76f813 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -42,11 +42,12 @@
killing_acceptor/1,killing_multi_acceptors/1,killing_multi_acceptors2/1,
several_accepts_in_one_go/1, accept_system_limit/1,
active_once_closed/1, send_timeout/1, send_timeout_active/1,
- otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1,
+ otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1, wrapping_oct/1,
otp_9389/1]).
%% Internal exports.
-export([sender/3, not_owner/1, passive_sockets_server/2, priority_server/1,
+ oct_acceptor/1,
otp_7731_server/1, zombie_server/2, do_iter_max_socks/2]).
init_per_testcase(_Func, Config) when is_list(Config) ->
@@ -75,6 +76,7 @@ all() ->
killing_acceptor, killing_multi_acceptors,
killing_multi_acceptors2, several_accepts_in_one_go, accept_system_limit,
active_once_closed, send_timeout, send_timeout_active, otp_7731,
+ wrapping_oct,
zombie_sockets, otp_7816, otp_8102, otp_9389].
groups() ->
@@ -2581,3 +2583,71 @@ otp_9389_loop(S, OrigLinkHdr, State) ->
3000 ->
?line error({timeout,header})
end.
+
+wrapping_oct(doc) ->
+ "Check that 64bit octet counters work.";
+wrapping_oct(suite) ->
+ [];
+wrapping_oct(Config) when is_list(Config) ->
+ Dog = test_server:timetrap(test_server:seconds(600)),
+ {ok,Sock} = gen_tcp:listen(0,[{active,false},{mode,binary}]),
+ {ok,Port} = inet:port(Sock),
+ spawn_link(?MODULE,oct_acceptor,[Sock]),
+ Res = oct_datapump(Port,16#1FFFFFFFF),
+ gen_tcp:close(Sock),
+ test_server:timetrap_cancel(Dog),
+ ok = Res,
+ ok.
+
+oct_datapump(Port,N) ->
+ {ok,Sock} = gen_tcp:connect("localhost",Port,
+ [{active,false},{mode,binary}]),
+ oct_pump(Sock,N,binary:copy(<<$a:8>>,100000),0).
+
+oct_pump(S,N,_,_) when N =< 0 ->
+ gen_tcp:close(S),
+ ok;
+oct_pump(S,N,Bin,Last) ->
+ case gen_tcp:send(S,Bin) of
+ ok ->
+ {ok,Stat}=inet:getstat(S),
+ {_,R}=lists:keyfind(send_oct,1,Stat),
+ case (R < Last) of
+ true ->
+ io:format("ERROR (output) ~p < ~p~n",[R,Last]),
+ output_counter_error;
+ false ->
+ oct_pump(S,N-byte_size(Bin),Bin,R)
+ end;
+ _ ->
+ input_counter_error
+ end.
+
+
+oct_acceptor(Sock) ->
+ {ok,Data} = gen_tcp:accept(Sock),
+ oct_aloop(Data,0,0).
+
+oct_aloop(S,X,Times) ->
+ case gen_tcp:recv(S,0) of
+ {ok,_} ->
+ {ok,Stat}=inet:getstat(S),
+ {_,R}=lists:keyfind(recv_oct,1,Stat),
+ case (R < X) of
+ true ->
+ io:format("ERROR ~p < ~p~n",[R,X]),
+ gen_tcp:close(S),
+ input_counter_error;
+ false ->
+ case Times rem 16#FFFFF of
+ 0 ->
+ io:format("Read: ~p~n",[R]);
+ _ ->
+ ok
+ end,
+ oct_aloop(S,R,Times+1)
+ end;
+ _ ->
+ gen_tcp:close(S),
+ closed
+ end.
diff --git a/lib/kernel/test/ignore_cores.erl b/lib/kernel/test/ignore_cores.erl
index 8b1ac0fe6c..d4bb02df3f 100644
--- a/lib/kernel/test/ignore_cores.erl
+++ b/lib/kernel/test/ignore_cores.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. 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
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index e5e1794514..1f7724d0dc 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 3f2195b609..382fd6f6a9 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl
index 60b818cbe3..98cff0222e 100644
--- a/lib/kernel/test/pdict_SUITE.erl
+++ b/lib/kernel/test/pdict_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. 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