aboutsummaryrefslogtreecommitdiffstats
path: root/erts/preloaded
diff options
context:
space:
mode:
Diffstat (limited to 'erts/preloaded')
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin50384 -> 50384 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin24316 -> 24320 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin44348 -> 44876 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1428 -> 1432 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin30536 -> 31552 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin57268 -> 65060 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin22428 -> 22432 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin10612 -> 10616 bytes
-rw-r--r--erts/preloaded/src/Makefile22
-rw-r--r--erts/preloaded/src/init.erl71
-rw-r--r--erts/preloaded/src/prim_file.erl109
-rw-r--r--erts/preloaded/src/prim_inet.erl250
12 files changed, 339 insertions, 113 deletions
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 222809e662..87ff5119fd 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 65c7369b76..6b0d96ff8e 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index f1b54b7fcb..8a7a9a1314 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index abf17bcb0e..5d544ff4aa 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index a3f300268f..3ed02ecd44 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index a777971b32..79a8d22366 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index 0fe38a1fb2..3cc8c6b8be 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 7108bf44d0..3f9e867542 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index 785ad531f3..145638802f 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2009. All Rights Reserved.
+# Copyright Ericsson AB 2008-2010. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -20,8 +20,7 @@
# be used when the preloaded modules actually are to be updated (i.e. the
# beam files are to be recompiled, which is normally not done).
# The beam files are placed in the current directory and should be copied
-# to the ../ebin directory by using the commit target (only works in
-# clearcase).
+# to the ../ebin directory by using the copy target.
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
@@ -62,26 +61,9 @@ debug opt: $(TARGET_FILES)
clean:
rm -f $(TARGET_FILES)
-prepare:
- cleartool co -nc $(STATIC_EBIN)/*
- cleartool co -nc $(STATIC_EBIN)
-
copy:
- for x in *.beam; do\
- if test '!' -f $(STATIC_EBIN)/$$x; then\
- cleartool mkelem -nc $$x;\
- fi;\
- done
cp *.beam $(STATIC_EBIN)
-commit:
- cleartool ci -ident -nc $(STATIC_EBIN)/*.beam
- cleartool ci -ident -nc $(STATIC_EBIN)
-
-cancel:
- -cleartool unco -rm $(STATIC_EBIN)
- -cleartool unco -rm $(STATIC_EBIN)/*.beam
-
include $(ERL_TOP)/make/otp_release_targets.mk
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 3b98b9cddc..24430a3d40 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -51,6 +51,9 @@
get_status/0,boot/1,get_arguments/0,get_plain_arguments/0,
get_argument/1,script_id/0]).
+%% for the on_load functionality; not for general use
+-export([run_on_load_handlers/0]).
+
%% internal exports
-export([fetch_loaded/0,ensure_loaded/1,make_permanent/2,
notify_when_started/1,wait_until_started/0,
@@ -69,6 +72,7 @@
script_id = [],
loaded = [],
subscribed = []}).
+-type state() :: #state{}.
-define(ON_LOAD_HANDLER, init__boot__on_load_handler).
@@ -143,10 +147,10 @@ restart() -> init ! {stop,restart}, ok.
-spec reboot() -> 'ok'.
reboot() -> init ! {stop,reboot}, ok.
--spec stop() -> no_return().
+-spec stop() -> 'ok'.
stop() -> init ! {stop,stop}, ok.
--spec stop(non_neg_integer() | string()) -> no_return().
+-spec stop(non_neg_integer() | string()) -> 'ok'.
stop(Status) -> init ! {stop,{stop,Status}}, ok.
-spec boot([binary()]) -> no_return().
@@ -275,7 +279,7 @@ crash(String, List) ->
halt(halt_string(String, List)).
%% Status is {InternalStatus,ProvidedStatus}
--spec boot_loop(pid(), #state{}) -> no_return().
+-spec boot_loop(pid(), state()) -> no_return().
boot_loop(BootPid, State) ->
receive
{BootPid,loaded,ModLoaded} ->
@@ -308,24 +312,6 @@ boot_loop(BootPid, State) ->
{stop,Reason} ->
stop(Reason,State);
{From,fetch_loaded} -> %% Fetch and reset initially loaded modules.
- case whereis(?ON_LOAD_HANDLER) of
- undefined ->
- %% There is no on_load handler process,
- %% probably because init:restart/0 has been
- %% called and it is not the first time we
- %% pass through here.
- ok;
- Pid when is_pid(Pid) ->
- Pid ! run_on_load,
- receive
- {'EXIT',Pid,on_load_done} ->
- ok;
- {'EXIT',Pid,Res} ->
- %% Failure to run an on_load handler.
- %% This is fatal during start-up.
- exit(Res)
- end
- end,
From ! {init,State#state.loaded},
garb_boot_loop(BootPid,State#state{loaded = []});
{From,{ensure_loaded,Module}} ->
@@ -736,6 +722,7 @@ do_boot(Init,Flags,Start) ->
BootList = get_boot(BootFile,Root),
LoadMode = b2a(get_flag('-mode',Flags,false)),
Deb = b2a(get_flag('-init_debug',Flags,false)),
+ catch ?ON_LOAD_HANDLER ! {init_debug_flag,Deb},
BootVars = get_flag_args('-boot_var',Flags),
ParallelLoad =
(Pgm =:= "efile") and (erlang:system_info(thread_pool_size) > 0),
@@ -1335,23 +1322,44 @@ archive_extension() ->
%%% Support for handling of on_load functions.
%%%
+run_on_load_handlers() ->
+ Ref = monitor(process, ?ON_LOAD_HANDLER),
+ catch ?ON_LOAD_HANDLER ! run_on_load,
+ receive
+ {'DOWN',Ref,process,_,noproc} ->
+ %% There is no on_load handler process,
+ %% probably because init:restart/0 has been
+ %% called and it is not the first time we
+ %% pass through here.
+ ok;
+ {'DOWN',Ref,process,_,on_load_done} ->
+ ok;
+ {'DOWN',Ref,process,_,Res} ->
+ %% Failure to run an on_load handler.
+ %% This is fatal during start-up.
+ exit(Res)
+ end.
+
start_on_load_handler_process() ->
register(?ON_LOAD_HANDLER,
- spawn_link(fun on_load_handler_init/0)).
+ spawn(fun on_load_handler_init/0)).
on_load_handler_init() ->
- on_load_loop([]).
+ on_load_loop([], false).
-on_load_loop(Mods) ->
+on_load_loop(Mods, Debug0) ->
receive
+ {init_debug_flag,Debug} ->
+ on_load_loop(Mods, Debug);
{loaded,Mod} ->
- on_load_loop([Mod|Mods]);
+ on_load_loop([Mod|Mods], Debug0);
run_on_load ->
- run_on_load_handlers(Mods),
+ run_on_load_handlers(Mods, Debug0),
exit(on_load_done)
end.
-run_on_load_handlers([M|Ms]) ->
+run_on_load_handlers([M|Ms], Debug) ->
+ debug(Debug, {running_on_load_handler,M}),
Fun = fun() ->
Res = erlang:call_on_load_function(M),
exit(Res)
@@ -1363,9 +1371,12 @@ run_on_load_handlers([M|Ms]) ->
erlang:finish_after_on_load(M, Keep),
case Keep of
false ->
- exit({on_load_function_failed,M});
+ Error = {on_load_function_failed,M},
+ debug(Debug, Error),
+ exit(Error);
true ->
- run_on_load_handlers(Ms)
+ debug(Debug, {on_load_handler_returned_ok,M}),
+ run_on_load_handlers(Ms, Debug)
end
end;
-run_on_load_handlers([]) -> ok.
+run_on_load_handlers([], _) -> ok.
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 7f24889bb2..10be852e92 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -109,6 +109,8 @@
-define(FILE_RESP_LDATA, 6).
-define(FILE_RESP_N2DATA, 7).
-define(FILE_RESP_EOF, 8).
+-define(FILE_RESP_FNAME, 9).
+-define(FILE_RESP_ALL_DATA, 10).
%% Open modes for the driver's open function.
-define(EFILE_MODE_READ, 1).
@@ -153,7 +155,7 @@
%% Opens a file using the driver port Port. Returns {error, Reason}
%% | {ok, FileDescriptor}
open(Port, File, ModeList) when is_port(Port),
- is_list(File),
+ (is_list(File) orelse is_binary(File)),
is_list(ModeList) ->
case open_mode(ModeList) of
{Mode, _Portopts, _Setopts} ->
@@ -165,10 +167,11 @@ open(_,_,_) ->
{error, badarg}.
%% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}.
-open(File, ModeList) when is_list(File), is_list(ModeList) ->
+open(File, ModeList) when (is_list(File) orelse is_binary(File)),
+ is_list(ModeList) ->
case open_mode(ModeList) of
{Mode, Portopts, Setopts} ->
- open_int({?FD_DRV, Portopts}, File, Mode, Setopts);
+ open_int({?FD_DRV, Portopts},File, Mode, Setopts);
Reason ->
{error, Reason}
end;
@@ -196,7 +199,7 @@ open_int({Driver, Portopts}, File, Mode, Setopts) ->
end;
open_int(Port, File, Mode, Setopts) ->
M = Mode band ?EFILE_MODE_MASK,
- case drv_command(Port, [<<?FILE_OPEN, M:32>>, File, 0]) of
+ case drv_command(Port, [<<?FILE_OPEN, M:32>>, pathname(File)]) of
{ok, Number} ->
open_int_setopts(Port, Number, Setopts);
Error ->
@@ -489,7 +492,7 @@ ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}},
%% Returns {ok, Contents} | {error, Reason}
-read_file(File) ->
+read_file(File) when (is_list(File) orelse is_binary(File)) ->
case drv_open(?FD_DRV, [binary]) of
{ok, Port} ->
Result = read_file(Port, File),
@@ -497,11 +500,14 @@ read_file(File) ->
Result;
{error, _} = Error ->
Error
- end.
+ end;
+read_file(_) ->
+ {error, badarg}.
%% Takes a Port opened with open/1.
-read_file(Port, File) when is_port(Port) ->
- Cmd = [?FILE_READ_FILE | File],
+read_file(Port, File) when is_port(Port),
+ (is_list(File) orelse is_binary(File))->
+ Cmd = [?FILE_READ_FILE | pathname(File)],
case drv_command(Port, Cmd) of
{error, enomem} ->
%% It could possibly help to do a
@@ -512,12 +518,14 @@ read_file(Port, File) when is_port(Port) ->
drv_command(Port, Cmd);
Result ->
Result
- end.
+ end;
+read_file(_,_) ->
+ {error, badarg}.
%% Returns {error, Reason} | ok.
-write_file(File, Bin) ->
+write_file(File, Bin) when (is_list(File) orelse is_binary(File)) ->
case open(File, [binary, write]) of
{ok, Handle} ->
Result = write(Handle, Bin),
@@ -525,8 +533,10 @@ write_file(File, Bin) ->
Result;
Error ->
Error
- end.
-
+ end;
+write_file(_, _) ->
+ {error, badarg}.
+
%%%-----------------------------------------------------------------
@@ -539,7 +549,7 @@ write_file(File, Bin) ->
%% Returns {ok, Port}, the Port should be used as first argument in all
%% the following functions. Returns {error, Reason} upon failure.
start() ->
- try erlang:open_port({spawn, atom_to_list(?DRV)}, []) of
+ try erlang:open_port({spawn, atom_to_list(?DRV)}, [binary]) of
Port ->
{ok, Port}
catch
@@ -596,7 +606,7 @@ get_cwd(_, _) ->
{error, badarg}.
get_cwd_int(Drive) ->
- get_cwd_int({?DRV, []}, Drive).
+ get_cwd_int({?DRV, [binary]}, Drive).
get_cwd_int(Port, Drive) ->
drv_command(Port, <<?FILE_PWD, Drive>>).
@@ -606,7 +616,7 @@ get_cwd_int(Port, Drive) ->
%% set_cwd/{1,2}
set_cwd(Dir) ->
- set_cwd_int({?DRV, []}, Dir).
+ set_cwd_int({?DRV, [binary]}, Dir).
set_cwd(Port, Dir) when is_port(Port) ->
set_cwd_int(Port, Dir).
@@ -632,89 +642,88 @@ set_cwd_int(Port, Dir0) ->
end),
%% Dir is now either a string or an EXIT tuple.
%% An EXIT tuple will fail in the following catch.
- drv_command(Port, [?FILE_CHDIR, Dir, 0]).
+ drv_command(Port, [?FILE_CHDIR, pathname(Dir)]).
%% delete/{1,2}
delete(File) ->
- delete_int({?DRV, []}, File).
+ delete_int({?DRV, [binary]}, File).
delete(Port, File) when is_port(Port) ->
delete_int(Port, File).
delete_int(Port, File) ->
- drv_command(Port, [?FILE_DELETE, File, 0]).
+ drv_command(Port, [?FILE_DELETE, pathname(File)]).
%% rename/{2,3}
rename(From, To) ->
- rename_int({?DRV, []}, From, To).
+ rename_int({?DRV, [binary]}, From, To).
rename(Port, From, To) when is_port(Port) ->
rename_int(Port, From, To).
rename_int(Port, From, To) ->
- drv_command(Port, [?FILE_RENAME, From, 0, To, 0]).
+ drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To)]).
%% make_dir/{1,2}
make_dir(Dir) ->
- make_dir_int({?DRV, []}, Dir).
+ make_dir_int({?DRV, [binary]}, Dir).
make_dir(Port, Dir) when is_port(Port) ->
make_dir_int(Port, Dir).
make_dir_int(Port, Dir) ->
- drv_command(Port, [?FILE_MKDIR, Dir, 0]).
+ drv_command(Port, [?FILE_MKDIR, pathname(Dir)]).
%% del_dir/{1,2}
del_dir(Dir) ->
- del_dir_int({?DRV, []}, Dir).
+ del_dir_int({?DRV, [binary]}, Dir).
del_dir(Port, Dir) when is_port(Port) ->
del_dir_int(Port, Dir).
del_dir_int(Port, Dir) ->
- drv_command(Port, [?FILE_RMDIR, Dir, 0]).
+ drv_command(Port, [?FILE_RMDIR, pathname(Dir)]).
%% read_file_info/{1,2}
read_file_info(File) ->
- read_file_info_int({?DRV, []}, File).
+ read_file_info_int({?DRV, [binary]}, File).
read_file_info(Port, File) when is_port(Port) ->
read_file_info_int(Port, File).
read_file_info_int(Port, File) ->
- drv_command(Port, [?FILE_FSTAT, File, 0]).
+ drv_command(Port, [?FILE_FSTAT, pathname(File)]).
%% altname/{1,2}
altname(File) ->
- altname_int({?DRV, []}, File).
+ altname_int({?DRV, [binary]}, File).
altname(Port, File) when is_port(Port) ->
altname_int(Port, File).
altname_int(Port, File) ->
- drv_command(Port, [?FILE_ALTNAME, File, 0]).
-
+ drv_command(Port, [?FILE_ALTNAME, pathname(File)]).
%% write_file_info/{2,3}
write_file_info(File, Info) ->
- write_file_info_int({?DRV, []}, File, Info).
+ write_file_info_int({?DRV, [binary]}, File, Info).
write_file_info(Port, File, Info) when is_port(Port) ->
write_file_info_int(Port, File, Info).
@@ -740,72 +749,72 @@ write_file_info_int(Port,
date_to_bytes(Atime),
date_to_bytes(Mtime),
date_to_bytes(Ctime),
- File, 0]).
+ pathname(File)]).
%% make_link/{2,3}
make_link(Old, New) ->
- make_link_int({?DRV, []}, Old, New).
+ make_link_int({?DRV, [binary]}, Old, New).
make_link(Port, Old, New) when is_port(Port) ->
make_link_int(Port, Old, New).
make_link_int(Port, Old, New) ->
- drv_command(Port, [?FILE_LINK, Old, 0, New, 0]).
+ drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New)]).
%% make_symlink/{2,3}
make_symlink(Old, New) ->
- make_symlink_int({?DRV, []}, Old, New).
+ make_symlink_int({?DRV, [binary]}, Old, New).
make_symlink(Port, Old, New) when is_port(Port) ->
make_symlink_int(Port, Old, New).
make_symlink_int(Port, Old, New) ->
- drv_command(Port, [?FILE_SYMLINK, Old, 0, New, 0]).
+ drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New)]).
%% read_link/{2,3}
read_link(Link) ->
- read_link_int({?DRV, []}, Link).
+ read_link_int({?DRV, [binary]}, Link).
read_link(Port, Link) when is_port(Port) ->
read_link_int(Port, Link).
read_link_int(Port, Link) ->
- drv_command(Port, [?FILE_READLINK, Link, 0]).
+ drv_command(Port, [?FILE_READLINK, pathname(Link)]).
%% read_link_info/{2,3}
read_link_info(Link) ->
- read_link_info_int({?DRV, []}, Link).
+ read_link_info_int({?DRV, [binary]}, Link).
read_link_info(Port, Link) when is_port(Port) ->
read_link_info_int(Port, Link).
read_link_info_int(Port, Link) ->
- drv_command(Port, [?FILE_LSTAT, Link, 0]).
+ drv_command(Port, [?FILE_LSTAT, pathname(Link)]).
%% list_dir/{1,2}
list_dir(Dir) ->
- list_dir_int({?DRV, []}, Dir).
+ list_dir_int({?DRV, [binary]}, Dir).
list_dir(Port, Dir) when is_port(Port) ->
list_dir_int(Port, Dir).
list_dir_int(Port, Dir) ->
- drv_command(Port, [?FILE_READDIR, Dir, 0], []).
+ drv_command(Port, [?FILE_READDIR, pathname(Dir)], []).
@@ -1026,8 +1035,6 @@ lseek_position(_) ->
translate_response(?FILE_RESP_OK, []) ->
ok;
-translate_response(?FILE_RESP_OK, Data) ->
- {ok, Data};
translate_response(?FILE_RESP_ERROR, List) when is_list(List) ->
{error, list_to_atom(List)};
translate_response(?FILE_RESP_NUMBER, List) ->
@@ -1074,6 +1081,16 @@ translate_response(?FILE_RESP_N2DATA = X, L0) when is_list(L0) ->
end;
translate_response(?FILE_RESP_EOF, []) ->
eof;
+translate_response(?FILE_RESP_FNAME, []) ->
+ ok;
+translate_response(?FILE_RESP_FNAME, Data) when is_binary(Data) ->
+ {ok, prim_file:internal_native2name(Data)};
+translate_response(?FILE_RESP_FNAME, Data) ->
+ {ok, Data};
+
+translate_response(?FILE_RESP_ALL_DATA, Data) ->
+ {ok, Data};
+
translate_response(X, Data) ->
{error, {bad_response_from_port, [X | Data]}}.
@@ -1209,3 +1226,9 @@ lists_split([Hd | Tl], N, Rev) ->
reverse(X) -> lists:reverse(X, []).
reverse(L, T) -> lists:reverse(L, T).
+
+% Will add zero termination too
+% The 'EXIT' tuple from a bad argument will eventually generate an error
+% in list_to_binary, which is caught and generates the {error,badarg} return
+pathname(File) ->
+ (catch prim_file:internal_name2native(File)).
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 91d39c6a73..446656e45f 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -37,7 +37,7 @@
-export([setopt/3, setopts/2, getopt/2, getopts/2, is_sockopt_val/2]).
-export([chgopt/3, chgopts/2]).
-export([getstat/2, getfd/1, getindex/1, getstatus/1, gettype/1,
- getiflist/1, ifget/3, ifset/3,
+ getifaddrs/1, getiflist/1, ifget/3, ifset/3,
gethostname/1]).
-export([getservbyname/3, getservbyport/3]).
-export([peername/1, setpeername/2]).
@@ -216,9 +216,10 @@ bindx(S, AddFlag, Addrs) ->
sctp ->
%% Really multi-homed "bindx". Stringified args:
%% [AddFlag, (Port, IP)+]:
- Args = ?int8(AddFlag) ++
- lists:concat([?int16(Port)++ip_to_bytes(IP) ||
- {IP, Port} <- Addrs]),
+ Args =
+ [?int8(AddFlag)|
+ [[?int16(Port)|ip_to_bytes(IP)] ||
+ {IP, Port} <- Addrs]],
case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
{ok,_} -> {ok, S};
Error -> Error
@@ -623,7 +624,7 @@ chgopt(S, Opt, Value) when is_port(S) ->
chgopts(S, [{Opt,Value}]).
chgopts(S, Opts) when is_port(S), is_list(Opts) ->
- case inet:getopts(S, need_template(Opts)) of
+ case getopts(S, need_template(Opts)) of
{ok,Templates} ->
try merge_options(Opts, Templates) of
NewOpts ->
@@ -636,7 +637,94 @@ chgopts(S, Opts) when is_port(S), is_list(Opts) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
-%% IFLIST(insock()) -> {ok,IfNameList} | {error, Reason}
+%% getifaddrs(insock()) -> {ok,IfAddrsList} | {error, Reason}
+%%
+%% IfAddrsList = [{Name,[Opts]}]
+%% Name = string()
+%% Opts = {flags,[Flag]} | {addr,Addr} | {netmask,Addr} | {broadaddr,Addr}
+%% | {dstaddr,Addr} | {hwaddr,HwAddr} | {mtu,integer()}
+%% Flag = up | broadcast | loopback | running | multicast
+%% Addr = ipv4addr() | ipv6addr()
+%% HwAddr = ethernet_addr()
+%%
+%% get interface name and addresses list
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+getifaddrs(S) when is_port(S) ->
+ case ctl_cmd(S, ?INET_REQ_GETIFADDRS, []) of
+ {ok, Data} ->
+ {ok, comp_ifaddrs(build_ifaddrs(Data), ktree_empty())};
+ {error,enotsup} ->
+ case getiflist(S) of
+ {ok, IFs} ->
+ {ok, getifaddrs_ifget(S, IFs)};
+ Err1 -> Err1
+ end;
+ Err2 -> Err2
+ end.
+
+%% Restructure interface properties per interface and remove duplicates
+
+comp_ifaddrs([{If,Opts}|IfOpts], T) ->
+ case ktree_is_defined(If, T) of
+ true ->
+ OptSet = comp_ifaddrs_add(ktree_get(If, T), Opts),
+ comp_ifaddrs(IfOpts, ktree_update(If, OptSet, T));
+ false ->
+ OptSet = comp_ifaddrs_add(ktree_empty(), Opts),
+ comp_ifaddrs(IfOpts, ktree_insert(If, OptSet, T))
+ end;
+comp_ifaddrs([], T) ->
+ [{If,ktree_keys(ktree_get(If, T))} || If <- ktree_keys(T)].
+
+comp_ifaddrs_add(OptSet, [Opt|Opts]) ->
+ case ktree_is_defined(Opt, OptSet) of
+ true
+ when element(1, Opt) =:= flags;
+ element(1, Opt) =:= hwaddr ->
+ comp_ifaddrs_add(OptSet, Opts);
+ _ ->
+ comp_ifaddrs_add(ktree_insert(Opt, undefined, OptSet), Opts)
+ end;
+comp_ifaddrs_add(OptSet, []) -> OptSet.
+
+%% Legacy emulation of getifaddrs
+
+getifaddrs_ifget(_, []) -> [];
+getifaddrs_ifget(S, [IF|IFs]) ->
+ case ifget(S, IF, [flags]) of
+ {ok,[{flags,Flags}]=FlagsVals} ->
+ BroadOpts =
+ case member(broadcast, Flags) of
+ true ->
+ [broadaddr,hwaddr];
+ false ->
+ [hwaddr]
+ end,
+ P2POpts =
+ case member(pointtopoint, Flags) of
+ true ->
+ [dstaddr|BroadOpts];
+ false ->
+ BroadOpts
+ end,
+ getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|P2POpts]);
+ _ ->
+ getifaddrs_ifget(S, IFs, IF, [], [addr,netmask,hwaddr])
+ end.
+
+getifaddrs_ifget(S, IFs, IF, FlagsVals, Opts) ->
+ OptVals =
+ case ifget(S, IF, Opts) of
+ {ok,OVs} -> OVs;
+ _ -> []
+ end,
+ [{IF,FlagsVals++OptVals}|getifaddrs_ifget(S, IFs)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% getiflist(insock()) -> {ok,IfNameList} | {error, Reason}
%%
%% get interface name list
%%
@@ -1325,6 +1413,19 @@ type_value_2({enum,List}, Enum) ->
{value,_} -> true;
false -> false
end;
+type_value_2(sockaddr, Addr) ->
+ case Addr of
+ any -> true;
+ loopback -> true;
+ {A,B,C,D} when ?ip(A,B,C,D) -> true;
+ {A,B,C,D,E,F,G,H} when ?ip6(A,B,C,D,E,F,G,H) -> true;
+ _ -> false
+ end;
+type_value_2(linkaddr, Addr) when is_list(Addr) ->
+ case len(Addr, 32768) of
+ undefined -> false;
+ _ -> true
+ end;
type_value_2({bitenumlist,List}, EnumList) ->
case enum_vals(EnumList, List) of
Ls when is_list(Ls) -> true;
@@ -1413,14 +1514,21 @@ enc_value_2(addr, {any,Port}) ->
[?INET_AF_ANY|?int16(Port)];
enc_value_2(addr, {loopback,Port}) ->
[?INET_AF_LOOPBACK|?int16(Port)];
-enc_value_2(addr, {IP,Port}) ->
- case tuple_size(IP) of
- 4 ->
- [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
- 8 ->
- [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]
- end;
+enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 ->
+ [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
+enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 ->
+ [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
enc_value_2(ether, [X1,X2,X3,X4,X5,X6]) -> [X1,X2,X3,X4,X5,X6];
+enc_value_2(sockaddr, any) ->
+ [?INET_AF_ANY];
+enc_value_2(sockaddr, loopback) ->
+ [?INET_AF_LOOPBACK];
+enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 4 ->
+ [?INET_AF_INET|ip4_to_bytes(IP)];
+enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 8 ->
+ [?INET_AF_INET6|ip6_to_bytes(IP)];
+enc_value_2(linkaddr, Linkaddr) ->
+ [?int16(length(Linkaddr)),Linkaddr];
enc_value_2(sctp_assoc_id, Val) -> ?int32(Val);
%% enc_value_2(sctp_assoc_id, Bin) -> [byte_size(Bin),Bin];
enc_value_2({enum,List}, Enum) ->
@@ -1465,6 +1573,10 @@ dec_value(time, [X3,X2,X1,X0|T]) ->
end;
dec_value(ip, [A,B,C,D|T]) -> {{A,B,C,D}, T};
dec_value(ether,[X1,X2,X3,X4,X5,X6|T]) -> {[X1,X2,X3,X4,X5,X6],T};
+dec_value(sockaddr, [X|T]) ->
+ get_ip(X, T);
+dec_value(linkaddr, [X1,X0|T]) ->
+ split(?i16(X1,X0), T);
dec_value({enum,List}, [X3,X2,X1,X0|T]) ->
Val = ?i32(X3,X2,X1,X0),
case enum_name(Val, List) of
@@ -1480,7 +1592,7 @@ dec_value({bitenumlist,List}, [X3,X2,X1,X0|T]) ->
%% {enum_names(Val, List), T};
dec_value(binary,[L0,L1,L2,L3|List]) ->
Len = ?i32(L0,L1,L2,L3),
- {X,T}=lists:split(Len,List),
+ {X,T}=split(Len,List),
{list_to_binary(X),T};
dec_value(Types, List) when is_tuple(Types) ->
{L,T} = dec_value_tuple(Types, List, 1, []),
@@ -1495,7 +1607,7 @@ dec_value_tuple(Types, List, N, Acc)
{Term,Tail} = dec_value(element(N, Types), List),
dec_value_tuple(Types, Tail, N+1, [Term|Acc]);
dec_value_tuple(_, List, _, Acc) ->
- {lists:reverse(Acc),List}.
+ {rev(Acc),List}.
borlist([V|Vs], Value) ->
borlist(Vs, V bor Value);
@@ -1702,11 +1814,11 @@ merge_fields(_, _, _) -> [].
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-type_ifopt(addr) -> ip;
-type_ifopt(broadaddr) -> ip;
-type_ifopt(dstaddr) -> ip;
+type_ifopt(addr) -> sockaddr;
+type_ifopt(broadaddr) -> sockaddr;
+type_ifopt(dstaddr) -> sockaddr;
type_ifopt(mtu) -> int;
-type_ifopt(netmask) -> ip;
+type_ifopt(netmask) -> sockaddr;
type_ifopt(flags) ->
{bitenumlist,
[{up, ?INET_IFF_UP},
@@ -1718,7 +1830,7 @@ type_ifopt(flags) ->
{no_pointtopoint, ?INET_IFF_NPOINTTOPOINT},
{running, ?INET_IFF_RUNNING},
{multicast, ?INET_IFF_MULTICAST}]};
-type_ifopt(hwaddr) -> ether;
+type_ifopt(hwaddr) -> linkaddr;
type_ifopt(Opt) when is_atom(Opt) -> undefined.
enc_ifopt(addr) -> ?INET_IFOPT_ADDR;
@@ -1903,6 +2015,30 @@ encode_ifname(Name) ->
if N > 255 -> {error, einval};
true -> {ok,[N | Name]}
end.
+
+build_ifaddrs(Cs) ->
+ build_ifaddrs(Cs, []).
+%%
+build_ifaddrs([], []) ->
+ [];
+build_ifaddrs([0|Cs], Acc) ->
+ Name = utf8_to_characters(rev(Acc)),
+ {Opts,Rest} = build_ifaddrs_opts(Cs, []),
+ [{Name,Opts}|build_ifaddrs(Rest)];
+build_ifaddrs([C|Cs], Acc) ->
+ build_ifaddrs(Cs, [C|Acc]).
+
+build_ifaddrs_opts([0|Cs], Acc) ->
+ {rev(Acc),Cs};
+build_ifaddrs_opts([C|Cs]=CCs, Acc) ->
+ case dec_ifopt(C) of
+ undefined ->
+ erlang:error(badarg, [CCs,Acc]);
+ Opt ->
+ Type = type_ifopt(Opt),
+ {Val,Rest} = dec_value(Type, Cs),
+ build_ifaddrs_opts(Rest, [{Opt,Val}|Acc])
+ end.
build_iflist(Cs) ->
build_iflist(Cs, [], []).
@@ -1927,6 +2063,80 @@ rev(L) -> rev(L,[]).
rev([C|L],Acc) -> rev(L,[C|Acc]);
rev([],Acc) -> Acc.
+split(N, L) -> split(N, L, []).
+split(0, L, R) when is_list(L) -> {rev(R),L};
+split(N, [H|T], R) when is_integer(N), N > 0 -> split(N-1, T, [H|R]).
+
+len(L, N) -> len(L, N, 0).
+len([], N, C) when is_integer(N), N >= 0 -> C;
+len(L, 0, _) when is_list(L) -> undefined;
+len([_|L], N, C) when is_integer(N), N >= 0 -> len(L, N-1, C+1).
+
+member(X, [X|_]) -> true;
+member(X, [_|Xs]) -> member(X, Xs);
+member(_, []) -> false.
+
+
+
+%% Lookup tree that keeps key insert order
+
+ktree_empty() -> {[],tree()}.
+ktree_is_defined(Key, {_,T}) -> tree(T, Key, is_defined).
+ktree_get(Key, {_,T}) -> tree(T, Key, get).
+ktree_insert(Key, V, {Keys,T}) -> {[Key|Keys],tree(T, Key, {insert,V})}.
+ktree_update(Key, V, {Keys,T}) -> {Keys,tree(T, Key, {update,V})}.
+ktree_keys({Keys,_}) -> rev(Keys).
+
+%% Simple lookup tree. Hash the key to get statistical balance.
+%% Key is matched equal, not compared equal.
+
+tree() -> nil.
+tree(T, Key, Op) -> tree(T, Key, Op, erlang:phash2(Key)).
+
+tree(nil, _, is_defined, _) -> false;
+tree(nil, K, {insert,V}, _) -> {K,V,nil,nil};
+tree({K,_,_,_}, K, is_defined, _) -> true;
+tree({K,V,_,_}, K, get, _) -> V;
+tree({K,_,L,R}, K, {update,V}, _) -> {K,V,L,R};
+tree({K0,V0,L,R}, K, Op, H) ->
+ H0 = erlang:phash2(K0),
+ if H0 < H; H0 =:= H, K0 < K ->
+ if is_tuple(Op) ->
+ {K0,V0,tree(L, K, Op, H),R};
+ true ->
+ tree(L, K, Op, H)
+ end;
+ true ->
+ if is_tuple(Op) ->
+ {K0,V0,L,tree(R, K, Op, H)};
+ true ->
+ tree(R, K, Op, H)
+ end
+ end.
+
+
+
+utf8_to_characters([]) -> [];
+utf8_to_characters([B|Bs]=Arg) when (B band 16#FF) =:= B ->
+ if 16#F8 =< B ->
+ erlang:error(badarg, [Arg]);
+ 16#F0 =< B ->
+ utf8_to_characters(Bs, B band 16#07, 3);
+ 16#E0 =< B ->
+ utf8_to_characters(Bs, B band 16#0F, 2);
+ 16#C0 =< B ->
+ utf8_to_characters(Bs, B band 16#1F, 1);
+ 16#80 =< B ->
+ erlang:error(badarg, [Arg]);
+ true ->
+ [B|utf8_to_characters(Bs)]
+ end.
+%%
+utf8_to_characters(Bs, U, 0) ->
+ [U|utf8_to_characters(Bs)];
+utf8_to_characters([B|Bs], U, N) when ((B band 16#3F) bor 16#80) =:= B ->
+ utf8_to_characters(Bs, (U bsl 6) bor (B band 16#3F), N-1).
+
ip_to_bytes(IP) when tuple_size(IP) =:= 4 -> ip4_to_bytes(IP);
ip_to_bytes(IP) when tuple_size(IP) =:= 8 -> ip6_to_bytes(IP).