aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/test/Makefile2
-rw-r--r--lib/common_test/test/Makefile2
-rw-r--r--lib/compiler/src/beam_dict.erl13
-rw-r--r--lib/compiler/src/sys_core_fold.erl192
-rw-r--r--lib/compiler/src/v3_core.erl69
-rw-r--r--lib/compiler/test/Makefile2
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl9
-rw-r--r--lib/compiler/test/warnings_SUITE.erl10
-rw-r--r--lib/cosFileTransfer/test/Makefile2
-rw-r--r--lib/crypto/test/Makefile2
-rw-r--r--lib/debugger/test/Makefile2
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl2
-rw-r--r--lib/docbuilder/test/Makefile2
-rw-r--r--lib/edoc/src/edoc_wiki.erl2
-rw-r--r--lib/edoc/test/Makefile2
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c2
-rw-r--r--lib/erl_interface/test/Makefile2
-rw-r--r--lib/et/test/Makefile2
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl2
-rw-r--r--lib/inets/test/Makefile4
-rw-r--r--lib/inviso/test/Makefile2
-rw-r--r--lib/kernel/doc/src/inet.xml2
-rw-r--r--lib/kernel/doc/src/rpc.xml2
-rw-r--r--lib/kernel/test/Makefile2
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl132
-rw-r--r--lib/kernel/test/init_SUITE.erl69
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/test/Makefile2
-rw-r--r--lib/mnesia/test/Makefile2
-rw-r--r--lib/observer/test/crashdump_helper.erl2
-rw-r--r--lib/orber/test/Makefile2
-rw-r--r--lib/parsetools/test/Makefile2
-rw-r--r--lib/percept/test/Makefile2
-rw-r--r--lib/public_key/doc/src/public_key.xml98
-rw-r--r--lib/public_key/include/public_key.hrl12
-rw-r--r--lib/public_key/src/Makefile1
-rw-r--r--lib/public_key/src/pubkey_cert.erl6
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl2
-rw-r--r--lib/public_key/src/pubkey_pem.erl38
-rw-r--r--lib/public_key/src/pubkey_ssh.erl431
-rw-r--r--lib/public_key/src/public_key.app.src6
-rw-r--r--lib/public_key/src/public_key.erl86
-rw-r--r--lib/public_key/test/Makefile2
-rw-r--r--lib/public_key/test/public_key_SUITE.erl416
-rw-r--r--lib/public_key/test/public_key_SUITE_data/auth_keys3
-rw-r--r--lib/public_key/test/public_key_SUITE_data/known_hosts3
-rw-r--r--lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub1
-rw-r--r--lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub3
-rw-r--r--lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub1
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys3
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts2
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub13
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub12
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub7
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub13
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub8
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub9
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub9
-rw-r--r--lib/reltool/src/reltool_server.erl2
-rw-r--r--lib/reltool/test/Makefile2
-rw-r--r--lib/reltool/test/reltool_app_SUITE.erl17
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl34
-rw-r--r--lib/runtime_tools/test/Makefile2
-rw-r--r--lib/sasl/doc/src/systools.xml16
-rw-r--r--lib/sasl/src/release_handler.erl42
-rw-r--r--lib/sasl/src/release_handler_1.erl44
-rw-r--r--lib/sasl/src/systools_make.erl83
-rw-r--r--lib/sasl/src/systools_relup.erl9
-rw-r--r--lib/snmp/test/Makefile2
-rw-r--r--lib/ssl/examples/certs/Makefile2
-rw-r--r--lib/ssl/examples/src/Makefile2
-rw-r--r--lib/ssl/src/ssl.erl7
-rw-r--r--lib/ssl/src/ssl_handshake.hrl5
-rw-r--r--lib/ssl/test/Makefile2
-rw-r--r--lib/stdlib/doc/src/binary.xml2
-rw-r--r--lib/stdlib/doc/src/zip.xml20
-rw-r--r--lib/stdlib/src/erl_parse.yrl10
-rw-r--r--lib/stdlib/src/erl_pp.erl10
-rw-r--r--lib/stdlib/src/log_mf_h.erl14
-rw-r--r--lib/stdlib/test/Makefile2
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl11
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl24
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/src/erl_recomment.erl2
-rw-r--r--lib/syntax_tools/test/Makefile2
-rw-r--r--lib/test_server/test/Makefile2
-rw-r--r--lib/tools/src/make.erl15
-rw-r--r--lib/tools/test/Makefile2
-rw-r--r--lib/tv/src/tv_io_lib.erl9
-rw-r--r--lib/typer/src/typer.erl17
90 files changed, 1667 insertions, 481 deletions
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index 4f3776e478..7ecd544d4b 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -194,7 +194,7 @@ release_tests_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/asn1_bin_v2_SUITE_data
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) asn1.spec asn1.cover $(INSTALL_PROGS) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
cd asn1_SUITE_data; tar cfh $(RELSYSDIR)/asn1_SUITE_data.tar *
cd $(RELSYSDIR)/asn1_SUITE_data; tar xf $(RELSYSDIR)/asn1_SUITE_data.tar
cd $(RELSYSDIR)/asn1_bin_SUITE_data; tar xf $(RELSYSDIR)/asn1_SUITE_data.tar
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 115565aaa0..b7b099069c 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -96,7 +96,7 @@ release_tests_spec:
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR)
$(INSTALL_DATA) common_test.spec $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index a503fcab38..c50ed28aa9 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -36,7 +36,6 @@
strings = <<>> :: binary(), %String pool
lambdas = [], %[{...}]
literals = dict:new() :: dict(), %Format: {Literal,Number}
- next_atom = 1 :: pos_integer(),
next_import = 0 :: non_neg_integer(),
string_offset = 0 :: non_neg_integer(),
next_literal = 0 :: non_neg_integer(),
@@ -66,13 +65,14 @@ highest_opcode(#asm{highest_opcode=Op}) -> Op.
%% atom(Atom, Dict) -> {Index,Dict'}
-spec atom(atom(), bdict()) -> {pos_integer(), bdict()}.
-atom(Atom, #asm{atoms=Atoms0,next_atom=NextIndex}=Dict) when is_atom(Atom) ->
+atom(Atom, #asm{atoms=Atoms0}=Dict) when is_atom(Atom) ->
case gb_trees:lookup(Atom, Atoms0) of
{value,Index} ->
{Index,Dict};
none ->
+ NextIndex = gb_trees:size(Atoms0) + 1,
Atoms = gb_trees:insert(Atom, NextIndex, Atoms0),
- {NextIndex,Dict#asm{atoms=Atoms,next_atom=NextIndex+1}}
+ {NextIndex,Dict#asm{atoms=Atoms}}
end.
%% Remembers an exported function.
@@ -139,7 +139,7 @@ lambda(Lbl, Index, OldUniq, NumFree, #asm{lambdas=Lambdas0}=Dict) ->
Lambdas = [{Lbl,{OldIndex,Lbl,Index,NumFree,OldUniq}}|Lambdas0],
{OldIndex,Dict#asm{lambdas=Lambdas}}.
-%% Returns the index for a literal (adding it to the atom table if necessary).
+%% Returns the index for a literal (adding it to the literal table if necessary).
%% literal(Literal, Dict) -> {Index,Dict'}
-spec literal(term(), bdict()) -> {non_neg_integer(), bdict()}.
@@ -156,14 +156,15 @@ literal(Lit, #asm{literals=Tab0,next_literal=NextIndex}=Dict) ->
%% atom_table(Dict) -> {LastIndex,[Length,AtomString...]}
-spec atom_table(bdict()) -> {non_neg_integer(), [[non_neg_integer(),...]]}.
-atom_table(#asm{atoms=Atoms,next_atom=NumAtoms}) ->
+atom_table(#asm{atoms=Atoms}) ->
+ NumAtoms = gb_trees:size(Atoms),
Sorted = lists:keysort(2, gb_trees:to_list(Atoms)),
Fun = fun({A,_}) ->
L = atom_to_list(A),
[length(L)|L]
end,
AtomTab = lists:map(Fun, Sorted),
- {NumAtoms-1,AtomTab}.
+ {NumAtoms,AtomTab}.
%% Returns the table of local functions.
%% local_table(Dict) -> {NumLocals, [{Function, Arity, Label}...]}
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 96015fbe58..9360556e00 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -460,7 +460,8 @@ eval_binary(#c_binary{anno=Anno,segments=Ss}=Bin) ->
Bin;
throw:{badarg,Warning} ->
add_warning(Bin, Warning),
- #c_call{module=#c_literal{val=erlang},
+ #c_call{anno=Anno,
+ module=#c_literal{val=erlang},
name=#c_literal{val=error},
args=[#c_literal{val=badarg}]}
end.
@@ -658,36 +659,34 @@ call_0(Call, M, N, As0, Sub) ->
%% We inline some very common higher order list operations.
%% We use the same evaluation order as the library function.
-call_1(_Call, lists, all, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, all, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^all',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]},
CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
- body=#c_apply{op=Loop, args=[Xs]}},
+ body=#c_apply{anno=Anno, op=Loop, args=[Xs]}},
CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=#c_literal{val=false}},
CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err1]}},
+ body=match_fail(Anno, Err1)},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_case{arg=#c_apply{op=F, args=[X]},
+ body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=true}},
Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err2]}},
+ body=match_fail(Anno, Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, any, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, any, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^any',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -696,72 +695,71 @@ call_1(_Call, lists, any, [Arg1,Arg2], Sub) ->
CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
body=#c_literal{val=true}},
CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
- body=#c_apply{op=Loop, args=[Xs]}},
+ body=#c_apply{anno=Anno, op=Loop, args=[Xs]}},
CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err1]}},
+ body=match_fail(Anno, Err1)},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_case{arg=#c_apply{op=F, args=[X]},
+ body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=false}},
Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err2]}},
+ body=match_fail(Anno, Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, foreach, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, foreach, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^foreach',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_seq{arg=#c_apply{op=F, args=[X]},
- body=#c_apply{op=Loop, args=[Xs]}}},
+ body=#c_seq{arg=#c_apply{anno=Anno, op=F, args=[X]},
+ body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=ok}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, map, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, map, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^map',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
H = #c_var{name='H'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_let{vars=[H], arg=#c_apply{op=F, args=[X]},
+ body=#c_let{vars=[H], arg=#c_apply{anno=Anno,
+ op=F,
+ args=[X]},
body=#c_cons{hd=H,
- tl=#c_apply{op=Loop,
+ tl=#c_apply{anno=Anno,
+ op=Loop,
args=[Xs]}}}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=[]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, flatmap, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, flatmap, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^flatmap',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -769,26 +767,27 @@ call_1(_Call, lists, flatmap, [Arg1,Arg2], Sub) ->
H = #c_var{name='H'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_let{vars=[H],
- arg=#c_apply{op=F, args=[X]},
- body=#c_call{module=#c_literal{val=erlang},
+ arg=#c_apply{anno=Anno, op=F, args=[X]},
+ body=#c_call{anno=Anno,
+ module=#c_literal{val=erlang},
name=#c_literal{val='++'},
args=[H,
- #c_apply{op=Loop,
+ #c_apply{anno=Anno,
+ op=Loop,
args=[Xs]}]}}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=[]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, filter, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^filter',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -800,72 +799,75 @@ call_1(_Call, lists, filter, [Arg1,Arg2], Sub) ->
CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=Xs},
CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err1]}},
+ body=match_fail(Anno, Err1)},
Case = #c_case{arg=B, clauses = [CC1, CC2, CC3]},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_let{vars=[B],
- arg=#c_apply{op=F, args=[X]},
+ arg=#c_apply{anno=Anno, op=F, args=[X]},
body=#c_let{vars=[Xs],
- arg=#c_apply{op=Loop,
+ arg=#c_apply{anno=Anno,
+ op=Loop,
args=[Xs]},
body=Case}}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=[]}},
Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err2]}},
+ body=match_fail(Anno, Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, foldl, [Arg1,Arg2,Arg3], Sub) ->
+call_1(#c_call{anno=Anno}, lists, foldl, [Arg1,Arg2,Arg3], Sub) ->
Loop = #c_var{name={'lists^foldl',2}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
A = #c_var{name='A'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_apply{op=Loop,
- args=[Xs, #c_apply{op=F, args=[X, A]}]}},
+ body=#c_apply{anno=Anno,
+ op=Loop,
+ args=[Xs, #c_apply{anno=Anno,
+ op=F,
+ args=[X, A]}]}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, A, L], arg=#c_values{es=[Arg1, Arg2, Arg3]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L, A]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L, A]}}},
Sub);
-call_1(_Call, lists, foldr, [Arg1,Arg2,Arg3], Sub) ->
+call_1(#c_call{anno=Anno}, lists, foldr, [Arg1,Arg2,Arg3], Sub) ->
Loop = #c_var{name={'lists^foldr',2}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
A = #c_var{name='A'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_apply{op=F, args=[X, #c_apply{op=Loop,
- args=[Xs, A]}]}},
+ body=#c_apply{anno=Anno,
+ op=F,
+ args=[X, #c_apply{anno=Anno,
+ op=Loop,
+ args=[Xs, A]}]}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, A, L], arg=#c_values{es=[Arg1, Arg2, Arg3]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L, A]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L, A]}}},
Sub);
-call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
+call_1(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
Loop = #c_var{name={'lists^mapfoldl',2}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -876,15 +878,16 @@ call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E},
Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]},
C2 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
#c_case{arg=A, clauses=[C1, C2]}
end,
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=Match(#c_apply{op=F, args=[X, Avar]},
+ body=Match(#c_apply{anno=Anno, op=F, args=[X, Avar]},
#c_tuple{es=[X, Avar]},
%%% Tuple passing version
- Match(#c_apply{op=Loop, args=[Xs, Avar]},
+ Match(#c_apply{anno=Anno,
+ op=Loop,
+ args=[Xs, Avar]},
#c_tuple{es=[Xs, Avar]},
#c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]})
%%% Multiple-value version
@@ -902,22 +905,23 @@ call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, Avar, L], arg=#c_values{es=[Arg1, Arg2, Arg3]},
body=#c_letrec{defs=[{Loop,Fun}],
%%% Tuple passing version
- body=#c_apply{op=Loop, args=[L, Avar]}}},
+ body=#c_apply{anno=Anno,
+ op=Loop,
+ args=[L, Avar]}}},
%%% Multiple-value version
%%% body=#c_let{vars=[Xs, A],
%%% arg=#c_apply{op=Loop,
%%% args=[L, A]},
%%% body=#c_tuple{es=[Xs, A]}}}},
Sub);
-call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
+call_1(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
Loop = #c_var{name={'lists^mapfoldr',2}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -928,15 +932,16 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E},
Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]},
C2 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
#c_case{arg=A, clauses=[C1, C2]}
end,
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
%%% Tuple passing version
- body=Match(#c_apply{op=Loop, args=[Xs, Avar]},
+ body=Match(#c_apply{anno=Anno,
+ op=Loop,
+ args=[Xs, Avar]},
#c_tuple{es=[Xs, Avar]},
- Match(#c_apply{op=F, args=[X, Avar]},
+ Match(#c_apply{anno=Anno, op=F, args=[X, Avar]},
#c_tuple{es=[X, Avar]},
#c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]}))
%%% Multiple-value version
@@ -955,15 +960,16 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, Avar, L], arg=#c_values{es=[Arg1, Arg2, Arg3]},
body=#c_letrec{defs=[{Loop,Fun}],
%%% Tuple passing version
- body=#c_apply{op=Loop, args=[L, Avar]}}},
+ body=#c_apply{anno=Anno,
+ op=Loop,
+ args=[L, Avar]}}},
%%% Multiple-value version
%%% body=#c_let{vars=[Xs, A],
%%% arg=#c_apply{op=Loop,
@@ -973,6 +979,11 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
call_1(#c_call{module=M, name=N}=Call, _, _, As, Sub) ->
call_0(Call, M, N, As, Sub).
+match_fail(Anno, Arg) ->
+ #c_primop{anno=Anno,
+ name=#c_literal{val='match_fail'},
+ args=[Arg]}.
+
%% fold_call(Call, Mod, Name, Args, Sub) -> Expr.
%% Try to safely evaluate the call. Just try to evaluate arguments,
%% do the call and convert return values to literals. If this
@@ -1280,9 +1291,9 @@ eval_setelement_2(Pos, [H|T], NewVal) when Pos > 1 ->
%%
eval_failure(Call, Reason) ->
add_warning(Call, {eval_failure,Reason}),
- #c_call{module=#c_literal{val=erlang},
- name=#c_literal{val=error},
- args=[#c_literal{val=Reason}]}.
+ Call#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=error},
+ args=[#c_literal{val=Reason}]}.
%% simplify_apply(Call0, Mod, Func, Args) -> Call
%% Simplify an apply/3 to a call if the number of arguments
@@ -1742,23 +1753,24 @@ opt_bool_clauses([_|_], _, _) ->
opt_bool_not(#c_case{arg=Arg,clauses=Cs0}=Case0) ->
case Arg of
- #c_call{module=#c_literal{val=erlang},
+ #c_call{anno=Anno,module=#c_literal{val=erlang},
name=#c_literal{val='not'},
args=[Expr]} ->
- Cs = opt_bool_not(Expr, Cs0),
+ Cs = opt_bool_not(Anno, Expr, Cs0),
Case = Case0#c_case{arg=Expr,clauses=Cs},
opt_bool_not(Case);
_ ->
opt_bool_case_redundant(Case0)
end.
-opt_bool_not(Expr, Cs) ->
+opt_bool_not(Anno, Expr, Cs) ->
Tail = case is_bool_expr(Expr) of
false ->
[#c_clause{anno=[compiler_generated],
pats=[#c_var{name=cor_variable}],
guard=#c_literal{val=true},
- body=#c_call{module=#c_literal{val=erlang},
+ body=#c_call{anno=Anno,
+ module=#c_literal{val=erlang},
name=#c_literal{val=error},
args=[#c_literal{val=badarg}]}}];
true -> []
@@ -1957,13 +1969,25 @@ case_tuple_pat([#c_tuple{es=Ps}], Arity) when length(Ps) =:= Arity ->
case_tuple_pat([#c_literal{val=T}], Arity) when tuple_size(T) =:= Arity ->
Ps = [#c_literal{val=E} || E <- tuple_to_list(T)],
{ok,Ps,[]};
-case_tuple_pat([#c_var{anno=A}=V], Arity) ->
- Vars = make_vars(A, 1, Arity),
- {ok,Vars,[{V,#c_tuple{es=Vars}}]};
+case_tuple_pat([#c_var{anno=Anno0}=V], Arity) ->
+ Vars = make_vars(Anno0, 1, Arity),
+
+ %% If the entire case statement is evaluated in an effect
+ %% context (e.g. "case {A,B} of ... end, ok"), there will
+ %% be a warning that a term is constructed but never used.
+ %% To avoid that warning, we must annotate the tuple as
+ %% compiler generated.
+
+ Anno = [compiler_generated|Anno0],
+ {ok,Vars,[{V,#c_tuple{anno=Anno,es=Vars}}]};
case_tuple_pat([#c_alias{var=V,pat=P}], Arity) ->
case case_tuple_pat([P], Arity) of
- {ok,Ps,Avs} -> {ok,Ps,[{V,#c_tuple{es=unalias_pat_list(Ps)}}|Avs]};
- error -> error
+ {ok,Ps,Avs} ->
+ Anno0 = core_lib:get_anno(P),
+ Anno = [compiler_generated|Anno0],
+ {ok,Ps,[{V,#c_tuple{anno=Anno,es=unalias_pat_list(Ps)}}|Avs]};
+ error ->
+ error
end;
case_tuple_pat(_, _) -> error.
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 2da24b2908..e1a593fffa 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1820,7 +1820,21 @@ upattern_list([], _, St) -> {[],[],[],[],St}.
%% upat_bin([Pat], [KnownVar], State) ->
%% {[Pat],[GuardTest],[NewVar],[UsedVar],State}.
upat_bin(Es0, Ks, St0) ->
- upat_bin(Es0, Ks, [], St0).
+ {Es1,Pg,Pv,Pu0,St1} = upat_bin(Es0, Ks, [], St0),
+
+ %% In a clause such as <<Sz:8,V:Sz>> in a function head, Sz will both
+ %% be new and used; a situation that is not handled properly by
+ %% uclause/4. (Basically, since Sz occurs in two sets that are
+ %% subtracted from each other, Sz will not be added to the list of
+ %% known variables and will seem to be new the next time it is
+ %% used in a match.)
+ %% Since the variable Sz really is new (it does not use a
+ %% value bound prior to the binary matching), Sz should only be
+ %% included in the set of new variables. Thus we should take it
+ %% out of the set of used variables.
+
+ Pu1 = subtract(Pu0, intersection(Pv, Pu0)),
+ {Es1,Pg,Pv,Pu1,St1}.
%% upat_bin([Pat], [KnownVar], [LocalVar], State) ->
%% {[Pat],[GuardTest],[NewVar],[UsedVar],State}.
@@ -1832,35 +1846,36 @@ upat_bin([], _, _, St) -> {[],[],[],[],St}.
%% upat_element(Segment, [KnownVar], [LocalVar], State) ->
-%% {Segment,[GuardTest],[NewVar],[UsedVar],[LocalVar],State}
-upat_element(#c_bitstr{val=H0,size=Sz}=Seg, Ks, Bs, St0) ->
- {H1,Hg,Hv,[],St1} = upattern(H0, Ks, St0),
- Bs1 = case H0 of
- #c_var{name=Hname} ->
- case H1 of
+%% {Segment,[GuardTest],[NewVar],[UsedVar],[LocalVar],State}
+upat_element(#c_bitstr{val=H0,size=Sz0}=Seg, Ks, Bs0, St0) ->
+ {H1,Hg,Hv,[],St1} = upattern(H0, Ks, St0),
+ Bs1 = case H0 of
#c_var{name=Hname} ->
- Bs;
- #c_var{name=Other} ->
- [{Hname, Other}|Bs]
- end;
- _ ->
- Bs
- end,
- {Sz1, Us} = case Sz of
- #c_var{name=Vname} ->
- rename_bitstr_size(Vname, Bs);
- _Other -> {Sz, []}
- end,
- {Seg#c_bitstr{val=H1, size=Sz1},Hg,Hv,Us,Bs1,St1}.
-
-rename_bitstr_size(V, [{V, N}|_]) ->
- New = #c_var{name=N},
- {New, [N]};
+ case H1 of
+ #c_var{name=Hname} ->
+ Bs0;
+ #c_var{name=Other} ->
+ [{Hname,Other}|Bs0]
+ end;
+ _ ->
+ Bs0
+ end,
+ {Sz1,Us} = case Sz0 of
+ #c_var{name=Vname} ->
+ rename_bitstr_size(Vname, Bs0);
+ _Other ->
+ {Sz0,[]}
+ end,
+ {Seg#c_bitstr{val=H1,size=Sz1},Hg,Hv,Us,Bs1,St1}.
+
+rename_bitstr_size(V, [{V,N}|_]) ->
+ New = #c_var{name=N},
+ {New,[N]};
rename_bitstr_size(V, [_|Rest]) ->
- rename_bitstr_size(V, Rest);
+ rename_bitstr_size(V, Rest);
rename_bitstr_size(V, []) ->
- Old = #c_var{name=V},
- {Old, [V]}.
+ Old = #c_var{name=V},
+ {Old,[V]}.
used_in_any(Les) ->
foldl(fun (Le, Ns) -> union((get_anno(Le))#a.us, Ns) end,
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index 934bf39393..fe713fd019 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -157,7 +157,7 @@ release_tests_spec: make_emakefile
$(EMAKEFILE) $(ERL_FILES) $(CORE_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \
$(INLINE_ERL_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 1e3c670fb8..9184e14cb2 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -142,7 +142,14 @@ otp_5269(Config) when is_list(Config) ->
[X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end,
%% "binsize variable" ^
[1,2]),
-
+ ?line check(fun() ->
+ (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) ->
+ case A of
+ B -> wrong;
+ _ -> ok
+ end
+ end)(<<1,2,3,4>>) end,
+ ok),
ok.
null_fields(Config) when is_list(Config) ->
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index 8cc3ca4199..dd18a6e1a3 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -453,6 +453,16 @@ effect(Config) when is_list(Config) ->
true -> ok
end,
ok.
+
+ m8(A, B) ->
+ case {A,B} of
+ V -> V
+ end,
+ ok.
+
+ m9(Bs) ->
+ [{B,ok} = {B,foo:bar(B)} || B <- Bs],
+ ok.
">>,
[],
{warnings,[{5,sys_core_fold,{no_effect,{erlang,is_integer,1}}},
diff --git a/lib/cosFileTransfer/test/Makefile b/lib/cosFileTransfer/test/Makefile
index ec7ebcafca..b46fb35356 100644
--- a/lib/cosFileTransfer/test/Makefile
+++ b/lib/cosFileTransfer/test/Makefile
@@ -130,4 +130,4 @@ release_tests_spec: tests
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
$(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile
index f4689a23df..3150bd472d 100644
--- a/lib/crypto/test/Makefile
+++ b/lib/crypto/test/Makefile
@@ -77,7 +77,7 @@ release_spec:
release_tests_spec: $(TEST_TARGET)
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) crypto.spec crypto.cover $(RELTEST_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
release_docs_spec:
diff --git a/lib/debugger/test/Makefile b/lib/debugger/test/Makefile
index 4409cd2b38..2296bd0ae6 100644
--- a/lib/debugger/test/Makefile
+++ b/lib/debugger/test/Makefile
@@ -100,7 +100,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) debugger.spec debugger.cover $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index 8d62f2c529..6033d7f17c 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -317,7 +317,7 @@ merge_plts_or_report_conflicts(PltFiles, Plts) ->
Msg = io_lib:format("Could not merge PLTs since they are not disjoint\n"
"The following files are included in more than one "
"PLTs:\n~p\n", [ConfFiles]),
- error(Msg)
+ plt_error(Msg)
end.
find_duplicates(List) ->
diff --git a/lib/docbuilder/test/Makefile b/lib/docbuilder/test/Makefile
index 96b940033e..53dff193dc 100644
--- a/lib/docbuilder/test/Makefile
+++ b/lib/docbuilder/test/Makefile
@@ -72,7 +72,7 @@ release_spec: opt
release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(SPEC_FILES) docb.cover $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl
index b36aaae6ce..9a31bc9a82 100644
--- a/lib/edoc/src/edoc_wiki.erl
+++ b/lib/edoc/src/edoc_wiki.erl
@@ -296,6 +296,8 @@ push_uri(Us, Ss, As) ->
strip_empty_lines(Cs) ->
strip_empty_lines(Cs, 0).
+strip_empty_lines([], N) ->
+ {[], N}; % reached the end of input
strip_empty_lines(Cs, N) ->
{Cs1, Cs2} = edoc_lib:split_at(Cs, $\n),
case edoc_lib:is_space(Cs1) of
diff --git a/lib/edoc/test/Makefile b/lib/edoc/test/Makefile
index f77bbaa09b..2dbdb77eff 100644
--- a/lib/edoc/test/Makefile
+++ b/lib/edoc/test/Makefile
@@ -60,7 +60,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) edoc.spec edoc.cover $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 158c1ec430..34362b4b9f 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -1197,7 +1197,7 @@ static char *hex(char digest[16], char buff[33])
char *p = buff;
int i;
- for (i = 0; i < sizeof(digest); ++i) {
+ for (i = 0; i < 16; ++i) {
*p++ = tab[(int)((*d) >> 4)];
*p++ = tab[(int)((*d++) & 0xF)];
}
diff --git a/lib/erl_interface/test/Makefile b/lib/erl_interface/test/Makefile
index 8ed6834443..4faf89c0d6 100644
--- a/lib/erl_interface/test/Makefile
+++ b/lib/erl_interface/test/Makefile
@@ -73,7 +73,7 @@ release_spec:
release_tests_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/et/test/Makefile b/lib/et/test/Makefile
index 9a24e3281b..e10a2a1587 100644
--- a/lib/et/test/Makefile
+++ b/lib/et/test/Makefile
@@ -74,7 +74,7 @@ release_tests_spec: opt
$(INSTALL_DATA) et.spec et.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
$(INSTALL_SCRIPT) ett $(RELSYSDIR)
$(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR)
-# chmod -f -R u+w $(RELSYSDIR)
+# chmod -R u+w $(RELSYSDIR)
# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 5859c345d0..0cc6c2deec 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -1045,7 +1045,7 @@ convert_matchstate(Ms) ->
build_sub_binary(Ms, ByteSize, ByteOffset, BitSize, BitOffset,
hipe_rtl:mk_imm(0), Orig),
size_from_header(SizeInWords, Header),
- hipe_rtl:mk_alu(Hole, SizeInWords, sub, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE-1)),
+ hipe_rtl:mk_alu(Hole, SizeInWords, sub, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE)),
mk_var_header(BigIntHeader, Hole, ?TAG_HEADER_POS_BIG),
hipe_rtl:mk_store(Ms, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE*WordSize-?TAG_PRIMARY_BOXED),
BigIntHeader)].
diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile
index 110ad54c3c..87ca60e4b3 100644
--- a/lib/inets/test/Makefile
+++ b/lib/inets/test/Makefile
@@ -308,11 +308,11 @@ release_spec: opt
release_tests_spec: opt
$(INSTALL_DIR) $(RELTESTSYSDIR)
$(INSTALL_DATA) $(RELTEST_FILES) $(RELTESTSYSDIR)
- chmod -f -R u+w $(RELTESTSYSDIR)
+ chmod -R u+w $(RELTESTSYSDIR)
tar chf - $(DATADIRS) | (cd $(RELTESTSYSDIR); tar xf -)
$(INSTALL_DIR) $(RELTESTSYSALLDATADIR)
$(INSTALL_DIR) $(RELTESTSYSBINDIR)
- chmod -f -R +x $(RELTESTSYSBINDIR)
+ chmod -R +x $(RELTESTSYSBINDIR)
$(INSTALL_DIR) $(RELTESTSYSALLDATADIR)/win32/lib
release_docs_spec:
diff --git a/lib/inviso/test/Makefile b/lib/inviso/test/Makefile
index cd372624b5..c1df29d631 100644
--- a/lib/inviso/test/Makefile
+++ b/lib/inviso/test/Makefile
@@ -53,7 +53,7 @@ release_spec: opt
release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) inviso.spec inviso.cover $(ERL_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index a22c0a8346..f05a224f33 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -432,7 +432,7 @@ fe80::204:acff:fe17:bf38
</desc>
</func>
<func>
- <name>port(Socket) -> {ok, Port}</name>
+ <name>port(Socket) -> {ok, Port} | {error, any()}</name>
<fsummary>Return the local port number for a socket</fsummary>
<type>
<v>Socket = socket()</v>
diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml
index 86c6ea9178..2b81de170d 100644
--- a/lib/kernel/doc/src/rpc.xml
+++ b/lib/kernel/doc/src/rpc.xml
@@ -454,7 +454,7 @@
</desc>
</func>
<func>
- <name>pmap({Module, Function}, ExtraArgs, List2) -> List1</name>
+ <name>pmap({Module, Function}, ExtraArgs, List1) -> List2</name>
<fsummary>Parallell evaluation of mapping a function over a list </fsummary>
<type>
<v>Module = Function = atom()</v>
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index 5f8f3a6bf6..95517ffd6a 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -144,7 +144,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DATA) $(APP_FILES) $(RELSYSDIR)
$(INSTALL_DATA) kernel.spec $(EMAKEFILE)\
$(COVERFILE) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 3b313a6c21..b1ef8826d5 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -39,7 +39,7 @@
accept_timeouts_in_order/1,accept_timeouts_in_order2/1,
accept_timeouts_in_order3/1,accept_timeouts_mixed/1,
killing_acceptor/1,killing_multi_acceptors/1,killing_multi_acceptors2/1,
- several_accepts_in_one_go/1,active_once_closed/1, send_timeout/1,
+ several_accepts_in_one_go/1,active_once_closed/1, send_timeout/1, send_timeout_active/1,
otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1]).
%% Internal exports.
@@ -71,7 +71,7 @@ all() ->
accept_timeouts_in_order3, accept_timeouts_mixed,
killing_acceptor, killing_multi_acceptors,
killing_multi_acceptors2, several_accepts_in_one_go,
- active_once_closed, send_timeout, otp_7731,
+ active_once_closed, send_timeout, send_timeout_active, otp_7731,
zombie_sockets, otp_7816, otp_8102].
groups() ->
@@ -1957,6 +1957,60 @@ send_timeout(Config) when is_list(Config) ->
ParaFun(false),
ParaFun(true),
ok.
+mad_sender(S) ->
+ {_, _, USec} = now(),
+ case gen_tcp:send(S, integer_to_list(USec)) of
+ ok ->
+ mad_sender(S);
+ Err ->
+ Err
+ end.
+
+
+flush() ->
+ receive
+ _X ->
+ %erlang:display(_X),
+ flush()
+ after 0 ->
+ ok
+ end.
+
+send_timeout_active(suite) ->
+ [];
+send_timeout_active(doc) ->
+ ["Test the send_timeout socket option for active sockets"];
+send_timeout_active(Config) when is_list(Config) ->
+ Dog = test_server:timetrap(test_server:seconds(20)),
+ %% Basic
+ BasicFun =
+ fun(AutoClose) ->
+ ?line {Loop,A,RNode,C} = setup_active_timeout_sink(1, AutoClose),
+ inet:setopts(A, [{active, once}]),
+ ?line Mad = spawn_link(RNode,fun() -> mad_sender(C) end),
+ ?line {error,timeout} =
+ Loop(fun() ->
+ receive
+ {tcp, Sock, _Data} ->
+ inet:setopts(A, [{active, once}]),
+ Res = gen_tcp:send(A,lists:duplicate(1000, $a)),
+ %erlang:display(Res),
+ Res;
+ Err ->
+ io:format("sock closed: ~p~n", [Err]),
+ Err
+ end
+ end),
+ unlink(Mad),
+ exit(Mad,kill),
+ ?line test_server:stop_node(RNode)
+ end,
+ BasicFun(false),
+ flush(),
+ BasicFun(true),
+ flush(),
+ test_server:timetrap_cancel(Dog),
+ ok.
after_send_timeout(AutoClose) ->
case AutoClose of
@@ -2039,35 +2093,35 @@ setup_closed_ao() ->
{Loop,A}.
setup_timeout_sink(Timeout, AutoClose) ->
- Dir = filename:dirname(code:which(?MODULE)),
- {ok,R} = test_server:start_node(test_default_options_slave,slave,
+ ?line Dir = filename:dirname(code:which(?MODULE)),
+ ?line {ok,R} = test_server:start_node(test_default_options_slave,slave,
[{args,"-pa " ++ Dir}]),
- Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))),
- {ok, L} = gen_tcp:listen(0, [{active,false},{packet,2},
+ ?line Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))),
+ ?line {ok, L} = gen_tcp:listen(0, [{active,false},{packet,2},
{send_timeout,Timeout},
{send_timeout_close,AutoClose}]),
- Fun = fun(F) ->
+ ?line Fun = fun(F) ->
receive
{From,X} when is_function(X) ->
From ! {self(),X()}, F(F);
die -> ok
end
end,
- Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]),
- {ok, Port} = inet:port(L),
- Remote = fun(Fu) ->
+ ?line Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]),
+ ?line {ok, Port} = inet:port(L),
+ ?line Remote = fun(Fu) ->
Pid ! {self(), Fu},
receive {Pid,X} -> X
end
end,
- {ok, C} = Remote(fun() ->
+ ?line {ok, C} = Remote(fun() ->
gen_tcp:connect(Host,Port,
[{active,false},{packet,2}])
end),
- {ok,A} = gen_tcp:accept(L),
- gen_tcp:send(A,"Hello"),
- {ok, "Hello"} = Remote(fun() -> gen_tcp:recv(C,0) end),
- Loop2 = fun(_,_,0) ->
+ ?line {ok,A} = gen_tcp:accept(L),
+ ?line gen_tcp:send(A,"Hello"),
+ ?line {ok, "Hello"} = Remote(fun() -> gen_tcp:recv(C,0) end),
+ ?line Loop2 = fun(_,_,0) ->
{failure, timeout};
(L2,F2,N) ->
Ret = F2(),
@@ -2078,9 +2132,53 @@ setup_timeout_sink(Timeout, AutoClose) ->
Other -> Other
end
end,
- Loop = fun(F3) -> Loop2(Loop2,F3,1000) end,
+ ?line Loop = fun(F3) -> Loop2(Loop2,F3,1000) end,
{Loop,A,R}.
-
+
+setup_active_timeout_sink(Timeout, AutoClose) ->
+ ?line Dir = filename:dirname(code:which(?MODULE)),
+ ?line {ok,R} = test_server:start_node(test_default_options_slave,slave,
+ [{args,"-pa " ++ Dir}]),
+ ?line Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))),
+ ?line {ok, L} = gen_tcp:listen(0, [binary,{active,false},{packet,0},{nodelay, true},{keepalive, true},
+ {send_timeout,Timeout},
+ {send_timeout_close,AutoClose}]),
+ ?line Fun = fun(F) ->
+ receive
+ {From,X} when is_function(X) ->
+ From ! {self(),X()}, F(F);
+ die -> ok
+ end
+ end,
+ ?line Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]),
+ ?line {ok, Port} = inet:port(L),
+ ?line Remote = fun(Fu) ->
+ Pid ! {self(), Fu},
+ receive {Pid,X} -> X
+ end
+ end,
+ ?line {ok, C} = Remote(fun() ->
+ gen_tcp:connect(Host,Port,
+ [{active,false}])
+ end),
+ ?line {ok,A} = gen_tcp:accept(L),
+ ?line gen_tcp:send(A,"Hello"),
+ ?line {ok, "H"++_} = Remote(fun() -> gen_tcp:recv(C,0) end),
+ ?line Loop2 = fun(_,_,0) ->
+ {failure, timeout};
+ (L2,F2,N) ->
+ Ret = F2(),
+ io:format("~p~n",[Ret]),
+ case Ret of
+ ok -> receive after 1 -> ok end,
+ L2(L2,F2,N-1);
+ Other -> Other
+ end
+ end,
+ ?line Loop = fun(F3) -> Loop2(Loop2,F3,1000) end,
+ {Loop,A,R,C}.
+
+
millistamp() ->
{Mega, Secs, Micros} = erlang:now(),
(Micros div 1000) + Secs * 1000 + Mega * 1000000000.
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index 06bfe97bc4..2db0f7dcb8 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -24,6 +24,7 @@
init_per_group/2,end_per_group/2]).
-export([get_arguments/1, get_argument/1, boot_var/1, restart/1,
+ many_restarts/1,
get_plain_arguments/1,
reboot/1, stop/1, get_status/1, script_id/1]).
-export([boot1/1, boot2/1]).
@@ -43,6 +44,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[get_arguments, get_argument, boot_var,
+ many_restarts,
get_plain_arguments, restart, get_status, script_id,
{group, boot}].
@@ -317,6 +319,73 @@ is_real_system(KernelVsn, StdlibVsn) ->
%% Therefore the slave process must be killed
%% before restart.
%% ------------------------------------------------
+many_restarts(doc) -> [];
+many_restarts(suite) ->
+ case ?t:os_type() of
+ {Fam, _} when Fam == unix; Fam == win32 ->
+ {req, [distribution, {local_slave_nodes, 1}, {time, 5}]};
+ _ ->
+ {skip, "Only run on unix and win32"}
+ end;
+
+many_restarts(Config) when is_list(Config) ->
+ ?line Dog = ?t:timetrap(?t:seconds(480)),
+ ?line {ok, Node} = loose_node:start(init_test, "", ?DEFAULT_TIMEOUT_SEC),
+ ?line loop_restart(30,Node,rpc:call(Node,erlang,whereis,[error_logger])),
+ ?line loose_node:stop(Node),
+ ?line ?t:timetrap_cancel(Dog),
+ ok.
+
+loop_restart(0,_,_) ->
+ ok;
+loop_restart(N,Node,EHPid) ->
+ ?line erlang:monitor_node(Node, true),
+ ?line ok = rpc:call(Node, init, restart, []),
+ ?line receive
+ {nodedown, Node} ->
+ ok
+ after 10000 ->
+ loose_node:stop(Node),
+ ?t:fail(not_stopping)
+ end,
+ ?line ok = wait_for(30, Node, EHPid),
+ ?line loop_restart(N-1,Node,rpc:call(Node,erlang,whereis,[error_logger])).
+
+wait_for(0,Node,_) ->
+ loose_node:stop(Node),
+ error;
+wait_for(N,Node,EHPid) ->
+ ?line case rpc:call(Node, erlang, whereis, [error_logger]) of
+ Pid when is_pid(Pid), Pid =/= EHPid ->
+ %% ?line erlang:display(ok),
+ ?line ok;
+ _X ->
+ %% ?line erlang:display(_X),
+ %% ?line Procs = rpc:call(Node, erlang, processes, []),
+ %% ?line erlang:display(Procs),
+ %% case is_list(Procs) of
+ %% true ->
+ %% ?line [(catch erlang:display(
+ %% rpc:call(Node,
+ %% erlang,
+ %% process_info,
+ %% [Y,registered_name])))
+ %% || Y <- Procs];
+ %% _ ->
+ %% ok
+ %% end,
+ receive
+ after 100 ->
+ ok
+ end,
+ ?line wait_for(N-1,Node,EHPid)
+ end.
+
+%% ------------------------------------------------
+%% Slave executes erlang:halt() on master nodedown.
+%% Therefore the slave process must be killed
+%% before restart.
+%% ------------------------------------------------
restart(doc) -> [];
restart(suite) ->
case ?t:os_type() of
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index e33b90a274..e7b71cc168 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.14.3
+KERNEL_VSN = 2.14.4
diff --git a/lib/megaco/test/Makefile b/lib/megaco/test/Makefile
index 682b83d368..88f6f06e73 100644
--- a/lib/megaco/test/Makefile
+++ b/lib/megaco/test/Makefile
@@ -754,5 +754,5 @@ release_tests_spec: tests
# $(HRL_FILES) $(ERL_FILES) \
# $(RELSYSDIR)
#
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile
index 973ac2900a..b165924ef2 100644
--- a/lib/mnesia/test/Makefile
+++ b/lib/mnesia/test/Makefile
@@ -110,7 +110,7 @@ release_tests_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) mnesia.spec mnesia.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
$(INSTALL_SCRIPT) mt $(INSTALL_PROGS) $(RELSYSDIR)
-# chmod -f -R u+w $(RELSYSDIR)
+# chmod -R u+w $(RELSYSDIR)
# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl
index 43b3db738f..6e9d4727ec 100644
--- a/lib/observer/test/crashdump_helper.erl
+++ b/lib/observer/test/crashdump_helper.erl
@@ -19,7 +19,7 @@
-module(crashdump_helper).
-export([n1_proc/2,remote_proc/2]).
--compile(r11).
+-compile(r12).
-include("test_server.hrl").
n1_proc(N2,Creator) ->
diff --git a/lib/orber/test/Makefile b/lib/orber/test/Makefile
index 88aeacbfe8..b682bcf24b 100644
--- a/lib/orber/test/Makefile
+++ b/lib/orber/test/Makefile
@@ -226,7 +226,7 @@ release_tests_spec: tests
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) $(COVER_FILE) \
$(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
$(INSTALL_DIR) $(RELSYSDIR)/$(IDLOUTDIR)
$(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
$(RELSYSDIR)/$(IDLOUTDIR)
diff --git a/lib/parsetools/test/Makefile b/lib/parsetools/test/Makefile
index dfb686d7ba..624c4e6975 100644
--- a/lib/parsetools/test/Makefile
+++ b/lib/parsetools/test/Makefile
@@ -72,7 +72,7 @@ release_spec: opt
release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) parsetools.spec parsetools.cover $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/percept/test/Makefile b/lib/percept/test/Makefile
index 5e8c438c5c..d927386d1c 100644
--- a/lib/percept/test/Makefile
+++ b/lib/percept/test/Makefile
@@ -83,7 +83,7 @@ release_spec: opt
release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) percept.spec percept.cover $(EMAKEFILE) $(SOURCE) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 81aedaea56..c5f57214b1 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -56,44 +56,43 @@
<p><em>Data Types </em></p>
- <p><c>boolean() = true | false</c></p>
+ <p><code>boolean() = true | false</code></p>
- <p><c>string = [bytes()]</c></p>
+ <p><code>string = [bytes()]</code></p>
- <p><c>der_encoded() = binary() </c></p>
-
- <p><c>decrypt_der() = binary() </c></p>
+ <p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey'
+ 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'</code></p>
- <p><c>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey'
- 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'</c></p>
-
- <p><c>pem_entry () = {pki_asn1_type(), der_encoded() | decrypt_der(), not_encrypted |
- {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}}.</c></p>
-
- <p><c>rsa_public_key() = #'RSAPublicKey'{}</c></p>
+ <p><code>pem_entry () = {pki_asn1_type(), binary() %% DER or encrypted DER
+ not_encrypted | {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}}.</code></p>
- <p><c>rsa_private_key() = #'RSAPrivateKey'{} </c></p>
+ <p><code>rsa_public_key() = #'RSAPublicKey'{}</code></p>
+
+ <p><code>rsa_private_key() = #'RSAPrivateKey'{} </code></p>
- <p><c>dsa_public_key() = {integer(), #'Dss-Parms'{}} </c></p>
+ <p><code>dsa_public_key() = {integer(), #'Dss-Parms'{}} </code></p>
- <p><c>rsa_private_key() = #'RSAPrivateKey'{} </c></p>
+ <p><code>rsa_private_key() = #'RSAPrivateKey'{} </code></p>
- <p><c>dsa_private_key() = #'DSAPrivateKey'{}</c></p>
+ <p><code>dsa_private_key() = #'DSAPrivateKey'{}</code></p>
- <p><c> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </c></p>
+ <p><code> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </code></p>
- <p><c> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
- | 'rsa_no_padding'</c></p>
+ <p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
+ | 'rsa_no_padding'</code></p>
- <p><c> rsa_digest_type() = 'md5' | 'sha' </c></p>
-
- <p><c> dss_digest_type() = 'none' | 'sha' </c></p>
+ <p><code> rsa_digest_type() = 'md5' | 'sha' </code></p>
+
+ <p><code> dss_digest_type() = 'none' | 'sha' </code></p>
+
+ <p><code> ssh_file() = openssh_public_key | rfc4716_public_key |
+ known_hosts | auth_keys </code></p>
-<!-- <p><c>policy_tree() = [Root, Children]</c></p> -->
+<!-- <p><code>policy_tree() = [Root, Children]</code></p> -->
-<!-- <p><c>Root = #policy_tree_node{}</c></p> -->
+<!-- <p><code>Root = #policy_tree_node{}</code></p> -->
-<!-- <p><c>Children = [] | policy_tree()</c></p> -->
+<!-- <p><code>Children = [] | policy_tree()</code></p> -->
<!-- <p> The policy_tree_node record has the following fields:</p> -->
@@ -403,6 +402,55 @@
</func>
<func>
+ <name>ssh_decode(SshBin, Type) -> [{public_key(), Attributes::list()}]</name>
+ <fsummary>Decodes a ssh file-binary. </fsummary>
+ <type>
+ <v>SshBin = binary()</v>
+ <d>Example {ok, SshBin} = file:read_file("known_hosts").</d>
+ <v> Type = public_key | ssh_file()</v>
+ <d>If <c>Type</c> is <c>public_key</c> the binary may be either
+ a rfc4716 public key or a openssh public key.</d>
+ </type>
+ <desc>
+ <p> Decodes a ssh file-binary. In the case of know_hosts or
+ auth_keys the binary may include one or more lines of the
+ file. Returns a list of public keys and their attributes, possible
+ attribute values depends on the file type represented by the
+ binary.
+ </p>
+
+ <taglist>
+ <tag>rfc4716 attributes - see RFC 4716</tag>
+ <item>{headers, [{string(), utf8_string()}]}</item>
+ <tag>auth_key attributes - see man sshd </tag>
+ <item>{comment, string()}</item>
+ <item>{options, [string()]}</item>
+ <item>{bits, integer()} - In ssh version 1 files</item>
+ <tag>known_host attributes - see man sshd</tag>
+ <item>{hostnames, [string()]}</item>
+ <item>{comment, string()}</item>
+ <item>{bits, integer()} - In ssh version 1 files</item>
+ </taglist>
+
+ </desc>
+ </func>
+
+ <func>
+ <name>ssh_encode([{Key, Attributes}], Type) -> binary()</name>
+ <fsummary> Encodes a list of ssh file entries to a binary.</fsummary>
+ <type>
+ <v>Key = public_key()</v>
+ <v>Attributes = list()</v>
+ <v>Type = ssh_file()</v>
+ </type>
+ <desc>
+ <p>Encodes a list of ssh file entries (public keys and attributes) to a binary. Possible
+ attributes depends on the file type, see <seealso
+ marker="ssh_decode"> ssh_decode/2 </seealso></p>
+ </desc>
+ </func>
+
+ <func>
<name>verify(Msg, DigestType, Signature, Key) -> boolean()</name>
<fsummary>Verifies a digital signature.</fsummary>
<type>
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 3498a2a433..5f97d80f7e 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -70,14 +70,18 @@
interim_reasons_mask
}).
-
--type der_encoded() :: binary().
--type decrypt_der() :: binary().
+-type public_key() :: rsa_public_key() | dsa_public_key().
+-type rsa_public_key() :: #'RSAPublicKey'{}.
+-type rsa_private_key() :: #'RSAPrivateKey'{}.
+-type dsa_private_key() :: #'DSAPrivateKey'{}.
+-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey'
| 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter'
| 'SubjectPublicKeyInfo'.
--type pem_entry() :: {pki_asn1_type(), der_encoded() | decrypt_der(),
+-type pem_entry() :: {pki_asn1_type(), binary(), %% DER or Encrypted DER
not_encrypted | {Cipher :: string(), Salt :: binary()}}.
-type asn1_type() :: atom(). %% see "OTP-PUB-KEY.hrl
+-type ssh_file() :: openssh_public_key | rfc4716_public_key | known_hosts |
+ auth_keys.
-endif. % -ifdef(public_key).
diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile
index b042b0c30a..5a24b02d2a 100644
--- a/lib/public_key/src/Makefile
+++ b/lib/public_key/src/Makefile
@@ -41,6 +41,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN)
MODULES = \
public_key \
pubkey_pem \
+ pubkey_ssh \
pubkey_cert \
pubkey_cert_records
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index fadb993ed9..5ab9642279 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -38,7 +38,7 @@
%%====================================================================
%%--------------------------------------------------------------------
--spec verify_data(der_encoded()) -> {md5 | sha, binary(), binary()}.
+-spec verify_data(DER::binary()) -> {md5 | sha, binary(), binary()}.
%%
%% Description: Extracts data from DerCert needed to call public_key:verify/4.
%%--------------------------------------------------------------------
@@ -146,7 +146,7 @@ validate_issuer(OtpCert, Issuer, UserState, VerifyFun) ->
verify_fun(OtpCert, {bad_cert, invalid_issuer}, UserState, VerifyFun)
end.
%%--------------------------------------------------------------------
--spec validate_signature(#'OTPCertificate'{}, der_encoded(),
+-spec validate_signature(#'OTPCertificate'{}, DER::binary(),
term(),term(), term(), fun()) -> term().
%%
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index 2441cfc0e0..b86d7a1f0c 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -30,7 +30,7 @@
%%====================================================================
%%--------------------------------------------------------------------
--spec decode_cert(der_encoded()) -> {ok, #'OTPCertificate'{}}.
+-spec decode_cert(DerCert::binary()) -> {ok, #'OTPCertificate'{}}.
%%
%% Description: Recursively decodes a Certificate.
%%--------------------------------------------------------------------
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index c8c69bcdd0..c26815bc04 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -69,8 +69,9 @@ encode(PemEntries) ->
encode_pem_entries(PemEntries).
%%--------------------------------------------------------------------
--spec decipher({pki_asn1_type(), decrypt_der(),{Cipher :: string(), Salt :: binary()}}, string()) ->
- der_encoded().
+-spec decipher({pki_asn1_type(), DerEncrypted::binary(),{Cipher :: string(),
+ Salt :: binary()}},
+ string()) -> Der::binary().
%%
%% Description: Deciphers a decrypted pem entry.
%%--------------------------------------------------------------------
@@ -78,7 +79,8 @@ decipher({_, DecryptDer, {Cipher,Salt}}, Password) ->
decode_key(DecryptDer, Password, Cipher, Salt).
%%--------------------------------------------------------------------
--spec cipher(der_encoded(),{Cipher :: string(), Salt :: binary()} , string()) -> binary().
+-spec cipher(Der::binary(),{Cipher :: string(), Salt :: binary()} ,
+ string()) -> binary().
%%
%% Description: Ciphers a PEM entry
%%--------------------------------------------------------------------
@@ -91,11 +93,11 @@ cipher(Der, {Cipher,Salt}, Password)->
encode_pem_entries(Entries) ->
[encode_pem_entry(Entry) || Entry <- Entries].
-encode_pem_entry({Asn1Type, Der, not_encrypted}) ->
- StartStr = pem_start(Asn1Type),
+encode_pem_entry({Type, Der, not_encrypted}) ->
+ StartStr = pem_start(Type),
[StartStr, "\n", b64encode_and_split(Der), "\n", pem_end(StartStr) ,"\n\n"];
-encode_pem_entry({Asn1Type, Der, {Cipher, Salt}}) ->
- StartStr = pem_start(Asn1Type),
+encode_pem_entry({Type, Der, {Cipher, Salt}}) ->
+ StartStr = pem_start(Type),
[StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n",
b64encode_and_split(Der), "\n", pem_end(StartStr) ,"\n\n"].
@@ -115,17 +117,17 @@ decode_pem_entries([Start| Lines], Entries) ->
end.
decode_pem_entry(Start, [<<"Proc-Type: 4,ENCRYPTED", _/binary>>, Line | Lines]) ->
- Asn1Type = asn1_type(Start),
+ Type = asn1_type(Start),
Cs = erlang:iolist_to_binary(Lines),
Decoded = base64:mime_decode(Cs),
[_, DekInfo0] = string:tokens(binary_to_list(Line), ": "),
[Cipher, Salt] = string:tokens(DekInfo0, ","),
- {Asn1Type, Decoded, {Cipher, unhex(Salt)}};
+ {Type, Decoded, {Cipher, unhex(Salt)}};
decode_pem_entry(Start, Lines) ->
- Asn1Type = asn1_type(Start),
+ Type = asn1_type(Start),
Cs = erlang:iolist_to_binary(Lines),
- Der = base64:mime_decode(Cs),
- {Asn1Type, Der, not_encrypted}.
+ Decoded = base64:mime_decode(Cs),
+ {Type, Decoded, not_encrypted}.
split_bin(Bin) ->
split_bin(0, Bin).
@@ -153,17 +155,7 @@ split_lines(Bin) ->
[Bin].
%% Ignore white space at end of line
-join_entry([<<"-----END CERTIFICATE-----", _/binary>>| Lines], Entry) ->
- {lists:reverse(Entry), Lines};
-join_entry([<<"-----END RSA PRIVATE KEY-----", _/binary>>| Lines], Entry) ->
- {lists:reverse(Entry), Lines};
-join_entry([<<"-----END PUBLIC KEY-----", _/binary>>| Lines], Entry) ->
- {lists:reverse(Entry), Lines};
-join_entry([<<"-----END RSA PUBLIC KEY-----", _/binary>>| Lines], Entry) ->
- {lists:reverse(Entry), Lines};
-join_entry([<<"-----END DSA PRIVATE KEY-----", _/binary>>| Lines], Entry) ->
- {lists:reverse(Entry), Lines};
-join_entry([<<"-----END DH PARAMETERS-----", _/binary>>| Lines], Entry) ->
+join_entry([<<"-----END ", _/binary>>| Lines], Entry) ->
{lists:reverse(Entry), Lines};
join_entry([Line | Lines], Entry) ->
join_entry(Lines, [Line | Entry]).
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
new file mode 100644
index 0000000000..f342eab159
--- /dev/null
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -0,0 +1,431 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(pubkey_ssh).
+
+-include("public_key.hrl").
+
+-export([decode/2, encode/2]).
+
+-define(UINT32(X), X:32/unsigned-big-integer).
+%% Max encoded line length is 72, but conformance examples use 68
+%% Comment from rfc 4716: "The following are some examples of public
+%% key files that are compliant (note that the examples all wrap
+%% before 72 bytes to meet IETF document requirements; however, they
+%% are still compliant.)" So we choose to use 68 also.
+-define(ENCODED_LINE_LENGTH, 68).
+
+%%====================================================================
+%% Internal application API
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}].
+%%
+%% Description: Decodes a ssh file-binary.
+%%--------------------------------------------------------------------
+decode(Bin, public_key)->
+ case binary:match(Bin, begin_marker()) of
+ nomatch ->
+ openssh_decode(Bin, openssh_public_key);
+ _ ->
+ rfc4716_decode(Bin)
+ end;
+decode(Bin, rfc4716_public_key) ->
+ rfc4716_decode(Bin);
+decode(Bin, Type) ->
+ openssh_decode(Bin, Type).
+
+%%--------------------------------------------------------------------
+-spec encode([{public_key(), Attributes::list()}], ssh_file()) ->
+ binary().
+%%
+%% Description: Encodes a list of ssh file entries.
+%%--------------------------------------------------------------------
+encode(Entries, Type) ->
+ erlang:iolist_to_binary(lists:map(fun({Key, Attributes}) ->
+ do_encode(Type, Key, Attributes)
+ end, Entries)).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+begin_marker() ->
+ <<"---- BEGIN SSH2 PUBLIC KEY ----">>.
+end_marker() ->
+ <<"---- END SSH2 PUBLIC KEY ----">>.
+
+rfc4716_decode(Bin) ->
+ Lines = binary:split(Bin, <<"\n">>, [global]),
+ do_rfc4716_decode(Lines, []).
+
+do_rfc4716_decode([<<"---- BEGIN SSH2 PUBLIC KEY ----", _/binary>> | Lines], Acc) ->
+ do_rfc4716_decode(Lines, Acc);
+%% Ignore empty lines before or after begin/end - markers.
+do_rfc4716_decode([<<>> | Lines], Acc) ->
+ do_rfc4716_decode(Lines, Acc);
+do_rfc4716_decode([], Acc) ->
+ lists:reverse(Acc);
+do_rfc4716_decode(Lines, Acc) ->
+ {Headers, PubKey, Rest} = rfc4716_decode_lines(Lines, []),
+ case Headers of
+ [_|_] ->
+ do_rfc4716_decode(Rest, [{PubKey, [{headers, Headers}]} | Acc]);
+ _ ->
+ do_rfc4716_decode(Rest, [{PubKey, []} | Acc])
+ end.
+
+rfc4716_decode_lines([Line | Lines], Acc) ->
+ case binary:last(Line) of
+ $\\ ->
+ NewLine = binary:replace(Line,<<"\\">>, hd(Lines), []),
+ rfc4716_decode_lines([NewLine | tl(Lines)], Acc);
+ _ ->
+ rfc4716_decode_line(Line, Lines, Acc)
+ end.
+
+rfc4716_decode_line(Line, Lines, Acc) ->
+ case binary:split(Line, <<":">>) of
+ [Tag, Value] ->
+ rfc4716_decode_lines(Lines, [{string_decode(Tag), unicode_decode(Value)} | Acc]);
+ _ ->
+ {Body, Rest} = join_entry([Line | Lines], []),
+ {lists:reverse(Acc), rfc4716_pubkey_decode(base64:mime_decode(Body)), Rest}
+ end.
+
+join_entry([<<"---- END SSH2 PUBLIC KEY ----", _/binary>>| Lines], Entry) ->
+ {lists:reverse(Entry), Lines};
+join_entry([Line | Lines], Entry) ->
+ join_entry(Lines, [Line | Entry]).
+
+
+rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary,
+ ?UINT32(SizeE), E:SizeE/binary,
+ ?UINT32(SizeN), N:SizeN/binary>>) when Type == <<"ssh-rsa">> ->
+ #'RSAPublicKey'{modulus = erlint(SizeN, N),
+ publicExponent = erlint(SizeE, E)};
+
+rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary,
+ ?UINT32(SizeP), P:SizeP/binary,
+ ?UINT32(SizeQ), Q:SizeQ/binary,
+ ?UINT32(SizeG), G:SizeG/binary,
+ ?UINT32(SizeY), Y:SizeY/binary>>) when Type == <<"ssh-dss">> ->
+ {erlint(SizeY, Y),
+ #'Dss-Parms'{p = erlint(SizeP, P),
+ q = erlint(SizeQ, Q),
+ g = erlint(SizeG, G)}}.
+
+openssh_decode(Bin, FileType) ->
+ Lines = binary:split(Bin, <<"\n">>, [global]),
+ do_openssh_decode(FileType, Lines, []).
+
+do_openssh_decode(_, [], Acc) ->
+ lists:reverse(Acc);
+%% Ignore empty lines
+do_openssh_decode(FileType, [<<>> | Lines], Acc) ->
+ do_openssh_decode(FileType, Lines, Acc);
+%% Ignore lines that start with #
+do_openssh_decode(FileType,[<<"#", _/binary>> | Lines], Acc) ->
+ do_openssh_decode(FileType, Lines, Acc);
+do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) ->
+ Split = binary:split(Line, <<" ">>, [global]),
+ case mend_split(Split, []) of
+ %% ssh2
+ [Options, KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>;
+ KeyType == <<"ssh-dss">> ->
+ do_openssh_decode(FileType, Lines,
+ [{openssh_pubkey_decode(KeyType, Base64Enc),
+ [{comment, string_decode(Comment)},
+ {options, comma_list_decode(Options)}]}
+ | Acc]);
+
+ [KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>;
+ KeyType == <<"ssh-dss">> ->
+ do_openssh_decode(FileType, Lines,
+ [{openssh_pubkey_decode(KeyType, Base64Enc),
+ [{comment, string_decode(Comment)}]} | Acc]);
+ %% ssh1
+ [Options, Bits, Exponent, Modulus, Comment] ->
+ do_openssh_decode(FileType, Lines,
+ [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
+ [{comment, string_decode(Comment)},
+ {options, comma_list_decode(Options)},
+ {bits, integer_decode(Bits)}]} | Acc]);
+ [Bits, Exponent, Modulus, Comment] ->
+ do_openssh_decode(FileType, Lines,
+ [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
+ [{comment, string_decode(Comment)},
+ {bits, integer_decode(Bits)}]} | Acc])
+ end;
+
+do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) ->
+ case binary:split(Line, <<" ">>, [global]) of
+ %% ssh 2
+ [HostNames, KeyType, Base64Enc] when KeyType == <<"ssh-rsa">>;
+ KeyType == <<"ssh-dss">> ->
+ do_openssh_decode(FileType, Lines,
+ [{openssh_pubkey_decode(KeyType, Base64Enc),
+ [{hostnames, comma_list_decode(HostNames)}]}| Acc]);
+ [HostNames, KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>;
+ KeyType == <<"ssh-dss">> ->
+ do_openssh_decode(FileType, Lines,
+ [{openssh_pubkey_decode(KeyType, Base64Enc),
+ [{comment, string_decode(Comment)},
+ {hostnames, comma_list_decode(HostNames)}]} | Acc]);
+ %% ssh 1
+ [HostNames, Bits, Exponent, Modulus, Comment] ->
+ do_openssh_decode(FileType, Lines,
+ [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
+ [{comment, string_decode(Comment)},
+ {hostnames, comma_list_decode(HostNames)},
+ {bits, integer_decode(Bits)}]} | Acc]);
+ [HostNames, Bits, Exponent, Modulus] ->
+ do_openssh_decode(FileType, Lines,
+ [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
+ [{comment, []},
+ {hostnames, comma_list_decode(HostNames)},
+ {bits, integer_decode(Bits)}]} | Acc])
+ end;
+
+do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) ->
+ case binary:split(Line, <<" ">>, [global]) of
+ [KeyType, Base64Enc, Comment0] when KeyType == <<"ssh-rsa">>;
+ KeyType == <<"ssh-dss">> ->
+ Comment = string:strip(binary_to_list(Comment0), right, $\n),
+ do_openssh_decode(FileType, Lines,
+ [{openssh_pubkey_decode(KeyType, Base64Enc),
+ [{comment, Comment}]} | Acc])
+ end.
+
+
+openssh_pubkey_decode(<<"ssh-rsa">>, Base64Enc) ->
+ <<?UINT32(StrLen), _:StrLen/binary,
+ ?UINT32(SizeE), E:SizeE/binary,
+ ?UINT32(SizeN), N:SizeN/binary>>
+ = base64:mime_decode(Base64Enc),
+ #'RSAPublicKey'{modulus = erlint(SizeN, N),
+ publicExponent = erlint(SizeE, E)};
+
+openssh_pubkey_decode(<<"ssh-dss">>, Base64Enc) ->
+ <<?UINT32(StrLen), _:StrLen/binary,
+ ?UINT32(SizeP), P:SizeP/binary,
+ ?UINT32(SizeQ), Q:SizeQ/binary,
+ ?UINT32(SizeG), G:SizeG/binary,
+ ?UINT32(SizeY), Y:SizeY/binary>>
+ = base64:mime_decode(Base64Enc),
+ {erlint(SizeY, Y),
+ #'Dss-Parms'{p = erlint(SizeP, P),
+ q = erlint(SizeQ, Q),
+ g = erlint(SizeG, G)}}.
+
+erlint(MPIntSize, MPIntValue) ->
+ Bits= MPIntSize * 8,
+ <<Integer:Bits/integer>> = MPIntValue,
+ Integer.
+
+ssh1_rsa_pubkey_decode(MBin, EBin) ->
+ #'RSAPublicKey'{modulus = integer_decode(MBin),
+ publicExponent = integer_decode(EBin)}.
+
+integer_decode(BinStr) ->
+ list_to_integer(binary_to_list(BinStr)).
+
+string_decode(BinStr) ->
+ binary_to_list(BinStr).
+
+unicode_decode(BinStr) ->
+ unicode:characters_to_list(BinStr).
+
+comma_list_decode(BinOpts) ->
+ CommaList = binary:split(BinOpts, <<",">>, [global]),
+ lists:map(fun(Item) ->
+ binary_to_list(Item)
+ end, CommaList).
+
+do_encode(rfc4716_public_key, Key, Attributes) ->
+ rfc4716_encode(Key, proplists:get_value(headers, Attributes, []), []);
+
+do_encode(Type, Key, Attributes) ->
+ openssh_encode(Type, Key, Attributes).
+
+rfc4716_encode(Key, [],[]) ->
+ erlang:iolist_to_binary([begin_marker(),"\n",
+ split_lines(base64:encode(ssh2_pubkey_encode(Key))),
+ "\n", end_marker(), "\n"]);
+rfc4716_encode(Key, [], [_|_] = Acc) ->
+ erlang:iolist_to_binary([begin_marker(), "\n",
+ lists:reverse(Acc),
+ split_lines(base64:encode(ssh2_pubkey_encode(Key))),
+ "\n", end_marker(), "\n"]);
+rfc4716_encode(Key, [ Header | Headers], Acc) ->
+ LinesStr = rfc4716_encode_header(Header),
+ rfc4716_encode(Key, Headers, [LinesStr | Acc]).
+
+rfc4716_encode_header({Tag, Value}) ->
+ TagLen = length(Tag),
+ ValueLen = length(Value),
+ case TagLen + 1 + ValueLen of
+ N when N > ?ENCODED_LINE_LENGTH ->
+ NumOfChars = ?ENCODED_LINE_LENGTH - (TagLen + 1),
+ {First, Rest} = lists:split(NumOfChars, Value),
+ [Tag,":" , First, [$\\], "\n", rfc4716_encode_value(Rest) , "\n"];
+ _ ->
+ [Tag, ":", Value, "\n"]
+ end.
+
+rfc4716_encode_value(Value) ->
+ case length(Value) of
+ N when N > ?ENCODED_LINE_LENGTH ->
+ {First, Rest} = lists:split(?ENCODED_LINE_LENGTH, Value),
+ [First, [$\\], "\n", rfc4716_encode_value(Rest)];
+ _ ->
+ Value
+ end.
+
+openssh_encode(openssh_public_key, Key, Attributes) ->
+ Comment = proplists:get_value(comment, Attributes),
+ Enc = base64:encode(ssh2_pubkey_encode(Key)),
+ erlang:iolist_to_binary([key_type(Key), " ", Enc, " ", Comment, "\n"]);
+
+openssh_encode(auth_keys, Key, Attributes) ->
+ Comment = proplists:get_value(comment, Attributes, ""),
+ Options = proplists:get_value(options, Attributes, undefined),
+ Bits = proplists:get_value(bits, Attributes, undefined),
+ case Bits of
+ undefined ->
+ openssh_ssh2_auth_keys_encode(Options, Key, Comment);
+ _ ->
+ openssh_ssh1_auth_keys_encode(Options, Bits, Key, Comment)
+ end;
+openssh_encode(known_hosts, Key, Attributes) ->
+ Comment = proplists:get_value(comment, Attributes, ""),
+ Hostnames = proplists:get_value(hostnames, Attributes),
+ Bits = proplists:get_value(bits, Attributes, undefined),
+ case Bits of
+ undefined ->
+ openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment);
+ _ ->
+ openssh_ssh1_known_hosts_encode(Hostnames, Bits, Key, Comment)
+ end.
+
+openssh_ssh2_auth_keys_encode(undefined, Key, Comment) ->
+ erlang:iolist_to_binary([key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]);
+openssh_ssh2_auth_keys_encode(Options, Key, Comment) ->
+ erlang:iolist_to_binary([comma_list_encode(Options, []), " ",
+ key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]).
+
+openssh_ssh1_auth_keys_encode(undefined, Bits,
+ #'RSAPublicKey'{modulus = N, publicExponent = E},
+ Comment) ->
+ erlang:iolist_to_binary([integer_to_list(Bits), " ", integer_to_list(E), " ", integer_to_list(N),
+ line_end(Comment)]);
+openssh_ssh1_auth_keys_encode(Options, Bits,
+ #'RSAPublicKey'{modulus = N, publicExponent = E},
+ Comment) ->
+ erlang:iolist_to_binary([comma_list_encode(Options, []), " ", integer_to_list(Bits),
+ " ", integer_to_list(E), " ", integer_to_list(N), line_end(Comment)]).
+
+openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment) ->
+ erlang:iolist_to_binary([comma_list_encode(Hostnames, []), " ",
+ key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]).
+
+openssh_ssh1_known_hosts_encode(Hostnames, Bits,
+ #'RSAPublicKey'{modulus = N, publicExponent = E},
+ Comment) ->
+ erlang:iolist_to_binary([comma_list_encode(Hostnames, [])," ", integer_to_list(Bits)," ",
+ integer_to_list(E)," ", integer_to_list(N), line_end(Comment)]).
+
+line_end("") ->
+ "\n";
+line_end(Comment) ->
+ [" ", Comment, "\n"].
+
+key_type(#'RSAPublicKey'{}) ->
+ <<"ssh-rsa">>;
+key_type({_, #'Dss-Parms'{}}) ->
+ <<"ssh-dss">>.
+
+comma_list_encode([Option], []) ->
+ Option;
+comma_list_encode([Option], Acc) ->
+ Acc ++ "," ++ Option;
+comma_list_encode([Option | Rest], []) ->
+ comma_list_encode(Rest, Option);
+comma_list_encode([Option | Rest], Acc) ->
+ comma_list_encode(Rest, Acc ++ "," ++ Option).
+
+ssh2_pubkey_encode(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
+ TypeStr = <<"ssh-rsa">>,
+ StrLen = size(TypeStr),
+ EBin = crypto:mpint(E),
+ NBin = crypto:mpint(N),
+ <<?UINT32(StrLen), TypeStr:StrLen/binary,
+ EBin/binary,
+ NBin/binary>>;
+ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
+ TypeStr = <<"ssh-dss">>,
+ StrLen = size(TypeStr),
+ PBin = crypto:mpint(P),
+ QBin = crypto:mpint(Q),
+ GBin = crypto:mpint(G),
+ YBin = crypto:mpint(Y),
+ <<?UINT32(StrLen), TypeStr:StrLen/binary,
+ PBin/binary,
+ QBin/binary,
+ GBin/binary,
+ YBin/binary>>.
+
+mend_split([Part1, Part2 | Rest] = List, Acc) ->
+ case option_end(Part1, Part2) of
+ true ->
+ lists:reverse(Acc) ++ List;
+ false ->
+ case length(binary:matches(Part1, <<"\"">>)) of
+ N when N rem 2 == 0 ->
+ mend_split(Rest, [Part1 | Acc]);
+ _ ->
+ mend_split([<<Part1/binary, Part2/binary>> | Rest], Acc)
+ end
+ end.
+
+option_end(Part1, Part2) ->
+ (is_key_field(Part1) orelse is_bits_field(Part1))
+ orelse
+ (is_key_field(Part2) orelse is_bits_field(Part2)).
+
+is_key_field(<<"ssh-dss">>) ->
+ true;
+is_key_field(<<"ssh-rsa">>) ->
+ true;
+is_key_field(_) ->
+ false.
+
+is_bits_field(Part) ->
+ try list_to_integer(binary_to_list(Part)) of
+ _ ->
+ true
+ catch _:_ ->
+ false
+ end.
+
+split_lines(<<Text:?ENCODED_LINE_LENGTH/binary>>) ->
+ [Text];
+split_lines(<<Text:?ENCODED_LINE_LENGTH/binary, Rest/binary>>) ->
+ [Text, $\n | split_lines(Rest)];
+split_lines(Bin) ->
+ [Bin].
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index 60487946fa..1963bd05d4 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -1,9 +1,9 @@
{application, public_key,
[{description, "Public key infrastructure"},
{vsn, "%VSN%"},
- {modules, [
- public_key,
- pubkey_pem,
+ {modules, [ public_key,
+ pubkey_pem,
+ pubkey_ssh,
pubkey_cert,
pubkey_cert_records,
'OTP-PUB-KEY'
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 7e022da7e5..2901020e83 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -41,7 +41,8 @@
pkix_is_issuer/2,
pkix_issuer_id/2,
pkix_normalize_name/1,
- pkix_path_validation/3
+ pkix_path_validation/3,
+ ssh_decode/2, ssh_encode/2
]).
%% Deprecated
@@ -51,10 +52,6 @@
-deprecated({decode_private_key, 1, next_major_release}).
-deprecated({decode_private_key, 2, next_major_release}).
--type rsa_public_key() :: #'RSAPublicKey'{}.
--type rsa_private_key() :: #'RSAPrivateKey'{}.
--type dsa_private_key() :: #'DSAPrivateKey'{}.
--type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
| 'rsa_no_padding'.
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
@@ -67,7 +64,6 @@
%%====================================================================
%% API
%%====================================================================
-
%%--------------------------------------------------------------------
-spec pem_decode(binary()) -> [pem_entry()].
%%
@@ -152,7 +148,7 @@ pem_entry_encode(Asn1Type, Entity,
{Asn1Type, DecryptDer, CipherInfo}.
%%--------------------------------------------------------------------
--spec der_decode(asn1_type(), der_encoded()) -> term().
+-spec der_decode(asn1_type(), Der::binary()) -> term().
%%
%% Description: Decodes a public key asn1 der encoded entity.
%%--------------------------------------------------------------------
@@ -166,7 +162,7 @@ der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
end.
%%--------------------------------------------------------------------
--spec der_encode(asn1_type(), term()) -> der_encoded().
+-spec der_encode(asn1_type(), term()) -> Der::binary().
%%
%% Description: Encodes a public key entity with asn1 DER encoding.
%%--------------------------------------------------------------------
@@ -180,7 +176,7 @@ der_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
end.
%%--------------------------------------------------------------------
--spec pkix_decode_cert(der_encoded(), plain | otp) ->
+-spec pkix_decode_cert(Cert::binary(), plain | otp) ->
#'Certificate'{} | #'OTPCertificate'{}.
%%
%% Description: Decodes an asn1 der encoded pkix certificate. The otp
@@ -201,7 +197,7 @@ pkix_decode_cert(DerCert, otp) when is_binary(DerCert) ->
end.
%%--------------------------------------------------------------------
--spec pkix_encode(asn1_type(), term(), otp | plain) -> der_encoded().
+-spec pkix_encode(asn1_type(), term(), otp | plain) -> Der::binary().
%%
%% Description: Der encodes a certificate or part of a certificate.
%% This function must be used for encoding certificates or parts of certificates
@@ -361,7 +357,7 @@ verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
crypto:mpint(G), crypto:mpint(Key)]).
%%--------------------------------------------------------------------
-spec pkix_sign(#'OTPTBSCertificate'{},
- rsa_private_key() | dsa_private_key()) -> der_encoded().
+ rsa_private_key() | dsa_private_key()) -> Der::binary().
%%
%% Description: Sign a pkix x.509 certificate. Returns the corresponding
%% der encoded 'Certificate'{}
@@ -370,7 +366,7 @@ pkix_sign(#'OTPTBSCertificate'{signature =
#'SignatureAlgorithm'{algorithm = Alg}
= SigAlg} = TBSCert, Key) ->
- Msg = pkix_encode('OTPTBSCertificate', TBSCert, otp),
+ Msg = pkix_encode('OTPTBSCertificate', TBSCert, otp),
DigestType = pubkey_cert:digest_type(Alg),
Signature = sign(Msg, DigestType, Key),
Cert = #'OTPCertificate'{tbsCertificate= TBSCert,
@@ -380,7 +376,7 @@ pkix_sign(#'OTPTBSCertificate'{signature =
pkix_encode('OTPCertificate', Cert, otp).
%%--------------------------------------------------------------------
--spec pkix_verify(der_encoded(), rsa_public_key()|
+-spec pkix_verify(Cert::binary(), rsa_public_key()|
dsa_public_key()) -> boolean().
%%
%% Description: Verify pkix x.509 certificate signature.
@@ -396,9 +392,9 @@ pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey)
verify(PlainText, DigestType, Signature, RSAKey).
%%--------------------------------------------------------------------
--spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{},
- IssuerCert :: der_encoded()|
- #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_issuer(Cert::binary()| #'OTPCertificate'{},
+ IssuerCert::binary()|
+ #'OTPCertificate'{}) -> boolean().
%%
%% Description: Checks if <IssuerCert> issued <Cert>.
%%--------------------------------------------------------------------
@@ -414,7 +410,7 @@ pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert},
Candidate#'OTPTBSCertificate'.subject).
%%--------------------------------------------------------------------
--spec pkix_is_self_signed(der_encoded()| #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_self_signed(Cert::binary()| #'OTPCertificate'{}) -> boolean().
%%
%% Description: Checks if a Certificate is self signed.
%%--------------------------------------------------------------------
@@ -425,7 +421,7 @@ pkix_is_self_signed(Cert) when is_binary(Cert) ->
pkix_is_self_signed(OtpCert).
%%--------------------------------------------------------------------
--spec pkix_is_fixed_dh_cert(der_encoded()| #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_fixed_dh_cert(Cert::binary()| #'OTPCertificate'{}) -> boolean().
%%
%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert.
%%--------------------------------------------------------------------
@@ -436,14 +432,14 @@ pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) ->
pkix_is_fixed_dh_cert(OtpCert).
%%--------------------------------------------------------------------
--spec pkix_issuer_id(der_encoded()| #'OTPCertificate'{},
- IssuedBy :: self | other) ->
- {ok, {SerialNr :: integer(),
- Issuer :: {rdnSequence,
- [#'AttributeTypeAndValue'{}]}}}
+-spec pkix_issuer_id(Cert::binary()| #'OTPCertificate'{},
+ IssuedBy :: self | other) ->
+ {ok, {SerialNr :: integer(),
+ Issuer :: {rdnSequence,
+ [#'AttributeTypeAndValue'{}]}}}
| {error, Reason :: term()}.
%
-%% Description: Returns the issuer id.
+%% Description: Returns the issuer id.
%%--------------------------------------------------------------------
pkix_issuer_id(#'OTPCertificate'{} = OtpCert, self) ->
pubkey_cert:issuer_id(OtpCert, self);
@@ -456,8 +452,8 @@ pkix_issuer_id(Cert, Signed) when is_binary(Cert) ->
pkix_issuer_id(OtpCert, Signed).
%%--------------------------------------------------------------------
--spec pkix_normalize_name({rdnSequence,
- [#'AttributeTypeAndValue'{}]}) ->
+-spec pkix_normalize_name({rdnSequence,
+ [#'AttributeTypeAndValue'{}]}) ->
{rdnSequence,
[#'AttributeTypeAndValue'{}]}.
%%
@@ -468,8 +464,8 @@ pkix_normalize_name(Issuer) ->
pubkey_cert:normalize_general_name(Issuer).
%%--------------------------------------------------------------------
--spec pkix_path_validation(der_encoded()| #'OTPCertificate'{} | atom(),
- CertChain :: [der_encoded()] ,
+-spec pkix_path_validation(Cert::binary()| #'OTPCertificate'{} | atom(),
+ CertChain :: [binary()] ,
Options :: list()) ->
{ok, {PublicKeyInfo :: term(),
PolicyTree :: term()}} |
@@ -496,7 +492,7 @@ pkix_path_validation(TrustedCert, CertChain, Options) when
is_binary(TrustedCert) -> OtpCert = pkix_decode_cert(TrustedCert,
otp), pkix_path_validation(OtpCert, CertChain, Options);
-pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
+pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
when is_list(CertChain), is_list(Options) ->
MaxPathDefault = length(CertChain),
ValidationState = pubkey_cert:init_validation_state(TrustedCert,
@@ -505,6 +501,37 @@ pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
path_validation(CertChain, ValidationState).
%%--------------------------------------------------------------------
+-spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}].
+%%
+%% Description: Decodes a ssh file-binary. In the case of know_hosts
+%% or auth_keys the binary may include one or more lines of the
+%% file. Returns a list of public keys and their attributes, possible
+%% attribute values depends on the file type represented by the
+%% binary.
+%%--------------------------------------------------------------------
+ssh_decode(SshBin, Type) when is_binary(SshBin),
+ Type == public_key;
+ Type == rfc4716_public_key;
+ Type == openssh_public_key;
+ Type == auth_keys;
+ Type == known_hosts ->
+ pubkey_ssh:decode(SshBin, Type).
+
+%%--------------------------------------------------------------------
+-spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) ->
+ binary().
+%% Description: Encodes a list of ssh file entries (public keys and
+%% attributes) to a binary. Possible attributes depends on the file
+%% type.
+%%--------------------------------------------------------------------
+ssh_encode(Entries, Type) when is_list(Entries),
+ Type == rfc4716_public_key;
+ Type == openssh_public_key;
+ Type == auth_keys;
+ Type == known_hosts ->
+ pubkey_ssh:encode(Entries, Type).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -518,7 +545,6 @@ decrypt_public(CipherText, N,E, Options) ->
crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)],
Padding).
-
path_validation([], #path_validation_state{working_public_key_algorithm
= Algorithm,
working_public_key =
diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile
index e20b903942..6889ae9a8a 100644
--- a/lib/public_key/test/Makefile
+++ b/lib/public_key/test/Makefile
@@ -80,7 +80,7 @@ release_tests_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(COVER_FILE) $(HRL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 6c482f9c30..b11e4d092a 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -102,11 +102,23 @@ end_per_testcase(_TestCase, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app, pk_decode_encode, encrypt_decrypt, sign_verify,
+ [app,
+ {group, pem_decode_encode},
+ {group, ssh_public_key_decode_encode},
+ encrypt_decrypt,
+ {group, sign_verify},
pkix, pkix_path_validation, deprecated].
groups() ->
- [].
+ [{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem,
+ dh_pem, cert_pem]},
+ {ssh_public_key_decode_encode, [],
+ [ssh_rsa_public_key, ssh_dsa_public_key, ssh_rfc4716_rsa_comment,
+ ssh_rfc4716_dsa_comment, ssh_rfc4716_rsa_subject, ssh_known_hosts,
+ ssh_auth_keys, ssh1_known_hosts, ssh1_auth_keys, ssh_openssh_public_key_with_comment,
+ ssh_openssh_public_key_long_header]},
+ {sign_verify, [], [rsa_sign_verify, dsa_sign_verify]}
+ ].
init_per_group(_GroupName, Config) ->
Config.
@@ -125,22 +137,20 @@ app(suite) ->
app(Config) when is_list(Config) ->
ok = test_server:app_test(public_key).
-pk_decode_encode(doc) ->
- ["Tests pem_decode/1, pem_encode/1, "
- "der_decode/2, der_encode/2, "
- "pem_entry_decode/1, pem_entry_decode/2,"
- "pem_entry_encode/2, pem_entry_encode/3."];
+%%--------------------------------------------------------------------
-pk_decode_encode(suite) ->
+dsa_pem(doc) ->
+ [""];
+dsa_pem(suite) ->
[];
-pk_decode_encode(Config) when is_list(Config) ->
+dsa_pem(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
- [{'DSAPrivateKey', DerDSAKey, not_encrypted} = Entry0 ] =
- erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")),
-
+ [{'DSAPrivateKey', DerDSAKey, not_encrypted} = Entry0 ] =
+ erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")),
+
DSAKey = public_key:der_decode('DSAPrivateKey', DerDSAKey),
-
+
DSAKey = public_key:pem_entry_decode(Entry0),
{ok, DSAPubPem} = file:read_file(filename:join(Datadir, "dsa_pub.pem")),
@@ -150,74 +160,107 @@ pk_decode_encode(Config) when is_list(Config) ->
true = check_entry_type(DSAPubKey, 'DSAPublicKey'),
PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', DSAPubKey),
DSAPubPemNoEndNewLines = strip_ending_newlines(DSAPubPem),
- DSAPubPemEndNoNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])),
-
- [{'RSAPrivateKey', DerRSAKey, not_encrypted} = Entry1 ] =
+ DSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])).
+
+%%--------------------------------------------------------------------
+
+rsa_pem(doc) ->
+ [""];
+rsa_pem(suite) ->
+ [];
+rsa_pem(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+ [{'RSAPrivateKey', DerRSAKey, not_encrypted} = Entry0 ] =
erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")),
-
+
RSAKey0 = public_key:der_decode('RSAPrivateKey', DerRSAKey),
+
+ RSAKey0 = public_key:pem_entry_decode(Entry0),
- RSAKey0 = public_key:pem_entry_decode(Entry1),
-
- [{'RSAPrivateKey', _, {_,_}} = Entry2] =
+ [{'RSAPrivateKey', _, {_,_}} = Entry1] =
erl_make_certs:pem_to_der(filename:join(Datadir, "rsa.pem")),
-
- true = check_entry_type(public_key:pem_entry_decode(Entry2, "abcd1234"),
+
+ true = check_entry_type(public_key:pem_entry_decode(Entry1, "abcd1234"),
'RSAPrivateKey'),
{ok, RSAPubPem} = file:read_file(filename:join(Datadir, "rsa_pub.pem")),
- [{'SubjectPublicKeyInfo', _, _} = PubEntry1] =
+ [{'SubjectPublicKeyInfo', _, _} = PubEntry0] =
public_key:pem_decode(RSAPubPem),
- RSAPubKey = public_key:pem_entry_decode(PubEntry1),
+ RSAPubKey = public_key:pem_entry_decode(PubEntry0),
true = check_entry_type(RSAPubKey, 'RSAPublicKey'),
- PubEntry1 = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey),
+ PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey),
RSAPubPemNoEndNewLines = strip_ending_newlines(RSAPubPem),
- RSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry1])),
+ RSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])),
{ok, RSARawPem} = file:read_file(filename:join(Datadir, "rsa_pub_key.pem")),
- [{'RSAPublicKey', _, _} = PubEntry2] =
+ [{'RSAPublicKey', _, _} = PubEntry1] =
public_key:pem_decode(RSARawPem),
- RSAPubKey = public_key:pem_entry_decode(PubEntry2),
+ RSAPubKey = public_key:pem_entry_decode(PubEntry1),
RSARawPemNoEndNewLines = strip_ending_newlines(RSARawPem),
- RSARawPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry2])),
+ RSARawPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry1])).
+
+%%--------------------------------------------------------------------
+
+encrypted_pem(doc) ->
+ [""];
+encrypted_pem(suite) ->
+ [];
+encrypted_pem(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ [{'RSAPrivateKey', DerRSAKey, not_encrypted}] =
+ erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")),
+
+ RSAKey = public_key:der_decode('RSAPrivateKey', DerRSAKey),
Salt0 = crypto:rand_bytes(8),
- Entry3 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey0,
+ Entry0 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey,
{{"DES-EDE3-CBC", Salt0}, "1234abcd"}),
-
- RSAKey0 = public_key:pem_entry_decode(Entry3,"1234abcd"),
-
+ RSAKey = public_key:pem_entry_decode(Entry0,"1234abcd"),
Des3KeyFile = filename:join(Datadir, "des3_client_key.pem"),
+ erl_make_certs:der_to_pem(Des3KeyFile, [Entry0]),
+ [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] =
+ erl_make_certs:pem_to_der(Des3KeyFile),
- erl_make_certs:der_to_pem(Des3KeyFile, [Entry3]),
-
- [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] = erl_make_certs:pem_to_der(Des3KeyFile),
-
Salt1 = crypto:rand_bytes(8),
- Entry4 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey0,
+ Entry1 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey,
{{"DES-CBC", Salt1}, "4567efgh"}),
-
-
DesKeyFile = filename:join(Datadir, "des_client_key.pem"),
+ erl_make_certs:der_to_pem(DesKeyFile, [Entry1]),
+ [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry2] =
+ erl_make_certs:pem_to_der(DesKeyFile),
+ true = check_entry_type(public_key:pem_entry_decode(Entry2, "4567efgh"),
+ 'RSAPrivateKey').
- erl_make_certs:der_to_pem(DesKeyFile, [Entry4]),
-
- [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry5] = erl_make_certs:pem_to_der(DesKeyFile),
-
-
- true = check_entry_type(public_key:pem_entry_decode(Entry5, "4567efgh"),
- 'RSAPrivateKey'),
+%%--------------------------------------------------------------------
- [{'DHParameter', DerDH, not_encrypted} = Entry6] =
+dh_pem(doc) ->
+ [""];
+dh_pem(suite) ->
+ [];
+dh_pem(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+ [{'DHParameter', DerDH, not_encrypted} = Entry] =
erl_make_certs:pem_to_der(filename:join(Datadir, "dh.pem")),
-
- erl_make_certs:der_to_pem(filename:join(Datadir, "new_dh.pem"), [Entry6]),
+
+ erl_make_certs:der_to_pem(filename:join(Datadir, "new_dh.pem"), [Entry]),
DHParameter = public_key:der_decode('DHParameter', DerDH),
- DHParameter = public_key:pem_entry_decode(Entry6),
+ DHParameter = public_key:pem_entry_decode(Entry),
- Entry6 = public_key:pem_entry_encode('DHParameter', DHParameter),
+ Entry = public_key:pem_entry_encode('DHParameter', DHParameter).
+%%--------------------------------------------------------------------
+cert_pem(doc) ->
+ [""];
+cert_pem(suite) ->
+ [];
+cert_pem(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ [Entry0] =
+ erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")),
+
[{'Certificate', DerCert, not_encrypted} = Entry7] =
erl_make_certs:pem_to_der(filename:join(Datadir, "client_cert.pem")),
@@ -227,15 +270,232 @@ pk_decode_encode(Config) when is_list(Config) ->
CertEntries = [{'Certificate', _, not_encrypted} = CertEntry0,
{'Certificate', _, not_encrypted} = CertEntry1] =
erl_make_certs:pem_to_der(filename:join(Datadir, "cacerts.pem")),
-
+
ok = erl_make_certs:der_to_pem(filename:join(Datadir, "wcacerts.pem"), CertEntries),
ok = erl_make_certs:der_to_pem(filename:join(Datadir, "wdsa.pem"), [Entry0]),
NewCertEntries = erl_make_certs:pem_to_der(filename:join(Datadir, "wcacerts.pem")),
true = lists:member(CertEntry0, NewCertEntries),
true = lists:member(CertEntry1, NewCertEntries),
- [Entry0] = erl_make_certs:pem_to_der(filename:join(Datadir, "wdsa.pem")),
- ok.
+ [Entry0] = erl_make_certs:pem_to_der(filename:join(Datadir, "wdsa.pem")).
+
+%%--------------------------------------------------------------------
+ssh_rsa_public_key(doc) ->
+ "";
+ssh_rsa_public_key(suite) ->
+ [];
+ssh_rsa_public_key(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_pub")),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, public_key),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, rfc4716_public_key),
+
+ {ok, RSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_rsa_pub")),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, public_key),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, openssh_public_key),
+
+ %% Can not check EncodedSSh == RSARawSsh2 and EncodedOpenSsh
+ %% = RSARawOpenSsh as line breakpoints may differ
+
+ EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
+ EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
+
+ [{PubKey, Attributes1}] =
+ public_key:ssh_decode(EncodedSSh, public_key),
+ [{PubKey, Attributes2}] =
+ public_key:ssh_decode(EncodedOpenSsh, public_key).
+
+%%--------------------------------------------------------------------
+
+ssh_dsa_public_key(doc) ->
+ "";
+ssh_dsa_public_key(suite) ->
+ [];
+ssh_dsa_public_key(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_pub")),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, public_key),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, rfc4716_public_key),
+
+ {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_pub")),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, public_key),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key),
+
+ %% Can not check EncodedSSh == DSARawSsh2 and EncodedOpenSsh
+ %% = DSARawOpenSsh as line breakpoints may differ
+
+ EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
+ EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
+
+ [{PubKey, Attributes1}] =
+ public_key:ssh_decode(EncodedSSh, public_key),
+ [{PubKey, Attributes2}] =
+ public_key:ssh_decode(EncodedOpenSsh, public_key).
+
+%%--------------------------------------------------------------------
+ssh_rfc4716_rsa_comment(doc) ->
+ "Test comment header and rsa key";
+ssh_rfc4716_rsa_comment(suite) ->
+ [];
+ssh_rfc4716_rsa_comment(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_comment_pub")),
+ [{#'RSAPublicKey'{} = PubKey, Attributes}] =
+ public_key:ssh_decode(RSARawSsh2, public_key),
+
+ Headers = proplists:get_value(headers, Attributes),
+
+ Value = proplists:get_value("Comment", Headers, undefined),
+ true = Value =/= undefined,
+ RSARawSsh2 = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key).
+
+%%--------------------------------------------------------------------
+ssh_rfc4716_dsa_comment(doc) ->
+ "Test comment header and dsa key";
+ssh_rfc4716_dsa_comment(suite) ->
+ [];
+ssh_rfc4716_dsa_comment(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_comment_pub")),
+ [{{_, #'Dss-Parms'{}} = PubKey, Attributes}] =
+ public_key:ssh_decode(DSARawSsh2, public_key),
+
+ Headers = proplists:get_value(headers, Attributes),
+
+ Value = proplists:get_value("Comment", Headers, undefined),
+ true = Value =/= undefined,
+
+ %% Can not check Encoded == DSARawSsh2 as line continuation breakpoints may differ
+ Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key),
+ [{PubKey, Attributes}] =
+ public_key:ssh_decode(Encoded, public_key).
+
+%%--------------------------------------------------------------------
+ssh_rfc4716_rsa_subject(doc) ->
+ "Test another header value than comment";
+ssh_rfc4716_rsa_subject(suite) ->
+ [];
+ssh_rfc4716_rsa_subject(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_subject_pub")),
+ [{#'RSAPublicKey'{} = PubKey, Attributes}] =
+ public_key:ssh_decode(RSARawSsh2, public_key),
+
+ Headers = proplists:get_value(headers, Attributes),
+
+ Value = proplists:get_value("Subject", Headers, undefined),
+ true = Value =/= undefined,
+
+ %% Can not check Encoded == RSARawSsh2 as line continuation breakpoints may differ
+ Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key),
+ [{PubKey, Attributes}] =
+ public_key:ssh_decode(Encoded, public_key).
+
+%%--------------------------------------------------------------------
+ssh_known_hosts(doc) ->
+ "";
+ssh_known_hosts(suite) ->
+ [];
+ssh_known_hosts(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "known_hosts")),
+ [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded =
+ public_key:ssh_decode(SshKnownHosts, known_hosts),
+
+ Value1 = proplists:get_value(hostnames, Attributes1, undefined),
+ Value2 = proplists:get_value(hostnames, Attributes2, undefined),
+ true = (Value1 =/= undefined) and (Value2 =/= undefined),
+
+ Encoded = public_key:ssh_encode(Decoded, known_hosts),
+ Decoded = public_key:ssh_decode(Encoded, known_hosts).
+
+%%--------------------------------------------------------------------
+
+ssh1_known_hosts(doc) ->
+ "";
+ssh1_known_hosts(suite) ->
+ [];
+ssh1_known_hosts(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "ssh1_known_hosts")),
+ [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded =
+ public_key:ssh_decode(SshKnownHosts, known_hosts),
+
+ Value1 = proplists:get_value(hostnames, Attributes1, undefined),
+ Value2 = proplists:get_value(hostnames, Attributes2, undefined),
+ true = (Value1 =/= undefined) and (Value2 =/= undefined),
+
+ Encoded = public_key:ssh_encode(Decoded, known_hosts),
+ Decoded = public_key:ssh_decode(Encoded, known_hosts).
+
+%%--------------------------------------------------------------------
+ssh_auth_keys(doc) ->
+ "";
+ssh_auth_keys(suite) ->
+ [];
+ssh_auth_keys(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "auth_keys")),
+ [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, _Attributes2}] = Decoded =
+ public_key:ssh_decode(SshAuthKeys, auth_keys),
+
+ Value1 = proplists:get_value(options, Attributes1, undefined),
+ true = Value1 =/= undefined,
+
+ Encoded = public_key:ssh_encode(Decoded, auth_keys),
+ Decoded = public_key:ssh_decode(Encoded, auth_keys).
+
+%%--------------------------------------------------------------------
+ssh1_auth_keys(doc) ->
+ "";
+ssh1_auth_keys(suite) ->
+ [];
+ssh1_auth_keys(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "ssh1_auth_keys")),
+ [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded =
+ public_key:ssh_decode(SshAuthKeys, auth_keys),
+
+ Value1 = proplists:get_value(bits, Attributes1, undefined),
+ Value2 = proplists:get_value(bits, Attributes2, undefined),
+ true = (Value1 =/= undefined) and (Value2 =/= undefined),
+
+ Encoded = public_key:ssh_encode(Decoded, auth_keys),
+ Decoded = public_key:ssh_decode(Encoded, auth_keys).
+
+%%--------------------------------------------------------------------
+ssh_openssh_public_key_with_comment(doc) ->
+ "Test that emty lines and lines starting with # are ignored";
+ssh_openssh_public_key_with_comment(suite) ->
+ [];
+ssh_openssh_public_key_with_comment(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_with_comment_pub")),
+ [{{_, #'Dss-Parms'{}}, _}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key).
+
+%%--------------------------------------------------------------------
+ssh_openssh_public_key_long_header(doc) ->
+ "Test that long headers are handled";
+ssh_openssh_public_key_long_header(suite) ->
+ [];
+ssh_openssh_public_key_long_header(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+
+ {ok,RSARawOpenSsh} = file:read_file(filename:join(Datadir, "ssh_rsa_long_header_pub")),
+ [{#'RSAPublicKey'{}, _}] = Decoded = public_key:ssh_decode(RSARawOpenSsh, public_key),
+
+ Encoded = public_key:ssh_encode(Decoded, rfc4716_public_key),
+ Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key).
%%--------------------------------------------------------------------
encrypt_decrypt(doc) ->
@@ -258,44 +518,49 @@ encrypt_decrypt(Config) when is_list(Config) ->
ok.
%%--------------------------------------------------------------------
-sign_verify(doc) ->
- ["Checks that we can sign and verify signatures."];
-sign_verify(suite) ->
+rsa_sign_verify(doc) ->
+ ["Checks that we can sign and verify rsa signatures."];
+rsa_sign_verify(suite) ->
[];
-sign_verify(Config) when is_list(Config) ->
- %% Make cert signs and validates the signature using RSA and DSA
+rsa_sign_verify(Config) when is_list(Config) ->
Ca = {_, CaKey} = erl_make_certs:make_cert([]),
+ {Cert1, _} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]),
PrivateRSA = #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} =
public_key:pem_entry_decode(CaKey),
-
- CertInfo = {Cert1,CertKey1} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]),
-
PublicRSA = #'RSAPublicKey'{modulus=Mod, publicExponent=Exp},
true = public_key:pkix_verify(Cert1, PublicRSA),
- {Cert2,_CertKey} = erl_make_certs:make_cert([{issuer, CertInfo}]),
-
- #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X} =
- public_key:pem_entry_decode(CertKey1),
- true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}),
-
- %% RSA sign
Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")),
-
RSASign = public_key:sign(Msg, sha, PrivateRSA),
true = public_key:verify(Msg, sha, RSASign, PublicRSA),
false = public_key:verify(<<1:8, Msg/binary>>, sha, RSASign, PublicRSA),
false = public_key:verify(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA),
RSASign1 = public_key:sign(Msg, md5, PrivateRSA),
- true = public_key:verify(Msg, md5, RSASign1, PublicRSA),
+ true = public_key:verify(Msg, md5, RSASign1, PublicRSA).
- %% DSA sign
+%%--------------------------------------------------------------------
+
+dsa_sign_verify(doc) ->
+ ["Checks that we can sign and verify dsa signatures."];
+dsa_sign_verify(suite) ->
+ [];
+dsa_sign_verify(Config) when is_list(Config) ->
+ Ca = erl_make_certs:make_cert([]),
+ CertInfo = {_,CertKey1} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]),
+ {Cert2,_CertKey} = erl_make_certs:make_cert([{issuer, CertInfo}]),
+
+ #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X} =
+ public_key:pem_entry_decode(CertKey1),
+ true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}),
+
Datadir = ?config(data_dir, Config),
[DsaKey = {'DSAPrivateKey', _, _}] =
erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")),
DSAPrivateKey = public_key:pem_entry_decode(DsaKey),
#'DSAPrivateKey'{p=P1, q=Q1, g=G1, y=Y1, x=_X1} = DSAPrivateKey,
+
+ Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")),
DSASign = public_key:sign(Msg, sha, DSAPrivateKey),
DSAPublicKey = Y1,
DSAParams = #'Dss-Parms'{p=P1, q=Q1, g=G1},
@@ -312,9 +577,8 @@ sign_verify(Config) when is_list(Config) ->
false = public_key:verify(<<1:8, RestDigest/binary>>, none, DigestSign,
{DSAPublicKey, DSAParams}),
false = public_key:verify(Digest, none, <<1:8, DigestSign/binary>>,
- {DSAPublicKey, DSAParams}),
-
- ok.
+ {DSAPublicKey, DSAParams}).
+
%%--------------------------------------------------------------------
pkix(doc) ->
"Misc pkix tests not covered elsewhere";
diff --git a/lib/public_key/test/public_key_SUITE_data/auth_keys b/lib/public_key/test/public_key_SUITE_data/auth_keys
new file mode 100644
index 0000000000..0c4b47edde
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/auth_keys
@@ -0,0 +1,3 @@
+command="dump /home",no-pty,no-port-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH
+
+ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH
diff --git a/lib/public_key/test/public_key_SUITE_data/known_hosts b/lib/public_key/test/public_key_SUITE_data/known_hosts
new file mode 100644
index 0000000000..30fc3b1fe8
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/known_hosts
@@ -0,0 +1,3 @@
+hostname.domain.com,192.168.0.1 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM=
+
+|1|BWO5qDxk/cFH0wa05JLdHn+j6xQ=|rXQvIxh5cDD3C43k5DPDamawVNA= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= [email protected]
diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub b/lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub
new file mode 100644
index 0000000000..a765ba8189
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH
diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub b/lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub
new file mode 100644
index 0000000000..d5a34a3f78
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub
@@ -0,0 +1,3 @@
+#This should be ignored!!
+
+ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH
diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub b/lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub
new file mode 100644
index 0000000000..0a0838db40
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys b/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys
new file mode 100644
index 0000000000..c91f4e4679
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys
@@ -0,0 +1,3 @@
+1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH
+
+command="dump /home",no-pty,no-port-forwarding 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts b/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts
new file mode 100644
index 0000000000..ec668fe05b
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts
@@ -0,0 +1,2 @@
+hostname.domain.com,192.168.0.1 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH
+hostname2.domain.com,192.168.0.2 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub
new file mode 100644
index 0000000000..ca5089dbd7
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub
@@ -0,0 +1,13 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+Comment: This is my public key for use on \
+servers which I don't like.
+AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbET
+W6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdH
+YI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5c
+vwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGf
+J0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAA
+vioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACB
+AN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HS
+n24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5
+sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub
new file mode 100644
index 0000000000..a5e38be81a
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub
@@ -0,0 +1,12 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+Comment: DSA Public Key for use with MyIsp
+AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbET
+W6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdH
+YI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5c
+vwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGf
+J0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAA
+vioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACB
+AN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HS
+n24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5
+sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub
new file mode 100644
index 0000000000..e4d446147c
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub
@@ -0,0 +1,7 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+Comment: "1024-bit RSA, converted from OpenSSH by [email protected]"
+x-command: /home/me/bin/lock-in-guest.sh
+AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb
+YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ
+5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE=
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub
new file mode 100644
index 0000000000..761088b517
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub
@@ -0,0 +1,13 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o
+39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS
+7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmt
+isaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2
+sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRu
+LDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368
++dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNW
+jeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4f
+uKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV22
+5JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRM
+IB+X+OTUUI8=
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub
new file mode 100644
index 0000000000..8b8ccda8ba
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub
@@ -0,0 +1,8 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+Subject: me
+Comment: 1024-bit rsa, created by [email protected] Mon Jan 15 \
+08:31:24 2001
+AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4
+596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4
+soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub b/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub
new file mode 100644
index 0000000000..7b42ced93e
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub
@@ -0,0 +1,9 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+Comment: This is an example of a very very very very looooooooooooo\
+ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\
+commment
+x-command: /home/me/bin/lock-in-guest.sh
+AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb
+YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ
+5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE=
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub b/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub
new file mode 100644
index 0000000000..7b42ced93e
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub
@@ -0,0 +1,9 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+Comment: This is an example of a very very very very looooooooooooo\
+ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\
+commment
+x-command: /home/me/bin/lock-in-guest.sh
+AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb
+YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ
+5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE=
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index d7cad8b29e..9743289ca6 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -1318,7 +1318,7 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) ->
Val =:= none;
Val =:= undefined ->
{Sys#sys{embedded_app_type = Val}, Status};
- app_file when Val =:= keep; Val =:= strip, Val =:= all ->
+ app_file when Val =:= keep; Val =:= strip; Val =:= all ->
{Sys#sys{app_file = Val}, Status};
debug_info when Val =:= keep; Val =:= strip ->
{Sys#sys{debug_info = Val}, Status};
diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile
index abd2e81cdf..62fe05238b 100644
--- a/lib/reltool/test/Makefile
+++ b/lib/reltool/test/Makefile
@@ -76,7 +76,7 @@ release_tests_spec: opt
$(INSTALL_DATA) reltool.spec reltool.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
$(INSTALL_SCRIPT) rtt $(INSTALL_PROGS) $(RELSYSDIR)
$(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR)
-# chmod -f -R u+w $(RELSYSDIR)
+# chmod -R u+w $(RELSYSDIR)
# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/reltool/test/reltool_app_SUITE.erl b/lib/reltool/test/reltool_app_SUITE.erl
index 97076589ba..a6e00cde08 100644
--- a/lib/reltool/test/reltool_app_SUITE.erl
+++ b/lib/reltool/test/reltool_app_SUITE.erl
@@ -45,15 +45,16 @@ init_per_suite(Config) ->
end_per_suite(Config) ->
reltool_test_lib:end_per_suite(Config).
+init_per_testcase(undef_funcs=Case, Config) ->
+ case test_server:is_debug() of
+ true ->
+ {skip,"Debug-compiled emulator -- far too slow"};
+ false ->
+ Config2 = [{tc_timeout, timer:minutes(10)} | Config],
+ reltool_test_lib:init_per_testcase(Case, Config2)
+ end;
init_per_testcase(Case, Config) ->
- Config2 =
- case Case of
- undef_funcs ->
- [{tc_timeout, timer:minutes(10)} | Config];
- _ ->
- Config
- end,
- reltool_test_lib:init_per_testcase(Case, Config2).
+ reltool_test_lib:init_per_testcase(Case, Config).
end_per_testcase(Func,Config) ->
reltool_test_lib:end_per_testcase(Func,Config).
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index ef3076f305..b77560db94 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -52,7 +52,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[start_server, set_config, create_release,
create_script, create_target, create_embedded,
- create_standalone, create_old_target].
+ create_standalone, create_old_target,
+ otp_9135].
groups() ->
[].
@@ -110,6 +111,37 @@ set_config(_Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% OTP-9135, test that app_file option can be set to all | keep | strip
+
+otp_9135(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+otp_9135(_Config) ->
+ Libs = lists:sort(erl_libs()),
+ StrippedDefaultSys =
+ case Libs of
+ [] -> [];
+ _ -> {lib_dirs, Libs}
+ end,
+
+ Config1 = {sys,[{app_file, keep}]}, % this is the default
+ {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, Config1}])),
+ ?m({ok, {sys,StrippedDefaultSys}}, reltool:get_config(Pid1)),
+ ?m(ok, reltool:stop(Pid1)),
+
+ Config2 = {sys,[{app_file, strip}]},
+ {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, Config2}])),
+ ExpectedConfig2 = StrippedDefaultSys++[{app_file,strip}],
+ ?m({ok, {sys,ExpectedConfig2}}, reltool:get_config(Pid2)),
+ ?m(ok, reltool:stop(Pid2)),
+
+ Config3 = {sys,[{app_file, all}]},
+ {ok, Pid3} = ?msym({ok, _}, reltool:start_server([{config, Config3}])),
+ ExpectedConfig3 = StrippedDefaultSys++[{app_file,all}],
+ ?m({ok, {sys,ExpectedConfig3}}, reltool:get_config(Pid3)),
+ ?m(ok, reltool:stop(Pid3)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate releases
create_release(TestInfo) when is_atom(TestInfo) ->
diff --git a/lib/runtime_tools/test/Makefile b/lib/runtime_tools/test/Makefile
index 7dc7a015e1..cfaf420d65 100644
--- a/lib/runtime_tools/test/Makefile
+++ b/lib/runtime_tools/test/Makefile
@@ -59,7 +59,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) runtime_tools.spec runtime_tools.cover $(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(EMAKEFILE) runtime_tools.cover $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml
index e28cd25f27..883c9c372b 100644
--- a/lib/sasl/doc/src/systools.xml
+++ b/lib/sasl/doc/src/systools.xml
@@ -130,7 +130,7 @@
<fsummary>Generate a boot script <c>.script/.boot</c>.</fsummary>
<type>
<v>Name = string()</v>
- <v>Opt = no_module_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] | silent | {outdir,Dir}</v>
+ <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] | silent | {outdir,Dir}</v>
<v>&nbsp;Dir = string()</v>
<v>&nbsp;Var = {VarName,Prefix}</v>
<v>&nbsp;&nbsp;VarName = Prefix = string()</v>
@@ -174,15 +174,13 @@
the applications.</p>
</item>
<item>
- <p>There should no duplicated modules, that is, modules with
+ <p>There should be no duplicated modules, that is, modules with
the same name but belonging to different applications.</p>
</item>
<item>
- <p>A warning is issued if the source code for a module is
- missing or newer than the object code. <br></br>
-
- If the <c>no_module_tests</c> option is specified, this
- check is omitted.</p>
+ <p>If the <c>src_tests</c> option is specified, a
+ warning is issued if the source code for a module is
+ missing or newer than the object code.</p>
</item>
</list>
<p>The applications are sorted according to the dependencies
@@ -242,7 +240,7 @@
<fsummary>Create a release package.</fsummary>
<type>
<v>Name = string()</v>
- <v>Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | no_module_tests | exref | {exref,[App]} | silent | {outdir,Dir}</v>
+ <v>Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | src_tests | exref | {exref,[App]} | silent | {outdir,Dir}</v>
<v>&nbsp;Dir = string()</v>
<v>&nbsp;IncDir = src | include | atom()</v>
<v>&nbsp;Var = {VarName,PreFix}</v>
@@ -330,7 +328,7 @@ myapp-1/ebin/myapp.app
system <c>{erts,Dir}</c> is copied to <c>erts-ErtsVsn/bin</c>.</p>
<p>All checks performed with the <c>make_script</c> function
are performed before the release package is created. The
- <c>no_module_tests</c> and <c>exref</c> options are also
+ <c>src_tests</c> and <c>exref</c> options are also
valid here.</p>
<p>The return value and the handling of errors and warnings
are the same as described for <c>make_script</c> above.</p>
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index 4c43277848..b60aa847df 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -791,7 +791,7 @@ check_rel(Root, RelFile, Masters) ->
check_rel(Root, RelFile, LibDirs, Masters) ->
case consult(RelFile, Masters) of
{ok, [RelData]} ->
- check_rel_data(RelData, Root, LibDirs);
+ check_rel_data(RelData, Root, LibDirs, Masters);
{ok, _} ->
throw({error, {bad_rel_file, RelFile}});
{error, Reason} when is_tuple(Reason) ->
@@ -800,7 +800,8 @@ check_rel(Root, RelFile, LibDirs, Masters) ->
throw({error, {FileError, RelFile}})
end.
-check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs) ->
+check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs,
+ Masters) ->
Libs2 =
lists:map(fun(LibSpec) ->
Lib = element(1, LibSpec),
@@ -810,7 +811,7 @@ check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs) ->
case lists:keysearch(Lib, 1, LibDirs) of
{value, {_Lib, _Vsn, Dir}} ->
Path = filename:join(Dir,LibName),
- check_path(Path),
+ check_path(Path, Masters),
Path;
_ ->
filename:join([Root, "lib", LibName])
@@ -820,19 +821,34 @@ check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs) ->
Libs),
#release{name = Name, vsn = Vsn, erts_vsn = EVsn,
libs = Libs2, status = unpacking};
-check_rel_data(RelData, _Root, _LibDirs) ->
+check_rel_data(RelData, _Root, _LibDirs, _Masters) ->
throw({error, {bad_rel_data, RelData}}).
check_path(Path) ->
- case file:read_file_info(Path) of
- {ok, Info} when Info#file_info.type==directory ->
- ok;
- {ok, _Info} ->
- throw({error, {not_a_directory, Path}});
- {error, _Reason} ->
- throw({error, {no_such_directory, Path}})
- end.
-
+ check_path_response(Path, file:read_file_info(Path)).
+check_path(Path, false) -> check_path(Path);
+check_path(Path, Masters) -> check_path_master(Masters, Path).
+
+%%-----------------------------------------------------------------
+%% check_path at any master node.
+%% If the path does not exist or is not a directory
+%% at one node it should not exist at any other node either.
+%%-----------------------------------------------------------------
+check_path_master([Master|Ms], Path) ->
+ case rpc:call(Master, file, read_file_info, [Path]) of
+ {badrpc, _} -> consult_master(Ms, Path);
+ Res -> check_path_response(Path, Res)
+ end;
+check_path_master([], _Path) ->
+ {error, no_master}.
+
+check_path_response(_Path, {ok, Info}) when Info#file_info.type==directory ->
+ ok;
+check_path_response(Path, {ok, _Info}) ->
+ throw({error, {not_a_directory, Path}});
+check_path_response(Path, {error, _Reason}) ->
+ throw({error, {no_such_directory, Path}}).
+
do_check_install_release(RelDir, Vsn, Releases, Masters) ->
case lists:keysearch(Vsn, #release.vsn, Releases) of
{value, #release{status = current}} ->
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index 9c0edf4e99..8d050fb7b0 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.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
@@ -20,7 +20,7 @@
%% External exports
-export([eval_script/3, eval_script/4, check_script/2]).
--export([get_vsn/1]). %% exported because used in a test case
+-export([get_current_vsn/1]). %% exported because used in a test case
-record(eval_state, {bins = [], stopped = [], suspended = [], apps = [],
libdirs, unpurged = [], vsns = [], newlibs = [],
@@ -223,7 +223,7 @@ eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) ->
FName = filename:join(Ebin, File),
case erl_prim_loader:get_file(FName) of
{ok, Bin, FName2} ->
- NVsns = add_new_vsn(Mod, FName2, Vsns),
+ NVsns = add_new_vsn(Mod, Bin, Vsns),
{[{Mod, Bin, FName2} | Bins],NVsns};
error ->
throw({error, {no_such_file,FName}})
@@ -609,17 +609,17 @@ sync_nodes(Id, Nodes) ->
add_old_vsn(Mod, Vsns) ->
case lists:keysearch(Mod, 1, Vsns) of
{value, {Mod, undefined, NewVsn}} ->
- OldVsn = get_vsn(code:which(Mod)),
+ OldVsn = get_current_vsn(Mod),
lists:keyreplace(Mod, 1, Vsns, {Mod, OldVsn, NewVsn});
{value, {Mod, _OldVsn, _NewVsn}} ->
Vsns;
false ->
- OldVsn = get_vsn(code:which(Mod)),
+ OldVsn = get_current_vsn(Mod),
[{Mod, OldVsn, undefined} | Vsns]
end.
-add_new_vsn(Mod, File, Vsns) ->
- NewVsn = get_vsn(File),
+add_new_vsn(Mod, Bin, Vsns) ->
+ NewVsn = get_vsn(Bin),
case lists:keysearch(Mod, 1, Vsns) of
{value, {Mod, OldVsn, undefined}} ->
lists:keyreplace(Mod, 1, Vsns, {Mod, OldVsn, NewVsn});
@@ -627,17 +627,35 @@ add_new_vsn(Mod, File, Vsns) ->
[{Mod, undefined, NewVsn} | Vsns]
end.
-
+%%-----------------------------------------------------------------
+%% Func: get_current_vsn/1
+%% Args: Mod = atom()
+%% Purpose: This function returns the equivalent of
+%% beam_lib:version(code:which(Mod)), but it will also handle the
+%% case when using erl_prim_loader loader different from 'efile'.
+%% The reason for not using the Binary from the 'bins' or the
+%% version directly from the 'vsns' state field is that these are
+%% updated already by load_object_code, and this function is called
+%% from load and remove.
+%% Returns: Vsn = term()
+%%-----------------------------------------------------------------
+get_current_vsn(Mod) ->
+ File = code:which(Mod),
+ case erl_prim_loader:get_file(File) of
+ {ok, Bin, _File2} ->
+ get_vsn(Bin);
+ error ->
+ throw({error, {no_such_file, File}})
+ end.
%%-----------------------------------------------------------------
%% Func: get_vsn/1
-%% Args: File = string()
+%% Args: Bin = binary()
%% Purpose: Finds the version attribute of a module.
-%% Returns: Vsn
-%% Vsn = term()
+%% Returns: Vsn = term()
%%-----------------------------------------------------------------
-get_vsn(File) ->
- {ok, {_Mod, Vsn}} = beam_lib:version(File),
+get_vsn(Bin) ->
+ {ok, {_Mod, Vsn}} = beam_lib:version(Bin),
case misc_supp:is_string(Vsn) of
true ->
Vsn;
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 20a142c763..7489ee58d2 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,7 +50,7 @@
%% the applications are found.
%%
%% New options: {path,Path} can contain wildcards
-%% no_module_tests
+%% src_tests
%% {variables,[{Name,AbsString}]}
%% {machine, jam | beam | vee}
%% exref | {exref, [AppName]}
@@ -82,8 +82,7 @@ make_script(RelName, Output, Flags) when is_list(RelName),
Path0 = get_path(Flags),
Path1 = mk_path(Path0), % expand wildcards etc.
Path = make_set(Path1 ++ code:get_path()),
- ModTestP = {not member(no_module_tests, Flags),
- xref_p(Flags)},
+ ModTestP = {member(src_tests, Flags),xref_p(Flags)},
case get_release(RelName, Path, ModTestP, machine(Flags)) of
{ok, Release, Appls, Warnings} ->
case generate_script(Output,Release,Appls,Flags) of
@@ -155,7 +154,7 @@ return({error,Mod,Error},_,Flags) ->
%% should be included in the release package and there it can be found.
%%
%% New options: {path,Path} can contain wildcards
-%% no_module_tests
+%% src_tests
%% exref | {exref, [AppName]}
%% {variables,[{Name,AbsString}]}
%% {machine, jam | beam | vee}
@@ -190,8 +189,7 @@ make_tar(RelName, Flags) when is_list(RelName), is_list(Flags) ->
Path0 = get_path(Flags),
Path1 = mk_path(Path0),
Path = make_set(Path1 ++ code:get_path()),
- ModTestP = {not member(no_module_tests, Flags),
- xref_p(Flags)},
+ ModTestP = {member(src_tests, Flags),xref_p(Flags)},
case get_release(RelName, Path, ModTestP, machine(Flags)) of
{ok, Release, Appls, Warnings} ->
case catch mk_tar(RelName, Release, Appls, Flags, Path1) of
@@ -218,7 +216,7 @@ make_tar(RelName, Flags) ->
%% {ok, #release, [{{Name,Vsn},#application}], Warnings} | {error, What}
get_release(File, Path) ->
- get_release(File, Path, true, false).
+ get_release(File, Path, {false,false}, false).
get_release(File, Path, ModTestP) ->
get_release(File, Path, ModTestP, false).
@@ -771,36 +769,40 @@ get_mod_vsn([]) ->
%% Use the module extension of the running machine as extension for
%% the checked modules.
-check_mods(Modules, Appls, Path, {true, XrefP}, Machine) ->
- Ext = objfile_extension(Machine),
- IncPath = create_include_path(Appls, Path),
- Res = append(map(fun(ModT) ->
- {Mod,_Vsn,App,_,Dir} = ModT,
- case check_mod(Mod,App,Dir,Ext,IncPath) of
- ok ->
- [];
- {error, Error} ->
- [{error,{Error, ModT}}];
- {warning, Warn} ->
- [{warning,{Warn,ModT}}]
- end
- end,
- Modules)),
- Res2 = Res ++ check_xref(Appls, Path, XrefP),
+check_mods(Modules, Appls, Path, {SrcTestP, XrefP}, Machine) ->
+ SrcTestRes = check_src(Modules, Appls, Path, SrcTestP, Machine),
+ XrefRes = check_xref(Appls, Path, XrefP),
+ Res = SrcTestRes ++ XrefRes,
case filter(fun({error, _}) -> true;
(_) -> false
end,
- Res2) of
+ Res) of
[] ->
{ok, filter(fun({warning, _}) -> true;
(_) -> false
end,
- Res2)};
+ Res)};
Errors ->
{error, Errors}
- end;
-check_mods(_, _, _, _, _) ->
- {ok, []}.
+ end.
+
+check_src(Modules, Appls, Path, true, Machine) ->
+ Ext = objfile_extension(Machine),
+ IncPath = create_include_path(Appls, Path),
+ append(map(fun(ModT) ->
+ {Mod,_Vsn,App,_,Dir} = ModT,
+ case check_mod(Mod,App,Dir,Ext,IncPath) of
+ ok ->
+ [];
+ {error, Error} ->
+ [{error,{Error, ModT}}];
+ {warning, Warn} ->
+ [{warning,{Warn,ModT}}]
+ end
+ end,
+ Modules));
+check_src(_, _, _, _, _) ->
+ [].
check_xref(_Appls, _Path, false) ->
[];
@@ -1853,11 +1855,11 @@ cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach,
cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach,
Xref, XrefApps, X}) ->
cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps, X});
-%%% no_module_tests ----------------------------------------------------
-cas([no_module_tests | Args], {Path, Sil, Loc, _Test, Var, Mach,
- Xref, XrefApps, X}) ->
+%%% src_tests -------------------------------------------------------
+cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach,
+ Xref, XrefApps, X}) ->
cas(Args,
- {Path, Sil, Loc, no_module_tests, Var, Mach, Xref, XrefApps,X});
+ {Path, Sil, Loc, src_tests, Var, Mach, Xref, XrefApps,X});
%%% variables ----------------------------------------------------------
cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach,
Xref, XrefApps, X}) when is_list(V) ->
@@ -1896,6 +1898,10 @@ cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach,
cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach,
Xref, XrefApps, X}) ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X});
+%%% no_module_tests (kept for backwards compatibility, but ignored) ----
+cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach,
+ Xref, XrefApps, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X});
%%% ERROR --------------------------------------------------------------
cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X}) ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X++[Y]}).
@@ -1935,10 +1941,10 @@ cat([{dirs, D} | Args], {Path, Sil, Dirs, Erts, Test,
cat([{erts, E} | Args], {Path, Sil, Dirs, _Erts, Test,
Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(E)->
cat(Args, {Path, Sil, Dirs, E, Test, Var, VarTar, Mach, Xref, XrefApps, X});
-%%% no_module_tests ----------------------------------------------------
-cat([no_module_tests | Args], {Path, Sil, Dirs, Erts, _Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
- cat(Args, {Path, Sil, Dirs, Erts, no_module_tests, Var, VarTar, Mach,
- Xref, XrefApps, X});
+%%% src_tests ----------------------------------------------------
+cat([src_tests | Args], {Path, Sil, Dirs, Erts, _Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
+ cat(Args, {Path, Sil, Dirs, Erts, src_tests, Var, VarTar, Mach,
+ Xref, XrefApps, X});
%%% variables ----------------------------------------------------------
cat([{variables, V} | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(V) ->
case check_vars(V) of
@@ -1982,6 +1988,9 @@ cat([{outdir, Dir} | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xre
%%% otp_build (secret, not documented) ---------------------------------
cat([otp_build | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+%%% no_module_tests (kept for backwards compatibility, but ignored) ----
+cat([no_module_tests | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
+ cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
%%% ERROR --------------------------------------------------------------
cat([Y | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X++[Y]}).
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl
index 6b0f77703e..ec5486226c 100644
--- a/lib/sasl/src/systools_relup.erl
+++ b/lib/sasl/src/systools_relup.erl
@@ -179,8 +179,7 @@ check_opts([]) ->
[].
do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) ->
- ModTest = false,
- case systools_make:get_release(to_list(TopRelFile), Path, ModTest) of
+ case systools_make:get_release(to_list(TopRelFile), Path) of
%%
%% TopRel = #release
%% NameVsnApps = [{{Name, Vsn}, #application}]
@@ -246,9 +245,8 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts,
{RUs4, Ws4} =
check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts),
- ModTest = false,
BaseApps =
- case systools_make:get_release(BaseRelFile, Path, ModTest) of
+ case systools_make:get_release(BaseRelFile, Path) of
{ok, _, NameVsnApps, _Warns} ->
lists:map(fun({_,App}) -> App end, NameVsnApps);
Other1 ->
@@ -283,9 +281,8 @@ foreach_baserel_dn(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts,
%%
{RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws, []),
- ModTest = false,
{BaseApps, Ws2} =
- case systools_make:get_release(BaseRelFile, Path, ModTest) of
+ case systools_make:get_release(BaseRelFile, Path) of
%%
%% NameVsnApps = [{{Name, Vsn}, #application}]
{ok, _, NameVsnApps, Warns} ->
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index 86af2460f5..b7975024b4 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -227,7 +227,7 @@ release_spec:
release_tests_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(RELTEST_FILES) $(COVER_SPEC_FILE) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
tar cf - snmp_test_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/ssl/examples/certs/Makefile b/lib/ssl/examples/certs/Makefile
index b811b461dc..a4f067ade6 100644
--- a/lib/ssl/examples/certs/Makefile
+++ b/lib/ssl/examples/certs/Makefile
@@ -57,5 +57,5 @@ release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/examples/certs
tar cf - etc | \
(cd $(RELSYSDIR)/examples/certs; tar xf -)
- chmod -f -R ug+rw $(RELSYSDIR)/examples
+ chmod -R ug+rw $(RELSYSDIR)/examples
release_docs_spec:
diff --git a/lib/ssl/examples/src/Makefile b/lib/ssl/examples/src/Makefile
index 46c0507b3a..ae5881d49b 100644
--- a/lib/ssl/examples/src/Makefile
+++ b/lib/ssl/examples/src/Makefile
@@ -66,7 +66,7 @@ release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/examples/src
$(INSTALL_DIR) $(RELSYSDIR)/examples/ebin
(cd ..; tar cf - src ebin | (cd $(RELSYSDIR)/examples; tar xf -))
- chmod -f -R ug+w $(RELSYSDIR)/examples
+ chmod -R ug+w $(RELSYSDIR)/examples
release_docs_spec:
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 3512e194bc..7b1fda4cf9 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -52,13 +52,12 @@
-type option() :: socketoption() | ssloption() | transportoption().
-type socketoption() :: [{property(), term()}]. %% See gen_tcp and inet
-type property() :: atom().
-
-type ssloption() :: {verify, verify_type()} |
{verify_fun, {fun(), InitialUserState::term()}} |
{fail_if_no_peer_cert, boolean()} | {depth, integer()} |
- {cert, der_encoded()} | {certfile, path()} | {key, der_encoded()} |
- {keyfile, path()} | {password, string()} | {cacerts, [der_encoded()]} |
- {cacertfile, path()} | {dh, der_encoded()} | {dhfile, path()} |
+ {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
+ {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
+ {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
{ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
{reuse_session, fun()} | {hibernate_after, integer()|undefined}.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 8ae4d2332e..fb0ebac7d1 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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
@@ -29,9 +29,8 @@
-include_lib("public_key/include/public_key.hrl").
-type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'.
--type public_key() :: #'RSAPublicKey'{} | integer().
-type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {algo_oid(), public_key(), public_key_params()}.
+-type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}.
-record(session, {
session_id,
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index fd3b6d06ad..53b2223035 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -128,7 +128,7 @@ release_tests_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(HRL_FILES_NEEDED_IN_TEST) $(COVER_FILE) $(RELSYSDIR)
$(INSTALL_DATA) ssl.spec ssl.cover $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml
index c5eb81a86a..c81023862e 100644
--- a/lib/stdlib/doc/src/binary.xml
+++ b/lib/stdlib/doc/src/binary.xml
@@ -485,7 +485,7 @@
<code>
1> Bin = &lt;&lt;1,2,3,4,5,6,7,8,9,10&gt;&gt;.
-2> binary:part(Bin,{byte_size(Bin), -5)).
+2> binary:part(Bin,{byte_size(Bin), -5}).
&lt;&lt;6,7,8,9,10&gt;&gt;
</code>
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index 4d98a20206..529a70a23d 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -34,11 +34,11 @@
<module>zip</module>
<modulesummary>Utility for reading and creating 'zip' archives.</modulesummary>
<description>
- <p>The <c>zip</c> module archives and extract files to and from a zip
+ <p>The <c>zip</c> module archives and extracts files to and from a zip
archive. The zip format is specified by the "ZIP Appnote.txt" file
available on PKWare's website www.pkware.com.</p>
<p>The zip module supports zip archive versions up to 6.1. However,
- password-protection and Zip64 is not supported.</p>
+ password-protection and Zip64 are not supported.</p>
<p>By convention, the name of a zip file should end in "<c>.zip</c>".
To abide to the convention, you'll need to add "<c>.zip</c>" yourself
to the name.</p>
@@ -52,7 +52,7 @@
<seealso marker="#unzip_2">unzip/2</seealso> function. (They are
also available as <c>extract</c>.)</p>
<p>To fold a function over all files in a zip archive, use the
- <seealso marker="#foldl_3">foldl_3</seealso>.</p>
+ <seealso marker="#foldl_3">foldl_3</seealso> function.</p>
<p>To return a list of the files in a zip archive, use the
<seealso marker="#list_dir_1">list_dir/1</seealso> or the
<seealso marker="#list_dir_2">list_dir/2</seealso> function. (They
@@ -155,13 +155,13 @@ zip_file() </code>
<p>Files will be compressed using the DEFLATE compression, as
described in the Appnote.txt file. However, files will be
stored without compression if they already are compressed.
- The <c>zip/2</c> and <c>zip/3</c> checks the file extension
+ The <c>zip/2</c> and <c>zip/3</c> functions check the file extension
to see whether the file should be stored without compression.
Files with the following extensions are not compressed:
<c>.Z</c>, <c>.zip</c>, <c>.zoo</c>, <c>.arc</c>, <c>.lzh</c>,
<c>.arj</c>.</p>
<p>It is possible to override the default behavior and
- explicitly control what types of files that should be
+ explicitly control what types of files should be
compressed by using the <c>{compress, What}</c> and
<c>{uncompress, What}</c> options. It is possible to have
several <c>compress</c> and <c>uncompress</c> options. In
@@ -208,7 +208,7 @@ zip_file() </code>
</item>
<tag><c>{compress, What}</c></tag>
<item>
- <p>Controls what types of files that will be
+ <p>Controls what types of files will be
compressed. It is by default set to <c>all</c>. The
following values of <c>What</c> are allowed:</p>
<taglist>
@@ -228,7 +228,7 @@ zip_file() </code>
</item>
<tag><c>{uncompress, What}</c></tag>
<item>
- <p>Controls what types of files that will be uncompressed. It is by
+ <p>Controls what types of files will be uncompressed. It is by
default set to <c>[".Z",".zip",".zoo",".arc",".lzh",".arj"]</c>.
The following values of <c>What</c> are allowed:</p>
<taglist>
@@ -292,7 +292,7 @@ zip_file() </code>
<p>By default, the <c>open/2</c> function will open the
zip file in <c>raw</c> mode, which is faster but does not allow
a remote (erlang) file server to be used. Adding <c>cooked</c>
- to the mode list will override the default and open zip file
+ to the mode list will override the default and open the zip file
without the <c>raw</c> option. The same goes for the files
extracted.</p>
</item>
@@ -301,7 +301,7 @@ zip_file() </code>
<p>By default, all existing files with the same name as file in
the zip archive will be overwritten. With the <c>keep_old_files</c>
option, the <c>unzip/2</c> function will not overwrite any existing
- files. Not that even with the <c>memory</c> option given, which
+ files. Note that even with the <c>memory</c> option given, which
means that no files will be overwritten, files existing will be
excluded from the result.</p>
</item>
@@ -418,7 +418,7 @@ zip_file() </code>
<p>By default, the <c>open/2</c> function will open the
zip file in <c>raw</c> mode, which is faster but does not allow
a remote (erlang) file server to be used. Adding <c>cooked</c>
- to the mode list will override the default and open zip file
+ to the mode list will override the default and open the zip file
without the <c>raw</c> option.</p>
</item>
</taglist>
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index bb4b18cf9b..15b45d72f4 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,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
@@ -757,7 +757,8 @@ record_fields([{typed,Expr,TypeInfo}|Fields]) ->
{atom, La, _} ->
case has_undefined(TypeInfo) of
false ->
- lift_unions(abstract(undefined, La), TypeInfo);
+ TypeInfo2 = maybe_add_paren(TypeInfo),
+ lift_unions(abstract(undefined, La), TypeInfo2);
true ->
TypeInfo
end
@@ -778,6 +779,11 @@ has_undefined({type,_,union,Ts}) ->
has_undefined(_) ->
false.
+maybe_add_paren({ann_type,L,T}) ->
+ {paren_type,L,[{ann_type,L,T}]};
+maybe_add_paren(T) ->
+ T.
+
term(Expr) ->
try normalise(Expr)
catch _:_R -> ret_err(?line(Expr), "bad attribute")
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index df4a20b833..66c80a45cb 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.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
@@ -558,17 +558,11 @@ record_field({typed_record_field,{record_field,_,F,Val},Type}, Hook) ->
Fl = lexpr(F, L, Hook),
Vl = typed(lexpr(Val, R, Hook), Type),
{list,[{cstep,[Fl,' ='],Vl}]};
-record_field({typed_record_field,Field,Type0}, Hook) ->
- Type = remove_undefined(Type0),
+record_field({typed_record_field,Field,Type}, Hook) ->
typed(record_field(Field, Hook), Type);
record_field({record_field,_,F}, Hook) ->
lexpr(F, 0, Hook).
-remove_undefined({type,L,union,[{atom,_,undefined}|T]}) ->
- {type,L,union,T};
-remove_undefined(T) -> % cannot happen
- T.
-
list({cons,_,H,T}, Es, Hook) ->
list(T, [H|Es], Hook);
list({nil,_}, Es, Hook) ->
diff --git a/lib/stdlib/src/log_mf_h.erl b/lib/stdlib/src/log_mf_h.erl
index 2729f27e51..5fa5360fa1 100644
--- a/lib/stdlib/src/log_mf_h.erl
+++ b/lib/stdlib/src/log_mf_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -185,13 +185,19 @@ read_index_file(Dir) ->
%%-----------------------------------------------------------------
%% Write the index file. This file contains one binary with
%% the last used filename (an integer).
+%% Write a temporary file and rename it in order to make the update
+%% atomic.
%%-----------------------------------------------------------------
write_index_file(Dir, Index) ->
- case file:open(Dir ++ "/index", [raw, write]) of
+ File = Dir ++ "/index",
+ TmpFile = File ++ ".tmp",
+ case file:open(TmpFile, [raw, write]) of
{ok, Fd} ->
- file:write(Fd, [Index]),
- ok = file:close(Fd);
+ ok = file:write(Fd, [Index]),
+ ok = file:close(Fd),
+ ok = file:rename(TmpFile,File),
+ ok;
_ -> exit(open_index_file)
end.
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 3dd0a91870..5502c69fa5 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -135,7 +135,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) stdlib.spec $(EMAKEFILE) \
$(ERL_FILES) $(COVERFILE) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 6b2eb78e2c..4b59cee99e 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -571,6 +571,17 @@ otp_5269(Config) when is_list(Config) ->
B:A>> <- [<<16:8,19:16>>],
<<X:8>> <- [<<B:8>>]].",
[19]),
+ ?line check(fun() ->
+ (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) ->
+ case A of
+ B -> wrong;
+ _ -> ok
+ end
+ end)(<<1,2,3,4>>) end,
+ "(fun(<<A:1/binary, B:8/integer, _C:B/binary>>) ->"
+ " case A of B -> wrong; _ -> ok end"
+ " end)(<<1, 2, 3, 4>>).",
+ ok),
ok.
otp_6539(doc) ->
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 822886cb8a..bc811355ab 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -48,7 +48,7 @@
neg_indent/1,
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
- otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1]).
+ otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1]).
%% Internal export.
-export([ehook/6]).
@@ -79,7 +79,7 @@ groups() ->
{attributes, [], [misc_attrs, import_export]},
{tickets, [],
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
- otp_8473, otp_8522, otp_8567, otp_8664]}].
+ otp_8473, otp_8522, otp_8567, otp_8664, otp_9147]}].
init_per_suite(Config) ->
Config.
@@ -1047,6 +1047,26 @@ otp_8664(Config) when is_list(Config) ->
ok.
+otp_9147(doc) ->
+ "OTP_9147. Create well-formed types when adding 'undefined'.";
+otp_9147(suite) -> [];
+otp_9147(Config) when is_list(Config) ->
+ FileName = filename('otp_9147.erl', Config),
+ C1 = <<"-module(otp_9147).\n"
+ "-export_type([undef/0]).\n"
+ "-record(undef, {f1 :: F1 :: a | b}).\n"
+ "-type undef() :: #undef{}.\n">>,
+ ?line ok = file:write_file(FileName, C1),
+ ?line {ok, _, []} =
+ compile:file(FileName, [return,'P',{outdir,?privdir}]),
+ PFileName = filename('otp_9147.P', Config),
+ ?line {ok, Bin} = file:read_file(PFileName),
+ %% The parentheses around "F1 :: a | b" are new (bugfix).
+ ?line true =
+ lists:member("-record(undef,{f1 :: undefined | (F1 :: a | b)}).",
+ string:tokens(binary_to_list(Bin), "\n")),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index ac02e1f359..c0956030cf 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 1.17.3
+STDLIB_VSN = 1.17.4
diff --git a/lib/syntax_tools/src/erl_recomment.erl b/lib/syntax_tools/src/erl_recomment.erl
index 919e9cfc5d..fc7c515700 100644
--- a/lib/syntax_tools/src/erl_recomment.erl
+++ b/lib/syntax_tools/src/erl_recomment.erl
@@ -163,7 +163,7 @@ recomment_forms_2(C, [N | Ns] = Nodes, Insert) ->
Trailing =
case Ns of
[] -> true;
- [Next | _] -> L < node_min(Next) - 2
+ [Next | _] -> L + Delta < node_min(Next) - 2
end,
if L > Max + 1 ; L =:= Max + 1, not Trailing ->
[N | recomment_forms_2(C, Ns, Insert)];
diff --git a/lib/syntax_tools/test/Makefile b/lib/syntax_tools/test/Makefile
index e793dec566..3e31bdbd50 100644
--- a/lib/syntax_tools/test/Makefile
+++ b/lib/syntax_tools/test/Makefile
@@ -60,6 +60,6 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) syntax_tools.spec syntax_tools.cover $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
release_docs_spec:
diff --git a/lib/test_server/test/Makefile b/lib/test_server/test/Makefile
index 34c55c595d..ab72a9d579 100644
--- a/lib/test_server/test/Makefile
+++ b/lib/test_server/test/Makefile
@@ -86,7 +86,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR)
$(INSTALL_DATA) test_server.spec test_server.cover $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/tools/src/make.erl b/lib/tools/src/make.erl
index 77c354651b..e78e2a43a4 100644
--- a/lib/tools/src/make.erl
+++ b/lib/tools/src/make.erl
@@ -222,12 +222,7 @@ recompilep(File, NoExec, Load, Opts) ->
recompilep1(File, NoExec, Load, Opts, ObjFile) ->
{ok, Erl} = file:read_file_info(lists:append(File, ".erl")),
{ok, Obj} = file:read_file_info(ObjFile),
- case {readable(Erl), writable(Obj)} of
- {true, true} ->
- recompilep1(Erl, Obj, File, NoExec, Load, Opts);
- _ ->
- error
- end.
+ recompilep1(Erl, Obj, File, NoExec, Load, Opts).
recompilep1(#file_info{mtime=Te},
#file_info{mtime=To}, File, NoExec, Load, Opts) when Te>To ->
@@ -277,14 +272,6 @@ exists(File) ->
false
end.
-readable(#file_info{access=read_write}) -> true;
-readable(#file_info{access=read}) -> true;
-readable(_) -> false.
-
-writable(#file_info{access=read_write}) -> true;
-writable(#file_info{access=write}) -> true;
-writable(_) -> false.
-
coerce_2_list(X) when is_atom(X) ->
atom_to_list(X);
coerce_2_list(X) ->
diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile
index 63f96520fd..8019b7269f 100644
--- a/lib/tools/test/Makefile
+++ b/lib/tools/test/Makefile
@@ -87,7 +87,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
$(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(EMAKEFILE) \
$(ERL_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/tv/src/tv_io_lib.erl b/lib/tv/src/tv_io_lib.erl
index f693ff796d..5457575b7d 100644
--- a/lib/tv/src/tv_io_lib.erl
+++ b/lib/tv/src/tv_io_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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
@@ -52,10 +52,11 @@ write(_Term, 0) -> "...";
write(Term, _D) when is_integer(Term) -> integer_to_list(Term);
write(Term, _D) when is_float(Term) -> tv_io_lib_format:fwrite_g(Term);
write(Atom, _D) when is_atom(Atom) -> write_atom(Atom);
-write(Term, _D) when is_port(Term) -> "#Port";
+write(Term, _D) when is_port(Term) -> lists:flatten(io_lib:write(Term));
write(Term, _D) when is_pid(Term) -> pid_to_list(Term);
-write(Term, _D) when is_reference(Term) -> "#Ref";
-write(Term, _D) when is_binary(Term) -> "#Bin";
+write(Term, _D) when is_reference(Term) -> io_lib:write(Term);
+write(Term, _D) when is_binary(Term), byte_size(Term) > 100 -> "#Bin";
+write(Term, _D) when is_binary(Term) -> "<<\"" ++ binary_to_list(Term) ++ "\">>";
write(Term, _D) when is_bitstring(Term) -> "#Bitstr";
write([], _D) -> "[]";
write({}, _D) -> "{}";
diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl
index fc8caa4f21..e40c4f39cd 100644
--- a/lib/typer/src/typer.erl
+++ b/lib/typer/src/typer.erl
@@ -628,6 +628,8 @@ cl(["-T"|Opts]) ->
cl(["-r"|Opts]) ->
{Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
{{files_r, Files}, RestOpts};
+cl(["-pa",Dir|Opts]) -> {{pa,Dir}, Opts};
+cl(["-pz",Dir|Opts]) -> {{pz,Dir}, Opts};
cl(["-"++H|_]) -> fatal_error("unknown option -"++H);
cl(Opts) ->
{Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
@@ -672,7 +674,13 @@ analyze_result({plt, Plt}, Args, Analysis) ->
analyze_result(show_succ, Args, Analysis) ->
{Args, Analysis#analysis{show_succ = true}};
analyze_result(no_spec, Args, Analysis) ->
- {Args, Analysis#analysis{no_spec = true}}.
+ {Args, Analysis#analysis{no_spec = true}};
+analyze_result({pa, Dir}, Args, Analysis) ->
+ code:add_patha(Dir),
+ {Args, Analysis};
+analyze_result({pz, Dir}, Args, Analysis) ->
+ code:add_pathz(Dir),
+ {Args, Analysis}.
%%--------------------------------------------------------------------
%% File processing.
@@ -1009,7 +1017,8 @@ version_message() ->
help_message() ->
S = <<" Usage: typer [--help] [--version] [--plt PLT] [--edoc]
[--show | --show-exported | --annotate | --annotate-inc-files]
- [-Ddefine]* [-I include_dir]* [-T application]* [-r] file*
+ [-Ddefine]* [-I include_dir]* [-pa dir]* [-pz dir]*
+ [-T application]* [-r] file*
Options:
-r dir*
@@ -1039,6 +1048,10 @@ help_message() ->
-I include_dir
pass the include_dir to TypEr
(The syntax of includes is the same as that used by \"erlc\".)
+ -pa dir
+ -pz dir
+ Set code path options to TypEr
+ (This is useful for files that use parse tranforms.)
--version (or -v)
prints the Typer version and exits
--help (or -h)