Returns the Value of the environment variable
++ VarName, or DefaultValue if the environment variable
++ is undefined.
++
If Unicode file name encoding is in effect (see the erl manual
++ page), the strings (both VarName and
++ Value) may contain characters with codepoints > 255.
++
++
++
+
+ Return the process identifier of the emulator process
+
+diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
+index 9415593..d5ef994 100644
+--- a/lib/kernel/src/os.erl
++++ b/lib/kernel/src/os.erl
+@@ -26,7 +26,7 @@
+
+ %%% BIFs
+
+--export([getenv/0, getenv/1, getpid/0, putenv/2, timestamp/0, unsetenv/1]).
++-export([getenv/0, getenv/1, getenv/2, getpid/0, putenv/2, timestamp/0, unsetenv/1]).
+
+ -spec getenv() -> [string()].
+
+@@ -39,6 +39,19 @@ getenv() -> erlang:nif_error(undef).
+ getenv(_) ->
+ erlang:nif_error(undef).
+
++-spec getenv(VarName, DefaultValue) -> Value when
++ VarName :: string(),
++ DefaultValue :: string(),
++ Value :: string().
++
++getenv(VarName, DefaultValue) ->
++ case os:getenv(VarName) of
++ false ->
++ DefaultValue;
++ Value ->
++ Value
++ end.
++
+ -spec getpid() -> Value when
+ Value :: string().
+
diff --git a/otp-0019-Patch-removes-support-for-SSLv3-protocol-because-it-.patch b/otp-0019-Patch-removes-support-for-SSLv3-protocol-because-it-.patch
new file mode 100644
index 0000000..359c011
--- /dev/null
+++ b/otp-0019-Patch-removes-support-for-SSLv3-protocol-because-it-.patch
@@ -0,0 +1,99 @@
+From: Sergei Golovan
+Date: Sun, 30 Nov 2014 20:20:41 +0300
+Subject: [PATCH] Patch removes support for SSLv3 protocol because it is proved
+ to be insecure and nobody should use it anymore.
+
+
+diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
+index 1d74faf..912acc2 100644
+--- a/lib/ssl/doc/src/ssl.xml
++++ b/lib/ssl/doc/src/ssl.xml
+@@ -123,7 +123,7 @@
+
+
Protocol that will be supported by started clients and
+ servers. If this option is not set it will default to all
+@@ -58,6 +58,9 @@
+ Note that this option may be overridden by the version option
+ to ssl:connect/[2,3] and ssl:listen/2.
+
++
For Debian GNU/Linux distribution the sslv3 protocol was
++ disabled due to its security issues.
++
This option only affects TLS-1.0 connections.
++ If set to false it disables the block cipher padding check
++ to be able to interoperate with legacy software.
++
++
++
Using this option makes TLS vulnerable to
++ the Poodle attack
+diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
+index 1757fa9..ebae0a5 100644
+--- a/erts/epmd/src/epmd.c
++++ b/erts/epmd/src/epmd.c
+@@ -342,7 +342,7 @@ static void run_daemon(EpmdVars *g)
+ for (fd = 0; fd < g->max_conn ; fd++) /* close all files ... */
+ close(fd);
+ /* Syslog on linux will try to write to whatever if we dont
+- inform it of that the log is closed. */
++ inform it that the log is closed. */
+ closelog();
+
+ /* These chouldn't be needed but for safety... */
+diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
+index 8817bde..ea7dac7 100644
+--- a/erts/epmd/src/epmd_cli.c
++++ b/erts/epmd/src/epmd_cli.c
+@@ -135,19 +135,33 @@ void epmd_call(EpmdVars *g,int what)
+ static int conn_to_epmd(EpmdVars *g)
+ {
+ struct EPMD_SOCKADDR_IN address;
++ size_t salen = 0;
+ int connect_sock;
+-
+- connect_sock = socket(FAMILY, SOCK_STREAM, 0);
+- if (connect_sock<0)
+- goto error;
++ unsigned short sport = g->port;
++
++#if defined(EPMD6)
++ SET_ADDR6(address, in6addr_loopback, sport);
++ salen = sizeof(struct sockaddr_in6);
++
++ connect_sock = socket(AF_INET6, SOCK_STREAM, 0);
++ if (connect_sock>=0) {
++
++ if (connect(connect_sock, (struct sockaddr*)&address, salen) == 0)
++ return connect_sock;
+
+- { /* store port number in unsigned short */
+- unsigned short sport = g->port;
+- SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport);
++ close(connect_sock);
+ }
++#endif
++ SET_ADDR(address, htonl(INADDR_LOOPBACK), sport);
++ salen = sizeof(struct sockaddr_in);
+
+- if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0)
++ connect_sock = socket(AF_INET, SOCK_STREAM, 0);
++ if (connect_sock<0)
+ goto error;
++
++ if (connect(connect_sock, (struct sockaddr*)&address, salen) < 0)
++ goto error;
++
+ return connect_sock;
+
+ error:
+diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
+index 363923e..c6d9173 100644
+--- a/erts/epmd/src/epmd_int.h
++++ b/erts/epmd/src/epmd_int.h
+@@ -47,6 +47,7 @@
+ # ifndef WINDOWS_H_INCLUDES_WINSOCK2_H
+ # include
+ # endif
++# include
+ # include
+ # include
+ #endif
+@@ -114,6 +115,10 @@
+ # include
+ #endif
+
++#if defined(HAVE_IN6) && defined(AF_INET6) && defined(HAVE_INET_PTON)
++# define EPMD6
++#endif
++
+ /* ************************************************************************ */
+ /* Replace some functions by others by making the function name a macro */
+
+@@ -167,33 +172,53 @@
+ /* ************************************************************************ */
+ /* Macros that let us use IPv6 */
+
+-#if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6)
++#if HAVE_IN6
++# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY
++# if HAVE_DECL_IN6ADDR_ANY_INIT
++static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } };
++# else
++static const struct in6_addr in6addr_any =
++ { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
++# endif /* HAVE_IN6ADDR_ANY_INIT */
++# endif /* ! HAVE_DECL_IN6ADDR_ANY */
++
++# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK
++# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT
++static const struct in6_addr in6addr_loopback =
++ { { IN6ADDR_LOOPBACK_INIT } };
++# else
++static const struct in6_addr in6addr_loopback =
++ { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };
++# endif /* HAVE_IN6ADDR_LOOPBACK_INIT */
++# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */
++#endif /* HAVE_IN6 */
++
++#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
++
++#if defined(EPMD6)
+
+-#define EPMD_SOCKADDR_IN sockaddr_in6
+-#define EPMD_IN_ADDR in6_addr
+-#define EPMD_S_ADDR s6_addr
+-#define EPMD_ADDR_LOOPBACK in6addr_loopback.s6_addr
+-#define EPMD_ADDR_ANY in6addr_any.s6_addr
++#define EPMD_SOCKADDR_IN sockaddr_storage
+ #define FAMILY AF_INET6
+
+-#define SET_ADDR(dst, addr, port) do { \
+- memset((char*)&(dst), 0, sizeof(dst)); \
+- memcpy((char*)&(dst).sin6_addr.s6_addr, (char*)&(addr), 16); \
+- (dst).sin6_family = AF_INET6; \
+- (dst).sin6_flowinfo = 0; \
+- (dst).sin6_port = htons(port); \
++#define SET_ADDR6(dst, addr, port) do { \
++ struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(dst); \
++ memset(sa, 0, sizeof(dst)); \
++ sa->sin6_family = AF_INET6; \
++ sa->sin6_addr = (addr); \
++ sa->sin6_port = htons(port); \
+ } while(0)
+
+-#define IS_ADDR_LOOPBACK(addr) \
+- (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0)
++#define SET_ADDR(dst, addr, port) do { \
++ struct sockaddr_in *sa = (struct sockaddr_in *)&(dst); \
++ memset(sa, 0, sizeof(dst)); \
++ sa->sin_family = AF_INET; \
++ sa->sin_addr.s_addr = (addr); \
++ sa->sin_port = htons(port); \
++ } while(0)
+
+ #else /* Not IP v6 */
+
+ #define EPMD_SOCKADDR_IN sockaddr_in
+-#define EPMD_IN_ADDR in_addr
+-#define EPMD_S_ADDR s_addr
+-#define EPMD_ADDR_LOOPBACK htonl(INADDR_LOOPBACK)
+-#define EPMD_ADDR_ANY htonl(INADDR_ANY)
+ #define FAMILY AF_INET
+
+ #define SET_ADDR(dst, addr, port) do { \
+@@ -203,8 +228,6 @@
+ (dst).sin_port = htons(port); \
+ } while(0)
+
+-#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
+-
+ #endif /* Not IP v6 */
+
+ /* ************************************************************************ */
+diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
+index 78524a6..28e30d4 100644
+--- a/erts/epmd/src/epmd_srv.c
++++ b/erts/epmd/src/epmd_srv.c
+@@ -70,6 +70,7 @@ static time_t current_time(EpmdVars*);
+
+ static Connection *conn_init(EpmdVars*);
+ static int conn_open(EpmdVars*,int);
++static int conn_local_peer_check(EpmdVars*, int);
+ static int conn_close_fd(EpmdVars*,int);
+
+ static void node_init(EpmdVars*);
+@@ -200,10 +201,11 @@ void run(EpmdVars *g)
+ {
+ struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS];
+ int listensock[MAX_LISTEN_SOCKETS];
+- int num_sockets;
++ int num_sockets = 0;
+ int i;
+ int opt;
+ unsigned short sport = g->port;
++ int bound = 0;
+
+ node_init(g);
+ g->conn = conn_init(g);
+@@ -246,64 +248,82 @@ void run(EpmdVars *g)
+ if (g->addresses != NULL && /* String contains non-separator characters if: */
+ g->addresses[strspn(g->addresses," ,")] != '\000')
+ {
+- char *tmp;
+- char *token;
+- int loopback_ok = 0;
++ char *tmp = NULL;
++ char *token = NULL;
++
++ /* Always listen on the loopback. */
++ SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_LOOPBACK),sport);
++ num_sockets++;
++#if defined(EPMD6)
++ SET_ADDR6(iserv_addr[num_sockets],in6addr_loopback,sport);
++ num_sockets++;
++#endif
+
+- if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL)
++ if ((tmp = strdup(g->addresses)) == NULL)
+ {
+ dbg_perror(g,"cannot allocate memory");
+ epmd_cleanup_exit(g,1);
+ }
+- strcpy(tmp,g->addresses);
+
+- for(token = strtok(tmp,", "), num_sockets = 0;
++ for(token = strtok(tmp,", ");
+ token != NULL;
+- token = strtok(NULL,", "), num_sockets++)
++ token = strtok(NULL,", "))
+ {
+- struct EPMD_IN_ADDR addr;
+-#ifdef HAVE_INET_PTON
+- int ret;
++ struct in_addr addr;
++#if defined(EPMD6)
++ struct in6_addr addr6;
++ struct sockaddr_storage *sa = &iserv_addr[num_sockets];
+
+- if ((ret = inet_pton(FAMILY,token,&addr)) == -1)
++ if (inet_pton(AF_INET6,token,&addr6) == 1)
+ {
+- dbg_perror(g,"cannot convert IP address to network format");
+- epmd_cleanup_exit(g,1);
++ SET_ADDR6(iserv_addr[num_sockets],addr6,sport);
++ }
++ else if (inet_pton(AF_INET,token,&addr) == 1)
++ {
++ SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
++ }
++ else
++#else
++ if ((addr.s_addr = inet_addr(token)) != INADDR_NONE)
++ {
++ SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
+ }
+- else if (ret == 0)
+-#elif !defined(EPMD6)
+- if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE)
++ else
+ #endif
+ {
+ dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token);
+ epmd_cleanup_exit(g,1);
+ }
+
++#if defined(EPMD6)
++ if (sa->ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&addr6))
++ continue;
++
++ if (sa->ss_family == AF_INET)
++#endif
+ if (IS_ADDR_LOOPBACK(addr))
+- loopback_ok = 1;
++ continue;
+
+- if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1)
++ num_sockets++;
++
++ if (num_sockets >= MAX_LISTEN_SOCKETS)
+ {
+ dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses",
+ MAX_LISTEN_SOCKETS);
+ epmd_cleanup_exit(g,1);
+ }
+-
+- SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport);
+ }
+
+ free(tmp);
+-
+- if (!loopback_ok)
+- {
+- SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport);
+- num_sockets++;
+- }
+ }
+ else
+ {
+- SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport);
+- num_sockets = 1;
++ SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_ANY),sport);
++ num_sockets++;
++#if defined(EPMD6)
++ SET_ADDR6(iserv_addr[num_sockets],in6addr_any,sport);
++ num_sockets++;
++#endif
+ }
+ #ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ }
+@@ -334,13 +354,39 @@ void run(EpmdVars *g)
+ #endif
+ for (i = 0; i < num_sockets; i++)
+ {
+- if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0)
++ struct sockaddr *sa = (struct sockaddr *)&iserv_addr[i];
++#if defined(EPMD6)
++ size_t salen = (sa->sa_family == AF_INET6 ?
++ sizeof(struct sockaddr_in6) :
++ sizeof(struct sockaddr_in));
++#else
++ size_t salen = sizeof(struct sockaddr_in);
++#endif
++
++ if ((listensock[i] = socket(sa->sa_family,SOCK_STREAM,0)) < 0)
+ {
+- dbg_perror(g,"error opening stream socket");
++ switch (errno) {
++ case EAFNOSUPPORT:
++ case EPROTONOSUPPORT:
++ continue;
++ default:
++ dbg_perror(g,"error opening stream socket");
++ epmd_cleanup_exit(g,1);
++ }
++ }
++ g->listenfd[bound++] = listensock[i];
++
++#if HAVE_DECL_IPV6_V6ONLY
++ opt = 1;
++ if (sa->sa_family == AF_INET6 &&
++ setsockopt(listensock[i],IPPROTO_IPV6,IPV6_V6ONLY,&opt,
++ sizeof(opt)) <0)
++ {
++ dbg_perror(g,"can't set IPv6 only socket option");
+ epmd_cleanup_exit(g,1);
+ }
+- g->listenfd[i] = listensock[i];
+-
++#endif
++
+ /*
+ * Note that we must not enable the SO_REUSEADDR on Windows,
+ * because addresses will be reused even if they are still in use.
+@@ -372,8 +418,7 @@ void run(EpmdVars *g)
+ dbg_perror(g,"failed to set non-blocking mode of listening socket %d",
+ listensock[i]);
+
+- if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i],
+- sizeof(iserv_addr[i])) < 0)
++ if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], salen) < 0)
+ {
+ if (errno == EADDRINUSE)
+ {
+@@ -394,6 +439,11 @@ void run(EpmdVars *g)
+ }
+ select_fd_set(g, listensock[i]);
+ }
++ if (bound == 0) {
++ dbg_perror(g,"unable to bind any address");
++ epmd_cleanup_exit(g,1);
++ }
++ num_sockets = bound;
+ #ifdef HAVE_SYSTEMD_SD_DAEMON_H
+ }
+ sd_notifyf(0, "READY=1\n"
+@@ -438,8 +488,8 @@ void run(EpmdVars *g)
+ }
+
+ for (i = 0; i < num_sockets; i++)
+- if (FD_ISSET(listensock[i],&read_mask)) {
+- if (do_accept(g, listensock[i]) && g->active_conn < g->max_conn) {
++ if (FD_ISSET(g->listenfd[i],&read_mask)) {
++ if (do_accept(g, g->listenfd[i]) && g->active_conn < g->max_conn) {
+ /*
+ * The accept() succeeded, and we have at least one file
+ * descriptor still free, which means that another accept()
+@@ -1001,15 +1051,6 @@ static int conn_open(EpmdVars *g,int fd)
+
+ for (i = 0; i < g->max_conn; i++) {
+ if (g->conn[i].open == EPMD_FALSE) {
+- struct sockaddr_in si;
+- struct sockaddr_in di;
+-#ifdef HAVE_SOCKLEN_T
+- socklen_t st;
+-#else
+- int st;
+-#endif
+- st = sizeof(si);
+-
+ g->active_conn++;
+ s = &g->conn[i];
+
+@@ -1020,20 +1061,7 @@ static int conn_open(EpmdVars *g,int fd)
+ s->open = EPMD_TRUE;
+ s->keep = EPMD_FALSE;
+
+- /* Determine if connection is from localhost */
+- if (getpeername(s->fd,(struct sockaddr*) &si,&st) ||
+- st < sizeof(si)) {
+- /* Failure to get peername is regarded as non local host */
+- s->local_peer = EPMD_FALSE;
+- } else {
+- /* Only 127.x.x.x and connections from the host's IP address
+- allowed, no false positives */
+- s->local_peer =
+- (((((unsigned) ntohl(si.sin_addr.s_addr)) & 0xFF000000U) ==
+- 0x7F000000U) ||
+- (getsockname(s->fd,(struct sockaddr*) &di,&st) ?
+- EPMD_FALSE : si.sin_addr.s_addr == di.sin_addr.s_addr));
+- }
++ s->local_peer = conn_local_peer_check(g, s->fd);
+ dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" :
+ "Non-local peer connected");
+
+@@ -1041,7 +1069,7 @@ static int conn_open(EpmdVars *g,int fd)
+ s->got = 0;
+ s->mod_time = current_time(g); /* Note activity */
+
+- s->buf = (char *)malloc(INBUF_SIZE);
++ s->buf = malloc(INBUF_SIZE);
+
+ if (s->buf == NULL) {
+ dbg_printf(g,0,"epmd: Insufficient memory");
+@@ -1059,6 +1087,60 @@ static int conn_open(EpmdVars *g,int fd)
+ return EPMD_FALSE;
+ }
+
++static int conn_local_peer_check(EpmdVars *g, int fd)
++{
++ struct EPMD_SOCKADDR_IN si;
++ struct EPMD_SOCKADDR_IN di;
++
++ struct sockaddr_in *si4 = (struct sockaddr_in *)&si;
++ struct sockaddr_in *di4 = (struct sockaddr_in *)&di;
++
++#if defined(EPMD6)
++ struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&si;
++ struct sockaddr_in6 *di6 = (struct sockaddr_in6 *)&di;
++#endif
++
++#ifdef HAVE_SOCKLEN_T
++ socklen_t st;
++#else
++ int st;
++#endif
++
++ st = sizeof(si);
++
++ /* Determine if connection is from localhost */
++ if (getpeername(fd,(struct sockaddr*) &si,&st) ||
++ st > sizeof(si)) {
++ /* Failure to get peername is regarded as non local host */
++ return EPMD_FALSE;
++ }
++
++ /* Only 127.x.x.x and connections from the host's IP address
++ allowed, no false positives */
++#if defined(EPMD6)
++ if (si.ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(si6->sin6_addr)))
++ return EPMD_TRUE;
++
++ if (si.ss_family == AF_INET)
++#endif
++ if ((((unsigned) ntohl(si4->sin_addr.s_addr)) & 0xFF000000U) ==
++ 0x7F000000U)
++ return EPMD_TRUE;
++
++ if (getsockname(fd,(struct sockaddr*) &di,&st))
++ return EPMD_FALSE;
++
++#if defined(EPMD6)
++ if (si.ss_family == AF_INET6)
++ return IN6_ARE_ADDR_EQUAL( &(si6->sin6_addr), &(di6->sin6_addr));
++ if (si.ss_family == AF_INET)
++#endif
++ return si4->sin_addr.s_addr == di4->sin_addr.s_addr;
++#if defined(EPMD6)
++ return EPMD_FALSE;
++#endif
++}
++
+ static int conn_close_fd(EpmdVars *g,int fd)
+ {
+ int i;
+diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl
+index cc24a55..8dfc21f 100644
+--- a/erts/epmd/test/epmd_SUITE.erl
++++ b/erts/epmd/test/epmd_SUITE.erl
+@@ -42,6 +42,7 @@
+ -export(
+ [
+ register_name/1,
++ register_name_ipv6/1,
+ register_names_1/1,
+ register_names_2/1,
+ register_duplicate_name/1,
+@@ -108,7 +109,8 @@
+ suite() -> [{ct_hooks,[ts_install_cth]}].
+
+ all() ->
+- [register_name, register_names_1, register_names_2,
++ [register_name, register_name_ipv6,
++ register_names_1, register_names_2,
+ register_duplicate_name, unicode_name, long_unicode_name,
+ get_port_nr, slow_get_port_nr,
+ unregister_others_name_1, unregister_others_name_2,
+@@ -165,6 +167,24 @@ register_name(Config) when is_list(Config) ->
+ ?line ok = close(Sock), % Unregister
+ ok.
+
++register_name_ipv6(doc) ->
++ ["Register a name over IPv6"];
++register_name_ipv6(suite) ->
++ [];
++register_name_ipv6(Config) when is_list(Config) ->
++ % Test if the host has an IPv6 loopback address
++ Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]),
++ case Res of
++ {ok,LSock} ->
++ gen_tcp:close(LSock),
++ ?line ok = epmdrun(),
++ ?line {ok,Sock} = register_node6("foobar6"),
++ ?line ok = close(Sock), % Unregister
++ ok;
++ _Error ->
++ {skip, "Host does not have an IPv6 loopback address"}
++ end.
++
+ register_names_1(doc) ->
+ ["Register and unregister two nodes"];
+ register_names_1(suite) ->
+@@ -238,13 +258,14 @@ register_node(Name) ->
+ register_node(Name,Port) ->
+ register_node_v2(Port,$M,0,5,5,Name,"").
+
++register_node6(Name) ->
++ register_node_v2({0,0,0,0,0,0,0,1},?DUMMY_PORT,$M,0,5,5,Name,"").
++
+ register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
+- Utf8Name = unicode:characters_to_binary(Name),
+- Req = [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot,
+- put16(HVsn), put16(LVsn),
+- put16(size(Utf8Name)), binary_to_list(Utf8Name),
+- size16(Extra), Extra],
+- case send_req(Req) of
++ register_node_v2("localhost", Port, NodeType, Prot, HVsn, LVsn, Name, Extra).
++register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
++ Req = alive2_req(Port, NodeType, Prot, HVsn, LVsn, Name, Extra),
++ case send_req(Req, Addr) of
+ {ok,Sock} ->
+ case recv(Sock,4) of
+ {ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} ->
+@@ -1129,7 +1150,9 @@ send_direct(Sock, Bytes) ->
+ end.
+
+ send_req(Req) ->
+- case connect() of
++ send_req(Req, "localhost").
++send_req(Req, Addr) ->
++ case connect(Addr) of
+ {ok,Sock} ->
+ case send(Sock, [size16(Req), Req]) of
+ ok ->
+diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
+index d511f2e..99ee635 100644
+--- a/lib/erl_interface/configure.in
++++ b/lib/erl_interface/configure.in
+@@ -250,7 +250,7 @@ case "$threads_disabled" in
+ ;;
+ win32_threads)
+ EI_THREADS="true"
+- THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0500 -DWINVER=0x0500"
++ THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600"
+ ;;
+ pthread)
+ EI_THREADS="true"
+diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
+index 91af49f..21a3dec 100644
+--- a/lib/kernel/src/erl_epmd.erl
++++ b/lib/kernel/src/erl_epmd.erl
+@@ -31,7 +31,7 @@
+ %% External exports
+ -export([start/0, start_link/0, stop/0, port_please/2,
+ port_please/3, names/0, names/1,
+- register_node/2, open/0, open/1, open/2]).
++ register_node/2, register_node/3, open/0, open/1, open/2]).
+
+ %% gen_server callbacks
+ -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+@@ -106,7 +106,9 @@ names1(HostName) ->
+
+
+ register_node(Name, PortNo) ->
+- gen_server:call(erl_epmd, {register, Name, PortNo}, infinity).
++ register_node(Name, PortNo, inet).
++register_node(Name, PortNo, Family) ->
++ gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
+
+ %%%----------------------------------------------------------------------
+ %%% Callback functions from gen_server
+@@ -124,10 +126,10 @@ init(_) ->
+ -spec handle_call(calls(), term(), state()) ->
+ {'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}.
+
+-handle_call({register, Name, PortNo}, _From, State) ->
++handle_call({register, Name, PortNo, Family}, _From, State) ->
+ case State#state.socket of
+ P when P < 0 ->
+- case do_register_node(Name, PortNo) of
++ case do_register_node(Name, PortNo, Family) of
+ {alive, Socket, Creation} ->
+ S = State#state{socket = Socket,
+ port_no = PortNo,
+@@ -210,8 +212,12 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) ->
+ close(Socket) ->
+ gen_tcp:close(Socket).
+
+-do_register_node(NodeName, TcpPort) ->
+- case open() of
++do_register_node(NodeName, TcpPort, Family) ->
++ Localhost = case Family of
++ inet -> open({127,0,0,1});
++ inet6 -> open({0,0,0,0,0,0,0,1})
++ end,
++ case Localhost of
+ {ok, Socket} ->
+ Name = to_string(NodeName),
+ Extra = "",
+diff --git a/lib/wx/configure.in b/lib/wx/configure.in
+index 3756786..be73888 100755
+--- a/lib/wx/configure.in
++++ b/lib/wx/configure.in
+@@ -163,14 +163,14 @@ case $host_os in
+ CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS"
+ ;;
+ mingw32)
+- CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0500 -D_WINDOWS -D_UNICODE -DUNICODE"
+- CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500"
++ CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE"
++ CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600"
+ AC_MSG_WARN([Reverting to 32-bit time_t])
+ CPPFLAGS="$CPPFLAGS -D_USE_32BIT_TIME_T"
+ ;;
+ win32)
+- CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0500 -D_WINDOWS -D_UNICODE -DUNICODE"
+- CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500"
++ CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE"
++ CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600"
+ ;;
+ *)
+ CFLAGS="$CFLAGS -Wno-deprecated-declarations"
diff --git a/otp-0024-Remove-unused-code-in-error-logger-handlers.patch b/otp-0024-Remove-unused-code-in-error-logger-handlers.patch
new file mode 100644
index 0000000..a3ea0ac
--- /dev/null
+++ b/otp-0024-Remove-unused-code-in-error-logger-handlers.patch
@@ -0,0 +1,1028 @@
+From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?=
+Date: Thu, 20 Aug 2015 09:44:43 +0200
+Subject: [PATCH] Remove unused code in error logger handlers
+
+A long time ago, errors from the emulator itself was sent as
+messages that would end up in the handle_info/2 function.
+Those clauses in handle_info/2 can be removed.
+
+The code for handling events tagged 'info' instead of 'info_msg'
+can also be taken out.
+
+error_logger_file_h: Refactor and modernize code
+
+Refactor, simplify, and modernize the code to facilitate future
+improvements in the following commits.
+
+Teach error_logger_file_h to truncate big messages
+
+Add the possibility to truncate big messages to avoid running out
+of memory.
+
+error_logger_tty_h: Refactor and modernize code
+
+Refactor, simplify, and modernize the code to facilitate future
+improvements in the following commits.
+
+Teach error_logger_tty_h to truncate big messages
+
+Add the possibility to truncate big messages to avoid running out
+of memory.
+
+stdlib: Fix leaking files after error_logger:logfile(close)
+
+Introduced when changing state from tuple to record.
+
+Make the scanned form of the io_lib format strings available for processing
+
+This adds three new functions to io_lib - scan_format/2, unscan_format/1,
+and build_text/1 - which expose the parsed form of the format control
+sequences to make it possible to easily modify or filter the input to
+io_lib:format/2. This can e.g. be used in order to replace unbounded-size
+control sequences like ~w or ~p with corresponding depth-limited ~W and ~P
+before doing the actual formatting.
+
+diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml
+index 90f24c4..6613dcd 100644
+--- a/lib/stdlib/doc/src/io.xml
++++ b/lib/stdlib/doc/src/io.xml
+@@ -505,7 +505,8 @@ ok
+
Writes the data with standard syntax in the same way as
+ ~w, but breaks terms whose printed representation
+ is longer than one line into many lines and indents each
+- line sensibly. It also tries to detect lists of
++ line sensibly. Left justification is not supported.
++ It also tries to detect lists of
+ printable characters and to output these as strings. The
+ Unicode translation modifier is used for determining
+ what characters are printable. For example:
+diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml
+index 68352ff..0c1c84d 100644
+--- a/lib/stdlib/doc/src/io_lib.xml
++++ b/lib/stdlib/doc/src/io_lib.xml
+@@ -4,7 +4,7 @@
+
+
+
+- 19962013
++ 19962014
+ Ericsson AB. All Rights Reserved.
+
+
+@@ -59,6 +59,35 @@
+
+
+
++
++
++
Description:
++
++
control_char is the type of control
++ sequence: $P, $w, and so on;
++
++
args is a list of the arguments used by the
++ control sequence, or an empty list if the control sequence
++ does not take any arguments;
++
++
width is the field width;
++
++
adjust is the adjustment;
++
++
precision is the precision of the printed
++ argument;
++
++
pad_char is the padding character;
++
++
encoding is set to true if the translation
++ modifier t is present;
++
++
strings is set to false if the modifier
++ l is present.
++
++
++
++
+
+
+
+@@ -260,6 +289,45 @@
+
+
+
++
++ Parse all control sequences in the format string
++
++
Returns a list corresponding to the given format string,
++ where control sequences have been replaced with
++ corresponding tuples. This list can be passed to io_lib:build_text/1 to have
++ the same effect as io_lib:format(Format, Args), or to
++ io_lib:unscan_format/1
++ in order to get the corresponding pair of Format and
++ Args (with every * and corresponding argument
++ expanded to numeric values).
++
A typical use of this function is to replace unbounded-size
++ control sequences like ~w and ~p with the
++ depth-limited variants ~W and ~P before
++ formatting to text, e.g. in a logger.
++
++
++
++
++ Revert a pre-parsed format list to a plain character list
++ and a list of arguments
++
++
See io_lib:scan_format/2 for
++ details.
++
++
++
++
++ Build the output text for a pre-parsed format list
++
++
See io_lib:scan_format/2 for
++ details.
++
++
++
+
+ Indentation after printing string
+
+diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl
+index e9364ed..ca44d01 100644
+--- a/lib/stdlib/src/error_logger_file_h.erl
++++ b/lib/stdlib/src/error_logger_file_h.erl
+@@ -23,24 +23,28 @@
+
+ %%%
+ %%% A handler that can be connected to the error_logger
+-%%% event handler.
+-%%% Writes all events formatted to file.
+-%%% Handles events tagged error, emulator and info.
++%%% event handler. Writes all events formatted to file.
+ %%%
+ %%% It can only be started from error_logger:swap_handler({logfile, File})
+-%%% or error_logger:logfile(File)
++%%% or error_logger:logfile(File).
+ %%%
+
+ -export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2, code_change/3]).
+
++-record(st,
++ {fd,
++ filename,
++ prev_handler,
++ depth=unlimited :: 'unlimited' | non_neg_integer()}).
++
+ %% This one is used when we takeover from the simple error_logger.
+ init({File, {error_logger, Buf}}) ->
+ case init(File, error_logger) of
+- {ok, {Fd, File, PrevHandler}} ->
+- write_events(Fd, Buf),
+- {ok, {Fd, File, PrevHandler}};
++ {ok, State} ->
++ write_events(State, Buf),
++ {ok, State};
+ Error ->
+ Error
+ end;
+@@ -52,49 +56,45 @@ init(File, PrevHandler) ->
+ process_flag(trap_exit, true),
+ case file:open(File, [write]) of
+ {ok,Fd} ->
+- {ok, {Fd, File, PrevHandler}};
++ Depth = get_depth(),
++ State = #st{fd=Fd,filename=File,prev_handler=PrevHandler,
++ depth=Depth},
++ {ok, State};
+ Error ->
+ Error
+ end.
+-
++
++get_depth() ->
++ case application:get_env(kernel, error_logger_format_depth) of
++ {ok, Depth} when is_integer(Depth) ->
++ max(10, Depth);
++ undefined ->
++ unlimited
++ end.
++
+ handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() ->
+ {ok, State};
+-handle_event(Event, {Fd, File, PrevHandler}) ->
+- write_event(Fd, tag_event(Event)),
+- {ok, {Fd, File, PrevHandler}};
+-handle_event(_, State) ->
++handle_event(Event, State) ->
++ write_event(State, Event),
+ {ok, State}.
+
+-handle_info({'EXIT', Fd, _Reason}, {Fd, _File, PrevHandler}) ->
++handle_info({'EXIT', Fd, _Reason}, #st{fd=Fd,prev_handler=PrevHandler}) ->
+ case PrevHandler of
+ [] ->
+ remove_handler;
+ _ ->
+ {swap_handler, install_prev, [], PrevHandler, go_back}
+ end;
+-handle_info({emulator, GL, Chars}, {Fd, File, PrevHandler})
+- when node(GL) == node() ->
+- write_event(Fd, tag_event({emulator, GL, Chars})),
+- {ok, {Fd, File, PrevHandler}};
+-handle_info({emulator, noproc, Chars}, {Fd, File, PrevHandler}) ->
+- write_event(Fd, tag_event({emulator, noproc, Chars})),
+- {ok, {Fd, File, PrevHandler}};
+ handle_info(_, State) ->
+ {ok, State}.
+
+-handle_call(filename, {Fd, File, Prev}) ->
+- {ok, File, {Fd, File, Prev}};
++handle_call(filename, #st{filename=File}=State) ->
++ {ok, File, State};
+ handle_call(_Query, State) ->
+ {ok, {error, bad_query}, State}.
+
+-terminate(_Reason, State) ->
+- case State of
+- {Fd, _File, _Prev} ->
+- ok = file:close(Fd);
+- _ ->
+- ok
+- end,
+- [].
++terminate(_Reason, #st{fd=Fd}) ->
++ file:close(Fd).
+
+ code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+@@ -103,69 +103,71 @@ code_change(_OldVsn, State, _Extra) ->
+ %%% Misc. functions.
+ %%% ------------------------------------------------------
+
+-tag_event(Event) ->
+- {erlang:universaltime(), Event}.
++write_events(State, [Ev|Es]) ->
++ %% Write the events in reversed order.
++ write_events(State, Es),
++ write_event(State, Ev);
++write_events(_State, []) ->
++ ok.
+
+-write_events(Fd, Events) -> write_events1(Fd, lists:reverse(Events)).
++write_event(#st{fd=Fd}=State, Event) ->
++ case parse_event(Event) of
++ ignore ->
++ ok;
++ {Head,Pid,FormatList} ->
++ Time = maybe_utc(erlang:universaltime()),
++ Header = write_time(Time, Head),
++ Body = format_body(State, FormatList),
++ AtNode = if
++ node(Pid) =/= node() ->
++ ["** at node ",atom_to_list(node(Pid))," **\n"];
++ true ->
++ []
++ end,
++ io:put_chars(Fd, [Header,Body,AtNode])
++ end.
+
+-write_events1(Fd, [Event|Es]) ->
+- write_event(Fd, Event),
+- write_events1(Fd, Es);
+-write_events1(_, []) ->
+- ok.
++format_body(State, [{Format,Args}|T]) ->
++ S = try format(State, Format, Args) of
++ S0 ->
++ S0
++ catch
++ _:_ ->
++ format(State, "ERROR: ~p - ~p\n", [Format,Args])
++ end,
++ [S|format_body(State, T)];
++format_body(_State, []) ->
++ [].
+
+-write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) ->
+- T = write_time(maybe_utc(Time)),
+- case catch io_lib:format(add_node(Format,Pid), Args) of
+- S when is_list(S) ->
+- io:format(Fd, T ++ S, []);
+- _ ->
+- F = add_node("ERROR: ~p - ~p~n", Pid),
+- io:format(Fd, T ++ F, [Format,Args])
+- end;
+-write_event(Fd, {Time, {emulator, _GL, Chars}}) ->
+- T = write_time(maybe_utc(Time)),
+- case catch io_lib:format(Chars, []) of
+- S when is_list(S) ->
+- io:format(Fd, T ++ S, []);
+- _ ->
+- io:format(Fd, T ++ "ERROR: ~p ~n", [Chars])
+- end;
+-write_event(Fd, {Time, {info, _GL, {Pid, Info, _}}}) ->
+- T = write_time(maybe_utc(Time)),
+- io:format(Fd, T ++ add_node("~p~n",Pid),[Info]);
+-write_event(Fd, {Time, {error_report, _GL, {Pid, std_error, Rep}}}) ->
+- T = write_time(maybe_utc(Time)),
+- S = format_report(Rep),
+- io:format(Fd, T ++ S ++ add_node("", Pid), []);
+-write_event(Fd, {Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
+- T = write_time(maybe_utc(Time), "INFO REPORT"),
+- S = format_report(Rep),
+- io:format(Fd, T ++ S ++ add_node("", Pid), []);
+-write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
+- T = write_time(maybe_utc(Time), "INFO REPORT"),
+- case catch io_lib:format(add_node(Format,Pid), Args) of
+- S when is_list(S) ->
+- io:format(Fd, T ++ S, []);
+- _ ->
+- F = add_node("ERROR: ~p - ~p~n", Pid),
+- io:format(Fd, T ++ F, [Format,Args])
+- end;
+-write_event(Fd, {Time, {warning_report, _GL, {Pid, std_warning, Rep}}}) ->
+- T = write_time(maybe_utc(Time), "WARNING REPORT"),
+- S = format_report(Rep),
+- io:format(Fd, T ++ S ++ add_node("", Pid), []);
+-write_event(Fd, {Time, {warning_msg, _GL, {Pid, Format, Args}}}) ->
+- T = write_time(maybe_utc(Time), "WARNING REPORT"),
+- case catch io_lib:format(add_node(Format,Pid), Args) of
+- S when is_list(S) ->
+- io:format(Fd, T ++ S, []);
+- _ ->
+- F = add_node("ERROR: ~p - ~p~n", Pid),
+- io:format(Fd, T ++ F, [Format,Args])
+- end;
+-write_event(_, _) ->
+- ok.
++format(#st{depth=unlimited}, Format, Args) ->
++ io_lib:format(Format, Args);
++format(#st{depth=Depth}, Format0, Args) ->
++ Format1 = io_lib:scan_format(Format0, Args),
++ Format = limit_format(Format1, Depth),
++ io_lib:build_text(Format).
++
++limit_format([{C0,As,F,Ad,P,Pad,Enc,Str}|T], Depth) when C0 =:= $p;
++ C0 =:= $w ->
++ C = C0 - ($a - $A), %To uppercase.
++ [{C,As++[Depth],F,Ad,P,Pad,Enc,Str}||limit_format(T, Depth)];
++limit_format([H|T], Depth) ->
++ [H|limit_format(T, Depth)];
++limit_format([], _) ->
++ [].
++
++parse_event({error, _GL, {Pid, Format, Args}}) ->
++ {"ERROR REPORT",Pid,[{Format,Args}]};
++parse_event({info_msg, _GL, {Pid, Format, Args}}) ->
++ {"INFO REPORT",Pid,[{Format, Args}]};
++parse_event({warning_msg, _GL, {Pid, Format, Args}}) ->
++ {"WARNING REPORT",Pid,[{Format,Args}]};
++parse_event({error_report, _GL, {Pid, std_error, Args}}) ->
++ {"ERROR REPORT",Pid,format_term(Args)};
++parse_event({info_report, _GL, {Pid, std_info, Args}}) ->
++ {"INFO REPORT",Pid,format_term(Args)};
++parse_event({warning_report, _GL, {Pid, std_warning, Args}}) ->
++ {"WARNING REPORT",Pid,format_term(Args)};
++parse_event(_) -> ignore.
+
+ maybe_utc(Time) ->
+ UTC = case application:get_env(sasl, utc_log) of
+@@ -182,30 +184,27 @@ maybe_utc(Time) ->
+ maybe_utc(Time, true) -> {utc, Time};
+ maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}.
+
+-format_report(Rep) when is_list(Rep) ->
+- case string_p(Rep) of
++format_term(Term) when is_list(Term) ->
++ case string_p(Term) of
+ true ->
+- io_lib:format("~s~n",[Rep]);
+- _ ->
+- format_rep(Rep)
++ [{"~s\n",[Term]}];
++ false ->
++ format_term_list(Term)
+ end;
+-format_report(Rep) ->
+- io_lib:format("~p~n",[Rep]).
+-
+-format_rep([{Tag,Data}|Rep]) ->
+- io_lib:format(" ~p: ~p~n",[Tag,Data]) ++ format_rep(Rep);
+-format_rep([Other|Rep]) ->
+- io_lib:format(" ~p~n",[Other]) ++ format_rep(Rep);
+-format_rep(_) ->
++format_term(Term) ->
++ [{"~p\n",[Term]}].
++
++format_term_list([{Tag,Data}|T]) ->
++ [{" ~p: ~p\n",[Tag,Data]}|format_term_list(T)];
++format_term_list([Data|T]) ->
++ [{" ~p\n",[Data]}|format_term_list(T)];
++format_term_list([]) ->
++ [];
++format_term_list(_) ->
++ %% Continue to allow non-proper lists for now.
++ %% FIXME: Remove this clause in OTP 19.
+ [].
+
+-add_node(X, Pid) when is_atom(X) ->
+- add_node(atom_to_list(X), Pid);
+-add_node(X, Pid) when node(Pid) =/= node() ->
+- lists:concat([X,"** at node ",node(Pid)," **~n"]);
+-add_node(X, _) ->
+- X.
+-
+ string_p([]) ->
+ false;
+ string_p(Term) ->
+@@ -221,15 +220,10 @@ string_p1([$\b|T]) -> string_p1(T);
+ string_p1([$\f|T]) -> string_p1(T);
+ string_p1([$\e|T]) -> string_p1(T);
+ string_p1([H|T]) when is_list(H) ->
+- case string_p1(H) of
+- true -> string_p1(T);
+- _ -> false
+- end;
++ string_p1(H) andalso string_p1(T);
+ string_p1([]) -> true;
+ string_p1(_) -> false.
+
+-write_time(Time) -> write_time(Time, "ERROR REPORT").
+-
+ write_time({utc,{{Y,Mo,D},{H,Mi,S}}}, Type) ->
+ io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
+ [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
+diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl
+index ad5891f..72a052f 100644
+--- a/lib/stdlib/src/error_logger_tty_h.erl
++++ b/lib/stdlib/src/error_logger_tty_h.erl
+@@ -22,144 +22,178 @@
+
+ %%%
+ %%% A handler that can be connected to the error_logger
+-%%% event handler.
+-%%% Writes all events formatted to stdout.
+-%%% Handles events tagged error, emulator and info.
++%%% event handler. Writes all events formatted to stdout.
+ %%%
+ %%% It can only be started from error_logger:swap_handler(tty)
+-%%% or error_logger:tty(true)
++%%% or error_logger:tty(true).
+ %%%
+
+ -export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+--export([write_event/2]).
++-export([write_event/2,write_event/3]).
++
++-record(st,
++ {user,
++ prev_handler,
++ io_mod=io,
++ depth=unlimited}).
+
+ %% This one is used when we takeover from the simple error_logger.
+ init({[], {error_logger, Buf}}) ->
+ User = set_group_leader(),
+- write_events(Buf,io),
+- {ok, {User, error_logger}};
++ Depth = get_depth(),
++ State = #st{user=User,prev_handler=error_logger,depth=Depth},
++ write_events(State, Buf),
++ {ok, State};
+ %% This one is used if someone took over from us, and now wants to
+ %% go back.
+ init({[], {error_logger_tty_h, PrevHandler}}) ->
+ User = set_group_leader(),
+- {ok, {User, PrevHandler}};
++ {ok, #st{user=User,prev_handler=PrevHandler}};
+ %% This one is used when we are started directly.
+ init([]) ->
+ User = set_group_leader(),
+- {ok, {User, []}}.
++ Depth = get_depth(),
++ {ok, #st{user=User,prev_handler=[],depth=Depth}}.
++
++get_depth() ->
++ case application:get_env(kernel, error_logger_format_depth) of
++ {ok, Depth} when is_integer(Depth) ->
++ max(10, Depth);
++ undefined ->
++ unlimited
++ end.
+
+ handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() ->
+ {ok, State};
+ handle_event(Event, State) ->
+- write_event(tag_event(Event),io),
++ ok = do_write_event(State, tag_event(Event)),
+ {ok, State}.
+
+-handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) ->
++handle_info({'EXIT', User, _Reason},
++ #st{user=User,prev_handler=PrevHandler}=State) ->
+ case PrevHandler of
+ [] ->
+ remove_handler;
+ _ ->
+- {swap_handler, install_prev, {User, PrevHandler},
++ {swap_handler, install_prev, State,
+ PrevHandler, go_back}
+ end;
+-handle_info({emulator, GL, Chars}, State) when node(GL) == node() ->
+- write_event(tag_event({emulator, GL, Chars}),io),
+- {ok, State};
+-handle_info({emulator, noproc, Chars}, State) ->
+- write_event(tag_event({emulator, noproc, Chars}),io),
+- {ok, State};
+ handle_info(_, State) ->
+ {ok, State}.
+
+ handle_call(_Query, State) -> {ok, {error, bad_query}, State}.
+
+-% unfortunately, we can't unlink from User - links are not counted!
+-% if pid(User) -> unlink(User); true -> ok end,
+ terminate(install_prev, _State) ->
+ [];
+-terminate(_Reason, {_User, PrevHandler}) ->
++terminate(_Reason, #st{prev_handler=PrevHandler}) ->
+ {error_logger_tty_h, PrevHandler}.
+
+ code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
++%% Exported (but unoffical) API.
++write_event(Event, IoMod) ->
++ do_write_event(#st{io_mod=IoMod}, Event).
++
++write_event(Event, IoMod, Depth) ->
++ do_write_event(#st{io_mod=IoMod,depth=Depth}, Event).
++
++
+ %%% ------------------------------------------------------
+ %%% Misc. functions.
+ %%% ------------------------------------------------------
+
+ set_group_leader() ->
+ case whereis(user) of
+- User when is_pid(User) -> link(User), group_leader(User,self()), User;
+- _ -> false
++ User when is_pid(User) ->
++ link(User),
++ group_leader(User,self()),
++ User;
++ _ ->
++ false
+ end.
+
+ tag_event(Event) ->
+ {erlang:universaltime(), Event}.
+
+-write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod).
+-
+-write_events1([Event|Es],IOMod) ->
+- write_event(Event,IOMod),
+- write_events1(Es,IOMod);
+-write_events1([],_IOMod) ->
++write_events(State, [Ev|Es]) ->
++ %% Write the events in reverse order.
++ _ = write_events(State, Es),
++ _ = do_write_event(State, Ev),
++ ok;
++write_events(_State, []) ->
+ ok.
+
+-write_event({Time, {error, _GL, {Pid, Format, Args}}},IOMod) ->
+- T = write_time(maybe_utc(Time)),
+- case catch io_lib:format(add_node(Format,Pid), Args) of
+- S when is_list(S) ->
+- format(IOMod, T ++ S);
+- _ ->
+- F = add_node("ERROR: ~p - ~p~n", Pid),
+- format(IOMod, T ++ F, [Format,Args])
++do_write_event(State, {Time0, Event}) ->
++ case parse_event(Event) of
++ ignore ->
++ ok;
++ {Head,Pid,FormatList} ->
++ Time = maybe_utc(Time0),
++ Header = write_time(Time, Head),
++ Body = format_body(State, FormatList),
++ AtNode = if
++ node(Pid) =/= node() ->
++ ["** at node ",atom_to_list(node(Pid))," **\n"];
++ true ->
++ []
++ end,
++ Str = [Header,Body,AtNode],
++ case State#st.io_mod of
++ io_lib ->
++ Str;
++ io ->
++ io:put_chars(user, Str)
++ end
+ end;
+-write_event({Time, {emulator, _GL, Chars}},IOMod) ->
+- T = write_time(maybe_utc(Time)),
+- case catch io_lib:format(Chars, []) of
+- S when is_list(S) ->
+- format(IOMod, T ++ S);
+- _ ->
+- format(IOMod, T ++ "ERROR: ~p ~n", [Chars])
+- end;
+-write_event({Time, {info, _GL, {Pid, Info, _}}},IOMod) ->
+- T = write_time(maybe_utc(Time)),
+- format(IOMod, T ++ add_node("~p~n",Pid),[Info]);
+-write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}},IOMod) ->
+- T = write_time(maybe_utc(Time)),
+- S = format_report(Rep),
+- format(IOMod, T ++ S ++ add_node("", Pid));
+-write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}},IOMod) ->
+- T = write_time(maybe_utc(Time), "INFO REPORT"),
+- S = format_report(Rep),
+- format(IOMod, T ++ S ++ add_node("", Pid));
+-write_event({Time, {info_msg, _GL, {Pid, Format, Args}}},IOMod) ->
+- T = write_time(maybe_utc(Time), "INFO REPORT"),
+- case catch io_lib:format(add_node(Format,Pid), Args) of
+- S when is_list(S) ->
+- format(IOMod, T ++ S);
+- _ ->
+- F = add_node("ERROR: ~p - ~p~n", Pid),
+- format(IOMod, T ++ F, [Format,Args])
+- end;
+-write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}},IOMod) ->
+- T = write_time(maybe_utc(Time), "WARNING REPORT"),
+- S = format_report(Rep),
+- format(IOMod, T ++ S ++ add_node("", Pid));
+-write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}},IOMod) ->
+- T = write_time(maybe_utc(Time), "WARNING REPORT"),
+- case catch io_lib:format(add_node(Format,Pid), Args) of
+- S when is_list(S) ->
+- format(IOMod, T ++ S);
+- _ ->
+- F = add_node("ERROR: ~p - ~p~n", Pid),
+- format(IOMod, T ++ F, [Format,Args])
+- end;
+-write_event({_Time, _Error},_IOMod) ->
++do_write_event(_, _) ->
+ ok.
+
++format_body(State, [{Format,Args}|T]) ->
++ S = try format(State, Format, Args) of
++ S0 ->
++ S0
++ catch
++ _:_ ->
++ format(State, "ERROR: ~p - ~p\n", [Format,Args])
++ end,
++ [S|format_body(State, T)];
++format_body(_State, []) ->
++ [].
++
++format(#st{depth=unlimited}, Format, Args) ->
++ io_lib:format(Format, Args);
++format(#st{depth=Depth}, Format0, Args) ->
++ Format1 = io_lib:scan_format(Format0, Args),
++ Format = limit_format(Format1, Depth),
++ io_lib:build_text(Format).
++
++limit_format([{C0,As,F,Ad,P,Pad,Enc,Str}|T], Depth) when C0 =:= $p;
++ C0 =:= $w ->
++ C = C0 - ($a - $A), %To uppercase.
++ [{C,As++[Depth],F,Ad,P,Pad,Enc,Str}|limit_format(T, Depth)];
++limit_format([H|T], Depth) ->
++ [H|limit_format(T, Depth)];
++limit_format([], _) ->
++ [].
++
++parse_event({error, _GL, {Pid, Format, Args}}) ->
++ {"ERROR REPORT",Pid,[{Format,Args}]};
++parse_event({info_msg, _GL, {Pid, Format, Args}}) ->
++ {"INFO REPORT",Pid,[{Format, Args}]};
++parse_event({warning_msg, _GL, {Pid, Format, Args}}) ->
++ {"WARNING REPORT",Pid,[{Format,Args}]};
++parse_event({error_report, _GL, {Pid, std_error, Args}}) ->
++ {"ERROR REPORT",Pid,format_term(Args)};
++parse_event({info_report, _GL, {Pid, std_info, Args}}) ->
++ {"INFO REPORT",Pid,format_term(Args)};
++parse_event({warning_report, _GL, {Pid, std_warning, Args}}) ->
++ {"WARNING REPORT",Pid,format_term(Args)};
++parse_event(_) -> ignore.
++
+ maybe_utc(Time) ->
+ UTC = case application:get_env(sasl, utc_log) of
+ {ok, Val} -> Val;
+@@ -175,33 +209,26 @@ maybe_utc(Time) ->
+ maybe_utc(Time, true) -> {utc, Time};
+ maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}.
+
+-format(IOMod, String) -> format(IOMod, String, []).
+-format(io_lib, String, Args) -> io_lib:format(String, Args);
+-format(io, String, Args) -> io:format(user, String, Args).
+-
+-format_report(Rep) when is_list(Rep) ->
+- case string_p(Rep) of
++format_term(Term) when is_list(Term) ->
++ case string_p(Term) of
+ true ->
+- io_lib:format("~s~n",[Rep]);
+- _ ->
+- format_rep(Rep)
++ [{"~s\n",[Term]}];
++ false ->
++ format_term_list(Term)
+ end;
+-format_report(Rep) ->
+- io_lib:format("~p~n",[Rep]).
+-
+-format_rep([{Tag,Data}|Rep]) ->
+- io_lib:format(" ~p: ~p~n",[Tag,Data]) ++ format_rep(Rep);
+-format_rep([Other|Rep]) ->
+- io_lib:format(" ~p~n",[Other]) ++ format_rep(Rep);
+-format_rep(_) ->
+- [].
++format_term(Term) ->
++ [{"~p\n",[Term]}].
+
+-add_node(X, Pid) when is_atom(X) ->
+- add_node(atom_to_list(X), Pid);
+-add_node(X, Pid) when node(Pid) =/= node() ->
+- lists:concat([X,"** at node ",node(Pid)," **~n"]);
+-add_node(X, _) ->
+- X.
++format_term_list([{Tag,Data}|T]) ->
++ [{" ~p: ~p\n",[Tag,Data]}|format_term_list(T)];
++format_term_list([Data|T]) ->
++ [{" ~p\n",[Data]}|format_term_list(T)];
++format_term_list([]) ->
++ [];
++format_term_list(_) ->
++ %% Continue to allow non-proper lists for now.
++ %% FIXME: Remove this clause in OTP 19.
++ [].
+
+ string_p([]) ->
+ false;
+@@ -225,7 +252,6 @@ string_p1([H|T]) when is_list(H) ->
+ string_p1([]) -> true;
+ string_p1(_) -> false.
+
+-write_time(Time) -> write_time(Time, "ERROR REPORT").
+ write_time({utc,{{Y,Mo,D},{H,Mi,S}}},Type) ->
+ io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
+ [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
+diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
+index 9e69601..3c173dc 100644
+--- a/lib/stdlib/src/io_lib.erl
++++ b/lib/stdlib/src/io_lib.erl
+@@ -2,7 +2,7 @@
+ %%
+ %% %CopyrightBegin%
+ %%
+-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
++%% Copyright Ericsson AB 1996-2014. 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
+@@ -61,6 +61,7 @@
+ -module(io_lib).
+
+ -export([fwrite/2,fread/2,fread/3,format/2]).
++-export([scan_format/2,unscan_format/1,build_text/1]).
+ -export([print/1,print/4,indentation/2]).
+
+ -export([write/1,write/2,write/3,nl/0,format_prompt/1,format_prompt/2]).
+@@ -84,7 +85,7 @@
+ deep_unicode_char_list/1]).
+
+ -export_type([chars/0, latin1_string/0, continuation/0,
+- fread_error/0, fread_item/0]).
++ fread_error/0, fread_item/0, format_spec/0]).
+
+ %%----------------------------------------------------------------------
+
+@@ -109,6 +110,18 @@
+
+ -type fread_item() :: string() | atom() | integer() | float().
+
++-type format_spec() ::
++ {
++ ControlChar :: char(),
++ Args :: [any()],
++ Width :: 'none' | integer(),
++ Adjust :: 'left' | 'right',
++ Precision :: 'none' | integer(),
++ PadChar :: char(),
++ Encoding :: 'unicode' | 'latin1',
++ Strings :: boolean()
++ }.
++
+ %%----------------------------------------------------------------------
+
+ %% Interface calls to sub-modules.
+@@ -157,6 +170,31 @@ format(Format, Args) ->
+ Other
+ end.
+
++-spec scan_format(Format, Data) -> FormatList when
++ Format :: io:format(),
++ Data :: [term()],
++ FormatList :: [char() | format_spec()].
++
++scan_format(Format, Args) ->
++ try io_lib_format:scan(Format, Args)
++ catch
++ _:_ -> erlang:error(badarg, [Format, Args])
++ end.
++
++-spec unscan_format(FormatList) -> {Format, Data} when
++ FormatList :: [char() | format_spec()],
++ Format :: io:format(),
++ Data :: [term()].
++
++unscan_format(FormatList) ->
++ io_lib_format:unscan(FormatList).
++
++-spec build_text(FormatList) -> chars() when
++ FormatList :: [char() | format_spec()].
++
++build_text(FormatList) ->
++ io_lib_format:build(FormatList).
++
+ -spec print(Term) -> chars() when
+ Term :: term().
+
+diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
+index 56e15a1..37b47d7 100644
+--- a/lib/stdlib/src/io_lib_format.erl
++++ b/lib/stdlib/src/io_lib_format.erl
+@@ -1,7 +1,7 @@
+ %%
+ %% %CopyrightBegin%
+ %%
+-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
++%% Copyright Ericsson AB 1996-2014. 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
+@@ -20,10 +20,9 @@
+
+ %% Formatting functions of io library.
+
+--export([fwrite/2,fwrite_g/1,indentation/2]).
++-export([fwrite/2,fwrite_g/1,indentation/2,scan/2,unscan/1,build/1]).
+
+-%% fwrite(Format, ArgList) -> string().
+-%% Format the arguments in ArgList after string Format. Just generate
++%% Format the arguments in Args after string Format. Just generate
+ %% an error if there is an error in the arguments.
+ %%
+ %% To do the printing command correctly we need to calculate the
+@@ -37,15 +36,83 @@
+ %% and it also splits the handling of the control characters into two
+ %% parts.
+
+-fwrite(Format, Args) when is_atom(Format) ->
+- fwrite(atom_to_list(Format), Args);
+-fwrite(Format, Args) when is_binary(Format) ->
+- fwrite(binary_to_list(Format), Args);
++-spec fwrite(Format, Data) -> FormatList when
++ Format :: io:format(),
++ Data :: [term()],
++ FormatList :: [char() | io_lib:format_spec()].
++
+ fwrite(Format, Args) ->
+- Cs = collect(Format, Args),
++ build(scan(Format, Args)).
++
++%% Build the output text for a pre-parsed format list.
++
++-spec build(FormatList) -> io_lib:chars() when
++ FormatList :: [char() | io_lib:format_spec()].
++
++build(Cs) ->
+ Pc = pcount(Cs),
+ build(Cs, Pc, 0).
+
++%% Parse all control sequences in the format string.
++
++-spec scan(Format, Data) -> FormatList when
++ Format :: io:format(),
++ Data :: [term()],
++ FormatList :: [char() | io_lib:format_spec()].
++
++scan(Format, Args) when is_atom(Format) ->
++ scan(atom_to_list(Format), Args);
++scan(Format, Args) when is_binary(Format) ->
++ scan(binary_to_list(Format), Args);
++scan(Format, Args) ->
++ collect(Format, Args).
++
++%% Revert a pre-parsed format list to a plain character list and a
++%% list of arguments.
++
++-spec unscan(FormatList) -> {Format, Data} when
++ FormatList :: [char() | io_lib:format_spec()],
++ Format :: io:format(),
++ Data :: [term()].
++
++unscan(Cs) ->
++ {print(Cs), args(Cs)}.
++
++args([{_C,As,_F,_Ad,_P,_Pad,_Enc,_Str} | Cs]) ->
++ As ++ args(Cs);
++args([_C | Cs]) ->
++ args(Cs);
++args([]) ->
++ [].
++
++print([{C,_As,F,Ad,P,Pad,Enc,Str} | Cs ]) ->
++ print(C, F, Ad, P, Pad, Enc, Str) ++ print(Cs);
++print([C | Cs]) ->
++ [C | print(Cs)];
++print([]) ->
++ [].
++
++print(C, F, Ad, P, Pad, Encoding, Strings) ->
++ [$~] ++ print_field_width(F, Ad) ++ print_precision(P) ++
++ print_pad_char(Pad) ++ print_encoding(Encoding) ++
++ print_strings(Strings) ++ [C].
++
++print_field_width(none, _Ad) -> "";
++print_field_width(F, left) -> integer_to_list(-F);
++print_field_width(F, right) -> integer_to_list(F).
++
++print_precision(none) -> "";
++print_precision(P) -> [$. | integer_to_list(P)].
++
++print_pad_char($\s) -> ""; % default, no need to make explicit
++print_pad_char(Pad) -> [$., Pad].
++
++print_encoding(unicode) -> "t";
++print_encoding(latin1) -> "".
++
++print_strings(false) -> "l";
++print_strings(true) -> "".
++
+ collect([$~|Fmt0], Args0) ->
+ {C,Fmt1,Args1} = collect_cseq(Fmt0, Args0),
+ [C|collect(Fmt1, Args1)];
+@@ -141,7 +208,7 @@ pcount([{$P,_As,_F,_Ad,_P,_Pad,_Enc,_Str}|Cs], Acc) -> pcount(Cs, Acc+1);
+ pcount([_|Cs], Acc) -> pcount(Cs, Acc);
+ pcount([], Acc) -> Acc.
+
+-%% build([Control], Pc, Indentation) -> string().
++%% build([Control], Pc, Indentation) -> io_lib:chars().
+ %% Interpret the control structures. Count the number of print
+ %% remaining and only calculate indentation when necessary. Must also
+ %% be smart when calculating indentation for characters in format.
+@@ -162,10 +229,14 @@ decr_pc($p, Pc) -> Pc - 1;
+ decr_pc($P, Pc) -> Pc - 1;
+ decr_pc(_, Pc) -> Pc.
+
+-%% indentation(String, Indentation) -> Indentation.
++
+ %% Calculate the indentation of the end of a string given its start
+ %% indentation. We assume tabs at 8 cols.
+
++-spec indentation(String, StartIndent) -> integer() when
++ String :: io_lib:chars(),
++ StartIndent :: integer().
++
+ indentation([$\n|Cs], _I) -> indentation(Cs, 0);
+ indentation([$\t|Cs], I) -> indentation(Cs, ((I + 8) div 8) * 8);
+ indentation([C|Cs], I) when is_integer(C) ->
+@@ -366,7 +437,6 @@ float_data([D|Cs], Ds) when D >= $0, D =< $9 ->
+ float_data([_|Cs], Ds) ->
+ float_data(Cs, Ds).
+
+-%% fwrite_g(Float)
+ %% Writes the shortest, correctly rounded string that converts
+ %% to Float when read back with list_to_float/1.
+ %%
+@@ -374,6 +444,8 @@ float_data([_|Cs], Ds) ->
+ %% in Proceedings of the SIGPLAN '96 Conference on Programming
+ %% Language Design and Implementation.
+
++-spec fwrite_g(float()) -> string().
++
+ fwrite_g(0.0) ->
+ "0.0";
+ fwrite_g(Float) when is_float(Float) ->
+@@ -642,7 +714,7 @@ prefixed_integer(Int, F, Adj, Base, Pad, Prefix, Lowercase)
+ term([Prefix|S], F, Adj, none, Pad)
+ end.
+
+-%% char(Char, Field, Adjust, Precision, PadChar) -> string().
++%% char(Char, Field, Adjust, Precision, PadChar) -> chars().
+
+ char(C, none, _Adj, none, _Pad) -> [C];
+ char(C, F, _Adj, none, _Pad) -> chars(C, F);
diff --git a/otp-0025-Teach-sasl_report-to-limit-crash-reports.patch b/otp-0025-Teach-sasl_report-to-limit-crash-reports.patch
new file mode 100644
index 0000000..e9e6450
--- /dev/null
+++ b/otp-0025-Teach-sasl_report-to-limit-crash-reports.patch
@@ -0,0 +1,74 @@
+From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?=
+Date: Tue, 25 Aug 2015 15:20:23 +0200
+Subject: [PATCH] Teach sasl_report to limit crash reports
+
+
+diff --git a/lib/sasl/src/sasl_report.erl b/lib/sasl/src/sasl_report.erl
+index c3e6fed..aa84e4f 100644
+--- a/lib/sasl/src/sasl_report.erl
++++ b/lib/sasl/src/sasl_report.erl
+@@ -61,27 +61,53 @@ write_report2(IO, Fd, Head, supervisor_report, Report) ->
+ Context = sup_get(errorContext, Report),
+ Reason = sup_get(reason, Report),
+ Offender = sup_get(offender, Report),
+- FmtString = " Supervisor: ~p~n Context: ~p~n Reason: "
+- "~80.18p~n Offender: ~80.18p~n~n",
+- write_report_action(IO, Fd, Head ++ FmtString,
+- [Name,Context,Reason,Offender]);
++ {FmtString,Args} = supervisor_format([Name,Context,Reason,Offender]),
++ write_report_action(IO, Fd, Head, FmtString, Args);
+ write_report2(IO, Fd, Head, progress, Report) ->
+ Format = format_key_val(Report),
+- write_report_action(IO, Fd, Head ++ "~s", [Format]);
++ write_report_action(IO, Fd, Head, "~s", [Format]);
+ write_report2(IO, Fd, Head, crash_report, Report) ->
+- Format = proc_lib:format(Report),
+- write_report_action(IO, Fd, Head ++ "~s", [Format]).
++ Depth = get_depth(),
++ Format = proc_lib:format(Report, latin1, Depth),
++ write_report_action(IO, Fd, Head, "~s", [Format]).
++
++supervisor_format(Args0) ->
++ case get_depth() of
++ unlimited ->
++ {" Supervisor: ~p~n"
++ " Context: ~p~n"
++ " Reason: ~80.18p~n"
++ " Offender: ~80.18p~n~n",
++ Args0};
++ Depth ->
++ [A,B,C,D] = Args0,
++ Args = [A,Depth,B,Depth,C,Depth,D,Depth],
++ {" Supervisor: ~P~n"
++ " Context: ~P~n"
++ " Reason: ~80.18P~n"
++ " Offender: ~80.18P~n~n",
++ Args}
++ end.
+
+-write_report_action(io, Fd, Format, Args) ->
+- io:format(Fd, Format, Args);
+-write_report_action(io_lib, _Fd, Format, Args) ->
+- io_lib:format(Format, Args).
++write_report_action(IO, Fd, Head, Format, Args) ->
++ S = [Head|io_lib:format(Format, Args)],
++ case IO of
++ io -> io:put_chars(Fd, S);
++ io_lib -> S
++ end.
+
+ format_key_val([{Tag,Data}|Rep]) ->
+ io_lib:format(" ~16w: ~p~n",[Tag,Data]) ++ format_key_val(Rep);
+ format_key_val(_) ->
+ [].
+
++get_depth() ->
++ case application:get_env(kernel, error_logger_format_depth) of
++ {ok, Depth} when is_integer(Depth) ->
++ max(10, Depth);
++ undefined ->
++ unlimited
++ end.
+
+ sup_get(Tag, Report) ->
+ case lists:keysearch(Tag, 1, Report) of
diff --git a/otp-0026-Revert-Remove-unused-code-in-error-logger-handlers.patch b/otp-0026-Revert-Remove-unused-code-in-error-logger-handlers.patch
new file mode 100644
index 0000000..dda297d
--- /dev/null
+++ b/otp-0026-Revert-Remove-unused-code-in-error-logger-handlers.patch
@@ -0,0 +1,1064 @@
+From: Peter Lemenkov
+Date: Wed, 9 Nov 2016 17:28:28 +0300
+Subject: [PATCH] Revert "Remove unused code in error logger handlers"
+
+This reverts commit f022259a41dbf5b078bea38fd3a7b98f0d4ed587.
+
+Revert "Teach sasl_report to limit crash reports"
+
+This reverts commit 33254666c90aedb190c6cffe36a027053918d92c.
+
+diff --git a/lib/sasl/src/sasl_report.erl b/lib/sasl/src/sasl_report.erl
+index aa84e4f..c3e6fed 100644
+--- a/lib/sasl/src/sasl_report.erl
++++ b/lib/sasl/src/sasl_report.erl
+@@ -61,53 +61,27 @@ write_report2(IO, Fd, Head, supervisor_report, Report) ->
+ Context = sup_get(errorContext, Report),
+ Reason = sup_get(reason, Report),
+ Offender = sup_get(offender, Report),
+- {FmtString,Args} = supervisor_format([Name,Context,Reason,Offender]),
+- write_report_action(IO, Fd, Head, FmtString, Args);
++ FmtString = " Supervisor: ~p~n Context: ~p~n Reason: "
++ "~80.18p~n Offender: ~80.18p~n~n",
++ write_report_action(IO, Fd, Head ++ FmtString,
++ [Name,Context,Reason,Offender]);
+ write_report2(IO, Fd, Head, progress, Report) ->
+ Format = format_key_val(Report),
+- write_report_action(IO, Fd, Head, "~s", [Format]);
++ write_report_action(IO, Fd, Head ++ "~s", [Format]);
+ write_report2(IO, Fd, Head, crash_report, Report) ->
+- Depth = get_depth(),
+- Format = proc_lib:format(Report, latin1, Depth),
+- write_report_action(IO, Fd, Head, "~s", [Format]).
+-
+-supervisor_format(Args0) ->
+- case get_depth() of
+- unlimited ->
+- {" Supervisor: ~p~n"
+- " Context: ~p~n"
+- " Reason: ~80.18p~n"
+- " Offender: ~80.18p~n~n",
+- Args0};
+- Depth ->
+- [A,B,C,D] = Args0,
+- Args = [A,Depth,B,Depth,C,Depth,D,Depth],
+- {" Supervisor: ~P~n"
+- " Context: ~P~n"
+- " Reason: ~80.18P~n"
+- " Offender: ~80.18P~n~n",
+- Args}
+- end.
++ Format = proc_lib:format(Report),
++ write_report_action(IO, Fd, Head ++ "~s", [Format]).
+
+-write_report_action(IO, Fd, Head, Format, Args) ->
+- S = [Head|io_lib:format(Format, Args)],
+- case IO of
+- io -> io:put_chars(Fd, S);
+- io_lib -> S
+- end.
++write_report_action(io, Fd, Format, Args) ->
++ io:format(Fd, Format, Args);
++write_report_action(io_lib, _Fd, Format, Args) ->
++ io_lib:format(Format, Args).
+
+ format_key_val([{Tag,Data}|Rep]) ->
+ io_lib:format(" ~16w: ~p~n",[Tag,Data]) ++ format_key_val(Rep);
+ format_key_val(_) ->
+ [].
+
+-get_depth() ->
+- case application:get_env(kernel, error_logger_format_depth) of
+- {ok, Depth} when is_integer(Depth) ->
+- max(10, Depth);
+- undefined ->
+- unlimited
+- end.
+
+ sup_get(Tag, Report) ->
+ case lists:keysearch(Tag, 1, Report) of
+diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml
+index 6613dcd..90f24c4 100644
+--- a/lib/stdlib/doc/src/io.xml
++++ b/lib/stdlib/doc/src/io.xml
+@@ -505,8 +505,7 @@ ok
+
Writes the data with standard syntax in the same way as
+ ~w, but breaks terms whose printed representation
+ is longer than one line into many lines and indents each
+- line sensibly. Left justification is not supported.
+- It also tries to detect lists of
++ line sensibly. It also tries to detect lists of
+ printable characters and to output these as strings. The
+ Unicode translation modifier is used for determining
+ what characters are printable. For example:
+diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml
+index 0c1c84d..68352ff 100644
+--- a/lib/stdlib/doc/src/io_lib.xml
++++ b/lib/stdlib/doc/src/io_lib.xml
+@@ -4,7 +4,7 @@
+
+
+
+- 19962014
++ 19962013
+ Ericsson AB. All Rights Reserved.
+
+
+@@ -59,35 +59,6 @@
+
+
+
+-
+-
+-
Description:
+-
+-
control_char is the type of control
+- sequence: $P, $w, and so on;
+-
+-
args is a list of the arguments used by the
+- control sequence, or an empty list if the control sequence
+- does not take any arguments;
+-
+-
width is the field width;
+-
+-
adjust is the adjustment;
+-
+-
precision is the precision of the printed
+- argument;
+-
+-
pad_char is the padding character;
+-
+-
encoding is set to true if the translation
+- modifier t is present;
+-
+-
strings is set to false if the modifier
+- l is present.
+-
+-
+-
+-
+
+
+
+@@ -289,45 +260,6 @@
+
+
+
+-
+- Parse all control sequences in the format string
+-
+-
Returns a list corresponding to the given format string,
+- where control sequences have been replaced with
+- corresponding tuples. This list can be passed to io_lib:build_text/1 to have
+- the same effect as io_lib:format(Format, Args), or to
+- io_lib:unscan_format/1
+- in order to get the corresponding pair of Format and
+- Args (with every * and corresponding argument
+- expanded to numeric values).
+-
A typical use of this function is to replace unbounded-size
+- control sequences like ~w and ~p with the
+- depth-limited variants ~W and ~P before
+- formatting to text, e.g. in a logger.
+-
+-
+-
+-
+- Revert a pre-parsed format list to a plain character list
+- and a list of arguments
+-
+-
See io_lib:scan_format/2 for
+- details.
+-
+-
+-
+-
+- Build the output text for a pre-parsed format list
+-
+-
See io_lib:scan_format/2 for
+- details.
+-
+-
+-
+
+ Indentation after printing string
+
+diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl
+index ca44d01..e9364ed 100644
+--- a/lib/stdlib/src/error_logger_file_h.erl
++++ b/lib/stdlib/src/error_logger_file_h.erl
+@@ -23,28 +23,24 @@
+
+ %%%
+ %%% A handler that can be connected to the error_logger
+-%%% event handler. Writes all events formatted to file.
++%%% event handler.
++%%% Writes all events formatted to file.
++%%% Handles events tagged error, emulator and info.
+ %%%
+ %%% It can only be started from error_logger:swap_handler({logfile, File})
+-%%% or error_logger:logfile(File).
++%%% or error_logger:logfile(File)
+ %%%
+
+ -export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+--record(st,
+- {fd,
+- filename,
+- prev_handler,
+- depth=unlimited :: 'unlimited' | non_neg_integer()}).
+-
+ %% This one is used when we takeover from the simple error_logger.
+ init({File, {error_logger, Buf}}) ->
+ case init(File, error_logger) of
+- {ok, State} ->
+- write_events(State, Buf),
+- {ok, State};
++ {ok, {Fd, File, PrevHandler}} ->
++ write_events(Fd, Buf),
++ {ok, {Fd, File, PrevHandler}};
+ Error ->
+ Error
+ end;
+@@ -56,45 +52,49 @@ init(File, PrevHandler) ->
+ process_flag(trap_exit, true),
+ case file:open(File, [write]) of
+ {ok,Fd} ->
+- Depth = get_depth(),
+- State = #st{fd=Fd,filename=File,prev_handler=PrevHandler,
+- depth=Depth},
+- {ok, State};
++ {ok, {Fd, File, PrevHandler}};
+ Error ->
+ Error
+ end.
+-
+-get_depth() ->
+- case application:get_env(kernel, error_logger_format_depth) of
+- {ok, Depth} when is_integer(Depth) ->
+- max(10, Depth);
+- undefined ->
+- unlimited
+- end.
+-
++
+ handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() ->
+ {ok, State};
+-handle_event(Event, State) ->
+- write_event(State, Event),
++handle_event(Event, {Fd, File, PrevHandler}) ->
++ write_event(Fd, tag_event(Event)),
++ {ok, {Fd, File, PrevHandler}};
++handle_event(_, State) ->
+ {ok, State}.
+
+-handle_info({'EXIT', Fd, _Reason}, #st{fd=Fd,prev_handler=PrevHandler}) ->
++handle_info({'EXIT', Fd, _Reason}, {Fd, _File, PrevHandler}) ->
+ case PrevHandler of
+ [] ->
+ remove_handler;
+ _ ->
+ {swap_handler, install_prev, [], PrevHandler, go_back}
+ end;
++handle_info({emulator, GL, Chars}, {Fd, File, PrevHandler})
++ when node(GL) == node() ->
++ write_event(Fd, tag_event({emulator, GL, Chars})),
++ {ok, {Fd, File, PrevHandler}};
++handle_info({emulator, noproc, Chars}, {Fd, File, PrevHandler}) ->
++ write_event(Fd, tag_event({emulator, noproc, Chars})),
++ {ok, {Fd, File, PrevHandler}};
+ handle_info(_, State) ->
+ {ok, State}.
+
+-handle_call(filename, #st{filename=File}=State) ->
+- {ok, File, State};
++handle_call(filename, {Fd, File, Prev}) ->
++ {ok, File, {Fd, File, Prev}};
+ handle_call(_Query, State) ->
+ {ok, {error, bad_query}, State}.
+
+-terminate(_Reason, #st{fd=Fd}) ->
+- file:close(Fd).
++terminate(_Reason, State) ->
++ case State of
++ {Fd, _File, _Prev} ->
++ ok = file:close(Fd);
++ _ ->
++ ok
++ end,
++ [].
+
+ code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+@@ -103,71 +103,69 @@ code_change(_OldVsn, State, _Extra) ->
+ %%% Misc. functions.
+ %%% ------------------------------------------------------
+
+-write_events(State, [Ev|Es]) ->
+- %% Write the events in reversed order.
+- write_events(State, Es),
+- write_event(State, Ev);
+-write_events(_State, []) ->
+- ok.
++tag_event(Event) ->
++ {erlang:universaltime(), Event}.
+
+-write_event(#st{fd=Fd}=State, Event) ->
+- case parse_event(Event) of
+- ignore ->
+- ok;
+- {Head,Pid,FormatList} ->
+- Time = maybe_utc(erlang:universaltime()),
+- Header = write_time(Time, Head),
+- Body = format_body(State, FormatList),
+- AtNode = if
+- node(Pid) =/= node() ->
+- ["** at node ",atom_to_list(node(Pid))," **\n"];
+- true ->
+- []
+- end,
+- io:put_chars(Fd, [Header,Body,AtNode])
+- end.
++write_events(Fd, Events) -> write_events1(Fd, lists:reverse(Events)).
+
+-format_body(State, [{Format,Args}|T]) ->
+- S = try format(State, Format, Args) of
+- S0 ->
+- S0
+- catch
+- _:_ ->
+- format(State, "ERROR: ~p - ~p\n", [Format,Args])
+- end,
+- [S|format_body(State, T)];
+-format_body(_State, []) ->
+- [].
+-
+-format(#st{depth=unlimited}, Format, Args) ->
+- io_lib:format(Format, Args);
+-format(#st{depth=Depth}, Format0, Args) ->
+- Format1 = io_lib:scan_format(Format0, Args),
+- Format = limit_format(Format1, Depth),
+- io_lib:build_text(Format).
+-
+-limit_format([{C0,As,F,Ad,P,Pad,Enc,Str}|T], Depth) when C0 =:= $p;
+- C0 =:= $w ->
+- C = C0 - ($a - $A), %To uppercase.
+- [{C,As++[Depth],F,Ad,P,Pad,Enc,Str}||limit_format(T, Depth)];
+-limit_format([H|T], Depth) ->
+- [H|limit_format(T, Depth)];
+-limit_format([], _) ->
+- [].
++write_events1(Fd, [Event|Es]) ->
++ write_event(Fd, Event),
++ write_events1(Fd, Es);
++write_events1(_, []) ->
++ ok.
+
+-parse_event({error, _GL, {Pid, Format, Args}}) ->
+- {"ERROR REPORT",Pid,[{Format,Args}]};
+-parse_event({info_msg, _GL, {Pid, Format, Args}}) ->
+- {"INFO REPORT",Pid,[{Format, Args}]};
+-parse_event({warning_msg, _GL, {Pid, Format, Args}}) ->
+- {"WARNING REPORT",Pid,[{Format,Args}]};
+-parse_event({error_report, _GL, {Pid, std_error, Args}}) ->
+- {"ERROR REPORT",Pid,format_term(Args)};
+-parse_event({info_report, _GL, {Pid, std_info, Args}}) ->
+- {"INFO REPORT",Pid,format_term(Args)};
+-parse_event({warning_report, _GL, {Pid, std_warning, Args}}) ->
+- {"WARNING REPORT",Pid,format_term(Args)};
+-parse_event(_) -> ignore.
++write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) ->
++ T = write_time(maybe_utc(Time)),
++ case catch io_lib:format(add_node(Format,Pid), Args) of
++ S when is_list(S) ->
++ io:format(Fd, T ++ S, []);
++ _ ->
++ F = add_node("ERROR: ~p - ~p~n", Pid),
++ io:format(Fd, T ++ F, [Format,Args])
++ end;
++write_event(Fd, {Time, {emulator, _GL, Chars}}) ->
++ T = write_time(maybe_utc(Time)),
++ case catch io_lib:format(Chars, []) of
++ S when is_list(S) ->
++ io:format(Fd, T ++ S, []);
++ _ ->
++ io:format(Fd, T ++ "ERROR: ~p ~n", [Chars])
++ end;
++write_event(Fd, {Time, {info, _GL, {Pid, Info, _}}}) ->
++ T = write_time(maybe_utc(Time)),
++ io:format(Fd, T ++ add_node("~p~n",Pid),[Info]);
++write_event(Fd, {Time, {error_report, _GL, {Pid, std_error, Rep}}}) ->
++ T = write_time(maybe_utc(Time)),
++ S = format_report(Rep),
++ io:format(Fd, T ++ S ++ add_node("", Pid), []);
++write_event(Fd, {Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
++ T = write_time(maybe_utc(Time), "INFO REPORT"),
++ S = format_report(Rep),
++ io:format(Fd, T ++ S ++ add_node("", Pid), []);
++write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
++ T = write_time(maybe_utc(Time), "INFO REPORT"),
++ case catch io_lib:format(add_node(Format,Pid), Args) of
++ S when is_list(S) ->
++ io:format(Fd, T ++ S, []);
++ _ ->
++ F = add_node("ERROR: ~p - ~p~n", Pid),
++ io:format(Fd, T ++ F, [Format,Args])
++ end;
++write_event(Fd, {Time, {warning_report, _GL, {Pid, std_warning, Rep}}}) ->
++ T = write_time(maybe_utc(Time), "WARNING REPORT"),
++ S = format_report(Rep),
++ io:format(Fd, T ++ S ++ add_node("", Pid), []);
++write_event(Fd, {Time, {warning_msg, _GL, {Pid, Format, Args}}}) ->
++ T = write_time(maybe_utc(Time), "WARNING REPORT"),
++ case catch io_lib:format(add_node(Format,Pid), Args) of
++ S when is_list(S) ->
++ io:format(Fd, T ++ S, []);
++ _ ->
++ F = add_node("ERROR: ~p - ~p~n", Pid),
++ io:format(Fd, T ++ F, [Format,Args])
++ end;
++write_event(_, _) ->
++ ok.
+
+ maybe_utc(Time) ->
+ UTC = case application:get_env(sasl, utc_log) of
+@@ -184,27 +182,30 @@ maybe_utc(Time) ->
+ maybe_utc(Time, true) -> {utc, Time};
+ maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}.
+
+-format_term(Term) when is_list(Term) ->
+- case string_p(Term) of
++format_report(Rep) when is_list(Rep) ->
++ case string_p(Rep) of
+ true ->
+- [{"~s\n",[Term]}];
+- false ->
+- format_term_list(Term)
++ io_lib:format("~s~n",[Rep]);
++ _ ->
++ format_rep(Rep)
+ end;
+-format_term(Term) ->
+- [{"~p\n",[Term]}].
+-
+-format_term_list([{Tag,Data}|T]) ->
+- [{" ~p: ~p\n",[Tag,Data]}|format_term_list(T)];
+-format_term_list([Data|T]) ->
+- [{" ~p\n",[Data]}|format_term_list(T)];
+-format_term_list([]) ->
+- [];
+-format_term_list(_) ->
+- %% Continue to allow non-proper lists for now.
+- %% FIXME: Remove this clause in OTP 19.
++format_report(Rep) ->
++ io_lib:format("~p~n",[Rep]).
++
++format_rep([{Tag,Data}|Rep]) ->
++ io_lib:format(" ~p: ~p~n",[Tag,Data]) ++ format_rep(Rep);
++format_rep([Other|Rep]) ->
++ io_lib:format(" ~p~n",[Other]) ++ format_rep(Rep);
++format_rep(_) ->
+ [].
+
++add_node(X, Pid) when is_atom(X) ->
++ add_node(atom_to_list(X), Pid);
++add_node(X, Pid) when node(Pid) =/= node() ->
++ lists:concat([X,"** at node ",node(Pid)," **~n"]);
++add_node(X, _) ->
++ X.
++
+ string_p([]) ->
+ false;
+ string_p(Term) ->
+@@ -220,10 +221,15 @@ string_p1([$\b|T]) -> string_p1(T);
+ string_p1([$\f|T]) -> string_p1(T);
+ string_p1([$\e|T]) -> string_p1(T);
+ string_p1([H|T]) when is_list(H) ->
+- string_p1(H) andalso string_p1(T);
++ case string_p1(H) of
++ true -> string_p1(T);
++ _ -> false
++ end;
+ string_p1([]) -> true;
+ string_p1(_) -> false.
+
++write_time(Time) -> write_time(Time, "ERROR REPORT").
++
+ write_time({utc,{{Y,Mo,D},{H,Mi,S}}}, Type) ->
+ io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
+ [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
+diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl
+index 72a052f..ad5891f 100644
+--- a/lib/stdlib/src/error_logger_tty_h.erl
++++ b/lib/stdlib/src/error_logger_tty_h.erl
+@@ -22,178 +22,144 @@
+
+ %%%
+ %%% A handler that can be connected to the error_logger
+-%%% event handler. Writes all events formatted to stdout.
++%%% event handler.
++%%% Writes all events formatted to stdout.
++%%% Handles events tagged error, emulator and info.
+ %%%
+ %%% It can only be started from error_logger:swap_handler(tty)
+-%%% or error_logger:tty(true).
++%%% or error_logger:tty(true)
+ %%%
+
+ -export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+--export([write_event/2,write_event/3]).
+-
+--record(st,
+- {user,
+- prev_handler,
+- io_mod=io,
+- depth=unlimited}).
++-export([write_event/2]).
+
+ %% This one is used when we takeover from the simple error_logger.
+ init({[], {error_logger, Buf}}) ->
+ User = set_group_leader(),
+- Depth = get_depth(),
+- State = #st{user=User,prev_handler=error_logger,depth=Depth},
+- write_events(State, Buf),
+- {ok, State};
++ write_events(Buf,io),
++ {ok, {User, error_logger}};
+ %% This one is used if someone took over from us, and now wants to
+ %% go back.
+ init({[], {error_logger_tty_h, PrevHandler}}) ->
+ User = set_group_leader(),
+- {ok, #st{user=User,prev_handler=PrevHandler}};
++ {ok, {User, PrevHandler}};
+ %% This one is used when we are started directly.
+ init([]) ->
+ User = set_group_leader(),
+- Depth = get_depth(),
+- {ok, #st{user=User,prev_handler=[],depth=Depth}}.
+-
+-get_depth() ->
+- case application:get_env(kernel, error_logger_format_depth) of
+- {ok, Depth} when is_integer(Depth) ->
+- max(10, Depth);
+- undefined ->
+- unlimited
+- end.
++ {ok, {User, []}}.
+
+ handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() ->
+ {ok, State};
+ handle_event(Event, State) ->
+- ok = do_write_event(State, tag_event(Event)),
++ write_event(tag_event(Event),io),
+ {ok, State}.
+
+-handle_info({'EXIT', User, _Reason},
+- #st{user=User,prev_handler=PrevHandler}=State) ->
++handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) ->
+ case PrevHandler of
+ [] ->
+ remove_handler;
+ _ ->
+- {swap_handler, install_prev, State,
++ {swap_handler, install_prev, {User, PrevHandler},
+ PrevHandler, go_back}
+ end;
++handle_info({emulator, GL, Chars}, State) when node(GL) == node() ->
++ write_event(tag_event({emulator, GL, Chars}),io),
++ {ok, State};
++handle_info({emulator, noproc, Chars}, State) ->
++ write_event(tag_event({emulator, noproc, Chars}),io),
++ {ok, State};
+ handle_info(_, State) ->
+ {ok, State}.
+
+ handle_call(_Query, State) -> {ok, {error, bad_query}, State}.
+
++% unfortunately, we can't unlink from User - links are not counted!
++% if pid(User) -> unlink(User); true -> ok end,
+ terminate(install_prev, _State) ->
+ [];
+-terminate(_Reason, #st{prev_handler=PrevHandler}) ->
++terminate(_Reason, {_User, PrevHandler}) ->
+ {error_logger_tty_h, PrevHandler}.
+
+ code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+-%% Exported (but unoffical) API.
+-write_event(Event, IoMod) ->
+- do_write_event(#st{io_mod=IoMod}, Event).
+-
+-write_event(Event, IoMod, Depth) ->
+- do_write_event(#st{io_mod=IoMod,depth=Depth}, Event).
+-
+-
+ %%% ------------------------------------------------------
+ %%% Misc. functions.
+ %%% ------------------------------------------------------
+
+ set_group_leader() ->
+ case whereis(user) of
+- User when is_pid(User) ->
+- link(User),
+- group_leader(User,self()),
+- User;
+- _ ->
+- false
++ User when is_pid(User) -> link(User), group_leader(User,self()), User;
++ _ -> false
+ end.
+
+ tag_event(Event) ->
+ {erlang:universaltime(), Event}.
+
+-write_events(State, [Ev|Es]) ->
+- %% Write the events in reverse order.
+- _ = write_events(State, Es),
+- _ = do_write_event(State, Ev),
+- ok;
+-write_events(_State, []) ->
++write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod).
++
++write_events1([Event|Es],IOMod) ->
++ write_event(Event,IOMod),
++ write_events1(Es,IOMod);
++write_events1([],_IOMod) ->
+ ok.
+
+-do_write_event(State, {Time0, Event}) ->
+- case parse_event(Event) of
+- ignore ->
+- ok;
+- {Head,Pid,FormatList} ->
+- Time = maybe_utc(Time0),
+- Header = write_time(Time, Head),
+- Body = format_body(State, FormatList),
+- AtNode = if
+- node(Pid) =/= node() ->
+- ["** at node ",atom_to_list(node(Pid))," **\n"];
+- true ->
+- []
+- end,
+- Str = [Header,Body,AtNode],
+- case State#st.io_mod of
+- io_lib ->
+- Str;
+- io ->
+- io:put_chars(user, Str)
+- end
++write_event({Time, {error, _GL, {Pid, Format, Args}}},IOMod) ->
++ T = write_time(maybe_utc(Time)),
++ case catch io_lib:format(add_node(Format,Pid), Args) of
++ S when is_list(S) ->
++ format(IOMod, T ++ S);
++ _ ->
++ F = add_node("ERROR: ~p - ~p~n", Pid),
++ format(IOMod, T ++ F, [Format,Args])
+ end;
+-do_write_event(_, _) ->
++write_event({Time, {emulator, _GL, Chars}},IOMod) ->
++ T = write_time(maybe_utc(Time)),
++ case catch io_lib:format(Chars, []) of
++ S when is_list(S) ->
++ format(IOMod, T ++ S);
++ _ ->
++ format(IOMod, T ++ "ERROR: ~p ~n", [Chars])
++ end;
++write_event({Time, {info, _GL, {Pid, Info, _}}},IOMod) ->
++ T = write_time(maybe_utc(Time)),
++ format(IOMod, T ++ add_node("~p~n",Pid),[Info]);
++write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}},IOMod) ->
++ T = write_time(maybe_utc(Time)),
++ S = format_report(Rep),
++ format(IOMod, T ++ S ++ add_node("", Pid));
++write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}},IOMod) ->
++ T = write_time(maybe_utc(Time), "INFO REPORT"),
++ S = format_report(Rep),
++ format(IOMod, T ++ S ++ add_node("", Pid));
++write_event({Time, {info_msg, _GL, {Pid, Format, Args}}},IOMod) ->
++ T = write_time(maybe_utc(Time), "INFO REPORT"),
++ case catch io_lib:format(add_node(Format,Pid), Args) of
++ S when is_list(S) ->
++ format(IOMod, T ++ S);
++ _ ->
++ F = add_node("ERROR: ~p - ~p~n", Pid),
++ format(IOMod, T ++ F, [Format,Args])
++ end;
++write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}},IOMod) ->
++ T = write_time(maybe_utc(Time), "WARNING REPORT"),
++ S = format_report(Rep),
++ format(IOMod, T ++ S ++ add_node("", Pid));
++write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}},IOMod) ->
++ T = write_time(maybe_utc(Time), "WARNING REPORT"),
++ case catch io_lib:format(add_node(Format,Pid), Args) of
++ S when is_list(S) ->
++ format(IOMod, T ++ S);
++ _ ->
++ F = add_node("ERROR: ~p - ~p~n", Pid),
++ format(IOMod, T ++ F, [Format,Args])
++ end;
++write_event({_Time, _Error},_IOMod) ->
+ ok.
+
+-format_body(State, [{Format,Args}|T]) ->
+- S = try format(State, Format, Args) of
+- S0 ->
+- S0
+- catch
+- _:_ ->
+- format(State, "ERROR: ~p - ~p\n", [Format,Args])
+- end,
+- [S|format_body(State, T)];
+-format_body(_State, []) ->
+- [].
+-
+-format(#st{depth=unlimited}, Format, Args) ->
+- io_lib:format(Format, Args);
+-format(#st{depth=Depth}, Format0, Args) ->
+- Format1 = io_lib:scan_format(Format0, Args),
+- Format = limit_format(Format1, Depth),
+- io_lib:build_text(Format).
+-
+-limit_format([{C0,As,F,Ad,P,Pad,Enc,Str}|T], Depth) when C0 =:= $p;
+- C0 =:= $w ->
+- C = C0 - ($a - $A), %To uppercase.
+- [{C,As++[Depth],F,Ad,P,Pad,Enc,Str}|limit_format(T, Depth)];
+-limit_format([H|T], Depth) ->
+- [H|limit_format(T, Depth)];
+-limit_format([], _) ->
+- [].
+-
+-parse_event({error, _GL, {Pid, Format, Args}}) ->
+- {"ERROR REPORT",Pid,[{Format,Args}]};
+-parse_event({info_msg, _GL, {Pid, Format, Args}}) ->
+- {"INFO REPORT",Pid,[{Format, Args}]};
+-parse_event({warning_msg, _GL, {Pid, Format, Args}}) ->
+- {"WARNING REPORT",Pid,[{Format,Args}]};
+-parse_event({error_report, _GL, {Pid, std_error, Args}}) ->
+- {"ERROR REPORT",Pid,format_term(Args)};
+-parse_event({info_report, _GL, {Pid, std_info, Args}}) ->
+- {"INFO REPORT",Pid,format_term(Args)};
+-parse_event({warning_report, _GL, {Pid, std_warning, Args}}) ->
+- {"WARNING REPORT",Pid,format_term(Args)};
+-parse_event(_) -> ignore.
+-
+ maybe_utc(Time) ->
+ UTC = case application:get_env(sasl, utc_log) of
+ {ok, Val} -> Val;
+@@ -209,27 +175,34 @@ maybe_utc(Time) ->
+ maybe_utc(Time, true) -> {utc, Time};
+ maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}.
+
+-format_term(Term) when is_list(Term) ->
+- case string_p(Term) of
++format(IOMod, String) -> format(IOMod, String, []).
++format(io_lib, String, Args) -> io_lib:format(String, Args);
++format(io, String, Args) -> io:format(user, String, Args).
++
++format_report(Rep) when is_list(Rep) ->
++ case string_p(Rep) of
+ true ->
+- [{"~s\n",[Term]}];
+- false ->
+- format_term_list(Term)
++ io_lib:format("~s~n",[Rep]);
++ _ ->
++ format_rep(Rep)
+ end;
+-format_term(Term) ->
+- [{"~p\n",[Term]}].
+-
+-format_term_list([{Tag,Data}|T]) ->
+- [{" ~p: ~p\n",[Tag,Data]}|format_term_list(T)];
+-format_term_list([Data|T]) ->
+- [{" ~p\n",[Data]}|format_term_list(T)];
+-format_term_list([]) ->
+- [];
+-format_term_list(_) ->
+- %% Continue to allow non-proper lists for now.
+- %% FIXME: Remove this clause in OTP 19.
++format_report(Rep) ->
++ io_lib:format("~p~n",[Rep]).
++
++format_rep([{Tag,Data}|Rep]) ->
++ io_lib:format(" ~p: ~p~n",[Tag,Data]) ++ format_rep(Rep);
++format_rep([Other|Rep]) ->
++ io_lib:format(" ~p~n",[Other]) ++ format_rep(Rep);
++format_rep(_) ->
+ [].
+
++add_node(X, Pid) when is_atom(X) ->
++ add_node(atom_to_list(X), Pid);
++add_node(X, Pid) when node(Pid) =/= node() ->
++ lists:concat([X,"** at node ",node(Pid)," **~n"]);
++add_node(X, _) ->
++ X.
++
+ string_p([]) ->
+ false;
+ string_p(Term) ->
+@@ -252,6 +225,7 @@ string_p1([H|T]) when is_list(H) ->
+ string_p1([]) -> true;
+ string_p1(_) -> false.
+
++write_time(Time) -> write_time(Time, "ERROR REPORT").
+ write_time({utc,{{Y,Mo,D},{H,Mi,S}}},Type) ->
+ io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
+ [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
+diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
+index 3c173dc..9e69601 100644
+--- a/lib/stdlib/src/io_lib.erl
++++ b/lib/stdlib/src/io_lib.erl
+@@ -2,7 +2,7 @@
+ %%
+ %% %CopyrightBegin%
+ %%
+-%% Copyright Ericsson AB 1996-2014. 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
+@@ -61,7 +61,6 @@
+ -module(io_lib).
+
+ -export([fwrite/2,fread/2,fread/3,format/2]).
+--export([scan_format/2,unscan_format/1,build_text/1]).
+ -export([print/1,print/4,indentation/2]).
+
+ -export([write/1,write/2,write/3,nl/0,format_prompt/1,format_prompt/2]).
+@@ -85,7 +84,7 @@
+ deep_unicode_char_list/1]).
+
+ -export_type([chars/0, latin1_string/0, continuation/0,
+- fread_error/0, fread_item/0, format_spec/0]).
++ fread_error/0, fread_item/0]).
+
+ %%----------------------------------------------------------------------
+
+@@ -110,18 +109,6 @@
+
+ -type fread_item() :: string() | atom() | integer() | float().
+
+--type format_spec() ::
+- {
+- ControlChar :: char(),
+- Args :: [any()],
+- Width :: 'none' | integer(),
+- Adjust :: 'left' | 'right',
+- Precision :: 'none' | integer(),
+- PadChar :: char(),
+- Encoding :: 'unicode' | 'latin1',
+- Strings :: boolean()
+- }.
+-
+ %%----------------------------------------------------------------------
+
+ %% Interface calls to sub-modules.
+@@ -170,31 +157,6 @@ format(Format, Args) ->
+ Other
+ end.
+
+--spec scan_format(Format, Data) -> FormatList when
+- Format :: io:format(),
+- Data :: [term()],
+- FormatList :: [char() | format_spec()].
+-
+-scan_format(Format, Args) ->
+- try io_lib_format:scan(Format, Args)
+- catch
+- _:_ -> erlang:error(badarg, [Format, Args])
+- end.
+-
+--spec unscan_format(FormatList) -> {Format, Data} when
+- FormatList :: [char() | format_spec()],
+- Format :: io:format(),
+- Data :: [term()].
+-
+-unscan_format(FormatList) ->
+- io_lib_format:unscan(FormatList).
+-
+--spec build_text(FormatList) -> chars() when
+- FormatList :: [char() | format_spec()].
+-
+-build_text(FormatList) ->
+- io_lib_format:build(FormatList).
+-
+ -spec print(Term) -> chars() when
+ Term :: term().
+
+diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
+index 37b47d7..56e15a1 100644
+--- a/lib/stdlib/src/io_lib_format.erl
++++ b/lib/stdlib/src/io_lib_format.erl
+@@ -1,7 +1,7 @@
+ %%
+ %% %CopyrightBegin%
+ %%
+-%% Copyright Ericsson AB 1996-2014. 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
+@@ -20,9 +20,10 @@
+
+ %% Formatting functions of io library.
+
+--export([fwrite/2,fwrite_g/1,indentation/2,scan/2,unscan/1,build/1]).
++-export([fwrite/2,fwrite_g/1,indentation/2]).
+
+-%% Format the arguments in Args after string Format. Just generate
++%% fwrite(Format, ArgList) -> string().
++%% Format the arguments in ArgList after string Format. Just generate
+ %% an error if there is an error in the arguments.
+ %%
+ %% To do the printing command correctly we need to calculate the
+@@ -36,83 +37,15 @@
+ %% and it also splits the handling of the control characters into two
+ %% parts.
+
+--spec fwrite(Format, Data) -> FormatList when
+- Format :: io:format(),
+- Data :: [term()],
+- FormatList :: [char() | io_lib:format_spec()].
+-
++fwrite(Format, Args) when is_atom(Format) ->
++ fwrite(atom_to_list(Format), Args);
++fwrite(Format, Args) when is_binary(Format) ->
++ fwrite(binary_to_list(Format), Args);
+ fwrite(Format, Args) ->
+- build(scan(Format, Args)).
+-
+-%% Build the output text for a pre-parsed format list.
+-
+--spec build(FormatList) -> io_lib:chars() when
+- FormatList :: [char() | io_lib:format_spec()].
+-
+-build(Cs) ->
++ Cs = collect(Format, Args),
+ Pc = pcount(Cs),
+ build(Cs, Pc, 0).
+
+-%% Parse all control sequences in the format string.
+-
+--spec scan(Format, Data) -> FormatList when
+- Format :: io:format(),
+- Data :: [term()],
+- FormatList :: [char() | io_lib:format_spec()].
+-
+-scan(Format, Args) when is_atom(Format) ->
+- scan(atom_to_list(Format), Args);
+-scan(Format, Args) when is_binary(Format) ->
+- scan(binary_to_list(Format), Args);
+-scan(Format, Args) ->
+- collect(Format, Args).
+-
+-%% Revert a pre-parsed format list to a plain character list and a
+-%% list of arguments.
+-
+--spec unscan(FormatList) -> {Format, Data} when
+- FormatList :: [char() | io_lib:format_spec()],
+- Format :: io:format(),
+- Data :: [term()].
+-
+-unscan(Cs) ->
+- {print(Cs), args(Cs)}.
+-
+-args([{_C,As,_F,_Ad,_P,_Pad,_Enc,_Str} | Cs]) ->
+- As ++ args(Cs);
+-args([_C | Cs]) ->
+- args(Cs);
+-args([]) ->
+- [].
+-
+-print([{C,_As,F,Ad,P,Pad,Enc,Str} | Cs ]) ->
+- print(C, F, Ad, P, Pad, Enc, Str) ++ print(Cs);
+-print([C | Cs]) ->
+- [C | print(Cs)];
+-print([]) ->
+- [].
+-
+-print(C, F, Ad, P, Pad, Encoding, Strings) ->
+- [$~] ++ print_field_width(F, Ad) ++ print_precision(P) ++
+- print_pad_char(Pad) ++ print_encoding(Encoding) ++
+- print_strings(Strings) ++ [C].
+-
+-print_field_width(none, _Ad) -> "";
+-print_field_width(F, left) -> integer_to_list(-F);
+-print_field_width(F, right) -> integer_to_list(F).
+-
+-print_precision(none) -> "";
+-print_precision(P) -> [$. | integer_to_list(P)].
+-
+-print_pad_char($\s) -> ""; % default, no need to make explicit
+-print_pad_char(Pad) -> [$., Pad].
+-
+-print_encoding(unicode) -> "t";
+-print_encoding(latin1) -> "".
+-
+-print_strings(false) -> "l";
+-print_strings(true) -> "".
+-
+ collect([$~|Fmt0], Args0) ->
+ {C,Fmt1,Args1} = collect_cseq(Fmt0, Args0),
+ [C|collect(Fmt1, Args1)];
+@@ -208,7 +141,7 @@ pcount([{$P,_As,_F,_Ad,_P,_Pad,_Enc,_Str}|Cs], Acc) -> pcount(Cs, Acc+1);
+ pcount([_|Cs], Acc) -> pcount(Cs, Acc);
+ pcount([], Acc) -> Acc.
+
+-%% build([Control], Pc, Indentation) -> io_lib:chars().
++%% build([Control], Pc, Indentation) -> string().
+ %% Interpret the control structures. Count the number of print
+ %% remaining and only calculate indentation when necessary. Must also
+ %% be smart when calculating indentation for characters in format.
+@@ -229,14 +162,10 @@ decr_pc($p, Pc) -> Pc - 1;
+ decr_pc($P, Pc) -> Pc - 1;
+ decr_pc(_, Pc) -> Pc.
+
+-
++%% indentation(String, Indentation) -> Indentation.
+ %% Calculate the indentation of the end of a string given its start
+ %% indentation. We assume tabs at 8 cols.
+
+--spec indentation(String, StartIndent) -> integer() when
+- String :: io_lib:chars(),
+- StartIndent :: integer().
+-
+ indentation([$\n|Cs], _I) -> indentation(Cs, 0);
+ indentation([$\t|Cs], I) -> indentation(Cs, ((I + 8) div 8) * 8);
+ indentation([C|Cs], I) when is_integer(C) ->
+@@ -437,6 +366,7 @@ float_data([D|Cs], Ds) when D >= $0, D =< $9 ->
+ float_data([_|Cs], Ds) ->
+ float_data(Cs, Ds).
+
++%% fwrite_g(Float)
+ %% Writes the shortest, correctly rounded string that converts
+ %% to Float when read back with list_to_float/1.
+ %%
+@@ -444,8 +374,6 @@ float_data([_|Cs], Ds) ->
+ %% in Proceedings of the SIGPLAN '96 Conference on Programming
+ %% Language Design and Implementation.
+
+--spec fwrite_g(float()) -> string().
+-
+ fwrite_g(0.0) ->
+ "0.0";
+ fwrite_g(Float) when is_float(Float) ->
+@@ -714,7 +642,7 @@ prefixed_integer(Int, F, Adj, Base, Pad, Prefix, Lowercase)
+ term([Prefix|S], F, Adj, none, Pad)
+ end.
+
+-%% char(Char, Field, Adjust, Precision, PadChar) -> chars().
++%% char(Char, Field, Adjust, Precision, PadChar) -> string().
+
+ char(C, none, _Adj, none, _Pad) -> [C];
+ char(C, F, _Adj, none, _Pad) -> chars(C, F);
diff --git a/otp-0027-Respect-proto_dist-switch-while-connection-to-EPMD.patch b/otp-0027-Respect-proto_dist-switch-while-connection-to-EPMD.patch
new file mode 100644
index 0000000..3e817d5
--- /dev/null
+++ b/otp-0027-Respect-proto_dist-switch-while-connection-to-EPMD.patch
@@ -0,0 +1,34 @@
+From: Peter Lemenkov
+Date: Thu, 14 Jul 2016 17:51:16 +0300
+Subject: [PATCH] Respect -proto_dist switch while connection to EPMD
+
+Signed-off-by: Peter Lemenkov
+
+diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
+index 21a3dec..0ba695c 100644
+--- a/lib/kernel/src/erl_epmd.erl
++++ b/lib/kernel/src/erl_epmd.erl
+@@ -107,6 +107,10 @@ names1(HostName) ->
+
+ register_node(Name, PortNo) ->
+ register_node(Name, PortNo, inet).
++register_node(Name, PortNo, inet_tcp) ->
++ register_node(Name, PortNo, inet);
++register_node(Name, PortNo, inet6_tcp) ->
++ register_node(Name, PortNo, inet6);
+ register_node(Name, PortNo, Family) ->
+ gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
+
+diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
+index 0739cf3..c64ddc8 100644
+--- a/lib/kernel/src/inet_tcp_dist.erl
++++ b/lib/kernel/src/inet_tcp_dist.erl
+@@ -72,7 +72,7 @@ gen_listen(Driver, Name) ->
+ {ok, Socket} ->
+ TcpAddress = get_tcp_address(Driver, Socket),
+ {_,Port} = TcpAddress#net_address.address,
+- case erl_epmd:register_node(Name, Port) of
++ case erl_epmd:register_node(Name, Port, Driver) of
+ {ok, Creation} ->
+ {ok, {Socket, TcpAddress, Creation}};
+ Error ->
diff --git a/otp-0028-mnesia-Send-mnesia_down-messages-to-waiting-transact.patch b/otp-0028-mnesia-Send-mnesia_down-messages-to-waiting-transact.patch
new file mode 100644
index 0000000..9514c34
--- /dev/null
+++ b/otp-0028-mnesia-Send-mnesia_down-messages-to-waiting-transact.patch
@@ -0,0 +1,38 @@
+From: Dan Gudmundsson
+Date: Thu, 17 Mar 2016 10:23:41 +0100
+Subject: [PATCH] mnesia: Send mnesia_down messages to waiting transactions
+
+Mnesia didn't forward mnesia_down to transactions which where already
+decided to be aborted, but that could lead to hanging transactions
+still waiting for messages from the node which had stopped.
+
+diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
+index 17af0ca..329192e 100644
+--- a/lib/mnesia/src/mnesia_tm.erl
++++ b/lib/mnesia/src/mnesia_tm.erl
+@@ -1714,13 +1714,10 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
+ ?eval_debug_fun({?MODULE, commit_participant, undo_prepare},
+ [{tid, Tid}]);
+
+- {'EXIT', _, _} ->
++ {'EXIT', _MnesiaTM, Reason} ->
++ reply(Coord, {do_abort, Tid, self(), {bad_commit,Reason}}),
+ mnesia_recover:log_decision(D#decision{outcome = aborted}),
+- ?eval_debug_fun({?MODULE, commit_participant, exit_log_abort},
+- [{tid, Tid}]),
+- mnesia_schema:undo_prepare_commit(Tid, C0),
+- ?eval_debug_fun({?MODULE, commit_participant, exit_undo_prepare},
+- [{tid, Tid}]);
++ mnesia_schema:undo_prepare_commit(Tid, C0);
+
+ Msg ->
+ verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~p~n",
+@@ -2236,8 +2233,6 @@ reconfigure_coordinators(N, [{Tid, [Store | _]} | Coordinators]) ->
+ true ->
+ send_mnesia_down(Tid, Store, N)
+ end;
+- aborted ->
+- ignore; % avoid spurious mnesia_down messages
+ _ ->
+ %% Tell the coordinator about the mnesia_down
+ send_mnesia_down(Tid, Store, N)
diff --git a/otp-0029-Fix-a-few-javadoc-errors.patch b/otp-0029-Fix-a-few-javadoc-errors.patch
new file mode 100644
index 0000000..c808303
--- /dev/null
+++ b/otp-0029-Fix-a-few-javadoc-errors.patch
@@ -0,0 +1,139 @@
+From: Anthony Ramine
+Date: Sun, 8 Jun 2014 12:37:10 +0200
+Subject: [PATCH] Fix a few javadoc errors
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reported-by: Boris Mühmer
+
+diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java
+index 9ba6a4a..7aa30ee 100644
+--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java
++++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java
+@@ -266,7 +266,7 @@ public abstract class AbstractConnection extends Thread {
+ *
+ * @param dest
+ * the Erlang PID of the remote process.
+- * @param msg
++ * @param payload
+ * the encoded message to send.
+ *
+ * @exception java.io.IOException
+diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpConnection.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpConnection.java
+index 8e8bd47..e7a9d10 100644
+--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpConnection.java
++++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpConnection.java
+@@ -404,7 +404,7 @@ public class OtpConnection extends AbstractConnection {
+ *
+ * @param dest
+ * the Erlang PID of the remote process.
+- * @param msg
++ * @param payload
+ * the encoded message to send.
+ *
+ * @exception java.io.IOException
+diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java
+index 7e3e2a7..84b1355 100644
+--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java
++++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java
+@@ -51,8 +51,8 @@ public class OtpErlangLong extends OtpErlangObject implements Serializable,
+ /**
+ * Create an Erlang integer from the given value.
+ *
+- * @param val
+- * the long value to use.
++ * @param v
++ * the big integer value to use.
+ */
+ public OtpErlangLong(final BigInteger v) {
+ if (v == null) {
+diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
+index fe81ce3..f75e435 100644
+--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
++++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
+@@ -162,7 +162,7 @@ public class OtpErlangPid extends OtpErlangObject implements Serializable,
+ * Determine if two PIDs are equal. PIDs are equal if their components are
+ * equal.
+ *
+- * @param port
++ * @param o
+ * the other PID to compare to.
+ *
+ * @return true if the PIDs are equal, false otherwise.
+diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
+index 6766b52..a5e202c 100644
+--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
++++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
+@@ -41,8 +41,6 @@ public class OtpErlangString extends OtpErlangObject implements Serializable,
+
+ /**
+ * Create an Erlang string from a list of integers.
+- *
+- * @return an Erlang string with Unicode code units.
+ *
+ * @throws OtpErlangException
+ * for non-proper and non-integer lists.
+diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
+index 0fd93b0..4a4a1e7 100644
+--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
++++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
+@@ -69,6 +69,7 @@ package com.ericsson.otp.erlang;
+ * notify other parties in a timely manner.
+ *
+ *
++ *
+ * When retrieving messages from a mailbox that has received an exit signal, an
+ * {@link OtpErlangExit OtpErlangExit} exception will be raised. Note that the
+ * exception is queued in the mailbox along with other messages, and will not be
+@@ -420,7 +421,6 @@ public class OtpMbox {
+
+ /**
+ * Equivalent to exit(new OtpErlangAtom(reason)).
+- *
+- * The header information that is available is as follows:
++ * The header information that is available is as follows:
+ *
a tag indicating the type of message
+ *
the intended recipient of the message, either as a
+ * {@link OtpErlangPid pid} or as a String, but never both.
+ *
(sometimes) the sender of the message. Due to some eccentric
+ * characteristics of the Erlang distribution protocol, not all messages have
+ * information about the sending process. In particular, only messages whose tag
+- * is {@link OtpMsg#regSendTag regSendTag} contain sender information.
+ * Message are sent using the Erlang external format (see separate
+diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
+index 78f47aa..fd4eba3 100644
+--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
++++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
+@@ -202,7 +202,7 @@ public class OtpOutputStream extends ByteArrayOutputStream {
+ /**
+ * Write an array of bytes to the stream.
+ *
+- * @param buf
++ * @param bytes
+ * the array of bytes to write.
+ *
+ */
+@@ -637,7 +637,7 @@ public class OtpOutputStream extends ByteArrayOutputStream {
+ * Write a positive short to the stream. The short is interpreted as a two's
+ * complement unsigned short even if it is negative.
+ *
+- * @param s
++ * @param us
+ * the short to use.
+ */
+ public void write_ushort(final short us) {
diff --git a/sources b/sources
index df29746..aa69160 100644
--- a/sources
+++ b/sources
@@ -1,4 +1 @@
-d27250e9ee98d6388e7f2e65379a0406 otp_src_R16B03-1.readme
-eff44490c9bbae3a5c5741bec2390ba3 otp_doc_html_R16B03-1.tar.gz
-39113c0d2515bdd8cd7e0f975a380122 otp_doc_man_R16B03-1.tar.gz
e5ece977375197338c1b93b3d88514f8 otp_src_R16B03-1.tar.gz