aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/.gitignore1
-rw-r--r--lib/appmon/doc/src/Makefile14
-rw-r--r--lib/appmon/priv/Makefile4
-rw-r--r--lib/appmon/src/Makefile8
-rw-r--r--lib/asn1/c_src/Makefile8
-rw-r--r--lib/asn1/doc/src/Makefile14
-rw-r--r--lib/asn1/src/Makefile16
-rw-r--r--lib/asn1/src/asn1ct_check.erl22
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl156
-rw-r--r--lib/asn1/src/asn1ct_gen.erl31
-rw-r--r--lib/asn1/src/asn1ct_gen_ber_bin_v2.erl2
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl40
-rw-r--r--lib/asn1/src/asn1ct_gen_per_rt2ct.erl39
-rw-r--r--lib/asn1/src/asn1ct_parser2.erl6
-rw-r--r--lib/asn1/src/asn1rt_per_bin.erl46
-rw-r--r--lib/asn1/src/asn1rt_per_bin_rt2ct.erl39
-rw-r--r--lib/asn1/test/Makefile16
-rw-r--r--lib/asn1/test/asn1_SUITE.erl22
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Constraints.py5
-rw-r--r--lib/asn1/test/asn1_SUITE_data/EnumN2N.asn125
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn18
-rw-r--r--lib/asn1/test/asn1_SUITE_data/LargeConstraints.py9
-rw-r--r--lib/asn1/test/testConstraints.erl74
-rw-r--r--lib/common_test/doc/src/Makefile29
-rw-r--r--lib/common_test/doc/src/ct_hooks_chapter.xml2
-rw-r--r--lib/common_test/doc/src/ref_man.xml3
-rw-r--r--lib/common_test/priv/Makefile.in12
-rw-r--r--lib/common_test/src/Makefile20
-rw-r--r--lib/common_test/src/common_test.app.src3
-rw-r--r--lib/common_test/src/ct.erl27
-rw-r--r--lib/common_test/src/ct_conn_log_h.erl230
-rw-r--r--lib/common_test/src/ct_event.erl16
-rw-r--r--lib/common_test/src/ct_gen_conn.erl247
-rw-r--r--lib/common_test/src/ct_netconfc.erl1828
-rw-r--r--lib/common_test/src/ct_netconfc.hrl58
-rw-r--r--lib/common_test/src/ct_util.erl22
-rw-r--r--lib/common_test/src/ct_util.hrl3
-rw-r--r--lib/common_test/src/cth_conn_log.erl124
-rw-r--r--lib/common_test/src/cth_surefire.erl53
-rw-r--r--lib/common_test/test/Makefile13
-rw-r--r--lib/common_test/test/common_test.spec2
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE.erl124
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1.cfg6
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl1130
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/ns.erl506
-rw-r--r--lib/compiler/doc/src/Makefile14
-rw-r--r--lib/compiler/doc/src/compile.xml9
-rw-r--r--lib/compiler/src/Makefile8
-rw-r--r--lib/compiler/src/beam_type.erl15
-rw-r--r--lib/compiler/src/beam_utils.erl5
-rw-r--r--lib/compiler/src/beam_validator.erl16
-rw-r--r--lib/compiler/src/compile.erl28
-rw-r--r--lib/compiler/src/sys_pre_expand.erl22
-rw-r--r--lib/compiler/src/v3_core.erl7
-rw-r--r--lib/compiler/src/v3_kernel.erl7
-rw-r--r--lib/compiler/test/Makefile10
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl4
-rw-r--r--lib/compiler/test/compile_SUITE.erl35
-rw-r--r--lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S8
-rw-r--r--lib/compiler/test/misc_SUITE.erl9
-rw-r--r--lib/cosEvent/doc/src/Makefile14
-rw-r--r--lib/cosEvent/src/Makefile16
-rw-r--r--lib/cosEvent/test/Makefile10
-rw-r--r--lib/cosEventDomain/doc/src/Makefile14
-rw-r--r--lib/cosEventDomain/src/Makefile16
-rw-r--r--lib/cosEventDomain/test/Makefile6
-rw-r--r--lib/cosFileTransfer/doc/src/Makefile14
-rw-r--r--lib/cosFileTransfer/src/Makefile14
-rw-r--r--lib/cosFileTransfer/test/Makefile8
-rw-r--r--lib/cosNotification/doc/src/Makefile14
-rw-r--r--lib/cosNotification/src/Makefile14
-rw-r--r--lib/cosNotification/test/Makefile10
-rw-r--r--lib/cosProperty/doc/src/Makefile14
-rw-r--r--lib/cosProperty/src/Makefile14
-rw-r--r--lib/cosProperty/test/Makefile10
-rw-r--r--lib/cosTime/doc/src/Makefile14
-rw-r--r--lib/cosTime/src/Makefile14
-rw-r--r--lib/cosTime/test/Makefile10
-rw-r--r--lib/cosTransactions/doc/src/Makefile14
-rw-r--r--lib/cosTransactions/examples/Makefile6
-rw-r--r--lib/cosTransactions/src/Makefile12
-rw-r--r--lib/cosTransactions/test/Makefile10
-rw-r--r--lib/crypto/c_src/Makefile.in10
-rw-r--r--lib/crypto/c_src/crypto.c3
-rw-r--r--lib/crypto/doc/src/Makefile18
-rw-r--r--lib/crypto/doc/src/crypto.xml42
-rw-r--r--lib/crypto/src/Makefile8
-rw-r--r--lib/crypto/test/Makefile6
-rw-r--r--lib/crypto/test/crypto_SUITE.erl17
-rw-r--r--lib/debugger/doc/src/Makefile14
-rw-r--r--lib/debugger/priv/Makefile4
-rw-r--r--lib/debugger/src/Makefile8
-rw-r--r--lib/debugger/test/Makefile10
-rw-r--r--lib/debugger/test/bs_construct_SUITE.erl8
-rw-r--r--lib/dialyzer/doc/src/Makefile14
-rw-r--r--lib/dialyzer/src/Makefile11
-rw-r--r--lib/dialyzer/src/dialyzer.hrl22
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl198
-rw-r--r--lib/dialyzer/src/dialyzer_behaviours.erl28
-rw-r--r--lib/dialyzer/src/dialyzer_callgraph.erl601
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl9
-rw-r--r--lib/dialyzer/src/dialyzer_cl_parse.erl23
-rw-r--r--lib/dialyzer/src/dialyzer_codeserver.erl302
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl79
-rw-r--r--lib/dialyzer/src/dialyzer_coordinator.erl250
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl379
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl16
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl93
-rw-r--r--lib/dialyzer/src/dialyzer_races.erl12
-rw-r--r--lib/dialyzer/src/dialyzer_succ_typings.erl464
-rw-r--r--lib/dialyzer/src/dialyzer_timing.erl133
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl963
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl12
-rw-r--r--lib/dialyzer/src/dialyzer_worker.erl189
-rw-r--r--lib/dialyzer/test/Makefile10
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/queue1
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes31
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/collapse_lists/a.erl9
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/collapse_lists/b.erl5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl267
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/deep_lc.erl14
-rw-r--r--lib/diameter/autoconf/vxworks/sed.general1
-rw-r--r--lib/diameter/doc/src/Makefile24
-rw-r--r--lib/diameter/src/Makefile18
-rw-r--r--lib/diameter/test/Makefile10
-rw-r--r--lib/edoc/doc/src/Makefile14
-rw-r--r--lib/edoc/include/Makefile4
-rw-r--r--lib/edoc/priv/Makefile6
-rw-r--r--lib/edoc/src/Makefile8
-rw-r--r--lib/edoc/src/edoc_data.erl5
-rw-r--r--lib/edoc/src/edoc_lib.erl4
-rw-r--r--lib/edoc/test/Makefile10
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/doc/src/Makefile18
-rw-r--r--lib/eldap/src/Makefile16
-rw-r--r--lib/eldap/test/Makefile10
-rw-r--r--lib/erl_docgen/doc/src/Makefile14
-rw-r--r--lib/erl_docgen/priv/bin/Makefile4
-rw-r--r--lib/erl_docgen/priv/css/Makefile8
-rw-r--r--lib/erl_docgen/priv/dtd/Makefile4
-rw-r--r--lib/erl_docgen/priv/dtd_html_entities/Makefile4
-rw-r--r--lib/erl_docgen/priv/dtd_man_entities/Makefile4
-rw-r--r--lib/erl_docgen/priv/images/Makefile8
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/Makefile8
-rw-r--r--lib/erl_docgen/priv/xsl/Makefile4
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl21
-rw-r--r--lib/erl_docgen/priv/xsl/db_man.xsl26
-rw-r--r--lib/erl_docgen/priv/xsl/db_pdf.xsl20
-rw-r--r--lib/erl_docgen/src/Makefile8
-rw-r--r--lib/erl_interface/doc/src/Makefile18
-rw-r--r--lib/erl_interface/src/Makefile.in50
-rw-r--r--lib/erl_interface/test/Makefile8
-rw-r--r--lib/erl_interface/test/all_SUITE_data/gccifier.c16
-rw-r--r--lib/erl_interface/test/ei_tmo_SUITE.erl20
-rw-r--r--lib/erl_interface/test/erl_match_SUITE.erl30
-rw-r--r--lib/et/doc/src/Makefile14
-rw-r--r--lib/et/doc/src/et_intro.xml4
-rw-r--r--lib/et/examples/Makefile4
-rw-r--r--lib/et/src/Makefile16
-rw-r--r--lib/et/src/et_wx_contents_viewer.erl23
-rw-r--r--lib/et/test/Makefile12
-rw-r--r--lib/eunit/doc/overview.edoc8
-rw-r--r--lib/eunit/doc/src/Makefile14
-rw-r--r--lib/eunit/examples/Makefile4
-rw-r--r--lib/eunit/include/eunit.hrl13
-rw-r--r--lib/eunit/src/Makefile12
-rw-r--r--lib/eunit/src/eunit.app.src1
-rw-r--r--lib/eunit/src/eunit.erl7
-rw-r--r--lib/eunit/src/eunit_data.erl39
-rw-r--r--lib/eunit/src/eunit_lib.erl94
-rw-r--r--lib/eunit/src/eunit_surefire.erl32
-rw-r--r--lib/eunit/src/eunit_test.erl26
-rw-r--r--lib/eunit/src/eunit_tty.erl59
-rw-r--r--lib/eunit/test/Makefile4
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/gs/contribs/bonk/Makefile16
-rw-r--r--lib/gs/contribs/cols/Makefile12
-rw-r--r--lib/gs/contribs/mandel/Makefile12
-rw-r--r--lib/gs/contribs/othello/Makefile12
-rw-r--r--lib/gs/doc/src/Makefile14
-rw-r--r--lib/gs/examples/Makefile8
-rw-r--r--lib/gs/src/Makefile12
-rw-r--r--lib/gs/tcl/Makefile.in6
-rw-r--r--lib/hipe/amd64/Makefile4
-rw-r--r--lib/hipe/arm/Makefile4
-rw-r--r--lib/hipe/cerl/Makefile10
-rw-r--r--lib/hipe/cerl/cerl_hybrid_transform.erl153
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl8
-rw-r--r--lib/hipe/cerl/erl_types.erl24
-rw-r--r--lib/hipe/doc/src/Makefile10
-rw-r--r--lib/hipe/flow/Makefile8
-rw-r--r--lib/hipe/icode/Makefile8
-rw-r--r--lib/hipe/main/Makefile10
-rw-r--r--lib/hipe/main/hipe.app.src1
-rw-r--r--lib/hipe/main/hipe.erl7
-rw-r--r--lib/hipe/misc/Makefile8
-rw-r--r--lib/hipe/opt/Makefile4
-rw-r--r--lib/hipe/ppc/Makefile4
-rw-r--r--lib/hipe/regalloc/Makefile4
-rw-r--r--lib/hipe/rtl/Makefile8
-rw-r--r--lib/hipe/sparc/Makefile4
-rw-r--r--lib/hipe/tools/Makefile4
-rw-r--r--lib/hipe/util/Makefile8
-rw-r--r--lib/hipe/x86/Makefile4
-rw-r--r--lib/ic/c_src/Makefile.in12
-rw-r--r--lib/ic/doc/src/Makefile14
-rw-r--r--lib/ic/doc/src/ic_clib.xml14
-rw-r--r--lib/ic/examples/pre_post_condition/Makefile4
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Makefile8
-rw-r--r--lib/ic/src/Makefile34
-rw-r--r--lib/ic/src/ic.erl2
-rw-r--r--lib/ic/src/ic_pp.erl39
-rw-r--r--lib/ic/test/Makefile50
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE.erl2
-rw-r--r--lib/inets/doc/src/Makefile14
-rw-r--r--lib/inets/doc/src/httpc.xml143
-rw-r--r--lib/inets/doc/src/notes.xml140
-rw-r--r--lib/inets/examples/httpd_load_test/Makefile2
-rw-r--r--lib/inets/examples/server_root/Makefile46
-rw-r--r--lib/inets/priv/Makefile4
-rw-r--r--lib/inets/src/ftp/Makefile10
-rw-r--r--lib/inets/src/http_client/Makefile10
-rw-r--r--lib/inets/src/http_client/httpc.erl26
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl27
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl197
-rw-r--r--lib/inets/src/http_lib/Makefile10
-rw-r--r--lib/inets/src/http_server/Makefile10
-rw-r--r--lib/inets/src/inets_app/Makefile14
-rw-r--r--lib/inets/src/inets_app/inets.appup.src82
-rw-r--r--lib/inets/src/inets_app/inets.mk6
-rw-r--r--lib/inets/src/inets_app/inets_service.erl17
-rw-r--r--lib/inets/src/tftp/Makefile10
-rw-r--r--lib/inets/src/tftp/tftp.erl18
-rw-r--r--lib/inets/test/Makefile16
-rw-r--r--lib/inets/test/httpc_SUITE.erl230
-rw-r--r--lib/inets/test/httpd_mod.erl237
-rw-r--r--lib/inets/test/inets_test_lib.erl39
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/inviso/doc/src/Makefile14
-rw-r--r--lib/inviso/src/Makefile12
-rw-r--r--lib/inviso/test/Makefile8
-rw-r--r--lib/jinterface/doc/src/Makefile18
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile12
-rw-r--r--lib/jinterface/test/Makefile6
-rw-r--r--lib/kernel/doc/src/Makefile22
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml2
-rw-r--r--lib/kernel/doc/src/gen_udp.xml4
-rw-r--r--lib/kernel/doc/src/inet.xml2
-rw-r--r--lib/kernel/doc/src/os.xml15
-rw-r--r--lib/kernel/doc/src/packages.xml6
-rw-r--r--lib/kernel/examples/Makefile4
-rw-r--r--lib/kernel/examples/uds_dist/c_src/uds_drv.c4
-rw-r--r--lib/kernel/src/Makefile14
-rw-r--r--lib/kernel/src/code.erl13
-rw-r--r--lib/kernel/src/code_server.erl4
-rw-r--r--lib/kernel/src/disk_log.erl7
-rw-r--r--lib/kernel/src/disk_log.hrl4
-rw-r--r--lib/kernel/src/file.erl2
-rw-r--r--lib/kernel/src/gen_sctp.erl5
-rw-r--r--lib/kernel/src/gen_udp.erl5
-rw-r--r--lib/kernel/src/inet.erl4
-rw-r--r--lib/kernel/src/rpc.erl2
-rw-r--r--lib/kernel/test/Makefile12
-rw-r--r--lib/kernel/test/bif_SUITE.erl94
-rw-r--r--lib/kernel/test/code_SUITE.erl6
-rw-r--r--lib/kernel/test/disk_log_SUITE.erl24
-rw-r--r--lib/kernel/test/erl_prim_loader_SUITE.erl8
-rw-r--r--lib/kernel/test/file_name_SUITE.erl52
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl35
-rw-r--r--lib/kernel/test/init_SUITE.erl4
-rw-r--r--lib/kernel/test/interactive_shell_SUITE.erl6
-rw-r--r--lib/megaco/Makefile25
-rw-r--r--lib/megaco/doc/src/Makefile18
-rw-r--r--lib/megaco/examples/meas/Makefile.in12
-rw-r--r--lib/megaco/examples/meas/megaco_codec_mstone_lib.erl5
-rw-r--r--lib/megaco/examples/simple/Makefile6
-rw-r--r--lib/megaco/src/app/Makefile16
-rw-r--r--lib/megaco/src/binary/Makefile10
-rw-r--r--lib/megaco/src/engine/Makefile12
-rw-r--r--lib/megaco/src/flex/Makefile.in18
-rw-r--r--lib/megaco/src/tcp/Makefile10
-rw-r--r--lib/megaco/src/text/Makefile10
-rw-r--r--lib/megaco/src/udp/Makefile10
-rw-r--r--lib/megaco/test/Makefile8
-rw-r--r--lib/mnesia/doc/src/Makefile14
-rw-r--r--lib/mnesia/examples/Makefile10
-rw-r--r--lib/mnesia/include/Makefile4
-rw-r--r--lib/mnesia/src/Makefile8
-rw-r--r--lib/mnesia/test/Makefile38
-rw-r--r--lib/mnesia/test/mnesia_consistency_test.erl22
-rw-r--r--lib/observer/doc/src/Makefile18
-rw-r--r--lib/observer/src/Makefile28
-rw-r--r--lib/observer/src/crashdump_viewer_html.erl4
-rw-r--r--lib/observer/src/observer_app_wx.erl36
-rw-r--r--lib/observer/src/observer_perf_wx.erl2
-rw-r--r--lib/observer/src/observer_pro_wx.erl24
-rw-r--r--lib/observer/src/observer_procinfo.erl36
-rw-r--r--lib/observer/src/observer_sys_wx.erl4
-rw-r--r--lib/observer/src/observer_trace_wx.erl4
-rw-r--r--lib/observer/src/observer_traceoptions_wx.erl8
-rw-r--r--lib/observer/src/observer_tv_table.erl14
-rw-r--r--lib/observer/src/observer_wx.erl57
-rw-r--r--lib/observer/test/Makefile6
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl46
-rw-r--r--lib/odbc/c_src/Makefile.in12
-rw-r--r--lib/odbc/doc/src/Makefile14
-rw-r--r--lib/odbc/src/Makefile12
-rw-r--r--lib/odbc/src/odbc.erl2
-rw-r--r--lib/odbc/test/Makefile4
-rw-r--r--lib/odbc/test/odbc_test_lib.erl3
-rw-r--r--lib/orber/COSS/CosNaming/Makefile10
-rw-r--r--lib/orber/c_src/Makefile.in24
-rw-r--r--lib/orber/doc/src/Makefile14
-rw-r--r--lib/orber/examples/Stack/Makefile4
-rw-r--r--lib/orber/java_src/Orber/Makefile4
-rw-r--r--lib/orber/priv/Makefile4
-rw-r--r--lib/orber/src/Makefile12
-rw-r--r--lib/orber/test/Makefile12
-rw-r--r--lib/orber/test/orber_test_lib.erl5
-rw-r--r--lib/os_mon/c_src/Makefile.in8
-rw-r--r--lib/os_mon/c_src/cpu_sup.c14
-rw-r--r--lib/os_mon/c_src/memsup.c25
-rw-r--r--lib/os_mon/c_src/win32sysinfo.c30
-rw-r--r--lib/os_mon/doc/src/Makefile18
-rw-r--r--lib/os_mon/mibs/Makefile16
-rw-r--r--lib/os_mon/src/Makefile10
-rw-r--r--lib/os_mon/src/disksup.erl10
-rw-r--r--lib/os_mon/src/memsup.erl2
-rw-r--r--lib/os_mon/src/os_mon.erl4
-rw-r--r--lib/os_mon/test/Makefile6
-rw-r--r--lib/otp_mibs/doc/src/Makefile14
-rw-r--r--lib/otp_mibs/mibs/Makefile16
-rw-r--r--lib/otp_mibs/src/Makefile8
-rw-r--r--lib/parsetools/doc/src/Makefile14
-rw-r--r--lib/parsetools/src/Makefile12
-rw-r--r--lib/parsetools/test/Makefile8
-rw-r--r--lib/percept/doc/src/Makefile14
-rw-r--r--lib/percept/priv/Makefile28
-rw-r--r--lib/percept/src/Makefile12
-rw-r--r--lib/percept/test/Makefile8
-rw-r--r--lib/pman/doc/src/Makefile14
-rw-r--r--lib/pman/priv/Makefile4
-rw-r--r--lib/pman/src/Makefile8
-rw-r--r--lib/public_key/asn1/Makefile12
-rw-r--r--lib/public_key/doc/src/Makefile14
-rw-r--r--lib/public_key/src/Makefile12
-rw-r--r--lib/public_key/test/Makefile10
-rw-r--r--lib/reltool/doc/src/Makefile14
-rw-r--r--lib/reltool/examples/Makefile4
-rw-r--r--lib/reltool/src/Makefile10
-rw-r--r--lib/reltool/test/Makefile12
-rw-r--r--lib/runtime_tools/c_src/Makefile.in8
-rw-r--r--lib/runtime_tools/c_src/dtrace_user.d28
-rw-r--r--lib/runtime_tools/c_src/dyntrace.c77
-rw-r--r--lib/runtime_tools/c_src/trace_ip_drv.c8
-rw-r--r--lib/runtime_tools/doc/src/Makefile18
-rw-r--r--lib/runtime_tools/examples/user-probe-n.d44
-rw-r--r--lib/runtime_tools/examples/user-probe-n.systemtap53
-rw-r--r--lib/runtime_tools/examples/user-probe.systemtap4
-rw-r--r--lib/runtime_tools/src/Makefile16
-rw-r--r--lib/runtime_tools/src/dyntrace.erl171
-rw-r--r--lib/runtime_tools/test/Makefile10
-rw-r--r--lib/sasl/doc/src/Makefile22
-rw-r--r--lib/sasl/examples/src/Makefile8
-rw-r--r--lib/sasl/src/Makefile10
-rw-r--r--lib/sasl/test/Makefile10
-rw-r--r--lib/sasl/test/installer.erl4
-rw-r--r--lib/snmp/doc/src/Makefile26
-rw-r--r--lib/snmp/doc/src/notes.xml92
-rw-r--r--lib/snmp/doc/src/snmp_config.xml3
-rw-r--r--lib/snmp/doc/src/snmpa_network_interface_filter.xml6
-rw-r--r--lib/snmp/doc/src/snmpm.xml14
-rw-r--r--lib/snmp/doc/src/snmpm_network_interface_filter.xml4
-rw-r--r--lib/snmp/examples/ex1/Makefile2
-rw-r--r--lib/snmp/examples/ex2/Makefile2
-rw-r--r--lib/snmp/mibs/Makefile.in24
-rw-r--r--lib/snmp/priv/conf/agent/Makefile6
-rw-r--r--lib/snmp/priv/conf/manager/Makefile6
-rw-r--r--lib/snmp/src/agent/Makefile14
-rw-r--r--lib/snmp/src/agent/snmp_user_based_sm_mib.erl190
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl113
-rw-r--r--lib/snmp/src/app/Makefile14
-rw-r--r--lib/snmp/src/app/snmp.appup.src49
-rw-r--r--lib/snmp/src/compile/Makefile14
-rw-r--r--lib/snmp/src/manager/Makefile14
-rw-r--r--lib/snmp/src/manager/snmpm.erl2
-rw-r--r--lib/snmp/src/misc/Makefile14
-rw-r--r--lib/snmp/src/misc/snmp_pdus.erl110
-rw-r--r--lib/snmp/test/Makefile12
-rw-r--r--lib/snmp/test/snmp_agent_test.erl56
-rw-r--r--lib/snmp/test/snmp_pdus_test.erl176
-rw-r--r--lib/snmp/vsn.mk2
-rw-r--r--lib/ssh/doc/src/Makefile14
-rw-r--r--lib/ssh/examples/Makefile4
-rw-r--r--lib/ssh/src/Makefile12
-rw-r--r--lib/ssh/src/ssh_connection.erl13
-rw-r--r--lib/ssh/src/ssh_connection_manager.erl6
-rw-r--r--lib/ssh/test/Makefile12
-rw-r--r--lib/ssl/doc/src/Makefile18
-rw-r--r--lib/ssl/doc/src/ssl.xml14
-rw-r--r--lib/ssl/examples/certs/Makefile6
-rw-r--r--lib/ssl/examples/src/Makefile8
-rw-r--r--lib/ssl/src/Makefile8
-rw-r--r--lib/ssl/src/ssl.erl36
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl193
-rw-r--r--lib/ssl/src/ssl_connection.erl317
-rw-r--r--lib/ssl/src/ssl_handshake.erl44
-rw-r--r--lib/ssl/src/ssl_manager.erl202
-rw-r--r--lib/ssl/src/ssl_session.erl120
-rw-r--r--lib/ssl/src/ssl_session_cache.erl4
-rw-r--r--lib/ssl/test/Makefile10
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl60
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl3
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl1
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl1
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl18
-rw-r--r--lib/stdlib/doc/src/Makefile18
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml8
-rw-r--r--lib/stdlib/examples/Makefile4
-rw-r--r--lib/stdlib/src/Makefile15
-rw-r--r--lib/stdlib/src/erl_lint.erl5
-rw-r--r--lib/stdlib/src/escript.erl18
-rw-r--r--lib/stdlib/src/filelib.erl3
-rw-r--r--lib/stdlib/src/filename.erl2
-rw-r--r--lib/stdlib/src/gen_server.erl2
-rw-r--r--lib/stdlib/src/lib.erl4
-rw-r--r--lib/stdlib/test/Makefile8
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl25
-rw-r--r--lib/stdlib/test/escript_SUITE.erl151
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl17
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl105
-rw-r--r--lib/stdlib/test/ets_SUITE.erl51
-rw-r--r--lib/stdlib/test/filename_SUITE.erl15
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl22
-rw-r--r--lib/stdlib/test/io_proto_SUITE.erl25
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl8
-rw-r--r--lib/stdlib/test/shell_SUITE.erl12
-rw-r--r--lib/syntax_tools/doc/src/Makefile14
-rw-r--r--lib/syntax_tools/examples/Makefile4
-rw-r--r--lib/syntax_tools/src/Makefile8
-rw-r--r--lib/syntax_tools/test/Makefile8
-rw-r--r--lib/test_server/doc/src/Makefile18
-rw-r--r--lib/test_server/src/Makefile20
-rw-r--r--lib/test_server/src/test_server_node.erl8
-rw-r--r--lib/test_server/src/ts_autoconf_win32.erl1
-rw-r--r--lib/test_server/src/ts_erl_config.erl47
-rw-r--r--lib/test_server/src/ts_install.erl11
-rw-r--r--lib/test_server/src/ts_make.erl4
-rw-r--r--lib/test_server/src/ts_run.erl2
-rw-r--r--lib/test_server/test/Makefile10
-rw-r--r--lib/toolbar/doc/src/Makefile14
-rw-r--r--lib/toolbar/src/Makefile8
-rw-r--r--lib/tools/c_src/Makefile.in8
-rw-r--r--lib/tools/doc/src/Makefile14
-rw-r--r--lib/tools/doc/src/eprof.xml10
-rw-r--r--lib/tools/emacs/Makefile8
-rw-r--r--lib/tools/emacs/erlang.el62
-rw-r--r--lib/tools/emacs/test.erl.indented43
-rw-r--r--lib/tools/emacs/test.erl.orig43
-rw-r--r--lib/tools/examples/Makefile4
-rw-r--r--lib/tools/priv/Makefile6
-rw-r--r--lib/tools/src/Makefile8
-rw-r--r--lib/tools/src/fprof.erl23
-rw-r--r--lib/tools/src/xref_utils.erl4
-rw-r--r--lib/tools/test/Makefile8
-rw-r--r--lib/tools/test/cover_SUITE.erl7
-rw-r--r--lib/tools/test/xref_SUITE.erl16
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/tv/doc/src/Makefile14
-rw-r--r--lib/tv/priv/Makefile4
-rw-r--r--lib/tv/src/Makefile8
-rw-r--r--lib/typer/src/Makefile8
-rw-r--r--lib/typer/src/typer.erl10
-rw-r--r--lib/webtool/doc/src/Makefile18
-rw-r--r--lib/webtool/priv/Makefile16
-rw-r--r--lib/webtool/src/Makefile8
-rw-r--r--lib/wx/api_gen/wx_extra/wxEvtHandler.erl2
-rw-r--r--lib/wx/c_src/Makefile.in10
-rw-r--r--lib/wx/doc/src/Makefile20
-rw-r--r--lib/wx/examples/demo/Makefile2
-rw-r--r--lib/wx/examples/simple/Makefile2
-rw-r--r--lib/wx/examples/sudoku/Makefile2
-rw-r--r--lib/wx/examples/xrc/Makefile2
-rw-r--r--lib/wx/src/Makefile18
-rw-r--r--lib/wx/src/gen/wxEvtHandler.erl2
-rw-r--r--lib/wx/test/Makefile6
-rw-r--r--lib/xmerl/doc/src/Makefile16
-rw-r--r--lib/xmerl/src/Makefile16
-rw-r--r--lib/xmerl/test/Makefile24
490 files changed, 12698 insertions, 5065 deletions
diff --git a/lib/.gitignore b/lib/.gitignore
index 56b1ed2b84..4125111ebd 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -7,6 +7,7 @@
/common_test/doc/src/ct_rpc.xml
/common_test/doc/src/ct_snmp.xml
/common_test/doc/src/ct_ssh.xml
+/common_test/doc/src/ct_netconfc.xml
/common_test/doc/src/ct_telnet.xml
/common_test/doc/src/unix_telnet.xml
diff --git a/lib/appmon/doc/src/Makefile b/lib/appmon/doc/src/Makefile
index 743f123c06..2bf560ee6b 100644
--- a/lib/appmon/doc/src/Makefile
+++ b/lib/appmon/doc/src/Makefile
@@ -107,14 +107,14 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/appmon/priv/Makefile b/lib/appmon/priv/Makefile
index 9af4fbd228..8920923c98 100644
--- a/lib/appmon/priv/Makefile
+++ b/lib/appmon/priv/Makefile
@@ -57,8 +57,8 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(HELP_FILES) $(TOOLBAR_FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(HELP_FILES) $(TOOLBAR_FILES) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/appmon/src/Makefile b/lib/appmon/src/Makefile
index 43f4f085b8..9ee7c92a4d 100644
--- a/lib/appmon/src/Makefile
+++ b/lib/appmon/src/Makefile
@@ -92,10 +92,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/asn1/c_src/Makefile b/lib/asn1/c_src/Makefile
index 8c06be56f8..903cf32838 100644
--- a/lib/asn1/c_src/Makefile
+++ b/lib/asn1/c_src/Makefile
@@ -110,10 +110,10 @@ $(NIF_SHARED_OBJ_FILE): $(NIF_OBJ_FILES)
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_PROGRAM) $(NIF_SHARED_OBJ_FILE) $(RELSYSDIR)/priv/lib
- $(INSTALL_DIR) $(RELSYSDIR)/c_src
- $(INSTALL_DATA) *.c $(RELSYSDIR)/c_src
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/lib"
+ $(INSTALL_PROGRAM) $(NIF_SHARED_OBJ_FILE) "$(RELSYSDIR)/priv/lib"
+ $(INSTALL_DIR) "$(RELSYSDIR)/c_src"
+ $(INSTALL_DATA) *.c "$(RELSYSDIR)/c_src"
release_docs_spec:
diff --git a/lib/asn1/doc/src/Makefile b/lib/asn1/doc/src/Makefile
index 20bd00a3b8..9ef5750353 100644
--- a/lib/asn1/doc/src/Makefile
+++ b/lib/asn1/doc/src/Makefile
@@ -119,13 +119,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 5614cbea91..4bd49aa93b 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -153,16 +153,16 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(APP_SRC) $(APPUP_SRC) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(EXAMPLES) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(APP_SRC) $(APPUP_SRC) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(EXAMPLES) "$(RELSYSDIR)/examples"
# there are no include files to be used by the user
-#$(INSTALL_DIR) $(RELSYSDIR)/include
-#$(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
+#$(INSTALL_DIR) "$(RELSYSDIR)/include"
+#$(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index 187339fb53..59e82b7a57 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -4177,7 +4177,7 @@ check_constraint(S,{'SizeConstraint',Lb}) ->
check_constraint(S,{'SingleValue', L}) when is_list(L) ->
F = fun(A) -> resolv_value(S,A) end,
- {'SingleValue',lists:map(F,L)};
+ {'SingleValue',lists:sort(lists:map(F,L))};
check_constraint(S,{'SingleValue', V}) when is_integer(V) ->
Val = resolv_value(S,V),
@@ -5991,17 +5991,25 @@ generate_automatic_tags1([H|T],[TagNo|TagNos]) when is_record(H,'ComponentType')
type={default,'IMPLICIT'},
form= 0 }]}, % PRIMITIVE
[H#'ComponentType'{typespec=NewTs}|generate_automatic_tags1(T,[TagNo+1|TagNos])];
-generate_automatic_tags1([ExtMark|T],[_TagNo|TagNos]) -> % EXTENSIONMARK
+generate_automatic_tags1([ExtMark = #'EXTENSIONMARK'{}|T],[_TagNo|TagNos]) ->
[ExtMark | generate_automatic_tags1(T,TagNos)];
+generate_automatic_tags1([H|T],TagList) -> % ExtensionAdditionGroup etc are just ignored
+ [H | generate_automatic_tags1(T,TagList)];
generate_automatic_tags1([],_) ->
[].
-any_manual_tag([#'ComponentType'{typespec=#type{tag=[]}}|Rest]) ->
- any_manual_tag(Rest);
-any_manual_tag([#'EXTENSIONMARK'{}|Rest]) ->
- any_manual_tag(Rest);
-any_manual_tag([_|_Rest]) ->
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Returns true if there is at least one ComponentType with a manually
+%% specified tag. No manual tag is indicated by typespec=#type{tag=[]}
+%% so we check if we find a tag =/= [] and return true in that case
+%% all other things in the componentlist like (EXTENSIONMARK,
+%% ExtensionAdditionGroup,...) except ComponentType is simply
+%% ignored/skipped
+any_manual_tag([#'ComponentType'{typespec=#type{tag=Tag}}|_Rest])
+ when Tag =/= []->
true;
+any_manual_tag([_|Rest]) ->
+ any_manual_tag(Rest);
any_manual_tag([]) ->
false.
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index e07680f10b..5f5138ef23 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -100,18 +100,26 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) ->
case Ext of
{ext,_,NumExt} when NumExt > 0 ->
case extgroup_pos_and_length(CompList) of
- {extgrouppos,ExtGroupPos,ExtGroupLen} ->
- Elements = make_elements(ExtGroupPos+1,
- "Val1",lists:seq(1,ExtGroupLen)),
- emit([
- {next,val}," = case [X || X <- [",Elements,
- "],X =/= asn1_NOVALUE] of",nl,
- "[] -> ",{curr,val},";",nl,
- "_ -> setelement(",{asis,ExtGroupPos+1},",",
- {curr,val},",",
- "{extaddgroup,", Elements,"})",nl,
- "end,",nl]),
- asn1ct_name:new(val);
+ {extgrouppos,[]} -> % no extenstionAdditionGroup
+ ok;
+ {extgrouppos,ExtGroupPosLenList} ->
+ ExtGroupFun =
+ fun({ExtActualGroupPos,ExtGroupVirtualPos,ExtGroupLen}) ->
+ Elements =
+ make_elements(ExtGroupVirtualPos+1,
+ "Val1",
+ lists:seq(1,ExtGroupLen)),
+ emit([
+ {next,val}," = case [X || X <- [",Elements,
+ "],X =/= asn1_NOVALUE] of",nl,
+ "[] -> ",{curr,val},";",nl,
+ "_ -> setelement(",{asis,ExtActualGroupPos+1},",",
+ {curr,val},",",
+ "{extaddgroup,", Elements,"})",nl,
+ "end,",nl]),
+ asn1ct_name:new(val)
+ end,
+ lists:foreach(ExtGroupFun,ExtGroupPosLenList);
_ -> % no extensionAdditionGroup
ok
end,
@@ -279,9 +287,9 @@ gen_decode_constructed(Erules,Typename,D) when is_record(D,type) ->
{false,false,false}
end
end,
- NewCompList = wrap_compList(CompList),
+%% NewCompList = wrap_compList(CompList),
{AccTerm,AccBytes} =
- gen_dec_components_call(Erules,Typename,NewCompList,MaybeComma2,DecObjInf,Ext,length(Optionals)),
+ gen_dec_components_call(Erules,Typename,CompList,MaybeComma2,DecObjInf,Ext,length(Optionals)),
case asn1ct_name:all(term) of
[] -> emit(MaybeComma2); % no components at all
_ -> emit({com,nl})
@@ -689,24 +697,28 @@ ext_length([],_,Acc) ->
Acc.
extgroup_pos_and_length(CompList) when is_list(CompList) ->
- noextgroup;
+ {extgrouppos,[]};
extgroup_pos_and_length({RootList,ExtList}) ->
- extgrouppos(ExtList,length(RootList)+1);
-extgroup_pos_and_length({Rl1,Ext,_Rl2}) ->
- extgrouppos(Ext,length(Rl1)+1).
-
-extgrouppos([{'ExtensionAdditionGroup',_Num}|T],Pos) ->
- extgrouppos(T,Pos,0);
-extgrouppos([_|T],Pos) ->
- extgrouppos(T,Pos+1);
-extgrouppos([],_) ->
- noextgroup.
-
-extgrouppos(['ExtensionAdditionGroupEnd'|_T],Pos,Len) ->
- {extgrouppos,Pos,Len};
-extgrouppos([_|T],Pos,Len) ->
- extgrouppos(T,Pos,Len+1).
-
+ ActualPos = length(RootList) +1,
+ %% position to get and deliver data in the record to the user
+ VirtualPos = ActualPos,
+ %% position to encode/decode the extaddgroup as an opentype sequence
+ extgrouppos(ExtList,ActualPos,VirtualPos,[]);
+extgroup_pos_and_length({RootList,ExtList,_Rl2}) ->
+ extgroup_pos_and_length({RootList,ExtList}).
+
+extgrouppos([{'ExtensionAdditionGroup',_Num}|T],ActualPos,VirtualPos,Acc) ->
+ extgrouppos(T,ActualPos,VirtualPos,0,Acc);
+extgrouppos([_|T],ActualPos,VirtualPos,Acc) ->
+ extgrouppos(T,ActualPos+1,VirtualPos+1,Acc);
+extgrouppos([],_,_,Acc) ->
+ {extgrouppos,lists:reverse(Acc)}.
+
+extgrouppos(['ExtensionAdditionGroupEnd'|T],ActualPos,VirtualPos,Len,Acc) ->
+ extgrouppos(T,ActualPos+1,VirtualPos+Len,[{ActualPos,VirtualPos,Len}|Acc]);
+extgrouppos([_|T],ActualPos,VirtualPos,Len,Acc) ->
+ extgrouppos(T,ActualPos,VirtualPos,Len+1,Acc).
+
gen_dec_extension_value(_) ->
@@ -817,19 +829,21 @@ add_textual_order1(Cs,NumIn) ->
end,
NumIn,Cs).
-gen_enc_components_call(Erule,TopType,{Root1,ExtList,Root2},MaybeComma,DynamicEnc,Ext) ->
- gen_enc_components_call(Erule,TopType,{Root1++Root2,ExtList},MaybeComma,DynamicEnc,Ext);
-gen_enc_components_call(Erule,TopType,{CompList,ExtList},MaybeComma,DynamicEnc,Ext) ->
+gen_enc_components_call(Erule,TopType,{Root,ExtList},MaybeComma,DynamicEnc,Ext) ->
+ gen_enc_components_call(Erule,TopType,{Root,ExtList,[]},MaybeComma,DynamicEnc,Ext);
+gen_enc_components_call(Erule,TopType,CL={Root,ExtList,Root2},MaybeComma,DynamicEnc,Ext) ->
%% The type has extensionmarker
- Rpos = gen_enc_components_call1(Erule,TopType,CompList,1,MaybeComma,DynamicEnc,noext),
+ Rpos = gen_enc_components_call1(Erule,TopType,Root++Root2,1,MaybeComma,DynamicEnc,noext),
case Ext of
{ext,_,ExtNum} when ExtNum > 0 ->
emit([nl,
",Extensions",nl]);
+
_ -> true
end,
%handle extensions
- NewExtList = wrap_extensionAdditionGroups(ExtList),
+ {extgrouppos,ExtGroupPosLen} = extgroup_pos_and_length(CL),
+ NewExtList = wrap_extensionAdditionGroups(ExtList,ExtGroupPosLen),
gen_enc_components_call1(Erule,TopType,NewExtList,Rpos,MaybeComma,DynamicEnc,Ext);
gen_enc_components_call(Erule,TopType, CompList, MaybeComma, DynamicEnc, Ext) ->
%% The type has no extensionmarker
@@ -938,7 +952,7 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
Atype =
case Type of
#type{def=#'ObjectClassFieldType'{type=InnerType}} ->
- InnerType;
+ InnerType;
_ ->
asn1ct_gen:get_inner(Type#type.def)
end,
@@ -948,6 +962,7 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
emit(["?RT_PER:encode_open_type(dummy,?RT_PER:complete("]);
_ -> true
end,
+
case Atype of
{typefield,_} ->
case DynamicEnc of
@@ -1023,20 +1038,22 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
emit("))");
_ -> true
end.
-gen_dec_components_call(Erule,TopType,{Root1,ExtList,Root2},MaybeComma,DecInfObj,Ext,NumberOfOptionals) ->
- gen_dec_components_call(Erule,TopType,{Root1++Root2,ExtList},MaybeComma,DecInfObj,Ext,NumberOfOptionals);
-gen_dec_components_call(Erule,TopType,{CompList,ExtList},MaybeComma,
+gen_dec_components_call(Erule,TopType,{Root,ExtList},MaybeComma,
DecInfObj,Ext,NumberOfOptionals) ->
+ gen_dec_components_call(Erule,TopType,{Root,ExtList,[]},MaybeComma,DecInfObj,Ext,NumberOfOptionals);
+gen_dec_components_call(Erule,TopType,CL={Root1,ExtList,Root2},MaybeComma,DecInfObj,Ext,NumberOfOptionals) ->
%% The type has extensionmarker
- OptTable = create_optionality_table(CompList),
+
+ OptTable = create_optionality_table(Root1++Root2),
{Rpos,AccTerm,AccBytes} =
- gen_dec_components_call1(Erule,TopType, CompList, 1, OptTable,
+ gen_dec_components_call1(Erule,TopType, Root1++Root2, 1, OptTable,
MaybeComma,DecInfObj,noext,[],[],
NumberOfOptionals),
emit([",",nl,"{Extensions,",{next,bytes},"} = "]),
emit(["?RT_PER:getextension(Ext,",{curr,bytes},"),",nl]),
asn1ct_name:new(bytes),
- NewExtList = wrap_extensionAdditionGroups(ExtList),
+ {extgrouppos,ExtGroupPosLen} = extgroup_pos_and_length(CL),
+ NewExtList = wrap_extensionAdditionGroups(ExtList,ExtGroupPosLen),
{_Epos,AccTermE,AccBytesE} =
gen_dec_components_call1(Erule,TopType,NewExtList,Rpos, OptTable,
"",DecInfObj,Ext,[],[],NumberOfOptionals),
@@ -1233,8 +1250,7 @@ gen_dec_line(Erule,TopType,Cname,Type,Pos,DecInfObj,Ext,Prop) ->
"} = ?RT_PER:decode_open_type(",{curr,bytes},
", []),",nl]),
emit([indent(2),"case (catch ObjFun(",
- {asis,Name},
- ",",{curr,tmpterm},",telltype,",
+ {asis,Name},",",{curr,tmpterm},",telltype,",
{asis,RestFieldNames},")) of", nl]),
emit([indent(4),"{'EXIT',",{curr,reason},"} ->",nl]),
emit([indent(6),"exit({'Type not ",
@@ -1596,42 +1612,44 @@ flat_complist({Rl1,El,Rl2}) -> Rl1 ++ El ++ Rl2;
flat_complist({Rl,El}) -> Rl ++ El;
flat_complist(CompList) -> CompList.
-wrap_compList({Root1,Ext,Root2}) ->
- {Root1,wrap_extensionAdditionGroups(Ext),Root2};
-wrap_compList({Root1,Ext}) ->
- {Root1,wrap_extensionAdditionGroups(Ext)};
-wrap_compList(CompList) ->
- CompList.
+%%wrap_compList({Root1,Ext,Root2}) ->
+%% {Root1,wrap_extensionAdditionGroups(Ext),Root2};
+%%wrap_compList({Root1,Ext}) ->
+%% {Root1,wrap_extensionAdditionGroups(Ext)};
+%%wrap_compList(CompList) ->
+%% CompList.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Will convert all componentTypes following 'ExtensionAdditionGroup'
%% up to the matching 'ExtensionAdditionGroupEnd' into one componentType
%% of type SEQUENCE with the componentTypes as components
%%
-wrap_extensionAdditionGroups(ExtCompList) ->
- wrap_extensionAdditionGroups(ExtCompList,[],0).
+wrap_extensionAdditionGroups(ExtCompList,ExtGroupPosLen) ->
+ wrap_extensionAdditionGroups(ExtCompList,ExtGroupPosLen,[],0,0).
-wrap_extensionAdditionGroups([{'ExtensionAdditionGroup',_Number}|Rest],Acc,0) ->
- {ExtGroupCompList=
- [#'ComponentType'{textual_order=TextPos}|_],
- ['ExtensionAdditionGroupEnd'|Rest2]} =
+wrap_extensionAdditionGroups([{'ExtensionAdditionGroup',_Number}|Rest],
+ [{ActualPos,_,_}|ExtGroupPosLenRest],Acc,_ExtAddGroupDiff,ExtGroupNum) ->
+ {ExtGroupCompList,['ExtensionAdditionGroupEnd'|Rest2]} =
lists:splitwith(fun(#'ComponentType'{}) -> true;
(_) -> false
end,
Rest),
- wrap_extensionAdditionGroups(Rest2,
+ wrap_extensionAdditionGroups(Rest2,ExtGroupPosLenRest,
[#'ComponentType'{
- name='ExtAddGroup', % FIXME: handles ony one ExtAddGroup
- typespec=#type{def=#'SEQUENCE'{
- extaddgroup=1,% FIXME: handles only one
+ name=list_to_atom("ExtAddGroup"++
+ integer_to_list(ExtGroupNum+1)),
+ typespec=#type{def=#'SEQUENCE'{
+ extaddgroup=ExtGroupNum+1,
components=ExtGroupCompList}},
- textual_order = TextPos,
- prop='OPTIONAL'}|Acc],length(ExtGroupCompList)-1);
-wrap_extensionAdditionGroups([H=#'ComponentType'{textual_order=Tord}|T],Acc,ExtAddGroupDiff) when is_integer(Tord) ->
- wrap_extensionAdditionGroups(T,[H#'ComponentType'{
- textual_order=Tord - ExtAddGroupDiff}|Acc],ExtAddGroupDiff);
-wrap_extensionAdditionGroups([H|T],Acc,ExtAddGroupDiff) ->
- wrap_extensionAdditionGroups(T,[H|Acc],ExtAddGroupDiff);
-wrap_extensionAdditionGroups([],Acc,_) ->
+ textual_order = ActualPos,
+ prop='OPTIONAL'}|Acc],length(ExtGroupCompList)-1,
+ ExtGroupNum+1);
+wrap_extensionAdditionGroups([H=#'ComponentType'{textual_order=Tord}|T],
+ ExtAddGrpLenPos,Acc,ExtAddGroupDiff,ExtGroupNum) when is_integer(Tord) ->
+ wrap_extensionAdditionGroups(T,ExtAddGrpLenPos,[H#'ComponentType'{
+ textual_order=Tord - ExtAddGroupDiff}|Acc],ExtAddGroupDiff,ExtGroupNum);
+wrap_extensionAdditionGroups([H|T],ExtAddGrpLenPos,Acc,ExtAddGroupDiff,ExtGroupNum) ->
+ wrap_extensionAdditionGroups(T,ExtAddGrpLenPos,[H|Acc],ExtAddGroupDiff,ExtGroupNum);
+wrap_extensionAdditionGroups([],_,Acc,_,_) ->
lists:reverse(Acc).
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index fda4e1c6d9..64a3555f62 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -129,28 +129,39 @@ pgen_types(Rtmod,Erules,N2nConvEnums,Module,[H|T]) ->
end,
pgen_types(Rtmod,Erules,N2nConvEnums,Module,T).
+%% Enumerated type with extension marker
pgen_n2nconversion(_Erules,#typedef{name=TypeName,typespec=#type{def={'ENUMERATED',{NN1,NN2}}}}) ->
NN = NN1 ++ NN2,
- pgen_name2numfunc(TypeName,NN),
- pgen_num2namefunc(TypeName,NN);
+ pgen_name2numfunc(TypeName,NN, extension_marker),
+ pgen_num2namefunc(TypeName,NN, extension_marker);
+%% Without extension marker
+pgen_n2nconversion(_Erules,#typedef{name=TypeName,typespec=#type{def={'ENUMERATED',NN}}}) ->
+ pgen_name2numfunc(TypeName,NN, no_extension_marker),
+ pgen_num2namefunc(TypeName,NN, no_extension_marker);
pgen_n2nconversion(_Erules,_) ->
true.
-pgen_name2numfunc(_TypeName,[]) ->
+pgen_name2numfunc(_TypeName,[], _) ->
true;
-pgen_name2numfunc(TypeName,[{Atom,Number}]) ->
+pgen_name2numfunc(TypeName,[{Atom,Number}], extension_marker) ->
+ emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,";",nl]),
+ emit(["name2num_",TypeName,"({asn1_enum, Num}) -> Num.",nl,nl]);
+pgen_name2numfunc(TypeName,[{Atom,Number}], _) ->
emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,".",nl,nl]);
-pgen_name2numfunc(TypeName,[{Atom,Number}|NNRest]) ->
+pgen_name2numfunc(TypeName,[{Atom,Number}|NNRest], EM) ->
emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,";",nl]),
- pgen_name2numfunc(TypeName,NNRest).
+ pgen_name2numfunc(TypeName,NNRest, EM).
-pgen_num2namefunc(_TypeName,[]) ->
+pgen_num2namefunc(_TypeName,[], _) ->
true;
-pgen_num2namefunc(TypeName,[{Atom,Number}]) ->
+pgen_num2namefunc(TypeName,[{Atom,Number}], extension_marker) ->
+ emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},";",nl]),
+ emit(["num2name_",TypeName,"(ExtensionNum) -> {asn1_enum, ExtensionNum}.",nl,nl]);
+pgen_num2namefunc(TypeName,[{Atom,Number}], _) ->
emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},".",nl,nl]);
-pgen_num2namefunc(TypeName,[{Atom,Number}|NNRest]) ->
+pgen_num2namefunc(TypeName,[{Atom,Number}|NNRest], EM) ->
emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},";",nl]),
- pgen_num2namefunc(TypeName,NNRest).
+ pgen_num2namefunc(TypeName,NNRest, EM).
pgen_objects(_,_,_,[]) ->
true;
diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
index 597fb0030b..3ccfca3784 100644
--- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
@@ -419,7 +419,7 @@ gen_decode_selected(Erules,Type,FuncName) ->
" {Tlv,_} = ?RT_BER:decode(Bin2",asn1ct_gen:nif_parameter(),"),",nl]),
emit("{ok,"),
gen_decode_selected_type(Erules,Type),
- emit(["};",nl," Err -> exit({error,{selctive_decode,Err}})",nl,
+ emit(["};",nl," Err -> exit({error,{selective_decode,Err}})",nl,
" end.",nl]).
gen_decode_selected_type(_Erules,TypeDef) ->
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index 59b4b3d261..bd5b81991d 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -321,19 +321,13 @@ effective_constr(_,[]) ->
[];
effective_constr('SingleValue',List) ->
SVList = lists:flatten(lists:map(fun(X)->element(2,X)end,List)),
- % sort and remove duplicates
- SortedSVList = lists:sort(SVList),
- RemoveDup = fun([],_) ->[];
- ([H],_) -> [H];
- ([H,H|T],F) -> F([H|T],F);
- ([H|T],F) -> [H|F(T,F)]
- end,
-
- case RemoveDup(SortedSVList,RemoveDup) of
+ %% Sort and remove duplicates before generating SingleValue or ValueRange
+ %% In case of ValueRange, also check for 'MIN and 'MAX'
+ case lists:usort(SVList) of
[N] ->
[{'SingleValue',N}];
- L when is_list(L) ->
- [{'ValueRange',{hd(L),lists:last(L)}}]
+ L when is_list(L) ->
+ [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}]
end;
effective_constr('ValueRange',List) ->
LBs = lists:map(fun({_,{Lb,_}})-> Lb end,List),
@@ -1405,19 +1399,21 @@ get_object_field(Name,ObjectFields) ->
%% have been specified within a SEQUENCE, therefore we construct a fake sequence type here
%% so that we can generate code for it
extaddgroup2sequence(ExtList) ->
- extaddgroup2sequence(ExtList,[]).
+ extaddgroup2sequence(ExtList,0,[]).
-extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],Acc) ->
+extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],ExtNum,Acc) ->
Number = case Number0 of undefined -> 1; _ -> Number0 end,
{ExtGroupComps,['ExtensionAdditionGroupEnd'|T2]} =
lists:splitwith(fun(Elem) -> is_record(Elem,'ComponentType') end,T),
- extaddgroup2sequence(T2,[#'ComponentType'{
- name='ExtAddGroup',
- typespec=#type{def=#'SEQUENCE'{
- extaddgroup=Number,
- components=ExtGroupComps}},
- prop='OPTIONAL'}|Acc]);
-extaddgroup2sequence([C|T],Acc) ->
- extaddgroup2sequence(T,[C|Acc]);
-extaddgroup2sequence([],Acc) ->
+ extaddgroup2sequence(T2,ExtNum+1,
+ [#'ComponentType'{
+ name=list_to_atom("ExtAddGroup"++
+ integer_to_list(ExtNum+1)),
+ typespec=#type{def=#'SEQUENCE'{
+ extaddgroup=Number,
+ components=ExtGroupComps}},
+ prop='OPTIONAL'}|Acc]);
+extaddgroup2sequence([C|T],ExtNum,Acc) ->
+ extaddgroup2sequence(T,ExtNum,[C|Acc]);
+extaddgroup2sequence([],_,Acc) ->
lists:reverse(Acc).
diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
index 4add659d79..16eec92847 100644
--- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
+++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
@@ -670,18 +670,13 @@ effective_constr(_,[]) ->
[];
effective_constr('SingleValue',List) ->
SVList = lists:flatten(lists:map(fun(X)->element(2,X)end,List)),
- % sort and remove duplicates
- RemoveDup = fun([],_) ->[];
- ([H],_) -> [H];
- ([H,H|T],F) -> F([H|T],F);
- ([H|T],F) -> [H|F(T,F)]
- end,
-
- case RemoveDup(SVList,RemoveDup) of
+ %% Sort and remove duplicates before generating SingleValue or ValueRange
+ %% In case of ValueRange, also check for 'MIN and 'MAX'
+ case lists:usort(SVList) of
[N] ->
[{'SingleValue',N}];
- L when is_list(L) ->
- [{'ValueRange',{hd(L),lists:last(L)}}]
+ L when is_list(L) ->
+ [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}]
end;
effective_constr('ValueRange',List) ->
LBs = lists:map(fun({_,{Lb,_}})-> Lb end,List),
@@ -1808,19 +1803,21 @@ dec_enumerated_cases([],_,_) ->
%% have been specified within a SEQUENCE, therefore we construct a fake sequence type here
%% so that we can generate code for it
extaddgroup2sequence(ExtList) ->
- extaddgroup2sequence(ExtList,[]).
+ extaddgroup2sequence(ExtList,0,[]).
-extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],Acc) ->
+extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],ExtNum,Acc) ->
Number = case Number0 of undefined -> 1; _ -> Number0 end,
{ExtGroupComps,['ExtensionAdditionGroupEnd'|T2]} =
lists:splitwith(fun(Elem) -> is_record(Elem,'ComponentType') end,T),
- extaddgroup2sequence(T2,[#'ComponentType'{
- name='ExtAddGroup',
- typespec=#type{def=#'SEQUENCE'{
- extaddgroup=Number,
- components=ExtGroupComps}},
- prop='OPTIONAL'}|Acc]);
-extaddgroup2sequence([C|T],Acc) ->
- extaddgroup2sequence(T,[C|Acc]);
-extaddgroup2sequence([],Acc) ->
+ extaddgroup2sequence(T2,ExtNum+1,
+ [#'ComponentType'{
+ name=list_to_atom("ExtAddGroup"++
+ integer_to_list(ExtNum+1)),
+ typespec=#type{def=#'SEQUENCE'{
+ extaddgroup=Number,
+ components=ExtGroupComps}},
+ prop='OPTIONAL'}|Acc]);
+extaddgroup2sequence([C|T],ExtNum,Acc) ->
+ extaddgroup2sequence(T,ExtNum,[C|Acc]);
+extaddgroup2sequence([],_,Acc) ->
lists:reverse(Acc).
diff --git a/lib/asn1/src/asn1ct_parser2.erl b/lib/asn1/src/asn1ct_parser2.erl
index 007d390a1b..7301f49085 100644
--- a/lib/asn1/src/asn1ct_parser2.erl
+++ b/lib/asn1/src/asn1ct_parser2.erl
@@ -769,9 +769,11 @@ resolve_module(_Type, Current, undefined) ->
Current;
resolve_module(Type, Current, Imports) ->
case [Mod || #'SymbolsFromModule'{symbols = S, module = Mod} <- Imports,
- #'Externaltypereference'{type = T} <- S,
+ #'Externaltypereference'{type = T} <- S,
Type == T] of
- [#'Externaltypereference'{type = Mod}] -> Mod;
+ [#'Externaltypereference'{type = Mod}|_] -> Mod;
+ %% This allows the same symbol to be imported several times
+ %% which ought to be checked elsewhere and flagged as an error
[] -> Current
end.
diff --git a/lib/asn1/src/asn1rt_per_bin.erl b/lib/asn1/src/asn1rt_per_bin.erl
index a124c7553d..85988aa21d 100644
--- a/lib/asn1/src/asn1rt_per_bin.erl
+++ b/lib/asn1/src/asn1rt_per_bin.erl
@@ -18,7 +18,6 @@
%%
%%
-module(asn1rt_per_bin).
-
%% encoding / decoding of PER aligned
-include("asn1_records.hrl").
@@ -57,7 +56,7 @@
encode_NumericString/2, decode_NumericString/2,
encode_ObjectDescriptor/2, decode_ObjectDescriptor/1
]).
--export([complete_bytes/1, getbits/2, getoctets/2]).
+-export([complete_bytes/1, getbits/2, getoctets/2, minimum_bits/1]).
-define('16K',16384).
-define('32K',32768).
@@ -695,21 +694,28 @@ encode_constrained_number({Lb,Ub},Val) when Val >= Lb, Ub >= Val ->
{octets,[Val2]};
Range =< 65536 ->
{octets,<<Val2:16>>};
- Range =< 16#1000000 ->
- Octs = eint_positive(Val2),
- [{bits,2,length(Octs)-1},{octets,Octs}];
- Range =< 16#100000000 ->
- Octs = eint_positive(Val2),
- [{bits,2,length(Octs)-1},{octets,Octs}];
- Range =< 16#10000000000 ->
- Octs = eint_positive(Val2),
- [{bits,3,length(Octs)-1},{octets,Octs}];
+ Range =< (1 bsl (255*8)) ->
+ Octs = binary:encode_unsigned(Val2),
+ RangeOcts = binary:encode_unsigned(Range - 1),
+ OctsLen = erlang:byte_size(Octs),
+ RangeOctsLen = erlang:byte_size(RangeOcts),
+ LengthBitsNeeded = minimum_bits(RangeOctsLen - 1),
+ [{bits, LengthBitsNeeded, OctsLen - 1}, {octets, Octs}];
true ->
exit({not_supported,{integer_range,Range}})
end;
encode_constrained_number(Range,Val) ->
exit({error,{asn1,{integer_range,Range,value,Val}}}).
+%% For some reason the minimum bits needed in the length field in encoding of
+%% constrained whole numbers must always be atleast 2?
+minimum_bits(N) when N < 4 -> 2;
+minimum_bits(N) when N < 8 -> 3;
+minimum_bits(N) when N < 16 -> 4;
+minimum_bits(N) when N < 32 -> 5;
+minimum_bits(N) when N < 64 -> 6;
+minimum_bits(N) when N < 128 -> 7;
+minimum_bits(_N) -> 8.
decode_constrained_number(Buffer,{Lb,Ub}) ->
Range = Ub - Lb + 1,
@@ -738,18 +744,12 @@ decode_constrained_number(Buffer,{Lb,Ub}) ->
getoctets(Buffer,1);
Range =< 65536 ->
getoctets(Buffer,2);
- Range =< 16#1000000 ->
- {Len,Bytes2} = decode_length(Buffer,{1,3}),
- {Octs,Bytes3} = getoctets_as_list(Bytes2,Len),
- {dec_pos_integer(Octs),Bytes3};
- Range =< 16#100000000 ->
- {Len,Bytes2} = decode_length(Buffer,{1,4}),
- {Octs,Bytes3} = getoctets_as_list(Bytes2,Len),
- {dec_pos_integer(Octs),Bytes3};
- Range =< 16#10000000000 ->
- {Len,Bytes2} = decode_length(Buffer,{1,5}),
- {Octs,Bytes3} = getoctets_as_list(Bytes2,Len),
- {dec_pos_integer(Octs),Bytes3};
+ Range =< (1 bsl (255*8)) ->
+ OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)),
+ RangeOctLen = length(OList),
+ {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}),
+ {Octs, RestBytes} = getoctets_as_list(Bytes, Len),
+ {binary:decode_unsigned(binary:list_to_bin(Octs)), RestBytes};
true ->
exit({not_supported,{integer_range,Range}})
end,
diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
index 750b59aba6..46d4bcb065 100644
--- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
+++ b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
@@ -18,7 +18,6 @@
%%
%%
-module(asn1rt_per_bin_rt2ct).
-
%% encoding / decoding of PER aligned
-include("asn1_records.hrl").
@@ -605,19 +604,13 @@ encode_constrained_number({Lb,Ub},Val) when Val >= Lb, Ub >= Val ->
Range =< 65536 ->
% Size = {octets,<<Val2:16>>};
[20,2,<<Val2:16>>];
- Range =< 16#1000000 ->
- Octs = eint_positive(Val2),
-% [{bits,2,length(Octs)-1},{octets,Octs}];
- Len = length(Octs),
- [10,2,Len-1,20,Len,Octs];
- Range =< 16#100000000 ->
- Octs = eint_positive(Val2),
- Len = length(Octs),
- [10,2,Len-1,20,Len,Octs];
- Range =< 16#10000000000 ->
- Octs = eint_positive(Val2),
- Len = length(Octs),
- [10,3,Len-1,20,Len,Octs];
+ Range =< (1 bsl (255*8)) ->
+ Octs = binary:encode_unsigned(Val2),
+ RangeOcts = binary:encode_unsigned(Range - 1),
+ OctsLen = erlang:byte_size(Octs),
+ RangeOctsLen = erlang:byte_size(RangeOcts),
+ LengthBitsNeeded = asn1rt_per_bin:minimum_bits(RangeOctsLen - 1),
+ [10,LengthBitsNeeded,OctsLen-1,20,OctsLen,Octs];
true ->
exit({not_supported,{integer_range,Range}})
end;
@@ -661,18 +654,12 @@ decode_constrained_number(Buffer,{Lb,_Ub},Range) ->
getoctets(Buffer,1);
Range =< 65536 ->
getoctets(Buffer,2);
- Range =< 16#1000000 ->
- {Len,Bytes2} = decode_length(Buffer,{1,3}),
- {Octs,Bytes3} = getoctets_as_bin(Bytes2,Len),
- {dec_pos_integer(Octs),Bytes3};
- Range =< 16#100000000 ->
- {Len,Bytes2} = decode_length(Buffer,{1,4}),
- {Octs,Bytes3} = getoctets_as_bin(Bytes2,Len),
- {dec_pos_integer(Octs),Bytes3};
- Range =< 16#10000000000 ->
- {Len,Bytes2} = decode_length(Buffer,{1,5}),
- {Octs,Bytes3} = getoctets_as_bin(Bytes2,Len),
- {dec_pos_integer(Octs),Bytes3};
+ Range =< (1 bsl (255*8)) ->
+ OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)),
+ RangeOctLen = length(OList),
+ {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}),
+ {Octs, RestBytes} = getoctets_as_bin(Bytes, Len),
+ {binary:decode_unsigned(Octs), RestBytes};
true ->
exit({not_supported,{integer_range,Range}})
end,
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index 1621abbec9..6e6374baf1 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -156,13 +156,13 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/asn1_SUITE_data
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) asn1.spec asn1.cover $(INSTALL_PROGS) $(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
- rm $(RELSYSDIR)/asn1_SUITE_data.tar
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/asn1_SUITE_data"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) asn1.spec asn1.cover $(INSTALL_PROGS) "$(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"
+ rm "$(RELSYSDIR)/asn1_SUITE_data.tar"
release_docs_spec:
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 3b9a7532c0..56f31de638 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -773,6 +773,7 @@ per_open_type(Config, Rule, Opts) ->
testConstraints(Config) -> test(Config, fun testConstraints/3).
testConstraints(Config, Rule, Opts) ->
asn1_test_lib:compile("Constraints", Config, [Rule|Opts]),
+ asn1_test_lib:compile("LargeConstraints", Config, [Rule|Opts]),
testConstraints:int_constraints(Rule).
@@ -1236,6 +1237,27 @@ testName2Number(Config) ->
0 = 'S1AP-IEs':name2num_CauseMisc('control-processing-overload'),
'unknown-PLMN' = 'S1AP-IEs':num2name_CauseMisc(5),
+
+ %% OTP-10144
+ %% Test that n2n option generates name2num and num2name functions supporting
+ %% values not within the extension root if the enumeration type has an
+ %% extension marker.
+ N2NOptionsExt = [{n2n, 'NoExt'}, {n2n, 'Ext'}, {n2n, 'Ext2'}],
+ asn1_test_lib:compile("EnumN2N", Config, N2NOptionsExt),
+ %% Previously, name2num and num2name was not generated if the type didn't
+ %% have an extension marker:
+ 0 = 'EnumN2N':name2num_NoExt('blue'),
+ 2 = 'EnumN2N':name2num_NoExt('green'),
+ blue = 'EnumN2N':num2name_NoExt(0),
+ green = 'EnumN2N':num2name_NoExt(2),
+
+ %% Test enumeration extension:
+ 7 = 'EnumN2N':name2num_Ext2('orange'),
+ orange = 'EnumN2N':num2name_Ext2(7),
+ %% 7 is not defined in Ext, only in Ext2.
+ {asn1_enum, 7} = 'EnumN2N':num2name_Ext(7),
+ 7 = 'EnumN2N':name2num_Ext({asn1_enum, 7}),
+ 42 = 'EnumN2N':name2num_Ext2({asn1_enum, 42}),
ok.
ticket_7407(Config) ->
diff --git a/lib/asn1/test/asn1_SUITE_data/Constraints.py b/lib/asn1/test/asn1_SUITE_data/Constraints.py
index de48c4c2ca..87243121f7 100644
--- a/lib/asn1/test/asn1_SUITE_data/Constraints.py
+++ b/lib/asn1/test/asn1_SUITE_data/Constraints.py
@@ -4,9 +4,14 @@ BEGIN
-- Single Value
SingleValue ::= INTEGER (1)
SingleValue2 ::= INTEGER (1..20)
+predefined INTEGER ::= 1
+SingleValue3 ::= INTEGER (predefined | 5 | 10)
Range2to19 ::= INTEGER (1<..<20)
Range10to20 ::= INTEGER (10..20)
ContainedSubtype ::= INTEGER (INCLUDES Range10to20)
+-- Some ranges for additional constrained number testing.
+LongLong ::= INTEGER (0..18446744073709551615)
+Range256to65536 ::= INTEGER (256..65536)
FixedSize ::= OCTET STRING (SIZE(10))
FixedSize2 ::= OCTET STRING (SIZE(10|20))
VariableSize ::= OCTET STRING (SIZE(1..10))
diff --git a/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1 b/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1
new file mode 100644
index 0000000000..a724f2f3f5
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1
@@ -0,0 +1,25 @@
+EnumN2N DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+NoExt ::= ENUMERATED {
+ blue(0),
+ red(1),
+ green(2)
+}
+
+Ext ::= ENUMERATED {
+ blue(0),
+ red(1),
+ green(2),
+ ...
+}
+
+Ext2 ::= ENUMERATED {
+ blue(0),
+ red(1),
+ green(2),
+ ...,
+ orange(7)
+}
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
index fc244c30a2..cacef8b922 100644
--- a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
+++ b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
@@ -79,4 +79,22 @@ Ax3 ::= SEQUENCE {
}
-- { a 253, b TRUE, s {sa 17, sb TRUE, sextaddgroup 11}}
+
+-- This is to test the case with more than one ExtensionAdditionGroup
+-- which did not work before
+
+AS-Config ::= SEQUENCE {
+ a INTEGER,
+ b BOOLEAN,
+ c OCTET STRING,
+ ...,
+ [[ sourceSystemInformationBlockType1Ext OCTET STRING OPTIONAL,
+ sourceOtherConfig-r9 INTEGER
+ ]],
+ [[ sourceSCellConfigList-r10 OCTET STRING OPTIONAL
+ ]]
+}
+
+
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/LargeConstraints.py b/lib/asn1/test/asn1_SUITE_data/LargeConstraints.py
new file mode 100644
index 0000000000..68c7616b62
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/LargeConstraints.py
@@ -0,0 +1,9 @@
+LargeConstraints DEFINITIONS ::=
+BEGIN
+
+-- Maximum number that can be encoded as a constrained whole number: 1 bsl (255*8)
+-- The number of octets needed to represent a number cannot be more than 255
+-- As the length field is encoded as a 8-bit bitfield.
+RangeMax ::= INTEGER (1..126238304966058622268417487065116999845484776053576109500509161826268184136202698801551568013761380717534054534851164138648904527931605160527688095259563605939964364716019515983399209962459578542172100149937763938581219604072733422507180056009672540900709554109516816573779593326332288314873251559077853068444977864803391962580800682760017849589281937637993445539366428356761821065267423102149447628375691862210717202025241630303118559188678304314076943801692528246980959705901641444238894928620825482303431806955690226308773426829503900930529395181208739591967195841536053143145775307050594328881077553168201547776)
+
+END
diff --git a/lib/asn1/test/testConstraints.erl b/lib/asn1/test/testConstraints.erl
index 1ce68ec522..543c106e8a 100644
--- a/lib/asn1/test/testConstraints.erl
+++ b/lib/asn1/test/testConstraints.erl
@@ -52,8 +52,6 @@ int_constraints(Rules) ->
?line {error,_Reason2} =
asn1_wrapper:encode('Constraints','SingleValue',1000)
end,
-
-
%%==========================================================
%% SingleValue2 ::= INTEGER (1..20)
@@ -86,7 +84,21 @@ int_constraints(Rules) ->
asn1_wrapper:encode('Constraints','SingleValue',1000)
end,
+ %%==========================================================
+ %% SingleValue3 ::= INTEGER (Predefined | 5 | 10)
+ %% Testcase for OTP-10139. A single value subtyping of an integer type
+ %% where one value is predefined.
+ %%==========================================================
+ ?line {ok,BytesSV3} = asn1_wrapper:encode('Constraints','SingleValue3',1),
+ ?line {ok,1} = asn1_wrapper:decode('Constraints','SingleValue3',
+ lists:flatten(BytesSV3)),
+ ?line {ok,BytesSV3_2} = asn1_wrapper:encode('Constraints','SingleValue3',5),
+ ?line {ok,5} = asn1_wrapper:decode('Constraints','SingleValue3',
+ lists:flatten(BytesSV3_2)),
+ ?line {ok,BytesSV3_3} = asn1_wrapper:encode('Constraints','SingleValue3',10),
+ ?line {ok,10} = asn1_wrapper:decode('Constraints','SingleValue3',
+ lists:flatten(BytesSV3_3)),
%%==========================================================
%% Range2to19 ::= INTEGER (1<..<20)
@@ -116,7 +128,65 @@ int_constraints(Rules) ->
?line {error,_Reason6} =
asn1_wrapper:encode('Constraints','Range2to19',20)
end,
+
+ %%==========================================================
+ %% Tests for Range above 16^4 up to maximum supported by asn1 assuming the
+ %% octet length field is encoded on max 8 bits
+ %%==========================================================
+ LastNumWithoutLengthEncoding = 65536,
+ ?line {ok,BytesFoo} = asn1_wrapper:encode('Constraints','Range256to65536',
+ LastNumWithoutLengthEncoding),
+ ?line {ok,LastNumWithoutLengthEncoding} =
+ asn1_wrapper:decode('Constraints','Range256to65536',lists:flatten(BytesFoo)),
+
+ FirstNumWithLengthEncoding = 65537,
+ ?line {ok,BytesBar} = asn1_wrapper:encode('LargeConstraints','RangeMax',
+ FirstNumWithLengthEncoding),
+ ?line {ok,FirstNumWithLengthEncoding} =
+ asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBar)),
+
+ FirstNumOver16_6 = 16777217,
+ ?line {ok, BytesBaz} =
+ asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_6),
+ ?line {ok, FirstNumOver16_6} =
+ asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBaz)),
+
+ FirstNumOver16_8 = 4294967297,
+ ?line {ok, BytesQux} =
+ asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_8),
+ ?line {ok, FirstNumOver16_8} =
+ asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesQux)),
+
+ FirstNumOver16_10 = 1099511627776,
+ ?line {ok, BytesBur} =
+ asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_10),
+ ?line {ok, FirstNumOver16_10} =
+ asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBur)),
+
+ FirstNumOver16_10 = 1099511627776,
+ ?line {ok, BytesBur} =
+ asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_10),
+ ?line {ok, FirstNumOver16_10} =
+ asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBur)),
+
+ HalfMax = 1 bsl (128*8),
+ ?line {ok, BytesHalfMax} =
+ asn1_wrapper:encode('LargeConstraints','RangeMax', HalfMax),
+ ?line {ok, HalfMax} =
+ asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesHalfMax)),
+
+ Max = 1 bsl (255*8),
+ ?line {ok, BytesMax} =
+ asn1_wrapper:encode('LargeConstraints','RangeMax', Max),
+ ?line {ok, Max} =
+ asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesMax)),
+ %% Random number within longlong range
+ LongLong = 12672809400538808320,
+ ?line {ok, BytesLongLong} =
+ asn1_wrapper:encode('Constraints','LongLong', LongLong),
+ ?line {ok, LongLong} =
+ asn1_wrapper:decode('Constraints','LongLong',lists:flatten(BytesLongLong)),
%%==========================================================
%% Constraint Combinations (Duboisson p. 285)
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile
index d9651f13b0..99161ce68a 100644
--- a/lib/common_test/doc/src/Makefile
+++ b/lib/common_test/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2011. All Rights Reserved.
+# Copyright Ericsson AB 2003-2012. 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
@@ -46,7 +46,8 @@ CT_MODULES = \
ct_rpc \
ct_snmp \
unix_telnet \
- ct_slave
+ ct_slave \
+ ct_netconfc
CT_XML_FILES = $(CT_MODULES:=.xml)
@@ -123,7 +124,7 @@ $(HTMLDIR)/%.gif: %.gif
docs: pdf html man
-$(CT_XML_FILES):
+$(CT_XML_FILES): %.xml: ../../src/%.erl
escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -preprocess true -i $(XMERL_DIR)/include \
-i ../../../test_server/include -i ../../include \
-i ../../../../erts/lib/kernel/include -i ../../../../lib/kernel/include \
@@ -158,18 +159,18 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man1
- $(INSTALL_DATA) $(MAN1DIR)/* $(RELEASE_PATH)/man/man1
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6DIR)/* $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DATA) $(MAN1DIR)/* "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6DIR)/* "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml
index 1dbb841fb0..014507c886 100644
--- a/lib/common_test/doc/src/ct_hooks_chapter.xml
+++ b/lib/common_test/doc/src/ct_hooks_chapter.xml
@@ -453,7 +453,7 @@ terminate(State) ->
<cell>Captures all test results and outputs them as surefire XML into
a file. The file which is created is by default called junit_report.xml.
The name can be by setting the path option for this hook. e.g.
- <code>-ct_hooks cth_surefix [{path,"/tmp/report.xml"}]</code>
+ <code>-ct_hooks cth_surefire [{path,"/tmp/report.xml"}]</code>
Surefire XML can forinstance be used by Jenkins to display test
results.</cell>
</row>
diff --git a/lib/common_test/doc/src/ref_man.xml b/lib/common_test/doc/src/ref_man.xml
index a9fdef7359..6fede88434 100644
--- a/lib/common_test/doc/src/ref_man.xml
+++ b/lib/common_test/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2003</year><year>2011</year>
+ <year>2003</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -71,6 +71,7 @@
<xi:include href="ct_cover.xml"/>
<xi:include href="ct_ftp.xml"/>
<xi:include href="ct_ssh.xml"/>
+ <xi:include href="ct_netconfc.xml"/>
<xi:include href="ct_rpc.xml"/>
<xi:include href="ct_snmp.xml"/>
<xi:include href="ct_telnet.xml"/>
diff --git a/lib/common_test/priv/Makefile.in b/lib/common_test/priv/Makefile.in
index d9033f6ef1..8be6248e17 100644
--- a/lib/common_test/priv/Makefile.in
+++ b/lib/common_test/priv/Makefile.in
@@ -85,12 +85,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
ifeq ($(XNIX),true)
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) "$(RELSYSDIR)/priv"
else
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) "$(RELSYSDIR)/priv"
endif
release_docs_spec:
@@ -125,8 +125,8 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index 6a16c6f3af..f7dce195d7 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -70,14 +70,18 @@ MODULES= \
ct_hooks\
ct_hooks_lock\
cth_log_redirect\
- cth_surefire
+ cth_surefire \
+ ct_netconfc \
+ ct_conn_log_h \
+ cth_conn_log
TARGET_MODULES= $(MODULES:%=$(EBIN)/%)
BEAM_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
ERL_FILES= $(MODULES:=.erl)
HRL_FILES = \
- ct_util.hrl
+ ct_util.hrl \
+ ct_netconfc.hrl
EXTERNAL_HRL_FILES = \
../include/ct.hrl \
../include/ct_event.hrl
@@ -133,12 +137,12 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) "$(RELSYSDIR)/include"
release_tests_spec: opt
$(INSTALL_DIR) $(RELEASE_PATH)/common_test_test
diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src
index ae9a51faeb..18c1dec784 100644
--- a/lib/common_test/src/common_test.app.src
+++ b/lib/common_test/src/common_test.app.src
@@ -33,6 +33,8 @@
ct_master_event,
ct_master_logs,
ct_master_status,
+ ct_netconfc,
+ ct_conn_log_h,
ct_repeat,
ct_rpc,
ct_run,
@@ -49,6 +51,7 @@
ct_config_xml,
ct_slave,
cth_log_redirect,
+ cth_conn_log,
cth_surefire
]},
{registered, [ct_logs,
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 571d99029f..6373634812 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -66,7 +66,8 @@
capture_start/0, capture_stop/0, capture_get/0, capture_get/1,
fail/1, fail/2, comment/1, comment/2, make_priv_dir/0,
testcases/2, userdata/2, userdata/3,
- timetrap/1, get_timetrap_info/0, sleep/1]).
+ timetrap/1, get_timetrap_info/0, sleep/1,
+ notify/2, sync_notify/2]).
%% New API for manipulating with config handlers
-export([add_config/2, remove_config/2]).
@@ -1047,3 +1048,27 @@ sleep({seconds,Ss}) ->
sleep(trunc(Ss * 1000));
sleep(Time) ->
test_server:adjusted_sleep(Time).
+
+%%%-----------------------------------------------------------------
+%%% @spec notify(Name,Data) -> ok
+%%% Name = atom()
+%%% Data = term()
+%%%
+%%% @doc <p>Sends a asynchronous notification of type <c>Name</c> with
+%%% <c>Data</c>to the common_test event manager. This can later be
+%%% caught by any installed event manager. </p>
+%%% @see //stdlib/gen_event
+notify(Name,Data) ->
+ ct_event:notify(Name, Data).
+
+%%%-----------------------------------------------------------------
+%%% @spec sync_notify(Name,Data) -> ok
+%%% Name = atom()
+%%% Data = term()
+%%%
+%%% @doc <p>Sends a synchronous notification of type <c>Name</c> with
+%%% <c>Data</c>to the common_test event manager. This can later be
+%%% caught by any installed event manager. </p>
+%%% @see //stdlib/gen_event
+sync_notify(Name,Data) ->
+ ct_event:sync_notify(Name, Data).
diff --git a/lib/common_test/src/ct_conn_log_h.erl b/lib/common_test/src/ct_conn_log_h.erl
new file mode 100644
index 0000000000..f3b6781971
--- /dev/null
+++ b/lib/common_test/src/ct_conn_log_h.erl
@@ -0,0 +1,230 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. 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(ct_conn_log_h).
+
+%%%
+%%% A handler that can be connected to the error_logger event
+%%% handler. Writes all ct connection events. See comments in
+%%% cth_conn_log for more information.
+%%%
+
+-include("ct_util.hrl").
+
+-export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+-record(state, {group_leader,logs=[]}).
+
+-define(WIDTH,80).
+
+%%%-----------------------------------------------------------------
+%%% Callbacks
+init({GL,Logs}) ->
+ open_files(Logs,#state{group_leader=GL}).
+
+open_files([{ConnMod,{LogType,Logs}}|T],State) ->
+ case do_open_files(Logs,[]) of
+ {ok,Fds} ->
+ open_files(T,State#state{logs=[{ConnMod,{LogType,Fds}} |
+ State#state.logs]});
+ Error ->
+ Error
+ end;
+open_files([],State) ->
+ {ok,State}.
+
+
+do_open_files([{Tag,File}|Logs],Acc) ->
+ case file:open(File, [write]) of
+ {ok,Fd} ->
+ do_open_files(Logs,[{Tag,Fd}|Acc]);
+ {error,Reason} ->
+ {error,{could_not_open_log,File,Reason}}
+ end;
+do_open_files([],Acc) ->
+ {ok,lists:reverse(Acc)}.
+
+handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() ->
+ {ok, State};
+handle_event({_Type,_GL,{Pid,{ct_connection,Action,ConnName},Report}},State) ->
+ Info = conn_info(Pid,#conn_log{name=ConnName,action=Action}),
+ write_report(now(),Info,Report,State),
+ {ok, State};
+handle_event({_Type,_GL,{Pid,Info=#conn_log{},Report}},State) ->
+ write_report(now(),conn_info(Pid,Info),Report,State),
+ {ok, State};
+handle_event({error_report,_,{Pid,_,[{ct_connection,ConnName}|R]}},State) ->
+ %% Error reports from connection
+ write_error(now(),conn_info(Pid,#conn_log{name=ConnName}),R,State),
+ {ok, State};
+handle_event(_, State) ->
+ {ok, State}.
+
+handle_info(_, State) ->
+ {ok, State}.
+
+handle_call(_Query, State) ->
+ {ok, {error, bad_query}, State}.
+
+terminate(_,#state{logs=Logs}) ->
+ [file:close(Fd) || {_,_,Fds} <- Logs, Fd <- Fds],
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% Writing reports
+write_report(Time,#conn_log{module=ConnMod}=Info,Data,State) ->
+ {LogType,Fd} = get_log(Info,State),
+ io:format(Fd,"~n~s~s~s",[format_head(ConnMod,LogType,Time),
+ format_title(LogType,Info),
+ format_data(ConnMod,LogType,Data)]).
+
+write_error(Time,#conn_log{module=ConnMod}=Info,Report,State) ->
+ case get_log(Info,State) of
+ {html,_} ->
+ %% The error will anyway be written in the html log by the
+ %% sasl error handler, so don't write it again.
+ ok;
+ {LogType,Fd} ->
+ io:format(Fd,"~n~s~s~s",[format_head(ConnMod,LogType,Time," ERROR"),
+ format_title(LogType,Info),
+ format_error(LogType,Report)])
+ end.
+
+get_log(Info,State) ->
+ case proplists:get_value(Info#conn_log.module,State#state.logs) of
+ {html,_} ->
+ {html,State#state.group_leader};
+ {LogType,Fds} ->
+ {LogType,get_fd(Info,Fds)};
+ undefined ->
+ {html,State#state.group_leader}
+ end.
+
+get_fd(#conn_log{name=undefined},Fds) ->
+ proplists:get_value(default,Fds);
+get_fd(#conn_log{name=ConnName},Fds) ->
+ case proplists:get_value(ConnName,Fds) of
+ undefined ->
+ proplists:get_value(default,Fds);
+ Fd ->
+ Fd
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Formatting
+format_head(ConnMod,LogType,Time) ->
+ format_head(ConnMod,LogType,Time,"").
+
+format_head(ConnMod,raw,Time,Text) ->
+ io_lib:format("~n~p, ~p~s, ",[now_to_time(Time),ConnMod,Text]);
+format_head(ConnMod,_,Time,Text) ->
+ Head = pad_char_end(?WIDTH,pretty_head(now_to_time(Time),ConnMod,Text),$=),
+ io_lib:format("~n~s",[Head]).
+
+format_title(raw,#conn_log{client=Client}=Info) ->
+ io_lib:format("Client ~p ~s ~s",[Client,actionstr(Info),serverstr(Info)]);
+format_title(_,Info) ->
+ Title = pad_char_end(?WIDTH,pretty_title(Info),$=),
+ io_lib:format("~n~s", [Title]).
+
+format_data(_,_,NoData) when NoData == ""; NoData == <<>> ->
+ "";
+format_data(ConnMod,LogType,Data) ->
+ ConnMod:format_data(LogType,Data).
+
+format_error(raw,Report) ->
+ io_lib:format("~n~p~n",[Report]);
+format_error(pretty,Report) ->
+ [io_lib:format("~n ~p: ~p",[K,V]) || {K,V} <- Report].
+
+
+
+
+%%%-----------------------------------------------------------------
+%%% Helpers
+conn_info(LoggingProc, #conn_log{client=undefined} = ConnInfo) ->
+ conn_info(ConnInfo#conn_log{client=LoggingProc});
+conn_info(_, ConnInfo) ->
+ conn_info(ConnInfo).
+
+conn_info(#conn_log{client=Client, module=undefined} = ConnInfo) ->
+ case ets:lookup(ct_connections,Client) of
+ [#conn{address=Address,callback=Callback}] ->
+ ConnInfo#conn_log{address=Address,module=Callback};
+ [] ->
+ ConnInfo
+ end;
+conn_info(ConnInfo) ->
+ ConnInfo.
+
+
+now_to_time({_,_,MicroS}=Now) ->
+ {calendar:now_to_local_time(Now),MicroS}.
+
+pretty_head({{{Y,Mo,D},{H,Mi,S}},MicroS},ConnMod,Text0) ->
+ Text = string:to_upper(atom_to_list(ConnMod) ++ Text0),
+ io_lib:format("= ~s ==== ~s-~s-~p::~s:~s:~s,~s ",
+ [Text,t(D),month(Mo),Y,t(H),t(Mi),t(S),
+ micro2milli(MicroS)]).
+
+pretty_title(#conn_log{client=Client}=Info) ->
+ io_lib:format("= Client ~p ~s Server ~s ",
+ [Client,actionstr(Info),serverstr(Info)]).
+
+actionstr(#conn_log{action=send}) -> "----->";
+actionstr(#conn_log{action=recv}) -> "<-----";
+actionstr(#conn_log{action=open}) -> "opened session to";
+actionstr(#conn_log{action=close}) -> "closed session to";
+actionstr(_) -> "<---->".
+
+serverstr(#conn_log{name=undefined,address=Address}) ->
+ io_lib:format("~p",[Address]);
+serverstr(#conn_log{name=Alias,address=Address}) ->
+ io_lib:format("~p(~p)",[Alias,Address]).
+
+month(1) -> "Jan";
+month(2) -> "Feb";
+month(3) -> "Mar";
+month(4) -> "Apr";
+month(5) -> "May";
+month(6) -> "Jun";
+month(7) -> "Jul";
+month(8) -> "Aug";
+month(9) -> "Sep";
+month(10) -> "Oct";
+month(11) -> "Nov";
+month(12) -> "Dec".
+
+micro2milli(X) ->
+ pad0(3,integer_to_list(X div 1000)).
+
+t(X) ->
+ pad0(2,integer_to_list(X)).
+
+pad0(N,Str) ->
+ M = length(Str),
+ lists:duplicate(N-M,$0) ++ Str.
+
+pad_char_end(N,Str,Char) ->
+ case length(lists:flatten(Str)) of
+ M when M<N -> Str ++ lists:duplicate(N-M,Char);
+ _ -> Str
+ end.
diff --git a/lib/common_test/src/ct_event.erl b/lib/common_test/src/ct_event.erl
index 3e79898ad1..998be35fda 100644
--- a/lib/common_test/src/ct_event.erl
+++ b/lib/common_test/src/ct_event.erl
@@ -31,7 +31,7 @@
%% API
-export([start_link/0, add_handler/0, add_handler/1, stop/0]).
--export([notify/1, sync_notify/1]).
+-export([notify/1, notify/2, sync_notify/1,sync_notify/2]).
-export([is_alive/0]).
%% gen_event callbacks
@@ -90,6 +90,13 @@ notify(Event) ->
end.
%%--------------------------------------------------------------------
+%% Function: notify(Name,Data) -> ok
+%% Description: Asynchronous notification to event manager.
+%%--------------------------------------------------------------------
+notify(Name, Data) ->
+ notify(#event{ name = Name, data = Data}).
+
+%%--------------------------------------------------------------------
%% Function: sync_notify(Event) -> ok
%% Description: Synchronous notification to event manager.
%%--------------------------------------------------------------------
@@ -102,6 +109,13 @@ sync_notify(Event) ->
end.
%%--------------------------------------------------------------------
+%% Function: sync_notify(Name,Data) -> ok
+%% Description: Synchronous notification to event manager.
+%%--------------------------------------------------------------------
+sync_notify(Name,Data) ->
+ sync_notify(#event{ name = Name, data = Data}).
+
+%%--------------------------------------------------------------------
%% Function: is_alive() -> true | false
%% Description: Check if Event Manager is alive.
%%--------------------------------------------------------------------
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index 5aab4dd2dd..5df9127725 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. 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
@@ -27,7 +27,7 @@
-compile(export_all).
-export([start/4, stop/1]).
--export([call/2, do_within_time/2]).
+-export([call/2, call/3, return/2, do_within_time/2]).
-ifdef(debug).
-define(dbg,true).
@@ -39,17 +39,24 @@
name,
address,
init_data,
+ reconnect = true,
+ forward = false,
+ use_existing = true,
+ old = false,
conn_pid,
cb_state,
ct_util_server}).
%%%-----------------------------------------------------------------
-%%% @spec start(Name,Address,InitData,CallbackMod) ->
+%%% @spec start(Address,InitData,CallbackMod,Opts) ->
%%% {ok,Handle} | {error,Reason}
%%% Name = term()
%%% CallbackMod = atom()
%%% InitData = term()
%%% Address = term()
+%%% Opts = [Opt]
+%%% Opt = {name,Name} | {use_existing_connection,boolean()} |
+%%% {reconnect,boolean()} | {forward_messages,boolean()}
%%%
%%% @doc Open a connection and start the generic connection owner process.
%%%
@@ -60,42 +67,59 @@
%%% <code>InitData</code> and returna
%%% <code>{ok,ConnectionPid,State}</code> or
%%% <code>{error,Reason}</code>.</p>
+%%%
+%%% If no name is given, the <code>Name</code> argument in init/3 will
+%%% have the value <code>undefined</code>.
+%%%
+%%% The callback modules must also export
+%%% ```
+%%% handle_msg(Msg,From,State) -> {reply,Reply,State} |
+%%% {noreply,State} |
+%%% {stop,Reply,State}
+%%% terminate(ConnectionPid,State) -> term()
+%%% close(Handle) -> term()
+%%% '''
+%%%
+%%% The <code>close/1</code> callback function is actually a callback
+%%% for ct_util, for closing registered connections when
+%%% ct_util_server is terminated. <code>Handle</code> is the Pid of
+%%% the ct_gen_conn process.
+%%%
+%%% If option <code>reconnect</code> is <code>true</code>, then the
+%%% callback must also export
+%%% ```
+%%% reconnect(Address,State) -> {ok,ConnectionPid,State}
+%%% '''
+%%%
+%%% If option <code>forward_messages</code> is <ocde>true</code>, then
+%%% the callback must also export
+%%% ```
+%%% handle_msg(Msg,State) -> {noreply,State} | {stop,State}
+%%% '''
+%%%
+%%% An old interface still exists. This is used by ct_telnet, ct_ftp
+%%% and ct_ssh. The start function then has an explicit
+%%% <code>Name</code> argument, and no <code>Opts</code> argument. The
+%%% callback must export:
+%%%
+%%% ```
+%%% init(Name,Address,InitData) -> {ok,ConnectionPid,State}
+%%% handle_msg(Msg,State) -> {Reply,State}
+%%% reconnect(Address,State) -> {ok,ConnectionPid,State}
+%%% terminate(ConnectionPid,State) -> term()
+%%% close(Handle) -> term()
+%%% '''
+%%%
+start(Address,InitData,CallbackMod,Opts) when is_list(Opts) ->
+ do_start(Address,InitData,CallbackMod,Opts);
start(Name,Address,InitData,CallbackMod) ->
- case ct_util:does_connection_exist(Name,Address,CallbackMod) of
- {ok,Pid} ->
- log("ct_gen_conn:start","Using existing connection!\n",[]),
- {ok,Pid};
- false ->
- Self = self(),
- Pid = spawn(fun() ->
- init_gen(Self, #gen_opts{callback=CallbackMod,
- name=Name,
- address=Address,
- init_data=InitData})
- end),
- MRef = erlang:monitor(process,Pid),
- receive
- {connected,Pid} ->
- erlang:demonitor(MRef, [flush]),
- ct_util:register_connection(Name,Address,CallbackMod,Pid),
- {ok,Pid};
- {Error,Pid} ->
- receive {'DOWN',MRef,process,_,_} -> ok end,
- Error;
- {'DOWN',MRef,process,_,Reason} ->
- log("ct_gen_conn:start",
- "Connection process died: ~p\n",
- [Reason]),
- {error,{connection_process_died,Reason}}
- end
- end.
-
+ do_start(Address,InitData,CallbackMod,[{name,Name},{old,true}]).
%%%-----------------------------------------------------------------
%%% @spec stop(Handle) -> ok
%%% Handle = handle()
%%%
-%%% @doc Close the telnet connection and stop the process managing it.
+%%% @doc Close the connection and stop the process managing it.
stop(Pid) ->
call(Pid,stop).
@@ -103,7 +127,7 @@ stop(Pid) ->
%%% @spec log(Heading,Format,Args) -> ok
%%%
%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:log/3
+%%% @see ct_logs:log/3
log(Heading,Format,Args) ->
log(log,[Heading,Format,Args]).
@@ -111,7 +135,7 @@ log(Heading,Format,Args) ->
%%% @spec start_log(Heading) -> ok
%%%
%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:start_log/1
+%%% @see ct_logs:start_log/1
start_log(Heading) ->
log(start_log,[Heading]).
@@ -119,7 +143,7 @@ start_log(Heading) ->
%%% @spec cont_log(Format,Args) -> ok
%%%
%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:cont_log/2
+%%% @see ct_logs:cont_log/2
cont_log(Format,Args) ->
log(cont_log,[Format,Args]).
@@ -127,7 +151,7 @@ cont_log(Format,Args) ->
%%% @spec end_log() -> ok
%%%
%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:end_log/0
+%%% @see ct_logs:end_log/0
end_log() ->
log(end_log,[]).
@@ -148,10 +172,10 @@ do_within_time(Fun,Timeout) ->
Silent = get(silent),
TmpPid = spawn_link(fun() -> put(silent,Silent),
R = Fun(),
- Self ! {self(),R}
+ Self ! {self(),R}
end),
ConnPid = get(conn_pid),
- receive
+ receive
{TmpPid,Result} ->
Result;
{'EXIT',ConnPid,_Reason}=M ->
@@ -159,7 +183,7 @@ do_within_time(Fun,Timeout) ->
exit(TmpPid,kill),
self() ! M,
{error,connection_closed}
- after
+ after
Timeout ->
exit(TmpPid,kill),
receive
@@ -176,12 +200,65 @@ do_within_time(Fun,Timeout) ->
%%%=================================================================
%%% Internal functions
+do_start(Address,InitData,CallbackMod,Opts0) ->
+ Opts = check_opts(Opts0,#gen_opts{callback=CallbackMod,
+ address=Address,
+ init_data=InitData}),
+ case ct_util:does_connection_exist(Opts#gen_opts.name,
+ Address,CallbackMod) of
+ {ok,Pid} when Opts#gen_opts.use_existing ->
+ log("ct_gen_conn:start","Using existing connection!\n",[]),
+ {ok,Pid};
+ {ok,Pid} when not Opts#gen_opts.use_existing ->
+ {error,{connection_exists,Pid}};
+ false ->
+ do_start(Opts)
+ end.
+
+do_start(Opts) ->
+ Self = self(),
+ Pid = spawn(fun() -> init_gen(Self, Opts) end),
+ MRef = erlang:monitor(process,Pid),
+ receive
+ {connected,Pid} ->
+ erlang:demonitor(MRef, [flush]),
+ ct_util:register_connection(Opts#gen_opts.name, Opts#gen_opts.address,
+ Opts#gen_opts.callback, Pid),
+ {ok,Pid};
+ {Error,Pid} ->
+ receive {'DOWN',MRef,process,_,_} -> ok end,
+ Error;
+ {'DOWN',MRef,process,_,Reason} ->
+ log("ct_gen_conn:start",
+ "Connection process died: ~p\n",
+ [Reason]),
+ {error,{connection_process_died,Reason}}
+ end.
+
+check_opts(Opts0) ->
+ check_opts(Opts0,#gen_opts{}).
+
+check_opts([{name,Name}|T],Opts) ->
+ check_opts(T,Opts#gen_opts{name=Name});
+check_opts([{reconnect,Bool}|T],Opts) ->
+ check_opts(T,Opts#gen_opts{reconnect=Bool});
+check_opts([{forward_messages,Bool}|T],Opts) ->
+ check_opts(T,Opts#gen_opts{forward=Bool});
+check_opts([{use_existing_connection,Bool}|T],Opts) ->
+ check_opts(T,Opts#gen_opts{use_existing=Bool});
+check_opts([{old,Bool}|T],Opts) ->
+ check_opts(T,Opts#gen_opts{old=Bool});
+check_opts([],Opts) ->
+ Opts.
+
call(Pid,Msg) ->
+ call(Pid,Msg,infinity).
+call(Pid,Msg,Timeout) ->
MRef = erlang:monitor(process,Pid),
Ref = make_ref(),
Pid ! {Msg,{self(),Ref}},
receive
- {Ref, Result} ->
+ {Ref, Result} ->
erlang:demonitor(MRef, [flush]),
case Result of
{retry,_Data} ->
@@ -189,8 +266,11 @@ call(Pid,Msg) ->
Other ->
Other
end;
- {'DOWN',MRef,process,_,Reason} ->
+ {'DOWN',MRef,process,_,Reason} ->
{error,{process_down,Pid,Reason}}
+ after Timeout ->
+ erlang:demonitor(MRef, [flush]),
+ exit(timeout)
end.
return({To,Ref},Result) ->
@@ -198,36 +278,47 @@ return({To,Ref},Result) ->
init_gen(Parent,Opts) ->
process_flag(trap_exit,true),
- CtUtilServer = whereis(ct_util_server),
- link(CtUtilServer),
put(silent,false),
- case catch (Opts#gen_opts.callback):init(Opts#gen_opts.name,
- Opts#gen_opts.address,
- Opts#gen_opts.init_data) of
+ try (Opts#gen_opts.callback):init(Opts#gen_opts.name,
+ Opts#gen_opts.address,
+ Opts#gen_opts.init_data) of
{ok,ConnPid,State} when is_pid(ConnPid) ->
link(ConnPid),
put(conn_pid,ConnPid),
+ CtUtilServer = whereis(ct_util_server),
+ link(CtUtilServer),
Parent ! {connected,self()},
loop(Opts#gen_opts{conn_pid=ConnPid,
cb_state=State,
ct_util_server=CtUtilServer});
{error,Reason} ->
Parent ! {{error,Reason},self()}
+ catch
+ throw:{error,Reason} ->
+ Parent ! {{error,Reason},self()}
end.
loop(Opts) ->
receive
{'EXIT',Pid,Reason} when Pid==Opts#gen_opts.conn_pid ->
- log("Connection down!\nOpening new!","Reason: ~p\nAddress: ~p\n",
- [Reason,Opts#gen_opts.address]),
- case reconnect(Opts) of
- {ok, NewPid, NewState} ->
- link(NewPid),
- put(conn_pid,NewPid),
- loop(Opts#gen_opts{conn_pid=NewPid,cb_state=NewState});
- Error ->
+ case Opts#gen_opts.reconnect of
+ true ->
+ log("Connection down!\nOpening new!",
+ "Reason: ~p\nAddress: ~p\n",
+ [Reason,Opts#gen_opts.address]),
+ case reconnect(Opts) of
+ {ok, NewPid, NewState} ->
+ link(NewPid),
+ put(conn_pid,NewPid),
+ loop(Opts#gen_opts{conn_pid=NewPid,cb_state=NewState});
+ Error ->
+ ct_util:unregister_connection(self()),
+ log("Reconnect failed. Giving up!","Reason: ~p\n",
+ [Error])
+ end;
+ false ->
ct_util:unregister_connection(self()),
- log("Reconnect failed. Giving up!","Reason: ~p\n",[Error])
+ log("Connection closed!","Reason: ~p\n",[Reason])
end;
{'EXIT',Pid,Reason} ->
case Opts#gen_opts.ct_util_server of
@@ -252,24 +343,40 @@ loop(Opts) ->
loop(Opts);
{{retry,{_Error,_Name,_CPid,Msg}}, From} ->
log("Rerunning command","Connection reestablished. Rerunning command...",[]),
- {Return,NewState} =
+ {Return,NewState} =
(Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state),
return(From, Return),
- loop(Opts#gen_opts{cb_state=NewState});
- {Msg,From={Pid,_Ref}} when is_pid(Pid) ->
- {Return,NewState} =
+ loop(Opts#gen_opts{cb_state=NewState});
+ {Msg,From={Pid,_Ref}} when is_pid(Pid), Opts#gen_opts.old==true ->
+ {Return,NewState} =
(Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state),
return(From, Return),
- loop(Opts#gen_opts{cb_state=NewState})
+ loop(Opts#gen_opts{cb_state=NewState});
+ {Msg,From={Pid,_Ref}} when is_pid(Pid) ->
+ case (Opts#gen_opts.callback):handle_msg(Msg,From,
+ Opts#gen_opts.cb_state) of
+ {reply,Reply,NewState} ->
+ return(From,Reply),
+ loop(Opts#gen_opts{cb_state=NewState});
+ {noreply,NewState} ->
+ loop(Opts#gen_opts{cb_state=NewState});
+ {stop,Reply,NewState} ->
+ ct_util:unregister_connection(self()),
+ (Opts#gen_opts.callback):terminate(Opts#gen_opts.conn_pid,
+ NewState),
+ return(From,Reply)
+ end;
+ Msg when Opts#gen_opts.forward==true ->
+ case (Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state) of
+ {noreply,NewState} ->
+ loop(Opts#gen_opts{cb_state=NewState});
+ {stop,NewState} ->
+ ct_util:unregister_connection(self()),
+ (Opts#gen_opts.callback):terminate(Opts#gen_opts.conn_pid,
+ NewState)
+ end
end.
-nozero({ok,S}) when is_list(S) ->
- {ok,[C || C <- S,
- C=/=0,
- C=/=13]};
-nozero(M) ->
- M.
-
reconnect(Opts) ->
(Opts#gen_opts.callback):reconnect(Opts#gen_opts.address,
Opts#gen_opts.cb_state).
@@ -277,10 +384,8 @@ reconnect(Opts) ->
log(Func,Args) ->
case get(silent) of
- true when not ?dbg->
+ true when not ?dbg->
ok;
_ ->
apply(ct_logs,Func,Args)
end.
-
-
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
new file mode 100644
index 0000000000..d9c4a962dc
--- /dev/null
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -0,0 +1,1828 @@
+%%----------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. 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%
+%%
+%%----------------------------------------------------------------------
+%% File: ct_netconfc.erl
+%%
+%% Description:
+%% This file contains the Netconf client interface
+%%
+%% @author Support
+%%
+%% @doc Netconf client module.
+%%
+%% <p>The Netconf client is compliant with RFC4741 and RFC4742.</p>
+%%
+%% <p> For each server to test against, the following entry can be
+%% added to a configuration file:</p>
+%%
+%% <p>`{server_id(),options()}.'</p>
+%%
+%% <p> The `server_id()' or an associated `target_name()' (see
+%% {@link ct}) shall then be used in calls to {@link open/2}.</p>
+%%
+%% <p>If no configuration exists for a server, a session can still be
+%% opened by calling {@link open/2} with all necessary options given
+%% in the call. The first argument to {@link open/2} can then be any
+%% atom.</p>
+%%
+%% == Logging ==
+%%
+%% The netconf server uses the `error_logger' for logging of netconf
+%% traffic. A special purpose error handler is implemented in
+%% `ct_conn_log_h'. To use this error handler, add the `cth_conn_log'
+%% hook in your test suite, e.g.
+%%
+%% ```
+%% suite() ->
+%% [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].
+%%'''
+%%
+%% The `conn_mod()' is the name of the common_test module implementing
+%% the connection protocol, e.g. `ct_netconfc'.
+%%
+%% The hook option `log_type' specifies the type of logging:
+%%
+%% <dl>
+%% <dt>`raw'</dt>
+%% <dd>The sent and received netconf data is logged to a separate
+%% text file as is without any formatting. A link to the file is
+%% added to the test case HTML log.</dd>
+%%
+%% <dt>`pretty'</dt>
+%% <dd>The sent and received netconf data is logged to a separate
+%% text file with XML data nicely indented. A link to the file is
+%% added to the test case HTML log.</dd>
+%%
+%% <dt>`html (default)'</dt>
+%% <dd>The sent and received netconf traffic is pretty printed
+%% directly in the test case HTML log.</dd>
+%%
+%% <dt>`silent'</dt>
+%% <dd>Netconf traffic is not logged.</dd>
+%% </dl>
+%%
+%% By default, all netconf traffic is logged in one single log
+%% file. However, it is possible to have different connections logged
+%% in separate files. To do this, use the hook option `hosts' and
+%% list the names of the servers/connections that will be used in the
+%% suite. Note that the connections must be named for this to work,
+%% i.e. they must be opened with {@link open/2}.
+%%
+%% The `hosts' option has no effect if `log_type' is set to `html' or
+%% `silent'.
+%%
+%% The hook options can also be specified in a configuration file with
+%% the configuration variable `ct_conn_log':
+%%
+%% ```
+%% {ct_conn_log,[{conn_mod(),hook_options()}]}.
+%% '''
+%%
+%% For example:
+%%
+%% ```
+%% {ct_conn_log,[{ct_netconfc,[{log_type,pretty},
+%% {hosts,[key_or_name()]}]}]}
+%% '''
+%%
+%% <b>Note</b> that hook options specified in a configuration file
+%% will overwrite the hardcoded hook options in the test suite.
+%%
+%% === Logging example 1 ===
+%%
+%% The following `ct_hooks' statement will cause pretty printing of
+%% netconf traffic to separate logs for the connections named
+%% `nc_server1' and `nc_server2'. Any other connections will be logged
+%% to default netconf log.
+%%
+%% ```
+%% suite() ->
+%% [{ct_hooks, [{cth_conn_log, [{ct_netconfc,[{log_type,pretty}},
+%% {hosts,[nc_server1,nc_server2]}]}
+%% ]}]}].
+%%'''
+%%
+%% Connections must be opened like this:
+%%
+%% ```
+%% open(nc_server1,[...]),
+%% open(nc_server2,[...]).
+%% '''
+%%
+%% === Logging example 2 ===
+%%
+%% The following configuration file will cause raw logging of all
+%% netconf traffic into one single text file.
+%%
+%% ```
+%% {ct_conn_log,[{ct_netconfc,[{log_type,raw}]}]}.
+%% '''
+%%
+%% The `ct_hooks' statement must look like this:
+%%
+%% ```
+%% suite() ->
+%% [{ct_hooks, [{cth_conn_log, []}]}].
+%% '''
+%%
+%% The same `ct_hooks' statement without the configuration file would
+%% cause HTML logging of all netconf connections into the test case
+%% HTML log.
+%%
+%% == Notifications ==
+%%
+%% The netconf client is also compliant with RFC5277 NETCONF Event
+%% Notifications, which defines a mechanism for an asynchronous
+%% message notification delivery service for the netconf protocol.
+%%
+%% Specific functions to support this are {@link
+%% create_subscription/6} and {@link get_event_streams/3}. (The
+%% functions also exist with other arities.)
+%%
+%% @end
+%%----------------------------------------------------------------------
+-module(ct_netconfc).
+
+-include("ct_netconfc.hrl").
+-include("ct_util.hrl").
+-include_lib("xmerl/include/xmerl.hrl").
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([open/1,
+ open/2,
+ only_open/1,
+ only_open/2,
+ hello/1,
+ hello/2,
+ close_session/1,
+ close_session/2,
+ kill_session/2,
+ kill_session/3,
+ send/2,
+ send/3,
+ send_rpc/2,
+ send_rpc/3,
+ lock/2,
+ lock/3,
+ unlock/2,
+ unlock/3,
+ get/2,
+ get/3,
+ get_config/3,
+ get_config/4,
+ edit_config/3,
+ edit_config/4,
+ delete_config/2,
+ delete_config/3,
+ copy_config/3,
+ copy_config/4,
+ action/2,
+ action/3,
+ create_subscription/1,
+ create_subscription/2,
+ create_subscription/3,
+ create_subscription/4,
+ create_subscription/5,
+ create_subscription/6,
+ get_event_streams/2,
+ get_event_streams/3,
+ get_capabilities/1,
+ get_capabilities/2,
+ get_session_id/1,
+ get_session_id/2]).
+
+%%----------------------------------------------------------------------
+%% Exported types
+%%----------------------------------------------------------------------
+-export_type([hook_options/0,
+ conn_mod/0,
+ log_type/0,
+ key_or_name/0,
+ notification/0]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+%% ct_gen_conn callbacks
+-export([init/3,
+ handle_msg/3,
+ handle_msg/2,
+ terminate/2,
+ close/1]).
+
+%% ct_conn_log callback
+-export([format_data/2]).
+
+%%----------------------------------------------------------------------
+%% Internal defines
+%%----------------------------------------------------------------------
+-define(APPLICATION,?MODULE).
+-define(VALID_SSH_OPTS,[user, password, user_dir]).
+-define(DEFAULT_STREAM,"NETCONF").
+
+-define(error(ConnName,Report),
+ error_logger:error_report([{ct_connection,ConnName},
+ {client,self()},
+ {module,?MODULE},
+ {line,?LINE} |
+ Report])).
+
+-define(is_timeout(T), (is_integer(T) orelse T==infinity)).
+-define(is_filter(F),
+ (is_atom(F) orelse (is_tuple(F) andalso is_atom(element(1,F))))).
+-define(is_string(S), (is_list(S) andalso is_integer(hd(S)))).
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+%% Client state
+-record(state, {host,
+ port,
+ connection, % #connection
+ capabilities,
+ session_id,
+ msg_id = 1,
+ hello_status,
+ buff = <<>>,
+ pending = [], % [#pending]
+ event_receiver}).% pid
+
+%% Run-time client options.
+-record(options, {ssh = [], % Options for the ssh application
+ host,
+ port = ?DEFAULT_PORT,
+ timeout = ?DEFAULT_TIMEOUT,
+ name}).
+
+%% Connection reference
+-record(connection, {reference, % {CM,Ch}
+ host,
+ port,
+ name}).
+
+%% Pending replies from server
+-record(pending, {tref, % timer ref (returned from timer:xxx)
+ ref, % pending ref
+ msg_id,
+ op,
+ caller}).% pid which sent the request
+
+%%----------------------------------------------------------------------
+%% Type declarations
+%%----------------------------------------------------------------------
+-type client() :: handle() | server_id() | target_name().
+-type handle() :: term().
+%% An opaque reference for a connection (netconf session). See {@link
+%% ct} for more information.
+
+-type server_id() :: atom().
+%% A `ServerId' which exists in a configuration file.
+-type target_name() :: atom().
+%% A name which is associated to a `server_id()' via a
+%% `require' statement or a call to {@link ct:require/2} in the
+%% test suite.
+-type key_or_name() :: server_id() | target_name().
+
+-type options() :: [option()].
+%% Options used for setting up ssh connection to a netconf server.
+
+-type option() :: {ssh,host()} | {port,inet:port_number()} | {user,string()} |
+ {password,string()} | {user_dir,string()} |
+ {timeout,timeout()}.
+-type host() :: inet:host_name() | inet:ip_address().
+
+-type notification() :: {notification, xml_attributes(), notification_content()}.
+-type notification_content() :: [event_time()|simple_xml()].
+-type event_time() :: {eventTime,xml_attributes(),[xs_datetime()]}.
+
+-type stream_name() :: string().
+-type streams() :: [{stream_name(),[stream_data()]}].
+-type stream_data() :: {description,string()} |
+ {replaySupport,string()} |
+ {replayLogCreationTime,string()} |
+ {replayLogAgedTime,string()}.
+%% See XML Schema for Event Notifications found in RFC5277 for further
+%% detail about the data format for the string values.
+
+-type hook_options() :: [hook_option()].
+%% Options that can be given to `cth_conn_log' in the `ct_hook' statement.
+-type hook_option() :: {log_type,log_type()} |
+ {hosts,[key_or_name()]}.
+-type log_type() :: raw | pretty | html | silent.
+%-type error_handler() :: module().
+-type conn_mod() :: ct_netconfc.
+
+-type error_reason() :: term().
+
+-type simple_xml() :: {xml_tag(), xml_attributes(), xml_content()} |
+ {xml_tag(), xml_content()} |
+ xml_tag().
+%% <p>This type is further described in the documentation for the
+%% <tt>Xmerl</tt> application.</p>
+-type xml_tag() :: atom().
+-type xml_attributes() :: [{xml_attribute_tag(),xml_attribute_value()}].
+-type xml_attribute_tag() :: atom().
+-type xml_attribute_value() :: string().
+-type xml_content() :: [simple_xml() | iolist()].
+-type xpath() :: {xpath,string()}.
+
+-type netconf_db() :: running | startup | candidate.
+-type xs_datetime() :: string().
+%% This date and time identifyer has the same format as the XML type
+%% dateTime and compliant to RFC3339. The format is
+%% ```[-]CCYY-MM-DDThh:mm:ss[.s][Z|(+|-)hh:mm]'''
+
+%%----------------------------------------------------------------------
+%% External interface functions
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+-spec open(Options) -> Result when
+ Options :: options(),
+ Result :: {ok,handle()} | {error,error_reason()}.
+%% @doc Open a netconf session and exchange `hello' messages.
+%%
+%% If the server options are specified in a configuration file, or if
+%% a named client is needed for logging purposes (see {@section
+%% Logging}) use {@link open/2} instead.
+%%
+%% The opaque `handler()' reference which is returned from this
+%% function is required as client identifier when calling any other
+%% function in this module.
+%%
+%% The `timeout' option (milli seconds) is used when setting up
+%% the ssh connection and when waiting for the hello message from the
+%% server. It is not used for any other purposes during the lifetime
+%% of the connection.
+%%
+%% @end
+%%----------------------------------------------------------------------
+open(Options) ->
+ open(Options,#options{},[],true).
+
+%%----------------------------------------------------------------------
+-spec open(KeyOrName, ExtraOptions) -> Result when
+ KeyOrName :: key_or_name(),
+ ExtraOptions :: options(),
+ Result :: {ok,handle()} | {error,error_reason()}.
+%% @doc Open a named netconf session and exchange `hello' messages.
+%%
+%% If `KeyOrName' is a configured `server_id()' or a
+%% `target_name()' associated with such an ID, then the options
+%% for this server will be fetched from the configuration file.
+%
+%% The `ExtraOptions' argument will be added to the options found in
+%% the configuration file. If the same options are given, the values
+%% from the configuration file will overwrite `ExtraOptions'.
+%%
+%% If the server is not specified in a configuration file, use {@link
+%% open/1} instead.
+%%
+%% The opaque `handle()' reference which is returned from this
+%% function can be used as client identifier when calling any other
+%% function in this module. However, if `KeyOrName' is a
+%% `target_name()', i.e. if the server is named via a call to
+%% `ct:require/2' or a `require' statement in the test
+%% suite, then this name may be used instead of the `handle()'.
+%%
+%% The `timeout' option (milli seconds) is used when setting up
+%% the ssh connection and when waiting for the hello message from the
+%% server. It is not used for any other purposes during the lifetime
+%% of the connection.
+%%
+%% @end
+%%----------------------------------------------------------------------
+open(KeyOrName, ExtraOpts) ->
+ open(KeyOrName, ExtraOpts, true).
+
+open(KeyOrName, ExtraOpts, Hello) ->
+ SortedExtra = lists:keysort(1,ExtraOpts),
+ SortedConfig = lists:keysort(1,ct:get_config(KeyOrName,[])),
+ AllOpts = lists:ukeymerge(1,SortedConfig,SortedExtra),
+ open(AllOpts,#options{name=KeyOrName},[{name,KeyOrName}],Hello).
+
+open(OptList,InitOptRec,NameOpt,Hello) ->
+ case check_options(OptList,undefined,undefined,InitOptRec) of
+ {Host,Port,Options} ->
+ case ct_gen_conn:start({Host,Port},Options,?MODULE,
+ NameOpt ++ [{reconnect,false},
+ {use_existing_connection,false},
+ {forward_messages,true}]) of
+ {ok,Client} when Hello==true ->
+ case hello(Client,Options#options.timeout) of
+ ok ->
+ {ok,Client};
+ Error ->
+ Error
+ end;
+ Other ->
+ Other
+ end;
+ Error ->
+ Error
+ end.
+
+
+%%----------------------------------------------------------------------
+-spec only_open(Options) -> Result when
+ Options :: options(),
+ Result :: {ok,handle()} | {error,error_reason()}.
+%% @doc Open a netconf session, but don't send `hello'.
+%%
+%% As {@link open/1} but does not send a `hello' message.
+%%
+%% @end
+%%----------------------------------------------------------------------
+only_open(Options) ->
+ open(Options,#options{},[],false).
+
+%%----------------------------------------------------------------------
+-spec only_open(KeyOrName,ExtraOptions) -> Result when
+ KeyOrName :: key_or_name(),
+ ExtraOptions :: options(),
+ Result :: {ok,handle()} | {error,error_reason()}.
+%% @doc Open a name netconf session, but don't send `hello'.
+%%
+%% As {@link open/2} but does not send a `hello' message.
+%%
+%% @end
+%%----------------------------------------------------------------------
+only_open(KeyOrName, ExtraOpts) ->
+ open(KeyOrName, ExtraOpts, false).
+
+%%----------------------------------------------------------------------
+%% @spec hello(Client) -> Result
+%% @equiv hello(Client, infinity)
+hello(Client) ->
+ hello(Client,?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec hello(Client,Timeout) -> Result when
+ Client :: handle(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Exchange `hello' messages with the server.
+%%
+%% Sends a `hello' message to the server and waits for the return.
+%%
+%% @end
+%%----------------------------------------------------------------------
+hello(Client,Timeout) ->
+ call(Client, {hello, Timeout}).
+
+%%----------------------------------------------------------------------
+%% @spec get_session_id(Client) -> Result
+%% @equiv get_session_id(Client, infinity)
+get_session_id(Client) ->
+ get_session_id(Client, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec get_session_id(Client, Timeout) -> Result when
+ Client :: client(),
+ Timeout :: timeout(),
+ Result :: pos_integer() | {error,error_reason()}.
+%% @doc Returns the session id associated with the given client.
+%%
+%% @end
+%%----------------------------------------------------------------------
+get_session_id(Client, Timeout) ->
+ call(Client, get_session_id, Timeout).
+
+%%----------------------------------------------------------------------
+%% @spec get_capabilities(Client) -> Result
+%% @equiv get_capabilities(Client, infinity)
+get_capabilities(Client) ->
+ get_capabilities(Client, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec get_capabilities(Client, Timeout) -> Result when
+ Client :: client(),
+ Timeout :: timeout(),
+ Result :: [string()] | {error,error_reason()}.
+%% @doc Returns the server side capabilities
+%%
+%% The following capability identifiers, defined in RFC 4741, can be returned:
+%%
+%% <ul>
+%% <li>`"urn:ietf:params:netconf:base:1.0"'</li>
+%% <li>`"urn:ietf:params:netconf:capability:writable-running:1.0"'</li>
+%% <li>`"urn:ietf:params:netconf:capability:candidate:1.0"'</li>
+%% <li>`"urn:ietf:params:netconf:capability:confirmed-commit:1.0"'</li>
+%% <li>`"urn:ietf:params:netconf:capability:rollback-on-error:1.0"'</li>
+%% <li>`"urn:ietf:params:netconf:capability:startup:1.0"'</li>
+%% <li>`"urn:ietf:params:netconf:capability:url:1.0"'</li>
+%% <li>`"urn:ietf:params:netconf:capability:xpath:1.0"'</li>
+%% </ul>
+%%
+%% Note, additional identifiers may exist, e.g. server side namespace.
+%%
+%% @end
+%%----------------------------------------------------------------------
+get_capabilities(Client, Timeout) ->
+ call(Client, get_capabilities, Timeout).
+
+%% @private
+send(Client, SimpleXml) ->
+ send(Client, SimpleXml, ?DEFAULT_TIMEOUT).
+%% @private
+send(Client, SimpleXml, Timeout) ->
+ call(Client,{send, Timeout, SimpleXml}).
+
+%% @private
+send_rpc(Client, SimpleXml) ->
+ send_rpc(Client, SimpleXml, ?DEFAULT_TIMEOUT).
+%% @private
+send_rpc(Client, SimpleXml, Timeout) ->
+ call(Client,{send_rpc, SimpleXml, Timeout}).
+
+
+
+%%----------------------------------------------------------------------
+%% @spec lock(Client, Target) -> Result
+%% @equiv lock(Client, Target, infinity)
+lock(Client, Target) ->
+ lock(Client, Target,?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec lock(Client, Target, Timeout) -> Result when
+ Client :: client(),
+ Target :: netconf_db(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Unlock configuration target.
+%%
+%% Which target parameters that can be used depends on if
+%% `:candidate' and/or `:startup' are supported by the
+%% server. If successfull, the configuration system of the device is
+%% not available to other clients (Netconf, CORBA, SNMP etc). Locks
+%% are intended to be short-lived.
+%%
+%% The operations {@link kill_session/2} or {@link kill_session/3} can
+%% be used to force the release of a lock owned by another Netconf
+%% session. How this is achieved by the server side is implementation
+%% specific.
+%%
+%% @end
+%%----------------------------------------------------------------------
+lock(Client, Target, Timeout) ->
+ call(Client,{send_rpc_op,lock,[Target],Timeout}).
+
+%%----------------------------------------------------------------------
+%% @spec unlock(Client, Target) -> Result
+%% @equiv unlock(Client, Target, infinity)
+unlock(Client, Target) ->
+ unlock(Client, Target,?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec unlock(Client, Target, Timeout) -> Result when
+ Client :: client(),
+ Target :: netconf_db(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Unlock configuration target.
+%%
+%% If the client earlier has aquired a lock, via {@link lock/2} or
+%% {@link lock/3}, this operation release the associated lock. To be
+%% able to access another target than `running', the server must
+%% support `:candidate' and/or `:startup'.
+%%
+%% @end
+%%----------------------------------------------------------------------
+unlock(Client, Target, Timeout) ->
+ call(Client, {send_rpc_op, unlock, [Target], Timeout}).
+
+%%----------------------------------------------------------------------
+%% @spec get(Client, Filter) -> Result
+%% @equiv get(Client, Filter, infinity)
+get(Client, Filter) ->
+ get(Client, Filter, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec get(Client, Filter, Timeout) -> Result when
+ Client :: client(),
+ Filter :: simple_xml() | xpath(),
+ Timeout :: timeout(),
+ Result :: {ok,simple_xml()} | {error,error_reason()}.
+%% @doc Get data.
+%%
+%% This operation returns both configuration and state data from the
+%% server.
+%%
+%% Filter type `xpath' can only be used if the server supports
+%% `:xpath'.
+%%
+%% @end
+%%----------------------------------------------------------------------
+get(Client, Filter, Timeout) ->
+ call(Client,{send_rpc_op, get, [Filter], Timeout}).
+
+%%----------------------------------------------------------------------
+%% @spec get_config(Client, Source, Filter) -> Result
+%% @equiv get_config(Client, Source, Filter, infinity)
+get_config(Client, Source, Filter) ->
+ get_config(Client, Source, Filter, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec get_config(Client, Source, Filter, Timeout) -> Result when
+ Client :: client(),
+ Source :: netconf_db(),
+ Filter :: simple_xml() | xpath(),
+ Timeout :: timeout(),
+ Result :: {ok,simple_xml()} | {error,error_reason()}.
+%% @doc Get configuration data.
+%%
+%% To be able to access another source than `running', the server
+%% must advertise `:candidate' and/or `:startup'.
+%%
+%% Filter type `xpath' can only be used if the server supports
+%% `:xpath'.
+%%
+%%
+%% @end
+%%----------------------------------------------------------------------
+get_config(Client, Source, Filter, Timeout) ->
+ call(Client, {send_rpc_op, get_config, [Source, Filter], Timeout}).
+
+%%----------------------------------------------------------------------
+%% @spec edit_config(Client, Target, Config) -> Result
+%% @equiv edit_config(Client, Target, Config, infinity)
+edit_config(Client, Target, Config) ->
+ edit_config(Client, Target, Config, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec edit_config(Client, Target, Config, Timeout) -> Result when
+ Client :: client(),
+ Target :: netconf_db(),
+ Config :: simple_xml(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Edit configuration data.
+%%
+%% Per default only the running target is available, unless the server
+%% include `:candidate' or `:startup' in its list of
+%% capabilities.
+%%
+%% @end
+%%----------------------------------------------------------------------
+edit_config(Client, Target, Config, Timeout) ->
+ call(Client, {send_rpc_op, edit_config, [Target,Config], Timeout}).
+
+
+%%----------------------------------------------------------------------
+%% @spec delete_config(Client, Target) -> Result
+%% @equiv delete_config(Client, Target, infinity)
+delete_config(Client, Target) ->
+ delete_config(Client, Target, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec delete_config(Client, Target, Timeout) -> Result when
+ Client :: client(),
+ Target :: startup | candidate,
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Delete configuration data.
+%%
+%% The running configuration cannot be deleted and `:candidate'
+%% or `:startup' must be advertised by the server.
+%%
+%% @end
+%%----------------------------------------------------------------------
+delete_config(Client, Target, Timeout) when Target == startup;
+ Target == candidate ->
+ call(Client,{send_rpc_op, delete_config, [Target], Timeout}).
+
+%%----------------------------------------------------------------------
+%% @spec copy_config(Client, Source, Target) -> Result
+%% @equiv copy_config(Client, Source, Target, infinity)
+copy_config(Client, Source, Target) ->
+ copy_config(Client, Source, Target, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec copy_config(Client, Target, Source, Timeout) -> Result when
+ Client :: client(),
+ Target :: netconf_db(),
+ Source :: netconf_db(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Copy configuration data.
+%%
+%% Which source and target options that can be issued depends on the
+%% capabilities supported by the server. I.e. `:candidate' and/or
+%% `:startup' are required.
+%%
+%% @end
+%%----------------------------------------------------------------------
+copy_config(Client, Target, Source, Timeout) ->
+ call(Client,{send_rpc_op, copy_config, [Target, Source], Timeout}).
+
+%%----------------------------------------------------------------------
+%% @spec action(Client, Action) -> Result
+%% @equiv action(Client, Action, infinity)
+action(Client,Action) ->
+ action(Client,Action,?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec action(Client, Action, Timeout) -> Result when
+ Client :: client(),
+ Action :: simple_xml(),
+ Timeout :: timeout(),
+ Result :: {ok,simple_xml()} | {error,error_reason()}.
+%% @doc Execute an action.
+%%
+%% @end
+%%----------------------------------------------------------------------
+action(Client,Action,Timeout) ->
+ call(Client,{send_rpc_op, action, [Action], Timeout}).
+
+%%----------------------------------------------------------------------
+create_subscription(Client) ->
+ create_subscription(Client,?DEFAULT_STREAM,?DEFAULT_TIMEOUT).
+
+create_subscription(Client,Timeout)
+ when ?is_timeout(Timeout) ->
+ create_subscription(Client,?DEFAULT_STREAM,Timeout);
+create_subscription(Client,Stream)
+ when is_list(Stream) ->
+ create_subscription(Client,Stream,?DEFAULT_TIMEOUT);
+create_subscription(Client,Filter)
+ when ?is_filter(Filter) ->
+ create_subscription(Client,?DEFAULT_STREAM,Filter,
+ ?DEFAULT_TIMEOUT).
+
+create_subscription(Client,Stream,Timeout)
+ when is_list(Stream) andalso
+ ?is_timeout(Timeout) ->
+ call(Client,{send_rpc_op,{create_subscription,self()},
+ [Stream,undefined,undefined,undefined],
+ Timeout});
+create_subscription(Client,StartTime,StopTime)
+ when is_list(StartTime) andalso
+ is_list(StopTime) ->
+ create_subscription(Client,?DEFAULT_STREAM,StartTime,StopTime,
+ ?DEFAULT_TIMEOUT);
+create_subscription(Client,Filter,Timeout)
+ when ?is_filter(Filter) andalso
+ ?is_timeout(Timeout) ->
+ create_subscription(Client,?DEFAULT_STREAM,Filter,Timeout);
+create_subscription(Client,Stream,Filter)
+ when is_list(Stream) andalso
+ ?is_filter(Filter) ->
+ create_subscription(Client,Stream,Filter,?DEFAULT_TIMEOUT).
+
+create_subscription(Client,StartTime,StopTime,Timeout)
+ when is_list(StartTime) andalso
+ is_list(StopTime) andalso
+ ?is_timeout(Timeout) ->
+ create_subscription(Client,?DEFAULT_STREAM,StartTime,StopTime,Timeout);
+create_subscription(Client,Stream,StartTime,StopTime)
+ when is_list(Stream) andalso
+ is_list(StartTime) andalso
+ is_list(StopTime) ->
+ create_subscription(Client,Stream,StartTime,StopTime,?DEFAULT_TIMEOUT);
+create_subscription(Client,Filter,StartTime,StopTime)
+ when ?is_filter(Filter) andalso
+ is_list(StartTime) andalso
+ is_list(StopTime) ->
+ create_subscription(Client,?DEFAULT_STREAM,Filter,
+ StartTime,StopTime,?DEFAULT_TIMEOUT);
+create_subscription(Client,Stream,Filter,Timeout)
+ when is_list(Stream) andalso
+ ?is_filter(Filter) andalso
+ ?is_timeout(Timeout) ->
+ call(Client,{send_rpc_op,{create_subscription,self()},
+ [Stream,Filter,undefined,undefined],
+ Timeout}).
+
+create_subscription(Client,Stream,StartTime,StopTime,Timeout)
+ when is_list(Stream) andalso
+ is_list(StartTime) andalso
+ is_list(StopTime) andalso
+ ?is_timeout(Timeout) ->
+ call(Client,{send_rpc_op,{create_subscription,self()},
+ [Stream,undefined,StartTime,StopTime],
+ Timeout});
+create_subscription(Client,Stream,Filter,StartTime,StopTime)
+ when is_list(Stream) andalso
+ ?is_filter(Filter) andalso
+ is_list(StartTime) andalso
+ is_list(StopTime) ->
+ create_subscription(Client,Stream,Filter,StartTime,StopTime,?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec create_subscription(Client, Stream, Filter,StartTime, StopTime, Timeout) ->
+ Result when
+ Client :: client(),
+ Stream :: stream_name(),
+ Filter :: simple_xml(),
+ StartTime :: xs_datetime(),
+ StopTime :: xs_datetime(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Create a subscription for event notifications.
+%%
+%% This function sets up a subscription for netconf event
+%% notifications of the given stream type, matching the given
+%% filter. The calling process will receive notifications as messages
+%% of type `notification()'.
+%%
+%% <dl>
+%% <dt>Stream:</dt>
+%% <dd> An optional parameter that indicates which stream of events
+%% is of interest. If not present, events in the default NETCONF
+%% stream will be sent.</dd>
+%%
+%% <dt>Filter:</dt>
+%% <dd>An optional parameter that indicates which subset of all
+%% possible events is of interest. The format of this parameter is
+%% the same as that of the filter parameter in the NETCONF protocol
+%% operations. If not present, all events not precluded by other
+%% parameters will be sent. See section 3.6 for more information on
+%% filters.</dd>
+%%
+%% <dt>StartTime:</dt>
+%% <dd>An optional parameter used to trigger the replay feature and
+%% indicate that the replay should start at the time specified. If
+%% `StartTime' is not present, this is not a replay subscription.
+%% It is not valid to specify start times that are later than the
+%% current time. If the `StartTime' specified is earlier than the
+%% log can support, the replay will begin with the earliest
+%% available notification. This parameter is of type dateTime and
+%% compliant to [RFC3339]. Implementations must support time
+%% zones.</dd>
+%%
+%% <dt>StopTime:</dt>
+%% <dd>An optional parameter used with the optional replay feature
+%% to indicate the newest notifications of interest. If `StopTime'
+%% is not present, the notifications will continue until the
+%% subscription is terminated. Must be used with and be later than
+%% `StartTime'. Values of `StopTime' in the future are valid. This
+%% parameter is of type dateTime and compliant to [RFC3339].
+%% Implementations must support time zones.</dd>
+%% </dl>
+%%
+%% See RFC5277 for further details about the event notification
+%% mechanism.
+%%
+%% @end
+%%----------------------------------------------------------------------
+create_subscription(Client,Stream,Filter,StartTime,StopTime,Timeout) ->
+ call(Client,{send_rpc_op,{create_subscription, self()},
+ [Stream,Filter,StartTime,StopTime],
+ Timeout}).
+
+%%----------------------------------------------------------------------
+%% @spec get_event_streams(Client, Timeout) -> Result
+%% @equiv get_event_streams(Client, [], Timeout)
+get_event_streams(Client,Timeout) when is_integer(Timeout); Timeout==infinity ->
+ get_event_streams(Client,[],Timeout);
+
+%%----------------------------------------------------------------------
+%% @spec get_event_streams(Client, Streams) -> Result
+%% @equiv get_event_streams(Client, Streams, infinity)
+get_event_streams(Client,Streams) when is_list(Streams) ->
+ get_event_streams(Client,Streams,?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec get_event_streams(Client, Streams, Timeout)
+ -> Result when
+ Client :: client(),
+ Streams :: [stream_name()],
+ Timeout :: timeout(),
+ Result :: {ok,streams()} | {error,error_reason()}.
+%% @doc Send a request to get the given event streams.
+%%
+%% `Streams' is a list of stream names. The following filter will
+%% be sent to the netconf server in a `get' request:
+%%
+%% ```
+%% <netconf xmlns="urn:ietf:params:xml:ns:netmod:notification">
+%% <streams>
+%% <stream>
+%% <name>StreamName1</name>
+%% </stream>
+%% <stream>
+%% <name>StreamName2</name>
+%% </stream>
+%% ...
+%% </streams>
+%% </netconf>
+%% '''
+%%
+%% If `Streams' is an empty list, ALL streams will be requested
+%% by sending the following filter:
+%%
+%% ```
+%% <netconf xmlns="urn:ietf:params:xml:ns:netmod:notification">
+%% <streams/>
+%% </netconf>
+%% '''
+%%
+%% If more complex filtering is needed, a use {@link get/2} or {@link
+%% get/3} and specify the exact filter according to XML Schema for
+%% Event Notifications found in RFC5277.
+%%
+%% @end
+%%----------------------------------------------------------------------
+get_event_streams(Client,Streams,Timeout) ->
+ call(Client,{get_event_streams,Streams,Timeout}).
+
+
+%%----------------------------------------------------------------------
+%% @spec close_session(Client) -> Result
+%% @equiv close_session(Client, infinity)
+close_session(Client) ->
+ close_session(Client, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec close_session(Client, Timeout) -> Result when
+ Client :: client(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Request graceful termination of the session associated with the client.
+%%
+%% When a netconf server receives a `close-session' request, it
+%% will gracefully close the session. The server will release any
+%% locks and resources associated with the session and gracefully
+%% close any associated connections. Any NETCONF requests received
+%% after a `close-session' request will be ignored.
+%%
+%% @end
+%%----------------------------------------------------------------------
+close_session(Client, Timeout) ->
+ call(Client,{send_rpc_op, close_session, [], Timeout}).
+
+
+%%----------------------------------------------------------------------
+%% @spec kill_session(Client, SessionId) -> Result
+%% @equiv kill_session(Client, SessionId, infinity)
+kill_session(Client, SessionId) ->
+ kill_session(Client, SessionId, ?DEFAULT_TIMEOUT).
+
+%%----------------------------------------------------------------------
+-spec kill_session(Client, SessionId, Timeout) -> Result when
+ Client :: client(),
+ SessionId :: pos_integer(),
+ Timeout :: timeout(),
+ Result :: ok | {error,error_reason()}.
+%% @doc Force termination of the session associated with the supplied
+%% session id.
+%%
+%% The server side shall abort any operations currently in process,
+%% release any locks and resources associated with the session, and
+%% close any associated connections.
+%%
+%% Only if the server is in the confirmed commit phase, the
+%% configuration will be restored to its state before entering the
+%% confirmed commit phase. Otherwise, no configuration roll back will
+%% be performed.
+%%
+%% If the given `SessionId' is equal to the current session id,
+%% an error will be returned.
+%%
+%% @end
+%% ----------------------------------------------------------------------
+kill_session(Client, SessionId, Timeout) ->
+ call(Client,{send_rpc_op, kill_session, [SessionId], Timeout}).
+
+
+%%----------------------------------------------------------------------
+%% Callback functions
+%%----------------------------------------------------------------------
+
+%% @private
+init(_KeyOrName,{_Host,_Port},Options) ->
+ case ssh_open(Options) of
+ {ok, Connection} ->
+ log(Connection,open),
+ {ConnPid,_} = Connection#connection.reference,
+ {ok, ConnPid, #state{connection = Connection}};
+ {error,Reason}->
+ {error,Reason}
+ end.
+
+%% @private
+terminate(_, #state{connection=Connection}) ->
+ ssh_close(Connection),
+ log(Connection,close),
+ ok.
+
+%% @private
+handle_msg({hello,Timeout}, From,
+ #state{connection=Connection,hello_status=HelloStatus} = State) ->
+ case do_send(Connection, client_hello()) of
+ ok ->
+ case HelloStatus of
+ undefined ->
+ {Ref,TRef} = set_request_timer(Timeout),
+ {noreply, State#state{hello_status=#pending{tref=TRef,
+ ref=Ref,
+ caller=From}}};
+ received ->
+ {reply, ok, State#state{hello_status=done}};
+ {error,Reason} ->
+ {stop, {error,Reason}, State}
+ end;
+ Error ->
+ {stop, Error, State}
+ end;
+handle_msg(_, _From, #state{session_id=undefined} = State) ->
+ %% Hello is not yet excanged - this shall never happen
+ {reply,{error,waiting_for_hello},State};
+handle_msg(get_capabilities, _From, #state{capabilities = Caps} = State) ->
+ {reply, Caps, State};
+handle_msg(get_session_id, _From, #state{session_id = Id} = State) ->
+ {reply, Id, State};
+handle_msg({send, Timeout, SimpleXml}, From,
+ #state{connection=Connection,pending=Pending} = State) ->
+ case do_send(Connection, SimpleXml) of
+ ok ->
+ {Ref,TRef} = set_request_timer(Timeout),
+ {noreply, State#state{pending=[#pending{tref=TRef,
+ ref=Ref,
+ caller=From} | Pending]}};
+ Error ->
+ {reply, Error, State}
+ end;
+handle_msg({send_rpc, SimpleXml, Timeout}, From, State) ->
+ do_send_rpc(undefined, SimpleXml, Timeout, From, State);
+handle_msg({send_rpc_op, Op, Data, Timeout}, From, State) ->
+ SimpleXml = encode_rpc_operation(Op,Data),
+ do_send_rpc(Op, SimpleXml, Timeout, From, State);
+handle_msg({get_event_streams=Op,Streams,Timeout}, From, State) ->
+ Filter = {netconf,?NETMOD_NOTIF_NAMESPACE_ATTR,
+ [{streams,[{stream,[{name,[Name]}]} || Name <- Streams]}]},
+ SimpleXml = encode_rpc_operation(get,[Filter]),
+ do_send_rpc(Op, SimpleXml, Timeout, From, State).
+
+handle_msg({ssh_cm, _CM, {data, _Ch, _Type, Data}}, State) ->
+ handle_data(Data, State);
+handle_msg({ssh_cm, _CM, {closed,_Ch}}, State) ->
+ %% This will happen if the server terminates the connection, as in
+ %% kill-session (or if ssh:close is called from somewhere
+ %% unexpected).
+
+ %%! Log this?? - i.e. as server closing the connection
+ %%! Currently the log will say that the client closed the
+ %%! connection - due to terminate/2
+
+ {stop, State};
+handle_msg({Ref,timeout},
+ #state{hello_status=#pending{ref=Ref,caller=Caller}} = State) ->
+ ct_gen_conn:return(Caller,{error,{hello_session_failed,timeout}}),
+ {stop,State#state{hello_status={error,timeout}}};
+handle_msg({Ref,timeout},#state{pending=Pending} = State) ->
+ {value,#pending{caller=Caller},Pending1} =
+ lists:keytake(Ref,#pending.ref,Pending),
+ ct_gen_conn:return(Caller,{error,timeout}),
+ {noreply,State#state{pending=Pending1}}.
+
+%% @private
+%% Called by ct_util_server to close registered connections before terminate.
+close(Client) ->
+ case get_handle(Client) of
+ {ok,Pid} ->
+ case ct_gen_conn:stop(Pid) of
+ {error,{process_down,Pid,noproc}} ->
+ {error,already_closed};
+ Result ->
+ Result
+ end;
+ Error ->
+ Error
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Internal functions
+%%----------------------------------------------------------------------
+call(Client, Msg) ->
+ call(Client, Msg, infinity).
+call(Client, Msg, Timeout) ->
+ case get_handle(Client) of
+ {ok,Pid} ->
+ case ct_gen_conn:call(Pid,Msg,Timeout) of
+ {error,{process_down,Client,noproc}} ->
+ {error,no_such_client};
+ {error,{process_down,Client,normal}} ->
+ {error,closed};
+ {error,{process_down,Client,Reason}} ->
+ {error,{closed,Reason}};
+ Other ->
+ Other
+ end;
+ Error ->
+ Error
+ end.
+
+get_handle(Client) when is_pid(Client) ->
+ {ok,Client};
+get_handle(Client) ->
+ case ct_util:get_connections(Client, ?MODULE) of
+ {ok,[{Pid,_}]} ->
+ {ok,Pid};
+ {ok,[]} ->
+ {error,{no_connection_found,Client}};
+ {ok,Conns} ->
+ {error,{multiple_connections_found,Client,Conns}};
+ Error ->
+ Error
+ end.
+
+check_options([], undefined, _Port, _Options) ->
+ {error, no_host_address};
+check_options([], _Host, undefined, _Options) ->
+ {error, no_port};
+check_options([], Host, Port, Options) ->
+ {Host,Port,Options};
+check_options([{ssh, Host}|T], _, Port, #options{} = Options) ->
+ check_options(T, Host, Port, Options#options{host=Host});
+check_options([{port,Port}|T], Host, _, #options{} = Options) ->
+ check_options(T, Host, Port, Options#options{port=Port});
+check_options([{timeout, Timeout}|T], Host, Port, Options)
+ when is_integer(Timeout); Timeout==infinity ->
+ check_options(T, Host, Port, Options#options{timeout = Timeout});
+check_options([{X,_}=Opt|T], Host, Port, #options{ssh=SshOpts}=Options) ->
+ case lists:member(X,?VALID_SSH_OPTS) of
+ true ->
+ check_options(T, Host, Port, Options#options{ssh=[Opt|SshOpts]});
+ false ->
+ {error, {invalid_option, Opt}}
+ end.
+
+%%%-----------------------------------------------------------------
+set_request_timer(infinity) ->
+ {undefined,undefined};
+set_request_timer(T) ->
+ Ref = make_ref(),
+ {ok,TRef} = timer:send_after(T,{Ref,timeout}),
+ {Ref,TRef}.
+
+
+%%%-----------------------------------------------------------------
+client_hello() ->
+ {hello, ?NETCONF_NAMESPACE_ATTR,
+ [{capabilities,
+ [{capability,[?NETCONF_BASE_CAP++?NETCONF_BASE_CAP_VSN]}]}]}.
+
+%%%-----------------------------------------------------------------
+
+encode_rpc_operation(Lock,[Target]) when Lock==lock; Lock==unlock ->
+ {Lock,[{target,[Target]}]};
+encode_rpc_operation(get,[Filter]) ->
+ {get,filter(Filter)};
+encode_rpc_operation(get_config,[Source,Filter]) ->
+ {'get-config',[{source,[Source]}] ++ filter(Filter)};
+encode_rpc_operation(edit_config,[Target,Config]) ->
+ {'edit-config',[{target,[Target]},{config,[Config]}]};
+encode_rpc_operation(delete_config,[Target]) ->
+ {'delete-config',[{target,[Target]}]};
+encode_rpc_operation(copy_config,[Target,Source]) ->
+ {'copy-config',[{target,[Target]},{source,[Source]}]};
+encode_rpc_operation(action,[Action]) ->
+ {action,?ACTION_NAMESPACE_ATTR,[{data,[Action]}]};
+encode_rpc_operation(kill_session,[SessionId]) ->
+ {'kill-session',[{'session-id',[integer_to_list(SessionId)]}]};
+encode_rpc_operation(close_session,[]) ->
+ 'close-session';
+encode_rpc_operation({create_subscription,_},
+ [Stream,Filter,StartTime,StopTime]) ->
+ {'create-subscription',?NETCONF_NOTIF_NAMESPACE_ATTR,
+ [{stream,[Stream]}] ++
+ filter(Filter) ++
+ maybe_element(startTime,StartTime) ++
+ maybe_element(stopTime,StopTime)}.
+
+filter(undefined) ->
+ [];
+filter({xpath,Filter}) when ?is_string(Filter) ->
+ [{filter,[{type,"xpath"},{select, Filter}],[]}];
+filter(Filter) ->
+ [{filter,[{type,"subtree"}],[Filter]}].
+
+maybe_element(_,undefined) ->
+ [];
+maybe_element(Tag,Value) ->
+ [{Tag,[Value]}].
+
+%%%-----------------------------------------------------------------
+%%% Send XML data to server
+do_send_rpc(PendingOp,SimpleXml,Timeout,Caller,
+ #state{connection=Connection,msg_id=MsgId,pending=Pending} = State) ->
+ case do_send_rpc(Connection, MsgId, SimpleXml) of
+ ok ->
+ {Ref,TRef} = set_request_timer(Timeout),
+ {noreply, State#state{msg_id=MsgId+1,
+ pending=[#pending{tref=TRef,
+ ref=Ref,
+ msg_id=MsgId,
+ op=PendingOp,
+ caller=Caller} | Pending]}};
+ Error ->
+ {reply, Error, State#state{msg_id=MsgId+1}}
+ end.
+
+do_send_rpc(Connection, MsgId, SimpleXml) ->
+ do_send(Connection,
+ {rpc,
+ [{'message-id',MsgId} | ?NETCONF_NAMESPACE_ATTR],
+ [SimpleXml]}).
+
+do_send(Connection, SimpleXml) ->
+ Xml=to_xml_doc(SimpleXml),
+ log(Connection,send,Xml),
+ ssh_send(Connection, Xml).
+
+to_xml_doc(Simple) ->
+ Prolog = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
+ Xml = list_to_binary(xmerl:export_simple([Simple],
+ xmerl_xml,
+ [#xmlAttribute{name=prolog,
+ value=Prolog}])),
+ <<Xml/binary,?END_TAG/binary>>.
+
+%%%-----------------------------------------------------------------
+%%% Parse and handle received XML data
+handle_data(NewData,#state{connection=Connection,buff=Buff} = State) ->
+ log(Connection,recv,NewData),
+ Data = <<Buff/binary,NewData/binary>>,
+ case xmerl_sax_parser:stream(<<>>,
+ [{continuation_fun,fun sax_cont/1},
+ {continuation_state,{Data,Connection,false}},
+ {event_fun,fun sax_event/3},
+ {event_state,[]}]) of
+ {ok, Simple, Rest} ->
+ decode(Simple,State#state{buff=Rest});
+ {fatal_error,_Loc,Reason,_EndTags,_EventState} ->
+ ?error(Connection#connection.name,[{parse_error,Reason},
+ {data,Data}]),
+ case Reason of
+ {could_not_fetch_data,Msg} ->
+ handle_msg(Msg,State#state{buff = <<>>});
+ _Other ->
+ Pending1 =
+ case State#state.pending of
+ [] ->
+ [];
+ Pending ->
+ %% Assuming the first request gets the
+ %% first answer
+ P=#pending{tref=TRef,caller=Caller} =
+ lists:last(Pending),
+ timer:cancel(TRef),
+ Reason1 = {failed_to_parse_received_data,Reason},
+ ct_gen_conn:return(Caller,{error,Reason1}),
+ lists:delete(P,Pending)
+ end,
+ {noreply,State#state{pending=Pending1,buff = <<>>}}
+ end
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Parsing of XML data
+%% Contiuation function for the sax parser
+sax_cont(done) ->
+ {<<>>,done};
+sax_cont({Data,Connection,false}) ->
+ case binary:split(Data,[?END_TAG],[]) of
+ [All] ->
+ %% No end tag found. Remove what could be a part
+ %% of an end tag from the data and save for next
+ %% iteration
+ SafeSize = size(All)-5,
+ <<New:SafeSize/binary,Save:5/binary>> = All,
+ {New,{Save,Connection,true}};
+ [_Msg,_Rest]=Msgs ->
+ %% We have at least one full message. Any excess data will
+ %% be returned from xmerl_sax_parser:stream/2 in the Rest
+ %% parameter.
+ {list_to_binary(Msgs),done}
+ end;
+sax_cont({Data,Connection,true}) ->
+ case ssh_receive_data() of
+ {ok,Bin} ->
+ log(Connection,recv,Bin),
+ sax_cont({<<Data/binary,Bin/binary>>,Connection,false});
+ {error,Reason} ->
+ throw({could_not_fetch_data,Reason})
+ end.
+
+
+
+%% Event function for the sax parser. It builds a simple XML structure.
+%% Care is taken to keep namespace attributes and prefixes as in the original XML.
+sax_event(Event,_Loc,State) ->
+ sax_event(Event,State).
+
+sax_event({startPrefixMapping, Prefix, Uri},Acc) ->
+ %% startPrefixMapping will always come immediately before the
+ %% startElement where the namespace is defined.
+ [{xmlns,{Prefix,Uri}}|Acc];
+sax_event({startElement,_Uri,_Name,QN,Attrs},Acc) ->
+ %% Pick out any namespace attributes inserted due to a
+ %% startPrefixMapping event.The rest of Acc will then be only
+ %% elements.
+ {NsAttrs,NewAcc} = split_attrs_and_elements(Acc,[]),
+ Tag = qn_to_tag(QN),
+ [{Tag,NsAttrs ++ parse_attrs(Attrs),[]}|NewAcc];
+sax_event({endElement,_Uri,_Name,_QN},[{Name,Attrs,Cont},{Parent,PA,PC}|Acc]) ->
+ [{Parent,PA,[{Name,Attrs,lists:reverse(Cont)}|PC]}|Acc];
+sax_event(endDocument,[{Tag,Attrs,Cont}]) ->
+ {Tag,Attrs,lists:reverse(Cont)};
+sax_event({characters,String},[{Name,Attrs,Cont}|Acc]) ->
+ [{Name,Attrs,[String|Cont]}|Acc];
+sax_event(_Event,State) ->
+ State.
+
+split_attrs_and_elements([{xmlns,{Prefix,Uri}}|Rest],Attrs) ->
+ split_attrs_and_elements(Rest,[{xmlnstag(Prefix),Uri}|Attrs]);
+split_attrs_and_elements(Elements,Attrs) ->
+ {Attrs,Elements}.
+
+xmlnstag([]) ->
+ xmlns;
+xmlnstag(Prefix) ->
+ list_to_atom("xmlns:"++Prefix).
+
+qn_to_tag({[],Name}) ->
+ list_to_atom(Name);
+qn_to_tag({Prefix,Name}) ->
+ list_to_atom(Prefix ++ ":" ++ Name).
+
+parse_attrs([{_Uri, [], Name, Value}|Attrs]) ->
+ [{list_to_atom(Name),Value}|parse_attrs(Attrs)];
+parse_attrs([{_Uri, Prefix, Name, Value}|Attrs]) ->
+ [{list_to_atom(Prefix ++ ":" ++ Name),Value}|parse_attrs(Attrs)];
+parse_attrs([]) ->
+ [].
+
+
+%%%-----------------------------------------------------------------
+%%% Decoding of parsed XML data
+decode({Tag,Attrs,_}=E, #state{connection=Connection,pending=Pending}=State) ->
+ ConnName = Connection#connection.name,
+ case get_local_name_atom(Tag) of
+ 'rpc-reply' ->
+ case get_msg_id(Attrs) of
+ undefined ->
+ case Pending of
+ [#pending{msg_id=MsgId}] ->
+ ?error(ConnName,[{warning,rpc_reply_missing_msg_id},
+ {assuming,MsgId}]),
+ decode_rpc_reply(MsgId,E,State);
+ _ ->
+ ?error(ConnName,[{error,rpc_reply_missing_msg_id}]),
+ {noreply,State}
+ end;
+ MsgId ->
+ decode_rpc_reply(MsgId,E,State)
+ end;
+ hello ->
+ case State#state.hello_status of
+ undefined ->
+ case decode_hello(E) of
+ {ok,SessionId,Capabilities} ->
+ {noreply,State#state{session_id = SessionId,
+ capabilities = Capabilities,
+ hello_status = received}};
+ {error,Reason} ->
+ {noreply,State#state{hello_status = {error,Reason}}}
+ end;
+ #pending{tref=TRef,caller=Caller} ->
+ timer:cancel(TRef),
+ case decode_hello(E) of
+ {ok,SessionId,Capabilities} ->
+ ct_gen_conn:return(Caller,ok),
+ {noreply,State#state{session_id = SessionId,
+ capabilities = Capabilities,
+ hello_status = done}};
+ {error,Reason} ->
+ ct_gen_conn:return(Caller,{error,Reason}),
+ {stop,State#state{hello_status={error,Reason}}}
+ end;
+ Other ->
+ ?error(ConnName,[{got_unexpected_hello,E},
+ {hello_status,Other}]),
+ {noreply,State}
+ end;
+ notification ->
+ EventReceiver = State#state.event_receiver,
+ EventReceiver ! E,
+ {noreply,State};
+ Other ->
+ %% Result of send/2, when not sending an rpc request - or
+ %% if netconf server sends noise. Can handle this only if
+ %% there is just one pending that matches (i.e. has
+ %% undefined msg_id and op)
+ case [P || P = #pending{msg_id=undefined,op=undefined} <- Pending] of
+ [#pending{tref=TRef,
+ caller=Caller}] ->
+ timer:cancel(TRef),
+ ct_gen_conn:return(Caller,E),
+ {noreply,State#state{pending=[]}};
+ _ ->
+ ?error(ConnName,[{got_unexpected_msg,Other},
+ {expecting,Pending}]),
+ {noreply,State}
+ end
+
+ end.
+
+get_msg_id(Attrs) ->
+ case lists:keyfind('message-id',1,Attrs) of
+ {_,Str} ->
+ list_to_integer(Str);
+ false ->
+ undefined
+ end.
+
+decode_rpc_reply(MsgId,{_,Attrs,Content0}=E,#state{pending=Pending} = State) ->
+ case lists:keytake(MsgId,#pending.msg_id,Pending) of
+ {value, #pending{tref=TRef,op=Op,caller=Caller}, Pending1} ->
+ timer:cancel(TRef),
+ Content = forward_xmlns_attr(Attrs,Content0),
+ {CallerReply,{ServerReply,State2}} =
+ do_decode_rpc_reply(Op,Content,State#state{pending=Pending1}),
+ ct_gen_conn:return(Caller,CallerReply),
+ {ServerReply,State2};
+ false ->
+ %% Result of send/2, when receiving a correct
+ %% rpc-reply. Can handle this only if there is just one
+ %% pending that matches (i.e. has undefined msg_id and op)
+ case [P || P = #pending{msg_id=undefined,op=undefined} <- Pending] of
+ [#pending{tref=TRef,
+ msg_id=undefined,
+ op=undefined,
+ caller=Caller}] ->
+ timer:cancel(TRef),
+ ct_gen_conn:return(Caller,E),
+ {noreply,State#state{pending=[]}};
+ _ ->
+ ConnName = (State#state.connection)#connection.name,
+ ?error(ConnName,[{got_unexpected_msg_id,MsgId},
+ {expecting,Pending}]),
+ {noreply,State}
+ end
+ end.
+
+do_decode_rpc_reply(Op,Result,State)
+ when Op==lock; Op==unlock; Op==edit_config; Op==delete_config;
+ Op==copy_config; Op==kill_session ->
+ {decode_ok(Result),{noreply,State}};
+do_decode_rpc_reply(Op,Result,State)
+ when Op==get; Op==get_config; Op==action ->
+ {decode_data(Result),{noreply,State}};
+do_decode_rpc_reply(close_session,Result,State) ->
+ case decode_ok(Result) of
+ ok -> {ok,{stop,State}};
+ Other -> {Other,{noreply,State}}
+ end;
+do_decode_rpc_reply({create_subscription,Caller},Result,State) ->
+ case decode_ok(Result) of
+ ok ->
+ {ok,{noreply,State#state{event_receiver=Caller}}};
+ Other ->
+ {Other,{noreply,State}}
+ end;
+do_decode_rpc_reply(get_event_streams,Result,State) ->
+ {decode_streams(decode_data(Result)),{noreply,State}};
+do_decode_rpc_reply(undefined,Result,State) ->
+ {Result,{noreply,State}}.
+
+
+
+decode_ok([{Tag,Attrs,Content}]) ->
+ case get_local_name_atom(Tag) of
+ ok ->
+ ok;
+ 'rpc-error' ->
+ {error,forward_xmlns_attr(Attrs,Content)};
+ _Other ->
+ {error,{unexpected_rpc_reply,[{Tag,Attrs,Content}]}}
+ end;
+decode_ok(Other) ->
+ {error,{unexpected_rpc_reply,Other}}.
+
+decode_data([{Tag,Attrs,Content}]) ->
+ case get_local_name_atom(Tag) of
+ data ->
+ %% Since content of data has nothing from the netconf
+ %% namespace, we remove the parent's xmlns attribute here
+ %% - just to make the result cleaner
+ {ok,forward_xmlns_attr(remove_xmlnsattr_for_tag(Tag,Attrs),Content)};
+ 'rpc-error' ->
+ {error,forward_xmlns_attr(Attrs,Content)};
+ _Other ->
+ {error,{unexpected_rpc_reply,[{Tag,Attrs,Content}]}}
+ end;
+decode_data(Other) ->
+ {error,{unexpected_rpc_reply,Other}}.
+
+get_qualified_name(Tag) ->
+ case string:tokens(atom_to_list(Tag),":") of
+ [TagStr] -> {[],TagStr};
+ [PrefixStr,TagStr] -> {PrefixStr,TagStr}
+ end.
+
+get_local_name_atom(Tag) ->
+ {_,TagStr} = get_qualified_name(Tag),
+ list_to_atom(TagStr).
+
+
+%% Remove the xmlns attr that points to the tag. I.e. if the tag has a
+%% prefix, remove {'xmlns:prefix',_}, else remove default {xmlns,_}.
+remove_xmlnsattr_for_tag(Tag,Attrs) ->
+ {Prefix,_TagStr} = get_qualified_name(Tag),
+ XmlnsTag = xmlnstag(Prefix),
+ case lists:keytake(XmlnsTag,1,Attrs) of
+ {value,_,NoNsAttrs} ->
+ NoNsAttrs;
+ false ->
+ Attrs
+ end.
+
+%% Take all xmlns attributes from the parent's attribute list and
+%% forward into all childrens' attribute lists. But do not overwrite
+%% any.
+forward_xmlns_attr(ParentAttrs,Children) ->
+ do_forward_xmlns_attr(get_all_xmlns_attrs(ParentAttrs,[]),Children).
+
+do_forward_xmlns_attr(XmlnsAttrs,[{ChT,ChA,ChC}|Children]) ->
+ ChA1 = add_xmlns_attrs(XmlnsAttrs,ChA),
+ [{ChT,ChA1,ChC} | do_forward_xmlns_attr(XmlnsAttrs,Children)];
+do_forward_xmlns_attr(_XmlnsAttrs,[]) ->
+ [].
+
+add_xmlns_attrs([{Key,_}=A|XmlnsAttrs],ChA) ->
+ case lists:keymember(Key,1,ChA) of
+ true ->
+ add_xmlns_attrs(XmlnsAttrs,ChA);
+ false ->
+ add_xmlns_attrs(XmlnsAttrs,[A|ChA])
+ end;
+add_xmlns_attrs([],ChA) ->
+ ChA.
+
+get_all_xmlns_attrs([{xmlns,_}=Default|Attrs],XmlnsAttrs) ->
+ get_all_xmlns_attrs(Attrs,[Default|XmlnsAttrs]);
+get_all_xmlns_attrs([{Key,_}=Attr|Attrs],XmlnsAttrs) ->
+ case atom_to_list(Key) of
+ "xmlns:"++_Prefix ->
+ get_all_xmlns_attrs(Attrs,[Attr|XmlnsAttrs]);
+ _ ->
+ get_all_xmlns_attrs(Attrs,XmlnsAttrs)
+ end;
+get_all_xmlns_attrs([],XmlnsAttrs) ->
+ XmlnsAttrs.
+
+
+%% Decode server hello to pick out session id and capabilities
+decode_hello({hello,_Attrs,Hello}) ->
+ case lists:keyfind('session-id',1,Hello) of
+ {'session-id',_,[SessionId]} ->
+ case lists:keyfind(capabilities,1,Hello) of
+ {capabilities,_,Capabilities} ->
+ case decode_caps(Capabilities,[],false) of
+ {ok,Caps} ->
+ {ok,list_to_integer(SessionId),Caps};
+ Error ->
+ Error
+ end;
+ false ->
+ {error,{incorrect_hello,capabilities_not_found}}
+ end;
+ false ->
+ {error,{incorrect_hello,no_session_id_found}}
+ end.
+
+decode_caps([{capability,[],[?NETCONF_BASE_CAP++Vsn=Cap]} |Caps], Acc, _) ->
+ case Vsn of
+ ?NETCONF_BASE_CAP_VSN ->
+ decode_caps(Caps, [Cap|Acc], true);
+ _ ->
+ {error,{incompatible_base_capability_vsn,Vsn}}
+ end;
+decode_caps([{capability,[],[Cap]}|Caps],Acc,Base) ->
+ decode_caps(Caps,[Cap|Acc],Base);
+decode_caps([H|_T],_,_) ->
+ {error,{unexpected_capability_element,H}};
+decode_caps([],_,false) ->
+ {error,{incorrect_hello,no_base_capability_found}};
+decode_caps([],Acc,true) ->
+ {ok,lists:reverse(Acc)}.
+
+
+%% Return a list of {Name,Data}, where data is a {Tag,Value} list for each stream
+decode_streams({error,Reason}) ->
+ {error,Reason};
+decode_streams({ok,[{netconf,_,Streams}]}) ->
+ {ok,decode_streams(Streams)};
+decode_streams([{streams,_,Streams}]) ->
+ decode_streams(Streams);
+decode_streams([{stream,_,Stream} | Streams]) ->
+ {name,_,[Name]} = lists:keyfind(name,1,Stream),
+ [{Name,[{Tag,Value} || {Tag,_,[Value]} <- Stream, Tag /= name]}
+ | decode_streams(Streams)];
+decode_streams([]) ->
+ [].
+
+
+%%%-----------------------------------------------------------------
+%%% Logging
+
+log(Connection,Action) ->
+ log(Connection,Action,<<>>).
+log(#connection{host=Host,port=Port,name=Name},Action,Data) ->
+ error_logger:info_report(#conn_log{client=self(),
+ address={Host,Port},
+ name=Name,
+ action=Action,
+ module=?MODULE},
+ Data).
+
+
+%% Log callback - called from the error handler process
+format_data(raw,Data) ->
+ io_lib:format("~n~s~n",[hide_password(Data)]);
+format_data(pretty,Data) ->
+ io_lib:format("~n~s~n",[indent(Data)]);
+format_data(html,Data) ->
+ io_lib:format("~n~s~n",[html_format(Data)]).
+
+%%%-----------------------------------------------------------------
+%%% Hide password elements from XML data
+hide_password(Bin) ->
+ re:replace(Bin,<<"(<password[^>]*>)[^<]*(</password>)">>,<<"\\1*****\\2">>,
+ [global,{return,binary}]).
+
+%%%-----------------------------------------------------------------
+%%% HTML formatting
+html_format(Bin) ->
+ binary:replace(indent(Bin),<<"<">>,<<"&lt;">>,[global]).
+
+%%%-----------------------------------------------------------------
+%%% Indentation of XML code
+indent(Bin) ->
+ String = normalize(hide_password(Bin)),
+ IndentedString =
+ case erase(part_of_line) of
+ undefined ->
+ indent1(String,[]);
+ Part ->
+ indent1(lists:reverse(Part)++String,erase(indent))
+ end,
+ list_to_binary(IndentedString).
+
+%% Normalizes the XML document by removing all space and newline
+%% between two XML tags.
+%% Returns a list, no matter if the input was a list or a binary.
+normalize(Str) ->
+ re:replace(Str,<<">[ \r\n\t]+<">>,<<"><">>,[global,{return,list}]).
+
+
+indent1("<?"++Rest1,Indent1) ->
+ %% Prolog
+ {Line,Rest2,Indent2} = indent_line(Rest1,Indent1,[$?,$<]),
+ Line++indent1(Rest2,Indent2);
+indent1("</"++Rest1,Indent1) ->
+ %% Stop tag
+ {Line,Rest2,Indent2} = indent_line1(Rest1,Indent1,[$/,$<]),
+ "\n"++Line++indent1(Rest2,Indent2);
+indent1("<"++Rest1,Indent1) ->
+ %% Start- or empty tag
+ put(tag,get_tag(Rest1)),
+ {Line,Rest2,Indent2} = indent_line(Rest1,Indent1,[$<]),
+ "\n"++Line++indent1(Rest2,Indent2);
+indent1([H|T],Indent) ->
+ [H|indent1(T,Indent)];
+indent1([],_Indent) ->
+ [].
+
+indent_line("?>"++Rest,Indent,Line) ->
+ %% Prolog
+ {lists:reverse(Line)++"?>",Rest,Indent};
+indent_line("/></"++Rest,Indent,Line) ->
+ %% Empty tag, and stop of parent tag -> one step out in indentation
+ {Indent++lists:reverse(Line)++"/>","</"++Rest,Indent--" "};
+indent_line("/>"++Rest,Indent,Line) ->
+ %% Empty tag, then probably next tag -> keep indentation
+ {Indent++lists:reverse(Line)++"/>",Rest,Indent};
+indent_line("></"++Rest,Indent,Line) ->
+ LastTag = erase(tag),
+ case get_tag(Rest) of
+ LastTag ->
+ %% Start and stop tag, but no content
+ indent_line1(Rest,Indent,[$/,$<,$>|Line]);
+ _ ->
+ %% Stop tag completed, and then stop tag of parent -> one step out
+ {Indent++lists:reverse(Line)++">","</"++Rest,Indent--" "}
+ end;
+indent_line("><"++Rest,Indent,Line) ->
+ %% Stop tag completed, and new tag comming -> keep indentation
+ {Indent++lists:reverse(Line)++">","<"++Rest," "++Indent};
+indent_line("</"++Rest,Indent,Line) ->
+ %% Stop tag starting -> search for end of this tag
+ indent_line1(Rest,Indent,[$/,$<|Line]);
+indent_line([H|T],Indent,Line) ->
+ indent_line(T,Indent,[H|Line]);
+indent_line([],Indent,Line) ->
+ %% The line is not complete - will be continued later
+ put(part_of_line,Line),
+ put(indent,Indent),
+ {[],[],Indent}.
+
+indent_line1("></"++Rest,Indent,Line) ->
+ %% Stop tag completed, and then stop tag of parent -> one step out
+ {Indent++lists:reverse(Line)++">","</"++Rest,Indent--" "};
+indent_line1(">"++Rest,Indent,Line) ->
+ %% Stop tag completed -> keep indentation
+ {Indent++lists:reverse(Line)++">",Rest,Indent};
+indent_line1([H|T],Indent,Line) ->
+ indent_line1(T,Indent,[H|Line]);
+indent_line1([],Indent,Line) ->
+ %% The line is not complete - will be continued later
+ put(part_of_line,Line),
+ put(indent,Indent),
+ {[],[],Indent}.
+
+get_tag("/>"++_) ->
+ [];
+get_tag(">"++_) ->
+ [];
+get_tag([H|T]) ->
+ [H|get_tag(T)];
+get_tag([]) ->
+ %% The line is not complete - will be continued later.
+ [].
+
+
+%%%-----------------------------------------------------------------
+%%% SSH stuff
+ssh_receive_data() ->
+ receive
+ {ssh_cm, _CM, {data, _Ch, _Type, Data}} ->
+ {ok, Data};
+ {ssh_cm, _CM, {Closed, _Ch}} = X when Closed == closed; Closed == eof ->
+ {error,X};
+ {_Ref,timeout} = X ->
+ {error,X}
+ end.
+
+ssh_open(#options{host=Host,timeout=Timeout,port=Port,ssh=SshOpts,name=Name}) ->
+ case ssh:connect(Host, Port,
+ [{user_interaction,false},
+ {silently_accept_hosts, true}|SshOpts]) of
+ {ok,CM} ->
+ case ssh_connection:session_channel(CM, Timeout) of
+ {ok,Ch} ->
+ case ssh_connection:subsystem(CM, Ch, "netconf", Timeout) of
+ success ->
+ {ok, #connection{reference = {CM,Ch},
+ host = Host,
+ port = Port,
+ name = Name}};
+ failure ->
+ ssh:close(CM),
+ {error,{ssh,could_not_execute_netconf_subsystem}}
+ end;
+ {error, Reason} ->
+ ssh:close(CM),
+ {error,{ssh,could_not_open_channel,Reason}};
+ Other ->
+ %% Bug in ssh?? got {closed,0} here once...
+ {error,{ssh,unexpected_from_session_channel,Other}}
+ end;
+ {error,Reason} ->
+ {error,{ssh,could_not_connect_to_server,Reason}}
+ end.
+
+ssh_send(#connection{reference = {CM,Ch}}, Data) ->
+ case ssh_connection:send(CM, Ch, Data) of
+ ok -> ok;
+ {error,Reason} -> {error,{ssh,failed_to_send_data,Reason}}
+ end.
+
+ssh_close(#connection{reference = {CM,_Ch}}) ->
+ ssh:close(CM).
+
+
+%%----------------------------------------------------------------------
+%% END OF MODULE
+%%----------------------------------------------------------------------
diff --git a/lib/common_test/src/ct_netconfc.hrl b/lib/common_test/src/ct_netconfc.hrl
new file mode 100644
index 0000000000..295a61a98b
--- /dev/null
+++ b/lib/common_test/src/ct_netconfc.hrl
@@ -0,0 +1,58 @@
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. 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%
+%%
+%%----------------------------------------------------------------------
+%% File: ct_netconfc.hrl
+%%
+%% Description:
+%% This file defines constant values and records used by the
+%% netconf client ct_netconfc.
+%%
+%% @author Support
+%% @doc Netconf Client Interface.
+%% @end
+%%----------------------------------------------------------------------
+%%----------------------------------------------------------------------
+
+
+%% Default port number (RFC 4742/IANA).
+-define(DEFAULT_PORT, 830).
+
+%% Default timeout to wait for netconf server to reply to a request
+-define(DEFAULT_TIMEOUT, infinity). %% msec
+
+%% Namespaces
+-define(NETCONF_NAMESPACE_ATTR,[{xmlns,?NETCONF_NAMESPACE}]).
+-define(ACTION_NAMESPACE_ATTR,[{xmlns,?ACTION_NAMESPACE}]).
+-define(NETCONF_NOTIF_NAMESPACE_ATTR,[{xmlns,?NETCONF_NOTIF_NAMESPACE}]).
+-define(NETMOD_NOTIF_NAMESPACE_ATTR,[{xmlns,?NETMOD_NOTIF_NAMESPACE}]).
+
+-define(NETCONF_NAMESPACE,"urn:ietf:params:xml:ns:netconf:base:1.0").
+-define(ACTION_NAMESPACE,"urn:com:ericsson:ecim:1.0").
+-define(NETCONF_NOTIF_NAMESPACE,
+ "urn:ietf:params:xml:ns:netconf:notification:1.0").
+-define(NETMOD_NOTIF_NAMESPACE,"urn:ietf:params:xml:ns:netmod:notification").
+
+%% Capabilities
+-define(NETCONF_BASE_CAP,"urn:ietf:params:netconf:base:").
+-define(NETCONF_BASE_CAP_VSN,"1.0").
+
+%% Misc
+-define(END_TAG,<<"]]>]]>">>).
+
+-define(FORMAT(_F, _A), lists:flatten(io_lib:format(_F, _A))).
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 9d6ee3c8b9..66ecb142ca 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -369,11 +369,23 @@ loop(Mode,TestData,StartDir) ->
{'EXIT',_Pid,normal} ->
loop(Mode,TestData,StartDir);
{'EXIT',Pid,Reason} ->
- %% Let process crash in case of error, this shouldn't happen!
- io:format("\n\nct_util_server got EXIT from ~p: ~p\n\n",
- [Pid,Reason]),
- file:set_cwd(StartDir),
- exit(Reason)
+ case ets:lookup(?conn_table,Pid) of
+ [#conn{address=A,callback=CB}] ->
+ %% A connection crashed - remove the connection but don't die
+ ct_logs:tc_log_async(ct_error_notify,
+ "Connection process died: "
+ "Pid: ~p, Address: ~p, Callback: ~p\n"
+ "Reason: ~p\n\n",
+ [Pid,A,CB,Reason]),
+ catch CB:close(Pid),
+ loop(Mode,TestData,StartDir);
+ _ ->
+ %% Let process crash in case of error, this shouldn't happen!
+ io:format("\n\nct_util_server got EXIT from ~p: ~p\n\n",
+ [Pid,Reason]),
+ file:set_cwd(StartDir),
+ exit(Reason)
+ end
end.
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 6b016e95df..474d36574e 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -64,3 +64,6 @@
-define(ct_config_txt, ct_config_plain).
-define(ct_profile_file, ".common_test").
+
+%% Logging information for error handler
+-record(conn_log, {client, name, address, action, module}).
diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl
new file mode 100644
index 0000000000..3af89db3a5
--- /dev/null
+++ b/lib/common_test/src/cth_conn_log.erl
@@ -0,0 +1,124 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. 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%
+%%
+%%----------------------------------------------------------------------
+%% CT hook for logging of connections.
+%%
+%% HookOptions can be hardcoded in the test suite:
+%%
+%% suite() ->
+%% [{ct_hooks, [{cth_conn_log,
+%% [{ct_netconfc:conn_mod(),ct_netconfc:hook_options()}]}]}].
+%%
+%% or specified in a configuration file:
+%%
+%% {ct_conn_log,[{ct_netconfc:conn_mod(),ct_netconfc:hook_options()}]}.
+%%
+%% The conn_mod() is the common test module implementing the protocol,
+%% e.g. ct_netconfc, ct_telnet, etc. This module must log by calling
+%%
+%% error_logger:info_report(ConnLogInfo,Data).
+%% ConnLogInfo = #conn_log{} | {ct_connection,Action,ConnName}
+%% Action = open | close | send | recv | term()
+%% ConnName = atom() - The 'KeyOrName' argument used when opening the connection
+%%
+%% ct_conn_log_h will print to html log or separate file (depending on
+%% log_type() option). conn_mod() must implement and export
+%%
+%% format_data(log_type(), Data).
+%%
+%% If logging to separate file, ct_conn_log_h will also log error
+%% reports which are witten like this:
+%%
+%% error_logger:error_report([{ct_connection,ConnName} | Report]).
+%%
+%%----------------------------------------------------------------------
+-module(cth_conn_log).
+
+-include_lib("common_test/include/ct.hrl").
+
+-export([init/2,
+ pre_init_per_testcase/3,
+ post_end_per_testcase/4]).
+
+-spec init(Id, HookOpts) -> Result when
+ Id :: term(),
+ HookOpts :: ct:hook_options(),
+ Result :: {ok,[{ct_netconfc:conn_mod(),
+ {ct_netconfc:log_type(),[ct_netconfc:key_or_name()]}}]}.
+init(_Id, HookOpts) ->
+ ConfOpts = ct:get_config(ct_conn_log,[]),
+ {ok,merge_log_info(ConfOpts,HookOpts)}.
+
+merge_log_info([{Mod,ConfOpts}|ConfList],HookList) ->
+ {Opts,HookList1} =
+ case lists:keytake(Mod,1,HookList) of
+ false ->
+ {ConfOpts,HookList};
+ {value,{_,HookOpts},HL1} ->
+ {ConfOpts ++ HookOpts, HL1} % ConfOpts overwrites HookOpts!
+ end,
+ [{Mod,get_log_opts(Opts)} | merge_log_info(ConfList,HookList1)];
+merge_log_info([],HookList) ->
+ [{Mod,get_log_opts(Opts)} || {Mod,Opts} <- HookList].
+
+get_log_opts(Opts) ->
+ LogType = proplists:get_value(log_type,Opts,html),
+ Hosts = proplists:get_value(hosts,Opts,[]),
+ {LogType,Hosts}.
+
+
+pre_init_per_testcase(TestCase,Config,CthState) ->
+ Logs =
+ lists:map(
+ fun({ConnMod,{LogType,Hosts}}) ->
+ case LogType of
+ LogType when LogType==raw; LogType==pretty ->
+ Dir = ?config(priv_dir,Config),
+ TCStr = atom_to_list(TestCase),
+ ConnModStr = atom_to_list(ConnMod),
+ DefLogName = TCStr ++ "-" ++ ConnModStr ++ ".txt",
+ DefLog = filename:join(Dir,DefLogName),
+ Ls = [{Host,
+ filename:join(Dir,TCStr ++ "-"++
+ atom_to_list(Host) ++ "-" ++
+ ConnModStr ++
+ ".txt")}
+ || Host <- Hosts]
+ ++[{default,DefLog}],
+ Str =
+ "<table borders=1>"
+ "<b>" ++ ConnModStr ++ " logs:</b>\n" ++
+ [io_lib:format(
+ "<tr><td>~p</td><td><a href=~p>~s</a></td></tr>",
+ [S,L,filename:basename(L)])
+ || {S,L} <- Ls] ++
+ "</table>",
+ io:format(Str,[]),
+ {ConnMod,{LogType,Ls}};
+ _ ->
+ {ConnMod,{LogType,[]}}
+ end
+ end,
+ CthState),
+ error_logger:add_report_handler(ct_conn_log_h,{group_leader(),Logs}),
+ {Config,CthState}.
+
+post_end_per_testcase(_TestCase,_Config,Return,CthState) ->
+ error_logger:delete_report_handler(ct_conn_log_h),
+ {Return,CthState}.
diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl
index ef7fe6c455..e7bd84e51b 100644
--- a/lib/common_test/src/cth_surefire.erl
+++ b/lib/common_test/src/cth_surefire.erl
@@ -49,9 +49,12 @@ init(Path, Opts) ->
properties = proplists:get_value(properties,Opts,[]),
timer = now() }.
-pre_init_per_suite(Suite,Config,State) ->
+pre_init_per_suite(Suite,Config,#state{ test_cases = [] } = State) ->
{Config, init_tc(State#state{ curr_suite = Suite, curr_suite_ts = now() },
- Config) }.
+ Config) };
+pre_init_per_suite(Suite,Config,State) ->
+ %% Have to close the previous suite
+ pre_init_per_suite(Suite,Config,close_suite(State)).
post_init_per_suite(_Suite,Config, Result, State) ->
{Result, end_tc(init_per_suite,Config,Result,State)}.
@@ -59,11 +62,7 @@ post_init_per_suite(_Suite,Config, Result, State) ->
pre_end_per_suite(_Suite,Config,State) -> {Config, init_tc(State, Config)}.
post_end_per_suite(_Suite,Config,Result,State) ->
- NewState = end_tc(end_per_suite,Config,Result,State),
- TCs = NewState#state.test_cases,
- Suite = get_suite(NewState, TCs),
- {Result, State#state{ test_cases = [],
- test_suites = [Suite | State#state.test_suites]}}.
+ {Result, end_tc(end_per_suite,Config,Result,State)}.
pre_init_per_group(Group,Config,State) ->
{Config, init_tc(State#state{ curr_group = [Group|State#state.curr_group]},
@@ -93,9 +92,14 @@ on_tc_fail(_TC, Res, State) ->
{fail,lists:flatten(io_lib:format("~p",[Res]))} },
State#state{ test_cases = [NewTC | tl(TCs)]}.
+on_tc_skip(Tc,{Type,Reason} = Res, State) when Type == tc_auto_skip ->
+ do_tc_skip(Res, end_tc(Tc,[],Res,init_tc(State,[])));
on_tc_skip(_Tc, _Res, State = #state{test_cases = []}) ->
State;
on_tc_skip(_Tc, Res, State) ->
+ do_tc_skip(Res, State).
+
+do_tc_skip(Res, State) ->
TCs = State#state.test_cases,
TC = hd(TCs),
NewTC = TC#testcase{
@@ -103,9 +107,11 @@ on_tc_skip(_Tc, Res, State) ->
{skipped,lists:flatten(io_lib:format("~p",[Res]))} },
State#state{ test_cases = [NewTC | tl(TCs)]}.
+init_tc(State, Config) when is_list(Config) == false ->
+ State#state{ timer = now(), tc_log = "" };
init_tc(State, Config) ->
State#state{ timer = now(),
- tc_log = proplists:get_value(tc_logfile, Config)}.
+ tc_log = proplists:get_value(tc_logfile, Config, [])}.
end_tc(Func, Config, Res, State) when is_atom(Func) ->
end_tc(atom_to_list(Func), Config, Res, State);
@@ -123,26 +129,35 @@ end_tc(Name, _Config, _Res, State = #state{ curr_suite = Suite,
name = Name,
time = TimeTakes,
failure = passed }| State#state.test_cases]}.
-
-get_suite(State, TCs) ->
+close_suite(#state{ test_cases = [] } = State) ->
+ State;
+close_suite(#state{ test_cases = TCs } = State) ->
Total = length(TCs),
Succ = length(lists:filter(fun(#testcase{ failure = F }) ->
F == passed
end,TCs)),
Fail = Total - Succ,
TimeTaken = timer:now_diff(now(),State#state.curr_suite_ts) / 1000000,
- #testsuite{ name = atom_to_list(State#state.curr_suite),
- package = State#state.package,
- time = io_lib:format("~f",[TimeTaken]),
- timestamp = now_to_string(State#state.curr_suite_ts),
- errors = Fail, tests = Total, testcases = lists:reverse(TCs) }.
-
-terminate(State) ->
- {ok,D} = file:open(State#state.filepath,[write]),
+ Suite = #testsuite{ name = atom_to_list(State#state.curr_suite),
+ package = State#state.package,
+ time = io_lib:format("~f",[TimeTaken]),
+ timestamp = now_to_string(State#state.curr_suite_ts),
+ errors = Fail, tests = Total,
+ testcases = lists:reverse(TCs) },
+ State#state{ test_cases = [],
+ test_suites = [Suite | State#state.test_suites]}.
+
+terminate(State = #state{ test_cases = [] }) ->
+ {ok,D} = file:open(State#state.filepath,[write,{encoding,utf8}]),
io:format(D, "<?xml version=\"1.0\" encoding= \"UTF-8\" ?>", []),
io:format(D, to_xml(State), []),
catch file:sync(D),
- catch file:close(D).
+ catch file:close(D);
+terminate(State) ->
+ %% Have to close the last suite
+ terminate(close_suite(State)).
+
+
to_xml(#testcase{ group = Group, classname = CL, log = L, name = N, time = T, timestamp = TS, failure = F}) ->
["<testcase ",
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 2a52f8ed74..4d85b84b5b 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -45,7 +45,8 @@ MODULES= \
ct_config_SUITE \
ct_master_SUITE \
ct_misc_1_SUITE \
- ct_hooks_SUITE
+ ct_hooks_SUITE \
+ ct_netconfc_SUITE
ERL_FILES= $(MODULES:%=%.erl)
@@ -97,10 +98,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec:
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR)
- $(INSTALL_DATA) common_test.spec $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(ERL_FILES) $(COVERFILE) "$(RELSYSDIR)"
+ $(INSTALL_DATA) common_test.spec "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/common_test/test/common_test.spec b/lib/common_test/test/common_test.spec
index 8755b08117..8bec66d6f2 100644
--- a/lib/common_test/test/common_test.spec
+++ b/lib/common_test/test/common_test.spec
@@ -1 +1 @@
-{suites,"../common_test_test",all}. \ No newline at end of file
+{suites,"../common_test_test",all}.
diff --git a/lib/common_test/test/ct_netconfc_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE.erl
new file mode 100644
index 0000000000..e6e8d5b09c
--- /dev/null
+++ b/lib/common_test/test/ct_netconfc_SUITE.erl
@@ -0,0 +1,124 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2012. 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_netconfc_SUITE
+%%%
+%%% Description:
+%%% Test ct_netconfc module
+%%%
+%%%-------------------------------------------------------------------
+-module(ct_netconfc_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config1 = ct_test_support:init_per_suite(Config),
+ Config1.
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ default
+ ].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+default(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, "netconfc1_SUITE"),
+ CfgFile = filename:join(DataDir, "netconfc1.cfg"),
+ {Opts,ERPid} = setup([{suite,Suite},{config,CfgFile},
+ {label,default}], Config),
+
+ ok = execute(default, Opts, ERPid, Config).
+
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+execute(Name, Opts, ERPid, Config) ->
+ ok = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(Name,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(Name,Config),
+ ct_test_support:verify_events(TestEvents, Events, Config).
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test,Config) ->
+ {module,_} = code:load_abs(filename:join(?config(data_dir,Config),
+ netconfc1_SUITE)),
+ TCs = netconfc1_SUITE:all(),
+ code:purge(netconfc1_SUITE),
+ code:delete(netconfc1_SUITE),
+
+ OneTest =
+ [{?eh,start_logging,{'DEF','RUNDIR'}}] ++
+ [{?eh,tc_done,{netconfc1_SUITE,TC,ok}} || TC <- TCs] ++
+ [{?eh,stop_logging,[]}],
+
+ %% 2 tests (ct:run_test + script_start) is default
+ OneTest ++ OneTest.
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1.cfg b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1.cfg
new file mode 100644
index 0000000000..6466571623
--- /dev/null
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1.cfg
@@ -0,0 +1,6 @@
+%% -*- erlang -*-
+{netconf1,[{ssh,"localhost"},
+ {port,2060},
+ {user,"xxx"},
+ {password,"xxx"}]}.
+{ct_conn_log,[{ct_netconfc,[{log_type,pretty}]}]}. %overrides args to cth_conn_log
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
new file mode 100644
index 0000000000..79768a9a6a
--- /dev/null
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -0,0 +1,1130 @@
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. 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%
+%%
+%%----------------------------------------------------------------------
+%% File: ct_netconfc_SUITE.erl
+%%
+%% Description:
+%% This file contains the test cases for the ct_netconfc API.
+%%
+%% @author Support
+%% @doc Netconf Client Interface.
+%% @end
+%%----------------------------------------------------------------------
+%%----------------------------------------------------------------------
+-module(netconfc1_SUITE).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/src/ct_netconfc.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-compile(export_all).
+
+%% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+-define(NS,ns).
+-define(LOCALHOST, "127.0.0.1").
+-define(SSH_PORT, 2060).
+
+-define(DEFAULT_SSH_OPTS,[{ssh,?LOCALHOST},
+ {port,?SSH_PORT},
+ {user,"xxx"},
+ {password,"xxx"}]).
+-define(DEFAULT_SSH_OPTS(Dir), ?DEFAULT_SSH_OPTS++[{user_dir,Dir}]).
+
+-define(ok,ok).
+
+suite() ->
+ [{ct_hooks, [{cth_conn_log,
+ [{ct_netconfc,[{log_type,html}, %will be overwritten by config
+ {hosts,[my_named_connection,netconf1]}]
+ }]
+ }]
+ }].
+
+all() ->
+ case os:find_executable("ssh") of
+ false ->
+ {skip, "SSH not installed on host"};
+ _ ->
+ [hello,
+ hello_from_server_first,
+ hello_named,
+ hello_configured,
+ hello_configured_extraopts,
+ hello_required,
+ hello_required_exists,
+ hello_global_pwd,
+ hello_no_session_id,
+ hello_incomp_base_vsn,
+ hello_no_base_cap,
+ hello_no_caps,
+ no_server_hello,
+ no_client_hello,
+ get_session_id,
+ get_capabilities,
+ faulty_user,
+ faulty_passwd,
+ faulty_port,
+ no_host,
+ no_port,
+ invalid_opt,
+ get,
+ get_xpath,
+ get_config,
+ get_config_xpath,
+ edit_config,
+ copy_config,
+ delete_config,
+ lock,
+ unlock,
+ kill_session,
+ get_no_such_client,
+ action,
+ send_any_rpc,
+ send_any,
+ hide_password,
+ not_proper_xml,
+ prefixed_namespace,
+ receive_chunked_data,
+ timeout_receive_chunked_data,
+ close_while_waiting_for_chunked_data,
+ connection_crash,
+ get_event_streams,
+ create_subscription,
+ receive_event]
+ end.
+
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(_Case, Config) ->
+ ets:delete_all_objects(ns_tab),
+ Dog = test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+init_per_suite(Config) ->
+ case catch {crypto:start(), ssh:start()} of
+ {ok, ok} ->
+ {ok, _} = get_id_keys(Config),
+ make_dsa_files(Config),
+ Server = ?NS:start(?config(data_dir,Config)),
+ [{server,Server}|Config];
+ _ ->
+ {skip, "Crypto and/or SSH could not be started!"}
+ end.
+
+end_per_suite(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ ?NS:stop(?config(server,Config)),
+ ssh:stop(),
+ crypto:stop(),
+ remove_id_keys(PrivDir),
+ Config.
+
+hello(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+hello_from_server_first(Config) ->
+ DataDir = ?config(data_dir,Config),
+ ?NS:hello(1),
+ {ok,Client} = ct_netconfc:only_open(?DEFAULT_SSH_OPTS(DataDir)),
+ ct:sleep(500),
+ ?NS:expect(hello),
+ ?ok = ct_netconfc:hello(Client),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+hello_named(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(any_name,DataDir),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+hello_configured() ->
+ [{require, netconf1}].
+hello_configured(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_configured_success(netconf1,DataDir),
+ ?NS:expect_do_reply('close-session',close,ok),
+ {error, {no_such_name,netconf1}} = ct_netconfc:close_session(netconf1),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+hello_configured_extraopts() ->
+ [{require, netconf1}].
+hello_configured_extraopts(Config) ->
+ DataDir = ?config(data_dir,Config),
+ %% Test that the cofiguration overwrites the ExtraOpts parameter
+ %% to ct_netconfc:open/2.
+ {ok,Client} = open_configured_success(netconf1,DataDir,[{password,"faulty"}]),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+hello_required() ->
+ [{require, my_named_connection, netconf1}].
+hello_required(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,_Client} = open_configured_success(my_named_connection,DataDir),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(my_named_connection),
+ ok.
+
+hello_required_exists() ->
+ [{require, my_named_connection, netconf1}].
+hello_required_exists(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,_Client1} = open_configured_success(my_named_connection,DataDir),
+
+ %% Check that same name can not be used twice
+ {error,{connection_exists,_Client1}} =
+ ct_netconfc:open(my_named_connection,[{user_dir,DataDir}]),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(my_named_connection),
+
+ %% Then check that it can be used again after the first is closed
+ {ok,_Client2} = open_configured_success(my_named_connection,DataDir),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(my_named_connection),
+ ok.
+
+hello_global_pwd(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir,[{user,"any-user"},
+ {password,"global-xxx"}]),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+hello_no_session_id(Config) ->
+ DataDir = ?config(data_dir,Config),
+ ?NS:hello(no_session_id),
+ ?NS:expect(hello),
+ {error,{incorrect_hello,no_session_id_found}} = open(DataDir),
+ ok.
+
+hello_incomp_base_vsn(Config) ->
+ DataDir = ?config(data_dir,Config),
+ ?NS:hello(1,{base,"1.1"}),
+ ?NS:expect(hello),
+ {error,{incompatible_base_capability_vsn,"1.1"}} = open(DataDir),
+ ok.
+
+hello_no_base_cap(Config) ->
+ DataDir = ?config(data_dir,Config),
+ ?NS:hello(1,no_base),
+ ?NS:expect(hello),
+ {error,{incorrect_hello,no_base_capability_found}} = open(DataDir),
+ ok.
+
+hello_no_caps(Config) ->
+ DataDir = ?config(data_dir,Config),
+ ?NS:hello(1,no_caps),
+ ?NS:expect(hello),
+ {error,{incorrect_hello,capabilities_not_found}} = open(DataDir),
+ ok.
+
+no_server_hello(Config) ->
+ DataDir = ?config(data_dir,Config),
+ ?NS:expect(hello),
+ {error,{hello_session_failed,timeout}} = open(DataDir,[{timeout,2000}]),
+ ok.
+
+no_client_hello(Config) ->
+ DataDir = ?config(data_dir,Config),
+ ?NS:hello(1),
+ {ok,Client} = ct_netconfc:only_open(?DEFAULT_SSH_OPTS(DataDir)),
+
+ %% Allow server hello to arrive
+ ct:sleep(500),
+
+ %% Tell server to receive a get request and then die without
+ %% replying since no hello has been received. (is this correct
+ %% behavoiur??)
+ ?NS:expect_do(get,close),
+ {error,closed} = ct_netconfc:get(Client,whatever),
+ ok.
+
+get_session_id(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ 1 = ct_netconfc:get_session_id(Client),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+get_capabilities(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ Caps = ct_netconfc:get_capabilities(Client),
+ BaseCap = ?NETCONF_BASE_CAP ++ ?NETCONF_BASE_CAP_VSN,
+ [BaseCap,"urn:ietf:params:netconf:capability:writable-running:1.0" |_] = Caps,
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+faulty_user(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {error,{ssh,could_not_connect_to_server,
+ "Unable to connect using the available authentication methods"}} =
+ open(DataDir,[{user,"yyy"}]),
+ ok.
+
+faulty_passwd(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {error,{ssh,could_not_connect_to_server,
+ "Unable to connect using the available authentication methods"}} =
+ open(DataDir,[{password,"yyy"}]),
+ ok.
+
+faulty_port(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {error,{ssh,could_not_connect_to_server,econnrefused}} =
+ open(DataDir,[{port,2062}]),
+ ok.
+
+no_host(Config) ->
+ DataDir = ?config(data_dir,Config),
+ Opts = lists:keydelete(ssh,1,?DEFAULT_SSH_OPTS(DataDir)),
+ {error,no_host_address} = ct_netconfc:open(Opts),
+ ok.
+
+no_port(Config) ->
+ DataDir = ?config(data_dir,Config),
+ Opts = lists:keydelete(port,1,?DEFAULT_SSH_OPTS(DataDir)),
+ {error,no_port} = ct_netconfc:open(Opts),
+ ok.
+
+invalid_opt(Config) ->
+ DataDir = ?config(data_dir,Config),
+ Opts1 = ?DEFAULT_SSH_OPTS(DataDir) ++ [{timeout,invalidvalue}],
+ {error,{invalid_option,{timeout,invalidvalue}}} = ct_netconfc:open(Opts1),
+ Opts2 = ?DEFAULT_SSH_OPTS(DataDir) ++ [{some_other_opt,true}],
+ {error,{invalid_option,{some_other_opt,true}}} = ct_netconfc:open(Opts2),
+ ok.
+
+get(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ Data = [{server,[{xmlns,"myns"}],[{name,[],["myserver"]}]}],
+ ?NS:expect_reply('get',{data,Data}),
+ {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+get_xpath(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ Data = [{server,[{xmlns,"myns"}],[{name,[],["myserver"]}]}],
+ ?NS:expect_reply({'get',xpath},{data,Data}),
+ {ok,Data} = ct_netconfc:get(Client,{xpath,"/server"}),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+get_config(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ Data = [{server,[{xmlns,"myns"}],[{name,[],["myserver"]}]}],
+ ?NS:expect_reply('get-config',{data,Data}),
+ {ok,Data} = ct_netconfc:get_config(Client,running,
+ {server,[{xmlns,"myns"}],[]}),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+get_config_xpath(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ Data = [{server,[{xmlns,"myns"}],[{name,[],["myserver"]}]}],
+ ?NS:expect_reply({'get-config',xpath},{data,Data}),
+ {ok,Data} = ct_netconfc:get_config(Client,running,{xpath,"/server"}),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+edit_config(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ ?NS:expect_reply('edit-config',ok),
+ ?ok = ct_netconfc:edit_config(Client,running,
+ {server,[{xmlns,"myns"}],
+ [{name,["myserver"]}]}),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+copy_config(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ ?NS:expect_reply('copy-config',ok),
+ ?ok = ct_netconfc:copy_config(Client,startup,running),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+delete_config(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ ?NS:expect_reply('delete-config',ok),
+ ?ok = ct_netconfc:delete_config(Client,startup),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+lock(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ ?NS:expect_reply('lock',ok),
+ ?ok = ct_netconfc:lock(Client,running),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+unlock(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ ?NS:expect_reply('unlock',ok),
+ ?ok = ct_netconfc:unlock(Client,running),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+kill_session(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ ?NS:hello(2),
+ ?NS:expect(hello),
+ {ok,_OtherClient} = open(DataDir),
+
+ ?NS:expect_do_reply('kill-session',{kill,2},ok),
+ ?ok = ct_netconfc:kill_session(Client,2),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+
+ ok.
+
+get_no_such_client(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ case ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}) of
+ {error,no_such_client} ->
+ ok;
+ {error,closed} ->
+ %% Means that the Client process was not terminated before the call.
+ %% Give it one more go.
+ {error,no_such_client} =
+ ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]})
+ end,
+ ok.
+
+action(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ Data = [{myactionreturn,[{xmlns,"myns"}],["value"]}],
+ ?NS:expect_reply(action,{data,Data}),
+ {ok,Data} = ct_netconfc:action(Client,{myaction,[{xmlns,"myns"}],[]}),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+send_any_rpc(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ Data = [{server,[{xmlns,"myns"}],[{name,[],["myserver"]}]}],
+ GetConf = {'get-config',
+ [{source,["running"]},
+ {filter,[{type,"subtree"}],
+ [{server,[{xmlns,"myns"}],[]}]}]},
+ ?NS:expect_reply('get-config',{data,Data}),
+ [{data,?NETCONF_NAMESPACE_ATTR,Data}] = ct_netconfc:send_rpc(Client,GetConf),
+
+ EditConf = {'edit-config',
+ [{target,["running"]},
+ {config,[{server,[{xmlns,"myns"}],
+ [{name,["myserver"]}]}]}]},
+ ?NS:expect_reply('edit-config',ok),
+ [{ok,?NETCONF_NAMESPACE_ATTR,[]}] = ct_netconfc:send_rpc(Client,EditConf),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+send_any(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ %% Correct get-config rpc
+ Data = [{server,[{xmlns,"myns"}],[{name,[],["myserver"]}]}],
+ RpcAttr1 = ?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"1"}],
+ RpcGetConf = {rpc,RpcAttr1,
+ [{'get-config',
+ [{source,["running"]},
+ {filter,[{type,"subtree"}],
+ [{server,[{xmlns,"myns"}],[]}]}]}]},
+ ?NS:expect_reply('get-config',{data,Data}),
+ {'rpc-reply',RpcAttr1,[{data,_,Data}]} = ct_netconfc:send(Client,RpcGetConf),
+
+ %% Correct edit-config rpc
+ RpcAttr2 = ?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"2"}],
+ RpcEditConf = {rpc,RpcAttr2,
+ [{'edit-config',
+ [{target,["running"]},
+ {config,[{server,[{xmlns,"myns"}],
+ [{name,["myserver"]}]}]}]}]},
+ ?NS:expect_reply('edit-config',ok),
+ {'rpc-reply',RpcAttr2,[{ok,_,[]}]} = ct_netconfc:send(Client,RpcEditConf),
+
+ %% Send any data
+ ?NS:expect_reply(any,{ok,[],[]}),
+ {ok,_,[]} = ct_netconfc:send(Client,{any,[],[]}),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+hide_password(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ Password = "my_very_secret_password",
+ Data = [{passwords,[{xmlns,"myns"}],
+ [{password,[{xmlns,"pwdns"}],[Password]},
+ {password,[],[Password]}]}],
+ ?NS:expect_reply('get',{data,Data}),
+ ct:capture_start(), % in case of html logging
+ {ok,Data} = ct_netconfc:get(Client,{passwords,[{xmlns,"myns"}],[]}),
+ ct:capture_stop(),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+
+ Log = filename:join(?config(priv_dir,Config),"hide_password-netconf.txt"),
+
+ Text =
+ case file:read_file(Log) of
+ {ok,Bin} ->
+ Bin;
+ _NoLog ->
+ %% Assume html logging
+ list_to_binary(ct:capture_get())
+ end,
+
+ nomatch = binary:match(Text,list_to_binary(Password)),
+
+ ok.
+
+not_proper_xml(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ NS = list_to_binary(?NETCONF_NAMESPACE),
+ NotProper = <<"<rpc-reply message-id=\"1\" xmlns=\"",
+ NS/binary,"\"><data></rpc-reply>">>,
+ ?NS:expect_reply('get',NotProper),
+ {error,{failed_to_parse_received_data,_}} =
+ ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+prefixed_namespace(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ NS = list_to_binary(?NETCONF_NAMESPACE),
+
+ %% Test that data element can be properly decoded and that
+ %% prefixed namespace attributes (exepct the netconf namespace)
+ %% are forwarded to the content of the data element - i.e. that
+ %% the xmlns:my is forwarded from the rpc-reply element to the
+ %% server element below.
+ Data = <<"<nc:rpc-reply message-id=\"1\" xmlns:nc=\"",
+ NS/binary,"\" xmlns:my=\"myns\"><nc:data><my:server>",
+ "<my:name my:lang=\"en\">myserver</my:name></my:server>"
+ "</nc:data></nc:rpc-reply>">>,
+ ?NS:expect_reply('get',Data),
+ {ok,[{'my:server',[{'xmlns:my',"myns"}],
+ [{'my:name',[{'my:lang',"en"}],["myserver"]}]}]} =
+ ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}),
+
+ Ok = <<"<nc:rpc-reply message-id=\"2\" xmlns:nc=\"",
+ NS/binary,"\"><nc:ok/></nc:rpc-reply>">>,
+ ?NS:expect_reply('edit-config',Ok),
+ ?ok = ct_netconfc:edit_config(Client,running,
+ {server,[{xmlns,"myns"}],
+ [{name,["myserver"]}]}),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+%% Test that the client can parse data which is received in chunks,
+%% i.e. when the complete rpc-reply is not contained in one single ssh
+%% data message.
+receive_chunked_data(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ %% Construct the data to return from netconf server
+ Data = [{servers,[{xmlns,"myns"}],
+ [{server,[],[{name,[],["server0"]}]},
+ {server,[],[{name,[],["server1"]}]},
+ {server,[],[{name,[],["server2"]}]},
+ {server,[],[{name,[],["server3"]}]},
+ {server,[],[{name,[],["server4"]}]},
+ {server,[],[{name,[],["server5"]}]},
+ {server,[],[{name,[],["server6"]}]},
+ {server,[],[{name,[],["server7"]}]},
+ {server,[],[{name,[],["server8"]}]},
+ {server,[],[{name,[],["server9"]}]}]
+ }],
+ Rpc = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"1"}],
+ [{data,Data}]},
+ Xml = list_to_binary(xmerl:export_simple_element(Rpc,xmerl_xml)),
+ Netconf =
+ <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
+ Xml/binary,"\n",?END_TAG/binary>>,
+
+ %% Split the data in some chunks
+ PartLength = size(Netconf) div 3,
+ <<Part1:PartLength/binary,Part2:PartLength/binary,Part3:PartLength/binary,
+ Part4/binary>> = Netconf,
+
+ %% Spawn a process which will wait a bit for the client to send
+ %% the request (below), then order the server to the chunks of the
+ %% rpc-reply one by one.
+ spawn(fun() -> timer:sleep(500),?NS:hupp(send,Part1),
+ timer:sleep(100),?NS:hupp(send,Part2),
+ timer:sleep(100),?NS:hupp(send,Part3),
+ timer:sleep(100),?NS:hupp(send,Part4)
+ end),
+
+ %% Order server to expect a get - then the process above will make
+ %% sure the rpc-reply is sent.
+ ?NS:expect('get'),
+ {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+%% Same as receive_chunked_data, but timeout waiting for last part.
+timeout_receive_chunked_data(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ %% Construct the data to return from netconf server
+ Data = [{servers,[{xmlns,"myns"}],
+ [{server,[],[{name,[],["server0"]}]},
+ {server,[],[{name,[],["server1"]}]},
+ {server,[],[{name,[],["server2"]}]},
+ {server,[],[{name,[],["server3"]}]},
+ {server,[],[{name,[],["server4"]}]},
+ {server,[],[{name,[],["server5"]}]},
+ {server,[],[{name,[],["server6"]}]},
+ {server,[],[{name,[],["server7"]}]},
+ {server,[],[{name,[],["server8"]}]},
+ {server,[],[{name,[],["server9"]}]}]
+ }],
+ Rpc = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"1"}],
+ [{data,Data}]},
+ Xml = list_to_binary(xmerl:export_simple_element(Rpc,xmerl_xml)),
+ Netconf =
+ <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
+ Xml/binary,"\n",?END_TAG/binary>>,
+
+ %% Split the data in some chunks
+ PartLength = size(Netconf) div 3,
+ <<Part1:PartLength/binary,Part2:PartLength/binary,_Part3:PartLength/binary,
+ _Part4/binary>> = Netconf,
+
+ %% Spawn a process which will wait a bit for the client to send
+ %% the request (below), then order the server to the chunks of the
+ %% rpc-reply one by one.
+ spawn(fun() -> timer:sleep(500),?NS:hupp(send,Part1),
+ timer:sleep(100),?NS:hupp(send,Part2)
+ end),
+
+ %% Order server to expect a get - then the process above will make
+ %% sure the rpc-reply is sent - but only a part of it - then timeout.
+ ?NS:expect('get'),
+ {error,timeout} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]},2000),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+%% Same as receive_chunked_data, but timeout waiting for last part.
+close_while_waiting_for_chunked_data(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ %% Construct the data to return from netconf server
+ Data = [{servers,[{xmlns,"myns"}],
+ [{server,[],[{name,[],["server0"]}]},
+ {server,[],[{name,[],["server1"]}]},
+ {server,[],[{name,[],["server2"]}]},
+ {server,[],[{name,[],["server3"]}]},
+ {server,[],[{name,[],["server4"]}]},
+ {server,[],[{name,[],["server5"]}]},
+ {server,[],[{name,[],["server6"]}]},
+ {server,[],[{name,[],["server7"]}]},
+ {server,[],[{name,[],["server8"]}]},
+ {server,[],[{name,[],["server9"]}]}]
+ }],
+ Rpc = {'rpc-reply',?NETCONF_NAMESPACE_ATTR ++ [{'message-id',"1"}],
+ [{data,Data}]},
+ Xml = list_to_binary(xmerl:export_simple_element(Rpc,xmerl_xml)),
+ Netconf =
+ <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
+ Xml/binary,"\n",?END_TAG/binary>>,
+
+ %% Split the data in some chunks
+ PartLength = size(Netconf) div 3,
+ <<Part1:PartLength/binary,Part2:PartLength/binary,_Part3:PartLength/binary,
+ _Part4/binary>> = Netconf,
+
+ %% Spawn a process which will wait a bit for the client to send
+ %% the request (below), then order the server to the chunks of the
+ %% rpc-reply one by one.
+ spawn(fun() -> timer:sleep(500),?NS:hupp(send,Part1),
+ timer:sleep(100),?NS:hupp(send,Part2),
+ timer:sleep(100),?NS:hupp(kill)
+ end),
+
+ %% Order server to expect a get - then the process above will make
+ %% sure the rpc-reply is sent - but only a part of it - then close.
+ ?NS:expect('get'),
+ {error,closed} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]},2000),
+ ok.
+
+connection_crash(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+
+ %% Test that if the test survives killing the connection
+ %% process. Earlier this caused ct_util_server to terminate, and
+ %% this aborting the complete test run.
+ spawn(fun() -> timer:sleep(500),exit(Client,kill) end),
+ ?NS:expect(get),
+ {error,{closed,killed}}=ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}),
+ ok.
+
+get_event_streams(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ StreamNames = ["NETCONF","stream1","stream2"],
+ Streams = [{N,[{description,"descr of " ++ N}]} || N <- StreamNames],
+ StreamsXml = [{stream,[{name,[N]}|[{Tag,[Value]} || {Tag,Value} <- Data]]}
+ || {N,Data} <- Streams],
+ ReplyData = [{netconf,?NETMOD_NOTIF_NAMESPACE_ATTR,[{streams,StreamsXml}]}],
+ ?NS:expect_reply('get',{data,ReplyData}),
+ {ok,Streams} = ct_netconfc:get_event_streams(Client,StreamNames),
+
+ ?NS:expect_reply('get',{data,ReplyData}),
+ {ok,Streams} = ct_netconfc:get_event_streams(Client,StreamNames,5000),
+
+ ?NS:expect('get'),
+ {error,timeout} = ct_netconfc:get_event_streams(Client,100),
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+ ok.
+
+create_subscription(Config) ->
+ DataDir = ?config(data_dir,Config),
+
+ %% All defaults
+ {ok,Client1} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream]},ok),
+ ?ok = ct_netconfc:create_subscription(Client1),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client1),
+
+ %% All defaults with timeout
+ {ok,Client1a} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream]},ok),
+ ?ok = ct_netconfc:create_subscription(Client1a,5000),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client1a),
+
+ %% All defaults timing out
+ {ok,Client1b} = open_success(DataDir),
+ ?NS:expect({'create-subscription',[stream]}),
+ {error,timeout} = ct_netconfc:create_subscription(Client1b,100),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client1b),
+
+ %% Stream
+ {ok,Client2} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream]},ok),
+ Stream = "some_stream",
+ ?ok = ct_netconfc:create_subscription(Client2,Stream),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client2),
+
+ %% Filter
+ {ok,Client3} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,filter]},ok),
+ Filter = {notification,?NETMOD_NOTIF_NAMESPACE_ATTR,
+ [eventTime]},
+ ?ok = ct_netconfc:create_subscription(Client3,Filter),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client3),
+
+ %% Filter with timeout
+ {ok,Client3a} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,filter]},ok),
+ ?ok = ct_netconfc:create_subscription(Client3a,Filter,5000),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client3a),
+
+ %% Filter timing out
+ {ok,Client3b} = open_success(DataDir),
+ ?NS:expect({'create-subscription',[stream,filter]}),
+ {error,timeout}=ct_netconfc:create_subscription(Client3b,Filter,100),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client3b),
+
+ %% Stream and filter
+ {ok,Client4} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,filter]},ok),
+ ?ok = ct_netconfc:create_subscription(Client4,Stream,Filter),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client4),
+
+ %% Start/stop time
+ {ok,Client5} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,startTime,stopTime]},ok),
+ StartTime = xs_datetime({D,{H,M,S}}= calendar:local_time()),
+ StopTime = xs_datetime({D,{H+2,M,S}}),
+ ?ok = ct_netconfc:create_subscription(Client5,StartTime,StopTime),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client5),
+
+ %% Start/stop time with timeout
+ {ok,Client5a} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,startTime,stopTime]},ok),
+ ?ok = ct_netconfc:create_subscription(Client5a,StartTime,StopTime,5000),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client5a),
+
+ %% Start/stop time timing out
+ {ok,Client5b} = open_success(DataDir),
+ ?NS:expect({'create-subscription',[stream,startTime,stopTime]}),
+ {error,timeout} =
+ ct_netconfc:create_subscription(Client5b,StartTime,StopTime,100),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client5b),
+
+ %% Stream and start/stop time
+ {ok,Client6} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,startTime,stopTime]},ok),
+ ?ok = ct_netconfc:create_subscription(Client6,Stream,StartTime,StopTime),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client6),
+
+ %% Filter and start/stop time
+ {ok,Client7} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,filter,startTime,stopTime]},
+ ok),
+ ?ok = ct_netconfc:create_subscription(Client7,Filter,
+ StartTime,StopTime),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client7),
+
+ %% Stream, filter and start/stop time
+ {ok,Client8} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream,filter,startTime,stopTime]},
+ ok),
+ ?ok = ct_netconfc:create_subscription(Client8,Stream,Filter,
+ StartTime,StopTime),
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client8),
+
+ ok.
+
+receive_event(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Client} = open_success(DataDir),
+ ?NS:expect_reply({'create-subscription',[stream]},ok),
+ ?ok = ct_netconfc:create_subscription(Client),
+
+ ?NS:hupp(send_event),
+
+ receive
+ %% Matching ?NS:make_msg(event)
+ {notification,?NETCONF_NOTIF_NAMESPACE_ATTR,
+ [{eventTime,[],[_Time]},
+ {event,[{xmlns,"http://my.namespaces.com/event"}],
+ [{severity,_,_},
+ {description,_,_}]}]} ->
+ ok;
+ Other ->
+ ct:fail({got_unexpected_while_waiting_for_event, Other})
+ after 3000 ->
+ ct:fail(timeout_waiting_for_event)
+ end,
+
+ ?NS:expect_do_reply('close-session',close,ok),
+ ?ok = ct_netconfc:close_session(Client),
+
+ ok.
+
+%%%-----------------------------------------------------------------
+
+break(_Config) ->
+ test_server:break("break test case").
+
+br() ->
+ test_server:break("").
+
+%%%-----------------------------------------------------------------
+%% Open a netconf session which is not specified in a config file
+open_success(Dir) ->
+ open_success(Dir,[]).
+
+%% Open a netconf session which is not specified in a config file, and
+%% give som extra options in addition to the test defaults.
+open_success(Dir,ExtraOpts) when is_list(Dir), is_list(ExtraOpts) ->
+ ?NS:hello(1), % tell server to send hello with session id 1
+ ?NS:expect(hello), % tell server to expect a hello message from client
+ open(Dir,ExtraOpts);
+
+%% Open a named netconf session which is not specified in a config file
+open_success(KeyOrName,Dir) when is_atom(KeyOrName), is_list(Dir) ->
+ ?NS:hello(1),
+ ?NS:expect(hello),
+ ct_netconfc:open(KeyOrName,?DEFAULT_SSH_OPTS(Dir)).
+
+open(Dir) ->
+ open(Dir,[]).
+open(Dir,ExtraOpts) ->
+ Opts = lists:ukeymerge(1,lists:keysort(1,ExtraOpts),
+ lists:keysort(1,?DEFAULT_SSH_OPTS(Dir))),
+ ct_netconfc:open(Opts).
+
+%%%-----------------------------------------------------------------
+%%% Open a netconf session which is specified in a config file
+%%% KeyOrName is the config key (server_id()) or name given in a
+%%% require statement (target_name()).
+open_configured_success(KeyOrName,Dir) when is_atom(KeyOrName) ->
+ open_configured_success(KeyOrName,Dir,[]).
+open_configured_success(KeyOrName,Dir,ExtraOpts) when is_atom(KeyOrName) ->
+ ?NS:hello(1),
+ ?NS:expect(hello),
+ ct_netconfc:open(KeyOrName,[{user_dir,Dir}|ExtraOpts]).
+
+%%%-----------------------------------------------------------------
+%%% Convert erlang datetime to the simplest variant of XML dateTime
+xs_datetime({{Y,M,D},{H,Mi,S}}) ->
+ lists:flatten(
+ io_lib:format("~p-~s-~sT~s:~s:~s",[Y,pad(M),pad(D),pad(H),pad(Mi),pad(S)])).
+
+pad(I) when I<10 ->
+ "0"++integer_to_list(I);
+pad(I) ->
+ integer_to_list(I).
+
+
+%%%-----------------------------------------------------------------
+%%% BEGIN SSH key management
+%% copy private keys to given dir from ~/.ssh
+get_id_keys(Config) ->
+ DstDir = ?config(priv_dir, Config),
+ SrcDir = filename:join(os:getenv("HOME"), ".ssh"),
+ RsaOk = copyfile(SrcDir, DstDir, "id_rsa"),
+ DsaOk = copyfile(SrcDir, DstDir, "id_dsa"),
+ case {RsaOk, DsaOk} of
+ {{ok, _}, {ok, _}} -> {ok, both};
+ {{ok, _}, _} -> {ok, rsa};
+ {_, {ok, _}} -> {ok, dsa};
+ {Error, _} -> Error
+ end.
+
+%% Remove later on. Use make_dsa_files instead.
+remove_id_keys(Config) ->
+ Dir = ?config(priv_dir, Config),
+ file:delete(filename:join(Dir, "id_rsa")),
+ file:delete(filename:join(Dir, "id_dsa")).
+
+
+make_dsa_files(Config) ->
+ make_dsa_files(Config, rfc4716_public_key).
+make_dsa_files(Config, Type) ->
+ {DSA, EncodedKey} = gen_dsa(128, 20),
+ PKey = DSA#'DSAPrivateKey'.y,
+ P = DSA#'DSAPrivateKey'.p,
+ Q = DSA#'DSAPrivateKey'.q,
+ G = DSA#'DSAPrivateKey'.g,
+ Dss = #'Dss-Parms'{p=P, q=Q, g=G},
+ {ok, Hostname} = inet:gethostname(),
+ {ok, {A, B, C, D}} = inet:getaddr(Hostname, inet),
+ IP = lists:concat([A, ".", B, ".", C, ".", D]),
+ Attributes = [], % Could be [{comment,"user@" ++ Hostname}],
+ HostNames = [{hostnames,[IP, IP]}],
+ PublicKey = [{{PKey, Dss}, Attributes}],
+ KnownHosts = [{{PKey, Dss}, HostNames}],
+
+ KnownHostsEnc = public_key:ssh_encode(KnownHosts, known_hosts),
+ KnownHosts = public_key:ssh_decode(KnownHostsEnc, known_hosts),
+
+ PublicKeyEnc = public_key:ssh_encode(PublicKey, Type),
+
+ SystemTmpDir = ?config(data_dir, Config),
+ filelib:ensure_dir(SystemTmpDir),
+ file:make_dir(SystemTmpDir),
+
+ DSAFile = filename:join(SystemTmpDir, "ssh_host_dsa_key.pub"),
+ file:delete(DSAFile),
+
+ DSAPrivateFile = filename:join(SystemTmpDir, "ssh_host_dsa_key"),
+ file:delete(DSAPrivateFile),
+
+ KHFile = filename:join(SystemTmpDir, "known_hosts"),
+ file:delete(KHFile),
+
+ PemBin = public_key:pem_encode([EncodedKey]),
+
+ file:write_file(DSAFile, PublicKeyEnc),
+ file:write_file(KHFile, KnownHostsEnc),
+ file:write_file(DSAPrivateFile, PemBin),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Creates a dsa key (OBS: for testing only)
+%% the sizes are in bytes
+%% gen_dsa(::integer()) -> {::atom(), ::binary(), ::opaque()}
+%%--------------------------------------------------------------------
+gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
+ Key = gen_dsa2(LSize, NSize),
+ {Key, encode_key(Key)}.
+
+encode_key(Key = #'RSAPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
+ {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
+encode_key(Key = #'DSAPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
+ {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% DSA key generation (OBS: for testing only)
+%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm
+%% and the fips_186-3.pdf
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+gen_dsa2(LSize, NSize) ->
+ Q = prime(NSize), %% Choose N-bit prime Q
+ X0 = prime(LSize),
+ P0 = prime((LSize div 2) +1),
+
+ %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
+ case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
+ error ->
+ gen_dsa2(LSize, NSize);
+ P ->
+ G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
+
+ X = prime(20), %% Choose x by some random method, where 0 < x < q.
+ Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
+
+ #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ end.
+
+%% See fips_186-3.pdf
+dsa_search(T, P0, Q, Iter) when Iter > 0 ->
+ P = 2*T*Q*P0 + 1,
+ case is_prime(crypto:mpint(P), 50) of
+ true -> P;
+ false -> dsa_search(T+1, P0, Q, Iter-1)
+ end;
+dsa_search(_,_,_,_) ->
+ error.
+
+
+%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+prime(ByteSize) ->
+ Rand = odd_rand(ByteSize),
+ crypto:erlint(prime_odd(Rand, 0)).
+
+prime_odd(Rand, N) ->
+ case is_prime(Rand, 50) of
+ true ->
+ Rand;
+ false ->
+ NotPrime = crypto:erlint(Rand),
+ prime_odd(crypto:mpint(NotPrime+2), N+1)
+ end.
+
+%% see http://en.wikipedia.org/wiki/Fermat_primality_test
+is_prime(_, 0) -> true;
+is_prime(Candidate, Test) ->
+ CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
+ case crypto:mod_exp(CoPrime, Candidate, Candidate) of
+ CoPrime -> is_prime(Candidate, Test-1);
+ _ -> false
+ end.
+
+odd_rand(Size) ->
+ Min = 1 bsl (Size*8-1),
+ Max = (1 bsl (Size*8))-1,
+ odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+
+odd_rand(Min,Max) ->
+ Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
+ BitSkip = (Sz+4)*8-1,
+ case Rand of
+ Odd = <<_:BitSkip, 1:1>> -> Odd;
+ Even = <<_:BitSkip, 0:1>> ->
+ crypto:mpint(crypto:erlint(Even)+1)
+ end.
+
+copyfile(SrcDir, DstDir, Fn) ->
+ file:copy(filename:join(SrcDir, Fn),
+ filename:join(DstDir, Fn)).
+
+%%% END SSH key management
+%%%-----------------------------------------------------------------
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
new file mode 100644
index 0000000000..665b0e556c
--- /dev/null
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
@@ -0,0 +1,506 @@
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. 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%
+%%
+%%----------------------------------------------------------------------
+%% A netconf server used for testing of netconfc
+-module(ns).
+
+%-compile(export_all).
+-include_lib("common_test/src/ct_netconfc.hrl").
+
+
+%%%-----------------------------------------------------------------
+%%% API
+-export([start/1,
+ stop/1,
+ hello/1,
+ hello/2,
+ expect/1,
+ expect_reply/2,
+ expect_do/2,
+ expect_do_reply/3,
+ hupp/1,
+ hupp/2]).
+
+%%%-----------------------------------------------------------------
+%%% ssh_channel callbacks
+-export([init/1,
+ terminate/2,
+ handle_ssh_msg/2,
+ handle_msg/2]).
+
+%%%-----------------------------------------------------------------
+%% Server specifications
+-define(SERVER_DATA_NAMESPACE, "ClientTest").
+-define(CAPABILITIES,?CAPABILITIES_VSN("1.0")).
+-define(CAPABILITIES_VSN(Vsn),
+ [
+ ?NETCONF_BASE_CAP ++ Vsn,
+ "urn:ietf:params:netconf:capability:writable-running:1.0",
+ "urn:ietf:params:netconf:capability:candidate:1.0",
+ "urn:ietf:params:netconf:capability:confirmed-commit:1.0",
+ "urn:ietf:params:netconf:capability:rollback-on-error:1.0",
+ "urn:ietf:params:netconf:capability:startup:1.0",
+ "urn:ietf:params:netconf:capability:url:1.0",
+ "urn:ietf:params:netconf:capability:xpath:1.0",
+ "urn:ietf:params:netconf:capability:notification:1.0",
+ "urn:ietf:params:netconf:capability:interleave:1.0",
+ ?ACTION_NAMESPACE,
+ ?SERVER_DATA_NAMESPACE
+ ]).
+-define(SSH_PORT, 2060).
+-define(ssh_config(Dir),[{port, ?SSH_PORT},
+ {interface, {127,0,0,1}},
+ {system_dir, Dir},
+ {user_dir, Dir},
+ {user_passwords, [{"xxx","xxx"}]},
+ {password, "global-xxx"}]).
+
+%% Some help for debugging
+%-define(dbg(F,A),io:format(F,A)).
+-define(dbg(F,A),ok).
+-define(dbg_event(Event,Expect),
+ ?dbg("Event: ~p~nExpected: ~p~n",[Event,Expect])).
+
+%% State
+-record(session, {cb,
+ connection,
+ buffer = <<>>,
+ session_id}).
+
+
+%%%-----------------------------------------------------------------
+%%% API
+
+%% Start the netconf server and use the given directory as system_dir
+%% and user_dir
+start(Dir) ->
+ spawn(fun() -> init_server(Dir) end).
+
+%% Stop the netconf server
+stop(Pid) ->
+ Pid ! {stop,self()},
+ receive stopped -> ok end.
+
+%% Set the session id for the hello message.
+%% If this is not called prior to starting the session, no hello
+%% message will be sent.
+%% 'Stuff' indicates some special handling to e.g. provoke error cases
+hello(SessionId) ->
+ hello(SessionId,undefined).
+hello(SessionId,Stuff) ->
+ insert(hello,{SessionId,Stuff}).
+
+%% Tell server to expect the given message without doing any further
+%% actions. To be called directly before sending a request.
+expect(Expect) ->
+ expect_do_reply(Expect,undefined,undefined).
+
+%% Tell server to expect the given message and reply with the give
+%% reply. To be called directly before sending a request.
+expect_reply(Expect,Reply) ->
+ expect_do_reply(Expect,undefined,Reply).
+
+%% Tell server to expect the given message and perform an action. To
+%% be called directly before sending a request.
+expect_do(Expect,Do) ->
+ expect_do_reply(Expect,Do,undefined).
+
+%% Tell server to expect the given message, perform an action and
+%% reply with the given reply. To be called directly before sending a
+%% request.
+expect_do_reply(Expect,Do,Reply) ->
+ add_expect({Expect,Do,Reply}).
+
+%% Hupp the server - i.e. tell it to do something -
+%% e.g. hupp(send_event) will cause send_event(State) to be called on
+%% the session channel process.
+hupp(send_event) ->
+ hupp(send,[make_msg(event)]);
+hupp(kill) ->
+ hupp(fun hupp_kill/1,[]).
+
+hupp(send,Data) ->
+ hupp(fun hupp_send/2,[Data]);
+hupp(Fun,Args) when is_function(Fun) ->
+ [{_,Pid}] = lookup(channel_process),
+ Pid ! {hupp,Fun,Args}.
+
+%%%-----------------------------------------------------------------
+%%% Main loop of the netconf server
+init_server(Dir) ->
+ ets:new(ns_tab,[set,named_table,public]),
+ Config = ?ssh_config(Dir),
+ {_,Host} = lists:keyfind(interface, 1, Config),
+ {_,Port} = lists:keyfind(port, 1, Config),
+ Opts = lists:filter(fun({Key,_}) ->
+ lists:member(Key,[system_dir,
+ password,
+ user_passwords,
+ pwdfun])
+ end,
+ Config),
+ {ok, Daemon} =
+ ssh:daemon(Host, Port,
+ [{subsystems,[{"netconf",{?MODULE,[]}}]}
+ |Opts]),
+ loop(Daemon).
+
+loop(Daemon) ->
+ receive
+ {stop,From} ->
+ ssh:stop_daemon(Daemon),
+ From ! stopped
+ end.
+
+%%----------------------------------------------------------------------
+%% Behaviour callback functions (ssh_channel)
+%%----------------------------------------------------------------------
+init([]) ->
+ {ok, undefined}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+handle_ssh_msg({ssh_cm,CM,{data, Ch, _Type = 0, Data}}, State) ->
+ %% erlang:display({self(),data,CM,Ch,State}),
+ data_for_channel(CM, Ch, Data, State);
+handle_ssh_msg({ssh_cm,CM,{closed, Ch}}, State) ->
+ %% erlang:display({self(),closed,CM,Ch,State}),
+ stop_channel(CM, Ch, State);
+handle_ssh_msg({ssh_cm,CM,{eof, Ch}}, State) ->
+ %% erlang:display({self(),eof,CM,Ch,State}),
+ data_for_channel(CM,Ch, <<>>, State).
+
+
+handle_msg({'EXIT', _Pid, _Reason}, State) ->
+ {ok, State};
+handle_msg({ssh_channel_up,Ch,CM},undefined) ->
+ %% erlang:display({self(),up,CM,Ch}),
+ ConnRef = {CM,Ch},
+ SessionId = maybe_hello(ConnRef),
+ insert(channel_process,self()), % used to hupp the server
+ {ok, #session{connection = ConnRef,
+ session_id = SessionId}};
+handle_msg({hupp,Fun,Args},State) ->
+ {ok,apply(Fun,Args ++ [State])}.
+
+data_for_channel(CM, Ch, Data, State) ->
+ try data(Data, State) of
+ {ok, NewState} ->
+ case erase(stop) of
+ true ->
+ stop_channel(CM, Ch, NewState);
+ _ ->
+ {ok, NewState}
+ end
+ catch
+ Class:Reason ->
+ Stacktrace = erlang:get_stacktrace(),
+ error_logger:error_report([{?MODULE, data_for_channel},
+ {request, Data},
+ {reason, {Class, Reason}},
+ {stacktrace, Stacktrace}]),
+ stop_channel(CM, Ch, State)
+ end.
+
+data(Data, State = #session{connection = ConnRef,
+ buffer = Buffer}) ->
+ AllData = <<Buffer/binary,Data/binary>>,
+ case find_endtag(AllData) of
+ {ok,Msgs,Rest} ->
+ [check_expected(ConnRef,Msg) || Msg <- Msgs],
+ {ok,State#session{buffer=Rest}};
+ need_more ->
+ {ok,State#session{buffer=AllData}}
+ end.
+
+stop_channel(CM, Ch, State) ->
+ ssh:close(CM),
+ {stop, Ch, State}.
+
+
+%%%-----------------------------------------------------------------
+%%% Functions to trigg via hupp/1:
+
+%% Send data spontaneously - e.g. an event
+hupp_send(Data,State = #session{connection = ConnRef}) ->
+ send(ConnRef,Data),
+ State.
+hupp_kill(State = #session{connection = ConnRef}) ->
+ kill(ConnRef),
+ State.
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+
+
+%%% Send ssh data to the client
+send({CM,Ch},Data) ->
+ ssh_connection:send(CM, Ch, Data).
+
+%%% Kill ssh connection
+kill({CM,_Ch}) ->
+ ssh:close(CM).
+
+add_expect(Add) ->
+ case lookup(expect) of
+ [] ->
+ insert(expect,[Add]);
+ [{expect,First}] ->
+ insert(expect,First ++ [Add])
+ end,
+ ok.
+
+insert(Key,Value) ->
+ ets:insert(ns_tab,{Key,Value}).
+lookup(Key) ->
+ ets:lookup(ns_tab,Key).
+
+maybe_hello(ConnRef) ->
+ case lookup(hello) of
+ [{hello,{SessionId,Stuff}}] ->
+ %% erlang:display({SessionId,Stuff}),
+ ets:delete(ns_tab,hello),
+ insert({session,SessionId},ConnRef),
+ reply(ConnRef,{hello,SessionId,Stuff}),
+ SessionId;
+ [] ->
+ undefined
+ end.
+
+find_endtag(Data) ->
+ case binary:split(Data,[?END_TAG],[global]) of
+ [Data] ->
+ need_more;
+ Msgs ->
+ {ok,lists:sublist(Msgs,length(Msgs)-1),lists:last(Msgs)}
+ end.
+
+check_expected(ConnRef,Msg) ->
+ case lookup(expect) of
+ [{expect,[{Expect,Do,Reply}|Rest]}] ->
+ insert(expect,Rest),
+ %% erlang:display({got,io_lib:format("~s",[Msg])}),
+ %% erlang:display({expected,Expect}),
+ match(Msg,Expect),
+ do(ConnRef, Do),
+ reply(ConnRef,Reply);
+ Expected ->
+ exit({error,{got_unexpected,Msg,Expected}})
+ end.
+
+match(Msg,Expect) ->
+ ?dbg("Match: ~p~n",[Msg]),
+ {ok,ok,<<>>} = xmerl_sax_parser:stream(Msg,[{event_fun,fun event/3},
+ {event_state,Expect}]).
+
+event(Event,_Loc,Expect) ->
+ ?dbg_event(Event,Expect),
+ event(Event,Expect).
+
+event(startDocument,Expect) -> match(Expect);
+event({startElement,_,Name,_,Attrs},[{se,Name}|Match]) ->
+ msg_id(Name,Attrs),
+ Match;
+event({startElement,_,Name,_,Attrs},[ignore,{se,Name}|Match]) ->
+ msg_id(Name,Attrs),
+ Match;
+event({startElement,_,Name,_,Attrs},[{se,Name,As}|Match]) ->
+ msg_id(Name,Attrs),
+ match_attrs(Name,As,Attrs),
+ Match;
+event({startElement,_,Name,_,Attrs},[ignore,{se,Name,As}|Match]) ->
+ msg_id(Name,Attrs),
+ match_attrs(Name,As,Attrs),
+ Match;
+event({startPrefixMapping,_,Ns},[{ns,Ns}|Match]) -> Match;
+event({startPrefixMapping,_,Ns},[ignore,{ns,Ns}|Match]) -> Match;
+event({endPrefixMapping,_},Match) -> Match;
+event({endElement,_,Name,_},[{ee,Name}|Match]) -> Match;
+event({endElement,_,Name,_},[ignore,{ee,Name}|Match]) -> Match;
+event(endDocument,Match) when Match==[]; Match==[ignore] -> ok;
+event(_,[ignore|_]=Match) -> Match;
+event(Event,Match) -> throw({nomatch,{Event,Match}}).
+
+msg_id("rpc",Attrs) ->
+ case lists:keyfind("message-id",3,Attrs) of
+ {_,_,_,Str} -> put(msg_id,Str);
+ false -> erase(msg_id)
+ end;
+msg_id(_,_) ->
+ ok.
+
+match_attrs(Name,[{Key,Value}|As],Attrs) ->
+ case lists:keyfind(atom_to_list(Key),3,Attrs) of
+ {_,_,_,Value} -> match_attrs(Name,As,Attrs);
+ false -> throw({missing_attr,Key,Name,Attrs});
+ _ -> throw({faulty_attr_value,Key,Name,Attrs})
+ end;
+match_attrs(_,[],_) ->
+ ok.
+
+do(ConnRef, close) ->
+ ets:match_delete(ns_tab,{{session,'_'},ConnRef}),
+ put(stop,true);
+do(_ConnRef, {kill,SessionId}) ->
+ case lookup({session,SessionId}) of
+ [{_,Owner}] ->
+ ets:delete(ns_tab,{session,SessionId}),
+ kill(Owner);
+ _ ->
+ exit({no_session_to_kill,SessionId})
+ end;
+do(_, undefined) ->
+ ok.
+
+reply(_,undefined) ->
+ ?dbg("no reply~n",[]),
+ ok;
+reply(ConnRef,Reply) ->
+ ?dbg("Reply: ~p~n",[Reply]),
+ send(ConnRef, make_msg(Reply)).
+
+from_simple(Simple) ->
+ list_to_binary(xmerl:export_simple_element(Simple,xmerl_xml)).
+
+xml(Content) ->
+ <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
+ Content/binary,"\n",?END_TAG/binary>>.
+
+rpc_reply(Content) when is_binary(Content) ->
+ MsgId = case erase(msg_id) of
+ undefined -> <<>>;
+ Id -> list_to_binary([" message-id=\"",Id,"\""])
+ end,
+ <<"<rpc-reply xmlns=\"",?NETCONF_NAMESPACE,"\"",MsgId/binary,">\n",
+ Content/binary,"\n</rpc-reply>">>;
+rpc_reply(Content) ->
+ rpc_reply(list_to_binary(Content)).
+
+session_id(no_session_id) ->
+ <<>>;
+session_id(SessionId0) ->
+ SessionId = list_to_binary(integer_to_list(SessionId0)),
+ <<"<session-id>",SessionId/binary,"</session-id>\n">>.
+
+capabilities(undefined) ->
+ CapsXml = list_to_binary([["<capability>",C,"</capability>\n"]
+ || C <- ?CAPABILITIES]),
+ <<"<capabilities>\n",CapsXml/binary,"</capabilities>\n">>;
+capabilities({base,Vsn}) ->
+ CapsXml = list_to_binary([["<capability>",C,"</capability>\n"]
+ || C <- ?CAPABILITIES_VSN(Vsn)]),
+ <<"<capabilities>\n",CapsXml/binary,"</capabilities>\n">>;
+capabilities(no_base) ->
+ [_|Caps] = ?CAPABILITIES,
+ CapsXml = list_to_binary([["<capability>",C,"</capability>\n"] || C <- Caps]),
+ <<"<capabilities>\n",CapsXml/binary,"</capabilities>\n">>;
+capabilities(no_caps) ->
+ <<>>.
+
+%%%-----------------------------------------------------------------
+%%% Match received netconf message from the client. Add a new clause
+%%% for each new message to recognize. The clause argument shall match
+%%% the Expect argument in expect/1, expect_reply/2 or
+%%% expect_do_reply/3.
+%%%
+%%% match(term()) -> [Match].
+%%% Match = ignore | {se,Name} | {se,Name,Attrs} | {ee,Name} | {ns,Namespace}
+%%% Name = string()
+%%% Attrs = [{atom(),string()}]
+%%% Namespace = string()
+%%%
+%%% 'se' means start element, 'ee' means end element - i.e. to match
+%%% an XML element you need one 'se' entry and one 'ee' entry with the
+%%% same name in the match list.
+match(hello) ->
+ [ignore,{se,"hello"},ignore,{ee,"hello"},ignore];
+match('close-session') ->
+ [ignore,{se,"rpc"},{se,"close-session"},
+ {ee,"close-session"},{ee,"rpc"},ignore];
+match('edit-config') ->
+ [ignore,{se,"rpc"},{se,"edit-config"},{se,"target"},ignore,{ee,"target"},
+ {se,"config"},ignore,{ee,"config"},{ee,"edit-config"},{ee,"rpc"},ignore];
+match('get') ->
+ match({get,subtree});
+match({'get',FilterType}) ->
+ [ignore,{se,"rpc"},{se,"get"},{se,"filter",[{type,atom_to_list(FilterType)}]},
+ ignore,{ee,"filter"},{ee,"get"},{ee,"rpc"},ignore];
+match('get-config') ->
+ match({'get-config',subtree});
+match({'get-config',FilterType}) ->
+ [ignore,{se,"rpc"},{se,"get-config"},{se,"source"},ignore,{ee,"source"},
+ {se,"filter",[{type,atom_to_list(FilterType)}]},ignore,{ee,"filter"},
+ {ee,"get-config"},{ee,"rpc"},ignore];
+match('copy-config') ->
+ [ignore,{se,"rpc"},{se,"copy-config"},{se,"target"},ignore,{ee,"target"},
+ {se,"source"},ignore,{ee,"source"},{ee,"copy-config"},{ee,"rpc"},ignore];
+match('delete-config') ->
+ [ignore,{se,"rpc"},{se,"delete-config"},{se,"target"},ignore,{ee,"target"},
+ {ee,"delete-config"},{ee,"rpc"},ignore];
+match('lock') ->
+ [ignore,{se,"rpc"},{se,"lock"},{se,"target"},ignore,{ee,"target"},
+ {ee,"lock"},{ee,"rpc"},ignore];
+match('unlock') ->
+ [ignore,{se,"rpc"},{se,"unlock"},{se,"target"},ignore,{ee,"target"},
+ {ee,"unlock"},{ee,"rpc"},ignore];
+match('kill-session') ->
+ [ignore,{se,"rpc"},{se,"kill-session"},{se,"session-id"},ignore,
+ {ee,"session-id"},{ee,"kill-session"},{ee,"rpc"},ignore];
+match(action) ->
+ [ignore,{se,"rpc"},{ns,?ACTION_NAMESPACE},{se,"action"},{se,"data"},ignore,
+ {ee,"data"},{ee,"action"},{ee,"rpc"},ignore];
+match({'create-subscription',Content}) ->
+ [ignore,{se,"rpc"},{ns,?NETCONF_NOTIF_NAMESPACE},
+ {se,"create-subscription"}] ++
+ lists:flatmap(fun(X) ->
+ [{se,atom_to_list(X)},ignore,{ee,atom_to_list(X)}]
+ end, Content) ++
+ [{ee,"create-subscription"},{ee,"rpc"},ignore];
+match(any) ->
+ [ignore].
+
+
+
+%%%-----------------------------------------------------------------
+%%% Make message to send to the client.
+%%% Add a new clause for each new message that shall be sent. The
+%%% clause shall match the Reply argument in expect_reply/2 or
+%%% expect_do_reply/3.
+make_msg({hello,SessionId,Stuff}) ->
+ SessionIdXml = session_id(SessionId),
+ CapsXml = capabilities(Stuff),
+ xml(<<"<hello xmlns=\"",?NETCONF_NAMESPACE,"\">\n",CapsXml/binary,
+ SessionIdXml/binary,"</hello>">>);
+make_msg(ok) ->
+ xml(rpc_reply("<ok/>"));
+make_msg({data,Data}) ->
+ xml(rpc_reply(from_simple({data,Data})));
+make_msg(event) ->
+ xml(<<"<notification xmlns=\"",?NETCONF_NOTIF_NAMESPACE,"\">"
+ "<eventTime>2012-06-14T14:50:54+02:00</eventTime>"
+ "<event xmlns=\"http://my.namespaces.com/event\">"
+ "<severity>major</severity>"
+ "<description>Something terrible happened</description>"
+ "</event>"
+ "</notification>">>);
+make_msg(Xml) when is_binary(Xml) ->
+ xml(Xml);
+make_msg(Simple) when is_tuple(Simple) ->
+ xml(from_simple(Simple)).
diff --git a/lib/compiler/doc/src/Makefile b/lib/compiler/doc/src/Makefile
index ee41a7074f..308e9c4d02 100644
--- a/lib/compiler/doc/src/Makefile
+++ b/lib/compiler/doc/src/Makefile
@@ -99,14 +99,14 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 84e9922847..be9eb1cd75 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -294,6 +294,12 @@ module.beam: module.erl \
describing what it is doing.</p>
</item>
+ <tag><c>{source,FileName}</c></tag>
+ <item>
+ <p>Sets the value of the source, as returned by
+ <c>module_info(compile)</c>.</p>
+ </item>
+
<tag><c>{outdir,Dir}</c></tag>
<item>
<p>Sets a new directory for the object code. The current
@@ -333,7 +339,8 @@ module.beam: module.erl \
<tag><c>{d,Macro,Value}</c></tag>
<item>
<p>Defines a macro <c>Macro</c> to have the value
- <c>Value</c>. The default is <c>true</c>.</p>
+ <c>Value</c>. <c>Macro</c> is of type atom, and <c>Value</c> can be any term.
+ The default <c>Value</c> is <c>true</c>.</p>
</item>
<tag><c>{parse_transform,Module}</c></tag>
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index 3415517fff..56c45d369c 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -163,11 +163,11 @@ $(EBIN)/cerl_inline.beam: $(ESRC)/cerl_inline.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(EXTRA_FILES) \
- $(YRL_FILE) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(INSTALL_FILES) $(RELSYSDIR)/ebin
+ $(YRL_FILE) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(INSTALL_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index 6f0ffb5b25..d307d192b2 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -29,10 +29,17 @@ module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
{ok,{Mod,Exp,Attr,Fs,Lc}}.
function({function,Name,Arity,CLabel,Asm0}) ->
- Asm1 = beam_utils:live_opt(Asm0),
- Asm2 = opt(Asm1, [], tdb_new()),
- Asm = beam_utils:delete_live_annos(Asm2),
- {function,Name,Arity,CLabel,Asm}.
+ try
+ Asm1 = beam_utils:live_opt(Asm0),
+ Asm2 = opt(Asm1, [], tdb_new()),
+ Asm = beam_utils:delete_live_annos(Asm2),
+ {function,Name,Arity,CLabel,Asm}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
%% opt([Instruction], Accumulator, TypeDb) -> {[Instruction'],TypeDb'}
%% Keep track of type information; try to simplify.
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index abcd93f280..194f089ba1 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -741,6 +741,9 @@ live_opt([{badmatch,Src}=I|Is], _, D, Acc) ->
live_opt([{case_end,Src}=I|Is], _, D, Acc) ->
Regs = x_live([Src], 0),
live_opt(Is, Regs, D, [I|Acc]);
+live_opt([{try_case_end,Src}=I|Is], _, D, Acc) ->
+ Regs = x_live([Src], 0),
+ live_opt(Is, Regs, D, [I|Acc]);
live_opt([if_end=I|Is], _, D, Acc) ->
Regs = 0,
live_opt(Is, Regs, D, [I|Acc]);
@@ -802,8 +805,6 @@ live_opt([{deallocate,_}=I|Is], Regs, D, Acc) ->
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{kill,_}=I|Is], Regs, D, Acc) ->
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{try_case_end,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
live_opt([{try_end,_}=I|Is], Regs, D, Acc) ->
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{loop_rec_end,_}=I|Is], Regs, D, Acc) ->
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index a52e7bb761..9f0bca9dd5 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -783,15 +783,27 @@ valfun_4({bs_utf16_size,{f,Fail},A,Dst}, Vst) ->
valfun_4({bs_bits_to_bytes,{f,Fail},Src,Dst}, Vst) ->
assert_term(Src, Vst),
set_type_reg({integer,[]}, Dst, branch_state(Fail, Vst));
-valfun_4({bs_init2,{f,Fail},_,Heap,Live,_,Dst}, Vst0) ->
+valfun_4({bs_init2,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
verify_live(Live, Vst0),
+ if
+ is_integer(Sz) ->
+ ok;
+ true ->
+ assert_term(Sz, Vst0)
+ end,
Vst1 = heap_alloc(Heap, Vst0),
Vst2 = branch_state(Fail, Vst1),
Vst3 = prune_x_regs(Live, Vst2),
Vst = bs_zero_bits(Vst3),
set_type_reg(binary, Dst, Vst);
-valfun_4({bs_init_bits,{f,Fail},_,Heap,Live,_,Dst}, Vst0) ->
+valfun_4({bs_init_bits,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
verify_live(Live, Vst0),
+ if
+ is_integer(Sz) ->
+ ok;
+ true ->
+ assert_term(Sz, Vst0)
+ end,
Vst1 = heap_alloc(Heap, Vst0),
Vst2 = branch_state(Fail, Vst1),
Vst3 = prune_x_regs(Live, Vst2),
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 9b505ad15c..7365706b94 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -146,10 +146,17 @@ env_default_opts() ->
do_compile(Input, Opts0) ->
Opts = expand_opts(Opts0),
- Self = self(),
- Serv = spawn_link(fun() -> internal(Self, Input, Opts) end),
+ {Pid,Ref} =
+ spawn_monitor(fun() ->
+ exit(try
+ internal(Input, Opts)
+ catch
+ error:Reason ->
+ {error,Reason}
+ end)
+ end),
receive
- {Serv,Rep} -> Rep
+ {'DOWN',Ref,process,Pid,Rep} -> Rep
end.
expand_opts(Opts0) ->
@@ -242,15 +249,12 @@ format_error({module_name,Mod,Filename}) ->
errors=[],
warnings=[]}).
-internal(Master, Input, Opts) ->
- Master ! {self(), try internal(Input, Opts)
- catch error:Reason -> {error, Reason}
- end}.
-
-internal({forms,Forms}, Opts) ->
- {_,Ps} = passes(forms, Opts),
- internal_comp(Ps, "", "", #compile{code=Forms,options=Opts,
- mod_options=Opts});
+internal({forms,Forms}, Opts0) ->
+ {_,Ps} = passes(forms, Opts0),
+ Source = proplists:get_value(source, Opts0, ""),
+ Opts1 = proplists:delete(source, Opts0),
+ Compile = #compile{code=Forms,options=Opts1,mod_options=Opts1},
+ internal_comp(Ps, Source, "", Compile);
internal({file,File}, Opts) ->
{Ext,Ps} = passes(file, Opts),
Compile = #compile{options=Opts,mod_options=Opts},
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index ba9cde1de0..6cea783090 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -42,7 +42,7 @@
compile=[], %Compile flags
attributes=[], %Attributes
callbacks=[], %Callbacks
- defined=[], %Defined functions
+ defined, %Defined functions (gb_set)
vcount=0, %Variable counter
func=[], %Current function
arity=[], %Arity for current function
@@ -83,7 +83,7 @@ module(Fs0, Opts0) ->
{Efs,St2} = expand_pmod(Tfs, St1),
%% Get the correct list of exported functions.
Exports = case member(export_all, St2#expand.compile) of
- true -> St2#expand.defined;
+ true -> gb_sets:to_list(St2#expand.defined);
false -> St2#expand.exports
end,
%% Generate all functions from stored info.
@@ -106,10 +106,11 @@ expand_pmod(Fs0, St0) ->
true ->
Ps0
end,
+ Def = gb_sets:to_list(St0#expand.defined),
{Fs1,Xs,Ds} = sys_expand_pmod:forms(Fs0, Ps,
St0#expand.exports,
- St0#expand.defined),
- St1 = St0#expand{exports=Xs, defined=Ds},
+ Def),
+ St1 = St0#expand{exports=Xs,defined=gb_sets:from_list(Ds)},
{Fs2,St2} = add_instance(Ps, Fs1, St1),
{Fs3,St3} = ensure_new(Base, Ps0, Fs2, St2),
{Fs3,St3#expand{attributes = [{abstract, 0, [true]}
@@ -118,7 +119,7 @@ expand_pmod(Fs0, St0) ->
get_base(As) ->
case lists:keyfind(extends, 1, As) of
- {extends,[Base]} when is_atom(Base) ->
+ {extends,_,[Base]} when is_atom(Base) ->
Base;
_ ->
[]
@@ -159,7 +160,7 @@ add_func(Name, Args, Body, Fs, St) ->
F = {function,0,Name,A,[{clause,0,Args,[],Body}]},
NA = {Name,A},
{[F|Fs],St#expand{exports=add_element(NA, St#expand.exports),
- defined=add_element(NA, St#expand.defined)}}.
+ defined=gb_sets:add_element(NA, St#expand.defined)}}.
%% define_function(Form, State) -> State.
%% Add function to defined if form is a function.
@@ -168,7 +169,7 @@ define_functions(Forms, #expand{defined=Predef}=St) ->
Fs = foldl(fun({function,_,N,A,_Cs}, Acc) -> [{N,A}|Acc];
(_, Acc) -> Acc
end, Predef, Forms),
- St#expand{defined=ordsets:from_list(Fs)}.
+ St#expand{defined=gb_sets:from_list(Fs)}.
module_attrs(#expand{attributes=Attributes}=St) ->
Attrs = [{attribute,Line,Name,Val} || {Name,Line,Val} <- Attributes],
@@ -187,7 +188,7 @@ module_predef_func_beh_info(#expand{callbacks=Callbacks,defined=Defined,
PreDef=[{behaviour_info,1}],
PreExp=PreDef,
{[gen_beh_info(Callbacks)],
- St#expand{defined=union(from_list(PreDef), Defined),
+ St#expand{defined=gb_sets:union(gb_sets:from_list(PreDef), Defined),
exports=union(from_list(PreExp), Exports)}}.
gen_beh_info(Callbacks) ->
@@ -215,7 +216,8 @@ module_predef_funcs_mod_info(St) ->
[{clause,0,[{var,0,'X'}],[],
[{call,0,{remote,0,{atom,0,erlang},{atom,0,get_module_info}},
[{atom,0,St#expand.module},{var,0,'X'}]}]}]}],
- St#expand{defined=union(from_list(PreDef), St#expand.defined),
+ St#expand{defined=gb_sets:union(gb_sets:from_list(PreDef),
+ St#expand.defined),
exports=union(from_list(PreExp), St#expand.exports)}}.
%% forms(Forms, State) ->
@@ -721,4 +723,4 @@ imported(F, A, St) ->
end.
defined(F, A, St) ->
- ordsets:is_element({F,A}, St#expand.defined).
+ gb_sets:is_element({F,A}, St#expand.defined).
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 242196c593..01042cc56f 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -823,6 +823,13 @@ bitstr({bin_element,_,E0,Size0,[Type,{unit,Unit}|Flags]}, St0) ->
{_,_} ->
throw(bad_binary)
end,
+ case Size1 of
+ #c_var{} -> ok;
+ #c_literal{val=Sz} when is_integer(Sz), Sz >= 0 -> ok;
+ #c_literal{val=undefined} -> ok;
+ #c_literal{val=all} -> ok;
+ _ -> throw(bad_binary)
+ end,
{#c_bitstr{val=E1,size=Size1,
unit=#c_literal{val=Unit},
type=#c_literal{val=Type},
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index c4e7b45aac..b184987625 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -278,11 +278,12 @@ expr(#c_binary{anno=A,segments=Cv}, Sub, St0) ->
{#k_binary{anno=A,segs=Kv},Ep,St1}
catch
throw:bad_element_size ->
+ St1 = add_warning(get_line(A), bad_segment_size, A, St0),
Erl = #c_literal{val=erlang},
Name = #c_literal{val=error},
Args = [#c_literal{val=badarg}],
Error = #c_call{anno=A,module=Erl,name=Name,args=Args},
- expr(Error, Sub, St0)
+ expr(Error, Sub, St1)
end;
expr(#c_fun{anno=A,vars=Cvs,body=Cb}, Sub0, #kern{ff=OldFF,func=Func}=St0) ->
FA = case OldFF of
@@ -1827,7 +1828,9 @@ format_error({nomatch_shadow,Line}) ->
format_error(nomatch_shadow) ->
"this clause cannot match because a previous clause always matches";
format_error(bad_call) ->
- "invalid module and/or function name; this call will always fail".
+ "invalid module and/or function name; this call will always fail";
+format_error(bad_segment_size) ->
+ "binary construction will fail because of a type mismatch".
add_warning(none, Term, Anno, #kern{ws=Ws}=St) ->
File = get_file(Anno),
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index e13ad4ae90..e047166ade 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -154,12 +154,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) compiler.spec compiler.cover \
- $(EMAKEFILE) $(ERL_FILES) $(CORE_FILES) $(RELSYSDIR)
+ $(EMAKEFILE) $(ERL_FILES) $(CORE_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \
- $(INLINE_ERL_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INLINE_ERL_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 31c7890f26..e8b30f44ce 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -468,6 +468,10 @@ opt(Config) when is_list(Config) ->
?line {'EXIT',_} = (catch <<<<23,56,0,2>>:64/float>>),
?line {'EXIT',_} = (catch <<<<23,56,0,2:7>>/binary>>),
+ %% Test constant propagation - there should be a warning.
+ BadSz = 2.5,
+ {'EXIT',_} = (catch <<<<N,56,0,2>>:BadSz/binary>>),
+
case id(false) of
true -> ?line opt_dont_call_me();
false -> ok
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 512fa0e4ac..da53a6ba9c 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -25,7 +25,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
app_test/1,
- file_1/1, module_mismatch/1, big_file/1, outdir/1,
+ file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1,
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
other_output/1, package_forms/1, encrypted_abstr/1,
bad_record_use1/1, bad_record_use2/1, strict_record/1,
@@ -42,7 +42,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [app_test, file_1, module_mismatch, big_file, outdir,
+ [app_test, file_1, forms_2, module_mismatch, big_file, outdir,
binary, makedep, cond_and_ifdef, listings, listings_big,
other_output, package_forms, encrypted_abstr,
{group, bad_record_use}, strict_record,
@@ -76,6 +76,9 @@ app_test(Config) when is_list(Config) ->
file_1(Config) when is_list(Config) ->
?line Dog = test_server:timetrap(test_server:minutes(5)),
+
+ process_flag(trap_exit, true),
+
?line {Simple, Target} = files(Config, "file_1"),
?line {ok, Cwd} = file:get_cwd(),
?line ok = file:set_cwd(filename:dirname(Target)),
@@ -102,9 +105,37 @@ file_1(Config) when is_list(Config) ->
%% Cleanup.
?line ok = file:delete(Target),
?line ok = file:del_dir(filename:dirname(Target)),
+
+ %% There should not be any messages in the messages.
+ receive
+ Any ->
+ ?t:fail({unexpected,Any})
+ after 10 ->
+ ok
+ end,
+
?line test_server:timetrap_cancel(Dog),
ok.
+forms_2(Config) when is_list(Config) ->
+ Src = "/foo/bar",
+ AbsSrc = filename:absname(Src),
+ {ok,simple,Binary} = compile:forms([{attribute,1,module,simple}],
+ [binary,{source,Src}]),
+ code:load_binary(simple, Src, Binary),
+ Info = simple:module_info(compile),
+
+ %% Test that the proper source is returned.
+ AbsSrc = proplists:get_value(source, Info),
+
+ %% Ensure that the options are not polluted with 'source'.
+ [] = proplists:get_value(options, Info),
+
+ %% Cleanup.
+ true = code:delete(simple),
+ false = code:purge(simple),
+ ok.
+
module_mismatch(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line File = filename:join(DataDir, "wrong_module_name.erl"),
diff --git a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S b/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
index c0bf04ed8f..cffb792920 100644
--- a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
+++ b/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
@@ -19,10 +19,10 @@
{get_tuple_element,{x,0},1,{x,2}}.
{get_tuple_element,{x,0},2,{x,3}}.
{get_tuple_element,{x,0},3,{x,4}}.
- {gc_bif,'+',{f,0},5,[{x,1},{x,2}],{x,0}}.
- {gc_bif,'+',{f,0},5,[{x,0},{x,3}],{x,0}}.
- {gc_bif,'+',{f,0},5,[{x,0},{x,4}],{x,0}}.
- {gc_bif,'+',{f,0},5,[{x,0},{x,5}],{x,0}}.
+ {gc_bif,'+',{f,0},6,[{x,1},{x,2}],{x,0}}.
+ {gc_bif,'+',{f,0},6,[{x,0},{x,3}],{x,0}}.
+ {gc_bif,'+',{f,0},6,[{x,0},{x,4}],{x,0}}.
+ {gc_bif,'+',{f,0},6,[{x,0},{x,5}],{x,0}}.
return.
{label,3}.
{badmatch,{x,0}}.
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index 5e13a93c52..b53d0dba1d 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -190,6 +190,15 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
?line expect_error(fun() -> beam_block:module(BlockInput, []) end),
+ %% beam_type
+ TypeInput = {?MODULE,[{foo,0}],[],
+ [{function,foo,0,2,
+ [{label,1},
+ {line,loc},
+ {func_info,{atom,?MODULE},{atom,foo},0},
+ {label,2}|non_proper_list]}],99},
+ expect_error(fun() -> beam_type:module(TypeInput, []) end),
+
%% beam_except
ExceptInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
diff --git a/lib/cosEvent/doc/src/Makefile b/lib/cosEvent/doc/src/Makefile
index 6a9b4201d7..4a0a7429e9 100644
--- a/lib/cosEvent/doc/src/Makefile
+++ b/lib/cosEvent/doc/src/Makefile
@@ -137,13 +137,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/cosEvent/src/Makefile b/lib/cosEvent/src/Makefile
index f8e751f218..1825beacc5 100644
--- a/lib/cosEvent/src/Makefile
+++ b/lib/cosEvent/src/Makefile
@@ -197,14 +197,14 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) ../info $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) ../info "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/cosEvent/test/Makefile b/lib/cosEvent/test/Makefile
index c3f07c156f..d5350d8293 100644
--- a/lib/cosEvent/test/Makefile
+++ b/lib/cosEvent/test/Makefile
@@ -141,11 +141,11 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/$(IDLOUTDIR)
+ $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
$(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
- $(RELSYSDIR)/$(IDLOUTDIR)
+ "$(RELSYSDIR)/$(IDLOUTDIR)"
diff --git a/lib/cosEventDomain/doc/src/Makefile b/lib/cosEventDomain/doc/src/Makefile
index cd159c623c..4e54b0fb55 100644
--- a/lib/cosEventDomain/doc/src/Makefile
+++ b/lib/cosEventDomain/doc/src/Makefile
@@ -131,13 +131,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/cosEventDomain/src/Makefile b/lib/cosEventDomain/src/Makefile
index 409cac47f1..41a31b332f 100644
--- a/lib/cosEventDomain/src/Makefile
+++ b/lib/cosEventDomain/src/Makefile
@@ -166,14 +166,14 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) ../info $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_GEN_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) ../info "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXTERNAL_GEN_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/cosEventDomain/test/Makefile b/lib/cosEventDomain/test/Makefile
index 160c8565e8..9349067eb5 100644
--- a/lib/cosEventDomain/test/Makefile
+++ b/lib/cosEventDomain/test/Makefile
@@ -98,8 +98,8 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
+ $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
diff --git a/lib/cosFileTransfer/doc/src/Makefile b/lib/cosFileTransfer/doc/src/Makefile
index d9c68987e4..706dec00ce 100644
--- a/lib/cosFileTransfer/doc/src/Makefile
+++ b/lib/cosFileTransfer/doc/src/Makefile
@@ -134,13 +134,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/cosFileTransfer/src/Makefile b/lib/cosFileTransfer/src/Makefile
index 1d51304f6b..1bb765db73 100644
--- a/lib/cosFileTransfer/src/Makefile
+++ b/lib/cosFileTransfer/src/Makefile
@@ -176,12 +176,12 @@ $(TARGET_FILES): IDL-GENERATED
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/cosFileTransfer/test/Makefile b/lib/cosFileTransfer/test/Makefile
index b46fb35356..177ad7616b 100644
--- a/lib/cosFileTransfer/test/Makefile
+++ b/lib/cosFileTransfer/test/Makefile
@@ -126,8 +126,8 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
+ $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
diff --git a/lib/cosNotification/doc/src/Makefile b/lib/cosNotification/doc/src/Makefile
index 5caee09ec5..d970818928 100644
--- a/lib/cosNotification/doc/src/Makefile
+++ b/lib/cosNotification/doc/src/Makefile
@@ -159,13 +159,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/cosNotification/src/Makefile b/lib/cosNotification/src/Makefile
index 92225c6cfd..7b8b73aa11 100644
--- a/lib/cosNotification/src/Makefile
+++ b/lib/cosNotification/src/Makefile
@@ -367,12 +367,12 @@ $(GEN_YECC_ERL_FILES) $(GEN_YECC_HRL_FILES): cosNotification_Grammar.yrl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(YECC_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILES) $(YECC_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(YECC_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILES) $(YECC_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/cosNotification/test/Makefile b/lib/cosNotification/test/Makefile
index ddd809ec65..17b60a8e9f 100644
--- a/lib/cosNotification/test/Makefile
+++ b/lib/cosNotification/test/Makefile
@@ -183,11 +183,11 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/$(IDLOUTDIR)
+ $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
$(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
- $(RELSYSDIR)/$(IDLOUTDIR)
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
+ "$(RELSYSDIR)/$(IDLOUTDIR)"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
diff --git a/lib/cosProperty/doc/src/Makefile b/lib/cosProperty/doc/src/Makefile
index 50f2e06f6c..9bfacc27bd 100644
--- a/lib/cosProperty/doc/src/Makefile
+++ b/lib/cosProperty/doc/src/Makefile
@@ -136,13 +136,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/cosProperty/src/Makefile b/lib/cosProperty/src/Makefile
index 8060421b4e..cb2c56743c 100644
--- a/lib/cosProperty/src/Makefile
+++ b/lib/cosProperty/src/Makefile
@@ -176,12 +176,12 @@ $(TARGET_FILES): IDL-GENERATED
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/cosProperty/test/Makefile b/lib/cosProperty/test/Makefile
index f6e0d0dbba..d85b8a655a 100644
--- a/lib/cosProperty/test/Makefile
+++ b/lib/cosProperty/test/Makefile
@@ -120,11 +120,11 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
-# $(INSTALL_DIR) $(RELSYSDIR)/$(IDLOUTDIR)
+ $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
+# $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
# $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
-# $(RELSYSDIR)/$(IDLOUTDIR)
+# "$(RELSYSDIR)/$(IDLOUTDIR)"
diff --git a/lib/cosTime/doc/src/Makefile b/lib/cosTime/doc/src/Makefile
index 4e97b07cf4..f89c022c4a 100644
--- a/lib/cosTime/doc/src/Makefile
+++ b/lib/cosTime/doc/src/Makefile
@@ -130,13 +130,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/cosTime/src/Makefile b/lib/cosTime/src/Makefile
index 18c25ca8f1..35f16edcef 100644
--- a/lib/cosTime/src/Makefile
+++ b/lib/cosTime/src/Makefile
@@ -195,12 +195,12 @@ $(TARGET_FILES): IDL-GENERATED
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/cosTime/test/Makefile b/lib/cosTime/test/Makefile
index a07b27eecb..ab4d140537 100644
--- a/lib/cosTime/test/Makefile
+++ b/lib/cosTime/test/Makefile
@@ -126,11 +126,11 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
-# $(INSTALL_DIR) $(RELSYSDIR)/$(IDLOUTDIR)
+ $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
+# $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
# $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
-# $(RELSYSDIR)/$(IDLOUTDIR)
+# "$(RELSYSDIR)/$(IDLOUTDIR)"
diff --git a/lib/cosTransactions/doc/src/Makefile b/lib/cosTransactions/doc/src/Makefile
index 4341ec04a3..4edad9829b 100644
--- a/lib/cosTransactions/doc/src/Makefile
+++ b/lib/cosTransactions/doc/src/Makefile
@@ -134,13 +134,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/cosTransactions/examples/Makefile b/lib/cosTransactions/examples/Makefile
index 24cd12202a..0408cad75d 100644
--- a/lib/cosTransactions/examples/Makefile
+++ b/lib/cosTransactions/examples/Makefile
@@ -149,9 +149,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(ERL_FILES) $(JAVA_FILES) $(IDL_FILES) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(INETRC_EXAMPLE) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(ERL_FILES) $(JAVA_FILES) $(IDL_FILES) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(INETRC_EXAMPLE) "$(RELSYSDIR)/examples"
@tar cf - java_output | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/cosTransactions/src/Makefile b/lib/cosTransactions/src/Makefile
index 3c799ca0ca..0922a21641 100644
--- a/lib/cosTransactions/src/Makefile
+++ b/lib/cosTransactions/src/Makefile
@@ -170,11 +170,11 @@ $(TARGET_FILES): IDL-GENERATED
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILE) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_GEN_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILE) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXTERNAL_GEN_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/cosTransactions/test/Makefile b/lib/cosTransactions/test/Makefile
index 0bc8c007da..80f4b6c624 100644
--- a/lib/cosTransactions/test/Makefile
+++ b/lib/cosTransactions/test/Makefile
@@ -142,11 +142,11 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/$(IDLOUTDIR)
+ $(COVER_FILE) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
$(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
- $(RELSYSDIR)/$(IDLOUTDIR)
+ "$(RELSYSDIR)/$(IDLOUTDIR)"
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 94d156b0ec..cfc9a447e0 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -133,11 +133,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/obj
- $(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_DATA) $(NIF_MAKEFILE) $(RELSYSDIR)/priv/obj
- $(INSTALL_PROGRAM) $(OBJS) $(RELSYSDIR)/priv/obj
- $(INSTALL_PROGRAM) $(NIF_LIB) $(RELSYSDIR)/priv/lib
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/obj"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/lib"
+ $(INSTALL_DATA) $(NIF_MAKEFILE) "$(RELSYSDIR)/priv/obj"
+ $(INSTALL_PROGRAM) $(OBJS) "$(RELSYSDIR)/priv/obj"
+ $(INSTALL_PROGRAM) $(NIF_LIB) "$(RELSYSDIR)/priv/lib"
release_docs_spec:
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 4be593e208..a6a81d6fe2 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -954,8 +954,7 @@ static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE
if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 16
|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &text)
- || text.size % 16 != 0) {
+ || !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
return enif_make_badarg(env);
}
diff --git a/lib/crypto/doc/src/Makefile b/lib/crypto/doc/src/Makefile
index 03aaba939b..00ae70fb4a 100644
--- a/lib/crypto/doc/src/Makefile
+++ b/lib/crypto/doc/src/Makefile
@@ -100,16 +100,16 @@ clean clean_docs clean_tex:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6DIR)/* $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6DIR)/* "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 19db6c9dd4..2868fe05f0 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -643,16 +643,14 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<func>
<name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode or Cipher Block Chaining mode</fsummary>
+ <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode</fsummary>
<type>
<v>Key = Text = iolist() | binary()</v>
<v>IVec = Cipher = binary()</v>
</type>
<desc>
<p>Encrypts <c>Text</c> according to AES in Cipher Feedback
- mode (CFB) or Cipher Block Chaining mode (CBC). <c>Text</c>
- must be a multiple of 128 bits (16 bytes). <c>Key</c> is the
+ mode (CFB). <c>Key</c> is the
AES key, and <c>IVec</c> is an arbitrary initializing vector.
The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
(16 bytes).</p>
@@ -660,15 +658,45 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</func>
<func>
<name>aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text</name>
+ <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode</fsummary>
+ <type>
+ <v>Key = Cipher = iolist() | binary()</v>
+ <v>IVec = Text = binary()</v>
+ </type>
+ <desc>
+ <p>Decrypts <c>Cipher</c> according to AES in Cipher Feedback Mode (CFB).
+ <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
+ initializing vector. <c>Key</c> and <c>IVec</c> must have
+ the same values as those used when encrypting. The lengths of
+ <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
+ </desc>
+ </func>
+ <func>
+ <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name>
+ <fsummary>Encrypt <c>Text</c>according to AES in Cipher Block Chaining mode</fsummary>
+ <type>
+ <v>Key = Text = iolist() | binary()</v>
+ <v>IVec = Cipher = binary()</v>
+ </type>
+ <desc>
+ <p>Encrypts <c>Text</c> according to AES in Cipher Block Chaining
+ mode (CBC). <c>Text</c>
+ must be a multiple of 128 bits (16 bytes). <c>Key</c> is the
+ AES key, and <c>IVec</c> is an arbitrary initializing vector.
+ The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
+ (16 bytes).</p>
+ </desc>
+ </func>
+ <func>
<name>aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode or Cipher Block Chaining mode</fsummary>
+ <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Block Chaining mode</fsummary>
<type>
<v>Key = Cipher = iolist() | binary()</v>
<v>IVec = Text = binary()</v>
</type>
<desc>
- <p>Decrypts <c>Cipher</c> according to Cipher Feedback Mode (CFB)
- or Cipher Block Chaining mode (CBC).
+ <p>Decrypts <c>Cipher</c> according to AES in Cipher Block
+ Chaining mode (CBC).
<c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
initializing vector. <c>Key</c> and <c>IVec</c> must have
the same values as those used when encrypting. <c>Cipher</c>
diff --git a/lib/crypto/src/Makefile b/lib/crypto/src/Makefile
index 0e886ce8bf..ddafb9168f 100644
--- a/lib/crypto/src/Makefile
+++ b/lib/crypto/src/Makefile
@@ -83,11 +83,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) \
- $(APPUP_TARGET) $(RELSYSDIR)/ebin
+ $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile
index 3150bd472d..ec8136b455 100644
--- a/lib/crypto/test/Makefile
+++ b/lib/crypto/test/Makefile
@@ -75,9 +75,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
release_tests_spec: $(TEST_TARGET)
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) crypto.spec crypto.cover $(RELTEST_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) crypto.spec crypto.cover $(RELTEST_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
release_docs_spec:
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 627c966dfb..196f00da5d 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -717,10 +717,19 @@ aes_cfb(Config) when is_list(Config) ->
?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
- ?line Cipher = crypto:aes_cfb_128_encrypt(Key, IVec, Plain),
- ?line m(Cipher, hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a")),
- ?line m(Plain,
- crypto:aes_cfb_128_decrypt(Key, IVec, Cipher)).
+ ?line Cipher = hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a"),
+
+ %% Try all prefixes of plain and cipher.
+ aes_cfb_do(byte_size(Plain), Plain, Cipher, Key, IVec).
+
+aes_cfb_do(N, Plain, Cipher, Key, IVec) when N >= 0 ->
+ <<P:N/binary, _/binary>> = Plain,
+ <<C:N/binary, _/binary>> = Cipher,
+ ?line C = crypto:aes_cfb_128_encrypt(Key, IVec, P),
+ ?line P = crypto:aes_cfb_128_decrypt(Key, IVec, C),
+ aes_cfb_do(N-1, Plain, Cipher, Key, IVec);
+aes_cfb_do(_, _, _, _, _) -> ok.
+
%%
%%
diff --git a/lib/debugger/doc/src/Makefile b/lib/debugger/doc/src/Makefile
index 1c0bbaf9d2..bc11ed7f46 100644
--- a/lib/debugger/doc/src/Makefile
+++ b/lib/debugger/doc/src/Makefile
@@ -110,12 +110,12 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- (/bin/cp -rf $(HTMLDIR) $(RELSYSDIR)/doc)
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ (/bin/cp -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/debugger/priv/Makefile b/lib/debugger/priv/Makefile
index 1036a5666b..2f3002331b 100644
--- a/lib/debugger/priv/Makefile
+++ b/lib/debugger/priv/Makefile
@@ -54,8 +54,8 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(TOOLBAR_FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(TOOLBAR_FILES) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/debugger/src/Makefile b/lib/debugger/src/Makefile
index be9a2d13cb..1f9d6f2058 100644
--- a/lib/debugger/src/Makefile
+++ b/lib/debugger/src/Makefile
@@ -129,9 +129,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(TOOLBOX_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(TARGET_TOOLBOX_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(TOOLBOX_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(TARGET_TOOLBOX_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/debugger/test/Makefile b/lib/debugger/test/Makefile
index 3dfbed31ff..bf948ce8b0 100644
--- a/lib/debugger/test/Makefile
+++ b/lib/debugger/test/Makefile
@@ -98,10 +98,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) debugger.spec debugger.cover $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) debugger.spec debugger.cover "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/debugger/test/bs_construct_SUITE.erl b/lib/debugger/test/bs_construct_SUITE.erl
index cf943677be..e0bda7eac8 100644
--- a/lib/debugger/test/bs_construct_SUITE.erl
+++ b/lib/debugger/test/bs_construct_SUITE.erl
@@ -477,7 +477,6 @@ mem_leak(0, _) -> ok;
mem_leak(N, B) ->
?line big_bin(B, <<23>>),
?line {'EXIT',{badarg,_}} = (catch big_bin(B, bad)),
- maybe_gc(),
mem_leak(N-1, B).
big_bin(B1, B2) ->
@@ -490,13 +489,6 @@ big_bin(B1, B2) ->
make_bin(0, Acc) -> Acc;
make_bin(N, Acc) -> make_bin(N-1, <<Acc/binary,Acc/binary>>).
-maybe_gc() ->
- case erlang:system_info(heap_type) of
- shared -> erlang:garbage_collect();
- hybrid -> erlang:garbage_collect();
- private -> ok
- end.
-
-define(COF(Int0),
?line (fun(Int) ->
true = <<Int:32/float>> =:= <<(float(Int)):32/float>>,
diff --git a/lib/dialyzer/doc/src/Makefile b/lib/dialyzer/doc/src/Makefile
index 45b0ffa5ff..a827281cc5 100644
--- a/lib/dialyzer/doc/src/Makefile
+++ b/lib/dialyzer/doc/src/Makefile
@@ -100,13 +100,13 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/dialyzer/src/Makefile b/lib/dialyzer/src/Makefile
index 04f3b844c4..63cc1c98f1 100644
--- a/lib/dialyzer/src/Makefile
+++ b/lib/dialyzer/src/Makefile
@@ -63,7 +63,10 @@ MODULES = \
dialyzer_plt \
dialyzer_races \
dialyzer_succ_typings \
+ dialyzer_timing \
dialyzer_typesig \
+ dialyzer_coordinator \
+ dialyzer_worker \
dialyzer_utils
HRL_FILES= dialyzer.hrl dialyzer_gui_wx.hrl
@@ -152,10 +155,10 @@ $(EBIN)/dialyzer_utils.beam: dialyzer.hrl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(EXTRA_FILES) \
- $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(INSTALL_FILES) $(RELSYSDIR)/ebin
+ "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(INSTALL_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl
index 5e089d1773..105a174e31 100644
--- a/lib/dialyzer/src/dialyzer.hrl
+++ b/lib/dialyzer/src/dialyzer.hrl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%%% Copyright Ericsson AB 2006-2012. 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
@@ -110,6 +110,8 @@
-type label() :: non_neg_integer().
-type rep_mode() :: 'quiet' | 'normal' | 'verbose'.
-type start_from() :: 'byte_code' | 'src_code'.
+-type mfa_or_funlbl() :: label() | mfa().
+-type solver() :: 'v1' | 'v2'.
%%--------------------------------------------------------------------
%% Record declarations used by various files
@@ -126,11 +128,15 @@
use_contracts = true :: boolean(),
race_detection = false :: boolean(),
behaviours_chk = false :: boolean(),
- callgraph_file = "" :: file:filename()}).
+ timing = false :: boolean() | 'debug',
+ timing_server :: dialyzer_timing:timing_server(),
+ callgraph_file = "" :: file:filename(),
+ solvers :: [solver()]}).
-record(options, {files = [] :: [file:filename()],
files_rec = [] :: [file:filename()],
analysis_type = succ_typings :: anal_type1(),
+ timing = false :: boolean() | 'debug',
defines = [] :: [dial_define()],
from = byte_code :: start_from(),
get_warnings = maybe :: boolean() | 'maybe',
@@ -145,10 +151,20 @@
output_format = formatted :: format(),
filename_opt = basename :: fopt(),
callgraph_file = "" :: file:filename(),
- check_plt = true :: boolean()}).
+ check_plt = true :: boolean(),
+ solvers = [] :: [solver()]}).
-record(contract, {contracts = [] :: [contract_pair()],
args = [] :: [erl_types:erl_type()],
forms = [] :: [{_, _}]}).
%%--------------------------------------------------------------------
+
+-define(timing(Server, Msg, Var, Expr),
+ begin
+ dialyzer_timing:start_stamp(Server, Msg),
+ Var = Expr,
+ dialyzer_timing:end_stamp(Server),
+ Var
+ end).
+-define(timing(Server, Msg, Expr),?timing(Server, Msg, _T, Expr)).
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 2c4622155a..496d317f8a 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -30,6 +30,15 @@
-export([start/3]).
+-export([compile_init_result/0,
+ add_to_result/4,
+ start_compilation/2,
+ continue_compilation/2]).
+
+-export_type([compile_init_data/0,
+ one_file_result/0,
+ compile_result/0]).
+
-include("dialyzer.hrl").
-record(analysis_state,
@@ -43,7 +52,9 @@
parent :: pid(),
plt :: dialyzer_plt:plt(),
start_from = byte_code :: start_from(),
- use_contracts = true :: boolean()
+ use_contracts = true :: boolean(),
+ timing_server :: dialyzer_timing:timing_server(),
+ solvers :: [solver()]
}).
-record(server_state, {parent :: pid(), legal_warnings :: [dial_warn_tag()]}).
@@ -55,12 +66,15 @@
-spec start(pid(), [dial_warn_tag()], #analysis{}) -> 'ok'.
start(Parent, LegalWarnings, Analysis) ->
+ TimingServer = dialyzer_timing:init(Analysis#analysis.timing),
RacesOn = ordsets:is_element(?WARN_RACE_CONDITION, LegalWarnings),
- Analysis0 = Analysis#analysis{race_detection = RacesOn},
+ Analysis0 =
+ Analysis#analysis{race_detection = RacesOn, timing_server = TimingServer},
Analysis1 = expand_files(Analysis0),
Analysis2 = run_analysis(Analysis1),
State = #server_state{parent = Parent, legal_warnings = LegalWarnings},
- loop(State, Analysis2, none).
+ loop(State, Analysis2, none),
+ dialyzer_timing:stop(TimingServer).
run_analysis(Analysis) ->
Self = self(),
@@ -122,7 +136,9 @@ analysis_start(Parent, Analysis) ->
plt = Plt,
parent = Parent,
start_from = Analysis#analysis.start_from,
- use_contracts = Analysis#analysis.use_contracts
+ use_contracts = Analysis#analysis.use_contracts,
+ timing_server = Analysis#analysis.timing_server,
+ solvers = Analysis#analysis.solvers
},
Files = ordsets:from_list(Analysis#analysis.files),
{Callgraph, NoWarn, TmpCServer0} = compile_and_store(Files, State),
@@ -146,7 +162,8 @@ analysis_start(Parent, Analysis) ->
dialyzer_codeserver:insert_temp_exported_types(MergedExpTypes,
TmpCServer1),
TmpCServer3 = dialyzer_utils:process_record_remote_types(TmpCServer2),
- dialyzer_contracts:process_contract_remote_types(TmpCServer3)
+ ?timing(State#analysis_state.timing_server, "remote",
+ dialyzer_contracts:process_contract_remote_types(TmpCServer3))
catch
throw:{error, _ErrorMsg} = Error -> exit(Error)
end,
@@ -174,72 +191,67 @@ analysis_start(Parent, Analysis) ->
send_codeserver_plt(Parent, CServer, State3#analysis_state.plt),
send_analysis_done(Parent, Plt2, State3#analysis_state.doc_plt).
-analyze_callgraph(Callgraph, State) ->
- Codeserver = State#analysis_state.codeserver,
- Parent = State#analysis_state.parent,
- DocPlt = State#analysis_state.doc_plt,
+analyze_callgraph(Callgraph, #analysis_state{codeserver = Codeserver,
+ doc_plt = DocPlt,
+ timing_server = TimingServer,
+ parent = Parent,
+ solvers = Solvers} = State) ->
Plt = dialyzer_plt:insert_callbacks(State#analysis_state.plt, Codeserver),
- Callgraph1 = dialyzer_callgraph:finalize(Callgraph),
{NewPlt, NewDocPlt} =
case State#analysis_state.analysis_type of
plt_build ->
- {dialyzer_succ_typings:analyze_callgraph(Callgraph1, Plt,
- Codeserver, Parent),
- DocPlt};
+ NewPlt0 =
+ dialyzer_succ_typings:analyze_callgraph(Callgraph, Plt, Codeserver,
+ TimingServer, Solvers, Parent),
+ {NewPlt0, DocPlt};
succ_typings ->
NoWarn = State#analysis_state.no_warn_unused,
{Warnings, NewPlt0, NewDocPlt0} =
- dialyzer_succ_typings:get_warnings(Callgraph1, Plt, DocPlt,
- Codeserver, NoWarn, Parent),
+ dialyzer_succ_typings:get_warnings(Callgraph, Plt, DocPlt, Codeserver,
+ NoWarn, TimingServer, Solvers, Parent),
send_warnings(State#analysis_state.parent, Warnings),
{NewPlt0, NewDocPlt0}
end,
- dialyzer_callgraph:delete(Callgraph1),
+ dialyzer_callgraph:delete(Callgraph),
State#analysis_state{plt = NewPlt, doc_plt = NewDocPlt}.
%%--------------------------------------------------------------------
%% Build the callgraph and fill the codeserver.
%%--------------------------------------------------------------------
+-record(compile_init,{
+ callgraph :: dialyzer_callgraph:callgraph(),
+ codeserver :: dialyzer_codeserver:codeserver(),
+ defines = [] :: [dial_define()],
+ include_dirs = [] :: [file:filename()],
+ start_from = byte_code :: start_from(),
+ use_contracts = true :: boolean()
+ }).
+
+make_compile_init(#analysis_state{codeserver = Codeserver,
+ defines = Defs,
+ include_dirs = Dirs,
+ use_contracts = UseContracts,
+ start_from = StartFrom}, Callgraph) ->
+ #compile_init{callgraph = Callgraph,
+ codeserver = Codeserver,
+ defines = [{d, Macro, Val} || {Macro, Val} <- Defs],
+ include_dirs = [{i, D} || D <- Dirs],
+ use_contracts = UseContracts,
+ start_from = StartFrom}.
+
compile_and_store(Files, #analysis_state{codeserver = CServer,
- defines = Defs,
- include_dirs = Dirs,
- parent = Parent,
- use_contracts = UseContracts,
- start_from = StartFrom
- } = State) ->
+ timing_server = Timing,
+ parent = Parent} = State) ->
send_log(Parent, "Reading files and computing callgraph... "),
{T1, _} = statistics(runtime),
- Includes = [{i, D} || D <- Dirs],
- Defines = [{d, Macro, Val} || {Macro, Val} <- Defs],
Callgraph = dialyzer_callgraph:new(),
- Fun = case StartFrom of
- src_code ->
- fun(File, {TmpCG, TmpCServer, TmpFailed, TmpNoWarn, TmpMods}) ->
- case compile_src(File, Includes, Defines, TmpCG,
- TmpCServer, UseContracts) of
- {error, Reason} ->
- {TmpCG, TmpCServer, [{File, Reason}|TmpFailed], TmpNoWarn,
- TmpMods};
- {ok, NewCG, NoWarn, NewCServer, Mod} ->
- {NewCG, NewCServer, TmpFailed, NoWarn++TmpNoWarn,
- [Mod|TmpMods]}
- end
- end;
- byte_code ->
- fun(File, {TmpCG, TmpCServer, TmpFailed, TmpNoWarn, TmpMods}) ->
- case compile_byte(File, TmpCG, TmpCServer, UseContracts) of
- {error, Reason} ->
- {TmpCG, TmpCServer, [{File, Reason}|TmpFailed], TmpNoWarn,
- TmpMods};
- {ok, NewCG, NoWarn, NewCServer, Mod} ->
- {NewCG, NewCServer, TmpFailed, NoWarn++TmpNoWarn,
- [Mod|TmpMods]}
- end
- end
- end,
- {NewCallgraph1, NewCServer, Failed, NoWarn, Modules} =
- lists:foldl(Fun, {Callgraph, CServer, [], [], []}, Files),
+ CompileInit = make_compile_init(State, Callgraph),
+ {{Failed, NoWarn, Modules}, NextLabel} =
+ ?timing(Timing, "compile", _C1,
+ dialyzer_coordinator:parallel_job(compile, Files,
+ CompileInit, Timing)),
+ CServer2 = dialyzer_codeserver:set_next_core_label(NextLabel, CServer),
case Failed =:= [] of
true ->
NewFiles = lists:zip(lists:reverse(Modules), Files),
@@ -255,11 +267,56 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
{T2, _} = statistics(runtime),
Msg1 = io_lib:format("done in ~.2f secs\nRemoving edges... ", [(T2-T1)/1000]),
send_log(Parent, Msg1),
- NewCallgraph2 = cleanup_callgraph(State, NewCServer, NewCallgraph1, Modules),
+ Callgraph =
+ ?timing(Timing, "clean", _C2,
+ cleanup_callgraph(State, CServer2, Callgraph, Modules)),
{T3, _} = statistics(runtime),
Msg2 = io_lib:format("done in ~.2f secs\n", [(T3-T2)/1000]),
send_log(Parent, Msg2),
- {NewCallgraph2, sets:from_list(NoWarn), NewCServer}.
+ {Callgraph, sets:from_list(NoWarn), CServer2}.
+
+-type compile_init_data() :: #compile_init{}.
+-type error_reason() :: string().
+-type compile_result() :: {[{file:filename(), error_reason()}], [mfa()],
+ [module()]}. %%opaque
+-type one_file_result() :: {error, error_reason()} |
+ {ok, [dialyzer_callgraph:callgraph_edge()],
+ [mfa_or_funlbl()], [mfa()], module()}. %%opaque
+-type compile_mid_data() :: {module(), cerl:cerl(), [mfa()],
+ dialyzer_callgraph:callgraph(),
+ dialyzer_codeserver:codeserver()}.
+
+-spec compile_init_result() -> compile_result().
+
+compile_init_result() -> {[], [], []}.
+
+-spec add_to_result(file:filename(), one_file_result(), compile_result(),
+ compile_init_data()) -> compile_result().
+
+add_to_result(File, NewData, {Failed, NoWarn, Mods}, InitData) ->
+ case NewData of
+ {error, Reason} ->
+ {[{File, Reason}|Failed], NoWarn, Mods};
+ {ok, V, E, NewNoWarn, Mod} ->
+ Callgraph = InitData#compile_init.callgraph,
+ dialyzer_callgraph:add_edges(E, V, Callgraph),
+ {Failed, NewNoWarn ++ NoWarn, [Mod|Mods]}
+ end.
+
+-spec start_compilation(file:filename(), compile_init_data()) ->
+ {error, error_reason()} |{ok, integer(), compile_mid_data()}.
+
+start_compilation(File,
+ #compile_init{callgraph = Callgraph, codeserver = Codeserver,
+ defines = Defines, include_dirs = IncludeD,
+ use_contracts = UseContracts,
+ start_from = StartFrom}) ->
+ case StartFrom of
+ src_code ->
+ compile_src(File, IncludeD, Defines, Callgraph, Codeserver, UseContracts);
+ byte_code ->
+ compile_byte(File, Callgraph, Codeserver, UseContracts)
+ end.
cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent,
codeserver = CodeServer
@@ -348,14 +405,18 @@ compile_common(File, AbstrCode, CompOpts, Callgraph, CServer, UseContracts) ->
store_core(Mod, Core, NoWarn, Callgraph, CServer) ->
Exp = get_exports_from_core(Core),
- OldExpTypes = dialyzer_codeserver:get_temp_exported_types(CServer),
- NewExpTypes = get_exported_types_from_core(Core),
- MergedExpTypes = sets:union(NewExpTypes, OldExpTypes),
- CServer1 = dialyzer_codeserver:insert_exports(Exp, CServer),
- CServer2 = dialyzer_codeserver:insert_temp_exported_types(MergedExpTypes,
- CServer1),
- {LabeledCore, CServer3} = label_core(Core, CServer2),
- store_code_and_build_callgraph(Mod, LabeledCore, Callgraph, CServer3, NoWarn).
+ ExpTypes = get_exported_types_from_core(Core),
+ CServer = dialyzer_codeserver:insert_exports(Exp, CServer),
+ CServer = dialyzer_codeserver:insert_temp_exported_types(ExpTypes, CServer),
+ CoreTree = cerl:from_records(Core),
+ {ok, cerl_trees:size(CoreTree), {Mod, CoreTree, NoWarn, Callgraph, CServer}}.
+
+-spec continue_compilation(integer(), compile_mid_data()) -> one_file_result().
+
+continue_compilation(NextLabel, {Mod, CoreTree, NoWarn, Callgraph, CServer}) ->
+ {LabeledTree, _NewNextLabel} = cerl_trees:label(CoreTree, NextLabel),
+ LabeledCore = cerl:to_records(LabeledTree),
+ store_code_and_build_callgraph(Mod, LabeledCore, Callgraph, NoWarn, CServer).
abs_get_nowarn(Abs, M) ->
Opts = lists:flatten([C || {attribute, _, compile, C} <- Abs]),
@@ -388,18 +449,11 @@ get_exports_from_core(Core) ->
M = cerl:atom_val(cerl:module_name(Tree)),
[{M, F, A} || {F, A} <- Exports2].
-label_core(Core, CServer) ->
- NextLabel = dialyzer_codeserver:get_next_core_label(CServer),
- CoreTree = cerl:from_records(Core),
- {LabeledTree, NewNextLabel} = cerl_trees:label(CoreTree, NextLabel),
- {cerl:to_records(LabeledTree),
- dialyzer_codeserver:set_next_core_label(NewNextLabel, CServer)}.
-
-store_code_and_build_callgraph(Mod, Core, Callgraph, CServer, NoWarn) ->
+store_code_and_build_callgraph(Mod, Core, Callgraph, NoWarn, CServer) ->
CoreTree = cerl:from_records(Core),
- NewCallgraph = dialyzer_callgraph:scan_core_tree(CoreTree, Callgraph),
- CServer2 = dialyzer_codeserver:insert(Mod, CoreTree, CServer),
- {ok, NewCallgraph, NoWarn, CServer2, Mod}.
+ {Vertices, Edges} = dialyzer_callgraph:scan_core_tree(CoreTree, Callgraph),
+ CServer = dialyzer_codeserver:insert(Mod, CoreTree, CServer),
+ {ok, Vertices, Edges, NoWarn, Mod}.
%%--------------------------------------------------------------------
%% Utilities
diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl
index 127e906135..b84071b95c 100644
--- a/lib/dialyzer/src/dialyzer_behaviours.erl
+++ b/lib/dialyzer/src/dialyzer_behaviours.erl
@@ -30,7 +30,7 @@
-module(dialyzer_behaviours).
--export([check_callbacks/4, get_behaviour_apis/1,
+-export([check_callbacks/5, get_behaviour_apis/1,
translate_behaviour_api_call/5, translatable_behaviours/1,
translate_callgraph/3]).
@@ -47,15 +47,16 @@
-record(state, {plt :: dialyzer_plt:plt(),
codeserver :: dialyzer_codeserver:codeserver(),
filename :: file:filename(),
- behlines :: [{behaviour(), non_neg_integer()}]}).
+ behlines :: [{behaviour(), non_neg_integer()}],
+ records :: dict()}).
%%--------------------------------------------------------------------
--spec check_callbacks(module(), [{cerl:cerl(), cerl:cerl()}],
+-spec check_callbacks(module(), [{cerl:cerl(), cerl:cerl()}], dict(),
dialyzer_plt:plt(),
dialyzer_codeserver:codeserver()) -> [dial_warning()].
-check_callbacks(Module, Attrs, Plt, Codeserver) ->
+check_callbacks(Module, Attrs, Records, Plt, Codeserver) ->
{Behaviours, BehLines} = get_behaviours(Attrs),
case Behaviours of
[] -> [];
@@ -64,7 +65,7 @@ check_callbacks(Module, Attrs, Plt, Codeserver) ->
{_Var,Code} = dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
File = get_file(cerl:get_ann(Code)),
State = #state{plt = Plt, filename = File, behlines = BehLines,
- codeserver = Codeserver},
+ codeserver = Codeserver, records = Records},
Warnings = get_warnings(Module, Behaviours, State),
[add_tag_file_line(Module, W, State) || W <- Warnings]
end.
@@ -92,24 +93,21 @@ get_warnings(Module, [Behaviour|Rest], State, Acc) ->
check_behaviour(Module, Behaviour, #state{plt = Plt} = State, Acc) ->
case dialyzer_plt:lookup_callbacks(Plt, Behaviour) of
- [] -> [{callback_info_missing, [Behaviour]}|Acc];
- Callbacks -> check_all_callbacks(Module, Behaviour, Callbacks, State, Acc)
+ none -> [{callback_info_missing, [Behaviour]}|Acc];
+ {value, Callbacks} ->
+ check_all_callbacks(Module, Behaviour, Callbacks, State, Acc)
end.
check_all_callbacks(_Module, _Behaviour, [], _State, Acc) ->
Acc;
check_all_callbacks(Module, Behaviour, [Cb|Rest],
- #state{plt = Plt, codeserver = Codeserver} = State, Acc) ->
+ #state{plt = Plt, codeserver = Codeserver,
+ records = Records} = State, Acc) ->
{{Behaviour, Function, Arity},
{{_BehFile, _BehLine}, Callback}} = Cb,
CbMFA = {Module, Function, Arity},
CbReturnType = dialyzer_contracts:get_contract_return(Callback),
CbArgTypes = dialyzer_contracts:get_contract_args(Callback),
- Records =
- case dict:find(Module, dialyzer_codeserver:get_records(Codeserver)) of
- {ok, V} -> V;
- error -> dict:new()
- end,
Acc0 = Acc,
Acc1 =
case dialyzer_plt:lookup(Plt, CbMFA) of
@@ -282,8 +280,8 @@ translate_callgraph([{Behaviour,_}|Behaviours], Module, Callgraph) ->
DirectCalls = [{From, {Module, Fun, Arity}} ||
{From, To} <- UsedCalls,{API, {Fun, Arity, _Ord}} <- Calls,
To =:= API],
- NewCallgraph = dialyzer_callgraph:add_edges(DirectCalls, Callgraph),
- translate_callgraph(Behaviours, Module, NewCallgraph);
+ dialyzer_callgraph:add_edges(DirectCalls, Callgraph),
+ translate_callgraph(Behaviours, Module, Callgraph);
translate_callgraph([], _Module, Callgraph) ->
Callgraph.
diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl
index effd619bde..64e0ee88af 100644
--- a/lib/dialyzer/src/dialyzer_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_callgraph.erl
@@ -28,6 +28,7 @@
-module(dialyzer_callgraph).
-export([add_edges/2,
+ add_edges/3,
all_nodes/1,
delete/1,
finalize/1,
@@ -43,12 +44,15 @@
%% module_postorder/1,
module_postorder_from_funs/2,
new/0,
+ get_depends_on/2,
+ get_required_by/2,
in_neighbours/2,
renew_race_info/4,
+ renew_race_code/2,
+ renew_race_public_tables/2,
reset_from_funs/2,
scan_core_tree/2,
strip_module_deps/2,
- take_scc/1,
remove_external/1,
to_dot/2,
to_ps/3]).
@@ -57,15 +61,14 @@
get_race_code/1, get_race_detection/1, race_code_new/1,
put_digraph/2, put_race_code/2, put_race_detection/2,
put_named_tables/2, put_public_tables/2, put_behaviour_api_calls/2,
- get_behaviour_api_calls/1]).
+ get_behaviour_api_calls/1, dispose_race_server/1, duplicate/1]).
--export_type([callgraph/0, mfa_or_funlbl/0]).
+-export_type([callgraph/0, mfa_or_funlbl/0, callgraph_edge/0]).
-include("dialyzer.hrl").
%%----------------------------------------------------------------------
--type mfa_or_funlbl() :: label() | mfa().
-type scc() :: [mfa_or_funlbl()].
-type mfa_calls() :: [{mfa_or_funlbl(), mfa_or_funlbl()}].
@@ -78,9 +81,6 @@
%% digraph - A digraph representing the callgraph.
%% Nodes are represented as MFAs or labels.
%% esc - A set of all escaping functions as reported by dialyzer_dep.
-%% postorder - A list of strongly connected components of the callgraph
-%% sorted in a topological bottom-up order.
-%% This is produced by calling finalize/1.
%% name_map - A mapping from label to MFA.
%% rev_name_map - A reverse mapping of the name_map.
%% rec_var_map - A dict mapping from letrec bound labels to function names.
@@ -91,29 +91,42 @@
%%-----------------------------------------------------------------------------
-record(callgraph, {digraph = digraph:new() :: digraph(),
- esc = sets:new() :: set(),
- name_map = dict:new() :: dict(),
- rev_name_map = dict:new() :: dict(),
- postorder = [] :: [scc()],
- rec_var_map = dict:new() :: dict(),
- self_rec = sets:new() :: set(),
- calls = dict:new() :: dict(),
- race_code = dict:new() :: dict(),
- public_tables = [] :: [label()],
- named_tables = [] :: [string()],
+ active_digraph :: active_digraph(),
+ esc :: ets:tid(),
+ name_map :: ets:tid(),
+ rev_name_map :: ets:tid(),
+ rec_var_map :: ets:tid(),
+ self_rec :: ets:tid(),
+ calls :: ets:tid(),
race_detection = false :: boolean(),
- beh_api_calls = [] :: [{mfa(), mfa()}]}).
+ race_data_server = new_race_data_server() :: pid()}).
+
+-record(race_data_state, {race_code = dict:new() :: dict(),
+ public_tables = [] :: [label()],
+ named_tables = [] :: [string()],
+ beh_api_calls = [] :: [{mfa(), mfa()}]}).
%% Exported Types
-type callgraph() :: #callgraph{}.
+-type active_digraph() :: {'d', digraph()} | {'e', ets:tid(), ets:tid()}.
+
%%----------------------------------------------------------------------
-spec new() -> callgraph().
new() ->
- #callgraph{}.
+ [ETSEsc, ETSNameMap, ETSRevNameMap, ETSRecVarMap, ETSSelfRec, ETSCalls] =
+ [ets:new(N,[public, {read_concurrency, true}]) ||
+ N <- [callgraph_esc, callgraph_name_map, callgraph_rev_name_map,
+ callgraph_rec_var_map, callgraph_self_rec, callgraph_calls]],
+ #callgraph{esc = ETSEsc,
+ name_map = ETSNameMap,
+ rev_name_map = ETSRevNameMap,
+ rec_var_map = ETSRecVarMap,
+ self_rec = ETSSelfRec,
+ calls = ETSCalls}.
-spec delete(callgraph()) -> 'true'.
@@ -129,32 +142,32 @@ all_nodes(#callgraph{digraph = DG}) ->
lookup_rec_var(Label, #callgraph{rec_var_map = RecVarMap})
when is_integer(Label) ->
- dict:find(Label, RecVarMap).
+ ets_lookup_dict(Label, RecVarMap).
-spec lookup_call_site(label(), callgraph()) -> 'error' | {'ok', [_]}. % XXX: refine
lookup_call_site(Label, #callgraph{calls = Calls})
when is_integer(Label) ->
- dict:find(Label, Calls).
+ ets_lookup_dict(Label, Calls).
-spec lookup_name(label(), callgraph()) -> 'error' | {'ok', mfa()}.
lookup_name(Label, #callgraph{name_map = NameMap})
when is_integer(Label) ->
- dict:find(Label, NameMap).
+ ets_lookup_dict(Label, NameMap).
-spec lookup_label(mfa_or_funlbl(), callgraph()) -> 'error' | {'ok', integer()}.
lookup_label({_,_,_} = MFA, #callgraph{rev_name_map = RevNameMap}) ->
- dict:find(MFA, RevNameMap);
+ ets_lookup_dict(MFA, RevNameMap);
lookup_label(Label, #callgraph{}) when is_integer(Label) ->
{ok, Label}.
-spec in_neighbours(mfa_or_funlbl(), callgraph()) -> 'none' | [mfa_or_funlbl(),...].
-in_neighbours(Label, #callgraph{digraph = Digraph, name_map = NameMap})
+in_neighbours(Label, #callgraph{digraph = Digraph} = CG)
when is_integer(Label) ->
- Name = case dict:find(Label, NameMap) of
+ Name = case lookup_name(Label, CG) of
{ok, Val} -> Val;
error -> Label
end,
@@ -165,34 +178,27 @@ in_neighbours({_, _, _} = MFA, #callgraph{digraph = Digraph}) ->
-spec is_self_rec(mfa_or_funlbl(), callgraph()) -> boolean().
is_self_rec(MfaOrLabel, #callgraph{self_rec = SelfRecs}) ->
- sets:is_element(MfaOrLabel, SelfRecs).
+ ets_lookup_set(MfaOrLabel, SelfRecs).
-spec is_escaping(label(), callgraph()) -> boolean().
is_escaping(Label, #callgraph{esc = Esc}) when is_integer(Label) ->
- sets:is_element(Label, Esc).
+ ets_lookup_set(Label, Esc).
-type callgraph_edge() :: {mfa_or_funlbl(),mfa_or_funlbl()}.
--spec add_edges([callgraph_edge()], callgraph()) -> callgraph().
+-spec add_edges([callgraph_edge()], callgraph()) -> ok.
-add_edges([], CG) ->
- CG;
-add_edges(Edges, #callgraph{digraph = Digraph} = CG) ->
- CG#callgraph{digraph = digraph_add_edges(Edges, Digraph)}.
+add_edges([], _CG) ->
+ ok;
+add_edges(Edges, #callgraph{digraph = Digraph}) ->
+ digraph_add_edges(Edges, Digraph).
--spec add_edges([callgraph_edge()], [mfa_or_funlbl()], callgraph()) -> callgraph().
+-spec add_edges([callgraph_edge()], [mfa_or_funlbl()], callgraph()) -> ok.
add_edges(Edges, MFAs, #callgraph{digraph = DG} = CG) ->
- DG = digraph_confirm_vertices(MFAs, DG),
+ digraph_confirm_vertices(MFAs, DG),
add_edges(Edges, CG).
--spec take_scc(callgraph()) -> 'none' | {'ok', scc(), callgraph()}.
-
-take_scc(#callgraph{postorder = [SCC|SCCs]} = CG) ->
- {ok, SCC, CG#callgraph{postorder = SCCs}};
-take_scc(#callgraph{postorder = []}) ->
- none.
-
-spec remove_external(callgraph()) -> {callgraph(), [tuple()]}.
remove_external(#callgraph{digraph = DG} = CG) ->
@@ -221,13 +227,25 @@ find_non_local_calls([{Label1, Label2}|Left], Set) when is_integer(Label1),
find_non_local_calls([], Set) ->
sets:to_list(Set).
--spec renew_race_info(callgraph(), dict(), [label()], [string()]) ->
- callgraph().
+-spec get_depends_on(scc() | module(), callgraph()) -> [scc()].
+
+get_depends_on(SCC, #callgraph{active_digraph = {'e', Out, _In}}) ->
+ case ets_lookup_dict(SCC, Out) of
+ {ok, Value} -> Value;
+ error -> []
+ end;
+get_depends_on(SCC, #callgraph{active_digraph = {'d', DG}}) ->
+ digraph:out_neighbours(DG, SCC).
+
+-spec get_required_by(scc() | module(), callgraph()) -> [scc()].
-renew_race_info(CG, RaceCode, PublicTables, NamedTables) ->
- CG#callgraph{race_code = RaceCode,
- public_tables = PublicTables,
- named_tables = NamedTables}.
+get_required_by(SCC, #callgraph{active_digraph = {'e', _Out, In}}) ->
+ case ets_lookup_dict(SCC, In) of
+ {ok, Value} -> Value;
+ error -> []
+ end;
+get_required_by(SCC, #callgraph{active_digraph = {'d', DG}}) ->
+ digraph:in_neighbours(DG, SCC).
%%----------------------------------------------------------------------
%% Handling of modules & SCCs
@@ -238,32 +256,37 @@ renew_race_info(CG, RaceCode, PublicTables, NamedTables) ->
modules(#callgraph{digraph = DG}) ->
ordsets:from_list([M || {M,_F,_A} <- digraph_vertices(DG)]).
--spec module_postorder(callgraph()) -> [[module()]].
+-spec module_postorder(callgraph()) -> {[module()], {'d', digraph()}}.
module_postorder(#callgraph{digraph = DG}) ->
- {MDG, _Nodes} = get_module_digraph_and_nodes(DG),
- MDG1 = digraph_utils:condensation(MDG),
- PostOrder = digraph_utils:postorder(MDG1),
- PostOrder1 = sort_sccs_internally(PostOrder, MDG),
- digraph:delete(MDG1),
- digraph_delete(MDG),
- PostOrder1.
+ Edges = lists:foldl(fun edge_fold/2, sets:new(), digraph_edges(DG)),
+ Nodes = sets:from_list([M || {M,_F,_A} <- digraph_vertices(DG)]),
+ MDG = digraph:new([acyclic]),
+ digraph_confirm_vertices(sets:to_list(Nodes), MDG),
+ Foreach = fun({M1,M2}) -> digraph:add_edge(MDG, M1, M2) end,
+ lists:foreach(Foreach, sets:to_list(Edges)),
+ {digraph_utils:topsort(MDG), {'d', MDG}}.
+
+edge_fold({{M1,_,_},{M2,_,_}}, Set) ->
+ case M1 =/= M2 of
+ true -> sets:add_element({M1,M2},Set);
+ false -> Set
+ end;
+edge_fold(_, Set) -> Set.
-get_module_digraph_and_nodes(DG) ->
- Edges = digraph_edges(DG),
- Nodes = ordsets:from_list([M || {M,_F,_A} <- digraph_vertices(DG)]),
- MDG = digraph:new(),
- MDG = digraph_confirm_vertices(Nodes, MDG),
- MDG = create_module_digraph(Edges, MDG),
- {MDG, Nodes}.
%% The module deps of a module are modules that depend on the module
-spec module_deps(callgraph()) -> dict().
module_deps(#callgraph{digraph = DG}) ->
- {MDG, Nodes} = get_module_digraph_and_nodes(DG),
+ Edges = lists:foldl(fun edge_fold/2, sets:new(), digraph_edges(DG)),
+ Nodes = sets:from_list([M || {M,_F,_A} <- digraph_vertices(DG)]),
+ MDG = digraph:new(),
+ digraph_confirm_vertices(sets:to_list(Nodes), MDG),
+ Foreach = fun({M1,M2}) -> digraph:add_edge(MDG, M1, M2) end,
+ lists:foreach(Foreach, sets:to_list(Edges)),
Deps = [{N, ordsets:from_list(digraph:in_neighbours(MDG, N))}
- || N <- Nodes],
+ || N <- sets:to_list(Nodes)],
digraph_delete(MDG),
dict:from_list(Deps).
@@ -276,52 +299,42 @@ strip_module_deps(ModDeps, StripSet) ->
FilterFun2 = fun(_Key, ValSet) -> ValSet =/= [] end,
dict:filter(FilterFun2, ModDeps1).
-sort_sccs_internally(PO, MDG) ->
- sort_sccs_internally(PO, MDG, []).
-
-sort_sccs_internally([SCC|SCCs], MDG, Acc) ->
- case SCC of
- [_, _, _ | _] -> % length(SCC) >= 3
- TmpDG = digraph_utils:subgraph(MDG, SCC),
- NewSCC = digraph_utils:postorder(TmpDG),
- digraph_delete(TmpDG),
- sort_sccs_internally(SCCs, MDG, [NewSCC|Acc]);
- _ ->
- sort_sccs_internally(SCCs, MDG, [SCC|Acc])
- end;
-sort_sccs_internally([], _MDG, Acc) ->
- lists:reverse(Acc).
-
-create_module_digraph([{{M, _, _}, {M, _, _}}|Left], MDG) ->
- create_module_digraph(Left, MDG);
-create_module_digraph([{{M1, _, _}, {M2, _, _}}|Left], MDG) ->
- create_module_digraph(Left, digraph_add_edge(M1, M2, MDG));
-create_module_digraph([{_, _}|Left], MDG) ->
- create_module_digraph(Left, MDG);
-create_module_digraph([], MDG) ->
- MDG.
-
--spec finalize(callgraph()) -> callgraph().
+-spec finalize(callgraph()) -> {[scc()], callgraph()}.
finalize(#callgraph{digraph = DG} = CG) ->
- CG#callgraph{postorder = digraph_finalize(DG)}.
+ {ActiveDG, Postorder} = condensation(DG),
+ {Postorder, CG#callgraph{active_digraph = ActiveDG}}.
--spec reset_from_funs([mfa_or_funlbl()], callgraph()) -> callgraph().
+-spec reset_from_funs([mfa_or_funlbl()], callgraph()) -> {[scc()], callgraph()}.
-reset_from_funs(Funs, #callgraph{digraph = DG} = CG) ->
+reset_from_funs(Funs, #callgraph{digraph = DG, active_digraph = ADG} = CG) ->
+ active_digraph_delete(ADG),
SubGraph = digraph_reaching_subgraph(Funs, DG),
- Postorder = digraph_finalize(SubGraph),
+ {NewActiveDG, Postorder} = condensation(SubGraph),
digraph_delete(SubGraph),
- CG#callgraph{postorder = Postorder}.
+ {Postorder, CG#callgraph{active_digraph = NewActiveDG}}.
--spec module_postorder_from_funs([mfa_or_funlbl()], callgraph()) -> [[module()]].
+-spec module_postorder_from_funs([mfa_or_funlbl()], callgraph()) ->
+ {[module()], callgraph()}.
-module_postorder_from_funs(Funs, #callgraph{digraph = DG} = CG) ->
+module_postorder_from_funs(Funs, #callgraph{digraph = DG,
+ active_digraph = ADG} = CG) ->
+ active_digraph_delete(ADG),
SubGraph = digraph_reaching_subgraph(Funs, DG),
- PO = module_postorder(CG#callgraph{digraph = SubGraph}),
+ {PO, Active} = module_postorder(CG#callgraph{digraph = SubGraph}),
digraph_delete(SubGraph),
- PO.
-
+ {PO, CG#callgraph{active_digraph = Active}}.
+
+ets_lookup_dict(Key, Table) ->
+ try ets:lookup_element(Table, Key, 2) of
+ Val -> {ok, Val}
+ catch
+ _:_ -> error
+ end.
+
+ets_lookup_set(Key, Table) ->
+ ets:lookup(Table, Key) =/= [].
+
%%----------------------------------------------------------------------
%% Core code
%%----------------------------------------------------------------------
@@ -330,36 +343,37 @@ module_postorder_from_funs(Funs, #callgraph{digraph = DG} = CG) ->
%% The set of labels in the tree must be disjoint from the set of
%% labels already occuring in the callgraph.
--spec scan_core_tree(cerl:c_module(), callgraph()) -> callgraph().
+-spec scan_core_tree(cerl:c_module(), callgraph()) ->
+ {[mfa_or_funlbl()], [callgraph_edge()]}.
-scan_core_tree(Tree, #callgraph{calls = OldCalls,
- esc = OldEsc,
- name_map = OldNameMap,
- rec_var_map = OldRecVarMap,
- rev_name_map = OldRevNameMap,
- self_rec = OldSelfRec} = CG) ->
+scan_core_tree(Tree, #callgraph{calls = ETSCalls,
+ esc = ETSEsc,
+ name_map = ETSNameMap,
+ rec_var_map = ETSRecVarMap,
+ rev_name_map = ETSRevNameMap,
+ self_rec = ETSSelfRec}) ->
%% Build name map and recursion variable maps.
- {NewNameMap, NewRevNameMap, NewRecVarMap} =
- build_maps(Tree, OldRecVarMap, OldNameMap, OldRevNameMap),
-
+ build_maps(Tree, ETSRecVarMap, ETSNameMap, ETSRevNameMap),
+
%% First find the module-local dependencies.
{Deps0, EscapingFuns, Calls} = dialyzer_dep:analyze(Tree),
- NewCalls = dict:merge(fun(_Key, Val, Val) -> Val end, OldCalls, Calls),
- NewEsc = sets:union(sets:from_list(EscapingFuns), OldEsc),
+ true = ets:insert(ETSCalls, dict:to_list(Calls)),
+ true = ets:insert(ETSEsc, [{E} || E <- EscapingFuns]),
+
LabelEdges = get_edges_from_deps(Deps0),
%% Find the self recursive functions. Named functions get both the
%% key and their name for convenience.
SelfRecs0 = lists:foldl(fun({Key, Key}, Acc) ->
- case dict:find(Key, NewNameMap) of
+ case ets_lookup_dict(Key, ETSNameMap) of
error -> [Key|Acc];
{ok, Name} -> [Key, Name|Acc]
end;
(_, Acc) -> Acc
end, [], LabelEdges),
- SelfRecs = sets:union(sets:from_list(SelfRecs0), OldSelfRec),
+ true = ets:insert(ETSSelfRec, [{S} || S <- SelfRecs0]),
- NamedEdges1 = name_edges(LabelEdges, NewNameMap),
+ NamedEdges1 = name_edges(LabelEdges, ETSNameMap),
%% We need to scan for inter-module calls since these are not tracked
%% by dialyzer_dep. Note that the caller is always recorded as the
@@ -378,27 +392,25 @@ scan_core_tree(Tree, #callgraph{calls = OldCalls,
NewNamedEdges1 =
[E || {From, To} = E <- NamedEdges1, From =/= top, To =/= top],
NamedEdges3 = NewNamedEdges1 ++ NewNamedEdges2,
- CG1 = add_edges(NamedEdges3, Names3, CG),
- CG1#callgraph{calls = NewCalls,
- esc = NewEsc,
- name_map = NewNameMap,
- rec_var_map = NewRecVarMap,
- rev_name_map = NewRevNameMap,
- self_rec = SelfRecs}.
-
-build_maps(Tree, RecVarMap, NameMap, RevNameMap) ->
+ {Names3, NamedEdges3}.
+
+build_maps(Tree, ETSRecVarMap, ETSNameMap, ETSRevNameMap) ->
%% We only care about the named (top level) functions. The anonymous
%% functions will be analysed together with their parents.
Defs = cerl:module_defs(Tree),
Mod = cerl:atom_val(cerl:module_name(Tree)),
- lists:foldl(fun({Var, Function}, {AccNameMap, AccRevNameMap, AccRecVarMap}) ->
- FunName = cerl:fname_id(Var),
- Arity = cerl:fname_arity(Var),
- MFA = {Mod, FunName, Arity},
- {dict:store(get_label(Function), MFA, AccNameMap),
- dict:store(MFA, get_label(Function), AccRevNameMap),
- dict:store(get_label(Var), MFA, AccRecVarMap)}
- end, {NameMap, RevNameMap, RecVarMap}, Defs).
+ Fun =
+ fun({Var, Function}) ->
+ FunName = cerl:fname_id(Var),
+ Arity = cerl:fname_arity(Var),
+ MFA = {Mod, FunName, Arity},
+ FunLabel = get_label(Function),
+ VarLabel = get_label(Var),
+ true = ets:insert(ETSNameMap, {FunLabel, MFA}),
+ true = ets:insert(ETSRevNameMap, {MFA, FunLabel}),
+ true = ets:insert(ETSRecVarMap, {VarLabel, MFA})
+ end,
+ lists:foreach(Fun, Defs).
get_edges_from_deps(Deps) ->
%% Convert the dependencies as produced by dialyzer_dep to a list of
@@ -411,22 +423,22 @@ get_edges_from_deps(Deps) ->
end, [], Deps),
lists:flatten(Edges).
-name_edges(Edges, NameMap) ->
+name_edges(Edges, ETSNameMap) ->
%% If a label is present in the name map it is renamed. Otherwise
%% keep the label as the identity.
MapFun = fun(X) ->
- case dict:find(X, NameMap) of
+ case ets_lookup_dict(X, ETSNameMap) of
error -> X;
{ok, MFA} -> MFA
end
end,
- name_edges(Edges, MapFun, NameMap, []).
+ name_edges(Edges, MapFun, []).
-name_edges([{From, To}|Left], MapFun, NameMap, Acc) ->
+name_edges([{From, To}|Left], MapFun, Acc) ->
NewFrom = MapFun(From),
NewTo = MapFun(To),
- name_edges(Left, MapFun, NameMap, [{NewFrom, NewTo}|Acc]);
-name_edges([], _MapFun, _NameMap, Acc) ->
+ name_edges(Left, MapFun, [{NewFrom, NewTo}|Acc]);
+name_edges([], _MapFun, Acc) ->
Acc.
scan_core_funs(Tree) ->
@@ -478,9 +490,10 @@ get_label(T) ->
%%----------------------------------------------------------------------
digraph_add_edges([{From, To}|Left], DG) ->
- digraph_add_edges(Left, digraph_add_edge(From, To, DG));
-digraph_add_edges([], DG) ->
- DG.
+ digraph_add_edge(From, To, DG),
+ digraph_add_edges(Left, DG);
+digraph_add_edges([], _DG) ->
+ ok.
digraph_add_edge(From, To, DG) ->
case digraph:vertex(DG, From) of
@@ -492,13 +505,13 @@ digraph_add_edge(From, To, DG) ->
{To, _} -> ok
end,
digraph:add_edge(DG, {From, To}, From, To, []),
- DG.
+ ok.
digraph_confirm_vertices([MFA|Left], DG) ->
digraph:add_vertex(DG, MFA, confirmed),
digraph_confirm_vertices(Left, DG);
-digraph_confirm_vertices([], DG) ->
- DG.
+digraph_confirm_vertices([], _DG) ->
+ ok.
digraph_remove_external(DG) ->
Vertices = digraph:vertices(DG),
@@ -522,6 +535,12 @@ remove_unconfirmed([], DG, Unconfirmed) ->
digraph_delete(DG) ->
digraph:delete(DG).
+active_digraph_delete({'d', DG}) ->
+ digraph:delete(DG);
+active_digraph_delete({'e', Out, In}) ->
+ ets:delete(Out),
+ ets:delete(In).
+
digraph_edges(DG) ->
digraph:edges(DG).
@@ -534,75 +553,6 @@ digraph_in_neighbours(V, DG) ->
List -> List
end.
-%% Pick all the independent nodes (leaves) from one module. Then try
-%% to stay within the module until no more independent nodes can be
-%% chosen. Then pick a new module and so on.
-%%
-%% Note that an SCC that ranges over more than one module is
-%% considered to belong to all modules to make sure that we do not
-%% lose any nodes.
-
-digraph_postorder(Digraph) ->
- %% Remove all self-edges for SCCs.
- Edges = [digraph:edge(Digraph, E) || E <- digraph:edges(Digraph)],
- SelfEdges = [E || {E, V, V, _} <- Edges],
- true = digraph:del_edges(Digraph, SelfEdges),
- %% Determine the first module outside of the loop.
- Leaves = digraph_leaves(Digraph),
- case Leaves =:= [] of
- true -> [];
- false ->
- {Module, Taken} = take_sccs_from_fresh_module(Leaves),
- true = digraph:del_vertices(Digraph, Taken),
- digraph_postorder(Digraph, Module, [Taken])
- end.
-
-digraph_postorder(Digraph, LastModule, Acc) ->
- Leaves = digraph_leaves(Digraph),
- case Leaves =:= [] of
- true -> lists:append(lists:reverse(Acc));
- false ->
- case [SCC || SCC <- Leaves, scc_belongs_to_module(SCC, LastModule)] of
- [] ->
- {NewModule, NewTaken} = take_sccs_from_fresh_module(Leaves),
- true = digraph:del_vertices(Digraph, NewTaken),
- digraph_postorder(Digraph, NewModule, [NewTaken|Acc]);
- NewTaken ->
- true = digraph:del_vertices(Digraph, NewTaken),
- digraph_postorder(Digraph, LastModule, [NewTaken|Acc])
- end
- end.
-
-digraph_leaves(Digraph) ->
- [V || V <- digraph:vertices(Digraph), digraph:out_degree(Digraph, V) =:= 0].
-
-take_sccs_from_fresh_module(Leaves) ->
- NewModule = find_module(hd(Leaves)),
- {NewModule,
- [SCC || SCC <- Leaves, scc_belongs_to_module(SCC, NewModule)]}.
-
--spec scc_belongs_to_module(scc(), module()) -> boolean().
-
-scc_belongs_to_module([Label|Left], Module) when is_integer(Label) ->
- scc_belongs_to_module(Left, Module);
-scc_belongs_to_module([{M, _, _}|Left], Module) ->
- if M =:= Module -> true;
- true -> scc_belongs_to_module(Left, Module)
- end;
-scc_belongs_to_module([], _Module) ->
- false.
-
--spec find_module(scc()) -> module().
-
-find_module([{M, _, _}|_]) -> M;
-find_module([Label|Left]) when is_integer(Label) -> find_module(Left).
-
-digraph_finalize(DG) ->
- DG1 = digraph_utils:condensation(DG),
- Postorder = digraph_postorder(DG1),
- digraph:delete(DG1),
- Postorder.
-
digraph_reaching_subgraph(Funs, DG) ->
Vertices = digraph_utils:reaching(Funs, DG),
digraph_utils:subgraph(DG, Vertices).
@@ -611,20 +561,71 @@ digraph_reaching_subgraph(Funs, DG) ->
%% Races
%%----------------------------------------------------------------------
+-spec renew_race_info(callgraph(), dict(), [label()], [string()]) ->
+ callgraph().
+
+renew_race_info(#callgraph{race_data_server = RaceDataServer} = CG,
+ RaceCode, PublicTables, NamedTables) ->
+ ok = race_data_server_cast(
+ {renew_race_info, {RaceCode, PublicTables, NamedTables}},
+ RaceDataServer),
+ CG.
+
+renew_race_info({RaceCode, PublicTables, NamedTables},
+ #race_data_state{} = State) ->
+ State#race_data_state{race_code = RaceCode,
+ public_tables = PublicTables,
+ named_tables = NamedTables}.
+
+-spec renew_race_code(dialyzer_races:races(), callgraph()) -> callgraph().
+
+renew_race_code(Races, #callgraph{race_data_server = RaceDataServer} = CG) ->
+ Fun = dialyzer_races:get_curr_fun(Races),
+ FunArgs = dialyzer_races:get_curr_fun_args(Races),
+ Code = lists:reverse(dialyzer_races:get_race_list(Races)),
+ ok = race_data_server_cast(
+ {renew_race_code, {Fun, FunArgs, Code}},
+ RaceDataServer),
+ CG.
+
+renew_race_code_handler({Fun, FunArgs, Code},
+ #race_data_state{race_code = RaceCode} = State) ->
+ State#race_data_state{race_code = dict:store(Fun, [FunArgs, Code], RaceCode)}.
+
+-spec renew_race_public_tables(label(), callgraph()) -> callgraph().
+
+renew_race_public_tables(VarLabel,
+ #callgraph{race_data_server = RaceDataServer} = CG) ->
+ ok =
+ race_data_server_cast({renew_race_public_tables, VarLabel}, RaceDataServer),
+ CG.
+
+renew_race_public_tables_handler(VarLabel,
+ #race_data_state{public_tables = PT}
+ = State) ->
+ State#race_data_state{public_tables = ordsets:add_element(VarLabel, PT)}.
+
-spec cleanup(callgraph()) -> callgraph().
-cleanup(#callgraph{digraph = Digraph,
- name_map = NameMap,
- rev_name_map = RevNameMap,
- public_tables = PublicTables,
- named_tables = NamedTables,
- race_code = RaceCode}) ->
+cleanup(#callgraph{digraph = Digraph,
+ name_map = NameMap,
+ rev_name_map = RevNameMap,
+ race_data_server = RaceDataServer}) ->
#callgraph{digraph = Digraph,
- name_map = NameMap,
- rev_name_map = RevNameMap,
- public_tables = PublicTables,
- named_tables = NamedTables,
- race_code = RaceCode}.
+ name_map = NameMap,
+ rev_name_map = RevNameMap,
+ race_data_server = race_data_server_call(dup, RaceDataServer)}.
+
+-spec duplicate(callgraph()) -> callgraph().
+
+duplicate(#callgraph{race_data_server = RaceDataServer} = Callgraph) ->
+ Callgraph#callgraph{
+ race_data_server = race_data_server_call(dup, RaceDataServer)}.
+
+-spec dispose_race_server(callgraph()) -> ok.
+
+dispose_race_server(#callgraph{race_data_server = RaceDataServer}) ->
+ race_data_server_cast(stop, RaceDataServer).
-spec get_digraph(callgraph()) -> digraph().
@@ -633,28 +634,34 @@ get_digraph(#callgraph{digraph = Digraph}) ->
-spec get_named_tables(callgraph()) -> [string()].
-get_named_tables(#callgraph{named_tables = NamedTables}) ->
- NamedTables.
+get_named_tables(#callgraph{race_data_server = RaceDataServer}) ->
+ race_data_server_call(get_named_tables, RaceDataServer).
-spec get_public_tables(callgraph()) -> [label()].
-get_public_tables(#callgraph{public_tables = PT}) ->
- PT.
+get_public_tables(#callgraph{race_data_server = RaceDataServer}) ->
+ race_data_server_call(get_public_tables, RaceDataServer).
-spec get_race_code(callgraph()) -> dict().
-get_race_code(#callgraph{race_code = RaceCode}) ->
- RaceCode.
+get_race_code(#callgraph{race_data_server = RaceDataServer}) ->
+ race_data_server_call(get_race_code, RaceDataServer).
-spec get_race_detection(callgraph()) -> boolean().
get_race_detection(#callgraph{race_detection = RD}) ->
RD.
+-spec get_behaviour_api_calls(callgraph()) -> [{mfa(), mfa()}].
+
+get_behaviour_api_calls(#callgraph{race_data_server = RaceDataServer}) ->
+ race_data_server_call(get_behaviour_api_calls, RaceDataServer).
+
-spec race_code_new(callgraph()) -> callgraph().
-race_code_new(Callgraph) ->
- Callgraph#callgraph{race_code = dict:new()}.
+race_code_new(#callgraph{race_data_server = RaceDataServer} = CG) ->
+ ok = race_data_server_cast(race_code_new, RaceDataServer),
+ CG.
-spec put_digraph(digraph(), callgraph()) -> callgraph().
@@ -663,8 +670,9 @@ put_digraph(Digraph, Callgraph) ->
-spec put_race_code(dict(), callgraph()) -> callgraph().
-put_race_code(RaceCode, Callgraph) ->
- Callgraph#callgraph{race_code = RaceCode}.
+put_race_code(RaceCode, #callgraph{race_data_server = RaceDataServer} = CG) ->
+ ok = race_data_server_cast({put_race_code, RaceCode}, RaceDataServer),
+ CG.
-spec put_race_detection(boolean(), callgraph()) -> callgraph().
@@ -673,13 +681,79 @@ put_race_detection(RaceDetection, Callgraph) ->
-spec put_named_tables([string()], callgraph()) -> callgraph().
-put_named_tables(NamedTables, Callgraph) ->
- Callgraph#callgraph{named_tables = NamedTables}.
+put_named_tables(NamedTables,
+ #callgraph{race_data_server = RaceDataServer} = CG) ->
+ ok = race_data_server_cast({put_named_tables, NamedTables}, RaceDataServer),
+ CG.
-spec put_public_tables([label()], callgraph()) -> callgraph().
-put_public_tables(PublicTables, Callgraph) ->
- Callgraph#callgraph{public_tables = PublicTables}.
+put_public_tables(PublicTables,
+ #callgraph{race_data_server = RaceDataServer} = CG) ->
+ ok = race_data_server_cast({put_public_tables, PublicTables}, RaceDataServer),
+ CG.
+
+-spec put_behaviour_api_calls([{mfa(), mfa()}], callgraph()) -> callgraph().
+
+put_behaviour_api_calls(Calls,
+ #callgraph{race_data_server = RaceDataServer} = CG) ->
+ ok = race_data_server_cast({put_behaviour_api_calls, Calls}, RaceDataServer),
+ CG.
+
+
+new_race_data_server() ->
+ spawn_link(fun() -> race_data_server_loop(#race_data_state{}) end).
+
+race_data_server_loop(State) ->
+ receive
+ {call, From, Ref, Query} ->
+ Reply = race_data_server_handle_call(Query, State),
+ From ! {Ref, Reply},
+ race_data_server_loop(State);
+ {cast, stop} ->
+ ok;
+ {cast, Message} ->
+ NewState = race_data_server_handle_cast(Message, State),
+ race_data_server_loop(NewState)
+ end.
+
+race_data_server_call(Query, Server) ->
+ Ref = make_ref(),
+ Server ! {call, self(), Ref, Query},
+ receive
+ {Ref, Reply} -> Reply
+ end.
+
+race_data_server_cast(Message, Server) ->
+ Server ! {cast, Message},
+ ok.
+
+race_data_server_handle_cast(race_code_new, State) ->
+ State#race_data_state{race_code = dict:new()};
+race_data_server_handle_cast({Tag, Data}, State) ->
+ case Tag of
+ renew_race_info -> renew_race_info(Data, State);
+ renew_race_code -> renew_race_code_handler(Data, State);
+ renew_race_public_tables -> renew_race_public_tables_handler(Data, State);
+ put_race_code -> State#race_data_state{race_code = Data};
+ put_public_tables -> State#race_data_state{public_tables = Data};
+ put_named_tables -> State#race_data_state{named_tables = Data};
+ put_behaviour_api_calls -> State#race_data_state{beh_api_calls = Data}
+ end.
+
+race_data_server_handle_call(Query,
+ #race_data_state{race_code = RaceCode,
+ public_tables = PublicTables,
+ named_tables = NamedTables,
+ beh_api_calls = BehApiCalls}
+ = State) ->
+ case Query of
+ dup -> spawn_link(fun() -> race_data_server_loop(State) end);
+ get_race_code -> RaceCode;
+ get_public_tables -> PublicTables;
+ get_named_tables -> NamedTables;
+ get_behaviour_api_calls -> BehApiCalls
+ end.
%%=============================================================================
%% Utilities for 'dot'
@@ -695,7 +769,7 @@ to_dot(#callgraph{digraph = DG, esc = Esc} = CG, File) ->
end
end,
Escaping = [{Fun(L), {color, red}}
- || L <- sets:to_list(Esc), L =/= external],
+ || L <- [E || {E} <- ets:tab2list(Esc)], L =/= external],
Vertices = digraph_edges(DG),
hipe_dot:translate_list(Vertices, File, "CG", Escaping).
@@ -708,14 +782,41 @@ to_ps(#callgraph{} = CG, File, Args) ->
_ = os:cmd(Command),
ok.
-%-------------------------------------------------------------------------------
-
--spec put_behaviour_api_calls([{mfa(), mfa()}], callgraph()) -> callgraph().
-
-put_behaviour_api_calls(Calls, Callgraph) ->
- Callgraph#callgraph{beh_api_calls = Calls}.
-
--spec get_behaviour_api_calls(callgraph()) -> [{mfa(), mfa()}].
-
-get_behaviour_api_calls(Callgraph) ->
- Callgraph#callgraph.beh_api_calls.
+condensation(G) ->
+ SCs = digraph_utils:strong_components(G),
+ V2I = ets:new(condensation_v2i, []),
+ I2C = ets:new(condensation_i2c, []),
+ I2I = ets:new(condensation_i2i, [bag]),
+ CFun =
+ fun(SC, N) ->
+ lists:foreach(fun(V) -> true = ets:insert(V2I, {V,N}) end, SC),
+ true = ets:insert(I2C, {N, SC}),
+ N + 1
+ end,
+ lists:foldl(CFun, 1, SCs),
+ Fun1 =
+ fun({V1, V2}) ->
+ I1 = ets:lookup_element(V2I, V1, 2),
+ I2 = ets:lookup_element(V2I, V2, 2),
+ case I1 =:= I2 of
+ true -> true;
+ false -> ets:insert(I2I, {I1, I2})
+ end
+ end,
+ lists:foreach(Fun1, digraph:edges(G)),
+ Fun3 =
+ fun({I1, I2}, {Out, In}) ->
+ SC1 = ets:lookup_element(I2C, I1, 2),
+ SC2 = ets:lookup_element(I2C, I2, 2),
+ {dict:append(SC1, SC2, Out), dict:append(SC2, SC1, In)}
+ end,
+ {OutDict, InDict} = ets:foldl(Fun3, {dict:new(), dict:new()}, I2I),
+ [OutETS, InETS] =
+ [ets:new(Name,[{read_concurrency, true}]) ||
+ Name <- [callgraph_deps_out, callgraph_deps_in]],
+ ets:insert(OutETS, dict:to_list(OutDict)),
+ ets:insert(InETS, dict:to_list(InDict)),
+ ets:delete(V2I),
+ ets:delete(I2C),
+ ets:delete(I2I),
+ {{'e', OutETS, InETS}, SCs}.
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index 04a0db890f..6732d96b98 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -2,7 +2,7 @@
%%-------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. 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
@@ -188,6 +188,7 @@ plt_common(#options{init_plts = [InitPlt]} = Opts, RemoveFiles, AddFiles) ->
ok ->
case Opts#options.output_plt of
none -> ok;
+ InitPlt -> ok;
OutPlt ->
{ok, Binary} = file:read_file(InitPlt),
ok = file:write_file(OutPlt, Binary)
@@ -393,10 +394,12 @@ do_analysis(Files, Options, Plt, PltInfo) ->
defines = Options#options.defines,
include_dirs = Options#options.include_dirs,
files = Files,
- start_from = Options#options.from,
+ start_from = Options#options.from,
+ timing = Options#options.timing,
plt = Plt,
use_contracts = Options#options.use_contracts,
- callgraph_file = Options#options.callgraph_file},
+ callgraph_file = Options#options.callgraph_file,
+ solvers = Options#options.solvers},
State3 = start_analysis(State2, InitAnalysis),
{T1, _} = statistics(wall_clock),
Return = cl_loop(State3),
diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl
index ff8fc39a5e..2ea3d3af5a 100644
--- a/lib/dialyzer/src/dialyzer_cl_parse.erl
+++ b/lib/dialyzer/src/dialyzer_cl_parse.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. 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
@@ -164,6 +164,13 @@ cl(["--src"|T]) ->
cl(["--no_spec"|T]) ->
put(dialyzer_options_use_contracts, false),
cl(T);
+cl(["--statistics"|T]) ->
+ put(dialyzer_timing, true),
+ cl(T);
+cl(["--resources"|T]) ->
+ put(dialyzer_options_report_mode, quiet),
+ put(dialyzer_timing, debug),
+ cl(T);
cl(["-v"|_]) ->
io:format("Dialyzer version "++?VSN++"\n"),
erlang:halt(?RET_NOTHING_SUSPICIOUS);
@@ -191,6 +198,9 @@ cl(["--gui"|T]) ->
cl(["--wx"|T]) ->
put(dialyzer_options_mode, {gui, wx}),
cl(T);
+cl(["--solver",Solver|T]) -> % not documented
+ append_var(dialyzer_solvers, [list_to_atom(Solver)]),
+ cl(T);
cl([H|_] = L) ->
case filelib:is_file(H) orelse filelib:is_dir(H) of
true ->
@@ -250,6 +260,8 @@ init() ->
put(dialyzer_output_format, formatted),
put(dialyzer_filename_opt, basename),
put(dialyzer_options_check_plt, DefaultOpts#options.check_plt),
+ put(dialyzer_timing, DefaultOpts#options.timing),
+ put(dialyzer_solvers, DefaultOpts#options.solvers),
ok.
append_defines([Def, Val]) ->
@@ -290,6 +302,7 @@ cl_options() ->
{filename_opt, get(dialyzer_filename_opt)},
{analysis_type, get(dialyzer_options_analysis_type)},
{get_warnings, get(dialyzer_options_get_warnings)},
+ {timing, get(dialyzer_timing)},
{callgraph_file, get(dialyzer_callgraph_file)}
|common_options()].
@@ -302,7 +315,8 @@ common_options() ->
{report_mode, get(dialyzer_options_report_mode)},
{use_spec, get(dialyzer_options_use_contracts)},
{warnings, get(dialyzer_warnings)},
- {check_plt, get(dialyzer_options_check_plt)}].
+ {check_plt, get(dialyzer_options_check_plt)},
+ {solvers, get(dialyzer_solvers)}].
%%-----------------------------------------------------------------------
@@ -351,7 +365,7 @@ help_message() ->
[--apps applications] [-o outfile]
[--build_plt] [--add_to_plt] [--remove_from_plt]
[--check_plt] [--no_check_plt] [--plt_info] [--get_warnings]
- [--no_native] [--fullpath]
+ [--no_native] [--fullpath] [--statistics]
Options:
files_or_dirs (for backwards compatibility also as: -c files_or_dirs)
Use Dialyzer from the command line to detect defects in the
@@ -418,6 +432,9 @@ Options:
Make Dialyzer a bit more quiet.
--verbose
Make Dialyzer a bit more verbose.
+ --statistics
+ Prints information about the progress of execution (analysis phases,
+ time spent in each and size of the relative input).
--build_plt
The analysis starts from an empty plt and creates a new one from the
files specified with -c and -r. Only works for beam files.
diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl
index f1e87affbd..9989118671 100644
--- a/lib/dialyzer/src/dialyzer_codeserver.erl
+++ b/lib/dialyzer/src/dialyzer_codeserver.erl
@@ -52,9 +52,7 @@
new/0,
set_next_core_label/2,
set_temp_records/2,
- store_records/3,
store_temp_records/3,
- store_contracts/3,
store_temp_contracts/4]).
-export_type([codeserver/0]).
@@ -63,85 +61,159 @@
%%--------------------------------------------------------------------
--record(codeserver, {table_pid :: pid(),
- exported_types = sets:new() :: set(), % set(mfa())
- temp_exported_types = sets:new() :: set(), % set(mfa())
- exports = sets:new() :: set(), % set(mfa())
- next_core_label = 0 :: label(),
- records = dict:new() :: dict(),
- temp_records = dict:new() :: dict(),
- contracts = dict:new() :: dict(),
- callbacks = dict:new() :: dict(),
- temp_contracts = dict:new() :: dict(),
- temp_callbacks = dict:new() :: dict()
+-type dict_ets() :: ets:tid().
+-type set_ets() :: ets:tid().
+
+-record(codeserver, {next_core_label = 0 :: label(),
+ code :: dict_ets(),
+ exported_types :: set_ets(), % set(mfa())
+ records :: dict_ets(),
+ contracts :: dict_ets(),
+ callbacks :: dict_ets(),
+ exports :: 'clean' | set_ets(), % set(mfa())
+ temp_exported_types :: 'clean' | set_ets(), % set(mfa())
+ temp_records :: 'clean' | dict_ets(),
+ temp_contracts :: 'clean' | dict_ets(),
+ temp_callbacks :: 'clean' | dict_ets()
}).
-opaque codeserver() :: #codeserver{}.
%%--------------------------------------------------------------------
+ets_dict_find(Key, Table) ->
+ try ets:lookup_element(Table, Key, 2) of
+ Val -> {ok, Val}
+ catch
+ _:_ -> error
+ end.
+
+ets_dict_store(Key, Element, Table) ->
+ true = ets:insert(Table, {Key, Element}),
+ Table.
+
+ets_dict_store_dict(Dict, Table) ->
+ true = ets:insert(Table, dict:to_list(Dict)).
+
+ets_dict_to_dict(Table) ->
+ Fold = fun({Key,Value}, Dict) -> dict:store(Key, Value, Dict) end,
+ ets:foldl(Fold, dict:new(), Table).
+
+ets_set_is_element(Key, Table) ->
+ case ets:lookup(Table, Key) of
+ [] -> false;
+ _ -> true
+ end.
+
+ets_set_insert_set(Set, Table) ->
+ ets_set_insert_list(sets:to_list(Set), Table).
+
+ets_set_insert_list(List, Table) ->
+ true = ets:insert(Table, [{E} || E <- List]).
+
+ets_set_to_set(Table) ->
+ Fold = fun({E}, Set) -> sets:add_element(E, Set) end,
+ ets:foldl(Fold, sets:new(), Table).
+
+ets_read_concurrent_table(Name) ->
+ ets:new(Name,[{read_concurrency, true}]).
+
+%%--------------------------------------------------------------------
+
-spec new() -> codeserver().
new() ->
- #codeserver{table_pid = table__new()}.
+ CodeOptions = [compressed, public, {read_concurrency, true}],
+ Code = ets:new(dialyzer_codeserver_code, CodeOptions),
+ TempOptions = [public, {write_concurrency, true}],
+ [Exports, TempExportedTypes, TempRecords, TempContracts, TempCallbacks] =
+ [ets:new(Name, TempOptions) ||
+ Name <-
+ [dialyzer_codeserver_exports, dialyzer_codeserver_temp_exported_types,
+ dialyzer_codeserver_temp_records, dialyzer_codeserver_temp_contracts,
+ dialyzer_codeserver_temp_callbacks]],
+ #codeserver{code = Code,
+ exports = Exports,
+ temp_exported_types = TempExportedTypes,
+ temp_records = TempRecords,
+ temp_contracts = TempContracts,
+ temp_callbacks = TempCallbacks}.
-spec delete(codeserver()) -> 'ok'.
-delete(#codeserver{table_pid = TablePid}) ->
- table__delete(TablePid).
+delete(#codeserver{code = Code, exported_types = ExportedTypes,
+ records = Records, contracts = Contracts,
+ callbacks = Callbacks}) ->
+ lists:foreach(fun ets:delete/1,
+ [Code, ExportedTypes, Records, Contracts, Callbacks]).
-spec insert(atom(), cerl:c_module(), codeserver()) -> codeserver().
insert(Mod, ModCode, CS) ->
- NewTablePid = table__insert(CS#codeserver.table_pid, Mod, ModCode),
- CS#codeserver{table_pid = NewTablePid}.
+ Name = cerl:module_name(ModCode),
+ Exports = cerl:module_exports(ModCode),
+ Attrs = cerl:module_attrs(ModCode),
+ Defs = cerl:module_defs(ModCode),
+ As = cerl:get_ann(ModCode),
+ Funs =
+ [{{Mod, cerl:fname_id(Var), cerl:fname_arity(Var)},
+ Val} || Val = {Var, _Fun} <- Defs],
+ Keys = [Key || {Key, _Value} <- Funs],
+ ModEntry = {Mod, {Name, Exports, Attrs, Keys, As}},
+ true = ets:insert(CS#codeserver.code, [ModEntry|Funs]),
+ CS.
+
+-spec get_temp_exported_types(codeserver()) -> set().
+
+get_temp_exported_types(#codeserver{temp_exported_types = TempExpTypes}) ->
+ ets_set_to_set(TempExpTypes).
-spec insert_temp_exported_types(set(), codeserver()) -> codeserver().
insert_temp_exported_types(Set, CS) ->
- CS#codeserver{temp_exported_types = Set}.
+ TempExportedTypes = CS#codeserver.temp_exported_types,
+ true = ets_set_insert_set(Set, TempExportedTypes),
+ CS.
-spec insert_exports([mfa()], codeserver()) -> codeserver().
insert_exports(List, #codeserver{exports = Exports} = CS) ->
- Set = sets:from_list(List),
- NewExports = sets:union(Exports, Set),
- CS#codeserver{exports = NewExports}.
+ true = ets_set_insert_list(List, Exports),
+ CS.
-spec is_exported(mfa(), codeserver()) -> boolean().
is_exported(MFA, #codeserver{exports = Exports}) ->
- sets:is_element(MFA, Exports).
+ ets_set_is_element(MFA, Exports).
-spec get_exported_types(codeserver()) -> set(). % set(mfa())
get_exported_types(#codeserver{exported_types = ExpTypes}) ->
- ExpTypes.
-
--spec get_temp_exported_types(codeserver()) -> set().
-
-get_temp_exported_types(#codeserver{temp_exported_types = TempExpTypes}) ->
- TempExpTypes.
+ ets_set_to_set(ExpTypes).
-spec get_exports(codeserver()) -> set(). % set(mfa())
get_exports(#codeserver{exports = Exports}) ->
- Exports.
+ ets_set_to_set(Exports).
-spec finalize_exported_types(set(), codeserver()) -> codeserver().
finalize_exported_types(Set, CS) ->
- CS#codeserver{exported_types = Set, temp_exported_types = sets:new()}.
+ ExportedTypes = ets_read_concurrent_table(dialyzer_codeserver_exported_types),
+ true = ets_set_insert_set(Set, ExportedTypes),
+ TempExpTypes = CS#codeserver.temp_exported_types,
+ true = ets:delete(TempExpTypes),
+ CS#codeserver{exported_types = ExportedTypes, temp_exported_types = clean}.
-spec lookup_mod_code(atom(), codeserver()) -> cerl:c_module().
lookup_mod_code(Mod, CS) when is_atom(Mod) ->
- table__lookup(CS#codeserver.table_pid, Mod).
+ table__lookup(CS#codeserver.code, Mod).
-spec lookup_mfa_code(mfa(), codeserver()) -> {cerl:c_var(), cerl:c_fun()}.
lookup_mfa_code({_M, _F, _A} = MFA, CS) ->
- table__lookup(CS#codeserver.table_pid, MFA).
+ table__lookup(CS#codeserver.code, MFA).
-spec get_next_core_label(codeserver()) -> label().
@@ -153,20 +225,10 @@ get_next_core_label(#codeserver{next_core_label = NCL}) ->
set_next_core_label(NCL, CS) ->
CS#codeserver{next_core_label = NCL}.
--spec store_records(atom(), dict(), codeserver()) -> codeserver().
-
-store_records(Mod, Dict, #codeserver{records = RecDict} = CS)
- when is_atom(Mod) ->
- case dict:size(Dict) =:= 0 of
- true -> CS;
- false -> CS#codeserver{records = dict:store(Mod, Dict, RecDict)}
- end.
-
-spec lookup_mod_records(atom(), codeserver()) -> dict().
-lookup_mod_records(Mod, #codeserver{records = RecDict})
- when is_atom(Mod) ->
- case dict:find(Mod, RecDict) of
+lookup_mod_records(Mod, #codeserver{records = RecDict}) when is_atom(Mod) ->
+ case ets_dict_find(Mod, RecDict) of
error -> dict:new();
{ok, Dict} -> Dict
end.
@@ -174,7 +236,7 @@ lookup_mod_records(Mod, #codeserver{records = RecDict})
-spec get_records(codeserver()) -> dict().
get_records(#codeserver{records = RecDict}) ->
- RecDict.
+ ets_dict_to_dict(RecDict).
-spec store_temp_records(atom(), dict(), codeserver()) -> codeserver().
@@ -182,59 +244,58 @@ store_temp_records(Mod, Dict, #codeserver{temp_records = TempRecDict} = CS)
when is_atom(Mod) ->
case dict:size(Dict) =:= 0 of
true -> CS;
- false -> CS#codeserver{temp_records = dict:store(Mod, Dict, TempRecDict)}
+ false -> CS#codeserver{temp_records = ets_dict_store(Mod, Dict, TempRecDict)}
end.
-spec get_temp_records(codeserver()) -> dict().
get_temp_records(#codeserver{temp_records = TempRecDict}) ->
- TempRecDict.
+ ets_dict_to_dict(TempRecDict).
-spec set_temp_records(dict(), codeserver()) -> codeserver().
set_temp_records(Dict, CS) ->
- CS#codeserver{temp_records = Dict}.
+ true = ets:delete(CS#codeserver.temp_records),
+ TempRecords = ets:new(dialyzer_codeserver_temp_records,[]),
+ true = ets_dict_store_dict(Dict, TempRecords),
+ CS#codeserver{temp_records = TempRecords}.
-spec finalize_records(dict(), codeserver()) -> codeserver().
finalize_records(Dict, CS) ->
- CS#codeserver{records = Dict, temp_records = dict:new()}.
-
--spec store_contracts(atom(), dict(), codeserver()) -> codeserver().
-
-store_contracts(Mod, Dict, #codeserver{contracts = C} = CS) when is_atom(Mod) ->
- case dict:size(Dict) =:= 0 of
- true -> CS;
- false -> CS#codeserver{contracts = dict:store(Mod, Dict, C)}
- end.
+ true = ets:delete(CS#codeserver.temp_records),
+ Records = ets_read_concurrent_table(dialyzer_codeserver_records),
+ true = ets_dict_store_dict(Dict, Records),
+ CS#codeserver{records = Records, temp_records = clean}.
-spec lookup_mod_contracts(atom(), codeserver()) -> dict().
lookup_mod_contracts(Mod, #codeserver{contracts = ContDict})
when is_atom(Mod) ->
- case dict:find(Mod, ContDict) of
+ case ets_dict_find(Mod, ContDict) of
error -> dict:new();
- {ok, Dict} -> Dict
+ {ok, Keys} ->
+ dict:from_list([get_contract_pair(Key, ContDict)|| Key <- Keys])
end.
+get_contract_pair(Key, ContDict) ->
+ {Key, ets:lookup_element(ContDict, Key, 2)}.
+
-spec lookup_mfa_contract(mfa(), codeserver()) ->
'error' | {'ok', dialyzer_contracts:file_contract()}.
-lookup_mfa_contract({M,_F,_A} = MFA, #codeserver{contracts = ContDict}) ->
- case dict:find(M, ContDict) of
- error -> error;
- {ok, Dict} -> dict:find(MFA, Dict)
- end.
+lookup_mfa_contract(MFA, #codeserver{contracts = ContDict}) ->
+ ets_dict_find(MFA, ContDict).
-spec get_contracts(codeserver()) -> dict().
get_contracts(#codeserver{contracts = ContDict}) ->
- ContDict.
+ ets_dict_to_dict(ContDict).
--spec get_callbacks(codeserver()) -> dict().
+-spec get_callbacks(codeserver()) -> list().
get_callbacks(#codeserver{callbacks = CallbDict}) ->
- CallbDict.
+ ets:tab2list(CallbDict).
-spec store_temp_contracts(atom(), dict(), dict(), codeserver()) ->
codeserver().
@@ -246,91 +307,44 @@ store_temp_contracts(Mod, SpecDict, CallbackDict,
CS1 =
case dict:size(SpecDict) =:= 0 of
true -> CS;
- false -> CS#codeserver{temp_contracts = dict:store(Mod, SpecDict, Cn)}
+ false ->
+ CS#codeserver{temp_contracts = ets_dict_store(Mod, SpecDict, Cn)}
end,
case dict:size(CallbackDict) =:= 0 of
true -> CS1;
- false -> CS1#codeserver{temp_callbacks = dict:store(Mod, CallbackDict, Cb)}
+ false ->
+ CS1#codeserver{temp_callbacks = ets_dict_store(Mod, CallbackDict, Cb)}
end.
-spec get_temp_contracts(codeserver()) -> {dict(), dict()}.
get_temp_contracts(#codeserver{temp_contracts = TempContDict,
temp_callbacks = TempCallDict}) ->
- {TempContDict, TempCallDict}.
+ {ets_dict_to_dict(TempContDict), ets_dict_to_dict(TempCallDict)}.
-spec finalize_contracts(dict(), dict(), codeserver()) -> codeserver().
-finalize_contracts(CnDict, CbDict, CS) ->
- CS#codeserver{contracts = CnDict,
- callbacks = CbDict,
- temp_contracts = dict:new(),
- temp_callbacks = dict:new()
- }.
-
-table__new() ->
- spawn_link(fun() -> table__loop(none, dict:new()) end).
-
-table__delete(TablePid) ->
- TablePid ! stop,
- ok.
-
-table__lookup(TablePid, Key) ->
- TablePid ! {self(), lookup, Key},
- receive
- {TablePid, Key, Ans} -> Ans
- end.
-
-table__insert(TablePid, Key, Val) ->
- TablePid ! {insert, [{Key, term_to_binary(Val, [compressed])}]},
- TablePid.
-
-table__loop(Cached, Map) ->
- receive
- stop -> ok;
- {Pid, lookup, {M, F, A} = MFA} ->
- {NewCached, Ans} =
- case Cached of
- {M, Tree} ->
- Val = find_fun(F, A, Tree),
- {Cached, Val};
- _ ->
- Tree = fetch_and_expand(M, Map),
- Val = find_fun(F, A, Tree),
- {{M, Tree}, Val}
- end,
- Pid ! {self(), MFA, Ans},
- table__loop(NewCached, Map);
- {Pid, lookup, Mod} when is_atom(Mod) ->
- Ans = case Cached of
- {Mod, Tree} -> Tree;
- _ -> fetch_and_expand(Mod, Map)
- end,
- Pid ! {self(), Mod, Ans},
- table__loop({Mod, Ans}, Map);
- {insert, List} ->
- NewMap = lists:foldl(fun({Key, Val}, AccMap) ->
- dict:store(Key, Val, AccMap)
- end, Map, List),
- table__loop(Cached, NewMap)
- end.
-
-fetch_and_expand(Mod, Map) ->
- try
- Bin = dict:fetch(Mod, Map),
- binary_to_term(Bin)
- catch
- _:_ ->
- S = atom_to_list(Mod),
- Msg = "found no module named '" ++ S ++ "' in the analyzed files",
- exit({error, Msg})
- end.
-
-find_fun(F, A, Tree) ->
- Pred =
- fun({Var, _Fun}) ->
- (cerl:fname_id(Var) =/= F) orelse
- (cerl:fname_arity(Var) =/= A)
- end,
- [Val|_] = lists:dropwhile(Pred, cerl:module_defs(Tree)),
- Val.
+finalize_contracts(SpecDict, CallbackDict, CS) ->
+ Contracts = ets_read_concurrent_table(dialyzer_codeserver_contracts),
+ Callbacks = ets_read_concurrent_table(dialyzer_codeserver_callbacks),
+ Contracts = dict:fold(fun decompose_spec_dict/3, Contracts, SpecDict),
+ Callbacks = dict:fold(fun decompose_cb_dict/3, Callbacks, CallbackDict),
+ CS#codeserver{contracts = Contracts, callbacks = Callbacks,
+ temp_contracts = clean, temp_callbacks = clean}.
+
+decompose_spec_dict(Mod, Dict, Table) ->
+ Keys = dict:fetch_keys(Dict),
+ true = ets:insert(Table, dict:to_list(Dict)),
+ true = ets:insert(Table, {Mod, Keys}),
+ Table.
+
+decompose_cb_dict(_Mod, Dict, Table) ->
+ true = ets:insert(Table, dict:to_list(Dict)),
+ Table.
+
+table__lookup(TablePid, M) when is_atom(M) ->
+ {Name, Exports, Attrs, Keys, As} = ets:lookup_element(TablePid, M, 2),
+ Defs = [table__lookup(TablePid, Key) || Key <- Keys],
+ cerl:ann_c_module(As, Name, Exports, Attrs, Defs);
+table__lookup(TablePid, MFA) ->
+ ets:lookup_element(TablePid, MFA, 2).
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index 2b78b736ab..76f23d00b9 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -344,7 +344,7 @@ insert_constraints([{subtype, Type1, Type2}|Left], Dict) ->
false ->
%% A lot of things should change to add supertypes
throw({error, io_lib:format("First argument of is_subtype constraint "
- "must be a type variable\n", [])})
+ "must be a type variable: ~p\n", [Type1])})
end;
insert_constraints([], Dict) -> Dict.
@@ -385,9 +385,8 @@ contract_from_form([{type, _L1, bounded_fun,
RecDict, FileLine, TypeAcc, FormAcc) ->
TypeFun =
fun(ExpTypes, AllRecords) ->
- Constr1 = [constraint_from_form(C, RecDict, ExpTypes, AllRecords)
- || C <- Constr],
- VarDict = insert_constraints(Constr1, dict:new()),
+ {Constr1, VarDict} =
+ process_constraints(Constr, RecDict, ExpTypes, AllRecords),
Type = erl_types:t_from_form(Form, RecDict, VarDict),
NewType = erl_types:t_solve_remote(Type, ExpTypes, AllRecords),
{NewType, Constr1}
@@ -398,18 +397,66 @@ contract_from_form([{type, _L1, bounded_fun,
contract_from_form([], _RecDict, _FileLine, TypeAcc, FormAcc) ->
{lists:reverse(TypeAcc), lists:reverse(FormAcc)}.
-constraint_from_form({type, _, constraint, [{atom, _, is_subtype},
- [Type1, Type2]]}, RecDict,
- ExpTypes, AllRecords) ->
- T1 = erl_types:t_from_form(Type1, RecDict),
- T2 = erl_types:t_from_form(Type2, RecDict),
- T3 = erl_types:t_solve_remote(T1, ExpTypes, AllRecords),
- T4 = erl_types:t_solve_remote(T2, ExpTypes, AllRecords),
- {subtype, T3, T4};
-constraint_from_form({type, _, constraint, [{atom,_,Name}, List]}, _RecDict,
- _ExpTypes, _AllRecords) ->
- N = length(List),
- throw({error, io_lib:format("Unsupported type guard ~w/~w\n", [Name, N])}).
+process_constraints(Constrs, RecDict, ExpTypes, AllRecords) ->
+ Init = initialize_constraints(Constrs, RecDict, ExpTypes, AllRecords),
+ constraints_fixpoint(Init, RecDict, ExpTypes, AllRecords).
+
+initialize_constraints(Constrs, RecDict, ExpTypes, AllRecords) ->
+ initialize_constraints(Constrs, RecDict, ExpTypes, AllRecords, []).
+
+initialize_constraints([], _RecDict, _ExpTypes, _AllRecords, Acc) ->
+ Acc;
+initialize_constraints([Constr|Rest], RecDict, ExpTypes, AllRecords, Acc) ->
+ case Constr of
+ {type, _, constraint, [{atom, _, is_subtype}, [Type1, Type2]]} ->
+ T1 = final_form(Type1, RecDict, ExpTypes, AllRecords, dict:new()),
+ Entry = {T1, Type2},
+ initialize_constraints(Rest, RecDict, ExpTypes, AllRecords, [Entry|Acc]);
+ {type, _, constraint, [{atom,_,Name}, List]} ->
+ N = length(List),
+ throw({error,
+ io_lib:format("Unsupported type guard ~w/~w\n", [Name, N])})
+ end.
+
+constraints_fixpoint(Constrs, RecDict, ExpTypes, AllRecords) ->
+ VarDict =
+ constraints_to_dict(Constrs, RecDict, ExpTypes, AllRecords, dict:new()),
+ constraints_fixpoint(VarDict, Constrs, RecDict, ExpTypes, AllRecords).
+
+constraints_fixpoint(OldVarDict, Constrs, RecDict, ExpTypes, AllRecords) ->
+ NewVarDict =
+ constraints_to_dict(Constrs, RecDict, ExpTypes, AllRecords, OldVarDict),
+ case NewVarDict of
+ OldVarDict ->
+ DictFold =
+ fun(Key, Value, Acc) ->
+ [{subtype, erl_types:t_var(Key), Value}|Acc]
+ end,
+ FinalConstrs = dict:fold(DictFold, [], NewVarDict),
+ {FinalConstrs, NewVarDict};
+ _Other ->
+ constraints_fixpoint(NewVarDict, Constrs, RecDict, ExpTypes, AllRecords)
+ end.
+
+-define(TYPE_LIMIT, 4).
+
+final_form(Form, RecDict, ExpTypes, AllRecords, VarDict) ->
+ T1 = erl_types:t_from_form(Form, RecDict, VarDict),
+ T2 = erl_types:t_solve_remote(T1, ExpTypes, AllRecords),
+ erl_types:t_limit(T2, ?TYPE_LIMIT).
+
+constraints_to_dict(Constrs, RecDict, ExpTypes, AllRecords, VarDict) ->
+ Subtypes =
+ constraints_to_subs(Constrs, RecDict, ExpTypes, AllRecords, VarDict, []),
+ insert_constraints(Subtypes, dict:new()).
+
+constraints_to_subs([], _RecDict, _ExpTypes, _AllRecords, _VarDict, Acc) ->
+ Acc;
+constraints_to_subs([C|Rest], RecDict, ExpTypes, AllRecords, VarDict, Acc) ->
+ {T1, Form2} = C,
+ T2 = final_form(Form2, RecDict, ExpTypes, AllRecords, VarDict),
+ NewAcc = [{subtype, T1, T2}|Acc],
+ constraints_to_subs(Rest, RecDict, ExpTypes, AllRecords, VarDict, NewAcc).
%% Gets the most general domain of a list of domains of all
%% the overloaded contracts
diff --git a/lib/dialyzer/src/dialyzer_coordinator.erl b/lib/dialyzer/src/dialyzer_coordinator.erl
new file mode 100644
index 0000000000..5719132215
--- /dev/null
+++ b/lib/dialyzer/src/dialyzer_coordinator.erl
@@ -0,0 +1,250 @@
+%% -*- erlang-indent-level: 2 -*-
+%%-----------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : dialyzer_coordinator.erl
+%%% Authors : Stavros Aronis <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(dialyzer_coordinator).
+
+%%% Export for dialyzer main process
+-export([parallel_job/4]).
+
+%%% Exports for all possible workers
+-export([wait_activation/0, job_done/3]).
+
+%%% Exports for the typesig and dataflow analysis workers
+-export([sccs_to_pids/2, request_activation/1]).
+
+%%% Exports for the compilation workers
+-export([get_next_label/2]).
+
+-export_type([coordinator/0, mode/0, init_data/0, result/0]).
+
+%%--------------------------------------------------------------------
+
+-type collector() :: pid().
+-type regulator() :: pid().
+-type scc_to_pid() :: ets:tid() | 'unused'.
+
+-type coordinator() :: {collector(), regulator(), scc_to_pid()}. %%opaque
+-type timing() :: dialyzer_timing:timing_server().
+
+-type scc() :: [mfa_or_funlbl()].
+-type mode() :: 'typesig' | 'dataflow' | 'compile' | 'warnings'.
+
+-type compile_jobs() :: [file:filename()].
+-type typesig_jobs() :: [scc()].
+-type dataflow_jobs() :: [module()].
+-type warnings_jobs() :: [module()].
+
+-type compile_init_data() :: dialyzer_analysis_callgraph:compile_init_data().
+-type typesig_init_data() :: dialyzer_succ_typings:typesig_init_data().
+-type dataflow_init_data() :: dialyzer_succ_typings:dataflow_init_data().
+-type warnings_init_data() :: dialyzer_succ_typings:warnings_init_data().
+
+-type compile_result() :: dialyzer_analysis_callgraph:compile_result().
+-type typesig_result() :: [mfa_or_funlbl()].
+-type dataflow_result() :: [mfa_or_funlbl()].
+-type warnings_result() :: [dial_warning()].
+
+-type init_data() :: compile_init_data() | typesig_init_data() |
+ dataflow_init_data() | warnings_init_data().
+
+-type result() :: compile_result() | typesig_result() |
+ dataflow_result() | warnings_result().
+
+-type job() :: scc() | module() | file:filename().
+-type job_result() :: dialyzer_analysis_callgraph:one_file_result() |
+ typesig_result() | dataflow_result() | warnings_result().
+
+-record(state, {mode :: mode(),
+ active = 0 :: integer(),
+ result :: result(),
+ next_label = 0 :: integer(),
+ init_data :: init_data(),
+ regulator :: regulator(),
+ scc_to_pid :: scc_to_pid()
+ }).
+
+-include("dialyzer.hrl").
+
+%%--------------------------------------------------------------------
+
+-spec parallel_job('compile', compile_jobs(), compile_init_data(), timing()) ->
+ {compile_result(), integer()};
+ ('typesig', typesig_jobs(), typesig_init_data(), timing()) ->
+ typesig_result();
+ ('dataflow', dataflow_jobs(), dataflow_init_data(),
+ timing()) -> dataflow_result();
+ ('warnings', warnings_jobs(), warnings_init_data(),
+ timing()) -> warnings_result().
+
+parallel_job(Mode, Jobs, InitData, Timing) ->
+ State = spawn_jobs(Mode, Jobs, InitData, Timing),
+ collect_result(State).
+
+spawn_jobs(Mode, Jobs, InitData, Timing) ->
+ Collector = self(),
+ Regulator = spawn_regulator(),
+ TypesigOrDataflow = (Mode =:= 'typesig') orelse (Mode =:= 'dataflow'),
+ SCCtoPID =
+ case TypesigOrDataflow of
+ true -> ets:new(scc_to_pid, [{read_concurrency, true}]);
+ false -> unused
+ end,
+ Coordinator = {Collector, Regulator, SCCtoPID},
+ Fold =
+ fun(Job, Count) ->
+ Pid = dialyzer_worker:launch(Mode, Job, InitData, Coordinator),
+ case TypesigOrDataflow of
+ true -> true = ets:insert(SCCtoPID, {Job, Pid});
+ false -> request_activation(Regulator, Pid)
+ end,
+ Count + 1
+ end,
+ JobCount = lists:foldl(Fold, 0, Jobs),
+ Unit =
+ case Mode of
+ 'typesig' -> "SCCs";
+ _ -> "modules"
+ end,
+ dialyzer_timing:send_size_info(Timing, JobCount, Unit),
+ InitResult =
+ case Mode of
+ 'compile' -> dialyzer_analysis_callgraph:compile_init_result();
+ _ -> []
+ end,
+ #state{mode = Mode, active = JobCount, result = InitResult, next_label = 0,
+ init_data = InitData, regulator = Regulator, scc_to_pid = SCCtoPID}.
+
+collect_result(#state{mode = Mode, active = Active, result = Result,
+ next_label = NextLabel, init_data = InitData,
+ regulator = Regulator, scc_to_pid = SCCtoPID} = State) ->
+ receive
+ {next_label_request, Estimation, Pid} ->
+ Pid ! {next_label_reply, NextLabel},
+ collect_result(State#state{next_label = NextLabel + Estimation});
+ {done, Job, Data} ->
+ NewResult = update_result(Mode, InitData, Job, Data, Result),
+ case Active of
+ 1 ->
+ kill_regulator(Regulator),
+ case Mode of
+ 'compile' ->
+ {NewResult, NextLabel};
+ X when X =:= 'typesig'; X =:= 'dataflow' ->
+ ets:delete(SCCtoPID),
+ NewResult;
+ 'warnings' ->
+ NewResult
+ end;
+ N ->
+ collect_result(State#state{result = NewResult, active = N - 1})
+ end
+ end.
+
+update_result(Mode, InitData, Job, Data, Result) ->
+ case Mode of
+ 'compile' ->
+ dialyzer_analysis_callgraph:add_to_result(Job, Data, Result,
+ InitData);
+ X when X =:= 'typesig'; X =:= 'dataflow' ->
+ dialyzer_succ_typings:lookup_names(Data, InitData) ++ Result;
+ 'warnings' ->
+ Data ++ Result
+ end.
+
+-spec sccs_to_pids([scc() | module()], coordinator()) ->
+ {[dialyzer_worker:worker()], [scc() | module()]}.
+
+sccs_to_pids(SCCs, {_Collector, _Regulator, SCCtoPID}) ->
+ Fold =
+ fun(SCC, {Pids, Unknown}) ->
+ try ets:lookup_element(SCCtoPID, SCC, 2) of
+ Result -> {[Result|Pids], Unknown}
+ catch
+ _:_ -> {Pids, [SCC|Unknown]}
+ end
+ end,
+ lists:foldl(Fold, {[], []}, SCCs).
+
+-spec job_done(job(), job_result(), coordinator()) -> ok.
+
+job_done(Job, Result, {Collector, Regulator, _SCCtoPID}) ->
+ Regulator ! done,
+ Collector ! {done, Job, Result},
+ ok.
+
+-spec get_next_label(integer(), coordinator()) -> integer().
+
+get_next_label(EstimatedSize, {Collector, _Regulator, _SCCtoPID}) ->
+ Collector ! {next_label_request, EstimatedSize, self()},
+ receive
+ {next_label_reply, NextLabel} -> NextLabel
+ end.
+
+-spec wait_activation() -> ok.
+
+wait_activation() ->
+ receive activate -> ok end.
+
+activate_pid(Pid) ->
+ Pid ! activate.
+
+-spec request_activation(coordinator()) -> ok.
+
+request_activation({_Collector, Regulator, _SCCtoPID}) ->
+ Regulator ! {req, self()},
+ wait_activation().
+
+request_activation(Regulator, Pid) ->
+ Regulator ! {req, Pid}.
+
+spawn_regulator() ->
+ InitTickets = dialyzer_utils:parallelism(),
+ spawn_link(fun() -> regulator_loop(InitTickets, queue:new()) end).
+
+regulator_loop(Tickets, Queue) ->
+ receive
+ {req, Pid} ->
+ case Tickets of
+ 0 ->
+ regulator_loop(0, queue:in(Pid, Queue));
+ N ->
+ activate_pid(Pid),
+ regulator_loop(N-1, Queue)
+ end;
+ done ->
+ {Waiting, NewQueue} = queue:out(Queue),
+ NewTickets =
+ case Waiting of
+ empty -> Tickets + 1;
+ {value, Pid} ->
+ activate_pid(Pid),
+ Tickets
+ end,
+ regulator_loop(NewTickets, NewQueue);
+ stop -> ok
+ end.
+
+kill_regulator(Regulator) ->
+ Regulator ! stop.
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index bd375b04fa..7131633da1 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -32,13 +32,11 @@
%% Data structure interfaces.
-export([state__add_warning/2, state__cleanup/1,
+ state__duplicate/1, dispose_state/1,
state__get_callgraph/1, state__get_races/1,
state__get_records/1, state__put_callgraph/2,
state__put_races/2, state__records_only/1]).
-%% Debug and test interfaces.
--export([get_top_level_signatures/2, pp/1]).
-
-export_type([state/0]).
-include("dialyzer.hrl").
@@ -67,7 +65,7 @@
%%-define(DEBUG, true).
%%-define(DEBUG_PP, true).
-%%-define(DOT, true).
+%%-define(DEBUG_TIME, true).
-ifdef(DEBUG).
-import(erl_types, [t_to_string/1]).
@@ -111,7 +109,7 @@
-spec get_warnings(cerl:c_module(), dialyzer_plt:plt(),
dialyzer_callgraph:callgraph(), dict(), set()) ->
- {[dial_warning()], dict(), dict(), [label()], [string()]}.
+ {[dial_warning()], dict()}.
get_warnings(Tree, Plt, Callgraph, Records, NoWarnUnused) ->
State1 = analyze_module(Tree, Plt, Callgraph, Records, true),
@@ -119,145 +117,14 @@ get_warnings(Tree, Plt, Callgraph, Records, NoWarnUnused) ->
State3 =
state__renew_warnings(state__get_warnings(State2, NoWarnUnused), State2),
State4 = state__get_race_warnings(State3),
- Callgraph1 = State2#state.callgraph,
- {State4#state.warnings, state__all_fun_types(State4),
- dialyzer_callgraph:get_race_code(Callgraph1),
- dialyzer_callgraph:get_public_tables(Callgraph1),
- dialyzer_callgraph:get_named_tables(Callgraph1)}.
+ {State4#state.warnings, state__all_fun_types(State4)}.
-spec get_fun_types(cerl:c_module(), dialyzer_plt:plt(),
- dialyzer_callgraph:callgraph(), dict()) ->
- {dict(), dict(), [label()], [string()]}.
+ dialyzer_callgraph:callgraph(), dict()) -> dict().
get_fun_types(Tree, Plt, Callgraph, Records) ->
State = analyze_module(Tree, Plt, Callgraph, Records, false),
- Callgraph1 = State#state.callgraph,
- {state__all_fun_types(State),
- dialyzer_callgraph:get_race_code(Callgraph1),
- dialyzer_callgraph:get_public_tables(Callgraph1),
- dialyzer_callgraph:get_named_tables(Callgraph1)}.
-
-%%--------------------------------------------------------------------
-
--spec pp(file:filename()) -> 'ok'.
-
-pp(File) ->
- {ok, Code} = dialyzer_utils:get_core_from_src(File, [no_copt]),
- Plt = get_def_plt(),
- AnnTree = annotate_module(Code, Plt),
- io:put_chars(cerl_prettypr:format(AnnTree, [{hook, cerl_typean:pp_hook()}])),
- io:nl().
-
-%%--------------------------------------------------------------------
-%% This is used in the testsuite.
-
--spec get_top_level_signatures(cerl:c_module(), dict()) ->
- [{{atom(), arity()}, erl_types:erl_type()}].
-
-get_top_level_signatures(Code, Records) ->
- {Tree, _} = cerl_trees:label(cerl:from_records(Code)),
- Callgraph0 = dialyzer_callgraph:new(),
- Callgraph1 = dialyzer_callgraph:scan_core_tree(Tree, Callgraph0),
- {Callgraph2, _} = dialyzer_callgraph:remove_external(Callgraph1),
- Callgraph = dialyzer_callgraph:finalize(Callgraph2),
- to_dot(Callgraph),
- Plt = get_def_plt(),
- FunTypes = get_fun_types(Tree, Plt, Callgraph, Records),
- FunTypes1 = lists:foldl(fun({V, F}, Acc) ->
- Label = get_label(F),
- case dict:find(Label, Acc) of
- error ->
- Arity = cerl:fname_arity(V),
- Type = t_fun(lists:duplicate(Arity,
- t_none()),
- t_none()),
- dict:store(Label, Type, Acc);
- {ok, _} -> Acc
- end
- end, FunTypes, cerl:module_defs(Tree)),
- dialyzer_callgraph:delete(Callgraph),
- Sigs = [{{cerl:fname_id(V), cerl:fname_arity(V)},
- dict:fetch(get_label(F), FunTypes1)}
- || {V, F} <- cerl:module_defs(Tree)],
- ordsets:from_list(Sigs).
-
-get_def_plt() ->
- try
- dialyzer_plt:from_file(dialyzer_plt:get_default_plt())
- catch
- throw:{dialyzer_error, _} -> dialyzer_plt:new()
- end.
-
-%%% ===========================================================================
-%%%
-%%% Annotate all top level funs.
-%%%
-%%% ===========================================================================
-
-annotate_module(Code, Plt) ->
- {Tree, _} = cerl_trees:label(cerl:from_records(Code)),
- Callgraph0 = dialyzer_callgraph:new(),
- Callgraph1 = dialyzer_callgraph:scan_core_tree(Tree, Callgraph0),
- {Callgraph2, _} = dialyzer_callgraph:remove_external(Callgraph1),
- Callgraph = dialyzer_callgraph:finalize(Callgraph2),
- State = analyze_module(Tree, Plt, Callgraph),
- Res = annotate(Tree, State),
- dialyzer_callgraph:delete(Callgraph),
- Res.
-
-annotate(Tree, State) ->
- case cerl:subtrees(Tree) of
- [] -> set_type(Tree, State);
- List ->
- NewSubTrees = [[annotate(Subtree, State) || Subtree <- Group]
- || Group <- List],
- NewTree = cerl:update_tree(Tree, NewSubTrees),
- set_type(NewTree, State)
- end.
-
-set_type(Tree, State) ->
- case cerl:type(Tree) of
- 'fun' ->
- Type = state__fun_type(Tree, State),
- case t_is_any(Type) of
- true ->
- cerl:set_ann(Tree, delete_ann(typesig, cerl:get_ann(Tree)));
- false ->
- cerl:set_ann(Tree, append_ann(typesig, Type, cerl:get_ann(Tree)))
- end;
- apply ->
- case state__find_apply_return(Tree, State) of
- unknown -> Tree;
- ReturnType ->
- case t_is_any(ReturnType) of
- true ->
- cerl:set_ann(Tree, delete_ann(type, cerl:get_ann(Tree)));
- false ->
- cerl:set_ann(Tree, append_ann(type, ReturnType,
- cerl:get_ann(Tree)))
- end
- end;
- _ ->
- Tree
- end.
-
-append_ann(Tag, Val, [X | Xs]) ->
- if tuple_size(X) >= 1, element(1, X) =:= Tag ->
- append_ann(Tag, Val, Xs);
- true ->
- [X | append_ann(Tag, Val, Xs)]
- end;
-append_ann(Tag, Val, []) ->
- [{Tag, Val}].
-
-delete_ann(Tag, [X | Xs]) ->
- if tuple_size(X) >= 1, element(1, X) =:= Tag ->
- delete_ann(Tag, Xs);
- true ->
- [X | delete_ann(Tag, Xs)]
- end;
-delete_ann(_, []) ->
- [].
+ state__all_fun_types(State).
%%% ===========================================================================
%%%
@@ -265,56 +132,46 @@ delete_ann(_, []) ->
%%%
%%% ===========================================================================
-analyze_module(Tree, Plt, Callgraph) ->
- analyze_module(Tree, Plt, Callgraph, dict:new(), false).
-
analyze_module(Tree, Plt, Callgraph, Records, GetWarnings) ->
debug_pp(Tree, false),
Module = cerl:atom_val(cerl:module_name(Tree)),
RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph),
- RaceCode = dialyzer_callgraph:get_race_code(Callgraph),
BehaviourTranslations =
case RaceDetection of
true -> dialyzer_behaviours:translatable_behaviours(Tree);
false -> []
end,
TopFun = cerl:ann_c_fun([{label, top}], [], Tree),
- State = state__new(dialyzer_callgraph:race_code_new(Callgraph),
- TopFun, Plt, Module, Records, BehaviourTranslations),
+ State =
+ state__new(Callgraph, TopFun, Plt, Module, Records, BehaviourTranslations),
State1 = state__race_analysis(not GetWarnings, State),
State2 = analyze_loop(State1),
case GetWarnings of
true ->
State3 = state__set_warning_mode(State2),
State4 = analyze_loop(State3),
- State5 = state__restore_race_code(RaceCode, State4),
%% EXPERIMENTAL: Turn all behaviour API calls into calls to the
%% respective callback module's functions.
case BehaviourTranslations of
- [] -> dialyzer_races:race(State5);
+ [] -> dialyzer_races:race(State4);
Behaviours ->
- Callgraph2 = State5#state.callgraph,
- Digraph = dialyzer_callgraph:get_digraph(Callgraph2),
+ Digraph = dialyzer_callgraph:get_digraph(State4#state.callgraph),
TranslatedCallgraph =
dialyzer_behaviours:translate_callgraph(Behaviours, Module,
- Callgraph2),
+ Callgraph),
St =
- dialyzer_races:race(State5#state{callgraph = TranslatedCallgraph}),
- Callgraph3 = dialyzer_callgraph:put_digraph(Digraph,
- St#state.callgraph),
- St#state{callgraph = Callgraph3}
+ dialyzer_races:race(State4#state{callgraph = TranslatedCallgraph}),
+ FinalCallgraph = dialyzer_callgraph:put_digraph(Digraph,
+ St#state.callgraph),
+ St#state{callgraph = FinalCallgraph}
end;
false ->
- Callgraph1 = State2#state.callgraph,
- RaceCode1 = dialyzer_callgraph:get_race_code(Callgraph1),
- state__restore_race_code(
- dict:merge(fun (_K, V1, _V2) -> V1 end,
- RaceCode, RaceCode1), State2)
+ State2
end.
-analyze_loop(#state{callgraph = Callgraph, races = Races} = State) ->
+analyze_loop(State) ->
case state__get_work(State) of
none -> State;
{Fun, NewState1} ->
@@ -340,10 +197,9 @@ analyze_loop(#state{callgraph = Callgraph, races = Races} = State) ->
Map1 = enter_type_lists(Vars, ArgTypes, Map),
Body = cerl:fun_body(Fun),
FunLabel = get_label(Fun),
- RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph),
- RaceAnalysis = dialyzer_races:get_race_analysis(Races),
+ IsRaceAnalysisEnabled = is_race_analysis_enabled(State),
NewState3 =
- case RaceDetection andalso RaceAnalysis of
+ case IsRaceAnalysisEnabled of
true ->
NewState2 = state__renew_curr_fun(
state__lookup_name(FunLabel, NewState1), FunLabel,
@@ -357,17 +213,8 @@ analyze_loop(#state{callgraph = Callgraph, races = Races} = State) ->
[state__lookup_name(get_label(Fun), State),
t_to_string(t_fun(ArgTypes, BodyType))]),
NewState5 =
- case RaceDetection andalso RaceAnalysis of
- true ->
- Races1 = NewState4#state.races,
- Code = lists:reverse(dialyzer_races:get_race_list(Races1)),
- Callgraph1 =
- renew_code(dialyzer_races:get_curr_fun(Races1),
- dialyzer_races:get_curr_fun_args(Races1),
- Code,
- state__warning_mode(NewState4),
- NewState4#state.callgraph),
- NewState4#state{callgraph = Callgraph1};
+ case IsRaceAnalysisEnabled of
+ true -> renew_race_code(NewState4);
false -> NewState4
end,
NewState6 =
@@ -582,9 +429,7 @@ handle_apply_or_call([{local, external}|Left], Args, ArgTypes, Map, Tree, State,
ArgTypes, t_any());
handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
Args, ArgTypes, Map, Tree,
- #state{callgraph = Callgraph, races = Races,
- opaques = Opaques} = State,
- AccArgTypes, AccRet) ->
+ #state{opaques = Opaques} = State, AccArgTypes, AccRet) ->
Any = t_any(),
AnyArgs = [Any || _ <- Args],
GenSig = {AnyArgs, fun(_) -> t_any() end},
@@ -680,8 +525,7 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
?debug("ContrRet: ~s\n", [erl_types:t_to_string(CRange(TmpArgTypes))]),
?debug("SigRet: ~s\n", [erl_types:t_to_string(SigRange)]),
State1 =
- case dialyzer_callgraph:get_race_detection(Callgraph) andalso
- dialyzer_races:get_race_analysis(Races) of
+ case is_race_analysis_enabled(State) of
true ->
Ann = cerl:get_ann(Tree),
File = get_file(Ann),
@@ -1047,20 +891,17 @@ handle_call(Tree, Map, State) ->
%%----------------------------------------
-handle_case(Tree, Map, #state{callgraph = Callgraph} = State) ->
+handle_case(Tree, Map, State) ->
Arg = cerl:case_arg(Tree),
Clauses = filter_match_fail(cerl:case_clauses(Tree)),
{State1, Map1, ArgType} = SMA = traverse(Arg, Map, State),
case t_is_none_or_unit(ArgType) of
true -> SMA;
false ->
- Races = State1#state.races,
State2 =
- case dialyzer_callgraph:get_race_detection(Callgraph) andalso
- dialyzer_races:get_race_analysis(Races) of
+ case is_race_analysis_enabled(State) of
true ->
- RaceList = dialyzer_races:get_race_list(Races),
- RaceListSize = dialyzer_races:get_race_list_size(Races),
+ {RaceList, RaceListSize} = get_race_list_and_size(State1),
state__renew_race_list([beg_case|RaceList],
RaceListSize + 1, State1);
false -> State1
@@ -1094,9 +935,8 @@ handle_cons(Tree, Map, State) ->
%%----------------------------------------
-handle_let(Tree, Map, #state{callgraph = Callgraph, races = Races} = State) ->
- RaceAnalysis = dialyzer_races:get_race_analysis(Races),
- RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph),
+handle_let(Tree, Map, State) ->
+ IsRaceAnalysisEnabled = is_race_analysis_enabled(State),
Arg = cerl:let_arg(Tree),
Vars = cerl:let_vars(Tree),
{Map0, State0} =
@@ -1104,10 +944,9 @@ handle_let(Tree, Map, #state{callgraph = Callgraph, races = Races} = State) ->
true ->
[Var] = Vars,
{enter_subst(Var, Arg, Map),
- case RaceDetection andalso RaceAnalysis of
+ case IsRaceAnalysisEnabled of
true ->
- RaceList = dialyzer_races:get_race_list(Races),
- RaceListSize = dialyzer_races:get_race_list_size(Races),
+ {RaceList, RaceListSize} = get_race_list_and_size(State),
state__renew_race_list(
[dialyzer_races:let_tag_new(Var, Arg)|RaceList],
RaceListSize + 1, State);
@@ -1117,9 +956,8 @@ handle_let(Tree, Map, #state{callgraph = Callgraph, races = Races} = State) ->
end,
Body = cerl:let_body(Tree),
{State1, Map1, ArgTypes} = SMA = traverse(Arg, Map0, State0),
- Callgraph1 = State1#state.callgraph,
- Callgraph2 =
- case RaceDetection andalso RaceAnalysis andalso cerl:is_c_call(Arg) of
+ State2 =
+ case IsRaceAnalysisEnabled andalso cerl:is_c_call(Arg) of
true ->
Mod = cerl:call_module(Arg),
Name = cerl:call_name(Arg),
@@ -1127,16 +965,11 @@ handle_let(Tree, Map, #state{callgraph = Callgraph, races = Races} = State) ->
cerl:concrete(Mod) =:= ets andalso
cerl:is_literal(Name) andalso
cerl:concrete(Name) =:= new of
- true ->
- NewTable = dialyzer_races:get_new_table(State1#state.races),
- renew_public_tables(Vars, NewTable,
- state__warning_mode(State1),
- Callgraph1);
- false -> Callgraph1
+ true -> renew_race_public_tables(Vars, State1);
+ false -> State1
end;
- false -> Callgraph1
+ false -> State1
end,
- State2 = State1#state{callgraph = Callgraph2},
case t_is_none_or_unit(ArgTypes) of
true -> SMA;
false ->
@@ -1167,16 +1000,13 @@ handle_module(Tree, Map, State) ->
%%----------------------------------------
-handle_receive(Tree, Map,
- #state{callgraph = Callgraph, races = Races} = State) ->
+handle_receive(Tree, Map, State) ->
Clauses = filter_match_fail(cerl:receive_clauses(Tree)),
Timeout = cerl:receive_timeout(Tree),
State1 =
- case dialyzer_callgraph:get_race_detection(Callgraph) andalso
- dialyzer_races:get_race_analysis(Races) of
+ case is_race_analysis_enabled(State) of
true ->
- RaceList = dialyzer_races:get_race_list(Races),
- RaceListSize = dialyzer_races:get_race_list_size(Races),
+ {RaceList, RaceListSize} = get_race_list_and_size(State),
state__renew_race_list([beg_case|RaceList],
RaceListSize + 1, State);
false -> State
@@ -1299,16 +1129,13 @@ handle_tuple(Tree, Map, State) ->
%%----------------------------------------
%% Clauses
%%
-handle_clauses([C|Left], Arg, ArgType, OrigArgType,
- #state{callgraph = Callgraph, races = Races} = State,
- CaseTypes, MapIn, Acc, ClauseAcc) ->
- RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph),
- RaceAnalysis = dialyzer_races:get_race_analysis(Races),
+handle_clauses([C|Left], Arg, ArgType, OrigArgType, State, CaseTypes, MapIn,
+ Acc, ClauseAcc) ->
+ IsRaceAnalysisEnabled = is_race_analysis_enabled(State),
State1 =
- case RaceDetection andalso RaceAnalysis of
+ case IsRaceAnalysisEnabled of
true ->
- RaceList = dialyzer_races:get_race_list(Races),
- RaceListSize = dialyzer_races:get_race_list_size(Races),
+ {RaceList, RaceListSize} = get_race_list_and_size(State),
state__renew_race_list(
[dialyzer_races:beg_clause_new(Arg, cerl:clause_pats(C),
cerl:clause_guard(C))|
@@ -1319,11 +1146,9 @@ handle_clauses([C|Left], Arg, ArgType, OrigArgType,
{State2, ClauseMap, BodyType, NewArgType} =
do_clause(C, Arg, ArgType, OrigArgType, MapIn, State1),
{NewClauseAcc, State3} =
- case RaceDetection andalso RaceAnalysis of
+ case IsRaceAnalysisEnabled of
true ->
- Races1 = State2#state.races,
- RaceList1 = dialyzer_races:get_race_list(Races1),
- RaceListSize1 = dialyzer_races:get_race_list_size(Races1),
+ {RaceList1, RaceListSize1} = get_race_list_and_size(State2),
EndClause = dialyzer_races:end_clause_new(Arg, cerl:clause_pats(C),
cerl:clause_guard(C)),
{[EndClause|ClauseAcc],
@@ -1338,30 +1163,25 @@ handle_clauses([C|Left], Arg, ArgType, OrigArgType,
end,
handle_clauses(Left, Arg, NewArgType, OrigArgType, State3,
NewCaseTypes, MapIn, NewAcc, NewClauseAcc);
-handle_clauses([], _Arg, _ArgType, _OrigArgType,
- #state{callgraph = Callgraph, races = Races} = State,
- CaseTypes, _MapIn, Acc, ClauseAcc) ->
+handle_clauses([], _Arg, _ArgType, _OrigArgType, State, CaseTypes, _MapIn, Acc,
+ ClauseAcc) ->
State1 =
- case dialyzer_callgraph:get_race_detection(Callgraph) andalso
- dialyzer_races:get_race_analysis(Races) of
+ case is_race_analysis_enabled(State) of
true ->
+ {RaceList, RaceListSize} = get_race_list_and_size(State),
state__renew_race_list(
- [dialyzer_races:end_case_new(ClauseAcc)|
- dialyzer_races:get_race_list(Races)],
- dialyzer_races:get_race_list_size(Races) + 1, State);
+ [dialyzer_races:end_case_new(ClauseAcc)|RaceList],
+ RaceListSize + 1, State);
false -> State
end,
{lists:reverse(Acc), State1, t_sup(CaseTypes)}.
-do_clause(C, Arg, ArgType0, OrigArgType, Map,
- #state{callgraph = Callgraph, races = Races} = State) ->
+do_clause(C, Arg, ArgType0, OrigArgType, Map, State) ->
Pats = cerl:clause_pats(C),
Guard = cerl:clause_guard(C),
Body = cerl:clause_body(C),
- RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph),
- RaceAnalysis = dialyzer_races:get_race_analysis(Races),
State1 =
- case RaceDetection andalso RaceAnalysis of
+ case is_race_analysis_enabled(State) of
true ->
state__renew_fun_args(Pats, State);
false -> State
@@ -2648,14 +2468,18 @@ join_maps(Maps, MapOut) ->
Keys = ordsets:from_list(dict:fetch_keys(Dict) ++ dict:fetch_keys(Subst)),
join_maps(Keys, Maps, MapOut).
-join_maps([Key|Left], Maps, MapOut) ->
+join_maps(Keys, Maps, MapOut) ->
+ KTs = join_maps_collect(Keys, Maps, MapOut),
+ lists:foldl(fun({K, T}, M) -> enter_type(K, T, M) end, MapOut, KTs).
+
+join_maps_collect([Key|Left], Maps, MapOut) ->
Type = join_maps_one_key(Maps, Key, t_none()),
case t_is_equal(lookup_type(Key, MapOut), Type) of
- true -> join_maps(Left, Maps, MapOut);
- false -> join_maps(Left, Maps, enter_type(Key, Type, MapOut))
+ true -> join_maps_collect(Left, Maps, MapOut);
+ false -> [{Key, Type} | join_maps_collect(Left, Maps, MapOut)]
end;
-join_maps([], _Maps, MapOut) ->
- MapOut.
+join_maps_collect([], _Maps, _MapOut) ->
+ [].
join_maps_one_key([Map|Left], Key, AccType) ->
case t_is_any(AccType) of
@@ -2914,10 +2738,6 @@ state__set_warning_mode(#state{tree_map = TreeMap, fun_tab = FunTab,
fun_tab = FunTab, warning_mode = true,
races = dialyzer_races:put_race_analysis(true, Races)}.
-state__restore_race_code(RaceCode, #state{callgraph = Callgraph} = State) ->
- State#state{callgraph = dialyzer_callgraph:put_race_code(RaceCode,
- Callgraph)}.
-
state__race_analysis(Analysis, #state{races = Races} = State) ->
State#state{races = dialyzer_races:put_race_analysis(Analysis, Races)}.
@@ -3260,21 +3080,6 @@ state__fun_info(Fun, #state{callgraph = CG, fun_tab = FunTab, plt = PLT}) ->
?debug("LocalRet: ~s\n", [t_to_string(LocalRet)]),
{Fun, Sig, Contract, LocalRet}.
-state__find_apply_return(Tree, #state{callgraph = Callgraph} = State) ->
- Apply = get_label(Tree),
- case dialyzer_callgraph:lookup_call_site(Apply, Callgraph) of
- error ->
- unknown;
- {ok, List} ->
- case lists:member(external, List) of
- true -> t_any();
- false ->
- FunTypes = [state__fun_type(F, State) || F <- List],
- Returns = [t_fun_range(F) || F <- FunTypes],
- t_sup(Returns)
- end
- end.
-
forward_args(Fun, ArgTypes, #state{work = Work, fun_tab = FunTab} = State) ->
{OldArgTypes, OldOut, Fixpoint} =
case dict:find(Fun, FunTab) of
@@ -3305,6 +3110,16 @@ state__cleanup(#state{callgraph = Callgraph,
races = dialyzer_races:cleanup(Races),
records = Records}.
+-spec state__duplicate(state()) -> state().
+
+state__duplicate(#state{callgraph = Callgraph} = State) ->
+ State#state{callgraph = dialyzer_callgraph:duplicate(Callgraph)}.
+
+-spec dispose_state(state()) -> ok.
+
+dispose_state(#state{callgraph = Callgraph}) ->
+ dialyzer_callgraph:dispose_race_server(Callgraph).
+
-spec state__get_callgraph(state()) -> dialyzer_callgraph:callgraph().
state__get_callgraph(#state{callgraph = Callgraph}) ->
@@ -3342,26 +3157,36 @@ state__records_only(#state{records = Records}) ->
%%%
%%% ===========================================================================
-renew_code(Fun, FunArgs, Code, WarningMode, Callgraph) ->
+is_race_analysis_enabled(#state{races = Races, callgraph = Callgraph}) ->
+ RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph),
+ RaceAnalysis = dialyzer_races:get_race_analysis(Races),
+ RaceDetection andalso RaceAnalysis.
+
+get_race_list_and_size(#state{races = Races}) ->
+ dialyzer_races:get_race_list_and_size(Races).
+
+renew_race_code(#state{races = Races, callgraph = Callgraph,
+ warning_mode = WarningMode} = State) ->
case WarningMode of
- true -> Callgraph;
+ true -> State;
false ->
- RaceCode = dialyzer_callgraph:get_race_code(Callgraph),
- dialyzer_callgraph:put_race_code(
- dict:store(Fun, [FunArgs, Code], RaceCode), Callgraph)
+ NewCallgraph = dialyzer_callgraph:renew_race_code(Races, Callgraph),
+ State#state{callgraph = NewCallgraph}
end.
-renew_public_tables([Var], Table, WarningMode, Callgraph) ->
+renew_race_public_tables([Var], #state{races = Races, callgraph = Callgraph,
+ warning_mode = WarningMode} = State) ->
case WarningMode of
- true -> Callgraph;
+ true -> State;
false ->
+ Table = dialyzer_races:get_new_table(Races),
case Table of
- no_t -> Callgraph;
- _Other ->
- VarLabel = get_label(Var),
- PTables = dialyzer_callgraph:get_public_tables(Callgraph),
- dialyzer_callgraph:put_public_tables(
- lists:usort([VarLabel|PTables]), Callgraph)
+ no_t -> State;
+ _Other ->
+ VarLabel = get_label(Var),
+ NewCallgraph =
+ dialyzer_callgraph:renew_race_public_tables(VarLabel, Callgraph),
+ State#state{callgraph = NewCallgraph}
end
end.
@@ -3688,17 +3513,3 @@ strip_annotations(Tree) ->
debug_pp(_Tree, _UseHook) ->
ok.
-endif.
-
-%%----------------------------------------------------------------------------
-
--spec to_dot(dialyzer_callgraph:callgraph()) -> 'ok'.
-
--ifdef(DOT).
-to_dot(CG) ->
- dialyzer_callgraph:to_dot(CG).
--else.
-to_dot(_CG) ->
- ok.
--endif.
-
-%%----------------------------------------------------------------------------
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index 866650a0b2..06672e595f 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2012. 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
@@ -194,6 +194,11 @@ build_options([{OptionName, Value} = Term|Rest], Options) ->
callgraph_file ->
assert_filename(Value),
build_options(Rest, Options#options{callgraph_file = Value});
+ timing ->
+ build_options(Rest, Options#options{timing = Value});
+ solvers ->
+ assert_solvers(Value),
+ build_options(Rest, Options#options{solvers = Value});
_ ->
bad_option("Unknown dialyzer command line option", Term)
end;
@@ -255,6 +260,15 @@ is_plt_mode(plt_remove) -> true;
is_plt_mode(plt_check) -> true;
is_plt_mode(succ_typings) -> false.
+assert_solvers([]) ->
+ ok;
+assert_solvers([v1|Terms]) ->
+ assert_solvers(Terms);
+assert_solvers([v2|Terms]) ->
+ assert_solvers(Terms);
+assert_solvers([Term|_]) ->
+ bad_option("Illegal value for solver", Term).
+
-spec build_warnings([atom()], [dial_warning()]) -> [dial_warning()].
build_warnings([Opt|Opts], Warnings) ->
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index 06eaadad9c..5f64099210 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -55,7 +55,10 @@
plt_and_info_from_file/1,
get_specs/1,
get_specs/4,
- to_file/4]).
+ to_file/4,
+ get_mini_plt/1,
+ restore_full_plt/2
+ ]).
%% Debug utilities
-export([pp_non_returning/0, pp_mod/1]).
@@ -82,7 +85,13 @@
contracts = table_new() :: dict(),
callbacks = table_new() :: dict(),
exported_types = sets:new() :: set()}).
--opaque plt() :: #plt{}.
+
+-record(mini_plt, {info :: ets:tid(),
+ contracts :: ets:tid(),
+ callbacks :: ets:tid()
+ }).
+
+-opaque plt() :: #plt{} | #mini_plt{}.
-include("dialyzer.hrl").
@@ -132,51 +141,48 @@ delete_list(#plt{info = Info, types = Types,
-spec insert_contract_list(plt(), dialyzer_contracts:plt_contracts()) -> plt().
-insert_contract_list(#plt{contracts = Contracts} = PLT, List) ->
- PLT#plt{contracts = table_insert_list(Contracts, List)}.
+insert_contract_list(#mini_plt{contracts = Contracts} = PLT, List) ->
+ true = ets:insert(Contracts, List),
+ PLT.
-spec insert_callbacks(plt(), dialyzer_codeserver:codeserver()) -> plt().
insert_callbacks(#plt{callbacks = Callbacks} = Plt, Codeserver) ->
- FunPreferNew = fun(_Key, _Val1, Val2) -> Val2 end,
- FunDictMerger =
- fun(_Key, Value, AccIn) -> dict:merge(FunPreferNew, Value, AccIn) end,
- MergedCallbacks = dict:fold(FunDictMerger, dict:new(),
- dialyzer_codeserver:get_callbacks(Codeserver)),
- List = dict:to_list(MergedCallbacks),
+ List = dialyzer_codeserver:get_callbacks(Codeserver),
Plt#plt{callbacks = table_insert_list(Callbacks, List)}.
-spec lookup_contract(plt(), mfa_patt()) -> 'none' | {'value', #contract{}}.
-lookup_contract(#plt{contracts = Contracts},
+lookup_contract(#mini_plt{contracts = ETSContracts},
{M, F, _} = MFA) when is_atom(M), is_atom(F) ->
- table_lookup(Contracts, MFA).
+ ets_table_lookup(ETSContracts, MFA).
-spec lookup_callbacks(plt(), module()) ->
- [{mfa(), {{Filename::string(), Line::pos_integer()}, #contract{}}}].
+ 'none' | {'value', [{mfa(), {{Filename::string(),
+ Line::pos_integer()},
+ #contract{}}}]}.
-lookup_callbacks(#plt{callbacks = Callbacks}, Mod) when is_atom(Mod) ->
- FunModFilter =
- fun({M, _F, _A}, _Val) -> M =:= Mod;
- ( _Key, _Val) -> false
- end,
- ModCallbacks = dict:filter(FunModFilter, Callbacks),
- dict:to_list(ModCallbacks).
+lookup_callbacks(#mini_plt{callbacks = ETSCallbacks}, Mod) when is_atom(Mod) ->
+ ets_table_lookup(ETSCallbacks, Mod).
-type ret_args_types() :: {erl_types:erl_type(), [erl_types:erl_type()]}.
-spec insert_list(plt(), [{mfa() | integer(), ret_args_types()}]) -> plt().
-insert_list(#plt{info = Info} = PLT, List) ->
- PLT#plt{info = table_insert_list(Info, List)}.
+insert_list(#mini_plt{info = Info} = PLT, List) ->
+ true = ets:insert(Info, List),
+ PLT.
-spec lookup(plt(), integer() | mfa_patt()) ->
'none' | {'value', ret_args_types()}.
-lookup(#plt{info = Info}, {M, F, _} = MFA) when is_atom(M), is_atom(F) ->
- table_lookup(Info, MFA);
-lookup(#plt{info = Info}, Label) when is_integer(Label) ->
- table_lookup(Info, Label).
+lookup(Plt, {M, F, _} = MFA) when is_atom(M), is_atom(F) ->
+ lookup_1(Plt, MFA);
+lookup(Plt, Label) when is_integer(Label) ->
+ lookup_1(Plt, Label).
+
+lookup_1(#mini_plt{info = Info}, MFAorLabel) ->
+ ets_table_lookup(Info, MFAorLabel).
-spec insert_types(plt(), dict()) -> plt().
@@ -503,6 +509,34 @@ init_md5_list_1([], DiffList, Acc) ->
init_md5_list_1(Md5List, [], Acc) ->
{ok, lists:reverse(Acc, Md5List)}.
+-spec get_mini_plt(plt()) -> plt().
+
+get_mini_plt(#plt{info = Info, contracts = Contracts, callbacks = Callbacks}) ->
+ [ETSInfo, ETSContracts, ETSCallbacks] =
+ [ets:new(Name, [public]) || Name <- [plt_info, plt_contracts, plt_callbacks]],
+ CallbackList = dict:to_list(Callbacks),
+ CallbacksByModule =
+ [{M, [Cb || {{M1,_,_},_} = Cb <- CallbackList, M1 =:= M]} ||
+ M <- lists:usort([M || {{M,_,_},_} <- CallbackList])],
+ [true, true] =
+ [ets:insert(ETS, dict:to_list(Data)) ||
+ {ETS, Data} <- [{ETSInfo, Info}, {ETSContracts, Contracts}]],
+ true = ets:insert(ETSCallbacks, CallbacksByModule),
+ #mini_plt{info = ETSInfo, contracts = ETSContracts, callbacks = ETSCallbacks};
+get_mini_plt(undefined) ->
+ undefined.
+
+-spec restore_full_plt(plt(), plt()) -> plt().
+
+restore_full_plt(#mini_plt{info = ETSInfo, contracts = ETSContracts}, Plt) ->
+ Info = dict:from_list(ets:tab2list(ETSInfo)),
+ Contracts = dict:from_list(ets:tab2list(ETSContracts)),
+ ets:delete(ETSContracts),
+ ets:delete(ETSInfo),
+ Plt#plt{info = Info, contracts = Contracts};
+restore_full_plt(undefined, undefined) ->
+ undefined.
+
%%---------------------------------------------------------------------------
%% Edoc
@@ -595,6 +629,13 @@ table_lookup(Plt, Obj) ->
{ok, Val} -> {value, Val}
end.
+ets_table_lookup(Plt, Obj) ->
+ try ets:lookup_element(Plt, Obj, 2) of
+ Val -> {value, Val}
+ catch
+ _:_ -> none
+ end.
+
table_lookup_module(Plt, Mod) ->
List = dict:fold(fun(Key, Val, Acc) ->
case Key of
diff --git a/lib/dialyzer/src/dialyzer_races.erl b/lib/dialyzer/src/dialyzer_races.erl
index cc635b0eef..cdb9f25999 100644
--- a/lib/dialyzer/src/dialyzer_races.erl
+++ b/lib/dialyzer/src/dialyzer_races.erl
@@ -36,6 +36,7 @@
-export([beg_clause_new/3, cleanup/1, end_case_new/1, end_clause_new/3,
get_curr_fun/1, get_curr_fun_args/1, get_new_table/1,
get_race_analysis/1, get_race_list/1, get_race_list_size/1,
+ get_race_list_and_size/1,
let_tag_new/2, new/0, put_curr_fun/3, put_fun_args/2,
put_race_analysis/2, put_race_list/3]).
@@ -346,6 +347,7 @@ fixup_race_list(RaceWarnTag, WarnVarArgs, State) ->
DepList2 =
fixup_race_list_helper(NewParents, Calls, CurrFun, WarnVarArgs,
RaceWarnTag, NewState),
+ dialyzer_dataflow:dispose_state(CleanState),
lists:usort(cleanup_dep_calls(DepList1 ++ DepList2)).
fixup_race_list_helper(Parents, Calls, CurrFun, WarnVarArgs, RaceWarnTag,
@@ -380,13 +382,15 @@ fixup_race_forward_pullout(CurrFun, CurrFunLabel, Calls, Code, RaceList,
InitFun, WarnVarArgs, RaceWarnTag, RaceVarMap,
FunDefVars, FunCallVars, FunArgTypes, NestingLevel,
State) ->
+ TState = dialyzer_dataflow:state__duplicate(State),
{DepList, NewCurrFun, NewCurrFunLabel, NewCalls,
NewCode, NewRaceList, NewRaceVarMap, NewFunDefVars,
NewFunCallVars, NewFunArgTypes, NewNestingLevel} =
fixup_race_forward(CurrFun, CurrFunLabel, Calls, Code, RaceList,
InitFun, WarnVarArgs, RaceWarnTag, RaceVarMap,
FunDefVars, FunCallVars, FunArgTypes, NestingLevel,
- cleanup_race_code(State)),
+ cleanup_race_code(TState)),
+ dialyzer_dataflow:dispose_state(TState),
case NewCode of
[] -> DepList;
[#fun_call{caller = NewCurrFun, callee = Call, arg_types = FunTypes,
@@ -2434,6 +2438,12 @@ get_race_list(#races{race_list = RaceList}) ->
get_race_list_size(#races{race_list_size = RaceListSize}) ->
RaceListSize.
+-spec get_race_list_and_size(races()) -> {code(), non_neg_integer()}.
+
+get_race_list_and_size(#races{race_list = RaceList,
+ race_list_size = RaceListSize}) ->
+ {RaceList, RaceListSize}.
+
-spec let_tag_new(var_to_map1(), var_to_map1()) -> #let_tag{}.
let_tag_new(Var, Arg) ->
diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl
index 5982603b7b..84379642bf 100644
--- a/lib/dialyzer/src/dialyzer_succ_typings.erl
+++ b/lib/dialyzer/src/dialyzer_succ_typings.erl
@@ -28,15 +28,22 @@
-module(dialyzer_succ_typings).
-export([analyze_callgraph/3,
- analyze_callgraph/4,
- get_warnings/6]).
+ analyze_callgraph/6,
+ get_warnings/8
+ ]).
-%% These are only intended as debug functions.
--export([doit/1,
- get_top_level_signatures/3]).
+-export([
+ find_succ_types_for_scc/2,
+ refine_one_module/2,
+ find_required_by/2,
+ find_depends_on/2,
+ collect_warnings/2,
+ lookup_names/2
+ ]).
+
+-export_type([typesig_init_data/0, dataflow_init_data/0, warnings_init_data/0]).
%%-define(DEBUG, true).
-%%-define(DEBUG_PP, true).
-ifdef(DEBUG).
-define(debug(X__, Y__), io:format(X__, Y__)).
@@ -54,11 +61,21 @@
%% State record -- local to this module
-type parent() :: 'none' | pid().
+-type typesig_init_data() :: term().
+-type dataflow_init_data() :: term().
+-type warnings_init_data() :: term().
+
+-type fixpoint_init_data() :: typesig_init_data() | dataflow_init_data().
+
+-type scc() :: [mfa_or_funlbl()] | [module()].
+
-record(st, {callgraph :: dialyzer_callgraph:callgraph(),
codeserver :: dialyzer_codeserver:codeserver(),
no_warn_unused :: set(),
parent = none :: parent(),
+ timing_server :: dialyzer_timing:timing_server(),
+ solvers :: [solver()],
plt :: dialyzer_plt:plt()}).
%%--------------------------------------------------------------------
@@ -68,60 +85,90 @@
dialyzer_plt:plt().
analyze_callgraph(Callgraph, Plt, Codeserver) ->
- analyze_callgraph(Callgraph, Plt, Codeserver, none).
+ analyze_callgraph(Callgraph, Plt, Codeserver, none, [], none).
-spec analyze_callgraph(dialyzer_callgraph:callgraph(), dialyzer_plt:plt(),
- dialyzer_codeserver:codeserver(), parent()) ->
+ dialyzer_codeserver:codeserver(),
+ dialyzer_timing:timing_server(),
+ [solver()], parent()) ->
dialyzer_plt:plt().
-analyze_callgraph(Callgraph, Plt, Codeserver, Parent) ->
- State = #st{callgraph = Callgraph, plt = Plt,
- codeserver = Codeserver, parent = Parent},
- NewState = get_refined_success_typings(State),
- NewState#st.plt.
+analyze_callgraph(Callgraph, Plt, Codeserver, TimingServer, Solvers, Parent) ->
+ NewState =
+ init_state_and_get_success_typings(Callgraph, Plt, Codeserver,
+ TimingServer, Solvers, Parent),
+ dialyzer_plt:restore_full_plt(NewState#st.plt, Plt).
%%--------------------------------------------------------------------
-get_refined_success_typings(State) ->
- case find_succ_typings(State) of
+init_state_and_get_success_typings(Callgraph, Plt, Codeserver,
+ TimingServer, Solvers, Parent) ->
+ {SCCs, Callgraph1} =
+ ?timing(TimingServer, "order", dialyzer_callgraph:finalize(Callgraph)),
+ State = #st{callgraph = Callgraph1, plt = dialyzer_plt:get_mini_plt(Plt),
+ codeserver = Codeserver, parent = Parent,
+ timing_server = TimingServer, solvers = Solvers},
+ get_refined_success_typings(SCCs, State).
+
+get_refined_success_typings(SCCs, #st{callgraph = Callgraph,
+ timing_server = TimingServer} = State) ->
+ case find_succ_typings(SCCs, State) of
{fixpoint, State1} -> State1;
{not_fixpoint, NotFixpoint1, State1} ->
- Callgraph = State1#st.callgraph,
- NotFixpoint2 = [lookup_name(F, Callgraph) || F <- NotFixpoint1],
- ModulePostorder =
- dialyzer_callgraph:module_postorder_from_funs(NotFixpoint2, Callgraph),
- case refine_succ_typings(ModulePostorder, State1) of
+ {ModulePostorder, ModCallgraph} =
+ ?timing(
+ TimingServer, "order", _C1,
+ dialyzer_callgraph:module_postorder_from_funs(NotFixpoint1,
+ Callgraph)),
+ ModState = State1#st{callgraph = ModCallgraph},
+ case refine_succ_typings(ModulePostorder, ModState) of
{fixpoint, State2} ->
State2;
- {not_fixpoint, NotFixpoint3, State2} ->
- Callgraph1 = State2#st.callgraph,
+ {not_fixpoint, NotFixpoint2, State2} ->
%% Need to reset the callgraph.
- NotFixpoint4 = [lookup_name(F, Callgraph1) || F <- NotFixpoint3],
- Callgraph2 = dialyzer_callgraph:reset_from_funs(NotFixpoint4,
- Callgraph1),
- get_refined_success_typings(State2#st{callgraph = Callgraph2})
+ {NewSCCs, Callgraph2} =
+ ?timing(TimingServer, "order", _C2,
+ dialyzer_callgraph:reset_from_funs(NotFixpoint2,
+ ModCallgraph)),
+ NewState = State2#st{callgraph = Callgraph2},
+ get_refined_success_typings(NewSCCs, NewState)
end
end.
-type doc_plt() :: 'undefined' | dialyzer_plt:plt().
-spec get_warnings(dialyzer_callgraph:callgraph(), dialyzer_plt:plt(),
doc_plt(), dialyzer_codeserver:codeserver(), set(),
- pid()) ->
+ dialyzer_timing:timing_server(), [solver()], pid()) ->
{[dial_warning()], dialyzer_plt:plt(), doc_plt()}.
-get_warnings(Callgraph, Plt, DocPlt, Codeserver, NoWarnUnused, Parent) ->
- InitState = #st{callgraph = Callgraph, codeserver = Codeserver,
- no_warn_unused = NoWarnUnused, parent = Parent, plt = Plt},
- NewState = get_refined_success_typings(InitState),
+get_warnings(Callgraph, Plt, DocPlt, Codeserver,
+ NoWarnUnused, TimingServer, Solvers, Parent) ->
+ InitState =
+ init_state_and_get_success_typings(Callgraph, Plt, Codeserver,
+ TimingServer, Solvers, Parent),
+ NewState = InitState#st{no_warn_unused = NoWarnUnused},
Mods = dialyzer_callgraph:modules(NewState#st.callgraph),
- CWarns = dialyzer_contracts:get_invalid_contract_warnings(Mods, Codeserver,
- NewState#st.plt),
- get_warnings_from_modules(Mods, NewState, DocPlt, CWarns).
-
-get_warnings_from_modules([M|Ms], State, DocPlt, Acc) when is_atom(M) ->
- send_log(State#st.parent, io_lib:format("Getting warnings for ~w\n", [M])),
+ MiniPlt = NewState#st.plt,
+ CWarns =
+ dialyzer_contracts:get_invalid_contract_warnings(Mods, Codeserver, MiniPlt),
+ MiniDocPlt = dialyzer_plt:get_mini_plt(DocPlt),
+ ModWarns =
+ ?timing(TimingServer, "warning",
+ get_warnings_from_modules(Mods, NewState, MiniDocPlt)),
+ {postprocess_warnings(CWarns ++ ModWarns, Codeserver),
+ dialyzer_plt:restore_full_plt(MiniPlt, Plt),
+ dialyzer_plt:restore_full_plt(MiniDocPlt, DocPlt)}.
+
+get_warnings_from_modules(Mods, State, DocPlt) ->
#st{callgraph = Callgraph, codeserver = Codeserver,
- no_warn_unused = NoWarnUnused, plt = Plt} = State,
+ no_warn_unused = NoWarnUnused, plt = Plt,
+ timing_server = TimingServer} = State,
+ Init = {Codeserver, Callgraph, NoWarnUnused, Plt, DocPlt},
+ dialyzer_coordinator:parallel_job(warnings, Mods, Init, TimingServer).
+
+-spec collect_warnings(module(), warnings_init_data()) -> [dial_warning()].
+
+collect_warnings(M, {Codeserver, Callgraph, NoWarnUnused, Plt, DocPlt}) ->
ModCode = dialyzer_codeserver:lookup_mod_code(M, Codeserver),
Records = dialyzer_codeserver:lookup_mod_records(M, Codeserver),
Contracts = dialyzer_codeserver:lookup_mod_contracts(M, Codeserver),
@@ -129,28 +176,27 @@ get_warnings_from_modules([M|Ms], State, DocPlt, Acc) when is_atom(M) ->
%% Check if there are contracts for functions that do not exist
Warnings1 =
dialyzer_contracts:contracts_without_fun(Contracts, AllFuns, Callgraph),
- {RawWarnings2, FunTypes, RaceCode, PublicTables, NamedTables} =
- dialyzer_dataflow:get_warnings(ModCode, Plt, Callgraph, Records, NoWarnUnused),
- {NewAcc, Warnings2} = postprocess_dataflow_warns(RawWarnings2, State, Acc),
+ {Warnings2, FunTypes} =
+ dialyzer_dataflow:get_warnings(ModCode, Plt, Callgraph,
+ Records, NoWarnUnused),
Attrs = cerl:module_attrs(ModCode),
- Warnings3 = dialyzer_behaviours:check_callbacks(M, Attrs, Plt, Codeserver),
- NewDocPlt = insert_into_doc_plt(FunTypes, Callgraph, DocPlt),
- NewCallgraph =
- dialyzer_callgraph:renew_race_info(Callgraph, RaceCode, PublicTables,
- NamedTables),
- State1 = st__renew_state_calls(NewCallgraph, State),
- get_warnings_from_modules(Ms, State1, NewDocPlt,
- [Warnings1, Warnings2, Warnings3|NewAcc]);
-get_warnings_from_modules([], #st{plt = Plt}, DocPlt, Acc) ->
- {lists:flatten(Acc), Plt, DocPlt}.
-
-postprocess_dataflow_warns(RawWarnings, State, WarnAcc) ->
- postprocess_dataflow_warns(RawWarnings, State, WarnAcc, []).
-
-postprocess_dataflow_warns([], _State, WAcc, Acc) ->
- {WAcc, lists:reverse(Acc)};
+ Warnings3 =
+ dialyzer_behaviours:check_callbacks(M, Attrs, Records, Plt, Codeserver),
+ DocPlt = insert_into_doc_plt(FunTypes, Callgraph, DocPlt),
+ lists:flatten([Warnings1, Warnings2, Warnings3]).
+
+postprocess_warnings(RawWarnings, Codeserver) ->
+ Pred =
+ fun({?WARN_CONTRACT_RANGE, _, _}) -> true;
+ (_) -> false
+ end,
+ {CRWarns, NonCRWarns} = lists:partition(Pred, RawWarnings),
+ postprocess_dataflow_warns(CRWarns, Codeserver, NonCRWarns, []).
+
+postprocess_dataflow_warns([], _Callgraph, WAcc, Acc) ->
+ lists:reverse(Acc, WAcc);
postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {CallF, CallL}, Msg}|Rest],
- #st{codeserver = Codeserver} = State, WAcc, Acc) ->
+ Codeserver, WAcc, Acc) ->
{contract_range, [Contract, M, F, A, ArgStrings, CRet]} = Msg,
case dialyzer_codeserver:lookup_mfa_contract({M,F,A}, Codeserver) of
{ok, {{ContrF, _ContrL} = FileLine, _C}} ->
@@ -163,87 +209,66 @@ postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {CallF, CallL}, Msg}|Rest],
(_) -> true
end,
FilterWAcc = lists:filter(Filter, WAcc),
- postprocess_dataflow_warns(Rest, State, FilterWAcc, [W|Acc]);
+ postprocess_dataflow_warns(Rest, Codeserver, FilterWAcc, [W|Acc]);
false ->
- postprocess_dataflow_warns(Rest, State, WAcc, Acc)
+ postprocess_dataflow_warns(Rest, Codeserver, WAcc, Acc)
end;
error ->
%% The contract is not in a module that is currently under analysis.
%% We display the warning in the file/line of the call.
NewMsg = {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]},
W = {?WARN_CONTRACT_RANGE, {CallF, CallL}, NewMsg},
- postprocess_dataflow_warns(Rest, State, WAcc, [W|Acc])
- end;
-postprocess_dataflow_warns([W|Rest], State, Wacc, Acc) ->
- postprocess_dataflow_warns(Rest, State, Wacc, [W|Acc]).
+ postprocess_dataflow_warns(Rest, Codeserver, WAcc, [W|Acc])
+ end.
-refine_succ_typings(ModulePostorder, State) ->
- ?debug("Module postorder: ~p\n", [ModulePostorder]),
- refine_succ_typings(ModulePostorder, State, []).
-
-refine_succ_typings([SCC|SCCs], State, Fixpoint) ->
- Msg = io_lib:format("Dataflow of one SCC: ~w\n", [SCC]),
- send_log(State#st.parent, Msg),
- ?debug("~s\n", [Msg]),
- {NewState, FixpointFromScc} =
- case SCC of
- [M] -> refine_one_module(M, State);
- [_|_] -> refine_one_scc(SCC, State)
- end,
- NewFixpoint = ordsets:union(Fixpoint, FixpointFromScc),
- refine_succ_typings(SCCs, NewState, NewFixpoint);
-refine_succ_typings([], State, Fixpoint) ->
- case Fixpoint =:= [] of
+refine_succ_typings(Modules, #st{codeserver = Codeserver,
+ callgraph = Callgraph,
+ plt = Plt,
+ timing_server = Timing,
+ solvers = Solvers} = State) ->
+ ?debug("Module postorder: ~p\n", [Modules]),
+ Init = {Codeserver, Callgraph, Plt, Solvers},
+ NotFixpoint =
+ ?timing(Timing, "refine",
+ dialyzer_coordinator:parallel_job(dataflow, Modules, Init, Timing)),
+ ?debug("==================== Dataflow done ====================\n\n", []),
+ case NotFixpoint =:= [] of
true -> {fixpoint, State};
- false -> {not_fixpoint, Fixpoint, State}
+ false -> {not_fixpoint, NotFixpoint, State}
end.
--spec refine_one_module(module(), #st{}) -> {#st{}, [label()]}. % ordset
+-spec find_depends_on(scc() | module(), fixpoint_init_data()) -> [scc()].
-refine_one_module(M, State) ->
- #st{callgraph = Callgraph, codeserver = CodeServer, plt = PLT} = State,
+find_depends_on(SCC, {_Codeserver, Callgraph, _Plt, _Solvers}) ->
+ dialyzer_callgraph:get_depends_on(SCC, Callgraph).
+
+-spec find_required_by(scc() | module(), fixpoint_init_data()) -> [scc()].
+
+find_required_by(SCC, {_Codeserver, Callgraph, _Plt, _Solvers}) ->
+ dialyzer_callgraph:get_required_by(SCC, Callgraph).
+
+-spec lookup_names([label()], fixpoint_init_data()) -> [mfa_or_funlbl()].
+
+lookup_names(Labels, {_Codeserver, Callgraph, _Plt, _Solvers}) ->
+ [lookup_name(F, Callgraph) || F <- Labels].
+
+-spec refine_one_module(module(), dataflow_init_data()) -> [label()]. % ordset
+
+refine_one_module(M, {CodeServer, Callgraph, Plt, _Solvers}) ->
ModCode = dialyzer_codeserver:lookup_mod_code(M, CodeServer),
AllFuns = collect_fun_info([ModCode]),
- FunTypes = get_fun_types_from_plt(AllFuns, Callgraph, PLT),
Records = dialyzer_codeserver:lookup_mod_records(M, CodeServer),
- {NewFunTypes, RaceCode, PublicTables, NamedTables} =
- dialyzer_dataflow:get_fun_types(ModCode, PLT, Callgraph, Records),
- NewCallgraph =
- dialyzer_callgraph:renew_race_info(Callgraph, RaceCode, PublicTables,
- NamedTables),
+ FunTypes = get_fun_types_from_plt(AllFuns, Callgraph, Plt),
+ NewFunTypes =
+ dialyzer_dataflow:get_fun_types(ModCode, Plt, Callgraph, Records),
case reached_fixpoint(FunTypes, NewFunTypes) of
- true ->
- State1 = st__renew_state_calls(NewCallgraph, State),
- {State1, ordsets:new()};
+ true -> [];
{false, NotFixpoint} ->
?debug("Not fixpoint\n", []),
- NewState = insert_into_plt(dict:from_list(NotFixpoint), State),
- NewState1 = st__renew_state_calls(NewCallgraph, NewState),
- {NewState1, ordsets:from_list([FunLbl || {FunLbl,_Type} <- NotFixpoint])}
+ Plt = insert_into_plt(dict:from_list(NotFixpoint), Callgraph, Plt),
+ [FunLbl || {FunLbl,_Type} <- NotFixpoint]
end.
-st__renew_state_calls(Callgraph, State) ->
- State#st{callgraph = Callgraph}.
-
-refine_one_scc(SCC, State) ->
- refine_one_scc(SCC, State, []).
-
-refine_one_scc(SCC, State, AccFixpoint) ->
- {NewState, FixpointFromScc} = refine_mods_in_scc(SCC, State, []),
- case FixpointFromScc =:= [] of
- true -> {NewState, AccFixpoint};
- false ->
- NewAccFixpoint = ordsets:union(AccFixpoint, FixpointFromScc),
- refine_one_scc(SCC, NewState, NewAccFixpoint)
- end.
-
-refine_mods_in_scc([Mod|Mods], State, Fixpoint) ->
- {NewState, FixpointFromModule} = refine_one_module(Mod, State),
- NewFixpoint = ordsets:union(FixpointFromModule, Fixpoint),
- refine_mods_in_scc(Mods, NewState, NewFixpoint);
-refine_mods_in_scc([], State, Fixpoint) ->
- {State, Fixpoint}.
-
reached_fixpoint(OldTypes, NewTypes) ->
reached_fixpoint(OldTypes, NewTypes, false).
@@ -299,31 +324,22 @@ compare_types_1([], [], _Strict, NotFixpoint) ->
false -> {false, NotFixpoint}
end.
-find_succ_typings(State) ->
- find_succ_typings(State, []).
-
-find_succ_typings(#st{callgraph = Callgraph, parent = Parent} = State,
- NotFixpoint) ->
- case dialyzer_callgraph:take_scc(Callgraph) of
- {ok, SCC, NewCallgraph} ->
- Msg = io_lib:format("Typesig analysis for SCC: ~w\n", [format_scc(SCC)]),
- ?debug("~s", [Msg]),
- send_log(Parent, Msg),
- {NewState, NewNotFixpoint1} =
- analyze_scc(SCC, State#st{callgraph = NewCallgraph}),
- NewNotFixpoint2 = ordsets:union(NewNotFixpoint1, NotFixpoint),
- find_succ_typings(NewState, NewNotFixpoint2);
- none ->
- ?debug("==================== Typesig done ====================\n\n", []),
- case NotFixpoint =:= [] of
- true -> {fixpoint, State};
- false -> {not_fixpoint, NotFixpoint, State}
- end
+find_succ_typings(SCCs, #st{codeserver = Codeserver, callgraph = Callgraph,
+ plt = Plt, timing_server = Timing,
+ solvers = Solvers} = State) ->
+ Init = {Codeserver, Callgraph, Plt, Solvers},
+ NotFixpoint =
+ ?timing(Timing, "typesig",
+ dialyzer_coordinator:parallel_job(typesig, SCCs, Init, Timing)),
+ ?debug("==================== Typesig done ====================\n\n", []),
+ case NotFixpoint =:= [] of
+ true -> {fixpoint, State};
+ false -> {not_fixpoint, NotFixpoint, State}
end.
-analyze_scc(SCC, #st{codeserver = Codeserver,
- callgraph = Callgraph,
- plt = Plt} = State) ->
+-spec find_succ_types_for_scc(scc(), typesig_init_data()) -> [mfa_or_funlbl()].
+
+find_succ_types_for_scc(SCC, {Codeserver, Callgraph, Plt, Solvers}) ->
SCC_Info = [{MFA,
dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
dialyzer_codeserver:lookup_mod_records(M, Codeserver)}
@@ -332,26 +348,18 @@ analyze_scc(SCC, #st{codeserver = Codeserver,
|| {_, _, _} = MFA <- SCC],
Contracts2 = [{MFA, Contract} || {MFA, {ok, Contract}} <- Contracts1],
Contracts3 = orddict:from_list(Contracts2),
- NextLabel = dialyzer_codeserver:get_next_core_label(Codeserver),
- {SuccTypes, PltContracts, NotFixpoint} =
- find_succ_types_for_scc(SCC_Info, Contracts3, NextLabel, Callgraph, Plt),
- State1 = insert_into_plt(SuccTypes, State),
- ContrPlt = dialyzer_plt:insert_contract_list(State1#st.plt, PltContracts),
- {State1#st{plt = ContrPlt}, NotFixpoint}.
-
-find_succ_types_for_scc(SCC_Info, Contracts, NextLabel, Callgraph, Plt) ->
- %% Assume that the PLT contains the current propagated types
+ Label = dialyzer_codeserver:get_next_core_label(Codeserver),
AllFuns = collect_fun_info([Fun || {_MFA, {_Var, Fun}, _Rec} <- SCC_Info]),
PropTypes = get_fun_types_from_plt(AllFuns, Callgraph, Plt),
- FunTypes = dialyzer_typesig:analyze_scc(SCC_Info, NextLabel,
- Callgraph, Plt, PropTypes),
+ %% Assume that the PLT contains the current propagated types
+ FunTypes = dialyzer_typesig:analyze_scc(SCC_Info, Label, Callgraph,
+ Plt, PropTypes, Solvers),
AllFunSet = sets:from_list([X || {X, _} <- AllFuns]),
- FilteredFunTypes = dict:filter(fun(X, _) ->
- sets:is_element(X, AllFunSet)
- end, FunTypes),
+ FilteredFunTypes =
+ dict:filter(fun(X, _) -> sets:is_element(X, AllFunSet) end, FunTypes),
%% Check contracts
- PltContracts = dialyzer_contracts:check_contracts(Contracts, Callgraph,
- FilteredFunTypes),
+ PltContracts =
+ dialyzer_contracts:check_contracts(Contracts3, Callgraph, FilteredFunTypes),
ContractFixpoint =
lists:all(fun({MFA, _C}) ->
%% Check the non-deleted PLT
@@ -360,14 +368,14 @@ find_succ_types_for_scc(SCC_Info, Contracts, NextLabel, Callgraph, Plt) ->
{value, _} -> true
end
end, PltContracts),
+ Plt = insert_into_plt(FilteredFunTypes, Callgraph, Plt),
+ Plt = dialyzer_plt:insert_contract_list(Plt, PltContracts),
case (ContractFixpoint andalso
reached_fixpoint_strict(PropTypes, FilteredFunTypes)) of
- true ->
- {FilteredFunTypes, PltContracts, []};
+ true -> [];
false ->
?debug("Not fixpoint for: ~w\n", [AllFuns]),
- {FilteredFunTypes, PltContracts,
- ordsets:from_list([Fun || {Fun, _Arity} <- AllFuns])}
+ [Fun || {Fun, _Arity} <- AllFuns]
end.
get_fun_types_from_plt(FunList, Callgraph, Plt) ->
@@ -407,10 +415,10 @@ insert_into_doc_plt(FunTypes, Callgraph, DocPlt) ->
SuccTypes = format_succ_types(FunTypes, Callgraph),
dialyzer_plt:insert_list(DocPlt, SuccTypes).
-insert_into_plt(SuccTypes0, #st{callgraph = Callgraph, plt = Plt} = State) ->
+insert_into_plt(SuccTypes0, Callgraph, Plt) ->
SuccTypes = format_succ_types(SuccTypes0, Callgraph),
debug_pp_succ_typings(SuccTypes),
- State#st{plt = dialyzer_plt:insert_list(Plt, SuccTypes)}.
+ dialyzer_plt:insert_list(Plt, SuccTypes).
format_succ_types(SuccTypes, Callgraph) ->
format_succ_types(dict:to_list(SuccTypes), Callgraph, []).
@@ -445,131 +453,3 @@ lookup_name(F, CG) ->
error -> F;
{ok, Name} -> Name
end.
-
-send_log(none, _Msg) ->
- ok;
-send_log(Parent, Msg) ->
- Parent ! {self(), log, lists:flatten(Msg)},
- ok.
-
-format_scc(SCC) ->
- [MFA || {_M, _F, _A} = MFA <- SCC].
-
-%% ============================================================================
-%%
-%% Debug interface.
-%%
-%% ============================================================================
-
--spec doit(atom() | file:filename()) -> 'ok'.
-
-doit(Module) ->
- {ok, AbstrCode} = dialyzer_utils:get_abstract_code_from_src(Module),
- {ok, Code} = dialyzer_utils:get_core_from_abstract_code(AbstrCode),
- {ok, Records} = dialyzer_utils:get_record_and_type_info(AbstrCode),
- %% contract typing info in dictionary format
- {ok, Contracts, _Callbacks} =
- dialyzer_utils:get_spec_info(cerl:concrete(cerl:module_name(Code)),
- AbstrCode, Records),
- Sigs0 = get_top_level_signatures(Code, Records, Contracts),
- M = if is_atom(Module) ->
- list_to_atom(filename:basename(atom_to_list(Module)));
- is_list(Module) ->
- list_to_atom(filename:basename(Module))
- end,
- Sigs1 = [{{M, F, A}, Type} || {{F, A}, Type} <- Sigs0],
- Sigs = ordsets:from_list(Sigs1),
- io:format("==================== Final result ====================\n\n", []),
- pp_signatures(Sigs, Records),
- ok.
-
--spec get_top_level_signatures(cerl:c_module(), dict(), dict()) ->
- [{{atom(), arity()}, erl_types:erl_type()}].
-
-get_top_level_signatures(Code, Records, Contracts) ->
- Tree = cerl:from_records(Code),
- {LabeledTree, NextLabel} = cerl_trees:label(Tree),
- Plt = get_def_plt(),
- ModuleName = cerl:atom_val(cerl:module_name(LabeledTree)),
- Plt1 = dialyzer_plt:delete_module(Plt, ModuleName),
- Plt2 = analyze_module(LabeledTree, NextLabel, Plt1, Records, Contracts),
- M = cerl:concrete(cerl:module_name(Tree)),
- Functions = [{M, cerl:fname_id(V), cerl:fname_arity(V)}
- || {V, _F} <- cerl:module_defs(LabeledTree)],
- %% First contracts check
- AllContracts = dict:fetch_keys(Contracts),
- ErrorContracts = AllContracts -- Functions,
- lists:foreach(fun(C) ->
- io:format("Contract for non-existing function: ~w\n",[C])
- end, ErrorContracts),
- Types = [{MFA, dialyzer_plt:lookup(Plt2, MFA)} || MFA <- Functions],
- Sigs = [{{F, A}, erl_types:t_fun(ArgT, RetT)}
- || {{_M, F, A}, {value, {RetT, ArgT}}} <- Types],
- ordsets:from_list(Sigs).
-
-get_def_plt() ->
- try
- dialyzer_plt:from_file(dialyzer_plt:get_default_plt())
- catch
- error:no_such_file -> dialyzer_plt:new();
- throw:{dialyzer_error, _} -> dialyzer_plt:new()
- end.
-
-pp_signatures([{{_, module_info, 0}, _}|Left], Records) ->
- pp_signatures(Left, Records);
-pp_signatures([{{_, module_info, 1}, _}|Left], Records) ->
- pp_signatures(Left, Records);
-pp_signatures([{{M, F, _A}, Type}|Left], Records) ->
- TypeString =
- case cerl:is_literal(Type) of
-%% Commented out so that dialyzer does not complain
-%% false ->
-%% "fun(" ++ String = erl_types:t_to_string(Type, Records),
-%% string:substr(String, 1, length(String)-1);
- true ->
- io_lib:format("~w", [cerl:concrete(Type)])
- end,
- io:format("~w:~w~s\n", [M, F, TypeString]),
- pp_signatures(Left, Records);
-pp_signatures([], _Records) ->
- ok.
-
--ifdef(DEBUG_PP).
-debug_pp(Tree, _Map) ->
- Tree1 = strip_annotations(Tree),
- io:put_chars(cerl_prettypr:format(Tree1)),
- io:nl().
-
-strip_annotations(Tree) ->
- cerl_trees:map(fun(T) ->
- case cerl:is_literal(T) orelse cerl:is_c_values(T) of
- true -> cerl:set_ann(T, []);
- false ->
- Label = cerl_trees:get_label(T),
- cerl:set_ann(T, [{'label', Label}])
- end
- end, Tree).
--else.
-debug_pp(_Tree, _Map) ->
- ok.
--endif. % DEBUG_PP
-
-%%
-%% Analysis of a single module
-%%
-analyze_module(LabeledTree, NextLbl, Plt, Records, Contracts) ->
- debug_pp(LabeledTree, dict:new()),
- CallGraph1 = dialyzer_callgraph:new(),
- CallGraph2 = dialyzer_callgraph:scan_core_tree(LabeledTree, CallGraph1),
- {CallGraph3, _Ext} = dialyzer_callgraph:remove_external(CallGraph2),
- CallGraph4 = dialyzer_callgraph:finalize(CallGraph3),
- CodeServer1 = dialyzer_codeserver:new(),
- Mod = cerl:concrete(cerl:module_name(LabeledTree)),
- CodeServer2 = dialyzer_codeserver:insert(Mod, LabeledTree, CodeServer1),
- CodeServer3 = dialyzer_codeserver:set_next_core_label(NextLbl, CodeServer2),
- CodeServer4 = dialyzer_codeserver:store_records(Mod, Records, CodeServer3),
- CodeServer5 = dialyzer_codeserver:store_contracts(Mod, Contracts, CodeServer4),
- Res = analyze_callgraph(CallGraph4, Plt, CodeServer5),
- dialyzer_callgraph:delete(CallGraph4),
- dialyzer_codeserver:delete(CodeServer5),
- Res.
diff --git a/lib/dialyzer/src/dialyzer_timing.erl b/lib/dialyzer/src/dialyzer_timing.erl
new file mode 100644
index 0000000000..b1a4bdc07c
--- /dev/null
+++ b/lib/dialyzer/src/dialyzer_timing.erl
@@ -0,0 +1,133 @@
+%% -*- erlang-indent-level: 2 -*-
+%%-------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2012. 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : dialyzer_timing.erl
+%%% Authors : Stavros Aronis <[email protected]>
+%%% Description : Timing reports for Dialyzer
+%%%-------------------------------------------------------------------
+
+-module(dialyzer_timing).
+
+-export([init/1, start_stamp/2, send_size_info/3, end_stamp/1, stop/1]).
+
+-export_type([timing_server/0]).
+
+-type timing_server() :: pid() | 'none'.
+
+-spec init(boolean() | 'debug') -> timing_server().
+
+init(Active) ->
+ case Active of
+ true ->
+ io:format("\n"),
+ spawn_link(fun() -> loop(now(), 0, "") end);
+ debug ->
+ io:format("\n"),
+ spawn_link(fun() -> debug_loop("") end);
+ false -> none
+ end.
+
+loop(LastNow, Size, Unit) ->
+ receive
+ {stamp, Msg, Now} ->
+ io:format(" ~-10s (+~4.2fs):", [Msg, diff(Now, LastNow)]),
+ loop(Now, 0, "");
+ {stamp, Now} ->
+ SizeStr =
+ case Size of
+ 0 -> "";
+ _ ->
+ Data = io_lib:format("~p ~s",[Size, Unit]),
+ io_lib:format(" (~12s)",[Data])
+ end,
+ io:format("~7.2fs~s\n", [diff(Now, LastNow), SizeStr]),
+ loop(Now, 0, "");
+ {size, NewSize, NewUnit} ->
+ loop(LastNow, NewSize, NewUnit);
+ {Pid, stop, Now} ->
+ io:format(" ~-9s (+~5.2fs)\n", ["",diff(Now, LastNow)]),
+ Pid ! ok;
+ {Pid, stop} ->
+ Pid ! ok
+ end.
+
+debug_loop(Phase) ->
+ receive
+ Message ->
+ {Runtime,_} = statistics(wall_clock),
+ Procs = erlang:system_info(process_count),
+ ProcMem = erlang:memory(total),
+ Status = io_lib:format("~12w ~6w ~20w", [Runtime, Procs, ProcMem]),
+ case Message of
+ {stamp, Msg, _Now} ->
+ io:format("~s ~s_start\n", [Status, Msg]),
+ debug_loop(Msg);
+ {stamp, _Now} ->
+ io:format("~s ~s_stop\n", [Status, Phase]),
+ debug_loop("");
+ {Pid, stop, _Now} ->
+ Pid ! ok;
+ {Pid, stop} ->
+ Pid ! ok;
+ _ ->
+ debug_loop(Phase)
+ end
+ after
+ 50 ->
+ {Runtime,_} = statistics(wall_clock),
+ Procs = erlang:system_info(process_count),
+ ProcMem = erlang:memory(total),
+ Status = io_lib:format("~12w ~6w ~20w", [Runtime, Procs, ProcMem]),
+ io:format("~s\n", [Status]),
+ debug_loop(Phase)
+ end.
+
+
+-spec start_stamp(timing_server(), string()) -> ok.
+
+start_stamp(none, _) -> ok;
+start_stamp(Pid, Msg) ->
+ Pid ! {stamp, Msg, now()},
+ ok.
+
+-spec end_stamp(timing_server()) -> ok.
+
+end_stamp(none) -> ok;
+end_stamp(Pid) ->
+ Pid ! {stamp, now()},
+ ok.
+
+-spec send_size_info(timing_server(), integer(), string()) -> ok.
+
+send_size_info(none, _, _) -> ok;
+send_size_info(Pid, Size, Unit) ->
+ Pid ! {size, Size, Unit},
+ ok.
+
+-spec stop(timing_server()) -> ok.
+
+stop(none) -> ok;
+stop(Pid) ->
+ Pid ! {self(), stop, now()},
+ receive ok -> ok end.
+
+diff(T2, T1) ->
+ timer:now_diff(T2,T1) / 1000000.
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index d0d27740f3..0df003a035 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -28,7 +28,7 @@
-module(dialyzer_typesig).
--export([analyze_scc/5]).
+-export([analyze_scc/6]).
-export([get_safe_underapprox/2]).
-import(erl_types,
@@ -78,6 +78,8 @@
-record(constraint_list, {type :: 'conj' | 'disj',
list :: [constr()],
deps :: [dep()],
+ masks :: [{dep(),[non_neg_integer()]}] |
+ {'d',dict()},
id :: {'list', dep()}}).
-type constraint_list() :: #constraint_list{}.
@@ -91,23 +93,26 @@
-type typesig_scc() :: [{mfa(), {cerl:c_var(), cerl:c_fun()}, dict()}].
-type typesig_funmap() :: [{type_var(), type_var()}]. %% Orddict
--record(state, {callgraph :: dialyzer_callgraph:callgraph(),
- cs = [] :: [constr()],
- cmap = dict:new() :: dict(),
- fun_map = [] :: typesig_funmap(),
- fun_arities = dict:new() :: dict(),
- in_match = false :: boolean(),
- in_guard = false :: boolean(),
- module :: module(),
- name_map = dict:new() :: dict(),
- next_label :: label(),
- self_recs :: [label()],
- plt :: dialyzer_plt:plt(),
- prop_types = dict:new() :: dict(),
- records = dict:new() :: dict(),
- opaques = [] :: [erl_types:erl_type()],
- scc = [] :: [type_var()],
- mfas = [] :: [dialyzer_callgraph:mfa_or_funlbl()]
+-type dict_or_ets() :: {'d', dict()} | {'e', ets:tid()}.
+
+-record(state, {callgraph :: dialyzer_callgraph:callgraph(),
+ cs = [] :: [constr()],
+ cmap = {'d', dict:new()} :: dict_or_ets(),
+ fun_map = [] :: typesig_funmap(),
+ fun_arities = dict:new() :: dict(),
+ in_match = false :: boolean(),
+ in_guard = false :: boolean(),
+ module :: module(),
+ name_map = dict:new() :: dict(),
+ next_label = 0 :: label(),
+ self_rec :: erl_types:erl_type(),
+ plt :: dialyzer_plt:plt(),
+ prop_types = {'d', dict:new()} :: dict_or_ets(),
+ records = dict:new() :: dict(),
+ opaques = [] :: [erl_types:erl_type()],
+ scc = [] :: [type_var()],
+ mfas :: [tuple()],
+ solvers = [] :: [solver()]
}).
%%-----------------------------------------------------------------------------
@@ -119,8 +124,10 @@
%%-define(DEBUG_CONSTRAINTS, true).
-ifdef(DEBUG).
-define(DEBUG_NAME_MAP, true).
+-define(DEBUG_LOOP_DETECTION, true).
-endif.
%%-define(DEBUG_NAME_MAP, true).
+%%-define(DEBUG_LOOP_DETECTION, true).
-ifdef(DEBUG).
-define(debug(__String, __Args), io:format(__String, __Args)).
@@ -139,7 +146,7 @@
%%-----------------------------------------------------------------------------
%% Analysis of strongly connected components.
%%
-%% analyze_scc(SCC, NextLabel, CallGraph, PLT, PropTypes) -> FunTypes
+%% analyze_scc(SCC, NextLabel, CallGraph, PLT, PropTypes, Solvers) -> FunTypes
%%
%% SCC - [{MFA, Def, Records}]
%% where Def = {Var, Fun} as in the Core Erlang module definitions.
@@ -152,15 +159,17 @@
%% about functions that can be called by this SCC.
%% PropTypes - A dictionary.
%% FunTypes - A dictionary.
+%% Solvers - User specified solvers.
%%-----------------------------------------------------------------------------
-spec analyze_scc(typesig_scc(), label(),
dialyzer_callgraph:callgraph(),
- dialyzer_plt:plt(), dict()) -> dict().
+ dialyzer_plt:plt(), dict(), [solver()]) -> dict().
-analyze_scc(SCC, NextLabel, CallGraph, Plt, PropTypes) ->
+analyze_scc(SCC, NextLabel, CallGraph, Plt, PropTypes, Solvers0) ->
+ Solvers = solvers(Solvers0),
assert_format_of_scc(SCC),
- State1 = new_state(SCC, NextLabel, CallGraph, Plt, PropTypes),
+ State1 = new_state(SCC, NextLabel, CallGraph, Plt, PropTypes, Solvers),
DefSet = add_def_list([Var || {_MFA, {Var, _Fun}, _Rec} <- SCC], sets:new()),
State2 = traverse_scc(SCC, DefSet, State1),
State3 = state__finalize(State2),
@@ -174,6 +183,9 @@ assert_format_of_scc([{_MFA, {_Var, _Fun}, _Records}|Left]) ->
assert_format_of_scc([]) ->
ok.
+solvers([]) -> [v2];
+solvers(Solvers) -> Solvers.
+
%% ============================================================================
%%
%% Gets the constraints by traversing the code.
@@ -1661,18 +1673,23 @@ get_bif_test_constr(Dst, Arg, Type, State) ->
solve([Fun], State) ->
?debug("============ Analyzing Fun: ~w ===========\n",
[debug_lookup_name(Fun)]),
- solve_fun(Fun, dict:new(), State);
+ solve_fun(Fun, map_new(), State);
solve([_|_] = SCC, State) ->
?debug("============ Analyzing SCC: ~w ===========\n",
[[debug_lookup_name(F) || F <- SCC]]),
- solve_scc(SCC, dict:new(), State, false).
+ {Parallel, NewState} =
+ case parallel_split(SCC) of
+ false -> {false, State};
+ SplitSCC -> {SplitSCC, minimize_state(State)}
+ end,
+ solve_scc(SCC, Parallel, map_new(), NewState, false).
solve_fun(Fun, FunMap, State) ->
Cs = state__get_cs(Fun, State),
Deps = get_deps(Cs),
Ref = mk_constraint_ref(Fun, Deps),
%% Note that functions are always considered to succeed.
- {ok, _MapDict, NewMap} = solve_ref_or_list(Ref, FunMap, dict:new(), State),
+ NewMap = solve(Fun, Ref, FunMap, State),
NewType = lookup_type(Fun, NewMap),
NewFunMap1 = case state__get_rec_var(Fun, State) of
error -> FunMap;
@@ -1680,21 +1697,23 @@ solve_fun(Fun, FunMap, State) ->
end,
enter_type(Fun, NewType, NewFunMap1).
-solve_scc(SCC, Map, State, TryingUnit) ->
- State1 = state__mark_as_non_self_rec(SCC, State),
+solve_scc(SCC, Parallel, Map, State, TryingUnit) ->
Vars0 = [{Fun, state__get_rec_var(Fun, State)} || Fun <- SCC],
Vars = [Var || {_, {ok, Var}} <- Vars0],
Funs = [Fun || {Fun, {ok, _}} <- Vars0],
Types = unsafe_lookup_type_list(Funs, Map),
RecTypes = [t_limit(Type, ?TYPE_LIMIT) || Type <- Types],
CleanMap = lists:foldl(fun(Fun, AccFunMap) ->
- dict:erase(t_var_name(Fun), AccFunMap)
+ erase_type(t_var_name(Fun), AccFunMap)
end, Map, SCC),
Map1 = enter_type_lists(Vars, RecTypes, CleanMap),
?debug("Checking SCC: ~w\n", [[debug_lookup_name(F) || F <- SCC]]),
- SolveFun = fun(X, Y) -> scc_fold_fun(X, Y, State1) end,
- Map2 = lists:foldl(SolveFun, Map1, SCC),
FunSet = ordsets:from_list([t_var_name(F) || F <- SCC]),
+ Map2 =
+ case Parallel of
+ false -> solve_whole_scc(SCC, Map1, State);
+ SplitSCC -> solve_whole_scc_parallel(SplitSCC, Map1, State)
+ end,
case maps_are_equal(Map2, Map, FunSet) of
true ->
?debug("SCC ~w reached fixpoint\n", [SCC]),
@@ -1708,20 +1727,134 @@ solve_scc(SCC, Map, State, TryingUnit) ->
true -> t_fun(t_fun_args(T), t_unit())
end || T <- NewTypes],
Map3 = enter_type_lists(Funs, UnitTypes, Map2),
- solve_scc(SCC, Map3, State, true);
+ solve_scc(SCC, Parallel, Map3, State, true);
false ->
+ case Parallel of
+ false -> true;
+ _ -> dispose_state(State)
+ end,
Map2
end;
false ->
?debug("SCC ~w did not reach fixpoint\n", [SCC]),
- solve_scc(SCC, Map2, State, TryingUnit)
+ solve_scc(SCC, Parallel, Map2, State, TryingUnit)
+ end.
+
+solve_whole_scc(SCC, Map, State) ->
+ SolveFun = fun(X, Y) -> scc_fold_fun(X, Y, State) end,
+ lists:foldl(SolveFun, Map, SCC).
+
+%%------------------------------------------------------------------------------
+
+-define(worth_it, 42).
+
+parallel_split(SCC) ->
+ Length = length(SCC),
+ case Length > 2*?worth_it of
+ false -> false;
+ true ->
+ case min(dialyzer_utils:parallelism(), 8) of
+ 1 -> false;
+ CPUs ->
+ FullShare = Length div CPUs + 1,
+ Unit = max(FullShare, ?worth_it),
+ split(SCC, Unit, [])
+ end
+ end.
+
+minimize_state(#state{
+ cmap = {d, CMap},
+ fun_map = FunMap,
+ fun_arities = FunArities,
+ self_rec = SelfRec,
+ prop_types = {d, PropTypes},
+ opaques = Opaques,
+ solvers = Solvers
+ }) ->
+ ETSCMap = ets:new(cmap,[{read_concurrency, true}]),
+ ETSPropTypes = ets:new(prop_types,[{read_concurrency, true}]),
+ true = ets:insert(ETSCMap, dict:to_list(CMap)),
+ true = ets:insert(ETSPropTypes, dict:to_list(PropTypes)),
+ #state
+ {cmap = {e, ETSCMap},
+ fun_map = FunMap,
+ fun_arities = FunArities,
+ self_rec = SelfRec,
+ prop_types = {e, ETSPropTypes},
+ opaques = Opaques,
+ solvers = Solvers
+ }.
+
+dispose_state(#state{cmap = {e, ETSCMap},
+ prop_types = {e, ETSPropTypes}}) ->
+ true = ets:delete(ETSCMap),
+ true = ets:delete(ETSPropTypes).
+
+solve_whole_scc_parallel(SplitSCC, Map, State) ->
+ Workers = spawn_workers(SplitSCC, Map, State),
+ wait_results(Workers, Map, fold_res_fun(State)).
+
+spawn_workers(SplitSCC, Map, State) ->
+ Spawner = solve_scc_spawner(self(), Map, State),
+ lists:foreach(Spawner, SplitSCC),
+ length(SplitSCC).
+
+wait_results(0, Map, _FoldResFun) ->
+ Map;
+wait_results(Pending, Map, FoldResFun) ->
+ Res = receive_scc_result(),
+ NewMap = lists:foldl(FoldResFun, Map, Res),
+ wait_results(Pending-1, NewMap, FoldResFun).
+
+solve_scc_spawner(Parent, Map, State) ->
+ fun(SCCPart) ->
+ spawn_link(fun() -> solve_scc_worker(Parent, SCCPart, Map, State) end)
+ end.
+
+split([], _Unit, Acc) ->
+ Acc;
+split(List, Unit, Acc) ->
+ {Taken, Rest} =
+ try
+ lists:split(Unit, List)
+ catch
+ _:_ -> {List, []}
+ end,
+ split(Rest, Unit, [Taken|Acc]).
+
+solve_scc_worker(Parent, SCCPart, Map, State) ->
+ SolveFun = fun(X, Y) -> scc_fold_fun(X, Y, State) end,
+ FinalMap = lists:foldl(SolveFun, Map, SCCPart),
+ Res =
+ [{F, t_limit(unsafe_lookup_type(F, FinalMap), ?TYPE_LIMIT)} ||
+ F <- SCCPart],
+ send_scc_result(Parent, Res).
+
+fold_res_fun(State) ->
+ fun({F, Type}, Map) ->
+ case state__get_rec_var(F, State) of
+ {ok, R} ->
+ enter_type(R, Type, enter_type(F, Type, Map));
+ error ->
+ enter_type(F, Type, Map)
+ end
end.
+receive_scc_result() ->
+ receive
+ {scc_fun, Res} -> Res
+ end.
+
+send_scc_result(Parent, Res) ->
+ Parent ! {scc_fun, Res}.
+
+%%------------------------------------------------------------------------------
+
scc_fold_fun(F, FunMap, State) ->
Deps = get_deps(state__get_cs(F, State)),
Cs = mk_constraint_ref(F, Deps),
%% Note that functions are always considered to succeed.
- {ok, _NewMapDict, Map} = solve_ref_or_list(Cs, FunMap, dict:new(), State),
+ Map = solve(F, Cs, FunMap, State),
NewType0 = unsafe_lookup_type(F, Map),
NewType = t_limit(NewType0, ?TYPE_LIMIT),
NewFunMap = case state__get_rec_var(F, State) of
@@ -1734,15 +1867,440 @@ scc_fold_fun(F, FunMap, State) ->
format_type(NewType)]),
NewFunMap.
+solve(Fun, Cs, FunMap, State) ->
+ Solvers = State#state.solvers,
+ R = [solver(S, solve_fun(S, Fun, Cs, FunMap, State)) || S <- Solvers],
+ check_solutions(R, Fun, no_solver, no_map).
+
+solver(Solver, SolveFun) ->
+ ?debug("Start solver ~w\n", [Solver]),
+ try timer:tc(SolveFun) of
+ {Time, {ok, Map}} ->
+ ?debug("End solver ~w (~w microsecs)\n", [Solver, Time]),
+ {Solver, Map, Time};
+ {_, _R} ->
+ ?debug("Solver ~w returned unexpected result:\n ~P\n",
+ [Solver, _R, 60]),
+ throw(error)
+ catch E:R ->
+ io:format("Solver ~w failed: ~w:~p\n ~p\n",
+ [Solver, E, R, erlang:get_stacktrace()]),
+ throw(error)
+ end.
+
+solve_fun(v1, _Fun, Cs, FunMap, State) ->
+ fun() ->
+ {ok, _MapDict, NewMap} = solve_ref_or_list(Cs, FunMap, dict:new(), State),
+ {ok, NewMap}
+ end;
+solve_fun(v2, Fun, _Cs, FunMap, State) ->
+ fun() -> v2_solve_ref(Fun, FunMap, State) end.
+
+check_solutions([], _Fun, _S, Map) ->
+ Map;
+check_solutions([{S1,Map1,_Time1}|Maps], Fun, S, Map) ->
+ ?debug("Solver ~w needed ~w microsecs\n", [S1, _Time1]),
+ case Map =:= no_map orelse sane_maps(Map, Map1, [Fun], S, S1) of
+ true ->
+ check_solutions(Maps, Fun, S1, Map1);
+ false ->
+ ?debug("Constraint solvers do not agree on ~w\n", [Fun]),
+ pp_map(atom_to_list(S), Map),
+ pp_map(atom_to_list(S1), Map1),
+ io:format("A bug was found. Please report it, and use the option "
+ "`--solver v1' until the bug has been fixed.\n"),
+ throw(error)
+ end.
+
+sane_maps(Map1, Map2, Keys, _S1, _S2) ->
+ lists:all(fun(Key) ->
+ V1 = unsafe_lookup_type(Key, Map1),
+ V2 = unsafe_lookup_type(Key, Map2),
+ case t_is_equal(V1, V2) of
+ true -> true;
+ false ->
+ ?debug("Constraint solvers do not agree on ~w\n", [Key]),
+ ?debug("~w: ~s\n",
+ [_S1, format_type(unsafe_lookup_type(Key, Map1))]),
+ ?debug("~w: ~s\n",
+ [_S2, format_type(unsafe_lookup_type(Key, Map2))]),
+ false
+ end
+ end, Keys).
+
+%% Solver v2
+
+-record(v2_state, {constr_data = dict:new() :: dict(),
+ state :: #state{}}).
+
+v2_solve_ref(Fun, Map, State) ->
+ V2State = #v2_state{state = State},
+ {ok, NewMap, _, _} = v2_solve_reference(Fun, Map, V2State),
+ {ok, NewMap}.
+
+v2_solve(#constraint{}=C, Map, V2State) ->
+ State = V2State#v2_state.state,
+ case solve_one_c(C, Map, State#state.opaques) of
+ error ->
+ report_failed_constraint(C, Map),
+ {error, V2State};
+ {ok, {NewMap, U}} ->
+ {ok, NewMap, V2State, U}
+ end;
+v2_solve(#constraint_list{type = disj}=C, Map, V2State) ->
+ v2_solve_disjunct(C, Map, V2State);
+v2_solve(#constraint_list{type = conj}=C, Map, V2State) ->
+ v2_solve_conjunct(C, Map, V2State);
+v2_solve(#constraint_ref{id = Id}, Map, V2State) ->
+ v2_solve_reference(Id, Map, V2State).
+
+v2_solve_reference(Id, Map, V2State0) ->
+ ?debug("Checking ref to fun: ~w\n", [debug_lookup_name(Id)]),
+ pp_map("Map", Map),
+ pp_constr_data("solve_ref", V2State0),
+ Map1 = restore_local_map(V2State0, Id, Map),
+ State = V2State0#v2_state.state,
+ Cs = state__get_cs(Id, State),
+ Res =
+ case state__is_self_rec(Id, State) of
+ true -> v2_solve_self_recursive(Cs, Map1, Id, t_none(), V2State0);
+ false -> v2_solve(Cs, Map1, V2State0)
+ end,
+ {FunType, V2State} =
+ case Res of
+ {error, V2State1} ->
+ ?debug("Error solving for function ~p\n", [debug_lookup_name(Id)]),
+ Arity = state__fun_arity(Id, State),
+ FunType0 =
+ case state__prop_domain(t_var_name(Id), State) of
+ error -> t_fun(Arity, t_none());
+ {ok, Dom} -> t_fun(Dom, t_none())
+ end,
+ {FunType0, V2State1};
+ {ok, NewMap, V2State1, U} ->
+ ?debug("Done solving fun: ~p\n", [debug_lookup_name(Id)]),
+ FunType0 = lookup_type(Id, NewMap),
+ V2State2 = save_local_map(V2State1, Id, U, NewMap),
+ {FunType0, V2State2}
+ end,
+ ?debug("ref Id=~w Assigned ~s\n", [Id, format_type(FunType)]),
+ {NewMap1, U1} = enter_var_type(Id, FunType, Map),
+ {NewMap2, U2} =
+ case state__get_rec_var(Id, State) of
+ {ok, Var} -> enter_var_type(Var, FunType, NewMap1);
+ error -> {NewMap1, []}
+ end,
+ {ok, NewMap2, V2State, lists:umerge(U1, U2)}.
+
+v2_solve_self_recursive(Cs, Map, Id, RecType0, V2State0) ->
+ ?debug("Solving self recursive ~w\n", [debug_lookup_name(Id)]),
+ State = V2State0#v2_state.state,
+ {ok, RecVar} = state__get_rec_var(Id, State),
+ ?debug("OldRecType ~s\n", [format_type(RecType0)]),
+ RecType = t_limit(RecType0, ?TYPE_LIMIT),
+ {Map1, U0} = enter_var_type(RecVar, RecType, Map),
+ V2State1 = save_updated_vars1(V2State0, Cs, U0), % Probably not necessary
+ case v2_solve(Cs, Map1, V2State1) of
+ {error, _V2State}=Error ->
+ case t_is_none(RecType0) of
+ true ->
+ %% Try again and assume that this is a non-terminating function.
+ Arity = state__fun_arity(Id, State),
+ NewRecType = t_fun(lists:duplicate(Arity, t_any()), t_unit()),
+ v2_solve_self_recursive(Cs, Map, Id, NewRecType, V2State0);
+ false ->
+ Error
+ end;
+ {ok, NewMap, V2State, U} ->
+ pp_map("recursive finished", NewMap),
+ NewRecType = unsafe_lookup_type(Id, NewMap),
+ case t_is_equal(NewRecType, RecType0) of
+ true ->
+ {NewMap2, U1} = enter_var_type(RecVar, NewRecType, NewMap),
+ {ok, NewMap2, V2State, lists:umerge(U, U1)};
+ false ->
+ v2_solve_self_recursive(Cs, Map, Id, NewRecType, V2State0)
+ end
+ end.
+
+enter_var_type(Var, Type, Map0) ->
+ {Map, Vs} = enter_type2(Var, Type, Map0),
+ {Map, [t_var_name(V) || V <- Vs]}.
+
+v2_solve_disjunct(Disj, Map, V2State0) ->
+ #constraint_list{type = disj, id = _Id, list = Cs, masks = Masks} = Disj,
+ ?debug("disjunct Id=~w~n", [_Id]),
+ pp_map("Map", Map),
+ pp_constr_data("disjunct", V2State0),
+ case get_flags(V2State0, Disj) of
+ {V2State1, failed_list} -> {error, V2State1}; % cannot happen
+ {V2State1, Flags} when Flags =/= [] ->
+ {ok, V2State, Eval, UL, MapL0, Uneval, Failed} =
+ v2_solve_disj(Flags, Cs, 1, Map, V2State1, [], [], [], [], false),
+ ?debug("disj ending _Id=~w Eval=~w, |Uneval|=~w |UL|=~w~n",
+ [_Id, Eval, length(Uneval), length(UL)]),
+ if Eval =:= [], Uneval =:= [] ->
+ {error, failed_list(Disj, V2State0)};
+ true ->
+ {Is0, UnIds} = lists:unzip(Uneval),
+ MapL = [restore_local_map(V2State, Id, Map) ||
+ Id <- UnIds] ++ MapL0,
+ %% If some branch has just failed every variable of the
+ %% non-failed branches need to be checked, not just the
+ %% updated ones.
+ U0 = case Failed of
+ false -> lists:umerge(UL);
+ true -> constrained_keys(MapL)
+ end,
+ if U0 =:= [] -> {ok, Map, V2State, []};
+ true ->
+ NotFailed = lists:umerge(Is0, Eval),
+ U1 = [V || V <- U0,
+ var_occurs_everywhere(V, Masks, NotFailed)],
+ NewMap = join_maps(U1, MapL, Map),
+ pp_map("NewMap", NewMap),
+ U = updated_vars_only(U1, Map, NewMap),
+ ?debug("disjunct finished _Id=~w\n", [_Id]),
+ {ok, NewMap, V2State, U}
+ end
+ end
+ end.
+
+var_occurs_everywhere(V, Masks, NotFailed) ->
+ ordsets:is_subset(NotFailed, get_mask(V, Masks)).
+
+v2_solve_disj([I|Is], [C|Cs], I, Map0, V2State0, UL, MapL, Eval, Uneval,
+ Failed0) ->
+ Id = C#constraint_list.id,
+ Map1 = restore_local_map(V2State0, Id, Map0),
+ case v2_solve(C, Map1, V2State0) of
+ {error, V2State} ->
+ ?debug("disj error I=~w~n", [I]),
+ Failed = Failed0 orelse not is_failed_list(C, V2State0),
+ v2_solve_disj(Is, Cs, I+1, Map0, V2State, UL, MapL, Eval, Uneval, Failed);
+ {ok, Map, V2State1, U} ->
+ ?debug("disj I=~w U=~w~n", [I, U]),
+ V2State = save_local_map(V2State1, Id, U, Map),
+ pp_map("DMap", Map),
+ v2_solve_disj(Is, Cs, I+1, Map0, V2State, [U|UL], [Map|MapL],
+ [I|Eval], Uneval, Failed0)
+ end;
+v2_solve_disj([], [], _I, _Map, V2State, UL, MapL, Eval, Uneval, Failed) ->
+ {ok, V2State, lists:reverse(Eval), UL, MapL, lists:reverse(Uneval), Failed};
+v2_solve_disj(Is, [C|Cs], I, Map, V2State, UL, MapL, Eval, Uneval0, Failed) ->
+ Uneval = [{I,C#constraint_list.id} ||
+ not is_failed_list(C, V2State)] ++ Uneval0,
+ v2_solve_disj(Is, Cs, I+1, Map, V2State, UL, MapL, Eval, Uneval, Failed).
+
+save_local_map(#v2_state{constr_data = ConData}=V2State, Id, U, Map) ->
+ Part0 = [{V,dict:fetch(V, Map)} || V <- U],
+ Part1 =
+ case dict:find(Id, ConData) of
+ error -> []; % cannot happen
+ {ok, {Part2,[]}} -> Part2
+ end,
+ ?debug("save local map Id=~w:\n", [Id]),
+ Part = lists:ukeymerge(1, lists:keysort(1, Part0), Part1),
+ pp_map("New Part", dict:from_list(Part0)),
+ pp_map("Old Part", dict:from_list(Part1)),
+ pp_map(" => Part", dict:from_list(Part)),
+ V2State#v2_state{constr_data = dict:store(Id, {Part,[]}, ConData)}.
+
+restore_local_map(#v2_state{constr_data = ConData}, Id, Map0) ->
+ case dict:find(Id, ConData) of
+ error -> Map0;
+ {ok, failed} -> Map0;
+ {ok, {[],_}} -> Map0;
+ {ok, {Part0,U}} ->
+ Part = [{K,V} || {K,V} <- Part0, not lists:member(K, U)],
+ ?debug("restore local map Id=~w U=~w\n", [Id, U]),
+ pp_map("Part", dict:from_list(Part)),
+ pp_map("Map0", Map0),
+ Map = lists:foldl(fun({K,V}, D) -> dict:store(K, V, D)end, Map0, Part),
+ pp_map("Map", Map),
+ Map
+ end.
+
+v2_solve_conjunct(Conj, Map, V2State0) ->
+ #constraint_list{type = conj, list = Cs} = Conj,
+ ?debug("conjunct Id=~w~n", [Conj#constraint_list.id]),
+ IsFlat = case Cs of [#constraint{}|_] -> true; _ -> false end,
+ case get_flags(V2State0, Conj) of
+ {V2State, failed_list} -> {error, V2State};
+ {V2State, Flags} ->
+ v2_solve_conj(Flags, Cs, 1, Map, Conj, IsFlat, V2State, [], [], [],
+ Map, Flags)
+ end.
+
+%% LastMap and LastFlags are used for loop detection.
+v2_solve_conj([I|Is], [Cs|Tail], I, Map0, Conj, IsFlat, V2State0,
+ UL, NewFs0, VarsUp, LastMap, LastFlags) ->
+ ?debug("conj Id=~w I=~w~n", [Conj#constraint_list.id, I]),
+ true = IsFlat =:= is_record(Cs, constraint),
+ pp_constr_data("conj", V2State0),
+ case v2_solve(Cs, Map0, V2State0) of
+ {error, V2State1} -> {error, failed_list(Conj, V2State1)};
+ {ok, Map, V2State1, []} ->
+ v2_solve_conj(Is, Tail, I+1, Map, Conj, IsFlat, V2State1,
+ UL, NewFs0, VarsUp, LastMap, LastFlags);
+ {ok, Map, V2State1, U} when IsFlat -> % optimization
+ %% It is ensured by enumerate_constraints() that every
+ %% #constraint{} has a conjunct as parent, and that such a
+ %% parent has nothing but #constraint{}:s as children, a fact
+ %% which is used here to simplify the flag calculation.
+ Mask = lists:umerge([get_mask(V, Conj#constraint_list.masks) || V <- U]),
+ {Is1, NewF} = add_mask_to_flags(Is, Mask, I, []),
+ NewFs = [NewF|NewFs0],
+ v2_solve_conj(Is1, Tail, I+1, Map, Conj, IsFlat, V2State1,
+ [U|UL], NewFs, VarsUp, LastMap, LastFlags);
+ {ok, Map, V2State1, U} ->
+ #constraint_list{masks = Masks, list = AllCs} = Conj,
+ M = lists:keydelete(I, 1, vars_per_child(U, Masks)),
+ {V2State2, NewF0} = save_updated_vars_list(AllCs, M, V2State1),
+ {NewF, F} = lists:splitwith(fun(J) -> J < I end, NewF0),
+ Is1 = lists:umerge(Is, F),
+ NewFs = [NewF|NewFs0],
+ v2_solve_conj(Is1, Tail, I+1, Map, Conj, IsFlat, V2State2,
+ [U|UL], NewFs, VarsUp, LastMap, LastFlags)
+ end;
+v2_solve_conj([], _Cs, _I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
+ LastMap, LastFlags) ->
+ U = lists:umerge(UL),
+ case lists:umerge(NewFs) of
+ [] ->
+ ?debug("conjunct finished Id=~w\n", [Conj#constraint_list.id]),
+ {ok, Map, V2State, lists:umerge([U|VarsUp])};
+ NewFlags when NewFlags =:= LastFlags, Map =:= LastMap ->
+ %% A loop was detected! The cause is some bug, possibly in erl_types.
+ %% The evaluation continues, but the results can be wrong.
+ report_detected_loop(Conj),
+ {ok, Map, V2State, lists:umerge([U|VarsUp])};
+ NewFlags ->
+ #constraint_list{type = conj, list = Cs} = Conj,
+ v2_solve_conj(NewFlags, Cs, 1, Map, Conj, IsFlat, V2State,
+ [], [], [U|VarsUp], Map, NewFlags)
+ end;
+v2_solve_conj(Is, [_|Tail], I, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
+ LastMap, LastFlags) ->
+ v2_solve_conj(Is, Tail, I+1, Map, Conj, IsFlat, V2State, UL, NewFs, VarsUp,
+ LastMap, LastFlags).
+
+-ifdef(DEBUG_LOOP_DETECTION).
+report_detected_loop(Conj) ->
+ io:format("A loop was detected in ~w\n", [Conj#constraint_list.id]).
+-else.
+report_detected_loop(_) ->
+ ok.
+-endif.
+
+add_mask_to_flags(Flags, [Im|M], I, L) when I > Im ->
+ add_mask_to_flags(Flags, M, I, [Im|L]);
+add_mask_to_flags(Flags, [_|M], _I, L) ->
+ {lists:umerge(Flags, M), lists:reverse(L)}.
+
+get_mask(V, {d, Masks}) ->
+ case dict:find(V, Masks) of
+ error -> [];
+ {ok, M} -> M
+ end;
+get_mask(V, Masks) ->
+ case lists:keyfind(V, 1, Masks) of
+ false -> [];
+ {V, M} -> M
+ end.
+
+get_flags(#v2_state{constr_data = ConData}=V2State0, C) ->
+ #constraint_list{id = Id, list = Cs, masks = Masks} = C,
+ case dict:find(Id, ConData) of
+ error ->
+ ?debug("get_flags Id=~w Flags=all ~w\n", [Id, length(Cs)]),
+ V2State = V2State0#v2_state{constr_data = dict:store(Id, {[],[]}, ConData)},
+ {V2State, lists:seq(1, length(Cs))};
+ {ok, failed} ->
+ {V2State0, failed_list};
+ {ok, {Part,U}} when U =/= [] ->
+ ?debug("get_flags Id=~w U=~w\n", [Id, U]),
+ V2State = V2State0#v2_state{constr_data = dict:store(Id, {Part,[]}, ConData)},
+ save_updated_vars_list(Cs, vars_per_child(U, Masks), V2State)
+ end.
+
+vars_per_child(U, Masks) ->
+ family([{I, V} || V <- lists:usort(U), I <- get_mask(V, Masks)]).
+
+save_updated_vars_list(Cs, IU, V2State) ->
+ save_updated_vars_list1(Cs, IU, V2State, 1, []).
+
+save_updated_vars_list1([C|Cs], [{I,U}|IU], V2State0, I, Is) ->
+ V2State = save_updated_vars(C, U, V2State0),
+ save_updated_vars_list1(Cs, IU, V2State, I+1, [I|Is]);
+save_updated_vars_list1([], [], V2State, _I, Is) ->
+ {V2State, lists:reverse(Is)};
+save_updated_vars_list1([_|Cs], IU, V2State, I, Is) ->
+ save_updated_vars_list1(Cs, IU, V2State, I+1, Is).
+
+save_updated_vars(#constraint{}, _, V2State) ->
+ V2State;
+save_updated_vars(#constraint_list{}=C, U, V2State0) ->
+ save_updated_vars1(V2State0, C, U);
+save_updated_vars(#constraint_ref{id = Id}, U, V2State) ->
+ Cs = state__get_cs(Id, V2State#v2_state.state),
+ save_updated_vars(Cs, U, V2State).
+
+save_updated_vars1(V2State, C, U) ->
+ #v2_state{constr_data = ConData} = V2State,
+ #constraint_list{id = Id} = C,
+ case dict:find(Id, ConData) of
+ error -> V2State; % error means everything is flagged
+ {ok, failed} -> V2State;
+ {ok, {Part,U0}} ->
+ %% Duplicates are not so common; let masks/2 remove them.
+ U1 = U ++ U0,
+ V2State#v2_state{constr_data = dict:store(Id, {Part,U1}, ConData)}
+ end.
+
+-ifdef(DEBUG).
+pp_constr_data(_Tag, #v2_state{constr_data = D}) ->
+ io:format("Constr data at ~p\n", [_Tag]),
+ _ = [begin
+ case _PartU of
+ {_Part, _U} ->
+ io:format("Id: ~w Vars: ~w\n", [_Id, _U]),
+ [pp_map("Part", dict:from_list(_Part)) || _Part =/= []];
+ failed ->
+ io:format("Id: ~w failed list\n", [_Id])
+ end
+ end ||
+ {_Id, _PartU} <- lists:keysort(1, dict:to_list(D))],
+ ok.
+
+-else.
+pp_constr_data(_Tag, _V2State) ->
+ ok.
+-endif.
+
+failed_list(#constraint_list{id = Id}, #v2_state{constr_data = D}=V2State) ->
+ ?debug("error list ~w~n", [Id]),
+ V2State#v2_state{constr_data = dict:store(Id, failed, D)}.
+
+is_failed_list(#constraint_list{id = Id}, #v2_state{constr_data = D}) ->
+ dict:find(Id, D) =:= {ok, failed}.
+
+%% Solver v1
+
solve_ref_or_list(#constraint_ref{id = Id, deps = Deps},
Map, MapDict, State) ->
{OldLocalMap, Check} =
case dict:find(Id, MapDict) of
- error -> {dict:new(), false};
+ error -> {map_new(), false};
{ok, M} -> {M, true}
end,
?debug("Checking ref to fun: ~w\n", [debug_lookup_name(Id)]),
+ %% Note: mk_constraint_ref() has already removed Id from Deps. The
+ %% reason for doing it there is that it makes it easy for
+ %% calculate_masks() to make the corresponding adjustment for
+ %% version v2.
CheckDeps = ordsets:del_element(t_var_name(Id), Deps),
+ true = CheckDeps =:= Deps,
case Check andalso maps_are_equal(OldLocalMap, Map, CheckDeps) of
true ->
?debug("Equal\n", []),
@@ -1771,6 +2329,7 @@ solve_ref_or_list(#constraint_ref{id = Id, deps = Deps},
FunType0 = lookup_type(Id, NewMap),
{NewMapDict0, FunType0}
end,
+ ?debug(" Id=~w Assigned ~s\n", [Id, format_type(FunType)]),
NewMap1 = enter_type(Id, FunType, Map),
NewMap2 =
case state__get_rec_var(Id, State) of
@@ -1783,17 +2342,21 @@ solve_ref_or_list(#constraint_list{type=Type, list = Cs, deps = Deps, id = Id},
Map, MapDict, State) ->
{OldLocalMap, Check} =
case dict:find(Id, MapDict) of
- error -> {dict:new(), false};
+ error -> {map_new(), false};
{ok, M} -> {M, true}
end,
?debug("Checking ref to list: ~w\n", [Id]),
- case Check andalso maps_are_equal(OldLocalMap, Map, Deps) of
+ if
+ OldLocalMap =:= error -> {error, MapDict};
true ->
- ?debug("~w equal ~w\n", [Type, Id]),
- {ok, MapDict, Map};
- false ->
- ?debug("~w not equal: ~w. Solving\n", [Type, Id]),
- solve_clist(Cs, Type, Id, Deps, MapDict, Map, State)
+ case Check andalso maps_are_equal(OldLocalMap, Map, Deps) of
+ true ->
+ ?debug("~w equal ~w\n", [Type, Id]),
+ {ok, MapDict, Map};
+ false ->
+ ?debug("~w not equal: ~w. Solving\n", [Type, Id]),
+ solve_clist(Cs, Type, Id, Deps, MapDict, Map, State)
+ end
end.
solve_self_recursive(Cs, Map, MapDict, Id, RecType0, State) ->
@@ -1801,8 +2364,8 @@ solve_self_recursive(Cs, Map, MapDict, Id, RecType0, State) ->
{ok, RecVar} = state__get_rec_var(Id, State),
?debug("OldRecType ~s\n", [format_type(RecType0)]),
RecType = t_limit(RecType0, ?TYPE_LIMIT),
- Map1 = enter_type(RecVar, RecType, dict:erase(t_var_name(Id), Map)),
- ?debug("\tMap in: ~p\n",[[{X, format_type(Y)}||{X, Y}<-dict:to_list(Map1)]]),
+ Map1 = enter_type(RecVar, RecType, erase_type(t_var_name(Id), Map)),
+ pp_map("Map1", Map1),
case solve_ref_or_list(Cs, Map1, MapDict, State) of
{error, _} = Error ->
case t_is_none(RecType0) of
@@ -1815,8 +2378,7 @@ solve_self_recursive(Cs, Map, MapDict, Id, RecType0, State) ->
Error
end;
{ok, NewMapDict, NewMap} ->
- ?debug("\tMap: ~p\n",
- [[{X, format_type(Y)} || {X, Y} <- dict:to_list(NewMap)]]),
+ pp_map("NewMap", NewMap),
NewRecType = unsafe_lookup_type(Id, NewMap),
case t_is_equal(NewRecType, RecType0) of
true ->
@@ -1828,7 +2390,8 @@ solve_self_recursive(Cs, Map, MapDict, Id, RecType0, State) ->
solve_clist(Cs, conj, Id, Deps, MapDict, Map, State) ->
case solve_cs(Cs, Map, MapDict, State) of
- {error, _} = Error -> Error;
+ {error, NewMapDict} ->
+ {error, dict:store(Id, error, NewMapDict)};
{ok, NewMapDict, NewMap} = Ret ->
case Cs of
[_] ->
@@ -1850,7 +2413,7 @@ solve_clist(Cs, disj, Id, _Deps, MapDict, Map, State) ->
end,
{Maps, NewMapDict} = lists:mapfoldl(Fun, MapDict, Cs),
case [X || {ok, X} <- Maps] of
- [] -> {error, NewMapDict};
+ [] -> {error, dict:store(Id, error, NewMapDict)};
MapList ->
NewMap = join_maps(MapList),
{ok, dict:store(Id, NewMap, NewMapDict), NewMap}
@@ -1869,14 +2432,9 @@ solve_cs([#constraint_list{} = C|Tail], Map, MapDict, State) ->
solve_cs([#constraint{} = C|Tail], Map, MapDict, State) ->
case solve_one_c(C, Map, State#state.opaques) of
error ->
- ?debug("+++++++++++\nFailed: ~s :: ~s ~w ~s :: ~s\n+++++++++++\n",
- [format_type(C#constraint.lhs),
- format_type(lookup_type(C#constraint.lhs, Map)),
- C#constraint.op,
- format_type(C#constraint.rhs),
- format_type(lookup_type(C#constraint.rhs, Map))]),
+ report_failed_constraint(C, Map),
{error, MapDict};
- {ok, NewMap} ->
+ {ok, {NewMap, _U}} ->
solve_cs(Tail, NewMap, MapDict, State)
end;
solve_cs([], Map, MapDict, _State) ->
@@ -1897,7 +2455,11 @@ solve_one_c(#constraint{lhs = Lhs, rhs = Rhs, op = Op}, Map, Opaques) ->
eq ->
case solve_subtype(Lhs, Inf, Map, Opaques) of
error -> error;
- {ok, Map1} -> solve_subtype(Rhs, Inf, Map1, Opaques)
+ {ok, {Map1, U1}} ->
+ case solve_subtype(Rhs, Inf, Map1, Opaques) of
+ error -> error;
+ {ok, {Map2, U2}} -> {ok, {Map2, lists:umerge(U1, U2)}}
+ end
end
end
end.
@@ -1920,18 +2482,34 @@ solve_subtype(Type, Inf, Map, Opaques) ->
end.
%% end.
+report_failed_constraint(_C, _Map) ->
+ ?debug("+++++++++++\nFailed: ~s :: ~s ~w ~s :: ~s\n+++++++++++\n",
+ [format_type(_C#constraint.lhs),
+ format_type(lookup_type(_C#constraint.lhs, _Map)),
+ _C#constraint.op,
+ format_type(_C#constraint.rhs),
+ format_type(lookup_type(_C#constraint.rhs, _Map))]).
+
%% ============================================================================
%%
%% Maps and types.
%%
%% ============================================================================
+map_new() ->
+ dict:new().
+
+join_maps([Map]) ->
+ Map;
join_maps(Maps) ->
- Keys = lists:foldl(fun(TmpMap, AccKeys) ->
- [Key || Key <- AccKeys, dict:is_key(Key, TmpMap)]
- end,
- dict:fetch_keys(hd(Maps)), tl(Maps)),
- join_maps(Keys, Maps, dict:new()).
+ Keys = constrained_keys(Maps),
+ join_maps(Keys, Maps, map_new()).
+
+constrained_keys(Maps) ->
+ lists:foldl(fun(TmpMap, AccKeys) ->
+ [Key || Key <- AccKeys, dict:is_key(Key, TmpMap)]
+ end,
+ dict:fetch_keys(hd(Maps)), tl(Maps)).
join_maps([Key|Left], Maps = [Map|MapsLeft], AccMap) ->
NewType = join_one_key(Key, MapsLeft, lookup_type(Key, Map)),
@@ -1994,13 +2572,13 @@ enter_type(Key, Val, Map) when is_integer(Key) ->
?debug("Entering ~s :: ~s\n", [format_type(t_var(Key)), format_type(Val)]),
case t_is_any(Val) of
true ->
- dict:erase(Key, Map);
+ erase_type(Key, Map);
false ->
LimitedVal = t_limit(Val, ?INTERNAL_TYPE_LIMIT),
case dict:find(Key, Map) of
{ok, LimitedVal} -> Map;
- {ok, _} -> dict:store(Key, LimitedVal, Map);
- error -> dict:store(Key, LimitedVal, Map)
+ {ok, _} -> map_store(Key, LimitedVal, Map);
+ error -> map_store(Key, LimitedVal, Map)
end
end;
enter_type(Key, Val, Map) ->
@@ -2008,13 +2586,13 @@ enter_type(Key, Val, Map) ->
KeyName = t_var_name(Key),
case t_is_any(Val) of
true ->
- dict:erase(KeyName, Map);
+ erase_type(KeyName, Map);
false ->
LimitedVal = t_limit(Val, ?INTERNAL_TYPE_LIMIT),
case dict:find(KeyName, Map) of
{ok, LimitedVal} -> Map;
- {ok, _} -> dict:store(KeyName, LimitedVal, Map);
- error -> dict:store(KeyName, LimitedVal, Map)
+ {ok, _} -> map_store(KeyName, LimitedVal, Map);
+ error -> map_store(KeyName, LimitedVal, Map)
end
end.
@@ -2024,11 +2602,25 @@ enter_type_lists([Key|KeyTail], [Val|ValTail], Map) ->
enter_type_lists([], [], Map) ->
Map.
-enter_type_list([{Key, Val}|Tail], Map) ->
+enter_type_list(KeyVals, Map) ->
+ enter_type_list(KeyVals, Map, []).
+
+enter_type_list([{Key, Val}|Tail], Map, U0) ->
+ {Map1,U1} = enter_type2(Key, Val, Map),
+ enter_type_list(Tail, Map1, U1++U0);
+enter_type_list([], Map, U) ->
+ {Map, ordsets:from_list(U)}.
+
+enter_type2(Key, Val, Map) ->
Map1 = enter_type(Key, Val, Map),
- enter_type_list(Tail, Map1);
-enter_type_list([], Map) ->
- Map.
+ {Map1, [Key || not is_same(Key, Map, Map1)]}.
+
+map_store(Key, Val, Map) ->
+ ?debug("Storing ~w :: ~s\n", [Key, format_type(Val)]),
+ dict:store(Key, Val, Map).
+
+erase_type(Key, Map) ->
+ dict:erase(Key, Map).
lookup_type_list(List, Map) ->
[lookup_type(X, Map) || X <- List].
@@ -2079,22 +2671,41 @@ mk_var_no_lit(Var) ->
mk_var_no_lit_list(List) ->
[mk_var_no_lit(X) || X <- List].
+updated_vars_only(U, OldMap, NewMap) ->
+ [V || V <- U, not is_same(V, OldMap, NewMap)].
+
+is_same(Key, Map1, Map2) ->
+ t_is_equal(lookup_type(Key, Map1), lookup_type(Key, Map2)).
+
+pp_map(_S, _Map) ->
+ ?debug("\t~s: ~p\n",
+ [_S, [{X, lists:flatten(format_type(Y))} ||
+ {X, Y} <- lists:keysort(1, dict:to_list(_Map))]]).
+
%% ============================================================================
%%
%% The State.
%%
%% ============================================================================
-new_state(SCC0, NextLabel, CallGraph, Plt, PropTypes) ->
+new_state(SCC0, NextLabel, CallGraph, Plt, PropTypes, Solvers) ->
List = [{MFA, Var} || {MFA, {Var, _Fun}, _Rec} <- SCC0],
NameMap = dict:from_list(List),
MFAs = [MFA || {MFA, _Var} <- List],
SCC = [mk_var(Fun) || {_MFA, {_Var, Fun}, _Rec} <- SCC0],
- SelfRecs = [F || F <- SCC,
- dialyzer_callgraph:is_self_rec(t_var_name(F), CallGraph)],
+ SelfRec =
+ case SCC of
+ [OneF] ->
+ Label = t_var_name(OneF),
+ case dialyzer_callgraph:is_self_rec(Label, CallGraph) of
+ true -> OneF;
+ false -> false
+ end;
+ _Many -> false
+ end,
#state{callgraph = CallGraph, name_map = NameMap, next_label = NextLabel,
- prop_types = PropTypes, plt = Plt, scc = ordsets:from_list(SCC),
- mfas = MFAs, self_recs = ordsets:from_list(SelfRecs)}.
+ prop_types = {d, PropTypes}, plt = Plt, scc = ordsets:from_list(SCC),
+ mfas = MFAs, self_rec = SelfRec, solvers = Solvers}.
state__set_rec_dict(State, RecDict) ->
State#state{records = RecDict}.
@@ -2193,14 +2804,21 @@ state__plt(#state{plt = PLT}) ->
state__new_constraint_context(State) ->
State#state{cs = []}.
-state__prop_domain(FunLabel, #state{prop_types = PropTypes}) ->
+state__prop_domain(FunLabel, #state{prop_types = {e, ETSPropTypes}}) ->
+ try ets:lookup_element(ETSPropTypes, FunLabel, 2) of
+ {_Range_Fun, Dom} -> {ok, Dom};
+ FunType -> {ok, t_fun_args(FunType)}
+ catch
+ _:_ -> error
+ end;
+state__prop_domain(FunLabel, #state{prop_types = {d, PropTypes}}) ->
case dict:find(FunLabel, PropTypes) of
error -> error;
{ok, {_Range_Fun, Dom}} -> {ok, Dom};
{ok, FunType} -> {ok, t_fun_args(FunType)}
end.
-state__add_prop_constrs(Tree, #state{prop_types = PropTypes} = State) ->
+state__add_prop_constrs(Tree, #state{prop_types = {d, PropTypes}} = State) ->
Label = cerl_trees:get_label(Tree),
case dict:find(Label, PropTypes) of
error -> State;
@@ -2263,21 +2881,17 @@ state__mk_vars(N, #state{next_label = NL} = State) ->
Vars = [t_var(X) || X <- lists:seq(NL, NewLabel-1)],
{State#state{next_label = NewLabel}, Vars}.
-state__store_constrs(Id, Cs, #state{cmap = Dict} = State) ->
+state__store_constrs(Id, Cs, #state{cmap = {d, Dict}} = State) ->
NewDict = dict:store(Id, Cs, Dict),
- State#state{cmap = NewDict}.
+ State#state{cmap = {d, NewDict}}.
-state__get_cs(Var, #state{cmap = Dict}) ->
+state__get_cs(Var, #state{cmap = {e, ETSDict}}) ->
+ ets:lookup_element(ETSDict, Var, 2);
+state__get_cs(Var, #state{cmap = {d, Dict}}) ->
dict:fetch(Var, Dict).
-%% The functions here will not be treated as self recursive.
-%% These functions will need to be handled as such manually.
-state__mark_as_non_self_rec(SCC, #state{self_recs = SelfRecs} = State) ->
- %% TODO: Check if the result is always empty and just set it to [] if so.
- State#state{self_recs = ordsets:subtract(SelfRecs, ordsets:from_list(SCC))}.
-
-state__is_self_rec(Fun, #state{self_recs = SelfRecs}) ->
- ordsets:is_element(Fun, SelfRecs).
+state__is_self_rec(Fun, #state{self_rec = SelfRec}) ->
+ Fun =:= SelfRec.
state__store_funs(Vars0, Funs0, #state{fun_map = Map} = State) ->
debug_make_name_map(Vars0, Funs0),
@@ -2314,7 +2928,7 @@ mk_constraint(Lhs, Op, Rhs) ->
case Deps =:= [] of
true ->
%% This constraint is constant. Solve it immediately.
- case solve_one_c(C, dict:new(), []) of
+ case solve_one_c(C, map_new(), []) of
error -> throw(error);
_ ->
%% This is always true, keep it anyway for logistic reasons
@@ -2337,8 +2951,9 @@ constraint_opnd_is_any(Type) -> t_is_any(Type).
-ifdef(DEBUG).
--spec mk_fun_var(fun((_) -> erl_types:erl_type()), [erl_types:erl_type()],
- integer()) -> #fun_var{}.
+-spec mk_fun_var(integer(),
+ fun((_) -> erl_types:erl_type()),
+ [erl_types:erl_type()]) -> #fun_var{}.
mk_fun_var(Line, Fun, Types) ->
Deps = [t_var_name(Var) || Var <- t_collect_vars(t_product(Types))],
@@ -2386,7 +3001,9 @@ mk_constraints([], _Op, []) ->
[].
mk_constraint_ref(Id, Deps) ->
- #constraint_ref{id = Id, deps = Deps}.
+ %% See also solve_ref_or_list(), #constraint_ref{}.
+ Ds = ordsets:del_element(t_var_name(Id), Deps),
+ #constraint_ref{id = Id, deps = Ds}.
mk_constraint_list(Type, List) ->
List1 = ordsets:from_list(lift_lists(Type, List)),
@@ -2523,19 +3140,21 @@ enumerate_constraints([#constraint_ref{id = Id} = C|Tail], N, Acc, State) ->
enumerate_constraints([#constraint_list{type = conj, list = List} = C|Tail],
N, Acc, State) ->
%% Separate the flat constraints from the deep ones to make a
- %% separate fixpoint interation over the flat ones for speed.
- {Flat, Deep} = lists:splitwith(fun(#constraint{}) -> true;
+ %% separate fixpoint iteration over the flat ones for speed.
+ {Flat, Deep} = lists:partition(fun(#constraint{}) -> true;
(#constraint_list{}) -> false;
(#constraint_ref{}) -> false
end, List),
{NewFlat, N1, State1} = enumerate_constraints(Flat, N, [], State),
{NewDeep, N2, State2} = enumerate_constraints(Deep, N1, [], State1),
{NewList, N3} =
- case shorter_than_two(NewFlat) orelse (NewDeep =:= []) of
- true -> {NewFlat ++ NewDeep, N2};
- false ->
- {NewCLists, TmpN} = group_constraints_in_components(NewFlat, N2),
- {NewCLists ++ NewDeep, TmpN}
+ if
+ NewFlat =:= [] -> {NewDeep, N2};
+ NewDeep =:= [] -> {NewFlat, N2};
+ true ->
+ TmpCList = mk_conj_constraint_list(NewFlat),
+ {[TmpCList#constraint_list{id = {list, N2}}| NewDeep],
+ N2 + 1}
end,
NewAcc = [C#constraint_list{list = NewList, id = {list, N3}}|Acc],
enumerate_constraints(Tail, N3+1, NewAcc, State2);
@@ -2549,42 +3168,6 @@ enumerate_constraints([#constraint{} = C|Tail], N, Acc, State) ->
enumerate_constraints([], N, Acc, State) ->
{lists:reverse(Acc), N, State}.
-shorter_than_two([]) -> true;
-shorter_than_two([_]) -> true;
-shorter_than_two([_|_]) -> false.
-
-group_constraints_in_components(Cs, N) ->
- DepList = [Deps || #constraint{deps = Deps} <- Cs],
- case find_dep_components(DepList, []) of
- [_] -> {Cs, N};
- [_|_] = Components ->
- ConstrComp = [[C || #constraint{deps = D} = C <- Cs,
- ordsets:is_subset(D, Comp)]
- || Comp <- Components],
- lists:mapfoldl(fun(CComp, TmpN) ->
- TmpCList = mk_conj_constraint_list(CComp),
- {TmpCList#constraint_list{id = {list, TmpN}},
- TmpN + 1}
- end, N, ConstrComp)
- end.
-
-find_dep_components([Set|Left], AccComponents) ->
- {Component, Ungrouped} = find_dep_components(Left, Set, []),
- case Component =:= Set of
- true -> find_dep_components(Ungrouped, [Component|AccComponents]);
- false -> find_dep_components([Component|Ungrouped], AccComponents)
- end;
-find_dep_components([], AccComponents) ->
- AccComponents.
-
-find_dep_components([Set|Left], AccSet, Ungrouped) ->
- case ordsets:intersection(Set, AccSet) of
- [] -> find_dep_components(Left, AccSet, [Set|Ungrouped]);
- [_|_] -> find_dep_components(Left, ordsets:union(Set, AccSet), Ungrouped)
- end;
-find_dep_components([], AccSet, Ungrouped) ->
- {AccSet, Ungrouped}.
-
%% Put the fun ref constraints last in any conjunction since we need
%% to separate the environment from the interior of the function.
order_fun_constraints(State) ->
@@ -2615,7 +3198,9 @@ order_fun_constraints([#constraint_list{list = List, type = Type} = C|Tail],
end,
lists:mapfoldl(FoldFun, State, List)
end,
- NewAcc = [update_constraint_list(C, NewList)|Acc],
+ C1 = update_constraint_list(C, NewList),
+ Masks = calculate_masks(NewList, 1, []),
+ NewAcc = [update_masks(C1, Masks)|Acc],
order_fun_constraints(Tail, Funs, NewAcc, NewState);
order_fun_constraints([#constraint{} = C|Tail], Funs, Acc, State) ->
order_fun_constraints(Tail, Funs, [C|Acc], State);
@@ -2623,6 +3208,22 @@ order_fun_constraints([], Funs, Acc, State) ->
NewState = order_fun_constraints(Funs, State),
{lists:reverse(Acc)++Funs, NewState}.
+update_masks(C, Masks) ->
+ C#constraint_list{masks = Masks}.
+
+-define(VARS_LIMIT, 50).
+
+calculate_masks([C|Cs], I, L0) ->
+ calculate_masks(Cs, I+1, [{V, I} || V <- get_deps(C)] ++ L0);
+calculate_masks([], _I, L) ->
+ M = family(L),
+ case length(M) > ?VARS_LIMIT of
+ true ->
+ {d, dict:from_list(M)};
+ false ->
+ M
+ end.
+
%% ============================================================================
%%
%% Utilities.
@@ -2700,6 +3301,9 @@ lookup_record(Records, Tag, Arity) ->
error
end.
+family(L) ->
+ sofs:to_external(sofs:rel2fam(sofs:relation(L))).
+
%% ============================================================================
%%
%% Pretty printer and debug facilities.
@@ -2714,13 +3318,24 @@ lookup_record(Records, Tag, Arity) ->
-ifdef(DEBUG).
format_type(#fun_var{deps = Deps, origin = Origin}) ->
- io_lib:format("Fun@L~p(~s)",
- [Origin, lists:flatten([format_type(t_var(X))||X<-Deps])]);
+ L = [format_type(t_var(X)) || X <- Deps],
+ io_lib:format("Fun@L~p(~s)", [Origin, join_chars(L, ",")]);
format_type(Type) ->
case cerl:is_literal(Type) of
true -> io_lib:format("~w", [cerl:concrete(Type)]);
false -> erl_types:t_to_string(Type)
end.
+
+join_chars([], _Sep) ->
+ [];
+join_chars([H|T], Sep) ->
+ [H|[[Sep,X] || X <- T]].
+
+debug_lookup_name(Var) ->
+ case dict:find(t_var_name(Var), get(dialyzer_typesig_map)) of
+ error -> Var;
+ {ok, Name} -> Name
+ end.
-endif.
-ifdef(DEBUG_NAME_MAP).
@@ -2739,12 +3354,6 @@ debug_make_name_map([Var|VarLeft], [Fun|FunLeft], Map) ->
debug_make_name_map([], [], Map) ->
Map.
-debug_lookup_name(Var) ->
- case dict:find(t_var_name(Var), get(dialyzer_typesig_map)) of
- error -> Var;
- {ok, Name} -> Name
- end.
-
-else.
debug_make_name_map(_Vars, _Funs) ->
ok.
@@ -2755,51 +3364,55 @@ pp_constrs_scc(SCC, State) ->
[pp_constrs(Fun, state__get_cs(Fun, State), State) || Fun <- SCC].
pp_constrs(Fun, Cs, State) ->
- io:format("Constraints for fun: ~w\n", [debug_lookup_name(Fun)]),
+ io:format("Constraints for fun: ~w", [debug_lookup_name(Fun)]),
MaxDepth = pp_constraints(Cs, State),
io:format("Depth: ~w\n", [MaxDepth]).
pp_constraints(Cs, State) ->
- Res = pp_constraints([Cs], none, 0, 0, State),
+ Res = pp_constraints([Cs], 0, 0, State),
io:nl(),
Res.
-pp_constraints([List|Tail], Separator, Level, MaxDepth,
- State) when is_list(List) ->
- pp_constraints(List++Tail, Separator, Level, MaxDepth, State);
-pp_constraints([#constraint_ref{id = Id}|Left], Separator,
- Level, MaxDepth, State) ->
+pp_constraints([List|Tail], Level, MaxDepth, State) when is_list(List) ->
+ pp_constraints(List++Tail, Level, MaxDepth, State);
+pp_constraints([#constraint_ref{id = Id}|Left], Level, MaxDepth, State) ->
Cs = state__get_cs(Id, State),
+ pp_indent(Level),
io:format("%Ref ~w%", [t_var_name(Id)]),
- pp_constraints([Cs|Left], Separator, Level, MaxDepth, State);
-pp_constraints([#constraint{lhs = Lhs, op = Op, rhs = Rhs}], _Separator,
- Level, MaxDepth, _State) ->
- io:format("~s ~w ~s", [format_type(Lhs), Op, format_type(Rhs)]),
+ pp_constraints([Cs|Left], Level, MaxDepth, State);
+pp_constraints([#constraint{}=C], Level, MaxDepth, _State) ->
+ pp_op(C, Level),
erlang:max(Level, MaxDepth);
-pp_constraints([#constraint{lhs = Lhs, op = Op, rhs = Rhs}|Tail], Separator,
- Level, MaxDepth, State) ->
- io:format("~s ~w ~s ~s ", [format_type(Lhs), Op, format_type(Rhs),Separator]),
- pp_constraints(Tail, Separator, Level, MaxDepth, State);
+pp_constraints([#constraint{}=C|Tail], Level, MaxDepth, State) ->
+ pp_op(C, Level),
+ pp_constraints(Tail, Level, MaxDepth, State);
pp_constraints([#constraint_list{type = Type, list = List, id = Id}],
- _Separator, Level, MaxDepth, State) ->
- io:format("%List ~w(", [Id]),
- NewSeparator = case Type of
- conj -> "*";
- disj -> "+"
- end,
- NewMaxDepth = pp_constraints(List, NewSeparator, Level + 1, MaxDepth, State),
+ Level, MaxDepth, State) ->
+ pp_indent(Level),
+ case Type of
+ conj -> io:format("Conj ~w (", [Id]);
+ disj -> io:format("Disj ~w (", [Id])
+ end,
+ NewMaxDepth = pp_constraints(List, Level + 1, MaxDepth, State),
io:format(")", []),
NewMaxDepth;
pp_constraints([#constraint_list{type = Type, list = List, id = Id}|Tail],
- Separator, Level, MaxDepth, State) ->
- io:format("List ~w(", [Id]),
- NewSeparator = case Type of
- conj -> "*";
- disj -> "+"
- end,
- NewMaxDepth = pp_constraints(List, NewSeparator, Level+1, MaxDepth, State),
- io:format(") ~s\n~s ", [Separator, Separator]),
- pp_constraints(Tail, Separator, Level, NewMaxDepth, State).
+ Level, MaxDepth, State) ->
+ pp_indent(Level),
+ case Type of
+ conj -> io:format("Conj ~w (", [Id]);
+ disj -> io:format("Disj ~w (", [Id])
+ end,
+ NewMaxDepth = pp_constraints(List, Level+1, MaxDepth, State),
+ io:format(")", []),
+ pp_constraints(Tail, Level, NewMaxDepth, State).
+
+pp_op(#constraint{lhs = Lhs, op = Op, rhs = Rhs}, Level) ->
+ pp_indent(Level),
+ io:format("~s ~w ~s", [format_type(Lhs), Op, format_type(Rhs)]).
+
+pp_indent(Level) ->
+ io:format("\n~*s", [Level*2, ""]).
-else.
pp_constrs_scc(_SCC, _State) ->
ok.
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 2a248fb028..149e777e1f 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -43,7 +43,8 @@
pp_hook/0,
process_record_remote_types/1,
sets_filter/2,
- src_compiler_opts/0
+ src_compiler_opts/0,
+ parallelism/0
]).
-include("dialyzer.hrl").
@@ -536,3 +537,12 @@ pp_unit(Unit, Ctxt, Cont) ->
pp_atom(Atom) ->
String = atom_to_list(cerl:atom_val(Atom)),
prettypr:text(String).
+
+%%------------------------------------------------------------------------------
+
+-spec parallelism() -> integer().
+
+parallelism() ->
+ CPUs = erlang:system_info(logical_processors_available),
+ Schedulers = erlang:system_info(schedulers),
+ min(CPUs, Schedulers).
diff --git a/lib/dialyzer/src/dialyzer_worker.erl b/lib/dialyzer/src/dialyzer_worker.erl
new file mode 100644
index 0000000000..50b2e31ed8
--- /dev/null
+++ b/lib/dialyzer/src/dialyzer_worker.erl
@@ -0,0 +1,189 @@
+%% -*- erlang-indent-level: 2 -*-
+%%-----------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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
+%% 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(dialyzer_worker).
+
+-export([launch/4, sequential/4]).
+
+-export_type([worker/0]).
+
+-type worker() :: pid(). %%opaque
+
+-type mode() :: dialyzer_coordinator:mode().
+-type coordinator() :: dialyzer_coordinator:coordinator().
+-type init_data() :: dialyzer_coordinator:init_data().
+-type result() :: dialyzer_coordinator:result().
+
+-record(state, {
+ mode :: mode(),
+ job :: mfa_or_funlbl() | file:filename(),
+ coordinator :: coordinator(),
+ init_data :: init_data(),
+ depends_on = [] :: list()
+ }).
+
+-include("dialyzer.hrl").
+
+%% -define(DEBUG, true).
+
+-ifdef(DEBUG).
+-define(debug(X__, Y__), io:format(X__, Y__)).
+-else.
+-define(debug(X__, Y__), ok).
+-endif.
+
+%%--------------------------------------------------------------------
+
+-spec launch(mode(), [mfa_or_funlbl()], init_data(), coordinator()) -> worker().
+
+launch(Mode, Job, InitData, Coordinator) ->
+ State = #state{mode = Mode,
+ job = Job,
+ init_data = InitData,
+ coordinator = Coordinator},
+ InitState =
+ case Mode of
+ X when X =:= 'typesig'; X =:= 'dataflow' -> initializing;
+ X when X =:= 'compile'; X =:= 'warnings' -> running
+ end,
+ spawn_link(fun() -> loop(InitState, State) end).
+
+%%--------------------------------------------------------------------
+
+loop(updating, State) ->
+ ?debug("Update: ~p\n",[State#state.job]),
+ NextStatus =
+ case waits_more_success_typings(State) of
+ true -> waiting;
+ false -> running
+ end,
+ loop(NextStatus, State);
+loop(initializing, #state{job = SCC, init_data = InitData} = State) ->
+ DependsOn = dialyzer_succ_typings:find_depends_on(SCC, InitData),
+ ?debug("Deps ~p: ~p\n",[State#state.job, DependsOn]),
+ loop(updating, State#state{depends_on = DependsOn});
+loop(waiting, State) ->
+ ?debug("Wait: ~p\n",[State#state.job]),
+ NewState = wait_for_success_typings(State),
+ loop(updating, NewState);
+loop(running, #state{mode = 'compile'} = State) ->
+ dialyzer_coordinator:wait_activation(),
+ ?debug("Compile: ~s\n",[State#state.job]),
+ Result =
+ case start_compilation(State) of
+ {ok, EstimatedSize, Data} ->
+ Label = ask_coordinator_for_label(EstimatedSize, State),
+ continue_compilation(Label, Data);
+ {error, _Reason} = Error ->
+ Error
+ end,
+ report_to_coordinator(Result, State);
+loop(running, #state{mode = 'warnings'} = State) ->
+ dialyzer_coordinator:wait_activation(),
+ ?debug("Warning: ~s\n",[State#state.job]),
+ Result = collect_warnings(State),
+ report_to_coordinator(Result, State);
+loop(running, #state{mode = Mode} = State) when
+ Mode =:= 'typesig'; Mode =:= 'dataflow' ->
+ request_activation(State),
+ ?debug("Run: ~p\n",[State#state.job]),
+ NotFixpoint = do_work(State),
+ ok = broadcast_done(State),
+ report_to_coordinator(NotFixpoint, State).
+
+waits_more_success_typings(#state{depends_on = Depends}) ->
+ Depends =/= [].
+
+broadcast_done(#state{job = SCC, init_data = InitData,
+ coordinator = Coordinator}) ->
+ RequiredBy = dialyzer_succ_typings:find_required_by(SCC, InitData),
+ {Callers, Unknown} =
+ dialyzer_coordinator:sccs_to_pids(RequiredBy, Coordinator),
+ send_done(Callers, SCC),
+ continue_broadcast_done(Unknown, SCC, Coordinator).
+
+send_done(Callers, SCC) ->
+ ?debug("Sending ~p: ~p\n",[SCC, Callers]),
+ SendSTFun = fun(PID) -> PID ! {done, SCC} end,
+ lists:foreach(SendSTFun, Callers).
+
+continue_broadcast_done([], _SCC, _Coordinator) -> ok;
+continue_broadcast_done(Rest, SCC, Coordinator) ->
+ %% This time limit should be greater than the time required
+ %% by the coordinator to spawn all processes.
+ timer:sleep(500),
+ {Callers, Unknown} = dialyzer_coordinator:sccs_to_pids(Rest, Coordinator),
+ send_done(Callers, SCC),
+ continue_broadcast_done(Unknown, SCC, Coordinator).
+
+wait_for_success_typings(#state{depends_on = DependsOn} = State) ->
+ receive
+ {done, SCC} ->
+ ?debug("GOT ~p: ~p\n",[State#state.job, SCC]),
+ State#state{depends_on = DependsOn -- [SCC]}
+ after
+ 5000 ->
+ ?debug("Still Waiting ~p: ~p\n",[State#state.job, DependsOn]),
+ State
+ end.
+
+request_activation(#state{coordinator = Coordinator}) ->
+ dialyzer_coordinator:request_activation(Coordinator).
+
+do_work(#state{mode = Mode, job = Job, init_data = InitData}) ->
+ case Mode of
+ typesig -> dialyzer_succ_typings:find_succ_types_for_scc(Job, InitData);
+ dataflow -> dialyzer_succ_typings:refine_one_module(Job, InitData)
+ end.
+
+report_to_coordinator(Result, #state{job = Job, coordinator = Coordinator}) ->
+ ?debug("Done: ~p\n",[Job]),
+ dialyzer_coordinator:job_done(Job, Result, Coordinator).
+
+start_compilation(#state{job = Job, init_data = InitData}) ->
+ dialyzer_analysis_callgraph:start_compilation(Job, InitData).
+
+ask_coordinator_for_label(EstimatedSize, #state{coordinator = Coordinator}) ->
+ dialyzer_coordinator:get_next_label(EstimatedSize, Coordinator).
+
+continue_compilation(Label, Data) ->
+ dialyzer_analysis_callgraph:continue_compilation(Label, Data).
+
+collect_warnings(#state{job = Job, init_data = InitData}) ->
+ dialyzer_succ_typings:collect_warnings(Job, InitData).
+
+%%------------------------------------------------------------------------------
+
+-type extra() :: label() | 'unused'.
+
+-spec sequential(mode(), [mfa_or_funlbl()], init_data(), extra()) -> result().
+
+sequential('compile', Job, InitData, Extra) ->
+ case dialyzer_analysis_callgraph:start_compilation(Job, InitData) of
+ {ok, EstimatedSize, Data} ->
+ {EstimatedSize, continue_compilation(Extra, Data)};
+ {error, _Reason} = Error -> {0, Error}
+ end;
+sequential('typesig', Job, InitData, _Extra) ->
+ dialyzer_succ_typings:find_succ_types_for_scc(Job, InitData);
+sequential('dataflow', Job, InitData, _Extra) ->
+ dialyzer_succ_typings:refine_one_module(Job, InitData);
+sequential('warnings', Job, InitData, _Extra) ->
+ dialyzer_succ_typings:collect_warnings(Job, InitData).
diff --git a/lib/dialyzer/test/Makefile b/lib/dialyzer/test/Makefile
index 6a1abce943..9f8a3f1194 100644
--- a/lib/dialyzer/test/Makefile
+++ b/lib/dialyzer/test/Makefile
@@ -25,10 +25,10 @@ RELSYSDIR = $(RELEASE_PATH)/dialyzer_test
include $(ERL_TOP)/make/otp_release_targets.mk
release_tests_spec:
- $(INSTALL_DIR) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- $(INSTALL_DATA) $(AUXILIARY_FILES) $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- cd $(RELSYSDIR);\
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(AUXILIARY_FILES) "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ cd "$(RELSYSDIR)";\
erlc dialyzer_common.erl file_utils.erl;\
erl -noshell -run dialyzer_common create_all_suites -s erlang halt
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/queue b/lib/dialyzer/test/opaque_SUITE_data/results/queue
index 59ce33f098..c3f04ea64d 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/queue
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/queue
@@ -5,6 +5,7 @@ queue_use.erl:27: The attempt to match a term of type queue() against the patter
queue_use.erl:33: Attempt to test for equality between a term of type {[42,...],[]} and a term of opaque type queue()
queue_use.erl:36: The attempt to match a term of type queue() against the pattern {F, _R} breaks the opaqueness of the term
queue_use.erl:40: The call queue:out({[42,...],[]}) does not have an opaque term of type queue() as 1st argument
+queue_use.erl:48: The call queue_use:add_unique(42,#db{p::[],q::queue()}) contains an opaque term as 2nd argument when terms of different types are expected in these positions
queue_use.erl:51: The call queue_use:is_in_queue(E::42,DB::#db{p::[],q::queue()}) contains an opaque term as 2nd argument when terms of different types are expected in these positions
queue_use.erl:56: The attempt to match a term of type #db{p::[],q::queue()} against the pattern {'db', _, {L1, L2}} breaks the opaqueness of queue()
queue_use.erl:62: The call queue_use:tuple_queue({42,'gazonk'}) does not have a term of type {_,queue()} (with opaque subterms) as 1st argument
diff --git a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
new file mode 100644
index 0000000000..8dc0361b0d
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
@@ -0,0 +1,31 @@
+
+contracts_with_subtypes.erl:106: The call contracts_with_subtypes:rec_arg({'a','b'}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:107: The call contracts_with_subtypes:rec_arg({'b','a'}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:108: The call contracts_with_subtypes:rec_arg({'a',{'b','a'}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:109: The call contracts_with_subtypes:rec_arg({'b',{'a','b'}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:110: The call contracts_with_subtypes:rec_arg({'a',{'b',{'a','b'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:111: The call contracts_with_subtypes:rec_arg({'b',{'a',{'b','a'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
+contracts_with_subtypes.erl:142: The pattern 1 can never match the type binary() | string()
+contracts_with_subtypes.erl:145: The pattern 'alpha' can never match the type {'ok',X} | {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:147: The pattern 42 can never match the type {'ok',_} | {'ok',_,binary() | string()}
+contracts_with_subtypes.erl:163: The pattern 'alpha' can never match the type {'ok',X}
+contracts_with_subtypes.erl:165: The pattern 42 can never match the type {'ok',X}
+contracts_with_subtypes.erl:183: The pattern 'alpha' can never match the type {'ok',X}
+contracts_with_subtypes.erl:185: The pattern 42 can never match the type {'ok',X}
+contracts_with_subtypes.erl:202: The pattern 1 can never match the type binary() | string()
+contracts_with_subtypes.erl:205: The pattern {'ok', _} can never match the type {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:206: The pattern 'alpha' can never match the type {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:207: The pattern {'ok', 42} can never match the type {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:208: The pattern 42 can never match the type {'ok',X,binary() | string()}
+contracts_with_subtypes.erl:234: Function flat_ets_new_t/0 has no local return
+contracts_with_subtypes.erl:235: The call contracts_with_subtypes:flat_ets_new(12,[]) breaks the contract (Name,Options) -> atom() when is_subtype(Name,atom()), is_subtype(Options,[Option]), is_subtype(Option,'set' | 'ordered_set' | 'bag' | 'duplicate_bag' | 'public' | 'protected' | 'private' | 'named_table' | {'keypos',integer()} | {'heir',pid(),term()} | {'heir','none'} | {'write_concurrency',boolean()} | {'read_concurrency',boolean()} | 'compressed')
+contracts_with_subtypes.erl:23: Invalid type specification for function contracts_with_subtypes:extract2/0. The success typing is () -> 'something'
+contracts_with_subtypes.erl:261: Function factored_ets_new_t/0 has no local return
+contracts_with_subtypes.erl:262: The call contracts_with_subtypes:factored_ets_new(12,[]) breaks the contract (Name,Options) -> atom() when is_subtype(Name,atom()), is_subtype(Options,[Option]), is_subtype(Option,Type | Access | 'named_table' | {'keypos',Pos} | {'heir',Pid::pid(),HeirData} | {'heir','none'} | Tweaks), is_subtype(Type,type()), is_subtype(Access,access()), is_subtype(Tweaks,{'write_concurrency',boolean()} | {'read_concurrency',boolean()} | 'compressed'), is_subtype(Pos,pos_integer()), is_subtype(HeirData,term())
+contracts_with_subtypes.erl:77: The call contracts_with_subtypes:foo1(5) breaks the contract (Arg1) -> Res when is_subtype(Arg1,atom()), is_subtype(Res,atom())
+contracts_with_subtypes.erl:78: The call contracts_with_subtypes:foo2(5) breaks the contract (Arg1) -> Res when is_subtype(Arg1,Arg2), is_subtype(Arg2,atom()), is_subtype(Res,atom())
+contracts_with_subtypes.erl:79: The call contracts_with_subtypes:foo3(5) breaks the contract (Arg1) -> Res when is_subtype(Arg2,atom()), is_subtype(Arg1,Arg2), is_subtype(Res,atom())
+contracts_with_subtypes.erl:7: Invalid type specification for function contracts_with_subtypes:extract/0. The success typing is () -> 'something'
+contracts_with_subtypes.erl:80: The call contracts_with_subtypes:foo4(5) breaks the contract (Type) -> Type when is_subtype(Type,atom())
+contracts_with_subtypes.erl:81: The call contracts_with_subtypes:foo5(5) breaks the contract (Type::atom()) -> Type::atom()
+contracts_with_subtypes.erl:82: The call contracts_with_subtypes:foo6(5) breaks the contract (Type) -> Type when is_subtype(Type,atom())
diff --git a/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/a.erl b/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/a.erl
new file mode 100644
index 0000000000..7efe870b0d
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/a.erl
@@ -0,0 +1,9 @@
+-module(a).
+-export([g/1]).
+
+-export_type([a/0, t/0]).
+-type a() :: integer().
+-type t() :: a() | maybe_improper_list(t(), t()).
+
+-spec g(t()) -> t().
+g(X) -> X.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/b.erl b/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/b.erl
new file mode 100644
index 0000000000..b08bc5e66c
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/collapse_lists/b.erl
@@ -0,0 +1,5 @@
+-module(b).
+-export([f/1]).
+
+-spec f(a:t()) -> a:t().
+f(X) -> a:g(X).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl b/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl
new file mode 100644
index 0000000000..d72138d509
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl
@@ -0,0 +1,267 @@
+-module(contracts_with_subtypes).
+
+-compile(export_all).
+
+%===============================================================================
+
+-spec extract() -> 'ok'.
+
+extract() ->
+ case dz_extract() of
+ {ok, Val} -> Val;
+ error -> exit(boom)
+ end.
+
+-spec dz_extract() -> RetValue when
+ FileList :: something,
+ RetValue :: {ok, FileList} | error.
+
+dz_extract() -> get(foo).
+
+%-------------------------------------------------------------------------------
+
+-spec extract2() -> 'ok'.
+
+extract2() ->
+ case dz_extract2() of
+ {ok, Val} -> Val;
+ error -> exit(boom)
+ end.
+
+-spec dz_extract2() -> RetValue when
+ RetValue :: {ok, FileList} | error,
+ FileList :: something.
+
+dz_extract2() -> get(foo).
+
+%===============================================================================
+
+-spec foo1(Arg1) -> Res when
+ Arg1 :: atom(),
+ Res :: atom().
+
+foo1(X) -> X.
+
+-spec foo2(Arg1) -> Res when
+ Arg1 :: Arg2,
+ Arg2 :: atom(),
+ Res :: atom().
+
+foo2(X) -> X.
+
+-spec foo3(Arg1) -> Res when
+ Arg2 :: atom(),
+ Arg1 :: Arg2,
+ Res :: atom().
+
+foo3(X) -> X.
+
+-spec foo4(Type) -> Type when is_subtype(Type, atom()).
+
+foo4(X) -> X.
+
+-spec foo5(Type :: atom()) -> Type :: atom().
+
+foo5(X) -> X.
+
+-spec foo6(Type) -> Type when Type :: atom().
+
+foo6(X) -> X.
+
+-spec foo7(Type) -> Type.
+
+foo7(X) -> X.
+
+%-------------------------------------------------------------------------------
+
+bar(1) -> foo1(5);
+bar(2) -> foo2(5);
+bar(3) -> foo3(5);
+bar(4) -> foo4(5);
+bar(5) -> foo5(5);
+bar(6) -> foo6(5);
+bar(7) -> foo7(5).
+
+wrong_foo6() ->
+ b = foo6(a).
+
+%===============================================================================
+
+-spec rec_arg(Arg) -> ok when
+ Arg :: {a, A} | {b, B},
+ A :: a | {b, B},
+ B :: b | {a, A}.
+
+rec_arg(X) -> get(X).
+
+c(aa) -> rec_arg({a, a});
+c(bb) -> rec_arg({b, b});
+c(abb) -> rec_arg({a, {b, b}});
+c(baa) -> rec_arg({b, {a, a}});
+c(abaa) -> rec_arg({a, {b, {a, a}}});
+c(babb) -> rec_arg({b, {a, {b, b}}});
+c(ababb) -> rec_arg({a, {b, {a, {b, b}}}});
+c(babaa) -> rec_arg({b, {a, {b, {a, a}}}}).
+
+w(ab) -> rec_arg({a, b});
+w(ba) -> rec_arg({b, a});
+w(aba) -> rec_arg({a, {b, a}});
+w(bab) -> rec_arg({b, {a, b}});
+w(abab) -> rec_arg({a, {b, {a, b}}});
+w(baba) -> rec_arg({b, {a, {b, a}}});
+w(ababa) -> rec_arg({a, {b, {a, {b, a}}}});
+w(babab) -> rec_arg({b, {a, {b, {a, b}}}}).
+
+%===============================================================================
+
+-type dublo(X) :: {X, X}.
+
+-type weird(X,Y) :: {X, Y, X, X}.
+
+-spec forfun(dublo(Var)) -> ok when Var :: atom().
+
+forfun(_) -> ok.
+
+-spec forfun2(weird(Var, Var)) -> ok when Var :: atom().
+
+forfun2(_) -> ok.
+
+%===============================================================================
+
+-spec shallow(X) -> {ok, X} | {ok, X, file:filename()} | err1 | err2.
+
+shallow(X) -> get(X).
+
+st(X) when is_atom(X) ->
+ case shallow(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ {ok, X, Res} ->
+ case Res of
+ 1 -> bad;
+ _Other -> ok
+ end;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-spec deep(X) -> Ret when
+ Ret :: {ok, X} | Err,
+ Err :: err1 | err2.
+
+deep(X) -> get(X).
+
+dt(X) when is_atom(X) ->
+ case deep(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-type local_errors() :: err1 | err2.
+
+-spec deep2(X) -> Ret when
+ Ret :: {ok, X} | Err,
+ Err :: local_errors().
+
+deep2(X) -> get(X).
+
+dt2(X) when is_atom(X) ->
+ case deep2(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-spec deep3(X) -> Ret when
+ Ret :: {ok, X, file:filename()} | Err,
+ Err :: local_errors().
+
+deep3(X) -> get(X).
+
+dt3(X) when is_atom(X) ->
+ case deep3(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X, Res} ->
+ case Res of
+ 1 -> bad;
+ _Other -> ok
+ end;
+ {ok, X} -> bad;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%===============================================================================
+
+-spec flat_ets_new(Name, Options) -> atom() when
+ Name :: atom(),
+ Options :: [Option],
+ Option :: set
+ | ordered_set
+ | bag
+ | duplicate_bag
+ | public
+ | protected
+ | private
+ | named_table
+ | {keypos, integer()}
+ | {heir, pid(), term()}
+ | {heir, none}
+ | {write_concurrency, boolean()}
+ | {read_concurrency, boolean()}
+ | compressed.
+
+flat_ets_new(Name, Options) ->
+ get({Name, Options}).
+
+flat_ets_new_t() ->
+ flat_ets_new(12,[]),
+ flat_ets_new({a,b},[]),
+ flat_ets_new(name,[foo]),
+ flat_ets_new(name,{bag}),
+ flat_ets_new(name,bag),
+ ok.
+
+-type access() :: public | protected | private.
+-type type() :: set | ordered_set | bag | duplicate_bag.
+
+-spec factored_ets_new(Name, Options) -> atom() when
+ Name :: atom(),
+ Options :: [Option],
+ Option :: Type | Access | named_table | {keypos,Pos}
+ | {heir, Pid :: pid(), HeirData} | {heir, none} | Tweaks,
+ Type :: type(),
+ Access :: access(),
+ Tweaks :: {write_concurrency, boolean()}
+ | {read_concurrency, boolean()}
+ | compressed,
+ Pos :: pos_integer(),
+ HeirData :: term().
+
+factored_ets_new(Name, Options) ->
+ get({Name, Options}).
+
+factored_ets_new_t() ->
+ factored_ets_new(12,[]),
+ factored_ets_new({a,b},[]),
+ factored_ets_new(name,[foo]),
+ factored_ets_new(name,{bag}),
+ factored_ets_new(name,bag),
+ ok.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/deep_lc.erl b/lib/dialyzer/test/small_SUITE_data/src/deep_lc.erl
new file mode 100644
index 0000000000..d9ca0817d9
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/deep_lc.erl
@@ -0,0 +1,14 @@
+-module(deep_lc).
+
+-export([t/0]).
+
+%% This is compile/test/lc_SUITE:deeply_nested/1
+%%
+%% Used to be _very_ slow. Unknown how slow, but more than 15 hours.
+
+t() ->
+ [[X1,X2,X3,X4,X5,X6,X7(),X8,X9,X10,X11,X12,X13,X14,X15,X16,X17,X18(),X19,X20] ||
+ X1 <- [99],X2 <- [98],X3 <- [97],X4 <- [96],X5 <- [42],X6 <- [17],
+ X7 <- [fun() -> X5*X5 end],X8 <- [12],X9 <- [11],X10 <- [10],
+ X11 <- [9],X12 <- [8],X13 <- [7],X14 <- [6],X15 <- [5],
+ X16 <- [4],X17 <- [3],X18 <- [fun() -> X16+X17 end],X19 <- [2],X20 <- [1]].
diff --git a/lib/diameter/autoconf/vxworks/sed.general b/lib/diameter/autoconf/vxworks/sed.general
index 77b306aa0a..9199983e16 100644
--- a/lib/diameter/autoconf/vxworks/sed.general
+++ b/lib/diameter/autoconf/vxworks/sed.general
@@ -66,7 +66,6 @@ s|@HCLIBS@||
s|@ENABLE_ALLOC_TYPE_VARS@||
s|@TERMCAP_LIB@||
s|@ERTS_BUILD_SMP_EMU@|no|
-s|@ERTS_BUILD_HYBRID_EMU@|no|
s|@HAVE_VALGRIND@|no|
s|@EXEEXT@||
s|@WITH_SCTP@||
diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile
index bc3e649e6b..cdf63e7fb6 100644
--- a/lib/diameter/doc/src/Makefile
+++ b/lib/diameter/doc/src/Makefile
@@ -162,18 +162,18 @@ include $(DIAMETER_TOP)/make/release_targets.mk
endif
release_docs_spec: $(LOCAL)docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man1
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man4
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(HTMLDIR)/*.* $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN4_FILES) $(RELEASE_PATH)/man/man4
- [ -z "$(LOCAL)" ] || cp -r $(HTMLDIR)/js $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man4"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(HTMLDIR)/*.* "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(MAN1_FILES) "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN4_FILES) "$(RELEASE_PATH)/man/man4"
+ [ -z "$(LOCAL)" ] || cp -r $(HTMLDIR)/js "$(RELSYSDIR)/doc/html"
echo $(LOCAL)
release_spec:
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index dbfaa4e140..de2eca0279 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -195,27 +195,27 @@ endif
release_spec: opt
for d in bin ebin include src/dict; do \
- $(INSTALL_DIR) $(RELSYSDIR)/$$d; \
+ $(INSTALL_DIR) "$(RELSYSDIR)/$$d"; \
done
- $(INSTALL_SCRIPT) $(BINS:%=../bin/%) $(RELSYSDIR)/bin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_SCRIPT) $(BINS:%=../bin/%) "$(RELSYSDIR)/bin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(EXTERNAL_HRLS:%=../include/%) $(DICT_HRLS) \
- $(RELSYSDIR)/include
- $(INSTALL_DATA) $(DICTS:%=dict/%.dia) $(RELSYSDIR)/src/dict
+ "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(DICTS:%=dict/%.dia) "$(RELSYSDIR)/src/dict"
$(MAKE) $(TARGET_DIRS:%/=release_src_%)
$(MAKE) $(EXAMPLE_DIRS:%/=release_examples_%)
$(TARGET_DIRS:%/=release_src_%): release_src_%:
- $(INSTALL_DIR) $(RELSYSDIR)/src/$*
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/$*"
$(INSTALL_DATA) $(filter $*/%, $(TARGET_MODULES:%=%.erl) \
$(INTERNAL_HRLS)) \
$(filter $*/%, compiler/$(DICT_YRL).yrl) \
- $(RELSYSDIR)/src/$*
+ "$(RELSYSDIR)/src/$*"
$(EXAMPLE_DIRS:%/=release_examples_%): release_examples_%:
- $(INSTALL_DIR) $(RELSYSDIR)/examples/$*
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/$*"
$(INSTALL_DATA) $(patsubst %, ../examples/%, $(filter $*/%, $(EXAMPLES))) \
- $(RELSYSDIR)/examples/$*
+ "$(RELSYSDIR)/examples/$*"
release_docs_spec:
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index ab5b45ff3d..1659330a91 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -141,7 +141,7 @@ log:
# ----------------------------------------------------
/%: % force
- sed -f release.sed $< > $(RELSYSDIR)$@
+ sed -f release.sed $< > "$(RELSYSDIR)$@"
ifeq ($(ERL_TOP),)
include $(DIAMETER_TOP)/make/release_targets.mk
@@ -152,17 +152,17 @@ endif
release_spec release_docs_spec:
release_tests_spec:
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(TEST_SPEC_FILE) \
$(COVER_SPEC_FILE) \
$(HRL_FILES) \
- $(RELSYSDIR)
+ "$(RELSYSDIR)"
$(MAKE) $(DATA_DIRS:%/=release_data_%)
$(MAKE) $(ERL_FILES:%=/%)
$(DATA_DIRS:%/=release_data_%): release_data_%:
- $(INSTALL_DIR) $(RELSYSDIR)/$*
- $(INSTALL_DATA) $(filter $*/%, $(DATA)) $(RELSYSDIR)/$*
+ $(INSTALL_DIR) "$(RELSYSDIR)/$*"
+ $(INSTALL_DATA) $(filter $*/%, $(DATA)) "$(RELSYSDIR)/$*"
force:
diff --git a/lib/edoc/doc/src/Makefile b/lib/edoc/doc/src/Makefile
index b933094464..1f92d36f12 100644
--- a/lib/edoc/doc/src/Makefile
+++ b/lib/edoc/doc/src/Makefile
@@ -124,13 +124,13 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/edoc/include/Makefile b/lib/edoc/include/Makefile
index 5b2ad38c9d..cf2e051632 100644
--- a/lib/edoc/include/Makefile
+++ b/lib/edoc/include/Makefile
@@ -49,8 +49,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(INCLUDE_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(INCLUDE_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/edoc/priv/Makefile b/lib/edoc/priv/Makefile
index 13225e6d1a..73c42c05eb 100644
--- a/lib/edoc/priv/Makefile
+++ b/lib/edoc/priv/Makefile
@@ -45,9 +45,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(PRIV_FILES) $(RELSYSDIR)/priv
- $(INSTALL_SCRIPT) $(GEN_SCRIPT) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(PRIV_FILES) "$(RELSYSDIR)/priv"
+ $(INSTALL_SCRIPT) $(GEN_SCRIPT) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/edoc/src/Makefile b/lib/edoc/src/Makefile
index fcb0b61292..72354ac711 100644
--- a/lib/edoc/src/Makefile
+++ b/lib/edoc/src/Makefile
@@ -85,10 +85,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(OBJECTS) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(SOURCES) $(HRL_FILES) $(YRL_FILE) $(RELSYSDIR)/src
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(OBJECTS) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(SOURCES) $(HRL_FILES) $(YRL_FILE) "$(RELSYSDIR)/src"
release_docs_spec:
diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl
index aad0b14371..624f9177a2 100644
--- a/lib/edoc/src/edoc_data.erl
+++ b/lib/edoc/src/edoc_data.erl
@@ -167,7 +167,10 @@ callbacks(Es, Module, Env, Opts) ->
case lists:any(fun (#entry{name = {behaviour_info, 1}}) -> true;
(_) -> false
end,
- Es) of
+ Es)
+ orelse
+ lists:keymember(callback, 1, Module#module.attributes)
+ of
true ->
try (Module#module.name):behaviour_info(callbacks) of
Fs ->
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index 7fd8358add..90fb8a679c 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -469,6 +469,10 @@ uri_get("ftp:" ++ Path) ->
uri_get("//" ++ Path) ->
Msg = io_lib:format("cannot access network-path: '//~s'.", [Path]),
{error, Msg};
+uri_get([C, $:, $/ | _]=Path) when C >= $A, C =< $Z; C >= $a, C =< $z ->
+ uri_get_file(Path); % special case for Windows
+uri_get([C, $:, $\ | _]=Path) when C >= $A, C =< $Z; C >= $a, C =< $z ->
+ uri_get_file(Path); % special case for Windows
uri_get(URI) ->
case is_relative_uri(URI) of
true ->
diff --git a/lib/edoc/test/Makefile b/lib/edoc/test/Makefile
index 2dbdb77eff..2033e003b3 100644
--- a/lib/edoc/test/Makefile
+++ b/lib/edoc/test/Makefile
@@ -57,10 +57,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) edoc.spec edoc.cover $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) edoc.spec edoc.cover "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index b8f33894f1..2f403212c8 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.7.9.1
+EDOC_VSN = 0.7.10
diff --git a/lib/eldap/doc/src/Makefile b/lib/eldap/doc/src/Makefile
index 4c827319b4..a4827793f4 100644
--- a/lib/eldap/doc/src/Makefile
+++ b/lib/eldap/doc/src/Makefile
@@ -99,16 +99,16 @@ clean clean_docs clean_tex:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-# $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
-# $(INSTALL_DATA) $(MAN6DIR)/* $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+# $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+# $(INSTALL_DATA) $(MAN6DIR)/* "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/eldap/src/Makefile b/lib/eldap/src/Makefile
index 4ddb8082d7..39a41d08e2 100644
--- a/lib/eldap/src/Makefile
+++ b/lib/eldap/src/Makefile
@@ -96,14 +96,14 @@ $(ASN1_HRL): ../asn1/$(ASN1_FILES)
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/asn1
- $(INSTALL_DATA) ../asn1/$(ASN1_FILES) $(RELSYSDIR)/asn1
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/asn1"
+ $(INSTALL_DATA) ../asn1/$(ASN1_FILES) "$(RELSYSDIR)/asn1"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile
index 2349e4b292..3c5810eece 100644
--- a/lib/eldap/test/Makefile
+++ b/lib/eldap/test/Makefile
@@ -75,9 +75,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(COVER_FILE) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
-# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(COVER_FILE) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+# @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/erl_docgen/doc/src/Makefile b/lib/erl_docgen/doc/src/Makefile
index ff50c12895..a254c4fb6d 100644
--- a/lib/erl_docgen/doc/src/Makefile
+++ b/lib/erl_docgen/doc/src/Makefile
@@ -124,13 +124,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6DIR)/* $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6DIR)/* "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/erl_docgen/priv/bin/Makefile b/lib/erl_docgen/priv/bin/Makefile
index 95ad36216a..449cc6691c 100644
--- a/lib/erl_docgen/priv/bin/Makefile
+++ b/lib/erl_docgen/priv/bin/Makefile
@@ -64,8 +64,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_SCRIPT) $(ESCRIPT_FILES) $(RELSYSDIR)/priv/bin
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/bin"
+ $(INSTALL_SCRIPT) $(ESCRIPT_FILES) "$(RELSYSDIR)/priv/bin"
release_docs_spec:
diff --git a/lib/erl_docgen/priv/css/Makefile b/lib/erl_docgen/priv/css/Makefile
index 81124fb111..0faca019f3 100644
--- a/lib/erl_docgen/priv/css/Makefile
+++ b/lib/erl_docgen/priv/css/Makefile
@@ -64,13 +64,13 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/css
- $(INSTALL_DATA) $(CSS_FILES) $(RELSYSDIR)/priv/css
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/css"
+ $(INSTALL_DATA) $(CSS_FILES) "$(RELSYSDIR)/priv/css"
release_docs_spec:
- $(INSTALL_DIR) $(RELEASE_PATH)/doc
- $(INSTALL_DATA) $(CSS_FILES) ../nyi.html $(RELEASE_PATH)/doc
+ $(INSTALL_DIR) "$(RELEASE_PATH)/doc"
+ $(INSTALL_DATA) $(CSS_FILES) ../nyi.html "$(RELEASE_PATH)/doc"
release_tests_spec:
diff --git a/lib/erl_docgen/priv/dtd/Makefile b/lib/erl_docgen/priv/dtd/Makefile
index 65c68fcca7..314374d34b 100644
--- a/lib/erl_docgen/priv/dtd/Makefile
+++ b/lib/erl_docgen/priv/dtd/Makefile
@@ -89,8 +89,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/dtd
- $(INSTALL_DATA) $(DTD_FILES) $(ENT_FILES) $(RELSYSDIR)/priv/dtd
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/dtd"
+ $(INSTALL_DATA) $(DTD_FILES) $(ENT_FILES) "$(RELSYSDIR)/priv/dtd"
release_docs_spec:
diff --git a/lib/erl_docgen/priv/dtd_html_entities/Makefile b/lib/erl_docgen/priv/dtd_html_entities/Makefile
index d57302bd1b..9cd3f38c4b 100644
--- a/lib/erl_docgen/priv/dtd_html_entities/Makefile
+++ b/lib/erl_docgen/priv/dtd_html_entities/Makefile
@@ -63,8 +63,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/dtd_html_entities
- $(INSTALL_DATA) $(ENTITY_FILES) $(RELSYSDIR)/priv/dtd_html_entities
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/dtd_html_entities"
+ $(INSTALL_DATA) $(ENTITY_FILES) "$(RELSYSDIR)/priv/dtd_html_entities"
release_docs_spec:
diff --git a/lib/erl_docgen/priv/dtd_man_entities/Makefile b/lib/erl_docgen/priv/dtd_man_entities/Makefile
index 5651d8bc29..b6f29af6b4 100644
--- a/lib/erl_docgen/priv/dtd_man_entities/Makefile
+++ b/lib/erl_docgen/priv/dtd_man_entities/Makefile
@@ -63,8 +63,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/dtd_man_entities
- $(INSTALL_DATA) $(ENTITY_FILES) $(RELSYSDIR)/priv/dtd_man_entities
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/dtd_man_entities"
+ $(INSTALL_DATA) $(ENTITY_FILES) "$(RELSYSDIR)/priv/dtd_man_entities"
release_docs_spec:
diff --git a/lib/erl_docgen/priv/images/Makefile b/lib/erl_docgen/priv/images/Makefile
index 8b858fefb3..389f9f98ae 100644
--- a/lib/erl_docgen/priv/images/Makefile
+++ b/lib/erl_docgen/priv/images/Makefile
@@ -66,13 +66,13 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/images
- $(INSTALL_DATA) $(GIF_FILES) $(PNG_FILES) $(RELSYSDIR)/priv/images
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/images"
+ $(INSTALL_DATA) $(GIF_FILES) $(PNG_FILES) "$(RELSYSDIR)/priv/images"
release_docs_spec:
- $(INSTALL_DIR) $(RELEASE_PATH)/doc
- $(INSTALL_DATA) $(PNG_FILES) $(RELEASE_PATH)/doc
+ $(INSTALL_DIR) "$(RELEASE_PATH)/doc"
+ $(INSTALL_DATA) $(PNG_FILES) "$(RELEASE_PATH)/doc"
release_tests_spec:
diff --git a/lib/erl_docgen/priv/js/flipmenu/Makefile b/lib/erl_docgen/priv/js/flipmenu/Makefile
index 65c5c91f35..682d186608 100644
--- a/lib/erl_docgen/priv/js/flipmenu/Makefile
+++ b/lib/erl_docgen/priv/js/flipmenu/Makefile
@@ -68,13 +68,13 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/js/flipmenu
- $(INSTALL_DATA) $(JS_FILES) $(GIF_FILES) $(RELSYSDIR)/priv/js/flipmenu
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/js/flipmenu"
+ $(INSTALL_DATA) $(JS_FILES) $(GIF_FILES) "$(RELSYSDIR)/priv/js/flipmenu"
release_docs_spec:
- $(INSTALL_DIR) $(RELEASE_PATH)/doc/js/flipmenu
- $(INSTALL_DATA) $(JS_FILES) $(GIF_FILES) $(RELEASE_PATH)/doc/js/flipmenu
+ $(INSTALL_DIR) "$(RELEASE_PATH)/doc/js/flipmenu"
+ $(INSTALL_DATA) $(JS_FILES) $(GIF_FILES) "$(RELEASE_PATH)/doc/js/flipmenu"
release_tests_spec:
diff --git a/lib/erl_docgen/priv/xsl/Makefile b/lib/erl_docgen/priv/xsl/Makefile
index 92a53b8c0b..ca7a4e8157 100644
--- a/lib/erl_docgen/priv/xsl/Makefile
+++ b/lib/erl_docgen/priv/xsl/Makefile
@@ -68,8 +68,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/xsl
- $(INSTALL_DATA) $(XSL_FILES) $(RELSYSDIR)/priv/xsl
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/xsl"
+ $(INSTALL_DATA) $(XSL_FILES) "$(RELSYSDIR)/priv/xsl"
release_docs_spec:
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index 7cf5465f90..4bc5abb364 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -1817,7 +1817,14 @@
<xsl:choose>
<xsl:when test="ancestor::cref">
- <a name="{substring-before(nametext, '(')}"><span class="bold_code"><xsl:value-of select="ret"/><xsl:text> </xsl:text><xsl:value-of select="nametext"/></span></a><br/>
+ <a name="{substring-before(nametext, '(')}">
+ <span class="bold_code">
+ <xsl:value-of select="ret"/>
+ <xsl:call-template name="maybe-space-after-ret">
+ <xsl:with-param name="s" select="ret"/>
+ </xsl:call-template>
+ <xsl:value-of select="nametext"/>
+ </span></a><br/>
</xsl:when>
<xsl:when test="ancestor::erlref">
<xsl:variable name="fname">
@@ -1845,6 +1852,18 @@
</xsl:template>
+ <xsl:template name="maybe-space-after-ret">
+ <xsl:param name="s"/>
+ <xsl:variable name="last_char"
+ select="substring($s, string-length($s), 1)"/>
+ <xsl:choose>
+ <xsl:when test="$last_char != '*'">
+ <xsl:text> </xsl:text>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
+
+
<!-- Type -->
<xsl:template match="type">
<xsl:param name="partnum"/>
diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl
index 5234ba6bd0..33808859c7 100644
--- a/lib/erl_docgen/priv/xsl/db_man.xsl
+++ b/lib/erl_docgen/priv/xsl/db_man.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2011. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2012. 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
@@ -758,10 +758,32 @@
<xsl:template name="name">
<xsl:text>&#10;.B&#10;</xsl:text>
- <xsl:apply-templates/>
+ <xsl:choose>
+ <xsl:when test="ancestor::cref">
+ <xsl:value-of select="ret"/>
+ <xsl:call-template name="maybe-space-after-ret">
+ <xsl:with-param name="s" select="ret"/>
+ </xsl:call-template>
+ <xsl:value-of select="nametext"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
<xsl:text>&#10;.br</xsl:text>
</xsl:template>
+ <xsl:template name="maybe-space-after-ret">
+ <xsl:param name="s"/>
+ <xsl:variable name="last_char"
+ select="substring($s, string-length($s), 1)"/>
+ <xsl:choose>
+ <xsl:when test="$last_char != '*'">
+ <xsl:text> </xsl:text>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
+
<!-- Type -->
<xsl:template match="type">
diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl
index bf17406d84..da96052462 100644
--- a/lib/erl_docgen/priv/xsl/db_pdf.xsl
+++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2011. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2012. 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
@@ -1424,7 +1424,13 @@
<xsl:param name="partnum"/>
<xsl:choose>
<xsl:when test="ancestor::cref">
- <fo:block id="{generate-id(nametext)}"><xsl:value-of select="ret"/><xsl:text></xsl:text><xsl:value-of select="nametext"/></fo:block>
+ <fo:block id="{generate-id(nametext)}">
+ <xsl:value-of select="ret"/>
+ <xsl:call-template name="maybe-space-after-ret">
+ <xsl:with-param name="s" select="ret"/>
+ </xsl:call-template>
+ <xsl:value-of select="nametext"/>
+ </fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block id="{generate-id(.)}"><xsl:value-of select="."/></fo:block>
@@ -1432,6 +1438,16 @@
</xsl:choose>
</xsl:template>
+ <xsl:template name="maybe-space-after-ret">
+ <xsl:param name="s"/>
+ <xsl:variable name="last_char"
+ select="substring($s, string-length($s), 1)"/>
+ <xsl:choose>
+ <xsl:when test="$last_char != '*'">
+ <xsl:text> </xsl:text>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
<!-- Type -->
<xsl:template match="type">
diff --git a/lib/erl_docgen/src/Makefile b/lib/erl_docgen/src/Makefile
index cbaf6e4627..4d8f43bfed 100644
--- a/lib/erl_docgen/src/Makefile
+++ b/lib/erl_docgen/src/Makefile
@@ -89,10 +89,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/erl_interface/doc/src/Makefile b/lib/erl_interface/doc/src/Makefile
index e05b647cb2..2bad8976b5 100644
--- a/lib/erl_interface/doc/src/Makefile
+++ b/lib/erl_interface/doc/src/Makefile
@@ -113,16 +113,16 @@ clean clean_docs clean_tex:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man1
- $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DATA) $(MAN1_FILES) "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
index d6b0ca1f16..661dbb68ac 100644
--- a/lib/erl_interface/src/Makefile.in
+++ b/lib/erl_interface/src/Makefile.in
@@ -843,32 +843,32 @@ EXTRA = \
$(TARGET)/eidefs.mk
release: opt
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/lib
- $(INSTALL_DIR) $(RELSYSDIR)/bin
- $(INSTALL_DIR) $(RELSYSDIR)/src/auxdir
- $(INSTALL_DIR) $(RELSYSDIR)/src/connect
- $(INSTALL_DIR) $(RELSYSDIR)/src/decode
- $(INSTALL_DIR) $(RELSYSDIR)/src/encode
- $(INSTALL_DIR) $(RELSYSDIR)/src/epmd
- $(INSTALL_DIR) $(RELSYSDIR)/src/legacy
- $(INSTALL_DIR) $(RELSYSDIR)/src/misc
- $(INSTALL_DIR) $(RELSYSDIR)/src/prog
- $(INSTALL_DIR) $(RELSYSDIR)/src/registry
- $(INSTALL_DATA) $(HEADERS) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(OBJ_TARGETS) $(RELSYSDIR)/lib
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/lib"
+ $(INSTALL_DIR) "$(RELSYSDIR)/bin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/auxdir"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/connect"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/decode"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/encode"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/epmd"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/legacy"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/misc"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/prog"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/registry"
+ $(INSTALL_DATA) $(HEADERS) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(OBJ_TARGETS) "$(RELSYSDIR)/lib"
ifneq ($(EXE_TARGETS),)
- $(INSTALL_PROGRAM) $(EXE_TARGETS) $(RELSYSDIR)/bin
-endif
- $(INSTALL_DATA) $(EXTRA) $(RELSYSDIR)/src
- $(INSTALL_DATA) connect/*.[ch] $(RELSYSDIR)/src/connect
- $(INSTALL_DATA) decode/*.[ch] $(RELSYSDIR)/src/decode
- $(INSTALL_DATA) encode/*.[ch] $(RELSYSDIR)/src/encode
- $(INSTALL_DATA) epmd/*.[ch] $(RELSYSDIR)/src/epmd
- $(INSTALL_DATA) misc/*.[ch] $(RELSYSDIR)/src/misc
- $(INSTALL_DATA) registry/*.[ch] $(RELSYSDIR)/src/registry
- $(INSTALL_DATA) legacy/*.[ch] $(RELSYSDIR)/src/legacy
- $(INSTALL_DATA) prog/*.[ch] $(RELSYSDIR)/src/prog
+ $(INSTALL_PROGRAM) $(EXE_TARGETS) "$(RELSYSDIR)/bin"
+endif
+ $(INSTALL_DATA) $(EXTRA) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) connect/*.[ch] "$(RELSYSDIR)/src/connect"
+ $(INSTALL_DATA) decode/*.[ch] "$(RELSYSDIR)/src/decode"
+ $(INSTALL_DATA) encode/*.[ch] "$(RELSYSDIR)/src/encode"
+ $(INSTALL_DATA) epmd/*.[ch] "$(RELSYSDIR)/src/epmd"
+ $(INSTALL_DATA) misc/*.[ch] "$(RELSYSDIR)/src/misc"
+ $(INSTALL_DATA) registry/*.[ch] "$(RELSYSDIR)/src/registry"
+ $(INSTALL_DATA) legacy/*.[ch] "$(RELSYSDIR)/src/legacy"
+ $(INSTALL_DATA) prog/*.[ch] "$(RELSYSDIR)/src/prog"
release_docs:
diff --git a/lib/erl_interface/test/Makefile b/lib/erl_interface/test/Makefile
index 4faf89c0d6..d11a138844 100644
--- a/lib/erl_interface/test/Makefile
+++ b/lib/erl_interface/test/Makefile
@@ -71,9 +71,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/erl_interface/test/all_SUITE_data/gccifier.c b/lib/erl_interface/test/all_SUITE_data/gccifier.c
index 9f556fc4ed..a1019f9a72 100644
--- a/lib/erl_interface/test/all_SUITE_data/gccifier.c
+++ b/lib/erl_interface/test/all_SUITE_data/gccifier.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2009. 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
@@ -16,7 +16,6 @@
*
* %CopyrightEnd%
*
-
*/
/*
@@ -74,17 +73,23 @@ save_arg(args_t *args, char *arg1, ...)
args->vec = (char **) (args->no
? realloc((void *) args->vec,
(sizeof(char *)
- *(args->no + ARGS_INCR + 1)))
+ *(args->no + ARGS_INCR + 2)))
: malloc((sizeof(char *)
- *(args->no + ARGS_INCR + 1))));
+ *(args->no + ARGS_INCR + 2))));
if (!args->vec)
enomem();
args->no += ARGS_INCR;
}
+ if (carg == arg1) {
+ args->vec[args->ix++] = "\"";
+ args->chars++;
+ }
args->vec[args->ix++] = carg;
args->chars += strlen(carg);
carg = va_arg(argp, char *);
}
+ args->vec[args->ix++] = "\"";
+ args->chars++;
args->vec[args->ix++] = " ";
args->chars++;
va_end(argp);
@@ -232,6 +237,9 @@ main(int argc, char *argv[])
CHECK_FIRST_LINK_ARG;
save_arg(&link_args, "-libpath:", arg, NULL);
}
+ else if (strcmp("-link",arg) == 0) {
+ CHECK_FIRST_LINK_ARG;
+ }
#endif /* #ifdef __WIN32__ */
else if (is_prefix("-l", &arg)) {
CHECK_FIRST_LINK_ARG;
diff --git a/lib/erl_interface/test/ei_tmo_SUITE.erl b/lib/erl_interface/test/ei_tmo_SUITE.erl
index 7ff8c08280..cc22cb7440 100644
--- a/lib/erl_interface/test/ei_tmo_SUITE.erl
+++ b/lib/erl_interface/test/ei_tmo_SUITE.erl
@@ -88,12 +88,12 @@ ei_recv_tmo(doc) ->
ei_recv_tmo(suite) ->
[];
ei_recv_tmo(Config) when is_list(Config) ->
- ?line do_one_recv(c_node_recv_tmo_1),
- ?line do_one_recv_failure(c_node_recv_tmo_2),
+ ?line do_one_recv(Config,c_node_recv_tmo_1),
+ ?line do_one_recv_failure(Config,c_node_recv_tmo_2),
ok.
-do_one_recv(CNode) ->
+do_one_recv(Config,CNode) ->
?line {_,Host} = split(node()),
?line P1 = runner:start(?recv_tmo),
?line runner:send_term(P1,{CNode,
@@ -107,7 +107,7 @@ do_one_recv(CNode) ->
?line {term, Term1} = runner:get_term(P1, 10000),
?line runner:recv_eot(P1).
-do_one_recv_failure(CNode) ->
+do_one_recv_failure(Config,CNode) ->
?line P1 = runner:start(?recv_tmo),
?line runner:send_term(P1,{CNode,
erlang:get_cookie(),
@@ -128,14 +128,14 @@ ei_send_tmo(Config) when is_list(Config) ->
%dbg:p(self()),
VxSim = ?config(vxsim, Config),
?line register(ei_send_tmo_1,self()),
- ?line do_one_send(self(),c_node_send_tmo_1),
- ?line do_one_send(ei_send_tmo_1,c_node_send_tmo_2),
- ?line do_one_send_failure(self(),cccc1,c_nod_send_tmo_3,VxSim),
- ?line do_one_send_failure(ei_send_tmo_1,cccc2,c_nod_send_tmo_4,VxSim),
+ ?line do_one_send(Config,self(),c_node_send_tmo_1),
+ ?line do_one_send(Config,ei_send_tmo_1,c_node_send_tmo_2),
+ ?line do_one_send_failure(Config,self(),cccc1,c_nod_send_tmo_3,VxSim),
+ ?line do_one_send_failure(Config,ei_send_tmo_1,cccc2,c_nod_send_tmo_4,VxSim),
ok.
-do_one_send(From,CNode) ->
+do_one_send(Config,From,CNode) ->
?line {_,Host} = split(node()),
?line P1 = runner:start(?send_tmo),
?line runner:send_term(P1,{CNode,
@@ -155,7 +155,7 @@ do_one_send(From,CNode) ->
?line {term, 0} = runner:get_term(P1, 10000),
?line runner:recv_eot(P1).
-do_one_send_failure(From,FakeName,CName,VxSim) ->
+do_one_send_failure(Config,From,FakeName,CName,VxSim) ->
?line {_,Host} = split(node()),
?line OurName = join(FakeName,Host),
?line Node = join(CName,Host),
diff --git a/lib/erl_interface/test/erl_match_SUITE.erl b/lib/erl_interface/test/erl_match_SUITE.erl
index e019fecca8..edbb17a8c1 100644
--- a/lib/erl_interface/test/erl_match_SUITE.erl
+++ b/lib/erl_interface/test/erl_match_SUITE.erl
@@ -29,7 +29,7 @@
bind/1, integers/1, floats/1, binaries/1, strings/1]).
%% For interactive running of matcher.
--export([start_matcher/0, erl_match/3]).
+-export([start_matcher/1, erl_match/3]).
%% This test suite tests the erl_match() function.
@@ -57,7 +57,7 @@ end_per_group(_GroupName, Config) ->
atoms(suite) -> [];
atoms(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line eq(P, '', ''),
?line eq(P, a, a),
@@ -74,7 +74,7 @@ atoms(Config) when is_list(Config) ->
lists(suite) -> [];
lists(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line eq(P, [], []),
?line ne(P, [], [a]),
@@ -101,7 +101,7 @@ lists(Config) when is_list(Config) ->
tuples(suite) -> [];
tuples(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line ne(P, {}, {a, b}),
?line ne(P, {a, b}, {}),
@@ -129,7 +129,7 @@ tuples(Config) when is_list(Config) ->
references(suite) -> [];
references(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line Ref1 = make_ref(),
?line Ref2 = make_ref(),
@@ -144,7 +144,7 @@ references(Config) when is_list(Config) ->
pids(suite) -> [];
pids(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line Pid1 = c:pid(0,1,2),
?line Pid2 = c:pid(0,1,3),
@@ -163,8 +163,8 @@ ports(Config) when is_list(Config) ->
vxworks ->
{skipped,"not on vxworks, pucko"};
_ ->
- ?line P = start_matcher(),
- ?line P2 = start_matcher(),
+ ?line P = start_matcher(Config),
+ ?line P2 = start_matcher(Config),
?line eq(P, P, P),
?line ne(P, P, P2),
@@ -176,7 +176,7 @@ ports(Config) when is_list(Config) ->
integers(suite) -> [];
integers(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line I1 = 123,
?line I2 = 12345,
?line I3 = -123,
@@ -195,7 +195,7 @@ integers(Config) when is_list(Config) ->
floats(suite) -> [];
floats(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line F1 = 3.1414,
?line F2 = 3.1415,
?line F3 = 3.1416,
@@ -218,7 +218,7 @@ floats(Config) when is_list(Config) ->
binaries(suite) -> [];
binaries(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line Bin1 = term_to_binary({kalle, 146015, {kungsgatan, 23}}),
?line Bin2 = term_to_binary(sune),
?line Bin3 = list_to_binary("sune"),
@@ -237,7 +237,7 @@ binaries(Config) when is_list(Config) ->
strings(suite) -> [];
strings(Config) when is_list(Config) ->
- ?line P = start_matcher(),
+ ?line P = start_matcher(Config),
?line S1 = "string",
?line S2 = "streng",
@@ -254,7 +254,7 @@ strings(Config) when is_list(Config) ->
bind(suite) -> [];
bind(Config) when is_list(Config) ->
- ?line P = start_bind(),
+ ?line P = start_bind(Config),
?line S = "[X,Y,Z]",
?line L1 = [301,302,302],
?line L2 = [65,66,67],
@@ -265,7 +265,7 @@ bind(Config) when is_list(Config) ->
?line runner:finish(P),
ok.
-start_bind() ->
+start_bind(Config) ->
runner:start(?erl_match_bind).
bind_ok(Port, Bind, Term) ->
@@ -287,7 +287,7 @@ erl_bind(Port, Pattern, Term) ->
-start_matcher() ->
+start_matcher(Config) ->
runner:start(?erl_match_server).
eq(Port, Pattern, Term) ->
diff --git a/lib/et/doc/src/Makefile b/lib/et/doc/src/Makefile
index 6bb8164e91..facd335449 100644
--- a/lib/et/doc/src/Makefile
+++ b/lib/et/doc/src/Makefile
@@ -97,14 +97,14 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/et/doc/src/et_intro.xml b/lib/et/doc/src/et_intro.xml
index 0c5fb14d55..60da289721 100644
--- a/lib/et/doc/src/et_intro.xml
+++ b/lib/et/doc/src/et_intro.xml
@@ -40,8 +40,8 @@
ports or files.</p>
<section>
- <title>Scope and Purpose</title>'
-
+ <title>Scope and Purpose</title>
+
<p>This manual describes the <c>Event Tracer (ET)</c> application,
as a component of the Erlang/Open Telecom Platform development
environment. It is assumed that the reader is familiar with the
diff --git a/lib/et/examples/Makefile b/lib/et/examples/Makefile
index 67a6536fdf..190d5e2d6a 100644
--- a/lib/et/examples/Makefile
+++ b/lib/et/examples/Makefile
@@ -73,8 +73,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(ERL_FILES) $(DATA_FILES) $(HRL_FILES) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(ERL_FILES) $(DATA_FILES) $(HRL_FILES) "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/et/src/Makefile b/lib/et/src/Makefile
index bb6632ee91..7693571c5c 100644
--- a/lib/et/src/Makefile
+++ b/lib/et/src/Makefile
@@ -104,14 +104,14 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/et/src/et_wx_contents_viewer.erl b/lib/et/src/et_wx_contents_viewer.erl
index 86f46f25d0..b559da8807 100644
--- a/lib/et/src/et_wx_contents_viewer.erl
+++ b/lib/et/src/et_wx_contents_viewer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2012. 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
@@ -245,12 +245,7 @@ handle_event(#wx{id = Id,
Data when is_record(Data, filter) ->
F = Data,
ChildState= S#state{active_filter = F#filter.name},
- case wx_object:start_link(?MODULE, [ChildState], []) of
- {ok, Pid} when S#state.parent_pid =/= self() ->
- unlink(Pid);
- _ ->
- ignore
- end;
+ wx_object:start_link(?MODULE, [ChildState], []);
{hide, Actors} ->
send_viewer_event(S, {delete_actors, Actors});
{show, Actors} ->
@@ -356,12 +351,7 @@ handle_event(#wx{event = #wxKey{rawCode = KeyCode}}, S) ->
case lists:keysearch(?DEFAULT_FILTER_NAME, #filter.name, S#state.filters) of
{value, F} when is_record(F, filter) ->
ChildState= S#state{active_filter = F#filter.name},
- case wx_object:start_link(?MODULE, [ChildState], []) of
- {ok, Pid} when S#state.parent_pid =/= self() ->
- unlink(Pid);
- _ ->
- ignore
- end;
+ wx_object:start_link(?MODULE, [ChildState], []);
false ->
ignore
end,
@@ -370,12 +360,7 @@ handle_event(#wx{event = #wxKey{rawCode = KeyCode}}, S) ->
case catch lists:nth(Int-$0, S#state.filters) of
F when is_record(F, filter) ->
ChildState= S#state{active_filter = F#filter.name},
- case wx_object:start_link(?MODULE, [ChildState], []) of
- {ok, Pid} when S#state.parent_pid =/= self() ->
- unlink(Pid);
- _ ->
- ignore
- end;
+ wx_object:start_link(?MODULE, [ChildState], []);
{'EXIT', _} ->
ignore
end,
diff --git a/lib/et/test/Makefile b/lib/et/test/Makefile
index e10a2a1587..7b4db7b0c3 100644
--- a/lib/et/test/Makefile
+++ b/lib/et/test/Makefile
@@ -70,12 +70,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) et.spec et.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_SCRIPT) ett $(RELSYSDIR)
- $(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR)
-# chmod -R u+w $(RELSYSDIR)
-# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) et.spec et.cover $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_SCRIPT) ett "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(INSTALL_PROGS) "$(RELSYSDIR)"
+# chmod -R u+w "$(RELSYSDIR)"
+# @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc
index ad449cb6fc..b4af31ae6a 100644
--- a/lib/eunit/doc/overview.edoc
+++ b/lib/eunit/doc/overview.edoc
@@ -723,8 +723,12 @@ A <em>simple test object</em> is one of the following:
```fun some_function/0'''
```fun some_module:some_function/0'''
</li>
- <li>A pair of atoms `{ModuleName, FunctionName}', referring to the
- function `ModuleName:FunctionName/0'</li>
+ <li>A tuple `{test, ModuleName, FunctionName}', where `ModuleName' and
+ `FunctionName' are atoms, referring to the function
+ `ModuleName:FunctionName/0'</li>
+ <li>(Obsolete) A pair of atoms `{ModuleName, FunctionName}', equivalent to
+ `{test, ModuleName, FunctionName}' if nothing else matches first. This
+ might be removed in a future version.</li>
<li>A pair `{LineNumber, SimpleTest}', where `LineNumber' is a
nonnegative integer and `SimpleTest' is another simple test
object. `LineNumber' should indicate the source line of the test.
diff --git a/lib/eunit/doc/src/Makefile b/lib/eunit/doc/src/Makefile
index 2cdc579275..cbcd4c1507 100644
--- a/lib/eunit/doc/src/Makefile
+++ b/lib/eunit/doc/src/Makefile
@@ -157,14 +157,14 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/eunit/examples/Makefile b/lib/eunit/examples/Makefile
index 48ec2ebf2b..cfa0a7a645 100644
--- a/lib/eunit/examples/Makefile
+++ b/lib/eunit/examples/Makefile
@@ -49,8 +49,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(EXAMPLE_FILES) "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl
index db68d8ae60..fba840c3bd 100644
--- a/lib/eunit/include/eunit.hrl
+++ b/lib/eunit/include/eunit.hrl
@@ -25,11 +25,12 @@
%% will become undefined. NODEBUG also implies NOASSERT, unless testing
%% is enabled.
%%
-%% If including this file causes TEST to be defined, then NOASSERT will
-%% be undefined, even if it was previously defined and even if NODEBUG
-%% is defined. If both ASSERT and NOASSERT are defined before the file
-%% is included, then ASSERT takes precedence, and NOASSERT will become
-%% undefined regardless of TEST.
+%% Defining NOASSERT disables asserts. NODEBUG implies NOASSERT unless
+%% testing is enabled. If including this file causes TEST to be defined,
+%% then NOASSERT will be undefined, even if it was previously defined and
+%% even if NODEBUG is defined. If both ASSERT and NOASSERT are defined
+%% before the file is included, then ASSERT takes precedence, and NOASSERT
+%% will become undefined regardless of TEST.
%%
%% After including this file, EUNIT will be defined if and only if TEST
%% is defined.
@@ -127,9 +128,9 @@
current_function)))).
-endif.
--ifdef(NOASSERT).
%% The plain assert macro should be defined to do nothing if this file
%% is included when debugging/testing is turned off.
+-ifdef(NOASSERT).
-ifndef(assert).
-define(assert(BoolExpr),ok).
-endif.
diff --git a/lib/eunit/src/Makefile b/lib/eunit/src/Makefile
index 0b6ed1e839..0a2e71cf7b 100644
--- a/lib/eunit/src/Makefile
+++ b/lib/eunit/src/Makefile
@@ -115,12 +115,12 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(PARSE_TRANSFORM_BIN) $(OBJECTS) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(PARSE_TRANSFORM) $(SOURCES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(INCLUDE_DELIVERABLES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(PARSE_TRANSFORM_BIN) $(OBJECTS) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(PARSE_TRANSFORM) $(SOURCES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(INCLUDE_DELIVERABLES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/eunit/src/eunit.app.src b/lib/eunit/src/eunit.app.src
index 5e16dfa2ce..431abac98b 100644
--- a/lib/eunit/src/eunit.app.src
+++ b/lib/eunit/src/eunit.app.src
@@ -14,7 +14,6 @@
eunit_striptests,
eunit_surefire,
eunit_test,
- eunit_tests,
eunit_tty]},
{registered,[]},
{applications, [kernel,stdlib]},
diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl
index 95857e83c8..51846d73b3 100644
--- a/lib/eunit/src/eunit.erl
+++ b/lib/eunit/src/eunit.erl
@@ -139,7 +139,7 @@ test(Tests, Options) ->
%% @private
%% @doc See {@link test/2}.
test(Server, Tests, Options) ->
- Listeners = [eunit_tty:start(Options) | listeners(Options)],
+ Listeners = listeners(Options),
Serial = eunit_serial:start(Listeners),
case eunit_server:start_test(Server, Serial, Tests, Options) of
{ok, Reference} -> test_run(Reference, Listeners);
@@ -194,7 +194,10 @@ submit(Server, T, Options) ->
eunit_server:start_test(Server, Dummy, T, Options).
listeners(Options) ->
- Ps = start_listeners(proplists:get_all_values(report, Options)),
+ %% note that eunit_tty must always run, because it sends the final
+ %% {result,...} message that the test_run() function is waiting for
+ Ls = [{eunit_tty, Options} | proplists:get_all_values(report, Options)],
+ Ps = start_listeners(Ls),
%% the event_log option is for debugging, to view the raw events
case proplists:get_value(event_log, Options) of
undefined ->
diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl
index 392d378a0e..0350f9bf6e 100644
--- a/lib/eunit/src/eunit_data.erl
+++ b/lib/eunit/src/eunit_data.erl
@@ -83,6 +83,7 @@
%% SimpleTest = TestFunction | {Line::integer(), SimpleTest}
%%
%% TestFunction = () -> any()
+%% | {test, M::moduleName(), F::functionName()}
%% | {M::moduleName(), F::functionName()}.
%%
%% AbstractTestFunction = (X::any()) -> any()
@@ -95,7 +96,6 @@
%%
%% @type moduleName() = atom()
%% @type functionName() = atom()
-%% @type arity() = integer()
%% @type appName() = atom()
%% @type fileName() = string()
@@ -156,8 +156,9 @@ iter_prev(#iter{prev = [T | Ts]} = I) ->
%% @spec (tests()) -> none | {testItem(), tests()}
%% @type testItem() = #test{} | #group{}
%% @throws {bad_test, term()}
-%% | {generator_failed, exception()}
-%% | {no_such_function, eunit_lib:mfa()}
+%% | {generator_failed, {{M::atom(),F::atom(),A::integer()},
+%% exception()}}
+%% | {no_such_function, mfa()}
%% | {module_not_found, moduleName()}
%% | {application_not_found, appName()}
%% | {file_read_error, {Reason::atom(), Message::string(),
@@ -221,17 +222,27 @@ parse({foreachx, P, S1, C1, Ps} = T)
[] ->
{data, []}
end;
-parse({generator, F} = T) when is_function(F) ->
+parse({generator, F}) when is_function(F) ->
+ {module, M} = erlang:fun_info(F, module),
+ {name, N} = erlang:fun_info(F, name),
+ {arity, A} = erlang:fun_info(F, arity),
+ parse({generator, F, {M,N,A}});
+parse({generator, F, {M,N,A}} = T)
+ when is_function(F), is_atom(M), is_atom(N), is_integer(A) ->
check_arity(F, 0, T),
%% use run_testfun/1 to handle wrapper exceptions
case eunit_test:run_testfun(F) of
{ok, T1} ->
+ case eunit_lib:is_not_test(T1) of
+ true -> throw({bad_generator, {{M,N,A}, T1}});
+ false -> ok
+ end,
{data, T1};
{error, {Class, Reason, Trace}} ->
- throw({generator_failed, {Class, Reason, Trace}})
+ throw({generator_failed, {{M,N,A}, {Class, Reason, Trace}}})
end;
parse({generator, M, F}) when is_atom(M), is_atom(F) ->
- parse({generator, eunit_test:function_wrapper(M, F)});
+ parse({generator, eunit_test:mf_wrapper(M, F), {M,F,0}});
parse({inorder, T}) ->
group(#group{tests = T, order = inorder});
parse({inparallel, T}) ->
@@ -421,8 +432,11 @@ parse_simple(F) ->
parse_function(F) when is_function(F) ->
check_arity(F, 0, F),
#test{f = F, location = eunit_lib:fun_parent(F)};
-parse_function({M,F}) when is_atom(M), is_atom(F) ->
- #test{f = eunit_test:function_wrapper(M, F), location = {M, F, 0}};
+parse_function({test, M, F}) when is_atom(M), is_atom(F) ->
+ #test{f = eunit_test:mf_wrapper(M, F), location = {M, F, 0}};
+parse_function({M, F}) when is_atom(M), is_atom(F) ->
+ %% {M,F} is now considered obsolete; use {test,M,F} instead
+ parse_function({test, M, F});
parse_function(F) ->
bad_test(F).
@@ -580,7 +594,7 @@ testfuns(Es, M, TestSuffix, GeneratorSuffix) ->
N = atom_to_list(F),
case lists:suffix(TestSuffix, N) of
true ->
- [{M,F} | Fs];
+ [{test, M, F} | Fs];
false ->
case lists:suffix(GeneratorSuffix, N) of
true ->
@@ -723,6 +737,7 @@ data_test_() ->
Tests = [T,T,T],
[?_assertMatch(ok, eunit:test(T)),
?_assertMatch(error, eunit:test(Fail)),
+ ?_assertMatch(ok, eunit:test({test, ?MODULE, trivial_test})),
?_assertMatch(ok, eunit:test({generator, fun () -> Tests end})),
?_assertMatch(ok, eunit:test({generator, fun generator/0})),
?_assertMatch(ok, eunit:test({generator, ?MODULE, generator_exported_})),
@@ -740,6 +755,12 @@ data_test_() ->
%%?_test({foreach, Setup, [T, T, T]})
].
+trivial_test() ->
+ ok.
+
+trivial_generator_test_() ->
+ [?_test(ok)].
+
lazy_test_() ->
{spawn, [?_test(undefined = put(count, 0)),
lazy_gen(7),
diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl
index 1c41e229c5..ea9e944d7e 100644
--- a/lib/eunit/src/eunit_lib.erl
+++ b/lib/eunit/src/eunit_lib.erl
@@ -30,7 +30,8 @@
-export([dlist_next/1, uniq/1, fun_parent/1, is_string/1, command/1,
command/2, command/3, trie_new/0, trie_store/2, trie_match/2,
split_node/1, consult_file/1, list_dir/1, format_exit_term/1,
- format_exception/1, format_exception/2, format_error/1]).
+ format_exception/1, format_exception/2, format_error/1,
+ is_not_test/1]).
%% Type definitions for describing exceptions
@@ -39,13 +40,10 @@
%%
%% @type exceptionClass() = error | exit | throw
%%
-%% @type stackTrace() = [{moduleName(), functionName(),
-%% arity() | argList()}]
+%% @type stackTrace() = [{moduleName(), functionName(), arity() | argList()}]
%%
%% @type moduleName() = atom()
%% @type functionName() = atom()
-%% @type arity() = integer()
-%% @type mfa() = {moduleName(), functionName(), arity()}
%% @type argList() = [term()]
%% @type fileName() = string()
@@ -59,8 +57,9 @@ format_exception({Class,Term,Trace}, Depth)
when is_atom(Class), is_list(Trace) ->
case is_stacktrace(Trace) of
true ->
- io_lib:format("~w:~P\n~s",
- [Class, Term, Depth, format_stacktrace(Trace)]);
+ io_lib:format("~s**~w:~s",
+ [format_stacktrace(Trace), Class,
+ format_term(Term, Depth)]);
false ->
format_term(Term, Depth)
end;
@@ -86,6 +85,12 @@ analyze_exit_term(Term) ->
is_stacktrace([]) ->
true;
+is_stacktrace([{M,F,A,L}|Fs])
+ when is_atom(M), is_atom(F), is_integer(A), is_list(L) ->
+ is_stacktrace(Fs);
+is_stacktrace([{M,F,As,L}|Fs])
+ when is_atom(M), is_atom(F), is_list(As), is_list(L) ->
+ is_stacktrace(Fs);
is_stacktrace([{M,F,A}|Fs]) when is_atom(M), is_atom(F), is_integer(A) ->
is_stacktrace(Fs);
is_stacktrace([{M,F,As}|Fs]) when is_atom(M), is_atom(F), is_list(As) ->
@@ -96,10 +101,11 @@ is_stacktrace(_) ->
format_stacktrace(Trace) ->
format_stacktrace(Trace, "in function", "in call from").
-format_stacktrace([{M,F,A}|Fs], Pre, Pre1) when is_integer(A) ->
- [io_lib:fwrite(" ~s ~w:~w/~w\n", [Pre, M, F, A])
+format_stacktrace([{M,F,A,L}|Fs], Pre, Pre1) when is_integer(A) ->
+ [io_lib:fwrite("~s ~w:~w/~w~s\n",
+ [Pre, M, F, A, format_stacktrace_location(L)])
| format_stacktrace(Fs, Pre1, Pre1)];
-format_stacktrace([{M,F,As}|Fs], Pre, Pre1) when is_list(As) ->
+format_stacktrace([{M,F,As,L}|Fs], Pre, Pre1) when is_list(As) ->
A = length(As),
C = case is_op(M,F,A) of
true when A =:= 1 ->
@@ -112,12 +118,23 @@ format_stacktrace([{M,F,As}|Fs], Pre, Pre1) when is_list(As) ->
false ->
io_lib:fwrite("~w(~s)", [F,format_arglist(As)])
end,
- [io_lib:fwrite(" ~s ~w:~w/~w\n called as ~s\n",
- [Pre,M,F,A,C])
+ [io_lib:fwrite("~s ~w:~w/~w~s\n called as ~s\n",
+ [Pre,M,F,A,format_stacktrace_location(L),C])
| format_stacktrace(Fs,Pre1,Pre1)];
+format_stacktrace([{M,F,As}|Fs], Pre, Pre1) ->
+ format_stacktrace([{M,F,As,[]}|Fs], Pre, Pre1);
format_stacktrace([],_Pre,_Pre1) ->
"".
+format_stacktrace_location(Location) ->
+ File = proplists:get_value(file, Location),
+ Line = proplists:get_value(line, Location),
+ if File =/= undefined, Line =/= undefined ->
+ io_lib:format(" (~s, line ~w)", [File, Line]);
+ true ->
+ ""
+ end.
+
format_arg(A) ->
io_lib:format("~P",[A,15]).
@@ -139,9 +156,13 @@ is_op(_M, _F, _A) ->
format_error({bad_test, Term}) ->
error_msg("bad test descriptor", "~P", [Term, 15]);
-format_error({generator_failed, Exception}) ->
- error_msg("test generator failed", "~s",
- [format_exception(Exception)]);
+format_error({bad_generator, {{M,F,A}, Term}}) ->
+ error_msg(io_lib:format("result from generator ~w:~w/~w is not a test",
+ [M,F,A]),
+ "~P", [Term, 15]);
+format_error({generator_failed, {{M,F,A}, Exception}}) ->
+ error_msg(io_lib:format("test generator ~w:~w/~w failed",[M,F,A]),
+ "~s", [format_exception(Exception)]);
format_error({no_such_function, {M,F,A}})
when is_atom(M), is_atom(F), is_integer(A) ->
error_msg(io_lib:format("no such function: ~w:~w/~w", [M,F,A]),
@@ -158,14 +179,55 @@ format_error({setup_failed, Exception}) ->
format_error({cleanup_failed, Exception}) ->
error_msg("context cleanup failed", "~s",
[format_exception(Exception)]);
+format_error({{bad_instantiator, {{M,F,A}, Term}}, _DummyException}) ->
+ error_msg(io_lib:format("result from instantiator ~w:~w/~w is not a test",
+ [M,F,A]),
+ "~P", [Term, 15]);
format_error({instantiation_failed, Exception}) ->
error_msg("instantiation of subtests failed", "~s",
[format_exception(Exception)]).
error_msg(Title, Fmt, Args) ->
- Msg = io_lib:format("::"++Fmt, Args), % gets indentation right
+ Msg = io_lib:format("**"++Fmt, Args), % gets indentation right
io_lib:fwrite("*** ~s ***\n~s\n\n", [Title, Msg]).
+-ifdef(TEST).
+format_exception_test_() ->
+ [?_assertMatch(
+ "\nymmud:rorre"++_,
+ lists:reverse(lists:flatten(
+ format_exception(try erlang:error(dummy)
+ catch C:R -> {C, R, erlang:get_stacktrace()}
+ end)))),
+ ?_assertMatch(
+ "\nymmud:rorre"++_,
+ lists:reverse(lists:flatten(
+ format_exception(try erlang:error(dummy, [a])
+ catch C:R -> {C, R, erlang:get_stacktrace()}
+ end))))].
+-endif.
+
+%% ---------------------------------------------------------------------
+%% detect common return values that are definitely not tests
+
+is_not_test(T) ->
+ case T of
+ ok -> true;
+ error -> true;
+ true -> true;
+ false -> true;
+ undefined -> true;
+ {ok, _} -> true;
+ {error, _} -> true;
+ {'EXIT', _} -> true;
+ N when is_number(N) -> true;
+ [N|_] when is_number(N) -> true;
+ X when is_binary(X) -> true;
+ X when is_pid(X) -> true;
+ X when is_port(X) -> true;
+ X when is_reference(X) -> true;
+ _ -> false
+ end.
%% ---------------------------------------------------------------------
%% Deep list iterator; accepts improper lists/sublists, and also accepts
diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl
index 2a6cbca14d..46b8c8b503 100644
--- a/lib/eunit/src/eunit_surefire.erl
+++ b/lib/eunit/src/eunit_surefire.erl
@@ -156,9 +156,33 @@ handle_end(test, Data, St) ->
St#state{testsuites=store_suite(NewTestSuite, TestSuites)}.
%% Cancel group does not give information on the individual cancelled test case
-%% We ignore this event
-handle_cancel(group, _Data, St) ->
- St;
+%% We ignore this event...
+handle_cancel(group, Data, St) ->
+ %% ...except when it tells us that a fixture setup or cleanup failed.
+ case proplists:get_value(reason, Data) of
+ {abort, {SomethingFailed, Exception}}
+ when SomethingFailed =:= setup_failed;
+ SomethingFailed =:= cleanup_failed ->
+ [GroupId|_] = proplists:get_value(id, Data),
+ TestSuites = St#state.testsuites,
+ TestSuite = lookup_suite_by_group_id(GroupId, TestSuites),
+
+ %% We don't have any proper name. Let's give all the
+ %% clues that we have.
+ Name = case SomethingFailed of
+ setup_failed -> "fixture setup ";
+ cleanup_failed -> "fixture cleanup "
+ end
+ ++ io_lib:format("~p", [proplists:get_value(id, Data)]),
+ Desc = format_desc(proplists:get_value(desc, Data)),
+ TestCase = #testcase{
+ name = Name, description = Desc,
+ time = 0, output = <<>>},
+ NewTestSuite = add_testcase_to_testsuite({error, Exception}, TestCase, TestSuite),
+ St#state{testsuites=store_suite(NewTestSuite, TestSuites)};
+ _ ->
+ St
+ end;
handle_cancel(test, Data, St) ->
%% Retrieve existing test suite:
[GroupId|_] = proplists:get_value(id, Data),
@@ -232,7 +256,7 @@ write_reports(TestSuites, XmlDir) ->
write_report(#testsuite{name = Name} = TestSuite, XmlDir) ->
Filename = filename:join(XmlDir, lists:flatten(["TEST-", escape_suitename(Name)], ".xml")),
- case file:open(Filename, [write, raw]) of
+ case file:open(Filename, [write,{encoding,utf8}]) of
{ok, FileDescriptor} ->
try
write_report_to(TestSuite, FileDescriptor)
diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl
index bca49ae626..9cf40a738d 100644
--- a/lib/eunit/src/eunit_test.erl
+++ b/lib/eunit/src/eunit_test.erl
@@ -21,8 +21,7 @@
-module(eunit_test).
--export([run_testfun/1, function_wrapper/2, enter_context/4,
- multi_setup/1]).
+-export([run_testfun/1, mf_wrapper/2, enter_context/4, multi_setup/1]).
-include("eunit.hrl").
@@ -43,8 +42,12 @@ get_stacktrace(Ts) ->
prune_trace([{eunit_data, _, _} | Rest], Tail) ->
prune_trace(Rest, Tail);
+prune_trace([{eunit_data, _, _, _} | Rest], Tail) ->
+ prune_trace(Rest, Tail);
prune_trace([{?MODULE, _, _} | _Rest], Tail) ->
Tail;
+prune_trace([{?MODULE, _, _, _} | _Rest], Tail) ->
+ Tail;
prune_trace([T | Ts], Tail) ->
[T | prune_trace(Ts, Tail)];
prune_trace([], Tail) ->
@@ -258,7 +261,7 @@ macro_test_() ->
%% @type wrapperError() = {no_such_function, mfa()}
%% | {module_not_found, moduleName()}
-function_wrapper(M, F) ->
+mf_wrapper(M, F) ->
fun () ->
try M:F()
catch
@@ -289,12 +292,12 @@ fail(Term) ->
wrapper_test_() ->
{"error handling in function wrapper",
[?_assertException(throw, {module_not_found, eunit_nonexisting},
- run_testfun(function_wrapper(eunit_nonexisting,test))),
+ run_testfun(mf_wrapper(eunit_nonexisting,test))),
?_assertException(throw,
{no_such_function, {?MODULE,nonexisting_test,0}},
- run_testfun(function_wrapper(?MODULE,nonexisting_test))),
+ run_testfun(mf_wrapper(?MODULE,nonexisting_test))),
?_test({error, {error, undef, _T}}
- = run_testfun(function_wrapper(?MODULE,wrapper_test_exported_)))
+ = run_testfun(mf_wrapper(?MODULE,wrapper_test_exported_)))
]}.
%% this must be exported (done automatically by the autoexport transform)
@@ -319,6 +322,17 @@ enter_context(Setup, Cleanup, Instantiate, Callback) ->
R ->
try Instantiate(R) of
T ->
+ case eunit_lib:is_not_test(T) of
+ true ->
+ catch throw(error), % generate a stack trace
+ {module,M} = erlang:fun_info(Instantiate, module),
+ {name,N} = erlang:fun_info(Instantiate, name),
+ {arity,A} = erlang:fun_info(Instantiate, arity),
+ context_error({bad_instantiator, {{M,N,A},T}},
+ error, badarg);
+ false ->
+ ok
+ end,
try Callback(T) %% call back to client code
after
%% Always run cleanup; client may be an idiot
diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl
index e3e7b710b2..f21b2da3d3 100644
--- a/lib/eunit/src/eunit_tty.erl
+++ b/lib/eunit/src/eunit_tty.erl
@@ -44,6 +44,7 @@ start(Options) ->
init(Options) ->
St = #state{verbose = proplists:get_bool(verbose, Options)},
+ put(no_tty, proplists:get_bool(no_tty, Options)),
receive
{start, _Reference} ->
if St#state.verbose -> print_header();
@@ -59,30 +60,30 @@ terminate({ok, Data}, St) ->
Cancel = proplists:get_value(cancel, Data, 0),
if Fail =:= 0, Skip =:= 0, Cancel =:= 0 ->
if Pass =:= 0 ->
- io:fwrite(" There were no tests to run.\n");
+ fwrite(" There were no tests to run.\n");
true ->
if St#state.verbose -> print_bar();
true -> ok
end,
if Pass =:= 1 ->
- io:fwrite(" Test passed.\n");
+ fwrite(" Test passed.\n");
true ->
- io:fwrite(" All ~w tests passed.\n", [Pass])
+ fwrite(" All ~w tests passed.\n", [Pass])
end
end,
sync_end(ok);
true ->
print_bar(),
- io:fwrite(" Failed: ~w. Skipped: ~w. Passed: ~w.\n",
- [Fail, Skip, Pass]),
+ fwrite(" Failed: ~w. Skipped: ~w. Passed: ~w.\n",
+ [Fail, Skip, Pass]),
if Cancel =/= 0 ->
- io:fwrite("One or more tests were cancelled.\n");
+ fwrite("One or more tests were cancelled.\n");
true -> ok
end,
sync_end(error)
end;
terminate({error, Reason}, _St) ->
- io:fwrite("Internal error: ~P.\n", [Reason, 25]),
+ fwrite("Internal error: ~P.\n", [Reason, 25]),
sync_end(error).
sync_end(Result) ->
@@ -93,10 +94,10 @@ sync_end(Result) ->
end.
print_header() ->
- io:fwrite("======================== EUnit ========================\n").
+ fwrite("======================== EUnit ========================\n").
print_bar() ->
- io:fwrite("=======================================================\n").
+ fwrite("=======================================================\n").
handle_begin(group, Data, St) ->
@@ -170,18 +171,18 @@ handle_cancel(test, Data, St) ->
indent(N) when is_integer(N), N >= 1 ->
- io:put_chars(lists:duplicate(N * 2, $\s));
+ fwrite(lists:duplicate(N * 2, $\s));
indent(_N) ->
ok.
print_group_start(I, Desc) ->
indent(I),
- io:fwrite("~s\n", [Desc]).
+ fwrite("~s\n", [Desc]).
print_group_end(I, Time) ->
if Time > 0 ->
indent(I),
- io:fwrite("[done in ~.3f s]\n", [Time/1000]);
+ fwrite("[done in ~.3f s]\n", [Time/1000]);
true ->
ok
end.
@@ -198,9 +199,9 @@ print_test_begin(I, Data) ->
end,
case proplists:get_value(source, Data) of
{Module, Name, _Arity} ->
- io:fwrite("~s:~s ~s~s...", [Module, L, Name, D]);
+ fwrite("~s:~s ~s~s...", [Module, L, Name, D]);
_ ->
- io:fwrite("~s~s...", [L, D])
+ fwrite("~s~s...", [L, D])
end.
print_test_end(Data) ->
@@ -208,36 +209,35 @@ print_test_end(Data) ->
T = if Time > 0 -> io_lib:fwrite("[~.3f s] ", [Time/1000]);
true -> ""
end,
- io:fwrite("~sok\n", [T]).
+ fwrite("~sok\n", [T]).
print_test_error({error, Exception}, Data) ->
Output = proplists:get_value(output, Data),
- io:fwrite("*failed*\n::~s",
- [eunit_lib:format_exception(Exception)]),
+ fwrite("*failed*\n~s", [eunit_lib:format_exception(Exception)]),
case Output of
<<>> ->
- io:put_chars("\n\n");
+ fwrite("\n\n");
<<Text:800/binary, _:1/binary, _/binary>> ->
- io:fwrite(" output:<<\"~s\">>...\n\n", [Text]);
+ fwrite(" output:<<\"~s\">>...\n\n", [Text]);
_ ->
- io:fwrite(" output:<<\"~s\">>\n\n", [Output])
+ fwrite(" output:<<\"~s\">>\n\n", [Output])
end;
print_test_error({skipped, Reason}, _) ->
- io:fwrite("*did not run*\n::~s\n", [format_skipped(Reason)]).
+ fwrite("*did not run*\n::~s\n", [format_skipped(Reason)]).
format_skipped({module_not_found, M}) ->
- io_lib:format("missing module: ~w", [M]);
+ io_lib:fwrite("missing module: ~w", [M]);
format_skipped({no_such_function, {M,F,A}}) ->
- io_lib:format("no such function: ~w:~w/~w", [M,F,A]).
+ io_lib:fwrite("no such function: ~w:~w/~w", [M,F,A]).
print_test_cancel(Reason) ->
- io:fwrite(format_cancel(Reason)).
+ fwrite(format_cancel(Reason)).
print_group_cancel(_I, {blame, _}) ->
ok;
print_group_cancel(I, Reason) ->
indent(I),
- io:fwrite(format_cancel(Reason)).
+ fwrite(format_cancel(Reason)).
format_cancel(undefined) ->
"*skipped*\n";
@@ -253,3 +253,12 @@ format_cancel({exit, Reason}) ->
[Reason, 15]);
format_cancel({abort, Reason}) ->
eunit_lib:format_error(Reason).
+
+fwrite(String) ->
+ fwrite(String, []).
+
+fwrite(String, Args) ->
+ case get(no_tty) of
+ false -> io:fwrite(String, Args);
+ true -> ok
+ end.
diff --git a/lib/eunit/test/Makefile b/lib/eunit/test/Makefile
index a2d276f619..1586dd8857 100644
--- a/lib/eunit/test/Makefile
+++ b/lib/eunit/test/Makefile
@@ -74,9 +74,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) eunit.spec $(EMAKEFILE) \
$(COVERFILE) $(ERL_FILES) \
- $(RELSYSDIR)
+ "$(RELSYSDIR)"
release_docs_spec:
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 445c070e96..174d197117 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.2.2
+EUNIT_VSN = 2.2.3
diff --git a/lib/gs/contribs/bonk/Makefile b/lib/gs/contribs/bonk/Makefile
index be096824dd..dc92149784 100644
--- a/lib/gs/contribs/bonk/Makefile
+++ b/lib/gs/contribs/bonk/Makefile
@@ -94,14 +94,14 @@ $(EBIN)/$(TOOLNAME).tool: $(TOOLNAME).tool
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/bonk/bitmaps
- $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) $(RELSYSDIR)/bonk/bitmaps
- $(INSTALL_DIR) $(RELSYSDIR)/bonk/sounds
- $(INSTALL_DATA) $(SOUNDS) $(RELSYSDIR)/bonk/sounds
- $(INSTALL_DIR) $(RELSYSDIR)/bonk
- $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) $(RELSYSDIR)/bonk
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/bonk/bitmaps"
+ $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) "$(RELSYSDIR)/bonk/bitmaps"
+ $(INSTALL_DIR) "$(RELSYSDIR)/bonk/sounds"
+ $(INSTALL_DATA) $(SOUNDS) "$(RELSYSDIR)/bonk/sounds"
+ $(INSTALL_DIR) "$(RELSYSDIR)/bonk"
+ $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) "$(RELSYSDIR)/bonk"
release_docs_spec:
diff --git a/lib/gs/contribs/cols/Makefile b/lib/gs/contribs/cols/Makefile
index 75ca75ffc0..4ce4204c92 100644
--- a/lib/gs/contribs/cols/Makefile
+++ b/lib/gs/contribs/cols/Makefile
@@ -91,12 +91,12 @@ $(EBIN)/help.gif: help.gif
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/cols/bitmaps
- $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) $(RELSYSDIR)/cols/bitmaps
- $(INSTALL_DIR) $(RELSYSDIR)/cols
- $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) $(RELSYSDIR)/cols
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/cols/bitmaps"
+ $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) "$(RELSYSDIR)/cols/bitmaps"
+ $(INSTALL_DIR) "$(RELSYSDIR)/cols"
+ $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) "$(RELSYSDIR)/cols"
release_docs_spec:
diff --git a/lib/gs/contribs/mandel/Makefile b/lib/gs/contribs/mandel/Makefile
index 61a7a612e0..451ece2c8f 100644
--- a/lib/gs/contribs/mandel/Makefile
+++ b/lib/gs/contribs/mandel/Makefile
@@ -90,11 +90,11 @@ $(EBIN)/help.gif: help.gif
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/mandel/bitmaps
- $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) $(RELSYSDIR)/mandel/bitmaps
- $(INSTALL_DIR) $(RELSYSDIR)/mandel
- $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) $(RELSYSDIR)/mandel
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/mandel/bitmaps"
+ $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) "$(RELSYSDIR)/mandel/bitmaps"
+ $(INSTALL_DIR) "$(RELSYSDIR)/mandel"
+ $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) "$(RELSYSDIR)/mandel"
release_docs_spec:
diff --git a/lib/gs/contribs/othello/Makefile b/lib/gs/contribs/othello/Makefile
index b81b35fb55..5f09f2ed13 100644
--- a/lib/gs/contribs/othello/Makefile
+++ b/lib/gs/contribs/othello/Makefile
@@ -89,12 +89,12 @@ $(EBIN)/$(TOOLNAME).tool: $(TOOLNAME).tool
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/othello
- $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) $(RELSYSDIR)/othello
- $(INSTALL_DIR) $(RELSYSDIR)/othello/priv
- $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) $(RELSYSDIR)/othello/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/othello"
+ $(INSTALL_DATA) $(ERL_FILES) $(EXTRA_FILES) "$(RELSYSDIR)/othello"
+ $(INSTALL_DIR) "$(RELSYSDIR)/othello/priv"
+ $(INSTALL_DATA) $(BITMAPS) $(TOOLBOX_FILES) "$(RELSYSDIR)/othello/priv"
release_docs_spec:
diff --git a/lib/gs/doc/src/Makefile b/lib/gs/doc/src/Makefile
index 192dd67a52..14204c52fc 100644
--- a/lib/gs/doc/src/Makefile
+++ b/lib/gs/doc/src/Makefile
@@ -144,13 +144,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- (/bin/cp -rf $(HTMLDIR) $(RELSYSDIR)/doc)
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ (/bin/cp -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/gs/examples/Makefile b/lib/gs/examples/Makefile
index 10b166b207..d214cd2256 100644
--- a/lib/gs/examples/Makefile
+++ b/lib/gs/examples/Makefile
@@ -87,9 +87,9 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src"
release_docs_spec:
diff --git a/lib/gs/src/Makefile b/lib/gs/src/Makefile
index 43b530295b..a9904161a4 100644
--- a/lib/gs/src/Makefile
+++ b/lib/gs/src/Makefile
@@ -107,13 +107,13 @@ $(GSTK_GENERIC_TARGET): gstk_generic.hrl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
$(INSTALL_DATA) $(APP_SRC) $(ERL_FILES) $(HRL_FILES) $(GEN_HRL_FILES) \
- $(GSTK_GENERIC) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bitmap
- $(INSTALL_DATA) $(IMAGES) $(RELSYSDIR)/priv/bitmap
+ $(GSTK_GENERIC) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/bitmap"
+ $(INSTALL_DATA) $(IMAGES) "$(RELSYSDIR)/priv/bitmap"
release_docs_spec:
diff --git a/lib/gs/tcl/Makefile.in b/lib/gs/tcl/Makefile.in
index dce34a4baa..0bccb60c7b 100644
--- a/lib/gs/tcl/Makefile.in
+++ b/lib/gs/tcl/Makefile.in
@@ -74,10 +74,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(TCL_FILES) $(EXTRA_FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(TCL_FILES) $(EXTRA_FILES) "$(RELSYSDIR)/priv"
ifneq ($(TCL_TAR),)
- gzip -dc $(TCL_TAR) | (cd $(RELSYSDIR)/priv && tar -xf -)
+ gzip -dc $(TCL_TAR) | (cd "$(RELSYSDIR)/priv" && tar -xf -)
endif
release_docs_spec:
diff --git a/lib/hipe/amd64/Makefile b/lib/hipe/amd64/Makefile
index 15291e9bbe..50cd024d72 100644
--- a/lib/hipe/amd64/Makefile
+++ b/lib/hipe/amd64/Makefile
@@ -105,8 +105,8 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/arm/Makefile b/lib/hipe/arm/Makefile
index a64f133679..651b82f1ed 100644
--- a/lib/hipe/arm/Makefile
+++ b/lib/hipe/arm/Makefile
@@ -106,8 +106,8 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/cerl/Makefile b/lib/hipe/cerl/Makefile
index 14e68f5233..506e993ff4 100644
--- a/lib/hipe/cerl/Makefile
+++ b/lib/hipe/cerl/Makefile
@@ -42,7 +42,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-MODULES = cerl_cconv cerl_closurean cerl_hipeify cerl_hybrid_transform \
+MODULES = cerl_cconv cerl_closurean cerl_hipeify \
cerl_lib cerl_messagean cerl_pmatch cerl_prettypr cerl_to_icode \
cerl_typean erl_bif_types erl_types
@@ -100,10 +100,10 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/cerl
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/cerl
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/cerl"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/cerl"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/cerl/cerl_hybrid_transform.erl b/lib/hipe/cerl/cerl_hybrid_transform.erl
deleted file mode 100644
index b248b0ccd0..0000000000
--- a/lib/hipe/cerl/cerl_hybrid_transform.erl
+++ /dev/null
@@ -1,153 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. 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(cerl_hybrid_transform).
-
-%% Use compile option `{core_transform, cerl_hybrid_transform}' to
-%% insert this as a compilation pass.
-
--export([transform/2, core_transform/2]).
-
--spec core_transform(cerl:cerl(), [term()]) -> cerl:cerl().
-
-core_transform(Code, Opts) ->
- cerl:to_records(transform(cerl:from_records(Code), Opts)).
-
--spec transform(cerl:cerl(), [term()]) -> cerl:cerl().
-
-transform(Code, _Opts) ->
- Code0 = cerl_trees:map(fun unfold_literal/1, Code),
- {Code1, _} = cerl_trees:label(Code0),
- io:fwrite("Running hybrid heap analysis..."),
- {T1,_} = statistics(runtime),
- {Code2, _, Vars} = cerl_messagean:annotate(Code1),
- {T2,_} = statistics(runtime),
- io:fwrite("(~w ms), transform...", [T2 - T1]),
- Code3 = rewrite(Code2, Vars),
- io:fwrite("done.\n"),
- cerl_trees:map(fun fold_literal/1, Code3).
-
-unfold_literal(T) ->
- cerl:unfold_literal(T).
-
-fold_literal(T) ->
- cerl:fold_literal(T).
-
-%% If escape-annotated:
-%% {...} => hybrid:tuple([...])
-%% [H | T] => hybrid:cons(H, T)
-%%
-%% Wrapper for args to hybrid:cons/hybrid:tuple that may need copying:
-%% hybrid:copy(A)
-
-rewrite(Node, Vars) ->
- case cerl:type(Node) of
- tuple ->
- Es = rewrite_list(cerl:tuple_es(Node), Vars),
- case is_escaping(Node) of
- false ->
- cerl:update_c_tuple(Node, Es);
- true ->
- Es1 = wrap(Es, Node, Vars),
- cerl:update_c_call(Node,
- cerl:abstract(hybrid),
- cerl:abstract(tuple),
- [cerl:make_list(Es1)])
-%%% cerl:update_c_call(Node, cerl:abstract(hybrid),
-%%% cerl:abstract(tuple), Es1)
- end;
- cons ->
- H = rewrite(cerl:cons_hd(Node), Vars),
- T = rewrite(cerl:cons_tl(Node), Vars),
- case is_escaping(Node) of
- false ->
- cerl:update_c_cons(Node, H, T);
- true ->
- Es = wrap([H, T], Node, Vars),
- cerl:update_c_call(Node,
- cerl:abstract(hybrid),
- cerl:abstract(cons),
- Es)
- end;
-%%% call ->
-%%% M = rewrite(cerl:call_module(Node)),
-%%% F = rewrite(cerl:call_name(Node)),
-%%% As = rewrite_list(cerl:call_args(Node)),
-%%% case cerl:is_c_atom(M) andalso cerl:is_c_atom(F) of
-%%% true ->
-%%% case {cerl:atom_val(M), cerl:atom_val(F), length(As)} of
-%%% {erlang, '!', 2} ->
-%%% cerl:update_c_call(Node,
-%%% cerl:abstract(hipe_bifs),
-%%% cerl:abstract(send),
-%%% [cerl:make_list(As)]);
-%%% _ ->
-%%% cerl:update_c_call(Node, M, F, As)
-%%% end;
-%%% false ->
-%%% cerl:update_c_call(Node, M, F, As)
-%%% end;
- clause ->
- B = rewrite(cerl:clause_body(Node), Vars),
- cerl:update_c_clause(Node, cerl:clause_pats(Node),
- cerl:clause_guard(Node), B);
- primop ->
- case cerl:atom_val(cerl:primop_name(Node)) of
- match_fail ->
- Node;
- _ ->
- As = rewrite_list(cerl:primop_args(Node), Vars),
- cerl:update_c_primop(Node, cerl:primop_name(Node), As)
- end;
- _T ->
- case cerl:subtrees(Node) of
- [] ->
- Node;
- Gs ->
- cerl:update_tree(Node, [rewrite_list(Ns, Vars)
- || Ns <- Gs])
- end
- end.
-
-rewrite_list([N | Ns], Vars) ->
- [rewrite(N, Vars) | rewrite_list(Ns, Vars)];
-rewrite_list([], _) ->
- [].
-
-is_escaping(T) ->
- lists:member(escapes, cerl:get_ann(T)).
-
-wrap(Es, Node, Vars) ->
- L = cerl_trees:get_label(Node),
- Xs = dict:fetch(L, Vars),
- wrap(Es, Xs).
-
-wrap([E | Es], [{S, _} | Xs]) ->
- case ordsets:is_element(unsafe, S) of
-%% case cerl:type(E) =/= literal of
- true ->
- [cerl:c_call(cerl:abstract(hybrid),
- cerl:abstract(copy),
- [E])
- | wrap(Es, Xs)];
- false ->
- [E | wrap(Es, Xs)]
- end;
-wrap([], _) ->
- [].
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 5033cef8c5..1ef73da1be 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -1269,7 +1269,6 @@ type(erlang, process_info, 2, Xs) ->
['links'] -> t_tuple([InfoItem, t_list(t_pid())]);
['memory'] ->
t_tuple([InfoItem, t_non_neg_integer()]);
- ['message_binary'] -> t_tuple([InfoItem, t_list()]);
['message_queue_len'] ->
t_tuple([InfoItem, t_non_neg_integer()]);
['messages'] -> t_tuple([InfoItem, t_list()]);
@@ -1594,14 +1593,10 @@ type(erlang, system_info, 1, Xs) ->
t_tuple([t_atom('fullsweep_after'), t_non_neg_integer()]);
['garbage_collection'] ->
t_list();
- ['global_heaps_size'] ->
- t_non_neg_integer();
['heap_sizes'] ->
t_list(t_integer());
['heap_type'] ->
- t_sup([t_atom('private'),
- t_atom('shared'),
- t_atom('hybrid')]);
+ t_atom('private');
['hipe_architecture'] ->
t_atoms(['amd64', 'arm', 'powerpc', 'ppc64',
'undefined', 'ultrasparc', 'x86']);
@@ -4743,7 +4738,6 @@ t_pinfo_item() ->
t_atom('last_calls'),
t_atom('links'),
t_atom('memory'),
- t_atom('message_binary'), % for hybrid heap only
t_atom('message_queue_len'),
t_atom('messages'),
t_atom('monitored_by'),
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index ceec31742e..410e29d269 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -2318,10 +2318,14 @@ t_inf(?product(_), _, _Mode) ->
?none;
t_inf(_, ?product(_), _Mode) ->
?none;
-t_inf(?tuple(?any, ?any, ?any), ?tuple(_, _, _) = T, _Mode) -> T;
-t_inf(?tuple(_, _, _) = T, ?tuple(?any, ?any, ?any), _Mode) -> T;
-t_inf(?tuple(?any, ?any, ?any), ?tuple_set(_) = T, _Mode) -> T;
-t_inf(?tuple_set(_) = T, ?tuple(?any, ?any, ?any), _Mode) -> T;
+t_inf(?tuple(?any, ?any, ?any), ?tuple(_, _, _) = T, _Mode) ->
+ subst_all_vars_to_any(T);
+t_inf(?tuple(_, _, _) = T, ?tuple(?any, ?any, ?any), _Mode) ->
+ subst_all_vars_to_any(T);
+t_inf(?tuple(?any, ?any, ?any), ?tuple_set(_) = T, _Mode) ->
+ subst_all_vars_to_any(T);
+t_inf(?tuple_set(_) = T, ?tuple(?any, ?any, ?any), _Mode) ->
+ subst_all_vars_to_any(T);
t_inf(?tuple(Elements1, Arity, _Tag1), ?tuple(Elements2, Arity, _Tag2), Mode) ->
case t_inf_lists_strict(Elements1, Elements2, Mode) of
bottom -> ?none;
@@ -2555,8 +2559,8 @@ t_subst_dict(?list(Contents, Termination, Size), Dict) ->
?nil -> ?list(NewContents, ?nil, Size);
?any -> ?list(NewContents, ?any, Size);
Other ->
- ?list(NewContents, NewTermination, _) = t_cons(NewContents, Other),
- ?list(NewContents, NewTermination, Size)
+ ?list(NewContents2, NewTermination, _) = t_cons(NewContents, Other),
+ ?list(NewContents2, NewTermination, Size)
end
end;
t_subst_dict(?function(Domain, Range), Dict) ->
@@ -2597,8 +2601,8 @@ t_subst_aux(?list(Contents, Termination, Size), VarMap) ->
?nil -> ?list(NewContents, ?nil, Size);
?any -> ?list(NewContents, ?any, Size);
Other ->
- ?list(NewContents, NewTermination, _) = t_cons(NewContents, Other),
- ?list(NewContents, NewTermination, Size)
+ ?list(NewContents2, NewTermination, _) = t_cons(NewContents, Other),
+ ?list(NewContents2, NewTermination, Size)
end
end;
t_subst_aux(?function(Domain, Range), VarMap) ->
@@ -3186,8 +3190,8 @@ t_abstract_records(?list(Contents, Termination, Size), RecDict) ->
?nil -> ?list(NewContents, ?nil, Size);
?any -> ?list(NewContents, ?any, Size);
Other ->
- ?list(NewContents, NewTermination, _) = t_cons(NewContents, Other),
- ?list(NewContents, NewTermination, Size)
+ ?list(NewContents2, NewTermination, _) = t_cons(NewContents, Other),
+ ?list(NewContents2, NewTermination, Size)
end
end;
t_abstract_records(?function(Domain, Range), RecDict) ->
diff --git a/lib/hipe/doc/src/Makefile b/lib/hipe/doc/src/Makefile
index a9cd583ff4..fbfd4ca327 100644
--- a/lib/hipe/doc/src/Makefile
+++ b/lib/hipe/doc/src/Makefile
@@ -106,12 +106,12 @@ realclean: clean
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
release_spec:
diff --git a/lib/hipe/flow/Makefile b/lib/hipe/flow/Makefile
index 1a531fdfe5..75e156b542 100644
--- a/lib/hipe/flow/Makefile
+++ b/lib/hipe/flow/Makefile
@@ -100,10 +100,10 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/flow
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(INC_FILES) $(RELSYSDIR)/flow
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/flow"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(INC_FILES) "$(RELSYSDIR)/flow"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/icode/Makefile b/lib/hipe/icode/Makefile
index 0d940d4b28..0f2d6db39b 100644
--- a/lib/hipe/icode/Makefile
+++ b/lib/hipe/icode/Makefile
@@ -118,10 +118,10 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/icode
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/icode
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/icode"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/icode"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/main/Makefile b/lib/hipe/main/Makefile
index fc8923db6c..673431a175 100644
--- a/lib/hipe/main/Makefile
+++ b/lib/hipe/main/Makefile
@@ -115,10 +115,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DATA) ../vsn.mk $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/main
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/main
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) ../vsn.mk "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/main"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/main"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src
index d38b9ea7b1..7db4db8a57 100644
--- a/lib/hipe/main/hipe.app.src
+++ b/lib/hipe/main/hipe.app.src
@@ -24,7 +24,6 @@
{modules, [cerl_cconv,
cerl_closurean,
cerl_hipeify,
- cerl_hybrid_transform,
cerl_lib,
cerl_messagean,
cerl_pmatch,
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index c73db872ac..b2789978a4 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -482,12 +482,7 @@ compile(Name, File, Opts0) when is_atom(Name) ->
compile_core(Name, Core0, File, Opts) ->
Core = cerl:from_records(Core0),
- Core1 = case (erlang:system_info(heap_type) =:= hybrid)
- andalso proplists:get_bool(hybrid, Opts) of
- true -> cerl_hybrid_transform:transform(Core, Opts);
- false -> Core
- end,
- compile(Name, Core1, File, Opts).
+ compile(Name, Core, File, Opts).
%% @spec compile(Name, Core, File, options()) ->
%% {ok, {Target, Binary}} | {error, Reason}
diff --git a/lib/hipe/misc/Makefile b/lib/hipe/misc/Makefile
index 98a69d62c7..1204ab7c0b 100644
--- a/lib/hipe/misc/Makefile
+++ b/lib/hipe/misc/Makefile
@@ -100,10 +100,10 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/misc
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/misc
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/misc"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/misc"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/opt/Makefile b/lib/hipe/opt/Makefile
index 426afd8052..a21c543574 100644
--- a/lib/hipe/opt/Makefile
+++ b/lib/hipe/opt/Makefile
@@ -97,8 +97,8 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/ppc/Makefile b/lib/hipe/ppc/Makefile
index c4b0c3ba9d..8bd2a8226c 100644
--- a/lib/hipe/ppc/Makefile
+++ b/lib/hipe/ppc/Makefile
@@ -108,8 +108,8 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/regalloc/Makefile b/lib/hipe/regalloc/Makefile
index d33f641640..d4be79ea85 100644
--- a/lib/hipe/regalloc/Makefile
+++ b/lib/hipe/regalloc/Makefile
@@ -112,8 +112,8 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index 30026831b7..426d1bd3ee 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -103,10 +103,10 @@ realclean: clean
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/rtl
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/rtl
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/rtl"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/rtl"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/sparc/Makefile b/lib/hipe/sparc/Makefile
index e9e9d54e0c..eb40117691 100644
--- a/lib/hipe/sparc/Makefile
+++ b/lib/hipe/sparc/Makefile
@@ -108,8 +108,8 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/tools/Makefile b/lib/hipe/tools/Makefile
index f90d3c9f70..6761f11b01 100644
--- a/lib/hipe/tools/Makefile
+++ b/lib/hipe/tools/Makefile
@@ -96,8 +96,8 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/util/Makefile b/lib/hipe/util/Makefile
index 2f17eee7f3..a5ee232057 100644
--- a/lib/hipe/util/Makefile
+++ b/lib/hipe/util/Makefile
@@ -103,10 +103,10 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/util
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/util
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/util"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/util"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/hipe/x86/Makefile b/lib/hipe/x86/Makefile
index f92e7eeec1..3602949944 100644
--- a/lib/hipe/x86/Makefile
+++ b/lib/hipe/x86/Makefile
@@ -116,8 +116,8 @@ $(DOCS)/%.html:%.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/ic/c_src/Makefile.in b/lib/ic/c_src/Makefile.in
index 5e034c47c6..d8b8c85a8e 100644
--- a/lib/ic/c_src/Makefile.in
+++ b/lib/ic/c_src/Makefile.in
@@ -140,12 +140,12 @@ $(OBJDIR)/%.o: %.c
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/c_src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_DATA) ic.c ic_tmo.c $(RELSYSDIR)/c_src
- $(INSTALL_DATA) $(IDL_FILES) $(H_FILES) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(LIBRARY) $(RELSYSDIR)/priv/lib
+ $(INSTALL_DIR) "$(RELSYSDIR)/c_src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/lib"
+ $(INSTALL_DATA) ic.c ic_tmo.c "$(RELSYSDIR)/c_src"
+ $(INSTALL_DATA) $(IDL_FILES) $(H_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(LIBRARY) "$(RELSYSDIR)/priv/lib"
release_docs_spec:
diff --git a/lib/ic/doc/src/Makefile b/lib/ic/doc/src/Makefile
index 208f16e441..0ee242b234 100644
--- a/lib/ic/doc/src/Makefile
+++ b/lib/ic/doc/src/Makefile
@@ -220,12 +220,12 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- (/bin/cp -rf $(HTMLDIR) $(RELSYSDIR)/doc)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ (/bin/cp -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/ic/doc/src/ic_clib.xml b/lib/ic/doc/src/ic_clib.xml
index b557c4b5f6..ebeaabae91 100644
--- a/lib/ic/doc/src/ic_clib.xml
+++ b/lib/ic/doc/src/ic_clib.xml
@@ -4,7 +4,7 @@
<cref>
<header>
<copyright>
- <year>2003</year><year>2009</year>
+ <year>2003</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -41,7 +41,7 @@
</section>
<funcs>
<func>
- <name><ret>CORBA_Environment*</ret><nametext>CORBA_Environment_alloc(int inbufsz, int outbufsz)</nametext></name>
+ <name><ret>CORBA_Environment *</ret><nametext>CORBA_Environment_alloc(int inbufsz, int outbufsz)</nametext></name>
<fsummary>Allocate environment data.</fsummary>
<desc>
<p>This function is used to allocate and initiate the
@@ -79,14 +79,14 @@
</desc>
</func>
<func>
- <name><ret>CORBA_char*</ret><nametext>CORBA_string_alloc(CORBA_unsigned_long len)</nametext></name>
+ <name><ret>CORBA_char *</ret><nametext>CORBA_string_alloc(CORBA_unsigned_long len)</nametext></name>
<fsummary>Allocate a string.</fsummary>
<desc>
<p>Allocates a (simple) CORBA character string of length <c>len + 1</c>.</p>
</desc>
</func>
<func>
- <name><ret>CORBA_wchar*</ret><nametext>CORBA_wstring_alloc(CORBA_unsigned_long len)</nametext></name>
+ <name><ret>CORBA_wchar *</ret><nametext>CORBA_wstring_alloc(CORBA_unsigned_long len)</nametext></name>
<fsummary>Allocate a wide string.</fsummary>
<desc>
<p>Allocates a CORBA wide string of length <c>len + 1</c>.</p>
@@ -101,7 +101,7 @@
</section>
<funcs>
<func>
- <name><ret>CORBA_char*</ret><nametext>CORBA_exception_id(CORBA_Environment *env)</nametext></name>
+ <name><ret>CORBA_char *</ret><nametext>CORBA_exception_id(CORBA_Environment *env)</nametext></name>
<fsummary>Get exception identity.</fsummary>
<desc>
<p>Returns the exception identity if an exception is set, otherwise
@@ -109,7 +109,7 @@
</desc>
</func>
<func>
- <name><ret>void*</ret><nametext>CORBA_exception_value(CORBA_Environment *env)</nametext></name>
+ <name><ret>void *</ret><nametext>CORBA_exception_value(CORBA_Environment *env)</nametext></name>
<fsummary>Get exception value.</fsummary>
<desc>
<p>Returns the exception value, if an exception is set, otherwise
@@ -160,7 +160,7 @@
</desc>
</func>
<func>
- <name><ret>oe_map_t*</ret><nametext>oe_merge_maps(oe_map_t *maps, int size)</nametext></name>
+ <name><ret>oe_map_t *</ret><nametext>oe_merge_maps(oe_map_t *maps, int size)</nametext></name>
<fsummary>Merge an array of server maps to one single map.</fsummary>
<desc>
<p>Merge an array of server maps to one single map.</p>
diff --git a/lib/ic/examples/pre_post_condition/Makefile b/lib/ic/examples/pre_post_condition/Makefile
index 8f85babb1a..8ae37394ed 100644
--- a/lib/ic/examples/pre_post_condition/Makefile
+++ b/lib/ic/examples/pre_post_condition/Makefile
@@ -124,8 +124,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples/pre_post_condition
- $(INSTALL_DATA) $(ERL_FILES) $(IDL_FILES) $(TXT_FILES) $(RELSYSDIR)/examples/pre_post_condition
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/pre_post_condition"
+ $(INSTALL_DATA) $(ERL_FILES) $(IDL_FILES) $(TXT_FILES) "$(RELSYSDIR)/examples/pre_post_condition"
release_docs_spec:
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Makefile b/lib/ic/java_src/com/ericsson/otp/ic/Makefile
index f730749ccb..1b14d4430f 100644
--- a/lib/ic/java_src/com/ericsson/otp/ic/Makefile
+++ b/lib/ic/java_src/com/ericsson/otp/ic/Makefile
@@ -109,10 +109,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/java_src/com/ericsson/otp/ic
- $(INSTALL_DATA) $(JAVA_FILES) $(RELSYSDIR)/java_src/com/ericsson/otp/ic
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/java_src/com/ericsson/otp/ic"
+ $(INSTALL_DATA) $(JAVA_FILES) "$(RELSYSDIR)/java_src/com/ericsson/otp/ic"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/ic/src/Makefile b/lib/ic/src/Makefile
index 5dac304e32..c830ebec95 100644
--- a/lib/ic/src/Makefile
+++ b/lib/ic/src/Makefile
@@ -196,23 +196,23 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DIR) $(RELSYSDIR)/examples/c-client
- $(INSTALL_DATA) $(CCL_EX_FILES) $(RELSYSDIR)/examples/c-client
- $(INSTALL_DIR) $(RELSYSDIR)/examples/c-server
- $(INSTALL_DATA) $(CSRV_EX_FILES) $(RELSYSDIR)/examples/c-server
- $(INSTALL_DIR) $(RELSYSDIR)/examples/erl-plain
- $(INSTALL_DATA) $(EPL_EX_FILES) $(RELSYSDIR)/examples/erl-plain
- $(INSTALL_DIR) $(RELSYSDIR)/examples/erl-genserv
- $(INSTALL_DATA) $(ESRV_EX_FILES) $(RELSYSDIR)/examples/erl-genserv
- $(INSTALL_DIR) $(RELSYSDIR)/examples/java-client-server
- $(INSTALL_DATA) $(JAVA_EX_FILES) $(RELSYSDIR)/examples/java-client-server
- $(INSTALL_DIR) $(RELSYSDIR)/examples/all-against-all
- $(INSTALL_DATA) $(MIXED_EX_FILES) $(RELSYSDIR)/examples/all-against-all
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/c-client"
+ $(INSTALL_DATA) $(CCL_EX_FILES) "$(RELSYSDIR)/examples/c-client"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/c-server"
+ $(INSTALL_DATA) $(CSRV_EX_FILES) "$(RELSYSDIR)/examples/c-server"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/erl-plain"
+ $(INSTALL_DATA) $(EPL_EX_FILES) "$(RELSYSDIR)/examples/erl-plain"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/erl-genserv"
+ $(INSTALL_DATA) $(ESRV_EX_FILES) "$(RELSYSDIR)/examples/erl-genserv"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/java-client-server"
+ $(INSTALL_DATA) $(JAVA_EX_FILES) "$(RELSYSDIR)/examples/java-client-server"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/all-against-all"
+ $(INSTALL_DATA) $(MIXED_EX_FILES) "$(RELSYSDIR)/examples/all-against-all"
release_docs_spec:
diff --git a/lib/ic/src/ic.erl b/lib/ic/src/ic.erl
index 50fad921c4..bc7ec8ba91 100644
--- a/lib/ic/src/ic.erl
+++ b/lib/ic/src/ic.erl
@@ -250,7 +250,7 @@ make_erl_options(Opts) ->
Optimize = Opts#options.optimize,
PreProc =
lists:flatten(
- lists:map(fun(D) -> io_lib:format("-I~s ", [ic_util:to_list(D)]) end,
+ lists:map(fun(D) -> io_lib:format("-I\"~s\" ", [ic_util:to_list(D)]) end,
Includes1)++
lists:map(
fun ({Name, Value}) ->
diff --git a/lib/ic/src/ic_pp.erl b/lib/ic/src/ic_pp.erl
index 8b53473caa..50eeeab48c 100644
--- a/lib/ic/src/ic_pp.erl
+++ b/lib/ic/src/ic_pp.erl
@@ -1894,23 +1894,37 @@ include_dir(Flags) when is_list(Flags)->
include_dir(_Flags) ->
[].
-include_dir(Flags,IncDir) ->
+include_dir(Flags,IncDirs) ->
case string:str(Flags,"-I") of
0 ->
- lists:reverse(IncDir);
+ lists:reverse(IncDirs);
X ->
- Rem2 = string:sub_string(Flags, X+2),
- Rem = string:strip(Rem2, left),
- Y = string:str(Rem," "),
- case string:str(Rem," ") of
- 0 ->
- lists:reverse([string:sub_string(Rem, Y+1)|IncDir]);
- Y ->
- include_dir(string:sub_string(Rem, Y+1),
- [string:sub_string(Rem,1,Y-1)|IncDir])
- end
+ {NewDir, RemainingFlags} =
+ gobble_inc_dir(string:sub_string(Flags, X+2),nq,[]),
+ include_dir(RemainingFlags, [NewDir|IncDirs])
end.
+% nq = not-quoted, q = quoted.
+% Possible strange scenarios:
+% /usr/test\ ing/
+% "/usr/test ing/"
+% /usr/test\"ing/
+% "/usr/test\"ing/"
+gobble_inc_dir([],nq,Acc) ->
+ % Only accept nq here, if we end up here in q mode the user has missed a "
+ {lists:reverse(Acc),[]};
+gobble_inc_dir([$\\,$"|R],Q,Acc) ->
+ gobble_inc_dir(R,Q,[$"|Acc]);
+gobble_inc_dir([$"|R],nq,Acc) ->
+ gobble_inc_dir(R,q,Acc);
+gobble_inc_dir([$"|R],q,Acc) ->
+ gobble_inc_dir(R,nq,Acc);
+gobble_inc_dir([$\\,$ |R],nq,Acc) ->
+ gobble_inc_dir(R,nq,[$ |Acc]);
+gobble_inc_dir([$ |R],nq,Acc) ->
+ {lists:reverse(Acc),R};
+gobble_inc_dir([C|R],Q,Acc) ->
+ gobble_inc_dir(R,Q,[C|Acc]).
%%===============================================================
@@ -1954,7 +1968,6 @@ find_inc_file2(FileName, [D|Rem]) ->
_ ->
D++"/"
end,
-
case catch file:read_file_info(Dir++FileName) of
{ok, _} ->
{ok, Dir++FileName};
diff --git a/lib/ic/test/Makefile b/lib/ic/test/Makefile
index 1d90a1bc17..65003d703b 100644
--- a/lib/ic/test/Makefile
+++ b/lib/ic/test/Makefile
@@ -239,39 +239,39 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/ic_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/ic_register_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/ic_pragma_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/ic_pp_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/ic_be_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/c_client_erl_server_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/c_client_erl_server_proto_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/c_client_erl_server_proto_tmo_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/erl_client_c_server_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/erl_client_c_server_proto_SUITE_data
- $(INSTALL_DIR) $(RELSYSDIR)/java_client_erl_server_SUITE_data
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ic_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ic_register_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ic_pragma_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ic_pp_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ic_be_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/c_client_erl_server_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/c_client_erl_server_proto_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/c_client_erl_server_proto_tmo_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/erl_client_c_server_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/erl_client_c_server_proto_SUITE_data"
+ $(INSTALL_DIR) "$(RELSYSDIR)/java_client_erl_server_SUITE_data"
$(INSTALL_DATA) $(IDL_FILES) ic.cover $(TEST_SPEC_FILE) $(ERL_FILES) \
- $(RELSYSDIR)
- $(INSTALL_DATA) $(COMPILER_TEST_FILES) $(RELSYSDIR)/ic_SUITE_data
+ "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(COMPILER_TEST_FILES) "$(RELSYSDIR)/ic_SUITE_data"
$(INSTALL_DATA) $(COMPILER_TEST_FILES2) \
- $(RELSYSDIR)/ic_register_SUITE_data
+ "$(RELSYSDIR)/ic_register_SUITE_data"
$(INSTALL_DATA) $(COMPILER_TEST_FILES3) \
- $(RELSYSDIR)/ic_pragma_SUITE_data
+ "$(RELSYSDIR)/ic_pragma_SUITE_data"
$(INSTALL_DATA) $(COMPILER_TEST_FILES4) \
- $(RELSYSDIR)/ic_be_SUITE_data
+ "$(RELSYSDIR)/ic_be_SUITE_data"
$(INSTALL_DATA) $(PREPROCESSOR_TEST_FILES) \
- $(RELSYSDIR)/ic_pp_SUITE_data
+ "$(RELSYSDIR)/ic_pp_SUITE_data"
$(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_TEST_FILES) \
- $(RELSYSDIR)/c_client_erl_server_SUITE_data
+ "$(RELSYSDIR)/c_client_erl_server_SUITE_data"
$(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_PROTO_TEST_FILES) \
- $(RELSYSDIR)/c_client_erl_server_proto_SUITE_data
+ "$(RELSYSDIR)/c_client_erl_server_proto_SUITE_data"
$(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_PROTO_TMO_TEST_FILES) \
- $(RELSYSDIR)/c_client_erl_server_proto_tmo_SUITE_data
+ "$(RELSYSDIR)/c_client_erl_server_proto_tmo_SUITE_data"
$(INSTALL_DATA) $(ERL_CLIENT_C_SERVER_TEST_FILES) \
- $(RELSYSDIR)/erl_client_c_server_SUITE_data
+ "$(RELSYSDIR)/erl_client_c_server_SUITE_data"
$(INSTALL_DATA) $(ERL_CLIENT_C_SERVER_PROTO_TEST_FILES) \
- $(RELSYSDIR)/erl_client_c_server_proto_SUITE_data
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
+ "$(RELSYSDIR)/erl_client_c_server_proto_SUITE_data"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(JAVA_CLIENT_ERL_SERVER_TEST_FILES) \
- $(RELSYSDIR)/java_client_erl_server_SUITE_data
+ "$(RELSYSDIR)/java_client_erl_server_SUITE_data"
diff --git a/lib/ic/test/java_client_erl_server_SUITE.erl b/lib/ic/test/java_client_erl_server_SUITE.erl
index 407c3d2d44..d4523dc2ad 100644
--- a/lib/ic/test/java_client_erl_server_SUITE.erl
+++ b/lib/ic/test/java_client_erl_server_SUITE.erl
@@ -249,7 +249,7 @@ marshal_any_2(Config) when is_list(Config) ->
java(Java, Dir, ClassAndArgs) ->
- cmd(Java++" -classpath "++classpath(Dir)++" "++ClassAndArgs).
+ cmd(Java++" -classpath \""++classpath(Dir)++"\" "++ClassAndArgs).
java(Java, Dir, Class, Args) ->
java(Java, Dir, Class++" "++to_string(Args)).
diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile
index b3a98fd6d5..1a8e1c7ca8 100644
--- a/lib/inets/doc/src/Makefile
+++ b/lib/inets/doc/src/Makefile
@@ -140,13 +140,13 @@ clean_man:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(HTMLDIR)/* $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(HTMLDIR)/* "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 70c845bade..14ce3cbe7f 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -480,66 +480,69 @@ apply(Module, Function, [ReplyInfo | Args])
<d>ex: "134.138" or "[FEDC:BA98" (all IP-addresses starting with 134.138 or FEDC:BA98), "66.35.250.150" or "[2010:836B:4179::836B:4179]" (a complete IP-address).</d>
<v>MaxSessions = integer() </v>
<d>Default is <c>2</c>.
- Maximum number of persistent connections to a host.</d>
+ Maximum number of persistent connections to a host.</d>
<v>MaxKeepAlive = integer() </v>
- <d>Default is <c>5</c>.
- Maximum number of outstanding requests on the same connection to
- a host.</d>
- <v>KeepAliveTimeout = integer() </v>
- <d>Default is <c>120000</c> (= 2 min).
- If a persistent connection is idle longer than the
- <c>keep_alive_timeout</c> the client will close the connection.
- The server may also have such a time out but you should
- not count on it!</d>
+ <d>Default is <c>5</c>.
+ Maximum number of outstanding requests on the same connection to
+ a host.</d>
+ <v>KeepAliveTimeout = integer() </v>
+ <d>Default is <c>120000</c> (= 2 min).
+ If a persistent connection is idle longer than the
+ <c>keep_alive_timeout</c> in milliseconds,
+ the client will close the connection.
+ The server may also have such a time out but you should
+ not count on it!</d>
<v>MaxPipeline = integer() </v>
- <d>Default is <c>2</c>.
- Maximum number of outstanding requests on a pipelined connection to a host.</d>
- <v>PipelineTimeout = integer() </v>
- <d>Default is <c>0</c>,
- which will result in pipelining not being used.
- If a persistent connection is idle longer than the
- <c>pipeline_timeout</c> the client will close the connection. </d>
+ <d>Default is <c>2</c>.
+ Maximum number of outstanding requests on a pipelined connection
+ to a host.</d>
+ <v>PipelineTimeout = integer() </v>
+ <d>Default is <c>0</c>,
+ which will result in pipelining not being used.
+ If a persistent connection is idle longer than the
+ <c>pipeline_timeout</c> in milliseconds,
+ the client will close the connection. </d>
<v>CookieMode = enabled | disabled | verify </v>
<d>Default is <c>disabled</c>.
- If Cookies are enabled all valid cookies will automatically be
- saved in the client manager's cookie database.
- If the option <c>verify</c> is used the function <c>store_cookies/2</c>
- has to be called for the cookies to be saved.</d>
- <v>IpFamily = inet | inet6 | inet6fb4 </v>
- <d>By default <c>inet</c>.
- When it is set to <c>inet6fb4</c> you can use both ipv4 and ipv6.
- It first tries <c>inet6</c> and if that does not works falls back to <c>inet</c>.
- The option is here to provide a workaround for buggy ipv6 stacks to ensure that
- ipv4 will always work.</d>
+ If Cookies are enabled all valid cookies will automatically be
+ saved in the client manager's cookie database.
+ If the option <c>verify</c> is used the function <c>store_cookies/2</c>
+ has to be called for the cookies to be saved.</d>
+ <v>IpFamily = inet | inet6 | inet6fb4 </v>
+ <d>By default <c>inet</c>.
+ When it is set to <c>inet6fb4</c> you can use both ipv4 and ipv6.
+ It first tries <c>inet6</c> and if that does not works falls back to <c>inet</c>.
+ The option is here to provide a workaround for buggy ipv6 stacks to ensure that
+ ipv4 will always work.</d>
<v>IpAddress = ip_address() </v>
- <d>If the host has several network interfaces, this option specifies which one to use.
- See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> for more info. </d>
+ <d>If the host has several network interfaces, this option specifies which one to use.
+ See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> for more info. </d>
<v>Port = integer() </v>
- <d>Specify which local port number to use.
- See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> for more info. </d>
- <v>VerboseMode = false | verbose | debug | trace </v>
- <d>Default is <c>false</c>.
- This option is used to switch on (or off)
- different levels of erlang trace on the client.
- It is a debug feature.</d>
+ <d>Specify which local port number to use.
+ See <seealso marker="kernel:gen_tcp#connect">gen_tcp:connect/3,4</seealso> for more info. </d>
+ <v>VerboseMode = false | verbose | debug | trace </v>
+ <d>Default is <c>false</c>.
+ This option is used to switch on (or off)
+ different levels of erlang trace on the client.
+ It is a debug feature.</d>
<v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v>
</type>
<desc>
- <p>Sets options to be used for subsequent requests.</p>
- <note>
- <p>If possible the client will keep its connections
- alive and use persistent connections
- with or without pipeline depending on configuration
- and current circumstances. The HTTP/1.1 specification does not
- provide a guideline for how many requests would be
- ideal to be sent on a persistent connection,
- this very much depends on the
- application. Note that a very long queue of requests may cause a
- user perceived delay as earlier requests may take a long time
- to complete. The HTTP/1.1 specification does suggest a
- limit of 2 persistent connections per server, which is the
- default value of the <c>max_sessions</c> option. </p>
- </note>
+ <p>Sets options to be used for subsequent requests.</p>
+ <note>
+ <p>If possible the client will keep its connections
+ alive and use persistent connections
+ with or without pipeline depending on configuration
+ and current circumstances. The HTTP/1.1 specification does not
+ provide a guideline for how many requests would be
+ ideal to be sent on a persistent connection,
+ this very much depends on the
+ application. Note that a very long queue of requests may cause a
+ user perceived delay as earlier requests may take a long time
+ to complete. The HTTP/1.1 specification does suggest a
+ limit of 2 persistent connections per server, which is the
+ default value of the <c>max_sessions</c> option. </p>
+ </note>
<marker id="get_options"></marker>
</desc>
@@ -648,6 +651,8 @@ apply(Module, Function, [ReplyInfo | Args])
<p>Resets (clears) the cookie database for the specified
<c>Profile</c>. If no profile is specified the default profile
will be used. </p>
+
+ <marker id="which_cookies"></marker>
</desc>
</func>
@@ -667,6 +672,42 @@ apply(Module, Function, [ReplyInfo | Args])
<p>This function produces a list of the entire cookie database.
It is intended for debugging/testing purposes.
If no profile is specified the default profile will be used. </p>
+
+ <marker id="which_sessions"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_sessions() -> session_info()</name>
+ <name>which_sessions(Profile) -> session_info()</name>
+ <fsummary>Produces a slightly processed dump of the sessions database.</fsummary>
+ <type>
+ <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v>
+ <v>session_info() = {GoodSessions, BadSessions, NonSessions}</v>
+ <v>GoodSessions = session()</v>
+ <v>BadSessions = tuple()</v>
+ <v>NonSessions = term()</v>
+ </type>
+ <desc>
+ <p>This function produces a slightly processed dump of the session
+ database. It is intended for debugging.
+ If no profile is specified the default profile will be used. </p>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>info() -> list()</name>
+ <name>info(Profile) -> list()</name>
+ <fsummary>Produces a list of miscelleneous info</fsummary>
+ <type>
+ <v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v>
+ </type>
+ <desc>
+ <p>This function produces a list of miscelleneous info.
+ It is intended for debugging.
+ If no profile is specified the default profile will be used. </p>
</desc>
</func>
</funcs>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index dfdeb4016c..3aae1ff70a 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -13,12 +13,12 @@
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.
-
+
</legalnotice>
<title>Inets Release Notes</title>
@@ -32,16 +32,93 @@
<file>notes.xml</file>
</header>
+
+ <section>
+ <title>Inets 5.9.1</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list>
+ <item>
+ <p>Better handling of errorI(s) during update of the session
+ database. </p>
+ <p>Also added and updated some debugging functions
+ <seealso marker="httpc#which_sessions">which_sessions/10,1</seealso>
+ and
+ <seealso marker="httpc#info">info/0</seealso>. </p>
+ <p>Own Id: OTP-10093</p>
+ <p>Aux Id: Seq 12062</p>
+ </item>
- <section><title>Inets 5.9</title>
-
- <section><title>Improvements and New Features</title>
-<!--
- <p>-</p>
--->
+ <item>
+ <p>Removed R14B compatible version of (inets-service and
+ tftp) behaviour definition. </p>
+ <p>Own Id: OTP-10095</p>
+ </item>
+
+ <item>
+ <p>[httpc] Documentation of KeepAlive and Pipeline timeout
+ options have been improved. </p>
+ <p>Own Id: OTP-10114</p>
+ </item>
+ </list>
+
+ </section>
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
<list>
<item>
+ <p>[httpc] Cancel request does not work due to incorrect
+ handler table creation (wrong keypos). </p>
+ <p>Vyacheslav Vorobyov</p>
+ <p>Own Id: OTP-10092</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+ <!--
+ <list>
+ <item>
+ <p>[httpc|httpd] The old ssl implementation (based on OpenSSL),
+ has been deprecated. The config option that specified usage of
+ this version of the ssl app, <c>ossl</c>, has been removed. </p>
+ <p>Own Id: OTP-9522</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ </section> <!-- 5.9.1 -->
+
+
+ <section>
+ <title>Inets 5.9</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list>
+ <item>
<p>[httpd] Make the server header configurable with new config
option
<seealso marker="httpd#prop_server_tokens">server_tokens</seealso>.
@@ -102,11 +179,11 @@
</section>
+<!--
<section>
<title>Incompatibilities</title>
<p>-</p>
-<!--
<list>
<item>
<p>[httpc|httpd] The old ssl implementation (based on OpenSSL),
@@ -116,9 +193,9 @@
</item>
</list>
--->
</section>
+-->
</section> <!-- 5.9 -->
@@ -285,31 +362,6 @@
</section>
- <section>
- <title>Incompatibilities</title>
-<!--
- <p>-</p>
--->
-
- <list>
- <item>
- <p>[httpc] Deprecated interface module <c>http</c> has been removed.
- It has (long) been replaced by http client interface module
- <seealso marker="httpc#">httpc</seealso>. </p>
- <p>Own Id: OTP-9359</p>
- </item>
-
- <item>
- <p>[httpc|httpd] The old ssl implementation (based on OpenSSL),
- has been deprecated. The config option that specified usage of
- this version of the ssl app, <c>ossl</c>, has been removed. </p>
- <p>Own Id: OTP-9522</p>
- </item>
-
- </list>
-
- </section>
-
<section><title>Fixed Bugs and Malfunctions</title>
<!--
<p>-</p>
@@ -332,6 +384,24 @@
</list>
</section>
+<!--
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+ <list>
+ <item>
+ <p>[httpc] Deprecated interface module <c>http</c> has been removed.
+ It has (long) been replaced by http client interface module
+ <seealso marker="httpc#">httpc</seealso>. </p>
+ <p>Own Id: OTP-9359</p>
+ </item>
+
+ </list>
+
+ </section>
+-->
+
</section> <!-- 5.7.2 -->
diff --git a/lib/inets/examples/httpd_load_test/Makefile b/lib/inets/examples/httpd_load_test/Makefile
index 1cc61ad8ae..de1b2a289f 100644
--- a/lib/inets/examples/httpd_load_test/Makefile
+++ b/lib/inets/examples/httpd_load_test/Makefile
@@ -34,7 +34,7 @@ VSN=$(INETS_VSN)
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN)
-EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples
+EXAMPLE_RELSYSDIR = "$(RELSYSDIR)/examples"
HDLT_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/httpd_load_test
diff --git a/lib/inets/examples/server_root/Makefile b/lib/inets/examples/server_root/Makefile
index d7a3231068..2230a7eafc 100644
--- a/lib/inets/examples/server_root/Makefile
+++ b/lib/inets/examples/server_root/Makefile
@@ -174,36 +174,36 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/auth
- $(INSTALL_DATA) $(AUTH_FILES) $(RELSYSDIR)/examples/server_root/auth
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/cgi-bin
- $(INSTALL_SCRIPT) $(CGI_FILES) $(RELSYSDIR)/examples/server_root/cgi-bin
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/conf
- $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/examples/server_root/conf
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/open
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/auth"
+ $(INSTALL_DATA) $(AUTH_FILES) "$(RELSYSDIR)/examples/server_root/auth"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/cgi-bin"
+ $(INSTALL_SCRIPT) $(CGI_FILES) "$(RELSYSDIR)/examples/server_root/cgi-bin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/conf"
+ $(INSTALL_DATA) $(CONF_FILES) "$(RELSYSDIR)/examples/server_root/conf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/htdocs/open"
$(INSTALL_DATA) $(OPEN_FILES) \
- $(RELSYSDIR)/examples/server_root/htdocs/open
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open
+ "$(RELSYSDIR)/examples/server_root/htdocs/open"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/htdocs/mnesia_open"
$(INSTALL_DATA) $(MNESIA_OPEN_FILES) \
- $(RELSYSDIR)/examples/server_root/htdocs/mnesia_open
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs/misc
+ "$(RELSYSDIR)/examples/server_root/htdocs/mnesia_open"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/htdocs/misc"
$(INSTALL_DATA) $(MISC_FILES) \
- $(RELSYSDIR)/examples/server_root/htdocs/misc
+ "$(RELSYSDIR)/examples/server_root/htdocs/misc"
$(INSTALL_DIR) \
- $(RELSYSDIR)/examples/server_root/htdocs/secret/top_secret
+ "$(RELSYSDIR)/examples/server_root/htdocs/secret/top_secret"
$(INSTALL_DIR) \
- $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret/top_secret
+ "$(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret/top_secret"
$(INSTALL_DATA) $(SECRET_FILES) \
- $(RELSYSDIR)/examples/server_root/htdocs/secret
+ "$(RELSYSDIR)/examples/server_root/htdocs/secret"
$(INSTALL_DATA) $(MNESIA_SECRET_FILES) \
- $(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/htdocs
- $(INSTALL_DATA) $(HTDOCS_FILES) $(RELSYSDIR)/examples/server_root/htdocs
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/icons
- $(INSTALL_DATA) $(ICON_FILES) $(RELSYSDIR)/examples/server_root/icons
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/ssl
- $(INSTALL_DATA) $(SSL_FILES) $(RELSYSDIR)/examples/server_root/ssl
- $(INSTALL_DIR) $(RELSYSDIR)/examples/server_root/logs
+ "$(RELSYSDIR)/examples/server_root/htdocs/mnesia_secret"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/htdocs"
+ $(INSTALL_DATA) $(HTDOCS_FILES) "$(RELSYSDIR)/examples/server_root/htdocs"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/icons"
+ $(INSTALL_DATA) $(ICON_FILES) "$(RELSYSDIR)/examples/server_root/icons"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/ssl"
+ $(INSTALL_DATA) $(SSL_FILES) "$(RELSYSDIR)/examples/server_root/ssl"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/server_root/logs"
release_docs_spec:
diff --git a/lib/inets/priv/Makefile b/lib/inets/priv/Makefile
index 85da409e55..4dc521f618 100644
--- a/lib/inets/priv/Makefile
+++ b/lib/inets/priv/Makefile
@@ -57,8 +57,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_SCRIPT) $(EXECUTABLES) $(RELSYSDIR)/priv/bin
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/bin"
+ $(INSTALL_SCRIPT) $(EXECUTABLES) "$(RELSYSDIR)/priv/bin"
release_docs_spec:
diff --git a/lib/inets/src/ftp/Makefile b/lib/inets/src/ftp/Makefile
index 19b93870df..426286f254 100644
--- a/lib/inets/src/ftp/Makefile
+++ b/lib/inets/src/ftp/Makefile
@@ -88,11 +88,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/ftp
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/ftp
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/ftp"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/ftp"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile
index d490e59929..850c790bd1 100644
--- a/lib/inets/src/http_client/Makefile
+++ b/lib/inets/src/http_client/Makefile
@@ -89,11 +89,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/http_client
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_client
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/http_client"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/http_client"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index f4802fb96d..b6e7708353 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -39,6 +39,7 @@
cookie_header/1, cookie_header/2, cookie_header/3,
which_cookies/0, which_cookies/1,
reset_cookies/0, reset_cookies/1,
+ which_sessions/0, which_sessions/1,
stream_next/1,
default_profile/0,
profile_name/1, profile_name/2,
@@ -267,6 +268,7 @@ set_option(Key, Value, Profile) ->
%% Reason - term()
%% Description: Retrieves the current options.
%%-------------------------------------------------------------------------
+
get_options() ->
record_info(fields, options).
@@ -373,8 +375,6 @@ cookie_header(Url, Opts, Profile)
{error, {not_started, Profile}}
end.
-
-
%%--------------------------------------------------------------------------
%% which_cookies() -> [cookie()]
@@ -398,6 +398,28 @@ which_cookies(Profile) ->
%%--------------------------------------------------------------------------
+%% which_sessions() -> {GoodSession, BadSessions, NonSessions}
+%% which_sessions(Profile) -> {GoodSession, BadSessions, NonSessions}
+%%
+%% Description: Debug function, dumping the sessions database, sorted
+%% into three groups (Good-, Bad- and Non-sessions).
+%%-------------------------------------------------------------------------
+which_sessions() ->
+ which_sessions(default_profile()).
+
+which_sessions(Profile) ->
+ ?hcrt("which sessions", [{profile, Profile}]),
+ try
+ begin
+ httpc_manager:which_sessions(profile_name(Profile))
+ end
+ catch
+ exit:{noproc, _} ->
+ {[], [], []}
+ end.
+
+
+%%--------------------------------------------------------------------------
%% info() -> list()
%% info(Profile) -> list()
%%
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index b8c34bd99b..6fe05dec80 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1713,7 +1713,32 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
catch
error:undef -> % This could happen during code upgrade
Session2 = erlang:setelement(Pos, Session, Value),
- insert_session(Session2, ProfileName)
+ insert_session(Session2, ProfileName);
+ T:E ->
+ error_logger:error_msg("Failed updating session: "
+ "~n ProfileName: ~p"
+ "~n SessionId: ~p"
+ "~n Pos: ~p"
+ "~n Value: ~p"
+ "~nwhen"
+ "~n Session (db) info: ~p"
+ "~n Session (db): ~p"
+ "~n Session (record): ~p"
+ "~n T: ~p"
+ "~n E: ~p",
+ [ProfileName, SessionId, Pos, Value,
+ (catch httpc_manager:which_session_info(ProfileName)),
+ Session,
+ (catch httpc_manager:lookup_session(ProfileName, SessionId)),
+ T, E]),
+ exit({failed_updating_session,
+ [{profile, ProfileName},
+ {session_id, SessionId},
+ {pos, Pos},
+ {value, Value},
+ {etype, T},
+ {error, E},
+ {stacktrace, erlang:get_stacktrace()}]})
end.
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index b225b43214..3612b331e7 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -34,8 +34,11 @@
retry_request/2,
redirect_request/2,
insert_session/2,
+ lookup_session/2,
update_session/4,
delete_session/2,
+ which_sessions/1,
+ which_session_info/1,
set_options/2,
get_options/2,
store_cookies/3,
@@ -59,17 +62,9 @@
options = #options{}
}).
--record(handler_info,
- {
- id, % Id of the request: request_id()
- starter, % Pid of the handler starter process (temp): pid()
- handler, % Pid of the handler process: pid()
- from, % From for the request: from()
- state % State of the handler: initiating | started | operational | canceled
- }).
-
-define(DELAY, 500).
+
%%====================================================================
%% Internal Application API
%%====================================================================
@@ -195,13 +190,28 @@ insert_session(Session, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: lookup_session(SessionId, ProfileName) -> _
+%% SessionId - term()
+%% ProfileName - atom()
+%%
+%% Description: Looks up a session record in the httpc manager
+%% table <ProfileName>__session_db.
+%%--------------------------------------------------------------------
+
+lookup_session(SessionId, ProfileName) ->
+ SessionDbName = session_db_name(ProfileName),
+ ?hcrt("lookup session", [{session_id, SessionId}, {profile, ProfileName}]),
+ ets:lookup(SessionDbName, SessionId).
+
+
+%%--------------------------------------------------------------------
%% Function: update_session(ProfileName, SessionId, Pos, Value) -> _
%% Session - #session{}
%% ProfileName - atom()
%%
%% Description: Update, only one field (Pos) of the session record
%% identified by the SessionId, the session information
-%% of the httpc manager table <ProfileName>_session_db.
+%% of the httpc manager table <ProfileName>__session_db.
%% Intended to be called by the httpc request handler process.
%%--------------------------------------------------------------------
@@ -216,12 +226,12 @@ update_session(ProfileName, SessionId, Pos, Value) ->
%%--------------------------------------------------------------------
-%% Function: delete_session(SessionId, ProfileName) -> _
+%% Function: delete_session(SessionId, ProfileName) -> void()
%% SessionId - {{Host, Port}, HandlerPid}
%% ProfileName - atom()
%%
%% Description: Deletes session information from the httpc manager
-%% table httpc_manager_session_db_<Profile>. Intended to be called by
+%% table <ProfileName>__session_db. Intended to be called by
%% the httpc request handler process.
%%--------------------------------------------------------------------
@@ -232,6 +242,57 @@ delete_session(SessionId, ProfileName) ->
%%--------------------------------------------------------------------
+%% Function: which sessions(ProfileName) -> SessionsInfo
+%% ProfileName - atom()
+%% SessionsInfo - {GoodSessions, BadSessions, NonSessions}
+%% GoodSessions - [#session{}]
+%% BadSessions - [tuple()]
+%% NonSessions - [term()]
+%%
+%% Description: Produces a list of all sessions in the session db.
+%% Used for debugging and since that is the intent, there is some
+%% checking and transforming done, which produces the results.
+%%--------------------------------------------------------------------
+
+which_sessions(ProfileName) ->
+ ?hcrt("which_sessions", [{profile, ProfileName}]),
+ SessionDbName = session_db_name(ProfileName),
+ which_sessions2(SessionDbName).
+
+which_sessions2(SessionDbName) ->
+ Sessions = which_sessions_order(ets:tab2list(SessionDbName)),
+ GoodSessions = [GoodSession || {good_session, GoodSession} <- Sessions],
+ BadSessions = [BadSession || {bad_session, BadSession} <- Sessions],
+ NonSessions = [NonSession || {non_session, NonSession} <- Sessions],
+ {lists:keysort(#session.id, GoodSessions),
+ lists:keysort(#session.id, BadSessions),
+ lists:sort(NonSessions)}.
+
+which_sessions_order([]) ->
+ [];
+which_sessions_order([Session|Sessions]) when is_record(Session, session) ->
+ [{good_session, Session} | which_sessions_order(Sessions)];
+which_sessions_order([BadSession|Sessions])
+ when is_tuple(BadSession) andalso
+ (element(1, BadSession) =:= session) ->
+ [{bad_session, BadSession} | which_sessions_order(Sessions)];
+which_sessions_order([NonSession|Sessions]) ->
+ [{non_session, NonSession} | which_sessions_order(Sessions)].
+
+
+%%--------------------------------------------------------------------
+%% Function: which session_info(ProfileName) -> list()
+%%
+%% Description: Produces a ets table info list of the sessions table
+%%--------------------------------------------------------------------
+
+which_session_info(ProfileName) ->
+ SessionDbName = session_db_name(ProfileName),
+ ?hcrt("which_session_info", [{profile, ProfileName}]),
+ ets:info(SessionDbName).
+
+
+%%--------------------------------------------------------------------
%% Function: set_options(Options, ProfileName) -> ok
%%
%% Options = [Option]
@@ -379,8 +440,7 @@ do_init(ProfileName, CookiesDir) ->
%% Create handler db
?hcrt("create handler/request db", []),
HandlerDbName = handler_db_name(ProfileName),
- ets:new(HandlerDbName,
- [protected, set, named_table, {keypos, #handler_info.id}]),
+ ets:new(HandlerDbName, [protected, set, named_table, {keypos, 1}]),
%% Cookie DB
?hcrt("create cookie db", []),
@@ -414,9 +474,10 @@ handle_call({request, Request}, _, State) ->
{stop, Error, httpc_response:error(Request, Error), State}
end;
-handle_call({cancel_request, RequestId}, From, State) ->
+handle_call({cancel_request, RequestId}, From,
+ #state{handler_db = HandlerDb} = State) ->
?hcri("cancel_request", [{request_id, RequestId}]),
- case ets:lookup(State#state.handler_db, RequestId) of
+ case ets:lookup(HandlerDb, RequestId) of
[] ->
%% The request has allready compleated make sure
%% it is deliverd to the client process queue so
@@ -428,9 +489,9 @@ handle_call({cancel_request, RequestId}, From, State) ->
{noreply, State};
[{_, Pid, _}] ->
httpc_handler:cancel(RequestId, Pid, From),
- {noreply, State#state{cancel =
- [{RequestId, Pid, From} |
- State#state.cancel]}}
+ {noreply,
+ State#state{cancel =
+ [{RequestId, Pid, From} | State#state.cancel]}}
end;
handle_call(reset_cookies, _, #state{cookie_db = CookieDb} = State) ->
@@ -457,8 +518,8 @@ handle_call({which_cookies, Url, Options}, _,
handle_call({get_options, OptionItems}, _, #state{options = Options} = State) ->
?hcrv("get options", [{option_items, OptionItems}]),
- Reply = [{OptionItem, get_option(OptionItem, Options)} || OptionItem <-
- OptionItems],
+ Reply = [{OptionItem, get_option(OptionItem, Options)} ||
+ OptionItem <- OptionItems],
{reply, Reply, State};
handle_call(info, _, State) ->
@@ -645,7 +706,7 @@ code_change(_,
code_change(_, State, _) ->
{ok, State}.
-%% This function is to catch everything that calls through the cracks...
+%% This function is used to catch everything that falls through the cracks...
update_session_table(SessionDB, Transform) ->
ets:safe_fixtable(SessionDB, true),
update_session_table(SessionDB, ets:first(SessionDB), Transform),
@@ -673,40 +734,56 @@ update_session_table(SessionDB, Key, Transform) ->
%%--------------------------------------------------------------------
get_manager_info(#state{handler_db = HDB,
- cookie_db = CDB} = _State) ->
+ session_db = SDB,
+ cookie_db = CDB,
+ options = Options} = _State) ->
HandlerInfo = get_handler_info(HDB),
+ SessionInfo = which_sessions2(SDB),
+ OptionsInfo =
+ [{Item, get_option(Item, Options)} ||
+ Item <- record_info(fields, options)],
CookieInfo = httpc_cookie:which_cookies(CDB),
- [{handlers, HandlerInfo}, {cookies, CookieInfo}].
+ [{handlers, HandlerInfo},
+ {sessions, SessionInfo},
+ {options, OptionsInfo},
+ {cookies, CookieInfo}].
+
+sort_handlers(Unsorted) ->
+ sort_handlers2(lists:keysort(1, Unsorted)).
+
+sort_handlers2([]) ->
+ [];
+sort_handlers2([{HandlerPid, RequestId}|L]) ->
+ {Handler, Rest} = sort_handlers2(HandlerPid, [RequestId], L),
+ [Handler | sort_handlers2(Rest)].
+
+sort_handlers2(HandlerPid, Reqs, []) ->
+ {{HandlerPid, lists:sort(Reqs)}, []};
+sort_handlers2(HandlerPid, Reqs, [{HandlerPid, ReqId}|Rest]) ->
+ sort_handlers2(HandlerPid, [ReqId|Reqs], Rest);
+sort_handlers2(HandlerPid1, Reqs, [{HandlerPid2, _}|_] = Rest)
+ when HandlerPid1 =/= HandlerPid2 ->
+ {{HandlerPid1, lists:sort(Reqs)}, Rest}.
get_handler_info(Tab) ->
- Pattern = #handler_info{handler = '$1',
- state = '$2',
- _ = '_'},
- Handlers1 = [{Pid, State} || [Pid, State] <- ets:match(Tab, Pattern)],
- F = fun({Pid, State} = Elem, Acc) when State =/= canceled ->
- case lists:keymember(Pid, 1, Acc) of
- true ->
- Acc;
- false ->
- [Elem | Acc]
- end;
- (_, Acc) ->
- Acc
- end,
- Handlers2 = lists:foldl(F, [], Handlers1),
- Handlers3 = [{Pid, State,
- case (catch httpc_handler:info(Pid)) of
- {'EXIT', _} ->
+ Pattern = {'$2', '$1', '_'},
+ Handlers1 = [{Pid, Id} || [Pid, Id] <- ets:match(Tab, Pattern)],
+ Handlers2 = sort_handlers(Handlers1),
+ Handlers3 = [{Pid, Reqs,
+ try
+ begin
+ httpc_handler:info(Pid)
+ end
+ catch
+ _:_ ->
%% Why would this crash?
%% Only if the process has died, but we don't
%% know about it?
- [];
- Else ->
- Else
- end} ||
- {Pid, State} <- Handlers2],
+ []
+ end} || {Pid, Reqs} <- Handlers2],
Handlers3.
+
handle_request(#request{settings =
#http_options{version = "HTTP/0.9"}} = Request,
State) ->
@@ -758,19 +835,21 @@ handle_request(Request, State = #state{options = Options}) ->
{reply, {ok, NewRequest#request.id}, State}.
-start_handler(Request, State) ->
+start_handler(#request{id = Id,
+ from = From} = Request,
+ #state{profile_name = ProfileName,
+ handler_db = HandlerDb,
+ options = Options}) ->
{ok, Pid} =
case is_inets_manager() of
true ->
httpc_handler_sup:start_child([whereis(httpc_handler_sup),
- Request, State#state.options,
- State#state.profile_name]);
+ Request, Options, ProfileName]);
false ->
- httpc_handler:start_link(self(), Request, State#state.options,
- State#state.profile_name)
+ httpc_handler:start_link(self(), Request, Options, ProfileName)
end,
- ets:insert(State#state.handler_db, {Request#request.id,
- Pid, Request#request.from}),
+ HandlerInfo = {Id, Pid, From},
+ ets:insert(HandlerDb, HandlerInfo),
erlang:monitor(process, Pid).
@@ -827,12 +906,14 @@ select_session(Candidates, Max) ->
{ok, HandlerPid}
end.
-pipeline_or_keep_alive(Request, HandlerPid, State) ->
+pipeline_or_keep_alive(#request{id = Id,
+ from = From} = Request,
+ HandlerPid,
+ #state{handler_db = HandlerDb} = State) ->
case (catch httpc_handler:send(Request, HandlerPid)) of
ok ->
- ets:insert(State#state.handler_db, {Request#request.id,
- HandlerPid,
- Request#request.from});
+ HandlerInfo = {Id, HandlerPid, From},
+ ets:insert(HandlerDb, HandlerInfo);
_ -> % timeout pipelining failed
start_handler(Request, State)
end.
diff --git a/lib/inets/src/http_lib/Makefile b/lib/inets/src/http_lib/Makefile
index aaf3cfb995..3ec6ce7436 100644
--- a/lib/inets/src/http_lib/Makefile
+++ b/lib/inets/src/http_lib/Makefile
@@ -87,11 +87,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/http_lib
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_lib
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/http_lib"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/http_lib"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/http_server/Makefile b/lib/inets/src/http_server/Makefile
index 60bb0d2527..67555d5f1c 100644
--- a/lib/inets/src/http_server/Makefile
+++ b/lib/inets/src/http_server/Makefile
@@ -123,11 +123,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/http_server
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_server
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/http_server"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/http_server"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile
index 6da6a1d79f..b8d923edd8 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -111,13 +111,13 @@ $(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/inets_app
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/inets_app
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/inets_app"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/inets_app"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index c7029f7b31..2adb2a0fc8 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,14 +18,25 @@
{"%VSN%",
[
+ {"5.9",
+ [
+ {load_module, tftp, soft_purge, soft_purge, [inets_service]},
+ {load_module, inets_service, soft_purge, soft_purge, []},
+ {load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpc_manager, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"5.8.1",
[
+ {load_module, tftp, soft_purge, soft_purge, [inets_service]},
+ {load_module, inets_service, soft_purge, soft_purge, []},
+
{load_module, http_uri, soft_purge, soft_purge, []},
{load_module, httpc_response, soft_purge, soft_purge, [http_uri]},
{load_module, httpc, soft_purge, soft_purge,
[http_uri, httpc_manager]},
- {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]},
{load_module, inets_app, soft_purge, soft_purge, [inets_sup]},
{update, inets_sup, soft, soft_purge, soft_purge, []},
@@ -35,36 +46,15 @@
{load_module, httpd_script_env, soft_purge, soft_purge, []},
{load_module, inets, soft_purge, soft_purge, [inets_trace]},
- {update, httpc_handler, soft, soft_purge, soft_purge, []},
+ {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]},
{update, httpd_sup, soft, soft_purge, soft_purge, []},
{add_module, inets_trace}
]
},
- {"5.8",
+ {"5.8",
[
- {load_module, http_uri, soft_purge, soft_purge, []},
- {load_module, httpc_response, soft_purge, soft_purge, [http_uri]},
-
- {load_module, httpc, soft_purge, soft_purge,
- [http_uri, httpc_manager]},
-
- {load_module, inets_app, soft_purge, soft_purge, [inets_sup]},
- {update, inets_sup, soft, soft_purge, soft_purge, []},
-
- {load_module, inets, soft_purge, soft_purge, [inets_trace]},
-
- {load_module, httpd_conf, soft_purge, soft_purge, []},
- {load_module, httpd_response, soft_purge, soft_purge, []},
- {load_module, httpd_script_env, soft_purge, soft_purge, []},
-
- {load_module, ftp, soft_purge, soft_purge, []},
- {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, []},
- {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, [http_uri, httpc_handler]},
- {update, httpd_sup, soft, soft_purge, soft_purge, []},
-
- {add_module, inets_trace}
+ {restart_application, inets}
]
},
{"5.7.2",
@@ -74,14 +64,25 @@
}
],
[
+ {"5.9",
+ [
+ {load_module, tftp, soft_purge, soft_purge, [inets_service]},
+ {load_module, inets_service, soft_purge, soft_purge, []},
+ {load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]},
+ {update, httpc_manager, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"5.8.1",
[
+ {load_module, tftp, soft_purge, soft_purge, [inets_service]},
+ {load_module, inets_service, soft_purge, soft_purge, []},
+
{load_module, http_uri, soft_purge, soft_purge, []},
{load_module, httpc_response, soft_purge, soft_purge, [http_uri]},
{load_module, httpc, soft_purge, soft_purge,
[http_uri, httpc_manager]},
- {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]},
{load_module, inets_app, soft_purge, soft_purge, [inets_sup]},
{update, inets_sup, soft, soft_purge, soft_purge, []},
@@ -91,36 +92,15 @@
{load_module, httpd_script_env, soft_purge, soft_purge, []},
{load_module, inets, soft_purge, soft_purge, []},
- {update, httpc_handler, soft, soft_purge, soft_purge, []},
+ {update, httpc_manager, soft, soft_purge, soft_purge, [http_uri]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, [httpc_manager]},
{update, httpd_sup, soft, soft_purge, soft_purge, []},
{remove, {inets_trace, soft_purge, brutal_purge}}
]
},
{"5.8",
[
- {load_module, http_uri, soft_purge, soft_purge, []},
- {load_module, httpc_response, soft_purge, soft_purge, [http_uri]},
-
- {load_module, httpc, soft_purge, soft_purge,
- [http_uri, httpc_manager]},
-
- {load_module, inets_app, soft_purge, soft_purge, [inets_sup]},
- {update, inets_sup, soft, soft_purge, soft_purge, []},
-
- {load_module, inets, soft_purge, soft_purge, []},
-
- {load_module, httpd_conf, soft_purge, soft_purge, []},
- {load_module, httpd_response, soft_purge, soft_purge, []},
- {load_module, httpd_script_env, soft_purge, soft_purge, []},
-
- {load_module, ftp, soft_purge, soft_purge, []},
- {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, []},
- {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, [http_uri, httpc_handler]},
- {update, httpd_sup, soft, soft_purge, soft_purge, []},
-
- {remove, {inets_trace, soft_purge, brutal_purge}}
+ {restart_application, inets}
]
},
{"5.7.2",
diff --git a/lib/inets/src/inets_app/inets.mk b/lib/inets/src/inets_app/inets.mk
index d24cc0aea3..adef32dc19 100644
--- a/lib/inets/src/inets_app/inets.mk
+++ b/lib/inets/src/inets_app/inets.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
+# Copyright Ericsson AB 2010-2012. 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
@@ -33,10 +33,6 @@ ifeq ($(WARN_UNUSED_WARS), true)
ERL_COMPILE_FLAGS += +warn_unused_vars
endif
-ifeq ($(shell erl -noshell -eval 'io:format("~4s", [erlang:system_info(otp_release)])' -s init stop), R14B)
-INETS_ERL_COMPILE_FLAGS += -D'OTP-R14B-COMPILER'
-endif
-
INETS_APP_VSN_COMPILE_FLAGS = \
+'{parse_transform,sys_pre_attributes}' \
+'{attribute,insert,app_vsn,$(APP_VSN)}'
diff --git a/lib/inets/src/inets_app/inets_service.erl b/lib/inets/src/inets_app/inets_service.erl
index a057a51e2c..d17fdfe13e 100644
--- a/lib/inets/src/inets_app/inets_service.erl
+++ b/lib/inets/src/inets_app/inets_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. 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,20 +20,6 @@
-module(inets_service).
--ifdef('OTP-R14B-COMPILER').
-
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{start_standalone, 1},
- {start_service, 1},
- {stop_service, 1},
- {services, 0},
- {service_info, 1}];
-behaviour_info(_) ->
- undefined.
-
--else.
%% Starts service stand-alone
%% start_standalone(Config) -> % {ok, Pid} | {error, Reason}
@@ -83,4 +69,3 @@ behaviour_info(_) ->
-callback service_info(Service :: term()) ->
{ok, [{Property :: term(), Value :: term()}]} | {error, Reason :: term()}.
--endif.
diff --git a/lib/inets/src/tftp/Makefile b/lib/inets/src/tftp/Makefile
index f728543adb..a9df8d0319 100644
--- a/lib/inets/src/tftp/Makefile
+++ b/lib/inets/src/tftp/Makefile
@@ -93,11 +93,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/tftp
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/tftp
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/tftp"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/tftp"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inets/src/tftp/tftp.erl b/lib/inets/src/tftp/tftp.erl
index 0d7ae1a89e..1621add246 100644
--- a/lib/inets/src/tftp/tftp.erl
+++ b/lib/inets/src/tftp/tftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. 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
@@ -224,20 +224,6 @@
service_info/1
]).
--ifdef('OTP-R14B-COMPILER').
-
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{prepare, 6},
- {open, 6},
- {read, 1},
- {write, 2},
- {abort, 3}];
-behaviour_info(_) ->
- undefined.
-
--else.
-type peer() :: {PeerType :: inet | inet6,
PeerHost :: inet:ip_address(),
@@ -280,8 +266,6 @@ behaviour_info(_) ->
-callback abort(Code :: error_code(), string(), State :: term()) -> 'ok'.
--endif.
-
-include("tftp.hrl").
diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile
index 87ca60e4b3..7befa82272 100644
--- a/lib/inets/test/Makefile
+++ b/lib/inets/test/Makefile
@@ -234,7 +234,7 @@ endif
# Release directory specification
# ----------------------------------------------------
-RELTESTSYSDIR = $(RELEASE_PATH)/inets_test
+RELTESTSYSDIR = "$(RELEASE_PATH)/inets_test"
RELTESTSYSALLDATADIR = $(RELTESTSYSDIR)/all_SUITE_data
RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin
@@ -284,9 +284,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/test
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/test
- $(INSTALL_DATA) $(INETS_FILES) $(RELSYSDIR)/test
+ $(INSTALL_DIR) "$(RELSYSDIR)/test"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/test"
+ $(INSTALL_DATA) $(INETS_FILES) "$(RELSYSDIR)/test"
@for d in $(DATADIRS); do \
echo "installing data dir $$d"; \
if test -f $$d/TAR.exclude; then \
@@ -299,9 +299,9 @@ release_spec: opt
find $$d -name 'erl_crash.dump' >> $$d/TAR.exclude2; \
find $$d -name 'core' >> $$d/TAR.exclude2; \
find $$d -name '.cmake.state' >> $$d/TAR.exclude2; \
- tar cfX - $$d/TAR.exclude2 $$d | (cd $(RELSYSDIR)/test; tar xf -); \
+ tar cfX - $$d/TAR.exclude2 $$d | (cd "$(RELSYSDIR)/test"; tar xf -); \
else \
- tar cf - $$d | (cd $(RELSYSDIR)/test; tar xf -); \
+ tar cf - $$d | (cd "$(RELSYSDIR)/test"; tar xf -); \
fi; \
done
@@ -330,8 +330,8 @@ info:
@echo "INETS_SPECS = $(INETS_SPECS)"
@echo "INETS_FILES = $(INETS_FILES)"
@echo ""
- @echo "RELEASE_PATH = $(RELEASE_PATH)"
- @echo "RELSYSDIR = $(RELSYSDIR)"
+ @echo "RELEASE_PATH = "$(RELEASE_PATH)""
+ @echo "RELSYSDIR = "$(RELSYSDIR)""
@echo "RELTESTSYSDIR = $(RELTESTSYSDIR)"
@echo "RELTESTSYSALLDATADIR = $(RELTESTSYSALLDATADIR)"
@echo "RELTESTSYSBINDIR = $(RELTESTSYSBINDIR)"
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index a116edef77..1cdd96f0b0 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -761,116 +761,158 @@ http_inets_pipe(Config) when is_list(Config) ->
test_pipeline(URL) ->
- p("test_pipeline -> entry with"
- "~n URL: ~p", [URL]),
-
- httpc:set_options([{pipeline_timeout, 50000}]),
-
- p("test_pipeline -> issue (async) request 1"),
- {ok, RequestId1} =
+ p("test_pipeline -> entry with"
+ "~n URL: ~p", [URL]),
+
+ httpc:set_options([{pipeline_timeout, 50000}]),
+
+ p("test_pipeline -> issue (async) request 1"
+ "~n when profile info: ~p", [httpc:info()]),
+ {ok, RequestIdA1} =
httpc:request(get, {URL, []}, [], [{sync, false}]),
- test_server:format("RequestId1: ~p~n", [RequestId1]),
- p("test_pipeline -> RequestId1: ~p", [RequestId1]),
-
- %% Make sure pipeline is initiated
- p("test_pipeline -> sleep some", []),
- test_server:sleep(4000),
-
- p("test_pipeline -> issue (async) request 2"),
- {ok, RequestId2} =
+ tsp("RequestIdA1: ~p", [RequestIdA1]),
+ p("test_pipeline -> RequestIdA1: ~p"
+ "~n when profile info: ~p", [RequestIdA1, httpc:info()]),
+
+ %% Make sure pipeline is initiated
+ p("test_pipeline -> sleep some", []),
+ test_server:sleep(4000),
+
+ p("test_pipeline -> issue (async) request A2, A3 and A4"
+ "~n when profile info: ~p", [httpc:info()]),
+ {ok, RequestIdA2} =
httpc:request(get, {URL, []}, [], [{sync, false}]),
- tsp("RequestId2: ~p", [RequestId2]),
- p("test_pipeline -> RequestId2: ~p", [RequestId2]),
-
- p("test_pipeline -> issue (sync) request 3"),
- {ok, {{_,200,_}, [_ | _], [_ | _]}} =
+ {ok, RequestIdA3} =
+ httpc:request(get, {URL, []}, [], [{sync, false}]),
+ {ok, RequestIdA4} =
+ httpc:request(get, {URL, []}, [], [{sync, false}]),
+ tsp("RequestIdAs => A2: ~p, A3: ~p and A4: ~p",
+ [RequestIdA2, RequestIdA3, RequestIdA4]),
+ p("test_pipeline -> RequestIds => A2: ~p, A3: ~p and A4: ~p"
+ "~n when profile info: ~p",
+ [RequestIdA2, RequestIdA3, RequestIdA4, httpc:info()]),
+
+ p("test_pipeline -> issue (sync) request 3"),
+ {ok, {{_,200,_}, [_ | _], [_ | _]}} =
httpc:request(get, {URL, []}, [], []),
+
+ p("test_pipeline -> expect reply for (async) request A1, A2, A3 and A4"
+ "~n when profile info: ~p", [httpc:info()]),
+ pipeline_await_async_reply([{RequestIdA1, a1, 200},
+ {RequestIdA2, a2, 200},
+ {RequestIdA3, a3, 200},
+ {RequestIdA4, a4, 200}], ?MINS(1)),
- p("test_pipeline -> expect reply for (async) request 1 or 2"),
- receive
- {http, {RequestId1, {{_, 200, _}, _, _}}} ->
- p("test_pipeline -> received reply for (async) request 1 - now wait for 2"),
- receive
- {http, {RequestId2, {{_, 200, _}, _, _}}} ->
- p("test_pipeline -> received reply for (async) request 2"),
- ok;
- {http, Msg1} ->
- tsf(Msg1)
- end;
- {http, {RequestId2, {{_, 200, _}, _, _}}} ->
- io:format("test_pipeline -> received reply for (async) request 2 - now wait for 1"),
- receive
- {http, {RequestId1, {{_, 200, _}, _, _}}} ->
- io:format("test_pipeline -> received reply for (async) request 1"),
- ok;
- {http, Msg2} ->
- tsf(Msg2)
- end;
- {http, Msg3} ->
- tsf(Msg3)
- after 60000 ->
- receive Any1 ->
- tsp("received crap after timeout: ~n ~p", [Any1]),
- tsf({error, {timeout, Any1}})
- end
- end,
-
- p("test_pipeline -> sleep some"),
- test_server:sleep(4000),
-
- p("test_pipeline -> issue (async) request 4"),
- {ok, RequestId3} =
+ p("test_pipeline -> sleep some"
+ "~n when profile info: ~p", [httpc:info()]),
+ test_server:sleep(4000),
+
+ p("test_pipeline -> issue (async) request B1, B2, B3 and B4"
+ "~n when profile info: ~p", [httpc:info()]),
+ {ok, RequestIdB1} =
httpc:request(get, {URL, []}, [], [{sync, false}]),
- tsp("RequestId3: ~p", [RequestId3]),
- p("test_pipeline -> RequestId3: ~p", [RequestId3]),
-
- p("test_pipeline -> issue (async) request 5"),
- {ok, RequestId4} =
+ {ok, RequestIdB2} =
httpc:request(get, {URL, []}, [], [{sync, false}]),
- tsp("RequestId4: ~p~n", [RequestId4]),
- p("test_pipeline -> RequestId4: ~p", [RequestId4]),
-
- p("test_pipeline -> cancel (async) request 4"),
- ok = httpc:cancel_request(RequestId3),
-
- p("test_pipeline -> expect *no* reply for cancelled (async) request 4 (for 3 secs)"),
- receive
- {http, {RequestId3, _}} ->
- tsf(http_cancel_request_failed)
- after 3000 ->
- ok
- end,
-
- p("test_pipeline -> expect reply for (async) request 4"),
- Body =
- receive
- {http, {RequestId4, {{_, 200, _}, _, BinBody4}}} = Res ->
- p("test_pipeline -> received reply for (async) request 5"),
- tsp("Receive : ~p", [Res]),
- BinBody4;
- {http, Msg4} ->
- tsf(Msg4)
- after 60000 ->
- receive Any2 ->
- tsp("received crap after timeout: ~n ~p", [Any2]),
- tsf({error, {timeout, Any2}})
- end
- end,
+ {ok, RequestIdB3} =
+ httpc:request(get, {URL, []}, [], [{sync, false}]),
+ {ok, RequestIdB4} =
+ httpc:request(get, {URL, []}, [], [{sync, false}]),
+ tsp("RequestIdBs => B1: ~p, B2: ~p, B3: ~p and B4: ~p",
+ [RequestIdB1, RequestIdB2, RequestIdB3, RequestIdB4]),
+ p("test_pipeline -> RequestIdBs => B1: ~p, B2: ~p, B3: ~p and B4: ~p"
+ "~n when profile info: ~p",
+ [RequestIdB1, RequestIdB2, RequestIdB3, RequestIdB4, httpc:info()]),
+
+ p("test_pipeline -> cancel (async) request B2"
+ "~n when profile info: ~p", [httpc:info()]),
+ ok = httpc:cancel_request(RequestIdB2),
+
+ p("test_pipeline -> "
+ "expect *no* reply for cancelled (async) request B2 (for 3 secs)"
+ "~n when profile info: ~p", [httpc:info()]),
+ receive
+ {http, {RequestIdB2, _}} ->
+ tsf(http_cancel_request_failed)
+ after 3000 ->
+ ok
+ end,
+
+ p("test_pipeline -> expect reply for (async) request B1, B3 and B4"
+ "~n when profile info: ~p", [httpc:info()]),
+ Bodies = pipeline_await_async_reply([{RequestIdB1, b1, 200},
+ {RequestIdB3, b3, 200},
+ {RequestIdB4, b4, 200}], ?MINS(1)),
+ [{b1, Body}|_] = Bodies,
- p("test_pipeline -> check reply for (async) request 5"),
+ p("test_pipeline -> check reply for (async) request B1"
+ "~n when profile info: ~p", [httpc:info()]),
inets_test_lib:check_body(binary_to_list(Body)),
-
- p("test_pipeline -> ensure no unexpected incomming"),
+
+ p("test_pipeline -> ensure no unexpected incomming"
+ "~n when profile info: ~p", [httpc:info()]),
receive
{http, Any} ->
tsf({unexpected_message, Any})
after 500 ->
ok
end,
-
- p("test_pipeline -> done"),
+
+ p("test_pipeline -> done"
+ "~n when profile info: ~p", [httpc:info()]),
ok.
+pipeline_await_async_reply(ReqIds, Timeout) ->
+ pipeline_await_async_reply(ReqIds, Timeout, []).
+
+pipeline_await_async_reply([], _, Acc) ->
+ lists:keysort(1, Acc);
+pipeline_await_async_reply(ReqIds, Timeout, Acc) when Timeout > 0 ->
+ T1 = inets_test_lib:timestamp(),
+ p("pipeline_await_async_reply -> await replies"
+ "~n ReqIds: ~p"
+ "~n Timeout: ~p", [ReqIds, Timeout]),
+ receive
+ {http, {RequestId, {{_, Status, _}, _, Body}}} ->
+ p("pipeline_await_async_reply -> received reply for"
+ "~n RequestId: ~p"
+ "~n Status: ~p", [RequestId, Status]),
+ case lists:keysearch(RequestId, 1, ReqIds) of
+ {value, {RequestId, N, Status}} ->
+ p("pipeline_await_async_reply -> "
+ "found expected request ~w", [N]),
+ ReqIds2 = lists:keydelete(RequestId, 1, ReqIds),
+ NewTimeout = Timeout - (inets_test_lib:timestamp()-T1),
+ pipeline_await_async_reply(ReqIds2, NewTimeout,
+ [{N, Body} | Acc]);
+ {value, {RequestId, N, WrongStatus}} ->
+ p("pipeline_await_async_reply -> "
+ "found request ~w with wrong status", [N]),
+ tsf({reply_with_unexpected_status,
+ {RequestId, N, WrongStatus}});
+ false ->
+ tsf({unexpected_reply, {RequestId, Status}})
+ end;
+ {http, Msg} ->
+ tsf({unexpected_reply, Msg})
+ after Timeout ->
+ receive
+ Any ->
+ tsp("pipeline_await_async_reply -> "
+ "received unknown data after timeout: "
+ "~n ~p", [Any]),
+ tsf({timeout, {unknown, Any}})
+ end
+ end;
+pipeline_await_async_reply(ReqIds, _, Acc) ->
+ tsp("pipeline_await_async_reply -> "
+ "timeout: "
+ "~n ~p"
+ "~nwhen"
+ "~n ~p", [ReqIds, Acc]),
+ tsf({timeout, ReqIds, Acc}).
+
+
+
%%-------------------------------------------------------------------------
http_trace(doc) ->
["Perform a TRACE request that goes through a proxy."];
diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl
index cb1214b7fb..387263ce58 100644
--- a/lib/inets/test/httpd_mod.erl
+++ b/lib/inets/test/httpd_mod.erl
@@ -82,19 +82,23 @@ actions(Type, Port, Host, Node) ->
[{statuscode, 200},
{version, "HTTP/1.0"}]).
+
%%-------------------------------------------------------------------------
security(ServerRoot, Type, Port, Host, Node) ->
- %% io:format(user, "~w:security -> entry with"
- %% "~n ServerRoot: ~p"
- %% "~n Type: ~p"
- %% "~n Port: ~p"
- %% "~n Host: ~p"
- %% "~n Node: ~p"
- %% "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]),
-
-%% io:format(user, "~w:security -> register~n", [?MODULE]),
+ tsp("security -> "
+ "entry with"
+ "~n ServerRoot: ~p"
+ "~n Type: ~p"
+ "~n Port: ~p"
+ "~n Host: ~p"
+ "~n Node: ~p", [ServerRoot, Type, Port, Host, Node]),
+
+ tsp("security -> "
+ "register - receive security events"),
global:register_name(mod_security_test, self()), % Receive events
+ tsp("security -> "
+ "sleep"),
test_server:sleep(5000),
OpenDir = filename:join([ServerRoot, "htdocs", "open"]),
@@ -102,133 +106,240 @@ security(ServerRoot, Type, Port, Host, Node) ->
%% Test blocking / unblocking of users.
%% /open, require user one Aladdin
-%% io:format(user, "~w:security -> remove user~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "remove all existing users"),
remove_users(Node, ServerRoot, Host, Port, "open"),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "auth request for nonex user 'one' - expect 401"),
auth_request(Type, Host, Port, Node, "/open/", "one", "onePassword",
[{statuscode, 401}]),
-%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]),
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "await fail security event"),
receive_security_event({event, auth_fail, Port, OpenDir,
[{user, "one"}, {password, "onePassword"}]},
Node, Port),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "auth request for nonex user 'two' - expect 401"),
auth_request(Type,Host,Port,Node,"/open/", "two", "twoPassword",
[{statuscode, 401}]),
-%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]),
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "await fail security event"),
receive_security_event({event, auth_fail, Port, OpenDir,
[{user, "two"}, {password, "twoPassword"}]},
Node, Port),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "auth request for nonex user 'Alladin' - expect 401"),
auth_request(Type, Host, Port, Node,"/open/", "Aladdin",
"AladdinPassword", [{statuscode, 401}]),
-%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]),
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "await fail security event"),
receive_security_event({event, auth_fail, Port, OpenDir,
[{user, "Aladdin"},
{password, "AladdinPassword"}]},
Node, Port),
-%% io:format(user, "~w:security -> add users~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "add user 'one'"),
add_user(Node, ServerRoot, Port, "open", "one", "onePassword", []),
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "add user 'two'"),
add_user(Node, ServerRoot, Port, "open", "two", "twoPassword", []),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "auth request 1 for user 'one' with wrong password - expect 401"),
auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword",
[{statuscode, 401}]),
-%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]),
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "await fail security event"),
receive_security_event({event, auth_fail, Port, OpenDir,
[{user, "one"}, {password, "WrongPassword"}]},
Node, Port),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "auth request 2 for user 'one' with wrong password - expect 401"),
auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword",
[{statuscode, 401}]),
-%% io:format(user, "~w:security -> await fail security event~n", [?MODULE]),
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "await fail security event"),
receive_security_event({event, auth_fail, Port, OpenDir,
[{user, "one"}, {password, "WrongPassword"}]},
Node, Port),
-%% io:format(user, "~w:security -> await block security event~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "await block security event (two failed attempts)"),
receive_security_event({event, user_block, Port, OpenDir,
[{user, "one"}]}, Node, Port),
-%% io:format(user, "~w:security -> unregister~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "unregister - no more security events"),
global:unregister_name(mod_security_test), % No more events.
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "auth request for user 'one' with wrong password - expect 401"),
auth_request(Type, Host, Port, Node,"/open/", "one", "WrongPassword",
[{statuscode, 401}]),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "auth request for user 'one' with correct password - expect 403"),
auth_request(Type, Host, Port, Node,"/open/", "one", "onePassword",
[{statuscode, 403}]),
%% User "one" should be blocked now..
- %% [{"one",_, Port, OpenDir,_}] = list_blocked_users(Node,Port),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "list blocked users - 'one' should be the only one"),
case list_blocked_users(Node, Port) of
[{"one",_, Port, OpenDir,_}] ->
ok;
Blocked ->
- %% io:format(user, "~w:security -> Blocked: ~p"
- %% "~n", [?MODULE, Blocked]),
+ tsp(" *** unexpected blocked users ***"
+ "~n Blocked: ~p", [Blocked]),
exit({unexpected_blocked, Blocked})
end,
-
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
- [{"one",_, Port, OpenDir,_}] = list_blocked_users(Node,Port,OpenDir),
-%% io:format(user, "~w:security -> unblock user~n", [?MODULE]),
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "list users blocked for dir '~p' - "
+ "user 'one' should be the only one", [OpenDir]),
+ [{"one",_, Port, OpenDir,_}] = list_blocked_users(Node, Port, OpenDir),
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "unblock user 'one' for dir '~p'", [OpenDir]),
true = unblock_user(Node, "one", Port, OpenDir),
- %% User "one" should not be blocked any more..
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+ %% User "one" should not be blocked any more.
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "ensure user 'one' is no longer blocked"),
[] = list_blocked_users(Node, Port),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
- [] = list_blocked_users(Node, Port, OpenDir),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+
+
+ tsp("security -> "
+ "blocking and unblocking of users - "
+ "auth request for user 'one' with correct password - expect 200"),
auth_request(Type, Host, Port, Node,"/open/", "one", "onePassword",
[{statuscode, 200}]),
+
+
%% Test list_auth_users & auth_timeout
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "list auth users - expect user 'one'"),
["one"] = list_auth_users(Node, Port),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
- ["one"] = list_auth_users(Node, Port, OpenDir),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "auth request for user 'two' with wrong password - expect 401"),
auth_request(Type, Host, Port, Node,"/open/", "two", "onePassword",
[{statuscode, 401}]),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "list auth users - expect user 'one'"),
["one"] = list_auth_users(Node, Port),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "list auth users for dir '~p' - expect user 'one'", [OpenDir]),
["one"] = list_auth_users(Node, Port, OpenDir),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "auth request for user 'two' with correct password - expect 401"),
auth_request(Type, Host, Port, Node,"/open/", "two", "twoPassword",
[{statuscode, 401}]),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "list auth users - expect user 'one'"),
["one"] = list_auth_users(Node, Port),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "list auth users for dir '~p' - expect user 'one'", [OpenDir]),
["one"] = list_auth_users(Node, Port, OpenDir),
+
%% Wait for successful auth to timeout.
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "wait for successful auth to timeout"),
test_server:sleep(?AUTH_TIMEOUT*1001),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "list auth users - expect none"),
[] = list_auth_users(Node, Port),
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "list auth users for dir '~p'~n - expect none", [OpenDir]),
[] = list_auth_users(Node, Port, OpenDir),
+
%% "two" is blocked.
-%% io:format(user, "~w:security -> unblock user~n", [?MODULE]),
+
+ tsp("security -> "
+ "list-auth-users and auth-timeout - "
+ "unblock user 'two' for dir '~p'", [OpenDir]),
true = unblock_user(Node, "two", Port, OpenDir),
+
+
%% Test explicit blocking. Block user 'two'.
-%% io:format(user, "~w:security -> list blocked users~n", [?MODULE]),
+
+ tsp("security -> "
+ "explicit blocking - list blocked users - should be none"),
[] = list_blocked_users(Node,Port,OpenDir),
-%% io:format(user, "~w:security -> block user~n", [?MODULE]),
+
+ tsp("security -> "
+ "explicit blocking - "
+ "block user 'two' for dir '~p'", [OpenDir]),
true = block_user(Node, "two", Port, OpenDir, 10),
-%% io:format(user, "~w:security -> auth request~n", [?MODULE]),
+
+ tsp("security -> "
+ "explicit blocking - "
+ "auth request for user 'two' with correct password - expect 401"),
auth_request(Type, Host, Port, Node,"/open/", "two", "twoPassword",
- [{statuscode, 401}]).
+ [{statuscode, 401}]),
+ tsp("security -> "
+ "done").
+
%%-------------------------------------------------------------------------
auth(Type, Port, Host, Node) ->
+ tsp("auth -> "
+ "entry with"
+ "~n Type: ~p"
+ "~n Port: ~p"
+ "~n Host: ~p"
+ "~n Node: ~p", [Type, Port, Host, Node]),
+
%% Authentication required!
ok = httpd_test_lib:verify_request(Type,Host,Port,Node,
"GET /open/ HTTP/1.0\r\n\r\n",
@@ -913,13 +1024,11 @@ list_users(Node, Root, _Host, Port, Dir) ->
receive_security_event(Event, Node, Port) ->
- %% io:format(user, "~w:receive_security_event -> entry with"
- %% "~n Event: ~p"
- %% "~n Node: ~p"
- %% "~n Port: ~p"
- %% "~n", [?MODULE, Event, Node, Port]),
+ tsp("receive_security_event -> await ~w event", [element(2, Event)]),
receive
Event ->
+ tsp("receive_security_event -> "
+ "received expected ~w event", [element(2, Event)]),
ok;
{'EXIT', _, _} ->
receive_security_event(Event, Node, Port)
@@ -1027,8 +1136,14 @@ check_lists_members1(L1,L2) ->
{error,{lists_not_equal,L1,L2}}.
-%% tsp(F) ->
-%% inets_test_lib:tsp(F).
+%% p(F) ->
+%% p(F, []).
+
+%% p(F, A) ->
+%% io:format(user, "~w:" ++ F ++ "~n", [?MODULE|A]).
+
+tsp(F) ->
+ inets_test_lib:tsp(F).
tsp(F, A) ->
inets_test_lib:tsp(F, A).
diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl
index c94be796cd..0f8671b682 100644
--- a/lib/inets/test/inets_test_lib.erl
+++ b/lib/inets/test/inets_test_lib.erl
@@ -31,6 +31,7 @@
send/3, close/2]).
-export([copy_file/3, copy_files/2, copy_dirs/2, del_dirs/1]).
-export([info/4, log/4, debug/4, print/4]).
+-export([timestamp/0, formated_timestamp/0]).
-export([tsp/1, tsp/2, tsf/1, tss/1]).
-export([check_body/1]).
-export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]).
@@ -530,34 +531,27 @@ connect(ip_comm, Host, Port, Opts, Type) ->
"~n Opts: ~p"
"~n Type: ~p", [Host, Port, Opts, Type]),
- case gen_tcp:connect(Host, Port, Opts) of
+ case gen_tcp:connect(Host, Port, Opts, timer:seconds(10)) of
{ok, Socket} ->
tsp("connect success"),
{ok, Socket};
- {error, nxdomain} when Type =:= inet6 ->
- tsp("connect error nxdomain when"
- "~n Opts: ~p", [Opts]),
- connect(ip_comm, Host, Port, Opts -- [inet6], inet);
- {error, eafnosupport} when Type =:= inet6 ->
- tsp("connect error eafnosupport when"
- "~n Opts: ~p", [Opts]),
- connect(ip_comm, Host, Port, Opts -- [inet6], inet);
- {error, econnreset} when Type =:= inet6 ->
- tsp("connect error econnreset when"
- "~n Opts: ~p", [Opts]),
- connect(ip_comm, Host, Port, Opts -- [inet6], inet);
- {error, enetunreach} when Type =:= inet6 ->
- tsp("connect error eafnosupport when"
- "~n Opts: ~p", [Opts]),
- connect(ip_comm, Host, Port, Opts -- [inet6], inet);
- {error, econnrefused} when Type =:= inet6 ->
- tsp("connect error econnrefused when"
- "~n Opts: ~p", [Opts]),
+ {error, Reason} when ((Type =:= inet6) andalso
+ ((Reason =:= timeout) orelse
+ (Reason =:= nxdomain) orelse
+ (Reason =:= eafnosupport) orelse
+ (Reason =:= econnreset) orelse
+ (Reason =:= enetunreach) orelse
+ (Reason =:= econnrefused) orelse
+ (Reason =:= ehostunreach))) ->
+ tsp("connect(ip_comm) -> Connect error: "
+ "~n Reason: ~p"
+ "~n Type: ~p"
+ "~n Opts: ~p", [Reason, Type, Opts]),
connect(ip_comm, Host, Port, Opts -- [inet6], inet);
Error ->
- tsp("connect(ip_conn) -> Fatal connect error: "
+ tsp("connect(ip_comm) -> Fatal connect error: "
"~n Error: ~p"
"~nwhen"
"~n Host: ~p"
@@ -642,6 +636,9 @@ tsf(Reason) ->
tss(Time) ->
test_server:sleep(Time).
+timestamp() ->
+ http_util:timestamp().
+
formated_timestamp() ->
format_timestamp( os:timestamp() ).
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 488947c3a1..949eceea7f 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.9
+INETS_VSN = 5.9.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/inviso/doc/src/Makefile b/lib/inviso/doc/src/Makefile
index 1b184ed78b..f00b10f29c 100644
--- a/lib/inviso/doc/src/Makefile
+++ b/lib/inviso/doc/src/Makefile
@@ -106,14 +106,14 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/inviso/src/Makefile b/lib/inviso/src/Makefile
index 1f2f8b1aff..292a2bec99 100644
--- a/lib/inviso/src/Makefile
+++ b/lib/inviso/src/Makefile
@@ -87,12 +87,12 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
-# $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+# $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/inviso/test/Makefile b/lib/inviso/test/Makefile
index c1df29d631..2650faa392 100644
--- a/lib/inviso/test/Makefile
+++ b/lib/inviso/test/Makefile
@@ -51,10 +51,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) inviso.spec inviso.cover $(ERL_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) inviso.spec inviso.cover $(ERL_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/jinterface/doc/src/Makefile b/lib/jinterface/doc/src/Makefile
index acd5307dee..858c97f187 100644
--- a/lib/jinterface/doc/src/Makefile
+++ b/lib/jinterface/doc/src/Makefile
@@ -160,17 +160,17 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/$(JAVA_PKG_PATH)
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- (/bin/cp -rf ../html $(RELSYSDIR)/doc)
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html/java/$(JAVA_PKG_PATH)"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ (/bin/cp -rf ../html "$(RELSYSDIR)/doc")
# $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
-# $(RELSYSDIR)/doc/html
-# $(INSTALL_DATA) $(JAVA_EXTRA_FILES) $(RELSYSDIR)/doc/html/java
-# $(INSTALL_DATA) $(TOP_HTML_FILES) $(RELSYSDIR)/doc
+# "$(RELSYSDIR)/doc/html"
+# $(INSTALL_DATA) $(JAVA_EXTRA_FILES) "$(RELSYSDIR)/doc/html/java"
+# $(INSTALL_DATA) $(TOP_HTML_FILES) "$(RELSYSDIR)/doc"
release_spec:
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
index 365798e68a..ec817aa39b 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
@@ -66,7 +66,7 @@ JARFLAGS=-cvf
JAVA_OPTIONS =
ifeq ($(TESTROOT),)
-RELEASE_PATH=$(ERL_TOP)/release/$(TARGET)
+RELEASE_PATH="$(ERL_TOP)/release/$(TARGET)"
else
RELEASE_PATH=$(TESTROOT)
endif
@@ -96,13 +96,13 @@ docs:
# include $(ERL_TOP)/make/otp_release_targets.mk
release release_docs release_tests release_html:
- $(MAKE) $(MFLAGS) RELEASE_PATH=$(RELEASE_PATH) $(TARGET_MAKEFILE) $@_spec
+ $(MAKE) $(MFLAGS) RELEASE_PATH="$(RELEASE_PATH)" $(TARGET_MAKEFILE) $@_spec
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/java_src/com/ericsson/otp/erlang
- $(INSTALL_DATA) $(JAVA_SRC) $(RELSYSDIR)/java_src/com/ericsson/otp/erlang
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/java_src/com/ericsson/otp/erlang"
+ $(INSTALL_DATA) $(JAVA_SRC) "$(RELSYSDIR)/java_src/com/ericsson/otp/erlang"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/jinterface/test/Makefile b/lib/jinterface/test/Makefile
index a85d0e7411..b70521c08d 100644
--- a/lib/jinterface/test/Makefile
+++ b/lib/jinterface/test/Makefile
@@ -80,6 +80,6 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(TEST_SPEC_FILE) $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(TEST_SPEC_FILE) $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile
index 214e994889..78e5f7bc26 100644
--- a/lib/kernel/doc/src/Makefile
+++ b/lib/kernel/doc/src/Makefile
@@ -155,18 +155,18 @@ $(SPECDIR)/specs_zlib_stub.xml:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man4
- $(INSTALL_DATA) $(MAN4_FILES) $(RELEASE_PATH)/man/man4
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man4"
+ $(INSTALL_DATA) $(MAN4_FILES) "$(RELEASE_PATH)/man/man4"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index daf26a0b63..11a0843c10 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -324,7 +324,7 @@ do_recv(Sock, Bs) ->
<c><anno>Socket</anno></c>. The controlling process is the process which
receives messages from the socket. If called by any other
process than the current controlling process,
- <c>{error, eperm}</c> is returned.</p>
+ <c>{error, not_owner}</c> is returned.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index 6b83dfa030..726dc30546 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -189,7 +189,9 @@
<desc>
<p>Assigns a new controlling process <c><anno>Pid</anno></c> to
<c><anno>Socket</anno></c>. The controlling process is the process which
- receives messages from the socket.</p>
+ receives messages from the socket. If called by any other
+ process than the current controlling process,
+ <c>{error, not_owner}</c> is returned.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 096ddfd847..b727960d96 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -452,8 +452,8 @@ fe80::204:acff:fe17:bf38
Scans every byte in received data-packets and checks if the 8 bit
is set in any of them. Information is retrieved with
<c>inet:getopts/2</c>.
- <note>Deprecated! Will be removed in Erlang/OTP R16.</note>
</p>
+ <p>Note that the <c>bit8</c> option is deprecated and will be removed in Erlang/OTP R16.</p>
</item>
<tag><c>{broadcast, Boolean}</c>(UDP sockets)</tag>
diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml
index e94119845a..09c525b376 100644
--- a/lib/kernel/doc/src/os.xml
+++ b/lib/kernel/doc/src/os.xml
@@ -80,6 +80,10 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
Each environment variable is given as a single string on
the format <c>"VarName=Value"</c>, where <c>VarName</c> is
the name of the variable and <c>Value</c> its value.</p>
+ <p>If Unicode file name encoding is in effect (see the <seealso
+ marker="erts:erl#file_name_encoding">erl manual
+ page</seealso>), the strings may contain characters with
+ codepoints > 255.</p>
</desc>
</func>
<func>
@@ -93,6 +97,10 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
<p>Returns the <c>Value</c> of the environment variable
<c>VarName</c>, or <c>false</c> if the environment variable
is undefined.</p>
+ <p>If Unicode file name encoding is in effect (see the <seealso
+ marker="erts:erl#file_name_encoding">erl manual
+ page</seealso>), the strings (both <c>VarName</c> and
+ <c>Value</c>) may contain characters with codepoints > 255.</p>
</desc>
</func>
<func>
@@ -123,6 +131,13 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
<desc>
<p>Sets a new <c>Value</c> for the environment variable
<c>VarName</c>.</p>
+ <p>If Unicode filename encoding is in effect (see the <seealso
+ marker="erts:erl#file_name_encoding">erl manual
+ page</seealso>), the strings (both <c>VarName</c> and
+ <c>Value</c>) may contain characters with codepoints > 255.</p>
+ <p>On Unix platforms, the environment will be set using UTF-8 encoding
+ if Unicode file name translation is in effect. On Windows the
+ environment is set using wide character interfaces.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/packages.xml b/lib/kernel/doc/src/packages.xml
index 80de2e05fc..81b8693baa 100644
--- a/lib/kernel/doc/src/packages.xml
+++ b/lib/kernel/doc/src/packages.xml
@@ -204,11 +204,5 @@ ok
Explicitly
declaring each use of a module makes for safe code.</p>
</description>
- <funcs>
- <func>
- <name>no functions exported</name>
- <fsummary>x</fsummary>
- </func>
- </funcs>
</erlref>
diff --git a/lib/kernel/examples/Makefile b/lib/kernel/examples/Makefile
index fb27f8d438..21dfd0ec0e 100644
--- a/lib/kernel/examples/Makefile
+++ b/lib/kernel/examples/Makefile
@@ -47,8 +47,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/kernel-$(KERNEL_VSN)/examples
EXAMPLES = uds_dist
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
tar cf - $(EXAMPLES) | \
- (cd $(RELSYSDIR); tar xf - ; chmod -R ug+w $(EXAMPLES) )
+ (cd "$(RELSYSDIR)"; tar xf - ; chmod -R ug+w $(EXAMPLES) )
release_docs_spec:
diff --git a/lib/kernel/examples/uds_dist/c_src/uds_drv.c b/lib/kernel/examples/uds_dist/c_src/uds_drv.c
index 9327ab19dc..9ad6b85a0f 100644
--- a/lib/kernel/examples/uds_dist/c_src/uds_drv.c
+++ b/lib/kernel/examples/uds_dist/c_src/uds_drv.c
@@ -967,7 +967,7 @@ static void *my_malloc(size_t size)
void *ptr;
if ((ptr = driver_alloc(size)) == NULL) {
- erl_exit(1,"Could not allocate %d bytes of memory",(int) size);
+ erl_exit(1,"Could not allocate %lu bytes of memory",(unsigned long) size);
}
return ptr;
}
@@ -977,7 +977,7 @@ static void *my_realloc(void *ptr, size_t size)
void erl_exit(int, char *, ...);
void *nptr;
if ((nptr = driver_realloc(ptr, size)) == NULL) {
- erl_exit(1,"Could not reallocate %d bytes of memory",(int) size);
+ erl_exit(1,"Could not reallocate %lu bytes of memory",(unsigned long) size);
}
return nptr;
}
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index 54f21eb2b8..a39864d6b7 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -198,13 +198,13 @@ $(EBIN)/erl_epmd.beam: $(ESRC)/erl_epmd.erl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index b7fda69ce0..363072951e 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -63,7 +63,7 @@
which/1,
where_is_file/1,
where_is_file/2,
- set_primary_archive/3,
+ set_primary_archive/4,
clash/0]).
-export_type([load_error_rsn/0, load_ret/0]).
@@ -107,7 +107,7 @@
%% unstick_mod(Module) -> true
%% is_sticky(Module) -> boolean()
%% which(Module) -> Filename | loaded_ret_atoms() | non_existing
-%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason}
+%% set_primary_archive((FileName, ArchiveBin, FileInfo, ParserFun) -> ok | {error, Reason}
%% clash() -> ok prints out number of clashes
%%----------------------------------------------------------------------------
@@ -481,13 +481,16 @@ where_is_file(Path, File) when is_list(Path), is_list(File) ->
-spec set_primary_archive(ArchiveFile :: file:filename(),
ArchiveBin :: binary(),
- FileInfo :: file:file_info())
+ FileInfo :: file:file_info(),
+ ParserFun :: fun())
-> 'ok' | {'error', atom()}.
-set_primary_archive(ArchiveFile0, ArchiveBin, #file_info{} = FileInfo)
+set_primary_archive(ArchiveFile0, ArchiveBin, #file_info{} = FileInfo,
+ ParserFun)
when is_list(ArchiveFile0), is_binary(ArchiveBin) ->
ArchiveFile = filename:absname(ArchiveFile0),
- case call({set_primary_archive, ArchiveFile, ArchiveBin, FileInfo}) of
+ case call({set_primary_archive, ArchiveFile, ArchiveBin, FileInfo,
+ ParserFun}) of
{ok, []} ->
ok;
{ok, _Mode, Ebins} ->
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index a2db7c9790..00ad923466 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -394,8 +394,8 @@ handle_call(stop,{_From,_Tag}, S) ->
handle_call({is_cached,_File}, {_From,_Tag}, S=#state{cache=no_cache}) ->
{reply, no, S};
-handle_call({set_primary_archive, File, ArchiveBin, FileInfo}, {_From,_Tag}, S=#state{mode=Mode}) ->
- case erl_prim_loader:set_primary_archive(File, ArchiveBin, FileInfo) of
+handle_call({set_primary_archive, File, ArchiveBin, FileInfo, ParserFun}, {_From,_Tag}, S=#state{mode=Mode}) ->
+ case erl_prim_loader:set_primary_archive(File, ArchiveBin, FileInfo, ParserFun) of
{ok, Files} ->
{reply, {ok, Mode, Files}, S};
{error, _Reason} = Error ->
diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl
index f5f972c112..5b1efcd395 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -282,7 +282,8 @@ change_notify(Log, Pid, NewNotify) ->
-spec change_header(Log, Header) -> 'ok' | {'error', Reason} when
Log :: log(),
- Header :: {head, dlog_head_opt()} | {head_func, mfa()},
+ Header :: {head, dlog_head_opt()}
+ | {head_func, MFA :: {atom(), atom(), list()}},
Reason :: no_such_log | nonode | {read_only_mode, Log}
| {blocked_log, Log} | {badarg, head}.
change_header(Log, NewHead) ->
@@ -336,7 +337,9 @@ format_error(Error) ->
ok | {blocked, QueueLogRecords :: boolean()}}
| {node, Node :: node()}
| {distributed, Dist :: local | [node()]}
- | {head, Head :: none | {head, term()} | mfa()}
+ | {head, Head :: none
+ | {head, term()}
+ | (MFA :: {atom(), atom(), list()})}
| {no_written_items, NoWrittenItems ::non_neg_integer()}
| {full, Full :: boolean}
| {no_current_bytes, non_neg_integer()}
diff --git a/lib/kernel/src/disk_log.hrl b/lib/kernel/src/disk_log.hrl
index 259967650f..242a25a7a6 100644
--- a/lib/kernel/src/disk_log.hrl
+++ b/lib/kernel/src/disk_log.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. 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
@@ -74,7 +74,7 @@
| {distributed, Nodes :: [node()]}
| {notify, boolean()}
| {head, Head :: dlog_head_opt()}
- | {head_func, mfa()}
+ | {head_func, MFA :: {atom(), atom(), list()}}
| {mode, Mode :: dlog_mode()}.
-type dlog_options() :: [dlog_option()].
-type dlog_repair() :: 'truncate' | boolean().
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index d8033ee192..cdb984c333 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -1258,7 +1258,7 @@ sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent)
when Bytes > BytesSent; Bytes == 0 ->
Size = if Bytes == 0 ->
ChunkSize;
- (Bytes - BytesSent + ChunkSize) > 0 ->
+ (Bytes - BytesSent) < ChunkSize ->
Bytes - BytesSent;
true ->
ChunkSize
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index d8954f0cf7..8fa963ec78 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -425,9 +425,10 @@ error_string(X) ->
erlang:error(badarg, [X]).
--spec controlling_process(Socket, Pid) -> ok when
+-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
Socket :: sctp_socket(),
- Pid :: pid().
+ Pid :: pid(),
+ Reason :: closed | not_owner | inet:posix().
controlling_process(S, Pid) when is_port(S), is_pid(Pid) ->
inet:udp_controlling_process(S, Pid);
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 8688799ae9..914854c65c 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -185,9 +185,10 @@ connect(S, Address, Port) when is_port(S) ->
Error
end.
--spec controlling_process(Socket, Pid) -> ok when
+-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when
Socket :: socket(),
- Pid :: pid().
+ Pid :: pid(),
+ Reason :: closed | not_owner | inet:posix().
controlling_process(S, NewOwner) ->
inet:udp_controlling_process(S, NewOwner).
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index abaf4486dc..0bb5444dbb 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1246,6 +1246,8 @@ udp_close(S) when is_port(S) ->
%% Set controlling process for TCP socket.
tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
case erlang:port_info(S, connected) of
+ {connected, NewOwner} ->
+ ok;
{connected, Pid} when Pid =/= self() ->
{error, not_owner};
undefined ->
@@ -1297,6 +1299,8 @@ tcp_sync_input(S, Owner, Flag) ->
%% Set controlling process for UDP or SCTP socket.
udp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
case erlang:port_info(S, connected) of
+ {connected, NewOwner} ->
+ ok;
{connected, Pid} when Pid =/= self() ->
{error, not_owner};
_ ->
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index e214ffa404..a3fc57a124 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -286,7 +286,7 @@ call(N,M,F,A) ->
Reason :: term(),
Timeout :: timeout().
-call(N,M,F,A,_Timeout) when node() =:= N -> %% Optimize local call
+call(N,M,F,A,infinity) when node() =:= N -> %% Optimize local call
local_call(M,F,A);
call(N,M,F,A,infinity) ->
do_call(N, {call,M,F,A,group_leader()}, infinity);
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index 5dcaad3f5e..7bb3e3a365 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -140,12 +140,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(APP_FILES) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(APP_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) kernel.spec $(EMAKEFILE)\
- $(COVERFILE) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(COVERFILE) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/kernel/test/bif_SUITE.erl b/lib/kernel/test/bif_SUITE.erl
index 6276270d20..a2826f34df 100644
--- a/lib/kernel/test/bif_SUITE.erl
+++ b/lib/kernel/test/bif_SUITE.erl
@@ -260,23 +260,15 @@ spawn_opt2(Config) when is_list(Config) ->
?line P1 = spawn_opt(fun() ->
Parent ! {self(), fetch_proc_vals(self())}
end,
- case heap_type() of
- separate ->
- [{fullsweep_after, 0},{min_heap_size, 1000}];
- shared ->
- []
- end
- ++ [link, {priority, max}]),
+ [{fullsweep_after, 0},{min_heap_size, 1000},
+ link, {priority, max}]),
?line receive
{P1, PV1} ->
?line Node = node(P1),
?line check_proc_vals(true, max, 0, 1000, PV1)
end,
?line P2 = spawn_opt(fun() -> Parent ! {self(), fetch_proc_vals(self())} end,
- case heap_type() of
- separate -> [{min_heap_size, 10}];
- shared -> []
- end),
+ [{min_heap_size, 10}]),
?line receive
{P2, PV2} ->
?line Node = node(P2),
@@ -295,13 +287,8 @@ spawn_opt3(Config) when is_list(Config) ->
fun() ->
Parent ! {self(), fetch_proc_vals(self())}
end,
- case heap_type() of
- separate ->
- [{fullsweep_after,0}, {min_heap_size,1000}];
- shared ->
- []
- end
- ++ [link, {priority, max}]),
+ [{fullsweep_after,0}, {min_heap_size,1000},
+ link, {priority, max}]),
?line receive
{P1, PV1} ->
?line Node = node(P1),
@@ -309,10 +296,7 @@ spawn_opt3(Config) when is_list(Config) ->
end,
?line P2 = spawn_opt(Node,
fun() -> Parent ! {self(), fetch_proc_vals(self())} end,
- case heap_type() of
- separate -> [{min_heap_size, 10}];
- shared -> []
- end),
+ [{min_heap_size, 10}]),
?line receive
{P2, PV2} ->
?line Node = node(P2),
@@ -333,13 +317,8 @@ spawn_opt4(Config) when is_list(Config) ->
[fun() ->
Parent ! {self(), fetch_proc_vals(self())}
end],
- case heap_type() of
- separate ->
- [{fullsweep_after,0}, {min_heap_size,1000}];
- shared ->
- []
- end
- ++ [link, {priority, max}]),
+ [{fullsweep_after,0}, {min_heap_size,1000},
+ link, {priority, max}]),
?line receive
{P1, PV1} ->
?line Node = node(P1),
@@ -350,10 +329,7 @@ spawn_opt4(Config) when is_list(Config) ->
[fun() ->
Parent ! {self(), fetch_proc_vals(self())}
end],
- case heap_type() of
- separate -> [{min_heap_size, 10}];
- shared -> []
- end),
+ [{min_heap_size, 10}]),
?line receive
{P2, PV2} ->
?line Node = node(P2),
@@ -374,13 +350,8 @@ spawn_opt5(Config) when is_list(Config) ->
[fun() ->
Parent ! {self(), fetch_proc_vals(self())}
end],
- case heap_type() of
- separate ->
- [{fullsweep_after,0}, {min_heap_size,1000}];
- shared ->
- []
- end
- ++ [link, {priority, max}]),
+ [{fullsweep_after,0}, {min_heap_size,1000},
+ link, {priority, max}]),
?line receive
{P1, PV1} ->
?line Node = node(P1),
@@ -392,10 +363,7 @@ spawn_opt5(Config) when is_list(Config) ->
[fun() ->
Parent ! {self(), fetch_proc_vals(self())}
end],
- case heap_type() of
- separate -> [{min_heap_size, 10}];
- shared -> []
- end),
+ [{min_heap_size, 10}]),
?line receive
{P2, PV2} ->
?line Node = node(P2),
@@ -532,34 +500,19 @@ spawn_failures(Config) when is_list(Config) ->
check_proc_vals(Link, Priority, FullsweepAfter, MinHeapSize, {Ls, P, FA, HS}) ->
?line Link = lists:member(self(), Ls),
?line Priority = P,
- ?line case heap_type() of
- separate ->
- ?line FullsweepAfter = FA,
- ?line true = (HS >= MinHeapSize);
- shared ->
- ?line ok
- end,
+ FullsweepAfter = FA,
+ true = (HS >= MinHeapSize),
?line ok.
fetch_proc_vals(Pid) ->
?line PI = process_info(Pid),
?line {value,{links, Ls}} = lists:keysearch(links, 1, PI),
?line {value,{priority,P}} = lists:keysearch(priority, 1, PI),
- ?line {FA, HS}
- = case heap_type() of
- separate ->
- ?line {value,
- {garbage_collection,
- Gs}} = lists:keysearch(garbage_collection, 1, PI),
- ?line {value,
- {fullsweep_after,
- Fa}} = lists:keysearch(fullsweep_after, 1, Gs),
- ?line {value,
- {heap_size,Hs}} = lists:keysearch(heap_size, 1, PI),
- ?line {Fa, Hs};
- shared ->
- {undefined, undefined}
- end,
+ {value,{garbage_collection,Gs}} =
+ lists:keysearch(garbage_collection, 1, PI),
+ {value,{fullsweep_after,FA}} =
+ lists:keysearch(fullsweep_after, 1, Gs),
+ {value,{heap_size,HS}} = lists:keysearch(heap_size, 1, PI),
?line {Ls, P, FA, HS}.
% This testcase should probably be moved somewhere else
@@ -650,12 +603,3 @@ stop_node(Node) ->
run_fun(Fun) ->
Fun().
-
-heap_type() ->
- case catch erlang:system_info(heap_type) of
- shared -> shared;
- unified -> shared;
- _ -> separate
- end.
-
-
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 2c59351600..3e8bdaf1ff 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -501,7 +501,7 @@ sticky_dir(doc) -> ["Test that a module with the same name as a module in ",
"a sticky directory cannot be loaded."];
sticky_dir(Config) when is_list(Config) ->
MyDir=filename:dirname(code:which(?MODULE)),
- ?line {ok, Node}=?t:start_node(sticky_dir, slave,[{args, "-pa "++MyDir}]),
+ ?line {ok, Node}=?t:start_node(sticky_dir, slave,[{args, "-pa \""++MyDir++"\""}]),
File=filename:join([?config(data_dir, Config), "calendar"]),
?line Ret=rpc:call(Node, ?MODULE, sticky_compiler, [File]),
case Ret of
@@ -822,7 +822,7 @@ load_cached(Config) when is_list(Config) ->
?line WD = filename:dirname(code:which(?MODULE)),
?line {ok,Node} =
?t:start_node(code_cache_node, peer, [{args,
- "-pa " ++ WD},
+ "-pa \"" ++ WD ++ "\""},
{erl, [this]}]),
CCTabCreated = fun(Tab) ->
case ets:info(Tab, name) of
@@ -907,7 +907,7 @@ add_and_rehash(Config) when is_list(Config) ->
?line WD = filename:dirname(code:which(?MODULE)),
?line {ok,Node} =
?t:start_node(code_cache_node, peer, [{args,
- "-pa " ++ WD},
+ "-pa \"" ++ WD ++ "\""},
{erl, [this]}]),
CCTabCreated = fun(Tab) ->
case ets:info(Tab, name) of
diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl
index ad987fe7a7..0c3f5c3514 100644
--- a/lib/kernel/test/disk_log_SUITE.erl
+++ b/lib/kernel/test/disk_log_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. 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
@@ -90,7 +90,7 @@
evil/1,
- otp_6278/1]).
+ otp_6278/1, otp_10131/1]).
-export([head_fun/1, hf/0, lserv/1,
measure/0, init_m/1, xx/0, head_exit/0, slow_header/1]).
@@ -124,7 +124,7 @@
[halt_int, wrap_int, halt_ext, wrap_ext, read_mode, head,
notif, new_idx_vsn, reopen, block, unblock, open, close,
error, chunk, truncate, many_users, info, change_size,
- change_attribute, distribution, evil, otp_6278]).
+ change_attribute, distribution, evil, otp_6278, otp_10131]).
%% The following two lists should be mutually exclusive. To skip a case
%% on VxWorks altogether, use the kernel.spec.vxworks file instead.
@@ -153,7 +153,7 @@ all() ->
{group, open}, {group, close}, {group, error}, chunk,
truncate, many_users, {group, info},
{group, change_size}, change_attribute,
- {group, distribution}, evil, otp_6278].
+ {group, distribution}, evil, otp_6278, otp_10131].
groups() ->
[{halt_int, [], [halt_int_inf, {group, halt_int_sz}]},
@@ -4915,6 +4915,22 @@ otp_6278(Conf) when is_list(Conf) ->
end,
?line error_logger:delete_report_handler(?MODULE).
+otp_10131(suite) -> [];
+otp_10131(doc) -> ["OTP-10131. head_func type."];
+otp_10131(Conf) when is_list(Conf) ->
+ Dir = ?privdir(Conf),
+ Log = otp_10131,
+ File = filename:join(Dir, lists:concat([Log, ".LOG"])),
+ HeadFunc = {?MODULE, head_fun, [{ok,"head"}]},
+ {ok, Log} = disk_log:open([{name,Log},{file,File},
+ {head_func, HeadFunc}]),
+ HeadFunc = info(Log, head, undef),
+ HeadFunc2 = {?MODULE, head_fun, [{ok,"head2"}]},
+ ok = disk_log:change_header(Log, {head_func, HeadFunc2}),
+ HeadFunc2 = info(Log, head, undef),
+ ok = disk_log:close(Log),
+ ok.
+
mark(FileName, What) ->
{ok,Fd} = file:open(FileName, [raw, binary, read, write]),
{ok,_} = file:position(Fd, 4),
diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl
index 6f4f27d594..72239641e9 100644
--- a/lib/kernel/test/erl_prim_loader_SUITE.erl
+++ b/lib/kernel/test/erl_prim_loader_SUITE.erl
@@ -426,7 +426,9 @@ primary_archive(Config) when is_list(Config) ->
ExpectedEbins = [Archive, DictDir ++ "/ebin", DummyDir ++ "/ebin"],
io:format("ExpectedEbins: ~p\n", [ExpectedEbins]),
?line {ok, FileInfo} = prim_file:read_file_info(Archive),
- ?line {ok, Ebins} = rpc:call(Node, erl_prim_loader, set_primary_archive, [Archive, ArchiveBin, FileInfo]),
+ ?line {ok, Ebins} = rpc:call(Node, erl_prim_loader, set_primary_archive,
+ [Archive, ArchiveBin, FileInfo,
+ fun escript:parse_file/1]),
?line ExpectedEbins = lists:sort(Ebins), % assert
?line {ok, TopFiles2} = rpc:call(Node, erl_prim_loader, list_dir, [Archive]),
@@ -435,7 +437,9 @@ primary_archive(Config) when is_list(Config) ->
?line ok = test_archive(Node, Archive, DictDir, BeamName),
%% Cleanup
- ?line {ok, []} = rpc:call(Node, erl_prim_loader, set_primary_archive, [undefined, undefined, undefined]),
+ ?line {ok, []} = rpc:call(Node, erl_prim_loader, set_primary_archive,
+ [undefined, undefined, undefined,
+ fun escript:parse_file/1]),
?line stop_node(Node),
?line ok = file:delete(Archive),
ok.
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index 53bcb1162d..be33ec2c06 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -74,7 +74,7 @@
init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2, end_per_testcase/2]).
--export([normal/1,icky/1,very_icky/1,normalize/1]).
+-export([normal/1,icky/1,very_icky/1,normalize/1,home_dir/1]).
init_per_testcase(_Func, Config) ->
@@ -88,7 +88,7 @@ end_per_testcase(_Func, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [normal, icky, very_icky, normalize].
+ [normal, icky, very_icky, normalize, home_dir].
groups() ->
[].
@@ -105,6 +105,54 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+home_dir(suite) ->
+ [];
+home_dir(doc) ->
+ ["Check that Erlang can be started with unicode named home directory"];
+home_dir(Config) when is_list(Config) ->
+ try
+ Name=[960,945,964,961,953,954],
+ Priv = ?config(priv_dir, Config),
+ UniMode = file:native_name_encoding() =/= latin1,
+ if
+ not UniMode ->
+ throw(need_unicode_mode);
+ true ->
+ ok
+ end,
+ NewHome=filename:join(Priv,Name),
+ file:make_dir(NewHome),
+ {SaveOldName,SaveOldValue} = case os:type() of
+ {win32,nt} ->
+ HomePath=re:replace(filename:nativename(NewHome),"^[a-zA-Z]:","",[{return,list},unicode]),
+ Save = os:getenv("HOMEPATH"),
+ os:putenv("HOMEPATH",HomePath),
+ {"HOMEPATH",Save};
+ {unix,_} ->
+ Save = os:getenv("HOME"),
+ os:putenv("HOME",NewHome),
+ {"HOME",Save};
+ _ ->
+ rm_rf(prim_file,NewHome),
+ throw(unsupported_os)
+ end,
+ try
+ {ok,Node} = test_server:start_node(test_unicode_homedir,slave,[{args,"-setcookie "++atom_to_list(erlang:get_cookie())}]),
+ test_server:stop_node(Node),
+ ok
+ after
+ os:putenv(SaveOldName,SaveOldValue),
+ rm_rf(prim_file,NewHome)
+ end
+ catch
+ throw:need_unicode_mode ->
+ io:format("Sorry, can only run in unicode mode.~n"),
+ {skipped,"VM needs to be started in Unicode filename mode"};
+ throw:unsupported_os ->
+ io:format("Sorry, can only run on Unix/Windows.~n"),
+ {skipped,"Runs only on Unix/Windows"}
+ end.
+
normalize(suite) ->
[];
normalize(doc) ->
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index c74a258af9..1592399996 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -24,7 +24,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- controlling_process/1, no_accept/1, close_with_pending_output/1,
+ controlling_process/1, controlling_process_self/1,
+ no_accept/1, close_with_pending_output/1,
data_before_close/1, iter_max_socks/1, get_status/1,
passive_sockets/1, accept_closed_by_other_process/1,
init_per_testcase/2, end_per_testcase/2,
@@ -58,7 +59,7 @@ end_per_testcase(_Func, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [controlling_process, no_accept,
+ [controlling_process, controlling_process_self, no_accept,
close_with_pending_output, data_before_close,
iter_max_socks, passive_sockets,
accept_closed_by_other_process, otp_3924, closed_socket,
@@ -307,6 +308,32 @@ not_owner(S) ->
ok
end.
+controlling_process_self(doc) ->
+ ["Open a listen port and assign the controlling process to "
+ "it self, then exit and make sure the port is closed properly."];
+controlling_process_self(Config) when is_list(Config) ->
+ S = self(),
+ process_flag(trap_exit,true),
+ spawn_link(fun() ->
+ {ok,Sock} = gen_tcp:listen(0,[]),
+ S ! {socket, Sock},
+ ok = gen_tcp:controlling_process(Sock,self()),
+ S ! done
+ end),
+ receive
+ done ->
+ receive
+ {socket,Sock} ->
+ process_flag(trap_exit,false),
+ %% Make sure the port is invalid after process crash
+ {error,einval} = inet:port(Sock)
+ end;
+ Msg when element(1,Msg) /= socket ->
+ process_flag(trap_exit,false),
+ exit({unknown_msg,Msg})
+ end.
+
+
no_accept(doc) ->
["Open a listen port and connect to it, then close the listen port ",
"without doing any accept. The connected socket should receive ",
@@ -2044,7 +2071,7 @@ send_timeout_active(Config) when is_list(Config) ->
?line {error,timeout} =
Loop(fun() ->
receive
- {tcp, Sock, _Data} ->
+ {tcp, _Sock, _Data} ->
inet:setopts(A, [{active, once}]),
Res = gen_tcp:send(A,lists:duplicate(1000, $a)),
%erlang:display(Res),
@@ -2536,7 +2563,7 @@ otp_8102_do(LSocket, PortNum, {Bin,PType}) ->
otp_9389(doc) -> ["Verify packet_size handles long HTTP header lines"];
otp_9389(suite) -> [];
otp_9389(Config) when is_list(Config) ->
- ?line {ok, LS} = gen_tcp:listen(0, []),
+ ?line {ok, LS} = gen_tcp:listen(0, [{active,false}]),
?line {ok, {_, PortNum}} = inet:sockname(LS),
io:format("Listening on ~w with port number ~p\n", [LS, PortNum]),
OrigLinkHdr = "/" ++ string:chars($S, 8192),
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index b39fadd65f..e3fa4642b7 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -608,7 +608,7 @@ boot2(Config) when is_list(Config) ->
%% Absolute boot file name
Boot = filename:join([code:root_dir(), "bin", "start_sasl"]),
- Args = args() ++ " -boot " ++ Boot,
+ Args = args() ++ " -boot \"" ++ Boot++"\"",
?line {ok, Node} = start_node(init_test, Args),
?line stop_node(Node),
@@ -618,7 +618,7 @@ boot2(Config) when is_list(Config) ->
%% converted to backslashes.
Win_boot = lists:map(fun($/) -> $\\; (C) -> C end,
Boot),
- Args2 = args() ++ " -boot " ++ Win_boot,
+ Args2 = args() ++ " -boot \"" ++ Win_boot ++ "\"",
?line {ok, Node2} = start_node(init_test, Args2),
?line stop_node(Node2);
_ ->
diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl
index b2308dd321..96e45cc23f 100644
--- a/lib/kernel/test/interactive_shell_SUITE.erl
+++ b/lib/kernel/test/interactive_shell_SUITE.erl
@@ -251,7 +251,7 @@ rtnode(Commands,Nodename,ErlPrefix) ->
?line {skip, Reason2};
Tempdir ->
?line SPid =
- start_runerl_node(RunErl,ErlPrefix++Erl,
+ start_runerl_node(RunErl,ErlPrefix++"\\\""++Erl++"\\\"",
Tempdir,Nodename),
?line CPid = start_toerl_server(ToErl,Tempdir),
?line erase(getline_skipped),
@@ -487,7 +487,7 @@ start_runerl_node(RunErl,Erl,Tempdir,Nodename) ->
" -setcookie "++atom_to_list(erlang:get_cookie())
end,
spawn(fun() ->
- os:cmd(RunErl++" "++Tempdir++"/ "++Tempdir++" \""++
+ os:cmd("\""++RunErl++"\" "++Tempdir++"/ "++Tempdir++" \""++
Erl++XArg++"\"")
end).
@@ -518,7 +518,7 @@ try_to_erl(Command, N) ->
end.
toerl_server(Parent,ToErl,Tempdir) ->
- Port = try_to_erl(ToErl++" "++Tempdir++"/ 2>/dev/null",8),
+ Port = try_to_erl("\""++ToErl++"\" "++Tempdir++"/ 2>/dev/null",8),
case Port of
P when is_port(P) ->
Parent ! {self(),started};
diff --git a/lib/megaco/Makefile b/lib/megaco/Makefile
index 9dc84c122c..fc8f408b0a 100644
--- a/lib/megaco/Makefile
+++ b/lib/megaco/Makefile
@@ -49,11 +49,14 @@ VSN=$(MEGACO_VSN)
DIR_NAME = megaco_src-$(VSN)$(PRE_VSN)
+nullstring :=
+space := $(nullstring) # a space at the end
+
ifndef APP_RELEASE_DIR
ifndef TESTROOT
APP_RELEASE_DIR = /tmp
else
- APP_RELEASE_DIR = $(TESTROOT)
+ APP_RELEASE_DIR = $(subst $(space),\ ,$(TESTROOT))
endif
endif
@@ -151,7 +154,7 @@ version:
# Application install (of a app built from source) targets
# ----------------------------------------------------
app_install:
- $(MAKE) TESTROOT=$(APP_INSTALL_DIR) release
+ $(MAKE) TESTROOT="$(APP_INSTALL_DIR)" release
# ----------------------------------------------------
@@ -185,20 +188,20 @@ TAR.exclude2: Makefile TAR.exclude
(cd ..; find megaco -name '.cmake.state' >> megaco/TAR.exclude2)
$(APP_DIR): tar_exclude
- mkdir -p $(APP_DIR); \
+ mkdir -p "$(subst $(space),\ ,$@)"; \
(cd ..; tar cfX - megaco/TAR.exclude2 megaco) | \
- (cd $(APP_DIR); tar xf -); \
- mv $(APP_DIR)/megaco/* $(APP_DIR)/; \
- mkdir $(APP_DIR)/autoconf; \
- cp autoconf/config.guess $(APP_DIR)/autoconf/; \
- cp autoconf/config.sub $(APP_DIR)/autoconf/; \
- cp autoconf/install-sh $(APP_DIR)/autoconf/; \
- rmdir $(APP_DIR)/megaco
+ (cd "$(subst $(space),\ ,$@)"; tar xf -); \
+ mv "$(subst $(space),\ ,$@)"/megaco/* "$(subst $(space),\ ,$@)"/; \
+ mkdir $(subst $(space),\ ,$@)/autoconf; \
+ cp autoconf/config.guess "$(subst $(space),\ ,$@)"/autoconf/; \
+ cp autoconf/config.sub "$(subst $(space),\ ,$@)"/autoconf/; \
+ cp autoconf/install-sh "$(subst $(space),\ ,$@)"/autoconf/; \
+ rmdir "$(subst $(space),\ ,$@)"/megaco
tar: $(APP_TAR_FILE)
$(APP_TAR_FILE): $(APP_DIR)
- (cd $(APP_RELEASE_DIR); gtar zcf $(APP_TAR_FILE) $(DIR_NAME))
+ (cd "$(APP_RELEASE_DIR)"; gtar zcf "$(subst $(space),\ ,$@)" $(DIR_NAME))
dialyzer_plt: $(DIA_PLT)
diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile
index 137f0315d8..493304523e 100644
--- a/lib/megaco/doc/src/Makefile
+++ b/lib/megaco/doc/src/Makefile
@@ -164,16 +164,16 @@ info:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELSYSDIR)/doc/standard
- $(INSTALL_DATA) $(STANDARDS) $(RELSYSDIR)/doc/standard
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/standard"
+ $(INSTALL_DATA) $(STANDARDS) "$(RELSYSDIR)/doc/standard"
release_spec:
diff --git a/lib/megaco/examples/meas/Makefile.in b/lib/megaco/examples/meas/Makefile.in
index 6af7ef6c65..607d81d440 100644
--- a/lib/megaco/examples/meas/Makefile.in
+++ b/lib/megaco/examples/meas/Makefile.in
@@ -131,12 +131,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(EXAMPLE_RELSYSDIR)
- $(INSTALL_DIR) $(MEAS_RELSYSDIR)
- $(INSTALL_DATA) $(MESSAGE_PACKAGES) $(MEAS_RELSYSDIR)
- $(INSTALL_DATA) $(SCRIPT_SKELETONS) $(MEAS_RELSYSDIR)
- $(INSTALL_DATA) $(TARGET_FILES) $(MEAS_RELSYSDIR)
- $(INSTALL_DATA) $(ERL_FILES) $(MEAS_RELSYSDIR)
+ $(INSTALL_DIR) "$(EXAMPLE_RELSYSDIR)"
+ $(INSTALL_DIR) "$(MEAS_RELSYSDIR)"
+ $(INSTALL_DATA) $(MESSAGE_PACKAGES) "$(MEAS_RELSYSDIR)"
+ $(INSTALL_DATA) $(SCRIPT_SKELETONS) "$(MEAS_RELSYSDIR)"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(MEAS_RELSYSDIR)"
+ $(INSTALL_DATA) $(ERL_FILES) "$(MEAS_RELSYSDIR)"
release_docs_spec:
diff --git a/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl b/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl
index ca8016d65f..9af88d9f50 100644
--- a/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl
+++ b/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl
@@ -100,7 +100,6 @@ display_system_info() ->
OtpRel = otp_release(),
SysVer = system_version(),
SysHT = heap_type(),
- SysGHSz = global_heaps_size(),
SysSMP = smp_support(),
SysNumSched = schedulers(),
SysProcLimit = process_limit(),
@@ -113,7 +112,6 @@ display_system_info() ->
io:format("OTP release: ~s~n", [OtpRel]),
io:format("System version: ~s~n", [SysVer]),
io:format("Heap type: ~s~n", [SysHT]),
- io:format("Global heap size: ~s~n", [SysGHSz]),
io:format("Thread support: ~s~n", [SysThreads]),
io:format("Thread pool size: ~s~n", [SysTPSz]),
io:format("Process limit: ~s~n", [SysProcLimit]),
@@ -137,9 +135,6 @@ system_version() ->
heap_type() ->
system_info(heap_type, any).
-global_heaps_size() ->
- system_info(global_heaps_size, any).
-
smp_support() ->
system_info(smp_support, any).
diff --git a/lib/megaco/examples/simple/Makefile b/lib/megaco/examples/simple/Makefile
index f91d1d886f..261acbb479 100644
--- a/lib/megaco/examples/simple/Makefile
+++ b/lib/megaco/examples/simple/Makefile
@@ -139,9 +139,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DIR) $(RELSYSDIR)/examples/simple
- $(INSTALL_DATA) $(ERL_FILES) $(TARGET_FILES) $(RELSYSDIR)/examples/simple
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/simple"
+ $(INSTALL_DATA) $(ERL_FILES) $(TARGET_FILES) "$(RELSYSDIR)/examples/simple"
release_docs_spec:
diff --git a/lib/megaco/src/app/Makefile b/lib/megaco/src/app/Makefile
index 01dfb9b860..a7b458845d 100644
--- a/lib/megaco/src/app/Makefile
+++ b/lib/megaco/src/app/Makefile
@@ -108,14 +108,14 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/app
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/app
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/app"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src/app"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/megaco/src/binary/Makefile b/lib/megaco/src/binary/Makefile
index d594f34f43..77b06c81d3 100644
--- a/lib/megaco/src/binary/Makefile
+++ b/lib/megaco/src/binary/Makefile
@@ -194,11 +194,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/binary
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(ASN1_FILES) $(RELSYSDIR)/src/binary
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/binary"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(ASN1_FILES) "$(RELSYSDIR)/src/binary"
release_docs_spec:
diff --git a/lib/megaco/src/engine/Makefile b/lib/megaco/src/engine/Makefile
index c6a8bc86c7..ae2fadb3fc 100644
--- a/lib/megaco/src/engine/Makefile
+++ b/lib/megaco/src/engine/Makefile
@@ -97,12 +97,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/engine
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/engine
- $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/engine"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src/engine"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in
index 7d82644246..976ecaa4f7 100644
--- a/lib/megaco/src/flex/Makefile.in
+++ b/lib/megaco/src/flex/Makefile.in
@@ -271,16 +271,16 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/flex
- $(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/flex
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/flex"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/lib"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src/flex"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true)
- $(INSTALL_DATA) $(FLEX_FILES) $(C_TARGETS) $(RELSYSDIR)/src/flex
- $(INSTALL_PROGRAM) $(SOLIBS) $(RELSYSDIR)/priv/lib
+ $(INSTALL_DATA) $(FLEX_FILES) $(C_TARGETS) "$(RELSYSDIR)/src/flex"
+ $(INSTALL_PROGRAM) $(SOLIBS) "$(RELSYSDIR)/priv/lib"
endif
diff --git a/lib/megaco/src/tcp/Makefile b/lib/megaco/src/tcp/Makefile
index 0bd4b7c4ee..efc76bb2c5 100644
--- a/lib/megaco/src/tcp/Makefile
+++ b/lib/megaco/src/tcp/Makefile
@@ -89,11 +89,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/tcp
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/tcp
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/tcp"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src/tcp"
release_docs_spec:
diff --git a/lib/megaco/src/text/Makefile b/lib/megaco/src/text/Makefile
index b2e8e762dd..2c7703cd33 100644
--- a/lib/megaco/src/text/Makefile
+++ b/lib/megaco/src/text/Makefile
@@ -130,11 +130,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(BEAM_TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/text
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_YRL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/text
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(BEAM_TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/text"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_YRL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src/text"
release_docs_spec:
diff --git a/lib/megaco/src/udp/Makefile b/lib/megaco/src/udp/Makefile
index 64b6478c2c..db9bb72d82 100644
--- a/lib/megaco/src/udp/Makefile
+++ b/lib/megaco/src/udp/Makefile
@@ -89,11 +89,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/udp
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/udp
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/udp"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src/udp"
release_docs_spec:
diff --git a/lib/megaco/test/Makefile b/lib/megaco/test/Makefile
index 88f6f06e73..b1bca10ca8 100644
--- a/lib/megaco/test/Makefile
+++ b/lib/megaco/test/Makefile
@@ -748,11 +748,11 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(RELTEST_FILES) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(RELTEST_FILES) "$(RELSYSDIR)"
# $(INSTALL_DATA) $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) \
# $(HRL_FILES) $(ERL_FILES) \
-# $(RELSYSDIR)
+# "$(RELSYSDIR)"
#
- chmod -R u+w $(RELSYSDIR)
+ chmod -R u+w "$(RELSYSDIR)"
diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile
index 1ac5760510..173e43ac1f 100644
--- a/lib/mnesia/doc/src/Makefile
+++ b/lib/mnesia/doc/src/Makefile
@@ -142,13 +142,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/mnesia/examples/Makefile b/lib/mnesia/examples/Makefile
index ff00ee76a5..5379761c64 100644
--- a/lib/mnesia/examples/Makefile
+++ b/lib/mnesia/examples/Makefile
@@ -78,9 +78,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(ERL_FILES) $(DATA_FILES) $(HRL_FILES) $(RELSYSDIR)/examples
- $(INSTALL_DIR) $(RELSYSDIR)/examples/bench
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(ERL_FILES) $(DATA_FILES) $(HRL_FILES) "$(RELSYSDIR)/examples"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/bench"
(cd bench; $(INSTALL_DATA) \
Makefile \
README \
@@ -96,8 +96,8 @@ release_spec: opt
bench.config5 \
bench.config6 \
bench.config7 \
- $(RELSYSDIR)/examples/bench)
- (cd bench; $(INSTALL_SCRIPT) bench.sh $(RELSYSDIR)/examples/bench)
+ "$(RELSYSDIR)/examples/bench")
+ (cd bench; $(INSTALL_SCRIPT) bench.sh "$(RELSYSDIR)/examples/bench")
release_docs_spec:
diff --git a/lib/mnesia/include/Makefile b/lib/mnesia/include/Makefile
index f9b7d72abe..20f62b5460 100644
--- a/lib/mnesia/include/Makefile
+++ b/lib/mnesia/include/Makefile
@@ -54,8 +54,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(INCLUDE_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(INCLUDE_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/mnesia/src/Makefile b/lib/mnesia/src/Makefile
index 1c8ec54605..1432eabc37 100644
--- a/lib/mnesia/src/Makefile
+++ b/lib/mnesia/src/Makefile
@@ -132,10 +132,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile
index ae4c9626c7..0451da697d 100644
--- a/lib/mnesia/test/Makefile
+++ b/lib/mnesia/test/Makefile
@@ -52,24 +52,29 @@ MODULES= \
mnesia_cost \
mnesia_dbn_meters
-MnesiaExamplesDir := ../examples
+DocExamplesDir := ../doc/src/
-ExampleModules = \
+DocExampleModules = \
company \
company_o \
- bup \
- mnesia_meter \
- mnesia_tpcb
-ExamplesHrl = \
+ bup
+
+DocExamplesHrl = \
company.hrl \
company_o.hrl
-ERL_FILES= $(MODULES:%=%.erl) $(ExampleModules:%=$(MnesiaExamplesDir)/%.erl)
+ExamplesDir := ../examples/
+
+ExampleModules = \
+ mnesia_meter \
+ mnesia_tpcb
-HRL_FILES= mnesia_test_lib.hrl $(ExamplesHrl:%=$(MnesiaExamplesDir)/%)
+ERL_FILES= $(MODULES:%=%.erl) $(DocExampleModules:%=$(DocExamplesDir)/%.erl) $(ExampleModules:%=$(ExamplesDir)/%.erl)
+
+HRL_FILES= mnesia_test_lib.hrl $(DocExamplesHrl:%=$(DocExamplesDir)/%)
TARGET_FILES= \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(ExampleModules:%=$(EBIN)/%.$(EMULATOR))
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(DocExampleModules:%=$(EBIN)/%.$(EMULATOR)) $(ExampleModules:%=$(EBIN)/%.$(EMULATOR))
INSTALL_PROGS= $(TARGET_FILES)
@@ -91,7 +96,10 @@ EBIN = .
tests debug opt: $(TARGET_FILES)
-$(EBIN)/%.beam: $(MnesiaExamplesDir)/%.erl
+$(EBIN)/%.beam: $(DocExamplesDir)/%.erl
+ $(ERLC) -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+
+$(EBIN)/%.beam: $(ExamplesDir)/%.erl
$(ERLC) -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
clean:
@@ -108,11 +116,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
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 -R u+w $(RELSYSDIR)
-# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) mnesia.spec mnesia.cover $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_SCRIPT) mt $(INSTALL_PROGS) "$(RELSYSDIR)"
+# chmod -R u+w "$(RELSYSDIR)"
+# @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/mnesia/test/mnesia_consistency_test.erl b/lib/mnesia/test/mnesia_consistency_test.erl
index f38e13f3a2..bb21723e27 100644
--- a/lib/mnesia/test/mnesia_consistency_test.erl
+++ b/lib/mnesia/test/mnesia_consistency_test.erl
@@ -100,7 +100,7 @@ groups() ->
{group, updates_during_checkpoint_iteration},
{group, load_table_with_activated_checkpoint},
{group,
- add_table_copy_to_table_with_activated_checkpoint}]},
+ add_table_copy_to_table_checkpoint}]},
{updates_during_checkpoint_activation, [],
[updates_during_checkpoint_activation_2_ram,
updates_during_checkpoint_activation_2_disc,
@@ -116,10 +116,10 @@ groups() ->
[load_table_with_activated_checkpoint_ram,
load_table_with_activated_checkpoint_disc,
load_table_with_activated_checkpoint_disc_only]},
- {add_table_copy_to_table_with_activated_checkpoint, [],
- [add_table_copy_to_table_with_activated_checkpoint_ram,
- add_table_copy_to_table_with_activated_checkpoint_disc,
- add_table_copy_to_table_with_activated_checkpoint_disc_only]},
+ {add_table_copy_to_table_checkpoint, [],
+ [add_table_copy_to_table_checkpoint_ram,
+ add_table_copy_to_table_checkpoint_disc,
+ add_table_copy_to_table_checkpoint_disc_only]},
{backup_consistency, [],
[{group, interupted_install_fallback},
{group, interupted_uninstall_fallback},
@@ -952,16 +952,16 @@ view(Source, Mod) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_table_copy_to_table_with_activated_checkpoint_ram(suite) -> [];
-add_table_copy_to_table_with_activated_checkpoint_ram(Config) when is_list(Config) ->
+add_table_copy_to_table_checkpoint_ram(suite) -> [];
+add_table_copy_to_table_checkpoint_ram(Config) when is_list(Config) ->
add_table_copy_to_table_with_activated_checkpoint(ram_copies, Config).
-add_table_copy_to_table_with_activated_checkpoint_disc(suite) -> [];
-add_table_copy_to_table_with_activated_checkpoint_disc(Config) when is_list(Config) ->
+add_table_copy_to_table_checkpoint_disc(suite) -> [];
+add_table_copy_to_table_checkpoint_disc(Config) when is_list(Config) ->
add_table_copy_to_table_with_activated_checkpoint(disc_copies, Config).
-add_table_copy_to_table_with_activated_checkpoint_disc_only(suite) -> [];
-add_table_copy_to_table_with_activated_checkpoint_disc_only(Config) when is_list(Config) ->
+add_table_copy_to_table_checkpoint_disc_only(suite) -> [];
+add_table_copy_to_table_checkpoint_disc_only(Config) when is_list(Config) ->
add_table_copy_to_table_with_activated_checkpoint(disc_only_copies, Config).
add_table_copy_to_table_with_activated_checkpoint(Type,Config) ->
diff --git a/lib/observer/doc/src/Makefile b/lib/observer/doc/src/Makefile
index cd9f9466ca..0f564d3299 100644
--- a/lib/observer/doc/src/Makefile
+++ b/lib/observer/doc/src/Makefile
@@ -133,16 +133,16 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile
index 91a4c656ad..7135a6abd5 100644
--- a/lib/observer/src/Makefile
+++ b/lib/observer/src/Makefile
@@ -129,20 +129,20 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_SCRIPT) $(EXECUTABLES) $(RELSYSDIR)/priv/bin
- $(INSTALL_DIR) $(RELSYSDIR)/priv/crashdump_viewer
- $(INSTALL_DATA) $(WEBTOOLFILES) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(GIF_FILES) $(RELSYSDIR)/priv/crashdump_viewer
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(EXAMPLE_FILES) "$(RELSYSDIR)/examples"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/bin"
+ $(INSTALL_SCRIPT) $(EXECUTABLES) "$(RELSYSDIR)/priv/bin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/crashdump_viewer"
+ $(INSTALL_DATA) $(WEBTOOLFILES) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(GIF_FILES) "$(RELSYSDIR)/priv/crashdump_viewer"
release_docs_spec:
diff --git a/lib/observer/src/crashdump_viewer_html.erl b/lib/observer/src/crashdump_viewer_html.erl
index 24a80b1916..3151b83bfb 100644
--- a/lib/observer/src/crashdump_viewer_html.erl
+++ b/lib/observer/src/crashdump_viewer_html.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. 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
@@ -1394,7 +1394,7 @@ timers_table(Timer) ->
td("ALIGN=right",Time)]).
loaded_mods_table(#loaded_mod{mod=Mod,current_size=CS,old_size=OS}) ->
- tr([td(href(["loaded_mod_details?mod=",Mod],Mod)),
+ tr([td(href(["loaded_mod_details?mod=",http_uri:encode(Mod)],Mod)),
td("ALIGN=right",CS),
td("ALIGN=right",OS)]).
diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl
index 7eac2b8fab..380532e90c 100644
--- a/lib/observer/src/observer_app_wx.erl
+++ b/lib/observer/src/observer_app_wx.erl
@@ -147,11 +147,11 @@ setup_scrollbar({CW, CH}, AppWin, #app{dim={W0,H0}}) ->
H = max(H0,CH),
PPC = 20,
if W0 =< CW, H0 =< CH ->
- wxScrolledWindow:setScrollbars(AppWin, W, H, 1, 1);
+ wxScrolledWindow:setScrollbars(AppWin, W, H, 0, 0);
H0 =< CH ->
- wxScrolledWindow:setScrollbars(AppWin, PPC, H, W div PPC+1, 1);
+ wxScrolledWindow:setScrollbars(AppWin, PPC, H, W div PPC+1, 0);
W0 =< CW ->
- wxScrolledWindow:setScrollbars(AppWin, W, PPC, 1, H div PPC+1);
+ wxScrolledWindow:setScrollbars(AppWin, W, PPC, 0, H div PPC+1);
true ->
wxScrolledWindow:setScrollbars(AppWin, PPC, PPC, W div PPC+1, H div PPC+1)
end;
@@ -204,7 +204,7 @@ handle_event(#wx{id=?ID_PROC_MSG, event=#wxCommand{type=command_menu_selected}},
handle_event(#wx{id=?ID_PROC_KILL, event=#wxCommand{type=command_menu_selected}},
State = #state{panel=Panel, sel={#box{s1=#str{pid=Pid}},_}}) ->
- case observer_lib:user_term(Panel, "Enter Exit Reason", "") of
+ case observer_lib:user_term(Panel, "Enter Exit Reason", "kill") of
cancel -> ok;
{ok, Term} -> exit(Pid, Term);
{error, Error} -> observer_lib:display_info_dialog(Error)
@@ -269,22 +269,21 @@ handle_cast(Event, _State) ->
%%%%%%%%%%
handle_info({active, Node}, State = #state{parent=Parent, current=Curr, appmon=Appmon}) ->
create_menus(Parent, []),
- {ok, Pid} = appmon_info:start_link(Node, self(), []),
- case Appmon of
- undefined -> ok;
- Pid -> ok;
- _ -> %% Deregister me as client (and stop appmon if last)
- exit(Appmon, normal)
- end,
+ Pid = try
+ Node = node(Appmon),
+ Appmon
+ catch _:_ ->
+ {ok, P} = appmon_info:start_link(Node, self(), []),
+ P
+ end,
appmon_info:app_ctrl(Pid, Node, true, []),
(Curr =/= undefined) andalso appmon_info:app(Pid, Curr, true, []),
{noreply, State#state{appmon=Pid}};
-
-handle_info(not_active, State = #state{appmon=AppMon, current=Prev}) ->
+handle_info(not_active, State = #state{appmon=AppMon}) ->
appmon_info:app_ctrl(AppMon, node(AppMon), false, []),
- (Prev =/= undefined) andalso appmon_info:app(AppMon, Prev, false, []),
- {noreply, State};
-
+ lists:member(node(AppMon), nodes()) andalso exit(AppMon, normal),
+ observer_wx:set_status(""),
+ {noreply, State#state{appmon=undefined}};
handle_info({delivery, Pid, app_ctrl, _, Apps0},
State = #state{appmon=Pid, apps_w=LBox, current=Curr0}) ->
Apps = [atom_to_list(App) || {_, App, {_, _, _}} <- Apps0],
@@ -341,6 +340,7 @@ handle_mouse_click(Node = {#box{s1=#str{pid=Pid}},_}, Type,
right_down -> popup_menu(Panel);
_ -> ok
end,
+ observer_wx:set_status(io_lib:format("Pid: ~p", [Pid])),
wxWindow:refresh(AppWin),
State#state{sel=Node};
handle_mouse_click(_, _, State = #state{sel=undefined}) ->
@@ -349,6 +349,7 @@ handle_mouse_click(_, right_down, State=#state{panel=Panel}) ->
popup_menu(Panel),
State;
handle_mouse_click(_, _, State=#state{app_w=AppWin}) ->
+ observer_wx:set_status(""),
wxWindow:refresh(AppWin),
State#state{sel=undefined}.
@@ -376,10 +377,11 @@ popup_menu(Panel) ->
wxMenu:append(Menu, ?ID_TRACE_NAME, "Trace named process"),
wxMenu:append(Menu, ?ID_TRACE_TREE_PIDS, "Trace process tree"),
wxMenu:append(Menu, ?ID_TRACE_TREE_NAMES, "Trace named process tree"),
+ wxMenu:append(Menu, ?ID_PROC_MSG, "Send Msg"),
+ wxMenu:append(Menu, ?ID_PROC_KILL, "Kill process"),
wxWindow:popupMenu(Panel, Menu),
wxMenu:destroy(Menu).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
locate_node(X, _Y, [{Box=#box{x=BX}, _Chs}|_Rest])
when X < BX ->
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index fa867e12f6..abf90ac612 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -123,7 +123,7 @@ init([Notebook, Parent]) ->
}}
catch _:Err ->
io:format("~p crashed ~p: ~p~n",[?MODULE, Err, erlang:get_stacktrace()]),
- {error, Err}
+ {stop, Err}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
index 7578215ff9..ee67664539 100644
--- a/lib/observer/src/observer_pro_wx.erl
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. 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
@@ -191,13 +191,20 @@ dump_to_file(Parent, FileName, Holder) ->
start_procinfo(undefined, _Frame, Opened) ->
Opened;
start_procinfo(Pid, Frame, Opened) ->
- case lists:member(Pid, Opened) of
- true ->
- Opened;
- false ->
- observer_procinfo:start(Pid, Frame, self()),
- [Pid | Opened]
+ %% This code doesn't work until we collect which windows have been
+ %% closed maybe it should moved to observer_wx.erl
+ %% and add a global menu which remembers windows.
+ %% case lists:keyfind(Pid, 1, Opened) of
+ %% false ->
+ case observer_procinfo:start(Pid, Frame, self()) of
+ {error, _} -> Opened;
+ PI -> [{Pid, PI} | Opened]
end.
+ %%;
+ %% {_, PI} ->
+ %% wxFrame:raise(PI),
+ %% Opened
+ %% end.
call(Holder, What) ->
Ref = erlang:monitor(process, Holder),
@@ -251,8 +258,7 @@ terminate(_Reason, #state{holder=Holder}) ->
ok.
code_change(_, _, State) ->
- {stop, not_yet_implemented, State}.
-
+ {ok, State}.
handle_call(Msg, _From, State) ->
io:format("~p:~p: Unhandled call ~p~n",[?MODULE, ?LINE, Msg]),
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index ec08d3aff1..45218c177b 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -49,7 +49,8 @@ init([Pid, ParentFrame, Parent]) ->
try
Title=case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, registered_name]) of
[] -> io_lib:format("~p",[Pid]);
- {registered_name, Registered} -> atom_to_list(Registered)
+ {registered_name, Registered} -> io_lib:format("~p (~p)",[Registered, Pid]);
+ undefined -> throw(process_undefined)
end,
Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [atom_to_list(node(Pid)), $:, Title],
[{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]),
@@ -75,7 +76,10 @@ init([Pid, ParentFrame, Parent]) ->
}}
catch error:{badrpc, _} ->
observer_wx:return_to_localnode(ParentFrame, node(Pid)),
- {stop, badrpc, #state{parent=Parent, pid=Pid}}
+ {stop, badrpc};
+ process_undefined ->
+ observer_lib:display_info_dialog("No such alive process"),
+ {stop, normal}
end.
init_panel(Notebook, Str, Pid, Fun) ->
@@ -94,8 +98,11 @@ handle_event(#wx{event=#wxClose{type=close_window}}, State) ->
handle_event(#wx{id=?wxID_CLOSE, event=#wxCommand{type=command_menu_selected}}, State) ->
{stop, normal, State};
-handle_event(#wx{id=?REFRESH}, #state{pages=Pages}=State) ->
- [(W#worker.callback)() || W <- Pages],
+handle_event(#wx{id=?REFRESH}, #state{frame=Frame, pid=Pid, pages=Pages}=State) ->
+ try [(W#worker.callback)() || W <- Pages]
+ catch process_undefined ->
+ wxFrame:setTitle(Frame, io_lib:format("*DEAD* ~p",[Pid]))
+ end,
{noreply, State};
handle_event(Event, _State) ->
@@ -120,17 +127,15 @@ terminate(_Reason, #state{parent=Parent,pid=Pid,frame=Frame}) ->
ok.
code_change(_, _, State) ->
- {stop, not_yet_implemented, State}.
+ {ok, State}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_process_page(Panel, Pid) ->
Fields0 = process_info_fields(Pid),
{FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields0),
- {FPanel, fun() -> case process_info_fields(Pid) of
- Fields when is_list(Fields) ->
- observer_lib:update_info(UpFields, Fields);
- _ -> ok
- end
+ {FPanel, fun() ->
+ Fields = process_info_fields(Pid),
+ observer_lib:update_info(UpFields, Fields)
end}.
init_text_page(Parent) ->
@@ -162,7 +167,8 @@ init_message_page(Parent, Pid) ->
false ->
wxTextCtrl:writeText(Text, Messages)
end;
- _ -> ok
+ _ ->
+ throw(process_undefined)
end
end,
Update(),
@@ -178,7 +184,8 @@ init_dict_page(Parent, Pid) ->
Last = wxTextCtrl:getLastPosition(Text),
wxTextCtrl:remove(Text, 0, Last),
wxTextCtrl:writeText(Text, Dict);
- _ -> ok
+ _ ->
+ throw(process_undefined)
end
end,
Update(),
@@ -216,7 +223,8 @@ init_stack_page(Parent, Pid) ->
wxListCtrl:setItem(LCtrl, Row, 1, FileLine),
Row+1
end, 0, RawBt);
- _ -> ok
+ _ ->
+ throw(process_undefined)
end
end,
Resize = fun(#wx{event=#wxSize{size={W,_}}},Ev) ->
@@ -266,7 +274,7 @@ process_info_fields(Pid) ->
RawInfo when is_list(RawInfo) ->
observer_lib:fill_info(Struct, RawInfo);
_ ->
- ok
+ throw(process_undefined)
end.
item_list() ->
diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl
index 09602bbd9e..f00a666a35 100644
--- a/lib/observer/src/observer_sys_wx.erl
+++ b/lib/observer/src/observer_sys_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. 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
@@ -147,7 +147,7 @@ terminate(_Reason, _State) ->
ok.
code_change(_, _, State) ->
- {stop, not_yet_implemented, State}.
+ {ok, State}.
handle_call(Msg, _From, State) ->
io:format("~p~p: Unhandled Call ~p~n",[?MODULE, ?LINE, Msg]),
diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl
index d0b6a1e063..f2a1084f85 100644
--- a/lib/observer/src/observer_trace_wx.erl
+++ b/lib/observer/src/observer_trace_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -489,7 +489,7 @@ terminate(_Reason, #state{nodes=_Nodes}) ->
ok.
code_change(_, _, State) ->
- {stop, not_yet_implemented, State}.
+ {ok, State}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
do_add_patterns({Module, NewPs}, State=#state{tpatterns=TPs0, m_view=Mview, f_view=Fview}) ->
diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl
index 6a634e06f0..e27f565abc 100644
--- a/lib/observer/src/observer_traceoptions_wx.erl
+++ b/lib/observer/src/observer_traceoptions_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2012. 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
@@ -167,8 +167,10 @@ module_selector(Parent, Node) ->
function_selector(Parent, Node, Module) ->
Functions = observer_wx:try_rpc(Node, Module, module_info, [functions]),
- Choices = lists:sort([{Name, Arity} || {Name, Arity} <- Functions,
- not(erl_internal:guard_bif(Name, Arity))]),
+ Externals = observer_wx:try_rpc(Node, Module, module_info, [exports]),
+
+ Choices = lists:usort([{Name, Arity} || {Name, Arity} <- Externals ++ Functions,
+ not(erl_internal:guard_bif(Name, Arity))]),
ParsedChoices = parse_function_names(Choices),
case check_selector(Parent, ParsedChoices) of
[] -> [{Module, '_', '_'}];
diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl
index f432173f57..8fdcbf331c 100644
--- a/lib/observer/src/observer_tv_table.erl
+++ b/lib/observer/src/observer_tv_table.erl
@@ -24,6 +24,8 @@
-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3,
handle_event/2, handle_sync_event/3, handle_cast/2]).
+-export([format/1]).
+
-include("observer_defs.hrl").
-import(observer_lib, [to_str/1]).
@@ -265,7 +267,8 @@ handle_event(#wx{id=?ID_DELETE},
wxStatusBar:setStatusText(StatusBar, io_lib:format("Deleted object: ~s",[Str])),
{noreply, State};
-handle_event(#wx{id=?wxID_CLOSE}, State) ->
+handle_event(#wx{id=?wxID_CLOSE}, State = #state{frame=Frame}) ->
+ wxFrame:destroy(Frame),
{stop, normal, State};
handle_event(Help = #wx{id=?wxID_HELP}, State) ->
@@ -453,7 +456,7 @@ get_attr(Table, Item) ->
Ref = erlang:monitor(process, Table),
Table ! {get_attr, self(), Item},
receive
- {'DOWN', Ref, _, _, _} -> "";
+ {'DOWN', Ref, _, _, _} -> wx:null();
{Table, Res} ->
erlang:demonitor(Ref),
Res
@@ -747,6 +750,13 @@ format(List) when is_list(List) ->
format_list(List);
format(Bin) when is_binary(Bin), byte_size(Bin) > 100 ->
io_lib:format("<<#Bin:~w>>", [byte_size(Bin)]);
+format(Bin) when is_binary(Bin) ->
+ try
+ true = printable_list(unicode:characters_to_list(Bin)),
+ io_lib:format("<<\"~ts\">>", [Bin])
+ catch _:_ ->
+ io_lib:format("~w", [Bin])
+ end;
format(Float) when is_float(Float) ->
io_lib:format("~.3g", [Float]);
format(Term) ->
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index e2b256d768..e433bea8c2 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -20,7 +20,7 @@
-behaviour(wx_object).
-export([start/0]).
--export([create_menus/2, get_attrib/1, get_tracer/0,
+-export([create_menus/2, get_attrib/1, get_tracer/0, set_status/1,
create_txt_dialog/4, try_rpc/4, return_to_localnode/2]).
-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3,
@@ -58,7 +58,8 @@
perf_panel,
active_tab,
node,
- nodes
+ nodes,
+ prev_node=""
}).
start() ->
@@ -73,6 +74,9 @@ create_menus(Object, Menus) when is_list(Menus) ->
get_attrib(What) ->
wx_object:call(observer, {get_attrib, What}).
+set_status(What) ->
+ wx_object:cast(observer, {status_bar, What}).
+
get_tracer() ->
wx_object:call(observer, get_tracer).
@@ -191,10 +195,13 @@ setup(#state{frame = Frame} = State) ->
%%Callbacks
handle_event(#wx{event=#wxNotebook{type=command_notebook_page_changing}},
#state{active_tab=Previous, node=Node} = State) ->
- Pid = get_active_pid(State),
- Previous ! not_active,
- Pid ! {active, Node},
- {noreply, State#state{active_tab=Pid}};
+ case get_active_pid(State) of
+ Previous -> {noreply, State};
+ Pid ->
+ Previous ! not_active,
+ Pid ! {active, Node},
+ {noreply, State#state{active_tab=Pid}}
+ end;
handle_event(#wx{event = #wxClose{}}, State) ->
{stop, normal, State};
@@ -258,20 +265,21 @@ handle_event(#wx{id = ?ID_CONNECT, event = #wxCommand{type = command_menu_select
handle_event(#wx{id = ?ID_PING, event = #wxCommand{type = command_menu_selected}},
#state{frame = Frame} = State) ->
UpdState = case create_connect_dialog(ping, State) of
- cancel -> State;
+ cancel -> State;
{value, Value} when is_list(Value) ->
try
Node = list_to_atom(Value),
case net_adm:ping(Node) of
pang ->
create_txt_dialog(Frame, "Connect failed", "Pang", ?wxICON_EXCLAMATION),
- State;
+ State#state{prev_node=Value};
pong ->
- change_node_view(Node, State)
+ State1 = change_node_view(Node, State),
+ State1#state{prev_node=Value}
end
catch _:_ ->
create_txt_dialog(Frame, "Connect failed", "Pang", ?wxICON_EXCLAMATION),
- State
+ State#state{prev_node=Value}
end
end,
{noreply, UpdState};
@@ -288,6 +296,10 @@ handle_event(Event, State) ->
Pid ! Event,
{noreply, State}.
+handle_cast({status_bar, Msg}, State=#state{status_bar=SB}) ->
+ wxStatusBar:setStatusText(SB, Msg),
+ {noreply, State};
+
handle_cast(_Cast, State) ->
{noreply, State}.
@@ -341,7 +353,7 @@ terminate(_Reason, #state{frame = Frame}) ->
ok.
code_change(_, _, State) ->
- {stop, not_yet_implemented, State}.
+ {ok, State}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -401,7 +413,9 @@ connect2(NodeName, Opts, Cookie) ->
end.
change_node_view(Node, State) ->
- get_active_pid(State) ! {active, Node},
+ Tab = get_active_pid(State),
+ Tab ! not_active,
+ Tab ! {active, Node},
StatusText = ["Observer - " | atom_to_list(Node)],
wxFrame:setTitle(State#state.frame, StatusText),
wxStatusBar:setStatusText(State#state.status_bar, StatusText),
@@ -439,8 +453,8 @@ pid2panel(Pid, #state{pro_panel=Pro, sys_panel=Sys,
end.
-create_connect_dialog(ping, #state{frame = Frame}) ->
- Dialog = wxTextEntryDialog:new(Frame, "Connect to node"),
+create_connect_dialog(ping, #state{frame = Frame, prev_node=Prev}) ->
+ Dialog = wxTextEntryDialog:new(Frame, "Connect to node", [{value, Prev}]),
case wxDialog:showModal(Dialog) of
?wxID_OK ->
Value = wxTextEntryDialog:getValue(Dialog),
@@ -560,7 +574,16 @@ remove_menu_items([], _MB) ->
ok.
get_nodes() ->
- Nodes = [node()| nodes()],
+ Nodes0 = case erlang:is_alive() of
+ false -> [];
+ true ->
+ case net_adm:names() of
+ {error, _} -> nodes();
+ {ok, Names} ->
+ epmd_nodes(Names) ++ nodes()
+ end
+ end,
+ Nodes = lists:usort(Nodes0),
{_, Menues} =
lists:foldl(fun(Node, {Id, Acc}) when Id < ?LAST_NODES_MENU_ID ->
{Id + 1, [#create_menu{id=Id + ?FIRST_NODES_MENU_ID,
@@ -568,6 +591,10 @@ get_nodes() ->
end, {1, []}, Nodes),
{Nodes, lists:reverse(Menues)}.
+epmd_nodes(Names) ->
+ [_, Host] = string:tokens(atom_to_list(node()),"@"),
+ [list_to_atom(Name ++ [$@|Host]) || {Name, _} <- Names].
+
update_node_list(State = #state{menubar=MenuBar}) ->
{Nodes, NodesMenuItems} = get_nodes(),
NodeMenuId = wxMenuBar:findMenu(MenuBar, "Nodes"),
diff --git a/lib/observer/test/Makefile b/lib/observer/test/Makefile
index bf99f07081..9df0591da5 100644
--- a/lib/observer/test/Makefile
+++ b/lib/observer/test/Makefile
@@ -82,11 +82,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) observer.spec $(EMAKEFILE) \
$(COVERFILE) $(ERL_FILES) \
- $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index 5bbce9d076..6f882d0be9 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -414,6 +414,10 @@ special(Port,File) ->
_ ->
ok
end;
+ ".strangemodname" ->
+ AllMods = contents(Port,"loaded_modules"),
+ open_all_modules(Port,AllMods),
+ ok;
%%! No longer needed - all atoms are shown on one page!!
%% ".250atoms" ->
%% Html1 = contents(Port,"atoms"),
@@ -496,6 +500,26 @@ expand_binary_link(Html) ->
expand_binary_link(T)
end.
+open_all_modules(Port,Modules) ->
+ case get_first_module(Modules) of
+ {Module,Rest} ->
+ ModuleDetails = contents(Port,"loaded_mod_details?mod=" ++ Module),
+ ModTitle = http_uri:decode(Module),
+ ModTitle = title(ModuleDetails),
+ open_all_modules(Port,Rest);
+ false ->
+ ok
+ end.
+
+get_first_module([]) ->
+ false;
+get_first_module(Html) ->
+ case Html of
+ "<TD><A HREF=\"loaded_mod_details?mod=" ++ Rest ->
+ {string:sub_word(Rest,1,$"),Rest};
+ [_H|T] ->
+ get_first_module(T)
+ end.
%% next_link(Html) ->
%% case Html of
@@ -565,7 +589,7 @@ create_dumps(DataDir,[Rel|Rels],Acc) ->
Fun = fun() -> do_create_dumps(DataDir,Rel) end,
Pa = filename:dirname(code:which(?MODULE)),
{SlAllocDumps,Dumps,DosDump} =
- ?t:run_on_shielded_node(Fun, compat_rel(Rel) ++ "-pa " ++ Pa),
+ ?t:run_on_shielded_node(Fun, compat_rel(Rel) ++ "-pa \"" ++ Pa ++ "\""),
create_dumps(DataDir,Rels,SlAllocDumps ++ Dumps ++ Acc ++ DosDump);
create_dumps(_DataDir,[],Acc) ->
Acc.
@@ -590,7 +614,8 @@ do_create_dumps(DataDir,Rel) ->
case Rel of
current ->
CD3 = dump_with_args(DataDir,Rel,"instr","+Mim true"),
- {SlAllocDumps, [CD1,CD2,CD3], DosDump};
+ CD4 = dump_with_strange_module_name(DataDir,Rel,"strangemodname"),
+ {SlAllocDumps, [CD1,CD2,CD3,CD4], DosDump};
_ ->
{SlAllocDumps, [CD1,CD2], DosDump}
end.
@@ -600,7 +625,7 @@ do_create_dumps(DataDir,Rel) ->
%% not connected node, and with monitors and links between nodes.
full_dist_dump(DataDir,Rel) ->
Opt = rel_opt(Rel),
- Pz = "-pz " ++ filename:dirname(code:which(?MODULE)),
+ Pz = "-pz \"" ++ filename:dirname(code:which(?MODULE)) ++ "\"",
PzOpt = [{args,Pz}],
{ok,N1} = ?t:start_node(n1,peer,Opt ++ PzOpt),
{ok,N2} = ?t:start_node(n2,peer,Opt ++ PzOpt),
@@ -648,7 +673,22 @@ dump_with_args(DataDir,Rel,DumpName,Args) ->
?t:stop_node(n1),
CD.
+%% This dump is added to test OTP-10090 - regarding URL encoding of
+%% module names in the module detail link.
+dump_with_strange_module_name(DataDir,Rel,DumpName) ->
+ Opt = rel_opt(Rel),
+ {ok,N1} = ?t:start_node(n1,peer,Opt),
+ Mod = '<mod ule#with?strange%name>',
+ File = atom_to_list(Mod) ++ ".erl",
+ Forms = [{attribute,1,file,{File,1}},
+ {attribute,1,module,Mod},
+ {eof,4}],
+ {ok,Mod,Bin} = rpc:call(N1,compile,forms,[Forms,[binary]]),
+ {module,Mod} = rpc:call(N1,code,load_binary,[Mod,File,Bin]),
+ CD = dump(N1,DataDir,Rel,DumpName),
+ ?t:stop_node(n1),
+ CD.
dump(Node,DataDir,Rel,DumpName) ->
rpc:call(Node,erlang,halt,[DumpName]),
diff --git a/lib/odbc/c_src/Makefile.in b/lib/odbc/c_src/Makefile.in
index 3a96a53ef8..5b37b352fb 100644
--- a/lib/odbc/c_src/Makefile.in
+++ b/lib/odbc/c_src/Makefile.in
@@ -128,12 +128,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
ifdef EXE_TARGET
- $(INSTALL_DIR) $(RELSYSDIR)/c_src
- $(INSTALL_DATA) $(C_FILES) $(H_FILES) $(RELSYSDIR)/c_src
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_DIR) $(RELSYSDIR)/priv/obj
- $(INSTALL_PROGRAM) $(EXE_TARGET) $(RELSYSDIR)/priv/bin
+ $(INSTALL_DIR) "$(RELSYSDIR)/c_src"
+ $(INSTALL_DATA) $(C_FILES) $(H_FILES) "$(RELSYSDIR)/c_src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/bin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/obj"
+ $(INSTALL_PROGRAM) $(EXE_TARGET) "$(RELSYSDIR)/priv/bin"
endif
release_docs_spec:
diff --git a/lib/odbc/doc/src/Makefile b/lib/odbc/doc/src/Makefile
index 0d456085f3..cd9bca0a55 100644
--- a/lib/odbc/doc/src/Makefile
+++ b/lib/odbc/doc/src/Makefile
@@ -125,13 +125,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/odbc/src/Makefile b/lib/odbc/src/Makefile
index b48dd768c8..7ca82d784b 100644
--- a/lib/odbc/src/Makefile
+++ b/lib/odbc/src/Makefile
@@ -108,13 +108,13 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
- $(RELSYSDIR)/ebin
+ "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/odbc/src/odbc.erl b/lib/odbc/src/odbc.erl
index 36afd1abcf..9f7b06dcf1 100644
--- a/lib/odbc/src/odbc.erl
+++ b/lib/odbc/src/odbc.erl
@@ -451,7 +451,7 @@ init(Args) ->
%% Start the port program (a c program) that utilizes the odbc driver
case os:find_executable(?SERVERPROG, ?SERVERDIR) of
FileName when is_list(FileName)->
- Port = open_port({spawn, FileName},
+ Port = open_port({spawn, "\""++FileName++"\""},
[{packet, ?LENGTH_INDICATOR_SIZE}, binary,
exit_status]),
State = #state{listen_sockets =
diff --git a/lib/odbc/test/Makefile b/lib/odbc/test/Makefile
index bc6449242e..84551f0eb1 100644
--- a/lib/odbc/test/Makefile
+++ b/lib/odbc/test/Makefile
@@ -101,8 +101,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
release_docs_spec:
diff --git a/lib/odbc/test/odbc_test_lib.erl b/lib/odbc/test/odbc_test_lib.erl
index a8439d5fb6..e814cd2aca 100644
--- a/lib/odbc/test/odbc_test_lib.erl
+++ b/lib/odbc/test/odbc_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2012. 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,6 +29,7 @@
unique_table_name() ->
lists:reverse(lists:foldl(fun($@, Acc) -> [$t, $A |Acc] ;
+ ($-,Acc) -> Acc;
(X, Acc) -> [X |Acc] end,
[], atom_to_list(node()))).
diff --git a/lib/orber/COSS/CosNaming/Makefile b/lib/orber/COSS/CosNaming/Makefile
index 064447f148..a61fcd08a6 100644
--- a/lib/orber/COSS/CosNaming/Makefile
+++ b/lib/orber/COSS/CosNaming/Makefile
@@ -141,11 +141,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/COSS/CosNaming
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILE) $(RELSYSDIR)/COSS/CosNaming
- $(INSTALL_DATA) $(GEN_FILES) $(RELSYSDIR)/COSS/CosNaming
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/COSS/CosNaming"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILE) "$(RELSYSDIR)/COSS/CosNaming"
+ $(INSTALL_DATA) $(GEN_FILES) "$(RELSYSDIR)/COSS/CosNaming"
release_docs_spec:
diff --git a/lib/orber/c_src/Makefile.in b/lib/orber/c_src/Makefile.in
index 56f0d57545..5953d41ff3 100644
--- a/lib/orber/c_src/Makefile.in
+++ b/lib/orber/c_src/Makefile.in
@@ -89,23 +89,23 @@ include $(ERL_TOP)/make/otp_release_targets.mk
ifeq ($(findstring win32,$(TARGET)),win32)
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/src
- $(INSTALL_DIR) $(RELSYSDIR)/priv/include
- $(INSTALL_PROGRAM) $(CC_FILES) $(RELSYSDIR)/priv/src
- $(INSTALL_PROGRAM) $(HH_FILES) $(RELSYSDIR)/priv/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/include"
+ $(INSTALL_PROGRAM) $(CC_FILES) "$(RELSYSDIR)/priv/src"
+ $(INSTALL_PROGRAM) $(HH_FILES) "$(RELSYSDIR)/priv/include"
else
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/priv/src
- $(INSTALL_DIR) $(RELSYSDIR)/priv/include
- $(INSTALL_PROGRAM) $(CC_FILES) $(RELSYSDIR)/priv/src
- $(INSTALL_PROGRAM) $(HH_FILES) $(RELSYSDIR)/priv/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/include"
+ $(INSTALL_PROGRAM) $(CC_FILES) "$(RELSYSDIR)/priv/src"
+ $(INSTALL_PROGRAM) $(HH_FILES) "$(RELSYSDIR)/priv/include"
else
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/src
- $(INSTALL_DIR) $(RELSYSDIR)/priv/include
- $(INSTALL_DATA) $(CC_FILES) $(RELSYSDIR)/priv/src
- $(INSTALL_DATA) $(HH_FILES) $(RELSYSDIR)/priv/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/include"
+ $(INSTALL_DATA) $(CC_FILES) "$(RELSYSDIR)/priv/src"
+ $(INSTALL_DATA) $(HH_FILES) "$(RELSYSDIR)/priv/include"
endif
endif
diff --git a/lib/orber/doc/src/Makefile b/lib/orber/doc/src/Makefile
index 68fbe3dce0..c429c1d80b 100644
--- a/lib/orber/doc/src/Makefile
+++ b/lib/orber/doc/src/Makefile
@@ -164,13 +164,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/orber/examples/Stack/Makefile b/lib/orber/examples/Stack/Makefile
index b985f348fa..b03d7c3b86 100644
--- a/lib/orber/examples/Stack/Makefile
+++ b/lib/orber/examples/Stack/Makefile
@@ -118,8 +118,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples/Stack
- $(INSTALL_DATA) $(ERL_FILES) $(JAVA_FILES) $(CPP_FILES) $(IDL_FILES) $(RELSYSDIR)/examples/Stack
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/Stack"
+ $(INSTALL_DATA) $(ERL_FILES) $(JAVA_FILES) $(CPP_FILES) $(IDL_FILES) "$(RELSYSDIR)/examples/Stack"
release_docs_spec:
diff --git a/lib/orber/java_src/Orber/Makefile b/lib/orber/java_src/Orber/Makefile
index 49da975a8b..4e52ed3635 100644
--- a/lib/orber/java_src/Orber/Makefile
+++ b/lib/orber/java_src/Orber/Makefile
@@ -63,8 +63,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/java_src/Orber
- $(INSTALL_DATA) $(JAVA_FILES) $(RELSYSDIR)/java_src/Orber
+ $(INSTALL_DIR) "$(RELSYSDIR)/java_src/Orber"
+ $(INSTALL_DATA) $(JAVA_FILES) "$(RELSYSDIR)/java_src/Orber"
release_docs_spec:
diff --git a/lib/orber/priv/Makefile b/lib/orber/priv/Makefile
index af82177466..7957f7bbf0 100644
--- a/lib/orber/priv/Makefile
+++ b/lib/orber/priv/Makefile
@@ -58,8 +58,8 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(HELP_FILES) $(HTML_FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(HELP_FILES) $(HTML_FILES) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/orber/src/Makefile b/lib/orber/src/Makefile
index d2e98686da..a57d6d948b 100644
--- a/lib/orber/src/Makefile
+++ b/lib/orber/src/Makefile
@@ -254,12 +254,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(GEN_HRL_FILES_LOC) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(GEN_HRL_FILES_EXT) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(GEN_HRL_FILES_LOC) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(GEN_HRL_FILES_EXT) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/orber/test/Makefile b/lib/orber/test/Makefile
index d4be009af3..8eef1934a4 100644
--- a/lib/orber/test/Makefile
+++ b/lib/orber/test/Makefile
@@ -209,12 +209,12 @@ release_spec:
release_docs_spec:
release_tests_spec: tests
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) $(COVER_FILE) \
- $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- $(INSTALL_DIR) $(RELSYSDIR)/$(IDLOUTDIR)
+ $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
$(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
- $(RELSYSDIR)/$(IDLOUTDIR)
+ "$(RELSYSDIR)/$(IDLOUTDIR)"
diff --git a/lib/orber/test/orber_test_lib.erl b/lib/orber/test/orber_test_lib.erl
index 0ddde49cd6..2bfa1ef871 100644
--- a/lib/orber/test/orber_test_lib.erl
+++ b/lib/orber/test/orber_test_lib.erl
@@ -282,6 +282,7 @@ starter(Host, Name, Args) ->
vxworks ->
test_server:start_node(Name, slave, [{args,Args}]);
_ ->
+ io:format("slave:start_link(~p,~p,~p).~n",[Host,Name,Args]),
slave:start_link(Host, Name, Args)
end.
@@ -403,8 +404,8 @@ create_paths() ->
filename:join(Path, "idl_output") ++
" -pa " ++
filename:join(Path, "all_SUITE_data") ++
- " -pa " ++
- filename:dirname(code:which(orber)).
+ " -pa \"" ++
+ filename:dirname(code:which(orber))++"\"".
%%------------------------------------------------------------
%% function : destroy_node
diff --git a/lib/os_mon/c_src/Makefile.in b/lib/os_mon/c_src/Makefile.in
index bac0413ece..45dc01e993 100644
--- a/lib/os_mon/c_src/Makefile.in
+++ b/lib/os_mon/c_src/Makefile.in
@@ -131,10 +131,10 @@ ifeq ($(findstring vxworks_simso,$(TARGET)),vxworks_simso)
release_spec:
else
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(C_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_PROGRAM) $(TARGET_FILES) $(RELSYSDIR)/priv/bin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(C_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/bin"
+ $(INSTALL_PROGRAM) $(TARGET_FILES) "$(RELSYSDIR)/priv/bin"
endif
release_docs_spec:
diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c
index 9c5f9a6aa5..a0432b3093 100644
--- a/lib/os_mon/c_src/cpu_sup.c
+++ b/lib/os_mon/c_src/cpu_sup.c
@@ -458,8 +458,18 @@ static void error(char* err_msg) {
* if we get error here we have trouble,
* silence unnecessary warnings
*/
- if(write(FD_ERR, err_msg, strlen(err_msg)));
- if(write(FD_ERR, "\n", 1));
+ char buffer[256] = "[os_mon] cpu supervisor port (cpu_sup): ";
+ int i = strlen(buffer), j = 0;
+ int n = strlen(err_msg);
+
+ while(i < 253 && j < n) {
+ buffer[i++] = err_msg[j++];
+ }
+ buffer[i++] = '\r';
+ buffer[i++] = '\n';
+
+ /* try to use one write only */
+ if(write(FD_ERR, buffer, i));
exit(-1);
}
diff --git a/lib/os_mon/c_src/memsup.c b/lib/os_mon/c_src/memsup.c
index 078f20ff98..593a066f98 100644
--- a/lib/os_mon/c_src/memsup.c
+++ b/lib/os_mon/c_src/memsup.c
@@ -493,7 +493,7 @@ get_basic_mem(unsigned long *tot, unsigned long *used, unsigned long *pagesize){
#elif defined(__linux__) && !defined(_SC_AVPHYS_PAGES)
memory_ext me;
if (get_mem_procfs(&me) < 0) {
- print_error("ProcFS read error.");
+ print_error("ProcFS read error");
exit(1);
}
*tot = me.total;
@@ -582,7 +582,7 @@ message_loop(int erlin_fd)
* Wait for command from Erlang
*/
if ((res = read(erlin_fd, &cmdLen, 1)) < 0) {
- print_error("Error reading from Erlang.");
+ print_error("Error reading from Erlang");
return;
}
@@ -603,19 +603,19 @@ message_loop(int erlin_fd)
break;
case 0:
- print_error("Erlang has closed.");
+ print_error("Erlang has closed");
return;
default:
- print_error("Error reading from Erlang.");
+ print_error("Error reading from Erlang");
return;
} /* switch() */
} else { /* cmdLen != 1 */
- print_error("Invalid command length (%d) received.", cmdLen);
+ print_error("Invalid command length (%d) received", cmdLen);
return;
}
} else { /* Erlang end closed */
- print_error("Erlang has closed.");
+ print_error("Erlang has closed");
return;
}
}
@@ -641,15 +641,12 @@ static void
print_error(const char *format,...)
{
va_list args;
+ char buffer[256];
va_start(args, format);
- fprintf(stderr, "%s: ", program_name);
- vfprintf(stderr, format, args);
+ vsnprintf(buffer, 256, format, args);
va_end(args);
- fprintf(stderr, " \n");
+ /* try to use one write only */
+ fprintf(stderr, "[os_mon] memory supervisor port (memsup): %s\r\n", buffer);
+ fflush(stderr);
}
-
-
-
-
-
diff --git a/lib/os_mon/c_src/win32sysinfo.c b/lib/os_mon/c_src/win32sysinfo.c
index 2a155aae87..9d4587393f 100644
--- a/lib/os_mon/c_src/win32sysinfo.c
+++ b/lib/os_mon/c_src/win32sysinfo.c
@@ -89,6 +89,7 @@ typedef BOOL (WINAPI *tfpGetDiskFreeSpaceEx)(LPCTSTR, PULARGE_INTEGER,PULARGE_IN
static tfpGetDiskFreeSpaceEx fpGetDiskFreeSpaceEx;
+static void print_error(const char *msg);
static void
return_answer(char* value)
{
@@ -98,7 +99,7 @@ return_answer(char* value)
res = write(1,(char*) &bytes,1);
if (res != 1) {
- fprintf(stderr,"win32sysinfo:Error writing to pipe");
+ print_error("Error writing to pipe");
exit(1);
}
@@ -107,9 +108,8 @@ return_answer(char* value)
while (left > 0)
{
res = write(1, value+bytes-left, left);
- if (res <= 0)
- {
- fprintf(stderr,"win32sysinfo:Error writing to pipe");
+ if (res <= 0) {
+ print_error("Error writing to pipe");
exit(1);
}
left -= res;
@@ -248,7 +248,6 @@ message_loop()
char cmd[512];
int res;
- fprintf(stderr,"in message_loop\n");
/* Startup ACK. */
return_answer(OK);
while (1)
@@ -257,12 +256,12 @@ message_loop()
* Wait for command from Erlang
*/
if ((res = read(0, &cmdLen, 1)) < 0) {
- fprintf(stderr,"win32sysinfo:Error reading from Erlang.");
+ print_error("Error reading from Erlang");
return;
}
if (res != 1){ /* Exactly one byte read ? */
- fprintf(stderr,"win32sysinfo:Erlang has closed.");
+ print_error("Erlang has closed");
return;
}
if ((res = read(0, &cmd, cmdLen)) == cmdLen){
@@ -291,11 +290,11 @@ message_loop()
return_answer("xEND");
}
else if (res == 0) {
- fprintf(stderr,"win32sysinfo:Erlang has closed.");
+ print_error("Erlang has closed");
return;
}
else {
- fprintf(stderr,"win32sysinfo:Error reading from Erlang.");
+ print_error("Error reading from Erlang");
return;
}
}
@@ -309,10 +308,9 @@ int main(int argc, char ** argv){
message_loop();
return 0;
}
-
-
-
-
-
-
-
+static void
+print_error(const char *msg) {
+ /* try to use one write only */
+ fprintf(stderr, "[os_mon] win32 supervisor port (win32sysinfo): %s\r\n", msg);
+ fflush(stderr);
+}
diff --git a/lib/os_mon/doc/src/Makefile b/lib/os_mon/doc/src/Makefile
index c9765749c9..aa8fb4b60c 100644
--- a/lib/os_mon/doc/src/Makefile
+++ b/lib/os_mon/doc/src/Makefile
@@ -109,16 +109,16 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6DIR)/* $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6DIR)/* "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/os_mon/mibs/Makefile b/lib/os_mon/mibs/Makefile
index 655190edf4..a6d8ab5042 100644
--- a/lib/os_mon/mibs/Makefile
+++ b/lib/os_mon/mibs/Makefile
@@ -88,13 +88,13 @@ $(SNMP_BIN_TARGET_DIR)/OTP-OS-MON-MIB.bin: \
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/mibs
- $(INSTALL_DIR) $(RELSYSDIR)/mibs/v1
- $(INSTALL_DATA) $(MIB_FILES) $(FUNCS_FILES) $(RELSYSDIR)/mibs
- $(INSTALL_DATA) $(V1_MIB_FILES) $(RELSYSDIR)/mibs/v1
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_TARGETS) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/priv/mibs
- $(INSTALL_DATA) $(BIN_TARGETS) $(RELSYSDIR)/priv/mibs
+ $(INSTALL_DIR) "$(RELSYSDIR)/mibs"
+ $(INSTALL_DIR) "$(RELSYSDIR)/mibs/v1"
+ $(INSTALL_DATA) $(MIB_FILES) $(FUNCS_FILES) "$(RELSYSDIR)/mibs"
+ $(INSTALL_DATA) $(V1_MIB_FILES) "$(RELSYSDIR)/mibs/v1"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_TARGETS) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/mibs"
+ $(INSTALL_DATA) $(BIN_TARGETS) "$(RELSYSDIR)/priv/mibs"
release_docs_spec:
diff --git a/lib/os_mon/src/Makefile b/lib/os_mon/src/Makefile
index 9a75446a89..a8ad26f6a1 100644
--- a/lib/os_mon/src/Makefile
+++ b/lib/os_mon/src/Makefile
@@ -94,11 +94,11 @@ $(EBIN)/memsup.$(EMULATOR): $(MEMSUP_HRL)
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/os_mon/src/disksup.erl b/lib/os_mon/src/disksup.erl
index 308cd1b7fa..c7abb7a386 100644
--- a/lib/os_mon/src/disksup.erl
+++ b/lib/os_mon/src/disksup.erl
@@ -43,24 +43,24 @@ start_link() ->
gen_server:start_link({local, disksup}, disksup, [], []).
get_disk_data() ->
- os_mon:call(disksup, get_disk_data).
+ os_mon:call(disksup, get_disk_data, infinity).
get_check_interval() ->
- os_mon:call(disksup, get_check_interval).
+ os_mon:call(disksup, get_check_interval, infinity).
set_check_interval(Minutes) ->
case param_type(disk_space_check_interval, Minutes) of
true ->
- os_mon:call(disksup, {set_check_interval, Minutes});
+ os_mon:call(disksup, {set_check_interval, Minutes}, infinity);
false ->
erlang:error(badarg)
end.
get_almost_full_threshold() ->
- os_mon:call(disksup, get_almost_full_threshold).
+ os_mon:call(disksup, get_almost_full_threshold, infinity).
set_almost_full_threshold(Float) ->
case param_type(disk_almost_full_threshold, Float) of
true ->
- os_mon:call(disksup, {set_almost_full_threshold, Float});
+ os_mon:call(disksup, {set_almost_full_threshold, Float}, infinity);
false ->
erlang:error(badarg)
end.
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index 5ef240f128..54771b4703 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -112,7 +112,7 @@ get_helper_timeout() ->
set_helper_timeout(Seconds) ->
case param_type(memsup_helper_timeout, Seconds) of
true ->
- os_mon:call(memsup, {set_helper_timeout, Seconds});
+ os_mon:call(memsup, {set_helper_timeout, Seconds}, infinity);
false ->
erlang:error(badarg)
end.
diff --git a/lib/os_mon/src/os_mon.erl b/lib/os_mon/src/os_mon.erl
index 3098c38808..2b6cd7c498 100644
--- a/lib/os_mon/src/os_mon.erl
+++ b/lib/os_mon/src/os_mon.erl
@@ -85,13 +85,13 @@ open_port(Name, Opts) ->
%% Check os_mon*/priv/bin/Name
case filelib:is_regular(ReleasedPath) of
true ->
- erlang:open_port({spawn, ReleasedPath}, Opts);
+ erlang:open_port({spawn, "\""++ReleasedPath++"\""}, Opts);
false ->
%% Use os_mon*/priv/bin/Arch/Name
ArchPath =
filename:join(
[PrivDir,"bin",erlang:system_info(system_architecture),Name]),
- erlang:open_port({spawn, ArchPath}, Opts)
+ erlang:open_port({spawn, "\""++ArchPath++"\""}, Opts)
end.
diff --git a/lib/os_mon/test/Makefile b/lib/os_mon/test/Makefile
index a240640f92..954cfef7fb 100644
--- a/lib/os_mon/test/Makefile
+++ b/lib/os_mon/test/Makefile
@@ -84,9 +84,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) os_mon.spec os_mon.cover $(EMAKEFILE) $(SOURCE) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) os_mon.spec os_mon.cover $(EMAKEFILE) $(SOURCE) "$(RELSYSDIR)"
-## tar chf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+## tar chf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/otp_mibs/doc/src/Makefile b/lib/otp_mibs/doc/src/Makefile
index bd2810034b..16a5bb39b4 100644
--- a/lib/otp_mibs/doc/src/Makefile
+++ b/lib/otp_mibs/doc/src/Makefile
@@ -102,14 +102,14 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/otp_mibs/mibs/Makefile b/lib/otp_mibs/mibs/Makefile
index 5e59824d3f..7ef8480b3e 100644
--- a/lib/otp_mibs/mibs/Makefile
+++ b/lib/otp_mibs/mibs/Makefile
@@ -76,13 +76,13 @@ v1/%.mib.v1: %.mib
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/mibs
- $(INSTALL_DIR) $(RELSYSDIR)/mibs/v1
- $(INSTALL_DATA) $(MIB_FILES) $(FUNCS_FILES) $(RELSYSDIR)/mibs
- $(INSTALL_DATA) $(V1_MIB_FILES) $(RELSYSDIR)/mibs/v1
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_TARGETS) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/priv/mibs
- $(INSTALL_DATA) $(BIN_TARGETS) $(RELSYSDIR)/priv/mibs
+ $(INSTALL_DIR) "$(RELSYSDIR)/mibs"
+ $(INSTALL_DIR) "$(RELSYSDIR)/mibs/v1"
+ $(INSTALL_DATA) $(MIB_FILES) $(FUNCS_FILES) "$(RELSYSDIR)/mibs"
+ $(INSTALL_DATA) $(V1_MIB_FILES) "$(RELSYSDIR)/mibs/v1"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_TARGETS) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/mibs"
+ $(INSTALL_DATA) $(BIN_TARGETS) "$(RELSYSDIR)/priv/mibs"
release_docs_spec:
diff --git a/lib/otp_mibs/src/Makefile b/lib/otp_mibs/src/Makefile
index 833a439adb..c9c40fec3a 100644
--- a/lib/otp_mibs/src/Makefile
+++ b/lib/otp_mibs/src/Makefile
@@ -95,10 +95,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGETS) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGETS) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/parsetools/doc/src/Makefile b/lib/parsetools/doc/src/Makefile
index 6e693e0cf0..464ea66af0 100644
--- a/lib/parsetools/doc/src/Makefile
+++ b/lib/parsetools/doc/src/Makefile
@@ -105,14 +105,14 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/parsetools/src/Makefile b/lib/parsetools/src/Makefile
index 89e079e411..e228ee88ef 100644
--- a/lib/parsetools/src/Makefile
+++ b/lib/parsetools/src/Makefile
@@ -89,12 +89,12 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/parsetools/test/Makefile b/lib/parsetools/test/Makefile
index 624c4e6975..430386bfe5 100644
--- a/lib/parsetools/test/Makefile
+++ b/lib/parsetools/test/Makefile
@@ -70,9 +70,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) parsetools.spec parsetools.cover $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- # @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) parsetools.spec parsetools.cover $(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ # @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/percept/doc/src/Makefile b/lib/percept/doc/src/Makefile
index f0d43c5a01..e749103783 100644
--- a/lib/percept/doc/src/Makefile
+++ b/lib/percept/doc/src/Makefile
@@ -175,15 +175,15 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTML_EXAMPLE_FILES) $(HTML_STYLESHEET_FILES) \
$(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/percept/priv/Makefile b/lib/percept/priv/Makefile
index 7c37ccd98b..4d7942c49c 100644
--- a/lib/percept/priv/Makefile
+++ b/lib/percept/priv/Makefile
@@ -77,20 +77,20 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
# Finished
- $(INSTALL_DIR) $(RELSYSDIR)/priv/logs
- $(INSTALL_DIR) $(RELSYSDIR)/priv/server_root
- $(INSTALL_DIR) $(RELSYSDIR)/priv/server_root/htdocs
- $(INSTALL_DATA) $(HTDOCS_FILES) $(RELSYSDIR)/priv/server_root/htdocs
- $(INSTALL_DIR) $(RELSYSDIR)/priv/server_root/conf
- $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/priv/server_root/conf
- $(INSTALL_DIR) $(RELSYSDIR)/priv/server_root/scripts
- $(INSTALL_DATA) $(SCRIPT_FILES) $(RELSYSDIR)/priv/server_root/scripts
- $(INSTALL_DIR) $(RELSYSDIR)/priv/server_root/css
- $(INSTALL_DATA) $(CSS_FILES) $(RELSYSDIR)/priv/server_root/css
- $(INSTALL_DIR) $(RELSYSDIR)/priv/server_root/images
- $(INSTALL_DATA) $(IMAGE_FILES) $(RELSYSDIR)/priv/server_root/images
- $(INSTALL_DIR) $(RELSYSDIR)/priv/fonts
- $(INSTALL_DATA) $(FONT_FILES) $(RELSYSDIR)/priv/fonts
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/logs"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/server_root"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/server_root/htdocs"
+ $(INSTALL_DATA) $(HTDOCS_FILES) "$(RELSYSDIR)/priv/server_root/htdocs"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/server_root/conf"
+ $(INSTALL_DATA) $(CONF_FILES) "$(RELSYSDIR)/priv/server_root/conf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/server_root/scripts"
+ $(INSTALL_DATA) $(SCRIPT_FILES) "$(RELSYSDIR)/priv/server_root/scripts"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/server_root/css"
+ $(INSTALL_DATA) $(CSS_FILES) "$(RELSYSDIR)/priv/server_root/css"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/server_root/images"
+ $(INSTALL_DATA) $(IMAGE_FILES) "$(RELSYSDIR)/priv/server_root/images"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/fonts"
+ $(INSTALL_DATA) $(FONT_FILES) "$(RELSYSDIR)/priv/fonts"
release_docs_spec:
diff --git a/lib/percept/src/Makefile b/lib/percept/src/Makefile
index 5dfc72575a..4b9a10cdb8 100644
--- a/lib/percept/src/Makefile
+++ b/lib/percept/src/Makefile
@@ -93,12 +93,12 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
-# $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+# $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/percept/test/Makefile b/lib/percept/test/Makefile
index d927386d1c..ee70966b01 100644
--- a/lib/percept/test/Makefile
+++ b/lib/percept/test/Makefile
@@ -81,10 +81,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) percept.spec percept.cover $(EMAKEFILE) $(SOURCE) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) percept.spec percept.cover $(EMAKEFILE) $(SOURCE) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/pman/doc/src/Makefile b/lib/pman/doc/src/Makefile
index 4e116cb23e..ec759091ab 100644
--- a/lib/pman/doc/src/Makefile
+++ b/lib/pman/doc/src/Makefile
@@ -103,14 +103,14 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/pman/priv/Makefile b/lib/pman/priv/Makefile
index 43f9d45d94..a89278fd3a 100644
--- a/lib/pman/priv/Makefile
+++ b/lib/pman/priv/Makefile
@@ -50,8 +50,8 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(TOOLBAR_FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(TOOLBAR_FILES) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/pman/src/Makefile b/lib/pman/src/Makefile
index e573e57220..2cd1c64c49 100644
--- a/lib/pman/src/Makefile
+++ b/lib/pman/src/Makefile
@@ -103,10 +103,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(TOOLBOX_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(TARGET_TOOLBOX_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(TOOLBOX_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(TARGET_TOOLBOX_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile
index 943d97bdb8..d48f48a5d5 100644
--- a/lib/public_key/asn1/Makefile
+++ b/lib/public_key/asn1/Makefile
@@ -91,13 +91,13 @@ $(INCLUDE)/%.hrl: %.hrl
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/asn1
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/asn1"
$(INSTALL_DATA) $(ASN_ASNS) $(ASN_ERLS) $(ASN_HRLS) $(ASN_CONFIGS) \
- $(GEN_ERLS) $(RELSYSDIR)/asn1
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(GEN_ERLS) "$(RELSYSDIR)/asn1"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/public_key/doc/src/Makefile b/lib/public_key/doc/src/Makefile
index 9616a96195..928aa62c1b 100644
--- a/lib/public_key/doc/src/Makefile
+++ b/lib/public_key/doc/src/Makefile
@@ -114,14 +114,14 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
info:
diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile
index 062c495a65..8a72da477f 100644
--- a/lib/public_key/src/Makefile
+++ b/lib/public_key/src/Makefile
@@ -102,11 +102,11 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile
index 397a0eb2d5..41d77f103b 100644
--- a/lib/public_key/test/Makefile
+++ b/lib/public_key/test/Makefile
@@ -78,11 +78,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(COVER_FILE) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(COVER_FILE) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/reltool/doc/src/Makefile b/lib/reltool/doc/src/Makefile
index 8bc1488f77..0b85b7e02c 100644
--- a/lib/reltool/doc/src/Makefile
+++ b/lib/reltool/doc/src/Makefile
@@ -97,13 +97,13 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(HTMLDIR)/* $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(HTMLDIR)/* "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/reltool/examples/Makefile b/lib/reltool/examples/Makefile
index dacfd4e7d4..afc47e1d12 100644
--- a/lib/reltool/examples/Makefile
+++ b/lib/reltool/examples/Makefile
@@ -72,8 +72,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(ERL_FILES) $(DATA_FILES) $(HRL_FILES) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(ERL_FILES) $(DATA_FILES) $(HRL_FILES) "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/reltool/src/Makefile b/lib/reltool/src/Makefile
index 4e6a112b7e..4730b4acff 100644
--- a/lib/reltool/src/Makefile
+++ b/lib/reltool/src/Makefile
@@ -97,11 +97,11 @@ $(TARGET_FILES): $(HRL_FILES) $(INTERNAL_HRL_FILES)
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile
index 932532d811..52cdef44da 100644
--- a/lib/reltool/test/Makefile
+++ b/lib/reltool/test/Makefile
@@ -73,12 +73,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) reltool.spec reltool.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_SCRIPT) rtt $(INSTALL_PROGS) $(RELSYSDIR)
- $(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) reltool.spec reltool.cover $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_SCRIPT) rtt $(INSTALL_PROGS) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(INSTALL_PROGS) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in
index cbbcfa2d56..754e6ccd78 100644
--- a/lib/runtime_tools/c_src/Makefile.in
+++ b/lib/runtime_tools/c_src/Makefile.in
@@ -193,10 +193,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/obj
- $(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_PROGRAM) $(DYNTRACE_OBJS) $(RELSYSDIR)/priv/obj
- $(INSTALL_PROGRAM) $(NIF_LIB) $(SOLIBS) $(RELSYSDIR)/priv/lib
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/obj"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/lib"
+ $(INSTALL_PROGRAM) $(DYNTRACE_OBJS) "$(RELSYSDIR)/priv/obj"
+ $(INSTALL_PROGRAM) $(NIF_LIB) $(SOLIBS) "$(RELSYSDIR)/priv/lib"
release_docs_spec:
diff --git a/lib/runtime_tools/c_src/dtrace_user.d b/lib/runtime_tools/c_src/dtrace_user.d
index 3a80d0f7a3..9e180a3cb2 100644
--- a/lib/runtime_tools/c_src/dtrace_user.d
+++ b/lib/runtime_tools/c_src/dtrace_user.d
@@ -19,31 +19,11 @@
*/
provider erlang {
- /**
- * Send a single string to a probe.
- *
- * @param NUL-terminated string
+ /*
+ * The set of probes for use by Erlang code ... moved from here to
+ * erts/emulator/beam/erlang_dtrace.d until a more portable solution is
+ * found; see erlang_dtrace.d for details.
*/
- probe user_trace__s1(char* message);
-
- /**
- * Multi-purpose probe: up to 4 NUL-terminated strings and 4
- * 64-bit integer arguments.
- *
- * @param proc, the PID (string form) of the sending process
- * @param user_tag, the user tag of the sender
- * @param i1, integer
- * @param i2, integer
- * @param i3, integer
- * @param i4, integer
- * @param s1, string/iolist. D's arg6 is NULL if not given by Erlang
- * @param s2, string/iolist. D's arg7 is NULL if not given by Erlang
- * @param s3, string/iolist. D's arg8 is NULL if not given by Erlang
- * @param s4, string/iolist. D's arg9 is NULL if not given by Erlang
- */
- probe user_trace__i4s4(char *proc, char *user_tag,
- int i1, int i2, int i3, int i4,
- char *s1, char *s2, char *s3, char *s4);
};
#pragma D attributes Evolving/Evolving/Common provider erlang provider
diff --git a/lib/runtime_tools/c_src/dyntrace.c b/lib/runtime_tools/c_src/dyntrace.c
index 96dbebbdfa..eef03afd1c 100644
--- a/lib/runtime_tools/c_src/dyntrace.c
+++ b/lib/runtime_tools/c_src/dyntrace.c
@@ -36,6 +36,10 @@
void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf);
void get_string_maybe(ErlNifEnv *env, const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz);
+#ifdef HAVE_USE_DTRACE
+ERL_NIF_TERM erl_nif_user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM erl_nif_user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+#endif
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -56,11 +60,13 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM user_trace_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ErlNifFunc nif_funcs[] = {
{"available", 0, available},
{"user_trace_s1", 1, user_trace_s1},
- {"user_trace_i4s4", 9, user_trace_i4s4}
+ {"user_trace_i4s4", 9, user_trace_i4s4},
+ {"user_trace_n", 10, user_trace_n}
};
ERL_NIF_INIT(dyntrace, nif_funcs, load, NULL, NULL, NULL)
@@ -96,76 +102,25 @@ static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
#ifdef HAVE_USE_DTRACE
- ErlNifBinary message_bin;
- DTRACE_CHARBUF(messagebuf, MESSAGE_BUFSIZ + 1);
-
- if (DTRACE_ENABLED(user_trace_s1)) {
- if (!enif_inspect_iolist_as_binary(env, argv[0], &message_bin) ||
- message_bin.size > MESSAGE_BUFSIZ) {
- return atom_badarg;
- }
- memcpy(messagebuf, (char *) message_bin.data, message_bin.size);
- messagebuf[message_bin.size] = '\0';
- DTRACE1(user_trace_s1, messagebuf);
- return atom_true;
- } else {
- return atom_false;
- }
+ return erl_nif_user_trace_s1(env, argc, argv);
#else
return atom_error;
#endif
}
-void
-get_string_maybe(ErlNifEnv *env,
- const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz)
+static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- ErlNifBinary str_bin;
-
- if (!enif_inspect_iolist_as_binary(env, term, &str_bin) ||
- str_bin.size > bufsiz) {
- *ptr = NULL;
- } else {
- memcpy(buf, (char *) str_bin.data, str_bin.size);
- buf[str_bin.size] = '\0';
- *ptr = buf;
- }
+#ifdef HAVE_USE_DTRACE
+ return erl_nif_user_trace_i4s4(env, argc, argv);
+#else
+ return atom_error;
+#endif
}
-static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM user_trace_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
#ifdef HAVE_USE_DTRACE
- DTRACE_CHARBUF(procbuf, 32 + 1);
- DTRACE_CHARBUF(user_tagbuf, MESSAGE_BUFSIZ + 1);
- char *utbuf = NULL;
- ErlNifSInt64 i1, i2, i3, i4;
- DTRACE_CHARBUF(messagebuf1, MESSAGE_BUFSIZ + 1);
- DTRACE_CHARBUF(messagebuf2, MESSAGE_BUFSIZ + 1);
- DTRACE_CHARBUF(messagebuf3, MESSAGE_BUFSIZ + 1);
- DTRACE_CHARBUF(messagebuf4, MESSAGE_BUFSIZ + 1);
- char *mbuf1 = NULL, *mbuf2 = NULL, *mbuf3 = NULL, *mbuf4 = NULL;
-
- if (DTRACE_ENABLED(user_trace_i4s4)) {
- dtrace_nifenv_str(env, procbuf);
- get_string_maybe(env, argv[0], &utbuf, user_tagbuf, MESSAGE_BUFSIZ);
- if (! enif_get_int64(env, argv[1], &i1))
- i1 = 0;
- if (! enif_get_int64(env, argv[2], &i2))
- i2 = 0;
- if (! enif_get_int64(env, argv[3], &i3))
- i3 = 0;
- if (! enif_get_int64(env, argv[4], &i4))
- i4 = 0;
- get_string_maybe(env, argv[5], &mbuf1, messagebuf1, MESSAGE_BUFSIZ);
- get_string_maybe(env, argv[6], &mbuf2, messagebuf2, MESSAGE_BUFSIZ);
- get_string_maybe(env, argv[7], &mbuf3, messagebuf3, MESSAGE_BUFSIZ);
- get_string_maybe(env, argv[8], &mbuf4, messagebuf4, MESSAGE_BUFSIZ);
- DTRACE10(user_trace_i4s4, procbuf, utbuf,
- i1, i2, i3, i4, mbuf1, mbuf2, mbuf3, mbuf4);
- return atom_true;
- } else {
- return atom_false;
- }
+ return erl_nif_user_trace_n(env, argc, argv);
#else
return atom_error;
#endif
diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c
index 7f7ab8dd9d..6b77128761 100644
--- a/lib/runtime_tools/c_src/trace_ip_drv.c
+++ b/lib/runtime_tools/c_src/trace_ip_drv.c
@@ -590,8 +590,8 @@ static void *my_alloc(size_t size)
void *ret;
if ((ret = driver_alloc(size)) == NULL) {
/* May or may not work... */
- fprintf(stderr, "Could not allocate %d bytes of memory in %s.",
- (int) size, __FILE__);
+ fprintf(stderr, "Could not allocate %lu bytes of memory in %s.",
+ (unsigned long) size, __FILE__);
exit(1);
}
return ret;
@@ -605,8 +605,8 @@ static ErlDrvBinary *my_alloc_binary(int size)
ErlDrvBinary *ret;
if ((ret = driver_alloc_binary(size)) == NULL) {
/* May or may not work... */
- fprintf(stderr, "Could not allocate a binary of %d bytes in %s.",
- (int) size, __FILE__);
+ fprintf(stderr, "Could not allocate a binary of %lu bytes in %s.",
+ (unsigned long) size, __FILE__);
exit(1);
}
return ret;
diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile
index c67f7bd1f6..d240b287c3 100644
--- a/lib/runtime_tools/doc/src/Makefile
+++ b/lib/runtime_tools/doc/src/Makefile
@@ -108,16 +108,16 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/runtime_tools/examples/user-probe-n.d b/lib/runtime_tools/examples/user-probe-n.d
new file mode 100644
index 0000000000..06a3e5c9b9
--- /dev/null
+++ b/lib/runtime_tools/examples/user-probe-n.d
@@ -0,0 +1,44 @@
+/* example usage: dtrace -q -s /path/to/user-probe.d */
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Scott Lystig Fritchie 2011-2012. 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%
+ */
+
+erlang*:::user_trace-n0
+{
+ printf("probe n0: %s %s %d %d %d %d '%s' '%s' '%s' '%s'\n",
+ copyinstr(arg0),
+ arg1 == NULL ? "" : copyinstr(arg1),
+ arg2, arg3, arg4, arg5,
+ arg6 == NULL ? "" : copyinstr(arg6),
+ arg7 == NULL ? "" : copyinstr(arg7),
+ arg8 == NULL ? "" : copyinstr(arg8),
+ arg9 == NULL ? "" : copyinstr(arg9));
+}
+
+erlang*:::user_trace-n1
+{
+ printf("probe n1: %s %s %d %d %d %d '%s' '%s' '%s' '%s'\n",
+ copyinstr(arg0),
+ arg1 == NULL ? "" : copyinstr(arg1),
+ arg2, arg3, arg4, arg5,
+ arg6 == NULL ? "" : copyinstr(arg6),
+ arg7 == NULL ? "" : copyinstr(arg7),
+ arg8 == NULL ? "" : copyinstr(arg8),
+ arg9 == NULL ? "" : copyinstr(arg9));
+}
+
diff --git a/lib/runtime_tools/examples/user-probe-n.systemtap b/lib/runtime_tools/examples/user-probe-n.systemtap
new file mode 100644
index 0000000000..6aa415bb67
--- /dev/null
+++ b/lib/runtime_tools/examples/user-probe-n.systemtap
@@ -0,0 +1,53 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011-2012. 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%
+ */
+/*
+ * Note: This file assumes that you're using the non-SMP-enabled Erlang
+ * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note that other variations of the virtual machine also have
+ * different names, e.g. the debug build of the SMP-enabled VM
+ * is "beam.debug.smp".
+ *
+ * To use a different virtual machine, replace each instance of
+ * "beam" with "beam.smp" or the VM name appropriate to your
+ * environment.
+ */
+
+probe process("beam").mark("user_trace-n0")
+{
+ printf("probe n0: %s %s %d %d %d %d '%s' '%s' '%s' '%s'\n",
+ user_string($arg1),
+ $arg2 == NULL ? "" : user_string($arg2),
+ $arg3, $arg4, $arg5, $arg6,
+ $arg7 == NULL ? "" : user_string($arg7),
+ $arg8 == NULL ? "" : user_string($arg8),
+ $arg9 == NULL ? "" : user_string($arg9),
+ $arg9 == NULL ? "" : user_string($arg9));
+}
+
+probe process("beam").mark("user_trace-n1")
+{
+ printf("probe n1: %s %s %d %d %d %d '%s' '%s' '%s' '%s'\n",
+ user_string($arg1),
+ $arg2 == NULL ? "" : user_string($arg2),
+ $arg3, $arg4, $arg5, $arg6,
+ $arg7 == NULL ? "" : user_string($arg7),
+ $arg8 == NULL ? "" : user_string($arg8),
+ $arg9 == NULL ? "" : user_string($arg9),
+ $arg9 == NULL ? "" : user_string($arg9));
+}
diff --git a/lib/runtime_tools/examples/user-probe.systemtap b/lib/runtime_tools/examples/user-probe.systemtap
index b41d7483ad..0482235324 100644
--- a/lib/runtime_tools/examples/user-probe.systemtap
+++ b/lib/runtime_tools/examples/user-probe.systemtap
@@ -28,12 +28,12 @@
* environment.
*/
-probe process("dyntrace.so").mark("user_trace-s1")
+probe process("beam").mark("user_trace-s1")
{
printf("%s\n", user_string($arg1));
}
-probe process("dyntrace.so").mark("user_trace-i4s4")
+probe process("beam").mark("user_trace-i4s4")
{
printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n",
user_string($arg1),
diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile
index cb302b79c2..810e3e8741 100644
--- a/lib/runtime_tools/src/Makefile
+++ b/lib/runtime_tools/src/Makefile
@@ -99,14 +99,14 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(EXAMPLE_FILES) "$(RELSYSDIR)/examples"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/runtime_tools/src/dyntrace.erl b/lib/runtime_tools/src/dyntrace.erl
index 388c7679b9..b4579fd5ce 100644
--- a/lib/runtime_tools/src/dyntrace.erl
+++ b/lib/runtime_tools/src/dyntrace.erl
@@ -6,23 +6,22 @@
%%% work on any operating system platform where user-space DTrace/Systemtap
%%% (and in the future LttNG UST) probes are supported.
%%%
-%%% Use the `dyntrace:init()' function to load the NIF shared library and
-%%% to initialize library's private state.
-%%%
%%% It is recommended that you use the `dyntrace:p()' function to add
%%% Dynamic trace probes to your Erlang code. This function can accept up to
%%% four integer arguments and four string arguments; the integer
-%%% argument(s) must come before any string argument. For example:
+%%% argument(s) must come before any string argument.
+%%%
+%%% If using DTrace, enable the dynamic trace probe using the 'dtrace'
+%%% command, for example:
+%%%
+%%% dtrace -s /your/path/to/lib/runtime_tools-1.8.7/examples/user-probe.d
+%%%
+%%% Then, back at the Erlang shell, try this example:
%%% ```
%%% 1> dyntrace:put_tag("GGOOOAAALL!!!!!").
%%% true
-%%% 2> dyntrace:init().
-%%% ok
-%%%
-%%% % % % If using dtrace, enable the Dynamic trace probe using the 'dtrace'
-%%% % % % command.
%%%
-%%% 3> dyntrace:p(7, 8, 9, "one", "four").
+%%% 2> dyntrace:p(7, 8, 9, "one", "four").
%%% true
%%% '''
%%%
@@ -38,15 +37,16 @@
-export([available/0,
user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4
- p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]).
+ p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8,
+ pn/1, pn/2, pn/3, pn/4, pn/5, pn/6, pn/7, pn/8, pn/9]).
-export([put_tag/1, get_tag/0, get_tag_data/0, spread_tag/1, restore_tag/1]).
--export([scaff/0]). % Development only
-export([user_trace_i4s4/9]). % Know what you're doing!
-on_load(on_load/0).
-type probe_arg() :: integer() | iolist().
-type int_p_arg() :: integer() | iolist() | undef.
+-type n_probe_label() :: 0..1023.
%% The *_maybe() types use atom() instead of a stricter 'undef'
%% because user_trace_i4s4/9 is exposed to the outside world, and
@@ -115,6 +115,16 @@ user_trace_s1(_Message) ->
user_trace_i4s4(_, _, _, _, _, _, _, _, _) ->
erlang:nif_error(nif_not_loaded).
+-spec user_trace_n(n_probe_label(), iolist(),
+ integer_maybe(), integer_maybe(),
+ integer_maybe(), integer_maybe(),
+ iolist_maybe(), iolist_maybe(),
+ iolist_maybe(), iolist_maybe()) ->
+ true | false | error | badarg.
+
+user_trace_n(_, _, _, _, _, _, _, _, _, _) ->
+ erlang:nif_error(nif_not_loaded).
+
%%%
%%% Erlang support functions
%%%
@@ -218,6 +228,106 @@ user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) ->
false
end.
+-spec pn(n_probe_label()) -> true | false | error | badarg.
+
+pn(ProbeLabel) ->
+ user_trace_n_int(ProbeLabel, undef, undef, undef, undef, undef, undef, undef, undef).
+
+-spec pn(n_probe_label(), probe_arg()) -> true | false | error | badarg.
+
+pn(ProbeLabel, I1) when is_integer(I1) ->
+ user_trace_n_int(ProbeLabel, I1, undef, undef, undef, undef, undef, undef, undef);
+pn(ProbeLabel, S1) ->
+ user_trace_n_int(ProbeLabel, undef, undef, undef, undef, S1, undef, undef, undef).
+
+-spec pn(n_probe_label(), probe_arg(), probe_arg()) -> true | false | error | badarg.
+
+pn(ProbeLabel, I1, I2) when is_integer(I1), is_integer(I2) ->
+ user_trace_n_int(ProbeLabel, I1, I2, undef, undef, undef, undef, undef, undef);
+pn(ProbeLabel, I1, S1) when is_integer(I1) ->
+ user_trace_n_int(ProbeLabel, I1, undef, undef, undef, S1, undef, undef, undef);
+pn(ProbeLabel, S1, S2) ->
+ user_trace_n_int(ProbeLabel, undef, undef, undef, undef, S1, S2, undef, undef).
+
+-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg.
+
+pn(ProbeLabel, I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, undef, undef, undef, undef, undef);
+pn(ProbeLabel, I1, I2, S1) when is_integer(I1), is_integer(I2) ->
+ user_trace_n_int(ProbeLabel, I1, I2, undef, undef, S1, undef, undef, undef);
+pn(ProbeLabel, I1, S1, S2) when is_integer(I1) ->
+ user_trace_n_int(ProbeLabel, I1, undef, undef, undef, S1, S2, undef, undef);
+pn(ProbeLabel, S1, S2, S3) ->
+ user_trace_n_int(ProbeLabel, undef, undef, undef, undef, S1, S2, S3, undef).
+
+-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg()) ->
+ true | false | error | badarg.
+
+pn(ProbeLabel, I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, I4, undef, undef, undef, undef);
+pn(ProbeLabel, I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, undef, S1, undef, undef, undef);
+pn(ProbeLabel, I1, I2, S1, S2) when is_integer(I1), is_integer(I2) ->
+ user_trace_n_int(ProbeLabel, I1, I2, undef, undef, S1, S2, undef, undef);
+pn(ProbeLabel, I1, S1, S2, S3) when is_integer(I1) ->
+ user_trace_n_int(ProbeLabel, I1, undef, undef, undef, S1, S2, S3, undef);
+pn(ProbeLabel, S1, S2, S3, S4) ->
+ user_trace_n_int(ProbeLabel, undef, undef, undef, undef, S1, S2, S3, S4).
+
+-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg(),
+ probe_arg()) ->
+ true | false | error | badarg.
+
+pn(ProbeLabel, I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, undef, undef, undef);
+pn(ProbeLabel, I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, undef, S1, S2, undef, undef);
+pn(ProbeLabel, I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) ->
+ user_trace_n_int(ProbeLabel, I1, I2, undef, undef, S1, S2, S3, undef);
+pn(ProbeLabel, I1, S1, S2, S3, S4) when is_integer(I1) ->
+ user_trace_n_int(ProbeLabel, I1, undef, undef, undef, S1, S2, S3, S4).
+
+-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg(),
+ probe_arg(), probe_arg()) ->
+ true | false | error | badarg.
+
+pn(ProbeLabel, I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, S2, undef, undef);
+pn(ProbeLabel, I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, undef, S1, S2, S3, undef);
+pn(ProbeLabel, I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) ->
+ user_trace_n_int(ProbeLabel, I1, I2, undef, undef, S1, S2, S3, S4).
+
+-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg(),
+ probe_arg(), probe_arg(), probe_arg()) ->
+ true | false | error | badarg.
+
+pn(ProbeLabel, I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, S2, S3, undef);
+pn(ProbeLabel, I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, undef, S1, S2, S3, S4).
+
+-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg(),
+ probe_arg(), probe_arg(), probe_arg(), probe_arg()) ->
+ true | false | error | badarg.
+
+pn(ProbeLabel, I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) ->
+ user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, S2, S3, S4).
+
+-spec user_trace_n_int(n_probe_label(),
+ int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(),
+ int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) ->
+ true | false | error | badarg.
+
+user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, S2, S3, S4) ->
+ UTag = get_tag(),
+ try
+ user_trace_n(ProbeLabel, UTag, I1, I2, I3, I4, S1, S2, S3, S4)
+ catch
+ error:nif_not_loaded ->
+ false
+ end.
+
-spec put_tag(undefined | iodata()) -> binary() | undefined.
put_tag(Data) ->
erlang:dt_put_tag(unicode:characters_to_binary(Data)).
@@ -240,40 +350,3 @@ spread_tag(B) ->
-spec restore_tag(true | {non_neg_integer(), binary() | []}) -> true.
restore_tag(T) ->
erlang:dt_restore_tag(T).
-
-
-%% Scaffolding to write tedious code: quick brute force and not 100% correct.
-
-scaff_int_args(N) ->
- L = lists:sublist(["I1", "I2", "I3", "I4"], N),
- [string:join(L, ", ")].
-
-scaff_int_guards(N) ->
- L = lists:sublist(["is_integer(I1)", "is_integer(I2)", "is_integer(I3)",
- "is_integer(I4)"], N),
- lists:flatten(string:join(L, ", ")).
-
-scaff_char_args(N) ->
- L = lists:sublist(["S1", "S2", "S3", "S4"], N),
- [string:join(L, ", ")].
-
-scaff_fill(N) ->
- [string:join(lists:duplicate(N, "undef"), ", ")].
-
-scaff() ->
- L = [begin
- IntArgs = scaff_int_args(N_int),
- IntGuards = scaff_int_guards(N_int),
- IntFill = scaff_fill(4 - N_int),
- CharArgs = scaff_char_args(N_char),
- CharFill = scaff_fill(4 - N_char),
- InArgs = string:join(IntArgs ++ CharArgs, ", "),
- OutArgs = string:join(IntArgs ++ IntFill ++ CharArgs ++ CharFill,
- ", "),
- {N_int + N_char,
- lists:flatten([io_lib:format("p(~s) when ~s ->\n",
- [InArgs, IntGuards]),
- io_lib:format(" user_trace_int(~s);\n", [OutArgs])
- ])}
- end || N_int <- [0,1,2,3,4], N_char <- [0,1,2,3,4]],
- [io:format("%%~p\n~s", [N, Str]) || {N, Str} <- lists:sort(L)].
diff --git a/lib/runtime_tools/test/Makefile b/lib/runtime_tools/test/Makefile
index 3e50ba02ca..4979b9c7b1 100644
--- a/lib/runtime_tools/test/Makefile
+++ b/lib/runtime_tools/test/Makefile
@@ -57,10 +57,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
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 -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) runtime_tools.spec runtime_tools.cover $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(EMAKEFILE) runtime_tools.cover "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/sasl/doc/src/Makefile b/lib/sasl/doc/src/Makefile
index eb880ccb78..b0ec671adc 100644
--- a/lib/sasl/doc/src/Makefile
+++ b/lib/sasl/doc/src/Makefile
@@ -116,18 +116,18 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man4
- $(INSTALL_DATA) $(MAN4_FILES) $(RELEASE_PATH)/man/man4
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man4"
+ $(INSTALL_DATA) $(MAN4_FILES) "$(RELEASE_PATH)/man/man4"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/sasl/examples/src/Makefile b/lib/sasl/examples/src/Makefile
index 9cf0d4c25d..47c8626205 100644
--- a/lib/sasl/examples/src/Makefile
+++ b/lib/sasl/examples/src/Makefile
@@ -63,10 +63,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples/src
- $(INSTALL_DIR) $(RELSYSDIR)/examples/ebin
- (cd ..; tar cf - src ebin | (cd $(RELSYSDIR)/examples; tar xf -))
- chmod -R ug+w $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/ebin"
+ (cd ..; tar cf - src ebin | (cd "$(RELSYSDIR)/examples"; tar xf -))
+ chmod -R ug+w "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/sasl/src/Makefile b/lib/sasl/src/Makefile
index 9a5d1e42d9..cae8146ebc 100644
--- a/lib/sasl/src/Makefile
+++ b/lib/sasl/src/Makefile
@@ -91,10 +91,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile
index 91a8c42484..bb3f82f411 100644
--- a/lib/sasl/test/Makefile
+++ b/lib/sasl/test/Makefile
@@ -85,10 +85,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cfh - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cfh - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl
index 6942ec21ea..634218e3fb 100644
--- a/lib/sasl/test/installer.erl
+++ b/lib/sasl/test/installer.erl
@@ -876,7 +876,9 @@ trace_disallowed_calls(Node) ->
MasterProc = self(),
rpc:call(Node,dbg,tracer,[process,{fun(T,_) -> MasterProc ! T end,[]}]),
rpc:call(Node,dbg,p,[all,call]),
- rpc:call(Node,dbg,tp,[file,[{'_',[],[{message,{caller}}]}]]).
+ rpc:call(Node,dbg,tp,[file,[{'_',[],[{message,{caller}}]}]]),
+ %% File:native_name_encoding/0 is a BIF and OK to use
+ rpc:call(Node,dbg,ctp,[file,native_name_encoding,0]).
check_disallowed_calls(TestNode,Line) ->
receive
diff --git a/lib/snmp/doc/src/Makefile b/lib/snmp/doc/src/Makefile
index 8645886590..6c58ae994a 100644
--- a/lib/snmp/doc/src/Makefile
+++ b/lib/snmp/doc/src/Makefile
@@ -170,20 +170,20 @@ $(MAN1DIR)/snmpc.1: snmpc_cmd.xml
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man1
- $(INSTALL_DATA) $(MAN1DIR)/* $(RELEASE_PATH)/man/man1
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6DIR)/* $(RELEASE_PATH)/man/man6
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man7
- $(INSTALL_DATA) $(MAN7DIR)/* $(RELEASE_PATH)/man/man7
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DATA) $(MAN1DIR)/* "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6DIR)/* "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man7"
+ $(INSTALL_DATA) $(MAN7DIR)/* "$(RELEASE_PATH)/man/man7"
release_spec:
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 2d045faa0f..442837d57d 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -34,6 +34,98 @@
<section>
+ <title>SNMP Development Toolkit 4.22.1</title>
+ <p>Version 4.22.1 supports code replacement in runtime from/to
+ version 4.22, 4.21.7 4.21.6 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1 and
+ 4.21. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Sematic fixes to SNMP-USER-BASED-SM-MIB.
+ The semantics allow the <c>usmUserAuthKeyChange</c> and
+ <c>usmUserPrivKeyChange</c> objects to be written to in the
+ same set requests that also creates and clones the user.
+ This was not possible beforehand, causing test tools checking
+ semantic SNMPv3 behaviour to fail on a lot of test cases. </p>
+ <p>Furthermore, once the user has been cloned by writing to an
+ instance of <c>usmUserCloneFrom</c>, further set-operations to
+ the same object will not return an error, but be no-ops.
+ Especially, it must be avoided to copy security parameters
+ again (possibly even from a different user). </p>
+ <p>Stefan Zegenhagen</p>
+ <p>Own Id: OTP-10166</p>
+ </item>
+
+ <item>
+ <p>[agent] Errors in <c>vacmAccessTable</c> RowStatus handling.
+ There are problems with the handling of vacmAccessTableStatus
+ that cause some SNMP test suites to report errors.
+ Most notably, erroneous set operations frequently cause "genErr"
+ errors to be returned. These "genErr" errors are usually caused
+ by badmatch exceptions coming from
+ <c>{ok, Row} = snmpa_vacm:get_row(RowIndex)</c>
+ if the row does not exist. </p>
+ <p>The semantics of the RowStatus handling in that table has
+ been adjusted to be compliant with the RowStatus
+ textual description of SNPMv2-TC MIB. </p>
+ <p>Stefan Zegenhagen</p>
+ <p>Own Id: OTP-10164</p>
+ </item>
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Fix walk over vacmAccessTable.
+ Fix the get_next implementation of vacmAccessTable to
+ return all table entries. </p>
+ <p>The get_next implementation of vacmAccessTable did not return
+ all available table data. Instead, it only returned the first
+ column for each row, and all columns for the last row available. </p>
+ <p>Stefan Zegenhagen</p>
+ <p>Own Id: OTP-10165</p>
+ </item>
+
+ <item>
+ <p>[manager]
+ <seealso marker="snmpm#log_to_io">snmpm:log_to_io/6</seealso>
+ did not use the LogName argument. </p>
+ <p>Own Id: OTP-10066</p>
+ </item>
+
+ <item>
+ <p>Incorrect TimeTicks decode. Also bad handling of
+ invalid encode (value outside of value range) for both
+ <c>TimeTicks</c> and <c>Unsigned32</c>. </p>
+ <p>Own Id: OTP-10132</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ </section> <!-- 4.22.1 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.22</title>
<p>Version 4.22 supports code replacement in runtime from/to
version 4.21.7 4.21.6 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1 and 4.21. </p>
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
index 340f2f1fa7..eec53162a1 100644
--- a/lib/snmp/doc/src/snmp_config.xml
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -963,7 +963,8 @@ Manager snmp config:
7b. User name? hobbes
7c. Security name? [hobbes]
7d. Authentication protocol (no/sha/md5)? [no] sha
-7e Authentication [sha] key (length 0 or 20)? [""] [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
+7e Authentication [sha] key (length 0 or 20)? [""] [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+ 17,18,19,20]
7d. Priv protocol (no/des/aes)? [no] des
7f Priv [des] key (length 0 or 16)? [""] 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25
7. Configure an usm user handled by this manager (y/n)? [y] n
diff --git a/lib/snmp/doc/src/snmpa_network_interface_filter.xml b/lib/snmp/doc/src/snmpa_network_interface_filter.xml
index 10419517dd..84953c5270 100644
--- a/lib/snmp/doc/src/snmpa_network_interface_filter.xml
+++ b/lib/snmp/doc/src/snmpa_network_interface_filter.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
@@ -84,7 +84,9 @@
<title>DATA TYPES</title>
<code type="none">
port() = integer() > 0
-pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | 'set-request' | trap | 'get-bulk-request' | 'inform-request' | report
+pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
+ 'set-request' | trap | 'get-bulk-request' | 'inform-request' |
+ report
</code>
<marker id="accept_recv"></marker>
</section>
diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml
index 9bbb6cdbdb..8ab3be8e18 100644
--- a/lib/snmp/doc/src/snmpm.xml
+++ b/lib/snmp/doc/src/snmpm.xml
@@ -173,16 +173,16 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv
</type>
<desc>
<p>Register the manager entity (=user) responsible for specific
- agent(s). </p>
+ agent(s). </p>
<p><c>Module</c> is the callback module (snmpm_user behaviour) which
- will be called whenever something happens (detected
- agent, incoming reply or incoming trap/notification).
- Note that this could have already been done as a
- consequence of the node config. (see users.conf).</p>
+ will be called whenever something happens (detected
+ agent, incoming reply or incoming trap/notification).
+ Note that this could have already been done as a
+ consequence of the node config. (see users.conf).</p>
- <p>The argument <c>DefaultAgentConfig</c> is used as default values when
- this user register agents.</p>
+ <p>The argument <c>DefaultAgentConfig</c> is used as default
+ values when this user register agents.</p>
<p>The type of <c>Val</c> depends on <c>Item</c>: </p>
<code type="none"><![CDATA[
diff --git a/lib/snmp/doc/src/snmpm_network_interface_filter.xml b/lib/snmp/doc/src/snmpm_network_interface_filter.xml
index 5f80cec94e..4dc133dd71 100644
--- a/lib/snmp/doc/src/snmpm_network_interface_filter.xml
+++ b/lib/snmp/doc/src/snmpm_network_interface_filter.xml
@@ -82,7 +82,9 @@
<title>DATA TYPES</title>
<code type="none">
port() = integer() > 0
-pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | 'set-request' | trap | 'get-bulk-request' | 'inform-request' | report | trappdu
+pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
+ 'set-request' | trap | 'get-bulk-request' | 'inform-request' |
+ report | trappdu
</code>
<marker id="accept_recv"></marker>
</section>
diff --git a/lib/snmp/examples/ex1/Makefile b/lib/snmp/examples/ex1/Makefile
index 1a55ba0470..996b686e0e 100644
--- a/lib/snmp/examples/ex1/Makefile
+++ b/lib/snmp/examples/ex1/Makefile
@@ -46,7 +46,7 @@ ERL_COMPILE_FLAGS += -I../include \
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
-EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples
+EXAMPLE_RELSYSDIR = "$(RELSYSDIR)/examples"
EX1_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/ex1
# ----------------------------------------------------
diff --git a/lib/snmp/examples/ex2/Makefile b/lib/snmp/examples/ex2/Makefile
index 7fbd7f530b..090b9274d4 100644
--- a/lib/snmp/examples/ex2/Makefile
+++ b/lib/snmp/examples/ex2/Makefile
@@ -47,7 +47,7 @@ ERL_COMPILE_FLAGS += -I../include \
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
-EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples
+EXAMPLE_RELSYSDIR = "$(RELSYSDIR)/examples"
EX2_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/ex2
# ----------------------------------------------------
diff --git a/lib/snmp/mibs/Makefile.in b/lib/snmp/mibs/Makefile.in
index 993a67c6f2..c74c0b2ac4 100644
--- a/lib/snmp/mibs/Makefile.in
+++ b/lib/snmp/mibs/Makefile.in
@@ -211,7 +211,7 @@ info:
@echo ""
@echo "SNMP_VSN = $(SNMP_VSN)"
@echo "VSN = $(VSN)"
- @echo "RELSYSDIR = $(RELSYSDIR)"
+ @echo "RELSYSDIR = "$(RELSYSDIR)""
v1/%.mib.v1: %.mib $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
@@ -223,17 +223,17 @@ v1/%.mib.v1: %.mib $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/mibs
- $(INSTALL_DIR) $(RELSYSDIR)/mibs/v1
- $(INSTALL_DATA) $(MIB_FILES) $(RELSYSDIR)/mibs
- $(INSTALL_DATA) $(STD_v2_MIB_FILES) $(RELSYSDIR)/mibs
- $(INSTALL_DATA) $(FUNCS_FILES) $(RELSYSDIR)/mibs
- $(INSTALL_DATA) $(STD_v1_MIB_FILES) $(RELSYSDIR)/mibs/v1
- $(INSTALL_DATA) $(V1_MIB_FILES) $(RELSYSDIR)/mibs/v1
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/priv/mibs
- $(INSTALL_DATA) $(BIN_TARGETS) $(RELSYSDIR)/priv/mibs
+ $(INSTALL_DIR) "$(RELSYSDIR)/mibs"
+ $(INSTALL_DIR) "$(RELSYSDIR)/mibs/v1"
+ $(INSTALL_DATA) $(MIB_FILES) "$(RELSYSDIR)/mibs"
+ $(INSTALL_DATA) $(STD_v2_MIB_FILES) "$(RELSYSDIR)/mibs"
+ $(INSTALL_DATA) $(FUNCS_FILES) "$(RELSYSDIR)/mibs"
+ $(INSTALL_DATA) $(STD_v1_MIB_FILES) "$(RELSYSDIR)/mibs/v1"
+ $(INSTALL_DATA) $(V1_MIB_FILES) "$(RELSYSDIR)/mibs/v1"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/mibs"
+ $(INSTALL_DATA) $(BIN_TARGETS) "$(RELSYSDIR)/priv/mibs"
release_docs_spec:
diff --git a/lib/snmp/priv/conf/agent/Makefile b/lib/snmp/priv/conf/agent/Makefile
index ee3a915c2b..c7921bacc2 100644
--- a/lib/snmp/priv/conf/agent/Makefile
+++ b/lib/snmp/priv/conf/agent/Makefile
@@ -55,9 +55,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/conf
- $(INSTALL_DIR) $(RELSYSDIR)/priv/conf/agent
- $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/priv/conf/agent
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/conf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/conf/agent"
+ $(INSTALL_DATA) $(CONF_FILES) "$(RELSYSDIR)/priv/conf/agent"
release_docs_spec:
diff --git a/lib/snmp/priv/conf/manager/Makefile b/lib/snmp/priv/conf/manager/Makefile
index 16355f0ff3..ba5a74c3fe 100644
--- a/lib/snmp/priv/conf/manager/Makefile
+++ b/lib/snmp/priv/conf/manager/Makefile
@@ -55,9 +55,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/conf
- $(INSTALL_DIR) $(RELSYSDIR)/priv/conf/manager
- $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/priv/conf/manager
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/conf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/conf/manager"
+ $(INSTALL_DATA) $(CONF_FILES) "$(RELSYSDIR)/priv/conf/manager"
release_docs_spec:
diff --git a/lib/snmp/src/agent/Makefile b/lib/snmp/src/agent/Makefile
index a67fe4d17c..9a982edf91 100644
--- a/lib/snmp/src/agent/Makefile
+++ b/lib/snmp/src/agent/Makefile
@@ -128,14 +128,14 @@ info:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/agent
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/agent
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/agent"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/agent"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
- $(RELSYSDIR)/ebin
-# $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+ "$(RELSYSDIR)/ebin"
+# $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
index 2e801622e7..3c4ba1af66 100644
--- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
+++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
@@ -54,6 +54,7 @@
%% Columns not accessible via SNMP
-define(usmUserAuthKey, 14).
-define(usmUserPrivKey, 15).
+-define(is_cloning, 16).
%%%-----------------------------------------------------------------
@@ -564,7 +565,9 @@ usmUserTable(set, RowIndex, Cols0) ->
{ok, Cols} ->
?vtrace("usmUserTable(set) -> verified"
"~n Cols: ~p", [Cols]),
- NCols = pre_set(RowIndex, Cols),
+ % check whether we're cloning. if so, get cloned params and add a few
+ % defaults that might be needed.
+ NCols = pre_set(RowIndex, validate_clone_from(RowIndex, Cols)),
?vtrace("usmUserTable(set) -> pre-set: "
"~n NCols: ~p", [NCols]),
%% NOTE: The NCols parameter is sent to snmp_generic, but not to
@@ -730,30 +733,40 @@ validate_is_set_ok(Error, _RowIndex, _Cols) ->
Error.
do_validate_is_set_ok(RowIndex, Cols) ->
- validate_clone_from(RowIndex, Cols),
- validate_auth_protocol(RowIndex, Cols),
- validate_auth_key_change(RowIndex, Cols),
- validate_own_auth_key_change(RowIndex, Cols),
- validate_priv_protocol(RowIndex, Cols),
- validate_priv_key_change(RowIndex, Cols),
- validate_own_priv_key_change(RowIndex, Cols),
+ NCols = validate_clone_from(RowIndex, Cols),
+ validate_auth_protocol(RowIndex, NCols),
+ validate_auth_key_change(RowIndex, NCols),
+ validate_own_auth_key_change(RowIndex, NCols),
+ validate_priv_protocol(RowIndex, NCols),
+ validate_priv_key_change(RowIndex, NCols),
+ validate_own_priv_key_change(RowIndex, NCols),
ok.
pre_set(RowIndex, Cols) ->
+ %% Remove the ?is_cloning member again; it must no longer be
+ %% present.
+ Cols0 = key1delete(?is_cloning, Cols),
%% Possibly initialize the usmUserSecurityName and privacy keys
case snmp_generic:table_row_exists(db(usmUserTable), RowIndex) of
- true -> Cols;
+ true -> Cols0;
false ->
SecName = get_user_name(RowIndex),
- [{?usmUserSecurityName, SecName} | Cols] ++
- [{?usmUserAuthKey, ""},
- {?usmUserPrivKey, ""}]
+ Cols1 = [{?usmUserSecurityName, SecName} | Cols0],
+ case proplists:get_value(?is_cloning, Cols) of
+ true ->
+ % the row is just being cloned. the cloned user's
+ % passwords are already present in Cols and must
+ % not be overwritten.
+ Cols1;
+ _ ->
+ Cols1 ++ [{?usmUserAuthKey, ""},
+ {?usmUserPrivKey, ""}]
+ end
end.
validate_set({noError, 0}, RowIndex, Cols) ->
%% Now, all is_set_ok validation steps have been executed. So
%% everything is ready for the set.
- set_clone_from(RowIndex, Cols),
set_auth_key_change(RowIndex, Cols),
set_own_auth_key_change(RowIndex, Cols),
set_priv_key_change(RowIndex, Cols),
@@ -769,7 +782,7 @@ validate_set(Error, _RowIndex, _Cols) ->
%% no further checks.
%%-----------------------------------------------------------------
validate_clone_from(RowIndex, Cols) ->
- case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
+ case key1search(?usmUserCloneFrom, Cols) of
{value, {_Col, RowPointer}} ->
RowIndex2 = extract_row(RowPointer),
OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
@@ -778,35 +791,63 @@ validate_clone_from(RowIndex, Cols) ->
case OldCloneFrom of
{value, Val} when Val /= noinit ->
%% This means that the cloning is already done...
- ok;
+ no_cloning(Cols);
_ ->
- %% Otherwise, we must check the CloneFrom value
- case snmp_generic:table_get_element(db(usmUserTable),
- RowIndex2,
- ?usmUserStatus) of
- {value, ?'RowStatus_active'} -> ok;
- _ -> inconsistentName(?usmUserCloneFrom)
- end
+ %% Otherwise, we must check the CloneFrom value. It
+ %% must relate to a usmUserEntry that exists and is active.
+ case snmp_generic:table_get_row(db(usmUserTable), RowIndex2) of
+ CloneFromRow when is_tuple(CloneFromRow) ->
+ case element(?usmUserStatus, CloneFromRow) of
+ ?'RowStatus_active' ->
+ get_cloned_cols(CloneFromRow, Cols);
+ _ ->
+ inconsistentName(?usmUserCloneFrom)
+ end;
+ undefined ->
+ inconsistentName(?usmUserCloneFrom)
+ end
end;
false ->
- ok
+ % no ?usmUserCloneFrom specified, don't modify columns
+ no_cloning(Cols)
end.
+get_cloned_cols(CloneFromRow, Cols) ->
+ % initialize cloned columns with data from CloneFromRow
+ % and overwrite that again with data found in Cols
+ AuthP = element(?usmUserAuthProtocol, CloneFromRow),
+ PrivP = element(?usmUserPrivProtocol, CloneFromRow),
+ AuthK = element(?usmUserAuthKey, CloneFromRow),
+ PrivK = element(?usmUserPrivKey, CloneFromRow),
+ ClonedCols = [{?usmUserAuthProtocol, AuthP},
+ {?usmUserPrivProtocol, PrivP},
+ {?usmUserAuthKey, AuthK},
+ {?usmUserPrivKey, PrivK},
+ {?is_cloning, true}
+ ],
+ Func = fun({Col, _} = Item, NCols) ->
+ key1store(Col, NCols, Item)
+ end,
+ Cols1 = lists:foldl(Func, ClonedCols, Cols),
+ key1sort(Cols1).
+
+no_cloning(Cols0) ->
+ Cols1 = key1delete(?usmUserCloneFrom, Cols0),
+ key1delete(?is_cloning, Cols1).
+
validate_auth_protocol(RowIndex, Cols) ->
- case lists:keysearch(?usmUserAuthProtocol, 1, Cols) of
+ case key1search(?usmUserAuthProtocol, Cols) of
{value, {_Col, AuthProtocol}} ->
- %% Check if the row has been cloned; we can't check the
+ %% Check if the row is being cloned; we can't check the
%% old value of authProtocol, because if the row was
%% createAndWaited, the default value would have been
%% written (usmNoAuthProtocol).
- OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
- RowIndex,
- ?usmUserCloneFrom),
- case OldCloneFrom of
- {value, Val} when Val /= noinit ->
- %% This means that the cloning is already done; set is ok
- %% if new protocol is usmNoAuthProtocol
+ IsCloning = proplists:get_value(?is_cloning, Cols, false),
+ if
+ not IsCloning ->
+ %% This means that the row is not being cloned right
+ %% now; set is ok if new protocol is usmNoAuthProtocol
case AuthProtocol of
?usmNoAuthProtocol ->
%% Check that the Priv protocl is noPriv
@@ -821,7 +862,7 @@ validate_auth_protocol(RowIndex, Cols) ->
_ ->
wrongValue(?usmUserAuthProtocol)
end;
- _ ->
+ true ->
%% Otherwise, check that the new protocol is known,
%% and that the system we're running supports the
%% hash function.
@@ -867,7 +908,7 @@ validate_own_priv_key_change(RowIndex, Cols) ->
%% Check that the requesting user is the same as the modified user
validate_requester(RowIndex, Cols, KeyChangeCol) ->
- case lists:keysearch(KeyChangeCol, 1, Cols) of
+ case key1search(KeyChangeCol, Cols) of
{value, _} ->
case get(sec_model) of % Check the securityModel in the request
?SEC_USM -> ok;
@@ -890,17 +931,14 @@ validate_requester(RowIndex, Cols, KeyChangeCol) ->
end.
validate_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
- case lists:keysearch(KeyChangeCol, 1, Cols) of
+ case key1search(KeyChangeCol, Cols) of
{value, {_Col, KeyC}} ->
%% Check if the row has been cloned; or if it is cloned in
%% this set-operation.
OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
RowIndex,
?usmUserCloneFrom),
- IsClonePresent = case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
- {value, _} -> true;
- false -> false
- end,
+ IsClonePresent = proplists:get_value(?is_cloning, Cols, false),
%% Set is ok if 1) the user already is created, 2) this is
%% a new user, which has been cloned, or is about to be
%% cloned.
@@ -912,7 +950,7 @@ validate_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
%% The user is cloned in this operation
ok;
_ ->
- %% The user doen't exist, or hasn't been cloned,
+ %% The user doesn't exist, or hasn't been cloned,
%% and is not cloned in this operation.
inconsistentName(KeyChangeCol)
end,
@@ -939,17 +977,15 @@ validate_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
end.
validate_priv_protocol(RowIndex, Cols) ->
- case lists:keysearch(?usmUserPrivProtocol, 1, Cols) of
+ case key1search(?usmUserPrivProtocol, Cols) of
{value, {_Col, PrivProtocol}} ->
%% Check if the row has been cloned; we can't check the
%% old value of privhProtocol, because if the row was
%% createAndWaited, the default value would have been
%% written (usmNoPrivProtocol).
- OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
- RowIndex,
- ?usmUserCloneFrom),
- case OldCloneFrom of
- {value, Val} when Val /= noinit ->
+ IsCloning = proplists:get_value(?is_cloning, Cols, false),
+ if
+ not IsCloning ->
%% This means that the cloning is already done; set is ok
%% if new protocol is usmNoPrivProtocol
case PrivProtocol of
@@ -962,7 +998,7 @@ validate_priv_protocol(RowIndex, Cols) ->
_ ->
wrongValue(?usmUserPrivProtocol)
end;
- _ ->
+ true ->
%% Otherwise, check that the new protocol is known,
%% and that the system we're running supports the
%% crypto function.
@@ -1005,31 +1041,6 @@ validate_priv_protocol(RowIndex, Cols) ->
end.
-set_clone_from(RowIndex, Cols) ->
- %% If CloneFrom is modified, do the cloning.
- case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
- {value, {_Col, RowPointer}} ->
- RowIndex2 = extract_row(RowPointer), % won't fail
- CloneRow = snmp_generic:table_get_row(db(usmUserTable), RowIndex2,
- foi(usmUserTable)),
- AuthP = element(?usmUserAuthProtocol, CloneRow),
- PrivP = element(?usmUserPrivProtocol, CloneRow),
- AuthK = element(?usmUserAuthKey, CloneRow),
- PrivK = element(?usmUserPrivKey, CloneRow),
- SCols = [{?usmUserAuthProtocol, AuthP},
- {?usmUserPrivProtocol, PrivP},
- {?usmUserAuthKey, AuthK},
- {?usmUserPrivKey, PrivK}],
- case snmp_generic:table_set_elements(db(usmUserTable),
- RowIndex,
- SCols) of
- true -> ok;
- false -> {commitFailed, ?usmUserCloneFrom}
- end;
- false ->
- ok
- end.
-
set_auth_key_change(RowIndex, Cols) ->
set_key_change(RowIndex, Cols, ?usmUserAuthKeyChange, auth).
@@ -1043,7 +1054,7 @@ set_own_priv_key_change(RowIndex, Cols) ->
set_key_change(RowIndex, Cols, ?usmUserOwnPrivKeyChange, priv).
set_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
- case lists:keysearch(KeyChangeCol, 1, Cols) of
+ case key1search(KeyChangeCol, Cols) of
{value, {_Col, KeyChange}} ->
KeyCol = case Type of
auth -> ?usmUserAuthKey;
@@ -1071,11 +1082,11 @@ extract_row([H | T], [H | T2]) -> extract_row(T, T2);
extract_row([], [?usmUserSecurityName | T]) -> T;
extract_row(_, _) -> wrongValue(?usmUserCloneFrom).
-%% Pre: the user exixt
+%% Pre: the user exists or is being cloned in this operation
get_auth_proto(RowIndex, Cols) ->
- %% The protocol can be chanegd by the request too, otherwise,
+ %% The protocol can be changed by the request too, otherwise,
%% check the stored protocol.
- case lists:keysearch(?usmUserAuthProtocol, 1, Cols) of
+ case key1search(?usmUserAuthProtocol, Cols) of
{value, {_, Protocol}} ->
Protocol;
false ->
@@ -1090,11 +1101,11 @@ get_auth_proto(RowIndex, Cols) ->
end
end.
-%% Pre: the user exixt
+%% Pre: the user exists or is being cloned in this operation
get_priv_proto(RowIndex, Cols) ->
- %% The protocol can be chanegd by the request too, otherwise,
+ %% The protocol can be changed by the request too, otherwise,
%% check the stored protocol.
- case lists:keysearch(?usmUserPrivProtocol, 1, Cols) of
+ case key1search(?usmUserPrivProtocol, Cols) of
{value, {_, Protocol}} ->
Protocol;
false ->
@@ -1232,6 +1243,27 @@ set_sname(_) -> %% Keep it, if already set.
error(Reason) ->
throw({error, Reason}).
+
+%%-----------------------------------------------------------------
+%% lists key-function(s) wrappers
+
+-compile({inline,key1delete/2}).
+key1delete(Key, List) ->
+ lists:keydelete(Key, 1, List).
+
+-compile({inline,key1search/2}).
+key1search(Key, List) ->
+ lists:keysearch(Key, 1, List).
+
+-compile({inline,key1store/3}).
+key1store(Key, List, Elem) ->
+ lists:keystore(Key, 1, List, Elem).
+
+-compile({inline,key1sort/1}).
+key1sort(List) ->
+ lists:keysort(1, List).
+
+
%%-----------------------------------------------------------------
info_msg(F, A) ->
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index 479a44795f..436f15eb9c 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -565,45 +565,85 @@ vacmAccessTable(is_set_ok, RowIndex, Cols0) ->
case (catch verify_vacmAccessTable_cols(Cols0, [])) of
{ok, Cols} ->
IsValidKey = is_valid_key(RowIndex),
- case lists:keysearch(?vacmAccessStatus, 1, Cols) of
- %% Ok, if contextMatch is init
- {value, {Col, ?'RowStatus_active'}} ->
- {ok, Row} = snmpa_vacm:get_row(RowIndex),
- case element(?vacmAContextMatch, Row) of
- noinit -> {inconsistentValue, Col};
- _ -> {noError, 0}
+ StatusCol = lists:keyfind(?vacmAccessStatus, 1, Cols),
+ MaybeRow = snmpa_vacm:get_row(RowIndex),
+ case {StatusCol, MaybeRow} of
+ {{Col, ?'RowStatus_active'}, false} ->
+ %% row does not yet exist => inconsistentValue
+ %% (see SNMPv2-TC.mib, RowStatus textual convention)
+ {inconsistentValue, Col};
+ {{Col, ?'RowStatus_active'}, {ok, Row}} ->
+ %% Ok, if contextMatch is init
+ case element(?vacmAContextMatch, Row) of
+ noinit ->
+ %% check whether ContextMatch is being set in
+ %% the same operation
+ case proplists:get_value(?vacmAccessContextMatch,
+ Cols) of
+ undefined ->
+ %% no, we can't make this row active yet
+ {inconsistentValue, Col};
+ _ ->
+ %% ok, activate the row
+ {noError, 0}
+ end;
+ _ ->
+ {noError, 0}
end;
- {value, {Col, ?'RowStatus_notInService'}} -> % Ok, if not notReady
- {ok, Row} = snmpa_vacm:get_row(RowIndex),
+ {{Col, ?'RowStatus_notInService'}, false} ->
+ %% row does not yet exist => inconsistentValue
+ %% (see SNMPv2-TC.mib, RowStatus textual convention)
+ {inconsistentValue, Col};
+ {{Col, ?'RowStatus_notInService'}, {ok, Row}} ->
+ %% Ok, if not notReady
case element(?vacmAStatus, Row) of
- ?'RowStatus_notReady' -> {inconsistentValue, Col};
- _ -> {noError, 0}
+ ?'RowStatus_notReady' ->
+ {inconsistentValue, Col};
+ _ ->
+ {noError, 0}
end;
- {value, {Col, ?'RowStatus_notReady'}} -> % never ok!
+ {{Col, ?'RowStatus_notReady'}, _} ->
+ %% never ok!
{inconsistentValue, Col};
- {value, {Col, ?'RowStatus_createAndGo'}} -> % ok, if it doesn't exist
+ {{Col, ?'RowStatus_createAndGo'}, false} ->
+ %% ok, if it doesn't exist
Res = lists:keysearch(?vacmAccessContextMatch, 1, Cols),
- case snmpa_vacm:get_row(RowIndex) of
- false when (IsValidKey =:= true) andalso
- is_tuple(Res) -> {noError, 0};
- false -> {noCreation, Col}; % Bad RowIndex
- _ -> {inconsistentValue, Col}
+ if
+ IsValidKey =/= true ->
+ %% bad RowIndex => noCreation
+ {noCreation, Col};
+ is_tuple(Res) ->
+ %% required field is present => noError
+ {noError, 0};
+ true ->
+ %% required field is missing => inconsistentValue
+ {inconsistentValue, Col}
end;
- {value, {Col, ?'RowStatus_createAndWait'}} -> % ok, if it doesn't exist
- case snmpa_vacm:get_row(RowIndex) of
- false when (IsValidKey =:= true) -> {noError, 0};
- false -> {noCreation, Col}; % Bad RowIndex
- _ -> {inconsistentValue, Col}
+ {{Col, ?'RowStatus_createAndGo'}, _} ->
+ %% row already exists => inconsistentValue
+ {inconsistentValue, Col};
+ {{Col, ?'RowStatus_createAndWait'}, false} ->
+ %% ok, if it doesn't exist
+ if
+ IsValidKey =:= true ->
+ %% RowIndex is valid => noError
+ {noError, 0};
+ true ->
+ {noCreation, Col}
end;
- {value, {_Col, ?'RowStatus_destroy'}} -> % always ok!
+ {{Col, ?'RowStatus_createAndWait'}, _} ->
+ %% Row already exists => inconsistentValue
+ {inconsistentValue, Col};
+ {value, {_Col, ?'RowStatus_destroy'}} ->
+ %% always ok!
{noError, 0};
- _ -> % otherwise, it's a change; it must exist
- case snmpa_vacm:get_row(RowIndex) of
- {ok, _} ->
- {noError, 0};
- false ->
- {inconsistentName, element(1, hd(Cols))}
- end
+ {_, false} ->
+ %% otherwise, it's a row change;
+ %% row does not exist => inconsistentName
+ {inconsistentName, element(1, hd(Cols))};
+ _ ->
+ %% row change and row exists => noError
+ {noError, 0}
end;
Error ->
Error
@@ -734,10 +774,15 @@ do_vacmAccessTable_set(RowIndex, Cols) ->
%% Cols are sorted, and all columns are > 3.
+do_get_next(_RowIndex, []) ->
+ % Cols can be empty because we're called for each
+ % output of split_cols(); and one of that may well
+ % be empty.
+ [];
do_get_next(RowIndex, Cols) ->
case snmpa_vacm:get_next_row(RowIndex) of
{NextIndex, Row} ->
- F1 = fun(Col) when Col < ?vacmAccessStatus ->
+ F1 = fun(Col) when Col =< ?vacmAccessStatus ->
{[Col | NextIndex], element(Col-3, Row)};
(_) ->
endOfTable
@@ -745,9 +790,9 @@ do_get_next(RowIndex, Cols) ->
lists:map(F1, Cols);
false ->
case snmpa_vacm:get_next_row([]) of
- {_NextIndex, Row} ->
+ {NextIndex2, Row} ->
F2 = fun(Col) when Col < ?vacmAccessStatus ->
- {[Col+1 | RowIndex], element(Col-2, Row)};
+ {[Col+1 | NextIndex2], element(Col-2, Row)};
(_) ->
endOfTable
end,
diff --git a/lib/snmp/src/app/Makefile b/lib/snmp/src/app/Makefile
index d89eb4e723..7a16d42c30 100644
--- a/lib/snmp/src/app/Makefile
+++ b/lib/snmp/src/app/Makefile
@@ -127,14 +127,14 @@ $(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/app
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/app
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/app"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/app"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
- $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+ "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 8360d88c94..593ddd82bd 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -22,8 +22,18 @@
%% ----- U p g r a d e -------------------------------------------------------
[
+ {"4.22",
+ [
+ {load_module, snmpm, soft_purge, soft_purge, []},
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21.7",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -50,6 +60,8 @@
},
{"4.21.6",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -76,6 +88,8 @@
},
{"4.21.5",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -107,6 +121,8 @@
},
{"4.21.4",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -141,6 +157,8 @@
},
{"4.21.3",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -175,6 +193,8 @@
},
{"4.21.2",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -211,6 +231,8 @@
},
{"4.21.1",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -248,6 +270,8 @@
},
{"4.21",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -288,8 +312,19 @@
%% ------D o w n g r a d e ---------------------------------------------------
[
+ {"4.22",
+ [
+ {load_module, snmpm, soft_purge, soft_purge, []},
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmp_user_based_sm_mib, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21.7",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -316,6 +351,8 @@
},
{"4.21.6",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -342,6 +379,8 @@
},
{"4.21.5",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -373,6 +412,8 @@
},
{"4.21.4",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -407,6 +448,8 @@
},
{"4.21.3",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -441,6 +484,8 @@
},
{"4.21.2",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -477,6 +522,8 @@
},
{"4.21.1",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
@@ -514,6 +561,8 @@
},
{"4.21",
[
+ {load_module, snmp_pdus, soft_purge, soft_purge, []},
+
{load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_conf, soft_purge, soft_purge, []},
{load_module, snmp_community_mib, soft_purge, soft_purge, [snmp_conf]},
diff --git a/lib/snmp/src/compile/Makefile b/lib/snmp/src/compile/Makefile
index 627af6f185..9658ee0005 100644
--- a/lib/snmp/src/compile/Makefile
+++ b/lib/snmp/src/compile/Makefile
@@ -120,13 +120,13 @@ $(GENERATED_PARSER): $(PARSER_SRC)
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/compiler
- $(INSTALL_DATA) $(ESCRIPT_SRC) $(PARSER_SRC) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/compiler
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(EBIN_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/bin
- $(INSTALL_SCRIPT) $(ESCRIPT_BIN) $(RELSYSDIR)/bin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/compiler"
+ $(INSTALL_DATA) $(ESCRIPT_SRC) $(PARSER_SRC) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src/compiler"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(EBIN_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/bin"
+ $(INSTALL_SCRIPT) $(ESCRIPT_BIN) "$(RELSYSDIR)/bin"
release_docs_spec:
diff --git a/lib/snmp/src/manager/Makefile b/lib/snmp/src/manager/Makefile
index c1d5703300..1f30669f02 100644
--- a/lib/snmp/src/manager/Makefile
+++ b/lib/snmp/src/manager/Makefile
@@ -111,13 +111,13 @@ info:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/manager
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/manager
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
-# $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/manager"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/manager"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+# $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
index 89eaee9f80..f590892c66 100644
--- a/lib/snmp/src/manager/snmpm.erl
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -1411,7 +1411,7 @@ log_to_io(LogDir, Mibs, LogName, LogFile) ->
log_to_io(LogDir, Mibs, LogName, LogFile, Start) ->
snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Start).
log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) ->
- snmp:log_to_io(LogDir, Mibs, LogFile, Start, Stop).
+ snmp:log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop).
change_log_size(NewSize) ->
diff --git a/lib/snmp/src/misc/Makefile b/lib/snmp/src/misc/Makefile
index 48d76bdbed..c6a5064d89 100644
--- a/lib/snmp/src/misc/Makefile
+++ b/lib/snmp/src/misc/Makefile
@@ -109,13 +109,13 @@ info:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/misc
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/misc
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
-# $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/misc"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/misc"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+# $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/snmp/src/misc/snmp_pdus.erl b/lib/snmp/src/misc/snmp_pdus.erl
index 0788d86b2d..5b8be90a71 100644
--- a/lib/snmp/src/misc/snmp_pdus.erl
+++ b/lib/snmp/src/misc/snmp_pdus.erl
@@ -254,68 +254,95 @@ strip(0, _Tail) ->
%%----------------------------------------------------------------------
%% Returns:{Type, Value}
%%----------------------------------------------------------------------
+
+%% OBJECT IDENTIFIER
dec_value([6 | Bytes]) ->
{Value, Rest} = dec_oid_notag(Bytes),
{{'OBJECT IDENTIFIER', Value}, Rest};
dec_value([5,0 | T]) ->
{{'NULL', 'NULL'}, T};
+
+%% INTEGER
dec_value([2 | Bytes]) ->
{Value, Rest} = dec_integer_notag(Bytes),
{{'INTEGER', Value}, Rest};
+
+%% OCTET STRING
dec_value([4 | Bytes]) ->
{Value, Rest} = dec_oct_str_notag(Bytes),
{{'OCTET STRING', Value}, Rest};
+
+%% IpAddress
dec_value([64 | Bytes]) ->
{Value, Rest} = dec_oct_str_notag(Bytes),
{{'IpAddress', Value}, Rest};
+
+%% Counter32
dec_value([65 | Bytes]) ->
%% Counter32 is an unsigned 32 but is actually encoded as
%% a signed integer 32 (INTEGER).
{Value, Rest} = dec_integer_notag(Bytes),
Value2 =
- if
+ if
+ (Value >= 0) andalso (Value =< 16#ffffffff) ->
+ %% We accept value above 16#7fffffff
+ %% in order to be backward bug-compatible
+ Value;
+ (Value < 0) ->
+ 16#ffffffff + Value + 1;
+ true ->
+ exit({error, {bad_counter32, Value}})
+ end,
+ {{'Counter32', Value2}, Rest};
+
+%% Unsigned32
+dec_value([66 | Bytes]) ->
+ {Value, Rest} = dec_integer_notag(Bytes),
+ Value2 =
+ if
(Value >= 0) andalso (Value =< 16#ffffffff) ->
- %% We accept value above 16#7fffffff
- %% in order to be backward bug-compatible
Value;
(Value < 0) ->
16#ffffffff + Value + 1;
true ->
- exit({error, {bad_counter32, Value}})
+ exit({error, {bad_unsigned32, Value}})
end,
- {{'Counter32', Value2}, Rest};
-dec_value([66 | Bytes]) ->
- {Value, Rest} = dec_integer_notag(Bytes),
- if
- (Value >= 0) andalso (Value =< 4294967295) ->
- {{'Unsigned32', Value}, Rest};
- true ->
- exit({error, {bad_unsigned32, Value}})
- end;
+ {{'Unsigned32', Value2}, Rest};
+
+%% TimeTicks
dec_value([67 | Bytes]) ->
{Value, Rest} = dec_integer_notag(Bytes),
- if
- (Value >= 0) andalso (Value =< 4294967295) ->
- {{'TimeTicks', Value}, Rest};
+ Value2 =
+ if
+ (Value >= 0) andalso (Value =< 16#ffffffff) ->
+ Value;
+ (Value < 0) ->
+ 16#ffffffff + Value + 1;
true ->
exit({error, {bad_timeticks, Value}})
- end;
+ end,
+ {{'TimeTicks', Value2}, Rest};
+
+%% Opaque
dec_value([68 | Bytes]) ->
{Value, Rest} = dec_oct_str_notag(Bytes),
{{'Opaque', Value}, Rest};
+
+%% Counter64
dec_value([70 | Bytes]) ->
%% Counter64 is an unsigned 64 but is actually encoded as
%% a signed integer 64.
{Value, Rest} = dec_integer_notag(Bytes),
Value2 =
- if
- (Value >= 0) andalso (Value < 16#8000000000000000) ->
- Value;
- (Value < 0) ->
- 18446744073709551615 + Value + 1;
- true ->
- exit({error, {bad_counter64, Value}}) end,
+ if
+ (Value >= 0) andalso (Value < 16#8000000000000000) ->
+ Value;
+ (Value < 0) ->
+ 16#ffffffffffffffff + Value + 1;
+ true ->
+ exit({error, {bad_counter64, Value}}) end,
{{'Counter64', Value2}, Rest};
+
dec_value([128,0|T]) ->
{{'NULL', noSuchObject}, T};
dec_value([129,0|T]) ->
@@ -629,7 +656,7 @@ enc_VarBind_attributes(#varbind{oid = Oid, variabletype = Type,value = Val}) ->
ValueBytes = enc_value(Type, Val),
lists:append(OidBytes, ValueBytes).
-enc_value('INTEGER',Val) ->
+enc_value('INTEGER', Val) ->
enc_integer_tag(Val);
enc_value('OCTET STRING', Val) ->
enc_oct_str_tag(Val);
@@ -637,7 +664,7 @@ enc_value('BITS', Val) ->
enc_oct_str_tag(bits_to_str(Val));
enc_value('OBJECT IDENTIFIER', Val) ->
enc_oid_tag(Val);
-enc_value('IpAddress',Val) ->
+enc_value('IpAddress', Val) ->
Bytes2 = enc_oct_str_notag(Val),
Len2 = elength(length(Bytes2)),
lists:append([64 | Len2],Bytes2);
@@ -668,6 +695,24 @@ enc_value('Counter32', Val) ->
Bytes2 = enc_integer_notag(Val2),
Len2 = elength(length(Bytes2)),
lists:append([65 | Len2],Bytes2);
+enc_value('Unsigned32', Val) ->
+ if
+ (Val >= 0) andalso (Val =< 4294967295) ->
+ Bytes2 = enc_integer_notag(Val),
+ Len2 = elength(length(Bytes2)),
+ lists:append([66 | Len2], Bytes2);
+ true ->
+ exit({error, {bad_counter32, Val}})
+ end;
+enc_value('TimeTicks', Val) ->
+ if
+ (Val >= 0) andalso (Val =< 4294967295) ->
+ Bytes2 = enc_integer_notag(Val),
+ Len2 = elength(length(Bytes2)),
+ lists:append([67 | Len2], Bytes2);
+ true ->
+ exit({error, {bad_timeticks, Val}})
+ end;
enc_value('Counter64', Val) ->
Val2 =
if
@@ -682,18 +727,7 @@ enc_value('Counter64', Val) ->
end,
Bytes2 = enc_integer_notag(Val2),
Len2 = elength(length(Bytes2)),
- lists:append([70 | Len2],Bytes2);
-enc_value(Type, Val) ->
- Bytes2 = enc_integer_notag(Val),
- Len2 = elength(length(Bytes2)),
- lists:append([enc_val_tag(Type,Val) | Len2],Bytes2).
-
-enc_val_tag('Counter32',Val) when (Val >= 0) andalso (Val =< 4294967295) ->
- 65;
-enc_val_tag('Unsigned32', Val) when (Val >= 0) andalso (Val =< 4294967295) ->
- 66;
-enc_val_tag('TimeTicks', Val) when (Val >= 0) andalso (Val =< 4294967295) ->
- 67.
+ lists:append([70 | Len2],Bytes2).
%%----------------------------------------------------------------------
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index 40a294f783..546d46a002 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -79,7 +79,7 @@ COVER_SPEC_FILE = snmp.cover
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/snmp_test
+RELSYSDIR = $(RELEASE_PATH)/snmp_test
# ----------------------------------------------------
@@ -235,10 +235,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(RELTEST_FILES) $(COVER_SPEC_FILE) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- tar cf - snmp_test_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(RELTEST_FILES) $(COVER_SPEC_FILE) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ tar cf - snmp_test_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
@@ -254,7 +254,7 @@ info:
@echo ""
@echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)"
@echo ""
- @echo "RELSYSDIR = $(RELSYSDIR)"
+ @echo "RELSYSDIR = "$(RELSYSDIR)""
@echo ""
@echo "SOURCE = $(SOURCE)"
@echo ""
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 8ee5dd534d..e1d7f33b3f 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -346,47 +346,72 @@ end_per_group(_GroupName, Config) ->
-init_per_testcase(otp8395 = Case, Config) when is_list(Config) ->
+%% ---- Init Per TestCase ----
+
+init_per_testcase(Case, Config) when is_list(Config) ->
?DBG("init_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
+
+ p("Agent Info: "
+ "~n ~p", [snmpa:info()]),
+
+ init_per_testcase1(Case, Config).
+
+init_per_testcase1(otp8395 = Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [Case, Config]),
otp8395({init, init_per_testcase2(Case, Config)});
-init_per_testcase(otp9884 = Case, Config) when is_list(Config) ->
- ?DBG("init_per_testcase -> entry with"
+init_per_testcase1(otp9884 = Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [Case, Config]),
otp9884({init, init_per_testcase2(Case, Config)});
-init_per_testcase(otp_7157_test = _Case, Config) when is_list(Config) ->
- ?DBG("init_per_testcase -> entry with"
+init_per_testcase1(otp_7157_test = _Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
Dog = ?WD_START(?MINS(1)),
[{watchdog, Dog} | Config ];
-init_per_testcase(v2_inform_i = _Case, Config) when is_list(Config) ->
- ?DBG("init_per_testcase -> entry with"
+init_per_testcase1(v2_inform_i = _Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
Dog = ?WD_START(?MINS(10)),
[{watchdog, Dog} | Config ];
-init_per_testcase(v3_inform_i = _Case, Config) when is_list(Config) ->
- ?DBG("init_per_testcase -> entry with"
+init_per_testcase1(v3_inform_i = _Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
Dog = ?WD_START(?MINS(10)),
[{watchdog, Dog} | Config ];
-init_per_testcase(_Case, Config) when is_list(Config) ->
+init_per_testcase1(_Case, Config) when is_list(Config) ->
?DBG("init_per_testcase -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
Dog = ?WD_START(?MINS(6)),
[{watchdog, Dog}| Config ].
-end_per_testcase(otp8395, Config) when is_list(Config) ->
+
+%% ---- End Per TestCase ----
+
+end_per_testcase(Case, Config) when is_list(Config) ->
+ ?DBG("end_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
+
+ p("Agent Info: "
+ "~n ~p", [snmpa:info()]),
+
+ display_log(Config),
+
+ end_per_testcase1(Case, Config).
+
+end_per_testcase1(otp8395, Config) when is_list(Config) ->
otp8395({fin, Config});
-end_per_testcase(otp9884, Config) when is_list(Config) ->
+end_per_testcase1(otp9884, Config) when is_list(Config) ->
otp9884({fin, Config});
-end_per_testcase(_Case, Config) when is_list(Config) ->
- ?DBG("end_per_testcase -> entry with"
+end_per_testcase1(_Case, Config) when is_list(Config) ->
+ ?DBG("end_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
Dog = ?config(watchdog, Config),
@@ -1406,9 +1431,6 @@ simple(Config) when is_list(Config) ->
try_test(simple_standard_test),
- p("Display log"),
- display_log(Config),
-
p("done"),
ok.
diff --git a/lib/snmp/test/snmp_pdus_test.erl b/lib/snmp/test/snmp_pdus_test.erl
index 07b6d6b657..0d78749bcb 100644
--- a/lib/snmp/test/snmp_pdus_test.erl
+++ b/lib/snmp/test/snmp_pdus_test.erl
@@ -39,6 +39,7 @@
otp7575/1,
otp8563/1,
otp9022/1,
+ otp10132/1,
init_per_testcase/2, end_per_testcase/2
]).
@@ -74,16 +75,16 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
%% Test case definitions
%%======================================================================
all() ->
-[{group, tickets}].
+ [{group, tickets}].
groups() ->
- [{tickets, [], [otp7575, otp8563, otp9022]}].
+ [{tickets, [], [otp7575, otp8563, otp9022, otp10132]}].
init_per_group(_GroupName, Config) ->
- Config.
+ Config.
end_per_group(_GroupName, Config) ->
- Config.
+ Config.
@@ -94,7 +95,7 @@ end_per_group(_GroupName, Config) ->
%%======================================================================
otp7575(suite) -> [];
-otp7575(doc) -> ["OTP-7575"];
+otp7575(doc) -> ["OTP-7575 - Message version"];
otp7575(Config) when is_list(Config) ->
io:format("attempt to decode message with valid version~n", []),
MsgWithOkVersion = <<48,39,2,1,0,4,6,112,117,98,108,105,99,160,26,2,2,1,49,2,1,0,2,1,0,48,14,48,12,6,8,43,6,1,2,1,1,5,0,5,0>>,
@@ -127,48 +128,55 @@ otp7575(Config) when is_list(Config) ->
otp8563(suite) -> [];
-otp8563(doc) -> ["OTP-8563"];
+otp8563(doc) -> ["OTP-8563 - Counter64"];
otp8563(Config) when is_list(Config) ->
Val1 = 16#7fffffffffffffff,
- io:format("try encode and decode ~w~n", [Val1]),
+ io:format("try encode and decode value 1: ~w (0x~.16b)~n", [Val1, Val1]),
Enc1 = snmp_pdus:enc_value('Counter64', Val1),
+ io:format(" => ~w~n", [Enc1]),
{{'Counter64', Val1}, []} = snmp_pdus:dec_value(Enc1),
Val2 = Val1 + 1,
- io:format("try encode and decode ~w~n", [Val2]),
+ io:format("try encode and decode value 2: ~w (0x~.16b)~n", [Val2, Val2]),
Enc2 = snmp_pdus:enc_value('Counter64', Val2),
+ io:format(" => ~w~n", [Enc2]),
{{'Counter64', Val2}, []} = snmp_pdus:dec_value(Enc2),
Val3 = Val2 + 1,
- io:format("try encode and decode ~w~n", [Val3]),
+ io:format("try encode and decode valule 3: ~w (0x~.16b)~n", [Val3, Val3]),
Enc3 = snmp_pdus:enc_value('Counter64', Val3),
+ io:format(" => ~w~n", [Enc3]),
{{'Counter64', Val3}, []} = snmp_pdus:dec_value(Enc3),
Val4 = 16#fffffffffffffffe,
- io:format("try encode and decode ~w~n", [Val4]),
+ io:format("try encode and decode value 4: ~w (0x~.16b)~n", [Val4, Val4]),
Enc4 = snmp_pdus:enc_value('Counter64', Val4),
+ io:format(" => ~w~n", [Enc4]),
{{'Counter64', Val4}, []} = snmp_pdus:dec_value(Enc4),
Val5 = Val4 + 1,
- io:format("try encode and decode ~w~n", [Val5]),
+ io:format("try encode and decode value 5: ~w (0x~.16b)~n", [Val5, Val5]),
Enc5 = snmp_pdus:enc_value('Counter64', Val5),
+ io:format(" => ~w~n", [Enc5]),
{{'Counter64', Val5}, []} = snmp_pdus:dec_value(Enc5),
Val6 = 16#ffffffffffffffff + 1,
- io:format("try and fail to encode ~w~n", [Val6]),
+ io:format("try and fail to encode value 6: ~w (0x~.16b)~n", [Val6, Val6]),
case (catch snmp_pdus:enc_value('Counter64', Val6)) of
{'EXIT', {error, {bad_counter64, Val6}}} ->
ok;
Unexpected6 ->
+ io:format(" => ~w~n", [Unexpected6]),
exit({unexpected_encode_result, Unexpected6, Val6})
end,
Val7 = -1,
- io:format("try and fail to encode ~w~n", [Val7]),
+ io:format("try and fail to encode value 7: ~w~n", [Val7]),
case (catch snmp_pdus:enc_value('Counter64', Val7)) of
{'EXIT', {error, {bad_counter64, Val7}}} ->
ok;
Unexpected7 ->
+ io:format(" => ~w~n", [Unexpected7]),
exit({unexpected_encode_result, Unexpected7, Val7})
end,
@@ -176,51 +184,151 @@ otp8563(Config) when is_list(Config) ->
otp9022(suite) -> [];
-otp9022(doc) -> ["OTP-9022"];
+otp9022(doc) -> ["OTP-9022 - Counter32"];
otp9022(Config) when is_list(Config) ->
- Val1 = 16#7fffffff,
- io:format("try encode and decode ~w~n", [Val1]),
+ Val0 = 2908389204,
+ io:format("try encode and decode value 0: ~w (0x~.16b)~n", [Val0, Val0]),
+ Enc0 = snmp_pdus:enc_value('Counter32', Val0),
+ io:format(" => ~w~n", [Enc0]),
+ {{'Counter32', Val0}, []} = snmp_pdus:dec_value(Enc0),
+
+ Val1 = 0,
+ io:format("try encode and decode value 1: ~w (0x~.16b)~n", [Val1, Val1]),
Enc1 = snmp_pdus:enc_value('Counter32', Val1),
+ io:format(" => ~w~n", [Enc1]),
{{'Counter32', Val1}, []} = snmp_pdus:dec_value(Enc1),
Val2 = Val1 + 1,
- io:format("try encode and decode ~w~n", [Val2]),
+ io:format("try encode and decode value 2: ~w (0x~.16b)~n", [Val2, Val2]),
Enc2 = snmp_pdus:enc_value('Counter32', Val2),
+ io:format(" => ~w~n", [Enc2]),
{{'Counter32', Val2}, []} = snmp_pdus:dec_value(Enc2),
- Val3 = Val2 + 1,
- io:format("try encode and decode ~w~n", [Val3]),
+ Val3 = 16#7ffffffe,
+ io:format("try encode and decode value 3: ~w (0x~.16b)~n", [Val3, Val3]),
Enc3 = snmp_pdus:enc_value('Counter32', Val3),
+ io:format(" => ~w~n", [Enc3]),
{{'Counter32', Val3}, []} = snmp_pdus:dec_value(Enc3),
- Val4 = 16#fffffffe,
- io:format("try encode and decode ~w~n", [Val4]),
+ Val4 = Val3 + 1,
+ io:format("try encode and decode value 4: ~w (0x~.16b)~n", [Val4, Val4]),
Enc4 = snmp_pdus:enc_value('Counter32', Val4),
+ io:format(" => ~w~n", [Enc4]),
{{'Counter32', Val4}, []} = snmp_pdus:dec_value(Enc4),
Val5 = Val4 + 1,
- io:format("try encode and decode ~w~n", [Val5]),
+ io:format("try encode and decode value 5: ~w (0x~.16b)~n", [Val5, Val5]),
Enc5 = snmp_pdus:enc_value('Counter32', Val5),
+ io:format(" => ~w~n", [Enc5]),
{{'Counter32', Val5}, []} = snmp_pdus:dec_value(Enc5),
- Val6 = 16#ffffffff + 1,
- io:format("try and fail to encode ~w~n", [Val6]),
- case (catch snmp_pdus:enc_value('Counter32', Val6)) of
- {'EXIT', {error, {bad_counter32, Val6}}} ->
+ Val6 = 16#fffffffe,
+ io:format("try encode and decode value 6: ~w (0x~.16b)~n", [Val6, Val6]),
+ Enc6 = snmp_pdus:enc_value('Counter32', Val6),
+ io:format(" => ~w~n", [Enc6]),
+ {{'Counter32', Val6}, []} = snmp_pdus:dec_value(Enc6),
+
+ Val7 = Val6 + 1,
+ io:format("try encode and decode value 7: ~w (0x~.16b)~n", [Val7, Val7]),
+ Enc7 = snmp_pdus:enc_value('Counter32', Val7),
+ io:format(" => ~w~n", [Enc7]),
+ {{'Counter32', Val7}, []} = snmp_pdus:dec_value(Enc7),
+
+ Val8 = 16#ffffffff + 1,
+ io:format("try and fail to encode value 8: ~w (0x~.16b)~n", [Val8, Val8]),
+ case (catch snmp_pdus:enc_value('Counter32', Val8)) of
+ {'EXIT', {error, {bad_counter32, Val8}}} ->
ok;
- Unexpected6 ->
- exit({unexpected_encode_result, Unexpected6, Val6})
+ Unexpected8 ->
+ io:format(" => ~w~n", [Unexpected8]),
+ exit({unexpected_encode_result, Unexpected8, Val8})
end,
- Val7 = -1,
- io:format("try and fail to encode ~w~n", [Val7]),
- case (catch snmp_pdus:enc_value('Counter32', Val7)) of
- {'EXIT', {error, {bad_counter32, Val7}}} ->
+ Val9 = -1,
+ io:format("try and fail to encode value 9: ~w~n", [Val9]),
+ case (catch snmp_pdus:enc_value('Counter32', Val9)) of
+ {'EXIT', {error, {bad_counter32, Val9}}} ->
ok;
- Unexpected7 ->
- exit({unexpected_encode_result, Unexpected7, Val7})
+ Unexpected9 ->
+ io:format(" => ~w~n", [Unexpected9]),
+ exit({unexpected_encode_result, Unexpected9, Val9})
+ end,
+
+ ok.
+
+
+otp10132(suite) -> [];
+otp10132(doc) -> ["OTP-10132 - TimeTicks"];
+otp10132(Config) when is_list(Config) ->
+ Val0 = 2159001034,
+ io:format("try encode and decode value 0: ~w (0x~.16b)~n", [Val0, Val0]),
+ Enc0 = snmp_pdus:enc_value('TimeTicks', Val0),
+ io:format(" => ~w~n", [Enc0]),
+ {{'TimeTicks', Val0}, []} = snmp_pdus:dec_value(Enc0),
+
+ Val1 = 0,
+ io:format("try encode and decode value 1: ~w (0x~.16b)~n", [Val1, Val1]),
+ Enc1 = snmp_pdus:enc_value('TimeTicks', Val1),
+ io:format(" => ~w~n", [Enc1]),
+ {{'TimeTicks', Val1}, []} = snmp_pdus:dec_value(Enc1),
+
+ Val2 = Val1 + 1,
+ io:format("try encode and decode value 2: ~w (0x~.16b)~n", [Val2, Val2]),
+ Enc2 = snmp_pdus:enc_value('TimeTicks', Val2),
+ io:format(" => ~w~n", [Enc2]),
+ {{'TimeTicks', Val2}, []} = snmp_pdus:dec_value(Enc2),
+
+ Val3 = 16#7ffffffe,
+ io:format("try encode and decode value 3: ~w (0x~.16b)~n", [Val3, Val3]),
+ Enc3 = snmp_pdus:enc_value('TimeTicks', Val3),
+ io:format(" => ~w~n", [Enc3]),
+ {{'TimeTicks', Val3}, []} = snmp_pdus:dec_value(Enc3),
+
+ Val4 = Val3 + 1,
+ io:format("try encode and decode value 4: ~w (0x~.16b)~n", [Val4, Val4]),
+ Enc4 = snmp_pdus:enc_value('TimeTicks', Val4),
+ io:format(" => ~w~n", [Enc4]),
+ {{'TimeTicks', Val4}, []} = snmp_pdus:dec_value(Enc4),
+
+ Val5 = Val4 + 1,
+ io:format("try encode and decode value 5: ~w (0x~.16b)~n", [Val5, Val5]),
+ Enc5 = snmp_pdus:enc_value('TimeTicks', Val5),
+ io:format(" => ~w~n", [Enc5]),
+ {{'TimeTicks', Val5}, []} = snmp_pdus:dec_value(Enc5),
+
+ Val6 = 16#fffffffe,
+ io:format("try encode and decode value 6: ~w (0x~.16b)~n", [Val6, Val6]),
+ Enc6 = snmp_pdus:enc_value('TimeTicks', Val6),
+ io:format(" => ~w~n", [Enc6]),
+ {{'TimeTicks', Val6}, []} = snmp_pdus:dec_value(Enc6),
+
+ Val7 = Val6 + 1,
+ io:format("try encode and decode value 7: ~w (0x~.16b)~n", [Val7, Val7]),
+ Enc7 = snmp_pdus:enc_value('TimeTicks', Val7),
+ io:format(" => ~w~n", [Enc7]),
+ {{'TimeTicks', Val7}, []} = snmp_pdus:dec_value(Enc7),
+
+ Val8 = Val7 + 1,
+ io:format("try and fail to encode value 8: ~w (0x~.16b)~n", [Val8, Val8]),
+ case (catch snmp_pdus:enc_value('TimeTicks', Val8)) of
+ {'EXIT', {error, {bad_timeticks, Val8}}} ->
+ ok;
+ Unexpected8 ->
+ io:format(" => ~w~n", [Unexpected8]),
+ exit({unexpected_encode_result, Unexpected8, Val8})
end,
+ Val9 = -1,
+ io:format("try and fail to encode value 9: ~w~n", [Val9]),
+ case (catch snmp_pdus:enc_value('TimeTicks', Val9)) of
+ {'EXIT', {error, {bad_timeticks, Val9}}} ->
+ ok;
+ Unexpected9 ->
+ io:format(" => ~w~n", [Unexpected9]),
+ exit({unexpected_encode_result, Unexpected9, Val9})
+ end,
+
+ io:format("done~n", []),
ok.
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 36b9764bc8..b90dbe4eef 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 4.22
+SNMP_VSN = 4.22.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile
index 125dcf8775..38782a3b00 100644
--- a/lib/ssh/doc/src/Makefile
+++ b/lib/ssh/doc/src/Makefile
@@ -109,13 +109,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/ssh/examples/Makefile b/lib/ssh/examples/Makefile
index 5f17542fb8..84c7edac8c 100644
--- a/lib/ssh/examples/Makefile
+++ b/lib/ssh/examples/Makefile
@@ -69,8 +69,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index a247692d9d..b8eecd3fa2 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -132,13 +132,13 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) \
- $(APPUP_TARGET) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(PUBLIC_HRL_FILES) $(RELSYSDIR)/include
+ $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(PUBLIC_HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 46f0c7e688..c46f799b6d 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -720,12 +720,17 @@ handle_msg(#ssh_msg_channel_request{request_type = "env"},
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = _Other,
- want_reply = WantReply}, Connection,
+ want_reply = WantReply}, #connection{channel_cache = Cache} = Connection,
ConnectionPid, _) ->
if WantReply == true ->
- FailMsg = channel_failure_msg(ChannelId),
- {{replies, [{connection_reply, ConnectionPid, FailMsg}]},
- Connection};
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = RemoteId} ->
+ FailMsg = channel_failure_msg(RemoteId),
+ {{replies, [{connection_reply, ConnectionPid, FailMsg}]},
+ Connection};
+ undefined -> %% Chanel has been closed
+ {noreply, Connection}
+ end;
true ->
{noreply, Connection}
end;
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index 8c1f88e572..e53cd4f4f7 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -267,7 +267,7 @@ handle_call({ssh_msg, Pid, Msg}, From,
disconnect_fun(Reason, SSHOpts),
{stop, {shutdown, normal}, State#state{connection_state = Connection}}
catch
- _:Reason ->
+ _:Error ->
{disconnect, Reason, {{replies, Replies}, Connection}} =
ssh_connection:handle_msg(
#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
@@ -277,7 +277,7 @@ handle_call({ssh_msg, Pid, Msg}, From,
lists:foreach(fun send_msg/1, Replies),
SSHOpts = proplists:get_value(ssh_opts, Opts),
disconnect_fun(Reason, SSHOpts),
- {stop, {shutdown, Reason}, State#state{connection_state = Connection}}
+ {stop, {shutdown, Error}, State#state{connection_state = Connection}}
end;
handle_call({global_request, Pid, _, _, _} = Request, From,
@@ -586,7 +586,7 @@ call(Pid, Msg, Timeout) ->
catch
exit:{timeout, _} ->
{error, timeout};
- exit:{normal} ->
+ exit:{normal, _} ->
{error, channel_closed};
exit:{{shutdown, _}, _} ->
{error, channel_closed};
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 145d5d2ad6..25072688ad 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -110,11 +110,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) ssh.spec ssh.cover $(RELSYSDIR)
- $(INSTALL_DATA) $(HRL_FILES_NEEDED_IN_TEST) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) ssh.spec ssh.cover "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(HRL_FILES_NEEDED_IN_TEST) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index 5d808d6727..8736913c72 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -117,15 +117,15 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index e019654685..28bf82b406 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -193,13 +193,13 @@
</item>
<tag>{depth, integer()}</tag>
- <item>Specifies the maximum
- verification depth, i.e. how far in a chain of certificates the
- verification process can proceed before the verification is
- considered to fail. Peer certificate = 0, CA certificate = 1,
- higher level CA certificate = 2, etc. The value 2 thus means
- that a chain can at most contain peer cert, CA cert, next CA
- cert, and an additional CA cert. The default value is 1.
+ <item>
+ The depth is the maximum number of non-self-issued
+ intermediate certificates that may follow the peer certificate
+ in a valid certification path. So if depth is 0 the PEER must
+ be signed by the trusted ROOT-CA directly, if 1 the path can
+ be PEER, CA, ROOT-CA, if it is 2 PEER, CA, CA, ROOT-CA and so
+ on. The default value is 1.
</item>
<tag>{verify_fun, {Verifyfun :: fun(), InitialUserState :: term()}}</tag>
diff --git a/lib/ssl/examples/certs/Makefile b/lib/ssl/examples/certs/Makefile
index a4f067ade6..549f11d709 100644
--- a/lib/ssl/examples/certs/Makefile
+++ b/lib/ssl/examples/certs/Makefile
@@ -54,8 +54,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples/certs
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/certs"
tar cf - etc | \
- (cd $(RELSYSDIR)/examples/certs; tar xf -)
- chmod -R ug+rw $(RELSYSDIR)/examples
+ (cd "$(RELSYSDIR)/examples/certs"; tar xf -)
+ chmod -R ug+rw "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/ssl/examples/src/Makefile b/lib/ssl/examples/src/Makefile
index c5f31b689c..420634c97e 100644
--- a/lib/ssl/examples/src/Makefile
+++ b/lib/ssl/examples/src/Makefile
@@ -63,10 +63,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples/src
- $(INSTALL_DIR) $(RELSYSDIR)/examples/ebin
- (cd ..; tar cf - src ebin | (cd $(RELSYSDIR)/examples; tar xf -))
- chmod -R ug+w $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/ebin"
+ (cd ..; tar cf - src ebin | (cd "$(RELSYSDIR)/examples"; tar xf -))
+ chmod -R ug+w "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index f99dd8559e..a08444b8dd 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -122,11 +122,11 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) \
- $(APPUP_TARGET) $(RELSYSDIR)/ebin
+ $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 0bcdffbeff..5e3ced144a 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -30,7 +30,7 @@
controlling_process/2, listen/2, pid/1, peername/1, peercert/1,
recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1,
versions/0, session_info/1, format_error/1,
- renegotiate/1, prf/5]).
+ renegotiate/1, prf/5, clear_pem_cache/0]).
-deprecated({pid, 1, next_major_release}).
@@ -431,6 +431,15 @@ prf(#sslsocket{pid = Pid, fd = new_ssl},
Secret, Label, Seed, WantedLength) ->
ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength).
+
+%%--------------------------------------------------------------------
+-spec clear_pem_cache() -> ok.
+%%
+%% Description: Clear the PEM cache
+%%--------------------------------------------------------------------
+clear_pem_cache() ->
+ ssl_manager:clear_pem_cache().
+
%%---------------------------------------------------------------
-spec format_error({error, term()}) -> list().
%%
@@ -532,7 +541,7 @@ handle_options(Opts0, _Role) ->
throw({error, {eoptions, {verify, Value}}})
end,
- CertFile = handle_option(certfile, Opts, ""),
+ CertFile = handle_option(certfile, Opts, <<>>),
SSLOptions = #ssl_options{
versions = handle_option(versions, Opts, []),
@@ -619,8 +628,12 @@ validate_option(depth, Value) when is_integer(Value),
validate_option(cert, Value) when Value == undefined;
is_binary(Value) ->
Value;
-validate_option(certfile, Value) when Value == undefined; is_list(Value) ->
+validate_option(certfile, undefined = Value) ->
Value;
+validate_option(certfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(certfile, Value) when is_list(Value) ->
+ list_to_binary(Value);
validate_option(key, undefined) ->
undefined;
@@ -631,8 +644,13 @@ validate_option(key, {KeyType, Value}) when is_binary(Value),
KeyType == 'DSAPrivateKey';
KeyType == 'PrivateKeyInfo' ->
{KeyType, Value};
-validate_option(keyfile, Value) when is_list(Value) ->
+
+validate_option(keyfile, undefined) ->
+ <<>>;
+validate_option(keyfile, Value) when is_binary(Value) ->
Value;
+validate_option(keyfile, Value) when is_list(Value), Value =/= "" ->
+ list_to_binary(Value);
validate_option(password, Value) when is_list(Value) ->
Value;
@@ -642,16 +660,20 @@ validate_option(cacerts, Value) when Value == undefined;
%% certfile must be present in some cases otherwhise it can be set
%% to the empty string.
validate_option(cacertfile, undefined) ->
- "";
-validate_option(cacertfile, Value) when is_list(Value), Value =/= "" ->
+ <<>>;
+validate_option(cacertfile, Value) when is_binary(Value) ->
Value;
+validate_option(cacertfile, Value) when is_list(Value), Value =/= ""->
+ list_to_binary(Value);
validate_option(dh, Value) when Value == undefined;
is_binary(Value) ->
Value;
validate_option(dhfile, undefined = Value) ->
Value;
-validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
+validate_option(dhfile, Value) when is_binary(Value) ->
Value;
+validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
+ list_to_binary(Value);
validate_option(ciphers, Value) when is_list(Value) ->
Version = ssl_record:highest_protocol_version([]),
try cipher_suites(Version, Value)
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index cb2473576a..01ddf056c9 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. 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
@@ -24,12 +24,13 @@
-module(ssl_certificate_db).
-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/file.hrl").
-export([create/0, remove/1, add_trusted_certs/3,
- remove_trusted_certs/2, lookup_trusted_cert/4, foldl/3,
- lookup_cached_certs/2, cache_pem_file/4, uncache_pem_file/2, lookup/2]).
-
--type time() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
+ remove_trusted_certs/2, insert/3, remove/2, clear/1, db_size/1,
+ ref_count/3, lookup_trusted_cert/4, foldl/3,
+ lookup_cached_pem/2, cache_pem_file/2, cache_pem_file/3,
+ lookup/2]).
%%====================================================================
%% Internal application API
@@ -43,9 +44,14 @@
%% the process that called create may call the other functions.
%%--------------------------------------------------------------------
create() ->
- [ets:new(ssl_otp_certificate_db, [set, protected]),
- ets:new(ssl_file_to_ref, [set, protected]),
- ets:new(ssl_pid_to_file, [bag, private])].
+ [%% Let connection process delete trusted certs
+ %% that can only belong to one connection. (Supplied directly
+ %% on DER format to ssl:connect/listen.)
+ ets:new(ssl_otp_cacertificate_db, [set, public]),
+ %% Let connection processes call ref_count/3 directly
+ ets:new(ssl_otp_ca_file_ref, [set, public]),
+ ets:new(ssl_otp_pem_cache, [set, protected])
+ ].
%%--------------------------------------------------------------------
-spec remove([db_handle()]) -> term().
@@ -53,7 +59,9 @@ create() ->
%% Description: Removes database db
%%--------------------------------------------------------------------
remove(Dbs) ->
- lists:foreach(fun(Db) -> true = ets:delete(Db) end, Dbs).
+ lists:foreach(fun(Db) ->
+ true = ets:delete(Db)
+ end, Dbs).
%%--------------------------------------------------------------------
-spec lookup_trusted_cert(db_handle(), certdb_ref(), serialnumber(), issuer()) ->
@@ -72,11 +80,14 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
{ok, Certs}
end.
-lookup_cached_certs(DbHandle, File) ->
- ets:lookup(DbHandle, {file, File}).
+lookup_cached_pem([_, _, PemChache], MD5) ->
+ lookup_cached_pem(PemChache, MD5);
+lookup_cached_pem(PemChache, MD5) ->
+ lookup(MD5, PemChache).
%%--------------------------------------------------------------------
--spec add_trusted_certs(pid(), string() | {der, list()}, [db_handle()]) -> {ok, [db_handle()]}.
+-spec add_trusted_certs(pid(), {erlang:timestamp(), string()} |
+ {der, list()}, [db_handle()]) -> {ok, [db_handle()]}.
%%
%% Description: Adds the trusted certificates from file <File> to the
%% runtime database. Returns Ref that should be handed to lookup_trusted_cert
@@ -86,82 +97,55 @@ add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) ->
NewRef = make_ref(),
add_certs_from_der(DerList, NewRef, CerDb),
{ok, NewRef};
-add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) ->
- Ref = case lookup(File, FileToRefDb) of
- undefined ->
- NewRef = make_ref(),
- add_certs_from_file(File, NewRef, CertsDb),
- insert(File, NewRef, 1, FileToRefDb),
- NewRef;
- [OldRef] ->
- ref_count(File,FileToRefDb,1),
- OldRef
- end,
- insert(Pid, File, PidToFileDb),
- {ok, Ref}.
+
+add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) ->
+ MD5 = crypto:md5(File),
+ case lookup_cached_pem(Db, MD5) of
+ [{_Content, Ref}] ->
+ ref_count(Ref, RefDb, 1),
+ {ok, Ref};
+ [Content] ->
+ Ref = make_ref(),
+ insert(Ref, [], 1, RefDb),
+ insert(MD5, {Content, Ref}, PemChache),
+ add_certs_from_pem(Content, Ref, CertsDb),
+ {ok, Ref};
+ undefined ->
+ new_trusted_cert_entry({MD5, File}, Db)
+ end.
%%--------------------------------------------------------------------
--spec cache_pem_file(pid(), string(), time(), [db_handle()]) -> term().
+-spec cache_pem_file(string(), [db_handle()]) -> term().
+-spec cache_pem_file(reference(), string(), [db_handle()]) -> term().
%%
%% Description: Cache file as binary in DB
%%--------------------------------------------------------------------
-cache_pem_file(Pid, File, Time, [CertsDb, _FileToRefDb, PidToFileDb]) ->
- {ok, PemBin} = file:read_file(File),
+cache_pem_file({MD5, File}, [_CertsDb, _RefDb, PemChache]) ->
+ {ok, PemBin} = file:read_file(File),
Content = public_key:pem_decode(PemBin),
- insert({file, File}, {Time, Content}, CertsDb),
- insert(Pid, File, PidToFileDb),
+ insert(MD5, Content, PemChache),
{ok, Content}.
-%--------------------------------------------------------------------
--spec uncache_pem_file(string(), [db_handle()]) -> no_return().
-%%
-%% Description: If a cached file is no longer valid (changed on disk)
-%% we must terminate the connections using the old file content, and
-%% when those processes are finish the cache will be cleaned. It is
-%% a rare but possible case a new ssl client/server is started with
-%% a filename with the same name as previously started client/server
-%% but with different content.
-%% --------------------------------------------------------------------
-uncache_pem_file(File, [_CertsDb, _FileToRefDb, PidToFileDb]) ->
- Pids = select(PidToFileDb, [{{'$1', File},[],['$$']}]),
- lists:foreach(fun([Pid]) ->
- exit(Pid, shutdown)
- end, Pids).
-
-%%--------------------------------------------------------------------
--spec remove_trusted_certs(pid(), [db_handle()]) -> term().
-
-%%
-%% Description: Removes trusted certs originating from
-%% the file associated to Pid from the runtime database.
-%%--------------------------------------------------------------------
-remove_trusted_certs(Pid, [CertsDb, FileToRefDb, PidToFileDb]) ->
- Files = lookup(Pid, PidToFileDb),
- delete(Pid, PidToFileDb),
- Clear = fun(File) ->
- delete({file,File}, CertsDb),
- try
- 0 = ref_count(File, FileToRefDb, -1),
- case lookup(File, FileToRefDb) of
- [Ref] when is_reference(Ref) ->
- remove_certs(Ref, CertsDb);
- _ -> ok
- end,
- delete(File, FileToRefDb)
- catch _:_ ->
- ok
- end
- end,
- case Files of
- undefined -> ok;
- _ ->
- [Clear(File) || File <- Files],
- ok
- end.
+cache_pem_file(Ref, {MD5, File}, [_CertsDb, _RefDb, PemChache]) ->
+ {ok, PemBin} = file:read_file(File),
+ Content = public_key:pem_decode(PemBin),
+ insert(MD5, {Content, Ref}, PemChache),
+ {ok, Content}.
+
+remove_trusted_certs(Ref, CertsDb) ->
+ remove_certs(Ref, CertsDb).
+
+%%--------------------------------------------------------------------
+-spec remove(term(), db_handle()) -> term().
+%%
+%% Description: Removes an element in a <Db>.
+%%--------------------------------------------------------------------
+remove(Key, Db) ->
+ _ = ets:delete(Db, Key).
%%--------------------------------------------------------------------
-spec lookup(term(), db_handle()) -> term() | undefined.
%%
-%% Description: Looks up an element in a certificat <Db>.
+%% Description: Looks up an element in a <Db>.
%%--------------------------------------------------------------------
lookup(Key, Db) ->
case ets:lookup(Db, Key) of
@@ -184,25 +168,47 @@ lookup(Key, Db) ->
%%--------------------------------------------------------------------
foldl(Fun, Acc0, Cache) ->
ets:foldl(Fun, Acc0, Cache).
-
+
%%--------------------------------------------------------------------
-%%% Internal functions
+-spec ref_count(term(), db_handle(), integer()) -> integer().
+%%
+%% Description: Updates a reference counter in a <Db>.
+%%--------------------------------------------------------------------
+ref_count(Key, Db, N) ->
+ ets:update_counter(Db,Key,N).
+
+%%--------------------------------------------------------------------
+-spec clear(db_handle()) -> term().
+%%
+%% Description: Clears the cache
+%%--------------------------------------------------------------------
+clear(Db) ->
+ ets:delete_all_objects(Db).
+
+%%--------------------------------------------------------------------
+-spec db_size(db_handle()) -> integer().
+%%
+%% Description: Returns the size of the db
+%%--------------------------------------------------------------------
+db_size(Db) ->
+ ets:info(Db, size).
+
+%%--------------------------------------------------------------------
+%%-spec insert(Key::term(), Data::term(), Db::db_handle()) -> no_return().
+%%
+%% Description: Inserts data into <Db>
%%--------------------------------------------------------------------
insert(Key, Data, Db) ->
true = ets:insert(Db, {Key, Data}).
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+insert(Key, [], Count, Db) ->
+ true = ets:insert(Db, {Key, Count});
insert(Key, Data, Count, Db) ->
true = ets:insert(Db, {Key, Count, Data}).
-ref_count(Key, Db,N) ->
- ets:update_counter(Db,Key,N).
-
-delete(Key, Db) ->
- _ = ets:delete(Db, Key).
-
-select(Db, MatchSpec)->
- ets:select(Db, MatchSpec).
-
remove_certs(Ref, CertsDb) ->
ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}).
@@ -210,10 +216,8 @@ add_certs_from_der(DerList, Ref, CertsDb) ->
Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end,
[Add(Cert) || Cert <- DerList].
-add_certs_from_file(File, Ref, CertsDb) ->
+add_certs_from_pem(PemEntries, Ref, CertsDb) ->
Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end,
- {ok, PemBin} = file:read_file(File),
- PemEntries = public_key:pem_decode(PemBin),
[Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries].
add_certs(Cert, Ref, CertsDb) ->
@@ -229,3 +233,10 @@ add_certs(Cert, Ref, CertsDb) ->
"it could not be correctly decoded.~n", []),
error_logger:info_report(Report)
end.
+
+new_trusted_cert_entry(FileRef, [CertsDb, RefDb, _] = Db) ->
+ Ref = make_ref(),
+ insert(Ref, [], 1, RefDb),
+ {ok, Content} = cache_pem_file(Ref, FileRef, Db),
+ add_certs_from_pem(Content, Ref, CertsDb),
+ {ok, Ref}.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 6c06baff98..c57930e821 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -47,8 +47,8 @@
-export([start_link/7]).
%% gen_fsm callbacks
--export([init/1, hello/2, certify/2, cipher/2, connection/2,
- abbreviated/2, handle_event/3,
+-export([init/1, hello/2, certify/2, cipher/2,
+ abbreviated/2, connection/2, handle_event/3,
handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
-record(state, {
@@ -83,13 +83,13 @@
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
diffie_hellman_keys, % {PublicKey, PrivateKey}
premaster_secret, %
- cert_db_ref, % ets_table()
- from, % term(), where to reply
+ file_ref_db, % ets()
+ cert_db_ref, % ref()
bytes_to_read, % integer(), # bytes to read in passive mode
user_data_buffer, % binary()
log_alert, % boolean()
renegotiation, % {boolean(), From | internal | peer}
- recv_from, %
+ start_or_recv_from, % "gen_fsm From"
send_queue, % queue()
terminated = false, %
allow_renegotiate = true
@@ -297,39 +297,30 @@ prf(ConnectionPid, Secret, Label, Seed, WantedLength) ->
%% does not return until Module:init/1 has returned.
%%--------------------------------------------------------------------
start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
- gen_fsm:start_link(?MODULE, [Role, Host, Port, Socket, Options,
- User, CbInfo], []).
+ {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]])}.
-%%====================================================================
-%% gen_fsm callbacks
-%%====================================================================
-%%--------------------------------------------------------------------
-%% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or
-%% gen_fsm:start_link/3,4, this function is called by the new process to
-%% initialize.
-%%--------------------------------------------------------------------
-init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
- User, CbInfo]) ->
+init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) ->
State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
Hashes0 = ssl_handshake:init_hashes(),
TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),
try ssl_init(SSLOpts0, Role) of
- {ok, Ref, CertDbHandle, CacheHandle, OwnCert, Key, DHParams} ->
+ {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, Key, DHParams} ->
Session = State0#state.session,
State = State0#state{tls_handshake_hashes = Hashes0,
session = Session#session{own_certificate = OwnCert,
time_stamp = TimeStamp},
+ file_ref_db = FileRefHandle,
cert_db_ref = Ref,
cert_db = CertDbHandle,
session_cache = CacheHandle,
private_key = Key,
diffie_hellman_params = DHParams},
- {ok, hello, State, get_timeout(State)}
- catch
+ gen_fsm:enter_loop(?MODULE, [], hello, State, get_timeout(State))
+ catch
throw:Error ->
- {stop, Error}
+ gen_fsm:enter_loop(?MODULE, [], error, {Error,State0}, get_timeout(State0))
end.
-
+
%%--------------------------------------------------------------------
%% Description:There should be one instance of this function for each
%% possible state name. Whenever a gen_fsm receives an event sent
@@ -337,6 +328,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
%% same name as the current state name StateName is called to handle
%% the event. It is also called if a timeout occurs.
%%
+
%%--------------------------------------------------------------------
-spec hello(start | #hello_request{} | #client_hello{} | #server_hello{} | term(),
#state{}) -> gen_fsm_state_return().
@@ -344,23 +336,23 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
hello(start, #state{host = Host, port = Port, role = client,
ssl_options = SslOpts,
session = #session{own_certificate = Cert} = Session0,
+ session_cache = Cache, session_cache_cb = CacheCb,
transport_cb = Transport, socket = Socket,
- connection_states = ConnectionStates,
+ connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _}} = State0) ->
- Hello = ssl_handshake:client_hello(Host, Port,
- ConnectionStates,
- SslOpts, Renegotiation, Cert),
+ Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert),
Version = Hello#client_hello.client_version,
Hashes0 = ssl_handshake:init_hashes(),
- {BinMsg, CS2, Hashes1} =
- encode_handshake(Hello, Version, ConnectionStates, Hashes0),
+ {BinMsg, ConnectionStates, Hashes} =
+ encode_handshake(Hello, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinMsg),
- State1 = State0#state{connection_states = CS2,
- negotiated_version = Version, %% Requested version
+ State1 = State0#state{connection_states = ConnectionStates,
+ negotiated_version = Version, %% Requested version at this point
session =
Session0#session{session_id = Hello#client_hello.session_id},
- tls_handshake_hashes = Hashes1},
+ tls_handshake_hashes = Hashes},
{Record, State} = next_record(State1),
next_state(hello, hello, Record, State);
@@ -394,7 +386,8 @@ hello(#server_hello{cipher_suite = CipherSuite,
case ssl_session:is_new(OldId, NewId) of
true ->
- handle_new_session(NewId, CipherSuite, Compression, State);
+ handle_new_session(NewId, CipherSuite, Compression,
+ State#state{connection_states = ConnectionStates});
false ->
handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
end;
@@ -552,8 +545,8 @@ certify(#server_hello_done{},
role = client} = State0) ->
case ssl_handshake:master_secret(Version, Session,
ConnectionStates0, client) of
- {MasterSecret, ConnectionStates1} ->
- State = State0#state{connection_states = ConnectionStates1},
+ {MasterSecret, ConnectionStates} ->
+ State = State0#state{connection_states = ConnectionStates},
client_certify_and_key_exchange(State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State0),
@@ -569,10 +562,10 @@ certify(#server_hello_done{},
role = client} = State0) ->
case ssl_handshake:master_secret(Version, PremasterSecret,
ConnectionStates0, client) of
- {MasterSecret, ConnectionStates1} ->
+ {MasterSecret, ConnectionStates} ->
Session = Session0#session{master_secret = MasterSecret},
- State = State0#state{connection_states = ConnectionStates1,
- session = Session},
+ State = State0#state{connection_states = ConnectionStates,
+ session = Session},
client_certify_and_key_exchange(State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State0),
@@ -691,22 +684,24 @@ cipher(Msg, State) ->
%%--------------------------------------------------------------------
connection(#hello_request{}, #state{host = Host, port = Port,
socket = Socket,
- session = #session{own_certificate = Cert},
+ session = #session{own_certificate = Cert} = Session0,
+ session_cache = Cache, session_cache_cb = CacheCb,
ssl_options = SslOpts,
negotiated_version = Version,
transport_cb = Transport,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _},
tls_handshake_hashes = Hashes0} = State0) ->
- Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0,
- SslOpts, Renegotiation, Cert),
+ Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert),
- {BinMsg, ConnectionStates1, Hashes1} =
+ {BinMsg, ConnectionStates, Hashes} =
encode_handshake(Hello, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinMsg),
{Record, State} = next_record(State0#state{connection_states =
- ConnectionStates1,
- tls_handshake_hashes = Hashes1}),
+ ConnectionStates,
+ session = Session0#session{session_id = Hello#client_hello.session_id},
+ tls_handshake_hashes = Hashes}),
next_state(connection, hello, Record, State);
connection(#client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) ->
%% Mitigate Computational DoS attack
@@ -732,6 +727,7 @@ connection(timeout, State) ->
connection(Msg, State) ->
handle_unexpected_message(Msg, connection, State).
+
%%--------------------------------------------------------------------
%% Description: Whenever a gen_fsm receives an event sent using
%% gen_fsm:send_all_state_event/2, this function is called to handle
@@ -761,8 +757,8 @@ handle_sync_event({application_data, Data}, From, StateName,
State#state{send_queue = queue:in({From, Data}, Queue)},
get_timeout(State)};
-handle_sync_event(start, From, hello, State) ->
- hello(start, State#state{from = From});
+handle_sync_event(start, StartFrom, hello, State) ->
+ hello(start, State#state{start_or_recv_from = StartFrom});
%% The two clauses below could happen if a server upgrades a socket in
%% active mode. Note that in this case we are lucky that
@@ -774,8 +770,10 @@ handle_sync_event(start, From, hello, State) ->
%% they upgrade a active socket.
handle_sync_event(start, _, connection, State) ->
{reply, connected, connection, State, get_timeout(State)};
-handle_sync_event(start, From, StateName, State) ->
- {next_state, StateName, State#state{from = From}, get_timeout(State)};
+handle_sync_event(start, _From, error, {Error, State = #state{}}) ->
+ {stop, {shutdown, Error}, {error, Error}, State};
+handle_sync_event(start, StartFrom, StateName, State) ->
+ {next_state, StateName, State#state{start_or_recv_from = StartFrom}, get_timeout(State)};
handle_sync_event(close, _, StateName, State) ->
%% Run terminate before returning
@@ -806,13 +804,13 @@ handle_sync_event({shutdown, How0}, _, StateName,
{stop, normal, Error, State}
end;
-handle_sync_event({recv, N}, From, connection = StateName, State0) ->
- passive_receive(State0#state{bytes_to_read = N, recv_from = From}, StateName);
+handle_sync_event({recv, N}, RecvFrom, connection = StateName, State0) ->
+ passive_receive(State0#state{bytes_to_read = N, start_or_recv_from = RecvFrom}, StateName);
%% Doing renegotiate wait with handling request until renegotiate is
%% finished. Will be handled by next_state_is_connection/2.
-handle_sync_event({recv, N}, From, StateName, State) ->
- {next_state, StateName, State#state{bytes_to_read = N, recv_from = From},
+handle_sync_event({recv, N}, RecvFrom, StateName, State) ->
+ {next_state, StateName, State#state{bytes_to_read = N, start_or_recv_from = RecvFrom},
get_timeout(State)};
handle_sync_event({new_user, User}, _From, StateName,
@@ -963,9 +961,9 @@ handle_info({CloseTag, Socket}, StateName,
{stop, normal, State};
handle_info({ErrorTag, Socket, econnaborted}, StateName,
- #state{socket = Socket, from = User, role = Role,
+ #state{socket = Socket, start_or_recv_from = StartFrom, role = Role,
error_tag = ErrorTag} = State) when StateName =/= connection ->
- alert_user(User, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role),
+ alert_user(StartFrom, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role),
{stop, normal, State};
handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket,
@@ -1002,16 +1000,19 @@ terminate(Reason, connection, #state{negotiated_version = Version,
connection_states = ConnectionStates,
transport_cb = Transport,
socket = Socket, send_queue = SendQueue,
- renegotiation = Renegotiate}) ->
+ renegotiation = Renegotiate} = State) ->
+ handle_trusted_certs_db(State),
notify_senders(SendQueue),
notify_renegotiater(Renegotiate),
BinAlert = terminate_alert(Reason, Version, ConnectionStates),
Transport:send(Socket, BinAlert),
workaround_transport_delivery_problems(Socket, Transport, Reason),
Transport:close(Socket);
+
terminate(Reason, _StateName, #state{transport_cb = Transport,
socket = Socket, send_queue = SendQueue,
- renegotiation = Renegotiate}) ->
+ renegotiation = Renegotiate} = State) ->
+ handle_trusted_certs_db(State),
notify_senders(SendQueue),
notify_renegotiater(Renegotiate),
workaround_transport_delivery_problems(Socket, Transport, Reason),
@@ -1059,12 +1060,12 @@ ssl_init(SslOpts, Role) ->
init_manager_name(SslOpts#ssl_options.erl_dist),
- {ok, CertDbRef, CertDbHandle, CacheHandle, OwnCert} = init_certificates(SslOpts, Role),
+ {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, OwnCert} = init_certificates(SslOpts, Role),
PrivateKey =
- init_private_key(CertDbHandle, SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile,
+ init_private_key(PemCacheHandle, SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile,
SslOpts#ssl_options.password, Role),
- DHParams = init_diffie_hellman(CertDbHandle, SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role),
- {ok, CertDbRef, CertDbHandle, CacheHandle, OwnCert, PrivateKey, DHParams}.
+ DHParams = init_diffie_hellman(PemCacheHandle, SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role),
+ {ok, CertDbRef, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, PrivateKey, DHParams}.
init_manager_name(false) ->
put(ssl_manager, ssl_manager);
@@ -1075,7 +1076,7 @@ init_certificates(#ssl_options{cacerts = CaCerts,
cacertfile = CACertFile,
certfile = CertFile,
cert = Cert}, Role) ->
- {ok, CertDbRef, CertDbHandle, CacheHandle} =
+ {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle} =
try
Certs = case CaCerts of
undefined ->
@@ -1083,38 +1084,38 @@ init_certificates(#ssl_options{cacerts = CaCerts,
_ ->
{der, CaCerts}
end,
- {ok, _, _, _} = ssl_manager:connection_init(Certs, Role)
+ {ok, _, _, _, _, _} = ssl_manager:connection_init(Certs, Role)
catch
Error:Reason ->
handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile,
erlang:get_stacktrace())
end,
- init_certificates(Cert, CertDbRef, CertDbHandle, CacheHandle, CertFile, Role).
+ init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CertFile, Role).
-init_certificates(undefined, CertDbRef, CertDbHandle, CacheHandle, "", _) ->
- {ok, CertDbRef, CertDbHandle, CacheHandle, undefined};
+init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, <<>>, _) ->
+ {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, undefined};
-init_certificates(undefined, CertDbRef, CertDbHandle, CacheHandle, CertFile, client) ->
+init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CertFile, client) ->
try
- [OwnCert] = ssl_certificate:file_to_certificats(CertFile, CertDbHandle),
- {ok, CertDbRef, CertDbHandle, CacheHandle, OwnCert}
+ [OwnCert] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
+ {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, OwnCert}
catch _Error:_Reason ->
- {ok, CertDbRef, CertDbHandle, CacheHandle, undefined}
+ {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, undefined}
end;
-init_certificates(undefined, CertDbRef, CertDbHandle, CacheRef, CertFile, server) ->
+init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CertFile, server) ->
try
- [OwnCert] = ssl_certificate:file_to_certificats(CertFile, CertDbHandle),
- {ok, CertDbRef, CertDbHandle, CacheRef, OwnCert}
+ [OwnCert] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle),
+ {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, OwnCert}
catch
Error:Reason ->
handle_file_error(?LINE, Error, Reason, CertFile, ecertfile,
erlang:get_stacktrace())
end;
-init_certificates(Cert, CertDbRef, CertDbHandle, CacheRef, _, _) ->
- {ok, CertDbRef, CertDbHandle, CacheRef, Cert}.
+init_certificates(Cert, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, _, _) ->
+ {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, Cert}.
-init_private_key(_, undefined, "", _Password, _Client) ->
+init_private_key(_, undefined, <<>>, _Password, _Client) ->
undefined;
init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
try
@@ -1225,11 +1226,11 @@ certify_client(#state{client_certificate_requested = true, role = client,
socket = Socket,
tls_handshake_hashes = Hashes0} = State) ->
Certificate = ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, client),
- {BinCert, ConnectionStates1, Hashes1} =
+ {BinCert, ConnectionStates, Hashes} =
encode_handshake(Certificate, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinCert),
- State#state{connection_states = ConnectionStates1,
- tls_handshake_hashes = Hashes1};
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes};
certify_client(#state{client_certificate_requested = false} = State) ->
State.
@@ -1246,12 +1247,12 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
Version, PrivateKey, Hashes0) of
#certificate_verify{} = Verified ->
- {BinVerified, ConnectionStates1, Hashes1} =
+ {BinVerified, ConnectionStates, Hashes} =
encode_handshake(Verified, Version,
ConnectionStates0, Hashes0),
Transport:send(Socket, BinVerified),
- State#state{connection_states = ConnectionStates1,
- tls_handshake_hashes = Hashes1};
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes};
ignore ->
State;
#alert{} = Alert ->
@@ -1261,7 +1262,7 @@ verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
do_server_hello(Type, #state{negotiated_version = Version,
- session = #session{session_id = SessId} = Session,
+ session = #session{session_id = SessId},
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _}}
= State0) when is_atom(Type) ->
@@ -1269,29 +1270,13 @@ do_server_hello(Type, #state{negotiated_version = Version,
ServerHello =
ssl_handshake:server_hello(SessId, Version,
ConnectionStates0, Renegotiation),
- State1 = server_hello(ServerHello, State0),
+ State = server_hello(ServerHello, State0),
case Type of
new ->
- new_server_hello(ServerHello, State1);
+ new_server_hello(ServerHello, State);
resumed ->
- ConnectionStates1 = State1#state.connection_states,
- case ssl_handshake:master_secret(Version, Session,
- ConnectionStates1, server) of
- {_, ConnectionStates2} ->
- State2 = State1#state{connection_states=ConnectionStates2,
- session = Session},
- {ConnectionStates, Hashes} =
- finalize_handshake(State2, abbreviated),
- State3 = State2#state{connection_states =
- ConnectionStates,
- tls_handshake_hashes = Hashes},
- {Record, State} = next_record(State3),
- next_state(hello, abbreviated, Record, State);
- #alert{} = Alert ->
- handle_own_alert(Alert, Version, hello, State1),
- {stop, normal, State1}
- end
+ resumed_server_hello(State)
end.
new_server_hello(#server_hello{cipher_suite = CipherSuite,
@@ -1314,6 +1299,27 @@ new_server_hello(#server_hello{cipher_suite = CipherSuite,
{stop, normal, State0}
end.
+resumed_server_hello(#state{session = Session,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version} = State0) ->
+
+ case ssl_handshake:master_secret(Version, Session,
+ ConnectionStates0, server) of
+ {_, ConnectionStates1} ->
+ State1 = State0#state{connection_states = ConnectionStates1,
+ session = Session},
+ {ConnectionStates, Hashes} =
+ finalize_handshake(State1, abbreviated),
+ State2 = State1#state{connection_states =
+ ConnectionStates,
+ tls_handshake_hashes = Hashes},
+ {Record, State} = next_record(State2),
+ next_state(hello, abbreviated, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, hello, State0),
+ {stop, normal, State0}
+ end.
+
handle_new_session(NewId, CipherSuite, Compression, #state{session = Session0} = State0) ->
Session = Session0#session{session_id = NewId,
cipher_suite = CipherSuite,
@@ -1329,10 +1335,10 @@ handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}),
case ssl_handshake:master_secret(Version, Session,
ConnectionStates0, client) of
- {_, ConnectionStates1} ->
+ {_, ConnectionStates} ->
{Record, State} =
next_record(State0#state{
- connection_states = ConnectionStates1,
+ connection_states = ConnectionStates,
session = Session}),
next_state(hello, abbreviated, Record, State);
#alert{} = Alert ->
@@ -1385,16 +1391,16 @@ server_hello(ServerHello, #state{transport_cb = Transport,
server_hello_done(#state{transport_cb = Transport,
socket = Socket,
negotiated_version = Version,
- connection_states = ConnectionStates,
- tls_handshake_hashes = Hashes} = State) ->
+ connection_states = ConnectionStates0,
+ tls_handshake_hashes = Hashes0} = State) ->
HelloDone = ssl_handshake:server_hello_done(),
- {BinHelloDone, NewConnectionStates, NewHashes} =
- encode_handshake(HelloDone, Version, ConnectionStates, Hashes),
+ {BinHelloDone, ConnectionStates, Hashes} =
+ encode_handshake(HelloDone, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinHelloDone),
- State#state{connection_states = NewConnectionStates,
- tls_handshake_hashes = NewHashes}.
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes}.
certify_server(#state{key_algorithm = dh_anon} = State) ->
State;
@@ -1402,18 +1408,18 @@ certify_server(#state{key_algorithm = dh_anon} = State) ->
certify_server(#state{transport_cb = Transport,
socket = Socket,
negotiated_version = Version,
- connection_states = ConnectionStates,
- tls_handshake_hashes = Hashes,
+ connection_states = ConnectionStates0,
+ tls_handshake_hashes = Hashes0,
cert_db = CertDbHandle,
cert_db_ref = CertDbRef,
session = #session{own_certificate = OwnCert}} = State) ->
case ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, server) of
CertMsg = #certificate{} ->
- {BinCertMsg, NewConnectionStates, NewHashes} =
- encode_handshake(CertMsg, Version, ConnectionStates, Hashes),
+ {BinCertMsg, ConnectionStates, Hashes} =
+ encode_handshake(CertMsg, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinCertMsg),
- State#state{connection_states = NewConnectionStates,
- tls_handshake_hashes = NewHashes
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes
};
Alert = #alert{} ->
throw(Alert)
@@ -1443,12 +1449,12 @@ key_exchange(#state{role = server, key_algorithm = Algo,
Algo, ClientRandom,
ServerRandom,
PrivateKey}),
- {BinMsg, ConnectionStates, Hashes1} =
+ {BinMsg, ConnectionStates, Hashes} =
encode_handshake(Msg, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
diffie_hellman_keys = Keys,
- tls_handshake_hashes = Hashes1};
+ tls_handshake_hashes = Hashes};
key_exchange(#state{role = client,
connection_states = ConnectionStates0,
@@ -1459,11 +1465,11 @@ key_exchange(#state{role = client,
socket = Socket, transport_cb = Transport,
tls_handshake_hashes = Hashes0} = State) ->
Msg = rsa_key_exchange(PremasterSecret, PublicKeyInfo),
- {BinMsg, ConnectionStates1, Hashes1} =
+ {BinMsg, ConnectionStates, Hashes} =
encode_handshake(Msg, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinMsg),
- State#state{connection_states = ConnectionStates1,
- tls_handshake_hashes = Hashes1};
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes};
key_exchange(#state{role = client,
connection_states = ConnectionStates0,
key_algorithm = Algorithm,
@@ -1475,11 +1481,11 @@ key_exchange(#state{role = client,
Algorithm == dhe_rsa;
Algorithm == dh_anon ->
Msg = ssl_handshake:key_exchange(client, {dh, DhPubKey}),
- {BinMsg, ConnectionStates1, Hashes1} =
+ {BinMsg, ConnectionStates, Hashes} =
encode_handshake(Msg, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinMsg),
- State#state{connection_states = ConnectionStates1,
- tls_handshake_hashes = Hashes1}.
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes}.
rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
when Algorithm == ?rsaEncryption;
@@ -1501,12 +1507,12 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer},
socket = Socket,
transport_cb = Transport} = State) ->
Msg = ssl_handshake:certificate_request(ConnectionStates0, CertDbHandle, CertDbRef),
- {BinMsg, ConnectionStates1, Hashes1} =
+ {BinMsg, ConnectionStates, Hashes} =
encode_handshake(Msg, Version, ConnectionStates0, Hashes0),
Transport:send(Socket, BinMsg),
State#state{client_certificate_requested = true,
- connection_states = ConnectionStates1,
- tls_handshake_hashes = Hashes1};
+ connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes};
request_client_cert(#state{ssl_options = #ssl_options{verify = verify_none}} =
State) ->
State.
@@ -1697,7 +1703,7 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
read_application_data(Data, #state{user_application = {_Mon, Pid},
socket_options = SOpts,
bytes_to_read = BytesToRead,
- recv_from = From,
+ start_or_recv_from = RecvFrom,
user_data_buffer = Buffer0} = State0) ->
Buffer1 = if
Buffer0 =:= <<>> -> Data;
@@ -1706,9 +1712,9 @@ read_application_data(Data, #state{user_application = {_Mon, Pid},
end,
case get_data(SOpts, BytesToRead, Buffer1) of
{ok, ClientData, Buffer} -> % Send data
- SocketOpt = deliver_app_data(SOpts, ClientData, Pid, From),
+ SocketOpt = deliver_app_data(SOpts, ClientData, Pid, RecvFrom),
State = State0#state{user_data_buffer = Buffer,
- recv_from = undefined,
+ start_or_recv_from = undefined,
bytes_to_read = 0,
socket_options = SocketOpt
},
@@ -1723,7 +1729,7 @@ read_application_data(Data, #state{user_application = {_Mon, Pid},
{more, Buffer} -> % no reply, we need more data
next_record(State0#state{user_data_buffer = Buffer});
{error,_Reason} -> %% Invalid packet in packet mode
- deliver_packet_error(SOpts, Buffer1, Pid, From),
+ deliver_packet_error(SOpts, Buffer1, Pid, RecvFrom),
{stop, normal, State0}
end.
@@ -1843,8 +1849,9 @@ format_reply(binary, _, N, Data) when N > 0 -> % Header mode
format_reply(binary, _, _, Data) ->
Data;
format_reply(list, Packet, _, Data)
- when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers}; Packet == httph;
- Packet == httph_bin->
+ when Packet == http; Packet == {http, headers};
+ Packet == http_bin; Packet == {http_bin, headers};
+ Packet == httph; Packet == httph_bin ->
Data;
format_reply(list, _,_, Data) ->
binary_to_list(Data).
@@ -2008,9 +2015,9 @@ next_state_connection(StateName, #state{send_queue = Queue0,
%% premaster_secret and public_key_info (only needed during handshake)
%% to reduce memory foot print of a connection.
next_state_is_connection(_, State =
- #state{recv_from = From,
+ #state{start_or_recv_from = RecvFrom,
socket_options =
- #socket_options{active = false}}) when From =/= undefined ->
+ #socket_options{active = false}}) when RecvFrom =/= undefined ->
passive_receive(State#state{premaster_secret = undefined,
public_key_info = undefined,
tls_handshake_hashes = {<<>>, <<>>}}, connection);
@@ -2073,7 +2080,7 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
log_alert = true,
session_cache_cb = SessionCacheCb,
renegotiation = {false, first},
- recv_from = undefined,
+ start_or_recv_from = undefined,
send_queue = queue:new()
}.
@@ -2177,7 +2184,7 @@ handle_alerts([Alert | Alerts], {next_state, StateName, State, _Timeout}) ->
handle_alerts(Alerts, handle_alert(Alert, StateName, State)).
handle_alert(#alert{level = ?FATAL} = Alert, StateName,
- #state{from = From, host = Host, port = Port, session = Session,
+ #state{start_or_recv_from = From, host = Host, port = Port, session = Session,
user_application = {_Mon, Pid},
log_alert = Log, role = Role, socket_options = Opts} = State) ->
invalidate_session(Role, Host, Port, Session),
@@ -2259,13 +2266,13 @@ handle_own_alert(Alert, Version, StateName,
ok
end.
-handle_normal_shutdown(Alert, _, #state{from = User, role = Role, renegotiation = {false, first}}) ->
- alert_user(User, Alert, Role);
+handle_normal_shutdown(Alert, _, #state{start_or_recv_from = StartFrom, role = Role, renegotiation = {false, first}}) ->
+ alert_user(StartFrom, Alert, Role);
handle_normal_shutdown(Alert, StateName, #state{socket_options = Opts,
user_application = {_Mon, Pid},
- from = User, role = Role}) ->
- alert_user(StateName, Opts, Pid, User, Alert, Role).
+ start_or_recv_from = RecvFrom, role = Role}) ->
+ alert_user(StateName, Opts, Pid, RecvFrom, Alert, Role).
handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) ->
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
@@ -2291,9 +2298,9 @@ ack_connection(#state{renegotiation = {true, From}} = State) ->
gen_fsm:reply(From, ok),
State#state{renegotiation = undefined};
ack_connection(#state{renegotiation = {false, first},
- from = From} = State) when From =/= undefined ->
- gen_fsm:reply(From, connected),
- State#state{renegotiation = undefined};
+ start_or_recv_from = StartFrom} = State) when StartFrom =/= undefined ->
+ gen_fsm:reply(StartFrom, connected),
+ State#state{renegotiation = undefined, start_or_recv_from = undefined};
ack_connection(State) ->
State.
@@ -2359,7 +2366,29 @@ linux_workaround_transport_delivery_problems(#alert{level = ?FATAL}, Socket) ->
linux_workaround_transport_delivery_problems(_, _) ->
ok.
-get_timeout(#state{ssl_options=#ssl_options{hibernate_after=undefined}}) ->
+get_timeout(#state{ssl_options=#ssl_options{hibernate_after = undefined}}) ->
infinity;
-get_timeout(#state{ssl_options=#ssl_options{hibernate_after=HibernateAfter}}) ->
+get_timeout(#state{ssl_options=#ssl_options{hibernate_after = HibernateAfter}}) ->
HibernateAfter.
+
+handle_trusted_certs_db(#state{ssl_options = #ssl_options{cacertfile = <<>>}}) ->
+ %% No trusted certs specified
+ ok;
+handle_trusted_certs_db(#state{cert_db_ref = Ref,
+ cert_db = CertDb,
+ ssl_options = #ssl_options{cacertfile = undefined}}) ->
+ %% Certs provided as DER directly can not be shared
+ %% with other connections and it is safe to delete them when the connection ends.
+ ssl_certificate_db:remove_trusted_certs(Ref, CertDb);
+handle_trusted_certs_db(#state{file_ref_db = undefined}) ->
+ %% Something went wrong early (typically cacertfile does not exist) so there is nothing to handle
+ ok;
+handle_trusted_certs_db(#state{cert_db_ref = Ref,
+ file_ref_db = RefDb,
+ ssl_options = #ssl_options{cacertfile = File}}) ->
+ case ssl_certificate_db:ref_count(Ref, RefDb, -1) of
+ 0 ->
+ ssl_manager:clean_cert_db(Ref, File);
+ _ ->
+ ok
+ end.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 2e0a3de182..06d45966c1 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -30,7 +30,7 @@
-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([master_secret/4, client_hello/6, server_hello/4, hello/4,
+-export([master_secret/4, client_hello/8, server_hello/4, hello/4,
hello_request/0, certify/7, certificate/4,
client_certificate_verify/5, certificate_verify/5,
certificate_request/3, key_exchange/2, server_key_exchange_hash/2,
@@ -51,14 +51,17 @@
%%====================================================================
%%--------------------------------------------------------------------
-spec client_hello(host(), inet:port_number(), #connection_states{},
- #ssl_options{}, boolean(), der_cert()) -> #client_hello{}.
+ #ssl_options{}, integer(), atom(), boolean(), der_cert()) ->
+ #client_hello{}.
%%
%% Description: Creates a client hello message.
%%--------------------------------------------------------------------
-client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
- ciphers = UserSuites}
- = SslOpts, Renegotiation, OwnCert) ->
-
+client_hello(Host, Port, ConnectionStates,
+ #ssl_options{versions = Versions,
+ ciphers = UserSuites
+ } = SslOpts,
+ Cache, CacheCb, Renegotiation, OwnCert) ->
+
Fun = fun(Version) ->
ssl_record:protocol_version(Version)
end,
@@ -67,15 +70,15 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
- Id = ssl_manager:client_session_id(Host, Port, SslOpts, OwnCert),
+ Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
- #client_hello{session_id = Id,
+ #client_hello{session_id = Id,
client_version = Version,
cipher_suites = cipher_suites(Ciphers, Renegotiation),
compression_methods = ssl_record:compressions(),
random = SecParams#security_parameters.client_random,
- renegotiation_info =
- renegotiation_info(client, ConnectionStates, Renegotiation)
+ renegotiation_info =
+ renegotiation_info(client, ConnectionStates, Renegotiation)
}.
%%--------------------------------------------------------------------
@@ -584,24 +587,23 @@ path_validation_alert({bad_cert, unknown_ca}) ->
path_validation_alert(_) ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE).
-select_session(Hello, Port, Session, Version,
+select_session(Hello, Port, Session, Version,
#ssl_options{ciphers = UserSuites} = SslOpts, Cache, CacheCb, Cert) ->
SuggestedSessionId = Hello#client_hello.session_id,
- SessionId = ssl_manager:server_session_id(Port, SuggestedSessionId,
- SslOpts, Cert),
-
- Suites = available_suites(Cert, UserSuites, Version),
- case ssl_session:is_new(SuggestedSessionId, SessionId) of
- true ->
- CipherSuite =
- select_cipher_suite(Hello#client_hello.cipher_suites, Suites),
+ {SessionId, Resumed} = ssl_session:server_id(Port, SuggestedSessionId,
+ SslOpts, Cert,
+ Cache, CacheCb),
+ Suites = available_suites(Cert, UserSuites, Version),
+ case Resumed of
+ undefined ->
+ CipherSuite = select_cipher_suite(Hello#client_hello.cipher_suites, Suites),
Compressions = Hello#client_hello.compression_methods,
Compression = select_compression(Compressions),
{new, Session#session{session_id = SessionId,
cipher_suite = CipherSuite,
compression_method = Compression}};
- false ->
- {resumed, CacheCb:lookup(Cache, {Port, SessionId})}
+ _ ->
+ {resumed, Resumed}
end.
available_suites(UserSuites, Version) ->
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 6389ff03f5..3e947af2c9 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. 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
@@ -30,9 +30,9 @@
-export([start_link/1, start_link_dist/1,
connection_init/2, cache_pem_file/2,
lookup_trusted_cert/4,
- client_session_id/4, server_session_id/4,
+ new_session_id/1, clean_cert_db/2,
register_session/2, register_session/3, invalidate_session/2,
- invalidate_session/3]).
+ invalidate_session/3, clear_pem_cache/0]).
% Spawn export
-export([init_session_validator/1]).
@@ -56,9 +56,12 @@
-define('24H_in_msec', 8640000).
-define('24H_in_sec', 8640).
+-define(GEN_UNIQUE_ID_MAX_TRIES, 10).
-define(SESSION_VALIDATION_INTERVAL, 60000).
--define(CERTIFICATE_CACHE_CLEANUP, 30000).
+-define(CLEAR_PEM_CACHE, 120000).
-define(CLEAN_SESSION_DB, 60000).
+-define(CLEAN_CERT_DB, 500).
+-define(NOT_TO_BIG, 10).
%%====================================================================
%% API
@@ -82,26 +85,46 @@ start_link_dist(Opts) ->
gen_server:start_link({local, ssl_manager_dist}, ?MODULE, [ssl_manager_dist, Opts], []).
%%--------------------------------------------------------------------
--spec connection_init(string()| {der, list()}, client | server) ->
+-spec connection_init(binary()| {der, list()}, client | server) ->
{ok, certdb_ref(), db_handle(), db_handle()}.
%%
%% Description: Do necessary initializations for a new connection.
%%--------------------------------------------------------------------
+connection_init({der, _} = Trustedcerts, Role) ->
+ call({connection_init, Trustedcerts, Role});
+
+connection_init(<<>> = Trustedcerts, Role) ->
+ call({connection_init, Trustedcerts, Role});
+
connection_init(Trustedcerts, Role) ->
call({connection_init, Trustedcerts, Role}).
+
%%--------------------------------------------------------------------
--spec cache_pem_file(string(), term()) -> {ok, term()} | {error, reason()}.
+-spec cache_pem_file(binary(), term()) -> {ok, term()} | {error, reason()}.
%%
%% Description: Cach a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
- try file:read_file_info(File) of
- {ok, #file_info{mtime = LastWrite}} ->
- cache_pem_file(File, LastWrite, DbHandle)
- catch
- _:Reason ->
- {error, Reason}
+ MD5 = crypto:md5(File),
+ case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of
+ [{Content,_}] ->
+ {ok, Content};
+ [Content] ->
+ {ok, Content};
+ undefined ->
+ call({cache_pem, {MD5, File}})
end.
+
+%%--------------------------------------------------------------------
+-spec clear_pem_cache() -> ok.
+%%
+%% Description: Clear the PEM cache
+%%--------------------------------------------------------------------
+clear_pem_cache() ->
+ %% Not supported for distribution at the moement, should it be?
+ put(ssl_manager, ssl_manager),
+ call(unconditionally_clear_pem_cache).
+
%%--------------------------------------------------------------------
-spec lookup_trusted_cert(term(), reference(), serialnumber(), issuer()) ->
undefined |
@@ -114,22 +137,15 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
ssl_certificate_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer).
%%--------------------------------------------------------------------
--spec client_session_id(host(), inet:port_number(), #ssl_options{},
- der_cert() | undefined) -> session_id().
+-spec new_session_id(integer()) -> session_id().
%%
-%% Description: Select a session id for the client.
+%% Description: Creates a session id for the server.
%%--------------------------------------------------------------------
-client_session_id(Host, Port, SslOpts, OwnCert) ->
- call({client_session_id, Host, Port, SslOpts, OwnCert}).
+new_session_id(Port) ->
+ call({new_session_id, Port}).
-%%--------------------------------------------------------------------
--spec server_session_id(host(), inet:port_number(), #ssl_options{},
- der_cert()) -> session_id().
-%%
-%% Description: Select a session id for the server.
-%%--------------------------------------------------------------------
-server_session_id(Port, SuggestedSessionId, SslOpts, OwnCert) ->
- call({server_session_id, Port, SuggestedSessionId, SslOpts, OwnCert}).
+clean_cert_db(Ref, File) ->
+ erlang:send_after(?CLEAN_CERT_DB, self(), {clean_cert_db, Ref, File}).
%%--------------------------------------------------------------------
-spec register_session(inet:port_number(), #session{}) -> ok.
@@ -177,6 +193,7 @@ init([Name, Opts]) ->
SessionCache = CacheCb:init(proplists:get_value(session_cb_init_args, Opts, [])),
Timer = erlang:send_after(SessionLifeTime * 1000,
self(), validate_sessions),
+ erlang:send_after(?CLEAR_PEM_CACHE, self(), clear_pem_cache),
{ok, #state{certificate_db = CertDb,
session_cache = SessionCache,
session_cache_cb = CacheCb,
@@ -194,55 +211,44 @@ init([Name, Opts]) ->
%%
%% Description: Handling call messages
%%--------------------------------------------------------------------
-handle_call({{connection_init, "", _Role}, Pid}, _From,
- #state{certificate_db = [CertDb |_],
+handle_call({{connection_init, <<>>, _Role}, _Pid}, _From,
+ #state{certificate_db = [CertDb, FileRefDb, PemChace],
session_cache = Cache} = State) ->
- erlang:monitor(process, Pid),
- Result = {ok, make_ref(),CertDb, Cache},
+ Result = {ok, make_ref(),CertDb, FileRefDb, PemChace, Cache},
{reply, Result, State};
handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From,
- #state{certificate_db = [CertDb|_] =Db,
+ #state{certificate_db = [CertDb, FileRefDb, PemChace] = Db,
session_cache = Cache} = State) ->
- erlang:monitor(process, Pid),
Result =
try
{ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, Trustedcerts, Db),
- {ok, Ref, CertDb, Cache}
+ {ok, Ref, CertDb, FileRefDb, PemChace, Cache}
catch
_:Reason ->
{error, Reason}
end,
{reply, Result, State};
-handle_call({{client_session_id, Host, Port, SslOpts, OwnCert}, _}, _,
- #state{session_cache = Cache,
- session_cache_cb = CacheCb} = State) ->
- Id = ssl_session:id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
- {reply, Id, State};
-
-handle_call({{server_session_id, Port, SuggestedSessionId, SslOpts, OwnCert}, _},
+handle_call({{new_session_id,Port}, _},
_, #state{session_cache_cb = CacheCb,
- session_cache = Cache,
- session_lifetime = LifeTime} = State) ->
- Id = ssl_session:id(Port, SuggestedSessionId, SslOpts,
- Cache, CacheCb, LifeTime, OwnCert),
+ session_cache = Cache} = State) ->
+ Id = new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb),
{reply, Id, State};
-handle_call({{cache_pem, File, LastWrite}, Pid}, _,
+
+handle_call({{cache_pem, File}, _Pid}, _,
#state{certificate_db = Db} = State) ->
- try ssl_certificate_db:cache_pem_file(Pid, File, LastWrite, Db) of
+ try ssl_certificate_db:cache_pem_file(File, Db) of
Result ->
{reply, Result, State}
catch
_:Reason ->
{reply, {error, Reason}, State}
end;
-handle_call({{recache_pem, File, LastWrite}, Pid}, From,
- #state{certificate_db = Db} = State) ->
- ssl_certificate_db:uncache_pem_file(File, Db),
- cast({recache_pem, File, LastWrite, Pid, From}),
- {noreply, State}.
+handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_,PemChace]} = State) ->
+ ssl_certificate_db:clear(PemChace),
+ {reply, ok, State}.
%%--------------------------------------------------------------------
-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}.
@@ -278,22 +284,7 @@ handle_cast({invalidate_session, Host, Port,
handle_cast({invalidate_session, Port, #session{session_id = ID} = Session},
#state{session_cache = Cache,
session_cache_cb = CacheCb} = State) ->
- invalidate_session(Cache, CacheCb, {Port, ID}, Session, State);
-
-handle_cast({recache_pem, File, LastWrite, Pid, From},
- #state{certificate_db = [_, FileToRefDb, _]} = State0) ->
- case ssl_certificate_db:lookup(File, FileToRefDb) of
- undefined ->
- {reply, Msg, State} =
- handle_call({{cache_pem, File, LastWrite}, Pid}, From, State0),
- gen_server:reply(From, Msg),
- {noreply, State};
- _ -> %% Send message to self letting cleanup messages be handled
- %% first so that no reference to the old version of file
- %% exists when we cache the new one.
- cast({recache_pem, File, LastWrite, Pid, From}),
- {noreply, State0}
- end.
+ invalidate_session(Cache, CacheCb, {Port, ID}, Session, State).
%%--------------------------------------------------------------------
-spec handle_info(msg(), #state{}) -> {noreply, #state{}}.
@@ -318,23 +309,38 @@ handle_info({delayed_clean_session, Key}, #state{session_cache = Cache,
CacheCb:delete(Cache, Key),
{noreply, State};
-handle_info({'EXIT', _, _}, State) ->
- %% Session validator died!! Do we need to take any action?
- %% maybe error log
+handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) ->
+ case ssl_certificate_db:db_size(PemChace) of
+ N when N < ?NOT_TO_BIG ->
+ ok;
+ _ ->
+ ssl_certificate_db:clear(PemChace)
+ end,
+ erlang:send_after(?CLEAR_PEM_CACHE, self(), clear_pem_cache),
{noreply, State};
-handle_info({'DOWN', _Ref, _Type, _Pid, ecacertfile}, State) ->
- {noreply, State};
-handle_info({'DOWN', _Ref, _Type, Pid, shutdown}, State) ->
- handle_info({remove_trusted_certs, Pid}, State);
-handle_info({'DOWN', _Ref, _Type, Pid, _Reason}, State) ->
- erlang:send_after(?CERTIFICATE_CACHE_CLEANUP, self(),
- {remove_trusted_certs, Pid}),
+handle_info({clean_cert_db, Ref, File},
+ #state{certificate_db = [CertDb,RefDb, PemCache]} = State) ->
+ case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
+ 0 ->
+ MD5 = crypto:md5(File),
+ case ssl_certificate_db:lookup_cached_pem(MD5, PemCache) of
+ [{Content, Ref}] ->
+ ssl_certificate_db:insert(MD5, Content, PemCache);
+ undefined ->
+ ok
+ end,
+ ssl_certificate_db:remove(Ref, RefDb),
+ ssl_certificate_db:remove_trusted_certs(Ref, CertDb);
+ _ ->
+ ok
+ end,
{noreply, State};
-handle_info({remove_trusted_certs, Pid},
- #state{certificate_db = Db} = State) ->
- ssl_certificate_db:remove_trusted_certs(Pid, Db),
+
+handle_info({'EXIT', _, _}, State) ->
+ %% Session validator died!! Do we need to take any action?
+ %% maybe error log
{noreply, State};
handle_info(_Info, State) ->
@@ -406,19 +412,6 @@ session_validation({{Port, _}, Session}, LifeTime) ->
validate_session(Port, Session, LifeTime),
LifeTime.
-cache_pem_file(File, LastWrite, DbHandle) ->
- case ssl_certificate_db:lookup_cached_certs(DbHandle,File) of
- [{_, {Mtime, Content}}] ->
- case LastWrite of
- Mtime ->
- {ok, Content};
- _ ->
- call({recache_pem, File, LastWrite})
- end;
- [] ->
- call({cache_pem, File, LastWrite})
- end.
-
delay_time() ->
case application:get_env(ssl, session_delay_cleanup_time) of
{ok, Time} when is_integer(Time) ->
@@ -448,3 +441,28 @@ last_delay_timer({{_,_},_}, TRef, {LastServer, _}) ->
{LastServer, TRef};
last_delay_timer({_,_}, TRef, {_, LastClient}) ->
{TRef, LastClient}.
+
+%% If we can not generate a not allready in use session ID in
+%% ?GEN_UNIQUE_ID_MAX_TRIES we make the new session uncacheable The
+%% value of ?GEN_UNIQUE_ID_MAX_TRIES is stolen from open SSL which
+%% states : "If we can not find a session id in
+%% ?GEN_UNIQUE_ID_MAX_TRIES either the RAND code is broken or someone
+%% is trying to open roughly very close to 2^128 (or 2^256) SSL
+%% sessions to our server"
+new_id(_, 0, _, _) ->
+ <<>>;
+new_id(Port, Tries, Cache, CacheCb) ->
+ Id = crypto:rand_bytes(?NUM_OF_SESSION_ID_BYTES),
+ case CacheCb:lookup(Cache, {Port, Id}) of
+ undefined ->
+ Now = calendar:datetime_to_gregorian_seconds({date(), time()}),
+ %% New sessions can not be set to resumable
+ %% until handshake is compleate and the
+ %% other session values are set.
+ CacheCb:update(Cache, {Port, Id}, #session{session_id = Id,
+ is_resumable = false,
+ time_stamp = Now}),
+ Id;
+ _ ->
+ new_id(Port, Tries - 1, Cache, CacheCb)
+ end.
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index df5d7e0146..2ad422fc03 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. 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
@@ -28,9 +28,9 @@
-include("ssl_internal.hrl").
%% Internal application API
--export([is_new/2, id/4, id/7, valid_session/2]).
+-export([is_new/2, client_id/4, server_id/6, valid_session/2]).
--define(GEN_UNIQUE_ID_MAX_TRIES, 10).
+-define('24H_in_sec', 8640).
-type seconds() :: integer().
@@ -48,13 +48,13 @@ is_new(_ClientSuggestion, _ServerDecision) ->
true.
%%--------------------------------------------------------------------
--spec id({host(), inet:port_number(), #ssl_options{}}, db_handle(), atom(),
+-spec client_id({host(), inet:port_number(), #ssl_options{}}, db_handle(), atom(),
undefined | binary()) -> binary().
%%
-%% Description: Should be called by the client side to get an id
+%% Description: Should be called by the client side to get an id
%% for the client hello message.
%%--------------------------------------------------------------------
-id(ClientInfo, Cache, CacheCb, OwnCert) ->
+client_id(ClientInfo, Cache, CacheCb, OwnCert) ->
case select_session(ClientInfo, Cache, CacheCb, OwnCert) of
no_session ->
<<>>;
@@ -62,27 +62,6 @@ id(ClientInfo, Cache, CacheCb, OwnCert) ->
SessionId
end.
-%%--------------------------------------------------------------------
--spec id(inet:port_number(), binary(), #ssl_options{}, db_handle(),
- atom(), seconds(), binary()) -> binary().
-%%
-%% Description: Should be called by the server side to get an id
-%% for the server hello message.
-%%--------------------------------------------------------------------
-id(Port, <<>>, _, Cache, CacheCb, _, _) ->
- new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb);
-
-id(Port, SuggestedSessionId, #ssl_options{reuse_sessions = ReuseEnabled,
- reuse_session = ReuseFun},
- Cache, CacheCb, SecondLifeTime, OwnCert) ->
- case is_resumable(SuggestedSessionId, Port, ReuseEnabled,
- ReuseFun, Cache, CacheCb, SecondLifeTime, OwnCert) of
- true ->
- SuggestedSessionId;
- false ->
- new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb)
- end.
-%%--------------------------------------------------------------------
-spec valid_session(#session{}, seconds()) -> boolean().
%%
%% Description: Check that the session has not expired
@@ -91,57 +70,51 @@ valid_session(#session{time_stamp = TimeStamp}, LifeTime) ->
Now = calendar:datetime_to_gregorian_seconds({date(), time()}),
Now - TimeStamp < LifeTime.
+server_id(Port, <<>>, _SslOpts, _Cert, _, _) ->
+ {ssl_manager:new_session_id(Port), undefined};
+server_id(Port, SuggestedId,
+ #ssl_options{reuse_sessions = ReuseEnabled,
+ reuse_session = ReuseFun},
+ Cert, Cache, CacheCb) ->
+ LifeTime = case application:get_env(ssl, session_lifetime) of
+ {ok, Time} when is_integer(Time) -> Time;
+ _ -> ?'24H_in_sec'
+ end,
+ case is_resumable(SuggestedId, Port, ReuseEnabled,ReuseFun,
+ Cache, CacheCb, LifeTime, Cert)
+ of
+ {true, Resumed} ->
+ {SuggestedId, Resumed};
+ {false, undefined} ->
+ {ssl_manager:new_session_id(Port), undefined}
+ end.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+select_session({_, _, #ssl_options{reuse_sessions=false}}, _Cache, _CacheCb, _OwnCert) ->
+ no_session;
select_session({HostIP, Port, SslOpts}, Cache, CacheCb, OwnCert) ->
Sessions = CacheCb:select_session(Cache, {HostIP, Port}),
select_session(Sessions, SslOpts, OwnCert).
select_session([], _, _) ->
no_session;
-
-select_session(Sessions, #ssl_options{ciphers = Ciphers,
- reuse_sessions = ReuseSession}, OwnCert) ->
- IsResumable =
- fun(Session) ->
- ReuseSession andalso resumable(Session#session.is_resumable) andalso
- lists:member(Session#session.cipher_suite, Ciphers)
- andalso (OwnCert == Session#session.own_certificate)
+select_session(Sessions, #ssl_options{ciphers = Ciphers}, OwnCert) ->
+ IsNotResumable =
+ fun([_Id, Session]) ->
+ not (resumable(Session#session.is_resumable) andalso
+ lists:member(Session#session.cipher_suite, Ciphers)
+ andalso (OwnCert == Session#session.own_certificate))
end,
- case [Id || [Id, Session] <- Sessions, IsResumable(Session)] of
- [] ->
- no_session;
- List ->
- hd(List)
- end.
-
-%% If we can not generate a not allready in use session ID in
-%% ?GEN_UNIQUE_ID_MAX_TRIES we make the new session uncacheable The
-%% value of ?GEN_UNIQUE_ID_MAX_TRIES is stolen from open SSL which
-%% states : "If we can not find a session id in
-%% ?GEN_UNIQUE_ID_MAX_TRIES either the RAND code is broken or someone
-%% is trying to open roughly very close to 2^128 (or 2^256) SSL
-%% sessions to our server"
-new_id(_, 0, _, _) ->
- <<>>;
-new_id(Port, Tries, Cache, CacheCb) ->
- Id = crypto:rand_bytes(?NUM_OF_SESSION_ID_BYTES),
- case CacheCb:lookup(Cache, {Port, Id}) of
- undefined ->
- Now = calendar:datetime_to_gregorian_seconds({date(), time()}),
- %% New sessions can not be set to resumable
- %% until handshake is compleate and the
- %% other session values are set.
- CacheCb:update(Cache, {Port, Id}, #session{session_id = Id,
- is_resumable = false,
- time_stamp = Now}),
- Id;
- _ ->
- new_id(Port, Tries - 1, Cache, CacheCb)
+ case lists:dropwhile(IsNotResumable, Sessions) of
+ [] -> no_session;
+ [[Id, _]|_] -> Id
end.
-is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache,
+is_resumable(_, _, false, _, _, _, _, _) ->
+ {false, undefined};
+is_resumable(SuggestedSessionId, Port, true, ReuseFun, Cache,
CacheCb, SecondLifeTime, OwnCert) ->
case CacheCb:lookup(Cache, {Port, SuggestedSessionId}) of
#session{cipher_suite = CipherSuite,
@@ -149,14 +122,17 @@ is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache,
compression_method = Compression,
is_resumable = IsResumable,
peer_certificate = PeerCert} = Session ->
- ReuseEnabled
- andalso resumable(IsResumable)
+ case resumable(IsResumable)
andalso (OwnCert == SessionOwnCert)
- andalso valid_session(Session, SecondLifeTime)
- andalso ReuseFun(SuggestedSessionId, PeerCert,
- Compression, CipherSuite);
+ andalso valid_session(Session, SecondLifeTime)
+ andalso ReuseFun(SuggestedSessionId, PeerCert,
+ Compression, CipherSuite)
+ of
+ true -> {true, Session};
+ false -> {false, undefined}
+ end;
undefined ->
- false
+ {false, undefined}
end.
resumable(new) ->
diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl
index f9bbf905e1..5c6ee3c54c 100644
--- a/lib/ssl/src/ssl_session_cache.erl
+++ b/lib/ssl/src/ssl_session_cache.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. 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
@@ -32,7 +32,7 @@
%% Description: Return table reference. Called by ssl_manager process.
%%--------------------------------------------------------------------
init(_) ->
- ets:new(cache_name(), [set, protected]).
+ ets:new(cache_name(), [ordered_set, protected]).
%%--------------------------------------------------------------------
%% Description: Handles cache table at termination of ssl manager.
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 6b1da63d08..a0f54c0359 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -120,11 +120,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
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 -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(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 -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 590ecf33ca..5a52917d6c 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -50,6 +50,7 @@
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
+ catch crypto:stop(),
try crypto:start() of
ok ->
application:start(public_key),
@@ -261,7 +262,8 @@ all() ->
no_reuses_session_server_restart_new_cert_file, reuseaddr,
hibernate, connect_twice, renegotiate_dos_mitigate_active,
renegotiate_dos_mitigate_passive,
- tcp_error_propagation_in_active_mode, rizzo, no_rizzo_rc4
+ tcp_error_propagation_in_active_mode, rizzo, no_rizzo_rc4,
+ recv_error_handling
].
groups() ->
@@ -3649,6 +3651,8 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client0),
+ ssl:clear_pem_cache(),
+
NewServerOpts = new_config(PrivDir, DsaServerOpts),
Server1 =
@@ -3872,16 +3876,16 @@ tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ServerOpts}]),
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
{Client, #sslsocket{pid=Pid} = SslSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, receive_msg, []}},
- {options, ClientOpts}]),
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, receive_msg, []}},
+ {options, ClientOpts}]),
{status, _, _, StatusInfo} = sys:get_status(Pid),
[_, _,_, _, Prop] = StatusInfo,
@@ -3892,6 +3896,32 @@ tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
Pid ! {tcp_error, Socket, etimedout},
ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}).
+
+
+%%--------------------------------------------------------------------
+
+recv_error_handling(doc) ->
+ ["Special case of call error handling"];
+recv_error_handling(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, recv_close, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, #sslsocket{pid=Pid} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+ ssl:close(SslSocket),
+ ssl_test_lib:check_result(Server, ok).
+
+
%%--------------------------------------------------------------------
rizzo(doc) -> ["Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is
@@ -3903,7 +3933,7 @@ rizzo(Config) when is_list(Config) ->
{?MODULE, send_recv_result_active_rizzo, []}),
run_send_recv_rizzo(Ciphers, Config, tlsv1,
{?MODULE, send_recv_result_active_rizzo, []}).
-
+%%--------------------------------------------------------------------
no_rizzo_rc4(doc) ->
["Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"];
@@ -3914,6 +3944,7 @@ no_rizzo_rc4(Config) when is_list(Config) ->
run_send_recv_rizzo(Ciphers, Config, tlsv1,
{?MODULE, send_recv_result_active_no_rizzo, []}).
+%%--------------------------------------------------------------------
run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
Result = lists:map(fun(Cipher) ->
rizzo_test(Cipher, Config, Version, Mfa) end,
@@ -3967,6 +3998,15 @@ send_recv_result(Socket) ->
{ok,"Hello world"} = ssl:recv(Socket, 11),
ok.
+recv_close(Socket) ->
+ {error, closed} = ssl:recv(Socket, 11),
+ receive
+ {_,{error,closed}} ->
+ error_extra_close_sent_to_user_process
+ after 500 ->
+ ok
+ end.
+
send_recv_result_active(Socket) ->
ssl:send(Socket, "Hello world"),
receive
diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index 12d92c8ca1..818f7f1897 100644
--- a/lib/ssl/test/ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -369,7 +369,7 @@ mk_node_cmdline(ListenPort, Name, Args) ->
_ -> "-name "
end,
{ok, Pwd} = file:get_cwd(),
- Prog ++ " "
+ "\"" ++ Prog ++ "\" "
++ Static ++ " "
++ NameSw ++ " " ++ Name ++ " "
++ "-pa " ++ Pa ++ " "
@@ -729,7 +729,7 @@ add_ssl_opts_config(Config) ->
[{ssl_opts, "-boot " ++ Script} | Config]
catch
_:_ ->
- [{ssl_opts, "-pa " ++ filename:dirname(code:which(ssl))}
+ [{ssl_opts, "-pa \"" ++ filename:dirname(code:which(ssl))++"\""}
| add_comment_config(
"Bootscript wasn't used since the test wasn't run on an "
"installed OTP system.",
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 4b74f57a60..593b1fda5e 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. 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
@@ -53,6 +53,7 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config) ->
+ catch crypto:stop(),
try crypto:start() of
ok ->
application:start(public_key),
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 24e86b3913..02b5516e35 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -37,6 +37,7 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config) ->
+ catch crypto:stop(),
try crypto:start() of
ok ->
application:start(public_key),
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 491aa893c2..6d758ecb01 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -49,6 +49,7 @@
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
+ catch crypto:stop(),
try crypto:start() of
ok ->
application:start(public_key),
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 01fca1f166..f593c1c552 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -50,6 +50,7 @@ init_per_suite(Config0) ->
false ->
{skip, "Openssl not found"};
_ ->
+ catch crypto:stop(),
try crypto:start() of
ok ->
application:start(public_key),
@@ -112,6 +113,9 @@ special_init(TestCase, Config)
special_init(ssl2_erlang_server_openssl_client, Config) ->
check_sane_openssl_sslv2(Config);
+special_init(ciphers_dsa_signed_certs, Config) ->
+ check_sane_openssl_dsa(Config);
+
special_init(_, Config) ->
Config.
@@ -600,7 +604,7 @@ erlang_server_openssl_client_no_wrap_sequence_number(Config) when is_list(Config
{from, self()},
{mfa, {ssl_test_lib,
trigger_renegotiate, [[Data, N+2]]}},
- {options, [{renegotiate_at, N} | ServerOpts]}]),
+ {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
@@ -1440,14 +1444,24 @@ check_sane_openssl_renegotaite(Config) ->
{skip, "Known renegotiation bug in OppenSSL"};
"OpenSSL 0.9.7" ++ _ ->
{skip, "Known renegotiation bug in OppenSSL"};
+ "OpenSSL 1.0.1c" ++ _ ->
+ {skip, "Known renegotiation bug in OppenSSL"};
_ ->
Config
end.
check_sane_openssl_sslv2(Config) ->
case os:cmd("openssl version") of
- "OpenSSL 1.0.0" ++ _ ->
+ "OpenSSL 1." ++ _ ->
{skip, "sslv2 by default turned of in 1.*"};
_ ->
Config
end.
+
+check_sane_openssl_dsa(Config) ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.1" ++ _ ->
+ {skip, "known dsa bug in openssl"};
+ _ ->
+ Config
+ end.
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile
index 6c92756ae7..c3138c4d9f 100644
--- a/lib/stdlib/doc/src/Makefile
+++ b/lib/stdlib/doc/src/Makefile
@@ -173,15 +173,15 @@ $(SPECDIR)/specs_erl_id_trans.xml:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index a7e010a05f..b7b5d497d0 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -53,7 +53,7 @@
<item>Basically the same as UTF-32, but without some Unicode semantics, defined by IEEE and has little use as a separate encoding standard. For all normal (and possibly abnormal) usages, UTF-32 and UCS-4 are interchangeable.</item>
</taglist>
<p>Certain ranges of characters are left unused and certain ranges are even deemed invalid. The most notable invalid range is 16#D800 - 16#DFFF, as the UTF-16 encoding does not allow for encoding of these numbers. It can be speculated that the UTF-16 encoding standard was, from the beginning, expected to be able to hold all Unicode characters in one 16-bit entity, but then had to be extended, leaving a hole in the Unicode range to cope with backward compatibility.</p>
-<p>Additionally, the codepoint 16#FEFF is used for byte order marks (BOM's) and use of that character is not encouraged in other contexts than that. It actually is valid though, as the character "ZWNBS" (Zero Width Non Breaking Space). BOM's are used to identify encodings and byte order for programs where such parameters are not known in advance. Byte order marks are more seldom used than one could expect, put their use is becoming more widely spread as they provide the means for programs to make educated guesses about the Unicode format of a certain file.</p>
+<p>Additionally, the codepoint 16#FEFF is used for byte order marks (BOM's) and use of that character is not encouraged in other contexts than that. It actually is valid though, as the character "ZWNBS" (Zero Width Non Breaking Space). BOM's are used to identify encodings and byte order for programs where such parameters are not known in advance. Byte order marks are more seldom used than one could expect, but their use is becoming more widely spread as they provide the means for programs to make educated guesses about the Unicode format of a certain file.</p>
</section>
<section>
<title>Standard Unicode representation in Erlang</title>
@@ -210,6 +210,12 @@ Eshell V5.7 (abort with ^G)
</section>
</section>
<section>
+<title>Unicode in environment variables and parameters</title>
+<p>Environment variables and their interpretation is handled much in the same way as file names. If Unicode file names are enabled, environment variables as well as parameters to the Erlang VM are expected to be in Unicode.</p>
+<p>If Unicode file names are enabled, the calls to <seealso marker="kernel:os#os_getenv/0"><c>os:getenv/0</c></seealso>, <seealso marker="kernel:os#os_getenv/1"><c>os:getenv/1</c></seealso> and <seealso marker="kernel:os#os_putenv/2"><c>os:putenv/2</c></seealso> will handle Unicode strings. On Unix-like platforms, the built-in functions will translate environment variables in UTF-8 to/from Unicode strings, possibly with codepoints > 255. On Windows the Unicode versions of the environment system API will be used, also allowing for codepoints > 255.</p>
+<p>On Unix-like operating systems, parameters are expected to be UTF-8 without translation if Unicode file names are enabled.</p>
+</section>
+<section>
<title>Unicode-aware modules</title>
<p>Most of the modules in Erlang/OTP are of course Unicode-unaware in the sense that they have no notion of Unicode and really shouldn't have. Typically they handle non-textual or byte-oriented data (like <c>gen_tcp</c> etc).</p>
<p>Modules that actually handle textual data (like <c>io_lib</c>, <c>string</c> etc) are sometimes subject to conversion or extension to be able to handle Unicode characters.</p>
diff --git a/lib/stdlib/examples/Makefile b/lib/stdlib/examples/Makefile
index 25c88d1de3..198aceb3a9 100644
--- a/lib/stdlib/examples/Makefile
+++ b/lib/stdlib/examples/Makefile
@@ -47,6 +47,6 @@ RELSYSDIR = $(RELEASE_PATH)/lib/stdlib-$(STDLIB_VSN)/examples
EXAMPLES = erl_id_trans.erl
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(EXAMPLES) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(EXAMPLES) "$(RELSYSDIR)"
release_docs_spec:
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 90e239b00f..54186a3ba7 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -167,6 +167,7 @@ docs:
# This is a trick so that the preloaded files will get the correct type
# specifications.
primary_bootstrap_compiler: \
+ $(BOOTSTRAP_COMPILER)/ebin/epp.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_scan.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_lint.beam \
@@ -198,13 +199,13 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) erl_parse.yrl $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) erl_parse.yrl "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index abab81d31f..648ff349a4 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -248,6 +248,8 @@ format_error({illegal_guard_local_call, {F,A}}) ->
io_lib:format("call to local/imported function ~w/~w is illegal in guard",
[F,A]);
format_error(illegal_guard_expr) -> "illegal guard expression";
+format_error(deprecated_tuple_fun) ->
+ "tuple funs are deprecated and will be removed in R16";
%% --- exports ---
format_error({explicit_export,F,A}) ->
io_lib:format("in this release, the call to ~w/~w must be written "
@@ -1914,7 +1916,8 @@ gexpr({call,Line,{remote,_Lr,{atom,_Lm,erlang},{atom,_Lf,F}},As}, Vt, St0) ->
true -> {Asvt,St1};
false -> {Asvt,add_error(Line, illegal_guard_expr, St1)}
end;
-gexpr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,F}]},As}, Vt, St) ->
+gexpr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,F}]},As}, Vt, St0) ->
+ St = add_warning(L, deprecated_tuple_fun, St0),
gexpr({call,L,{remote,Lt,{atom,Lm,erlang},{atom,Lf,F}},As}, Vt, St);
gexpr({op,Line,Op,A}, Vt, St0) ->
{Avt,St1} = gexpr(A, Vt, St0),
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index 27e70ac4d4..498d850df3 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -22,7 +22,7 @@
-export([script_name/0, create/2, extract/2]).
%% Internal API.
--export([start/0, start/1]).
+-export([start/0, start/1, parse_file/1]).
%%-----------------------------------------------------------------------
@@ -346,7 +346,8 @@ parse_and_run(File, Args, Options) ->
case Source of
archive ->
{ok, FileInfo} = file:read_file_info(File),
- case code:set_primary_archive(File, FormsOrBin, FileInfo) of
+ case code:set_primary_archive(File, FormsOrBin, FileInfo,
+ fun escript:parse_file/1) of
ok when CheckOnly ->
case code:load_file(Module) of
{module, _} ->
@@ -396,6 +397,19 @@ parse_and_run(File, Args, Options) ->
%% Parse script
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Only used as callback by erl_prim_loader
+parse_file(File) ->
+ try parse_file(File, false) of
+ {_Source, _Module, FormsOrBin, _HasRecs, _Mode}
+ when is_binary(FormsOrBin) ->
+ {ok, FormsOrBin};
+ _ ->
+ {error, no_archive_bin}
+ catch
+ throw:Reason ->
+ {error, Reason}
+ end.
+
parse_file(File, CheckOnly) ->
{HeaderSz, NextLineNo, Fd, Sections} =
parse_header(File, false),
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index d532cea187..b098d4cb91 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -264,6 +264,9 @@ ensure_dir(F) ->
case do_is_dir(Dir, file) of
true ->
ok;
+ false when Dir =:= F ->
+ %% Protect against infinite loop
+ {error,einval};
false ->
ensure_dir(Dir),
case file:make_dir(Dir) of
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index dbfcbea4f7..870af4e95f 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -726,6 +726,8 @@ nativename(Name0) ->
_ -> Name
end.
+win32_nativename(Name) when is_binary(Name) ->
+ binary:replace(Name, <<"/">>, <<"\\">>, [global]);
win32_nativename([$/|Rest]) ->
[$\\|win32_nativename(Rest)];
win32_nativename([C|Rest]) ->
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 59c6d240ba..04308a51b7 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -270,7 +270,7 @@ enter_loop(Mod, Options, State) ->
enter_loop(Mod, Options, State, self(), infinity).
enter_loop(Mod, Options, State, ServerName = {Scope, _})
- when Scope == local; Scope == local ->
+ when Scope == local; Scope == global ->
enter_loop(Mod, Options, State, ServerName, infinity);
enter_loop(Mod, Options, State, ServerName = {via, _, _}) ->
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
index 314fd60903..cf4b87d7eb 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. 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
@@ -209,7 +209,7 @@ explain_reason(badarg, error, [], _PF, _S) ->
explain_reason({badarg,V}, error=Cl, [], PF, S) -> % orelse, andalso
format_value(V, <<"bad argument: ">>, Cl, PF, S);
explain_reason(badarith, error, [], _PF, _S) ->
- <<"bad argument in an arithmetic expression">>;
+ <<"an error occurred when evaluating an arithmetic expression">>;
explain_reason({badarity,{Fun,As}}, error, [], _PF, _S)
when is_function(Fun) ->
%% Only the arity is displayed, not the arguments As.
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 4de6ea3ee7..29b8e28d3a 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -135,10 +135,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) stdlib.spec $(EMAKEFILE) \
- $(ERL_FILES) $(COVERFILE) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(ERL_FILES) $(COVERFILE) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index dcd622b984..9f9d97b619 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1331,17 +1331,20 @@ guard(Config) when is_list(Config) ->
foo.
">>,
[warn_unused_vars, nowarn_obsolete_guard],
- {errors,[{2,erl_lint,illegal_guard_expr},
- {4,erl_lint,illegal_guard_expr},
- {6,erl_lint,illegal_guard_expr},
- {8,erl_lint,illegal_guard_expr},
- {10,erl_lint,illegal_guard_expr},
- {12,erl_lint,illegal_guard_expr},
- {14,erl_lint,illegal_guard_expr},
- {16,erl_lint,illegal_guard_expr},
- {18,erl_lint,illegal_guard_expr},
- {20,erl_lint,illegal_guard_expr}],
- []}},
+ {error,[{2,erl_lint,illegal_guard_expr},
+ {4,erl_lint,illegal_guard_expr},
+ {6,erl_lint,illegal_guard_expr},
+ {8,erl_lint,illegal_guard_expr},
+ {10,erl_lint,illegal_guard_expr},
+ {12,erl_lint,illegal_guard_expr},
+ {14,erl_lint,illegal_guard_expr},
+ {16,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr},
+ {20,erl_lint,illegal_guard_expr}],
+ [{8,erl_lint,deprecated_tuple_fun},
+ {14,erl_lint,deprecated_tuple_fun},
+ {20,erl_lint,deprecated_tuple_fun},
+ {28,erl_lint,deprecated_tuple_fun}]}},
{guard6,
<<"-record(apa,{a=a,b=foo:bar()}).
apa() ->
diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl
index 9f95df062b..38c085616d 100644
--- a/lib/stdlib/test/escript_SUITE.erl
+++ b/lib/stdlib/test/escript_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2012. 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,6 +29,7 @@
module_script/1,
beam_script/1,
archive_script/1,
+ archive_script_file_access/1,
epp/1,
create_and_extract/1,
foldl/1,
@@ -44,7 +45,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[basic, errors, strange_name, emulator_flags,
module_script, beam_script, archive_script, epp,
- create_and_extract, foldl, overflow].
+ create_and_extract, foldl, overflow,
+ archive_script_file_access].
groups() ->
[].
@@ -62,7 +64,7 @@ end_per_group(_GroupName, Config) ->
Config.
init_per_testcase(_Case, Config) ->
- ?line Dog = ?t:timetrap(?t:minutes(1)),
+ ?line Dog = ?t:timetrap(?t:minutes(2)),
[{watchdog,Dog}|Config].
end_per_testcase(_Case, Config) ->
@@ -356,7 +358,7 @@ beam_script(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Create an archive file containing two entire applications plus two
%% alternate main modules. Generate a new escript containing the archive
-%% (with .app and .beam files and ) and the escript header.
+%% (with .app and .beam files and) and the escript header.
archive_script(Config) when is_list(Config) ->
%% Copy the orig files to priv_dir
@@ -464,6 +466,147 @@ archive_script(Config) when is_list(Config) ->
ok.
+%% Test the correction of OTP-10071
+%% The errors identified are
+%%
+%% a) If primary archive was named "xxx", then a file in the same
+%% directory named "xxxyyy" would be interpreted as a file named yyy
+%% inside the archive.
+%%
+%% b) erl_prim_loader did not correctly create and normalize absolute
+%% paths for primary archive and files inside it, so unless given
+%% with exact same path files inside the archive would not be
+%% found. E.g. if escript was started as ./xxx then "xxx/file"
+%% would not be found since erl_prim_loader would try to match
+%% /full/path/to/xxx with /full/path/to/./xxx. Same problem with
+%% ../. Also, the use of symlinks in the path to the archive would
+%% cause problems.
+%%
+%% c) Depending on how the primary archive was built,
+%% erl_prim_loader:list_dir/1 would sometimes return an empty string
+%% inside the file list. This was a virtual element representing the
+%% top directory of the archive. This shall not occur.
+%%
+archive_script_file_access(Config) when is_list(Config) ->
+ %% Copy the orig files to priv_dir
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ MainMod = "archive_script_file_access",
+ MainSrc = MainMod ++ ".erl",
+ MainBeam = MainMod ++ ".beam",
+
+ Archive = filename:join([PrivDir, "archive_script_file_access.zip"]),
+ ?line {ok, _} = zip:create(Archive, ["archive_script_file_access"],
+ [{compress, []}, {cwd, DataDir}]),
+ ?line {ok, _} = zip:extract(Archive, [{cwd, PrivDir}]),
+ TopDir = filename:join([PrivDir, "archive_script_file_access"]),
+
+ %% Compile the code
+ ?line ok = compile_files([MainSrc], TopDir, TopDir),
+
+ %% First, create a file structure which will be included in the archive:
+ %%
+ %% dir1/
+ %% dir1/subdir1/
+ %% dir1/subdir1/file1
+ %%
+ {ok, OldDir} = file:get_cwd(),
+ ok = file:set_cwd(TopDir),
+ DummyDir = "dir1",
+ DummySubDir = filename:join(DummyDir, "subdir1"),
+ RelDummyFile = filename:join(DummySubDir, "file1"),
+ DummyFile = filename:join(TopDir,RelDummyFile),
+ ok = filelib:ensure_dir(DummyFile),
+ ok = file:write_file(DummyFile, ["foo\nbar\nbaz"]),
+
+ %% 1. Create zip archive by adding the dummy file and the beam
+ %% file as binaries to zip.
+ %%
+ %% This used to provoke the following issues when the script was run as
+ %% "./<script_name>":
+ %% a. erl_prim_loader:read_file_info/1 returning 'error'
+ %% b. erl_prim_loader:list_dir/1 returning {ok, ["dir1", [], "file1"]}
+ %% leading to an infinite loop in reltool_target:spec_dir/1
+ Files1 =
+ lists:map(fun(Filename) ->
+ {ok, Bin} = file:read_file(Filename),
+ {Filename,Bin}
+ end,
+ [RelDummyFile,MainBeam]),
+ {ok, {"mem", Bin1}} = zip:create("mem", Files1, [memory]),
+
+ %% Create the escript
+ ScriptName1 = "archive_script_file_access1",
+ Script1 = filename:join([PrivDir, ScriptName1]),
+ Flags = "-escript main " ++ MainMod,
+ ok = escript:create(Script1,[shebang,{emu_args,Flags},{archive,Bin1}]),
+ ok = file:change_mode(Script1,8#00744),
+
+ %% If supported, create a symlink to the script. This is used to
+ %% test error b) described above this test case.
+ SymlinkName1 = "symlink_to_"++ScriptName1,
+ Symlink1 = filename:join([PrivDir, SymlinkName1]),
+ file:make_symlink(ScriptName1,Symlink1), % will fail if not supported
+
+ %% Also add a dummy file in the same directory with the same name
+ %% as the script except is also has an extension. This used to
+ %% test error a) described above this test case.
+ ok = file:write_file(Script1 ++ ".extension",
+ <<"same name as script, but with extension">>),
+
+ %% Change to script's directory and run it as "./<script_name>"
+ ok = file:set_cwd(PrivDir),
+ run(PrivDir, "./" ++ ScriptName1 ++ " " ++ ScriptName1,
+ [<<"ExitCode:0">>]),
+ ok = file:set_cwd(TopDir),
+
+
+ %% 2. Create zip archive by letting zip read the files from the file system
+ %%
+ %% The difference compared to the archive_script_file_access1 is
+ %% that this will have a file element for each directory in the
+ %% archive - while archive_script_file_access1 will only have a
+ %% file element per regular file.
+ Files2 = [DummyDir,MainBeam],
+ {ok, {"mem", Bin2}} = zip:create("mem", Files2, [memory]),
+
+ %% Create the escript
+ ScriptName2 = "archive_script_file_access2",
+ Script2 = filename:join([PrivDir, ScriptName2]),
+ ok = escript:create(Script2,[shebang,{emu_args,Flags},{archive,Bin2}]),
+ ok = file:change_mode(Script2,8#00744),
+
+ %% Also add a dummy file in the same directory with the same name
+ %% as the script except is also has an extension. This used to
+ %% test error a) described above this test case.
+ ok = file:write_file(Script2 ++ ".extension",
+ <<"same name as script, but with extension">>),
+
+ %% If supported, create a symlink to the script. This is used to
+ %% test error b) described above this test case.
+ SymlinkName2 = "symlink_to_"++ScriptName2,
+ Symlink2 = filename:join([PrivDir, SymlinkName2]),
+ file:make_symlink(ScriptName2,Symlink2), % will fail if not supported
+
+ %% Change to script's directory and run it as "./<script_name>"
+ ok = file:set_cwd(PrivDir),
+ run(PrivDir, "./" ++ ScriptName2 ++ " " ++ ScriptName2,
+ [<<"ExitCode:0">>]),
+
+ %% 3. If symlinks are supported, run one of the scripts via a symlink.
+ %%
+ %% This is in order to test error b) described above this test case.
+ case file:read_link(Symlink2) of
+ {ok,_} ->
+ run(PrivDir, "./" ++ SymlinkName2 ++ " " ++ ScriptName2,
+ [<<"ExitCode:0">>]);
+ _ -> % not supported
+ ok
+ end,
+ ok = file:set_cwd(OldDir).
+
+
compile_app(TopDir, AppName) ->
AppDir = filename:join([TopDir, AppName]),
SrcDir = filename:join([AppDir, "src"]),
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl
index de56579998..431a51b0e5 100644
--- a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl
@@ -21,6 +21,8 @@
-export([main/1]).
+-include_lib("kernel/include/file.hrl").
+
-define(DUMMY, archive_script_dummy).
-define(DICT, archive_script_dict).
@@ -32,7 +34,7 @@ main(MainArgs) ->
io:format("dummy:~p\n",[[E || E <- ErlArgs, element(1, E) =:= ?DUMMY]]),
%% Start the applications
- {error, {not_started, ?DICT}} = application:start(archive_script_dummy),
+ {error, {not_started, ?DICT}} = application:start(?DUMMY),
ok = application:start(?DICT),
ok = application:start(?DUMMY),
@@ -57,4 +59,17 @@ main(MainArgs) ->
ok = ?DICT:erase(Tab, Key),
error = ?DICT:find(Tab, Key),
ok = ?DICT:erase(Tab),
+
+ %% Check mtime related caching bug with escript/primary archive files
+ Escript = escript:script_name(),
+ {ok, FileInfo} = file:read_file_info(Escript),
+ %% Modify mtime of archive file and try to reload module
+ FileInfo2 = FileInfo#file_info{mtime=calendar:now_to_local_time(now())},
+ ok = file:write_file_info(Escript, FileInfo2),
+ Module = ?DICT,
+ {file, _} = code:is_loaded(Module),
+ true = code:delete(Module),
+ false = code:is_loaded(Module),
+ {module, Module} = code:ensure_loaded(Module),
+
ok.
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl
new file mode 100644
index 0000000000..b03c8ba70d
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl
@@ -0,0 +1,105 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. 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(archive_script_file_access).
+-behaviour(escript).
+
+-export([main/1]).
+
+-include_lib("kernel/include/file.hrl").
+
+main([RelArchiveFile]) ->
+
+ AbsArchiveFile = filename:absname(RelArchiveFile),
+ DotSlashArchiveFile = "./" ++ RelArchiveFile,
+
+ Beam = atom_to_list(?MODULE) ++ ".beam",
+ AbsBeam = filename:join(AbsArchiveFile,Beam),
+ RelBeam = filename:join(RelArchiveFile,Beam),
+ DotSlashBeam = filename:join(DotSlashArchiveFile,Beam),
+ Dir = "dir1",
+ AbsDir = filename:join(AbsArchiveFile,Dir),
+ RelDir = filename:join(RelArchiveFile,Dir),
+ DotSlashDir = filename:join(DotSlashArchiveFile,Dir),
+ SubDir = "subdir1",
+ AbsSubDir = filename:join(AbsDir,SubDir),
+ RelSubDir = filename:join(RelDir,SubDir),
+ DotSlashSubDir = filename:join(DotSlashDir,SubDir),
+
+ {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile),
+ {ok,List1} = erl_prim_loader:list_dir(RelArchiveFile),
+ {ok,List1} = erl_prim_loader:list_dir(DotSlashArchiveFile),
+ {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile ++ "/"),
+ {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile ++ "/."),
+ {ok,List1} = erl_prim_loader:list_dir(filename:join([AbsDir,".."])),
+ {ok,List1} = erl_prim_loader:list_dir(filename:join([RelDir,".."])),
+ {ok,List1} = erl_prim_loader:list_dir(filename:join([DotSlashDir,".."])),
+ {ok,List1} = erl_prim_loader:list_dir(filename:join([AbsSubDir,"..",".."])),
+ {ok,List1} = erl_prim_loader:list_dir(filename:join([RelSubDir,"..",".."])),
+ {ok,List1} = erl_prim_loader:list_dir(filename:join([DotSlashSubDir,"..",".."])),
+ false = lists:member([],List1),
+
+ %% If symlinks are supported on this platform...
+ RelSymlinkArchiveFile = "symlink_to_" ++ RelArchiveFile,
+ case file:read_link(RelSymlinkArchiveFile) of
+ {ok,_} ->
+ DotSlashSymlinkArchiveFile = "./" ++ RelSymlinkArchiveFile,
+ AbsSymlinkArchiveFile=filename:join(filename:dirname(AbsArchiveFile),
+ RelSymlinkArchiveFile),
+ {ok,List1} = erl_prim_loader:list_dir(AbsSymlinkArchiveFile),
+ {ok,List1} = erl_prim_loader:list_dir(RelSymlinkArchiveFile),
+ {ok,List1} = erl_prim_loader:list_dir(DotSlashSymlinkArchiveFile);
+ _ -> % not supported
+ ok
+ end,
+
+
+ {ok,List2} = erl_prim_loader:list_dir(AbsDir),
+ {ok,List2} = erl_prim_loader:list_dir(RelDir),
+ {ok,List2} = erl_prim_loader:list_dir(DotSlashDir),
+ false = lists:member([],List2),
+
+ error = erl_prim_loader:list_dir(AbsBeam),
+ error = erl_prim_loader:list_dir(RelBeam),
+ error = erl_prim_loader:list_dir(DotSlashBeam),
+
+ error = erl_prim_loader:get_file(AbsArchiveFile),
+ error = erl_prim_loader:get_file(RelArchiveFile),
+ error = erl_prim_loader:get_file(DotSlashArchiveFile),
+ error = erl_prim_loader:get_file(AbsArchiveFile ++ "/"),
+ error = erl_prim_loader:get_file(AbsArchiveFile ++ "/."),
+ {ok,Bin,AbsBeam} = erl_prim_loader:get_file(AbsBeam),
+ {ok,Bin,RelBeam} = erl_prim_loader:get_file(RelBeam),
+ {ok,Bin,DotSlashBeam} = erl_prim_loader:get_file(DotSlashBeam),
+
+ {ok,#file_info{type=directory}=DFI} =
+ erl_prim_loader:read_file_info(AbsArchiveFile),
+ {ok,DFI} = erl_prim_loader:read_file_info(RelArchiveFile),
+ {ok,DFI} = erl_prim_loader:read_file_info(DotSlashArchiveFile),
+ {ok,DFI} = erl_prim_loader:read_file_info(AbsArchiveFile ++ "/"),
+ {ok,DFI} = erl_prim_loader:read_file_info(AbsArchiveFile ++ "/."),
+ {ok,#file_info{type=regular}=RFI} = erl_prim_loader:read_file_info(AbsBeam),
+ {ok,RFI} = erl_prim_loader:read_file_info(RelBeam),
+ {ok,RFI} = erl_prim_loader:read_file_info(DotSlashBeam),
+
+ F = AbsArchiveFile ++ ".extension",
+ error = erl_prim_loader:list_dir(F),
+ {ok,_,_} = erl_prim_loader:get_file(F),
+ {ok,#file_info{type=regular}} = erl_prim_loader:read_file_info(F),
+
+ ok.
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 954d19a46f..97ac433cb9 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -74,6 +74,7 @@
-export([bad_table/1, types/1]).
-export([otp_9932/1]).
-export([otp_9423/1]).
+-export([otp_10182/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
@@ -146,6 +147,7 @@ all() ->
exit_many_large_table_owner, exit_many_tables_owner,
exit_many_many_tables_owner, write_concurrency, heir,
give_away, setopts, bad_table, types,
+ otp_10182,
otp_9932,
otp_9423].
@@ -715,30 +717,17 @@ adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = _Mem0) ->
TabDiff = ?TAB_STRUCT_SZ,
Mem1 = {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff},
- Mem2 = case {erlang:system_info({wordsize,internal}),erlang:system_info({wordsize,external})} of
- %% Halfword, corrections for regular pointers occupying two internal words.
- {4,8} ->
- {A1,B1,C1,D1} = Mem1,
- {A1+4*ets:info(T1, size)+?DB_TREE_STACK_NEED,
- B1+3*ets:info(T2, size)+?DB_HASH_SIZEOF_EXTSEG,
- C1+3*ets:info(T3, size)+?DB_HASH_SIZEOF_EXTSEG,
- D1+3*ets:info(T4, size)+?DB_HASH_SIZEOF_EXTSEG};
- _ ->
- Mem1
- end,
-
- %% Adjust for hybrid and shared heaps:
- %% Each record is one word smaller.
- %%Mem2 = case erlang:system_info(heap_type) of
- %% private ->
- %% Mem1;
- %% _ ->
- %% {A1,B1,C1,D1} = Mem1,
- %% {A1-ets:info(T1, size),B1-ets:info(T2, size),
- %% C1-ets:info(T3, size),D1-ets:info(T4, size)}
- %% end,
- %%{Mem2,{ets:info(T1,stats),ets:info(T2,stats),ets:info(T3,stats),ets:info(T4,stats)}}.
- Mem2.
+ case {erlang:system_info({wordsize,internal}),erlang:system_info({wordsize,external})} of
+ %% Halfword, corrections for regular pointers occupying two internal words.
+ {4,8} ->
+ {A1,B1,C1,D1} = Mem1,
+ {A1+4*ets:info(T1, size)+?DB_TREE_STACK_NEED,
+ B1+3*ets:info(T2, size)+?DB_HASH_SIZEOF_EXTSEG,
+ C1+3*ets:info(T3, size)+?DB_HASH_SIZEOF_EXTSEG,
+ D1+3*ets:info(T4, size)+?DB_HASH_SIZEOF_EXTSEG};
+ _ ->
+ Mem1
+ end.
t_whitebox(doc) ->
["Diverse whitebox testes"];
@@ -5483,6 +5472,20 @@ otp_9423(Config) when is_list(Config) ->
Skipped -> Skipped
end.
+
+%% Corrupted binary in compressed table
+otp_10182(Config) when is_list(Config) ->
+ Bin = <<"aHR0cDovL2hvb3RzdWl0ZS5jb20vYy9wcm8tYWRyb2xsLWFi">>,
+ Key = {test, Bin},
+ Value = base64:decode(Bin),
+ In = {Key,Value},
+ Db = ets:new(undefined, [set, protected, {read_concurrency, true}, compressed]),
+ ets:insert(Db, In),
+ [Out] = ets:lookup(Db, Key),
+ io:format("In : ~p\nOut: ~p\n", [In,Out]),
+ ets:delete(Db),
+ In = Out.
+
diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl
index 4cfa589660..99516c0c04 100644
--- a/lib/stdlib/test/filename_SUITE.erl
+++ b/lib/stdlib/test/filename_SUITE.erl
@@ -25,7 +25,7 @@
-export([pathtype/1,rootname/1,split/1,find_src/1]).
-export([absname_bin/1, absname_bin_2/1,
basename_bin_1/1, basename_bin_2/1,
- dirname_bin/1, extension_bin/1, join_bin/1]).
+ dirname_bin/1, extension_bin/1, join_bin/1, t_nativename_bin/1]).
-export([pathtype_bin/1,rootname_bin/1,split_bin/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -38,7 +38,7 @@ all() ->
join, pathtype, rootname, split, t_nativename, find_src,
absname_bin, absname_bin_2, basename_bin_1, basename_bin_2, dirname_bin,
extension_bin,
- join_bin, pathtype_bin, rootname_bin, split_bin].
+ join_bin, pathtype_bin, rootname_bin, split_bin, t_nativename_bin].
groups() ->
[].
@@ -804,3 +804,14 @@ split_bin(Config) when is_list(Config) ->
ok
end.
+t_nativename_bin(Config) when is_list(Config) ->
+ ?line <<"abcedf">> = filename:nativename(<<"abcedf">>),
+ case os:type() of
+ {win32, _} ->
+ ?line <<"a:\\temp\\arne.exe">> =
+ filename:nativename(<<"A:/temp//arne.exe/">>);
+ _ ->
+ ?line <<"/usr/tmp/arne">> =
+ filename:nativename(<<"/usr/tmp//arne/">>)
+ end.
+
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index cdf15ba017..48ef7e55ed 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -37,7 +37,8 @@
% spawn export
-export([spec_init_local/2, spec_init_global/2, spec_init_via/2,
- spec_init_default_timeout/2, spec_init_anonymous/1,
+ spec_init_default_timeout/2, spec_init_global_default_timeout/2,
+ spec_init_anonymous/1,
spec_init_anonymous_default_timeout/1,
spec_init_not_proc_lib/1, cast_fast_messup/0]).
@@ -749,7 +750,7 @@ spec_init(suite) ->
spec_init(Config) when is_list(Config) ->
OldFlag = process_flag(trap_exit, true),
-
+
?line {ok, Pid0} = start_link(spec_init_local, [{ok, my_server}, []]),
?line ok = gen_server:call(Pid0, started_p),
?line ok = gen_server:call(Pid0, stop),
@@ -819,6 +820,14 @@ spec_init(Config) when is_list(Config) ->
test_server:fail(gen_server_did_not_die)
end,
+ %% Before the OTP-10130 fix this failed because a timeout message
+ %% was generated as the spawned process crashed because a {global, Name}
+ %% was matched as a timeout value instead of matching on scope.
+ {ok, _PidHurra} =
+ start_link(spec_init_global_default_timeout, [{ok, hurra}, []]),
+ timer:sleep(1000),
+ ok = gen_server:call(_PidHurra, started_p),
+
?line Pid5 =
erlang:spawn_link(?MODULE, spec_init_not_proc_lib, [[]]),
receive
@@ -1125,6 +1134,15 @@ spec_init_default_timeout({ok, Name}, Options) ->
%% Supervised init can occur here ...
gen_server:enter_loop(?MODULE, Options, {}, {local, Name}).
+%% OTP-10130, A bug was introduced where global scope was not matched when
+%% enter_loop/4 was called (no timeout).
+spec_init_global_default_timeout({ok, Name}, Options) ->
+ process_flag(trap_exit, true),
+ global:register_name(Name, self()),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {}, {global, Name}).
+
spec_init_anonymous(Options) ->
process_flag(trap_exit, true),
proc_lib:init_ack({ok, self()}),
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index 9bed20f771..661d57c85b 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -137,7 +137,7 @@ unicode_prompt(Config) when is_list(Config) ->
{putline, "io:get_line('')."},
{putline, "hej"},
{getline, "<<\"hej\\n\">>"}
- ],[],[],"-pa "++ PA),
+ ],[],[],"-pa \""++ PA++"\""),
%% And one with oldshell
?line rtnode([{putline,""},
{putline, "2."},
@@ -153,7 +153,7 @@ unicode_prompt(Config) when is_list(Config) ->
{putline, "io:get_line('')."},
{putline, "hej"},
{getline_re, ".*<<\"hej\\\\n\">>"}
- ],[],[],"-oldshell -pa "++PA),
+ ],[],[],"-oldshell -pa \""++PA++"\""),
ok.
@@ -732,7 +732,7 @@ bc_with_r12_1(Config) ->
PA = filename:dirname(code:which(?MODULE)),
Name1 = io_proto_r12_1,
?line N1 = list_to_atom(atom_to_list(Name1) ++ "@" ++ hostname()),
- ?line ?t:start_node(Name1, peer, [{args, "-pz "++PA},{erl,[{release,"r12b"}]}]),
+ ?line ?t:start_node(Name1, peer, [{args, "-pz \""++PA++"\""},{erl,[{release,"r12b"}]}]),
DataDir = ?config(data_dir,Config),
%PrivDir = ?config(priv_dir,Config),
FileName1 = filename:join([DataDir,"testdata_latin1.dat"]),
@@ -908,7 +908,7 @@ bc_with_r12_gl_1(_Config,Machine) ->
PA = filename:dirname(code:which(?MODULE)),
Name1 = io_proto_r12_gl_1,
?line N1 = list_to_atom(atom_to_list(Name1) ++ "@" ++ hostname()),
- ?line ?t:start_node(Name1, peer, [{args, "-pz "++PA},{erl,[{release,"r12b"}]}]),
+ ?line ?t:start_node(Name1, peer, [{args, "-pz \""++PA++"\""},{erl,[{release,"r12b"}]}]),
TestDataLine1 = [229,228,246],
TestDataLine1BinUtf = unicode:characters_to_binary(TestDataLine1),
TestDataLine1BinLatin = list_to_binary(TestDataLine1),
@@ -1290,7 +1290,7 @@ eof_on_pipe(Config) when is_list(Config) ->
end
end,
CommandLine1 = EchoLine ++
- Erl++" -noshell -eval "
+ "\""++Erl++"\" -noshell -eval "
"'io:format(\"~p\",[io:get_line(\"\")]),"
"io:format(\"~p\",[io:get_line(\"\")]),"
"io:format(\"~p\",[io:get_line(\"\")]).' -run init stop",
@@ -1301,7 +1301,7 @@ eof_on_pipe(Config) when is_list(Config) ->
exit({unexpected1,Other1})
end,
CommandLine2 = EchoLine ++
- Erl++" -noshell -eval "
+ "\""++Erl++"\" -noshell -eval "
"'io:setopts([binary]),io:format(\"~p\",[io:get_line(\"\")]),"
"io:format(\"~p\",[io:get_line(\"\")]),"
"io:format(\"~p\",[io:get_line(\"\")]).' -run init stop",
@@ -1340,7 +1340,8 @@ rtnode(Commands,Nodename,ErlPrefix,Extra) ->
?line {skip, Reason2};
Tempdir ->
?line SPid =
- start_runerl_node(RunErl,ErlPrefix++Erl,
+ start_runerl_node(RunErl,ErlPrefix++
+ "\\\""++Erl++"\\\"",
Tempdir,Nodename, Extra),
?line CPid = start_toerl_server(ToErl,Tempdir),
?line erase(getline_skipped),
@@ -1607,10 +1608,10 @@ start_runerl_node(RunErl,Erl,Tempdir,Nodename,Extra) ->
" "++Extra
end,
spawn(fun() ->
- ?dbg(RunErl++" "++Tempdir++"/ "++Tempdir++" \""++
- Erl++XArg++XXArg++"\""),
- os:cmd(RunErl++" "++Tempdir++"/ "++Tempdir++" \""++
- Erl++XArg++XXArg++"\"")
+ ?dbg("\""++RunErl++"\" "++Tempdir++"/ "++Tempdir++
+ " \""++Erl++XArg++XXArg++"\""),
+ os:cmd("\""++RunErl++"\" "++Tempdir++"/ "++Tempdir++
+ " \""++Erl++XArg++XXArg++"\"")
end).
start_toerl_server(ToErl,Tempdir) ->
@@ -1640,7 +1641,7 @@ try_to_erl(Command, N) ->
end.
toerl_server(Parent,ToErl,Tempdir) ->
- Port = try_to_erl(ToErl++" "++Tempdir++"/ 2>/dev/null",8),
+ Port = try_to_erl("\""++ToErl++"\" "++Tempdir++"/ 2>/dev/null",8),
case Port of
P when is_port(P) ->
Parent ! {self(),started};
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 1e74ad7727..192268f90e 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -2969,12 +2969,14 @@ lookup1(Config) when is_list(Config) ->
[3] = lookup_keys(Q)
end, [{1,a},{3,3}])">>,
+ {cres,
<<"A = 3,
etsc(fun(E) ->
Q = qlc:q([X || X <- ets:table(E), A =:= {erlang,element}(1, X)]),
[{3,3}] = qlc:e(Q),
[3] = lookup_keys(Q)
end, [{1,a},{3,3}])">>,
+ {warnings,[{3,erl_lint,deprecated_tuple_fun}]}},
<<"etsc(fun(E) ->
A = 3,
@@ -3439,12 +3441,14 @@ lookup2(Config) when is_list(Config) ->
[r] = qlc:e(Q),
[r] = lookup_keys(Q)
end, [{keypos,1}], [#r{}])">>,
+ {cres,
<<"etsc(fun(E) ->
Q = qlc:q([element(1, X) || X <- ets:table(E),
{erlang,is_record}(X, r, 2)]),
[r] = qlc:e(Q),
[r] = lookup_keys(Q)
end, [{keypos,1}], [#r{}])">>,
+ {warnings,[{4,erl_lint,deprecated_tuple_fun}]}},
{cres,
<<"etsc(fun(E) ->
Q = qlc:q([element(1, X) || X <- ets:table(E),
@@ -3465,12 +3469,14 @@ lookup2(Config) when is_list(Config) ->
[r] = qlc:e(Q),
[r] = lookup_keys(Q)
end, [{keypos,1}], [#r{}])">>,
+ {cres,
<<"etsc(fun(E) ->
Q = qlc:q([element(1, X) || X <- ets:table(E),
{erlang,is_record}(X, r)]),
[r] = qlc:e(Q),
[r] = lookup_keys(Q)
- end, [{keypos,1}], [#r{}])">>
+ end, [{keypos,1}], [#r{}])">>,
+ {warnings,[{4,erl_lint,deprecated_tuple_fun}]}}
],
?line run(Config, <<"-record(r, {a}).\n">>, TsR),
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index 5be14767fa..4b83e42ee0 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -153,7 +153,7 @@ start_restricted_from_shell(Config) when is_list(Config) ->
comm_err(<<"begin init:stop() end.">>),
?line "exception exit: restricted shell does not allow init:stop()" =
comm_err(<<"begin F = fun() -> init:stop() end, F() end.">>),
- ?line "exception error: bad argument in an arithmetic expression" =
+ ?line "exception error: an error occurred when evaluating an arithmetic expression" =
comm_err(<<"begin +a end.">>),
?line "exception exit: restricted shell does not allow a + b" =
comm_err(<<"begin a+b end.">>),
@@ -2359,7 +2359,7 @@ otp_6554(Config) when is_list(Config) ->
comm_err(<<"fun(X) -> not X end(a).">>),
?line "exception error: bad argument: a" =
comm_err(<<"fun(A, B) -> A orelse B end(a, b).">>),
- ?line "exception error: bad argument in an arithmetic expression" =
+ ?line "exception error: an error occurred when evaluating an arithmetic expression" =
comm_err(<<"math:sqrt(2)/round(math:sqrt(0)).">>),
?line "exception error: interpreted function with arity 1 called with no arguments" =
comm_err(<<"fun(V) -> V end().">>),
@@ -2478,9 +2478,9 @@ otp_6554(Config) when is_list(Config) ->
" receive {'EXIT', Pid, {{nocatch,foo},_}} -> ok end "
"end.">>),
- ?line "exception error: bad argument in an arithmetic expression" =
+ ?line "exception error: an error occurred when evaluating an arithmetic expression" =
comm_err(<<"begin catch_exception(true), 1/0 end.">>),
- ?line "exception error: bad argument in an arithmetic expression" =
+ ?line "exception error: an error occurred when evaluating an arithmetic expression" =
comm_err(<<"begin catch_exception(false), 1/0 end.">>),
?line "exception error: no function clause matching call to catch_exception/1" =
comm_err(<<"catch_exception(1).">>),
@@ -2637,7 +2637,7 @@ otp_8393(Config) when is_list(Config) ->
prompt_err(<<"shell:prompt_func('> ').">>),
?line _ = shell:prompt_func(default),
- ?line "exception error: bad argument in an arithmetic expression"++_ =
+ ?line "exception error: an error occurred when evaluating an arithmetic expression"++_ =
prompt_err(<<"shell:prompt_func({shell_SUITE,prompt4}).">>),
?line _ = shell:prompt_func(default),
@@ -2710,7 +2710,7 @@ prompt3(L) ->
integer_to_list(N).
prompt4(_L) ->
- erlang:apply({erlang,'/'}, [1,0]).
+ erlang:apply(fun erlang:'/'/2, [1,0]).
prompt5(_L) ->
[1050,1072,1082,1074,1086,32,1077,32,85,110,105,99,111,100,101,32,63].
diff --git a/lib/syntax_tools/doc/src/Makefile b/lib/syntax_tools/doc/src/Makefile
index 291b3e3047..d1c6989bd9 100644
--- a/lib/syntax_tools/doc/src/Makefile
+++ b/lib/syntax_tools/doc/src/Makefile
@@ -125,13 +125,13 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/syntax_tools/examples/Makefile b/lib/syntax_tools/examples/Makefile
index 7cfe9185c2..2724b0899b 100644
--- a/lib/syntax_tools/examples/Makefile
+++ b/lib/syntax_tools/examples/Makefile
@@ -49,8 +49,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(EXAMPLE_FILES) "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile
index bac138e95a..dca5e78be9 100644
--- a/lib/syntax_tools/src/Makefile
+++ b/lib/syntax_tools/src/Makefile
@@ -80,10 +80,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(OBJECTS) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(SOURCES) $(RELSYSDIR)/src
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(OBJECTS) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(SOURCES) "$(RELSYSDIR)/src"
release_docs_spec:
diff --git a/lib/syntax_tools/test/Makefile b/lib/syntax_tools/test/Makefile
index 3e31bdbd50..d4733b9a42 100644
--- a/lib/syntax_tools/test/Makefile
+++ b/lib/syntax_tools/test/Makefile
@@ -57,9 +57,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) syntax_tools.spec syntax_tools.cover $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) syntax_tools.spec syntax_tools.cover "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
release_docs_spec:
diff --git a/lib/test_server/doc/src/Makefile b/lib/test_server/doc/src/Makefile
index b32f3d3c59..3ce549f0e1 100644
--- a/lib/test_server/doc/src/Makefile
+++ b/lib/test_server/doc/src/Makefile
@@ -119,16 +119,16 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6"
+ $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6"
release_spec:
diff --git a/lib/test_server/src/Makefile b/lib/test_server/src/Makefile
index 4bc51873c2..a75855eaab 100644
--- a/lib/test_server/src/Makefile
+++ b/lib/test_server/src/Makefile
@@ -124,22 +124,22 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_tests_spec: opt
- $(INSTALL_DIR) $(RELEASE_PATH)/test_server
+ $(INSTALL_DIR) "$(RELEASE_PATH)/test_server"
$(INSTALL_DATA) $(ERL_FILES) $(TS_ERL_FILES) \
$(HRL_FILES) $(INTERNAL_HRL_FILES) $(TS_HRL_FILES) \
$(TS_TARGET_FILES) \
$(AUTOCONF_FILES) $(C_FILES) $(COVER_FILES) $(CONFIG) \
- $(RELEASE_PATH)/test_server
- $(INSTALL_SCRIPT) $(PROGRAMS) $(RELEASE_PATH)/test_server
+ "$(RELEASE_PATH)/test_server"
+ $(INSTALL_SCRIPT) $(PROGRAMS) "$(RELEASE_PATH)/test_server"
release_docs_spec:
diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl
index e8498a43f2..6358efa764 100644
--- a/lib/test_server/src/test_server_node.erl
+++ b/lib/test_server/src/test_server_node.erl
@@ -407,7 +407,7 @@ start_node_peer(SlaveName, OptList, From, TI) ->
% Support for erl_crash_dump files..
CrashFile = filename:join([TI#target_info.test_server_dir,
"erl_crash_dump."++cast_to_list(SlaveName)]),
- CrashArgs = lists:concat([" -env ERL_CRASH_DUMP ",CrashFile," "]),
+ CrashArgs = lists:concat([" -env ERL_CRASH_DUMP \"",CrashFile,"\" "]),
FailOnError = start_node_get_option_value(fail_on_error, OptList, true),
Pa = TI#target_info.test_server_dir,
Prog0 = start_node_get_option_value(erl, OptList, default),
@@ -420,7 +420,7 @@ start_node_peer(SlaveName, OptList, From, TI) ->
Cmd = lists:concat([Prog,
" -detached ",
TI#target_info.naming, " ", SlaveName,
- " -pa ", Pa,
+ " -pa \"", Pa,"\"",
NodeStarted,
CrashArgs,
" ", Args]),
@@ -472,9 +472,9 @@ start_node_slave(SlaveName, OptList, From, TI) ->
CrashFile = filename:join([TI#target_info.test_server_dir,
"erl_crash_dump."++cast_to_list(SlaveName)]),
- CrashArgs = lists:concat([" -env ERL_CRASH_DUMP ",CrashFile," "]),
+ CrashArgs = lists:concat([" -env ERL_CRASH_DUMP \"",CrashFile,"\" "]),
Pa = TI#target_info.test_server_dir,
- Args = lists:concat([" -pa ", Pa, " ", SuppliedArgs, CrashArgs]),
+ Args = lists:concat([" -pa \"", Pa, "\" ", SuppliedArgs, CrashArgs]),
Prog0 = start_node_get_option_value(erl, OptList, default),
Prog = pick_erl_program(Prog0),
diff --git a/lib/test_server/src/ts_autoconf_win32.erl b/lib/test_server/src/ts_autoconf_win32.erl
index 9103542fd2..258040b39e 100644
--- a/lib/test_server/src/ts_autoconf_win32.erl
+++ b/lib/test_server/src/ts_autoconf_win32.erl
@@ -67,6 +67,7 @@ system_type(Vars) ->
{5,1,_} -> "Windows XP";
{5,2,_} -> "Windows 2003";
{6,0,_} -> "Windows Vista";
+ {6,1,_} -> "Windows 7";
{_,_,_} -> "Windows NCC-1701-D"
end;
{win32, windows} ->
diff --git a/lib/test_server/src/ts_erl_config.erl b/lib/test_server/src/ts_erl_config.erl
index ed26156180..45d88016a4 100644
--- a/lib/test_server/src/ts_erl_config.erl
+++ b/lib/test_server/src/ts_erl_config.erl
@@ -128,15 +128,15 @@ erts_lib(Vars,OsType) ->
ErtsLibInternal}
end,
[{erts_lib_include,
- filename:nativename(ErtsLibInclude)},
+ quote(filename:nativename(ErtsLibInclude))},
{erts_lib_include_generated,
- filename:nativename(ErtsLibIncludeGenerated)},
+ quote(filename:nativename(ErtsLibIncludeGenerated))},
{erts_lib_include_internal,
- filename:nativename(ErtsLibIncludeInternal)},
+ quote(filename:nativename(ErtsLibIncludeInternal))},
{erts_lib_include_internal_generated,
- filename:nativename(ErtsLibIncludeInternalGenerated)},
- {erts_lib_path, filename:nativename(ErtsLibPath)},
- {erts_lib_internal_path, filename:nativename(ErtsLibInternalPath)},
+ quote(filename:nativename(ErtsLibIncludeInternalGenerated))},
+ {erts_lib_path, quote(filename:nativename(ErtsLibPath))},
+ {erts_lib_internal_path, quote(filename:nativename(ErtsLibInternalPath))},
{erts_lib_multi_threaded, erts_lib_name(multi_threaded, OsType)},
{erts_lib_single_threaded, erts_lib_name(single_threaded, OsType)}
| Vars].
@@ -145,13 +145,13 @@ erl_include(Vars) ->
Include =
case erl_root(Vars) of
{installed, Root} ->
- filename:join([Root, "usr", "include"]);
+ quote(filename:join([Root, "usr", "include"]));
{srctree, Root, Target} ->
- filename:join([Root, "erts", "emulator", "beam"])
- ++ " -I" ++ filename:join([Root, "erts", "emulator"])
+ quote(filename:join([Root, "erts", "emulator", "beam"]))
+ ++ " -I" ++ quote(filename:join([Root, "erts", "emulator"]))
++ system_include(Root, Vars)
- ++ " -I" ++ filename:join([Root, "erts", "include"])
- ++ " -I" ++ filename:join([Root, "erts", "include", Target])
+ ++ " -I" ++ quote(filename:join([Root, "erts", "include"]))
+ ++ " -I" ++ quote(filename:join([Root, "erts", "include", Target]))
end,
[{erl_include, filename:nativename(Include)}|Vars].
@@ -163,7 +163,7 @@ system_include(Root, Vars) ->
"VxWorks" -> "sys.vxworks";
_ -> "sys/unix"
end,
- " -I" ++ filename:nativename(filename:join([Root, "erts", "emulator", SysDir])).
+ " -I" ++ quote(filename:nativename(filename:join([Root, "erts", "emulator", SysDir]))).
erl_interface(Vars,OsType) ->
{Incl, {LibPath, MkIncl}} =
@@ -220,15 +220,15 @@ erl_interface(Vars,OsType) ->
_ ->
"" % VxWorks
end,
- [{erl_interface_libpath, filename:nativename(LibPath)},
+ [{erl_interface_libpath, quote(filename:nativename(LibPath))},
{erl_interface_sock_libs, sock_libraries(OsType)},
{erl_interface_lib, Lib},
{erl_interface_eilib, Lib1},
{erl_interface_lib_drv, LibDrv},
{erl_interface_eilib_drv, Lib1Drv},
{erl_interface_threadlib, ThreadLib},
- {erl_interface_include, filename:nativename(Incl)},
- {erl_interface_mk_include, filename:nativename(MkIncl)}
+ {erl_interface_include, quote(filename:nativename(Incl))},
+ {erl_interface_mk_include, quote(filename:nativename(MkIncl))}
| Vars].
ic(Vars, OsType) ->
@@ -246,10 +246,10 @@ ic(Vars, OsType) ->
end,
filename:join(Dir, "include")}
end,
- [{ic_classpath, filename:nativename(ClassPath)},
- {ic_libpath, filename:nativename(LibPath)},
+ [{ic_classpath, quote(filename:nativename(ClassPath))},
+ {ic_libpath, quote(filename:nativename(LibPath))},
{ic_lib, link_library("ic", OsType)},
- {ic_include_path, filename:nativename(Incl)}|Vars].
+ {ic_include_path, quote(filename:nativename(Incl))}|Vars].
jinterface(Vars, _OsType) ->
ClassPath =
@@ -259,7 +259,7 @@ jinterface(Vars, _OsType) ->
Dir ->
filename:join([Dir, "priv", "OtpErlang.jar"])
end,
- [{jinterface_classpath, filename:nativename(ClassPath)}|Vars].
+ [{jinterface_classpath, quote(filename:nativename(ClassPath))}|Vars].
lib_dir(Vars, Lib) ->
LibLibDir = case Lib of
@@ -354,10 +354,17 @@ ssl(Vars, _OsType) ->
{error, bad_name} ->
throw({cannot_find_app, ssl});
Dir ->
- [{ssl_libdir, filename:nativename(Dir)}| Vars]
+ [{ssl_libdir, quote(filename:nativename(Dir))}| Vars]
end.
separators(Vars, {win32,_}) ->
[{'DS',"\\"},{'PS',";"}|Vars];
separators(Vars, _) ->
[{'DS',"/"},{'PS',":"}|Vars].
+
+quote([$ |R]) ->
+ "\\ "++quote(R);
+quote([C|R]) ->
+ [C|quote(R)];
+quote([]) ->
+ [].
diff --git a/lib/test_server/src/ts_install.erl b/lib/test_server/src/ts_install.erl
index c70a41be4b..99ccfbc9bc 100644
--- a/lib/test_server/src/ts_install.erl
+++ b/lib/test_server/src/ts_install.erl
@@ -132,7 +132,7 @@ unix_autoconf(XConf) ->
OSXEnv = macosx_cflags(),
io:format("Running ~sEnv: ~p~n",
[lists:flatten(Configure ++ Args),Env++OSXEnv]),
- Port = open_port({spawn, lists:flatten(Configure ++ Args)},
+ Port = open_port({spawn, lists:flatten(["\"",Configure,"\"",Args])},
[stream, eof, {env,Env++OSXEnv}]),
ts_lib:print_data(Port);
false ->
@@ -280,12 +280,11 @@ platform(Vars) ->
LC = lock_checking(),
MT = modified_timing(),
AsyncThreads = async_threads(),
- HeapType = heap_type_label(),
Debug = debug(),
CpuBits = word_size(),
Common = lists:concat([Hostname,"/",OsType,"/",CpuType,CpuBits,LinuxDist,
Schedulers,BindType,KP,IOTHR,LC,MT,AsyncThreads,
- HeapType,Debug,ExtraLabel]),
+ Debug,ExtraLabel]),
PlatformId = lists:concat([ErlType, " ", Version, Common]),
PlatformLabel = ErlType ++ Common,
PlatformFilename = platform_as_filename(PlatformId),
@@ -343,12 +342,6 @@ hostname() ->
"/localhost"
end.
-heap_type_label() ->
- case catch erlang:system_info(heap_type) of
- hybrid -> "/Hybrid";
- _ -> "" %private
- end.
-
async_threads() ->
case catch erlang:system_info(threads) of
true -> "/A"++integer_to_list(erlang:system_info(thread_pool_size));
diff --git a/lib/test_server/src/ts_make.erl b/lib/test_server/src/ts_make.erl
index f0db60013a..1d8ef230c7 100644
--- a/lib/test_server/src/ts_make.erl
+++ b/lib/test_server/src/ts_make.erl
@@ -85,7 +85,7 @@ run_make_script({win32, _}, Make, Dir, Makefile) ->
{"run_make.bat",
".\\run_make",
["@echo off\r\n",
- "cd ", filename:nativename(Dir), "\r\n",
+ "cd \"", filename:nativename(Dir), "\"\r\n",
Make, " -f ", Makefile, " \r\n",
"if errorlevel 1 echo *error*\r\n",
"if not errorlevel 1 echo *ok*\r\n"]};
@@ -93,7 +93,7 @@ run_make_script({unix, _}, Make, Dir, Makefile) ->
{"run_make",
"/bin/sh ./run_make",
["#!/bin/sh\n",
- "cd ", Dir, "\n",
+ "cd \"", Dir, "\"\n",
Make, " -f ", Makefile, " 2>&1\n",
"case $? in\n",
" 0) echo '*ok*';;\n",
diff --git a/lib/test_server/src/ts_run.erl b/lib/test_server/src/ts_run.erl
index 885a3c9b96..a61028e4bc 100644
--- a/lib/test_server/src/ts_run.erl
+++ b/lib/test_server/src/ts_run.erl
@@ -229,7 +229,7 @@ make_command(Vars, Spec, State) ->
%% uncomment the line below to disable exception formatting
%% " -test_server_format_exception false",
" -boot start_sasl -sasl errlog_type error",
- " -pz ",Cwd,
+ " -pz \"",Cwd,"\"",
" -ct_test_vars ",TestVars,
" -eval \"file:set_cwd(\\\"",TestDir,"\\\")\" "
" -eval \"ct:run_test(",
diff --git a/lib/test_server/test/Makefile b/lib/test_server/test/Makefile
index 198440bb17..b2ac95afaa 100644
--- a/lib/test_server/test/Makefile
+++ b/lib/test_server/test/Makefile
@@ -83,10 +83,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR)
- $(INSTALL_DATA) test_server_test_lib.hrl test_server.spec test_server.cover $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(COVERFILE) "$(RELSYSDIR)"
+ $(INSTALL_DATA) test_server_test_lib.hrl test_server.spec test_server.cover "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/toolbar/doc/src/Makefile b/lib/toolbar/doc/src/Makefile
index 76147c111e..af907859d7 100644
--- a/lib/toolbar/doc/src/Makefile
+++ b/lib/toolbar/doc/src/Makefile
@@ -102,14 +102,14 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/toolbar/src/Makefile b/lib/toolbar/src/Makefile
index 14e1451609..91ce305e26 100644
--- a/lib/toolbar/src/Makefile
+++ b/lib/toolbar/src/Makefile
@@ -84,10 +84,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in
index b8c4aed6e2..0382d3228d 100644
--- a/lib/tools/c_src/Makefile.in
+++ b/lib/tools/c_src/Makefile.in
@@ -188,11 +188,11 @@ include ../vsn.mk
RELSYSDIR = $(RELEASE_PATH)/lib/tools-$(TOOLS_VSN)
release_spec: all
- $(INSTALL_DIR) $(RELSYSDIR)/c_src
- $(INSTALL_DATA) $(EMEM_SRCS) $(EMEM_HEADERS) $(RELSYSDIR)/c_src
+ $(INSTALL_DIR) "$(RELSYSDIR)/c_src"
+ $(INSTALL_DATA) $(EMEM_SRCS) $(EMEM_HEADERS) "$(RELSYSDIR)/c_src"
ifneq ($(PROGS),)
- $(INSTALL_DIR) $(RELSYSDIR)/bin
- $(INSTALL_PROGRAM) $(PROGS) $(RELSYSDIR)/bin
+ $(INSTALL_DIR) "$(RELSYSDIR)/bin"
+ $(INSTALL_PROGRAM) $(PROGS) "$(RELSYSDIR)/bin"
endif
release_docs_spec:
diff --git a/lib/tools/doc/src/Makefile b/lib/tools/doc/src/Makefile
index 433f123ae5..a76ce98ad6 100644
--- a/lib/tools/doc/src/Makefile
+++ b/lib/tools/doc/src/Makefile
@@ -121,14 +121,14 @@ clean clean_docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml
index 8b614d8860..1c5e38109b 100644
--- a/lib/tools/doc/src/eprof.xml
+++ b/lib/tools/doc/src/eprof.xml
@@ -67,9 +67,9 @@
<p><c>Rootset</c> is a list of pids and registered names.</p>
<p>The function returns <c>profiling</c> if tracing could be enabled
for all processes in <c>Rootset</c>, or <c>error</c> otherwise.</p>
- <p>A pattern can be selected to narrow the profiling. For instance ca a specific
- module be selected and only the code processes executes in that module will be
- profiled.</p>
+ <p>A pattern can be selected to narrow the profiling. For instance a
+ specific module can be selected, and only the code executed in that
+ module will be profiled.</p>
</desc>
</func>
<func>
@@ -147,8 +147,8 @@
</type>
<desc>
<p>This function ensures that the results displayed by
- <c>analyze/0,1,2</c> are printed both to
- the file <c>File</c> and the screen.</p>
+ <c>analyze/0,1,2</c> are printed both to the file
+ <c>File</c> and the screen.</p>
</desc>
</func>
<func>
diff --git a/lib/tools/emacs/Makefile b/lib/tools/emacs/Makefile
index 8533488463..e5ed56b412 100644
--- a/lib/tools/emacs/Makefile
+++ b/lib/tools/emacs/Makefile
@@ -71,9 +71,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/emacs
+ $(INSTALL_DIR) "$(RELSYSDIR)/emacs"
$(INSTALL_DATA) $(EL_FILES) $(README_FILES) $(TEST_FILES) \
- $(RELSYSDIR)/emacs
+ "$(RELSYSDIR)/emacs"
ifeq ($(DOCTYPE),pdf)
release_docs_spec:
@@ -82,7 +82,7 @@ ifeq ($(DOCTYPE),ps)
release_docs_spec:
else
release_docs_spec: docs
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN_FILES) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN_FILES) "$(RELEASE_PATH)/man/man3"
endif
endif
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index bc7a190fb4..8f98d6c85c 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -1516,7 +1516,7 @@ Other commands:
;; A dollar sign right before the double quote that ends a
;; string is not a character escape.
;;
- ;; And a "string" has with a double quote not escaped by a
+ ;; And a "string" consists of a double quote not escaped by a
;; dollar sign, any number of non-backslash non-newline
;; characters or escaped backslashes, a dollar sign
;; (otherwise we wouldn't care) and a double quote. This
@@ -1525,6 +1525,8 @@ Other commands:
;; know whether matching started inside a string: limiting
;; search to a single line keeps things sane.
. (("\\(?:^\\|[^$]\\)\"\\(?:[^\"\n]\\|\\\\\"\\)*\\(\\$\\)\"" 1 "w")
+ ;; Likewise for atoms
+ ("\\(?:^\\|[^$]\\)'\\(?:[^'\n]\\|\\\\'\\)*\\(\\$\\)'" 1 "w")
;; And the dollar sign in $\" escapes two characters, not
;; just one.
("\\(\\$\\)\\\\\\\"" 1 "'"))))))
@@ -2986,18 +2988,52 @@ This assumes that the preceding expression is either simple
(forward-sexp (- arg))
(let ((col (current-column)))
(skip-chars-backward " \t")
- ;; Needed to match the colon in "'foo':'bar'".
- (if (not (memq (preceding-char) '(?# ?:)))
- col
- ;; Special hack to handle: (note line break)
- ;; [#myrecord{
- ;; foo = foo}]
- (or
- (ignore-errors
- (backward-char 1)
- (forward-sexp -1)
- (current-column))
- col)))))
+ ;; Special hack to handle: (note line break)
+ ;; [#myrecord{
+ ;; foo = foo}]
+ ;; where the call (forward-sexp -1) will fail when point is at the `#'.
+ (or
+ (ignore-errors
+ ;; Needed to match the colon in "'foo':'bar'".
+ (cond ((eq (preceding-char) ?:)
+ (backward-char 1)
+ (forward-sexp -1)
+ (current-column))
+ ((eq (preceding-char) ?#)
+ ;; We may now be at:
+ ;; - either a construction of a new record
+ ;; - or update of a record, in which case we want
+ ;; the column of the expression to be updated.
+ ;;
+ ;; To see which of the two cases we are at, we first
+ ;; move an expression backwards, check for keywords,
+ ;; then immediately an expression forwards. Moving
+ ;; backwards skips past tokens like `,' or `->', but
+ ;; when moving forwards again, we won't skip past such
+ ;; tokens. We use this: if, after having moved
+ ;; forwards, we're back where we started, then it was
+ ;; a record update.
+ ;; The check for keywords is to detect cases like:
+ ;; case Something of #record_construction{...}
+ (backward-char 1)
+ (let ((record-start (point))
+ (record-start-col (current-column)))
+ (forward-sexp -1)
+ (let ((preceding-expr-col (current-column))
+ ;; white space definition according to erl_scan
+ (white-space "\000-\040\200-\240"))
+ (if (erlang-at-keyword)
+ ;; The (forward-sexp -1) call moved past a keyword
+ (1+ record-start-col)
+ (forward-sexp 1)
+ (skip-chars-forward white-space record-start)
+ ;; Are we back where we started? If so, it was an update.
+ (if (= (point) record-start)
+ preceding-expr-col
+ (goto-char record-start)
+ (1+ (current-column)))))))
+ (t col)))
+ col))))
(defun erlang-indent-parenthesis (stack-position)
(let ((previous (erlang-indent-find-preceding-expr)))
diff --git a/lib/tools/emacs/test.erl.indented b/lib/tools/emacs/test.erl.indented
index 2948ccf1b5..45d9593000 100644
--- a/lib/tools/emacs/test.erl.indented
+++ b/lib/tools/emacs/test.erl.indented
@@ -215,6 +215,11 @@ highlighting(X) % Function definitions should be highlighted
"char $in string", atom,
+ 'atom$', atom, 'atom$', atom,
+ 'atom\$', atom,
+
+ 'char $in atom', atom,
+
$[, ${, $\\, atom,
?MACRO_1,
?MACRO_2(foo),
@@ -657,3 +662,41 @@ indent_comprehensions() ->
foo() ->
[#foo{
foo = foo}].
+
+%% Record indentation
+some_function_with_a_very_long_name() ->
+ #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b},
+ case dummy_function_with_a_very_very_long_name(x) of
+ #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b} ->
+ ok;
+ Var = #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b} ->
+ Var#'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b};
+ #xyz{
+ a=1,
+ b=2} ->
+ ok
+ end.
+
+another_function_with_a_very_very_long_name() ->
+ #rec{
+ field1=1,
+ field2=1}.
+
+some_function_name_xyz(xyzzy, #some_record{
+ field1=Field1,
+ field2=Field2}) ->
+ SomeVariable = f(#'Some-long-record-name'{
+ field_a = 1,
+ 'inter-xyz-parameters' =
+ #'Some-other-very-long-record-name'{
+ field2 = Field1,
+ field2 = Field2}}),
+ {ok, SomeVariable}.
diff --git a/lib/tools/emacs/test.erl.orig b/lib/tools/emacs/test.erl.orig
index 1221c5655e..e123150dd1 100644
--- a/lib/tools/emacs/test.erl.orig
+++ b/lib/tools/emacs/test.erl.orig
@@ -215,6 +215,11 @@ highlighting(X) % Function definitions should be highlighted
"char $in string", atom,
+ 'atom$', atom, 'atom$', atom,
+ 'atom\$', atom,
+
+ 'char $in atom', atom,
+
$[, ${, $\\, atom,
?MACRO_1,
?MACRO_2(foo),
@@ -657,3 +662,41 @@ ok.
foo() ->
[#foo{
foo = foo}].
+
+%% Record indentation
+some_function_with_a_very_long_name() ->
+ #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b},
+ case dummy_function_with_a_very_very_long_name(x) of
+ #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b} ->
+ ok;
+ Var = #'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b} ->
+ Var#'a-long-record-name-like-it-sometimes-is-with-asn.1-records'{
+ field1=a,
+ field2=b};
+ #xyz{
+ a=1,
+ b=2} ->
+ ok
+ end.
+
+another_function_with_a_very_very_long_name() ->
+ #rec{
+ field1=1,
+ field2=1}.
+
+some_function_name_xyz(xyzzy, #some_record{
+ field1=Field1,
+ field2=Field2}) ->
+ SomeVariable = f(#'Some-long-record-name'{
+ field_a = 1,
+ 'inter-xyz-parameters' =
+ #'Some-other-very-long-record-name'{
+ field2 = Field1,
+ field2 = Field2}}),
+ {ok, SomeVariable}.
diff --git a/lib/tools/examples/Makefile b/lib/tools/examples/Makefile
index 9fb8434633..fc14ee54d6 100644
--- a/lib/tools/examples/Makefile
+++ b/lib/tools/examples/Makefile
@@ -50,7 +50,7 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(EXAMPLE_FILES) "$(RELSYSDIR)/examples"
release_docs_spec:
diff --git a/lib/tools/priv/Makefile b/lib/tools/priv/Makefile
index 6fea580c00..b32ba5820d 100644
--- a/lib/tools/priv/Makefile
+++ b/lib/tools/priv/Makefile
@@ -58,9 +58,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(HTDOCS_FILES) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(TOOL_FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(HTDOCS_FILES) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(TOOL_FILES) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/tools/src/Makefile b/lib/tools/src/Makefile
index 360f4f8f29..4c0cc8cde7 100644
--- a/lib/tools/src/Makefile
+++ b/lib/tools/src/Makefile
@@ -105,10 +105,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
- $(RELSYSDIR)/ebin
+ "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl
index 8165a6c13a..4cbb910f11 100644
--- a/lib/tools/src/fprof.erl
+++ b/lib/tools/src/fprof.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2012. 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
@@ -89,9 +89,7 @@ dbg(_, _, _) ->
apply({M, F}, Args)
when is_atom(M), is_atom(F), is_list(Args) ->
- Arity = length(Args),
- Function = fun M:F/Arity,
- apply_1(Function, Args, []);
+ apply_1(M, F, Args, []);
apply(Fun, Args)
when is_function(Fun), is_list(Args) ->
apply_1(Fun, Args, []);
@@ -99,26 +97,25 @@ apply(A, B) ->
erlang:error(badarg, [A, B]).
apply(M, F, Args) when is_atom(M), is_atom(F), is_list(Args) ->
- apply_1({M, F}, Args, []);
+ apply_1(M, F, Args, []);
apply({M, F}, Args, Options)
when is_atom(M), is_atom(F), is_list(Args), is_list(Options) ->
- Arity = length(Args),
- Function = fun M:F/Arity,
- apply_1(Function, Args, Options);
+ apply_1(M, F, Args, Options);
apply(Fun, Args, Options)
when is_function(Fun), is_list(Args), is_list(Options) ->
apply_1(Fun, Args, Options);
apply(A, B, C) ->
erlang:error(badarg, [A, B, C]).
-apply(Module, Function, Args, Options)
- when is_atom(Module), is_atom(Function), is_list(Args), is_list(Options) ->
- Arity = length(Args),
- Fun = fun Module:Function/Arity,
- apply_1(Fun, Args, Options);
+apply(M, F, Args, Options)
+ when is_atom(M), is_atom(F), is_list(Args), is_list(Options) ->
+ apply_1(M, F, Args, Options);
apply(A, B, C, D) ->
erlang:error(badarg, [A, B, C, D]).
+apply_1(M, F, Args, Options) ->
+ Arity = length(Args),
+ apply_1(fun M:F/Arity, Args, Options).
apply_1(Function, Args, Options) ->
{[_, Procs, Continue], Options_1} =
diff --git a/lib/tools/src/xref_utils.erl b/lib/tools/src/xref_utils.erl
index 9d4a175d88..680563e9df 100644
--- a/lib/tools/src/xref_utils.erl
+++ b/lib/tools/src/xref_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2012. 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
@@ -141,7 +141,7 @@ is_string([], _) ->
is_string(Term, C) ->
is_string1(Term, C).
-is_string1([H | T], C) when H > C, H < 127 ->
+is_string1([H | T], C) when H > C ->
is_string1(T, C);
is_string1([], _) ->
true;
diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile
index 8019b7269f..b9a42041a2 100644
--- a/lib/tools/test/Makefile
+++ b/lib/tools/test/Makefile
@@ -84,11 +84,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(EMAKEFILE) \
- $(ERL_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(ERL_FILES) "$(RELSYSDIR)"
+ chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index 576d7e261c..0cd53a05db 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -574,14 +574,7 @@ otp_5418(Config) when is_list(Config) ->
ok.
-otp_6115(suite) -> [];
otp_6115(Config) when is_list(Config) ->
- case erlang:system_info(heap_type) of
- hybrid -> {skip,"Hybrid-heap emulator doesn't keep track of funs"};
- _ -> otp_6115_1(Config)
- end.
-
-otp_6115_1(Config) ->
?line {ok, CWD} = file:get_cwd(),
?line Dir = filename:join(?config(data_dir, Config), otp_6115),
?line ok = file:set_cwd(Dir),
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index 78e49044a5..fd3e111d8d 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -53,7 +53,7 @@
analyze/1, basic/1, md/1, q/1, variables/1, unused_locals/1]).
-export([
- format_error/1, otp_7423/1, otp_7831/1]).
+ format_error/1, otp_7423/1, otp_7831/1, otp_10192/1]).
-import(lists, [append/2, flatten/1, keysearch/3, member/2, sort/1, usort/1]).
@@ -86,7 +86,7 @@ groups() ->
fun_mfa_r14, fun_mfa_vars, qlc]},
{analyses, [],
[analyze, basic, md, q, variables, unused_locals]},
- {misc, [], [format_error, otp_7423, otp_7831]}].
+ {misc, [], [format_error, otp_7423, otp_7831, otp_10192]}].
init_per_suite(Config) ->
init(Config).
@@ -2515,6 +2515,18 @@ otp_7831(Conf) when is_list(Conf) ->
?line xref:stop(Pid2),
ok.
+otp_10192(suite) -> [];
+otp_10192(doc) ->
+ ["OTP-10192. Allow filenames with character codes greater than 126."];
+otp_10192(Conf) when is_list(Conf) ->
+ PrivDir = ?privdir,
+ {ok, _Pid} = xref:start(s),
+ Dir = filename:join(PrivDir, "�"),
+ ok = file:make_dir(Dir),
+ {ok, []} = xref:add_directory(s, Dir),
+ xref:stop(s),
+ ok.
+
%%%
%%% Utilities
%%%
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index 30a6d282fe..788ee12900 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.6.7
+TOOLS_VSN = 2.6.8
diff --git a/lib/tv/doc/src/Makefile b/lib/tv/doc/src/Makefile
index 21478d0931..e36dd84b73 100644
--- a/lib/tv/doc/src/Makefile
+++ b/lib/tv/doc/src/Makefile
@@ -125,14 +125,14 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/tv/priv/Makefile b/lib/tv/priv/Makefile
index 69e3e32c8a..73ea8f4ee9 100644
--- a/lib/tv/priv/Makefile
+++ b/lib/tv/priv/Makefile
@@ -64,8 +64,8 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(TOOLBAR_FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(TOOLBAR_FILES) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/tv/src/Makefile b/lib/tv/src/Makefile
index 457b9d38c4..f078e5dee1 100644
--- a/lib/tv/src/Makefile
+++ b/lib/tv/src/Makefile
@@ -126,10 +126,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/typer/src/Makefile b/lib/typer/src/Makefile
index 620b3ebb69..c3fae0ad42 100644
--- a/lib/typer/src/Makefile
+++ b/lib/typer/src/Makefile
@@ -101,10 +101,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(YRL_FILES) \
- $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(INSTALL_FILES) $(RELSYSDIR)/ebin
+ "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(INSTALL_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl
index 6392f5765f..1e40b8926e 100644
--- a/lib/typer/src/typer.erl
+++ b/lib/typer/src/typer.erl
@@ -83,6 +83,7 @@ start() ->
{Args, Analysis} = process_cl_args(),
%% io:format("Args: ~p\n", [Args]),
%% io:format("Analysis: ~p\n", [Analysis]),
+ Timer = dialyzer_timing:init(false),
TrustedFiles = filter_fd(Args#args.trusted, [], fun is_erl_file/1),
Analysis2 = extract(Analysis, TrustedFiles),
All_Files = get_all_files(Args),
@@ -91,6 +92,7 @@ start() ->
Analysis4 = collect_info(Analysis3),
%% io:format("Final: ~p\n", [Analysis4#analysis.fms]),
TypeInfo = get_type_info(Analysis4),
+ dialyzer_timing:stop(Timer),
show_or_annotate(TypeInfo),
%% io:format("\nTyper analysis finished\n"),
erlang:halt(0).
@@ -181,7 +183,6 @@ get_type_info(#analysis{callgraph = CallGraph,
remove_external(CallGraph, PLT) ->
{StrippedCG0, Ext} = dialyzer_callgraph:remove_external(CallGraph),
- StrippedCG = dialyzer_callgraph:finalize(StrippedCG0),
case get_external(Ext, PLT) of
[] -> ok;
Externals ->
@@ -192,7 +193,7 @@ remove_external(CallGraph, PLT) ->
_ -> msg(io_lib:format(" Unknown types: ~p\n", [ExtTypes]))
end
end,
- StrippedCG.
+ StrippedCG0.
-spec get_external([{mfa(), mfa()}], plt()) -> [mfa()].
@@ -901,8 +902,9 @@ analyze_core_tree(Core, Records, SpecInfo, CbInfo, ExpTypes, Analysis, File) ->
MergedExpTypes = sets:union(ExpTypes, OldExpTypes),
CS6 = dialyzer_codeserver:insert_temp_exported_types(MergedExpTypes, CS5),
Ex_Funcs = [{0,F,A} || {_,_,{F,A}} <- cerl:module_exports(Tree)],
- TmpCG = Analysis#analysis.callgraph,
- CG = dialyzer_callgraph:scan_core_tree(Tree, TmpCG),
+ CG = Analysis#analysis.callgraph,
+ {V, E} = dialyzer_callgraph:scan_core_tree(Tree, CG),
+ dialyzer_callgraph:add_edges(E, V, CG),
Fun = fun analyze_one_function/2,
All_Defs = cerl:module_defs(Tree),
Acc = lists:foldl(Fun, #tmpAcc{file = File, module = Module}, All_Defs),
diff --git a/lib/webtool/doc/src/Makefile b/lib/webtool/doc/src/Makefile
index 7b86752738..32269e9424 100644
--- a/lib/webtool/doc/src/Makefile
+++ b/lib/webtool/doc/src/Makefile
@@ -112,16 +112,16 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man1
- $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DATA) $(MAN1_FILES) "$(RELEASE_PATH)/man/man1"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/webtool/priv/Makefile b/lib/webtool/priv/Makefile
index 6e1c6606fe..6af997c2bb 100644
--- a/lib/webtool/priv/Makefile
+++ b/lib/webtool/priv/Makefile
@@ -67,14 +67,14 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DIR) $(RELSYSDIR)/priv/root
- $(INSTALL_DIR) $(RELSYSDIR)/priv/root/conf
- $(INSTALL_DIR) $(RELSYSDIR)/priv/root/doc
- $(INSTALL_DATA) $(HTDOCS_FILES) $(RELSYSDIR)/priv/root/doc
- $(INSTALL_DATA) $(WEBSERVER_CONFIG_FILES) $(RELSYSDIR)/priv/root/conf
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_SCRIPT) $(SCRIPTS) $(RELSYSDIR)/priv/bin
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/root"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/root/conf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/root/doc"
+ $(INSTALL_DATA) $(HTDOCS_FILES) "$(RELSYSDIR)/priv/root/doc"
+ $(INSTALL_DATA) $(WEBSERVER_CONFIG_FILES) "$(RELSYSDIR)/priv/root/conf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv/bin"
+ $(INSTALL_SCRIPT) $(SCRIPTS) "$(RELSYSDIR)/priv/bin"
release_docs_spec:
diff --git a/lib/webtool/src/Makefile b/lib/webtool/src/Makefile
index 62845cd370..45e8b2a6f0 100644
--- a/lib/webtool/src/Makefile
+++ b/lib/webtool/src/Makefile
@@ -87,11 +87,11 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
- $(RELSYSDIR)/ebin
+ "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
index 23a34225ca..c5802af679 100644
--- a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
+++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
@@ -61,7 +61,7 @@ connect(This, EventType) ->
%% {userData, term()} An erlang term that will be sent with the event. Default: [].
-spec connect(This::wxEvtHandler(), EventType::wxEventType(), [Option]) -> ok when
Option :: {id, integer()} | {lastId, integer()} | {skip, boolean()} |
- {callback, function()} | {userData, term()}.
+ callback | {callback, function()} | {userData, term()}.
connect(This=#wx_ref{type=ThisT}, EventType, Options) ->
EvH = parse_opts(Options, #evh{et=EventType}),
?CLASS(ThisT,wxEvtHandler),
diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in
index ce7f4bf53e..1497ac4d16 100644
--- a/lib/wx/c_src/Makefile.in
+++ b/lib/wx/c_src/Makefile.in
@@ -176,10 +176,10 @@ $(TARGET_DIR)/erl_gl$(SO_EXT): $(GL_OBJECTS)
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) ../priv/erlang-logo32.png $(RELSYSDIR)/priv/
- $(INSTALL_DATA) ../priv/erlang-logo64.png $(RELSYSDIR)/priv/
- $(INSTALL_PROGRAM) $(TARGET_DIR)/wxe_driver$(SO_EXT) $(RELSYSDIR)/priv/
- $(INSTALL_PROGRAM) $(TARGET_DIR)/erl_gl$(SO_EXT) $(RELSYSDIR)/priv/
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) ../priv/erlang-logo32.png "$(RELSYSDIR)/priv/"
+ $(INSTALL_DATA) ../priv/erlang-logo64.png "$(RELSYSDIR)/priv/"
+ $(INSTALL_PROGRAM) $(TARGET_DIR)/wxe_driver$(SO_EXT) "$(RELSYSDIR)/priv/"
+ $(INSTALL_PROGRAM) $(TARGET_DIR)/erl_gl$(SO_EXT) "$(RELSYSDIR)/priv/"
release_docs_spec:
diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile
index 834f887076..4e6727b6a6 100644
--- a/lib/wx/doc/src/Makefile
+++ b/lib/wx/doc/src/Makefile
@@ -95,13 +95,13 @@ ref_man.xml: ref_man.xml.src
@echo "</application>" >> ref_man.xml
@echo
-$(ErlMods:%.erl=%.xml):
+$(ErlMods:%.erl=%.xml): ../../src/$(@:%.xml=%.erl)
escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -preprocess true -sort_functions false ../../src/$(@:%.xml=%.erl)
-$(GenMods:%.erl=%.xml):
+$(GenMods:%.erl=%.xml): ../../src/gen/$(@:%.xml=%.erl)
escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -i ../../src -preprocess true -sort_functions false ../../src/gen/$(@:%.xml=%.erl)
-$(XML_CHAPTER_FILES):
+$(XML_CHAPTER_FILES): ../overview.edoc
escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -chapter ../overview.edoc
debug opt:
@@ -120,14 +120,14 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/wx/examples/demo/Makefile b/lib/wx/examples/demo/Makefile
index 872723fb98..c60e9c3d50 100644
--- a/lib/wx/examples/demo/Makefile
+++ b/lib/wx/examples/demo/Makefile
@@ -69,7 +69,7 @@ docs:
run: opt
erl -smp -detached -pa $(TOPDIR)/ebin -s demo
-EXRELSYSDIR = $(RELSYSDIR)/examples/demo
+EXRELSYSDIR = "$(RELSYSDIR)/examples/demo"
include $(ERL_TOP)/make/otp_release_targets.mk
docs:
diff --git a/lib/wx/examples/simple/Makefile b/lib/wx/examples/simple/Makefile
index 0178aea890..3f2bf01556 100644
--- a/lib/wx/examples/simple/Makefile
+++ b/lib/wx/examples/simple/Makefile
@@ -40,7 +40,7 @@ docs:
run: opt
erl -smp -detached -pa $(TOPDIR)/ebin -s hello
-EXRELSYSDIR = $(RELSYSDIR)/examples/simple
+EXRELSYSDIR = "$(RELSYSDIR)/examples/simple"
include $(ERL_TOP)/make/otp_release_targets.mk
docs:
diff --git a/lib/wx/examples/sudoku/Makefile b/lib/wx/examples/sudoku/Makefile
index 89919ff50c..ec900f37e2 100644
--- a/lib/wx/examples/sudoku/Makefile
+++ b/lib/wx/examples/sudoku/Makefile
@@ -40,7 +40,7 @@ docs:
run: opt
erl -smp -detached -pa $(TOPDIR)/ebin -s sudoku
-EXRELSYSDIR = $(RELSYSDIR)/examples/sudoku
+EXRELSYSDIR = "$(RELSYSDIR)/examples/sudoku"
include $(ERL_TOP)/make/otp_release_targets.mk
docs:
diff --git a/lib/wx/examples/xrc/Makefile b/lib/wx/examples/xrc/Makefile
index 341fdbb2cc..9a976628a7 100644
--- a/lib/wx/examples/xrc/Makefile
+++ b/lib/wx/examples/xrc/Makefile
@@ -49,7 +49,7 @@ docs:
run: opt
erl -smp -detached -pa $(TOPDIR)/ebin -s xrc
-EXRELSYSDIR = $(RELSYSDIR)/examples/xrc
+EXRELSYSDIR = "$(RELSYSDIR)/examples/xrc"
include $(ERL_TOP)/make/otp_release_targets.mk
docs:
diff --git a/lib/wx/src/Makefile b/lib/wx/src/Makefile
index 16b425e6f0..777fb7d998 100644
--- a/lib/wx/src/Makefile
+++ b/lib/wx/src/Makefile
@@ -120,15 +120,15 @@ $(EBIN)/%.beam: $(EGEN)/%.erl $(HEADER_FILES)
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/gen
- $(INSTALL_DATA) $(GEN_HRL) $(GEN_FILES) $(RELSYSDIR)/src/gen
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXT_HRL) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src/gen"
+ $(INSTALL_DATA) $(GEN_HRL) $(GEN_FILES) "$(RELSYSDIR)/src/gen"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(EXT_HRL) "$(RELSYSDIR)/include"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
# $(INSTALL_DATA) ../$(ARCHIVE) $(RELEASE_PATH)/lib
release_docs_spec:
diff --git a/lib/wx/src/gen/wxEvtHandler.erl b/lib/wx/src/gen/wxEvtHandler.erl
index cf4a72da5a..22c203392c 100644
--- a/lib/wx/src/gen/wxEvtHandler.erl
+++ b/lib/wx/src/gen/wxEvtHandler.erl
@@ -80,7 +80,7 @@ connect(This, EventType) ->
%% {userData, term()} An erlang term that will be sent with the event. Default: [].
-spec connect(This::wxEvtHandler(), EventType::wxEventType(), [Option]) -> ok when
Option :: {id, integer()} | {lastId, integer()} | {skip, boolean()} |
- {callback, function()} | {userData, term()}.
+ callback | {callback, function()} | {userData, term()}.
connect(This=#wx_ref{type=ThisT}, EventType, Options) ->
EvH = parse_opts(Options, #evh{et=EventType}),
?CLASS(ThisT,wxEvtHandler),
diff --git a/lib/wx/test/Makefile b/lib/wx/test/Makefile
index ac8a4bdd60..836885a308 100644
--- a/lib/wx/test/Makefile
+++ b/lib/wx/test/Makefile
@@ -53,8 +53,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) wx.spec wx.cover wx_test_lib.hrl $(ErlSrc) $(ErlTargets) $(RELSYSDIR)
- $(INSTALL_SCRIPT) wxt $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) wx.spec wx.cover wx_test_lib.hrl $(ErlSrc) $(ErlTargets) "$(RELSYSDIR)"
+ $(INSTALL_SCRIPT) wxt "$(RELSYSDIR)"
release_docs_spec:
diff --git a/lib/xmerl/doc/src/Makefile b/lib/xmerl/doc/src/Makefile
index 100a2feb0a..4de06249df 100644
--- a/lib/xmerl/doc/src/Makefile
+++ b/lib/xmerl/doc/src/Makefile
@@ -161,15 +161,15 @@ info:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(EXAMPLE_FILES) $(HTML_EXAMPLE_FILES) $(HTML_STYLESHEET_FILES) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(EXAMPLE_FILES) $(HTML_EXAMPLE_FILES) $(HTML_STYLESHEET_FILES) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/xmerl/src/Makefile b/lib/xmerl/src/Makefile
index a5dbe45909..ce1aa11fba 100644
--- a/lib/xmerl/src/Makefile
+++ b/lib/xmerl/src/Makefile
@@ -214,14 +214,14 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(APP_SRC) $(APPUP_SRC) $(RELSYSDIR)/src
- $(INSTALL_DATA) xmerl_xpath_parse.yrl $(RELSYSDIR)/src
- $(INSTALL_DATA) xmerl_b64Bin.yrl $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(APP_SRC) $(APPUP_SRC) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) xmerl_xpath_parse.yrl "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) xmerl_b64Bin.yrl "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+ $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/xmerl/test/Makefile b/lib/xmerl/test/Makefile
index 5a2a585841..1fdbb7ca0d 100644
--- a/lib/xmerl/test/Makefile
+++ b/lib/xmerl/test/Makefile
@@ -113,15 +113,15 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) $(SUITE_FILES) $(RELSYSDIR)
- $(INSTALL_DATA) xmerl.spec xmerl.cover $(RELSYSDIR)
- cp $(XML_FILES) $(RELSYSDIR)
- @tar cfh - xmerl_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- @tar cfh - xmerl_std_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- @tar cfh - xmerl_xsd_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- @tar cfh - xmerl_xsd_MS2002-01-16_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- @tar cfh - xmerl_xsd_NIST2002-01-16_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- @tar cfh - xmerl_xsd_Sun2002-01-16_SUITE_data | (cd $(RELSYSDIR); tar xf -)
- chmod -R u+w $(RELSYSDIR)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(SUITE_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) xmerl.spec xmerl.cover "$(RELSYSDIR)"
+ cp $(XML_FILES) "$(RELSYSDIR)"
+ @tar cfh - xmerl_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cfh - xmerl_std_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cfh - xmerl_xsd_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cfh - xmerl_xsd_MS2002-01-16_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cfh - xmerl_xsd_NIST2002-01-16_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cfh - xmerl_xsd_Sun2002-01-16_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ chmod -R u+w "$(RELSYSDIR)"