From 95ed86fc9893460751c5141ff872bdc13814a273 Mon Sep 17 00:00:00 2001
From: Geoff Cant
Date: Sat, 12 Jun 2010 16:49:54 -0700
Subject: Fix format_status bug for unregistered gen_event processes
Port the gen_fsm code for format_status to gen_event in order to
prevent a lists:concat([...,pid()]) crash when calling
sys:get_status/1 on an unregistered gen_event process.
Refactor format_status header code from gen_* behaviours to module gen.
Extend the format_status tests in gen_event_SUITE to cover
format_status bugs with anonymous gen_event processes.
---
lib/stdlib/src/gen.erl | 9 +++++++++
lib/stdlib/src/gen_event.erl | 3 ++-
lib/stdlib/src/gen_fsm.erl | 11 ++---------
lib/stdlib/src/gen_server.erl | 11 ++---------
lib/stdlib/test/gen_event_SUITE.erl | 22 ++++++++++++++++++++--
5 files changed, 35 insertions(+), 21 deletions(-)
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index 43df6f621d..574146b1cd 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -29,6 +29,8 @@
-export([init_it/6, init_it/7]).
+-export([format_status_header/2]).
+
-define(default_timeout, 5000).
%%-----------------------------------------------------------------
@@ -315,3 +317,10 @@ debug_options(Opts) ->
{ok, Options} -> sys:debug_options(Options);
_ -> []
end.
+
+format_status_header(TagLine, Pid) when is_pid(Pid) ->
+ lists:concat([TagLine, " ", pid_to_list(Pid)]);
+format_status_header(TagLine, RegName) when is_atom(RegName) ->
+ lists:concat([TagLine, " ", RegName]);
+format_status_header(TagLine, Name) ->
+ {TagLine, Name}.
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index b1e9e3a02f..b00910771f 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -724,7 +724,8 @@ get_modules(MSL) ->
%%-----------------------------------------------------------------
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, _Debug, [ServerName, MSL, _Hib]] = StatusData,
- Header = lists:concat(["Status for event handler ", ServerName]),
+ Header = gen:format_status_header("Status for event handler",
+ ServerName),
FmtMSL = [case erlang:function_exported(Mod, format_status, 2) of
true ->
Args = [PDict, State],
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index 7d9960b912..f2f1365d3d 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -614,15 +614,8 @@ get_msg(Msg) -> Msg.
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, Debug, [Name, StateName, StateData, Mod, _Time]] =
StatusData,
- StatusHdr = "Status for state machine",
- Header = if
- is_pid(Name) ->
- lists:concat([StatusHdr, " ", pid_to_list(Name)]);
- is_atom(Name); is_list(Name) ->
- lists:concat([StatusHdr, " ", Name]);
- true ->
- {StatusHdr, Name}
- end,
+ Header = gen:format_status_header("Status for state machine",
+ Name),
Log = sys:get_debug(log, Debug, []),
DefaultStatus = [{data, [{"StateData", StateData}]}],
Specfic =
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index ac81df9cab..09d94a9c40 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -840,15 +840,8 @@ name_to_pid(Name) ->
%%-----------------------------------------------------------------
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, Debug, [Name, State, Mod, _Time]] = StatusData,
- StatusHdr = "Status for generic server",
- Header = if
- is_pid(Name) ->
- lists:concat([StatusHdr, " ", pid_to_list(Name)]);
- is_atom(Name); is_list(Name) ->
- lists:concat([StatusHdr, " ", Name]);
- true ->
- {StatusHdr, Name}
- end,
+ Header = gen:format_status_header("Status for generic server",
+ Name),
Log = sys:get_debug(log, Debug, []),
DefaultStatus = [{data, [{"State", State}]}],
Specfic =
diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl
index 4f7de451e3..4c6466d860 100644
--- a/lib/stdlib/test/gen_event_SUITE.erl
+++ b/lib/stdlib/test/gen_event_SUITE.erl
@@ -24,10 +24,12 @@
-export([start/1, test_all/1, add_handler/1, add_sup_handler/1,
delete_handler/1, swap_handler/1, swap_sup_handler/1,
notify/1, sync_notify/1, call/1, info/1, hibernate/1,
- call_format_status/1, error_format_status/1]).
+ call_format_status/1, call_format_status_anon/1,
+ error_format_status/1]).
all(suite) -> {req, [stdlib], [start, test_all, hibernate,
- call_format_status, error_format_status]}.
+ call_format_status, call_format_status_anon,
+ error_format_status]}.
%% --------------------------------------
%% Start an event manager.
@@ -868,6 +870,22 @@ call_format_status(Config) when is_list(Config) ->
?line {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo2,
ok.
+call_format_status_anon(suite) ->
+ [];
+call_format_status_anon(doc) ->
+ ["Test that sys:get_status/1,2 calls format_status/2 for anonymous gen_event processes"];
+call_format_status_anon(Config) when is_list(Config) ->
+ ?line {ok, Pid} = gen_event:start(),
+ %% The 'Name' of the gen_event process will be a pid() here, so
+ %% the next line will crash if format_status can't string-ify pids.
+ ?line Status1 = sys:get_status(Pid),
+ ?line ok = gen_event:stop(Pid),
+ Header = "Status for event handler " ++ pid_to_list(Pid),
+ ?line {status, Pid, _, [_, _, Pid, [], Data1]} = Status1,
+ ?line Header = proplists:get_value(header, Data1),
+ ok.
+
+
error_format_status(suite) ->
[];
error_format_status(doc) ->
--
cgit v1.2.3
From eb02beb1c33fafb32e0596d947310d8c17e8bbf2 Mon Sep 17 00:00:00 2001
From: Tobias Schlager
Date: Thu, 23 Sep 2010 11:40:19 +0200
Subject: add user specified compiler options on form reloading
In order to be able to test non-exported functions from another (test) module
it is necessary to compile the specific module (at least during the test phase)
with the export_all compiler option. This allows complete separation of testing
and productive code. At the moment it is not possible to combine this with a
test code coverage using the cover module. The problem is that when cover
compiling a module using cover:compile_* the code is reloaded into the emulator
omitting/filtering the passed user options. In my example above the export_all
option would be removed and the non-exported functions cannot be called any
more.
---
lib/tools/src/cover.erl | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index c4d1bd1d2f..b8884fed2c 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -229,6 +229,7 @@ compile_modules(Files,Options) ->
{i, Dir} when is_list(Dir) -> true;
{d, _Macro} -> true;
{d, _Macro, _Value} -> true;
+ export_all -> true;
_ -> false
end
end,
@@ -569,7 +570,7 @@ main_process_loop(State) ->
case get_beam_file(Module,BeamFile0,Compiled0) of
{ok,BeamFile} ->
{Reply,Compiled} =
- case do_compile_beam(Module,BeamFile) of
+ case do_compile_beam(Module,BeamFile,[]) of
{ok, Module} ->
remote_load_compiled(State#main_state.nodes,
[{Module,BeamFile}]),
@@ -1227,13 +1228,13 @@ do_compile(File, UserOptions) ->
Options = [debug_info,binary,report_errors,report_warnings] ++ UserOptions,
case compile:file(File, Options) of
{ok, Module, Binary} ->
- do_compile_beam(Module,Binary);
+ do_compile_beam(Module,Binary,UserOptions);
error ->
error
end.
%% Beam is a binary or a .beam file name
-do_compile_beam(Module,Beam) ->
+do_compile_beam(Module,Beam,UserOptions) ->
%% Clear database
do_clear(Module),
@@ -1253,7 +1254,7 @@ do_compile_beam(Module,Beam) ->
%% Compile and load the result
%% It's necessary to check the result of loading since it may
%% fail, for example if Module resides in a sticky directory
- {ok, Module, Binary} = compile:forms(Forms, []),
+ {ok, Module, Binary} = compile:forms(Forms, UserOptions),
case code:load_binary(Module, ?TAG, Binary) of
{module, Module} ->
--
cgit v1.2.3
From bcf3b3d0d589666575d9b044d0779be2e40e1762 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Holger=20Wei=C3=9F?=
Date: Wed, 10 Nov 2010 23:03:44 +0100
Subject: Allow user to specify the IP address epmd binds to
The IP address(es) epmd binds to can now be specified by the user,
either via epmd's new "-address" option or (if that's not used) by
setting the environment variable ERL_EPMD_ADDRESS. Multiple addresses
may be specified using a comma-separated list. If the loopback address
is not in this list, it will be added implicitly, so that the daemon can
be queried by an interactive epmd process.
---
erts/configure.in | 2 +-
erts/doc/src/epmd.xml | 19 +++++
erts/doc/src/erl.xml | 9 +++
erts/epmd/src/epmd.c | 37 ++++++---
erts/epmd/src/epmd_cli.c | 2 +-
erts/epmd/src/epmd_int.h | 59 +++++++-------
erts/epmd/src/epmd_srv.c | 207 +++++++++++++++++++++++++++++++----------------
7 files changed, 224 insertions(+), 111 deletions(-)
diff --git a/erts/configure.in b/erts/configure.in
index 8c6f2ac076..fdaeb90d9c 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -1716,7 +1716,7 @@ AC_CHECK_FUNCS([getnameinfo getipnodebyname getipnodebyaddr gethostbyname2])
AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \
pread pwrite writev memmove strerror strerror_r strncasecmp \
- gethrtime localtime_r gmtime_r mmap mremap memcpy mallopt \
+ gethrtime localtime_r gmtime_r inet_pton mmap mremap memcpy mallopt \
sbrk _sbrk __sbrk brk _brk __brk \
flockfile fstat strlcpy strlcat setsid posix2time setlocale nl_langinfo poll])
diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml
index f01cf90a36..f2ea325be7 100644
--- a/erts/doc/src/epmd.xml
+++ b/erts/doc/src/epmd.xml
@@ -116,6 +116,16 @@
These options are available when starting the actual name server. The name server is normally started automatically by the erl command (if not already available), but it can also be started at i.e. system start-up.
+
+ -
+
Let this instance of epmd listen only on the
+ comma-separated list of IP addresses and on the loopback address
+ (which is implicitely added to the list if it has not been
+ specified). This can also be set using the
+ environment variable, see the
+ section Environment
+ variables below.
+
-
Let this instance of epmd listen to another TCP port than
@@ -228,6 +238,15 @@
Environment variables
+
+ -
+
This environment variable may be set to a comma-separated
+ list of IP addresses, in which case the epmd daemon
+ will listen only on the specified address(es) and on the
+ loopback address (which is implicitely added to the list if it
+ has not been specified). The default behaviour is to listen on
+ all available IP addresses.
+
-
This environment variable can contain the port number epmd will use.
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index 09c9cf6812..2fd804cd04 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -981,6 +981,15 @@
add to the code path.
See code(3).
+
+ -
+
This environment variable may be set to a comma-separated
+ list of IP addresses, in which case the
+ epmd daemon
+ will listen only on the specified address(es) and on the
+ loopback address (which is implicitely added to the list if it
+ has not been specified).
+
-
This environment variable can contain the port number to use when
diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
index 65ff0cd6b2..9ba1069663 100644
--- a/erts/epmd/src/epmd.c
+++ b/erts/epmd/src/epmd.c
@@ -33,6 +33,7 @@
static void usage(EpmdVars *);
static void run_daemon(EpmdVars*);
+static char* get_addresses(void);
static int get_port_no(void);
static int check_relaxed(void);
#ifdef __WIN32__
@@ -133,6 +134,7 @@ int main(int argc, char** argv)
{
EpmdVars g_empd_vars;
EpmdVars *g = &g_empd_vars;
+ int i;
#ifdef __WIN32__
WORD wVersionRequested;
WSADATA wsaData;
@@ -158,8 +160,9 @@ int main(int argc, char** argv)
g->argv = NULL;
#endif
- g->port = get_port_no();
- g->debug = 0;
+ g->addresses = get_addresses();
+ g->port = get_port_no();
+ g->debug = 0;
g->silent = 0;
g->is_daemon = 0;
@@ -168,12 +171,14 @@ int main(int argc, char** argv)
g->delay_accept = 0;
g->delay_write = 0;
g->progname = argv[0];
- g->listenfd = -1;
g->conn = NULL;
g->nodes.reg = g->nodes.unreg = g->nodes.unreg_tail = NULL;
g->nodes.unreg_count = 0;
g->active_conn = 0;
+ for (i = 0; i < MAX_LISTEN_SOCKETS; i++)
+ g->listenfd[i] = -1;
+
argc--;
argv++;
while (argc > 0) {
@@ -208,6 +213,11 @@ int main(int argc, char** argv)
else
usage(g);
epmd_cleanup_exit(g,0);
+ } else if (strcmp(argv[0], "-address") == 0) {
+ if (argc == 1)
+ usage(g);
+ g->addresses = argv[1];
+ argv += 2; argc -= 2;
} else if (strcmp(argv[0], "-port") == 0) {
if ((argc == 1) ||
((g->port = atoi(argv[1])) == 0))
@@ -252,13 +262,10 @@ int main(int argc, char** argv)
/*
* max_conn must not be greater than FD_SETSIZE.
* (at least QNX crashes)
- *
- * More correctly, it must be FD_SETSIZE - 1, beacuse the
- * listen FD is stored outside the connection array.
*/
if (g->max_conn > FD_SETSIZE) {
- g->max_conn = FD_SETSIZE - 1;
+ g->max_conn = FD_SETSIZE;
}
if (g->is_daemon) {
@@ -393,11 +400,14 @@ static void run_daemon(EpmdVars *g)
static void usage(EpmdVars *g)
{
- fprintf(stderr, "usage: epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon]\n");
- fprintf(stderr, " [-relaxed_command_check]\n");
+ fprintf(stderr, "usage: epmd [-d|-debug] [DbgExtra...] [-address List]\n");
+ fprintf(stderr, " [-port No] [-daemon] [-relaxed_command_check]\n");
fprintf(stderr, " epmd [-d|-debug] [-port No] [-names|-kill|-stop name]\n\n");
fprintf(stderr, "See the Erlang epmd manual page for info about the usage.\n\n");
fprintf(stderr, "Regular options\n");
+ fprintf(stderr, " -address List\n");
+ fprintf(stderr, " Let epmd listen only on the comma-separated list of IP\n");
+ fprintf(stderr, " addresses (and on the loopback interface).\n");
fprintf(stderr, " -port No\n");
fprintf(stderr, " Let epmd listen to another port than default %d\n",
EPMD_PORT_NO);
@@ -555,8 +565,9 @@ void epmd_cleanup_exit(EpmdVars *g, int exitval)
epmd_conn_close(g,&g->conn[i]);
free(g->conn);
}
- if(g->listenfd >= 0)
- close(g->listenfd);
+ for(i=0; i < MAX_LISTEN_SOCKETS; i++)
+ if(g->listenfd[i] >= 0)
+ close(g->listenfd[i]);
free_all_nodes(g);
if(g->argv){
for(i=0; g->argv[i] != NULL; ++i)
@@ -568,6 +579,10 @@ void epmd_cleanup_exit(EpmdVars *g, int exitval)
exit(exitval);
}
+static char* get_addresses(void)
+{
+ return getenv("ERL_EPMD_ADDRESS");
+}
static int get_port_no(void)
{
char* port_str = getenv("ERL_EPMD_PORT");
diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
index 7c60ba0420..ac55ba6bb6 100644
--- a/erts/epmd/src/epmd_cli.c
+++ b/erts/epmd/src/epmd_cli.c
@@ -137,7 +137,7 @@ static int conn_to_epmd(EpmdVars *g)
{ /* store port number in unsigned short */
unsigned short sport = g->port;
- SET_ADDR_LOOPBACK(address, FAMILY, sport);
+ SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport);
}
if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0)
diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
index c2558d52a1..2a0de4df9c 100644
--- a/erts/epmd/src/epmd_int.h
+++ b/erts/epmd/src/epmd_int.h
@@ -168,42 +168,40 @@
#if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6)
#define EPMD_SOCKADDR_IN sockaddr_in6
-#define FAMILY AF_INET6
-
-#define SET_ADDR_LOOPBACK(addr, af, port) do { \
- memset((char*)&(addr), 0, sizeof(addr)); \
- (addr).sin6_family = (af); \
- (addr).sin6_flowinfo = 0; \
- (addr).sin6_addr = in6addr_loopback; \
- (addr).sin6_port = htons(port); \
+#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 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); \
} while(0)
-#define SET_ADDR_ANY(addr, af, port) do { \
- memset((char*)&(addr), 0, sizeof(addr)); \
- (addr).sin6_family = (af); \
- (addr).sin6_flowinfo = 0; \
- (addr).sin6_addr = in6addr_any; \
- (addr).sin6_port = htons(port); \
- } while(0)
+#define IS_ADDR_LOOPBACK(addr) \
+ (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0)
#else /* Not IP v6 */
#define EPMD_SOCKADDR_IN sockaddr_in
-#define FAMILY AF_INET
-
-#define SET_ADDR_LOOPBACK(addr, af, port) do { \
- memset((char*)&(addr), 0, sizeof(addr)); \
- (addr).sin_family = (af); \
- (addr).sin_addr.s_addr = htonl(INADDR_LOOPBACK); \
- (addr).sin_port = htons(port); \
+#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 { \
+ memset((char*)&(dst), 0, sizeof(dst)); \
+ (dst).sin_family = AF_INET; \
+ (dst).sin_addr.s_addr = (addr); \
+ (dst).sin_port = htons(port); \
} while(0)
-#define SET_ADDR_ANY(addr, af, port) do { \
- memset((char*)&(addr), 0, sizeof(addr)); \
- (addr).sin_family = (af); \
- (addr).sin_addr.s_addr = htonl(INADDR_ANY); \
- (addr).sin_port = htons(port); \
- } while(0)
+#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
#endif /* Not IP v6 */
@@ -231,6 +229,8 @@
/* Maximum length of a node name == atom name */
#define MAXSYMLEN 255
+#define MAX_LISTEN_SOCKETS 16
+
#define INBUF_SIZE 1024
#define OUTBUF_SIZE 1024
@@ -299,7 +299,8 @@ typedef struct {
Connection *conn;
Nodes nodes;
fd_set orig_read_mask;
- int listenfd;
+ int listenfd[MAX_LISTEN_SOCKETS];
+ char *addresses;
char **argv;
} EpmdVars;
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
index ef471a473a..73b09e7299 100644
--- a/erts/epmd/src/epmd_srv.c
+++ b/erts/epmd/src/epmd_srv.c
@@ -24,6 +24,10 @@
#include "epmd.h" /* Renamed from 'epmd_r4.h' */
#include "epmd_int.h"
+#ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+#endif
+
/*
*
* This server is a local name server for Erlang nodes. Erlang nodes can
@@ -79,90 +83,154 @@ static void print_names(EpmdVars*);
void run(EpmdVars *g)
{
- int listensock;
+ struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS];
+ int listensock[MAX_LISTEN_SOCKETS];
+ int num_sockets;
int i;
int opt;
- struct EPMD_SOCKADDR_IN iserv_addr;
+ unsigned short sport = g->port;
node_init(g);
g->conn = conn_init(g);
dbg_printf(g,2,"try to initiate listening port %d", g->port);
-
- if ((listensock = socket(FAMILY,SOCK_STREAM,0)) < 0) {
- dbg_perror(g,"error opening stream socket");
- epmd_cleanup_exit(g,1);
- }
- g->listenfd = listensock;
+
+ if (g->addresses != NULL)
+ {
+ char *tmp;
+ char *token;
+ int loopback_ok = 0;
+
+ if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL)
+ {
+ dbg_perror(g,"cannot allocate memory");
+ epmd_cleanup_exit(g,1);
+ }
+ strcpy(tmp,g->addresses);
+
+ for(token = strtok(tmp,", "), num_sockets = 0;
+ token != NULL;
+ token = strtok(NULL,", "), num_sockets++)
+ {
+ struct EPMD_IN_ADDR addr;
+#ifdef HAVE_INET_PTON
+ int ret;
+
+ if ((ret = inet_pton(FAMILY,token,&addr)) == -1)
+ {
+ dbg_perror(g,"cannot convert IP address to network format");
+ epmd_cleanup_exit(g,1);
+ }
+ else if (ret == 0)
+#elif !defined(EPMD6)
+ if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE)
+#endif
+ {
+ dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token);
+ epmd_cleanup_exit(g,1);
+ }
+
+ if (IS_ADDR_LOOPBACK(addr))
+ loopback_ok = 1;
+
+ if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1)
+ {
+ 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;
+ }
+
+#if !defined(__WIN32__)
+ /* We ignore the SIGPIPE signal that is raised when we call write
+ twice on a socket closed by the other end. */
+ signal(SIGPIPE, SIG_IGN);
+#endif
/*
* Initialize number of active file descriptors.
* Stdin, stdout, and stderr are still open.
- * One for the listen socket.
*/
- g->active_conn = 3+1;
+ g->active_conn = 3 + num_sockets;
+ g->max_conn -= num_sockets;
+
+ FD_ZERO(&g->orig_read_mask);
+
+ for (i = 0; i < num_sockets; i++)
+ {
+ if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0)
+ {
+ dbg_perror(g,"error opening stream socket");
+ epmd_cleanup_exit(g,1);
+ }
+ g->listenfd[i] = listensock[i];
- /*
- * Note that we must not enable the SO_REUSEADDR on Windows,
- * because addresses will be reused even if they are still in use.
- */
+ /*
+ * Note that we must not enable the SO_REUSEADDR on Windows,
+ * because addresses will be reused even if they are still in use.
+ */
#if !defined(__WIN32__)
- /* We ignore the SIGPIPE signal that is raised when we call write
- twice on a socket closed by the other end. */
- signal(SIGPIPE, SIG_IGN);
-
- opt = 1; /* Set this option */
- if (setsockopt(listensock,SOL_SOCKET,SO_REUSEADDR,(char* ) &opt,
- sizeof(opt)) <0) {
- dbg_perror(g,"can't set sockopt");
- epmd_cleanup_exit(g,1);
- }
+ opt = 1;
+ if (setsockopt(listensock[i],SOL_SOCKET,SO_REUSEADDR,(char* ) &opt,
+ sizeof(opt)) <0)
+ {
+ dbg_perror(g,"can't set sockopt");
+ epmd_cleanup_exit(g,1);
+ }
#endif
- /* In rare cases select returns because there is someone
- to accept but the request is withdrawn before the
- accept function is called. We set the listen socket
- to be non blocking to prevent us from being hanging
- in accept() waiting for the next request. */
+ /* In rare cases select returns because there is someone
+ to accept but the request is withdrawn before the
+ accept function is called. We set the listen socket
+ to be non blocking to prevent us from being hanging
+ in accept() waiting for the next request. */
#if (defined(__WIN32__) || defined(NO_FCNTL))
- opt = 1;
- if (ioctl(listensock, FIONBIO, &opt) != 0) /* Gives warning in VxWorks */
+ opt = 1;
+ /* Gives warning in VxWorks */
+ if (ioctl(listensock[i], FIONBIO, &opt) != 0)
#else
- opt = fcntl(listensock, F_GETFL, 0);
- if (fcntl(listensock, F_SETFL, opt | O_NONBLOCK) == -1)
+ opt = fcntl(listensock[i], F_GETFL, 0);
+ if (fcntl(listensock[i], F_SETFL, opt | O_NONBLOCK) == -1)
#endif /* __WIN32__ || VXWORKS */
- dbg_perror(g,"failed to set non-blocking mode of listening socket %d",
- listensock);
+ dbg_perror(g,"failed to set non-blocking mode of listening socket %d",
+ listensock[i]);
- { /* store port number in unsigned short */
- unsigned short sport = g->port;
- SET_ADDR_ANY(iserv_addr, FAMILY, sport);
- }
-
- if(bind(listensock,(struct sockaddr*) &iserv_addr, sizeof(iserv_addr)) < 0 )
- {
- if (errno == EADDRINUSE)
- {
- dbg_tty_printf(g,1,"there is already a epmd running at port %d",
- g->port);
- epmd_cleanup_exit(g,0);
- }
- else
+ if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i],
+ sizeof(iserv_addr[i])) < 0)
{
- dbg_perror(g,"failed to bind socket");
- epmd_cleanup_exit(g,1);
+ if (errno == EADDRINUSE)
+ {
+ dbg_tty_printf(g,1,"there is already a epmd running at port %d",
+ g->port);
+ epmd_cleanup_exit(g,0);
+ }
+ else
+ {
+ dbg_perror(g,"failed to bind socket");
+ epmd_cleanup_exit(g,1);
+ }
}
+ listen(listensock[i],SOMAXCONN);
+ FD_SET(listensock[i],&g->orig_read_mask);
}
- dbg_printf(g,2,"starting");
-
- listen(listensock, SOMAXCONN);
-
-
- FD_ZERO(&g->orig_read_mask);
- FD_SET(listensock,&g->orig_read_mask);
-
dbg_tty_printf(g,2,"entering the main select() loop");
select_again:
@@ -198,17 +266,18 @@ void run(EpmdVars *g)
sleep(g->delay_accept);
}
- if (FD_ISSET(listensock,&read_mask)) {
- if (do_accept(g, listensock) && g->active_conn < g->max_conn) {
- /*
- * The accept() succeeded, and we have at least one file
- * descriptor still free, which means that another accept()
- * could succeed. Go do do another select(), in case there
- * are more incoming connections waiting to be accepted.
- */
- goto select_again;
+ 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) {
+ /*
+ * The accept() succeeded, and we have at least one file
+ * descriptor still free, which means that another accept()
+ * could succeed. Go do do another select(), in case there
+ * are more incoming connections waiting to be accepted.
+ */
+ goto select_again;
+ }
}
- }
/* Check all open streams marked by select for data or a
close. We also close all open sockets except ALIVE
--
cgit v1.2.3
From 5b68030b9d57a839ad798415f30936660ca83904 Mon Sep 17 00:00:00 2001
From: Michael Santos
Date: Wed, 24 Nov 2010 19:38:04 -0500
Subject: epmd: include host address in local access check
In FreeBSD jails, the source and destination address of connections
to localhost are changed to be the IP address of the jail. Consider
connections from the host's IP address to itself (e.g., the source and
destination address match) to be local for the access control checks.
Reported-By: tom@diogunix.com
---
erts/epmd/src/epmd_srv.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
index ef471a473a..ace736b836 100644
--- a/erts/epmd/src/epmd_srv.c
+++ b/erts/epmd/src/epmd_srv.c
@@ -736,6 +736,7 @@ 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
@@ -756,12 +757,16 @@ static int conn_open(EpmdVars *g,int fd)
/* Determine if connection is from localhost */
if (getpeername(s->fd,(struct sockaddr*) &si,&st) ||
st < sizeof(si)) {
- /* Failure to get peername is regarder as non local host */
+ /* 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); /* Only 127.x.x.x allowed, no false positives */
+ (((((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));
}
dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" :
"Non-local peer connected");
--
cgit v1.2.3
From 169d7e440437c8b329cef82c4a260a990956caa7 Mon Sep 17 00:00:00 2001
From: Markus Knofe
Date: Fri, 10 Dec 2010 19:14:08 +0100
Subject: Fix list returned by net_kernel:epmd_module
Function epmd_module of net_kernel returns a list
instead of an atom, when the epmd_module-flag is used.
---
lib/kernel/src/net_kernel.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index f5e2820bbe..6c2e0f5514 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -1254,7 +1254,7 @@ protocol_childspecs([H|T]) ->
epmd_module() ->
case init:get_argument(epmd_module) of
{ok,[[Module]]} ->
- Module;
+ list_to_atom(Module);
_ ->
erl_epmd
end.
--
cgit v1.2.3
From 345454e7dcfd4bc38992870cf5aa5ab7efe0c475 Mon Sep 17 00:00:00 2001
From: Tuncer Ayaz
Date: Thu, 10 Mar 2011 20:50:46 +0100
Subject: erts: Remove unused variables
---
erts/emulator/beam/beam_bif_load.c | 3 ---
erts/emulator/beam/beam_load.c | 2 --
erts/emulator/beam/bif.c | 2 --
erts/emulator/beam/dist.c | 2 --
erts/emulator/beam/erl_bits.c | 6 ------
erts/emulator/beam/erl_gc.c | 3 +--
erts/emulator/beam/erl_process.c | 2 --
erts/emulator/beam/erl_unicode.c | 2 --
erts/emulator/beam/io.c | 5 +----
erts/etc/unix/to_erl.c | 8 +-------
10 files changed, 3 insertions(+), 32 deletions(-)
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 6ae9736141..1ca405961f 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -472,9 +472,6 @@ check_process_code(Process* rp, Module* modp)
for (oh = MSO(rp).first; oh; oh = oh->next) {
if (thing_subtag(oh->thing_word) == FUN_SUBTAG) {
ErlFunThing* funp = (ErlFunThing*) oh;
- BeamInstr* fun_code;
-
- fun_code = funp->fe->address;
if (INSIDE((BeamInstr *) funp->fe->address)) {
if (done_gc) {
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 788cb4209c..2a28002957 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -1413,7 +1413,6 @@ static int
load_code(LoaderState* stp)
{
int i;
- int tmp;
int ci;
int last_func_start = 0;
char* sign;
@@ -1933,7 +1932,6 @@ load_code(LoaderState* stp)
case 'P': /* Byte offset into tuple or stack */
case 'Q': /* Like 'P', but packable */
VerifyTag(stp, tag, TAG_u);
- tmp = tmp_op->a[arg].val;
code[ci++] = (BeamInstr) ((tmp_op->a[arg].val+1) * sizeof(Eterm));
break;
case 'l': /* Floating point register. */
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index f01580eb2b..6b1ce823cb 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -368,7 +368,6 @@ static int demonitor(Process *c_p, Eterm ref)
ErtsMonitor *mon = NULL; /* The monitor entry to delete */
Process *rp; /* Local target process */
Eterm to = NIL; /* Monitor link traget */
- Eterm ref_p; /* Pid of this end */
DistEntry *dep = NULL; /* Target's distribution entry */
int deref_de = 0;
int res;
@@ -381,7 +380,6 @@ static int demonitor(Process *c_p, Eterm ref)
res = ERTS_DEMONITOR_BADARG;
goto done; /* Cannot be this monitor's ref */
}
- ref_p = c_p->id;
mon = erts_lookup_monitor(c_p->monitors, ref);
if (!mon) {
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 02910fad90..54f029bdc5 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -900,7 +900,6 @@ int erts_net_message(Port *prt,
ErtsDistExternal ede;
byte *t;
Sint ctl_len;
- int orig_ctl_len;
Eterm arg;
Eterm from, to;
Eterm watcher, watched;
@@ -981,7 +980,6 @@ int erts_net_message(Port *prt,
PURIFY_MSG("data error");
goto data_error;
}
- orig_ctl_len = ctl_len;
if (ctl_len > DIST_CTL_DEFAULT_SIZE) {
ctl = erts_alloc(ERTS_ALC_T_DCTRL_BUF, ctl_len * sizeof(Eterm));
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index 6f8a7436d5..0174e5fc43 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -177,7 +177,6 @@ erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuff
byte* LSB;
byte* MSB;
Uint* hp;
- Uint* hp_end;
Uint words_needed;
Uint actual;
Uint v32;
@@ -405,7 +404,6 @@ erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuff
default:
words_needed = 1+WSIZE(bytes);
hp = HeapOnlyAlloc(p, words_needed);
- hp_end = hp + words_needed;
res = bytes_to_big(LSB, bytes, sgn, hp);
if (is_small(res)) {
p->htop = hp;
@@ -425,7 +423,6 @@ Eterm
erts_bs_get_binary_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb)
{
ErlSubBin* sb;
- size_t num_bytes; /* Number of bytes in binary. */
if (mb->size - mb->offset < num_bits) { /* Asked for too many bits. */
return THE_NON_VALUE;
@@ -435,7 +432,6 @@ erts_bs_get_binary_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffe
* From now on, we can't fail.
*/
- num_bytes = NBYTES(num_bits);
sb = (ErlSubBin *) HeapOnlyAlloc(p, ERL_SUB_BIN_SIZE);
sb->thing_word = HEADER_SUB_BIN;
@@ -1557,7 +1553,6 @@ Uint32
erts_bs_get_unaligned_uint32(ErlBinMatchBuffer* mb)
{
Uint bytes;
- Uint bits;
Uint offs;
byte bigbuf[4];
byte* LSB;
@@ -1567,7 +1562,6 @@ erts_bs_get_unaligned_uint32(ErlBinMatchBuffer* mb)
ASSERT(mb->size - mb->offset >= 32);
bytes = 4;
- bits = 8;
offs = 0;
LSB = bigbuf;
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index d9150d86fe..c30d67ac88 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -455,7 +455,6 @@ erts_garbage_collect_hibernate(Process* p)
Eterm* heap;
Eterm* htop;
Rootset rootset;
- int n;
char* src;
Uint src_size;
Uint actual_size;
@@ -486,7 +485,7 @@ erts_garbage_collect_hibernate(Process* p)
sizeof(Eterm)*heap_size);
htop = heap;
- n = setup_rootset(p, p->arg_reg, p->arity, &rootset);
+ (void) setup_rootset(p, p->arg_reg, p->arity, &rootset);
#if HIPE
hipe_empty_nstack(p);
#endif
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 428ca12eb1..841730b282 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -1267,7 +1267,6 @@ ssi_flags_set_wake(ErtsSchedulerSleepInfo *ssi)
static void
wake_scheduler(ErtsRunQueue *rq, int incq, int one)
{
- int res;
ErtsSchedulerSleepInfo *ssi;
ErtsSchedulerSleepList *sl;
@@ -1298,7 +1297,6 @@ wake_scheduler(ErtsRunQueue *rq, int incq, int one)
if (ssi->next)
ssi->next->prev = ssi->prev;
- res = sl->list != NULL;
erts_smp_spin_unlock(&sl->lock);
ERTS_THR_MEMORY_BARRIER;
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index 545b345a71..dacf228e92 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -902,7 +902,6 @@ static BIF_RETTYPE build_utf8_return(Process *p,Eterm bin,int pos,
static BIF_RETTYPE characters_to_utf8_trap(BIF_ALIST_3)
{
Eterm *real_bin;
- Sint need;
byte* bytes;
Eterm rest_term;
int left, sleft;
@@ -918,7 +917,6 @@ static BIF_RETTYPE characters_to_utf8_trap(BIF_ALIST_3)
ASSERT(is_binary(BIF_ARG_1));
real_bin = binary_val(BIF_ARG_1);
ASSERT(*real_bin == HEADER_PROC_BIN);
- need = ((ProcBin *) real_bin)->val->orig_size;
pos = (int) binary_size(BIF_ARG_1);
bytes = binary_bytes(BIF_ARG_1);
sleft = left = allowed_iterations(BIF_P);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index f21a96c754..2e884a350e 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -1226,7 +1226,6 @@ void init_io(void)
{
int i;
ErlDrvEntry** dp;
- ErlDrvEntry* drv;
char maxports[21]; /* enough for any 64-bit integer */
size_t maxportssize = sizeof(maxports);
Uint ports_bits = ERTS_PORTS_BITS;
@@ -1309,10 +1308,8 @@ void init_io(void)
init_driver(&fd_driver, &fd_driver_entry, NULL);
init_driver(&vanilla_driver, &vanilla_driver_entry, NULL);
init_driver(&spawn_driver, &spawn_driver_entry, NULL);
- for (dp = driver_tab; *dp != NULL; dp++) {
- drv = *dp;
+ for (dp = driver_tab; *dp != NULL; dp++)
erts_add_driver_entry(*dp, NULL, 1);
- }
erts_smp_tsd_set(driver_list_lock_status_key, NULL);
erts_smp_mtx_unlock(&erts_driver_list_lock);
diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c
index 886b301997..b7c3c956c6 100644
--- a/erts/etc/unix/to_erl.c
+++ b/erts/etc/unix/to_erl.c
@@ -125,7 +125,7 @@ static void usage(char *pname)
int main(int argc, char **argv)
{
char FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX];
- int i, len, wfd, rfd, result = 0;
+ int i, len, wfd, rfd;
fd_set readfds;
char buf[BUFSIZ];
char pipename[FILENAME_MAX];
@@ -367,7 +367,6 @@ int main(int argc, char **argv)
}
else {
fprintf(stderr, "Error in select.\n");
- result = -1;
break;
}
}
@@ -398,7 +397,6 @@ int main(int argc, char **argv)
close(wfd);
if (len < 0) {
fprintf(stderr, "Error in reading from stdin.\n");
- result = -1;
} else {
fprintf(stderr, "[EOF]\n\r");
}
@@ -420,7 +418,6 @@ int main(int argc, char **argv)
fprintf(stderr, "Error in writing to FIFO.\n");
close(rfd);
close(wfd);
- result = -1;
break;
}
STATUS("\" OK\r\n");
@@ -447,7 +444,6 @@ int main(int argc, char **argv)
close(wfd);
if (len < 0) {
fprintf(stderr, "Error in reading from FIFO.\n");
- result = -1;
} else
fprintf(stderr, "[End]\n\r");
break;
@@ -456,7 +452,6 @@ int main(int argc, char **argv)
if ((len=version_handshake(buf,len,wfd)) < 0) {
close(rfd);
close(wfd);
- result = -1;
break;
}
if (protocol_ver >= 1) {
@@ -475,7 +470,6 @@ int main(int argc, char **argv)
fprintf(stderr, "Error in writing to terminal.\n");
close(rfd);
close(wfd);
- result = -1;
break;
}
STATUS("\" OK\r\n");
--
cgit v1.2.3
From e6a7750c3a922ab1e2d25b98157de56d60a533c9 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Wed, 30 Mar 2011 10:03:14 +0200
Subject: rb help error
Start and end date for rb:filter/2 was specified as {{Y-M-D},...} in
the help text instead of {{Y,M,D},...}. This has been corrected.
---
lib/sasl/src/rb.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/sasl/src/rb.erl b/lib/sasl/src/rb.erl
index 38e486b7a7..13753565d8 100644
--- a/lib/sasl/src/rb.erl
+++ b/lib/sasl/src/rb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -169,7 +169,7 @@ print_filters() ->
print_dates() ->
io:format(" - {StartDate, EndDate}~n"),
- io:format(" StartDate = EndDate = {{Y-M-D},{H,M,S}} ~n"),
+ io:format(" StartDate = EndDate = {{Y,M,D},{H,M,S}} ~n"),
io:format(" prints the reports with date between StartDate and EndDate~n"),
io:format(" - {StartDate, from}~n"),
io:format(" prints the reports with date greater than StartDate~n"),
--
cgit v1.2.3
From beec1818a8f6b3176bd0c7558feaf7cecad3da3a Mon Sep 17 00:00:00 2001
From: Stavros Aronis
Date: Tue, 29 Mar 2011 19:19:19 +0300
Subject: Fix crash related with the contract blame assignment patch
The relevant commit is 8342fcf5395133a19d647f2ace606af9b7fc1732.
The old patch could emit warnings even for function that had a
problematic spec even without refinement. This warnings would
consume the relevant invalid spec warnings. This patch takes
care of this by ensuring that normal invalid spec messages are
emitted if the call that triggers the blame contract range
warning is in another module.
---
lib/dialyzer/src/dialyzer_succ_typings.erl | 25 ++++++++------
lib/dialyzer/test/small_tests_SUITE.erl | 38 +++++++++++++---------
.../small_tests_SUITE_data/results/invalid_specs | 3 ++
.../src/invalid_specs/invalid_spec1.erl | 28 ++++++++++++++++
.../src/invalid_specs/invalid_spec2.erl | 11 +++++++
5 files changed, 79 insertions(+), 26 deletions(-)
create mode 100644 lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs
create mode 100644 lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl
create mode 100644 lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl
diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl
index 24d6013692..b8da57d3f9 100644
--- a/lib/dialyzer/src/dialyzer_succ_typings.erl
+++ b/lib/dialyzer/src/dialyzer_succ_typings.erl
@@ -155,19 +155,24 @@ postprocess_dataflow_warns(RawWarnings, State, WarnAcc) ->
postprocess_dataflow_warns([], _State, WAcc, Acc) ->
{WAcc, lists:reverse(Acc)};
-postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {File, CallL}, Msg}|Rest],
+postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {CallF, CallL}, Msg}|Rest],
#st{codeserver = Codeserver} = State, WAcc, Acc) ->
{contract_range, [Contract, M, F, A, ArgStrings, CRet]} = Msg,
- {ok, {{File, _ContrL} = FileLine, _C}} =
+ {ok, {{ContrF, _ContrL} = FileLine, _C}} =
dialyzer_codeserver:lookup_mfa_contract({M,F,A}, Codeserver),
- NewMsg =
- {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]},
- W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg},
- Filter =
- fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false;
- (_) -> true
- end,
- postprocess_dataflow_warns(Rest, State, lists:filter(Filter, WAcc), [W|Acc]);
+ case CallF =:= ContrF of
+ true ->
+ NewMsg = {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]},
+ W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg},
+ Filter =
+ fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false;
+ (_) -> true
+ end,
+ FilterWAcc = lists:filter(Filter, WAcc),
+ postprocess_dataflow_warns(Rest, State, FilterWAcc, [W|Acc]);
+ false ->
+ postprocess_dataflow_warns(Rest, State, WAcc, Acc)
+ end;
postprocess_dataflow_warns([W|Rest], State, Wacc, Acc) ->
postprocess_dataflow_warns(Rest, State, Wacc, [W|Acc]).
diff --git a/lib/dialyzer/test/small_tests_SUITE.erl b/lib/dialyzer/test/small_tests_SUITE.erl
index 21a2c76160..dbcc044eea 100644
--- a/lib/dialyzer/test/small_tests_SUITE.erl
+++ b/lib/dialyzer/test/small_tests_SUITE.erl
@@ -18,18 +18,18 @@
contract5/1, disj_norm_form/1, eqeq/1, ets_select/1,
exhaust_case/1, failing_guard1/1, flatten/1, fun_app/1,
fun_ref_match/1, fun_ref_record/1, gencall/1, gs_make/1,
- inf_loop2/1, letrec1/1, list_match/1, lzip/1, make_tuple/1,
- minus_minus/1, mod_info/1, my_filter/1, my_sofs/1, no_match/1,
- no_unused_fun/1, no_unused_fun2/1, non_existing/1,
- not_guard_crash/1, or_bug/1, orelsebug/1, orelsebug2/1,
- overloaded1/1, port_info_test/1, process_info_test/1, pubsub/1,
- receive1/1, record_construct/1, record_pat/1,
- record_send_test/1, record_test/1, recursive_types1/1,
- recursive_types2/1, recursive_types3/1, recursive_types4/1,
- recursive_types5/1, recursive_types6/1, recursive_types7/1,
- refine_bug1/1, toth/1, trec/1, try1/1, tuple1/1,
- unsafe_beamcode_bug/1, unused_cases/1, unused_clauses/1,
- zero_tuple/1]).
+ inf_loop2/1, invalid_specs/1, letrec1/1, list_match/1, lzip/1,
+ make_tuple/1, minus_minus/1, mod_info/1, my_filter/1,
+ my_sofs/1, no_match/1, no_unused_fun/1, no_unused_fun2/1,
+ non_existing/1, not_guard_crash/1, or_bug/1, orelsebug/1,
+ orelsebug2/1, overloaded1/1, port_info_test/1,
+ process_info_test/1, pubsub/1, receive1/1, record_construct/1,
+ record_pat/1, record_send_test/1, record_test/1,
+ recursive_types1/1, recursive_types2/1, recursive_types3/1,
+ recursive_types4/1, recursive_types5/1, recursive_types6/1,
+ recursive_types7/1, refine_bug1/1, toth/1, trec/1, try1/1,
+ tuple1/1, unsafe_beamcode_bug/1, unused_cases/1,
+ unused_clauses/1, zero_tuple/1]).
suite() ->
[{timetrap, {minutes, 1}}].
@@ -51,10 +51,10 @@ all() ->
atom_guard,atom_widen,bs_fail_constr,bs_utf8,cerl_hipeify,comm_layer,
compare1,confusing_warning,contract2,contract3,contract5,disj_norm_form,
eqeq,ets_select,exhaust_case,failing_guard1,flatten,fun_app,fun_ref_match,
- fun_ref_record,gencall,gs_make,inf_loop2,letrec1,list_match,lzip,
- make_tuple,minus_minus,mod_info,my_filter,my_sofs,no_match,no_unused_fun,
- no_unused_fun2,non_existing,not_guard_crash,or_bug,orelsebug,orelsebug2,
- overloaded1,port_info_test,process_info_test,pubsub,receive1,
+ fun_ref_record,gencall,gs_make,inf_loop2,invalid_specs,letrec1,list_match,
+ lzip,make_tuple,minus_minus,mod_info,my_filter,my_sofs,no_match,
+ no_unused_fun,no_unused_fun2,non_existing,not_guard_crash,or_bug,orelsebug,
+ orelsebug2,overloaded1,port_info_test,process_info_test,pubsub,receive1,
record_construct,record_pat,record_send_test,record_test,recursive_types1,
recursive_types2,recursive_types3,recursive_types4,recursive_types5,
recursive_types6,recursive_types7,refine_bug1,toth,trec,try1,tuple1,
@@ -235,6 +235,12 @@ inf_loop2(Config) ->
Error -> ct:fail(Error)
end.
+invalid_specs(Config) ->
+ case dialyze(Config, invalid_specs) of
+ 'same' -> 'same';
+ Error -> ct:fail(Error)
+ end.
+
letrec1(Config) ->
case dialyze(Config, letrec1) of
'same' -> 'same';
diff --git a/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs b/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs
new file mode 100644
index 0000000000..c95c0ff1f8
--- /dev/null
+++ b/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs
@@ -0,0 +1,3 @@
+
+invalid_spec1.erl:5: Invalid type specification for function invalid_spec1:get_plan_dirty/1. The success typing is ([string()]) -> {maybe_improper_list(),[atom()]}
+invalid_spec2.erl:5: Function foo/0 has no local return
diff --git a/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl
new file mode 100644
index 0000000000..06ab2f9a22
--- /dev/null
+++ b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl
@@ -0,0 +1,28 @@
+-module(invalid_spec1).
+
+-export([get_plan_dirty/1]).
+
+-spec get_plan_dirty([string()]) -> {{atom(), any()}, [atom()]}.
+
+get_plan_dirty(ClassL) ->
+ get_plan_dirty(ClassL, [], []).
+
+get_plan_dirty([], Res, FoundClassList) ->
+ {Res,FoundClassList};
+get_plan_dirty([Class|ClassL], Res, FoundClassList) ->
+ ClassPlan = list_to_atom(Class ++ "_plan"),
+ case catch mnesia:dirty_all_keys(ClassPlan) of
+ {'EXIT',_} ->
+ get_plan_dirty(ClassL, Res, FoundClassList);
+ [] ->
+ get_plan_dirty(ClassL, Res, FoundClassList);
+ KeyL ->
+ ClassAtom = list_to_atom(Class),
+ Res2 =
+ lists:foldl(fun(Key, Acc) ->
+ [{ClassAtom,Key}|Acc]
+ end,
+ Res,
+ KeyL),
+ get_plan_dirty(ClassL, Res2, [ClassAtom|FoundClassList])
+ end.
diff --git a/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl
new file mode 100644
index 0000000000..e49f73d014
--- /dev/null
+++ b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl
@@ -0,0 +1,11 @@
+-module(invalid_spec2).
+
+-export([foo/0]).
+
+foo() ->
+ case
+ invalid_spec1:get_plan_dirty(mnesia:dirty_all_keys(cmClassInfo))
+ of
+ {[],[]} -> foo;
+ { _, _} -> bar
+ end.
--
cgit v1.2.3
From 6d1cfbcd7a782cc96f58b86372d108b50c14cc05 Mon Sep 17 00:00:00 2001
From: Andrew Thompson
Date: Fri, 1 Apr 2011 00:34:21 -0400
Subject: Add support for DragonFlyBSD to memsup
DragonFly was partially supported by os_mon already but when trying to
start the os_mon application it'd crash with an error about an unknown
operating system in memsup. This patch changes memsup to use the FreeBSD
sysctl method to get memory information when on DragonFly.
---
lib/os_mon/src/memsup.erl | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index 822e1f939c..6c677fae8e 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -176,6 +176,7 @@ init([]) ->
PortMode = case OS of
{unix, darwin} -> false;
{unix, freebsd} -> false;
+ {unix, dragonfly} -> false;
% Linux supports this.
{unix, linux} -> true;
{unix, openbsd} -> true;
@@ -610,6 +611,7 @@ code_change(Vsn, PrevState, "1.8") ->
PortMode = case OS of
{unix, darwin} -> false;
{unix, freebsd} -> false;
+ {unix, dragonfly} -> false;
{unix, linux} -> false;
{unix, openbsd} -> true;
{unix, sunos} -> true;
@@ -687,6 +689,7 @@ get_os_wordsize({unix, linux}) -> get_os_wordsize_with_uname();
get_os_wordsize({unix, darwin}) -> get_os_wordsize_with_uname();
get_os_wordsize({unix, netbsd}) -> get_os_wordsize_with_uname();
get_os_wordsize({unix, freebsd}) -> get_os_wordsize_with_uname();
+get_os_wordsize({unix, dragonfly}) -> get_os_wordsize_with_uname();
get_os_wordsize({unix, openbsd}) -> get_os_wordsize_with_uname();
get_os_wordsize(_) -> unsupported_os.
@@ -736,7 +739,7 @@ get_memory_usage({unix,darwin}) ->
%% FreeBSD: Look in /usr/include/sys/vmmeter.h for the format of struct
%% vmmeter
-get_memory_usage({unix,freebsd}) ->
+get_memory_usage({unix,OSname}) when OSname == freebsd; OSname == dragonfly ->
PageSize = freebsd_sysctl("vm.stats.vm.v_page_size"),
PageCount = freebsd_sysctl("vm.stats.vm.v_page_count"),
FreeCount = freebsd_sysctl("vm.stats.vm.v_free_count"),
@@ -779,6 +782,9 @@ get_ext_memory_usage(OS, {Alloc, Total}) ->
{unix, freebsd} ->
[{total_memory, Total}, {free_memory, Total-Alloc},
{system_total_memory, Total}];
+ {unix, dragonfly} ->
+ [{total_memory, Total}, {free_memory, Total-Alloc},
+ {system_total_memory, Total}];
{unix, darwin} ->
[{total_memory, Total}, {free_memory, Total-Alloc},
{system_total_memory, Total}];
--
cgit v1.2.3
From ca1223e5b5c8b25e92fef0d97a6a12abad8ccd71 Mon Sep 17 00:00:00 2001
From: Andrew Thompson
Date: Sun, 3 Apr 2011 21:32:02 -0400
Subject: Add NetBSD support to memsup and disksup
---
lib/os_mon/src/disksup.erl | 4 ++++
lib/os_mon/src/memsup.erl | 2 ++
2 files changed, 6 insertions(+)
diff --git a/lib/os_mon/src/disksup.erl b/lib/os_mon/src/disksup.erl
index 3340f7ee72..3ee1df759f 100644
--- a/lib/os_mon/src/disksup.erl
+++ b/lib/os_mon/src/disksup.erl
@@ -103,6 +103,7 @@ init([]) ->
Flavor==darwin;
Flavor==linux;
Flavor==openbsd;
+ Flavor==netbsd;
Flavor==irix64;
Flavor==irix ->
start_portprogram();
@@ -267,6 +268,9 @@ check_disk_space({unix, freebsd}, Port, Threshold) ->
check_disk_space({unix, openbsd}, Port, Threshold) ->
Result = my_cmd("/bin/df -k -t ffs", Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
+check_disk_space({unix, netbsd}, Port, Threshold) ->
+ Result = my_cmd("/bin/df -k -t ffs", Port),
+ check_disks_solaris(skip_to_eol(Result), Threshold);
check_disk_space({unix, sunos4}, Port, Threshold) ->
Result = my_cmd("df", Port),
check_disks_solaris(skip_to_eol(Result), Threshold);
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index 822e1f939c..8ed5e2d595 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -179,6 +179,7 @@ init([]) ->
% Linux supports this.
{unix, linux} -> true;
{unix, openbsd} -> true;
+ {unix, netbsd} -> true;
{unix, irix64} -> true;
{unix, irix} -> true;
{unix, sunos} -> true;
@@ -612,6 +613,7 @@ code_change(Vsn, PrevState, "1.8") ->
{unix, freebsd} -> false;
{unix, linux} -> false;
{unix, openbsd} -> true;
+ {unix, netbsd} -> true;
{unix, sunos} -> true;
{win32, _OSname} -> false;
vxworks -> true
--
cgit v1.2.3
From 02e09f135b2ef75ff440ee008e3db437b8fc3ff7 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson
Date: Fri, 25 Mar 2011 13:14:35 +0100
Subject: Mnesia sometimes failed to tell all nodes that it had started.
---
lib/mnesia/src/mnesia_controller.erl | 83 ++++++++++++++++++++++--------------
1 file changed, 50 insertions(+), 33 deletions(-)
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 021be8af2a..0254769758 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -457,7 +457,7 @@ connect_nodes2(Father, Ns, UserFun) ->
New1 = mnesia_lib:intersect(Ns, Connected),
New = New1 -- Current,
process_flag(trap_exit, true),
- Res = try_merge_schema(New, UserFun),
+ Res = try_merge_schema(New, [], UserFun),
Msg = {schema_is_merged, [], late_merge, []},
multicall([node()|Ns], Msg),
After = val({current, db_nodes}),
@@ -471,7 +471,7 @@ connect_nodes2(Father, Ns, UserFun) ->
merge_schema() ->
AllNodes = mnesia_lib:all_nodes(),
- case try_merge_schema(AllNodes, fun default_merge/1) of
+ case try_merge_schema(AllNodes, [node()], fun default_merge/1) of
ok ->
schema_is_merged();
{aborted, {throw, Str}} when is_list(Str) ->
@@ -483,11 +483,17 @@ merge_schema() ->
default_merge(F) ->
F([]).
-try_merge_schema(Nodes, UserFun) ->
+try_merge_schema(Nodes, Told0, UserFun) ->
case mnesia_schema:merge_schema(UserFun) of
{atomic, not_merged} ->
%% No more nodes that we need to merge the schema with
- ok;
+ %% Ensure we have told everybody that we are running
+ case val({current,db_nodes}) -- mnesia_lib:uniq(Told0) of
+ [] -> ok;
+ Tell ->
+ im_running(Tell, [node()]),
+ ok
+ end;
{atomic, {merged, OldFriends, NewFriends}} ->
%% Check if new nodes has been added to the schema
Diff = mnesia_lib:all_nodes() -- [node() | Nodes],
@@ -496,12 +502,18 @@ try_merge_schema(Nodes, UserFun) ->
%% Tell everybody to adopt orphan tables
im_running(OldFriends, NewFriends),
im_running(NewFriends, OldFriends),
-
- try_merge_schema(Nodes, UserFun);
+ Told = case lists:member(node(), NewFriends) of
+ true -> Told0 ++ OldFriends;
+ false -> Told0 ++ NewFriends
+ end,
+ try_merge_schema(Nodes, Told, UserFun);
{atomic, {"Cannot get cstructs", Node, Reason}} ->
dbg_out("Cannot get cstructs, Node ~p ~p~n", [Node, Reason]),
- timer:sleep(1000), % Avoid a endless loop look alike
- try_merge_schema(Nodes, UserFun);
+ timer:sleep(300), % Avoid a endless loop look alike
+ try_merge_schema(Nodes, Told0, UserFun);
+ {aborted, {shutdown, _}} -> %% One of the nodes is going down
+ timer:sleep(300), % Avoid a endless loop look alike
+ try_merge_schema(Nodes, Told0, UserFun);
Other ->
Other
end.
@@ -915,6 +927,7 @@ handle_cast(unblock_controller, State) ->
handle_cast({mnesia_down, Node}, State) ->
maybe_log_mnesia_down(Node),
mnesia_lib:del({current, db_nodes}, Node),
+ mnesia_lib:unset({node_up, Node}),
mnesia_checkpoint:tm_mnesia_down(Node),
Alltabs = val({schema, tables}),
reconfigure_tables(Node, Alltabs),
@@ -977,11 +990,12 @@ handle_cast(Msg, State) when State#state.schema_is_merged /= true ->
%% This must be done after schema_is_merged otherwise adopt_orphan
%% might trigger a table load from wrong nodes as a result of that we don't
%% know which tables we can load safly first.
-handle_cast({im_running, _Node, NewFriends}, State) ->
+handle_cast({im_running, Node, NewFriends}, State) ->
LocalTabs = mnesia_lib:local_active_tables() -- [schema],
RemoveLocalOnly = fun(Tab) -> not val({Tab, local_content}) end,
Tabs = lists:filter(RemoveLocalOnly, LocalTabs),
- Ns = mnesia_lib:intersect(NewFriends, val({current, db_nodes})),
+ Nodes = mnesia_lib:union([Node],val({current, db_nodes})),
+ Ns = mnesia_lib:intersect(NewFriends, Nodes),
abcast(Ns, {adopt_orphans, node(), Tabs}),
noreply(State);
@@ -1042,30 +1056,33 @@ handle_cast({master_nodes_updated, Tab, Masters}, State) ->
end;
handle_cast({adopt_orphans, Node, Tabs}, State) ->
-
State2 = node_has_tabs(Tabs, Node, State),
- %% Register the other node as up and running
- mnesia_recover:log_mnesia_up(Node),
- verbose("Logging mnesia_up ~w~n",[Node]),
- mnesia_lib:report_system_event({mnesia_up, Node}),
-
- %% Load orphan tables
- LocalTabs = val({schema, local_tables}) -- [schema],
- Nodes = val({current, db_nodes}),
- {LocalOrphans, RemoteMasters} =
- orphan_tables(LocalTabs, Node, Nodes, [], []),
- Reason = {adopt_orphan, node()},
- mnesia_late_loader:async_late_disc_load(node(), LocalOrphans, Reason),
-
- Fun =
- fun(N) ->
- RemoteOrphans =
- [Tab || {Tab, Ns} <- RemoteMasters,
- lists:member(N, Ns)],
- mnesia_late_loader:maybe_async_late_disc_load(N, RemoteOrphans, Reason)
- end,
- lists:foreach(Fun, Nodes),
+ case ?catch_val({node_up,Node}) of
+ true -> ignore;
+ _ ->
+ %% Register the other node as up and running
+ set({node_up, Node}, true),
+ mnesia_recover:log_mnesia_up(Node),
+ verbose("Logging mnesia_up ~w~n",[Node]),
+ mnesia_lib:report_system_event({mnesia_up, Node}),
+ %% Load orphan tables
+ LocalTabs = val({schema, local_tables}) -- [schema],
+ Nodes = val({current, db_nodes}),
+ {LocalOrphans, RemoteMasters} =
+ orphan_tables(LocalTabs, Node, Nodes, [], []),
+ Reason = {adopt_orphan, node()},
+ mnesia_late_loader:async_late_disc_load(node(), LocalOrphans, Reason),
+
+ Fun =
+ fun(N) ->
+ RemoteOrphans =
+ [Tab || {Tab, Ns} <- RemoteMasters,
+ lists:member(N, Ns)],
+ mnesia_late_loader:maybe_async_late_disc_load(N, RemoteOrphans, Reason)
+ end,
+ lists:foreach(Fun, Nodes)
+ end,
noreply(State2);
handle_cast(Msg, State) ->
--
cgit v1.2.3
From 12634a96eaa9ab3e46ee5d4de771be9a8ddeab28 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson
Date: Mon, 4 Apr 2011 14:52:23 +0200
Subject: Prepare release
---
lib/mnesia/src/mnesia.appup.src | 30 +++++++++++++++++++-----------
lib/mnesia/vsn.mk | 2 +-
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src
index 0eff761b61..7bad6c4ea6 100644
--- a/lib/mnesia/src/mnesia.appup.src
+++ b/lib/mnesia/src/mnesia.appup.src
@@ -1,25 +1,33 @@
%% -*- erlang -*-
{"%VSN%",
[
- {"4.4.16",[
- {update, mnesia_frag, soft, soft_purge, soft_purge, []},
- {update, mnesia_schema, soft, soft_purge, soft_purge, []}
+ {"4.4.17",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []}
]},
- {"4.4.15",[
- {update, mnesia_frag, soft, soft_purge, soft_purge, []},
- {update, mnesia, soft, soft_purge, soft_purge, []},
- {update, mnesia_dumper, soft, soft_purge, soft_purge, []}
- ]}
- ],
- [
{"4.4.16",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []},
{update, mnesia_frag, soft, soft_purge, soft_purge, []},
{update, mnesia_schema, soft, soft_purge, soft_purge, []}
]},
{"4.4.15",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []},
{update, mnesia_frag, soft, soft_purge, soft_purge, []},
{update, mnesia, soft, soft_purge, soft_purge, []},
{update, mnesia_dumper, soft, soft_purge, soft_purge, []}
]}
- ]
+ ],
+ {"4.4.17",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []}
+ ]},
+ {"4.4.16",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []},
+ {update, mnesia_frag, soft, soft_purge, soft_purge, []},
+ {update, mnesia_schema, soft, soft_purge, soft_purge, []}
+ ]},
+ {"4.4.15",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []},
+ {update, mnesia_frag, soft, soft_purge, soft_purge, []},
+ {update, mnesia, soft, soft_purge, soft_purge, []},
+ {update, mnesia_dumper, soft, soft_purge, soft_purge, []}
+ ]}
}.
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 5247657b68..38e1a94545 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.4.17
+MNESIA_VSN = 4.4.18
--
cgit v1.2.3
From 6a3ff7ea9207bc18d2ca13666dcc286cbafa7de6 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Mon, 4 Apr 2011 15:31:36 +0200
Subject: Update release notes
---
lib/mnesia/doc/src/notes.xml | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index ccf70b8373..19574a1434 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -38,7 +38,35 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.
- Mnesia 4.4.17
+ Mnesia 4.4.18
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Call chmod without the "-f" flag
+
+ "-f" is a non-standard chmod option which at least SGI
+ IRIX and HP UX do not support. As the only effect of the
+ "-f" flag is to suppress warning messages, it can be
+ safely omitted. (Thanks to Holger Weiß)
+
+ Own Id: OTP-9170
+
+ -
+
+ Mnesia sometimes failed to update meta-information in
+ large systems, which could cause table content to be
+ inconsistent between nodes.
+
+ Own Id: OTP-9186 Aux Id: seq11728
+
+
+
+
+
+
+Mnesia 4.4.17
Fixed Bugs and Malfunctions
--
cgit v1.2.3
From ca8dcd1911a9a382ac8dd0d511d009d5c3ae37c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?=
Date: Mon, 11 Apr 2011 15:08:06 +0200
Subject: Remove documentation for non-existent init:get_args/0
init:get_args/0 was deprecated in R9C and removed in R12B.
Reported-by: Eric Pailleau
---
erts/doc/src/init.xml | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/erts/doc/src/init.xml b/erts/doc/src/init.xml
index 33364c709a..0e828389f6 100644
--- a/erts/doc/src/init.xml
+++ b/erts/doc/src/init.xml
@@ -66,19 +66,6 @@
respectively.
-
- get_args() -> [Arg]
- Get all non-flag command line arguments
-
- Arg = atom()
-
-
- Returns any plain command line arguments as a list of atoms
- (possibly empty). It is recommended that
- get_plain_arguments/1 is used instead, because of
- the limited length of atoms.
-
-
get_argument(Flag) -> {ok, Arg} | error
Get the values associated with a command line user flag
--
cgit v1.2.3