aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile54
-rw-r--r--lib/appmon/doc/src/appmon.xml6
-rw-r--r--lib/appmon/doc/src/appmon_chapter.xml6
-rw-r--r--lib/appmon/src/appmon.erl5
-rw-r--r--lib/appmon/src/appmon_a.erl5
-rw-r--r--lib/appmon/src/appmon_lb.erl7
-rw-r--r--lib/appmon/src/appmon_txt.erl5
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c5
-rw-r--r--lib/asn1/src/asn1ct_check.erl3
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl4
-rw-r--r--lib/asn1/src/asn1ct_gen_per_rt2ct.erl4
-rw-r--r--lib/asn1/test/asn1_SUITE.erl.src24
-rw-r--r--lib/compiler/doc/src/compile.xml2
-rw-r--r--lib/compiler/src/Makefile1
-rw-r--r--lib/compiler/src/beam_except.erl149
-rw-r--r--lib/compiler/src/beam_utils.erl11
-rw-r--r--lib/compiler/src/cerl_inline.erl24
-rw-r--r--lib/compiler/src/compile.erl2
-rw-r--r--lib/compiler/src/compiler.app.src1
-rw-r--r--lib/compiler/src/sys_core_fold.erl6
-rw-r--r--lib/compiler/src/v3_codegen.erl37
-rw-r--r--lib/compiler/src/v3_kernel.erl22
-rw-r--r--lib/compiler/src/v3_life.erl34
-rw-r--r--lib/compiler/test/Makefile3
-rw-r--r--lib/compiler/test/beam_expect_SUITE.erl67
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl27
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl7
-rw-r--r--lib/compiler/test/compilation_SUITE.erl49
-rw-r--r--lib/compiler/test/compilation_SUITE_data/on_load_inline.erl23
-rw-r--r--lib/compiler/test/compile_SUITE.erl37
-rw-r--r--lib/compiler/test/compile_SUITE_data/attributes.erl23
-rw-r--r--lib/compiler/test/compiler.cover2
-rw-r--r--lib/compiler/test/core_SUITE.erl34
-rw-r--r--lib/compiler/test/core_SUITE_data/eval_is_boolean.core22
-rw-r--r--lib/compiler/test/core_SUITE_data/make_effect_seq.core51
-rw-r--r--lib/compiler/test/core_SUITE_data/nomatch_shadow.core28
-rw-r--r--lib/compiler/test/core_SUITE_data/reversed_annos.core49
-rw-r--r--lib/compiler/test/core_SUITE_data/unsafe_case.core25
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl14
-rw-r--r--lib/compiler/test/misc_SUITE.erl20
-rw-r--r--lib/compiler/test/parteval_SUITE.erl66
-rw-r--r--lib/compiler/test/parteval_SUITE_data/t1.erl140
-rw-r--r--lib/compiler/test/test_lib.erl9
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl18
-rw-r--r--lib/debugger/src/dbg_ui_break_win.erl12
-rw-r--r--lib/debugger/src/dbg_ui_edit_win.erl6
-rw-r--r--lib/debugger/src/dbg_ui_filedialog_win.erl7
-rw-r--r--lib/debugger/src/dbg_ui_mon_win.erl13
-rw-r--r--lib/debugger/src/dbg_ui_trace_win.erl19
-rw-r--r--lib/debugger/src/dbg_ui_win.erl9
-rw-r--r--lib/debugger/src/dbg_ui_winman.erl5
-rw-r--r--lib/debugger/src/dbg_wx_trace_win.erl1
-rw-r--r--lib/debugger/test/bs_construct_SUITE.erl2
-rw-r--r--lib/debugger/test/bs_match_misc_SUITE.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl13
-rw-r--r--lib/dialyzer/src/dialyzer_gui.erl17
-rw-r--r--lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_12
-rw-r--r--lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_20
-rw-r--r--lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_33
-rw-r--r--lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl18
-rw-r--r--lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl18
-rw-r--r--lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl16
-rw-r--r--lib/diameter/examples/code/GNUmakefile (renamed from lib/diameter/examples/GNUmakefile)10
-rw-r--r--lib/diameter/examples/code/client.erl (renamed from lib/diameter/examples/client.erl)2
-rw-r--r--lib/diameter/examples/code/client_cb.erl (renamed from lib/diameter/examples/client_cb.erl)0
-rw-r--r--lib/diameter/examples/code/peer.erl (renamed from lib/diameter/examples/peer.erl)0
-rw-r--r--lib/diameter/examples/code/redirect.erl (renamed from lib/diameter/examples/redirect.erl)0
-rw-r--r--lib/diameter/examples/code/redirect_cb.erl (renamed from lib/diameter/examples/redirect_cb.erl)0
-rw-r--r--lib/diameter/examples/code/relay.erl (renamed from lib/diameter/examples/relay.erl)0
-rw-r--r--lib/diameter/examples/code/relay_cb.erl (renamed from lib/diameter/examples/relay_cb.erl)0
-rw-r--r--lib/diameter/examples/code/sctp.erl (renamed from lib/diameter/examples/sctp.erl)18
-rw-r--r--lib/diameter/examples/code/server.erl (renamed from lib/diameter/examples/server.erl)0
-rw-r--r--lib/diameter/examples/code/server_cb.erl (renamed from lib/diameter/examples/server_cb.erl)0
-rw-r--r--lib/diameter/examples/dict/rfc4004_mip.dia280
-rw-r--r--lib/diameter/examples/dict/rfc4005_nas.dia740
-rw-r--r--lib/diameter/examples/dict/rfc4006_cc.dia349
-rw-r--r--lib/diameter/examples/dict/rfc4072_eap.dia150
-rw-r--r--lib/diameter/examples/dict/rfc4590_digest.dia45
-rw-r--r--lib/diameter/examples/dict/rfc4740_sip.dia446
-rw-r--r--lib/diameter/src/Makefile16
-rw-r--r--lib/diameter/src/base/diameter_service.erl20
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl40
-rw-r--r--lib/diameter/src/compiler/diameter_dict_util.erl19
-rw-r--r--lib/diameter/src/modules.mk22
-rw-r--r--lib/diameter/test/Makefile16
-rw-r--r--lib/diameter/test/diameter_capx_SUITE.erl58
-rw-r--r--lib/diameter/test/diameter_codec_SUITE.erl28
-rw-r--r--lib/diameter/test/diameter_codec_SUITE_data/avps.dia25
-rw-r--r--lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl76
-rw-r--r--lib/diameter/test/diameter_codec_SUITE_data/recv.dia51
-rw-r--r--lib/diameter/test/diameter_codec_SUITE_data/send.dia56
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl62
-rw-r--r--lib/diameter/test/diameter_dict_SUITE.erl15
-rw-r--r--lib/diameter/test/diameter_failover_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_gen_sctp_SUITE.erl354
-rw-r--r--lib/diameter/test/diameter_reg_SUITE.erl13
-rw-r--r--lib/diameter/test/diameter_relay_SUITE.erl28
-rw-r--r--lib/diameter/test/diameter_stats_SUITE.erl13
-rw-r--r--lib/diameter/test/diameter_sync_SUITE.erl13
-rw-r--r--lib/diameter/test/diameter_tls_SUITE.erl22
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl23
-rw-r--r--lib/diameter/test/diameter_transport_SUITE.erl37
-rw-r--r--lib/diameter/test/diameter_util.erl2
-rw-r--r--lib/diameter/test/diameter_watchdog_SUITE.erl11
-rw-r--r--lib/diameter/test/modules.mk7
-rw-r--r--lib/erl_docgen/priv/css/otp_doc.css29
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl154
-rw-r--r--lib/erl_interface/src/misc/ei_format.c3
-rw-r--r--lib/et/src/et_gs_contents_viewer.erl11
-rw-r--r--lib/et/src/et_gs_viewer.erl17
-rw-r--r--lib/gs/contribs/bonk/bonk.erl6
-rw-r--r--lib/gs/contribs/cols/cols.erl6
-rw-r--r--lib/gs/contribs/cols/highscore.erl7
-rw-r--r--lib/gs/contribs/mandel/mandel.erl5
-rw-r--r--lib/gs/contribs/othello/othello_board.erl6
-rw-r--r--lib/gs/doc/src/gs.xml4
-rw-r--r--lib/gs/examples/ball.erl6
-rw-r--r--lib/gs/examples/browser.erl8
-rw-r--r--lib/gs/examples/calc.erl5
-rw-r--r--lib/gs/examples/calc2.erl6
-rw-r--r--lib/gs/examples/color_demo.erl5
-rw-r--r--lib/gs/examples/color_demo2.erl4
-rw-r--r--lib/gs/examples/distrib_draw.erl5
-rw-r--r--lib/gs/examples/entry_demo.erl6
-rw-r--r--lib/gs/examples/event_test.erl3
-rw-r--r--lib/gs/examples/file_dialog.erl5
-rw-r--r--lib/gs/examples/focus_demo.erl5
-rw-r--r--lib/gs/examples/frac.erl3
-rw-r--r--lib/gs/examples/line_demo.erl6
-rw-r--r--lib/gs/examples/man.erl9
-rw-r--r--lib/gs/examples/menu_demo.erl6
-rw-r--r--lib/gs/examples/rubber.erl8
-rw-r--r--lib/gs/src/gs.erl8
-rw-r--r--lib/gs/src/gs_frontend.erl2
-rw-r--r--lib/gs/src/gs_make.erl1
-rw-r--r--lib/gs/src/gse.erl62
-rw-r--r--lib/gs/src/gstk.erl2
-rw-r--r--lib/gs/src/gstk_arc.erl1
-rw-r--r--lib/gs/src/gstk_canvas.erl2
-rw-r--r--lib/gs/src/gstk_editor.erl3
-rw-r--r--lib/gs/src/gstk_entry.erl1
-rw-r--r--lib/gs/src/gstk_generic.erl1
-rw-r--r--lib/gs/src/gstk_grid.erl1
-rw-r--r--lib/gs/src/gstk_gridline.erl2
-rw-r--r--lib/gs/src/gstk_image.erl1
-rw-r--r--lib/gs/src/gstk_menu.erl1
-rw-r--r--lib/gs/src/gstk_menuitem.erl1
-rw-r--r--lib/gs/src/gstk_port_handler.erl1
-rw-r--r--lib/gs/src/gstk_rectangle.erl1
-rw-r--r--lib/gs/src/gstk_window.erl1
-rw-r--r--lib/gs/src/tcl2erl.erl1
-rw-r--r--lib/gs/src/tool_file_dialog.erl10
-rw-r--r--lib/gs/src/tool_utils.erl5
-rw-r--r--lib/hipe/cerl/cerl_hipe_primops.hrl1
-rw-r--r--lib/hipe/cerl/cerl_hipeify.erl1
-rw-r--r--lib/hipe/cerl/cerl_messagean.erl1
-rw-r--r--lib/hipe/cerl/cerl_to_icode.erl3
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl57
-rw-r--r--lib/hipe/flow/Makefile2
-rw-r--r--lib/hipe/icode/Makefile2
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl4
-rw-r--r--lib/hipe/icode/hipe_icode_inline_bifs.erl3
-rw-r--r--lib/hipe/icode/hipe_icode_type.erl6
-rw-r--r--lib/hipe/opt/Makefile2
-rw-r--r--lib/hipe/rtl/Makefile52
-rw-r--r--lib/hipe/tools/hipe_tool.erl12
-rw-r--r--lib/inets/doc/src/notes.xml54
-rw-r--r--lib/inets/src/ftp/ftp.erl7
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl140
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl36
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl90
-rw-r--r--lib/inets/src/inets_app/inets.appup.src20
-rw-r--r--lib/inets/test/httpc_SUITE.erl330
-rw-r--r--lib/inets/test/httpd_SUITE.erl1
-rw-r--r--lib/inets/test/httpd_test_lib.erl33
-rw-r--r--lib/inets/vsn.mk4
-rw-r--r--lib/inviso/test/inviso_tool_SUITE.erl7
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java17
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java4
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java4
-rw-r--r--lib/jinterface/test/nc_SUITE.erl7
-rw-r--r--lib/jinterface/test/nc_SUITE_data/echo_server.java6
-rw-r--r--lib/kernel/src/code_server.erl10
-rw-r--r--lib/kernel/src/gen_sctp.erl6
-rw-r--r--lib/kernel/test/code_SUITE.erl49
-rw-r--r--lib/kernel/test/erl_prim_loader_SUITE.erl8
-rw-r--r--lib/kernel/test/file_SUITE.erl167
-rwxr-xr-xlib/kernel/test/inet_res_SUITE_data/run-named21
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl109
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/mnesia/src/mnesia_locker.erl181
-rw-r--r--lib/observer/src/etop_gui.erl7
-rw-r--r--lib/observer/src/observer_lib.erl36
-rw-r--r--lib/observer/src/observer_procinfo.erl101
-rw-r--r--lib/observer/src/observer_tv_table.erl109
-rw-r--r--lib/observer/src/observer_tv_wx.erl4
-rw-r--r--lib/observer/test/etop_SUITE.erl13
-rw-r--r--lib/orber/src/orber_ifr.erl2
-rw-r--r--lib/orber/src/orber_tb.erl2
-rw-r--r--lib/orber/test/orber_SUITE.erl36
-rw-r--r--lib/orber/test/orber_acl_SUITE.erl2
-rw-r--r--lib/os_mon/c_src/memsup.c12
-rw-r--r--lib/os_mon/src/cpu_sup.erl5
-rw-r--r--lib/os_mon/src/memsup.erl3
-rw-r--r--lib/os_mon/src/os_mon.erl20
-rw-r--r--lib/os_mon/src/os_mon_sysinfo.erl6
-rw-r--r--lib/pman/doc/src/pman.xml6
-rw-r--r--lib/pman/doc/src/pman_chapter.xml6
-rw-r--r--lib/pman/src/pman_buf_converter.erl1
-rw-r--r--lib/pman/src/pman_buf_printer.erl2
-rw-r--r--lib/pman/src/pman_main.erl2
-rw-r--r--lib/pman/src/pman_module_info.erl2
-rw-r--r--lib/pman/src/pman_shell.erl4
-rw-r--r--lib/pman/src/pman_tool.erl1
-rw-r--r--lib/pman/src/pman_win.erl10
-rw-r--r--lib/public_key/.gitignore10
-rw-r--r--lib/public_key/doc/src/public_key.xml2
-rw-r--r--lib/public_key/src/pubkey_ssh.erl95
-rw-r--r--lib/runtime_tools/c_src/trace_ip_drv.c22
-rw-r--r--lib/runtime_tools/test/inviso_SUITE.erl17
-rw-r--r--lib/sasl/doc/src/appup.xml2
-rw-r--r--lib/sasl/doc/src/systools.xml4
-rw-r--r--lib/sasl/src/release_handler.erl2
-rw-r--r--lib/sasl/src/systools_make.erl94
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl56
-rw-r--r--lib/sasl/test/systools_SUITE.erl125
-rw-r--r--lib/snmp/doc/src/notes.xml537
-rw-r--r--lib/snmp/doc/src/notes_history.xml351
-rw-r--r--lib/snmp/doc/src/snmp_app.xml109
-rw-r--r--lib/snmp/doc/src/snmp_config.xml104
-rw-r--r--lib/snmp/doc/src/snmpa.xml22
-rw-r--r--lib/snmp/src/agent/depend.mk2
-rw-r--r--lib/snmp/src/agent/snmp_generic_mnesia.erl5
-rw-r--r--lib/snmp/src/agent/snmp_target_mib.erl16
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl29
-rw-r--r--lib/snmp/src/agent/snmpa.erl4
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl628
-rw-r--r--lib/snmp/src/agent/snmpa_internal.hrl9
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl10
-rw-r--r--lib/snmp/src/agent/snmpa_mib.erl14
-rw-r--r--lib/snmp/src/agent/snmpa_mib_lib.erl20
-rw-r--r--lib/snmp/src/agent/snmpa_mpd.erl2
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl40
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl21
-rw-r--r--lib/snmp/src/agent/snmpa_vacm.erl52
-rw-r--r--lib/snmp/src/app/snmp.appup.src331
-rw-r--r--lib/snmp/test/snmp_agent_test.erl253
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl15
-rw-r--r--lib/snmp/test/snmp_manager_config_test.erl15
-rw-r--r--lib/snmp/test/snmp_manager_test.erl18
-rw-r--r--lib/snmp/test/snmp_test_lib.erl11
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl15
-rw-r--r--lib/snmp/test/snmp_test_mgr_misc.erl15
-rw-r--r--lib/snmp/vsn.mk8
-rw-r--r--lib/ssh/doc/src/ssh.xml57
-rw-r--r--lib/ssh/src/DSS.asn120
-rw-r--r--lib/ssh/src/Makefile33
-rw-r--r--lib/ssh/src/PKCS-1.asn1116
-rw-r--r--lib/ssh/src/prebuild.skip2
-rw-r--r--lib/ssh/src/ssh.app.src7
-rw-r--r--lib/ssh/src/ssh.erl96
-rw-r--r--lib/ssh/src/ssh.hrl17
-rw-r--r--lib/ssh/src/ssh_auth.erl160
-rw-r--r--lib/ssh/src/ssh_bits.erl6
-rw-r--r--lib/ssh/src/ssh_connection.erl4
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl45
-rw-r--r--lib/ssh/src/ssh_connection_manager.erl6
-rw-r--r--lib/ssh/src/ssh_dsa.erl95
-rw-r--r--lib/ssh/src/ssh_file.erl641
-rw-r--r--lib/ssh/src/ssh_key_api.erl45
-rw-r--r--lib/ssh/src/ssh_rsa.erl298
-rw-r--r--lib/ssh/src/ssh_sftpd.erl22
-rw-r--r--lib/ssh/src/ssh_transport.erl266
-rw-r--r--lib/ssh/src/ssh_xfer.erl16
-rw-r--r--lib/ssh/test/Makefile3
-rw-r--r--lib/ssh/test/ssh_SUITE.erl72
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl173
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_dsa13
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_rsa15
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key16
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key.pub5
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE.erl44
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/id_rsa15
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub1
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE.erl42
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE_data/id_dsa13
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl57
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_dsa13
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_test_lib.erl620
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl149
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssl/src/inet_tls_dist.erl14
-rw-r--r--lib/ssl/src/ssl_handshake.erl17
-rw-r--r--lib/ssl/src/ssl_tls_dist_proxy.erl46
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl105
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl10
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl6
-rw-r--r--lib/stdlib/doc/src/binary.xml2
-rw-r--r--lib/stdlib/doc/src/gb_trees.xml18
-rw-r--r--lib/stdlib/doc/src/io.xml2
-rw-r--r--lib/stdlib/doc/src/ms_transform.xml4
-rw-r--r--lib/stdlib/doc/src/sofs.xml10
-rw-r--r--lib/stdlib/doc/src/supervisor.xml13
-rw-r--r--lib/stdlib/src/erl_eval.erl1
-rw-r--r--lib/stdlib/src/erl_expand_records.erl17
-rw-r--r--lib/stdlib/src/erl_lint.erl35
-rw-r--r--lib/stdlib/src/error_logger_file_h.erl23
-rw-r--r--lib/stdlib/src/error_logger_tty_h.erl23
-rw-r--r--lib/stdlib/src/gen_fsm.erl2
-rw-r--r--lib/stdlib/src/gen_server.erl2
-rw-r--r--lib/stdlib/src/ms_transform.erl2
-rw-r--r--lib/stdlib/src/otp_internal.erl18
-rw-r--r--lib/stdlib/src/supervisor.erl12
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl25
-rw-r--r--lib/stdlib/test/erl_expand_records_SUITE.erl12
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl30
-rw-r--r--lib/stdlib/test/ets_SUITE.erl16
-rw-r--r--lib/stdlib/test/ms_transform_SUITE.erl5
-rw-r--r--lib/stdlib/test/re_SUITE.erl54
-rw-r--r--lib/stdlib/test/shell_SUITE.erl29
-rw-r--r--lib/stdlib/test/sofs_SUITE.erl64
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl65
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/src/Makefile2
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl3
-rw-r--r--lib/toolbar/doc/src/toolbar.xml5
-rw-r--r--lib/toolbar/doc/src/toolbar_chapter.xml5
-rw-r--r--lib/toolbar/src/canvasbutton.erl3
-rw-r--r--lib/toolbar/src/toolbar.erl1
-rw-r--r--lib/toolbar/src/toolbar_graphics.erl3
-rw-r--r--lib/toolbar/src/toolbar_toolconfig.erl5
-rw-r--r--lib/tools/c_src/Makefile.in27
-rw-r--r--lib/tools/c_src/erl_memory.c7
-rw-r--r--lib/tools/test/fprof_SUITE.erl16
-rw-r--r--lib/tv/doc/src/table_visualizer_chapter.xml6
-rw-r--r--lib/tv/doc/src/tv.xml6
-rw-r--r--lib/tv/src/tv_db.erl4
-rw-r--r--lib/tv/src/tv_db_search.erl12
-rw-r--r--lib/tv/src/tv_etsread.erl3
-rw-r--r--lib/tv/src/tv_info.erl8
-rw-r--r--lib/tv/src/tv_ip.erl6
-rw-r--r--lib/tv/src/tv_main.erl14
-rw-r--r--lib/tv/src/tv_new_table.erl10
-rw-r--r--lib/tv/src/tv_nodewin.erl9
-rw-r--r--lib/tv/src/tv_pb.erl3
-rw-r--r--lib/tv/src/tv_pb_funcs.erl6
-rw-r--r--lib/tv/src/tv_pc.erl1
-rw-r--r--lib/tv/src/tv_pc_menu_handling.erl4
-rw-r--r--lib/tv/src/tv_pd.erl5
-rw-r--r--lib/tv/src/tv_pd_display.erl7
-rw-r--r--lib/tv/src/tv_pd_frames.erl2
-rw-r--r--lib/tv/src/tv_pd_scale.erl2
-rw-r--r--lib/tv/src/tv_pg.erl1
-rw-r--r--lib/tv/src/tv_pg_gridfcns.erl4
-rw-r--r--lib/tv/src/tv_poll_dialog.erl8
-rw-r--r--lib/tv/src/tv_pw.erl1
-rw-r--r--lib/tv/src/tv_pw_window.erl4
-rw-r--r--lib/tv/src/tv_rec_edit.erl10
-rw-r--r--lib/tv/src/tv_utils.erl3
-rw-r--r--lib/wx/doc/src/Makefile2
-rw-r--r--lib/xmerl/doc/src/xmerl_ug.xmlsrc4
-rw-r--r--lib/xmerl/src/xmerl_uri.erl2
372 files changed, 9644 insertions, 4334 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 402e73722a..aa4e074830 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -19,53 +19,21 @@
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
-#
-# Macros
-#
-ifeq ($(findstring vxworks,$(TARGET)),vxworks)
- ERTS_SUB_DIRECTORIES = stdlib sasl kernel compiler
- OTHER_SUB_DIRECTORIES = \
- snmp otp_mibs appmon erl_interface os_mon tools runtime_tools
- ifdef BUILD_ALL
- OTHER_SUB_DIRECTORIES += mnesia jinterface ic asn1 debugger \
- inets mnesia_session diameter orber pman tv observer \
- cosTransactions cosEvent cosTime cosNotification cosProperty
- cosFileTransfer cosEventDomain
- endif
-else
-#
-# unix and win32
-# --------------
-#
- ERTS_SUB_DIRECTORIES = stdlib sasl kernel compiler
- OTHER_SUB_DIRECTORIES = tools test_server common_test runtime_tools
- ifdef BUILD_ALL
- ifeq ($(findstring win32,$(TARGET)),win32) # BUILD_ALL on win32
- OTHER_SUB_DIRECTORIES += \
- snmp otp_mibs appmon erl_interface asn1 jinterface gs wx inets ic \
- mnesia crypto orber os_mon parsetools syntax_tools pman \
- public_key ssl toolbar tv observer debugger reltool odbc \
- diameter \
- cosTransactions cosEvent cosTime cosNotification cosProperty \
- cosFileTransfer cosEventDomain et megaco webtool \
- xmerl edoc eunit ssh inviso typer erl_docgen \
- common_test percept dialyzer
-# dialyzer
- OTHER_SUB_DIRECTORIES += hipe
- else # BUILD_ALL on unix
- OTHER_SUB_DIRECTORIES += \
- snmp otp_mibs appmon erl_interface asn1 jinterface wx debugger reltool gs inets \
+ERTS_SUB_DIRECTORIES = stdlib sasl kernel compiler
+OTHER_SUB_DIRECTORIES = tools test_server common_test runtime_tools
+ifdef BUILD_ALL
+ OTHER_SUB_DIRECTORIES += \
+ snmp otp_mibs appmon erl_interface asn1 jinterface \
+ wx debugger reltool gs inets \
ic mnesia crypto orber os_mon parsetools syntax_tools \
pman public_key ssl toolbar tv observer odbc \
diameter \
cosTransactions cosEvent cosTime cosNotification \
cosProperty cosFileTransfer cosEventDomain et megaco webtool \
xmerl edoc eunit ssh inviso typer erl_docgen \
- common_test percept dialyzer
-# dialyzer
- OTHER_SUB_DIRECTORIES += hipe $(TSP_APP)
- endif
- endif
+ percept dialyzer hipe
+ EXTRA_FILE := $(wildcard EXTRA-APPLICATIONS)
+ EXTRA_APPLICATIONS := $(if $(EXTRA_FILE),$(shell cat $(EXTRA_FILE)))
endif
ifdef BOOTSTRAP
@@ -78,7 +46,9 @@ else
ifdef TERTIARY_BOOTSTRAP
SUB_DIRECTORIES = snmp sasl jinterface ic syntax_tools wx
else # Not bootstrap build
- SUB_DIRECTORIES = $(ERTS_SUB_DIRECTORIES) $(OTHER_SUB_DIRECTORIES)
+ SUB_DIRECTORIES = $(ERTS_SUB_DIRECTORIES) \
+ $(OTHER_SUB_DIRECTORIES) \
+ $(EXTRA_APPLICATIONS)
endif
endif
endif
diff --git a/lib/appmon/doc/src/appmon.xml b/lib/appmon/doc/src/appmon.xml
index ae6147a387..5af50daa53 100644
--- a/lib/appmon/doc/src/appmon.xml
+++ b/lib/appmon/doc/src/appmon.xml
@@ -32,6 +32,12 @@
<module>appmon</module>
<modulesummary>A graphical node and application process tree viewer.</modulesummary>
<description>
+ <warning>
+ <p>
+ The Appmon application has been superseded by the Observer application.
+ Appmon will be removed in R16.
+ </p>
+ </warning>
<p>The application monitor Appmon is a graphical utility used to
supervise applications executing either locally or on remote nodes.
The process tree of an application can furthermore be monitored.</p>
diff --git a/lib/appmon/doc/src/appmon_chapter.xml b/lib/appmon/doc/src/appmon_chapter.xml
index 0dab23b549..3f642ad002 100644
--- a/lib/appmon/doc/src/appmon_chapter.xml
+++ b/lib/appmon/doc/src/appmon_chapter.xml
@@ -31,6 +31,12 @@
<section>
<title>Introduction</title>
+ <warning>
+ <p>
+ The Appmon application has been superseded by the Observer application.
+ Appmon will be removed in R16.
+ </p>
+ </warning>
<p>The application monitor Appmon is a graphical node and application viewer. The tool shows an overview of all applications on all known nodes, and it is possible to view the process tree for an application running on any of the nodes.</p>
<note>
<p>If the Appmon code is not available at a node, for example an
diff --git a/lib/appmon/src/appmon.erl b/lib/appmon/src/appmon.erl
index 2b982cddf0..7a6d86c9ab 100644
--- a/lib/appmon/src/appmon.erl
+++ b/lib/appmon/src/appmon.erl
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
-module(appmon).
-behaviour(gen_server).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,1}}]).
%%%---------------------------------------------------------------------
%%% Appmon main module.
diff --git a/lib/appmon/src/appmon_a.erl b/lib/appmon/src/appmon_a.erl
index b0b5847343..2c8185a85d 100644
--- a/lib/appmon/src/appmon_a.erl
+++ b/lib/appmon/src/appmon_a.erl
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
-module(appmon_a).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,1}}]).
%%----------------------------------------------------------------------
%%
diff --git a/lib/appmon/src/appmon_lb.erl b/lib/appmon/src/appmon_lb.erl
index 4e433f37c5..55fda83027 100644
--- a/lib/appmon/src/appmon_lb.erl
+++ b/lib/appmon/src/appmon_lb.erl
@@ -29,6 +29,13 @@
%%% then pressing the load button, its application window is started.
-module(appmon_lb).
+-compile([{nowarn_deprecated_function,{gs,button,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,listbox,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
-export ([
start/1,
diff --git a/lib/appmon/src/appmon_txt.erl b/lib/appmon/src/appmon_txt.erl
index 4e1785c53f..8647bc9890 100644
--- a/lib/appmon/src/appmon_txt.erl
+++ b/lib/appmon/src/appmon_txt.erl
@@ -22,6 +22,11 @@
%%------------------------------------------------------------
-module(appmon_txt).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,1}}]).
-export([start/0, start/1, print/1, fprint/1]).
%% gen_server stuff
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
index 9c9f83bc2a..accd368af1 100644
--- a/lib/asn1/c_src/asn1_erl_nif.c
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -580,7 +580,7 @@ int per_insert_bits_as_bits(int desired_no, int no_bytes,
unsigned char **input_ptr, unsigned char **output_ptr, int *unused) {
unsigned char *in_ptr = *input_ptr;
unsigned char val;
- int no_bits, ret, ret2;
+ int no_bits, ret;
if (desired_no == (no_bytes * 8)) {
if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
@@ -606,8 +606,7 @@ int per_insert_bits_as_bits(int desired_no, int no_bytes,
== ASN1_ERROR
)
return ASN1_ERROR;
- ret2 = per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused);
- /* printf("ret2 = %d\n\r",ret2); */
+ per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused);
ret = CEIL(desired_no,8);
/* printf("ret = %d\n\r",ret); */
}
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index e318477234..105fc02819 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -5253,6 +5253,9 @@ check_int(S,[{'NamedNumber',Id,Num}|T],Acc) when is_integer(Num) ->
check_int(S,[{'NamedNumber',Id,{identifier,_,Name}}|T],Acc) ->
Val = dbget_ex(S,S#state.mname,Name),
check_int(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc);
+check_int(S,[{'NamedNumber',Id,{'Externalvaluereference',_,Mod,Name}}|T],Acc) ->
+ Val = dbget_ex(S,Mod,Name),
+ check_int(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc);
check_int(_S,[],Acc) ->
lists:keysort(2,Acc).
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index b90a0adf81..8fd7a69a19 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -358,6 +358,10 @@ greatest_common_range2({_,Int},VR={_Lb,_Ub}) when is_integer(Int) ->
greatest_common_range2({_,L},{Lb,Ub}) when is_list(L) ->
Min = least_Lb([Lb|L]),
Max = greatest_Ub([Ub|L]),
+ [{'ValueRange',{Min,Max}}];
+greatest_common_range2({Lb1,Ub1},{Lb2,Ub2}) ->
+ Min = least_Lb([Lb1,Lb2]),
+ Max = greatest_Ub([Ub1,Ub2]),
[{'ValueRange',{Min,Max}}].
mk_vr([{Type,I}]) when is_atom(Type), is_integer(I) ->
diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
index 1a0a0e211d..fb9613c18d 100644
--- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
+++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
@@ -704,6 +704,10 @@ greatest_common_range([{_,Int}],VR=[{_,{_Lb,_Ub}}]) when is_integer(Int) ->
greatest_common_range([{_,L}],[{_,{Lb,Ub}}]) when is_list(L) ->
Min = least_Lb([Lb|L]),
Max = greatest_Ub([Ub|L]),
+ [{'ValueRange',{Min,Max}}];
+greatest_common_range([{_,{Lb1,Ub1}}],[{_,{Lb2,Ub2}}]) ->
+ Min = least_Lb([Lb1,Lb2]),
+ Max = greatest_Ub([Ub1,Ub2]),
[{'ValueRange',{Min,Max}}].
diff --git a/lib/asn1/test/asn1_SUITE.erl.src b/lib/asn1/test/asn1_SUITE.erl.src
index 124ee2d2bb..3f51b125ec 100644
--- a/lib/asn1/test/asn1_SUITE.erl.src
+++ b/lib/asn1/test/asn1_SUITE.erl.src
@@ -96,7 +96,8 @@ all() -> [{group,compile},parse,default_per,default_ber,default_per_opt,per,
testSSLspecs, testNortel,test_undecoded_rest,
test_inline, testTcapsystem, testNBAPsystem,
test_compile_options,testDoubleEllipses, test_modified_x420,
- testX420, test_x691,ticket_6143, testExtensionAdditionGroup
+ testX420, test_x691,ticket_6143, testExtensionAdditionGroup,
+ test_OTP_9688
] ++ common() ++ particular().
groups() ->
@@ -2369,4 +2370,23 @@ test_modules() ->
"LDAP"
].
-
+test_OTP_9688(Config) ->
+ Asn1Mod = "OTP-9688.asn1",
+ %%DataDir = ?config(data_dir,Config),
+ PrivDir = ?config(priv_dir,Config),
+ Data = "
+OTP-9688 DEFINITIONS ::= BEGIN
+
+ foo INTEGER ::= 1
+ bar INTEGER ::= 42
+
+ Baz ::= INTEGER {x-y-z1(foo), x-y-z2(bar)}
+ Qux ::= SEQUENCE {flerpInfo SEQUENCE {x INTEGER (-10 | -9 | (0..4))} OPTIONAL}
+
+END
+",
+ File = filename:join(PrivDir,Asn1Mod),
+ ok = file:write_file(File, Data),
+ %% Does it compile with changes to asn1ct_check and asn1ct_gen_per_rt2ct?
+ %% (see ticket)
+ ok = asn1ct:compile(File, [{outdir, PrivDir}]).
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 522c1dc411..0f8abf1ccf 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -333,7 +333,7 @@ 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>. The default 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 7a237608ad..3415517fff 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -53,6 +53,7 @@ MODULES = \
beam_dead \
beam_dict \
beam_disasm \
+ beam_except \
beam_flatten \
beam_jump \
beam_listing \
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
new file mode 100644
index 0000000000..fb1a43cd9e
--- /dev/null
+++ b/lib/compiler/src/beam_except.erl
@@ -0,0 +1,149 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(beam_except).
+-export([module/2]).
+
+%%% Rewrite certain calls to erlang:error/{1,2} to specialized
+%%% instructions:
+%%%
+%%% erlang:error({badmatch,Value}) => badmatch Value
+%%% erlang:error({case_clause,Value}) => case_end Value
+%%% erlang:error({try_clause,Value}) => try_case_end Value
+%%% erlang:error(if_clause) => if_end
+%%% erlang:error(function_clause, Args) => jump FuncInfoLabel
+%%%
+
+-import(lists, [reverse/1]).
+
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,{Mod,Exp,Attr,Fs,Lc}}.
+
+function({function,Name,Arity,CLabel,Is0}) ->
+ try
+ Is = function_1(Is0),
+ {function,Name,Arity,CLabel,Is}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+-record(st,
+ {lbl, %func_info label
+ loc %location for func_info
+ }).
+
+function_1(Is0) ->
+ case Is0 of
+ [{label,Lbl},{line,Loc}|_] ->
+ St = #st{lbl=Lbl,loc=Loc},
+ translate(Is0, St, []);
+ [{label,_}|_] ->
+ %% No line numbers. The source must be a .S file.
+ %% There is no need to do anything.
+ Is0
+ end.
+
+translate([{call_ext,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) ->
+ translate_1(Ar, I, Is, St, Acc);
+translate([{call_ext_only,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) ->
+ translate_1(Ar, I, Is, St, Acc);
+translate([{call_ext_last,Ar,{extfunc,erlang,error,Ar},_}=I|Is], St, Acc) ->
+ translate_1(Ar, I, Is, St, Acc);
+translate([I|Is], St, Acc) ->
+ translate(Is, St, [I|Acc]);
+translate([], _, Acc) ->
+ reverse(Acc).
+
+translate_1(Ar, I, Is, St, [{line,_}=Line|Acc1]=Acc0) ->
+ case dig_out(Ar, Acc1) of
+ no ->
+ translate(Is, St, [I|Acc0]);
+ {yes,function_clause,Acc2} ->
+ case {Line,St} of
+ {{line,Loc},#st{lbl=Fi,loc=Loc}} ->
+ Instr = {jump,{f,Fi}},
+ translate(Is, St, [Instr|Acc2]);
+ {_,_} ->
+ %% This must be "error(function_clause, Args)" in
+ %% the Erlang source code. Don't translate.
+ translate(Is, St, [I|Acc0])
+ end;
+ {yes,Instr,Acc2} ->
+ translate(Is, St, [Instr,Line|Acc2])
+ end.
+
+dig_out(Ar, [{kill,_}|Is]) ->
+ dig_out(Ar, Is);
+dig_out(1, [{block,Bl0}|Is]) ->
+ case dig_out_block(reverse(Bl0)) of
+ no -> no;
+ {yes,What,[]} ->
+ {yes,What,Is};
+ {yes,What,Bl} ->
+ {yes,What,[{block,Bl}|Is]}
+ end;
+dig_out(2, [{block,Bl}|Is]) ->
+ case dig_out_block_fc(Bl) of
+ no -> no;
+ {yes,What} -> {yes,What,Is}
+ end;
+dig_out(_, _) -> no.
+
+dig_out_block([{set,[{x,0}],[{atom,if_clause}],move}]) ->
+ {yes,if_end,[]};
+dig_out_block([{set,[{x,0}],[{literal,{Exc,Value}}],move}|Is]) ->
+ translate_exception(Exc, {literal,Value}, Is, 0);
+dig_out_block([{set,[{x,0}],[Tuple],move},
+ {set,[],[Value],put},
+ {set,[],[{atom,Exc}],put},
+ {set,[Tuple],[],{put_tuple,2}}|Is]) ->
+ translate_exception(Exc, Value, Is, 3);
+dig_out_block([{set,[],[Value],put},
+ {set,[],[{atom,Exc}],put},
+ {set,[{x,0}],[],{put_tuple,2}}|Is]) ->
+ translate_exception(Exc, Value, Is, 3);
+dig_out_block(_) -> no.
+
+translate_exception(badmatch, Val, Is, Words) ->
+ {yes,{badmatch,Val},fix_block(Is, Words)};
+translate_exception(case_clause, Val, Is, Words) ->
+ {yes,{case_end,Val},fix_block(Is, Words)};
+translate_exception(try_clause, Val, Is, Words) ->
+ {yes,{try_case_end,Val},fix_block(Is, Words)};
+translate_exception(_, _, _, _) -> no.
+
+fix_block(Is, 0) ->
+ reverse(Is);
+fix_block(Is0, Words) ->
+ [{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is] = reverse(Is0),
+ [{set,[],[],{alloc,Live,{F1,F2,Needed-Words,F3}}}|Is].
+
+dig_out_block_fc([{set,[],[],{alloc,Live,_}}|Bl]) ->
+ dig_out_fc(Bl, Live-1, nil);
+dig_out_block_fc(_) -> no.
+
+dig_out_fc([{set,[Dst],[{x,Reg},Dst0],put_list}|Is], Reg, Dst0) ->
+ dig_out_fc(Is, Reg-1, Dst);
+dig_out_fc([{set,[{x,0}],[{atom,function_clause}],move}], -1, {x,1}) ->
+ {yes,function_clause};
+dig_out_fc(_, _, _) -> no.
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index a631b8cd69..116ede0bc9 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -474,8 +474,15 @@ check_liveness(R, [{make_fun2,_,_,_,NumFree}|Is], St) ->
end;
check_liveness(R, [{try_end,Y}|Is], St) ->
case R of
- Y -> {killed,St};
- _ -> check_liveness(R, Is, St)
+ Y ->
+ {killed,St};
+ {y,_} ->
+ %% y registers will be used if an exception occurs and
+ %% control transfers to the label given in the previous
+ %% try/2 instruction.
+ {used,St};
+ _ ->
+ check_liveness(R, Is, St)
end;
check_liveness(R, [{catch_end,Y}|Is], St) ->
case R of
diff --git a/lib/compiler/src/cerl_inline.erl b/lib/compiler/src/cerl_inline.erl
index c15103999f..589685d72d 100644
--- a/lib/compiler/src/cerl_inline.erl
+++ b/lib/compiler/src/cerl_inline.erl
@@ -1262,8 +1262,9 @@ i_receive_1(E, Cs, T, B, S) ->
i_module(E, Ctxt, Ren, Env, S) ->
%% Cf. `i_letrec'. Note that we pass a dummy constant value for the
%% "body" parameter.
+ Exps = i_module_exports(E),
{Es, _, Xs1, S1} = i_letrec(module_defs(E), void(),
- module_exports(E), Ctxt, Ren, Env, S),
+ Exps, Ctxt, Ren, Env, S),
%% Sanity check:
case Es of
[] ->
@@ -1276,6 +1277,27 @@ i_module(E, Ctxt, Ren, Env, S) ->
E1 = update_c_module(E, module_name(E), Xs1, module_attrs(E), Es),
{E1, count_size(weight(module), S1)}.
+i_module_exports(E) ->
+ %% If a function is named in an `on_load' attribute, we will
+ %% pretend that it is exported to ensure that it will not be removed.
+ Exps = module_exports(E),
+ Attrs = module_attrs(E),
+ case i_module_on_load(Attrs) of
+ none ->
+ Exps;
+ [{_,_}=FA] ->
+ ordsets:add_element(c_var(FA), Exps)
+ end.
+
+i_module_on_load([{Key,Val}|T]) ->
+ case concrete(Key) of
+ on_load ->
+ concrete(Val);
+ _ ->
+ i_module_on_load(T)
+ end;
+i_module_on_load([]) -> none.
+
%% Binary-syntax expressions are too complicated to do anything
%% interesting with here - that is beyond the scope of this program;
%% also, their construction could have side effects, so even in effect
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index a17a10046e..9b505ad15c 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -629,6 +629,8 @@ asm_passes() ->
[{unless,no_postopt,
[{pass,beam_block},
{iff,dblk,{listing,"block"}},
+ {unless,no_except,{pass,beam_except}},
+ {iff,dexcept,{listing,"except"}},
{unless,no_bopt,{pass,beam_bool}},
{iff,dbool,{listing,"bool"}},
{unless,no_topt,{pass,beam_type}},
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index fb06f2521c..1133882728 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -28,6 +28,7 @@
beam_dead,
beam_dict,
beam_disasm,
+ beam_except,
beam_flatten,
beam_jump,
beam_listing,
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 6ea67741fa..5b155398dc 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2641,9 +2641,9 @@ bsm_leftmost_2([_|Ps], Cs, N, Pos) ->
bsm_leftmost_2([], Cs, _, Pos) ->
bsm_leftmost_1(Cs, Pos).
-%% bsm_notempty(Cs, Pos) -> true|false
+%% bsm_nonempty(Cs, Pos) -> true|false
%% Check if at least one of the clauses matches a non-empty
-%% binary in the given argumet position.
+%% binary in the given argument position.
%%
bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) ->
case nth(Pos, Ps) of
@@ -2704,7 +2704,7 @@ bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) ->
%%
%% But if the clauses can't be freely rearranged, as in
%%
- %% b(Var, <<>>) -> ...
+ %% b(Var, <<X>>) -> ...
%% b(1, 2) -> ...
%%
%% we do have a problem.
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index e7dae67085..6623485609 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -53,7 +53,6 @@
%% Main codegen structure.
-record(cg, {lcount=1, %Label counter
- finfo, %Function info label
bfail, %Fail label for BIFs
break, %Break label
recv, %Receive label
@@ -126,7 +125,6 @@ cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, Anno, St0) ->
stk=[]}, 0, Vdb),
{B,_Aft,St} = cg_list(Les, 0, Vdb, Bef,
St3#cg{bfail=0,
- finfo=Fi,
ultimate_failure=UltimateMatchFail,
is_top_block=true}),
{Name,Arity} = NameArity,
@@ -147,8 +145,6 @@ cg({match,M,Rs}, Le, Vdb, Bef, St) ->
match_cg(M, Rs, Le, Vdb, Bef, St);
cg({guard_match,M,Rs}, Le, Vdb, Bef, St) ->
guard_match_cg(M, Rs, Le, Vdb, Bef, St);
-cg({match_fail,F}, Le, Vdb, Bef, St) ->
- match_fail_cg(F, Le, Vdb, Bef, St);
cg({call,Func,As,Rs}, Le, Vdb, Bef, St) ->
call_cg(Func, As, Rs, Le, Vdb, Bef, St);
cg({enter,Func,As}, Le, Vdb, Bef, St) ->
@@ -294,39 +290,6 @@ match_cg({block,Es}, Le, _Fail, Bef, St) ->
Int = clear_dead(Bef, Le#l.i, Le#l.vdb),
block_cg(Es, Le, Int, St).
-%% match_fail_cg(FailReason, Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%% Generate code for the match_fail "call". N.B. there is no generic
-%% case for when the fail value has been created elsewhere.
-
-match_fail_cg({function_clause,As}, Le, Vdb, Bef, St) ->
- %% Must have the args in {x,0}, {x,1},...
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- {Sis ++ [{jump,{f,St#cg.finfo}}],
- Int#sr{reg=clear_regs(Int#sr.reg)},St};
-match_fail_cg({badmatch,Term}, Le, Vdb, Bef, St) ->
- R = cg_reg_arg(Term, Bef),
- Int0 = clear_dead(Bef, Le#l.i, Vdb),
- {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb),
- {Sis ++ [line(Le),{badmatch,R}],
- Int#sr{reg=clear_regs(Int0#sr.reg)},St};
-match_fail_cg({case_clause,Reason}, Le, Vdb, Bef, St) ->
- R = cg_reg_arg(Reason, Bef),
- Int0 = clear_dead(Bef, Le#l.i, Vdb),
- {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb),
- {Sis++[line(Le),{case_end,R}],
- Int#sr{reg=clear_regs(Bef#sr.reg)},St};
-match_fail_cg(if_clause, Le, Vdb, Bef, St) ->
- Int0 = clear_dead(Bef, Le#l.i, Vdb),
- {Sis,Int1} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb),
- {Sis++[line(Le),if_end],Int1#sr{reg=clear_regs(Int1#sr.reg)},St};
-match_fail_cg({try_clause,Reason}, Le, Vdb, Bef, St) ->
- R = cg_reg_arg(Reason, Bef),
- Int0 = clear_dead(Bef, Le#l.i, Vdb),
- {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb),
- {Sis ++ [line(Le),{try_case_end,R}],
- Int#sr{reg=clear_regs(Int0#sr.reg)},St}.
-
%% bsm_rename_ctx([Clause], Var) -> [Clause]
%% We know from an annotation that the register for a binary can
%% be reused for the match context because the two are not truly
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index d76291f57f..f2eaa37617 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -83,6 +83,7 @@
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,
keymember/3,keyfind/3]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
+-import(cerl, [c_tuple/1]).
-include("core_parse.hrl").
-include("v3_kernel.hrl").
@@ -422,10 +423,11 @@ expr(#c_call{anno=A,module=M0,name=F0,args=Cargs}, Sub, St0) ->
end;
expr(#c_primop{anno=A,name=#c_literal{val=match_fail},args=Cargs0}, Sub, St0) ->
Cargs = translate_match_fail(Cargs0, Sub, A, St0),
- %% This special case will disappear.
{Kargs,Ap,St} = atomic_list(Cargs, Sub, St0),
Ar = length(Cargs),
- Call = #k_call{anno=A,op=#k_internal{name=match_fail,arity=Ar},args=Kargs},
+ Call = #k_call{anno=A,op=#k_remote{mod=#k_atom{val=erlang},
+ name=#k_atom{val=error},
+ arity=Ar},args=Kargs},
{Call,Ap,St};
expr(#c_primop{anno=A,name=#c_literal{val=N},args=Cargs}, Sub, St0) ->
{Kargs,Ap,St1} = atomic_list(Cargs, Sub, St0),
@@ -455,14 +457,14 @@ expr(#ireceive_accept{anno=A}, _Sub, St) -> {#k_receive_accept{anno=A},[],St}.
translate_match_fail(Args, Sub, Anno, St) ->
case Args of
[#c_tuple{es=[#c_literal{val=function_clause}|As]}] ->
- translate_match_fail_1(Anno, Args, As, Sub, St);
+ translate_match_fail_1(Anno, As, Sub, St);
[#c_literal{val=Tuple}] when is_tuple(Tuple) ->
%% The inliner may have created a literal out of
%% the original #c_tuple{}.
case tuple_to_list(Tuple) of
[function_clause|As0] ->
As = [#c_literal{val=E} || E <- As0],
- translate_match_fail_1(Anno, Args, As, Sub, St);
+ translate_match_fail_1(Anno, As, Sub, St);
_ ->
Args
end;
@@ -471,7 +473,7 @@ translate_match_fail(Args, Sub, Anno, St) ->
Args
end.
-translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) ->
+translate_match_fail_1(Anno, As, Sub, #kern{ff=FF}) ->
AnnoFunc = case keyfind(function_name, 1, Anno) of
false ->
none; %Force rewrite.
@@ -481,10 +483,10 @@ translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) ->
case {AnnoFunc,FF} of
{Same,Same} ->
%% Still in the correct function.
- Args;
+ translate_fc(As);
{{F,_},F} ->
%% Still in the correct function.
- Args;
+ translate_fc(As);
_ ->
%% Wrong function or no function_name annotation.
%%
@@ -493,9 +495,12 @@ translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) ->
%% the current function). match_fail(function_clause) will
%% only work at the top level of the function it was originally
%% defined in, so we will need to rewrite it to a case_clause.
- [#c_tuple{es=[#c_literal{val=case_clause},#c_tuple{es=As}]}]
+ [c_tuple([#c_literal{val=case_clause},c_tuple(As)])]
end.
+translate_fc(Args) ->
+ [#c_literal{val=function_clause},make_list(Args)].
+
%% call_type(Module, Function, Arity) -> call | bif | apply | error.
%% Classify the call.
call_type(#c_literal{val=M}, #c_literal{val=F}, Ar) when is_atom(M), is_atom(F) ->
@@ -1494,7 +1499,6 @@ iletrec_funs_gen(Fs, FreeVs, St) ->
%% is_exit_expr(Kexpr) -> boolean().
%% Test whether Kexpr always exits and never returns.
-is_exit_expr(#k_call{op=#k_internal{name=match_fail,arity=1}}) -> true;
is_exit_expr(#k_receive_next{}) -> true;
is_exit_expr(_) -> false.
diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl
index fac9a9843d..93f8034230 100644
--- a/lib/compiler/src/v3_life.erl
+++ b/lib/compiler/src/v3_life.erl
@@ -89,19 +89,8 @@ function(#k_fdef{anno=#k{a=Anno},func=F,arity=Ar,vars=Vs,body=Kb}) ->
end.
%% body(Kbody, I, Vdb) -> {[Expr],MaxI,Vdb}.
-%% Handle a body, need special cases for transforming match_fails.
-%% We KNOW that they only occur last in a body.
-
-body(#k_seq{arg=#k_put{anno=Pa,arg=Arg,ret=[R]},
- body=#k_enter{anno=Ea,op=#k_internal{name=match_fail,arity=1},
- args=[R]}},
- I, Vdb0) ->
- Vdb1 = use_vars(Pa#k.us, I, Vdb0), %All used here
- {[match_fail(Arg, I, Pa#k.a ++ Ea#k.a)],I,Vdb1};
-body(#k_enter{anno=Ea,op=#k_internal{name=match_fail,arity=1},args=[Arg]},
- I, Vdb0) ->
- Vdb1 = use_vars(Ea#k.us, I, Vdb0),
- {[match_fail(Arg, I, Ea#k.a)],I,Vdb1};
+%% Handle a body.
+
body(#k_seq{arg=Ke,body=Kb}, I, Vdb0) ->
%%ok = io:fwrite("life ~w:~p~n", [?LINE,{Ke,I,Vdb0}]),
A = get_kanno(Ke),
@@ -353,25 +342,6 @@ guard_clause(#k_guard_clause{anno=A,guard=Kg,body=Kb}, Ls, I, Ctxt, Vdb0) ->
i=I,vdb=use_vars((get_kanno(Kg))#k.us, I+2, Vdb1),
a=A#k.a}.
-%% match_fail(FailValue, I, Anno) -> Expr.
-%% Generate the correct match_fail instruction. N.B. there is no
-%% generic case for when the fail value has been created elsewhere.
-
-match_fail(#k_literal{anno=Anno,val={Atom,Val}}, I, A) when is_atom(Atom) ->
- match_fail(#k_tuple{anno=Anno,es=[#k_atom{val=Atom},#k_literal{val=Val}]}, I, A);
-match_fail(#k_literal{anno=Anno,val={Atom}}, I, A) when is_atom(Atom) ->
- match_fail(#k_tuple{anno=Anno,es=[#k_atom{val=Atom}]}, I, A);
-match_fail(#k_tuple{es=[#k_atom{val=function_clause}|As]}, I, A) ->
- #l{ke={match_fail,{function_clause,literal_list(As, [])}},i=I,a=A};
-match_fail(#k_tuple{es=[#k_atom{val=badmatch},Val]}, I, A) ->
- #l{ke={match_fail,{badmatch,literal(Val, [])}},i=I,a=A};
-match_fail(#k_tuple{es=[#k_atom{val=case_clause},Val]}, I, A) ->
- #l{ke={match_fail,{case_clause,literal(Val, [])}},i=I,a=A};
-match_fail(#k_atom{val=if_clause}, I, A) ->
- #l{ke={match_fail,if_clause},i=I,a=A};
-match_fail(#k_tuple{es=[#k_atom{val=try_clause},Val]}, I, A) ->
- #l{ke={match_fail,{try_clause,literal(Val, [])}},i=I,a=A}.
-
%% type(Ktype) -> Type.
type(k_literal) -> literal;
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index b90adaf917..e13ad4ae90 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -10,6 +10,7 @@ MODULES= \
apply_SUITE \
beam_validator_SUITE \
beam_disasm_SUITE \
+ beam_expect_SUITE \
bs_bincomp_SUITE \
bs_bit_binaries_SUITE \
bs_construct_SUITE \
@@ -29,7 +30,6 @@ MODULES= \
misc_SUITE \
num_bif_SUITE \
pmod_SUITE \
- parteval_SUITE \
receive_SUITE \
record_SUITE \
trycatch_SUITE \
@@ -39,6 +39,7 @@ MODULES= \
NO_OPT= \
andor \
apply \
+ beam_expect \
bs_construct \
bs_match \
bs_utf \
diff --git a/lib/compiler/test/beam_expect_SUITE.erl b/lib/compiler/test/beam_expect_SUITE.erl
new file mode 100644
index 0000000000..6f216eac4f
--- /dev/null
+++ b/lib/compiler/test/beam_expect_SUITE.erl
@@ -0,0 +1,67 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(beam_expect_SUITE).
+
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ coverage/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [coverage].
+
+groups() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+coverage(_) ->
+ File = {file,"fake.erl"},
+ ok = fc(a),
+ {'EXIT',{function_clause,
+ [{?MODULE,fc,[[x]],[File,{line,2}]}|_]}} =
+ (catch fc([x])),
+ {'EXIT',{function_clause,
+ [{?MODULE,fc,[y],[File,{line,2}]}|_]}} =
+ (catch fc(y)),
+ {'EXIT',{function_clause,
+ [{?MODULE,fc,[[a,b,c]],[File,{line,6}]}|_]}} =
+ (catch fc([a,b,c])),
+
+ {'EXIT',{undef,[{erlang,error,[a,b,c],_}|_]}} =
+ (catch erlang:error(a, b, c)),
+ ok.
+
+-file("fake.erl", 1).
+fc(a) -> %Line 2
+ ok; %Line 3
+fc(L) when length(L) > 2 -> %Line 4
+ %% Not the same as a "real" function_clause error.
+ error(function_clause, [L]). %Line 6
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 556dc54a8f..902867bc19 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -79,21 +79,18 @@ beam_files(Config) when is_list(Config) ->
%% a grammatical error in the output of the io:format/2 call below. ;-)
?line [_,_|_] = Fs = filelib:wildcard(Wc),
?line io:format("~p files\n", [length(Fs)]),
- beam_files_1(Fs, 0).
-
-beam_files_1([F|Fs], Errors) ->
- ?line case beam_validator:file(F) of
- ok ->
- beam_files_1(Fs, Errors);
- {error,Es} ->
- io:format("File: ~s", [F]),
- io:format("Error: ~p\n", [Es]),
- beam_files_1(Fs, Errors+1)
- end;
-beam_files_1([], 0) -> ok;
-beam_files_1([], Errors) ->
- ?line io:format("~p error(s)", [Errors]),
- ?line ?t:fail().
+ test_lib:p_run(fun do_beam_file/1, Fs).
+
+
+do_beam_file(F) ->
+ case beam_validator:file(F) of
+ ok ->
+ ok;
+ {error,Es} ->
+ io:format("File: ~s", [F]),
+ io:format("Error: ~p\n", [Es]),
+ error
+ end.
compiler_bug(Config) when is_list(Config) ->
%% Check that the compiler returns an error if we try to
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index f8c71a0257..01b7568122 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -342,6 +342,10 @@ partitioned_bs_match(Config) when is_list(Config) ->
?line fc(partitioned_bs_match_2, [4,<<0:17>>],
catch partitioned_bs_match_2(4, <<0:17>>)),
+
+ anything = partitioned_bs_match_3(anything, <<42>>),
+ ok = partitioned_bs_match_3(1, 2),
+
ok.
partitioned_bs_match(_, <<42:8,T/binary>>) ->
@@ -356,6 +360,9 @@ partitioned_bs_match_2(1, <<B:8,T/binary>>) ->
partitioned_bs_match_2(Len, <<_:8,T/binary>>) ->
{Len,T}.
+partitioned_bs_match_3(Var, <<_>>) -> Var;
+partitioned_bs_match_3(1, 2) -> ok.
+
function_clause(Config) when is_list(Config) ->
?line ok = function_clause_1(<<0,7,0,7,42>>),
?line fc(function_clause_1, [<<0,1,2,3>>],
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index 1343fbd1c9..408fd5ed53 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -44,7 +44,7 @@ all() ->
trycatch_4, opt_crash, otp_5404, otp_5436, otp_5481,
otp_5553, otp_5632, otp_5714, otp_5872, otp_6121,
otp_6121a, otp_6121b, otp_7202, otp_7345, on_load,
- string_table,otp_8949_a,otp_8949_a].
+ string_table,otp_8949_a,otp_8949_a,split_cases].
groups() ->
[{vsn, [], [vsn_1, vsn_2, vsn_3]}].
@@ -159,6 +159,7 @@ split({int, N}, <<N:16,B:N/binary,T/binary>>) ->
?comp(convopts).
?comp(otp_7202).
?comp(on_load).
+?comp(on_load_inline).
beam_compiler_7(doc) ->
"Code snippet submitted from Ulf Wiger which fails in R3 Beam.";
@@ -427,9 +428,9 @@ self_compile_1(Config, Prefix, Opts) ->
%% Compile the compiler again using the newly compiled compiler.
%% (In another node because reloading the compiler would disturb cover.)
CompilerB = Prefix++"compiler_b",
- ?line CompB = make_compiler_dir(Priv, Prefix++"compiler_b"),
+ CompB = make_compiler_dir(Priv, CompilerB),
?line VsnB = VsnA ++ ".0",
- ?line self_compile_node(CompilerB, CompA, CompB, VsnB, Opts),
+ self_compile_node(CompA, CompB, VsnB, Opts),
%% Compare compiler directories.
?line compare_compilers(CompA, CompB),
@@ -438,21 +439,26 @@ self_compile_1(Config, Prefix, Opts) ->
?line CompilerC = Prefix++"compiler_c",
?line CompC = make_compiler_dir(Priv, CompilerC),
?line VsnC = VsnB ++ ".0",
- ?line self_compile_node(CompilerC, CompB, CompC, VsnC, Opts),
+ self_compile_node(CompB, CompC, VsnC, Opts),
?line compare_compilers(CompB, CompC),
?line test_server:timetrap_cancel(Dog),
ok.
-self_compile_node(NodeName0, CompilerDir, OutDir, Version, Opts) ->
- ?line NodeName = list_to_atom(NodeName0),
- ?line Dog = test_server:timetrap(test_server:minutes(10)),
+self_compile_node(CompilerDir, OutDir, Version, Opts) ->
+ ?line Dog = test_server:timetrap(test_server:minutes(15)),
?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)) ++
" -pa " ++ CompilerDir,
- ?line {ok,Node} = start_node(NodeName, Pa),
?line Files = compiler_src(),
- ?line ok = rpc:call(Node, ?MODULE, compile_compiler, [Files,OutDir,Version,Opts]),
- ?line test_server:stop_node(Node),
+
+ %% We don't want the cover server started on the other node,
+ %% because it will load the same cover-compiled code as on this
+ %% node. Use a shielded node to prevent the cover server from
+ %% being started.
+ ?t:run_on_shielded_node(
+ fun() ->
+ compile_compiler(Files, OutDir, Version, Opts)
+ end, Pa),
?line test_server:timetrap_cancel(Dog),
ok.
@@ -465,9 +471,12 @@ compile_compiler(Files, OutDir, Version, InlineOpts) ->
{d,'COMPILER_VSN',"\""++Version++"\""},
nowarn_shadow_vars,
{i,filename:join(code:lib_dir(stdlib), "include")}|InlineOpts],
- lists:foreach(fun(File) ->
- {ok,_} = compile:file(File, Opts)
- end, Files).
+ test_lib:p_run(fun(File) ->
+ case compile:file(File, Opts) of
+ {ok,_} -> ok;
+ _ -> error
+ end
+ end, Files).
compiler_src() ->
filelib:wildcard(filename:join([code:lib_dir(compiler), "src", "*.erl"])).
@@ -657,5 +666,19 @@ otp_8949_b(A, B) ->
id(Var)
end.
+split_cases(_) ->
+ dummy1 = do_split_cases(x),
+ {'EXIT',{{badmatch,b},_}} = (catch do_split_cases(y)),
+ ok.
+
+do_split_cases(A) ->
+ case A of
+ x ->
+ Z = dummy1;
+ _ ->
+ Z = dummy2,
+ a=b
+ end,
+ Z.
id(I) -> I.
diff --git a/lib/compiler/test/compilation_SUITE_data/on_load_inline.erl b/lib/compiler/test/compilation_SUITE_data/on_load_inline.erl
new file mode 100644
index 0000000000..322843b61e
--- /dev/null
+++ b/lib/compiler/test/compilation_SUITE_data/on_load_inline.erl
@@ -0,0 +1,23 @@
+-module(on_load_inline).
+-export([?MODULE/0]).
+-on_load(on_load/0).
+-compile(inline).
+
+?MODULE() ->
+ [{pid,Pid}] = ets:lookup(on_load_executed, pid),
+ exit(Pid, kill),
+ ok.
+
+on_load() ->
+ Parent = self(),
+ spawn(fun() ->
+ T = ets:new(on_load_executed, [named_table]),
+ ets:insert(T, {pid,self()}),
+ Parent ! done,
+ receive
+ wait_forever -> ok
+ end
+ end),
+ receive
+ done -> ok
+ end.
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index fedbd98f71..640849f2ec 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -29,7 +29,8 @@
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,
- missing_testheap/1, cover/1, env/1, core/1, asm/1]).
+ missing_testheap/1, cover/1, env/1, core/1, asm/1,
+ sys_pre_attributes/1]).
-export([init/3]).
@@ -45,7 +46,8 @@ all() ->
binary, makedep, cond_and_ifdef, listings, listings_big,
other_output, package_forms, encrypted_abstr,
{group, bad_record_use}, strict_record,
- missing_testheap, cover, env, core, asm].
+ missing_testheap, cover, env, core, asm,
+ sys_pre_attributes].
groups() ->
[{bad_record_use, [],
@@ -785,6 +787,37 @@ do_asm(Beam, Outdir) ->
error
end.
+sys_pre_attributes(Config) ->
+ DataDir = ?config(data_dir, Config),
+ File = filename:join(DataDir, "attributes.erl"),
+ Mod = attributes,
+ CommonOpts = [binary,report,verbose,
+ {parse_transform,sys_pre_attributes}],
+ PreOpts = [{attribute,delete,deleted}],
+ PostOpts = [{attribute,insert,inserted,"value"}],
+ PrePostOpts = [{attribute,replace,replaced,42},
+ {attribute,replace,replace_nonexisting,new}],
+ {ok,Mod,Code} = compile:file(File, PrePostOpts ++ PreOpts ++
+ PostOpts ++ CommonOpts),
+ code:load_binary(Mod, File, Code),
+ Attr = Mod:module_info(attributes),
+ io:format("~p", [Attr]),
+ {inserted,"value"} = lists:keyfind(inserted, 1, Attr),
+ {replaced,[42]} = lists:keyfind(replaced, 1, Attr),
+ {replace_nonexisting,[new]} = lists:keyfind(replace_nonexisting, 1, Attr),
+ false = lists:keymember(deleted, 1, Attr),
+
+ %% Cover more code.
+ {ok,Mod,_} = compile:file(File, PostOpts ++ CommonOpts),
+ {ok,Mod,_} = compile:file(File, CommonOpts -- [verbose]),
+ {ok,Mod,_} = compile:file(File, PreOpts ++ CommonOpts),
+ {ok,Mod,_} = compile:file(File,
+ [{attribute,replace,replaced,42}|CommonOpts]),
+ {ok,Mod,_} = compile:file(File, PrePostOpts ++ PreOpts ++
+ PostOpts ++ CommonOpts --
+ [report,verbose]),
+ ok.
+
%%%
%%% Utilities.
%%%
diff --git a/lib/compiler/test/compile_SUITE_data/attributes.erl b/lib/compiler/test/compile_SUITE_data/attributes.erl
new file mode 100644
index 0000000000..9c3451d272
--- /dev/null
+++ b/lib/compiler/test/compile_SUITE_data/attributes.erl
@@ -0,0 +1,23 @@
+%%
+%% %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(attributes).
+-deleted(dummy).
+-replaced(dummy).
+
diff --git a/lib/compiler/test/compiler.cover b/lib/compiler/test/compiler.cover
index 9fc4c7dd43..3fd7fc1937 100644
--- a/lib/compiler/test/compiler.cover
+++ b/lib/compiler/test/compiler.cover
@@ -1,5 +1,5 @@
{incl_app,compiler,details}.
%% -*- erlang -*-
-{excl_mods,[sys_pre_attributes,core_scan,core_parse]}.
+{excl_mods,compiler,[core_scan,core_parse]}.
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 26173c62b8..874e02803d 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -21,7 +21,9 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
- dehydrated_itracer/1,nested_tries/1]).
+ dehydrated_itracer/1,nested_tries/1,
+ make_effect_seq/1,eval_is_boolean/1,
+ unsafe_case/1,nomatch_shadow/1,reversed_annos/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -41,7 +43,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [dehydrated_itracer, nested_tries].
+ [dehydrated_itracer,nested_tries,make_effect_seq,
+ eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos].
groups() ->
[].
@@ -61,19 +64,18 @@ end_per_group(_GroupName, Config) ->
?comp(dehydrated_itracer).
?comp(nested_tries).
+?comp(make_effect_seq).
+?comp(eval_is_boolean).
+?comp(unsafe_case).
+?comp(nomatch_shadow).
+?comp(reversed_annos).
try_it(Mod, Conf) ->
- ?line Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)),
- ?line Out = ?config(priv_dir,Conf),
- ?line io:format("Compiling: ~s\n", [Src]),
- ?line CompRc0 = compile:file(Src, [from_core,{outdir,Out},report,time]),
- ?line io:format("Result: ~p\n",[CompRc0]),
- ?line {ok,Mod} = CompRc0,
-
- ?line {module,Mod} = code:load_abs(filename:join(Out, Mod)),
- ?line ok = Mod:Mod(),
- ok.
-
-
-
-
+ Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)),
+ compile_and_load(Src, []),
+ compile_and_load(Src, [no_copt]).
+
+compile_and_load(Src, Opts) ->
+ {ok,Mod,Bin} = compile:file(Src, [from_core,report,time,binary|Opts]),
+ {module,Mod} = code:load_binary(Mod, Mod, Bin),
+ ok = Mod:Mod().
diff --git a/lib/compiler/test/core_SUITE_data/eval_is_boolean.core b/lib/compiler/test/core_SUITE_data/eval_is_boolean.core
new file mode 100644
index 0000000000..6a68b1414d
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/eval_is_boolean.core
@@ -0,0 +1,22 @@
+module 'eval_is_boolean' ['eval_is_boolean'/0]
+ attributes []
+'eval_is_boolean'/0 =
+ %% Line 4
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ case call 'erlang':'is_boolean'(call 'erlang':'make_ref'()) of
+ <'false'> when 'true' ->
+ 'ok'
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'eval_is_boolean',0}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/make_effect_seq.core b/lib/compiler/test/core_SUITE_data/make_effect_seq.core
new file mode 100644
index 0000000000..9941e63b76
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/make_effect_seq.core
@@ -0,0 +1,51 @@
+module 'make_effect_seq' ['make_effect_seq'/0]
+ attributes []
+'make_effect_seq'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ let <_cor0> =
+ catch
+ apply 't'/1
+ ('a')
+ in
+ case _cor0 of
+ <{'EXIT',{'badarg',_cor3}}> when 'true' ->
+ let <_cor4> =
+ apply 't'/1
+ ({'a','b','c'})
+ in
+ case _cor4 of
+ <'ok'> when 'true' ->
+ ( _cor4
+ -| ['compiler_generated'] )
+ ( <_cor2> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor2})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'make_effect_seq',0}}] )
+ -| ['compiler_generated'] )
+ end
+'t'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <T> when 'true' ->
+ do
+ {'ok',call 'erlang':'element'(2, T)}
+ 'ok'
+ ( <_cor2> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor2})
+ -| [{'function_name',{'t',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/nomatch_shadow.core b/lib/compiler/test/core_SUITE_data/nomatch_shadow.core
new file mode 100644
index 0000000000..565d9dc0f3
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/nomatch_shadow.core
@@ -0,0 +1,28 @@
+module 'nomatch_shadow' ['nomatch_shadow'/0]
+ attributes []
+'nomatch_shadow'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ apply 't'/1
+ (42)
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'nomatch_shadow',0}}] )
+ -| ['compiler_generated'] )
+ end
+'t'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <42> when 'true' ->
+ 'ok'
+ <42> when 'true' ->
+ 'ok'
+ ( <_cor1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor1})
+ -| [{'function_name',{'t',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/reversed_annos.core b/lib/compiler/test/core_SUITE_data/reversed_annos.core
new file mode 100644
index 0000000000..95b3cd52d6
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/reversed_annos.core
@@ -0,0 +1,49 @@
+module 'reversed_annos' ['reversed_annos'/0]
+ attributes []
+'reversed_annos'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ case apply 't'/1
+ (['a']) of
+ <'ok'> when 'true' ->
+ let <_cor2> =
+ apply 't'/1
+ (['a'|['b']])
+ in
+ case _cor2 of
+ <'ok'> when 'true' ->
+ ( _cor2
+ -| ['compiler_generated'] )
+ ( <_cor1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor1})
+ -| ['compiler_generated'] )
+ end
+ ( <_cor0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor0})
+ -| ['compiler_generated'] )
+ end
+ ( <> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause'})
+ -| [{'function_name',{'reversed_annos',0}}] )
+ -| ['compiler_generated'] )
+ end
+'t'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <[_cor2|_cor3]> when 'true' ->
+ 'ok'
+ %% Cover v3_kernel:get_line/1.
+ ( <['a']> when 'true' ->
+ 'error'
+ -| [{'file',"reversed_annos.erl"},11] )
+ ( <_cor1> when 'true' ->
+ ( primop 'match_fail'
+ ({'function_clause',_cor1})
+ -| [{'function_name',{'t',1}}] )
+ -| ['compiler_generated'] )
+ end
+end
diff --git a/lib/compiler/test/core_SUITE_data/unsafe_case.core b/lib/compiler/test/core_SUITE_data/unsafe_case.core
new file mode 100644
index 0000000000..84cb2c310a
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/unsafe_case.core
@@ -0,0 +1,25 @@
+module 'unsafe_case' ['unsafe_case'/0]
+ attributes []
+'unsafe_case'/0 =
+ fun () ->
+ case apply 't'/1
+ (42) of
+ <{'ok',42}> when 'true' ->
+ 'ok'
+ ( <_cor0> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_cor0})
+ -| ['compiler_generated'] )
+ end
+'t'/1 =
+ fun (_cor0) ->
+ case _cor0 of
+ <X>
+ when call 'erlang':'>'
+ (_cor0,
+ 0) ->
+ {'ok',X}
+ %% The default case is intentionally missing
+ %% to cover v3_kernel:build_match/2.
+ end
+end
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index ac14d36e82..fb5ec88c9f 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -214,6 +214,7 @@ coverage(Config) when is_list(Config) ->
(catch cover_will_match_list_type({a,b,c,d})),
?line a = cover_remove_non_vars_alias({a,b,c}),
?line error = cover_will_match_lit_list(),
+ {ok,[a]} = cover_is_safe_bool_expr(a),
%% Make sure that we don't attempt to make literals
%% out of pids. (Putting a pid into a #c_literal{}
@@ -249,4 +250,17 @@ cover_will_match_lit_list() ->
error
end.
+cover_is_safe_bool_expr(X) ->
+ %% Use a try...catch that looks like a try...catch in a guard.
+ try
+ %% let V = [X] in {ok,V}
+ %% is_safe_simple([X]) ==> true
+ %% is_safe_bool_expr([X]) ==> false
+ V = [X],
+ {ok,V}
+ catch
+ _:_ ->
+ false
+ end.
+
id(I) -> I.
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index 9b414cade6..5e13a93c52 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_except
+ ExceptInput = {?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_except:module(ExceptInput, []) end),
+
%% beam_bool
BoolInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -253,8 +262,15 @@ expect_error(Fun) ->
io:format("~p", [Any]),
?t:fail(call_was_supposed_to_fail)
catch
- _:_ ->
- io:format("~p\n", [erlang:get_stacktrace()])
+ Class:Reason ->
+ Stk = erlang:get_stacktrace(),
+ io:format("~p:~p\n~p\n", [Class,Reason,Stk]),
+ case {Class,Reason} of
+ {error,undef} ->
+ ?t:fail(not_supposed_to_fail_with_undef);
+ {_,_} ->
+ ok
+ end
end.
confused_literals(Config) when is_list(Config) ->
diff --git a/lib/compiler/test/parteval_SUITE.erl b/lib/compiler/test/parteval_SUITE.erl
deleted file mode 100644
index 6b1ae38c1b..0000000000
--- a/lib/compiler/test/parteval_SUITE.erl
+++ /dev/null
@@ -1,66 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(parteval_SUITE).
-
--include_lib("test_server/include/test_server.hrl").
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2, pe2/1]).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [pe2].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% (This is more general than needed, since we once compiled the same
-%% source code with and without a certain option.)
-compile_and_load(Srcname, Outdir, Module, Options) ->
- ?line Objname = filename:join(Outdir, "t1") ++ code:objfile_extension(),
- ?line {ok, Module} =
- compile:file(Srcname,
- [{d, 'M', Module}, {outdir, Outdir}] ++ Options),
- ?line {ok, B} = file:read_file(Objname),
- ?line {module, Module} = code:load_binary(Module, Objname, B),
- B.
-
-pe2(Config) when is_list(Config) ->
- ?line DataDir = ?config(data_dir, Config),
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Srcname = filename:join(DataDir, "t1.erl"),
- ?line compile_and_load(Srcname, PrivDir, t1, []),
-
- ?line {Correct, Actual} = t1:run(),
- ?line Correct = Actual,
- ok.
diff --git a/lib/compiler/test/parteval_SUITE_data/t1.erl b/lib/compiler/test/parteval_SUITE_data/t1.erl
deleted file mode 100644
index 5e4a40f103..0000000000
--- a/lib/compiler/test/parteval_SUITE_data/t1.erl
+++ /dev/null
@@ -1,140 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-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(?M).
-
--compile(export_all).
-
-%%% The arity-0 functions are all called from the test suite.
-
-f2() ->
- size({1,2}).
-
-i() ->
- case [] of
- [] ->
- ok;
- X ->
- hopp
- end.
-
-e() ->
- case 4+5 of
-% X when X>10 -> kvock; % not removed by BEAM opt.
- {X,X} when list(X) ->
- kvack;
- 9 ->
- ok;
- _ ->
- ko
- end.
-
-f() ->
- element(2,{a,b,c,d}),
- erlang:element(2,{a,b,c,d}),
- "hej" ++ "hopp".
-
-g(X) ->
- if
- float(3.4) ->
- hej;
- X == 5, 4==4 ->
- japp;
- 4 == 4, size({1,2}) == 1 ->
- ok
- end.
-
-g() ->
- {g(3),g(5)}.
-
-bliff() ->
- if
- 3==4 ->
- himm
- end.
-
-fi() ->
- case 4 of
- X when 4==3 ->
- {X};
- 4 ->
- 4;
- _ ->
- ok
- end.
-
-iff() when 3==2 ->
- if
- 3 == 4 ->
- baff;
- 3 == 3 ->
- nipp
- end.
-
-sleep(I) -> receive after I -> ok end.
-
-sleep() ->
- sleep(45).
-
-s() ->
- case 4 of
- 3 ->
- ok
- end.
-
-error_reason(R) when atom(R) ->
- R;
-error_reason(R) when tuple(R) ->
- error_reason(element(1, R)).
-
-plusplus() ->
- ?MODULE ++ " -> mindre snygg felhantering".
-
-call_it(F) ->
- case (catch apply(?MODULE, F, [])) of
- {'EXIT', R0} ->
- {'EXIT', error_reason(R0)};
- V ->
- V
- end.
-
-run() ->
- L = [{f2, 2},
- {i, ok},
- {e, ok},
- {f, "hejhopp"},
- {g, {hej, hej}},
- {bliff, {'EXIT', if_clause}},
- {fi, 4},
- {iff, {'EXIT', function_clause}},
- {sleep, ok},
- {s, {'EXIT', case_clause},
- {plusplus, {'EXIT', badarg}}}],
- Actual = [call_it(F) || {F, _} <- L],
- Correct = [C || {_, C} <- L],
- {Correct, Actual}.
-
-
-%%% Don't call, only compile.
-t(A) ->
- receive
- A when 1==2 ->
- ok;
- B ->
- B
- end.
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 53d8c04169..2295592a38 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -77,7 +77,14 @@ get_data_dir(Config) ->
%% Will fail the test case if there were any errors.
p_run(Test, List) ->
- N = erlang:system_info(schedulers) + 1,
+ N = case ?t:is_cover() of
+ false ->
+ erlang:system_info(schedulers);
+ true ->
+ %% Cover is running. Using more than one process
+ %% will probably only slow down compilation.
+ 1
+ end,
p_run_loop(Test, List, N, [], 0, 0).
p_run_loop(_, [], _, [], Errors, Ws) ->
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index 760cf17225..09a23724fe 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -24,7 +24,7 @@
catch_oops/1,after_oops/1,eclectic/1,rethrow/1,
nested_of/1,nested_catch/1,nested_after/1,
nested_horrid/1,last_call_optimization/1,bool/1,
- plain_catch_coverage/1,andalso_orelse/1]).
+ plain_catch_coverage/1,andalso_orelse/1,get_in_try/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -35,7 +35,7 @@ all() ->
[basic, lean_throw, try_of, try_after, catch_oops,
after_oops, eclectic, rethrow, nested_of, nested_catch,
nested_after, nested_horrid, last_call_optimization,
- bool, plain_catch_coverage, andalso_orelse].
+ bool, plain_catch_coverage, andalso_orelse, get_in_try].
groups() ->
[].
@@ -928,3 +928,17 @@ andalso_orelse_2({Type,Keyval}) ->
zero() ->
0.0.
+
+get_in_try(_) ->
+ undefined = get_valid_line([a], []),
+ ok.
+
+get_valid_line([_|T]=Path, Annotations) ->
+ try
+ get(Path)
+ %% beam_dead used to optimize away an assignment to {y,1}
+ %% because it didn't appear to be used.
+ catch
+ _:not_found ->
+ get_valid_line(T, Annotations)
+ end.
diff --git a/lib/debugger/src/dbg_ui_break_win.erl b/lib/debugger/src/dbg_ui_break_win.erl
index abbec158b0..2894e8223b 100644
--- a/lib/debugger/src/dbg_ui_break_win.erl
+++ b/lib/debugger/src/dbg_ui_break_win.erl
@@ -17,6 +17,18 @@
%% %CopyrightEnd%
%%
-module(dbg_ui_break_win).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,entry,2}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,listbox,2}},
+ {nowarn_deprecated_function,{gs,menu,2}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,radiobutton,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
%% External exports
-export([create_win/5,
diff --git a/lib/debugger/src/dbg_ui_edit_win.erl b/lib/debugger/src/dbg_ui_edit_win.erl
index 9b0441b44c..fb40ab3812 100644
--- a/lib/debugger/src/dbg_ui_edit_win.erl
+++ b/lib/debugger/src/dbg_ui_edit_win.erl
@@ -17,6 +17,12 @@
%% %CopyrightEnd%
%%
-module(dbg_ui_edit_win).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,entry,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
%% External exports
-export([create_win/5, get_window/1,
diff --git a/lib/debugger/src/dbg_ui_filedialog_win.erl b/lib/debugger/src/dbg_ui_filedialog_win.erl
index 1eced1104d..50d198f361 100644
--- a/lib/debugger/src/dbg_ui_filedialog_win.erl
+++ b/lib/debugger/src/dbg_ui_filedialog_win.erl
@@ -18,6 +18,13 @@
%%
-module(dbg_ui_filedialog_win).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,entry,3}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,listbox,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
%% External exports
-export([create_win/6, create_win/7, get_window/1,
diff --git a/lib/debugger/src/dbg_ui_mon_win.erl b/lib/debugger/src/dbg_ui_mon_win.erl
index 52e8f433ba..f446fb7fcd 100644
--- a/lib/debugger/src/dbg_ui_mon_win.erl
+++ b/lib/debugger/src/dbg_ui_mon_win.erl
@@ -17,6 +17,19 @@
%% %CopyrightEnd%
%%
-module(dbg_ui_mon_win).
+-compile([{nowarn_deprecated_function,{gs,checkbutton,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,grid,2}},
+ {nowarn_deprecated_function,{gs,gridline,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,listbox,2}},
+ {nowarn_deprecated_function,{gs,menu,2}},
+ {nowarn_deprecated_function,{gs,menubar,2}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
%% External exports
-export([init/0]).
diff --git a/lib/debugger/src/dbg_ui_trace_win.erl b/lib/debugger/src/dbg_ui_trace_win.erl
index 82d4199630..f237f30e4a 100644
--- a/lib/debugger/src/dbg_ui_trace_win.erl
+++ b/lib/debugger/src/dbg_ui_trace_win.erl
@@ -17,6 +17,25 @@
%% %CopyrightEnd%
%%
-module(dbg_ui_trace_win).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,button,3}},
+ {nowarn_deprecated_function,{gs,checkbutton,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,editor,2}},
+ {nowarn_deprecated_function,{gs,editor,3}},
+ {nowarn_deprecated_function,{gs,entry,2}},
+ {nowarn_deprecated_function,{gs,entry,3}},
+ {nowarn_deprecated_function,{gs,frame,3}},
+ {nowarn_deprecated_function,{gs,grid,3}},
+ {nowarn_deprecated_function,{gs,gridline,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,label,3}},
+ {nowarn_deprecated_function,{gs,menubar,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,window,2}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
%% External exports
-export([init/0]).
diff --git a/lib/debugger/src/dbg_ui_win.erl b/lib/debugger/src/dbg_ui_win.erl
index 9bed6a1ec5..cef091ee28 100644
--- a/lib/debugger/src/dbg_ui_win.erl
+++ b/lib/debugger/src/dbg_ui_win.erl
@@ -17,6 +17,15 @@
%% %CopyrightEnd%
%%
-module(dbg_ui_win).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,menu,2}},
+ {nowarn_deprecated_function,{gs,menu,3}},
+ {nowarn_deprecated_function,{gs,menubutton,2}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,menuitem,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,1}}]).
%% External exports
-export([init/0,
diff --git a/lib/debugger/src/dbg_ui_winman.erl b/lib/debugger/src/dbg_ui_winman.erl
index c7aac0df23..8619be344b 100644
--- a/lib/debugger/src/dbg_ui_winman.erl
+++ b/lib/debugger/src/dbg_ui_winman.erl
@@ -18,6 +18,11 @@
%%
-module(dbg_ui_winman).
-behaviour(gen_server).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,menu,3}},
+ {nowarn_deprecated_function,{gs,menubutton,3}},
+ {nowarn_deprecated_function,{gs,menuitem,3}}]).
%% External exports
-export([start/0]).
diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl
index 79cf87ae62..aab8fddda7 100644
--- a/lib/debugger/src/dbg_wx_trace_win.erl
+++ b/lib/debugger/src/dbg_wx_trace_win.erl
@@ -19,6 +19,7 @@
%%
-module(dbg_wx_trace_win).
+-compile([{nowarn_deprecated_function,{gs,config,2}}]).
%% External exports
-export([init/0, stop/1]).
diff --git a/lib/debugger/test/bs_construct_SUITE.erl b/lib/debugger/test/bs_construct_SUITE.erl
index 187c9f53b0..fa7b40ff1e 100644
--- a/lib/debugger/test/bs_construct_SUITE.erl
+++ b/lib/debugger/test/bs_construct_SUITE.erl
@@ -56,7 +56,7 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
- Dog = test_server:timetrap(?t:minutes(1)),
+ Dog = test_server:timetrap(?t:minutes(15)),
[{watchdog,Dog}|Config].
end_per_testcase(_Case, Config) ->
diff --git a/lib/debugger/test/bs_match_misc_SUITE.erl b/lib/debugger/test/bs_match_misc_SUITE.erl
index 89fce263f5..ec3746d76a 100644
--- a/lib/debugger/test/bs_match_misc_SUITE.erl
+++ b/lib/debugger/test/bs_match_misc_SUITE.erl
@@ -57,7 +57,7 @@ end_per_suite(Config) when is_list(Config) ->
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
- Dog = test_server:timetrap(?t:minutes(1)),
+ Dog = test_server:timetrap(?t:minutes(15)),
[{watchdog,Dog}|Config].
end_per_testcase(_Case, Config) ->
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index b42f5e8191..458f3a4c81 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -359,8 +359,17 @@ store_core(Mod, Core, NoWarn, Callgraph, CServer) ->
store_code_and_build_callgraph(Mod, LabeledCore, Callgraph, CServer3, NoWarn).
abs_get_nowarn(Abs, M) ->
- [{M, F, A}
- || {attribute, _, compile, {nowarn_unused_function, {F, A}}} <- Abs].
+ Opts = lists:flatten([C || {attribute, _, compile, C} <- Abs]),
+ Warn = erl_lint:bool_option(warn_unused_function, nowarn_unused_function,
+ true, Opts),
+ case Warn of
+ false ->
+ [{M, F, A} || {function, _, F, A, _} <- Abs]; % all functions
+ true ->
+ [{M, F, A} ||
+ {nowarn_unused_function, FAs} <- Opts,
+ {F, A} <- lists:flatten([FAs])]
+ end.
get_exported_types_from_core(Core) ->
Attrs = cerl:module_attrs(Core),
diff --git a/lib/dialyzer/src/dialyzer_gui.erl b/lib/dialyzer/src/dialyzer_gui.erl
index ccd80a4835..f60194e01f 100644
--- a/lib/dialyzer/src/dialyzer_gui.erl
+++ b/lib/dialyzer/src/dialyzer_gui.erl
@@ -28,6 +28,23 @@
%%%-----------------------------------------------------------------------
-module(dialyzer_gui).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,editor,2}},
+ {nowarn_deprecated_function,{gs,entry,2}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,listbox,2}},
+ {nowarn_deprecated_function,{gs,menu,2}},
+ {nowarn_deprecated_function,{gs,menubar,2}},
+ {nowarn_deprecated_function,{gs,menubutton,2}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,radiobutton,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,stop,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/1]).
diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1
new file mode 100644
index 0000000000..de416455e2
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1
@@ -0,0 +1,2 @@
+
+nowarn_unused_function_1.erl:17: Function f3/1 will never be called
diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2
diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3
new file mode 100644
index 0000000000..8ae78673d5
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3
@@ -0,0 +1,3 @@
+
+nowarn_unused_function_3.erl:12: Function f2/1 will never be called
+nowarn_unused_function_3.erl:9: Function f1/1 will never be called
diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl
new file mode 100644
index 0000000000..fcce532f73
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl
@@ -0,0 +1,18 @@
+%% Test that option 'nowarn_unused_funcion' works similarly in
+%% Dialyzer as in the compiler.
+
+-module(nowarn_unused_function_1).
+
+-compile(warn_unused_function).
+
+-compile({nowarn_unused_function,f1/1}).
+f1(_) ->
+ a.
+
+-compile({nowarn_unused_function,[{f2,1}]}).
+f2(_) ->
+ a.
+
+-compile({warn_unused_function,[{f3,1}]}).
+f3(_) ->
+ a.
diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl
new file mode 100644
index 0000000000..9bc3ab14ea
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl
@@ -0,0 +1,18 @@
+%% Test that option 'nowarn_unused_funcion' works similarly in
+%% Dialyzer as in the compiler.
+
+-module(nowarn_unused_function_2).
+
+-compile(nowarn_unused_function).
+
+-compile({warn_unused_function,f1/1}).
+f1(_) ->
+ a.
+
+-compile({warn_unused_function,[{f2,1}]}).
+f2(_) ->
+ a.
+
+-compile({nowarn_unused_function,[{f3,1}]}).
+f3(_) ->
+ a.
diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl
new file mode 100644
index 0000000000..604c5e436b
--- /dev/null
+++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl
@@ -0,0 +1,16 @@
+%% Test that option 'nowarn_unused_funcion' works similarly in
+%% Dialyzer as in the compiler.
+
+-module(nowarn_unused_function_3).
+
+-compile({warn_unused_function,[{f1,1},{f2,1}]}).
+-compile({nowarn_unused_function,[{f3,1}]}).
+
+f1(_) ->
+ a.
+
+f2(_) ->
+ a.
+
+f3(_) ->
+ a.
diff --git a/lib/diameter/examples/GNUmakefile b/lib/diameter/examples/code/GNUmakefile
index 4c3f87939b..a0669119d2 100644
--- a/lib/diameter/examples/GNUmakefile
+++ b/lib/diameter/examples/code/GNUmakefile
@@ -1,19 +1,19 @@
-#
+#
# %CopyrightBegin%
-#
+#
# Copyright Ericsson AB 2010-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%
#
diff --git a/lib/diameter/examples/client.erl b/lib/diameter/examples/code/client.erl
index 36a77dd524..9e65f98de0 100644
--- a/lib/diameter/examples/client.erl
+++ b/lib/diameter/examples/code/client.erl
@@ -112,7 +112,7 @@ cast(Name) ->
{'Auth-Application-Id', 0},
{'Re-Auth-Request-Type', 1}],
diameter:call(Name, ?APP_ALIAS, RAR, [detach]).
-
+
cast() ->
cast(?SVC_NAME).
diff --git a/lib/diameter/examples/client_cb.erl b/lib/diameter/examples/code/client_cb.erl
index 524a8f94a1..524a8f94a1 100644
--- a/lib/diameter/examples/client_cb.erl
+++ b/lib/diameter/examples/code/client_cb.erl
diff --git a/lib/diameter/examples/peer.erl b/lib/diameter/examples/code/peer.erl
index 89203e15c3..89203e15c3 100644
--- a/lib/diameter/examples/peer.erl
+++ b/lib/diameter/examples/code/peer.erl
diff --git a/lib/diameter/examples/redirect.erl b/lib/diameter/examples/code/redirect.erl
index b54701243f..b54701243f 100644
--- a/lib/diameter/examples/redirect.erl
+++ b/lib/diameter/examples/code/redirect.erl
diff --git a/lib/diameter/examples/redirect_cb.erl b/lib/diameter/examples/code/redirect_cb.erl
index ea7ad38749..ea7ad38749 100644
--- a/lib/diameter/examples/redirect_cb.erl
+++ b/lib/diameter/examples/code/redirect_cb.erl
diff --git a/lib/diameter/examples/relay.erl b/lib/diameter/examples/code/relay.erl
index deecb1cfc0..deecb1cfc0 100644
--- a/lib/diameter/examples/relay.erl
+++ b/lib/diameter/examples/code/relay.erl
diff --git a/lib/diameter/examples/relay_cb.erl b/lib/diameter/examples/code/relay_cb.erl
index 9ed6517d5c..9ed6517d5c 100644
--- a/lib/diameter/examples/relay_cb.erl
+++ b/lib/diameter/examples/code/relay_cb.erl
diff --git a/lib/diameter/examples/sctp.erl b/lib/diameter/examples/code/sctp.erl
index 2e0e9d8b0b..08de023571 100644
--- a/lib/diameter/examples/sctp.erl
+++ b/lib/diameter/examples/code/sctp.erl
@@ -1,3 +1,21 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
-module(sctp).
diff --git a/lib/diameter/examples/server.erl b/lib/diameter/examples/code/server.erl
index ebb408e501..ebb408e501 100644
--- a/lib/diameter/examples/server.erl
+++ b/lib/diameter/examples/code/server.erl
diff --git a/lib/diameter/examples/server_cb.erl b/lib/diameter/examples/code/server_cb.erl
index 43b8e24b5c..43b8e24b5c 100644
--- a/lib/diameter/examples/server_cb.erl
+++ b/lib/diameter/examples/code/server_cb.erl
diff --git a/lib/diameter/examples/dict/rfc4004_mip.dia b/lib/diameter/examples/dict/rfc4004_mip.dia
new file mode 100644
index 0000000000..575ad4394a
--- /dev/null
+++ b/lib/diameter/examples/dict/rfc4004_mip.dia
@@ -0,0 +1,280 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+;;
+;; RFC 4004, Diameter Mobile IPv4 Application
+;;
+;; Edits:
+;;
+;; - MIP-nonce -> MIP-Nonce
+;; - Session-ID -> Session-Id
+;; - Omit MIP-HA-to-MN-SPI, MIP-MN-FA-SPI and MIP-MN-HA-SPI, none of
+;; which are defined.
+;;
+
+@id 2
+
+@inherits rfc3588_base
+
+;; ===========================================================================
+
+@avp_types
+
+ MIP-Reg-Request 320 OctetString M
+ MIP-Reg-Reply 321 OctetString M
+ MIP-MN-AAA-Auth 322 Grouped M
+ MIP-Mobile-Node-Address 333 Address M
+ MIP-Home-Agent-Address 334 Address M
+ MIP-Candidate-Home-Agent-Host 336 DiamIdent M
+ MIP-Feature-Vector 337 Unsigned32 M
+ MIP-Auth-Input-Data-Length 338 Unsigned32 M
+ MIP-Authenticator-Length 339 Unsigned32 M
+ MIP-Authenticator-Offset 340 Unsigned32 M
+ MIP-MN-AAA-SPI 341 Unsigned32 M
+ MIP-Filter-Rule 342 IPFilterRule M
+ MIP-FA-Challenge 344 OctetString M
+ MIP-Originating-Foreign-AAA 347 Grouped M
+ MIP-Home-Agent-Host 348 Grouped M
+
+ MIP-FA-to-HA-SPI 318 Unsigned32 M
+ MIP-FA-to-MN-SPI 319 Unsigned32 M
+ MIP-HA-to-FA-SPI 323 Unsigned32 M
+ MIP-MN-to-FA-MSA 325 Grouped M
+ MIP-FA-to-MN-MSA 326 Grouped M
+ MIP-FA-to-HA-MSA 328 Grouped M
+ MIP-HA-to-FA-MSA 329 Grouped M
+ MIP-MN-to-HA-MSA 331 Grouped M
+ MIP-HA-to-MN-MSA 332 Grouped M
+ MIP-Nonce 335 OctetString M
+ MIP-Session-Key 343 OctetString M
+ MIP-Algorithm-Type 345 Enumerated M
+ MIP-Replay-Mode 346 Enumerated M
+ MIP-MSA-Lifetime 367 Unsigned32 M
+
+;; ===========================================================================
+
+@messages
+
+ ;; 5.1. AA-Mobile-Node-Request
+
+ AMR ::= < Diameter Header: 260, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { User-Name }
+ { Destination-Realm }
+ { Origin-Host }
+ { Origin-Realm }
+ { MIP-Reg-Request }
+ { MIP-MN-AAA-Auth }
+ [ Acct-Multi-Session-Id ]
+ [ Destination-Host ]
+ [ Origin-State-Id ]
+ [ MIP-Mobile-Node-Address ]
+ [ MIP-Home-Agent-Address ]
+ [ MIP-Feature-Vector ]
+ [ MIP-Originating-Foreign-AAA ]
+ [ Authorization-Lifetime ]
+ [ Auth-Session-State ]
+ [ MIP-FA-Challenge ]
+ [ MIP-Candidate-Home-Agent-Host ]
+ [ MIP-Home-Agent-Host ]
+ [ MIP-HA-to-FA-SPI ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 5.2. AA-Mobile-Node-Answer
+
+ AMA ::= < Diameter Header: 260, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ Acct-Multi-Session-Id ]
+ [ User-Name ]
+ [ Authorization-Lifetime ]
+ [ Auth-Session-State ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ [ Re-Auth-Request-Type ]
+ [ MIP-Feature-Vector ]
+ [ MIP-Reg-Reply ]
+ [ MIP-MN-to-FA-MSA ]
+ [ MIP-MN-to-HA-MSA ]
+ [ MIP-FA-to-MN-MSA ]
+ [ MIP-FA-to-HA-MSA ]
+ [ MIP-HA-to-MN-MSA ]
+ [ MIP-MSA-Lifetime ]
+ [ MIP-Home-Agent-Address ]
+ [ MIP-Mobile-Node-Address ]
+ * [ MIP-Filter-Rule ]
+ [ Origin-State-Id ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+ ;; 5.3. Home-Agent-MIP-Request
+
+ HAR ::= < Diameter Header: 262, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Authorization-Lifetime }
+ { Auth-Session-State }
+ { MIP-Reg-Request }
+ { Origin-Host }
+ { Origin-Realm }
+ { User-Name }
+ { Destination-Realm }
+ { MIP-Feature-Vector }
+ [ Destination-Host ]
+ [ MIP-MN-to-HA-MSA ]
+ [ MIP-MN-to-FA-MSA ]
+ [ MIP-HA-to-MN-MSA ]
+ [ MIP-HA-to-FA-MSA ]
+ [ MIP-MSA-Lifetime ]
+ [ MIP-Originating-Foreign-AAA ]
+ [ MIP-Mobile-Node-Address ]
+ [ MIP-Home-Agent-Address ]
+ * [ MIP-Filter-Rule ]
+ [ Origin-State-Id ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 5.4. Home-Agent-MIP-Answer
+
+ HAA ::= < Diameter Header: 262, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ Acct-Multi-Session-Id ]
+ [ User-Name ]
+ [ Error-Reporting-Host ]
+ [ Error-Message ]
+ [ MIP-Reg-Reply ]
+ [ MIP-Home-Agent-Address ]
+ [ MIP-Mobile-Node-Address ]
+ [ MIP-FA-to-HA-SPI ]
+ [ MIP-FA-to-MN-SPI ]
+ [ Origin-State-Id ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+;; ===========================================================================
+
+@grouped
+
+ MIP-MN-AAA-Auth ::= < AVP Header: 322 >
+
+ { MIP-MN-AAA-SPI }
+ { MIP-Auth-Input-Data-Length }
+ { MIP-Authenticator-Length }
+ { MIP-Authenticator-Offset }
+ * [ AVP ]
+
+
+ MIP-Originating-Foreign-AAA ::= < AVP Header: 347 >
+
+ { Origin-Realm }
+ { Origin-Host }
+ * [ AVP ]
+
+ MIP-Home-Agent-Host ::= < AVP Header: 348 >
+
+ { Destination-Realm }
+ { Destination-Host }
+ * [ AVP ]
+
+ MIP-FA-to-MN-MSA ::= < AVP Header: 326 >
+
+ { MIP-FA-to-MN-SPI }
+ { MIP-Algorithm-Type }
+ { MIP-Session-Key }
+ * [ AVP ]
+
+ MIP-FA-to-HA-MSA ::= < AVP Header: 328 >
+
+ { MIP-FA-to-HA-SPI }
+ { MIP-Algorithm-Type }
+ { MIP-Session-Key }
+ * [ AVP ]
+
+ MIP-HA-to-FA-MSA ::= < AVP Header: 329 >
+
+ { MIP-HA-to-FA-SPI }
+ { MIP-Algorithm-Type }
+ { MIP-Session-Key }
+ * [ AVP ]
+
+ MIP-HA-to-MN-MSA ::= < AVP Header: 332 >
+
+ ; { MIP-HA-to-MN-SPI }
+ { MIP-Algorithm-Type }
+ { MIP-Replay-Mode }
+ { MIP-Session-Key }
+ * [ AVP ]
+
+ MIP-MN-to-FA-MSA ::= < AVP Header: 325 >
+
+ ; { MIP-MN-FA-SPI }
+ { MIP-Algorithm-Type }
+ { MIP-Nonce }
+ * [ AVP ]
+
+ MIP-MN-to-HA-MSA ::= < AVP Header: 331 >
+
+ ; { MIP-MN-HA-SPI }
+ { MIP-Algorithm-Type }
+ { MIP-Replay-Mode }
+ { MIP-Nonce }
+ * [ AVP ]
+
+;; ===========================================================================
+
+@enum MIP-Algorithm-Type
+
+ HMAC-SHA-1 2
+
+@enum MIP-Replay-Mode
+
+ NONE 1
+ TIMESTAMPS 2
+ NONCES 3
+
+;; ===========================================================================
+
+@define Result-Code
+
+ ;; 6.1. Transient Failures
+
+ MIP_REPLY_FAILURE 4005
+ HA_NOT_AVAILABLE 4006
+ BAD_KEY 4007
+ MIP_FILTER_NOT_SUPPORTED 4008
+
+ ;; 6.2. Permanent Failures
+
+ NO_FOREIGN_HA_SERVICE 5024
+ END_TO_END_MIP_KEY_ENCRYPTION 5025
diff --git a/lib/diameter/examples/dict/rfc4005_nas.dia b/lib/diameter/examples/dict/rfc4005_nas.dia
new file mode 100644
index 0000000000..a4b44e38bb
--- /dev/null
+++ b/lib/diameter/examples/dict/rfc4005_nas.dia
@@ -0,0 +1,740 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+;;
+;; RFC 4005, Diameter Network Access Server Application
+;;
+;; Edits:
+;;
+;; - Acounting-Auth-Method -> Accounting-Auth-Method
+;; - Connection-Info -> ConnectInfo
+;; - Framed-Appletalk-Link -> Framed-AppleTalk-Link
+;; - Framed-Appletalk-Network -> Framed-AppleTalk-Network
+;; - Framed-Appletalk-Zone -> Framed-AppleTalk-Zone
+;; - Qos-Filter-Rule -> QoS-Filter-Rule
+;; - Redirect-Host-Usase -> Redirect-Host-Usage
+;; - Redirected-Host -> Redirect-Host
+;; - Redirected-Host-Usage -> Redirect-Host-Usage
+;; - Redirected-Host-Cache-Time -> Redirect-Max-Cache-Time
+;; - Redirected-Max-Cache-Time -> Redirect-Max-Cache-Time
+;;
+
+@id 1
+
+@inherits rfc3588_base
+
+;; ===========================================================================
+
+@avp_types
+
+ ;; 4. NAS Session AVPs
+
+ NAS-Port 5 Unsigned32 M
+ NAS-Port-Id 87 UTF8String M
+ NAS-Port-Type 61 Enumerated M
+ Called-Station-Id 30 UTF8String M
+ Calling-Station-Id 31 UTF8String M
+ Connect-Info 77 UTF8String M
+ Originating-Line-Info 94 OctetString -
+ Reply-Message 18 UTF8String M
+
+ ;; 5. NAS Authentication AVPs
+
+ User-Password 2 OctetString M
+ Password-Retry 75 Unsigned32 M
+ Prompt 76 Enumerated M
+ CHAP-Auth 402 Grouped M
+ CHAP-Algorithm 403 Enumerated M
+ CHAP-Ident 404 OctetString M
+ CHAP-Response 405 OctetString M
+ CHAP-Challenge 60 OctetString M
+ ARAP-Password 70 OctetString M
+ ARAP-Challenge-Response 84 OctetString M
+ ARAP-Security 73 Unsigned32 M
+ ARAP-Security-Data 74 OctetString M
+
+ ;; 6. NAS Authorization AVPs
+
+ Service-Type 6 Enumerated M
+ Callback-Number 19 UTF8String M
+ Callback-Id 20 UTF8String M
+ Idle-Timeout 28 Unsigned32 M
+ Port-Limit 62 Unsigned32 M
+ NAS-Filter-Rule 400 IPFilterRule M
+ Filter-Id 11 UTF8String M
+ Configuration-Token 78 OctetString M
+ QoS-Filter-Rule 407 QoSFilterRule -
+ Framed-Protocol 7 Enumerated M
+ Framed-Routing 10 Enumerated M
+ Framed-MTU 12 Unsigned32 M
+ Framed-Compression 13 Enumerated M
+ Framed-IP-Address 8 OctetString M
+ Framed-IP-Netmask 9 OctetString M
+ Framed-Route 22 UTF8String M
+ Framed-Pool 88 OctetString M
+ Framed-Interface-Id 96 Unsigned64 M
+ Framed-IPv6-Prefix 97 OctetString M
+ Framed-IPv6-Route 99 UTF8String M
+ Framed-IPv6-Pool 100 OctetString M
+ Framed-IPX-Network 23 UTF8String M
+ Framed-AppleTalk-Link 37 Unsigned32 M
+ Framed-AppleTalk-Network 38 Unsigned32 M
+ Framed-AppleTalk-Zone 39 OctetString M
+ ARAP-Features 71 OctetString M
+ ARAP-Zone-Access 72 Enumerated M
+ Login-IP-Host 14 OctetString M
+ Login-IPv6-Host 98 OctetString M
+ Login-Service 15 Enumerated M
+ Login-TCP-Port 16 Unsigned32 M
+ Login-LAT-Service 34 OctetString M
+ Login-LAT-Node 35 OctetString M
+ Login-LAT-Group 36 OctetString M
+ Login-LAT-Port 63 OctetString M
+
+ ;; 7. NAS Tunneling
+
+ Tunneling 401 Grouped M
+ Tunnel-Type 64 Enumerated M
+ Tunnel-Medium-Type 65 Enumerated M
+ Tunnel-Client-Endpoint 66 UTF8String M
+ Tunnel-Server-Endpoint 67 UTF8String M
+ Tunnel-Password 69 OctetString M
+ Tunnel-Private-Group-Id 81 OctetString M
+ Tunnel-Assignment-Id 82 OctetString M
+ Tunnel-Preference 83 Unsigned32 M
+ Tunnel-Client-Auth-Id 90 UTF8String M
+ Tunnel-Server-Auth-Id 91 UTF8String M
+
+ ;; 8. NAS Accounting
+
+ Accounting-Input-Octets 363 Unsigned64 M
+ Accounting-Output-Octets 364 Unsigned64 M
+ Accounting-Input-Packets 365 Unsigned64 M
+ Accounting-Output-Packets 366 Unsigned64 M
+ Acct-Session-Time 46 Unsigned32 M
+ Acct-Authentic 45 Enumerated M
+ Accounting-Auth-Method 406 Enumerated M
+ Acct-Delay-Time 41 Unsigned32 M
+ Acct-Link-Count 51 Unsigned32 M
+ Acct-Tunnel-Connection 68 OctetString M
+ Acct-Tunnel-Packets-Lost 86 Unsigned32 M
+
+ ;; 9.3. AVPs Used Only for Compatibility
+
+ NAS-Identifier 32 UTF8String M
+ NAS-IP-Address 4 OctetString M
+ NAS-IPv6-Address 95 OctetString M
+ State 24 OctetString M
+ ;;Termination-Cause 295 Enumerated M
+ Origin-AAA-Protocol 408 Enumerated M
+
+;; ===========================================================================
+
+@messages
+
+ AAR ::= < Diameter Header: 265, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Auth-Request-Type }
+ [ Destination-Host ]
+ [ NAS-Identifier ]
+ [ NAS-IP-Address ]
+ [ NAS-IPv6-Address ]
+ [ NAS-Port ]
+ [ NAS-Port-Id ]
+ [ NAS-Port-Type ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ [ Port-Limit ]
+ [ User-Name ]
+ [ User-Password ]
+ [ Service-Type ]
+ [ State ]
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ [ Auth-Session-State ]
+ [ Callback-Number ]
+ [ Called-Station-Id ]
+ [ Calling-Station-Id ]
+ [ Originating-Line-Info ]
+ [ Connect-Info ]
+ [ CHAP-Auth ]
+ [ CHAP-Challenge ]
+ * [ Framed-Compression ]
+ [ Framed-Interface-Id ]
+ [ Framed-IP-Address ]
+ * [ Framed-IPv6-Prefix ]
+ [ Framed-IP-Netmask ]
+ [ Framed-MTU ]
+ [ Framed-Protocol ]
+ [ ARAP-Password ]
+ [ ARAP-Security ]
+ * [ ARAP-Security-Data ]
+ * [ Login-IP-Host ]
+ * [ Login-IPv6-Host ]
+ [ Login-LAT-Group ]
+ [ Login-LAT-Node ]
+ [ Login-LAT-Port ]
+ [ Login-LAT-Service ]
+ * [ Tunneling ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ AAA ::= < Diameter Header: 265, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Request-Type }
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ [ Service-Type ]
+ * [ Class ]
+ * [ Configuration-Token ]
+ [ Acct-Interim-Interval ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ [ Idle-Timeout ]
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ [ Auth-Session-State ]
+ [ Re-Auth-Request-Type ]
+ [ Multi-Round-Time-Out ]
+ [ Session-Timeout ]
+ [ State ]
+ * [ Reply-Message ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ * [ Filter-Id ]
+ [ Password-Retry ]
+ [ Port-Limit ]
+ [ Prompt ]
+ [ ARAP-Challenge-Response ]
+ [ ARAP-Features ]
+ [ ARAP-Security ]
+ * [ ARAP-Security-Data ]
+ [ ARAP-Zone-Access ]
+ [ Callback-Id ]
+ [ Callback-Number ]
+ [ Framed-AppleTalk-Link ]
+ * [ Framed-AppleTalk-Network ]
+ [ Framed-AppleTalk-Zone ]
+ * [ Framed-Compression ]
+ [ Framed-Interface-Id ]
+ [ Framed-IP-Address ]
+ * [ Framed-IPv6-Prefix ]
+ [ Framed-IPv6-Pool ]
+ * [ Framed-IPv6-Route ]
+ [ Framed-IP-Netmask ]
+ * [ Framed-Route ]
+ [ Framed-Pool ]
+ [ Framed-IPX-Network ]
+ [ Framed-MTU ]
+ [ Framed-Protocol ]
+ [ Framed-Routing ]
+ * [ Login-IP-Host ]
+ * [ Login-IPv6-Host ]
+ [ Login-LAT-Group ]
+ [ Login-LAT-Node ]
+ [ Login-LAT-Port ]
+ [ Login-LAT-Service ]
+ [ Login-Service ]
+ [ Login-TCP-Port ]
+ * [ NAS-Filter-Rule ]
+ * [ QoS-Filter-Rule ]
+ * [ Tunneling ]
+ * [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+ RAR ::= < Diameter Header: 258, REQ, PXY >
+
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Destination-Host }
+ { Auth-Application-Id }
+ { Re-Auth-Request-Type }
+ [ User-Name ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ [ NAS-Identifier ]
+ [ NAS-IP-Address ]
+ [ NAS-IPv6-Address ]
+ [ NAS-Port ]
+ [ NAS-Port-Id ]
+ [ NAS-Port-Type ]
+ [ Service-Type ]
+ [ Framed-IP-Address ]
+ [ Framed-IPv6-Prefix ]
+ [ Framed-Interface-Id ]
+ [ Called-Station-Id ]
+ [ Calling-Station-Id ]
+ [ Originating-Line-Info ]
+ [ Acct-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ State ]
+ * [ Class ]
+ [ Reply-Message ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ RAA ::= < Diameter Header: 258, PXY >
+
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ * [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ [ Service-Type ]
+ * [ Configuration-Token ]
+ [ Idle-Timeout ]
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ [ Re-Auth-Request-Type ]
+ [ State ]
+ * [ Class ]
+ * [ Reply-Message ]
+ [ Prompt ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+ STR ::= < Diameter Header: 275, REQ, PXY >
+
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Auth-Application-Id }
+ { Termination-Cause }
+ [ User-Name ]
+ [ Destination-Host ]
+ * [ Class ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ STA ::= < Diameter Header: 275, PXY >
+
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ * [ Class ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ * [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+ ASR ::= < Diameter Header: 274, REQ, PXY >
+
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Destination-Host }
+ { Auth-Application-Id }
+ [ User-Name ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ [ NAS-Identifier ]
+ [ NAS-IP-Address ]
+ [ NAS-IPv6-Address ]
+ [ NAS-Port ]
+ [ NAS-Port-Id ]
+ [ NAS-Port-Type ]
+ [ Service-Type ]
+ [ Framed-IP-Address ]
+ [ Framed-IPv6-Prefix ]
+ [ Framed-Interface-Id ]
+ [ Called-Station-Id ]
+ [ Calling-Station-Id ]
+ [ Originating-Line-Info ]
+ [ Acct-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ State ]
+ * [ Class ]
+ * [ Reply-Message ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ASA ::= < Diameter Header: 274, PXY >
+
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ [ State]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ * [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+ ACR ::= < Diameter Header: 271, REQ, PXY >
+
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Accounting-Record-Type }
+ { Accounting-Record-Number }
+ [ Acct-Application-Id ]
+ [ Vendor-Specific-Application-Id ]
+ [ User-Name ]
+ [ Accounting-Sub-Session-Id ]
+ [ Acct-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ [ Destination-Host ]
+ [ Event-Timestamp ]
+ [ Acct-Delay-Time ]
+ [ NAS-Identifier ]
+ [ NAS-IP-Address ]
+ [ NAS-IPv6-Address ]
+ [ NAS-Port ]
+ [ NAS-Port-Id ]
+ [ NAS-Port-Type ]
+ * [ Class ]
+ [ Service-Type ]
+ [ Termination-Cause ]
+ [ Accounting-Input-Octets ]
+ [ Accounting-Input-Packets ]
+ [ Accounting-Output-Octets ]
+ [ Accounting-Output-Packets ]
+ [ Acct-Authentic ]
+ [ Accounting-Auth-Method ]
+ [ Acct-Link-Count ]
+ [ Acct-Session-Time ]
+ [ Acct-Tunnel-Connection ]
+ [ Acct-Tunnel-Packets-Lost ]
+ [ Callback-Id ]
+ [ Callback-Number ]
+ [ Called-Station-Id ]
+ [ Calling-Station-Id ]
+ * [ Connect-Info ]
+ [ Originating-Line-Info ]
+ [ Authorization-Lifetime ]
+ [ Session-Timeout ]
+ [ Idle-Timeout ]
+ [ Port-Limit ]
+ [ Accounting-Realtime-Required ]
+ [ Acct-Interim-Interval ]
+ * [ Filter-Id ]
+ * [ NAS-Filter-Rule ]
+ * [ QoS-Filter-Rule ]
+ [ Framed-AppleTalk-Link ]
+ [ Framed-AppleTalk-Network ]
+ [ Framed-AppleTalk-Zone ]
+ [ Framed-Compression ]
+ [ Framed-Interface-Id ]
+ [ Framed-IP-Address ]
+ [ Framed-IP-Netmask ]
+ * [ Framed-IPv6-Prefix ]
+ [ Framed-IPv6-Pool ]
+ * [ Framed-IPv6-Route ]
+ [ Framed-IPX-Network ]
+ [ Framed-MTU ]
+ [ Framed-Pool ]
+ [ Framed-Protocol ]
+ * [ Framed-Route ]
+ [ Framed-Routing ]
+ * [ Login-IP-Host ]
+ * [ Login-IPv6-Host ]
+ [ Login-LAT-Group ]
+ [ Login-LAT-Node ]
+ [ Login-LAT-Port ]
+ [ Login-LAT-Service ]
+ [ Login-Service ]
+ [ Login-TCP-Port ]
+ * [ Tunneling ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ACA ::= < Diameter Header: 271, PXY >
+
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ { Accounting-Record-Type }
+ { Accounting-Record-Number }
+ [ Acct-Application-Id ]
+ [ Vendor-Specific-Application-Id ]
+ [ User-Name ]
+ [ Accounting-Sub-Session-Id ]
+ [ Acct-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ Event-Timestamp ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ [ Origin-AAA-Protocol ]
+ [ Origin-State-Id ]
+ [ NAS-Identifier ]
+ [ NAS-IP-Address ]
+ [ NAS-IPv6-Address ]
+ [ NAS-Port ]
+ [ NAS-Port-Id ]
+ [ NAS-Port-Type ]
+ [ Service-Type ]
+ [ Termination-Cause ]
+ [ Accounting-Realtime-Required ]
+ [ Acct-Interim-Interval ]
+ * [ Class ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+;; ===========================================================================
+
+@grouped
+
+ CHAP-Auth ::= < AVP Header: 402 >
+
+ { CHAP-Algorithm }
+ { CHAP-Ident }
+ [ CHAP-Response ]
+ * [ AVP ]
+
+ Tunneling ::= < AVP Header: 401 >
+
+ { Tunnel-Type }
+ { Tunnel-Medium-Type }
+ { Tunnel-Client-Endpoint }
+ { Tunnel-Server-Endpoint }
+ [ Tunnel-Preference ]
+ [ Tunnel-Client-Auth-Id ]
+ [ Tunnel-Server-Auth-Id ]
+ [ Tunnel-Assignment-Id ]
+ [ Tunnel-Password ]
+ [ Tunnel-Private-Group-Id ]
+
+;; ===========================================================================
+
+@enum NAS-Port-Type
+
+ ASYNC 0
+ SYNC 1
+ ISDN_SYNC 2
+ ISDN_ASYNC_V120 3
+ ISDN_ASYNC_V110 4
+ VIRTUAL 5
+ PIAFS 6
+ HDLC_CLEAR_CHANNEL 7
+ X25 8
+ X75 9
+ G3FAX 10
+ SDSL 11
+ ADSL-CAP 12
+ ADSL-DMT 13
+ IDSL 14
+ ETHERNET 15
+ XDSL 16
+ CABLE 17
+ WIRELESS_OTHER 18
+ 'WIRELESS_802.11' 19
+ TOKEN-RING 20
+ FDDI 21
+ WIRELESS_CDMA2000 22
+ WIRELESS_UMTS 23
+ WIRELESS_1X-EV 24
+ IAPP 25
+
+@enum Prompt
+
+ NO_ECHO 0
+ ECHO 1
+
+@enum CHAP-Algorithm
+
+ WITH_MD5 5
+
+@enum Service-Type
+
+ LOGIN 1
+ FRAMED 2
+ CALLBACK_LOGIN 3
+ CALLBACK_FRAMED 4
+ OUTBOUND 5
+ ADMINISTRATIVE 6
+ NAS_PROMPT 7
+ AUTHENTICATE_ONLY 8
+ CALLBACK_NAS_PROMPT 9
+ CALL_CHECK 10
+ CALLBACK_ADMINISTRATIVE 11
+ VOICE 12
+ FAX 13
+ MODEM_RELAY 14
+ IAPP-REGISTER 15
+ IAPP-AP-CHECK 16
+ AUTHORIZE_ONLY 17
+
+@enum Framed-Protocol
+
+ PPP 1
+ SLIP 2
+ ARAP 3
+ GANDALF 4
+ XYLOGICS 5
+ X75 6
+
+@enum Framed-Routing
+
+ NONE 0
+ SEND 1
+ LISTEN 2
+ SEND_AND_LISTEN 3
+
+@enum Framed-Compression
+
+ NONE 0
+ VJ 1
+ IPX 2
+ STAC-LZS 3
+
+@enum ARAP-Zone-Access
+
+ DEFAULT 1
+ FILTER_INCLUSIVELY 2
+ FILTER_EXCLUSIVELY 4
+
+@enum Login-Service
+
+ TELNET 0
+ RLOGIN 1
+ TCP_CLEAR 2
+ PORTMASTER 3
+ LAT 4
+ X25-PAD 5
+ X25-T3POS 6
+ TCP_CLEAR_QUIET 8
+
+@enum Tunnel-Type
+
+ PPTP 1
+ L2F 2
+ L2TP 3
+ ATMP 4
+ VTP 5
+ AH 6
+ IP-IP 7
+ MIN-IP-IP 8
+ ESP 9
+ GRE 10
+ DVS 11
+ IP-IN-IP 12
+ VLAN 13
+
+@enum Tunnel-Medium-Type
+
+ IPV4 1
+ IPV6 2
+ NSAP 3
+ HDLC 4
+ BBN_1822 5
+ '802' 6
+ E163 7
+ E164 8
+ F69 9
+ X121 10
+ IPX 11
+ APPLETALK 12
+ DECNET_IV 13
+ BANYAN_VINES 14
+ E164_NSAP 15
+
+
+@enum Acct-Authentic
+
+ RADIUS 1
+ LOCAL 2
+ REMOTE 3
+ DIAMETER 4
+
+@enum Accounting-Auth-Method
+
+ PAP 1
+ CHAP 2
+ MS-CHAP-1 3
+ MS-CHAP-2 4
+ EAP 5
+ NONE 7
+
+@enum Termination-Cause
+
+ USER_REQUEST 11
+ LOST_CARRIER 12
+ LOST_SERVICE 13
+ IDLE_TIMEOUT 14
+ SESSION_TIMEOUT 15
+ ADMIN_RESET 16
+ ADMIN_REBOOT 17
+ PORT_ERROR 18
+ NAS_ERROR 19
+ NAS_REQUEST 20
+ NAS_REBOOT 21
+ PORT_UNNEEDED 22
+ PORT_PREEMPTED 23
+ PORT_SUSPENDED 24
+ SERVICE_UNAVAILABLE 25
+ CALLBACK 26
+ USER_ERROR 27
+ HOST_REQUEST 28
+ SUPPLICANT_RESTART 29
+ REAUTHORIZATION_FAILURE 30
+ PORT_REINIT 31
+ PORT_DISABLED 32
diff --git a/lib/diameter/examples/dict/rfc4006_cc.dia b/lib/diameter/examples/dict/rfc4006_cc.dia
new file mode 100644
index 0000000000..b723e4ddbb
--- /dev/null
+++ b/lib/diameter/examples/dict/rfc4006_cc.dia
@@ -0,0 +1,349 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+;;
+;; RFC 4006, Diameter Credit-Control Application
+;;
+
+@id 4
+
+@inherits rfc3588_base
+@inherits rfc4005_nas Filter-Id
+
+;; ===========================================================================
+
+@avp_types
+
+ CC-Correlation-Id 411 OctetString -
+ CC-Input-Octets 412 Unsigned64 M
+ CC-Money 413 Grouped M
+ CC-Output-Octets 414 Unsigned64 M
+ CC-Request-Number 415 Unsigned32 M
+ CC-Request-Type 416 Enumerated M
+ CC-Service-Specific-Units 417 Unsigned64 M
+ CC-Session-Failover 418 Enumerated M
+ CC-Sub-Session-Id 419 Unsigned64 M
+ CC-Time 420 Unsigned32 M
+ CC-Total-Octets 421 Unsigned64 M
+ CC-Unit-Type 454 Enumerated M
+ Check-Balance-Result 422 Enumerated M
+ Cost-Information 423 Grouped M
+ Cost-Unit 424 UTF8String M
+ Credit-Control 426 Enumerated M
+ Credit-Control-Failure-Handling 427 Enumerated M
+ Currency-Code 425 Unsigned32 M
+ Direct-Debiting-Failure-Handling 428 Enumerated M
+ Exponent 429 Integer32 M
+ Final-Unit-Action 449 Enumerated M
+ Final-Unit-Indication 430 Grouped M
+ Granted-Service-Unit 431 Grouped M
+ G-S-U-Pool-Identifier 453 Unsigned32 M
+ G-S-U-Pool-Reference 457 Grouped M
+ Multiple-Services-Credit-Control 456 Grouped M
+ Multiple-Services-Indicator 455 Enumerated M
+ Rating-Group 432 Unsigned32 M
+ Redirect-Address-Type 433 Enumerated M
+ Redirect-Server 434 Grouped M
+ Redirect-Server-Address 435 UTF8String M
+ Requested-Action 436 Enumerated M
+ Requested-Service-Unit 437 Grouped M
+ Restriction-Filter-Rule 438 IPFilterRule M
+ Service-Context-Id 461 UTF8String M
+ Service-Identifier 439 Unsigned32 M
+ Service-Parameter-Info 440 Grouped -
+ Service-Parameter-Type 441 Unsigned32 -
+ Service-Parameter-Value 442 OctetString -
+ Subscription-Id 443 Grouped M
+ Subscription-Id-Data 444 UTF8String M
+ Subscription-Id-Type 450 Enumerated M
+ Tariff-Change-Usage 452 Enumerated M
+ Tariff-Time-Change 451 Time M
+ Unit-Value 445 Grouped M
+ Used-Service-Unit 446 Grouped M
+ User-Equipment-Info 458 Grouped -
+ User-Equipment-Info-Type 459 Enumerated -
+ User-Equipment-Info-Value 460 OctetString -
+ Value-Digits 447 Integer64 M
+ Validity-Time 448 Unsigned32 M
+
+;; ===========================================================================
+
+@messages
+
+ CCR ::= < Diameter Header: 272, REQ, PXY >
+
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Auth-Application-Id }
+ { Service-Context-Id }
+ { CC-Request-Type }
+ { CC-Request-Number }
+ [ Destination-Host ]
+ [ User-Name ]
+ [ CC-Sub-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ Origin-State-Id ]
+ [ Event-Timestamp ]
+ * [ Subscription-Id ]
+ [ Service-Identifier ]
+ [ Termination-Cause ]
+ [ Requested-Service-Unit ]
+ [ Requested-Action ]
+ * [ Used-Service-Unit ]
+ [ Multiple-Services-Indicator ]
+ * [ Multiple-Services-Credit-Control ]
+ * [ Service-Parameter-Info ]
+ [ CC-Correlation-Id ]
+ [ User-Equipment-Info ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ CCA ::= < Diameter Header: 272, PXY >
+
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ { Auth-Application-Id }
+ { CC-Request-Type }
+ { CC-Request-Number }
+ [ User-Name ]
+ [ CC-Session-Failover ]
+ [ CC-Sub-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ Origin-State-Id ]
+ [ Event-Timestamp ]
+ [ Granted-Service-Unit ]
+ * [ Multiple-Services-Credit-Control ]
+ [ Cost-Information]
+ [ Final-Unit-Indication ]
+ [ Check-Balance-Result ]
+ [ Credit-Control-Failure-Handling ]
+ [ Direct-Debiting-Failure-Handling ]
+ [ Validity-Time]
+ * [ Redirect-Host]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ Failed-AVP ]
+ * [ AVP ]
+
+;; ===========================================================================
+
+@grouped
+
+ Cost-Information ::= < AVP Header: 423 >
+
+ { Unit-Value }
+ { Currency-Code }
+ [ Cost-Unit ]
+
+ Unit-Value ::= < AVP Header: 445 >
+
+ { Value-Digits }
+ [ Exponent ]
+
+ Multiple-Services-Credit-Control ::= < AVP Header: 456 >
+
+ [ Granted-Service-Unit ]
+ [ Requested-Service-Unit ]
+ * [ Used-Service-Unit ]
+ [ Tariff-Change-Usage ]
+ * [ Service-Identifier ]
+ [ Rating-Group ]
+ * [ G-S-U-Pool-Reference ]
+ [ Validity-Time ]
+ [ Result-Code ]
+ [ Final-Unit-Indication ]
+ * [ AVP ]
+
+ Granted-Service-Unit ::= < AVP Header: 431 >
+
+ [ Tariff-Time-Change ]
+ [ CC-Time ]
+ [ CC-Money ]
+ [ CC-Total-Octets ]
+ [ CC-Input-Octets ]
+ [ CC-Output-Octets ]
+ [ CC-Service-Specific-Units ]
+ * [ AVP ]
+
+ Requested-Service-Unit ::= < AVP Header: 437 >
+
+ [ CC-Time ]
+ [ CC-Money ]
+ [ CC-Total-Octets ]
+ [ CC-Input-Octets ]
+ [ CC-Output-Octets ]
+ [ CC-Service-Specific-Units ]
+ * [ AVP ]
+
+ Used-Service-Unit ::= < AVP Header: 446 >
+
+ [ Tariff-Change-Usage ]
+ [ CC-Time ]
+ [ CC-Money ]
+ [ CC-Total-Octets ]
+ [ CC-Input-Octets ]
+ [ CC-Output-Octets ]
+ [ CC-Service-Specific-Units ]
+ * [ AVP ]
+
+ CC-Money ::= < AVP Header: 413 >
+
+ { Unit-Value }
+ [ Currency-Code ]
+
+ G-S-U-Pool-Reference ::= < AVP Header: 457 >
+
+ { G-S-U-Pool-Identifier }
+ { CC-Unit-Type }
+ { Unit-Value }
+
+ Final-Unit-Indication ::= < AVP Header: 430 >
+
+ { Final-Unit-Action }
+ * [ Restriction-Filter-Rule ]
+ * [ Filter-Id ]
+ [ Redirect-Server ]
+
+ Redirect-Server ::= < AVP Header: 434 >
+
+ { Redirect-Address-Type }
+ { Redirect-Server-Address }
+
+ Service-Parameter-Info ::= < AVP Header: 440 >
+
+ { Service-Parameter-Type }
+ { Service-Parameter-Value }
+
+ Subscription-Id ::= < AVP Header: 443 >
+
+ { Subscription-Id-Type }
+ { Subscription-Id-Data }
+
+ User-Equipment-Info ::= < AVP Header: 458 >
+
+ { User-Equipment-Info-Type }
+ { User-Equipment-Info-Value }
+
+;; ===========================================================================
+
+@enum CC-Request-Type
+
+ INITIAL_REQUEST 1
+ UPDATE_REQUEST 2
+ TERMINATION_REQUEST 3
+ EVENT_REQUEST 4
+
+@enum CC-Session-Failover
+
+ NOT_SUPPORTED 0
+ SUPPORTED 1
+
+@enum Check-Balance-Result
+
+ ENOUGH_CREDIT 0
+ NO_CREDIT 1
+
+@enum Credit-Control
+
+ AUTHORIZATION 0
+ RE_AUTHORIZATION 1
+
+@enum Credit-Control-Failure-Handling
+
+ TERMINATE 0
+ CONTINUE 1
+ RETRY_AND_TERMINATE 2
+
+@enum Direct-Debiting-Failure-Handling
+
+ TERMINATE_OR_BUFFER 0
+ CONTINUE 1
+
+@enum Tariff-Change-Usage
+
+ UNIT_BEFORE_TARIFF_CHANGE 0
+ UNIT_AFTER_TARIFF_CHANGE 1
+ UNIT_INDETERMINATE 2
+
+@enum CC-Unit-Type
+
+ TIME 0
+ MONEY 1
+ TOTAL-OCTETS 2
+ INPUT-OCTETS 3
+ OUTPUT-OCTETS 4
+ SERVICE-SPECIFIC-UNITS 5
+
+@enum Final-Unit-Action
+
+ TERMINATE 0
+ REDIRECT 1
+ RESTRICT_ACCESS 2
+
+@enum Redirect-Address-Type
+
+ IPV4 0
+ IPV6 1
+ URL 2
+ SIP_URI 3
+
+@enum Multiple-Services-Indicator
+
+ NOT_SUPPORTED 0
+ SUPPORTED 1
+
+@enum Requested-Action
+
+ DIRECT_DEBITING 0
+ REFUND_ACCOUNT 1
+ CHECK_BALANCE 2
+ PRICE_ENQUIRY 3
+
+@enum Subscription-Id-Type
+
+ END_USER_E164 0
+ END_USER_IMSI 1
+ END_USER_SIP_URI 2
+ END_USER_NAI 3
+ END_USER_PRIVATE 4
+
+@enum User-Equipment-Info-Type
+
+ IMEISV 0
+ MAC 1
+ EUI64 2
+ MODIFIED_EUI64 3
+
+;; ===========================================================================
+
+@define Result-Code
+
+ END_USER_SERVICE_DENIED 4010
+ CREDIT_CONTROL_NOT_APPLICABLE 4011
+ CREDIT_LIMIT_REACHED 4012
+
+ USER_UNKNOWN 5030
+ RATING_FAILED 5031
diff --git a/lib/diameter/examples/dict/rfc4072_eap.dia b/lib/diameter/examples/dict/rfc4072_eap.dia
new file mode 100644
index 0000000000..111516b347
--- /dev/null
+++ b/lib/diameter/examples/dict/rfc4072_eap.dia
@@ -0,0 +1,150 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+;;
+;; RFC 4072, Diameter Extensible Authentication Protocol (EAP) Application
+;;
+;; Edits:
+;;
+;; - Move EAP-Payload to not break fixed/required/optional order
+;; - Framed-Appletalk-Link -> Framed-AppleTalk-Link
+;; - Framed-Appletalk-Network -> Framed-AppleTalk-Network
+;; - Framed-Appletalk-Zone -> Framed-AppleTalk-Zone
+;;
+
+@id 5
+
+@inherits rfc3588_base
+@inherits rfc4005_nas
+
+;; ===========================================================================
+
+@avp_types
+
+ EAP-Master-Session-Key 464 OctetString -
+ EAP-Key-Name 102 OctetString -
+ EAP-Payload 462 OctetString -
+ EAP-Reissued-Payload 463 OctetString -
+ Accounting-EAP-Auth-Method 465 Unsigned64 -
+
+;; ===========================================================================
+
+@messages
+
+ DER ::= < Diameter Header: 268, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Auth-Request-Type }
+ { EAP-Payload }
+ [ Destination-Host ]
+ [ NAS-Identifier ]
+ [ NAS-IP-Address ]
+ [ NAS-IPv6-Address ]
+ [ NAS-Port ]
+ [ NAS-Port-Id ]
+ [ NAS-Port-Type ]
+ [ Origin-State-Id ]
+ [ Port-Limit ]
+ [ User-Name ]
+ [ EAP-Key-Name ]
+ [ Service-Type ]
+ [ State ]
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ [ Auth-Session-State ]
+ [ Callback-Number ]
+ [ Called-Station-Id ]
+ [ Calling-Station-Id ]
+ [ Originating-Line-Info ]
+ [ Connect-Info ]
+ * [ Framed-Compression ]
+ [ Framed-Interface-Id ]
+ [ Framed-IP-Address ]
+ * [ Framed-IPv6-Prefix ]
+ [ Framed-IP-Netmask ]
+ [ Framed-MTU ]
+ [ Framed-Protocol ]
+ * [ Tunneling ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ DEA ::= < Diameter Header: 268, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Request-Type }
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ [ EAP-Payload ]
+ [ EAP-Reissued-Payload ]
+ [ EAP-Master-Session-Key ]
+ [ EAP-Key-Name ]
+ [ Multi-Round-Time-Out ]
+ [ Accounting-EAP-Auth-Method ]
+ [ Service-Type ]
+ * [ Class ]
+ * [ Configuration-Token ]
+ [ Acct-Interim-Interval ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ [ Idle-Timeout ]
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ [ Auth-Session-State ]
+ [ Re-Auth-Request-Type ]
+ [ Session-Timeout ]
+ [ State ]
+ * [ Reply-Message ]
+ [ Origin-State-Id ]
+ * [ Filter-Id ]
+ [ Port-Limit ]
+ [ Callback-Id ]
+ [ Callback-Number ]
+ [ Framed-AppleTalk-Link ]
+ * [ Framed-AppleTalk-Network ]
+ [ Framed-AppleTalk-Zone ]
+ * [ Framed-Compression ]
+ [ Framed-Interface-Id ]
+ [ Framed-IP-Address ]
+ * [ Framed-IPv6-Prefix ]
+ [ Framed-IPv6-Pool ]
+ * [ Framed-IPv6-Route ]
+ [ Framed-IP-Netmask ]
+ * [ Framed-Route ]
+ [ Framed-Pool ]
+ [ Framed-IPX-Network ]
+ [ Framed-MTU ]
+ [ Framed-Protocol ]
+ [ Framed-Routing ]
+ * [ NAS-Filter-Rule ]
+ * [ QoS-Filter-Rule ]
+ * [ Tunneling ]
+ * [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ AVP ]
diff --git a/lib/diameter/examples/dict/rfc4590_digest.dia b/lib/diameter/examples/dict/rfc4590_digest.dia
new file mode 100644
index 0000000000..a4ebe0c456
--- /dev/null
+++ b/lib/diameter/examples/dict/rfc4590_digest.dia
@@ -0,0 +1,45 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+;;
+;; RFC 4590, RADIUS Extension for Digest Authentication
+;;
+
+@avp_types
+
+ Digest-Response 103 OctetString -
+ Digest-Realm 104 OctetString -
+ Digest-Nonce 105 OctetString -
+ Digest-Response-Auth 106 OctetString -
+ Digest-Nextnonce 107 OctetString -
+ Digest-Method 108 OctetString -
+ Digest-URI 109 OctetString -
+ Digest-Qop 110 OctetString -
+ Digest-Algorithm 111 OctetString -
+ Digest-Entity-Body-Hash 112 OctetString -
+ Digest-CNonce 113 OctetString -
+ Digest-Nonce-Count 114 OctetString -
+ Digest-Username 115 OctetString -
+ Digest-Opaque 116 OctetString -
+ Digest-Auth-Param 117 OctetString -
+ Digest-AKA-Auts 118 OctetString -
+ Digest-Domain 119 OctetString -
+ Digest-Stale 120 OctetString -
+ Digest-HA1 121 OctetString -
+ SIP-AOR 122 OctetString -
diff --git a/lib/diameter/examples/dict/rfc4740_sip.dia b/lib/diameter/examples/dict/rfc4740_sip.dia
new file mode 100644
index 0000000000..8c21882649
--- /dev/null
+++ b/lib/diameter/examples/dict/rfc4740_sip.dia
@@ -0,0 +1,446 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+;;
+;; RFC 4740, Diameter Session Initiation Protocol (SIP) Application
+;;
+
+@id 6
+
+@inherits rfc3588_base
+@inherits rfc4590_digest
+
+;; ===========================================================================
+
+@avp_types
+
+ SIP-Accounting-Information 368 Grouped M
+ SIP-Accounting-Server-URI 369 DiameterURI M
+ SIP-Credit-Control-Server-URI 370 DiameterURI M
+ SIP-Server-URI 371 UTF8String M
+ SIP-Server-Capabilities 372 Grouped M
+ SIP-Mandatory-Capability 373 Unsigned32 M
+ SIP-Optional-Capability 374 Unsigned32 M
+ SIP-Server-Assignment-Type 375 Enumerated M
+ SIP-Auth-Data-Item 376 Grouped M
+ SIP-Authentication-Scheme 377 Enumerated M
+ SIP-Item-Number 378 Unsigned32 M
+ SIP-Authenticate 379 Grouped M
+ SIP-Authorization 380 Grouped M
+ SIP-Authentication-Info 381 Grouped M
+ SIP-Number-Auth-Items 382 Unsigned32 M
+ SIP-Deregistration-Reason 383 Grouped M
+ SIP-Reason-Code 384 Enumerated M
+ SIP-Reason-Info 385 UTF8String M
+ SIP-Visited-Network-Id 386 UTF8String M
+ SIP-User-Authorization-Type 387 Enumerated M
+ SIP-Supported-User-Data-Type 388 UTF8String M
+ SIP-User-Data 389 Grouped M
+ SIP-User-Data-Type 390 UTF8String M
+ SIP-User-Data-Contents 391 OctetString M
+ SIP-User-Data-Already-Available 392 Enumerated M
+ SIP-Method 393 UTF8String M
+
+;; ===========================================================================
+
+@messages
+
+ ;; 8.1. User-Authorization-Request
+
+ UAR ::= < Diameter Header: 283, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { SIP-AOR }
+ [ Destination-Host ]
+ [ User-Name ]
+ [ SIP-Visited-Network-Id ]
+ [ SIP-User-Authorization-Type ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.2. User-Authorization-Answer
+
+ UAA ::= < Diameter Header: 283, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Session-State }
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ SIP-Server-URI ]
+ [ SIP-Server-Capabilities ]
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.3. Server-Assignment-Request
+
+ SAR ::= < Diameter Header: 284, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { SIP-Server-Assignment-Type }
+ { SIP-User-Data-Already-Available }
+ [ Destination-Host ]
+ [ User-Name ]
+ [ SIP-Server-URI ]
+ * [ SIP-Supported-User-Data-Type ]
+ * [ SIP-AOR ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.4. Server-Assignment-Answer
+
+ SAA ::= < Diameter Header: 284, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Result-Code }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ * [ SIP-User-Data ]
+ [ SIP-Accounting-Information ]
+ * [ SIP-Supported-User-Data-Type ]
+ [ User-Name ]
+ [ Auth-Grace-Period ]
+ [ Authorization-Lifetime ]
+ [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.5. Location-Info-Request
+
+ LIR ::= < Diameter Header: 285, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { SIP-AOR }
+ [ Destination-Host ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.6. Location-Info-Answer
+
+ LIA ::= < Diameter Header: 285, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Result-Code }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ [ SIP-Server-URI ]
+ [ SIP-Server-Capabilities ]
+ [ Auth-Grace-Period ]
+ [ Authorization-Lifetime ]
+ [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.7. Multimedia-Auth-Request
+
+ MAR ::= < Diameter Header: 286, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { SIP-AOR }
+ { SIP-Method }
+ [ Destination-Host ]
+ [ User-Name ]
+ [ SIP-Server-URI ]
+ [ SIP-Number-Auth-Items ]
+ [ SIP-Auth-Data-Item ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.8. Multimedia-Auth-Answer
+
+ MAA ::= < Diameter Header: 286, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Result-Code }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ [ SIP-AOR ]
+ [ SIP-Number-Auth-Items ]
+ * [ SIP-Auth-Data-Item ]
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.9. Registration-Termination-Request
+
+ RTR ::= < Diameter Header: 287, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Host }
+ { SIP-Deregistration-Reason }
+ [ Destination-Realm ]
+ [ User-Name ]
+ * [ SIP-AOR ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.10. Registration-Termination-Answer
+
+ RTA ::= < Diameter Header: 287, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Result-Code }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.11. Push-Profile-Request
+
+ PPR ::= < Diameter Header: 288, REQ, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { User-Name }
+ * [ SIP-User-Data ]
+ [ SIP-Accounting-Information ]
+ [ Destination-Host ]
+ [ Authorization-Lifetime ]
+ [ Auth-Grace-Period ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ;; 8.12. Push-Profile-Answer
+
+ PPA ::= < Diameter Header: 288, PXY >
+
+ < Session-Id >
+ { Auth-Application-Id }
+ { Result-Code }
+ { Auth-Session-State }
+ { Origin-Host }
+ { Origin-Realm }
+ [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+;; ===========================================================================
+
+@grouped
+
+ SIP-Accounting-Information ::= < AVP Header: 368 >
+
+ * [ SIP-Accounting-Server-URI ]
+ * [ SIP-Credit-Control-Server-URI ]
+ * [ AVP]
+
+ SIP-Server-Capabilities ::= < AVP Header: 372 >
+
+ * [ SIP-Mandatory-Capability ]
+ * [ SIP-Optional-Capability ]
+ * [ SIP-Server-URI ]
+ * [ AVP ]
+
+ SIP-Auth-Data-Item ::= < AVP Header: 376 >
+
+ { SIP-Authentication-Scheme }
+ [ SIP-Item-Number ]
+ [ SIP-Authenticate ]
+ [ SIP-Authorization ]
+ [ SIP-Authentication-Info ]
+ * [ AVP ]
+
+ SIP-Authenticate ::= < AVP Header: 379 >
+
+ { Digest-Realm }
+ { Digest-Nonce }
+ [ Digest-Domain ]
+ [ Digest-Opaque ]
+ [ Digest-Stale ]
+ [ Digest-Algorithm ]
+ [ Digest-Qop ]
+ [ Digest-HA1]
+ * [ Digest-Auth-Param ]
+ * [ AVP ]
+
+ SIP-Authorization ::= < AVP Header: 380 >
+
+ { Digest-Username }
+ { Digest-Realm }
+ { Digest-Nonce }
+ { Digest-URI }
+ { Digest-Response }
+ [ Digest-Algorithm ]
+ [ Digest-CNonce ]
+ [ Digest-Opaque ]
+ [ Digest-Qop ]
+ [ Digest-Nonce-Count ]
+ [ Digest-Method]
+ [ Digest-Entity-Body-Hash ]
+ * [ Digest-Auth-Param ]
+ * [ AVP ]
+
+ SIP-Authentication-Info ::= < AVP Header: 381 >
+
+ [ Digest-Nextnonce ]
+ [ Digest-Qop ]
+ [ Digest-Response-Auth ]
+ [ Digest-CNonce ]
+ [ Digest-Nonce-Count ]
+ * [ AVP ]
+
+ SIP-Deregistration-Reason ::= < AVP Header: 383 >
+
+ { SIP-Reason-Code }
+ [ SIP-Reason-Info ]
+ * [ AVP ]
+
+ SIP-User-Data ::= < AVP Header: 389 >
+
+ { SIP-User-Data-Type }
+ { SIP-User-Data-Contents }
+ * [ AVP ]
+
+;; ===========================================================================
+
+@enum SIP-Server-Assignment-Type
+
+ NO_ASSIGNMENT 0
+ REGISTRATION 1
+ RE_REGISTRATION 2
+ UNREGISTERED_USER 3
+ TIMEOUT_DEREGISTRATION 4
+ USER_DEREGISTRATION 5
+ TIMEOUT_DEREGISTRATION_STORE 6
+ USER_DEREGISTRATION_STORE 7
+ ADMINISTRATIVE_DEREGISTRATION 8
+ AUTHENTICATION_FAILURE 9
+ AUTHENTICATION_TIMEOUT 10
+ DEREGISTRATION_TOO_MUCH_DATA 11
+
+@enum SIP-Authentication-Scheme
+
+ DIGEST 0
+
+@enum SIP-Reason-Code
+
+ PERMANENT_TERMINATION 0
+ NEW_SIP_SERVER_ASSIGNED 1
+ SIP_SERVER_CHANGE 2
+ REMOVE_SIP_SERVER 3
+
+@enum SIP-User-Authorization-Type
+
+ REGISTRATION 0
+ DEREGISTRATION 1
+ REGISTRATION_AND_CAPABILITIES 2
+
+@enum SIP-User-Data-Already-Available
+
+ USER_DATA_NOT_AVAILABLE 0
+ USER_DATA_ALREADY_AVAILABLE 1
+
+;; ===========================================================================
+
+@define Result-Code
+
+ ;; Success
+
+ FIRST_REGISTRATION 2003
+ SUBSEQUENT_REGISTRATION 2004
+ UNREGISTERED_SERVICE 2005
+ SUCCESS_SERVER_NAME_NOT_STORED 2006
+ SERVER_SELECTION 2007
+ SUCCESS_AUTH_SENT_SERVER_NOT_STORED 2008
+
+ ;; Transient Failures
+
+ USER_NAME_REQUIRED 4013
+
+ ;; Permanent Failures
+
+ USER_UNKNOWN 5032
+ IDENTITIES_DONT_MATCH 5033
+ IDENTITY_NOT_REGISTERED 5034
+ ROAMING_NOT_ALLOWED 5035
+ IDENTITY_ALREADY_REGISTERED 5036
+ AUTH_SCHEME_NOT_SUPPORTED 5037
+ IN_ASSIGNMENT_TYPE 5038
+ TOO_MUCH_DATA 5039
+ NOT_SUPPORTED_USER_DATA 5040
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 2ec016ecbc..dbfaa4e140 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -88,6 +88,9 @@ TARGET_FILES = \
# Subdirectories of src to release modules into.
TARGET_DIRS = $(sort $(dir $(TARGET_MODULES)))
+# Ditto for examples.
+EXAMPLE_DIRS = $(sort $(dir $(EXAMPLES)))
+
APP_FILE = diameter.app
APP_SRC = $(APP_FILE).src
APP_TARGET = $(EBIN)/$(APP_FILE)
@@ -169,6 +172,8 @@ info:
@echo
@$(call list,EXAMPLES)
@echo
+ @$(call list,EXAMPLE_DIRS)
+ @echo
@$(call list,BINS)
@echo ========================================
@@ -189,23 +194,29 @@ endif
# Can't $(INSTALL_DIR) more than one directory at a time on Solaris.
release_spec: opt
- for d in bin ebin examples include src/dict $(TARGET_DIRS:%/=src/%); do \
+ for d in bin ebin include src/dict; do \
$(INSTALL_DIR) $(RELSYSDIR)/$$d; \
done
$(INSTALL_SCRIPT) $(BINS:%=../bin/%) $(RELSYSDIR)/bin
$(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(EXAMPLES:%=../examples/%) $(RELSYSDIR)/examples
$(INSTALL_DATA) $(EXTERNAL_HRLS:%=../include/%) $(DICT_HRLS) \
$(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_DATA) $(filter $*/%, $(TARGET_MODULES:%=%.erl) \
$(INTERNAL_HRLS)) \
$(filter $*/%, compiler/$(DICT_YRL).yrl) \
$(RELSYSDIR)/src/$*
+$(EXAMPLE_DIRS:%/=release_examples_%): release_examples_%:
+ $(INSTALL_DIR) $(RELSYSDIR)/examples/$*
+ $(INSTALL_DATA) $(patsubst %, ../examples/%, $(filter $*/%, $(EXAMPLES))) \
+ $(RELSYSDIR)/examples/$*
+
release_docs_spec:
# ----------------------------------------------------
@@ -237,6 +248,7 @@ depend.mk: depend.sed $(MODULES:%=%.erl) Makefile
.PHONY: app clean depend dict info release_subdir
.PHONY: debug opt release_docs_spec release_spec
.PHONY: $(TARGET_DIRS:%/=%) $(TARGET_DIRS:%/=release_src_%)
+.PHONY: $(EXAMPLE_DIRS:%/=release_examples_%)
# Keep intermediate files.
.SECONDARY: $(DICT_ERLS) $(DICT_HRLS) gen/$(DICT_YRL:%=%.erl)
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 0893956f97..3dfdcee2b2 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -629,10 +629,6 @@ insert(Tbl, Rec) ->
ets:insert(Tbl, Rec),
Rec.
-monitor(Pid) ->
- erlang:monitor(process, Pid),
- Pid.
-
%% Using the process dictionary for the callback state was initially
%% just a way to make what was horrendous trace (big state record and
%% much else everywhere) somewhat more readable. There's not as much
@@ -814,10 +810,10 @@ start(Ref, Type, Opts, #state{peerT = PeerT,
service = Svc})
when Type == connect;
Type == accept ->
- Pid = monitor(s(Type, Ref, {ConnT,
- Opts,
- SvcName,
- merge_service(Opts, Svc)})),
+ Pid = s(Type, Ref, {ConnT,
+ Opts,
+ SvcName,
+ merge_service(Opts, Svc)}),
insert(PeerT, #peer{pid = Pid,
type = Type,
ref = Ref,
@@ -830,7 +826,13 @@ start(Ref, Type, Opts, #state{peerT = PeerT,
%% callbacks.
s(Type, Ref, T) ->
- diameter_watchdog:start({Type, Ref}, T).
+ case diameter_watchdog:start({Type, Ref}, T) of
+ {_MRef, Pid} ->
+ Pid;
+ Pid when is_pid(Pid) -> %% from old code
+ erlang:monitor(process, Pid),
+ Pid
+ end.
%% merge_service/2
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index 6dc53d9f31..fb22fd8275 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -59,10 +59,19 @@
message_data}). %% term passed into diameter_service with message
%% start/2
+%%
+%% Start a monitor before the watchdog is allowed to proceed to ensure
+%% that a failed capabilities exchange produces the desired exit
+%% reason.
start({_,_} = Type, T) ->
- {ok, Pid} = diameter_watchdog_sup:start_child({Type, self(), T}),
- Pid.
+ Ref = make_ref(),
+ {ok, Pid} = diameter_watchdog_sup:start_child({Ref, {Type, self(), T}}),
+ try
+ {erlang:monitor(process, Pid), Pid}
+ after
+ Pid ! Ref
+ end.
start_link(T) ->
{ok, _} = proc_lib:start_link(?MODULE,
@@ -80,14 +89,29 @@ init(T) ->
proc_lib:init_ack({ok, self()}),
gen_server:enter_loop(?MODULE, [], i(T)).
-i({T, Pid, {ConnT, Opts, SvcName, #diameter_service{applications = Apps,
- capabilities = Caps}
- = Svc}}) ->
- {M,S,U} = now(),
- random:seed(M,S,U),
+i({Ref, {_, Pid, _} = T}) ->
+ MRef = erlang:monitor(process, Pid),
+ receive
+ Ref ->
+ make_state(T);
+ {'DOWN', MRef, process, _, _} = D ->
+ exit({shutdown, D})
+ end;
+
+i({_, Pid, _} = T) -> %% from old code
+ erlang:monitor(process, Pid),
+ make_state(T).
+
+make_state({T, Pid, {ConnT,
+ Opts,
+ SvcName,
+ #diameter_service{applications = Apps,
+ capabilities = Caps}
+ = Svc}}) ->
+ random:seed(now()),
putr(restart, {T, Opts, Svc}), %% save seeing it in trace
putr(dwr, dwr(Caps)), %%
- #watchdog{parent = monitor(Pid),
+ #watchdog{parent = Pid,
transport = monitor(diameter_peer_fsm:start(T, Opts, Svc)),
tw = proplists:get_value(watchdog_timer,
Opts,
diff --git a/lib/diameter/src/compiler/diameter_dict_util.erl b/lib/diameter/src/compiler/diameter_dict_util.erl
index e4cd29ab7f..36a6efa294 100644
--- a/lib/diameter/src/compiler/diameter_dict_util.erl
+++ b/lib/diameter/src/compiler/diameter_dict_util.erl
@@ -630,13 +630,28 @@ reset(K, Dict, Opts) ->
opt({inherits = Key, "-"}, Dict) ->
dict:erase(Key, Dict);
+
opt({inherits = Key, Mod}, Dict) ->
- dict:append(Key, [0, {word, 0, Mod}], Dict);
+ case lists:splitwith(fun(C) -> C /= $/ end, Mod) of
+ {Mod, ""} ->
+ dict:append(Key, [0, {word, 0, Mod}], Dict);
+ {From, [$/|To]} ->
+ dict:store(Key,
+ [reinherit(From, To, M) || M <- find(Key, Dict)],
+ Dict)
+ end;
+
opt({Key, Val}, Dict) ->
- dict:store(Key, [0, {word, 0, Val}], Dict);
+ dict:store(Key, [[0, {word, 0, Val}]], Dict);
+
opt(_, Dict) ->
Dict.
+reinherit(From, To, [L, {word, _, From} = T | Avps]) ->
+ [L, setelement(3, T, To) | Avps];
+reinherit(_, _, T) ->
+ T.
+
%% ===========================================================================
%% pass1/1
%%
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
index 11d354e57e..7a700a6d53 100644
--- a/lib/diameter/src/modules.mk
+++ b/lib/diameter/src/modules.mk
@@ -88,11 +88,17 @@ BINS = \
# Released files relative to ../examples.
EXAMPLES = \
- GNUmakefile \
- peer.erl \
- client.erl \
- client_cb.erl \
- server.erl \
- server_cb.erl \
- relay.erl \
- relay_cb.erl
+ code/GNUmakefile \
+ code/peer.erl \
+ code/client.erl \
+ code/client_cb.erl \
+ code/server.erl \
+ code/server_cb.erl \
+ code/relay.erl \
+ code/relay_cb.erl \
+ dict/rfc4004_mip.dia \
+ dict/rfc4005_nas.dia \
+ dict/rfc4006_cc.dia \
+ dict/rfc4072_eap.dia \
+ dict/rfc4590_digest.dia \
+ dict/rfc4740_sip.dia
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index 97d9069f4a..ab5b45ff3d 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -50,6 +50,8 @@ TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
SUITE_MODULES = $(filter diameter_%_SUITE, $(MODULES))
SUITES = $(SUITE_MODULES:diameter_%_SUITE=%)
+DATA_DIRS = $(sort $(dir $(DATA)))
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -121,12 +123,12 @@ help:
# diameter_ct:run/1 itself can't tell (it seems). The absolute -pa is
# because ct will change directories.
$(SUITES): log opt
- $(ERL) -noshell \
+ $(ERL) -noinput \
-pa $(realpath ../ebin) \
-sname diameter_test_$@ \
-s diameter_ct run diameter_$@_SUITE \
-s init stop \
- | awk '1{rc=0} {print} / FAILED /{rc=1} END{exit rc}'
+ | awk '{print} / FAILED /{rc=1} END{exit rc}' rc=0
# Shorter in sed but requires a GNU extension (ie. Q).
log:
@@ -147,9 +149,7 @@ else
include $(ERL_TOP)/make/otp_release_targets.mk
endif
-release_spec:
-
-release_docs_spec:
+release_spec release_docs_spec:
release_tests_spec:
$(INSTALL_DIR) $(RELSYSDIR)
@@ -157,12 +157,18 @@ release_tests_spec:
$(COVER_SPEC_FILE) \
$(HRL_FILES) \
$(RELSYSDIR)
+ $(MAKE) $(DATA_DIRS:%/=release_data_%)
$(MAKE) $(ERL_FILES:%=/%)
+$(DATA_DIRS:%/=release_data_%): release_data_%:
+ $(INSTALL_DIR) $(RELSYSDIR)/$*
+ $(INSTALL_DATA) $(filter $*/%, $(DATA)) $(RELSYSDIR)/$*
+
force:
.PHONY: release_spec release_docs_spec release_test_specs
.PHONY: force
+.PHONY: $(DATA_DIRS:%/=release_data_%)
# Can't just make $(ERL_FILES:%=/%) phony since then implicit rule
# searching is skipped.
diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl
index e6b1558bf6..54a161d606 100644
--- a/lib/diameter/test/diameter_capx_SUITE.erl
+++ b/lib/diameter/test/diameter_capx_SUITE.erl
@@ -27,8 +27,6 @@
-export([suite/0,
all/0,
groups/0,
- init_per_group/2,
- end_per_group/2,
init_per_testcase/2,
end_per_testcase/2]).
@@ -93,30 +91,26 @@
-define(cea, #diameter_base_CEA).
-define(answer_message, #'diameter_base_answer-message').
+-define(fail(T), erlang:error({T, process_info(self(), messages)})).
+
+-define(TIMEOUT, 2000).
+
%% ===========================================================================
suite() ->
[{timetrap, {seconds, 10}}].
-all() ->
- [start, start_services, add_listeners
- | [{group, N} || {N, _, _} <- groups()]]
- ++ [remove_listeners, stop_services, stop].
+all() -> [start,
+ start_services,
+ add_listeners,
+ {group, all},
+ {group, all, [parallel]},
+ remove_listeners,
+ stop_services,
+ stop].
groups() ->
- Ts = testcases(),
- [{grp(P), P, Ts} || P <- [[], [parallel]]].
-
-grp([]) ->
- sequential;
-grp([parallel = P]) ->
- P.
-
-init_per_group(_Name, Config) ->
- Config.
-
-end_per_group(_, _) ->
- ok.
+ [{all, [], lists:flatmap(fun tc/1, tc())}].
%% Generate a unique hostname for each testcase so that watchdogs
%% don't prevent a connection from being brought up immediately.
@@ -137,9 +131,6 @@ end_per_testcase(Name, Config) ->
ok = diameter:remove_transport(?CLIENT, CRef).
%% Testcases all come in two flavours, client and server.
-testcases() ->
- lists:flatmap(fun tc/1, tc()).
-
tc(Name) ->
[?A([C,$_|?L(Name)]) || C <- "cs"].
@@ -270,8 +261,8 @@ s_client_reject(Config) ->
?packet{}}}
= Info ->
Info
- after 2000 ->
- fail({LRef, OH})
+ after ?TIMEOUT ->
+ ?fail({LRef, OH})
end.
c_client_reject(Config) ->
@@ -307,12 +298,12 @@ server_closed(Config, F, RC) ->
= Reason,
{listen, _}}} ->
Reason
- after 2000 ->
- fail({LRef, OH})
+ after ?TIMEOUT ->
+ ?fail({LRef, OH})
end.
%% server_reject/3
-
+
server_reject(Config, F, RC) ->
true = diameter:subscribe(?SERVER),
OH = host(Config),
@@ -328,8 +319,8 @@ server_reject(Config, F, RC) ->
= Reason,
{listen, _}}} ->
Reason
- after 2000 ->
- fail({LRef, OH})
+ after ?TIMEOUT ->
+ ?fail({LRef, OH})
end.
%% cliient_closed/4
@@ -345,13 +336,13 @@ client_closed(Config, Host, F, RC) ->
%% client_recv/1
-client_recv(CRef) ->
+client_recv(CRef) ->
receive
?event{service = ?CLIENT,
info = {closed, CRef, Reason, {connect, _}}} ->
Reason
- after 2000 ->
- fail(CRef)
+ after ?TIMEOUT ->
+ ?fail(CRef)
end.
%% server_capx/3
@@ -373,9 +364,6 @@ client_capx(_, ?caps{origin_host = {[_,$_|"client_reject." ++ _], _}}) ->
%% ===========================================================================
-fail(T) ->
- erlang:error({T, process_info(self(), messages)}).
-
host(Config) ->
{_, H} = lists:keyfind(host, 1, Config),
?HOST(H).
diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl
index 30c60be8e9..2e219bbb10 100644
--- a/lib/diameter/test/diameter_codec_SUITE.erl
+++ b/lib/diameter/test/diameter_codec_SUITE.erl
@@ -35,7 +35,8 @@
%% testcases
-export([base/1,
gen/1,
- lib/1]).
+ lib/1,
+ unknown/1]).
-include("diameter_ct.hrl").
@@ -47,7 +48,7 @@ suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [base, gen, lib].
+ [base, gen, lib, unknown].
init_per_testcase(gen, Config) ->
[{application, ?APP, App}] = diameter_util:consult(?APP, app),
@@ -74,3 +75,26 @@ gen([{dicts, Ms} | _]) ->
lib(_Config) ->
diameter_codec_test:lib().
+
+%% Have a separate AVP dictionary just to exercise more code.
+unknown(Config) ->
+ Priv = proplists:get_value(priv_dir, Config),
+ Data = proplists:get_value(data_dir, Config),
+ ok = make(Data, "recv.dia"),
+ ok = make(Data, "avps.dia"),
+ {ok, _, _} = compile("diameter_test_avps.erl"),
+ ok = make(Data, "send.dia"),
+ {ok, _, _} = compile("diameter_test_send.erl"),
+ {ok, _, _} = compile("diameter_test_recv.erl"),
+ {ok, _, _} = compile(filename:join([Data, "diameter_test_unknown.erl"]),
+ [{i, Priv}]),
+ diameter_test_unknown:run().
+
+make(Dir, File) ->
+ diameter_make:codec(filename:join([Dir, File])).
+
+compile(File) ->
+ compile(File, []).
+
+compile(File, Opts) ->
+ compile:file(File, [return | Opts]).
diff --git a/lib/diameter/test/diameter_codec_SUITE_data/avps.dia b/lib/diameter/test/diameter_codec_SUITE_data/avps.dia
new file mode 100644
index 0000000000..c9d80a37a9
--- /dev/null
+++ b/lib/diameter/test/diameter_codec_SUITE_data/avps.dia
@@ -0,0 +1,25 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+@name diameter_test_avps
+
+@avp_types
+
+ XXX 111 Unsigned32 M
+ YYY 222 Unsigned32 -
diff --git a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl
new file mode 100644
index 0000000000..bce3d78a37
--- /dev/null
+++ b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl
@@ -0,0 +1,76 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(diameter_test_unknown).
+
+-compile(export_all).
+
+%%
+%% Test reception of unknown AVP's.
+%%
+
+-include_lib("diameter/include/diameter.hrl").
+-include("diameter_test_send.hrl").
+-include("diameter_test_recv.hrl").
+
+-define(HOST, "test.erlang.org").
+-define(REALM, "erlang.org").
+
+%% Patterns to match decoded AVP's.
+-define(MANDATORY_XXX, #diameter_avp{code = 111}).
+-define(NOT_MANDATORY_YYY, #diameter_avp{code = 222}).
+
+%% Ensure that an unknown AVP with an M flag is regarded as an error
+%% while one without an M flag is returned as 'AVP'.
+
+run() ->
+ H = #diameter_header{version = 1,
+ end_to_end_id = 1,
+ hop_by_hop_id = 1},
+ Vs = [{'Origin-Host', ?HOST},
+ {'Origin-Realm', ?REALM},
+ {'XXX', [0]},
+ {'YYY', [1]}],
+ Pkt = #diameter_packet{header = H,
+ msg = Vs},
+
+ [] = diameter_util:run([{?MODULE, [run, M, enc(M, Pkt)]}
+ || M <- ['AR','BR']]).
+
+enc(M, #diameter_packet{msg = Vs} = P) ->
+ diameter_codec:encode(diameter_test_send,
+ P#diameter_packet{msg = [M|Vs]}).
+
+run(M, Pkt) ->
+ dec(M, diameter_codec:decode(diameter_test_recv, Pkt)).
+%% Note that the recv dictionary defines neither XXX nor YYY.
+
+dec('AR', #diameter_packet
+ {msg = #recv_AR{'Origin-Host' = ?HOST,
+ 'Origin-Realm' = ?REALM,
+ 'AVP' = [?NOT_MANDATORY_YYY]},
+ errors = [{5001, ?MANDATORY_XXX}]}) ->
+ ok;
+
+dec('BR', #diameter_packet
+ {msg = #recv_BR{'Origin-Host' = ?HOST,
+ 'Origin-Realm' = ?REALM},
+ errors = [{5008, ?NOT_MANDATORY_YYY},
+ {5001, ?MANDATORY_XXX}]}) ->
+ ok.
diff --git a/lib/diameter/test/diameter_codec_SUITE_data/recv.dia b/lib/diameter/test/diameter_codec_SUITE_data/recv.dia
new file mode 100644
index 0000000000..15fec5a5dd
--- /dev/null
+++ b/lib/diameter/test/diameter_codec_SUITE_data/recv.dia
@@ -0,0 +1,51 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+@id 17
+@name diameter_test_recv
+@prefix recv
+
+@inherits diameter_gen_base_rfc3588
+
+ Origin-Host
+ Origin-Realm
+ Result-Code
+
+@messages
+
+ AR ::= < Diameter Header: 123, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+ * [ AVP ]
+
+ AA ::= < Diameter Header: 123 >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ * [ AVP ]
+
+ BR ::= < Diameter Header: 124, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+
+ BA ::= < Diameter Header: 124 >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ * [ AVP ]
diff --git a/lib/diameter/test/diameter_codec_SUITE_data/send.dia b/lib/diameter/test/diameter_codec_SUITE_data/send.dia
new file mode 100644
index 0000000000..1472f146ae
--- /dev/null
+++ b/lib/diameter/test/diameter_codec_SUITE_data/send.dia
@@ -0,0 +1,56 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-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%
+;;
+
+@id 17
+@name diameter_test_send
+@prefix send
+
+@inherits diameter_gen_base_rfc3588
+
+ Origin-Host
+ Origin-Realm
+ Result-Code
+
+@inherits diameter_test_avps
+
+@messages
+
+ AR ::= < Diameter Header: 123, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+ [ XXX ]
+ [ YYY ]
+
+ AA ::= < Diameter Header: 123 >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ * [ AVP ]
+
+ BR ::= < Diameter Header: 124, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+ [ XXX ]
+ [ YYY ]
+
+ BA ::= < Diameter Header: 124 >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ * [ AVP ]
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index 66d788f6ec..3b4c9706e0 100644
--- a/lib/diameter/test/diameter_compiler_SUITE.erl
+++ b/lib/diameter/test/diameter_compiler_SUITE.erl
@@ -29,9 +29,10 @@
end_per_suite/1]).
%% testcases
--export([format/1, format/2,
- replace/1, replace/2,
- generate/1, generate/4, generate/0]).
+-export([format/1, format/2,
+ replace/1, replace/2,
+ generate/1, generate/4, generate/0,
+ examples/1, examples/0]).
-export([dict/0]). %% fake dictionary module
@@ -327,6 +328,14 @@
"@codecs mymod "
"Origin-Host Origin-Realm\n&"}]}]).
+%% Standard dictionaries in examples/dict.
+-define(EXAMPLES, [rfc4004_mip,
+ rfc4005_nas,
+ rfc4006_cc,
+ rfc4072_eap,
+ rfc4590_digest,
+ rfc4740_sip]).
+
%% ===========================================================================
suite() ->
@@ -335,7 +344,8 @@ suite() ->
all() ->
[format,
replace,
- generate].
+ generate,
+ examples].
%% Error handling testcases will make an erroneous dictionary out of
%% the base dictionary and check that the expected error results.
@@ -349,8 +359,6 @@ end_per_suite(_Config) ->
ok.
%% ===========================================================================
-%% testcases
-
%% format/1
%%
%% Ensure that parse o format is the identity map.
@@ -367,6 +375,7 @@ format(Mods, Bin) ->
{ok, D} = diameter_dict_util:parse(diameter_dict_util:format(Dict), []),
{Dict, Dict} = {Dict, D}.
+%% ===========================================================================
%% replace/1
%%
%% Ensure the expected success/error when parsing a morphed common
@@ -393,12 +402,13 @@ replace({E, Mods}, Bin) ->
re({RE, Repl}, Bin) ->
re:replace(Bin, RE, Repl, [multiline]).
+%% ===========================================================================
%% generate/1
%%
%% Ensure success when generating code and compiling.
generate() ->
- [{timetrap, {seconds, length(?REPLACE)}}].
+ [{timetrap, {seconds, 2*length(?REPLACE)}}].
generate(Config) ->
Bin = proplists:get_value(base, Config),
@@ -422,6 +432,44 @@ generate(Mods, Bin, N, Mode) ->
andalso ({ok, _} = compile:file(File ++ ".erl", [return_errors])).
%% ===========================================================================
+%% examples/1
+%%
+%% Compile dictionaries extracted from various standards.
+
+examples() ->
+ [{timetrap, {seconds, 3*length(?EXAMPLES)}}].
+
+examples(_Config) ->
+ Dir = filename:join([code:lib_dir(diameter, examples), "dict"]),
+ [D || D <- ?EXAMPLES, _ <- [examples(?S(D), Dir)]].
+
+examples(Dict, Dir) ->
+ {Name, Pre} = make_name(Dict),
+ ok = diameter_make:codec(filename:join([Dir, Dict ++ ".dia"]),
+ [{name, Name},
+ {prefix, Pre},
+ inherits("rfc3588_base")
+ | opts(Dict)]),
+ {ok, _, _} = compile:file(Name ++ ".erl", [return]).
+
+opts(M)
+ when M == "rfc4006_cc";
+ M == "rfc4072_eap" ->
+ [inherits("rfc4005_nas")];
+opts("rfc4740_sip") ->
+ [inherits("rfc4590_digest")];
+opts(_) ->
+ [].
+
+inherits(File) ->
+ {Name, _} = make_name(File),
+ {inherits, File ++ "/" ++ Name}.
+
+make_name(File) ->
+ {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, File),
+ {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}.
+
+%% ===========================================================================
modify(Bin, Mods) ->
lists:foldl(fun re/2, Bin, Mods).
diff --git a/lib/diameter/test/diameter_dict_SUITE.erl b/lib/diameter/test/diameter_dict_SUITE.erl
index 87bb9727fe..5cf8506d3f 100644
--- a/lib/diameter/test/diameter_dict_SUITE.erl
+++ b/lib/diameter/test/diameter_dict_SUITE.erl
@@ -25,9 +25,7 @@
-export([suite/0,
all/0,
- groups/0,
- init_per_group/2,
- end_per_group/2]).
+ groups/0]).
%% testcases
-export([append/1,
@@ -53,10 +51,11 @@ suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [{group, all} | tc()].
+ [{group, all},
+ {group, all, [parallel]}].
groups() ->
- [{all, [parallel], tc()}].
+ [{all, [], tc()}].
tc() ->
[append,
@@ -71,12 +70,6 @@ tc() ->
update,
update_counter].
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(_, _) ->
- ok.
-
%% ===========================================================================
-define(KV100, [{N,[N]} || N <- lists:seq(1,100)]).
diff --git a/lib/diameter/test/diameter_failover_SUITE.erl b/lib/diameter/test/diameter_failover_SUITE.erl
index 429b6328e6..53398dd93e 100644
--- a/lib/diameter/test/diameter_failover_SUITE.erl
+++ b/lib/diameter/test/diameter_failover_SUITE.erl
@@ -174,7 +174,7 @@ realm(Host) ->
call(Req, Opts) ->
diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts).
-
+
set([H|T], Vs) ->
[H | Vs ++ T].
diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl
new file mode 100644
index 0000000000..7f435a6b7a
--- /dev/null
+++ b/lib/diameter/test/diameter_gen_sctp_SUITE.erl
@@ -0,0 +1,354 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-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%
+%%
+
+%%
+%% Some gen_sctp-specific tests demonstrating problems that were
+%% encountered during diameter development but have nothing
+%% specifically to do with diameter. At least one of them can cause
+%% diameter_transport_SUITE testcases to fail.
+%%
+
+-module(diameter_gen_sctp_SUITE).
+
+-export([suite/0,
+ all/0,
+ init_per_suite/1,
+ end_per_suite/1]).
+
+%% testcases
+-export([send_not_from_controlling_process/1,
+ send_from_multiple_clients/1,
+ receive_what_was_sent/1]).
+
+-include_lib("kernel/include/inet_sctp.hrl").
+
+%% Message from gen_sctp are of this form.
+-define(SCTP(Sock, Data), {sctp, Sock, _, _, Data}).
+
+%% Open sockets on the loopback address.
+-define(ADDR, {127,0,0,1}).
+
+%% Snooze, nap, siesta.
+-define(SLEEP(T), receive after T -> ok end).
+
+%% An indescribably long number of milliseconds after which everthing
+%% that should have happened has.
+-define(FOREVER, 2000).
+
+%% The first byte in each message we send as a simple guard against
+%% not receiving what was sent.
+-define(MAGIC, 42).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {minutes, 2}}].
+
+all() ->
+ [send_not_from_controlling_process,
+ send_from_multiple_clients,
+ receive_what_was_sent].
+
+init_per_suite(Config) ->
+ case gen_sctp:open() of
+ {ok, Sock} ->
+ gen_sctp:close(Sock),
+ Config;
+ {error, E} when E == eprotonosupport;
+ E == esocktnosupport ->
+ {skip, no_sctp}
+ end.
+
+end_per_suite(_Config) ->
+ ok.
+
+%% ===========================================================================
+
+%% send_not_from_controlling_process/1
+%%
+%% This testcase failing shows gen_sctp:send/4 hanging when called
+%% outside the controlling process of the socket in question.
+
+send_not_from_controlling_process(_) ->
+ Pids = send_not_from_controlling_process(),
+ ?SLEEP(?FOREVER),
+ try
+ [] = [{P,I} || P <- Pids, I <- [process_info(P)], I /= undefined]
+ after
+ lists:foreach(fun(P) -> exit(P, kill) end, Pids)
+ end.
+
+%% send_not_from_controlling_process/0
+%%
+%% Returns the pids of three spawned processes: a listening process, a
+%% connecting process and a sending process.
+%%
+%% The expected behaviour is that all three processes exit:
+%%
+%% - The listening process exits upon receiving an SCTP message
+%% sent by the sending process.
+%% - The connecting process exits upon listening process exit.
+%% - The sending process exits upon gen_sctp:send/4 return.
+%%
+%% The observed behaviour is that all three processes remain alive
+%% indefinitely:
+%%
+%% - The listening process never receives the SCTP message sent
+%% by the sending process.
+%% - The connecting process has an inet_reply message in its mailbox
+%% as a consequence of the call to gen_sctp:send/4 call from the
+%% sending process.
+%% - The call to gen_sctp:send/4 in the sending process doesn't return,
+%% hanging in prim_inet:getopts/2.
+
+send_not_from_controlling_process() ->
+ FPid = self(),
+ {L, MRef} = spawn_monitor(fun() -> listen(FPid) end),%% listening process
+ receive
+ {?MODULE, C, S} ->
+ erlang:demonitor(MRef, [flush]),
+ [L,C,S];
+ {'DOWN', MRef, process, _, _} = T ->
+ error(T)
+ end.
+
+%% listen/1
+
+listen(FPid) ->
+ {ok, Sock} = open(),
+ ok = gen_sctp:listen(Sock, true),
+ {ok, PortNr} = inet:port(Sock),
+ LPid = self(),
+ spawn(fun() -> connect1(PortNr, FPid, LPid) end), %% connecting process
+ Id = assoc(Sock),
+ ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], _Bin})
+ = recv(). %% Waits with this as current_function.
+
+%% recv/0
+
+recv() ->
+ receive T -> T end.
+
+%% connect1/3
+
+connect1(PortNr, FPid, LPid) ->
+ {ok, Sock} = open(),
+ ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []),
+ Id = assoc(Sock),
+ FPid ! {?MODULE,
+ self(),
+ spawn(fun() -> send(Sock, Id) end)}, %% sending process
+ MRef = erlang:monitor(process, LPid),
+ down(MRef). %% Waits with this as current_function.
+
+%% down/1
+
+down(MRef) ->
+ receive {'DOWN', MRef, process, _, Reason} -> Reason end.
+
+%% send/2
+
+send(Sock, Id) ->
+ ok = gen_sctp:send(Sock, Id, 0, <<0:32>>).
+
+%% ===========================================================================
+
+%% send_from_multiple_clients/0
+%%
+%% Demonstrates sluggish delivery of messages.
+
+send_from_multiple_clients(_) ->
+ {S, Rs} = T = send_from_multiple_clients(8, 1024),
+ {false, [], _} = {?FOREVER < S,
+ Rs -- [OI || {O,_} = OI <- Rs, is_integer(O)],
+ T}.
+
+%% send_from_multiple_clients/2
+%%
+%% Opens a listening socket and then spawns a specified number of
+%% processes, each of which connects to the listening socket. Each
+%% connecting process then sends a message, whose size in bytes is
+%% passed as an argument, the listening process sends a reply
+%% containing the time at which the message was received, and the
+%% connecting process then exits upon reception of this reply.
+%%
+%% Returns the elapsed time for all connecting process to exit
+%% together with a list of exit reasons for the connecting processes.
+%% In the successful case a connecting process exits with the
+%% outbound/inbound transit times for the sent/received message as
+%% reason.
+%%
+%% The observed behaviour is that some outbound messages (that is,
+%% from a connecting process to the listening process) can take an
+%% unexpectedly long time to complete their journey. The more
+%% connecting processes, the longer the possible delay it seems.
+%%
+%% eg. (With F = fun send_from_multiple_clients/2.)
+%%
+%% 5> F(2, 1024).
+%% {875,[{128,116},{113,139}]}
+%% 6> F(4, 1024).
+%% {2995290,[{2994022,250},{2994071,80},{200,130},{211,113}]}
+%% 7> F(8, 1024).
+%% {8997461,[{8996161,116},
+%% {2996471,86},
+%% {2996278,116},
+%% {2996360,95},
+%% {246,112},
+%% {213,159},
+%% {373,173},
+%% {376,118}]}
+%% 8> F(8, 1024).
+%% {21001891,[{20999968,128},
+%% {8997891,172},
+%% {8997927,91},
+%% {2995716,164},
+%% {2995860,87},
+%% {134,100},
+%% {117,98},
+%% {149,125}]}
+
+send_from_multiple_clients(N, Sz)
+ when is_integer(N), 0 < N, is_integer(Sz), 0 < Sz ->
+ timer:tc(fun listen/2, [N, <<?MAGIC, 0:Sz/unit:8>>]).
+
+%% listen/2
+
+listen(N, Bin) ->
+ {ok, Sock} = open(),
+ ok = gen_sctp:listen(Sock, true),
+ {ok, PortNr} = inet:port(Sock),
+
+ %% Spawn a middleman that in turn spawns N connecting processes,
+ %% collects a list of exit reasons and then exits with the list as
+ %% reason. loop/3 returns when we receive this list from the
+ %% middleman's 'DOWN'.
+
+ Self = self(),
+ Fun = fun() -> exit(connect2(Self, PortNr, Bin)) end,
+ {_, MRef} = spawn_monitor(fun() -> exit(fold(N, Fun)) end),
+ loop(Sock, MRef, Bin).
+
+%% fold/2
+%%
+%% Spawn N processes and collect their exit reasons in a list.
+
+fold(N, Fun) ->
+ start(N, Fun),
+ acc(N, []).
+
+start(0, _) ->
+ ok;
+start(N, Fun) ->
+ spawn_monitor(Fun),
+ start(N-1, Fun).
+
+acc(0, Acc) ->
+ Acc;
+acc(N, Acc) ->
+ receive
+ {'DOWN', _MRef, process, _, RC} ->
+ acc(N-1, [RC | Acc])
+ end.
+
+%% loop/3
+
+loop(Sock, MRef, Bin) ->
+ receive
+ ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], B}) ->
+ Sz = size(Bin),
+ {Sz, Bin} = {size(B), B}, %% assert
+ ok = send(Sock, Id, mark(Bin)),
+ loop(Sock, MRef, Bin);
+ ?SCTP(Sock, _) ->
+ loop(Sock, MRef, Bin);
+ {'DOWN', MRef, process, _, Reason} ->
+ Reason
+ end.
+
+%% connect2/3
+
+connect2(Pid, PortNr, Bin) ->
+ erlang:monitor(process, Pid),
+
+ {ok, Sock} = open(),
+ ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []),
+ Id = assoc(Sock),
+
+ %% T1 = time before send
+ %% T2 = time after listening process received our message
+ %% T3 = time after reply is received
+
+ T1 = now(),
+ ok = send(Sock, Id, Bin),
+ T2 = unmark(recv(Sock, Id)),
+ T3 = now(),
+ {timer:now_diff(T2, T1), timer:now_diff(T3, T2)}. %% {Outbound, Inbound}
+
+%% recv/2
+
+recv(Sock, Id) ->
+ receive
+ ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], Bin}) ->
+ Bin;
+ T -> %% eg. 'DOWN'
+ exit(T)
+ end.
+
+%% send/3
+
+send(Sock, Id, Bin) ->
+ gen_sctp:send(Sock, Id, 0, Bin).
+
+%% mark/1
+
+mark(Bin) ->
+ Info = term_to_binary(now()),
+ <<Info/binary, Bin/binary>>.
+
+%% unmark/1
+
+unmark(Bin) ->
+ {_,_,_} = binary_to_term(Bin).
+
+%% ===========================================================================
+
+%% receive_what_was_sent/1
+%%
+%% Demonstrates reception of a message that differs from that sent.
+
+receive_what_was_sent(_Config) ->
+ send_from_multiple_clients(1, 1024*32). %% fails
+
+%% ===========================================================================
+
+%% open/0
+
+open() ->
+ gen_sctp:open([{ip, ?ADDR}, {port, 0}, {active, true}, binary]).
+
+%% assoc/1
+
+assoc(Sock) ->
+ receive
+ ?SCTP(Sock, {[], #sctp_assoc_change{state = S,
+ assoc_id = Id}}) ->
+ comm_up = S, %% assert
+ Id
+ end.
diff --git a/lib/diameter/test/diameter_reg_SUITE.erl b/lib/diameter/test/diameter_reg_SUITE.erl
index ade824c9dd..ec6a0ca731 100644
--- a/lib/diameter/test/diameter_reg_SUITE.erl
+++ b/lib/diameter/test/diameter_reg_SUITE.erl
@@ -26,8 +26,6 @@
-export([suite/0,
all/0,
groups/0,
- init_per_group/2,
- end_per_group/2,
init_per_suite/1,
end_per_suite/1]).
@@ -48,10 +46,11 @@ suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [{group, all} | tc()].
+ [{group, all},
+ {group, all, [parallel]}].
groups() ->
- [{all, [parallel], tc()}].
+ [{all, [], tc()}].
tc() ->
[add,
@@ -61,12 +60,6 @@ tc() ->
terms,
pids].
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(_, _) ->
- ok.
-
init_per_suite(Config) ->
ok = diameter:start(),
Config.
diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl
index c0351f8cf2..70e1866791 100644
--- a/lib/diameter/test/diameter_relay_SUITE.erl
+++ b/lib/diameter/test/diameter_relay_SUITE.erl
@@ -35,9 +35,7 @@
-export([suite/0,
all/0,
- groups/0,
- init_per_group/2,
- end_per_group/2]).
+ groups/0]).
%% testcases
-export([start/1,
@@ -117,21 +115,17 @@ suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [start, start_services, connect]
- ++ tc()
- ++ [{group, all},
- disconnect,
- stop_services,
- stop].
+ [start,
+ start_services,
+ connect,
+ {group, all},
+ {group, all, [parallel]},
+ disconnect,
+ stop_services,
+ stop].
groups() ->
- [{all, [parallel], tc()}].
-
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(_, _) ->
- ok.
+ [{all, [], tc()}].
%% Traffic cases run when services are started and connections
%% established.
@@ -248,7 +242,7 @@ call(Server) ->
call(Req, Opts) ->
diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts).
-
+
set([H|T], Vs) ->
[H | Vs ++ T].
diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl
index e50a0050a6..e7807fd360 100644
--- a/lib/diameter/test/diameter_stats_SUITE.erl
+++ b/lib/diameter/test/diameter_stats_SUITE.erl
@@ -26,8 +26,6 @@
-export([suite/0,
all/0,
groups/0,
- init_per_group/2,
- end_per_group/2,
init_per_suite/1,
end_per_suite/1]).
@@ -44,21 +42,16 @@ suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [{group, all} | tc()].
+ [{group, all},
+ {group, all, [parallel]}].
groups() ->
- [{all, [parallel], tc()}].
+ [{all, [], tc()}].
tc() ->
[an,
twa].
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(_, _) ->
- ok.
-
init_per_suite(Config) ->
ok = diameter:start(),
Config.
diff --git a/lib/diameter/test/diameter_sync_SUITE.erl b/lib/diameter/test/diameter_sync_SUITE.erl
index 84f77b6066..ab629fb1c1 100644
--- a/lib/diameter/test/diameter_sync_SUITE.erl
+++ b/lib/diameter/test/diameter_sync_SUITE.erl
@@ -26,8 +26,6 @@
-export([suite/0,
all/0,
groups/0,
- init_per_group/2,
- end_per_group/2,
init_per_suite/1,
end_per_suite/1]).
@@ -48,10 +46,11 @@ suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [{group, all} | tc()].
+ [{group, all},
+ {group, all, [parallel]}].
groups() ->
- [{all, [parallel], tc()}].
+ [{all, [], tc()}].
tc() ->
[call,
@@ -59,12 +58,6 @@ tc() ->
timeout,
flush].
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(_, _) ->
- ok.
-
init_per_suite(Config) ->
ok = diameter:start(),
Config.
diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl
index 38282282b8..85b953dc1a 100644
--- a/lib/diameter/test/diameter_tls_SUITE.erl
+++ b/lib/diameter/test/diameter_tls_SUITE.erl
@@ -36,8 +36,6 @@
-export([suite/0,
all/0,
groups/0,
- init_per_group/2,
- end_per_group/2,
init_per_suite/1,
end_per_suite/1]).
@@ -136,20 +134,16 @@ all() ->
start_diameter,
make_certs,
start_services,
- add_transports]
- ++ [{group, N} || {N, _, _} <- groups()]
- ++ [remove_transports, stop_services, stop_diameter, stop_ssl].
+ add_transports,
+ {group, all},
+ {group, all, [parallel]},
+ remove_transports,
+ stop_services,
+ stop_diameter,
+ stop_ssl].
groups() ->
- Ts = tc(),
- [{all, [], Ts},
- {p, [parallel], Ts}].
-
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(_, _) ->
- ok.
+ [{all, [], tc()}].
%% Shouldn't really have to know about crypto here but 'ok' from
%% ssl:start() isn't enough to guarantee that TLS is available.
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 78131b4ec4..6eed8d3b5d 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -162,27 +162,16 @@ suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [start, start_services, add_transports, result_codes
- | [{group, N} || {N, _, _} <- groups()]]
+ [start, start_services, add_transports, result_codes]
+ ++ [{group, E, P} || E <- ?ENCODINGS, P <- [[], [parallel]]]
++ [remove_transports, stop_services, stop].
groups() ->
Ts = tc(),
- [{grp(E,P), P, Ts} || E <- ?ENCODINGS, P <- [[], [parallel]]].
-
-grp(E, []) ->
- E;
-grp(E, [parallel]) ->
- ?P(E).
+ [{E, [], Ts} || E <- ?ENCODINGS].
init_per_group(Name, Config) ->
- E = case ?L(Name) of
- "p_" ++ Rest ->
- ?A(Rest);
- _ ->
- Name
- end,
- [{encode, E} | Config].
+ [{encode, Name} | Config].
end_per_group(_, _) ->
ok.
@@ -516,10 +505,10 @@ send_multiple_filters(Config, Fs) ->
%% Ensure that we can pass a request in any form to diameter:call/4,
%% only the return value from the prepare_request callback being
%% significant.
-send_anything(Config) ->
+send_anything(Config) ->
#diameter_base_STA{'Result-Code' = ?SUCCESS}
= call(Config, anything).
-
+
%% ===========================================================================
call(Config, Req) ->
diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl
index df7161fd1e..893b7ba2f9 100644
--- a/lib/diameter/test/diameter_transport_SUITE.erl
+++ b/lib/diameter/test/diameter_transport_SUITE.erl
@@ -27,8 +27,6 @@
-export([suite/0,
all/0,
groups/0,
- init_per_group/2,
- end_per_group/2,
init_per_suite/1,
end_per_suite/1]).
@@ -92,10 +90,13 @@ suite() ->
[{timetrap, {minutes, 2}}].
all() ->
- [start | tc()] ++ [{group, all}, stop].
+ [start,
+ {group, all},
+ {group, all, [parallel]},
+ stop].
groups() ->
- [{all, [parallel], tc()}].
+ [{all, [], tc()}].
tc() ->
[tcp_accept,
@@ -103,12 +104,6 @@ tc() ->
sctp_accept,
sctp_connect].
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(_, _) ->
- ok.
-
init_per_suite(Config) ->
[{sctp, have_sctp()} | Config].
@@ -175,16 +170,13 @@ connect(Prot) ->
%% have_sctp/0
have_sctp() ->
- try gen_sctp:open() of
+ case gen_sctp:open() of
{ok, Sock} ->
gen_sctp:close(Sock),
true;
{error, E} when E == eprotonosupport;
E == esocktnosupport -> %% fail on any other reason
false
- catch
- error: badarg ->
- false
end.
%% if_sctp/2
@@ -220,7 +212,7 @@ init(gen_connect, {Prot, Ref}) ->
[PortNr] = ?util:lport(Prot, Ref, 20),
%% Connect, send a message and receive it back.
- {ok, Sock} = gen_connect(Prot, PortNr, Ref),
+ {ok, Sock} = gen_connect(Prot, PortNr),
Bin = make_msg(),
ok = gen_send(Prot, Sock, Bin),
Bin = gen_recv(Prot, Sock);
@@ -359,20 +351,7 @@ tmod(tcp) ->
%% ===========================================================================
-%% gen_connect/3
-
-gen_connect(Prot, PortNr, Ref) ->
- Pid = sync(connect, Ref),
-
- %% Stagger connect attempts to avoid the situation that no
- %% transport process is accepting yet.
- receive after 250 -> ok end,
-
- try
- gen_connect(Prot, PortNr)
- after
- Pid ! Ref
- end.
+%% gen_connect/2
gen_connect(sctp = P, PortNr) ->
{ok, Sock} = Ok = gen_sctp:open([{ip, ?ADDR}, {port, 0} | ?SCTP_OPTS]),
diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl
index 6b1dc1f0c9..0c42f955ad 100644
--- a/lib/diameter/test/diameter_util.erl
+++ b/lib/diameter/test/diameter_util.erl
@@ -212,7 +212,7 @@ read_priv(Config, Name) ->
read(Path) ->
{ok, Bin} = file:read_file(Path),
binary_to_term(Bin).
-
+
%% map_priv/3
%%
%% Modify a term in a file and return both old and new values.
diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl
index b40d7c104d..ff40326947 100644
--- a/lib/diameter/test/diameter_watchdog_SUITE.erl
+++ b/lib/diameter/test/diameter_watchdog_SUITE.erl
@@ -306,11 +306,8 @@ watchdog(Type, Ref, TPid, Wd) ->
Opts = [{transport_module, ?MODULE},
{transport_config, TPid},
{watchdog_timer, Wd}],
- monitor(diameter_watchdog:start({Type, Ref},
- {false, Opts, false, ?SERVICE})).
-
-monitor(Pid) ->
- erlang:monitor(process, Pid),
+ {_MRef, Pid} = diameter_watchdog:start({Type, Ref},
+ {false, Opts, false, ?SERVICE}),
Pid.
%% ===========================================================================
@@ -350,6 +347,10 @@ init(_, _, TPid, _) ->
monitor(TPid),
3.
+monitor(Pid) ->
+ erlang:monitor(process, Pid),
+ Pid.
+
%% Generate a unique hostname for the faked peer.
hostname() ->
lists:flatten(io_lib:format("~p-~p-~p", tuple_to_list(now()))).
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index 54978d820c..7f163536fb 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -33,6 +33,7 @@ MODULES = \
diameter_sync_SUITE \
diameter_stats_SUITE \
diameter_watchdog_SUITE \
+ diameter_gen_sctp_SUITE \
diameter_transport_SUITE \
diameter_capx_SUITE \
diameter_traffic_SUITE \
@@ -42,3 +43,9 @@ MODULES = \
HRL_FILES = \
diameter_ct.hrl
+
+DATA = \
+ diameter_codec_SUITE_data/avps.dia \
+ diameter_codec_SUITE_data/send.dia \
+ diameter_codec_SUITE_data/recv.dia \
+ diameter_codec_SUITE_data/diameter_test_unknown.erl
diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css
index 97d8c2df74..c56de378f4 100644
--- a/lib/erl_docgen/priv/css/otp_doc.css
+++ b/lib/erl_docgen/priv/css/otp_doc.css
@@ -1,6 +1,5 @@
-
-
-body {
+/* standard OTP style sheet */
+body {
background: white;
font-family: Verdana, Arial, Helvetica, sans-serif;
margin: 0;
@@ -11,7 +10,6 @@ body {
max-height: 100%;
}
-
th { font-family: Verdana, Arial, Helvetica, sans-serif }
td { font-family: Verdana, Arial, Helvetica, sans-serif }
p { font-family: Verdana, Arial, Helvetica, sans-serif }
@@ -33,8 +31,7 @@ a:visited { color: blue; text-decoration: none }
background-color: #fff;
}
-
-#leftnav {
+#leftnav {
position: fixed;
float: left;
top: 0;
@@ -47,8 +44,7 @@ a:visited { color: blue; text-decoration: none }
border-right: 1px solid red;
}
-
-#content {
+#content {
margin-left: 240px; /* set left value to WidthOfFrameDiv */
}
@@ -57,7 +53,6 @@ a:visited { color: blue; text-decoration: none }
padding-top: 50px; /* Magins for inner DIV inside each DIV (to provide padding) */
}
-
.innertube
{
margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
@@ -66,16 +61,15 @@ a:visited { color: blue; text-decoration: none }
.footer
{
margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
-
}
-span.bold_code { font-family: courier;font-weight: bold}
-span.code { font-family: courier;font-weight: normal}
+
+span.bold_code { font-family: Courier, monospace; font-weight: bold }
+span.code { font-family: Courier, monospace; font-weight: normal }
.note, .warning {
border: solid black 1px;
margin: 1em 3em;
}
-
.note .label {
background: #30d42a;
color: white;
@@ -102,16 +96,15 @@ span.code { font-family: courier;font-weight: normal}
font-size: 90%;
padding: 5px 10px;
}
-
-.example {
+.example {
background-color:#eeeeff;
padding: 0px 10px;
-}
+}
-pre { font-family: courier; font-weight: normal }
+pre { font-family: Courier, monospace; font-weight: normal }
.REFBODY { margin-left: 13mm }
.REFTYPES { margin-left: 8mm }
-footer { }
+footer { }
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index bdef7bfd3d..7cf5465f90 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.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
@@ -40,6 +40,11 @@
<xsl:variable name="m2a" select="document($mod2app_file)"></xsl:variable>
<xsl:key name="mod2app" match="module" use="@name"/>
+ <xsl:key
+ name="mfa"
+ match="func/name[string-length(@arity) > 0 and ancestor::erlref]"
+ use="concat(ancestor::erlref/module,':',@name, '/', @arity)"/>
+
<xsl:template name="err">
<xsl:param name="f"/>
<xsl:param name="m"/>
@@ -101,10 +106,14 @@
</xsl:message>
</xsl:when>
<xsl:when test="ancestor::erlref">
+ <!-- Do not to use preceding since it is very slow! -->
+ <xsl:variable name="curModule" select="ancestor::erlref/module"/>
+ <xsl:variable name="mfas"
+ select="key('mfa',
+ concat($curModule,':',$name,'/',$arity))"/>
<xsl:choose>
- <xsl:when test="preceding-sibling::name[position() = 1
- and @name = $name and @arity = $arity]">
- <!-- Avoid duplicated anchors.-->
+ <xsl:when test="generate-id($mfas[1]) != generate-id(.)">
+ <!-- Avoid duplicated anchors. See also menu.funcs. -->
</xsl:when>
<xsl:otherwise>
<a name="{$name}-{$arity}"></a>
@@ -546,6 +555,23 @@
<!-- End of Dialyzer type/spec tags -->
+ <!-- Cache for each module all the elements used for navigation. -->
+ <xsl:variable name="erlref.nav" select="exsl:node-set($erlref.nav_rtf)"/>
+
+ <xsl:variable name="erlref.nav_rtf">
+ <xsl:for-each select="//erlref">
+ <xsl:variable name="cval" select="module"/>
+ <xsl:variable name="link_cval"><xsl:value-of select="translate($cval, '&#173;', '')"/></xsl:variable>
+ <module name="{$cval}">
+ <xsl:call-template name="menu.funcs">
+ <xsl:with-param name="entries" select="funcs/func/name"/>
+ <xsl:with-param name="cval" select="$cval"/>
+ <xsl:with-param name="basename" select="$link_cval"/>
+ </xsl:call-template>
+ </module>
+ </xsl:for-each>
+ </xsl:variable>
+
<!-- Page layout -->
<xsl:template name="pagelayout">
<xsl:param name="chapnum"/>
@@ -1315,11 +1341,25 @@
Top of manual page
</a>
</li>
- <xsl:call-template name="menu.funcs">
- <xsl:with-param name="entries"
- select="funcs/func/name"/>
- <xsl:with-param name="basename"><xsl:value-of select="$link_cval"/></xsl:with-param>
- </xsl:call-template>
+ <xsl:call-template name="nl"/>
+ <xsl:choose>
+ <xsl:when test="local-name() = 'erlref'">
+ <!-- Use the cached value in order to save time.
+ value-of a string node is _much_ faster than
+ copy-of a rtf -->
+ <xsl:value-of
+ disable-output-escaping="yes"
+ select="$erlref.nav/module[@name = $cval]"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="menu.funcs">
+ <xsl:with-param name="entries"
+ select="funcs/func/name"/>
+ <xsl:with-param name="basename"><xsl:value-of select="$link_cval"/></xsl:with-param>
+ <xsl:with-param name="cval" select="$cval"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
</ul>
</li>
</xsl:when>
@@ -1349,6 +1389,7 @@
<xsl:template name="menu.funcs">
<xsl:param name="entries"/>
<xsl:param name="basename"/>
+ <xsl:param name="cval"/>
<xsl:for-each select="$entries">
@@ -1434,17 +1475,41 @@
</xsl:choose>
</xsl:variable>
+ <!-- Avoid duplicated entries. See also template "spec_name" -->
+ <!-- Do not to use preceding since it is very slow! -->
+ <xsl:variable name="mfas"
+ select="key('mfa',
+ concat($cval,':',$fname,'/',$arity))"/>
<xsl:choose>
- <xsl:when test="preceding-sibling::name[position() = 1
- and @name = $fname and @arity = $arity]">
+ <xsl:when test="string-length(@name) > 0 and
+ generate-id($mfas[1]) != generate-id(.)">
<!-- Skip. Only works for Dialyzer specs. -->
</xsl:when>
<xsl:otherwise>
+<!--
<li title="{$fname}-{$arity}">
<a href="{$basename}.html#{$fname}-{$arity}">
<xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/>
</a>
</li>
+-->
+ <!-- Generate a text node -->
+ <xsl:text>&lt;li title="</xsl:text>
+ <xsl:value-of select="$fname"/>
+ <xsl:text>-</xsl:text>
+ <xsl:value-of select="$arity"/>
+ <xsl:text>">&lt;a href="</xsl:text>
+ <xsl:value-of select="$basename"/>
+ <xsl:text>.html#</xsl:text>
+ <xsl:value-of select="$fname"/>
+ <xsl:text>-</xsl:text>
+ <xsl:value-of select="$arity"/>
+ <xsl:text>"></xsl:text>
+ <xsl:value-of select="$fname"/>
+ <xsl:text>/</xsl:text>
+ <xsl:value-of select="$arity"/>
+ <xsl:text>&lt;/a>&lt;/li></xsl:text>
+ <xsl:call-template name="nl"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
@@ -1854,18 +1919,24 @@
<xsl:choose>
<xsl:when test="string-length($filepart) > 0">
- <xsl:variable name="modulepart"><xsl:value-of select="substring-before($filepart, ':')"/></xsl:variable>
+ <!-- "Filepart#Linkpart" (or "Filepart#") -->
+ <xsl:variable name="app_part"><xsl:value-of select="substring-before($filepart, ':')"/></xsl:variable>
<xsl:choose>
- <xsl:when test="string-length($modulepart) > 0">
- <xsl:variable name="filepart1"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable>
- <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html#{$linkpart}');"><xsl:apply-templates/></a></span>
+ <xsl:when test="string-length($app_part) > 0">
+ <!-- "AppPart:ModPart#Linkpart" -->
+ <xsl:variable name="mod_part"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable>
+ <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html#{$linkpart}');"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
+ <!-- "Filepart#Linkpart (there is no ':' in Filepart) -->
+ <xsl:variable name="minus_prefix"
+ select="substring-before($linkpart, '-')"/>
<xsl:choose>
- <!-- Dialyzer seealso (the application is unknown) -->
- <xsl:when test="string-length($specs_file) > 0
+ <xsl:when test="$minus_prefix = 'type'
+ and string-length($specs_file) > 0
and count($i/specs/module[@name=$filepart]) = 0">
- <!-- Deemed to slow; use key() instead
+ <!-- Dialyzer seealso (the application is unknown) -->
+ <!-- Following code deemed too slow; use key() instead
<xsl:variable name="app"
select="$m2a/mod2app/module[@name=$filepart]"/>
-->
@@ -1877,41 +1948,45 @@
<span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app}','{$filepart}.html#{$linkpart}');"><xsl:value-of select="$this"/></a></span>
</xsl:when>
<xsl:otherwise>
- <!-- Unknown application; no link -->
- <xsl:value-of select="$this"/>
+ <!-- Unknown application -->
+ <xsl:message terminate="yes">
+ Error <xsl:value-of select="$filepart"/>: cannot find module exporting type
+ </xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
<xsl:when test="string-length($linkpart) > 0">
+ <!-- Still Filepart#Linkpart (there is no ':' in Filepart -->
<span class="bold_code"><a href="{$filepart}.html#{$linkpart}"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
+ <!-- "Filepart#" (there is no ':' in Filepart -->
<span class="bold_code"><a href="{$filepart}.html"><xsl:apply-templates/></a></span>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
+ </xsl:when> <!-- string-length($filepart) > 0 -->
+ <xsl:when test="string-length($linkpart) > 0">
+ <!-- "#Linkpart" -->
+ <span class="bold_code"><a href="#{$linkpart}"><xsl:apply-templates/></a></span>
</xsl:when>
<xsl:otherwise>
- <xsl:choose>
- <xsl:when test="string-length($linkpart) > 0">
- <span class="bold_code"><a href="#{$linkpart}"><xsl:apply-templates/></a></span>
- </xsl:when>
- <xsl:otherwise>
- <xsl:variable name="modulepart"><xsl:value-of select="substring-before(@marker, ':')"/></xsl:variable>
+ <!-- "AppPart:Mod" or "Mod" (there is no '#') -->
+ <xsl:variable name="app_part"><xsl:value-of select="substring-before(@marker, ':')"/></xsl:variable>
- <xsl:choose>
- <xsl:when test="string-length($modulepart) > 0">
- <xsl:variable name="filepart1"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable>
- <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html');"><xsl:apply-templates/></a></span>
- </xsl:when>
- <xsl:otherwise>
- <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:otherwise>
- </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="string-length($app_part) > 0">
+ <!-- "App:Mod" -->
+ <xsl:variable name="mod_part"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable>
+ <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html');"><xsl:apply-templates/></a></span>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- "Mod" -->
+ <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span>
+ </xsl:otherwise>
+ </xsl:choose>
</xsl:otherwise>
</xsl:choose>
@@ -2200,4 +2275,9 @@
</xsl:template>
+ <xsl:template name="nl">
+ <xsl:text>
+</xsl:text>
+ </xsl:template>
+
</xsl:stylesheet>
diff --git a/lib/erl_interface/src/misc/ei_format.c b/lib/erl_interface/src/misc/ei_format.c
index cf50f12451..c1e5d998e4 100644
--- a/lib/erl_interface/src/misc/ei_format.c
+++ b/lib/erl_interface/src/misc/ei_format.c
@@ -149,7 +149,7 @@ static int pdigit(const char** fmt, ei_x_buff* x)
{
const char* start = *fmt;
char c;
- int len, dotp=0;
+ int dotp=0;
double d;
long l;
@@ -166,7 +166,6 @@ static int pdigit(const char** fmt, ei_x_buff* x)
break;
}
--(*fmt);
- len = *fmt - start;
if (dotp) {
sscanf(start, "%lf", &d);
return ei_x_encode_double(x, d);
diff --git a/lib/et/src/et_gs_contents_viewer.erl b/lib/et/src/et_gs_contents_viewer.erl
index f6a87bd608..5331c7697a 100644
--- a/lib/et/src/et_gs_contents_viewer.erl
+++ b/lib/et/src/et_gs_contents_viewer.erl
@@ -21,6 +21,17 @@
%%----------------------------------------------------------------------
-module(et_gs_contents_viewer).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,editor,2}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,menu,2}},
+ {nowarn_deprecated_function,{gs,menubar,2}},
+ {nowarn_deprecated_function,{gs,menubutton,2}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,menuitem,3}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-behaviour(gen_server).
diff --git a/lib/et/src/et_gs_viewer.erl b/lib/et/src/et_gs_viewer.erl
index 0af7814d15..4e6f0e3f64 100644
--- a/lib/et/src/et_gs_viewer.erl
+++ b/lib/et/src/et_gs_viewer.erl
@@ -21,6 +21,23 @@
%%----------------------------------------------------------------------
-module(et_gs_viewer).
+-compile([{nowarn_deprecated_function,{gs,canvas,2}},
+ {nowarn_deprecated_function,{gs,checkbutton,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,line,2}},
+ {nowarn_deprecated_function,{gs,menu,2}},
+ {nowarn_deprecated_function,{gs,menu,3}},
+ {nowarn_deprecated_function,{gs,menubar,2}},
+ {nowarn_deprecated_function,{gs,menubutton,2}},
+ {nowarn_deprecated_function,{gs,menubutton,3}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,menuitem,3}},
+ {nowarn_deprecated_function,{gs,scale,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,text,2}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-behaviour(gen_server).
diff --git a/lib/gs/contribs/bonk/bonk.erl b/lib/gs/contribs/bonk/bonk.erl
index 79f01bf659..7e68a4ddc5 100644
--- a/lib/gs/contribs/bonk/bonk.erl
+++ b/lib/gs/contribs/bonk/bonk.erl
@@ -19,6 +19,12 @@
%%
-module(bonk).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
+
-export([run/0, run/1,bonk_dir/0,start/0]).
-record(colors, {miss, x, bomb, face}).
diff --git a/lib/gs/contribs/cols/cols.erl b/lib/gs/contribs/cols/cols.erl
index 111c9a58f1..9c44837f3e 100644
--- a/lib/gs/contribs/cols/cols.erl
+++ b/lib/gs/contribs/cols/cols.erl
@@ -19,6 +19,12 @@
%%
-module(cols).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
-export([start/0, init/0]).
diff --git a/lib/gs/contribs/cols/highscore.erl b/lib/gs/contribs/cols/highscore.erl
index 9ffbea50a7..8f984aaa83 100644
--- a/lib/gs/contribs/cols/highscore.erl
+++ b/lib/gs/contribs/cols/highscore.erl
@@ -19,6 +19,13 @@
%%
-module(highscore).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,grid,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([run/2]).
diff --git a/lib/gs/contribs/mandel/mandel.erl b/lib/gs/contribs/mandel/mandel.erl
index 0f1df5c665..6293f867e2 100644
--- a/lib/gs/contribs/mandel/mandel.erl
+++ b/lib/gs/contribs/mandel/mandel.erl
@@ -18,6 +18,11 @@
%%
-module(mandel).
+-compile([{nowarn_deprecated_function,{gs,assq,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,image,2}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
-author('(mbj,eklas)@erlang.ericsson.se').
%% User's interface
diff --git a/lib/gs/contribs/othello/othello_board.erl b/lib/gs/contribs/othello/othello_board.erl
index 212ba9bfe1..c52211a495 100644
--- a/lib/gs/contribs/othello/othello_board.erl
+++ b/lib/gs/contribs/othello/othello_board.erl
@@ -19,6 +19,12 @@
%%
-module(othello_board).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
+
-export([start/0,stop/0,init/0]).
diff --git a/lib/gs/doc/src/gs.xml b/lib/gs/doc/src/gs.xml
index f2182fc673..c61e8c4938 100644
--- a/lib/gs/doc/src/gs.xml
+++ b/lib/gs/doc/src/gs.xml
@@ -39,9 +39,7 @@
graphical user interface.
</p>
<p>
- GS is not maintained and we plan to deprecate and remove it from
- the distribution as soon as possible, maybe already in the next
- major release (R15).
+ GS is deprecated and will be removed in the R16 release.
</p>
</warning>
<p>The Graphics System, GS, is easy to learn and
diff --git a/lib/gs/examples/ball.erl b/lib/gs/examples/ball.erl
index 3f91a7b379..03fac3b5fc 100644
--- a/lib/gs/examples/ball.erl
+++ b/lib/gs/examples/ball.erl
@@ -24,6 +24,12 @@
%% ------------------------------------------------------------
-module(ball).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,canvas,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,oval,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0,init/0]).
diff --git a/lib/gs/examples/browser.erl b/lib/gs/examples/browser.erl
index 1dba5a915b..0f8b3fc7e6 100644
--- a/lib/gs/examples/browser.erl
+++ b/lib/gs/examples/browser.erl
@@ -23,6 +23,14 @@
%% ------------------------------------------------------------
-module(browser).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,entry,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,listbox,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0,start/2,init/3]).
diff --git a/lib/gs/examples/calc.erl b/lib/gs/examples/calc.erl
index 992b8adb4e..ca29ae1cb9 100644
--- a/lib/gs/examples/calc.erl
+++ b/lib/gs/examples/calc.erl
@@ -23,6 +23,11 @@
%% ------------------------------------------------------------
-module(calc).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0,calc/0]).
diff --git a/lib/gs/examples/calc2.erl b/lib/gs/examples/calc2.erl
index 0e841397f6..83e1870b7a 100644
--- a/lib/gs/examples/calc2.erl
+++ b/lib/gs/examples/calc2.erl
@@ -24,6 +24,12 @@
%% ------------------------------------------------------------
-module(calc2).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
+
-export([start/0,calc/0]).
start() ->
diff --git a/lib/gs/examples/color_demo.erl b/lib/gs/examples/color_demo.erl
index 650f853061..a2f4d0eb87 100644
--- a/lib/gs/examples/color_demo.erl
+++ b/lib/gs/examples/color_demo.erl
@@ -24,6 +24,11 @@
%% ------------------------------------------------------------
-module(color_demo).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,scale,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0,init/0]).
diff --git a/lib/gs/examples/color_demo2.erl b/lib/gs/examples/color_demo2.erl
index 817cc9ed7d..3b0b36221d 100644
--- a/lib/gs/examples/color_demo2.erl
+++ b/lib/gs/examples/color_demo2.erl
@@ -24,6 +24,10 @@
%% ------------------------------------------------------------
-module(color_demo2).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
-export([start/0,init/0]).
diff --git a/lib/gs/examples/distrib_draw.erl b/lib/gs/examples/distrib_draw.erl
index ecb1386c25..8f76bc6650 100644
--- a/lib/gs/examples/distrib_draw.erl
+++ b/lib/gs/examples/distrib_draw.erl
@@ -43,6 +43,11 @@
%%
-module(distrib_draw).
+-compile([{nowarn_deprecated_function,{gs,canvas,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,line,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
-export([start/2,init/0]).
diff --git a/lib/gs/examples/entry_demo.erl b/lib/gs/examples/entry_demo.erl
index a5ecfbc4d3..4bb64e949e 100644
--- a/lib/gs/examples/entry_demo.erl
+++ b/lib/gs/examples/entry_demo.erl
@@ -23,6 +23,12 @@
%% ------------------------------------------------------------
-module(entry_demo).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0,init/1]).
diff --git a/lib/gs/examples/event_test.erl b/lib/gs/examples/event_test.erl
index f6fcc9b4b9..8c0a109df4 100644
--- a/lib/gs/examples/event_test.erl
+++ b/lib/gs/examples/event_test.erl
@@ -21,6 +21,9 @@
%% Demo for testing some events
-module(event_test).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0,init/0]).
diff --git a/lib/gs/examples/file_dialog.erl b/lib/gs/examples/file_dialog.erl
index ff20321374..c1ef6ed8b1 100644
--- a/lib/gs/examples/file_dialog.erl
+++ b/lib/gs/examples/file_dialog.erl
@@ -23,6 +23,11 @@
%% ------------------------------------------------------------
-module(file_dialog).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
-export([start/0,start/1,start/2,fs_init/3]).
diff --git a/lib/gs/examples/focus_demo.erl b/lib/gs/examples/focus_demo.erl
index b9d86866e6..71ca9c6ff5 100644
--- a/lib/gs/examples/focus_demo.erl
+++ b/lib/gs/examples/focus_demo.erl
@@ -23,6 +23,11 @@
%% ------------------------------------------------------------
-module(focus_demo).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0,init/0]).
diff --git a/lib/gs/examples/frac.erl b/lib/gs/examples/frac.erl
index 139a4be310..46af83de8a 100644
--- a/lib/gs/examples/frac.erl
+++ b/lib/gs/examples/frac.erl
@@ -21,6 +21,9 @@
%% Purpose : Fractal trees
-module(frac).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
-export([start/0, go/0, test/0, grow/2, expand/3, subst/2]).
diff --git a/lib/gs/examples/line_demo.erl b/lib/gs/examples/line_demo.erl
index c8a6a69e2e..ba88605118 100644
--- a/lib/gs/examples/line_demo.erl
+++ b/lib/gs/examples/line_demo.erl
@@ -24,6 +24,12 @@
%% ------------------------------------------------------------
-module(line_demo).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,canvas,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,line,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0,init/0,line/3]).
diff --git a/lib/gs/examples/man.erl b/lib/gs/examples/man.erl
index a0ffd3364e..bddd6930ab 100644
--- a/lib/gs/examples/man.erl
+++ b/lib/gs/examples/man.erl
@@ -23,6 +23,15 @@
%% ------------------------------------------------------------
-module(man).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,entry,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,listbox,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
-export([start/0,init/0]).
-export([man_list/0]).
diff --git a/lib/gs/examples/menu_demo.erl b/lib/gs/examples/menu_demo.erl
index c95fc33152..6b2fc4113a 100644
--- a/lib/gs/examples/menu_demo.erl
+++ b/lib/gs/examples/menu_demo.erl
@@ -19,6 +19,12 @@
%%
-module(menu_demo).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-compile(export_all).
diff --git a/lib/gs/examples/rubber.erl b/lib/gs/examples/rubber.erl
index ba263f07ac..da4aa57391 100644
--- a/lib/gs/examples/rubber.erl
+++ b/lib/gs/examples/rubber.erl
@@ -23,6 +23,14 @@
%% ------------------------------------------------------------
-module(rubber).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,canvas,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,radiobutton,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/0, init/0]).
diff --git a/lib/gs/src/gs.erl b/lib/gs/src/gs.erl
index 3e9a1c4b8b..92dce12580 100644
--- a/lib/gs/src/gs.erl
+++ b/lib/gs/src/gs.erl
@@ -24,7 +24,13 @@
%%
-module(gs).
-
+-deprecated(module).
+-compile([{nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,create_tree,2}},
+ {nowarn_deprecated_function,{gs,foreach,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,1}}]).
%% ----- Exports -----
-export([start/0, stop/0, start/1]).
diff --git a/lib/gs/src/gs_frontend.erl b/lib/gs/src/gs_frontend.erl
index 009b264e69..73954baa8d 100644
--- a/lib/gs/src/gs_frontend.erl
+++ b/lib/gs/src/gs_frontend.erl
@@ -24,6 +24,8 @@
%%
-module(gs_frontend).
+-compile([{nowarn_deprecated_function,{gs,assq,2}},
+ {nowarn_deprecated_function,{gs,error,2}}]).
-export([create/2,
config/2,
diff --git a/lib/gs/src/gs_make.erl b/lib/gs/src/gs_make.erl
index e41183f9bf..bf8a66001f 100644
--- a/lib/gs/src/gs_make.erl
+++ b/lib/gs/src/gs_make.erl
@@ -19,6 +19,7 @@
%%
-module(gs_make).
+-compile([{nowarn_deprecated_function,{gs,assq,2}}]).
-export([start/0]).
diff --git a/lib/gs/src/gse.erl b/lib/gs/src/gse.erl
index b3ea2af4d4..c62badcc27 100644
--- a/lib/gs/src/gse.erl
+++ b/lib/gs/src/gse.erl
@@ -23,6 +23,68 @@
%%%----------------------------------------------------------------------
-module(gse).
+-compile([{nowarn_deprecated_function,{gs,arc,2}},
+ {nowarn_deprecated_function,{gs,arc,3}},
+ {nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,button,3}},
+ {nowarn_deprecated_function,{gs,canvas,2}},
+ {nowarn_deprecated_function,{gs,canvas,3}},
+ {nowarn_deprecated_function,{gs,checkbutton,2}},
+ {nowarn_deprecated_function,{gs,checkbutton,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,create_tree,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,editor,2}},
+ {nowarn_deprecated_function,{gs,editor,3}},
+ {nowarn_deprecated_function,{gs,entry,2}},
+ {nowarn_deprecated_function,{gs,entry,3}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,frame,3}},
+ {nowarn_deprecated_function,{gs,grid,2}},
+ {nowarn_deprecated_function,{gs,grid,3}},
+ {nowarn_deprecated_function,{gs,gridline,2}},
+ {nowarn_deprecated_function,{gs,gridline,3}},
+ {nowarn_deprecated_function,{gs,image,2}},
+ {nowarn_deprecated_function,{gs,image,3}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,label,3}},
+ {nowarn_deprecated_function,{gs,line,2}},
+ {nowarn_deprecated_function,{gs,line,3}},
+ {nowarn_deprecated_function,{gs,listbox,2}},
+ {nowarn_deprecated_function,{gs,listbox,3}},
+ {nowarn_deprecated_function,{gs,menu,2}},
+ {nowarn_deprecated_function,{gs,menu,3}},
+ {nowarn_deprecated_function,{gs,menubar,2}},
+ {nowarn_deprecated_function,{gs,menubar,3}},
+ {nowarn_deprecated_function,{gs,menubutton,2}},
+ {nowarn_deprecated_function,{gs,menubutton,3}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,menuitem,3}},
+ {nowarn_deprecated_function,{gs,message,2}},
+ {nowarn_deprecated_function,{gs,message,3}},
+ {nowarn_deprecated_function,{gs,oval,2}},
+ {nowarn_deprecated_function,{gs,oval,3}},
+ {nowarn_deprecated_function,{gs,polygon,2}},
+ {nowarn_deprecated_function,{gs,polygon,3}},
+ {nowarn_deprecated_function,{gs,prompter,2}},
+ {nowarn_deprecated_function,{gs,prompter,3}},
+ {nowarn_deprecated_function,{gs,radiobutton,2}},
+ {nowarn_deprecated_function,{gs,radiobutton,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,rectangle,2}},
+ {nowarn_deprecated_function,{gs,rectangle,3}},
+ {nowarn_deprecated_function,{gs,scale,2}},
+ {nowarn_deprecated_function,{gs,scale,3}},
+ {nowarn_deprecated_function,{gs,scrollbar,2}},
+ {nowarn_deprecated_function,{gs,scrollbar,3}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,start,1}},
+ {nowarn_deprecated_function,{gs,text,2}},
+ {nowarn_deprecated_function,{gs,text,3}},
+ {nowarn_deprecated_function,{gs,window,2}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
%%-compile(export_all).
-export([
diff --git a/lib/gs/src/gstk.erl b/lib/gs/src/gstk.erl
index 6f83cf8be4..ee974a5f63 100644
--- a/lib/gs/src/gstk.erl
+++ b/lib/gs/src/gstk.erl
@@ -20,6 +20,8 @@
%%
-module(gstk).
+-compile([{nowarn_deprecated_function,{gs,assq,2}},
+ {nowarn_deprecated_function,{gs,creation_error,2}}]).
-export([start_link/4,
stop/1,
diff --git a/lib/gs/src/gstk_arc.erl b/lib/gs/src/gstk_arc.erl
index 8e80ef92b5..3c6fe54d36 100644
--- a/lib/gs/src/gstk_arc.erl
+++ b/lib/gs/src/gstk_arc.erl
@@ -23,6 +23,7 @@
%% ------------------------------------------------------------
-module(gstk_arc).
+-compile([{nowarn_deprecated_function,{gs,creation_error,2}}]).
%%-----------------------------------------------------------------------------
%% ARC OPTIONS
diff --git a/lib/gs/src/gstk_canvas.erl b/lib/gs/src/gstk_canvas.erl
index 868b3020fe..5d15529995 100644
--- a/lib/gs/src/gstk_canvas.erl
+++ b/lib/gs/src/gstk_canvas.erl
@@ -23,6 +23,8 @@
%% ------------------------------------------------------------
-module(gstk_canvas).
+-compile([{nowarn_deprecated_function,{gs,pair,2}},
+ {nowarn_deprecated_function,{gs,val,2}}]).
%%-----------------------------------------------------------------------------
%% CANVAS OPTIONS
diff --git a/lib/gs/src/gstk_editor.erl b/lib/gs/src/gstk_editor.erl
index 6b90cee1d2..2686997036 100644
--- a/lib/gs/src/gstk_editor.erl
+++ b/lib/gs/src/gstk_editor.erl
@@ -23,6 +23,9 @@
%% ------------------------------------------------------------
-module(gstk_editor).
+-compile([{nowarn_deprecated_function,{gs,assq,2}},
+ {nowarn_deprecated_function,{gs,error,2}},
+ {nowarn_deprecated_function,{gs,val,2}}]).
%%------------------------------------------------------------------------------
%% CANVAS OPTIONS
diff --git a/lib/gs/src/gstk_entry.erl b/lib/gs/src/gstk_entry.erl
index 14f7831151..432ccd5fde 100644
--- a/lib/gs/src/gstk_entry.erl
+++ b/lib/gs/src/gstk_entry.erl
@@ -23,6 +23,7 @@
%% ------------------------------------------------------------
-module(gstk_entry).
+-compile([{nowarn_deprecated_function,{gs,error,2}}]).
%%------------------------------------------------------------------------------
%% ENTRY OPTIONS
diff --git a/lib/gs/src/gstk_generic.erl b/lib/gs/src/gstk_generic.erl
index 8fe19b428c..50c3da8dc5 100644
--- a/lib/gs/src/gstk_generic.erl
+++ b/lib/gs/src/gstk_generic.erl
@@ -20,6 +20,7 @@
%%
-module(gstk_generic).
+-compile([{nowarn_deprecated_function,{gs,assq,2}}]).
-export([out_opts/8,
read_option/5,
diff --git a/lib/gs/src/gstk_grid.erl b/lib/gs/src/gstk_grid.erl
index 4189246822..f703dad074 100644
--- a/lib/gs/src/gstk_grid.erl
+++ b/lib/gs/src/gstk_grid.erl
@@ -19,6 +19,7 @@
%%
-module(gstk_grid).
+-compile([{nowarn_deprecated_function,{gs,val,2}}]).
-export([event/5,create/3,config/3,option/5,read/3,delete/2,destroy/2,
mk_create_opts_for_child/4,read_option/5]).
diff --git a/lib/gs/src/gstk_gridline.erl b/lib/gs/src/gstk_gridline.erl
index c1dd5a1443..4585c7e043 100644
--- a/lib/gs/src/gstk_gridline.erl
+++ b/lib/gs/src/gstk_gridline.erl
@@ -19,6 +19,8 @@
%%
-module(gstk_gridline).
+-compile([{nowarn_deprecated_function,{gs,val,2}},
+ {nowarn_deprecated_function,{gs,val,3}}]).
-export([event/5,create/3,config/3,option/5,read/3,delete/2,destroy/3,
read_option/5]).
diff --git a/lib/gs/src/gstk_image.erl b/lib/gs/src/gstk_image.erl
index 53789b312d..2b7a324e28 100644
--- a/lib/gs/src/gstk_image.erl
+++ b/lib/gs/src/gstk_image.erl
@@ -23,6 +23,7 @@
%% ------------------------------------------------------------
-module(gstk_image).
+-compile([{nowarn_deprecated_function,{gs,pair,2}}]).
%%-----------------------------------------------------------------------------
%% BITMAP OPTIONS
diff --git a/lib/gs/src/gstk_menu.erl b/lib/gs/src/gstk_menu.erl
index 3957951a35..e878669de6 100644
--- a/lib/gs/src/gstk_menu.erl
+++ b/lib/gs/src/gstk_menu.erl
@@ -23,6 +23,7 @@
%%------------------------------------------------------------------------------
-module(gstk_menu).
+-compile([{nowarn_deprecated_function,{gs,error,2}}]).
%%------------------------------------------------------------------------------
%% MENU OPTIONS
diff --git a/lib/gs/src/gstk_menuitem.erl b/lib/gs/src/gstk_menuitem.erl
index 36a9253598..8abf5d13aa 100644
--- a/lib/gs/src/gstk_menuitem.erl
+++ b/lib/gs/src/gstk_menuitem.erl
@@ -23,6 +23,7 @@
%% ------------------------------------------------------------
-module(gstk_menuitem).
+-compile([{nowarn_deprecated_function,{gs,error,2}}]).
%%-----------------------------------------------------------------------------
%% MENUITEM OPTIONS
diff --git a/lib/gs/src/gstk_port_handler.erl b/lib/gs/src/gstk_port_handler.erl
index 93f3e58dc2..c6ca2c0f5b 100644
--- a/lib/gs/src/gstk_port_handler.erl
+++ b/lib/gs/src/gstk_port_handler.erl
@@ -34,6 +34,7 @@
%% ------------------------------------------------------------
-module(gstk_port_handler).
+-compile([{nowarn_deprecated_function,{gs,error,2}}]).
-include("gstk.hrl").
diff --git a/lib/gs/src/gstk_rectangle.erl b/lib/gs/src/gstk_rectangle.erl
index 1e02977c9a..14be16c990 100644
--- a/lib/gs/src/gstk_rectangle.erl
+++ b/lib/gs/src/gstk_rectangle.erl
@@ -23,6 +23,7 @@
%% ------------------------------------------------------------
-module(gstk_rectangle).
+-compile([{nowarn_deprecated_function,{gs,pair,2}}]).
%%-----------------------------------------------------------------------------
%% RECTANGLE OPTIONS
diff --git a/lib/gs/src/gstk_window.erl b/lib/gs/src/gstk_window.erl
index acac452ed1..4b4706eb88 100644
--- a/lib/gs/src/gstk_window.erl
+++ b/lib/gs/src/gstk_window.erl
@@ -23,6 +23,7 @@
%% ------------------------------------------------------------
-module(gstk_window).
+-compile([{nowarn_deprecated_function,{gs,destroy,1}}]).
%%------------------------------------------------------------------------------
%% WINDOW OPTIONS
diff --git a/lib/gs/src/tcl2erl.erl b/lib/gs/src/tcl2erl.erl
index 8845cf0b9a..d159681c5c 100644
--- a/lib/gs/src/tcl2erl.erl
+++ b/lib/gs/src/tcl2erl.erl
@@ -25,6 +25,7 @@
%% ------------------------------------------------------------
-module(tcl2erl).
+-compile([{nowarn_deprecated_function,{gs,error,2}}]).
-export([parse_event/1,
ret_int/1,
diff --git a/lib/gs/src/tool_file_dialog.erl b/lib/gs/src/tool_file_dialog.erl
index 6b2c2e8c81..cfcfcd1bf6 100644
--- a/lib/gs/src/tool_file_dialog.erl
+++ b/lib/gs/src/tool_file_dialog.erl
@@ -19,6 +19,16 @@
%%
-module(tool_file_dialog).
+-compile([{nowarn_deprecated_function,{gs,button,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,entry,3}},
+ {nowarn_deprecated_function,{gs,frame,3}},
+ {nowarn_deprecated_function,{gs,label,3}},
+ {nowarn_deprecated_function,{gs,listbox,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
+
-export([start/1]).
-record(opts, {type, % open | save | multiselect
diff --git a/lib/gs/src/tool_utils.erl b/lib/gs/src/tool_utils.erl
index f1b93c1af8..69919b18bd 100644
--- a/lib/gs/src/tool_utils.erl
+++ b/lib/gs/src/tool_utils.erl
@@ -19,6 +19,11 @@
%%
-module(tool_utils).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}}]).
+
-include_lib("kernel/include/file.hrl").
%%%---------------------------------------------------------------------
diff --git a/lib/hipe/cerl/cerl_hipe_primops.hrl b/lib/hipe/cerl/cerl_hipe_primops.hrl
index 36b1b62901..1d82f7bfc7 100644
--- a/lib/hipe/cerl/cerl_hipe_primops.hrl
+++ b/lib/hipe/cerl/cerl_hipe_primops.hrl
@@ -59,7 +59,6 @@
-define(PRIMOP_IS_ATOM, 'is_atom'). % arity 1
-define(PRIMOP_IS_BIGNUM, 'is_bignum'). % arity 1
-define(PRIMOP_IS_BINARY, 'is_binary'). % arity 1
--define(PRIMOP_IS_CONSTANT, 'is_constant'). % arity 1
-define(PRIMOP_IS_FIXNUM, 'is_fixnum'). % arity 1
-define(PRIMOP_IS_FLOAT, 'is_float'). % arity 1
-define(PRIMOP_IS_FUNCTION, 'is_function'). % arity 1
diff --git a/lib/hipe/cerl/cerl_hipeify.erl b/lib/hipe/cerl/cerl_hipeify.erl
index 8f6c3561c9..89b4ec147d 100644
--- a/lib/hipe/cerl/cerl_hipeify.erl
+++ b/lib/hipe/cerl/cerl_hipeify.erl
@@ -392,7 +392,6 @@ call_to_primop(erlang, '=<', 2) -> {yes, ?PRIMOP_LE};
call_to_primop(erlang, '>=', 2) -> {yes, ?PRIMOP_GE};
call_to_primop(erlang, is_atom, 1) -> {yes, ?PRIMOP_IS_ATOM};
call_to_primop(erlang, is_binary, 1) -> {yes, ?PRIMOP_IS_BINARY};
-call_to_primop(erlang, is_constant, 1) -> {yes, ?PRIMOP_IS_CONSTANT};
call_to_primop(erlang, is_float, 1) -> {yes, ?PRIMOP_IS_FLOAT};
call_to_primop(erlang, is_function, 1) -> {yes, ?PRIMOP_IS_FUNCTION};
call_to_primop(erlang, is_integer, 1) -> {yes, ?PRIMOP_IS_INTEGER};
diff --git a/lib/hipe/cerl/cerl_messagean.erl b/lib/hipe/cerl/cerl_messagean.erl
index 6dd93adaa3..b9f82f2a43 100644
--- a/lib/hipe/cerl/cerl_messagean.erl
+++ b/lib/hipe/cerl/cerl_messagean.erl
@@ -1083,7 +1083,6 @@ is_imm_op(erlang, is_alive, 0) -> true;
is_imm_op(erlang, is_atom, 1) -> true;
is_imm_op(erlang, is_binary, 1) -> true;
is_imm_op(erlang, is_builtin, 3) -> true;
-is_imm_op(erlang, is_constant, 1) -> true;
is_imm_op(erlang, is_float, 1) -> true;
is_imm_op(erlang, is_function, 1) -> true;
is_imm_op(erlang, is_integer, 1) -> true;
diff --git a/lib/hipe/cerl/cerl_to_icode.erl b/lib/hipe/cerl/cerl_to_icode.erl
index 362c427cbe..089e3f021e 100644
--- a/lib/hipe/cerl/cerl_to_icode.erl
+++ b/lib/hipe/cerl/cerl_to_icode.erl
@@ -88,7 +88,6 @@
-define(TYPE_IS_ATOM, atom).
-define(TYPE_IS_BIGNUM, bignum).
-define(TYPE_IS_BINARY, binary).
--define(TYPE_IS_CONSTANT, constant).
-define(TYPE_IS_FIXNUM, fixnum).
-define(TYPE_IS_FLOAT, float).
-define(TYPE_IS_FUNCTION, function).
@@ -2051,7 +2050,6 @@ is_record_test(T, A, N, True, False, Ctxt, Env, S) ->
type_test(?PRIMOP_IS_ATOM) -> ?TYPE_IS_ATOM;
type_test(?PRIMOP_IS_BIGNUM) -> ?TYPE_IS_BIGNUM;
type_test(?PRIMOP_IS_BINARY) -> ?TYPE_IS_BINARY;
-type_test(?PRIMOP_IS_CONSTANT) -> ?TYPE_IS_CONSTANT;
type_test(?PRIMOP_IS_FIXNUM) -> ?TYPE_IS_FIXNUM;
type_test(?PRIMOP_IS_FLOAT) -> ?TYPE_IS_FLOAT;
type_test(?PRIMOP_IS_FUNCTION) -> ?TYPE_IS_FUNCTION;
@@ -2082,7 +2080,6 @@ is_bool_op(Op, A) when is_atom(Op), is_integer(A) -> false.
is_type_test(?PRIMOP_IS_ATOM, 1) -> true;
is_type_test(?PRIMOP_IS_BIGNUM, 1) -> true;
is_type_test(?PRIMOP_IS_BINARY, 1) -> true;
-is_type_test(?PRIMOP_IS_CONSTANT, 1) -> true;
is_type_test(?PRIMOP_IS_FIXNUM, 1) -> true;
is_type_test(?PRIMOP_IS_FLOAT, 1) -> true;
is_type_test(?PRIMOP_IS_FUNCTION, 1) -> true;
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index cee399e861..845df0ca61 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -54,7 +54,6 @@
t_cons/2,
t_cons_hd/1,
t_cons_tl/1,
- t_constant/0,
t_fixnum/0,
t_non_neg_fixnum/0,
t_pos_fixnum/0,
@@ -81,7 +80,6 @@
t_is_bitstr/1,
t_is_boolean/1,
t_is_cons/1,
- t_is_constant/1,
t_is_float/1,
t_is_float/1,
t_is_fun/1,
@@ -845,11 +843,6 @@ type(erlang, is_boolean, 1, Xs) ->
strict(arg_types(erlang, is_boolean, 1), Xs, Fun);
type(erlang, is_builtin, 3, Xs) ->
strict(arg_types(erlang, is_builtin, 3), Xs, fun (_) -> t_boolean() end);
-type(erlang, is_constant, 1, Xs) ->
- Fun = fun (X) ->
- check_guard(X, fun (Y) -> t_is_constant(Y) end, t_constant())
- end,
- strict(arg_types(erlang, is_constant, 1), Xs, Fun);
type(erlang, is_float, 1, Xs) ->
Fun = fun (X) ->
check_guard(X, fun (Y) -> t_is_float(Y) end, t_float())
@@ -1202,11 +1195,13 @@ type(erlang, process_flag, 2, Xs) ->
case t_atom_vals(Flag) of
['error_handler'] -> t_atom();
['min_heap_size'] -> t_non_neg_integer();
+ ['min_bin_vheap_size'] -> t_non_neg_integer();
['scheduler'] -> t_non_neg_integer();
['monitor_nodes'] -> t_boolean();
['priority'] -> t_process_priority_level();
['save_calls'] -> t_non_neg_integer();
['trap_exit'] -> t_boolean();
+ ['sensitive'] -> t_boolean();
List when is_list(List) ->
T_process_flag_returns;
unknown ->
@@ -1503,6 +1498,8 @@ type(erlang, system_flag, 2, Xs) ->
t_non_neg_fixnum();
['min_heap_size'] ->
t_non_neg_fixnum();
+ ['min_bin_vheap_size'] ->
+ t_non_neg_fixnum();
['multi_scheduling'] ->
t_system_multi_scheduling();
['schedulers_online'] ->
@@ -1546,8 +1543,12 @@ type(erlang, system_info, 1, Xs) ->
t_list(t_tuple([t_atom(),
t_list(t_tuple([t_atom(),
t_any()]))]))]);
+ ['build_type'] ->
+ t_system_build_type_return();
['break_ignored'] ->
t_boolean();
+ ['c_compiler_used'] ->
+ t_tuple([t_atom(), t_any()]);
['cpu_topology'] ->
t_system_cpu_topology();
['compat_rel'] ->
@@ -1560,6 +1561,8 @@ type(erlang, system_info, 1, Xs) ->
t_binary();
['dist_ctrl'] ->
t_list(t_tuple([t_atom(), t_sup([t_pid(), t_port])]));
+ ['driver_version'] ->
+ t_string();
%% elib_malloc is intentionally not included,
%% because it scheduled for removal in R15.
['endian'] ->
@@ -1573,7 +1576,9 @@ type(erlang, system_info, 1, Xs) ->
['heap_sizes'] ->
t_list(t_integer());
['heap_type'] ->
- t_sup([t_atom('private'), t_atom('hybrid')]);
+ t_sup([t_atom('private'),
+ t_atom('shared'),
+ t_atom('hybrid')]);
['hipe_architecture'] ->
t_atoms(['amd64', 'arm', 'powerpc', 'ppc64',
'undefined', 'ultrasparc', 'x86']);
@@ -1581,12 +1586,20 @@ type(erlang, system_info, 1, Xs) ->
t_binary();
['internal_cpu_topology'] -> %% Undocumented internal feature
t_internal_cpu_topology();
+ ['kernel_poll'] ->
+ t_boolean();
['loaded'] ->
t_binary();
['logical_processors'] ->
t_non_neg_fixnum();
['machine'] ->
t_string();
+ ['min_heap_size'] ->
+ t_tuple([t_atom('min_heap_size'),
+ t_non_neg_integer()]);
+ ['min_bin_vheap_size'] ->
+ t_tuple([t_atom('min_bin_vheap_size'),
+ t_non_neg_integer()]);
['multi_scheduling'] ->
t_system_multi_scheduling();
['multi_scheduling_blockers'] ->
@@ -1601,6 +1614,8 @@ type(erlang, system_info, 1, Xs) ->
t_non_neg_fixnum(),
t_non_neg_fixnum()]),
t_string());
+ ['otp_release'] ->
+ t_string();
['process_count'] ->
t_non_neg_fixnum();
['process_limit'] ->
@@ -1630,6 +1645,8 @@ type(erlang, system_info, 1, Xs) ->
t_non_neg_fixnum();
['trace_control_word'] ->
t_integer();
+ ['update_cpu_info'] ->
+ t_sup([t_atom('changed'), t_atom('unchanged')]);
['version'] ->
t_string();
['wordsize'] ->
@@ -3567,8 +3584,6 @@ arg_types(erlang, is_boolean, 1) ->
[t_any()];
arg_types(erlang, is_builtin, 3) ->
[t_atom(), t_atom(), t_arity()];
-arg_types(erlang, is_constant, 1) ->
- [t_any()];
arg_types(erlang, is_float, 1) ->
[t_any()];
arg_types(erlang, is_function, 1) ->
@@ -3747,8 +3762,13 @@ arg_types(erlang, pre_loaded, 0) ->
arg_types(erlang, process_display, 2) ->
[t_pid(), t_atom('backtrace')];
arg_types(erlang, process_flag, 2) ->
- [t_sup([t_atom('trap_exit'), t_atom('error_handler'),
- t_atom('min_heap_size'), t_atom('priority'), t_atom('save_calls'),
+ [t_sup([t_atom('trap_exit'),
+ t_atom('error_handler'),
+ t_atom('min_heap_size'),
+ t_atom('min_bin_vheap_size'),
+ t_atom('priority'),
+ t_atom('save_calls'),
+ t_atom('sensitive'),
t_atom('scheduler'), % undocumented
t_atom('monitor_nodes'), % undocumented
t_tuple([t_atom('monitor_nodes'), t_list()])]), % undocumented
@@ -3861,6 +3881,7 @@ arg_types(erlang, system_flag, 2) ->
t_atom('display_items'), % undocumented
t_atom('fullsweep_after'),
t_atom('min_heap_size'),
+ t_atom('min_bin_vheap_size'),
t_atom('multi_scheduling'),
t_atom('schedulers_online'),
t_atom('scheduler_bind_type'),
@@ -4733,6 +4754,7 @@ t_spawn_options() ->
t_atom('monitor'),
t_tuple([t_atom('priority'), t_process_priority_level()]),
t_tuple([t_atom('min_heap_size'), t_fixnum()]),
+ t_tuple([t_atom('min_bin_vheap_size'), t_fixnum()]),
t_tuple([t_atom('fullsweep_after'), t_fixnum()])]).
t_spawn_opt_return(List) ->
@@ -4821,6 +4843,17 @@ t_system_profile_return() ->
t_sup(t_atom('undefined'),
t_tuple([t_sup(t_pid(), t_port()), t_system_profile_options()])).
+t_system_build_type_return() ->
+ t_sup([t_atom('opt'),
+ t_atom('debug'),
+ t_atom('purify'),
+ t_atom('quantify'),
+ t_atom('purecov'),
+ t_atom('gcov'),
+ t_atom('valgrind'),
+ t_atom('gprof'),
+ t_atom('lcnt')]).
+
%% =====================================================================
%% These are used for the built-in functions of 'ets'
%% =====================================================================
diff --git a/lib/hipe/flow/Makefile b/lib/hipe/flow/Makefile
index 02f610587b..bbe8ef8666 100644
--- a/lib/hipe/flow/Makefile
+++ b/lib/hipe/flow/Makefile
@@ -65,7 +65,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec # +warn_untyped_record
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/icode/Makefile b/lib/hipe/icode/Makefile
index eced90b0ec..bd6436c8b3 100644
--- a/lib/hipe/icode/Makefile
+++ b/lib/hipe/icode/Makefile
@@ -83,7 +83,7 @@ DOC_FILES= $(DOC_MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec # +warn_untyped_record
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 992f387bd5..2d2b414a70 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -465,10 +465,6 @@ trans_fun([{test,is_nil,{f,Lbl},[Arg]}|Instructions], Env) ->
trans_fun([{test,is_binary,{f,Lbl},[Arg]}|Instructions], Env) ->
{Code,Env1} = trans_type_test(binary,Lbl,Arg,Env),
[Code | trans_fun(Instructions,Env1)];
-%%--- is_constant ---
-trans_fun([{test,is_constant,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(constant,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
%%--- is_list ---
trans_fun([{test,is_list,{f,Lbl},[Arg]}|Instructions], Env) ->
{Code,Env1} = trans_type_test(list,Lbl,Arg,Env),
diff --git a/lib/hipe/icode/hipe_icode_inline_bifs.erl b/lib/hipe/icode/hipe_icode_inline_bifs.erl
index 27296dcad5..9a2fb7846a 100644
--- a/lib/hipe/icode/hipe_icode_inline_bifs.erl
+++ b/lib/hipe/icode/hipe_icode_inline_bifs.erl
@@ -29,7 +29,7 @@
%% Currently inlined BIFs:
%% and, or, xor, not, <, >, >=, =<, ==, /=, =/=, =:=
-%% is_atom, is_boolean, is_binary, is_constant, is_float, is_function,
+%% is_atom, is_boolean, is_binary, is_float, is_function,
%% is_integer, is_list, is_pid, is_port, is_reference, is_tuple
-module(hipe_icode_inline_bifs).
@@ -131,7 +131,6 @@ is_type_test(Name) ->
is_boolean -> {true, boolean};
is_function -> {true, function};
is_reference -> {true, reference};
- is_constant -> {true, constant};
is_port -> {true, port};
_ -> false
end.
diff --git a/lib/hipe/icode/hipe_icode_type.erl b/lib/hipe/icode/hipe_icode_type.erl
index 3f9488d7c3..cae4325b9e 100644
--- a/lib/hipe/icode/hipe_icode_type.erl
+++ b/lib/hipe/icode/hipe_icode_type.erl
@@ -899,9 +899,7 @@ test_type0(list, T) ->
test_type0(cons, T) ->
t_is_cons(T);
test_type0(nil, T) ->
- t_is_nil(T);
-test_type0(constant, T) ->
- t_is_constant(T).
+ t_is_nil(T).
true_branch_info(integer) ->
@@ -940,8 +938,6 @@ true_branch_info(nil) ->
t_nil();
true_branch_info(boolean) ->
t_boolean();
-true_branch_info(constant) ->
- t_constant();
true_branch_info(T) ->
exit({?MODULE,unknown_typetest,T}).
diff --git a/lib/hipe/opt/Makefile b/lib/hipe/opt/Makefile
index 74fde26c0b..4596201801 100644
--- a/lib/hipe/opt/Makefile
+++ b/lib/hipe/opt/Makefile
@@ -63,7 +63,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec # +warn_untyped_record
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index 690045b978..48086ec79f 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -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
@@ -139,27 +139,35 @@ hipe_literals.hrl: $(HIPE_MKLITERALS)
../main/hipe.hrl: ../vsn.mk ../main/hipe.hrl.src
(cd ../main && $(MAKE) hipe.hrl)
-$(EBIN)/hipe_rtl.beam: hipe_rtl.hrl ../main/hipe.hrl
-$(EBIN)/hipe_rtl_arch.beam: hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_binary.beam: hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_bin_util.beam: hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_cfg.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc ../main/hipe.hrl
-$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl
-$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc
-$(EBIN)/hipe_icode2rtl.beam: hipe_literals.hrl ../main/hipe.hrl ../icode/hipe_icode.hrl
-$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_primops.beam: hipe_rtl.hrl ../icode/hipe_icode_primops.hrl hipe_literals.hrl ../main/hipe.hrl
+# 2012-02-24. Please keep these dependencies up to date. They tend to rot.
+# grep ^-include *.erl says a lot, but you need to dig further, e.g:
+# grep ^-include ../flow/*.{hrl,inc}
+$(EBIN)/hipe_icode2rtl.beam: \
+ ../main/hipe.hrl ../icode/hipe_icode.hrl hipe_literals.hrl
+$(EBIN)/hipe_rtl_arch.beam: hipe_literals.hrl
$(EBIN)/hipe_rtl_arith_32.beam: ../main/hipe.hrl hipe_rtl_arith.inc
$(EBIN)/hipe_rtl_arith_64.beam: ../main/hipe.hrl hipe_rtl_arith.inc
-$(EBIN)/hipe_rtl_bs_ops.beam: hipe_literals.hrl ../main/hipe.hrl
-$(EBIN)/hipe_rtl_cerl_bs_ops.beam: ../main/hipe.hrl hipe_literals.hrl hipe_rtl.hrl
-$(EBIN)/hipe_rtl_exceptions.beam: hipe_literals.hrl ../main/hipe.hrl
-$(EBIN)/hipe_rtl_inline_bs_ops.beam: hipe_rtl.hrl hipe_literals.hrl ../main/hipe.hrl
+$(EBIN)/hipe_rtl_binary_construct.beam: \
+ ../main/hipe.hrl hipe_rtl.hrl hipe_literals.hrl
+$(EBIN)/hipe_rtl_binary_match.beam: hipe_literals.hrl
+$(EBIN)/hipe_rtl_cfg.beam: \
+ ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc
+$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl
+$(EBIN)/hipe_rtl.beam: ../main/hipe.hrl hipe_rtl.hrl
+$(EBIN)/hipe_rtl_exceptions.beam: ../main/hipe.hrl hipe_literals.hrl
+$(EBIN)/hipe_rtl_lcm.beam: ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl
+$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc
$(EBIN)/hipe_rtl_mk_switch.beam: ../main/hipe.hrl
-$(EBIN)/hipe_rtl_lcm.beam: ../flow/cfg.hrl hipe_rtl.hrl
-$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl ../flow/cfg.hrl ../icode/hipe_icode_primops.hrl
-$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl ../icode/hipe_icode.hrl
-
-$(EBIN)/hipe_rtl_ssa.beam: ../ssa/hipe_ssa.inc ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc hipe_rtl.hrl
-$(EBIN)/hipe_rtl_ssa_const_prop.beam: hipe_rtl.hrl ../main/hipe.hrl ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc
-$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl ../flow/cfg.hrl hipe_rtl.hrl
+$(EBIN)/hipe_rtl_primops.beam: ../main/hipe.hrl \
+ ../icode/hipe_icode_primops.hrl hipe_rtl.hrl hipe_literals.hrl
+$(EBIN)/hipe_rtl_ssa_avail_expr.beam: ../main/hipe.hrl hipe_rtl.hrl
+$(EBIN)/hipe_rtl_ssa_const_prop.beam: ../main/hipe.hrl hipe_rtl.hrl \
+ ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc
+$(EBIN)/hipe_rtl_ssa.beam: hipe_rtl.hrl \
+ ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc ../ssa/hipe_ssa.inc
+$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl hipe_rtl.hrl
+$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl \
+ ../icode/hipe_icode_primops.hrl
+$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl \
+ ../misc/hipe_consttab.hrl ../icode/hipe_icode.hrl
+$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl
diff --git a/lib/hipe/tools/hipe_tool.erl b/lib/hipe/tools/hipe_tool.erl
index 990805ceca..190a68ee56 100644
--- a/lib/hipe/tools/hipe_tool.erl
+++ b/lib/hipe/tools/hipe_tool.erl
@@ -30,6 +30,18 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-module(hipe_tool).
+-compile([{nowarn_deprecated_function,{gs,button,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,editor,3}},
+ {nowarn_deprecated_function,{gs,label,3}},
+ {nowarn_deprecated_function,{gs,listbox,3}},
+ {nowarn_deprecated_function,{gs,menu,3}},
+ {nowarn_deprecated_function,{gs,menubar,3}},
+ {nowarn_deprecated_function,{gs,menubutton,3}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
-export([start/0]).
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 369762d0c6..cfc58b8ddb 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2011</year>
+ <year>2002</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,58 @@
<file>notes.xml</file>
</header>
+
+ <section><title>Inets 5.8.1</title>
+ <section><title>Improvements and New Features</title>
+ <p>-</p>
+
+<!--
+ <list>
+ <item>
+ <p>[httpc|httpd] Added support for IPv6 with ssl. </p>
+ <p>Own Id: OTP-5566</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>[ftp] Fails to open IPv6 connection due to badly formatted
+ IPv6 address in EPRT command. The address part of the command
+ incorrectly contained decimal elements instead of hexadecimal. </p>
+ <p>Own Id: OTP-9827</p>
+ <p>Aux Id: Seq 11970 </p>
+ </item>
+
+ <item>
+ <p>[httpc] Bad Keep Alive Mode. When selecting a session,
+ the "state" of the session (specifically if the server has
+ responded) was not taken into account. </p>
+ <p>Own Id: OTP-9847</p>
+ </item>
+
+ <item>
+ <p>[httpc] The client incorrectly streams 404 responses.
+ The documentation specifies that only 200 and 206 responses
+ shall be streamed. </p>
+ <p>Shane Evens</p>
+ <p>Own Id: OTP-9860</p>
+ </item>
+
+ </list>
+ </section>
+
+ </section> <!-- 5.8.1 -->
+
+
<section><title>Inets 5.8</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index b6da92947c..560ee55271 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -1987,17 +1987,14 @@ setup_ctrl_connection(Host, Port, Timeout, State) ->
setup_data_connection(#state{mode = active,
caller = Caller,
csock = CSock} = State) ->
- IntToString = fun(Element) -> integer_to_list(Element) end,
-
case (catch inet:sockname(CSock)) of
{ok, {{_, _, _, _, _, _, _, _} = IP, _}} ->
{ok, LSock} =
gen_tcp:listen(0, [{ip, IP}, {active, false},
inet6, binary, {packet, 0}]),
{ok, Port} = inet:port(LSock),
- Cmd = mk_cmd("EPRT |2|~s:~s:~s:~s:~s:~s:~s:~s|~s|",
- lists:map(IntToString,
- tuple_to_list(IP) ++ [Port])),
+ IpAddress = inet_parse:ntoa(IP),
+ Cmd = mk_cmd("EPRT |2|~s|~p|", [IpAddress, Port]),
send_ctrl_message(State, Cmd),
activate_ctrl_connection(State),
{noreply, State#state{caller = {setup_data_connection,
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 587e24cc8d..bfe9b14ef6 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -157,12 +157,12 @@ info(Pid) ->
%% memory in vain.)
%%--------------------------------------------------------------------
%% Request should not be streamed
-stream(BodyPart, Request = #request{stream = none}, _) ->
+stream(BodyPart, #request{stream = none} = Request, _) ->
?hcrt("stream - none", []),
{BodyPart, Request};
%% Stream to caller
-stream(BodyPart, Request = #request{stream = Self}, Code)
+stream(BodyPart, #request{stream = Self} = Request, Code)
when ((Code =:= 200) orelse (Code =:= 206)) andalso
((Self =:= self) orelse (Self =:= {self, once})) ->
?hcrt("stream - self", [{stream, Self}, {code, Code}]),
@@ -170,17 +170,10 @@ stream(BodyPart, Request = #request{stream = Self}, Code)
{Request#request.id, stream, BodyPart}),
{<<>>, Request};
-stream(BodyPart, Request = #request{stream = Self}, 404)
- when (Self =:= self) orelse (Self =:= {self, once}) ->
- ?hcrt("stream - self with 404", [{stream, Self}]),
- httpc_response:send(Request#request.from,
- {Request#request.id, stream, BodyPart}),
- {<<>>, Request};
-
%% Stream to file
%% This has been moved to start_stream/3
%% We keep this for backward compatibillity...
-stream(BodyPart, Request = #request{stream = Filename}, Code)
+stream(BodyPart, #request{stream = Filename} = Request, Code)
when ((Code =:= 200) orelse (Code =:= 206)) andalso is_list(Filename) ->
?hcrt("stream - filename", [{stream, Filename}, {code, Code}]),
case file:open(Filename, [write, raw, append, delayed_write]) of
@@ -192,7 +185,7 @@ stream(BodyPart, Request = #request{stream = Filename}, Code)
end;
%% Stream to file
-stream(BodyPart, Request = #request{stream = Fd}, Code)
+stream(BodyPart, #request{stream = Fd} = Request, Code)
when ((Code =:= 200) orelse (Code =:= 206)) ->
?hcrt("stream to file", [{stream, Fd}, {code, Code}]),
case file:write(Fd, BodyPart) of
@@ -295,7 +288,7 @@ handle_call(#request{address = Addr} = Request, _,
%% Queue + current
queue:len(NewPipeline) + 1,
client_close = ClientClose},
- httpc_manager:insert_session(NewSession, ProfileName),
+ insert_session(NewSession, ProfileName),
?hcrd("session updated", []),
{reply, ok, State#state{pipeline = NewPipeline,
session = NewSession,
@@ -363,7 +356,7 @@ handle_call(#request{address = Addr} = Request, _,
%% Queue + current
queue:len(NewKeepAlive) + 1,
client_close = ClientClose},
- httpc_manager:insert_session(NewSession, ProfileName),
+ insert_session(NewSession, ProfileName),
?hcrd("session updated", []),
{reply, ok, State#state{keep_alive = NewKeepAlive,
session = NewSession,
@@ -377,7 +370,7 @@ handle_call(#request{address = Addr} = Request, _,
NewSession =
Session#session{queue_length = 1,
client_close = ClientClose},
- httpc_manager:insert_session(NewSession, ProfileName),
+ insert_session(NewSession, ProfileName),
Relaxed =
(Request#request.settings)#http_options.relaxed,
MFA = {httpc_response, parse,
@@ -766,23 +759,52 @@ deliver_answer(Request) ->
%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
%% Purpose: Convert process state when code is changed
%%--------------------------------------------------------------------
-%% code_change(_, #state{request = Request, pipeline = Queue} = State,
-%% [{from, '5.0.1'}, {to, '5.0.2'}]) ->
-%% Settings = new_http_options(Request#request.settings),
-%% NewRequest = Request#request{settings = Settings},
-%% NewQueue = new_queue(Queue, fun new_http_options/1),
-%% {ok, State#state{request = NewRequest, pipeline = NewQueue}};
-
-%% code_change(_, #state{request = Request, pipeline = Queue} = State,
-%% [{from, '5.0.2'}, {to, '5.0.1'}]) ->
-%% Settings = old_http_options(Request#request.settings),
-%% NewRequest = Request#request{settings = Settings},
-%% NewQueue = new_queue(Queue, fun old_http_options/1),
-%% {ok, State#state{request = NewRequest, pipeline = NewQueue}};
+
+code_change(_,
+ #state{session = OldSession,
+ profile_name = ProfileName} = State,
+ upgrade_from_pre_5_8_1) ->
+ case OldSession of
+ {session,
+ Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type} ->
+ NewSession = #session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type},
+ insert_session(NewSession, ProfileName),
+ {ok, State#state{session = NewSession}};
+ _ ->
+ {ok, State}
+ end;
+
+code_change(_,
+ #state{session = OldSession,
+ profile_name = ProfileName} = State,
+ downgrade_to_pre_5_8_1) ->
+ case OldSession of
+ #session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type} ->
+ NewSession = {session,
+ Id, ClientClose, Scheme, Socket, SocketType,
+ QueueLen, Type},
+ insert_session(NewSession, ProfileName),
+ {ok, State#state{session = NewSession}};
+ _ ->
+ {ok, State}
+ end;
code_change(_, State, _) ->
{ok, State}.
+
%% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
%% Auth, Relaxed}) ->
%% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
@@ -1181,7 +1203,7 @@ handle_pipeline(#state{status = pipeline,
case queue:out(State#state.pipeline) of
{empty, _} ->
- ?hcrd("epmty pipeline queue", []),
+ ?hcrd("pipeline queue empty", []),
%% The server may choose too teminate an idle pipeline
%% in this case we want to receive the close message
@@ -1191,9 +1213,8 @@ handle_pipeline(#state{status = pipeline,
%% If a pipeline that has been idle for some time is not
%% closed by the server, the client may want to close it.
- NewState = activate_queue_timeout(TimeOut, State),
- NewSession = Session#session{queue_length = 0},
- httpc_manager:insert_session(NewSession, ProfileName),
+ NewState = activate_queue_timeout(TimeOut, State),
+ update_session(ProfileName, Session, #session.queue_length, 0),
%% Note mfa will be initilized when a new request
%% arrives.
{noreply,
@@ -1203,6 +1224,7 @@ handle_pipeline(#state{status = pipeline,
headers = undefined,
body = undefined}};
{{value, NextRequest}, Pipeline} ->
+ ?hcrd("pipeline queue non-empty", []),
case lists:member(NextRequest#request.id,
State#state.canceled) of
true ->
@@ -1218,7 +1240,7 @@ handle_pipeline(#state{status = pipeline,
Session#session{queue_length =
%% Queue + current
queue:len(Pipeline) + 1},
- httpc_manager:insert_session(NewSession, ProfileName),
+ insert_session(NewSession, ProfileName),
Relaxed =
(NextRequest#request.settings)#http_options.relaxed,
MFA = {httpc_response,
@@ -1257,7 +1279,7 @@ handle_keep_alive_queue(
case queue:out(State#state.keep_alive) of
{empty, _} ->
- ?hcrd("empty keep_alive queue", []),
+ ?hcrd("keep_alive queue empty", []),
%% The server may choose too terminate an idle keep_alive session
%% in this case we want to receive the close message
%% at once and not when trying to send the next
@@ -1266,8 +1288,7 @@ handle_keep_alive_queue(
%% If a keep_alive session has been idle for some time is not
%% closed by the server, the client may want to close it.
NewState = activate_queue_timeout(TimeOut, State),
- NewSession = Session#session{queue_length = 0},
- httpc_manager:insert_session(NewSession, ProfileName),
+ update_session(ProfileName, Session, #session.queue_length, 0),
%% Note mfa will be initilized when a new request
%% arrives.
{noreply,
@@ -1279,6 +1300,7 @@ handle_keep_alive_queue(
}
};
{{value, NextRequest}, KeepAlive} ->
+ ?hcrd("keep_alive queue non-empty", []),
case lists:member(NextRequest#request.id,
State#state.canceled) of
true ->
@@ -1388,10 +1410,10 @@ try_to_enable_pipeline_or_keep_alive(
case (is_pipeline_enabled_client(Session) andalso
httpc_request:is_idempotent(Method)) of
true ->
- httpc_manager:insert_session(Session, ProfileName),
+ insert_session(Session, ProfileName),
State#state{status = pipeline};
false ->
- httpc_manager:insert_session(Session, ProfileName),
+ insert_session(Session, ProfileName),
%% Make sure type is keep_alive in session
%% as it in this case might be pipeline
NewSession = Session#session{type = keep_alive},
@@ -1403,7 +1425,9 @@ try_to_enable_pipeline_or_keep_alive(
end.
answer_request(#request{id = RequestId, from = From} = Request, Msg,
- #state{timers = Timers, profile_name = ProfileName} = State) ->
+ #state{session = Session,
+ timers = Timers,
+ profile_name = ProfileName} = State) ->
?hcrt("answer request", [{request, Request}, {msg, Msg}]),
httpc_response:send(From, Msg),
RequestTimers = Timers#timers.request_timers,
@@ -1412,12 +1436,20 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
Timer = {RequestId, TimerRef},
cancel_timer(TimerRef, {timeout, Request#request.id}),
httpc_manager:request_done(RequestId, ProfileName),
-
+ NewSession = maybe_make_session_available(ProfileName, Session),
+ Timers2 = Timers#timers{request_timers = lists:delete(Timer,
+ RequestTimers)},
State#state{request = Request#request{from = answer_sent},
- timers =
- Timers#timers{request_timers =
- lists:delete(Timer, RequestTimers)}}.
-
+ session = NewSession,
+ timers = Timers2}.
+
+maybe_make_session_available(ProfileName,
+ #session{available = false} = Session) ->
+ update_session(ProfileName, Session, #session.available, true),
+ Session#session{available = true};
+maybe_make_session_available(_ProfileName, Session) ->
+ Session.
+
cancel_timers(#timers{request_timers = ReqTmrs, queue_timer = QTmr}) ->
cancel_timer(QTmr, timeout_queue),
CancelTimer = fun({_, Timer}) -> cancel_timer(Timer, timeout) end,
@@ -1656,6 +1688,28 @@ send_raw(SocketType, Socket, ProcessBody, Acc) ->
end.
+%% ---------------------------------------------------------------------
+%% Session wrappers
+%% ---------------------------------------------------------------------
+
+insert_session(Session, ProfileName) ->
+ httpc_manager:insert_session(Session, ProfileName).
+
+
+update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
+ try
+ begin
+ httpc_manager:update_session(ProfileName, SessionId, Pos, Value)
+ end
+ catch
+ error:undef -> % This could happen during code upgrade
+ Session2 = erlang:setelement(Pos, Session, Value),
+ insert_session(Session2, ProfileName)
+ end.
+
+
+%% ---------------------------------------------------------------------
+
call(Msg, Pid) ->
Timeout = infinity,
call(Msg, Pid, Timeout).
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 1fbbaa8d13..8af752546c 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -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
@@ -115,17 +115,37 @@
}
).
+
-record(session,
{
- id, % {{Host, Port}, HandlerPid}
- client_close, % true | false
- scheme, % http (HTTP/TCP) | https (HTTP/SSL/TCP)
- socket, % Open socket, used by connection
- socket_type, % socket-type, used by connection
- queue_length = 1, % Current length of pipeline or keep-alive queue
- type % pipeline | keep_alive (wait for response before sending new request)
+ %% {{Host, Port}, HandlerPid}
+ id,
+
+ %% true | false
+ client_close,
+
+ %% http (HTTP/TCP) | https (HTTP/SSL/TCP)
+ scheme,
+
+ %% Open socket, used by connection
+ socket,
+
+ %% socket-type, used by connection
+ socket_type,
+
+ %% Current length of pipeline or keep-alive queue
+ queue_length = 1,
+
+ %% pipeline | keep_alive (wait for response before sending new request)
+ type,
+
+ %% true | false
+ %% This will be true, when a response has been received for
+ %% the first request. See type above.
+ available = false
}).
+
-record(http_cookie,
{
domain,
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index a97cbb83f1..453081da21 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.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
@@ -34,6 +34,7 @@
retry_request/2,
redirect_request/2,
insert_session/2,
+ update_session/4,
delete_session/2,
set_options/2,
store_cookies/3,
@@ -193,6 +194,27 @@ insert_session(Session, ProfileName) ->
%%--------------------------------------------------------------------
+%% 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.
+%% Intended to be called by the httpc request handler process.
+%%--------------------------------------------------------------------
+
+update_session(ProfileName, SessionId, Pos, Value) ->
+ SessionDbName = session_db_name(ProfileName),
+ ?hcrt("update session",
+ [{id, SessionId},
+ {pos, Pos},
+ {value, Value},
+ {profile, ProfileName}]),
+ ets:update_element(SessionDbName, SessionId, {Pos, Value}).
+
+
+%%--------------------------------------------------------------------
%% Function: delete_session(SessionId, ProfileName) -> _
%% SessionId - {{Host, Port}, HandlerPid}
%% ProfileName - atom()
@@ -559,9 +581,70 @@ terminate(_, State) ->
%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
%% Purpose: Convert process state when code is changed
%%--------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
+code_change(_,
+ #state{session_db = SessionDB} = State,
+ upgrade_from_pre_5_8_1) ->
+ Upgrade =
+ fun({session,
+ Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type}) ->
+ {ok, #session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type}};
+ (_) -> % Already upgraded (by handler)
+ ignore
+ end,
+ (catch update_session_table(SessionDB, Upgrade)),
+ {ok, State};
+
+code_change(_,
+ #state{session_db = SessionDB} = State,
+ downgrade_to_pre_5_8_1) ->
+ Downgrade =
+ fun(#session{id = Id,
+ client_close = ClientClose,
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType,
+ queue_length = QueueLen,
+ type = Type}) ->
+ {ok, {session,
+ Id, ClientClose, Scheme, Socket, SocketType,
+ QueueLen, Type}};
+ (_) -> % Already downgraded (by handler)
+ ignore
+ end,
+ (catch update_session_table(SessionDB, Downgrade)),
+ {ok, State};
+
+code_change(_, State, _) ->
{ok, State}.
+%% This function is to catch everything that calls through the cracks...
+update_session_table(SessionDB, Transform) ->
+ ets:safe_fixtable(SessionDB, true),
+ update_session_table(SessionDB, ets:first(SessionDB), Transform),
+ ets:safe_fixtable(SessionDB, false).
+
+update_session_table(_SessionDB, '$end_of_table', _Transform) ->
+ ok;
+update_session_table(SessionDB, Key, Transform) ->
+ case ets:lookup(SessionDB, Key) of
+ [OldSession] ->
+ case Transform(OldSession) of
+ {ok, NewSession} ->
+ ets:insert(SessionDB, NewSession);
+ ignore ->
+ ok
+ end;
+ _ ->
+ ok
+ end,
+ update_session_table(SessionDB, ets:next(SessionDB, Key), Transform).
+
%%--------------------------------------------------------------------
%% Internal functions
@@ -690,6 +773,7 @@ select_session(Method, HostPort, Scheme, SessionType,
scheme = Scheme,
queue_length = '$2',
type = SessionType,
+ available = true,
_ = '_'},
%% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp},
Candidates = ets:match(SessionDb, Pattern),
@@ -727,7 +811,7 @@ pipeline_or_keep_alive(Request, HandlerPid, State) ->
ets:insert(State#state.handler_db, {Request#request.id,
HandlerPid,
Request#request.from});
- _ -> %timeout pipelining failed
+ _ -> % timeout pipelining failed
start_handler(Request, State)
end.
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 779dd8e439..e80cb2a23b 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -1,7 +1,7 @@
%% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -18,6 +18,15 @@
{"%VSN%",
[
+ {"5.8",
+ [
+ {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, [httpc_handler]}
+ ]
+ },
{"5.7.2",
[
{restart_application, inets}
@@ -40,6 +49,15 @@
}
],
[
+ {"5.8",
+ [
+ {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, [httpc_handler]}
+ ]
+ },
{"5.7.2",
[
{restart_application, inets}
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 6e69c9a469..881266b70a 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -90,6 +90,7 @@ all() ->
parse_url,
options,
headers_as_is,
+ selecting_session,
{group, proxy},
{group, ssl},
{group, stream},
@@ -252,7 +253,7 @@ init_per_testcase(Case, Timeout, Config) ->
%% inets:enable_trace(max, io, httpd),
%% inets:enable_trace(max, io, httpc),
- inets:enable_trace(max, io, all),
+ %% inets:enable_trace(max, io, all),
NewConfig =
case atom_to_list(Case) of
@@ -1765,6 +1766,7 @@ http_stream(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+
http_stream_once(doc) ->
["Test the option stream for asynchrony requests"];
http_stream_once(suite) ->
@@ -1772,12 +1774,12 @@ http_stream_once(suite) ->
http_stream_once(Config) when is_list(Config) ->
p("http_stream_once -> entry with"
"~n Config: ~p", [Config]),
-
+
p("http_stream_once -> set ipfamily to inet", []),
ok = httpc:set_options([{ipfamily, inet}]),
p("http_stream_once -> start dummy server", []),
{DummyServerPid, Port} = dummy_server(ipv4),
-
+
PortStr = integer_to_list(Port),
p("http_stream_once -> once", []),
once(?URL_START ++ PortStr ++ "/once.html"),
@@ -1785,14 +1787,14 @@ http_stream_once(Config) when is_list(Config) ->
once(?URL_START ++ PortStr ++ "/once_chunked.html"),
p("http_stream_once -> dummy", []),
once(?URL_START ++ PortStr ++ "/dummy.html"),
-
+
p("http_stream_once -> stop dummy server", []),
DummyServerPid ! stop,
p("http_stream_once -> set ipfamily to inet6fb4", []),
ok = httpc:set_options([{ipfamily, inet6fb4}]),
p("http_stream_once -> done", []),
ok.
-
+
once(URL) ->
p("once -> issue sync request for ~p", [URL]),
{ok, {{_,200,_}, [_ | _], Body}} =
@@ -2001,6 +2003,7 @@ ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) ->
%%-------------------------------------------------------------------------
+
headers_as_is(doc) ->
["Test the option headers_as_is"];
headers_as_is(suite) ->
@@ -2018,6 +2021,321 @@ headers_as_is(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+
+selecting_session(doc) ->
+ ["Test selection of sessions - OTP-9847"];
+selecting_session(suite) ->
+ [];
+selecting_session(Config) when is_list(Config) ->
+ tsp("selecting_session -> entry with"
+ "~n Config: ~p", [Config]),
+
+ tsp("selecting_session -> set ipfamily to inet"),
+ ok = httpc:set_options([{ipfamily, inet}]),
+
+ tsp("selecting_session -> start server"),
+ {ServerPid, Port} = otp_9847_server(),
+
+ PortStr = integer_to_list(Port),
+ URL = ?URL_START ++ PortStr ++ "/index.html",
+
+ tsp("selecting_session -> issue the first batch (three) requests"),
+ lists:foreach(fun(P) ->
+ tsp("selecting_session:fun1 -> "
+ "send stop request to ~p", [P]),
+ P ! stop
+ end,
+ reqs(URL, ServerPid, 3, 3, false)),
+ tsp("selecting_session -> sleep some (1) to make sure nothing lingers"),
+ ?SLEEP(5000),
+ tsp("selecting_session -> "
+ "instruct the server to reply to the first request"),
+ ServerPid ! {answer, true},
+ receive
+ {answer, true} ->
+ tsp("selecting_session -> "
+ "received ack from server to reply to the first request"),
+ ok
+ end,
+ tsp("selecting_session -> issue the second batch (four) requests"),
+ lists:foreach(fun(P) ->
+ tsp("selecting_session:fun2 -> "
+ "send stop request to ~p", [P]),
+ P ! stop
+ end,
+ reqs(URL, ServerPid, 4, 1, true)),
+ tsp("selecting_session -> sleep some (2) to make sure nothing lingers"),
+ ?SLEEP(5000),
+
+ tsp("selecting_session -> stop server"),
+ ServerPid ! stop,
+ tsp("selecting_session -> set ipfamily (back) to inet6fb4"),
+ ok = httpc:set_options([{ipfamily, inet6fb4}]),
+ tsp("selecting_session -> done"),
+ ok.
+
+reqs(URL, ServerPid, NumReqs, NumHandlers, InitialSync) ->
+ tsp("reqs -> entry with"
+ "~n URL: ~p"
+ "~n ServerPid: ~w"
+ "~n NumReqs: ~w"
+ "~n NumHandlers: ~w"
+ "~n InitialSync: ~w",
+ [URL, ServerPid, NumReqs, NumHandlers, InitialSync]),
+ Handlers = reqs2(URL, NumReqs, [], InitialSync),
+ tsp("reqs -> "
+ "~n Handlers: ~w", [Handlers]),
+ case length(Handlers) of
+ NumHandlers ->
+ tsp("reqs -> "
+ "~n NumHandlers: ~w", [NumHandlers]),
+ ServerPid ! num_handlers,
+ receive
+ {num_handlers, NumHandlers} ->
+ tsp("reqs -> received num_handlers with"
+ "~n NumHandlers: ~w", [NumHandlers]),
+ Handlers;
+ {num_handlers, WrongNumHandlers} ->
+ tsp("reqs -> received num_handlers with"
+ "~n WrongNumHandlers: ~w", [WrongNumHandlers]),
+ exit({wrong_num_handlers1, WrongNumHandlers, NumHandlers})
+ end;
+ WrongNumHandlers ->
+ tsp("reqs -> "
+ "~n WrongNumHandlers: ~w", [WrongNumHandlers]),
+ exit({wrong_num_handlers2, WrongNumHandlers, NumHandlers})
+ end.
+
+
+reqs2(_URL, 0, Acc, _Sync) ->
+ lists:reverse(Acc);
+reqs2(URL, Num, Acc, Sync) ->
+ tsp("reqs2 -> entry with"
+ "~n Num: ~w"
+ "~n Sync: ~w", [Num, Sync]),
+ case httpc:request(get, {URL, []}, [], [{sync, Sync}]) of
+ {ok, _Reply} ->
+ tsp("reqs2 -> successful request: ~p", [_Reply]),
+ receive
+ {handler, Handler, _Manager} ->
+ %% This is when a new handler is created
+ tsp("reqs2 -> received handler: ~p", [Handler]),
+ case lists:member(Handler, Acc) of
+ true ->
+ tsp("reqs2 -> duplicate handler"),
+ exit({duplicate_handler, Handler, Num, Acc});
+ false ->
+ tsp("reqs2 -> wait for data ack"),
+ receive
+ {data_received, Handler} ->
+ tsp("reqs2 -> "
+ "received data ack from ~p", [Handler]),
+ case Sync of
+ true ->
+ reqs2(URL, Num-1, [Handler|Acc],
+ false);
+ false ->
+ reqs2(URL, Num-1, [Handler|Acc],
+ Sync)
+ end
+ end
+ end;
+
+ {data_received, Handler} ->
+ tsp("reqs2 -> "
+ "received data ack from ~p", [Handler]),
+ reqs2(URL, Num-1, Acc, false)
+
+ end;
+
+ {error, Reason} ->
+ tsp("reqs2 -> request ~w failed: ~p", [Num, Reason]),
+ exit({request_failed, Reason, Num, Acc})
+ end.
+
+otp_9847_server() ->
+ TC = self(),
+ Pid = spawn_link(fun() -> otp_9847_server_init(TC) end),
+ receive
+ {port, Port} ->
+ {Pid, Port}
+ end.
+
+otp_9847_server_init(TC) ->
+ tsp("otp_9847_server_init -> entry with"
+ "~n TC: ~p", [TC]),
+ {ok, ListenSocket} =
+ gen_tcp:listen(0, [binary, inet, {packet, 0},
+ {reuseaddr,true},
+ {active, false}]),
+ tsp("otp_9847_server_init -> listen socket created: "
+ "~n ListenSocket: ~p", [ListenSocket]),
+ {ok, Port} = inet:port(ListenSocket),
+ tsp("otp_9847_server_init -> Port: ~p", [Port]),
+ TC ! {port, Port},
+ otp_9847_server_main(TC, ListenSocket, false, []).
+
+otp_9847_server_main(TC, ListenSocket, Answer, Handlers) ->
+ tsp("otp_9847_server_main -> entry with"
+ "~n TC: ~p"
+ "~n ListenSocket: ~p"
+ "~n Answer: ~p"
+ "~n Handlers: ~p", [TC, ListenSocket, Answer, Handlers]),
+ case gen_tcp:accept(ListenSocket, 1000) of
+ {ok, Sock} ->
+ tsp("otp_9847_server_main -> accepted"
+ "~n Sock: ~p", [Sock]),
+ {Handler, Mon, Port} = otp_9847_handler(TC, Sock, Answer),
+ tsp("otp_9847_server_main -> handler ~p created for ~w",
+ [Handler, Port]),
+ gen_tcp:controlling_process(Sock, Handler),
+ tsp("otp_9847_server_main -> control transfer"),
+ Handler ! owner,
+ tsp("otp_9847_server_main -> "
+ "handler ~p informed of owner transfer", [Handler]),
+ TC ! {handler, Handler, self()},
+ tsp("otp_9847_server_main -> "
+ "TC ~p informed of handler ~p", [TC, Handler]),
+ otp_9847_server_main(TC, ListenSocket, Answer,
+ [{Handler, Mon, Sock, Port}|Handlers]);
+
+ {error, timeout} ->
+ tsp("otp_9847_server_main -> timeout"),
+ receive
+ {answer, true} ->
+ tsp("otp_9847_server_main -> received answer request"),
+ TC ! {answer, true},
+ otp_9847_server_main(TC, ListenSocket, true, Handlers);
+
+ {'DOWN', _Mon, process, Pid, _Reason} ->
+ %% Could be one of the handlers
+ tsp("otp_9847_server_main -> received DOWN for ~p", [Pid]),
+ otp_9847_server_main(TC, ListenSocket, Answer,
+ lists:keydelete(Pid, 1, Handlers));
+
+ num_handlers ->
+ tsp("otp_9847_server_main -> "
+ "received request for number of handlers (~w)",
+ [length(Handlers)]),
+ TC ! {num_handlers, length(Handlers)},
+ otp_9847_server_main(TC, ListenSocket, Answer, Handlers);
+
+ stop ->
+ tsp("otp_9847_server_main -> received stop request"),
+ %% Stop all handlers (just in case)
+ Pids = [Handler || {Handler, _, _} <- Handlers],
+ lists:foreach(fun(Pid) -> Pid ! stop end, Pids),
+ exit(normal);
+
+ Any ->
+ tsp("otp_9847_server_main -> received"
+ "~n Any: ~p", [Any]),
+ exit({crap, Any})
+
+ after 0 ->
+ tsp("otp_9847_server_main -> nothing in queue"),
+ otp_9847_server_main(TC, ListenSocket, Answer, Handlers)
+ end;
+
+ Error ->
+ exit(Error)
+ end.
+
+
+otp_9847_handler(TC, Sock, Answer) ->
+ tsp("otp_9847_handler -> entry with"
+ "~n TC: ~p"
+ "~n Sock: ~p"
+ "~n Answer: ~p", [TC, Sock, Answer]),
+ Self = self(),
+ {Pid, Mon} =
+ spawn_opt(fun() ->
+ otp_9847_handler_init(TC, Self, Sock, Answer)
+ end,
+ [monitor]),
+ receive
+ {port, Port} ->
+ tsp("otp_9847_handler -> received port message (from ~p)"
+ "~n Port: ~p", [Pid, Port]),
+ {Pid, Mon, Port}
+ end.
+
+
+otp_9847_handler_init(TC, Server, Sock, Answer) ->
+ tsp("otp_9847_handler_init -> entry with"
+ "~n TC: ~p"
+ "~n Server: ~p"
+ "~n Sock: ~p"
+ "~n Answer: ~p", [TC, Server, Sock, Answer]),
+ {ok, Port} = inet:port(Sock),
+ Server ! {port, Port},
+ receive
+ owner ->
+ tsp("otp_9847_handler_init -> "
+ "received owner message - activate socket"),
+ inet:setopts(Sock, [{active, true}]),
+ otp_9847_handler_main(TC, Server, Sock, Answer, [?HTTP_MAX_HEADER_SIZE])
+ end.
+
+otp_9847_handler_main(TC, Server, Sock, Answer, ParseArgs) ->
+ tsp("otp_9847_handler_main -> entry with"
+ "~n TC: ~p"
+ "~n Server: ~p"
+ "~n Sock: ~p"
+ "~n Answer: ~p"
+ "~n ParseArgs: ~p", [TC, Server, Sock, Answer, ParseArgs]),
+ receive
+ stop ->
+ tsp("otp_9847_handler_main -> received stop request"),
+ exit(normal);
+
+ {tcp, Sock, _Data} when Answer =:= false ->
+ tsp("otp_9847_handler_main -> received tcp data - no answer"),
+ TC ! {data_received, self()},
+ inet:setopts(Sock, [{active, true}]),
+ %% Ignore all data
+ otp_9847_handler_main(TC, Server, Sock, Answer, ParseArgs);
+
+ {tcp, Sock, Data} when Answer =:= true ->
+ tsp("otp_9847_handler_main -> received tcp data - answer"),
+ TC ! {data_received, self()},
+ inet:setopts(Sock, [{active, true}]),
+ NewParseArgs = otp_9847_handler_request(Sock, [Data|ParseArgs]),
+ otp_9847_handler_main(TC, Server, Sock, Answer, NewParseArgs);
+
+ {tcp_closed, Sock} ->
+ tsp("otp_9847_handler_main -> received tcp socket closed"),
+ exit(normal);
+
+ {tcp_error, Sock, Reason} ->
+ tsp("otp_9847_handler_main -> socket error: ~p", [Reason]),
+ (catch gen_tcp:close(Sock)),
+ exit(normal)
+
+ %% after 30000 ->
+ %% gen_tcp:close(Sock),
+ %% exit(normal)
+ end.
+
+otp_9847_handler_request(Sock, Args) ->
+ Msg =
+ case httpd_request:parse(Args) of
+ {ok, {_, "/index.html" = _RelUrl, _, _, _}} ->
+ B =
+ "<HTML><BODY>" ++
+ "...some body part..." ++
+ "</BODY></HTML>",
+ Len = integer_to_list(length(B)),
+ "HTTP/1.1 200 ok\r\n" ++
+ "Content-Length:" ++ Len ++ "\r\n\r\n" ++ B
+ end,
+ gen_tcp:send(Sock, Msg),
+ [?HTTP_MAX_HEADER_SIZE].
+
+
+
+%%-------------------------------------------------------------------------
+
options(doc) ->
["Test the option parameters."];
options(suite) ->
@@ -2042,6 +2360,7 @@ options(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+
http_invalid_http(doc) ->
["Test parse error"];
http_invalid_http(suite) ->
@@ -2855,6 +3174,7 @@ otp_8739_dummy_server_main(_Parent, ListenSocket) ->
exit(Error)
end.
+
%%-------------------------------------------------------------------------
initial_server_connect(doc) ->
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 5b571a9649..a4bb8f7159 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -2227,6 +2227,7 @@ ticket_5865(doc) ->
ticket_5865(suite) ->
[];
ticket_5865(Config) ->
+ ?SKIP(as_of_r15_behaviour_of_calendar_has_changed),
Host = ?config(host,Config),
ServerRoot = ?config(server_root, Config),
DocRoot = filename:join([ServerRoot, "htdocs"]),
diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl
index 1c7bb512cc..2f5867559a 100644
--- a/lib/inets/test/httpd_test_lib.erl
+++ b/lib/inets/test/httpd_test_lib.erl
@@ -80,14 +80,18 @@
%% API
%%------------------------------------------------------------------
verify_request(SocketType, Host, Port, Node, RequestStr, Options) ->
- verify_request(SocketType, Host, Port, Node, RequestStr, Options, 30000).
+ verify_request(SocketType, Host, Port, Node, RequestStr,
+ Options, 30000).
verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options)
when is_list(TranspOpts) ->
- verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, 30000);
+ verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr,
+ Options, 30000);
verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut)
when (is_integer(TimeOut) orelse (TimeOut =:= infinity)) ->
- verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut).
-verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, TimeOut) ->
+ verify_request(SocketType, Host, Port, [], Node, RequestStr,
+ Options, TimeOut).
+verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr,
+ Options, TimeOut) ->
tsp("verify_request -> entry with"
"~n SocketType: ~p"
"~n Host: ~p"
@@ -259,10 +263,10 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _},
headers = Headers,
body = Body}, Options, N, P) ->
- %% tsp("validate -> entry with"
- %% "~n StatusCode: ~p"
- %% "~n Headers: ~p"
- %% "~n Body: ~p", [StatusCode, Headers, Body]),
+ tsp("validate -> entry with"
+ "~n StatusCode: ~p"
+ "~n Headers: ~p"
+ "~n Body: ~p", [StatusCode, Headers, Body]),
check_version(Version, Options),
case lists:keysearch(statuscode, 1, Options) of
@@ -320,9 +324,9 @@ do_validate(Header, [{header, HeaderField}|Rest], N, P) ->
{value, {LowerHeaderField, _Value}} ->
ok;
false ->
- test_server:fail({missing_header_field, LowerHeaderField, Header});
+ tsf({missing_header_field, LowerHeaderField, Header});
_ ->
- test_server:fail({missing_header_field, LowerHeaderField, Header})
+ tsf({missing_header_field, LowerHeaderField, Header})
end,
do_validate(Header, Rest, N, P);
do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) ->
@@ -331,18 +335,15 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) ->
{value, {LowerHeaderField, Value}} ->
ok;
false ->
- test_server:fail({wrong_header_field_value, LowerHeaderField,
- Header});
+ tsf({wrong_header_field_value, LowerHeaderField, Header});
_ ->
- test_server:fail({wrong_header_field_value, LowerHeaderField,
- Header})
+ tsf({wrong_header_field_value, LowerHeaderField, Header})
end,
do_validate(Header, Rest, N, P);
do_validate(Header,[{no_last_modified, HeaderField}|Rest],N,P) ->
case lists:keysearch(HeaderField,1,Header) of
{value,_} ->
- test_server:fail({wrong_header_field_value, HeaderField,
- Header});
+ tsf({wrong_header_field_value, HeaderField, Header});
_ ->
ok
end,
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 1df4558e45..77eb43a7ed 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -2,7 +2,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
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.8
+INETS_VSN = 5.8.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/inviso/test/inviso_tool_SUITE.erl b/lib/inviso/test/inviso_tool_SUITE.erl
index 6b16e506eb..f8a9cea47f 100644
--- a/lib/inviso/test/inviso_tool_SUITE.erl
+++ b/lib/inviso/test/inviso_tool_SUITE.erl
@@ -52,7 +52,12 @@ end_per_group(_GroupName, Config) ->
%% -----------------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ case test_server:is_native(lists) of
+ true ->
+ {skip,"Native libs -- tracing doesn't work"};
+ false ->
+ Config
+ end.
%% -----------------------------------------------------------------------------
end_per_suite(_Config) ->
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java
index 4d53447164..60eef7a126 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java
@@ -53,7 +53,7 @@ public class OtpErlangAtom extends OtpErlangObject implements Serializable,
if (atom.length() > maxAtomLength) {
throw new java.lang.IllegalArgumentException("Atom may not exceed "
- + maxAtomLength + " characters");
+ + maxAtomLength + " characters: " + atom);
}
this.atom = atom;
}
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
index 8cd900aada..be8b7c5c12 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
@@ -154,13 +154,16 @@ public class OtpErlangString extends OtpErlangObject implements Serializable,
* Unicode code points
*/
- public static int[] stringToCodePoints(final String s) {
- final int m = s.codePointCount(0, s.length());
- final int [] codePoints = new int[m];
- for (int i = 0, j = 0; j < m; i = s.offsetByCodePoints(i, 1), j++) {
- codePoints[j] = s.codePointAt(i);
- }
- return codePoints;
+ public static int[] stringToCodePoints(final String s) {
+ final int m = s.codePointCount(0, s.length());
+ final int[] codePoints = new int[m];
+ int j = 0;
+ for (int offset = 0; offset < s.length();) {
+ final int codepoint = s.codePointAt(offset);
+ codePoints[j++] = codepoint;
+ offset += Character.charCount(codepoint);
+ }
+ return codePoints;
}
/**
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
index 71a419497a..b0b64e6953 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
@@ -31,7 +31,7 @@ package com.ericsson.otp.erlang;
* the recipient of the message. When sending messages to other mailboxes, the
* recipient can only respond if the sender includes the pid as part of the
* message contents. The sender can determine his own pid by calling
- * {@link #self self()}.
+ * {@link #self() self()}.
* </p>
*
* <p>
@@ -141,7 +141,7 @@ public class OtpMbox {
* Get the registered name of this mailbox.
*
* @return the registered name of this mailbox, or null if the mailbox had
- * no registerd name.
+ * no registered name.
*/
public String getName() {
return name;
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java
index d499fae3fb..be7c8e5b1a 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java
@@ -182,7 +182,7 @@ public class OtpNode extends OtpLocalNode {
* Create an unnamed {@link OtpMbox mailbox} that can be used to send and
* receive messages with other, similar mailboxes and with Erlang processes.
* Messages can be sent to this mailbox by using its associated
- * {@link OtpMbox#self pid}.
+ * {@link OtpMbox#self() pid}.
*
* @return a mailbox.
*/
@@ -248,7 +248,7 @@ public class OtpNode extends OtpLocalNode {
* Create an named mailbox that can be used to send and receive messages
* with other, similar mailboxes and with Erlang processes. Messages can be
* sent to this mailbox by using its registered name or the associated
- * {@link OtpMbox#self pid}.
+ * {@link OtpMbox#self() pid}.
*
* @param name
* a name to register for this mailbox. The name must be unique
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index da54f5bf51..9c88400c2a 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -296,7 +296,8 @@ lists_roundtrip_2(Config) when is_list(Config) ->
{[z,23|24],tail3},
{[z|25],tail3},
{"abc123",sub3atom},
- {"abc",sub3atom}
+ {"abc",sub3atom},
+ {"abcdefg",codepointBug}
],
Trans =
fun ([_|T], tail) ->
@@ -308,7 +309,9 @@ lists_roundtrip_2(Config) when is_list(Config) ->
(L, tail3) when is_list(L) ->
null;
([_,_,_|L], sub3atom) ->
- list_to_atom(L)
+ list_to_atom(L);
+ (L, codepointBug) ->
+ L
end,
OutTrans =
fun ({L,Twist}) ->
diff --git a/lib/jinterface/test/nc_SUITE_data/echo_server.java b/lib/jinterface/test/nc_SUITE_data/echo_server.java
index 0550e4beb1..5ecb5b72a7 100644
--- a/lib/jinterface/test/nc_SUITE_data/echo_server.java
+++ b/lib/jinterface/test/nc_SUITE_data/echo_server.java
@@ -202,6 +202,12 @@ public class echo_server {
final OtpErlangAtom o = new OtpErlangAtom(s.stringValue()
.substring(3));
return o;
+ } else if (atomValue.equals("codepointBug")
+ && i instanceof OtpErlangString) {
+ final OtpErlangString s = (OtpErlangString) i;
+ final String ss = s.stringValue().substring(3, 6);
+ final int[] cps = OtpErlangString.stringToCodePoints(ss);
+ return s;
} else if (atomValue.equals("utf8")) {
if (i instanceof OtpErlangString) {
final OtpErlangString s = (OtpErlangString) i;
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 32a12e2b52..5d4f2eb70c 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1317,15 +1317,21 @@ int_list([H|T]) when is_integer(H) -> int_list(T);
int_list([_|_]) -> false;
int_list([]) -> true.
+load_file(Mod0, {From,_}=Caller, St0) ->
+ Mod = to_atom(Mod0),
+ case pending_on_load(Mod, From, St0) of
+ no -> load_file_1(Mod, Caller, St0);
+ {yes,St} -> {noreply,St}
+ end.
-load_file(Mod, Caller, #state{path=Path,cache=no_cache}=St) ->
+load_file_1(Mod, Caller, #state{path=Path,cache=no_cache}=St) ->
case mod_to_bin(Path, Mod) of
error ->
{reply,{error,nofile},St};
{Mod,Binary,File} ->
try_load_module(File, Mod, Binary, Caller, St)
end;
-load_file(Mod, Caller, #state{cache=Cache}=St0) ->
+load_file_1(Mod, Caller, #state{cache=Cache}=St0) ->
Key = {obj,Mod},
case ets:lookup(Cache, Key) of
[] ->
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 77ca26b845..d8954f0cf7 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.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
@@ -314,7 +314,7 @@ eof_or_abort(S, AssocId, Action) ->
-spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when
Socket :: sctp_socket(),
SndRcvInfo :: #sctp_sndrcvinfo{},
- Data :: binary | iolist(),
+ Data :: binary() | iolist(),
Reason :: term().
%% Full-featured send. Rarely needed.
@@ -331,7 +331,7 @@ send(S, SRI, Data) ->
Socket :: sctp_socket(),
Assoc :: #sctp_assoc_change{} | assoc_id(),
Stream :: integer(),
- Data :: binary | iolist(),
+ Data :: binary() | iolist(),
Reason :: term().
send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data)
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 10ab3e4370..99b0cd2ffb 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -30,9 +30,9 @@
load_cached/1, start_node_with_cache/1, add_and_rehash/1,
where_is_file_cached/1, where_is_file_no_cache/1,
purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1,
- code_archive/1, code_archive2/1, on_load/1,
- big_boot_embedded/1,
- on_load_embedded/1, on_load_errors/1, native_early_modules/1]).
+ code_archive/1, code_archive2/1, on_load/1, on_load_binary/1,
+ on_load_embedded/1, on_load_errors/1, big_boot_embedded/1,
+ native_early_modules/1]).
-export([init_per_testcase/2, end_per_testcase/2,
init_per_suite/1, end_per_suite/1,
@@ -55,8 +55,8 @@ all() ->
add_and_rehash, where_is_file_no_cache,
where_is_file_cached, purge_stacktrace, mult_lib_roots,
bad_erl_libs, code_archive, code_archive2, on_load,
- on_load_embedded, big_boot_embedded, on_load_errors,
- native_early_modules].
+ on_load_binary, on_load_embedded, on_load_errors,
+ big_boot_embedded, native_early_modules].
groups() ->
[].
@@ -1286,6 +1286,45 @@ on_load_wait_for_all([Ref|T]) ->
end;
on_load_wait_for_all([]) -> ok.
+on_load_binary(_) ->
+ Master = on_load_binary_test_case_process,
+ register(Master, self()),
+
+ %% Construct, compile and pretty-print.
+ Mod = on_load_binary,
+ File = atom_to_list(Mod) ++ ".erl",
+ Forms = [{attribute,1,file,{File,1}},
+ {attribute,1,module,Mod},
+ {attribute,2,export,[{ok,0}]},
+ {attribute,3,on_load,{init,0}},
+ {function,5,init,0,
+ [{clause,5,[],[],
+ [{op,6,'!',
+ {atom,6,Master},
+ {tuple,6,[{atom,6,Mod},{call,6,{atom,6,self},[]}]}},
+ {'receive',7,[{clause,8,[{atom,8,go}],[],[{atom,8,ok}]}]}]}]},
+ {function,11,ok,0,[{clause,11,[],[],[{atom,11,true}]}]}],
+ {ok,Mod,Bin} = compile:forms(Forms, [report]),
+ [io:put_chars(erl_pp:form(F)) || F <- Forms],
+
+ {Pid1,Ref1} = spawn_monitor(fun() ->
+ code:load_binary(Mod, File, Bin),
+ true = on_load_binary:ok()
+ end),
+ receive {Mod,OnLoadPid} -> ok end,
+ {Pid2,Ref2} = spawn_monitor(fun() ->
+ true = on_load_binary:ok()
+ end),
+ erlang:yield(),
+ OnLoadPid ! go,
+ receive {'DOWN',Ref1,process,Pid1,Exit1} -> ok end,
+ receive {'DOWN',Ref2,process,Pid2,Exit2} -> ok end,
+ normal = Exit1,
+ normal = Exit2,
+ true = code:delete(on_load_binary),
+ false = code:purge(on_load_binary),
+ ok.
+
on_load_embedded(Config) when is_list(Config) ->
try
on_load_embedded_1(Config)
diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl
index 7599a89779..d0d52c5ea7 100644
--- a/lib/kernel/test/erl_prim_loader_SUITE.erl
+++ b/lib/kernel/test/erl_prim_loader_SUITE.erl
@@ -175,10 +175,10 @@ wait_really_started(Node, N) ->
inet_disconnects(doc) -> ["Start a node using the 'inet' loading method, ",
"then lose the connection."];
inet_disconnects(Config) when is_list(Config) ->
- case os:type() of
- vxworks ->
- {comment, "VxWorks: tested separately"};
- _ ->
+ case test_server:is_native(erl_boot_server) of
+ true ->
+ {skip,"erl_boot_server is native"};
+ false ->
?line Name = erl_prim_test_inet_disconnects,
?line Host = host(),
?line Cookie = atom_to_list(erlang:get_cookie()),
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 85346762ac..2b6af7e1fb 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.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
@@ -78,7 +78,7 @@
-export([altname/1]).
--export([large_file/1]).
+-export([large_file/1, large_write/1]).
-export([read_line_1/1, read_line_2/1, read_line_3/1,read_line_4/1]).
@@ -92,6 +92,8 @@
-export([bytes/2, iterate/3]).
+%% System probe functions that might be handy to check from the shell
+-export([disc_free/1, memsize/0]).
-include_lib("test_server/include/test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -106,7 +108,7 @@ all() ->
{group, compression}, {group, links}, copy,
delayed_write, read_ahead, segment_read, segment_write,
ipread, pid2name, interleaved_read_write, otp_5814,
- large_file, read_line_1, read_line_2, read_line_3,
+ large_file, large_write, read_line_1, read_line_2, read_line_3,
read_line_4, standard_io].
groups() ->
@@ -143,6 +145,13 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config) when is_list(Config) ->
+ SaslConfig = case application:start(sasl) of
+ {error, {already_started, sasl}} ->
+ [];
+ ok ->
+ [{sasl,started}]
+ end,
+ ok = application:start(os_mon),
case os:type() of
{win32, _} ->
Priv = ?config(priv_dir, Config),
@@ -154,9 +163,9 @@ init_per_suite(Config) when is_list(Config) ->
{ok, _} ->
[]
end,
- ?FILE_INIT(HasAccessTime++Config);
+ ?FILE_INIT(HasAccessTime++Config++SaslConfig);
_ ->
- ?FILE_INIT(Config)
+ ?FILE_INIT(Config++SaslConfig)
end.
end_per_suite(Config) when is_list(Config) ->
@@ -166,6 +175,13 @@ end_per_suite(Config) when is_list(Config) ->
_ ->
ok
end,
+ application:stop(os_mon),
+ case proplists:get_value(sasl, Config) of
+ started ->
+ application:stop(sasl);
+ _Else ->
+ ok
+ end,
?FILE_FINI(Config).
init_per_testcase(_Func, Config) ->
@@ -394,6 +410,7 @@ make_del_dir(Config) when is_list(Config) ->
%% Don't worry ;-) the parent directory should never be empty, right?
?line case ?FILE_MODULE:del_dir('..') of
{error, eexist} -> ok;
+ {error, eacces} -> ok; %OpenBSD
{error, einval} -> ok %FreeBSD
end,
?line {error, enoent} = ?FILE_MODULE:del_dir(""),
@@ -3287,50 +3304,13 @@ large_file(suite) ->
large_file(doc) ->
["Tests positioning in large files (> 4G)"];
large_file(Config) when is_list(Config) ->
- case {os:type(),os:version()} of
- {{win32,nt},_} ->
- do_large_file(Config);
- {{unix,sunos},{A,B,C}}
- when A == 5, B == 5, C >= 1; A == 5, B >= 6; A >= 6 ->
- do_large_file(Config);
- {{unix,Unix},_} when Unix =/= sunos ->
- N = unix_free(Config),
- io:format("Free: ~w KByte~n", [N]),
- if N < 5 * (1 bsl 20) ->
- %% Less than 5 GByte free
- {skipped,"Less than 5 GByte free"};
- true ->
- do_large_file(Config)
- end;
- _ ->
- {skipped,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
- end.
+ run_large_file_test(Config,
+ fun(Name) -> do_large_file(Name) end,
+ "_large_file").
-unix_free(Config) ->
- Cmd = ["df -k '",?config(priv_dir, Config),"'"],
- DF0 = os:cmd(Cmd),
- io:format("$ ~s~n~s", [Cmd,DF0]),
- [$\n|DF1] = lists:dropwhile(fun ($\n) -> false; (_) -> true end, DF0),
- {ok,[N],_} = io_lib:fread(" ~*s ~d", DF1),
- N.
+do_large_file(Name) ->
+ ?line Watchdog = ?t:timetrap(?t:minutes(20)),
-do_large_file(Config) ->
- ?line Watchdog = ?t:timetrap(?t:minutes(5)),
- %%
- ?line Name = filename:join(?config(priv_dir, Config),
- ?MODULE_STRING ++ "_large_file"),
- ?line Tester = self(),
- Deleter =
- spawn(
- fun() ->
- Mref = erlang:monitor(process, Tester),
- receive
- {'DOWN',Mref,_,_,_} -> ok;
- {Tester,done} -> ok
- end,
- ?FILE_MODULE:delete(Name)
- end),
- %%
?line S = "1234567890",
L = length(S),
R = lists:reverse(S),
@@ -3366,15 +3346,36 @@ do_large_file(Config) ->
?line {ok,R} = ?FILE_MODULE:read(F1, L+1),
?line ok = ?FILE_MODULE:close(F1),
%%
- ?line Mref = erlang:monitor(process, Deleter),
- ?line Deleter ! {Tester,done},
- ?line receive {'DOWN',Mref,_,_,_} -> ok end,
- %%
?line ?t:timetrap_cancel(Watchdog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+large_write(Config) when is_list(Config) ->
+ run_large_file_test(Config,
+ fun(Name) -> do_large_write(Name) end,
+ "_large_write").
+
+do_large_write(Name) ->
+ Memsize = memsize(),
+ io:format("Memsize = ~w Bytes~n", [Memsize]),
+ case {erlang:system_info(wordsize),Memsize} of
+ {4,_} ->
+ {skip,"Needs a 64-bit emulator"};
+ {8,N} when N < 6 bsl 30 ->
+ {skip,
+ "This machine has < 6 GB memory: "
+ ++integer_to_list(N)};
+ {8,_} ->
+ Size = 4*1024*1024*1024+1,
+ Bin = <<0:Size/unit:8>>,
+ ok = file:write_file(Name, Bin),
+ {ok,#file_info{size=Size}} = file:read_file_info(Name),
+ ok
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
response_analysis(Module, Function, Arguments) ->
@@ -3950,3 +3951,67 @@ flush(Msgs) ->
after 0 ->
lists:reverse(Msgs)
end.
+
+%%%
+%%% Support for testing large files.
+%%%
+
+run_large_file_test(Config, Run, Name) ->
+ case {os:type(),os:version()} of
+ {{win32,nt},_} ->
+ do_run_large_file_test(Config, Run, Name);
+ {{unix,sunos},OsVersion} when OsVersion < {5,5,1} ->
+ {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"};
+ {{unix,_},_} ->
+ N = disc_free(?config(priv_dir, Config)),
+ io:format("Free disk: ~w KByte~n", [N]),
+ if N < 5 * (1 bsl 20) ->
+ %% Less than 5 GByte free
+ {skip,"Less than 5 GByte free"};
+ true ->
+ do_run_large_file_test(Config, Run, Name)
+ end;
+ _ ->
+ {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
+ end.
+
+
+do_run_large_file_test(Config, Run, Name0) ->
+ Name = filename:join(?config(priv_dir, Config),
+ ?MODULE_STRING ++ Name0),
+
+ %% Set up a process that will delete this file.
+ Tester = self(),
+ Deleter =
+ spawn(
+ fun() ->
+ Mref = erlang:monitor(process, Tester),
+ receive
+ {'DOWN',Mref,_,_,_} -> ok;
+ {Tester,done} -> ok
+ end,
+ ?FILE_MODULE:delete(Name)
+ end),
+
+ %% Run the test case.
+ Res = Run(Name),
+
+ %% Delete file and finish deleter process.
+ Mref = erlang:monitor(process, Deleter),
+ Deleter ! {Tester,done},
+ receive {'DOWN',Mref,_,_,_} -> ok end,
+
+ Res.
+
+disc_free(Path) ->
+ Data = disksup:get_disk_data(),
+ {_,Tot,Perc} = hd(lists:filter(
+ fun({P,_Size,_Full}) ->
+ lists:prefix(filename:nativename(P),
+ filename:nativename(Path))
+ end, lists:reverse(lists:sort(Data)))),
+ round(Tot * (1-(Perc/100))).
+
+memsize() ->
+ {Tot,_Used,_} = memsup:get_memory_data(),
+ Tot.
diff --git a/lib/kernel/test/inet_res_SUITE_data/run-named b/lib/kernel/test/inet_res_SUITE_data/run-named
index eeca680ab5..211d2c7af7 100755
--- a/lib/kernel/test/inet_res_SUITE_data/run-named
+++ b/lib/kernel/test/inet_res_SUITE_data/run-named
@@ -2,7 +2,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
@@ -47,7 +47,6 @@ CONF_FILE=named.conf
INC_FILE=named_inc.conf
PID_FILE=named.pid
LOG_FILE=named.log
-EXIT_FILE=named.exit
error () {
r=$?
@@ -150,7 +149,6 @@ cat >>"$CONF_FILE" <<-CONF_FILE
( cd "$SRCDIR" && ls -1 ) | while read f; do
cp -fp "$SRCDIR/$f" .
done
-rm -f "$EXIT_FILE"
# Start nameserver
echo "Cwd: `pwd`"
@@ -158,19 +156,20 @@ echo "Nameserver: $NAMED_VER"
echo "Port: $2"
echo "ZoneDir: $3"
echo "Command: $NAMED $NAMED_FG -c $CONF_FILE"
-($NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null; \
- echo "$?" >"$EXIT_FILE")&
+$NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null &
NAMED_PID=$!
-trap "kill -TERM $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \
+echo "Pid: $NAMED_PID"
+trap "kill $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \
0 1 2 3 15
+
sleep 5 # Give name server time to load its zone files
-if [ -f "$EXIT_FILE" ]; then
- ERROR="`cat "$EXIT_FILE"`"
- (exit "$ERROR")& error "$NAMED returned $ERROR on start"
-else
+
+if ps -p $NAMED_PID >/dev/null 2>&1 || ps p $NAMED_PID >/dev/null 2>&1; then
echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED_PID]..."
while read LINE; do
test :"$LINE" = :'quit' && break
done
+ echo "Closing: Terminating nameserver..."
+else
+ error "$NAMED failed to start"
fi
-echo "Closing: Terminating nameserver..."
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index ccf26ee034..3e2202922c 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -52,6 +52,10 @@
list_dir_limit/1]).
-export([advise/1]).
+-export([large_write/1]).
+
+%% System probe functions that might be handy to check from the shell
+-export([unix_free/1]).
-include_lib("test_server/include/test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -83,7 +87,7 @@ groups() ->
cur_dir_1a, cur_dir_1b]},
{files, [],
[{group, open}, {group, pos}, {group, file_info},
- truncate, sync, datasync, advise]},
+ truncate, sync, datasync, advise, large_write]},
{open, [],
[open1, modes, close, access, read_write, pread_write,
append, exclusive]},
@@ -290,6 +294,7 @@ make_del_dir(Config, Handle, Suffix) ->
%% Don't worry ;-) the parent directory should never be empty, right?
?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of
{error, eexist} -> ok;
+ {error, eacces} -> ok; %OpenBSD
{error, einval} -> ok %FreeBSD
end,
?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]),
@@ -1322,6 +1327,41 @@ advise(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+large_write(Config) when is_list(Config) ->
+ run_large_file_test(Config,
+ fun(Name) -> do_large_write(Name) end,
+ "_large_write").
+
+do_large_write(Name) ->
+ Dog = test_server:timetrap(test_server:minutes(60)),
+ ChunkSize = (256 bsl 20) + 1, % 256 M + 1
+ Chunks = 16, % times 16 -> 4 G + 16
+ Base = 100,
+ Interleave = lists:seq(Base+1, Base+Chunks),
+ Chunk = <<0:ChunkSize/unit:8>>,
+ Data = zip_data(lists:duplicate(Chunks, Chunk), Interleave),
+ Size = Chunks * ChunkSize + Chunks, % 4 G + 32
+ Wordsize = erlang:system_info(wordsize),
+ case prim_file:write_file(Name, Data) of
+ ok when Wordsize =:= 8 ->
+ {ok,#file_info{size=Size}} = file:read_file_info(Name),
+ {ok,Fd} = prim_file:open(Name, [read]),
+ check_large_write(Dog, Fd, ChunkSize, 0, Interleave);
+ {error,einval} when Wordsize =:= 4 ->
+ ok
+ end.
+
+check_large_write(Dog, Fd, ChunkSize, Pos, [X|Interleave]) ->
+ Pos1 = Pos + ChunkSize,
+ {ok,Pos1} = prim_file:position(Fd, {cur,ChunkSize}),
+ {ok,[X]} = prim_file:read(Fd, 1),
+ check_large_write(Dog, Fd, ChunkSize, Pos1+1, Interleave);
+check_large_write(Dog, Fd, _, _, []) ->
+ eof = prim_file:read(Fd, 1),
+ test_server:timetrap_cancel(Dog),
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2044,3 +2084,70 @@ list_dir_limit_cleanup(Dir, Handle, N, Cnt) ->
?PRIM_FILE:delete(Handle, filename:join(Dir, Name)),
list_dir_limit_cleanup(Dir, Handle, N, Cnt+1).
+%%%
+%%% Support for testing large files.
+%%%
+
+run_large_file_test(Config, Run, Name) ->
+ case {os:type(),os:version()} of
+ {{win32,nt},_} ->
+ do_run_large_file_test(Config, Run, Name);
+ {{unix,sunos},OsVersion} when OsVersion < {5,5,1} ->
+ {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"};
+ {{unix,_},_} ->
+ N = unix_free(?config(priv_dir, Config)),
+ io:format("Free disk: ~w KByte~n", [N]),
+ if N < 5 bsl 20 ->
+ %% Less than 5 GByte free
+ {skip,"Less than 5 GByte free disk"};
+ true ->
+ do_run_large_file_test(Config, Run, Name)
+ end;
+ _ ->
+ {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
+ end.
+
+
+do_run_large_file_test(Config, Run, Name0) ->
+ Name = filename:join(?config(priv_dir, Config),
+ ?MODULE_STRING ++ Name0),
+
+ %% Set up a process that will delete this file.
+ Tester = self(),
+ Deleter =
+ spawn(
+ fun() ->
+ Mref = erlang:monitor(process, Tester),
+ receive
+ {'DOWN',Mref,_,_,_} -> ok;
+ {Tester,done} -> ok
+ end,
+ prim_file:delete(Name)
+ end),
+
+ %% Run the test case.
+ Res = Run(Name),
+
+ %% Delete file and finish deleter process.
+ Mref = erlang:monitor(process, Deleter),
+ Deleter ! {Tester,done},
+ receive {'DOWN',Mref,_,_,_} -> ok end,
+
+ Res.
+
+unix_free(Path) ->
+ Cmd = ["df -k '",Path,"'"],
+ DF0 = os:cmd(Cmd),
+ io:format("$ ~s~n~s", [Cmd,DF0]),
+ Lines = re:split(DF0, "\n", [trim,{return,list}]),
+ Last = lists:last(Lines),
+ RE = "^[^\\s]*\\s+\\d+\\s+\\d+\\s+(\\d+)",
+ {match,[Avail]} = re:run(Last, RE, [{capture,all_but_first,list}]),
+ list_to_integer(Avail).
+
+zip_data([A|As], [B|Bs]) ->
+ [[A,B]|zip_data(As, Bs)];
+zip_data([], Bs) ->
+ Bs;
+zip_data(As, []) ->
+ As.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 76c62ece67..76d3003ff4 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.15
+KERNEL_VSN = 2.15.1
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index de4811f8e4..a22c95d454 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.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
@@ -66,7 +66,7 @@
-record(queue, {oid, tid, op, pid, lucky}).
-%% mnesia_held_locks: contain {Oid, Op, Tid} entries (bag)
+%% mnesia_held_locks: contain {Oid, MaxLock, [{Op, Tid}]} entries
-define(match_oid_held_locks(Oid), {Oid, '_', '_'}).
%% mnesia_tid_locks: contain {Tid, Oid, Op} entries (bag)
-define(match_oid_tid_locks(Tid), {Tid, '_', '_'}).
@@ -83,7 +83,7 @@ start() ->
init(Parent) ->
register(?MODULE, self()),
process_flag(trap_exit, true),
- ?ets_new_table(mnesia_held_locks, [bag, private, named_table]),
+ ?ets_new_table(mnesia_held_locks, [ordered_set, private, named_table]),
?ets_new_table(mnesia_tid_locks, [bag, private, named_table]),
?ets_new_table(mnesia_sticky_locks, [set, private, named_table]),
?ets_new_table(mnesia_lock_queue, [bag, private, named_table, {keypos, 2}]),
@@ -235,10 +235,17 @@ loop(State) ->
loop(State)
end.
-set_lock(Tid, Oid, Op) ->
- ?dbg("Granted ~p ~p ~p~n", [Tid,Oid,Op]),
- ?ets_insert(mnesia_held_locks, {Oid, Op, Tid}),
- ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}).
+set_lock(Tid, Oid, Op, []) ->
+ ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}),
+ ?ets_insert(mnesia_held_locks, {Oid, Op, [{Op, Tid}]});
+set_lock(Tid, Oid, read, [{Oid, Prev, Items}]) ->
+ ?ets_insert(mnesia_tid_locks, {Tid, Oid, read}),
+ ?ets_insert(mnesia_held_locks, {Oid, Prev, [{read, Tid}|Items]});
+set_lock(Tid, Oid, write, [{Oid, _Prev, Items}]) ->
+ ?ets_insert(mnesia_tid_locks, {Tid, Oid, write}),
+ ?ets_insert(mnesia_held_locks, {Oid, write, [{write, Tid}|Items]});
+set_lock(Tid, Oid, Op, undefined) ->
+ set_lock(Tid, Oid, Op, ?ets_lookup(mnesia_held_locks, Oid)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Acquire locks
@@ -261,14 +268,14 @@ try_lock(Tid, Op, Pid, Oid) ->
try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) ->
case can_lock(Tid, Lock, Oid, {no, bad_luck}) of
- yes ->
- Reply = grant_lock(Tid, SimpleOp, Lock, Oid),
+ {yes, Default} ->
+ Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default),
reply(Pid, Reply);
- {no, Lucky} ->
+ {{no, Lucky},_} ->
C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky},
?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]),
reply(Pid, {not_granted, C});
- {queue, Lucky} ->
+ {{queue, Lucky},_} ->
?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]),
%% Append to queue: Nice place for trace output
?ets_insert(mnesia_lock_queue,
@@ -277,16 +284,16 @@ try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) ->
?ets_insert(mnesia_tid_locks, {Tid, Oid, {queued, Op}})
end.
-grant_lock(Tid, read, Lock, Oid = {Tab, Key})
+grant_lock(Tid, read, Lock, Oid = {Tab, Key}, Default)
when Key /= ?ALL, Tab /= ?GLOBAL ->
case node(Tid#tid.pid) == node() of
true ->
- set_lock(Tid, Oid, Lock),
+ set_lock(Tid, Oid, Lock, Default),
{granted, lookup_in_client};
false ->
try
Val = mnesia_lib:db_get(Tab, Key), %% lookup as well
- set_lock(Tid, Oid, Lock),
+ set_lock(Tid, Oid, Lock, Default),
{granted, Val}
catch _:_Reason ->
%% Table has been deleted from this node,
@@ -296,19 +303,19 @@ grant_lock(Tid, read, Lock, Oid = {Tab, Key})
{not_granted, C}
end
end;
-grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}) ->
+grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}, Default) ->
try
Res = ix_read_res(Tab, IxKey,Pos),
- set_lock(Tid, Oid, Lock),
+ set_lock(Tid, Oid, Lock, Default),
{granted, Res, [?ALL]}
catch _:_ ->
{not_granted, {no_exists, Tab, {index, [Pos]}}}
end;
-grant_lock(Tid, read, Lock, Oid) ->
- set_lock(Tid, Oid, Lock),
+grant_lock(Tid, read, Lock, Oid, Default) ->
+ set_lock(Tid, Oid, Lock, Default),
{granted, ok};
-grant_lock(Tid, write, Lock, Oid) ->
- set_lock(Tid, Oid, Lock),
+grant_lock(Tid, write, Lock, Oid, Default) ->
+ set_lock(Tid, Oid, Lock, Default),
granted.
%% 1) Impose an ordering on all transactions favour old (low tid) transactions
@@ -318,55 +325,40 @@ grant_lock(Tid, write, Lock, Oid) ->
%% 3) TabLocks is the problem :-) They should not starve and not deadlock
%% handle tablocks in queue as they had locks on unlocked records.
-can_lock(Tid, read, {Tab, Key}, AlreadyQ) when Key /= ?ALL ->
- %% The key is bound, no need for the other BIF
- Oid = {Tab, Key},
- ObjLocks = ?ets_match_object(mnesia_held_locks, {Oid, write, '_'}),
- TabLocks = ?ets_match_object(mnesia_held_locks, {{Tab, ?ALL}, write, '_'}),
- check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, read);
+can_lock(Tid, read, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL ->
+ ObjLocks = ?ets_lookup(mnesia_held_locks, Oid),
+ TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}),
+ {check_lock(Tid, Oid,
+ filter_write(ObjLocks),
+ filter_write(TabLocks),
+ yes, AlreadyQ, read),
+ ObjLocks};
can_lock(Tid, read, Oid, AlreadyQ) -> % Whole tab
Tab = element(1, Oid),
ObjLocks = ?ets_match_object(mnesia_held_locks, {{Tab, '_'}, write, '_'}),
- check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read);
+ {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read), undefined};
-can_lock(Tid, write, {Tab, Key}, AlreadyQ) when Key /= ?ALL ->
- Oid = {Tab, Key},
+can_lock(Tid, write, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL ->
ObjLocks = ?ets_lookup(mnesia_held_locks, Oid),
TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}),
- check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write);
+ {check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write), ObjLocks};
can_lock(Tid, write, Oid, AlreadyQ) -> % Whole tab
Tab = element(1, Oid),
ObjLocks = ?ets_match_object(mnesia_held_locks, ?match_oid_held_locks({Tab, '_'})),
- check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write).
+ {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write), undefined}.
+
+filter_write([{_, read, _}]) -> [];
+filter_write(Res) -> Res.
%% Check held locks for conflicting locks
-check_lock(Tid, Oid, [Lock | Locks], TabLocks, X, AlreadyQ, Type) ->
- case element(3, Lock) of
- Tid ->
- check_lock(Tid, Oid, Locks, TabLocks, X, AlreadyQ, Type);
- WaitForTid ->
- Queue = allowed_to_be_queued(WaitForTid,Tid),
- if Queue == true ->
- check_lock(Tid, Oid, Locks, TabLocks, {queue, WaitForTid}, AlreadyQ, Type);
- Tid#tid.pid == WaitForTid#tid.pid ->
- dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n",
- [Oid, Lock, Tid, WaitForTid]),
- %% Test..
- {Tab, _Key} = Oid,
- HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= [])
- orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []),
- if
- HaveQ ->
- {no, WaitForTid};
- true ->
- check_lock(Tid,Oid,Locks,TabLocks,{queue,WaitForTid},AlreadyQ,Type)
- end;
- %%{no, WaitForTid}; Safe solution
- true ->
- {no, WaitForTid}
- end
+check_lock(Tid, Oid, [{_, _, Lock} | Locks], TabLocks, _X, AlreadyQ, Type) ->
+ case can_queue(Lock, Tid, Oid, _X) of
+ {no, _} = Res ->
+ Res;
+ Res ->
+ check_lock(Tid, Oid, Locks, TabLocks, Res, AlreadyQ, Type)
end;
check_lock(_, _, [], [], X, {queue, bad_luck}, _) ->
@@ -375,8 +367,7 @@ check_lock(_, _, [], [], X, {queue, bad_luck}, _) ->
check_lock(_, _, [], [], X = {queue, _Tid}, _AlreadyQ, _) ->
X;
-check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) ->
- {Tab, Key} = Oid,
+check_lock(Tid, Oid = {Tab, Key}, [], [], X, AlreadyQ, Type) ->
if
Type == write ->
check_queue(Tid, Tab, X, AlreadyQ);
@@ -403,6 +394,26 @@ check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) ->
check_lock(Tid, Oid, [], TabLocks, X, AlreadyQ, Type) ->
check_lock(Tid, Oid, TabLocks, [], X, AlreadyQ, Type).
+can_queue([{_Op, Tid}|Locks], Tid, Oid, Res) ->
+ can_queue(Locks, Tid, Oid, Res);
+can_queue([{Op, WaitForTid}|Locks], Tid, Oid = {Tab, _}, _) ->
+ case allowed_to_be_queued(WaitForTid,Tid) of
+ true when Tid#tid.pid == WaitForTid#tid.pid ->
+ dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n",
+ [Oid, Op, Tid, WaitForTid]),
+ HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= [])
+ orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []),
+ case HaveQ of
+ true -> {no, WaitForTid};
+ false -> can_queue(Locks, Tid, Oid, {queue, WaitForTid})
+ end;
+ true ->
+ can_queue(Locks, Tid, Oid, {queue, WaitForTid});
+ false ->
+ {no, WaitForTid}
+ end;
+can_queue([], _, _, Res) -> Res.
+
%% True if WaitForTid > Tid -> % Important order
allowed_to_be_queued(WaitForTid, Tid) ->
case get(pid_sort_order) of
@@ -456,14 +467,14 @@ set_read_lock_on_all_keys(Tid, From, Tab, IxKey, Pos) ->
Op = {ix_read,IxKey, Pos},
Lock = read,
case can_lock(Tid, Lock, Oid, {no, bad_luck}) of
- yes ->
- Reply = grant_lock(Tid, Op, Lock, Oid),
+ {yes, Default} ->
+ Reply = grant_lock(Tid, Op, Lock, Oid, Default),
reply(From, Reply);
- {no, Lucky} ->
+ {{no, Lucky},_} ->
C = #cyclic{op = Op, lock = Lock, oid = Oid, lucky = Lucky},
?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]),
reply(From, {not_granted, C});
- {queue, Lucky} ->
+ {{queue, Lucky},_} ->
?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]),
%% Append to queue: Nice place for trace output
?ets_insert(mnesia_lock_queue,
@@ -520,14 +531,24 @@ release_locks([]) ->
release_lock({Tid, Oid, {queued, _}}) ->
?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = '_',
pid = '_', lucky = '_'});
-release_lock({Tid, Oid, Op}) ->
- if
- Op == write ->
- ?ets_delete(mnesia_held_locks, Oid);
- Op == read ->
- ets:delete_object(mnesia_held_locks, {Oid, Op, Tid})
+release_lock({_Tid, Oid, write}) ->
+ ?ets_delete(mnesia_held_locks, Oid);
+release_lock({Tid, Oid, read}) ->
+ case ?ets_lookup(mnesia_held_locks, Oid) of
+ [{Oid, Prev, Locks0}] ->
+ case remove_tid(Locks0, Tid, []) of
+ [] -> ?ets_delete(mnesia_held_locks, Oid);
+ Locks -> ?ets_insert(mnesia_held_locks, {Oid, Prev, Locks})
+ end;
+ [] -> ok
end.
+remove_tid([{_Op, Tid}|Ls], Tid, Acc) ->
+ remove_tid(Ls,Tid, Acc);
+remove_tid([Keep|Ls], Tid, Acc) ->
+ remove_tid(Ls,Tid, [Keep|Acc]);
+remove_tid([], _, Acc) -> Acc.
+
rearrange_queue([{_Tid, {Tab, Key}, _} | Locks]) ->
if
Key /= ?ALL->
@@ -592,18 +613,18 @@ try_waiter({queue, Oid, Tid, Op, ReplyTo, _}) ->
try_waiter(Oid, Op, SimpleOp, Lock, ReplyTo, Tid) ->
case can_lock(Tid, Lock, Oid, {queue, bad_luck}) of
- yes ->
+ {yes, Default} ->
%% Delete from queue: Nice place for trace output
?ets_match_delete(mnesia_lock_queue,
#queue{oid=Oid, tid = Tid, op = Op,
pid = ReplyTo, lucky = '_'}),
- Reply = grant_lock(Tid, SimpleOp, Lock, Oid),
+ Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default),
reply(ReplyTo,Reply),
locked;
- {queue, _Why} ->
+ {{queue, _Why}, _} ->
?dbg("Keep ~p ~p ~p ~p~n", [Tid, Oid, Lock, _Why]),
queued; % Keep waiter in queue
- {no, Lucky} ->
+ {{no, Lucky}, _} ->
C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky},
verbose("** WARNING ** Restarted transaction, possible deadlock in lock queue ~w: cyclic = ~w~n",
[Tid, C]),
@@ -1116,11 +1137,23 @@ rec_requests([], _Oid, _Store) ->
get_held_locks() ->
?MODULE ! {get_table, self(), mnesia_held_locks},
- receive {mnesia_held_locks, Locks} -> Locks end.
+ Locks = receive {mnesia_held_locks, Ls} -> Ls after 5000 -> [] end,
+ rewrite_locks(Locks, []).
+
+rewrite_locks([{Oid, _, Ls}|Locks], Acc0) ->
+ Acc = rewrite_locks(Ls, Oid, Acc0),
+ rewrite_locks(Locks, Acc);
+rewrite_locks([], Acc) ->
+ lists:reverse(Acc).
+
+rewrite_locks([{Op, Tid}|Ls], Oid, Acc) ->
+ rewrite_locks(Ls, Oid, [{Oid, Op, Tid}|Acc]);
+rewrite_locks([], _, Acc) ->
+ Acc.
get_lock_queue() ->
?MODULE ! {get_table, self(), mnesia_lock_queue},
- Q = receive {mnesia_lock_queue, Locks} -> Locks end,
+ Q = receive {mnesia_lock_queue, Locks} -> Locks after 5000 -> [] end,
[{Oid, Op, Pid, Tid, WFT} || {queue, Oid, Tid, Op, Pid, WFT} <- Q].
do_stop() ->
diff --git a/lib/observer/src/etop_gui.erl b/lib/observer/src/etop_gui.erl
index ff1b8078ad..9248d67344 100644
--- a/lib/observer/src/etop_gui.erl
+++ b/lib/observer/src/etop_gui.erl
@@ -17,6 +17,13 @@
%% %CopyrightEnd%
%%
-module(etop_gui).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
+
-author('[email protected]').
-export([init/1,stop/1]).
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 967baa5c7a..5260861497 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.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
@@ -339,17 +339,37 @@ user_term(Parent, Title, Default) ->
?wxID_OK ->
Str = wxTextEntryDialog:getValue(Dialog),
wxTextEntryDialog:destroy(Dialog),
- parse_string(Str);
+ parse_string(ensure_last_is_dot(Str));
?wxID_CANCEL ->
- wxTextEntryDialog:destroy(Dialog)
+ wxTextEntryDialog:destroy(Dialog),
+ cancel
end.
parse_string(Str) ->
try
- {ok, Tokens, _} = erl_scan:string(Str),
- erl_parse:parse_term(Tokens)
- catch _:{badmatch, {error, {_, _, Err}}} ->
- {error, ["Parse error: ", Err]};
- _Err ->
+ Tokens = case erl_scan:string(Str) of
+ {ok, Ts, _} -> Ts;
+ {error, {_SLine, SMod, SError}, _} ->
+ throw(io_lib:format("~s", [SMod:format_error(SError)]))
+ end,
+ case erl_parse:parse_term(Tokens) of
+ {error, {_PLine, PMod, PError}} ->
+ throw(io_lib:format("~s", [PMod:format_error(PError)]));
+ Res -> Res
+ end
+ catch
+ throw:ErrStr ->
+ {error, ErrStr};
+ _:_Err ->
{error, ["Syntax error in: ", Str]}
end.
+
+ensure_last_is_dot([]) ->
+ ".";
+ensure_last_is_dot(String) ->
+ case lists:last(String) =:= $. of
+ true ->
+ String;
+ false ->
+ String ++ "."
+ end.
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index a4c5914c49..ec08d3aff1 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.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
@@ -124,9 +124,14 @@ code_change(_, _, State) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_process_page(Panel, Pid) ->
- Fields = process_info_fields(Pid),
- {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields),
- {FPanel, fun() -> observer_lib:update_info(UpFields, process_info_fields(Pid)) end}.
+ 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
+ end}.
init_text_page(Parent) ->
Style = ?wxTE_MULTILINE bor ?wxTE_RICH2 bor ?wxTE_READONLY,
@@ -144,16 +149,20 @@ init_message_page(Parent, Pid) ->
Number+1}
end,
Update = fun() ->
- {messages,RawMessages} =
- observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, messages]),
- {Messages,_} = lists:mapfoldl(Format, 1, RawMessages),
- Last = wxTextCtrl:getLastPosition(Text),
- wxTextCtrl:remove(Text, 0, Last),
- case Messages =:= [] of
- true ->
- wxTextCtrl:writeText(Text, "No messages");
- false ->
- wxTextCtrl:writeText(Text, Messages)
+ case observer_wx:try_rpc(node(Pid), erlang, process_info,
+ [Pid, messages])
+ of
+ {messages,RawMessages} ->
+ {Messages,_} = lists:mapfoldl(Format, 1, RawMessages),
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ case Messages =:= [] of
+ true ->
+ wxTextCtrl:writeText(Text, "No messages");
+ false ->
+ wxTextCtrl:writeText(Text, Messages)
+ end;
+ _ -> ok
end
end,
Update(),
@@ -162,12 +171,15 @@ init_message_page(Parent, Pid) ->
init_dict_page(Parent, Pid) ->
Text = init_text_page(Parent),
Update = fun() ->
- {dictionary,RawDict} =
- observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]),
- Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict],
- Last = wxTextCtrl:getLastPosition(Text),
- wxTextCtrl:remove(Text, 0, Last),
- wxTextCtrl:writeText(Text, Dict)
+ case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary])
+ of
+ {dictionary,RawDict} ->
+ Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict],
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ wxTextCtrl:writeText(Text, Dict);
+ _ -> ok
+ end
end,
Update(),
{Text, Update}.
@@ -183,24 +195,29 @@ init_stack_page(Parent, Pid) ->
wxListCtrl:setColumnWidth(LCtrl, 1, 300),
wxListItem:destroy(Li),
Update = fun() ->
- {current_stacktrace,RawBt} =
- observer_wx:try_rpc(node(Pid), erlang, process_info,
- [Pid, current_stacktrace]),
- wxListCtrl:deleteAllItems(LCtrl),
- wx:foldl(fun({M, F, A, Info}, Row) ->
- _Item = wxListCtrl:insertItem(LCtrl, Row, ""),
- ?EVEN(Row) andalso
- wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN),
- wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})),
- FileLine = case Info of
- [{file,File},{line,Line}] ->
- io_lib:format("~s:~w", [File,Line]);
- _ ->
- []
- end,
- wxListCtrl:setItem(LCtrl, Row, 1, FileLine),
- Row+1
- end, 0, RawBt)
+ case observer_wx:try_rpc(node(Pid), erlang, process_info,
+ [Pid, current_stacktrace])
+ of
+ {current_stacktrace,RawBt} ->
+ observer_wx:try_rpc(node(Pid), erlang, process_info,
+ [Pid, current_stacktrace]),
+ wxListCtrl:deleteAllItems(LCtrl),
+ wx:foldl(fun({M, F, A, Info}, Row) ->
+ _Item = wxListCtrl:insertItem(LCtrl, Row, ""),
+ ?EVEN(Row) andalso
+ wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN),
+ wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})),
+ FileLine = case Info of
+ [{file,File},{line,Line}] ->
+ io_lib:format("~s:~w", [File,Line]);
+ _ ->
+ []
+ end,
+ wxListCtrl:setItem(LCtrl, Row, 1, FileLine),
+ Row+1
+ end, 0, RawBt);
+ _ -> ok
+ end
end,
Resize = fun(#wx{event=#wxSize{size={W,_}}},Ev) ->
wxEvent:skip(Ev),
@@ -216,7 +233,6 @@ create_menus(MenuBar) ->
observer_lib:create_menus(Menus, MenuBar, new_window).
process_info_fields(Pid) ->
- RawInfo = observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]),
Struct = [{"Overview",
[{"Initial Call", initial_call},
{"Current Function", current_function},
@@ -246,7 +262,12 @@ process_info_fields(Pid) ->
{"GC Min Heap Size", {bytes, get_gc_info(min_heap_size)}},
{"GC FullSweep After", get_gc_info(fullsweep_after)}
]}],
- observer_lib:fill_info(Struct, RawInfo).
+ case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]) of
+ RawInfo when is_list(RawInfo) ->
+ observer_lib:fill_info(Struct, RawInfo);
+ _ ->
+ ok
+ end.
item_list() ->
[ %% backtrace,
diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl
index 31d5f3d632..f432173f57 100644
--- a/lib/observer/src/observer_tv_table.erl
+++ b/lib/observer/src/observer_tv_table.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
@@ -58,7 +58,7 @@
source,
tab,
attrs,
- timer
+ timer={false, 30}
}).
-record(opt,
@@ -268,8 +268,8 @@ handle_event(#wx{id=?ID_DELETE},
handle_event(#wx{id=?wxID_CLOSE}, State) ->
{stop, normal, State};
-handle_event(Help = #wx{id=?wxID_HELP}, State = #state{parent=Parent}) ->
- Parent ! Help,
+handle_event(Help = #wx{id=?wxID_HELP}, State) ->
+ observer ! Help,
{noreply, State};
handle_event(#wx{id=?GOTO_ENTRY, event=#wxCommand{cmdString=Str}},
@@ -374,40 +374,51 @@ handle_event(#wx{id=?ID_REFRESH_INTERVAL},
Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60),
{noreply, State#state{timer=Timer}};
-handle_event(Event, State) ->
- io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]),
+handle_event(_Event, State) ->
+ %io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]),
{noreply, State}.
-handle_sync_event(Event, _Obj, _State) ->
- io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]),
+handle_sync_event(_Event, _Obj, _State) ->
+ %io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]),
ok.
-handle_call(Event, From, State) ->
- io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]),
+handle_call(_Event, _From, State) ->
+ %io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]),
{noreply, State}.
-handle_cast(Event, State) ->
- io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]),
+handle_cast(_Event, State) ->
+ %io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]),
{noreply, State}.
handle_info({no_rows, N}, State = #state{grid=Grid, status=StatusBar}) ->
wxListCtrl:setItemCount(Grid, N),
wxStatusBar:setStatusText(StatusBar, io_lib:format("Objects: ~w",[N])),
{noreply, State};
+
handle_info({new_cols, New}, State = #state{grid=Grid, columns=Cols0}) ->
Cols = add_columns(Grid, Cols0, New),
{noreply, State#state{columns=Cols}};
+
handle_info({refresh, Min, Max}, State = #state{grid=Grid}) ->
wxListCtrl:refreshItems(Grid, Min, Max),
{noreply, State};
+
+handle_info(refresh_interval, State = #state{pid=Pid}) ->
+ Pid ! refresh,
+ {noreply, State};
+
handle_info({error, Error}, State = #state{frame=Frame}) ->
- Dlg = wxMessageDialog:new(Frame, Error),
+ ErrorStr =
+ try io_lib:format("~ts", [Error]), Error
+ catch _:_ -> io_lib:format("~p", [Error])
+ end,
+ Dlg = wxMessageDialog:new(Frame, ErrorStr),
wxMessageDialog:showModal(Dlg),
wxMessageDialog:destroy(Dlg),
{noreply, State};
-handle_info(Event, State) ->
- io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, Event]),
+handle_info(_Event, State) ->
+ %% io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, _Event]),
{noreply, State}.
terminate(_Event, #state{pid=Pid, attrs=Attrs}) ->
@@ -588,19 +599,22 @@ search([Str, Row, Dir0, CaseSens],
true -> [];
false -> [caseless]
end,
- {ok, Re} = re:compile(Str, Opt),
Dir = case Dir0 of
true -> 1;
false -> -1
end,
- Res = search(Row, Dir, Re, Table),
+ Res = case re:compile(Str, Opt) of
+ {ok, Re} ->
+ search(Row, Dir, Re, Table);
+ {error, _} -> false
+ end,
Parent ! {self(), Res},
S#holder{search=Res}.
search(Row, Dir, Re, Table) ->
Res = try lists:nth(Row+1, Table) of
Term ->
- Str = io_lib:format("~w", [Term]),
+ Str = format(Term),
re:run(Str, Re)
catch _:_ -> no_more
end,
@@ -613,9 +627,9 @@ search(Row, Dir, Re, Table) ->
get_row(From, Row, Col, Table) ->
case lists:nth(Row+1, Table) of
[Object|_] when Col =:= all ->
- From ! {self(), io_lib:format("~w", [Object])};
+ From ! {self(), format(Object)};
[Object|_] when tuple_size(Object) >= Col ->
- From ! {self(), io_lib:format("~w", [element(Col, Object)])};
+ From ! {self(), format(element(Col, Object))};
_ ->
From ! {self(), ""}
end.
@@ -724,3 +738,58 @@ key_pos(Node, ets, TabId) ->
KeyPos = rpc:call(Node, ets, info, [TabId, keypos]),
is_integer(KeyPos) orelse throw(node_or_table_down),
KeyPos.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+format(Tuple) when is_tuple(Tuple) ->
+ [${ |format_tuple(Tuple, 1, tuple_size(Tuple))];
+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(Float) when is_float(Float) ->
+ io_lib:format("~.3g", [Float]);
+format(Term) ->
+ io_lib:format("~w", [Term]).
+
+format_tuple(Tuple, I, Max) when I < Max ->
+ [format(element(I, Tuple)), $,|format_tuple(Tuple, I+1, Max)];
+format_tuple(Tuple, Max, Max) ->
+ [format(element(Max, Tuple)), $}];
+format_tuple(_Tuple, 1, 0) ->
+ [$}].
+
+format_list([]) -> "[]";
+format_list(List) ->
+ case printable_list(List) of
+ true -> io_lib:format("\"~ts\"", [List]);
+ false -> [$[ | make_list(List)]
+ end.
+
+make_list([Last]) ->
+ [format(Last), $]];
+make_list([Head|Tail]) ->
+ [format(Head), $,|make_list(Tail)].
+
+%% printable_list([Char]) -> bool()
+%% Return true if CharList is a list of printable characters, else
+%% false.
+
+printable_list([C|Cs]) when is_integer(C), C >= $ , C =< 255 ->
+ printable_list(Cs);
+printable_list([$\n|Cs]) ->
+ printable_list(Cs);
+printable_list([$\r|Cs]) ->
+ printable_list(Cs);
+printable_list([$\t|Cs]) ->
+ printable_list(Cs);
+printable_list([$\v|Cs]) ->
+ printable_list(Cs);
+printable_list([$\b|Cs]) ->
+ printable_list(Cs);
+printable_list([$\f|Cs]) ->
+ printable_list(Cs);
+printable_list([$\e|Cs]) ->
+ printable_list(Cs);
+printable_list([]) -> true;
+printable_list(_Other) -> false. %Everything else is false
diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl
index ad3e8c14ab..b276965f83 100644
--- a/lib/observer/src/observer_tv_wx.erl
+++ b/lib/observer/src/observer_tv_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
@@ -313,7 +313,7 @@ display_table_info(Parent0, Node, Source, Table) ->
list_to_strings([]) -> "None";
list_to_strings([A]) -> integer_to_list(A);
-list_to_strings([A,B]) ->
+list_to_strings([A|B]) ->
integer_to_list(A) ++ " ," ++ list_to_strings(B).
handle_error(Foo) ->
diff --git a/lib/observer/test/etop_SUITE.erl b/lib/observer/test/etop_SUITE.erl
index a0782ea809..a277453620 100644
--- a/lib/observer/test/etop_SUITE.erl
+++ b/lib/observer/test/etop_SUITE.erl
@@ -57,11 +57,14 @@ end_per_group(_GroupName, Config) ->
Config.
-text(suite) ->
- [];
-text(doc) ->
- ["Start etop with text presentation"];
-text(Config) when is_list(Config) ->
+%% Start etop with text presentation
+text(_) ->
+ case test_server:is_native(lists) of
+ true -> {skip,"Native libs -- tracing does not work"};
+ false -> text()
+ end.
+
+text() ->
?line {ok,Node} = ?t:start_node(node2,peer,[]),
%% Must spawn this process, else the test case will never end.
diff --git a/lib/orber/src/orber_ifr.erl b/lib/orber/src/orber_ifr.erl
index c23374cd68..6799bc1db4 100644
--- a/lib/orber/src/orber_ifr.erl
+++ b/lib/orber/src/orber_ifr.erl
@@ -478,7 +478,7 @@ get_module(Id, Type) ->
What ->
orber:dbg("[~p] ~p:get_module(~p, ~p).~n"
"Id doesn't exist, mismatch Id vs Type or DB error: ~p",
- [?LINE, ?MODULE, Id, What], ?DEBUG_LEVEL),
+ [?LINE, ?MODULE, Id, Type, What], ?DEBUG_LEVEL),
corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE})
end.
diff --git a/lib/orber/src/orber_tb.erl b/lib/orber/src/orber_tb.erl
index eee67296d7..d3e3a8497d 100644
--- a/lib/orber/src/orber_tb.erl
+++ b/lib/orber/src/orber_tb.erl
@@ -209,7 +209,7 @@ check_illegal_tcp_options([binary |T], IllegalOpts) ->
check_illegal_tcp_options(T,[binary |IllegalOpts]);
check_illegal_tcp_options([{reuseaddr, V} |T], IllegalOpts) ->
check_illegal_tcp_options(T,[{reuseaddr, V} |IllegalOpts]);
-check_illegal_tcp_options([H|T], IllegalOpts) ->
+check_illegal_tcp_options([_H|T], IllegalOpts) ->
check_illegal_tcp_options(T, IllegalOpts).
%%----------------------------------------------------------------------
diff --git a/lib/orber/test/orber_SUITE.erl b/lib/orber/test/orber_SUITE.erl
index be6ffa201c..72b0db1e0d 100644
--- a/lib/orber/test/orber_SUITE.erl
+++ b/lib/orber/test/orber_SUITE.erl
@@ -20,7 +20,6 @@
-module(orber_SUITE).
-include_lib("test_server/include/test_server.hrl").
-
-define(default_timeout, ?t:minutes(15)).
-define(application, orber).
@@ -31,7 +30,11 @@
% Test cases must be exported.
-export([app_test/1, undefined_functions/1, install_load_order/1,
- install_local_content/1]).
+ install_local_content/1,
+ otp_9887/1]).
+
+%% Exporting error handler callbacks for use in otp_9887
+-export([init/1, handle_event/2]).
%%
%% all/1
@@ -40,7 +43,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[app_test, undefined_functions, install_load_order,
- install_local_content].
+ install_local_content,
+ otp_9887].
groups() ->
[].
@@ -76,6 +80,27 @@ app_test(_Config) ->
?line ok=?t:app_test(orber),
ok.
+otp_9887(_Config) ->
+ orber:jump_stop(),
+ application:set_env(orber, orber_debug_level, 10),
+ orber:jump_start([]),
+
+ mnesia:create_table(orber_light_ifr, []),
+
+ error_logger:add_report_handler(?MODULE,[self()]),
+ catch orber_ifr:get_module(foo, bar),
+
+ receive
+ {stolen,Reason} ->
+ {error,_Pid1, {_Pid2, _ErrorString, ArgumentList}} = Reason,
+ 5 = length(ArgumentList)
+ after 500 ->
+ test_server:fail("OTP_9887 TIMED OUT")
+ end,
+
+ orber:jump_stop(),
+ ok.
+
%% Install Orber using the load_order option.
install_load_order(suite) ->
[];
@@ -192,5 +217,10 @@ key1search(Key, L) ->
fail(Reason) ->
exit({suite_failed, Reason}).
+%% Error handler
+init([Proc]) -> {ok,Proc}.
+handle_event(Event, Proc) ->
+ Proc ! {stolen,Event},
+ {ok,Proc}.
diff --git a/lib/orber/test/orber_acl_SUITE.erl b/lib/orber/test/orber_acl_SUITE.erl
index b43a00be19..49107cde84 100644
--- a/lib/orber/test/orber_acl_SUITE.erl
+++ b/lib/orber/test/orber_acl_SUITE.erl
@@ -80,7 +80,7 @@ end_per_group(_GroupName, Config) ->
%%-----------------------------------------------------------------
init_per_suite(Config) ->
if
- list(Config) ->
+ is_list(Config) ->
Config;
true ->
exit("Config not a list")
diff --git a/lib/os_mon/c_src/memsup.c b/lib/os_mon/c_src/memsup.c
index 241e7718db..b6e417eaa0 100644
--- a/lib/os_mon/c_src/memsup.c
+++ b/lib/os_mon/c_src/memsup.c
@@ -327,27 +327,27 @@ get_mem_procfs(memory_ext *me){
/* Total and free is NEEDED! */
bp = strstr(buffer, "MemTotal:");
- if (sscanf(bp, "MemTotal: %lu kB\n", &(me->total))) me->flag |= F_MEM_TOTAL;
+ if (bp != NULL && sscanf(bp, "MemTotal: %lu kB\n", &(me->total))) me->flag |= F_MEM_TOTAL;
bp = strstr(buffer, "MemFree:");
- if (sscanf(bp, "MemFree: %lu kB\n", &(me->free))) me->flag |= F_MEM_FREE;
+ if (bp != NULL && sscanf(bp, "MemFree: %lu kB\n", &(me->free))) me->flag |= F_MEM_FREE;
/* Extensions */
bp = strstr(buffer, "Buffers:");
- if (sscanf(bp, "Buffers: %lu kB\n", &(me->buffered))) me->flag |= F_MEM_BUFFERS;
+ if (bp != NULL && sscanf(bp, "Buffers: %lu kB\n", &(me->buffered))) me->flag |= F_MEM_BUFFERS;
bp = strstr(buffer, "Cached:");
- if (sscanf(bp, "Cached: %lu kB\n", &(me->cached))) me->flag |= F_MEM_CACHED;
+ if (bp != NULL && sscanf(bp, "Cached: %lu kB\n", &(me->cached))) me->flag |= F_MEM_CACHED;
/* Swap */
bp = strstr(buffer, "SwapTotal:");
- if (sscanf(bp, "SwapTotal: %lu kB\n", &(me->total_swap))) me->flag |= F_SWAP_TOTAL;
+ if (bp != NULL && sscanf(bp, "SwapTotal: %lu kB\n", &(me->total_swap))) me->flag |= F_SWAP_TOTAL;
bp = strstr(buffer, "SwapFree:");
- if (sscanf(bp, "SwapFree: %lu kB\n", &(me->free_swap))) me->flag |= F_SWAP_FREE;
+ if (bp != NULL && sscanf(bp, "SwapFree: %lu kB\n", &(me->free_swap))) me->flag |= F_SWAP_FREE;
me->pagesize = 1024; /* procfs defines its size in kB */
diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl
index e414e2c10b..34251178ee 100644
--- a/lib/os_mon/src/cpu_sup.erl
+++ b/lib/os_mon/src/cpu_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. 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
@@ -764,8 +764,7 @@ port_receive_cpu_util_entries(_, _, Data) ->
exit({data_mismatch, Data}).
start_portprogram() ->
- Command = filename:join([code:priv_dir(os_mon), "bin", "cpu_sup"]),
- Port = open_port({spawn, Command}, [stream]),
+ Port = os_mon:open_port("cpu_sup", [stream]),
port_command(Port, ?ping),
4711 = port_receive_uint32(Port, 5000),
Port.
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index ba07a529bc..49533da1f7 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -802,8 +802,7 @@ port_init() ->
port_idle(Port).
start_portprogram() ->
- Command = filename:join([code:priv_dir(os_mon), "bin", "memsup"]),
- open_port({spawn, Command}, [{packet, 1}]).
+ os_mon:open_port("memsup",[{packet,1}]).
%% The connected process loops are a bit awkward (several different
%% functions doing almost the same thing) as
diff --git a/lib/os_mon/src/os_mon.erl b/lib/os_mon/src/os_mon.erl
index ef368571db..3098c38808 100644
--- a/lib/os_mon/src/os_mon.erl
+++ b/lib/os_mon/src/os_mon.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. 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
@@ -22,7 +22,7 @@
-behaviour(supervisor).
%% API
--export([call/2, call/3, get_env/2]).
+-export([call/2, call/3, get_env/2, open_port/2]).
%% Application callbacks
-export([start/2, stop/1]).
@@ -79,6 +79,22 @@ get_env(Service, Param) ->
Service:param_default(Param)
end.
+open_port(Name, Opts) ->
+ PrivDir = code:priv_dir(os_mon),
+ ReleasedPath = filename:join([PrivDir,"bin",Name]),
+ %% Check os_mon*/priv/bin/Name
+ case filelib:is_regular(ReleasedPath) of
+ true ->
+ 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)
+ end.
+
+
%%%-----------------------------------------------------------------
%%% Application callbacks
%%%-----------------------------------------------------------------
diff --git a/lib/os_mon/src/os_mon_sysinfo.erl b/lib/os_mon/src/os_mon_sysinfo.erl
index 5d12bd95d1..080885d5d6 100644
--- a/lib/os_mon/src/os_mon_sysinfo.erl
+++ b/lib/os_mon/src/os_mon_sysinfo.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -108,9 +108,7 @@ code_change(_OldVsn, State, _Extra) ->
%%----------------------------------------------------------------------
start_portprogram() ->
- Command =
- filename:join([code:priv_dir(os_mon),"bin","win32sysinfo.exe"]),
- Port = open_port({spawn,Command}, [{packet,1}]),
+ Port = os_mon:open_port("win32sysinfo.exe", [{packet,1}]),
receive
{Port, {data, [?OK]}} ->
Port;
diff --git a/lib/pman/doc/src/pman.xml b/lib/pman/doc/src/pman.xml
index 84d5a5772a..5f95aecc04 100644
--- a/lib/pman/doc/src/pman.xml
+++ b/lib/pman/doc/src/pman.xml
@@ -32,6 +32,12 @@
<module>pman</module>
<modulesummary>A graphical process manager.</modulesummary>
<description>
+ <warning>
+ <p>
+ The Pman application has been superseded by the Observer application.
+ Pman will be removed in R16.
+ </p>
+ </warning>
<p>A graphical tool used to inspect the Erlang processes executing either
locally or on remote nodes. It is also possible to trace events in
the individual processes.</p>
diff --git a/lib/pman/doc/src/pman_chapter.xml b/lib/pman/doc/src/pman_chapter.xml
index 141b488415..8668628bfa 100644
--- a/lib/pman/doc/src/pman_chapter.xml
+++ b/lib/pman/doc/src/pman_chapter.xml
@@ -32,6 +32,12 @@
<section>
<title>Introduction</title>
+ <warning>
+ <p>
+ The Pman application has been superseded by the Observer application.
+ Pman will be removed in R16.
+ </p>
+ </warning>
<p>The process manager Pman is a tool for viewing processes executing
locally or on remote nodes. Its main purpose is to locate
erroneous code by inspecting the state of the processes and by tracing
diff --git a/lib/pman/src/pman_buf_converter.erl b/lib/pman/src/pman_buf_converter.erl
index b6f560411c..c6cd8ec9ee 100644
--- a/lib/pman/src/pman_buf_converter.erl
+++ b/lib/pman/src/pman_buf_converter.erl
@@ -29,6 +29,7 @@
%%----------------------------------------------------------------------
-module(pman_buf_converter).
+-compile([{nowarn_deprecated_function,{gs,start,0}}]).
%%-compile(export_all).
-export([init/2]).
diff --git a/lib/pman/src/pman_buf_printer.erl b/lib/pman/src/pman_buf_printer.erl
index 74e935171a..62407648d5 100644
--- a/lib/pman/src/pman_buf_printer.erl
+++ b/lib/pman/src/pman_buf_printer.erl
@@ -18,6 +18,8 @@
%%
-module(pman_buf_printer).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
%%-compile(export_all).
-export([init/2]).
diff --git a/lib/pman/src/pman_main.erl b/lib/pman/src/pman_main.erl
index b68da1d2c3..adb5b65cd4 100644
--- a/lib/pman/src/pman_main.erl
+++ b/lib/pman/src/pman_main.erl
@@ -17,6 +17,8 @@
%% %CopyrightEnd%
%%
-module(pman_main).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,read,2}}]).
%% Main process and window
diff --git a/lib/pman/src/pman_module_info.erl b/lib/pman/src/pman_module_info.erl
index cfd711a6e1..58f956aa42 100644
--- a/lib/pman/src/pman_module_info.erl
+++ b/lib/pman/src/pman_module_info.erl
@@ -17,6 +17,8 @@
%% %CopyrightEnd%
%%
-module(pman_module_info).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,start,1}}]).
%% Window with module information (View->Module Info...)
diff --git a/lib/pman/src/pman_shell.erl b/lib/pman/src/pman_shell.erl
index 0b13890460..393ef5f84d 100644
--- a/lib/pman/src/pman_shell.erl
+++ b/lib/pman/src/pman_shell.erl
@@ -25,6 +25,10 @@
%% ---------------------------------------------------------------
-module(pman_shell).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,start,1}}]).
%% ---------------------------------------------------------------
%% The user interface exports
diff --git a/lib/pman/src/pman_tool.erl b/lib/pman/src/pman_tool.erl
index 1d33fb9764..c548e17d00 100644
--- a/lib/pman/src/pman_tool.erl
+++ b/lib/pman/src/pman_tool.erl
@@ -17,6 +17,7 @@
%% %CopyrightEnd%
%%
-module(pman_tool).
+-compile([{nowarn_deprecated_function,{gs,read,2}}]).
%% Listbox selection window
diff --git a/lib/pman/src/pman_win.erl b/lib/pman/src/pman_win.erl
index 52d5a237cf..9dd446cd81 100644
--- a/lib/pman/src/pman_win.erl
+++ b/lib/pman/src/pman_win.erl
@@ -21,6 +21,16 @@
%% ------------------------------------------------------------
-module(pman_win).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,canvas,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,create,4}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,1}},
+ {nowarn_deprecated_function,{gs,text,2}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
%% ---------------------------------------------------------------
%% The user interface exports
diff --git a/lib/public_key/.gitignore b/lib/public_key/.gitignore
index db24906676..d30fe62c9d 100644
--- a/lib/public_key/.gitignore
+++ b/lib/public_key/.gitignore
@@ -1,7 +1,7 @@
# public_key
-/lib/public_key/asn1/*.asn1db
-/lib/public_key/asn1/*.erl
-/lib/public_key/asn1/*.hrl
-/lib/public_key/include/OTP-PUB-KEY.hrl
-/lib/public_key/include/PKCS-FRAME.hrl
+asn1/*.asn1db
+asn1/*.erl
+asn1/*.hrl
+include/OTP-PUB-KEY.hrl
+include/PKCS-FRAME.hrl
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 821e7a2300..0b6673e826 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -453,7 +453,7 @@
<desc>
<p>Encodes a list of ssh file entries (public keys and attributes) to a binary. Possible
attributes depends on the file type, see <seealso
- marker="ssh_decode"> ssh_decode/2 </seealso></p>
+ marker="#ssh_decode-2"> ssh_decode/2 </seealso></p>
</desc>
</func>
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index f342eab159..f0c94e29a5 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-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
@@ -146,16 +146,7 @@ do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) ->
Split = binary:split(Line, <<" ">>, [global]),
case mend_split(Split, []) of
%% ssh2
- [Options, KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>;
- KeyType == <<"ssh-dss">> ->
- do_openssh_decode(FileType, Lines,
- [{openssh_pubkey_decode(KeyType, Base64Enc),
- [{comment, string_decode(Comment)},
- {options, comma_list_decode(Options)}]}
- | Acc]);
-
- [KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>;
- KeyType == <<"ssh-dss">> ->
+ [KeyType, Base64Enc, Comment] ->
do_openssh_decode(FileType, Lines,
[{openssh_pubkey_decode(KeyType, Base64Enc),
[{comment, string_decode(Comment)}]} | Acc]);
@@ -166,44 +157,32 @@ do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) ->
[{comment, string_decode(Comment)},
{options, comma_list_decode(Options)},
{bits, integer_decode(Bits)}]} | Acc]);
- [Bits, Exponent, Modulus, Comment] ->
- do_openssh_decode(FileType, Lines,
- [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
- [{comment, string_decode(Comment)},
- {bits, integer_decode(Bits)}]} | Acc])
- end;
+ [A, B, C, D] ->
+ ssh_2_or_1(FileType, Lines, Acc, A,B,C,D)
+ end;
do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) ->
- case binary:split(Line, <<" ">>, [global]) of
+ Split = binary:split(Line, <<" ">>, [global]),
+ case mend_split(Split, []) of
%% ssh 2
- [HostNames, KeyType, Base64Enc] when KeyType == <<"ssh-rsa">>;
- KeyType == <<"ssh-dss">> ->
+ [HostNames, KeyType, Base64Enc] ->
do_openssh_decode(FileType, Lines,
[{openssh_pubkey_decode(KeyType, Base64Enc),
[{hostnames, comma_list_decode(HostNames)}]}| Acc]);
- [HostNames, KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>;
- KeyType == <<"ssh-dss">> ->
- do_openssh_decode(FileType, Lines,
- [{openssh_pubkey_decode(KeyType, Base64Enc),
- [{comment, string_decode(Comment)},
- {hostnames, comma_list_decode(HostNames)}]} | Acc]);
+ [A, B, C, D] ->
+ ssh_2_or_1(FileType, Lines, Acc, A, B, C, D);
%% ssh 1
[HostNames, Bits, Exponent, Modulus, Comment] ->
do_openssh_decode(FileType, Lines,
[{ssh1_rsa_pubkey_decode(Modulus, Exponent),
[{comment, string_decode(Comment)},
{hostnames, comma_list_decode(HostNames)},
- {bits, integer_decode(Bits)}]} | Acc]);
- [HostNames, Bits, Exponent, Modulus] ->
- do_openssh_decode(FileType, Lines,
- [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
- [{comment, []},
- {hostnames, comma_list_decode(HostNames)},
{bits, integer_decode(Bits)}]} | Acc])
end;
do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) ->
- case binary:split(Line, <<" ">>, [global]) of
+ Split = binary:split(Line, <<" ">>, [global]),
+ case mend_split(Split, []) of
[KeyType, Base64Enc, Comment0] when KeyType == <<"ssh-rsa">>;
KeyType == <<"ssh-dss">> ->
Comment = string:strip(binary_to_list(Comment0), right, $\n),
@@ -212,6 +191,46 @@ do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) ->
[{comment, Comment}]} | Acc])
end.
+ssh_2_or_1(known_hosts = FileType, Lines, Acc, A, B, C, D) ->
+ try integer_decode(B) of
+ Int ->
+ file_type_decode_ssh1(FileType, Lines, Acc, A, Int, C,D)
+ catch
+ error:badarg ->
+ file_type_decode_ssh2(FileType, Lines, Acc, A,B,C,D)
+ end;
+ssh_2_or_1(auth_keys = FileType, Lines, Acc, A, B, C, D) ->
+ try integer_decode(A) of
+ Int ->
+ file_type_decode_ssh1(FileType, Lines, Acc, Int, B, C,D)
+ catch
+ error:badarg ->
+ file_type_decode_ssh2(FileType, Lines, Acc, A,B,C,D)
+ end.
+
+file_type_decode_ssh1(known_hosts = FileType, Lines, Acc, HostNames, Bits, Exponent, Modulus) ->
+ do_openssh_decode(FileType, Lines,
+ [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
+ [{comment, []},
+ {hostnames, comma_list_decode(HostNames)},
+ {bits, Bits}]} | Acc]);
+file_type_decode_ssh1(auth_keys = FileType, Lines, Acc, Bits, Exponent, Modulus, Comment) ->
+ do_openssh_decode(FileType, Lines,
+ [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
+ [{comment, string_decode(Comment)},
+ {bits, Bits}]} | Acc]).
+
+file_type_decode_ssh2(known_hosts = FileType, Lines, Acc, HostNames, KeyType, Base64Enc, Comment) ->
+ do_openssh_decode(FileType, Lines,
+ [{openssh_pubkey_decode(KeyType, Base64Enc),
+ [{comment, string_decode(Comment)},
+ {hostnames, comma_list_decode(HostNames)}]} | Acc]);
+file_type_decode_ssh2(auth_keys = FileType, Lines, Acc, Options, KeyType, Base64Enc, Comment) ->
+ do_openssh_decode(FileType, Lines,
+ [{openssh_pubkey_decode(KeyType, Base64Enc),
+ [{comment, string_decode(Comment)},
+ {options, comma_list_decode(Options)}]}
+ | Acc]).
openssh_pubkey_decode(<<"ssh-rsa">>, Base64Enc) ->
<<?UINT32(StrLen), _:StrLen/binary,
@@ -231,7 +250,9 @@ openssh_pubkey_decode(<<"ssh-dss">>, Base64Enc) ->
{erlint(SizeY, Y),
#'Dss-Parms'{p = erlint(SizeP, P),
q = erlint(SizeQ, Q),
- g = erlint(SizeG, G)}}.
+ g = erlint(SizeG, G)}};
+openssh_pubkey_decode(KeyType, Base64Enc) ->
+ {KeyType, base64:mime_decode(Base64Enc)}.
erlint(MPIntSize, MPIntValue) ->
Bits= MPIntSize * 8,
@@ -412,6 +433,12 @@ is_key_field(<<"ssh-dss">>) ->
true;
is_key_field(<<"ssh-rsa">>) ->
true;
+is_key_field(<<"ecdsa-sha2-nistp256">>) ->
+ true;
+is_key_field(<<"ecdsa-sha2-nistp384">>) ->
+ true;
+is_key_field(<<"ecdsa-sha2-nistp521">>) ->
+ true;
is_key_field(_) ->
false.
diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c
index 5396b8afa9..7ae6c1b329 100644
--- a/lib/runtime_tools/c_src/trace_ip_drv.c
+++ b/lib/runtime_tools/c_src/trace_ip_drv.c
@@ -212,11 +212,11 @@ static TraceIpData *lookup_data_by_port(int portno);
static int set_nonblocking(SOCKET sock);
static TraceIpMessage *make_buffer(int datasiz, unsigned char op,
unsigned number);
-static void enque_message(TraceIpData *data, unsigned char *buff, int bufflen,
+static void enque_message(TraceIpData *data, char *buff, int bufflen,
int byteswritten);
static void clean_que(TraceIpData *data);
static void close_client(TraceIpData *data);
-static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen);
+static int trywrite(TraceIpData *data, char *buff, int bufflen);
static SOCKET my_accept(SOCKET sock);
static void close_unlink_port(TraceIpData *data);
enum MySelectOp { SELECT_ON, SELECT_OFF, SELECT_CLOSE };
@@ -518,7 +518,7 @@ static void trace_ip_ready_output(ErlDrvData handle, ErlDrvEvent fd)
tim = data->que[data->questart];
towrite = tim->siz - tim->written;
while((res = write_until_done(data->fd,
- tim->bin + tim->written, towrite))
+ (char *)tim->bin + tim->written, towrite))
== towrite) {
driver_free(tim);
data->que[data->questart] = NULL;
@@ -561,7 +561,7 @@ static ErlDrvSSizeT trace_ip_control(ErlDrvData handle,
TraceIpData *data = (TraceIpData *) handle;
ErlDrvBinary *b = my_alloc_binary(3);
b->orig_bytes[0] = '\0'; /* OK */
- put_be16(data->listen_portno, &(b->orig_bytes[1]));
+ put_be16(data->listen_portno, (unsigned char *)&(b->orig_bytes[1]));
*res = void_ptr = b;
return 0;
}
@@ -696,7 +696,7 @@ static TraceIpMessage *make_buffer(int datasiz, unsigned char op,
** Add message to que, discarding in a politically correct way...
** The FLAG_DROP_OLDEST is currently ingored...
*/
-static void enque_message(TraceIpData *data, unsigned char *buff, int bufflen,
+static void enque_message(TraceIpData *data, char *buff, int bufflen,
int byteswritten)
{
int diff = data->questop - data->questart;
@@ -763,13 +763,13 @@ static void close_client(TraceIpData *data)
** Try to write a message from erlang directly (only called when que is empty
** and client is connected)
*/
-static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen)
+static int trywrite(TraceIpData *data, char *buff, int bufflen)
{
- unsigned char op[5];
+ char op[5];
int res;
op[0] = OP_BINARY;
- put_be32(bufflen, op + 1);
+ put_be32(bufflen, (unsigned char *)op + 1);
if ((res = write_until_done(data->fd, op, 5)) < 0) {
close_client(data);
@@ -793,7 +793,11 @@ static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen)
static SOCKET my_accept(SOCKET sock)
{
struct sockaddr_in sin;
- int sin_size = sizeof(sin);
+#ifdef HAVE_SOCKLEN_T
+ socklen_t sin_size = sizeof(sin);
+#else
+ int sin_size = (int) sizeof(sin);
+#endif
return accept(sock, (struct sockaddr *) &sin, &sin_size);
}
diff --git a/lib/runtime_tools/test/inviso_SUITE.erl b/lib/runtime_tools/test/inviso_SUITE.erl
index 758867cf45..33626ffd9e 100644
--- a/lib/runtime_tools/test/inviso_SUITE.erl
+++ b/lib/runtime_tools/test/inviso_SUITE.erl
@@ -66,13 +66,18 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config) ->
- %% No never know who skrewed up this node before this suite! :-)
- erlang:trace_pattern({'_','_','_'},[],[local]),
- erlang:trace_pattern({'_','_','_'},[],[global]),
- erlang:trace(all,false,[all]),
+ case test_server:is_native(lists) of
+ true ->
+ {skip,"Native libs -- tracing doesn't work"};
+ false ->
+ %% We never know who messed up this node before this suite! :-)
+ erlang:trace_pattern({'_','_','_'},[],[local]),
+ erlang:trace_pattern({'_','_','_'},[],[global]),
+ erlang:trace(all,false,[all]),
- ?l ok=application:start(runtime_tools),
- Config.
+ ok=application:start(runtime_tools),
+ Config
+ end.
end_per_suite(_Config) ->
?l ok=application:stop(runtime_tools).
diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml
index 195f9fe1d3..770b7c2492 100644
--- a/lib/sasl/doc/src/appup.xml
+++ b/lib/sasl/doc/src/appup.xml
@@ -332,7 +332,7 @@ restart_new_emulator
<p>An info report will be written when the upgrade is
completed. To programatically find out if the upgrade is
complete,
- call <seealso marker="release_handler#which_release/0">
+ call <seealso marker="release_handler#which_releases/0">
release_handler:which_releases</seealso> and check if the
expected release has status <c>current</c>.</p>
<p>The new release must still be made permanent after the upgrade
diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml
index 32c2149a8d..84fed0a25f 100644
--- a/lib/sasl/doc/src/systools.xml
+++ b/lib/sasl/doc/src/systools.xml
@@ -196,6 +196,10 @@
<p>The applications are sorted according to the dependencies
between the applications. Where there are no dependencies,
the order in the <c>.rel</c> file is kept.</p>
+ <p>The function will fail if the mandatory
+ applications <c>kernel</c> and <c>stdlib</c> are not
+ included in the <c>.rel</c> file and have start
+ type <c>permanent</c> (default).</p>
<p>If <c>sasl</c> is not included as an application in
the <c>.rel</c> file, a warning is emitted because such a
release can not be used in an upgrade. To turn off this
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index 522c7b496b..8d2b9c35d3 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -1572,7 +1572,7 @@ memlib(_Lib, []) -> false.
%% recursively remove file or directory
remove_file(File) ->
- case file:read_file_info(File) of
+ case file:read_link_info(File) of
{ok, Info} when Info#file_info.type==directory ->
case file:list_dir(File) of
{ok, Files} ->
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 8fd90c50f9..12ba2a5476 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -463,30 +463,35 @@ check_appl(Appl) ->
end,
Appl) of
[] ->
- {ok,Ws} = mandatory_applications(Appl),
- {split_app_incl(Appl),Ws};
+ {ApplsNoIncls,Incls} = split_app_incl(Appl),
+ {ok,Ws} = mandatory_applications(ApplsNoIncls,undefined,
+ undefined,undefined),
+ {{ApplsNoIncls,Incls},Ws};
Illegal ->
throw({error, {illegal_applications,Illegal}})
end.
-mandatory_applications(Appl) ->
- AppNames = map(fun(AppT) -> element(1, AppT) end,
- Appl),
- Mand = mandatory_applications(),
- case filter(fun(X) -> member(X, AppNames) end, Mand) of
- Mand ->
- case member(sasl,AppNames) of
- true ->
- {ok,[]};
- _ ->
- {ok, [{warning,missing_sasl}]}
- end;
- _ ->
- throw({error, {missing_mandatory_app, Mand}})
- end.
-
-mandatory_applications() ->
- [kernel, stdlib].
+mandatory_applications([{kernel,_,Type}|Apps],undefined,Stdlib,Sasl) ->
+ mandatory_applications(Apps,Type,Stdlib,Sasl);
+mandatory_applications([{stdlib,_,Type}|Apps],Kernel,undefined,Sasl) ->
+ mandatory_applications(Apps,Kernel,Type,Sasl);
+mandatory_applications([{sasl,_,Type}|Apps],Kernel,Stdlib,undefined) ->
+ mandatory_applications(Apps,Kernel,Stdlib,Type);
+mandatory_applications([_|Apps],Kernel,Stdlib,Sasl) ->
+ mandatory_applications(Apps,Kernel,Stdlib,Sasl);
+mandatory_applications([],Type,_,_) when Type=/=permanent ->
+ error_mandatory_application(kernel,Type);
+mandatory_applications([],_,Type,_) when Type=/=permanent ->
+ error_mandatory_application(sasl,Type);
+mandatory_applications([],_,_,undefined) ->
+ {ok, [{warning,missing_sasl}]};
+mandatory_applications([],_,_,_) ->
+ {ok,[]}.
+
+error_mandatory_application(App,undefined) ->
+ throw({error, {missing_mandatory_app, App}});
+error_mandatory_application(App,Type) ->
+ throw({error, {mandatory_app, App, Type}}).
split_app_incl(Appl) -> split_app_incl(Appl, [], []).
@@ -1677,6 +1682,7 @@ add_system_files(Tar, RelName, Release, Path1) ->
false ->
ignore;
Relup ->
+ check_relup(Relup),
add_to_tar(Tar, Relup, filename:join(RelVsnDir, "relup"))
end,
@@ -1684,6 +1690,7 @@ add_system_files(Tar, RelName, Release, Path1) ->
false ->
ignore;
Sys ->
+ check_sys_config(Sys),
add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config"))
end,
@@ -1700,6 +1707,44 @@ lookup_file(Name, [Dir|Path]) ->
lookup_file(_Name, []) ->
false.
+%% Check that relup can be parsed and has expected format
+check_relup(File) ->
+ case file:consult(File) of
+ {ok,[{Vsn,UpFrom,DownTo}]} when is_list(Vsn), is_integer(hd(Vsn)),
+ is_list(UpFrom), is_list(DownTo) ->
+ ok;
+ {ok,_} ->
+ throw({error,{tar_error,{add,"relup",[invalid_format]}}});
+ Other ->
+ throw({error,{tar_error,{add,"relup",[Other]}}})
+ end.
+
+%% Check that sys.config can be parsed and has expected format
+check_sys_config(File) ->
+ case file:consult(File) of
+ {ok,[SysConfig]} ->
+ case lists:all(fun({App,KeyVals}) when is_atom(App),
+ is_list(KeyVals)->
+ true;
+ (OtherConfig) when is_list(OtherConfig),
+ is_integer(hd(OtherConfig)) ->
+ true;
+ (_) ->
+ false
+ end,
+ SysConfig) of
+ true ->
+ ok;
+ false ->
+ throw({error,{tar_error,
+ {add,"sys.config",[invalid_format]}}})
+ end;
+ {ok,_} ->
+ throw({error,{tar_error,{add,"sys.config",[invalid_format]}}});
+ Other ->
+ throw({error,{tar_error,{add,"sys.config",[Other]}}})
+ end.
+
%%______________________________________________________________________
%% Add either a application located under a variable dir or all other
%% applications to a tar file.
@@ -2187,9 +2232,12 @@ format_error({missing_parameter,Par}) ->
format_error({illegal_applications,Names}) ->
io_lib:format("Illegal applications in the release file: ~p~n",
[Names]);
-format_error({missing_mandatory_app,Names}) ->
- io_lib:format("Mandatory applications (~p) must be specified in the release file~n",
- [Names]);
+format_error({missing_mandatory_app,Name}) ->
+ io_lib:format("Mandatory application ~p must be specified in the release file~n",
+ [Name]);
+format_error({mandatory_app,Name,Type}) ->
+ io_lib:format("Mandatory application ~p must be of type 'permanent' in the release file. Is '~p'.~n",
+ [Name,Type]);
format_error({duplicate_register,Dups}) ->
io_lib:format("Duplicated register names: ~n~s",
[map(fun({{Reg,App1,_,_},{Reg,App2,_,_}}) ->
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index ac616dab72..467d1226b3 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -59,7 +59,7 @@ win32_cases() ->
cases() ->
[otp_2740, otp_2760, otp_5761, otp_9402, otp_9417,
otp_9395_check_old_code, otp_9395_check_and_purge,
- otp_9395_update_many_mods, otp_9395_rm_many_mods,
+ otp_9395_update_many_mods, otp_9395_rm_many_mods, otp_9864,
instructions, eval_appup, eval_appup_with_restart,
supervisor_which_children_timeout,
release_handler_which_releases, install_release_syntax_check,
@@ -1205,6 +1205,60 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
otp_9395_rm_many_mods(cleanup,_Conf) ->
stop_node(node_name(otp_9395_rm_many_mods)).
+otp_9864(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_9864"),
+ RelDir = filename:join(?config(data_dir, Conf), "app1_app2"),
+ LibDir1 = filename:join(RelDir, "lib1"),
+ LibDir2 = filename:join(RelDir, "lib2"),
+
+ %% Create the releases
+ Rel1 = create_and_install_fake_first_release(Dir,
+ [{app1,"1.0",LibDir1},
+ {app2,"1.0",LibDir1}]),
+ Rel2 = create_fake_upgrade_release(Dir,
+ "2",
+ [{app1,"2.0",LibDir2},
+ {app2,"1.0",LibDir2}],
+ {[Rel1],[Rel1],[LibDir1]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(otp_9864, Rel1, filename:join(Rel1Dir,"sys.config")),
+
+ %% Unpack rel2 (make sure it does not work if an AppDir is bad)
+ LibDir3 = filename:join(RelDir, "lib3"),
+ {error, {no_such_directory, _}} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", [{app1,"2.0",LibDir2}, {app2,"1.0",LibDir3}]]),
+ {ok, RelVsn2} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", [{app1,"2.0",LibDir2}, {app2,"1.0",LibDir2}]]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+ %% Install RelVsn2 without {update_paths, true} option
+ {ok, RelVsn1, []} =
+ rpc:call(Node, release_handler, install_release, [RelVsn2]),
+
+ %% Install RelVsn1 again
+ {ok, RelVsn1, []} =
+ rpc:call(Node, release_handler, install_release, [RelVsn1]),
+
+ TempRel2Dir = filename:join(Dir,"releases/2"),
+ file:make_symlink(TempRel2Dir, filename:join(TempRel2Dir, "foo_symlink_dir")),
+
+ %% This will fail if symlinks are not handled
+ ok = rpc:call(Node, release_handler, remove_release, [RelVsn2]),
+
+ ok.
+
upgrade_supervisor(Conf) when is_list(Conf) ->
%% Set some paths
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 43366d8917..4cf7364d74 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -46,9 +46,11 @@
included_script/1, included_override_script/1,
included_fail_script/1, included_bug_script/1, exref_script/1,
otp_3065_circular_dependenies/1]).
--export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1,
- src_tests_tar/1, var_tar/1,
- exref_tar/1, link_tar/1, otp_9507_path_ebin/1]).
+-export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, system_files_tar/1,
+ system_files_tar/2, invalid_system_files_tar/1,
+ invalid_system_files_tar/2, variable_tar/1,
+ src_tests_tar/1, var_tar/1, exref_tar/1, link_tar/1,
+ otp_9507_path_ebin/1]).
-export([normal_relup/1, restart_relup/1, abnormal_relup/1, no_sasl_relup/1,
no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1,
regexp_relup/1]).
@@ -80,7 +82,8 @@ groups() ->
included_fail_script, included_bug_script, exref_script,
otp_3065_circular_dependenies]},
{tar, [],
- [tar_options, normal_tar, no_mod_vsn_tar, variable_tar,
+ [tar_options, normal_tar, no_mod_vsn_tar, system_files_tar,
+ invalid_system_files_tar, variable_tar,
src_tests_tar, var_tar, exref_tar, link_tar, otp_9507_path_ebin]},
{relup, [],
[normal_relup, restart_relup, abnormal_relup, no_sasl_relup,
@@ -146,7 +149,10 @@ init_per_testcase(_Case, Config) ->
Dog = test_server:timetrap(?default_timeout),
[{watchdog, Dog}|Config].
-end_per_testcase(_Case, Config) ->
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
Dog=?config(watchdog, Config),
test_server:timetrap_cancel(Dog),
case {?config(path,Config),?config(cwd,Config)} of
@@ -483,9 +489,17 @@ crazy_script(Config) when is_list(Config) ->
ok = file:set_cwd(LatestDir2),
error = systools:make_script(LatestName2),
- {error, _, {missing_mandatory_app,[kernel,stdlib]}} =
+ {error, _, {missing_mandatory_app,kernel}} =
systools:make_script(LatestName2, [silent,{path,P}]),
+ %% Run with .rel file with non-permanent kernel
+ {LatestDir3, LatestName3} = create_script(latest_kernel_start_type, Config),
+ ok = file:set_cwd(LatestDir3),
+
+ error = systools:make_script(LatestName3),
+ {error, _, {mandatory_app,kernel,load}} =
+ systools:make_script(LatestName3, [silent,{path,P}]),
+
ok = file:set_cwd(OldDir),
ok.
@@ -756,6 +770,102 @@ no_mod_vsn_tar(Config) when is_list(Config) ->
ok = file:set_cwd(OldDir),
ok.
+
+%% make_tar: Check that relup or sys.config are included if they exist
+system_files_tar(Config) ->
+ {ok, OldDir} = file:get_cwd(),
+
+ {LatestDir, LatestName} = create_script(latest,Config),
+
+ DataDir = filename:absname(?copydir),
+ LibDir = fname([DataDir, d_normal, lib]),
+ P = [fname([LibDir, 'db-2.1', ebin]),
+ fname([LibDir, 'fe-3.1', ebin])],
+
+ ok = file:set_cwd(LatestDir),
+
+ %% Add dummy relup and sys.config
+ ok = file:write_file("sys.config","[].\n"),
+ ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"),
+
+ {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ ok = systools:make_tar(LatestName, [{path, P}]),
+ ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName),
+ ok = check_tar(fname(["releases","LATEST","relup"]), LatestName),
+ {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]),
+ ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName),
+ ok = check_tar(fname(["releases","LATEST","relup"]), LatestName),
+
+ ok = file:set_cwd(OldDir),
+
+ ok.
+
+system_files_tar(cleanup,Config) ->
+ Dir = ?privdir,
+ file:delete(filename:join(Dir,"sys.config")),
+ file:delete(filename:join(Dir,"relup")),
+ ok.
+
+
+%% make_tar: Check that make_tar fails if relup or sys.config exist
+%% but do not have valid content
+invalid_system_files_tar(Config) ->
+ {ok, OldDir} = file:get_cwd(),
+
+ {LatestDir, LatestName} = create_script(latest,Config),
+
+ DataDir = filename:absname(?copydir),
+ LibDir = fname([DataDir, d_normal, lib]),
+ P = [fname([LibDir, 'db-2.1', ebin]),
+ fname([LibDir, 'fe-3.1', ebin])],
+
+ ok = file:set_cwd(LatestDir),
+
+ {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+
+ %% Add dummy relup and sys.config - faulty sys.config
+ ok = file:write_file("sys.config","[]\n"), %!!! syntax error - missing '.'
+ ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"),
+
+ error = systools:make_tar(LatestName, [{path, P}]),
+ {error,_,{tar_error,{add,"sys.config",[{error,_}]}}} =
+ systools:make_tar(LatestName, [{path, P}, silent]),
+
+ %% Add dummy relup and sys.config - faulty sys.config
+ ok = file:write_file("sys.config","[x,y].\n"), %!!! faulty format
+ ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"),
+
+ error = systools:make_tar(LatestName, [{path, P}]),
+ {error,_,{tar_error,{add,"sys.config",[invalid_format]}}} =
+ systools:make_tar(LatestName, [{path, P}, silent]),
+
+ %% Add dummy relup and sys.config - faulty relup
+ ok = file:write_file("sys.config","[]\n"),
+ ok = file:write_file("relup","{\"LATEST\"\n"), %!!! syntax error - truncated
+
+ error = systools:make_tar(LatestName, [{path, P}]),
+ {error,_,{tar_error,{add,"relup",[{error,_}]}}} =
+ systools:make_tar(LatestName, [{path, P}, silent]),
+
+ %% Add dummy relup and sys.config - faulty relup
+ ok = file:write_file("sys.config","[]\n"),
+ ok = file:write_file("relup","[].\n"), %!!! faulty format
+
+ error = systools:make_tar(LatestName, [{path, P}]),
+ {error,_,{tar_error,{add,"relup",[invalid_format]}}} =
+ systools:make_tar(LatestName, [{path, P}, silent]),
+
+ ok = file:set_cwd(OldDir),
+
+ ok.
+
+invalid_system_files_tar(cleanup,Config) ->
+ Dir = ?privdir,
+ file:delete(filename:join(Dir,"sys.config")),
+ file:delete(filename:join(Dir,"relup")),
+ ok.
+
+
%% make_tar: Use variable and create separate tar (included in generated tar).
variable_tar(Config) when is_list(Config) ->
{ok, OldDir} = file:get_cwd(),
@@ -1915,6 +2025,9 @@ create_script(latest_small2,Config) ->
create_script(latest_nokernel,Config) ->
Apps = [{db,"2.1"},{fe,"3.1"}],
do_create_script(latest_nokernel,Config,"4.4",Apps);
+create_script(latest_kernel_start_type,Config) ->
+ Apps = [{kernel,"1.0",load},{db,"2.1"},{fe,"3.1"}],
+ do_create_script(latest_kernel_start_type,Config,"4.4",Apps);
create_script(latest_app_start_type1,Config) ->
Apps = core_apps(current),
do_create_script(latest_app_start_type1,Config,current,Apps);
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 64a0d1a13f..704ff0a20f 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,188 @@
<section>
+ <title>SNMP Development Toolkit 4.21.7</title>
+ <p>Version 4.21.7 supports code replacement in runtime from/to
+ version 4.21.6, 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and
+ 4.20. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] DoS attack using GET-BULK with large value of
+ MaxRepetitions.
+ A preventive method has been implementing by simply
+ limit the number of varbinds that can be included in
+ a Get-BULK response message. This is specified by the
+ new config option,
+ <seealso marker="snmp_app#agent_gb_max_vbs">gb_max_vbs</seealso>.
+ </p>
+ <p>Own Id: OTP-9700</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Simultaneous
+ <seealso marker="snmpa#backup">snmpa:backup/1,2</seealso>
+ calls can interfere.
+ The master agent did not check if a backup was already in
+ progress when a backup request was accepted. </p>
+ <p>Own Id: OTP-9884</p>
+ <p>Aux Id: Seq 11995</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ </section> <!-- 4.21.7 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.21.6</title>
+ <p>Version 4.21.6 supports code replacement in runtime from/to
+ version 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and
+ 4.20. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] DoS attack using GET-BULK with large value of
+ MaxRepetitions.
+ A preventive method has been implementing by simply
+ limit the number of varbinds that can be included in
+ a Get-BULK response message. This is specified by the
+ new config option,
+ <seealso marker="snmp_app#agent_gb_max_vbs">gb_max_vbs</seealso>.
+ </p>
+ <p>Own Id: OTP-9700</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Mib server cache gclimit update function incorrectly calls
+ age update function.
+ The gclimit update function,
+ <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1</seealso>,
+ <em>incorrectly</em> called the age update function,
+ <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/2</seealso>. </p>
+ <p>Johan Claesson</p>
+ <p>Own Id: OTP-9868</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ </section> <!-- 4.21.6 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.21.5</title>
+ <p>Version 4.21.5 supports code replacement in runtime from/to
+ version 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and 4.20. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Removed (more) use of old style tuple funs. </p>
+ <p>Own Id: OTP-9783</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Repeated vacm table dumping fails due to file name
+ conflict. When dumping the vacm table to disk, a temoporary
+ file with a fixed name was used. If the table dumping
+ (snmpa_vacm:dump_table/0) was initiated from several different
+ processes in rapid succesion, the dumping could fail because the
+ different processes was simultaniously trying to write to the
+ same file. This problem has been eliminated by creating a unique
+ name for the temporary file. </p>
+ <p>Own Id: OTP-9851</p>
+ <p>Aux Id: Seq 11980</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>foo. </p>
+ <p>Own Id: OTP-9718</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ </section> <!-- 4.21.5 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.21.4</title>
+ <p>This version has never been released for R14B.</p>
<p>Version 4.21.4 supports code replacement in runtime from/to
version 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1, 4.20 and 4.19. </p>
@@ -46,7 +227,7 @@
<list type="bulleted">
<item>
<p>[compiler] Improved version info printout from the
- <seealso marker="snmpc(command)#">MIB compiler frontend escript</seealso>. </p>
+ <seealso marker="snmpc(command)#">MIB compiler frontend escript</seealso>. </p>
<p>Own Id: OTP-9618</p>
</item>
@@ -70,7 +251,6 @@
</list>
</section>
-
<section>
<title>Incompatibilities</title>
<p>-</p>
@@ -78,7 +258,7 @@
<!--
<list type="bulleted">
<item>
- <p>foo. </p>
+ <p>foo. </p>
<p>Own Id: OTP-9718</p>
</item>
@@ -641,355 +821,6 @@ snmp_view_basec_acm_mib:vacmAccessTable(set, RowIndex, Cols).
</section> <!-- 4.18 -->
- <section>
- <title>SNMP Development Toolkit 4.17.1</title>
- <p>Version 4.17.1 supports code replacement in runtime from/to
- version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>When the function FilterMod:accept_recv/2
- returned false the SNMP agent stopped collecting
- messages from UDP.</p>
- <p>Own Id: OTP-8761</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.17.1 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.17</title>
- <p>Version 4.17 supports code replacement in runtime from/to
- version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] Added very basic support for multiple SNMPv3
- EngineIDs in a single agent. See
- <seealso marker="snmpa#send_notification">send_notification/7</seealso>,
- <seealso marker="snmpa_mpd#process_packet">process_packet/7</seealso>,
- <seealso marker="snmpa_mpd#generate_response_msg">generate_response_msg/6</seealso> or
- <seealso marker="snmpa_mpd#generate_msg">generate_msg/6</seealso>
- for more info. </p>
-
- <p>Own Id: OTP-8478</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <p>-</p>
-
- <!--
- <list type="bulleted">
- <item>
- <p>The config utility
- (<seealso marker="snmp#config">snmp:config/0</seealso>)
- generated a default notify.conf
- with a bad name for the standard trap entry (was "stadard trap",
- but should have been "standard trap"). This has been corrected. </p>
- <p>Kenji Rikitake</p>
- <p>Own Id: OTP-8433</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.17 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.16.2</title>
- <p>Version 4.16.2 supports code replacement in runtime from/to
- version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[compiler] The SMI specifies that a table row OID should be
- named: { &lt;tableIdentifier&gt; "1" }. </p>
- <p>A new option has been introduced,
- <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>,
- that allows for a more liberal numbering scheme</p>
- <p>Own Id: OTP-8574</p>
- </item>
-
- <item>
- <p>[agent|manager] Changes to make snmp (forward) compatible with
- the new version of the crypto application (released in R14).
- As of R14, crypto is implemented using NIFs. Also,
- the API is more strict. </p>
- <p>Own Id: OTP-8594</p>
- </item>
-
- <item>
- <p>Auto [agent] Changed default value for the MIB server cache.
- GC is now on by default. </p>
- <p>Own Id: OTP-8648</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>Encode/decode of Counter64 values larger than
- 16#7fffffffffffffff (9223372036854775807) failed. </p>
- <p>Own Id: OTP-8563</p>
- </item>
-
- <item>
- <p>[compiler] Fails to compile non-contiguous BITS. </p>
- <p>Per Hedeland</p>
- <p>Own Id: OTP-8595</p>
- </item>
-
- <item>
- <p>[manager] Raise condition causing the manager server process to
- crash. Unregistering an agent while traffic (set/get-operations)
- is ongoing could cause a crash in the manager server process
- (raise condition). </p>
- <p>Own Id: OTP-8646</p>
- <p>Aux Id: Seq 11585</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.16.2 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.16.1</title>
- <p>Version 4.16.1 supports code replacement in runtime from/to
- version 4.16, 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
- <!--
- <list type="bulleted">
- <item>
- <p>[agent|manager] Entries in the audit trail log can now be
- augmented by a sequence number. </p>
- <p>This is enabled by the <c>seqno</c> option, which is part of the
- <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso>
- config option. </p>
- <p>See the
- <seealso marker="snmp_app#configuration_params">reference manual</seealso>
- or the
- <seealso marker="snmp_config#configuration_params">Configuring the application</seealso>
- chapter of the User's Guide for further info. </p>
-
- <p>Own Id: OTP-8395</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>[manager] Fixed an upgrade/downgrade problem. </p>
- <p>Upgrade/downgrade from/to 4.13.5 did not work for the net-if
- process. This has now been fixed. </p>
- <p>Own Id: OTP-8481</p>
- </item>
-
- <item>
- <p>[agent] A minor mnesia related performance improvement. </p>
- <p>Own Id: OTP-8480</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.16.1 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.16</title>
- <p>Version 4.16 supports code replacement in runtime from/to
- version 4.15, 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent|manager] Entries in the audit trail log can now be
- augmented by a sequence number. </p>
- <p>This is enabled by the <c>seqno</c> option, which is part of the
- <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso>
- config option. </p>
- <p>See the
- <seealso marker="snmp_app#configuration_params">reference manual</seealso>
- or the
- <seealso marker="snmp_config#configuration_params">Configuring the application</seealso>
- chapter of the User's Guide for further info. </p>
-
- <p>Own Id: OTP-8395</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>[manager] Registration of agents using the config file,
- <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>,
- does not work. This has now been corrected. </p>
- <p>Per Hedeland</p>
- <p>Own Id: OTP-8442</p>
- </item>
-
- <item>
- <p>The config utility
- (<seealso marker="snmp#config">snmp:config/0</seealso>)
- generated a default notify.conf
- with a bad name for the standard trap entry (was "stadard trap",
- but should have been "standard trap"). This has been corrected. </p>
- <p>Kenji Rikitake</p>
- <p>Own Id: OTP-8433</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.16 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.15</title>
-
- <p>Version 4.15 supports code replacement in runtime from/to
- version 4.14 and 4.13.5.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>The documentation is now built with open source tools
- (<em>xsltproc</em> and <em>fop</em>) that exists on most
- platforms. One visible change is that the frames are removed.</p>
- <p>Own Id: OTP-8249</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[manager] When information from an unknown agent is received,
- it was previously delivered to the default user via calls to all
- the functions of the callback API depending on the info type
- (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>).
- The problem was that the <c>TargetName</c> argument was useless
- in this case (only an already known agent has a known/valid
- <c>TargetName</c>, but the <c>TargetName</c> used in these calls
- was generated "on the fly"). </p>
- <p>This has now been changed so that when a message is received
- from an unknown agent, then only
- <seealso marker="snmpm_user#handle_agent">handle_agent</seealso>
- (for the default user) is called, but now this call also has a
- <c>Type</c> argument, which is
- <c>pdu | trap | report | inform</c>, depending on what kind of
- message was actually received, thus making it possible for the
- user to properly analyze the data received. </p>
- <p>To handle this, the
- <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has
- been updated. </p>
- <p>*** POTENTIAL INCOMPATIBILITY ***</p>
- <p>Own Id: OTP-8229</p>
- <!-- <p>Aux Id: Seq 11312</p> -->
- </item>
-
- </list>
-
- </section>
-
- </section> <!-- 4.15 -->
-
-
<!-- section>
<title>Release notes history</title>
<p>For information about older versions see
diff --git a/lib/snmp/doc/src/notes_history.xml b/lib/snmp/doc/src/notes_history.xml
index e833335ffb..023717cd7c 100644
--- a/lib/snmp/doc/src/notes_history.xml
+++ b/lib/snmp/doc/src/notes_history.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2011</year>
+ <year>2004</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,6 +33,355 @@
</header>
<section>
+ <title>SNMP Development Toolkit 4.17.1</title>
+ <p>Version 4.17.1 supports code replacement in runtime from/to
+ version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>When the function FilterMod:accept_recv/2
+ returned false the SNMP agent stopped collecting
+ messages from UDP.</p>
+ <p>Own Id: OTP-8761</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.17.1 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.17</title>
+ <p>Version 4.17 supports code replacement in runtime from/to
+ version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Added very basic support for multiple SNMPv3
+ EngineIDs in a single agent. See
+ <seealso marker="snmpa#send_notification">send_notification/7</seealso>,
+ <seealso marker="snmpa_mpd#process_packet">process_packet/7</seealso>,
+ <seealso marker="snmpa_mpd#generate_response_msg">generate_response_msg/6</seealso> or
+ <seealso marker="snmpa_mpd#generate_msg">generate_msg/6</seealso>
+ for more info. </p>
+
+ <p>Own Id: OTP-8478</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>The config utility
+ (<seealso marker="snmp#config">snmp:config/0</seealso>)
+ generated a default notify.conf
+ with a bad name for the standard trap entry (was "stadard trap",
+ but should have been "standard trap"). This has been corrected. </p>
+ <p>Kenji Rikitake</p>
+ <p>Own Id: OTP-8433</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.17 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.16.2</title>
+ <p>Version 4.16.2 supports code replacement in runtime from/to
+ version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[compiler] The SMI specifies that a table row OID should be
+ named: { &lt;tableIdentifier&gt; "1" }. </p>
+ <p>A new option has been introduced,
+ <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>,
+ that allows for a more liberal numbering scheme</p>
+ <p>Own Id: OTP-8574</p>
+ </item>
+
+ <item>
+ <p>[agent|manager] Changes to make snmp (forward) compatible with
+ the new version of the crypto application (released in R14).
+ As of R14, crypto is implemented using NIFs. Also,
+ the API is more strict. </p>
+ <p>Own Id: OTP-8594</p>
+ </item>
+
+ <item>
+ <p>Auto [agent] Changed default value for the MIB server cache.
+ GC is now on by default. </p>
+ <p>Own Id: OTP-8648</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>Encode/decode of Counter64 values larger than
+ 16#7fffffffffffffff (9223372036854775807) failed. </p>
+ <p>Own Id: OTP-8563</p>
+ </item>
+
+ <item>
+ <p>[compiler] Fails to compile non-contiguous BITS. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-8595</p>
+ </item>
+
+ <item>
+ <p>[manager] Raise condition causing the manager server process to
+ crash. Unregistering an agent while traffic (set/get-operations)
+ is ongoing could cause a crash in the manager server process
+ (raise condition). </p>
+ <p>Own Id: OTP-8646</p>
+ <p>Aux Id: Seq 11585</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.16.2 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.16.1</title>
+ <p>Version 4.16.1 supports code replacement in runtime from/to
+ version 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent|manager] Entries in the audit trail log can now be
+ augmented by a sequence number. </p>
+ <p>This is enabled by the <c>seqno</c> option, which is part of the
+ <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso>
+ config option. </p>
+ <p>See the
+ <seealso marker="snmp_app#configuration_params">reference manual</seealso>
+ or the
+ <seealso marker="snmp_config#configuration_params">Configuring the application</seealso>
+ chapter of the User's Guide for further info. </p>
+
+ <p>Own Id: OTP-8395</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[manager] Fixed an upgrade/downgrade problem. </p>
+ <p>Upgrade/downgrade from/to 4.13.5 did not work for the net-if
+ process. This has now been fixed. </p>
+ <p>Own Id: OTP-8481</p>
+ </item>
+
+ <item>
+ <p>[agent] A minor mnesia related performance improvement. </p>
+ <p>Own Id: OTP-8480</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.16.1 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.16</title>
+ <p>Version 4.16 supports code replacement in runtime from/to
+ version 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent|manager] Entries in the audit trail log can now be
+ augmented by a sequence number. </p>
+ <p>This is enabled by the <c>seqno</c> option, which is part of the
+ <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso>
+ config option. </p>
+ <p>See the
+ <seealso marker="snmp_app#configuration_params">reference manual</seealso>
+ or the
+ <seealso marker="snmp_config#configuration_params">Configuring the application</seealso>
+ chapter of the User's Guide for further info. </p>
+
+ <p>Own Id: OTP-8395</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[manager] Registration of agents using the config file,
+ <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>,
+ does not work. This has now been corrected. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-8442</p>
+ </item>
+
+ <item>
+ <p>The config utility
+ (<seealso marker="snmp#config">snmp:config/0</seealso>)
+ generated a default notify.conf
+ with a bad name for the standard trap entry (was "stadard trap",
+ but should have been "standard trap"). This has been corrected. </p>
+ <p>Kenji Rikitake</p>
+ <p>Own Id: OTP-8433</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.16 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.15</title>
+
+ <p>Version 4.15 supports code replacement in runtime from/to
+ version 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>The documentation is now built with open source tools
+ (<em>xsltproc</em> and <em>fop</em>) that exists on most
+ platforms. One visible change is that the frames are removed.</p>
+ <p>Own Id: OTP-8249</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] When information from an unknown agent is received,
+ it was previously delivered to the default user via calls to all
+ the functions of the callback API depending on the info type
+ (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>).
+ The problem was that the <c>TargetName</c> argument was useless
+ in this case (only an already known agent has a known/valid
+ <c>TargetName</c>, but the <c>TargetName</c> used in these calls
+ was generated "on the fly"). </p>
+ <p>This has now been changed so that when a message is received
+ from an unknown agent, then only
+ <seealso marker="snmpm_user#handle_agent">handle_agent</seealso>
+ (for the default user) is called, but now this call also has a
+ <c>Type</c> argument, which is
+ <c>pdu | trap | report | inform</c>, depending on what kind of
+ message was actually received, thus making it possible for the
+ user to properly analyze the data received. </p>
+ <p>To handle this, the
+ <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has
+ been updated. </p>
+ <p>*** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>Own Id: OTP-8229</p>
+ <!-- <p>Aux Id: Seq 11312</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ </section> <!-- 4.15 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.14</title>
<p>Version 4.14 supports code replacement in runtime from/to
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml
index 694e619da1..f6abe783b3 100644
--- a/lib/snmp/doc/src/snmp_app.xml
+++ b/lib/snmp/doc/src/snmp_app.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -78,7 +78,15 @@
].
</pre>
- <!-- The info below is also found in the snmp_config.xml file -->
+
+ <!--
+ ********************************************************
+
+ The info below is also found in the snmp_config.xml file
+
+ ********************************************************
+ -->
+
<p>Each snmp component has its own set of configuration parameters,
even though some of the types are common to both components. </p>
@@ -92,6 +100,7 @@
{agent_verbosity, verbosity()} |
{discovery, agent_discovery()} |
{versions, versions()} |
+ {gb_max_vbs, gb_max_vbs()} |
{priority, priority()} |
{multi_threaded, multi_threaded()} |
{db_dir, db_dir()} |
@@ -122,8 +131,10 @@
{def_user_data, def_user_data()}
</pre>
+ <marker id="agent_opts_and_types"></marker>
<p>Agent specific config options and types:</p>
<taglist>
+ <marker id="agent_type"></marker>
<tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag>
<item>
<p>If <c>master</c>, one master agent is
@@ -131,6 +142,7 @@
<p>Default is <c>master</c>.</p>
</item>
+ <marker id="agent_disco"></marker>
<tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_discovery_opt() =
@@ -143,6 +155,7 @@
<p>For defaults see the options in <c>agent_discovery_opt()</c>.</p>
</item>
+ <marker id="agent_term_disco_opts"></marker>
<tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_terminating_discovery_opt() =
@@ -160,6 +173,7 @@
</list>
</item>
+ <marker id="agent_orig_disco_opts"></marker>
<tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_originating_discovery_opt() =
@@ -173,6 +187,7 @@
</list>
</item>
+ <marker id="agent_mt"></marker>
<tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, the agent is multi-threaded, with one
@@ -180,11 +195,21 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_data_dir"></marker>
<tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP agent internal db files are stored.</p>
</item>
+ <marker id="agent_gb_max_vbs"></marker>
+ <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>Defines the maximum number of varbinds allowed
+ in a Get-BULK response.</p>
+ <p>Default is <c>1000</c>.</p>
+ </item>
+
+ <marker id="agent_local_db"></marker>
<tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag>
<item>
<p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p>
@@ -192,6 +217,7 @@
<p>For defaults see the options in <c>local_db_opt()</c>.</p>
</item>
+ <marker id="agent_ldb_repair"></marker>
<tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag>
<item>
<p>When starting snmpa_local_db it always tries to open an
@@ -202,6 +228,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="agent_ldb_auto_save"></marker>
<tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag>
<item>
<p>The auto save interval. The table is flushed to disk
@@ -209,6 +236,7 @@
<p>Default is <c>5000</c>.</p>
</item>
+ <marker id="agent_net_if"></marker>
<tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_opt() = {module, agent_net_if_module()} | {verbosity, verbosity()} | {options, agent_net_if_options()}</c></p>
@@ -217,6 +245,7 @@
<p>For defaults see the options in <c>agent_net_if_opt()</c>.</p>
</item>
+ <marker id="agent_ni_module"></marker>
<tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface part for the
@@ -225,6 +254,7 @@
<p>Default is <c>snmpa_net_if</c>.</p>
</item>
+ <marker id="agent_ni_opts"></marker>
<tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_option() = {bind_to, bind_to()} |
@@ -239,12 +269,14 @@
<p>For defaults see the options in <c>agent_net_if_option()</c>.</p>
</item>
+ <marker id="agent_ni_req_limit"></marker>
<tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag>
<item>
<p>Max number of simultaneous requests handled by the agent.</p>
<p>Default is <c>infinity</c>.</p>
</item>
+ <marker id="agent_ni_filter_opts"></marker>
<tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_filter_option() = {module, agent_net_if_filter_module()}</c></p>
@@ -255,6 +287,7 @@
<c>agent_net_if_filter_option()</c>.</p>
</item>
+ <marker id="agent_ni_filter_module"></marker>
<tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface filter part for the
@@ -263,6 +296,7 @@
<p>Default is <c>snmpa_net_if_filter</c>.</p>
</item>
+ <marker id="agent_mibs"></marker>
<tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag>
<item>
<p>Specifies a list of MIBs (including path) that defines which MIBs
@@ -277,6 +311,7 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="agent_mib_storage"></marker>
<tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag>
<item>
<p>Specifies how info retrieved from the mibs will be stored.</p>
@@ -302,6 +337,7 @@
mnesia/dets table already exist.</p>
</item>
+ <marker id="agent_mib_server"></marker>
<tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
<item>
<p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p>
@@ -309,6 +345,7 @@
<p>For defaults see the options in <c>mib_server_opt()</c>.</p>
</item>
+ <marker id="agent_ms_meo"></marker>
<tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag>
<item>
<p>If this value is false, then when loading a mib each mib-
@@ -318,6 +355,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_teo"></marker>
<tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag>
<item>
<p>If this value is false, then when loading a mib each trap
@@ -327,6 +365,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_cache"></marker>
<tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag>
<item>
<p>Shall the agent utilize the mib server lookup cache or not.</p>
@@ -334,6 +373,7 @@
default values apply).</p>
</item>
+ <marker id="agent_ms_cache_opts"></marker>
<tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag>
<item>
<p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p>
@@ -341,6 +381,7 @@
<p>For defaults see the options in <c>mibs_cache_opt()</c>.</p>
</item>
+ <marker id="agent_ms_cache_autogc"></marker>
<tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag>
<item>
<p>Defines if the mib server shall perform cache gc automatically or
@@ -349,6 +390,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="agent_ms_cache_age"></marker>
<tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag>
<item>
<p>Defines how old the entries in the cache will be allowed before
@@ -358,6 +400,7 @@
<p>Default is <c>10 timutes</c>.</p>
</item>
+ <marker id="agent_ms_cache_gclimit"></marker>
<tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag>
<item>
<p>When performing a GC, this is the max number of cache entries
@@ -368,6 +411,7 @@
<p>Default is <c>100</c>.</p>
</item>
+ <marker id="agent_error_report_mod"></marker>
<tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag>
<item>
<p>Defines an error report module, implementing the
@@ -377,6 +421,7 @@
<p>Default is <c>snmpa_error_logger</c>.</p>
</item>
+ <marker id="agent_symbolic_store"></marker>
<tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag>
<item>
<p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p>
@@ -384,23 +429,29 @@
<p>For defaults see the options in <c>symbolic_store_opt()</c>.</p>
</item>
+ <marker id="agent_target_cache"></marker>
<tag><c>target_cache() = [target_cache_opt()]</c></tag>
<item>
<p><c>target_cache_opt() = {verbosity, verbosity()}</c></p>
<p>Defines options specific for the SNMP agent target cache. </p>
<p>For defaults see the options in <c>target_cache_opt()</c>.</p>
</item>
+
+ <marker id="agent_config"></marker>
<tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag>
<item>
<p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p>
<p>Defines specific config related options for the SNMP agent. </p>
<p>For defaults see the options in <c>agent_config_opt()</c>.</p>
</item>
+
+ <marker id="agent_config_dir"></marker>
<tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP agent configuration files are stored.</p>
</item>
+ <marker id="agent_force_load"></marker>
<tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c> the configuration files are re-read
@@ -412,14 +463,18 @@
</item>
</taglist>
+ <marker id="manager_opts_and_types"></marker>
<p>Manager specific config options and types:</p>
<taglist>
+ <marker id="manager_server"></marker>
<tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag>
<item>
<p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p>
<p>Specifies the options for the manager server process.</p>
<p>Default is <c>silence</c>.</p>
</item>
+
+ <marker id="manager_server_timeout"></marker>
<tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag>
<item>
<p>Asynchroneous request cleanup time. For every requests,
@@ -440,6 +495,7 @@
<p>Default is <c>30000</c>.</p>
</item>
+ <marker id="manager_config"></marker>
<tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag>
<item>
<p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p>
@@ -447,16 +503,19 @@
<p>For defaults see the options in <c>manager_config_opt()</c>.</p>
</item>
+ <marker id="manager_config_dir"></marker>
<tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP manager configuration files are stored.</p>
</item>
+ <marker id="manager_config_db_dir"></marker>
<tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP manager store persistent data.</p>
</item>
+ <marker id="manager_config_repair"></marker>
<tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag>
<item>
<p>Defines the repair option for the persistent database (if
@@ -464,6 +523,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="manager_config_auto_save"></marker>
<tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag>
<item>
<p>The auto save interval. The table is flushed to disk
@@ -471,6 +531,7 @@
<p>Default is <c>5000</c>.</p>
</item>
+ <marker id="manager_irb"></marker>
<tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag>
<item>
<p>This option defines how the manager will handle the sending of
@@ -500,6 +561,7 @@
<p>Default is <c>auto</c>.</p>
</item>
+ <marker id="manager_mibs"></marker>
<tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag>
<item>
<p>Specifies a list of MIBs (including path) and defines which MIBs
@@ -507,6 +569,7 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="manager_net_if"></marker>
<tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_opt() = {module, manager_net_if_module()} |
@@ -517,6 +580,7 @@
<p>For defaults see the options in <c>manager_net_if_opt()</c>.</p>
</item>
+ <marker id="manager_ni_opts"></marker>
<tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_option() = {bind_to, bind_to()} |
@@ -530,6 +594,7 @@
<p>For defaults see the options in <c>manager_net_if_option()</c>.</p>
</item>
+ <marker id="manager_ni_module"></marker>
<tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface part for the
@@ -538,6 +603,7 @@
<p>Default is <c>snmpm_net_if</c>.</p>
</item>
+ <marker id="manager_ni_filter_opts"></marker>
<tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p>
@@ -548,6 +614,7 @@
<c>manager_net_if_filter_option()</c>.</p>
</item>
+ <marker id="manager_ni_filter_module"></marker>
<tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface filter part for the
@@ -556,6 +623,7 @@
<p>Default is <c>snmpm_net_if_filter</c>.</p>
</item>
+ <marker id="manager_def_user_module"></marker>
<tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag>
<item>
<p>The module implementing the default user. See the
@@ -563,6 +631,7 @@
<p>Default is <c>snmpm_user_default</c>.</p>
</item>
+ <marker id="manager_def_user_data"></marker>
<tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag>
<item>
<p>Data for the default user. Passed to the user module when
@@ -571,8 +640,10 @@
</item>
</taglist>
+ <marker id="common_types"></marker>
<p>Common config types:</p>
<taglist>
+ <marker id="restart_type"></marker>
<tag><c>restart_type() = permanent | transient | temporary</c></tag>
<item>
<p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso>
@@ -580,6 +651,8 @@
<p>Default is <c>permanent</c> for the agent and <c>transient</c>
for the manager.</p>
</item>
+
+ <marker id="db_init_error"></marker>
<tag><c>db_init_error() = terminate | create</c></tag>
<item>
<p>Defines what to do if the agent or manager is unable to open an
@@ -588,23 +661,31 @@
agent/manager will remove the faulty file(s) and create new ones.</p>
<p>Default is <c>terminate</c>.</p>
</item>
+
+ <marker id="prio"></marker>
<tag><c><![CDATA[priority() = atom() <optional>]]></c></tag>
<item>
<p>Defines the Erlang priority for all SNMP processes.</p>
<p>Default is <c>normal</c>.</p>
</item>
+
+ <marker id="versions"></marker>
<tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag>
<item>
<p><c>version() = v1 | v2 | v3</c></p>
<p>Which SNMP versions shall be accepted/used.</p>
<p>Default is <c>[v1,v2,v3]</c>.</p>
</item>
+
+ <marker id="verbosity"></marker>
<tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag>
<item>
<p>Verbosity for a SNMP process. This specifies now much debug info
is printed.</p>
<p>Default is <c>silence</c>.</p>
</item>
+
+ <marker id="bind_to"></marker>
<tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, net_if binds to the IP address.
@@ -612,6 +693,8 @@
where it is running. </p>
<p>Default is <c>false</c>.</p>
</item>
+
+ <marker id="no_reuse"></marker>
<tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, net_if does not specify that the IP
@@ -619,22 +702,30 @@
the address is set to reusable. </p>
<p>Default is <c>false</c>.</p>
</item>
+
+ <marker id="recbuf"></marker>
<tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag>
<item>
<p>Receive buffer size. </p>
<p>Default value is defined by <c>gen_udp</c>.</p>
</item>
+
+ <marker id="sndbuf"></marker>
<tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag>
<item>
<p>Send buffer size. </p>
<p>Default value is defined by <c>gen_udp</c>.</p>
</item>
+
+ <marker id="note_store"></marker>
<tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag>
<item>
<p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p>
<p>Specifies the start-up verbosity for the SNMP note store.</p>
<p>For defaults see the options in <c>note_store_opt()</c>.</p>
</item>
+
+ <marker id="ns_timeout"></marker>
<tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag>
<item>
<p>Note cleanup time. When storing a note in the note store,
@@ -643,9 +734,9 @@
milli-seconds.</p>
<p>Default is <c>30000</c>.</p>
- <marker id="audit_trail_log"></marker>
</item>
+ <marker id="audit_trail_log"></marker>
<tag><c><![CDATA[audit_trail_log() = [audit_trail_log_opt()] <optional>]]></c></tag>
<item>
<p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p>
@@ -655,6 +746,8 @@
<c>size</c> options are mandatory.</p>
<p>If not present, audit trail logging is not used.</p>
</item>
+
+ <marker id="atl_type"></marker>
<tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag>
<item>
<p>Specifies what type of an audit trail log should be used.
@@ -675,12 +768,16 @@
</list>
<p>Default is <c>read_write</c>.</p>
</item>
+
+ <marker id="atl_dir"></marker>
<tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Specifies where the audit trail log should be stored.</p>
<p>If <c>audit_trail_log</c> specifies that logging should take
place, this parameter <em>must</em> be defined.</p>
</item>
+
+ <marker id="atl_size"></marker>
<tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag>
<item>
<p>Specifies the size of the audit
@@ -688,6 +785,8 @@
<p>If <c>audit_trail_log</c> specifies that logging should
take place, this parameter <em>must</em> be defined.</p>
</item>
+
+ <marker id="atl_repair"></marker>
<tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag>
<item>
<p>Specifies if and how the audit trail log shall be repaired
@@ -699,6 +798,8 @@
analysis.</p>
<p>Default is <c>true</c>.</p>
</item>
+
+ <marker id="atl_seqno"></marker>
<tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag>
<item>
<p>Specifies if the audit trail log entries will be (sequence)
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
index fc8562b638..0a49b7a62e 100644
--- a/lib/snmp/doc/src/snmp_config.xml
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -40,6 +40,7 @@
<item>starting the application (agent and/or manager)</item>
<item>debugging the application (agent and/or manager)</item>
</list>
+
<p>Refer also to the chapter(s)
<seealso marker="snmp_agent_config_files">Definition of Agent Configuration Files</seealso> and
<seealso marker="snmp_manager_config_files">Definition of Manager Configuration Files</seealso> which contains more detailed information
@@ -73,7 +74,14 @@
</item>
</list>
- <!-- The info below is also found in the snmp_app.xml file -->
+
+ <!--
+ *****************************************************
+
+ The info below is also found in the snmp_app.xml file
+
+ *****************************************************
+ -->
<p>The agent and manager uses (application) configuration parameters to
find out where these directories are located. The parameters should be
@@ -87,6 +95,7 @@
{agent_verbosity, verbosity()} |
{versions, versions()} |
{discovery, agent_discovery()} |
+ {gb_max_vbs, gb_max_vbs()} |
{priority, priority()} |
{multi_threaded, multi_threaded()} |
{db_dir, db_dir()} |
@@ -117,8 +126,10 @@
{def_user_data, def_user_data()}
</pre>
+ <marker id="agent_opts_and_types"></marker>
<p>Agent specific config options and types:</p>
<taglist>
+ <marker id="agent_type"></marker>
<tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag>
<item>
<p>If <c>master</c>, one master agent is
@@ -126,6 +137,7 @@
<p>Default is <c>master</c>.</p>
</item>
+ <marker id="agent_disco"></marker>
<tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_discovery_opt() =
@@ -138,6 +150,7 @@
<p>For defaults see the options in <c>agent_discovery_opt()</c>.</p>
</item>
+ <marker id="agent_term_disco_opts"></marker>
<tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_terminating_discovery_opt() =
@@ -155,6 +168,7 @@
</list>
</item>
+ <marker id="agent_orig_disco_opts"></marker>
<tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_originating_discovery_opt() =
@@ -168,6 +182,7 @@
</list>
</item>
+ <marker id="agent_mt"></marker>
<tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, the agent is multi-threaded, with one
@@ -175,11 +190,21 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_data_dir"></marker>
<tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP agent internal db files are stored.</p>
</item>
+ <marker id="agent_gb_max_vbs"></marker>
+ <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>Defines the maximum number of varbinds allowed
+ in a Get-BULK response.</p>
+ <p>Default is <c>1000</c>.</p>
+ </item>
+
+ <marker id="agent_local_db"></marker>
<tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag>
<item>
<p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p>
@@ -187,6 +212,7 @@
<p>For defaults see the options in <c>local_db_opt()</c>.</p>
</item>
+ <marker id="agent_ldb_repair"></marker>
<tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag>
<item>
<p>When starting snmpa_local_db it always tries to open an
@@ -197,6 +223,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="agent_ldb_auto_save"></marker>
<tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag>
<item>
<p>The auto save interval. The table is flushed to disk
@@ -204,6 +231,7 @@
<p>Default is <c>5000</c>.</p>
</item>
+ <marker id="agent_net_if"></marker>
<tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_option() = {module, agent_net_if_module()} |
@@ -214,6 +242,7 @@
<p>For defaults see the options in <c>agent_net_if_opt()</c>.</p>
</item>
+ <marker id="agent_ni_module"></marker>
<tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface part for the
@@ -222,6 +251,7 @@
<p>Default is <c>snmpa_net_if</c>.</p>
</item>
+ <marker id="agent_ni_opts"></marker>
<tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_option() = {bind_to, bind_to()} |
@@ -236,6 +266,14 @@
<p>For defaults see the options in <c>agent_net_if_option()</c>.</p>
</item>
+ <marker id="agent_ni_req_limit"></marker>
+ <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>Max number of simultaneous requests handled by the agent.</p>
+ <p>Default is <c>infinity</c>.</p>
+ </item>
+
+ <marker id="agent_ni_filter_opts"></marker>
<tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag>
<item>
<p><c><![CDATA[agent_net_if_filter_option() = {module, agent_net_if_filter_module()}]]></c></p>
@@ -245,6 +283,7 @@
<p>For defaults see the options in <c>agent_net_if_filter_option()</c>.</p>
</item>
+ <marker id="agent_ni_filter_module"></marker>
<tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface filter part for the
@@ -254,12 +293,7 @@
<p>Default is <c>snmpa_net_if_filter</c>.</p>
</item>
- <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag>
- <item>
- <p>Max number of simultaneous requests handled by the agent.</p>
- <p>Default is <c>infinity</c>.</p>
- </item>
-
+ <marker id="agent_mibs"></marker>
<tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag>
<item>
<p>Specifies a list of MIBs (including path) that defines which MIBs
@@ -274,6 +308,7 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="agent_mib_storage"></marker>
<tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag>
<item>
<p>Specifies how info retrieved from the mibs will be stored.</p>
@@ -299,6 +334,7 @@
mnesia/dets table already exist.</p>
</item>
+ <marker id="agent_mib_server"></marker>
<tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
<item>
<p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p>
@@ -306,6 +342,7 @@
<p>For defaults see the options in <c>mib_server_opt()</c>.</p>
</item>
+ <marker id="agent_ms_meo"></marker>
<tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag>
<item>
<p>If this value is false, then when loading a mib each mib-
@@ -315,6 +352,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_teo"></marker>
<tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag>
<item>
<p>If this value is false, then when loading a mib each trap
@@ -324,6 +362,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_cache"></marker>
<tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag>
<item>
<p>Shall the agent utilize the mib server lookup cache or not.</p>
@@ -331,6 +370,7 @@
default values apply).</p>
</item>
+ <marker id="agent_ms_cache_opts"></marker>
<tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag>
<item>
<p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p>
@@ -338,6 +378,7 @@
<p>For defaults see the options in <c>mibs_cache_opt()</c>.</p>
</item>
+ <marker id="agent_ms_cache_autogc"></marker>
<tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag>
<item>
<p>Defines if the mib server shall perform cache gc automatically or
@@ -346,6 +387,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="agent_ms_cache_age"></marker>
<tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag>
<item>
<p>Defines how old the entries in the cache will be allowed before
@@ -355,6 +397,7 @@
<p>Default is <c>10 timutes</c>.</p>
</item>
+ <marker id="agent_ms_cache_gclimit"></marker>
<tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag>
<item>
<p>When performing a GC, this is the max number of cache entries
@@ -365,6 +408,7 @@
<p>Default is <c>100</c>.</p>
</item>
+ <marker id="agent_error_report_mod"></marker>
<tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag>
<item>
<p>Defines an error report module, implementing the
@@ -374,6 +418,7 @@
<p>Default is <c>snmpa_error_logger</c>.</p>
</item>
+ <marker id="agent_symbolic_store"></marker>
<tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag>
<item>
<p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p>
@@ -381,12 +426,15 @@
<p>For defaults see the options in <c>symbolic_store_opt()</c>.</p>
</item>
+ <marker id="agent_target_cache"></marker>
<tag><c>target_cache() = [target_cache_opt()]</c></tag>
<item>
<p><c>target_cache_opt() = {verbosity, verbosity()}</c></p>
<p>Defines options specific for the SNMP agent target cache. </p>
<p>For defaults see the options in <c>target_cache_opt()</c>.</p>
</item>
+
+ <marker id="agent_config"></marker>
<tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag>
<item>
<p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p>
@@ -394,11 +442,13 @@
<p>For defaults see the options in <c>agent_config_opt()</c>.</p>
</item>
+ <marker id="agent_config_dir"></marker>
<tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP agent configuration files are stored.</p>
</item>
+ <marker id="agent_force_load"></marker>
<tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c> the configuration files are re-read
@@ -410,14 +460,18 @@
</item>
</taglist>
+ <marker id="manager_opts_and_types"></marker>
<p>Manager specific config options and types:</p>
<taglist>
+ <marker id="manager_server"></marker>
<tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag>
<item>
<p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p>
<p>Specifies the options for the manager server process.</p>
<p>Default is <c>silence</c>.</p>
</item>
+
+ <marker id="manager_server_timeout"></marker>
<tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag>
<item>
<p>Asynchroneous request cleanup time. For every requests,
@@ -438,6 +492,7 @@
<p>Default is <c>30000</c>.</p>
</item>
+ <marker id="manager_config"></marker>
<tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag>
<item>
<p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p>
@@ -445,16 +500,19 @@
<p>For defaults see the options in <c>manager_config_opt()</c>.</p>
</item>
+ <marker id="manager_config_dir"></marker>
<tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP manager configuration files are stored.</p>
</item>
+ <marker id="manager_config_db_dir"></marker>
<tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Defines where the SNMP manager store persistent data.</p>
</item>
+ <marker id="manager_config_repair"></marker>
<tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag>
<item>
<p>Defines the repair option for the persistent database (if
@@ -462,6 +520,7 @@
<p>Default is <c>true</c>.</p>
</item>
+ <marker id="manager_config_auto_save"></marker>
<tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag>
<item>
<p>The auto save interval. The table is flushed to disk
@@ -469,6 +528,7 @@
<p>Default is <c>5000</c>.</p>
</item>
+ <marker id="manager_irb"></marker>
<tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag>
<item>
<p>This option defines how the manager will handle the sending of
@@ -498,6 +558,7 @@
<p>Default is <c>auto</c>.</p>
</item>
+ <marker id="manager_mibs"></marker>
<tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag>
<item>
<p>Specifies a list of MIBs (including path) and defines which MIBs
@@ -505,6 +566,7 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="manager_net_if"></marker>
<tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_opt() = {module, manager_net_if_module()} |
@@ -515,6 +577,7 @@
<p>For defaults see the options in <c>manager_net_if_opt()</c>.</p>
</item>
+ <marker id="manager_ni_opts"></marker>
<tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_option() = {bind_to, bind_to()} |
@@ -528,6 +591,7 @@
<p>For defaults see the options in <c>manager_net_if_option()</c>.</p>
</item>
+ <marker id="manager_ni_module"></marker>
<tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface part for the
@@ -536,6 +600,7 @@
<p>Default is <c>snmpm_net_if</c>.</p>
</item>
+ <marker id="manager_ni_filter_opts"></marker>
<tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag>
<item>
<p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p>
@@ -546,6 +611,7 @@
<c>manager_net_if_filter_option()</c>.</p>
</item>
+ <marker id="manager_ni_filter_module"></marker>
<tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag>
<item>
<p>Module which handles the network interface filter part for the
@@ -554,6 +620,7 @@
<p>Default is <c>snmpm_net_if_filter</c>.</p>
</item>
+ <marker id="manager_def_user_module"></marker>
<tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag>
<item>
<p>The module implementing the default user. See the
@@ -561,6 +628,7 @@
<p>Default is <c>snmpm_user_default</c>.</p>
</item>
+ <marker id="manager_def_user_data"></marker>
<tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag>
<item>
<p>Data for the default user. Passed to the user when calling
@@ -569,8 +637,10 @@
</item>
</taglist>
+ <marker id="common_types"></marker>
<p>Common config types:</p>
<taglist>
+ <marker id="restart_type"></marker>
<tag><c>restart_type() = permanent | transient | temporary</c></tag>
<item>
<p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso>
@@ -579,6 +649,7 @@
for the manager.</p>
</item>
+ <marker id="db_init_error"></marker>
<tag><c>db_init_error() = terminate | create</c></tag>
<item>
<p>Defines what to do if the agent is unable to open an
@@ -588,12 +659,14 @@
<p>Default is <c>terminate</c>.</p>
</item>
+ <marker id="prio"></marker>
<tag><c><![CDATA[priority() = atom() <optional>]]></c></tag>
<item>
<p>Defines the Erlang priority for all SNMP processes.</p>
<p>Default is <c>normal</c>.</p>
</item>
+ <marker id="versions"></marker>
<tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag>
<item>
<p><c>version() = v1 | v2 | v3</c></p>
@@ -601,6 +674,7 @@
<p>Default is <c>[v1,v2,v3]</c>.</p>
</item>
+ <marker id="verbosity"></marker>
<tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag>
<item>
<p>Verbosity for a SNMP process. This specifies now much debug info
@@ -608,6 +682,7 @@
<p>Default is <c>silence</c>.</p>
</item>
+ <marker id="bind_to"></marker>
<tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, net_if binds to the IP address.
@@ -616,6 +691,7 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="no_reuse"></marker>
<tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag>
<item>
<p>If <c>true</c>, net_if does not specify that the IP
@@ -624,17 +700,21 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="recbuf"></marker>
<tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag>
<item>
<p>Receive buffer size. </p>
<p>Default value is defined by <c>gen_udp</c>.</p>
</item>
+
+ <marker id="sndbuf"></marker>
<tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag>
<item>
<p>Send buffer size. </p>
<p>Default value is defined by <c>gen_udp</c>.</p>
</item>
+ <marker id="note_store"></marker>
<tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag>
<item>
<p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p>
@@ -642,6 +722,7 @@
<p>For defaults see the options in <c>note_store_opt()</c>.</p>
</item>
+ <marker id="ns_timeout"></marker>
<tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag>
<item>
<p>Note cleanup time. When storing a note in the note store,
@@ -649,10 +730,9 @@
process performs a GC to remove the expired note's. Time in
milli-seconds.</p>
<p>Default is <c>30000</c>.</p>
-
- <marker id="audit_trail_log"></marker>
</item>
+ <marker id="audit_trail_log"></marker>
<tag><c><![CDATA[audit_trail_log() [audit_trail_log_opt()] <optional>]]></c></tag>
<item>
<p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p>
@@ -663,6 +743,7 @@
<p>If not present, audit trail logging is not used.</p>
</item>
+ <marker id="atl_type"></marker>
<tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag>
<item>
<p>Specifies what type of an audit trail log should be used.
@@ -684,6 +765,7 @@
<p>Default is <c>read_write</c>.</p>
</item>
+ <marker id="atl_dir"></marker>
<tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag>
<item>
<p>Specifies where the audit trail log should be stored.</p>
@@ -691,6 +773,7 @@
place, this parameter <em>must</em> be defined.</p>
</item>
+ <marker id="atl_size"></marker>
<tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag>
<item>
<p>Specifies the size of the audit
@@ -699,6 +782,7 @@
take place, this parameter <em>must</em> be defined.</p>
</item>
+ <marker id="atl_repair"></marker>
<tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag>
<item>
<p>Specifies if and how the audit trail log shall be repaired
@@ -710,6 +794,8 @@
analysis.</p>
<p>Default is <c>true</c>.</p>
</item>
+
+ <marker id="atl_seqno"></marker>
<tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag>
<item>
<p>Specifies if the audit trail log entries will be (sequence)
diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml
index 27d89ea4e3..2322af28cc 100644
--- a/lib/snmp/doc/src/snmpa.xml
+++ b/lib/snmp/doc/src/snmpa.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2011</year>
+ <year>2004</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -198,12 +198,18 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<type>
<v>BackupDir = string()</v>
<v>Agent = pid() | atom()</v>
+ <v>Reason = backup_in_progress | term()</v>
</type>
<desc>
<p>Backup persistent/permanent data handled by the agent
(such as local-db, mib-data and vacm). </p>
<p>Data stored by mnesia is not handled. </p>
<p>BackupDir cannot be identical to DbDir. </p>
+ <p>Simultaneous backup calls are <em>not</em> allowed.
+ That is, two different processes cannot simultaneously
+ successfully call this function. One of them will be first,
+ and succeed. The second will fail with the error reason
+ <c>backup_in_progress</c>. </p>
<marker id="info"></marker>
</desc>
@@ -217,13 +223,13 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</type>
<desc>
<p>Returns a list (a dictionary) containing information about
- the agent. Information includes loaded MIBs, registered
- sub-agents, some information about the memory allocation. </p>
- <p>As of version 4.4 the format of the info has been changed.
- To convert the info to the old format, call the
- <seealso marker="#old_info_format">old_info_format</seealso>
- function. </p>
-
+ the agent. Information includes loaded MIBs, registered
+ sub-agents, some information about the memory allocation. </p>
+ <p>As of version 4.4 the format of the info has been changed.
+ To convert the info to the old format, call the
+ <seealso marker="#old_info_format">old_info_format</seealso>
+ function. </p>
+
<marker id="old_info_format"></marker>
</desc>
</func>
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index bc39e1fa35..078ef15821 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -52,6 +52,7 @@ $(EBIN)/snmpa_acm.$(EMULATOR): \
$(EBIN)/snmpa_agent.$(EMULATOR): \
snmpa_agent.erl \
+ snmpa_internal.hrl \
../misc/snmp_debug.hrl \
../misc/snmp_verbosity.hrl \
../../include/snmp_types.hrl
@@ -136,6 +137,7 @@ $(EBIN)/snmpa_set_lib.$(EMULATOR): \
$(EBIN)/snmpa_supervisor.$(EMULATOR): \
snmpa_supervisor.erl \
+ snmpa_internal.hrl \
../misc/snmp_debug.hrl \
../misc/snmp_verbosity.hrl
diff --git a/lib/snmp/src/agent/snmp_generic_mnesia.erl b/lib/snmp/src/agent/snmp_generic_mnesia.erl
index a73aad5b33..ce42af404b 100644
--- a/lib/snmp/src/agent/snmp_generic_mnesia.erl
+++ b/lib/snmp/src/agent/snmp_generic_mnesia.erl
@@ -121,7 +121,7 @@ table_func(set, RowIndex, Cols, Name) ->
fun() ->
snmp_generic:table_set_row(
{Name, mnesia}, nofunc,
- {snmp_generic_mnesia, table_try_make_consistent},
+ fun table_try_make_consistent/2,
RowIndex, Cols)
end) of
{atomic, Value} ->
@@ -368,7 +368,8 @@ table_set_elements(Name, RowIndex, Cols) ->
_ -> false
end.
table_set_elements(Name, RowIndex, Cols, ConsFunc) ->
- #table_info{index_types = Indexes, first_own_index = FirstOwnIndex} =
+ #table_info{index_types = Indexes,
+ first_own_index = FirstOwnIndex} =
snmp_generic:table_info(Name),
AddCol = if
FirstOwnIndex == 0 -> 2;
diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl
index 60bd3e0912..a45db89c09 100644
--- a/lib/snmp/src/agent/snmp_target_mib.erl
+++ b/lib/snmp/src/agent/snmp_target_mib.erl
@@ -46,8 +46,14 @@
%% Column not accessible via SNMP - needed when the agent sends informs
-define(snmpTargetAddrEngineId, 10).
%% Extra comlumns for the augmented table snmpTargetAddrExtTable
--define(snmpTargetAddrTMask, 11).
--define(snmpTargetAddrMMS, 12).
+-define(snmpTargetAddrTMask, 11).
+-define(snmpTargetAddrMMS, 12).
+
+-ifdef(snmp_extended_verbosity).
+-define(vt(F,A), ?vtrace(F, A)).
+-else.
+-define(vt(_F, _A), ok).
+-endif.
%%-----------------------------------------------------------------
@@ -459,10 +465,16 @@ get_target_addrs() ->
get_target_addrs(Key, {Tab, _} = TabDb, Acc) ->
+ ?vt("get_target_addrs -> entry with"
+ "~n Key: ~p", [Key]),
case table_next(Tab, Key) of
endOfTable ->
+ ?vt("get_target_addrs -> endOfTable when"
+ "~n Acc: ~p", [Acc]),
Acc;
NextKey ->
+ ?vt("get_target_addrs -> next ok: "
+ "~n NextKey: ~p", [NextKey]),
case get_target_addr(TabDb, NextKey) of
{ok, Targ} ->
get_target_addrs(NextKey, TabDb, [Targ| Acc]);
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 37f6dd3f26..2cee91b081 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -203,18 +203,16 @@ init_sec2group_table([Row | T]) ->
init_sec2group_table(T);
init_sec2group_table([]) -> true.
-init_access_table([{GN, Prefix, Model, Level, Row} | T]) ->
-%% ?vtrace("init access table: "
-%% "~n GN: ~p"
-%% "~n Prefix: ~p"
-%% "~n Model: ~p"
-%% "~n Level: ~p"
-%% "~n Row: ~p",[GN, Prefix, Model, Level, Row]),
- Key = [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level],
- snmpa_vacm:insert([{Key, Row}], false),
- init_access_table(T);
-init_access_table([]) ->
- snmpa_vacm:dump_table().
+make_access_key(GN, Prefix, Model, Level) ->
+ [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level].
+
+make_access_entry({GN, Prefix, Model, Level, Row}) ->
+ Key = make_access_key(GN, Prefix, Model, Level),
+ {Key, Row}.
+
+init_access_table(TableData) ->
+ TableData2 = [make_access_entry(E) || E <- TableData],
+ snmpa_vacm:insert(TableData2, true).
init_view_table([Row | T]) ->
%% ?vtrace("init view table: "
@@ -276,10 +274,7 @@ add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) ->
Match, RV, WV, NV},
case (catch check_vacm(Access)) of
{ok, {vacmAccess, {GN, Pref, SM, SL, Row}}} ->
- Key1 = [length(GN) | GN],
- Key2 = [length(Pref) | Pref],
- Key3 = [SM, SL],
- Key = Key1 ++ Key2 ++ Key3,
+ Key = make_access_key(GN, Pref, SM, SL),
snmpa_vacm:insert([{Key, Row}], false),
snmpa_agent:invalidate_ca_cache(),
{ok, Key};
diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl
index 50b169e4e7..c400aaddf7 100644
--- a/lib/snmp/src/agent/snmpa.erl
+++ b/lib/snmp/src/agent/snmpa.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -547,7 +547,7 @@ update_mibs_cache_age(Agent, Age) ->
update_mibs_cache_gclimit(GcLimit) ->
- update_mibs_cache_age(snmp_master_agent, GcLimit).
+ update_mibs_cache_gclimit(snmp_master_agent, GcLimit).
update_mibs_cache_gclimit(Agent, GcLimit) ->
snmpa_agent:update_mibs_cache_gclimit(Agent, GcLimit).
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 46c634969d..9cc986cf47 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.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
@@ -68,8 +68,11 @@
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3, tr_var/2, tr_varbind/1,
- handle_pdu/7, worker/2, worker_loop/1,
+ handle_pdu/8, worker/2, worker_loop/1,
do_send_trap/7, do_send_trap/8]).
+%% <BACKWARD-COMPAT>
+-export([handle_pdu/7]).
+%% </BACKWARD-COMPAT>
-include("snmpa_internal.hrl").
@@ -87,7 +90,6 @@
-define(DISCO_TERMINATING_TRIGGER_USERNAME, "").
-
-ifdef(snmp_debug).
-define(GS_START_LINK3(Prio, Parent, Ref, Opts),
gen_server:start_link(?MODULE, [Prio, Parent, Ref, Opts],
@@ -103,13 +105,49 @@
gen_server:start_link({local, Name}, ?MODULE,
[Prio, Parent, Ref, Opts],[])).
-endif.
-
+
+%% Increment this whenever a change is made to the worker interface
+-define(WORKER_INTERFACE_VERSION, 1).
+
+%% -- Utility macros for creating worker commands --
+-define(mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
+ #wrequest{cmd = handle_pdu,
+ info = [{vsn, Vsn},
+ {pdu, Pdu},
+ {pdu_ms, PduMS},
+ {acm_data, ACMData},
+ {addr, Address},
+ {gb_max_vbs, GbMaxVBs},
+ {extra, Extra}]}).
+-define(mk_send_trap_wreq(TrapRec, NotifyName, ContextName,
+ Recv, Vbs, LocalEngineID, Extra),
+ #wrequest{cmd = send_trap,
+ info = [{trap_rec, TrapRec},
+ {notify_name, NotifyName},
+ {context_name, ContextName},
+ {receiver, Recv},
+ {varbinds, Vbs},
+ {local_engine_id, LocalEngineID},
+ {extra, Extra}]}).
+-define(mk_terminate_wreq(), #wrequest{cmd = terminate, info = []}).
+-define(mk_verbosity_wreq(V), #wrequest{cmd = verbosity,
+ info = [{verbosity, V}]}).
+
-record(notification_filter, {id, mod, data}).
-record(disco,
{from, rec, sender, target, engine_id,
sec_level, ctx, ivbs, stage, handler, extra}).
+%% This record is used when sending requests to the worker processes
+-record(wrequest,
+ {
+ version = ?WORKER_INTERFACE_VERSION,
+ cmd,
+ info
+ }
+ ).
+
%%-----------------------------------------------------------------
%% The agent is multi-threaded, i.e. each request is handled
@@ -142,7 +180,8 @@
net_if_mod,
backup,
disco,
- mibs_cache_request}).
+ mibs_cache_request,
+ gb_max_vbs}).
%%%-----------------------------------------------------------------
@@ -330,6 +369,8 @@ do_init(Prio, Parent, Ref, Options) ->
MultiT = get_multi_threaded(Options),
Vsns = get_versions(Options),
+ GbMaxVbs = get_gb_max_vbs(Options),
+
NS = start_note_store(Prio, Ref, Options),
{Type, NetIfPid, NetIfMod} =
start_net_if(Parent, Prio, Ref, Vsns, NS, Options),
@@ -348,7 +389,8 @@ do_init(Prio, Parent, Ref, Options) ->
ref = Ref,
vsns = Vsns,
note_store = NS,
- net_if_mod = NetIfMod}}.
+ net_if_mod = NetIfMod,
+ gb_max_vbs = GbMaxVbs}}.
start_note_store(Prio, Ref, Options) ->
@@ -410,7 +452,8 @@ start_net_if(Parent, _Prio, _Ref, _Vsns, _NoteStore, _Options)
start_mib_server(Prio, Ref, Mibs, Options) ->
?vdebug("start_mib_server -> with Prio: ~p", [Prio]),
MibStorage = get_mib_storage(Options),
- MibsOpts = [{mib_storage, MibStorage}|get_option(mib_server, Options, [])],
+ MibsOpts = [{mib_storage, MibStorage} |
+ get_option(mib_server, Options, [])],
?vtrace("start_mib_server -> "
"~n Mibs: ~p"
@@ -751,7 +794,8 @@ handle_info({snmp_pdu, Vsn, Pdu, PduMS, ACMData, Address, Extra}, S) ->
?vdebug("handle_info(snmp_pdu) -> entry with"
"~n Vsn: ~p"
"~n Pdu: ~p"
- "~n Address: ~p", [Vsn, Pdu, Address]),
+ "~n Address: ~p"
+ "~n Extra: ~p", [Vsn, Pdu, Address, Extra]),
NewS = handle_snmp_pdu(is_valid_pdu_type(Pdu#pdu.type),
Vsn, Pdu, PduMS, ACMData, Address, Extra, S),
@@ -934,6 +978,7 @@ handle_info({'EXIT', Pid, Reason}, S) ->
end,
{noreply, S}
end;
+
handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}},
#state{mibs_cache_request = {Pid, Ref, From}} = S) ->
?vlog("reply from the mibs cache request handler (~p): ~n~p",
@@ -1075,7 +1120,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) ->
"~n PduData: ~p",
[MibView,Varbinds,PduData]),
put_pdu_data(PduData),
- {reply, do_get_next(MibView, Varbinds), S};
+ {reply, do_get_next(MibView, Varbinds, infinity), S};
handle_call({subagent_set, Arguments, PduData}, _From, S) ->
?vlog("[handle_call] subagent set:"
"~n Arguments: ~p"
@@ -1116,7 +1161,7 @@ handle_call({get_next, Vars, Context}, _From, S) ->
?vdebug("Varbinds: ~p",[Varbinds]),
MibView = snmpa_acm:get_root_mib_view(),
Reply =
- case do_get_next(MibView, Varbinds) of
+ case do_get_next(MibView, Varbinds, infinity) of
{noError, 0, NewVarbinds} ->
Vbs = lists:keysort(#varbind.org_index, NewVarbinds),
[{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs];
@@ -1217,7 +1262,8 @@ handle_call(info, _From, S) ->
handle_call(get_net_if, _From, S) ->
{reply, get(net_if), S};
-handle_call({backup, BackupDir}, From, S) ->
+%% Only accept a backup request if there is none already in progress
+handle_call({backup, BackupDir}, From, #state{backup = undefined} = S) ->
?vlog("backup: ~p", [BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -1234,7 +1280,11 @@ handle_call({backup, BackupDir}, From, S) ->
end),
?vtrace("backup server: ~p", [BackupServer]),
{noreply, S#state{backup = {BackupServer, From}}};
-
+
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(dump_mibs, _From, S) ->
Reply = snmpa_mib:dump(get(mibserver)),
{reply, Reply, S};
@@ -1283,27 +1333,27 @@ handle_call({me_of, Oid}, _From, S) ->
{reply, Reply, S};
handle_call(get_log_type, _From, S) ->
- ?vlog("get_log_type", []),
+ ?vlog("handle_call(get_log_type) -> entry with", []),
Reply = handle_get_log_type(S),
{reply, Reply, S};
handle_call({set_log_type, NewType}, _From, S) ->
- ?vlog("set_log_type -> "
+ ?vlog("handle_call(set_log_type) -> entry with"
"~n NewType: ~p", [NewType]),
Reply = handle_set_log_type(S, NewType),
{reply, Reply, S};
handle_call(get_request_limit, _From, S) ->
- ?vlog("get_request_limit", []),
+ ?vlog("handle_call(get_request_limit) -> entry with", []),
Reply = handle_get_request_limit(S),
{reply, Reply, S};
handle_call({set_request_limit, NewLimit}, _From, S) ->
- ?vlog("set_request_limit -> "
+ ?vlog("handle_call(set_request_limit) -> entry with"
"~n NewLimit: ~p", [NewLimit]),
Reply = handle_set_request_limit(S, NewLimit),
{reply, Reply, S};
-
+
handle_call(stop, _From, S) ->
{stop, normal, ok, S};
@@ -1312,15 +1362,15 @@ handle_call(Req, _From, S) ->
Reply = {error, {unknown, Req}},
{reply, Reply, S}.
-handle_cast({verbosity,Verbosity}, S) ->
- ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+handle_cast({verbosity, Verbosity}, S) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity), Verbosity]),
put(verbosity,snmp_verbosity:validate(Verbosity)),
case S#state.worker of
- Pid when is_pid(Pid) -> Pid ! {verbosity,Verbosity};
+ Pid when is_pid(Pid) -> Pid ! ?mk_verbosity_wreq(Verbosity);
_ -> ok
end,
case S#state.set_worker of
- Pid2 when is_pid(Pid2) -> Pid2 ! {verbosity,Verbosity};
+ Pid2 when is_pid(Pid2) -> Pid2 ! ?mk_verbosity_wreq(Verbosity);
_ -> ok
end,
{noreply, S};
@@ -1407,13 +1457,80 @@ handle_mibs_cache_request(MibServer, Req) ->
%% Downgrade
%%
-%% code_change({down, _Vsn}, S, downgrade_to_pre_4_13) ->
-%% {ok, S2};
+code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) ->
+ #state{type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR} = S1,
+ S2 = {state,
+ type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR},
+ {ok, S2};
%% Upgrade
%%
-%% code_change(_Vsn, S, upgrade_from_pre_4_13) ->
-%% {ok, S2};
+code_change(_Vsn, S1, upgrade_from_pre_4_17_3) ->
+ {state,
+ type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR} = S1,
+ S2 = #state{type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MT,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NF,
+ note_store = NoteStore,
+ mib_server = MS,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup,
+ disco = Disco,
+ mibs_cache_request = MCR,
+ gb_max_vbs = ?DEFAULT_GB_MAX_VBS},
+ {ok, S2};
code_change(_Vsn, S, _Extra) ->
{ok, S}.
@@ -1453,7 +1570,7 @@ worker_start(Dict) ->
%% worker_stop(Pid, infinity).
worker_stop(Pid, Timeout) when is_pid(Pid) ->
- Pid ! terminate,
+ Pid ! ?mk_terminate_wreq(),
receive
{'EXIT', Pid, normal} ->
ok
@@ -1590,9 +1707,11 @@ invalidate_ca_cache() ->
%%
%%-----------------------------------------------------------------
-spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
+%% This functions spawns a temporary worker process,
+%% that evaluates one request and then silently exits.
+spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) ->
Dict = get(),
- Args = [Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict],
+ Args = [Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict],
proc_lib:spawn_link(?MODULE, handle_pdu, Args).
spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs,
@@ -1610,7 +1729,7 @@ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, Dict) ->
lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
- put(sname,trap_sender_short_name(get(sname))),
+ put(sname, trap_sender_short_name(get(sname))),
?vlog("starting",[]),
snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, get(net_if)).
@@ -1622,58 +1741,122 @@ worker(Master, Dict) ->
worker_loop(Master).
worker_loop(Master) ->
- receive
- {Vsn, Pdu, PduMS, ACMData, Address, Extra} ->
- ?vtrace("worker_loop -> received request", []),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
- Master ! worker_available;
-
- %% We don't trap EXITs!
- {TrapRec, NotifyName, ContextName, Recv, Vbs} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- ?DEFAULT_NOTIF_EXTRA_INFO,
- get(net_if)),
- Master ! worker_available;
-
- %% We don't trap EXITs!
- {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- LocalEngineID, ?DEFAULT_NOTIF_EXTRA_INFO,
- get(net_if)),
- Master ! worker_available;
-
- {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo} ->
- ?vtrace("worker_loop -> send trap:"
- "~n ~p", [TrapRec]),
- snmpa_trap:send_trap(TrapRec, NotifyName,
- ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo,
- get(net_if)),
- Master ! worker_available;
-
- {verbosity, Verbosity} ->
- put(verbosity,snmp_verbosity:validate(Verbosity));
-
- terminate ->
- exit(normal);
-
- _X ->
- %% ignore
- ok
-
- after 30000 ->
- %% This is to assure that the worker process leaves a
- %% possibly old version of this module.
- ok
- end,
+ Res =
+ receive
+ #wrequest{cmd = handle_pdu,
+ info = Info} = Req ->
+ ?vtrace("worker_loop -> received handle_pdu request with"
+ "~n Info: ~p", [Info]),
+ Vsn = proplists:get_value(vsn, Info),
+ Pdu = proplists:get_value(pdu, Info),
+ PduMS = proplists:get_value(pdu_ms, Info),
+ ACMData = proplists:get_value(acm_data, Info),
+ Address = proplists:get_value(addr, Info),
+ GbMaxVBs = proplists:get_value(gb_max_vbs, Info),
+ Extra = proplists:get_value(extra, Info),
+ HandlePduRes =
+ try
+ begin
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address,
+ GbMaxVBs, Extra)
+ end
+ catch
+ T:E ->
+ exit({worker_crash, Req, T, E,
+ erlang:get_stacktrace()})
+ end,
+ Master ! worker_available,
+ HandlePduRes; % For debugging...
+
+
+ #wrequest{cmd = send_trap,
+ info = Info} = Req ->
+ ?vtrace("worker_loop -> received send_trap request with"
+ "~n Info: ~p", [Info]),
+ TrapRec = proplists:get_value(trap_rec, Info),
+ NotifyName = proplists:get_value(notify_name, Info),
+ ContextName = proplists:get_value(context_name, Info),
+ Recv = proplists:get_value(receiver, Info),
+ Vbs = proplists:get_value(varbinds, Info),
+ LocalEngineID = proplists:get_value(local_engine_id, Info),
+ Extra = proplists:get_value(extra, Info),
+ SendTrapRes =
+ try
+ begin
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, Extra,
+ get(net_if))
+ end
+ catch
+ T:E ->
+ exit({worker_crash, Req, T, E,
+ erlang:get_stacktrace()})
+ end,
+ Master ! worker_available,
+ SendTrapRes; % For debugging...
+
+
+ #wrequest{cmd = verbosity,
+ info = Info} ->
+ Verbosity = proplists:get_value(verbosity, Info),
+ put(verbosity, snmp_verbosity:validate(Verbosity));
+
+
+ #wrequest{cmd = terminate} ->
+ ?vtrace("worker_loop -> received terminate request", []),
+ exit(normal);
+
+
+ %% *************************************************************
+ %%
+ %% Kept for backward compatibillity reasons
+ %%
+ %% *************************************************************
+
+ {Vsn, Pdu, PduMS, ACMData, Address, Extra} ->
+ ?vtrace("worker_loop -> received request", []),
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address,
+ ?DEFAULT_GB_MAX_VBS, Extra),
+ Master ! worker_available;
+
+ %% We don't trap exits!
+ {TrapRec, NotifyName, ContextName, Recv, Vbs} ->
+ ?vtrace("worker_loop -> send trap:"
+ "~n ~p", [TrapRec]),
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs, get(net_if)),
+ Master ! worker_available;
+
+ %% We don't trap exits!
+ {send_trap,
+ TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
+ ExtraInfo} ->
+ ?vtrace("worker_loop -> send trap:"
+ "~n ~p", [TrapRec]),
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo,
+ get(net_if)),
+ Master ! worker_available;
+
+ {verbosity, Verbosity} ->
+ put(verbosity, snmp_verbosity:validate(Verbosity));
+
+ terminate ->
+ exit(normal);
+
+ _X ->
+ %% ignore
+ ignore_unknown
+
+ after 30000 ->
+ %% This is to assure that the worker process leaves a
+ %% possibly old version of this module.
+ ok
+ end,
+ ?vtrace("worker_loop -> wrap with"
+ "~n ~p", [Res]),
?MODULE:worker_loop(Master).
@@ -1681,42 +1864,52 @@ worker_loop(Master) ->
%%-----------------------------------------------------------------
handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra,
- #state{multi_threaded = false} = S) ->
+ #state{multi_threaded = false,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> single-thread agent",[]),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
S;
handle_snmp_pdu(true, Vsn, #pdu{type = 'set-request'} = Pdu, PduMS,
ACMData, Address, Extra,
#state{set_worker = Worker} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"send set-request to main worker",[]),
- Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra},
+ WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, infinity, Extra),
+ Worker ! WRequest,
S#state{worker_state = busy};
handle_snmp_pdu(true, Vsn, Pdu, PduMS,
ACMData, Address, Extra,
- #state{worker_state = busy} = S) ->
+ #state{worker_state = busy,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"main worker busy - create new worker",[]),
- spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
S;
handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra,
- #state{worker = Worker} = S) ->
+ #state{worker = Worker,
+ gb_max_vbs = GbMaxVBs} = S) ->
?vtrace("handle_snmp_pdu -> multi-thread agent: "
"send to main worker",[]),
- Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra},
+ WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra),
+ Worker ! WRequest,
S#state{worker_state = busy};
handle_snmp_pdu(_, _Vsn, _Pdu, _PduMS, _ACMData, _Address, _Extra, S) ->
S.
%% Called via the spawn_thread function
+%% <BACKWARD-COMPAT>
handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict) ->
+ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, ?DEFAULT_GB_MAX_VBS, Extra,
+ Dict).
+%% </BACKWARD-COMPAT>
+handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict) ->
lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
put(sname, pdu_handler_short_name(get(sname))),
?vlog("new worker starting",[]),
- handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra).
+ handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra).
-handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
+handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) ->
%% OTP-3324
AuthMod = get(auth_module),
case AuthMod:init_check_access(Pdu, ACMData) of
@@ -1725,7 +1918,8 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
"~n MibView: ~p"
"~n ContextName: ~p", [MibView, ContextName]),
AgentData = cheat(ACMData, Address, ContextName),
- do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra);
+ do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData,
+ GbMaxVBs, Extra);
{error, Reason} ->
?vlog("handle_pdu -> error:"
"~n Reason: ~p", [Reason]),
@@ -1739,16 +1933,19 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
end.
do_handle_pdu(MibView, Vsn, Pdu, PduMS,
- ACMData, {Community, Address, ContextName}, Extra) ->
+ ACMData, {Community, Address, ContextName},
+ GbMaxVBs, Extra) ->
put(net_if_data, Extra),
+
RePdu = process_msg(MibView, Vsn, Pdu, PduMS, Community,
- Address, ContextName),
+ Address, ContextName, GbMaxVBs),
?vtrace("do_handle_pdu -> processed:"
"~n RePdu: ~p", [RePdu]),
- get(net_if) ! {snmp_response, Vsn, RePdu,
- RePdu#pdu.type, ACMData, Address, Extra}.
+ NetIf = get(net_if),
+ NetIf ! {snmp_response, Vsn, RePdu,
+ RePdu#pdu.type, ACMData, Address, Extra}.
handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) ->
@@ -1949,9 +2146,9 @@ do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds,
master_agent ->
%% Send to main worker
?vtrace("do_handle_send_trap -> send to main worker",[]),
- S#state.worker ! {send_trap,
- TrapRec, NotifyName, ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo},
+ S#state.worker ! ?mk_send_trap_wreq(TrapRec, NotifyName,
+ ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo),
{ok, S#state{worker_state = busy}}
end.
@@ -2291,17 +2488,18 @@ handle_mib_of(MibServer, Oid) ->
%% Func: process_msg/7
%% Returns: RePdu
%%-----------------------------------------------------------------
-process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName) ->
+process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName,
+ GbMaxVBs) ->
#pdu{request_id = ReqId} = Pdu,
put(snmp_address, {tuple_to_list(Ip), Udp}),
put(snmp_request_id, ReqId),
put(snmp_community, Community),
put(snmp_context, ContextName),
?vtrace("process ~p",[Pdu#pdu.type]),
- process_pdu(Pdu, PduMS, Vsn, MibView).
+ process_pdu(Pdu, PduMS, Vsn, MibView, GbMaxVBs).
process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
- _PduMS, Vsn, MibView) ->
+ _PduMS, Vsn, MibView, _GbMaxVBs) ->
?vtrace("get ~p",[ReqId]),
Res = get_err(do_get(MibView, Vbs, false)),
?vtrace("get result: "
@@ -2322,12 +2520,12 @@ process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
- _PduMS, Vsn, MibView) ->
+ _PduMS, Vsn, MibView, _GbMaxVBs) ->
?vtrace("process get-next-request -> entry with"
"~n ReqId: ~p"
"~n Vbs: ~p"
"~n MibView: ~p",[ReqId, Vbs, MibView]),
- Res = get_err(do_get_next(MibView, Vbs)),
+ Res = get_err(do_get_next(MibView, Vbs, infinity)),
?vtrace("get-next result: "
"~n ~p",[Res]),
{ErrStatus, ErrIndex, ResVarbinds} =
@@ -2344,11 +2542,15 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
"~n ~p",[ResponseVarbinds]),
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
-process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs,
- error_status = NonRepeaters, error_index = MaxRepetitions},
- PduMS, _Vsn, MibView)->
+process_pdu(#pdu{type = 'get-bulk-request',
+ request_id = ReqId,
+ varbinds = Vbs,
+ error_status = NonRepeaters,
+ error_index = MaxRepetitions},
+ PduMS, _Vsn, MibView, GbMaxVBs) ->
{ErrStatus, ErrIndex, ResponseVarbinds} =
- get_err(do_get_bulk(MibView,NonRepeaters,MaxRepetitions,PduMS,Vbs)),
+ get_err(do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs,
+ GbMaxVBs)),
?vtrace("get-bulk final result: "
"~n Error status: ~p"
"~n Error index: ~p"
@@ -2357,7 +2559,7 @@ process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs,
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs},
- _PduMS, Vsn, MibView)->
+ _PduMS, Vsn, MibView, _GbMaxVbs)->
Res = do_set(MibView, Vbs),
?vtrace("set result: "
"~n ~p",[Res]),
@@ -2414,7 +2616,8 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res)
{noSuchName, Vb#varbind.org_index};
validate_next_v1_2([Vb | Vbs], MibView, Res)
when Vb#varbind.variabletype =:= 'Counter64' ->
- case validate_next_v1(do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of
+ case validate_next_v1(
+ do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of
{noError, 0, [NVb]} ->
validate_next_v1_2(Vbs, MibView, [NVb | Res]);
{Error, Index, _OrgVb} ->
@@ -2887,59 +3090,97 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
%% that this really matters, since many nexts across the same
%% subagent must be considered to be very rare.
%%-----------------------------------------------------------------
-do_get_next(MibView, UnsortedVarbinds) ->
- SortedVarbinds = oid_sort_varbindlist(UnsortedVarbinds),
- next_loop_varbinds([], SortedVarbinds, MibView, [], []).
-oid_sort_varbindlist(Vbs) ->
+%% It may be a bit agressive to check this already,
+%% but since it is a security measure, it makes sense.
+do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+do_get_next(MibView, UnsortedVBs, GbMaxVBs) ->
+ ?vt("do_get_next -> entry when"
+ "~n MibView: ~p"
+ "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
+ SortedVBs = oid_sort_vbs(UnsortedVBs),
+ ?vt("do_get_next -> "
+ "~n SortedVBs: ~p", [SortedVBs]),
+ next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
+
+oid_sort_vbs(Vbs) ->
lists:keysort(#varbind.oid, Vbs).
+next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso
+ ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+
%% LAVb is Last Accessible Vb
-next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb) ->
+next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds -> entry when"
"~n Vb: ~p"
"~n MibView: ~p", [Vb, MibView]),
case varbind_next(Vb, MibView) of
endOfMibView ->
+ ?vt("next_loop_varbind -> endOfMibView", []),
RVb = if LAVb =:= [] -> Vb;
true -> LAVb
end,
NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []);
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
+
{variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
(ME#me.access =/= 'write-only') andalso
(ME#me.access =/= 'accessible-for-notify')) ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n ME: ~p"
+ "~n VarOid: ~p", [ME, VarOid]),
case try_get_instance(Vb, ME) of
{value, noValue, _NoSuchSomething} ->
+ ?vt("next_loop_varbind -> noValue", []),
%% Try next one
- NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, []);
+ NewVb = Vb#varbind{oid = VarOid,
+ value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
+ GbMaxVBs);
{value, Type, Value} ->
- NewVb = Vb#varbind{oid = VarOid, variabletype = Type,
- value = Value},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []);
+ ?vt("next_loop_varbind -> value"
+ "~n Type: ~p"
+ "~n Value: ~p", [Type, Value]),
+ NewVb = Vb#varbind{oid = VarOid,
+ variabletype = Type,
+ value = Value},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
+ GbMaxVBs);
{error, ErrorStatus} ->
?vdebug("next loop varbinds:"
"~n ErrorStatus: ~p",[ErrorStatus]),
{ErrorStatus, Vb#varbind.org_index, []}
end;
{variable, _ME, VarOid} ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n VarOid: ~p", [VarOid]),
RVb = if LAVb =:= [] -> Vb;
true -> LAVb
end,
NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb);
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
{table, TableOid, TableRestOid, ME} ->
+ ?vt("next_loop_varbind -> table: "
+ "~n TableOid: ~p"
+ "~n TableRestOid: ~p"
+ "~n ME: ~p", [TableOid, TableRestOid, ME]),
next_loop_varbinds({table, TableOid, ME,
[{tab_oid(TableRestOid), Vb}]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
{subagent, SubAgentPid, SAOid} ->
+ ?vt("next_loop_varbind -> subagent: "
+ "~n SubAgentPid: ~p"
+ "~n SAOid: ~p", [SubAgentPid, SAOid]),
NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
- Vbs, MibView, Res, [])
+ Vbs, MibView, Res, [], GbMaxVBs)
end;
next_loop_varbinds({table, TableOid, ME, TabOids},
- [Vb | Vbs], MibView, Res, _LAVb) ->
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(table) -> entry with"
"~n TableOid: ~p"
"~n Vb: ~p", [TableOid, Vb]),
@@ -2947,13 +3188,14 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
{table, TableOid, TableRestOid, _ME} ->
next_loop_varbinds({table, TableOid, ME,
[{tab_oid(TableRestOid), Vb} | TabOids]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
_ ->
case get_next_table(ME, TableOid, TabOids, MibView) of
{ok, TabRes, TabEndOfTabVbs} ->
NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{ErrorStatus, OrgIndex} ->
?vdebug("next loop varbinds: next varbind"
"~n ErrorStatus: ~p"
@@ -2963,7 +3205,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
end
end;
next_loop_varbinds({table, TableOid, ME, TabOids},
- [], MibView, Res, _LAVb) ->
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(table) -> entry with"
"~n TableOid: ~p", [TableOid]),
case get_next_table(ME, TableOid, TabOids, MibView) of
@@ -2972,7 +3214,8 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
"~n TabRes: ~p"
"~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, []);
+ next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
+ GbMaxVBs);
{ErrorStatus, OrgIndex} ->
?vdebug("next loop varbinds: next table"
"~n ErrorStatus: ~p"
@@ -2981,7 +3224,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids},
{ErrorStatus, OrgIndex, []}
end;
next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [Vb | Vbs], MibView, Res, _LAVb) ->
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(subagent) -> entry with"
"~n SAPid: ~p"
"~n SAOid: ~p"
@@ -2990,13 +3233,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
{subagent, _SubAgentPid, SAOid} ->
next_loop_varbinds({subagent, SAPid, SAOid,
[Vb | SAVbs]},
- Vbs, MibView, Res, []);
+ Vbs, MibView, Res, [], GbMaxVBs);
_ ->
case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
{ok, SARes, SAEndOfMibViewVbs} ->
NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{noSuchName, OrgIndex} ->
%% v1 reply, treat this Vb as endOfMibView, and try again
%% for the others.
@@ -3009,12 +3253,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
case lists:delete(EVb, SAVbs) of
[] ->
next_loop_varbinds([], [EndOfVb, Vb | Vbs],
- MibView, Res, []);
+ MibView, Res, [],
+ GbMaxVBs);
TryAgainVbs ->
next_loop_varbinds({subagent, SAPid, SAOid,
TryAgainVbs},
[EndOfVb, Vb | Vbs],
- MibView, Res, [])
+ MibView, Res, [],
+ GbMaxVBs)
end;
false ->
%% bad index from subagent
@@ -3030,14 +3276,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
end
end;
next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [], MibView, Res, _LAVb) ->
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
?vt("next_loop_varbinds(subagent) -> entry with"
"~n SAPid: ~p"
"~n SAOid: ~p", [SAPid, SAOid]),
case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
{ok, SARes, SAEndOfMibViewVbs} ->
NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, []);
+ next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
+ GbMaxVBs);
{noSuchName, OrgIndex} ->
%% v1 reply, treat this Vb as endOfMibView, and try again for
%% the others.
@@ -3048,11 +3295,13 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
value = {endOfMibView, NextOid}},
case lists:delete(EVb, SAVbs) of
[] ->
- next_loop_varbinds([], [EndOfVb], MibView, Res, []);
+ next_loop_varbinds([], [EndOfVb], MibView, Res, [],
+ GbMaxVBs);
TryAgainVbs ->
next_loop_varbinds({subagent, SAPid, SAOid,
TryAgainVbs},
- [EndOfVb], MibView, Res, [])
+ [EndOfVb], MibView, Res, [],
+ GbMaxVBs)
end;
false ->
%% bad index from subagent
@@ -3065,12 +3314,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
[ErrorStatus,OrgIndex]),
{ErrorStatus, OrgIndex, []}
end;
-next_loop_varbinds([], [], _MibView, Res, _LAVb) ->
+next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
?vt("next_loop_varbinds -> entry when done", []),
{noError, 0, Res}.
try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
- ?vtrace("try get instance from <~p,~p,~p>",[M,F,A]),
+ ?vtrace("try_get_instance -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [M,F,A]),
Result = (catch dbg_apply(M, F, [get | A])),
% mib shall return {value, <a-nice-value-within-range>} |
% {noValue, noSuchName} (v1) |
@@ -3081,6 +3333,7 @@ try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
tab_oid([]) -> [0];
tab_oid(X) -> X.
+
%%-----------------------------------------------------------------
%% Perform a next, using the varbinds Oid if value is simple
%% value. If value is {endOf<something>, NextOid}, use NextOid.
@@ -3327,22 +3580,30 @@ next_oid(Oid) ->
%%%-----------------------------------------------------------------
%%% 5. GET-BULK REQUEST
+%%%
+%%% In order to prevent excesses in reply sizes there are two
+%%% preventive methods in place. One is to check that the encode
+%%% size does not exceed Max PDU size (this is mentioned in the
+%%% standard). The other is a simple VBs limit. That is, the
+%%% resulting response cannot contain more then this number of VBs.
%%%-----------------------------------------------------------------
-do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
- ?vtrace("do get bulk: start with"
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) ->
+ ?vtrace("do_get_bulk -> entry with"
"~n MibView: ~p"
"~n NonRepeaters: ~p"
"~n MaxRepetitions: ~p"
"~n PduMS: ~p"
- "~n Varbinds: ~p",
- [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds]),
+ "~n Varbinds: ~p"
+ "~n GbMaxVBs: ~p",
+ [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
{NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []),
- ?vt("do get bulk -> split: "
+ ?vt("do_get_bulk -> split: "
"~n NonRepVbs: ~p"
"~n RestVbs: ~p", [NonRepVbs, RestVbs]),
- case do_get_next(MibView, NonRepVbs) of
- {noError, 0, UResNonRepVbs} ->
- ?vt("do get bulk -> next: "
+ case do_get_next(MibView, NonRepVbs, GbMaxVBs) of
+ {noError, 0, UResNonRepVbs} ->
+ ?vt("do_get_bulk -> next noError: "
"~n UResNonRepVbs: ~p", [UResNonRepVbs]),
ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
%% Decode the first varbinds, produce a reversed list of
@@ -3352,11 +3613,12 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
{genErr, Idx, []};
{SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
- ?vtrace("do get bulk -> encoded: "
+ ?vtrace("do_get_bulk -> encoded: "
"~n SizeLeft: ~p"
"~n Res: ~w", [SizeLeft, Res]),
case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
- RestVbs, Res)) of
+ RestVbs, Res,
+ length(UResNonRepVbs), GbMaxVBs)) of
{error, Idx, Reason} ->
user_err("failed encoding varbind ~w:~n~p",
[Idx, Reason]),
@@ -3365,6 +3627,10 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
?vtrace("do get bulk -> Res: "
"~n ~w", [Res]),
{noError, 0, conv_res(Res)};
+ {noError, 0, Data} = OK ->
+ ?vtrace("do get bulk -> OK: "
+ "~n length(Data): ~w", [length(Data)]),
+ OK;
Else ->
?vtrace("do get bulk -> Else: "
"~n ~w", [Else]),
@@ -3373,6 +3639,7 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
Res when is_list(Res) ->
{noError, 0, conv_res(Res)}
end;
+
{ErrorStatus, Index, _} ->
?vdebug("do get bulk: "
"~n ErrorStatus: ~p"
@@ -3422,11 +3689,12 @@ enc_vbs(SizeLeft, Vbs) ->
end,
lists:foldl(Fun, {SizeLeft, []}, Vbs).
-do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res)
+do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
when MaxRepetitions >= 0 ->
- do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res);
-do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res) ->
- do_get_rep(Sz, MibView, 0, 0, Varbinds, Res).
+ do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
+ GbNumVBs, GbMaxVBs);
+do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
conv_res(ResVarbinds) ->
conv_res(ResVarbinds, []).
@@ -3435,22 +3703,30 @@ conv_res([VbListOfBytes | T], Bytes) ->
conv_res([], Bytes) ->
Bytes.
-do_get_rep(_Sz, _MibView, Max, Max, _, Res) ->
+%% The only other value, then a positive integer, is infinity.
+do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
+ ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
+ "~n Count: ~p"
+ "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
+ {tooBig, 0, []};
+do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
?vt("do_get_rep -> done when: "
"~n Res: ~p", [Res]),
{noError, 0, conv_res(Res)};
-do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) ->
+do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
?vt("do_get_rep -> entry when: "
"~n Sz: ~p"
"~n Count: ~p"
"~n Res: ~w", [Sz, Count, Res]),
- case try_get_bulk(Sz, MibView, Varbinds) of
+ case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
{noError, NextVarbinds, SizeLeft, Res2} ->
?vt("do_get_rep -> noError: "
"~n SizeLeft: ~p"
"~n Res2: ~p", [SizeLeft, Res2]),
do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
- Res2 ++ Res);
+ Res2 ++ Res,
+ GbNumVBs + length(Varbinds), GbMaxVBs);
{endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
?vt("do_get_rep -> endOfMibView: "
"~n Res2: ~p", [Res2]),
@@ -3462,22 +3738,29 @@ do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) ->
{ErrorStatus, Index, []}
end.
-try_get_bulk(Sz, MibView, Varbinds) ->
+org_index_sort_vbs(Vbs) ->
+ lists:keysort(#varbind.org_index, Vbs).
+
+try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
?vt("try_get_bulk -> entry with"
- "~n Sz: ~w", [Sz]),
- case do_get_next(MibView, Varbinds) of
+ "~n Sz: ~w"
+ "~n MibView: ~w"
+ "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
+ case do_get_next(MibView, Varbinds, GbMaxVBs) of
{noError, 0, UNextVarbinds} ->
- ?vt("try_get_bulk -> noError", []),
- NextVarbinds = lists:keysort(#varbind.org_index, UNextVarbinds),
+ ?vt("try_get_bulk -> noError: "
+ "~n UNextVarbinds: ~p", [UNextVarbinds]),
+ NextVarbinds = org_index_sort_vbs(UNextVarbinds),
case (catch enc_vbs(Sz, NextVarbinds)) of
{error, Idx, Reason} ->
user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- ?vtrace("try_get_bulk -> error: "
+ ?vtrace("try_get_bulk -> encode error: "
"~n Idx: ~p"
"~n Reason: ~p", [Idx, Reason]),
{genErr, Idx};
- {SizeLeft, Res} when is_integer(SizeLeft) andalso is_list(Res) ->
- ?vt("try get bulk -> "
+ {SizeLeft, Res} when is_integer(SizeLeft) andalso
+ is_list(Res) ->
+ ?vt("try get bulk -> encode ok: "
"~n SizeLeft: ~w"
"~n Res: ~w", [SizeLeft, Res]),
{check_end_of_mibview(NextVarbinds),
@@ -3488,9 +3771,9 @@ try_get_bulk(Sz, MibView, Varbinds) ->
{endOfMibView, [], 0, Res}
end;
{ErrorStatus, Index, _} ->
- ?vt("try get bulk: "
+ ?vt("try_get_bulk -> error: "
"~n ErrorStatus: ~p"
- "~n Index: ~p",[ErrorStatus, Index]),
+ "~n Index: ~p", [ErrorStatus, Index]),
{ErrorStatus, Index}
end.
@@ -3631,9 +3914,8 @@ get_err({ErrC, ErrI, Vbs}) ->
{get_err_i(ErrC), ErrI, Vbs}.
get_err_i(noError) -> noError;
-get_err_i(S) ->
- ?vtrace("convert '~p' to 'genErr'",[S]),
- genErr.
+get_err_i(tooBig) -> tooBig; % OTP-9700
+get_err_i(ES) -> ?vtrace("convert ErrorStatus '~p' to 'genErr'", [ES]), genErr.
v2err_to_v1err(noError) -> noError;
v2err_to_v1err(noAccess) -> noSuchName;
@@ -3859,6 +4141,7 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) ->
{Accu2,[R|Rs]};
mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}.
+
%%-----------------------------------------------------------------
%% Runtime debugging of the agent.
%%-----------------------------------------------------------------
@@ -3983,7 +4266,7 @@ handle_set_request_limit(_, _) ->
{error, not_supported}.
-agent_info(#state{worker = W, set_worker = SW}) ->
+agent_info(#state{worker = W, set_worker = SW}) ->
case (catch get_agent_info(W, SW)) of
Info when is_list(Info) ->
Info;
@@ -4142,6 +4425,9 @@ get_multi_threaded(Opts) ->
get_versions(Opts) ->
get_option(versions, Opts, [v1,v2,v3]).
+get_gb_max_vbs(Opts) ->
+ get_option(gb_max_vbs, Opts, infinity).
+
get_note_store_opt(Opts) ->
get_option(note_store, Opts, []).
diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl
index 20a36cc118..c435b519d9 100644
--- a/lib/snmp/src/agent/snmpa_internal.hrl
+++ b/lib/snmp/src/agent/snmpa_internal.hrl
@@ -26,6 +26,15 @@
-define(DEFAULT_LOCAL_ENGINE_ID, snmp_framework_mib:get_engine_id()).
-define(DEFAULT_NOTIF_EXTRA_INFO, {snmpa_default_notification_extra_info}).
+%% -- Max number of VBs in a Get-BULK response --
+%% (( The default value, 1000, is *way* more ))
+%% (( then there is room for in a normal pdu ))
+%% (( (unless the max pdu size has been ))
+%% (( cranked way up), so this value should ))
+%% (( suffice as "infinity" without actually ))
+%% (( causing memory issues for the VM ... ))
+-define(DEFAULT_GB_MAX_VBS, 1000).
+
-define(snmpa_info(F, A), ?snmp_info("agent", F, A)).
-define(snmpa_warning(F, A), ?snmp_warning("agent", F, A)).
-define(snmpa_error(F, A), ?snmp_error("agent", F, A)).
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index 5b04c70054..1ec8dd3874 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -486,7 +486,11 @@ handle_call({match, Name, Db, Pattern}, _From, State) ->
L1 = match(Db, Name, Pattern, State),
{reply, lists:delete([undef], L1), State};
-handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) ->
+%% This check (that there is no backup already in progress) is also
+%% done in the master agent process, but just in case a user issues
+%% a backup call to this process directly, we add a similar check here.
+handle_call({backup, BackupDir}, From,
+ #state{backup = undefined, dets = Dets} = State) ->
?vlog("backup: ~p",[BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -511,6 +515,10 @@ handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) ->
{reply, Error, State}
end;
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(dump, _From, #state{dets = Dets} = State) ->
?vlog("dump",[]),
dets_sync(Dets),
diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl
index ce90db18b3..574467d38f 100644
--- a/lib/snmp/src/agent/snmpa_mib.erl
+++ b/lib/snmp/src/agent/snmpa_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. 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
@@ -552,8 +552,12 @@ handle_call({dump, File}, _From, #state{data = Data} = State) ->
Reply = snmpa_mib_data:dump(Data, File),
{reply, Reply, State};
-handle_call({backup, BackupDir}, From, #state{data = Data} = State) ->
- ?vlog("backup to ~s",[BackupDir]),
+%% This check (that there is no backup already in progress) is also
+%% done in the master agent process, but just in case a user issues
+%% a backup call to this process directly, we add a similar check here.
+handle_call({backup, BackupDir}, From,
+ #state{backup = undefined, data = Data} = State) ->
+ ?vlog("backup to ~s", [BackupDir]),
Pid = self(),
V = get(verbosity),
case file:read_file_info(BackupDir) of
@@ -576,6 +580,10 @@ handle_call({backup, BackupDir}, From, #state{data = Data} = State) ->
{reply, Error, State}
end;
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(stop, _From, State) ->
?vlog("stop",[]),
{stop, normal, ok, State};
diff --git a/lib/snmp/src/agent/snmpa_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl
index 078e681945..3c94cc8095 100644
--- a/lib/snmp/src/agent/snmpa_mib_lib.erl
+++ b/lib/snmp/src/agent/snmpa_mib_lib.erl
@@ -61,23 +61,23 @@ table_del_row({Tab, Db} = TabDb, Key) ->
get_table(NameDb, FOI) ->
(catch get_table(NameDb, FOI, [], [])).
-get_table(NameDb, FOI, Oid, Acc) ->
- case table_next(NameDb, Oid) of
+get_table(NameDb, FOI, Key, Acc) ->
+ case table_next(NameDb, Key) of
endOfTable ->
?vdebug("end of table",[]),
{ok, lists:reverse(Acc)};
- Oid ->
+ Key ->
%% Crap, circular ref
- ?vinfo("cyclic reference: ~w -> ~w", [Oid,Oid]),
- throw({error, {cyclic_db_reference, Oid, Acc}});
- NextOid ->
- ?vtrace("get row for oid ~w", [NextOid]),
- case table_get_row(NameDb, NextOid, FOI) of
+ ?vinfo("cyclic reference: ~w -> ~w", [Key, Key]),
+ throw({error, {cyclic_db_reference, Key, Acc}});
+ NextKey ->
+ ?vtrace("get row for key ~w", [NextKey]),
+ case table_get_row(NameDb, NextKey, FOI) of
undefined ->
- throw({error, {invalid_rowindex, NextOid, Acc}});
+ throw({error, {invalid_rowindex, NextKey, Acc}});
Row ->
?vtrace("row: ~w", [Row]),
- get_table(NameDb, FOI, NextOid, [{NextOid, Row}|Acc])
+ get_table(NameDb, FOI, NextKey, [{NextKey, Row}|Acc])
end
end.
diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl
index 0305e1fbec..2d37ea56f0 100644
--- a/lib/snmp/src/agent/snmpa_mpd.erl
+++ b/lib/snmp/src/agent/snmpa_mpd.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
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index 5ef5914e18..7a9c214e0d 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -176,8 +176,8 @@ init([AgentType, Opts]) ->
"~n AgentType: ~p"
"~n Opts: ~p", [AgentType, Opts]),
- put(sname, asup),
- put(verbosity,get_verbosity(Opts)),
+ put(sname, asup),
+ put(verbosity, get_verbosity(Opts)),
?vlog("starting",[]),
@@ -203,7 +203,12 @@ init([AgentType, Opts]) ->
Vsns = get_opt(versions, Opts, [v1,v2,v3]),
?vdebug("[agent table] store versions: ~p",[Vsns]),
ets:insert(snmp_agent_table, {versions, Vsns}),
-
+
+ %% -- Max number of VBs in a Get-BULK response --
+ GbMaxVBs = get_gb_max_vbs(Opts),
+ ?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]),
+ ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}),
+
%% -- DB-directory --
DbDir = get_opt(db_dir, Opts),
?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]),
@@ -377,7 +382,8 @@ init([AgentType, Opts]) ->
{versions, Vsns},
{net_if, NiOpts},
{mib_server, MibsOpts},
- {note_store, NsOpts}|
+ {note_store, NsOpts},
+ {gb_max_vbs, GbMaxVBs} |
get_opt(master_agent_options, Opts, [])],
AgentSpec =
@@ -542,6 +548,32 @@ get_verbosity(Opts) ->
get_agent_type(Opts) ->
get_opt(agent_type, Opts, master).
+
+%% We validate this option! This should really be done for all
+%% options, but it is beyond the scope of this ticket, OTP-9700.
+
+get_gb_max_vbs(Opts) ->
+ Validate =
+ fun(GbMaxVBs)
+ when ((is_integer(GbMaxVBs) andalso (GbMaxVBs > 0)) orelse
+ (GbMaxVBs =:= infinity)) ->
+ ok;
+ (_) ->
+ error
+ end,
+ get_option(gb_max_vbs, ?DEFAULT_GB_MAX_VBS, Validate, Opts).
+
+get_option(Key, Default, Validate, Opts)
+ when is_list(Opts) andalso is_function(Validate) ->
+ Value = get_opt(Key, Opts, Default),
+ case Validate(Value) of
+ ok ->
+ Value;
+ error ->
+ exit({bad_option, Key, Value})
+ end.
+
+
get_opt(Key, Opts) ->
snmp_misc:get_option(Key, Opts).
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index 5b579efc13..994d926224 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -352,11 +352,26 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, ExtraInfo, NetIf) ->
send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, NetIf).
+%% The agent normally does not care about the result,
+%% but since it can be usefull when debugging, add
+%% some info when we fail to send the trap(s).
send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
ExtraInfo, NetIf) ->
- (catch do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
- LocalEngineID, ExtraInfo, NetIf)).
-
+ try
+ begin
+ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
+ LocalEngineID, ExtraInfo, NetIf)
+ end
+ catch
+ T:E ->
+ Info = [{args, [TrapRec, NotifyName, ContextName,
+ Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]},
+ {tag, T},
+ {err, E},
+ {stacktrace, erlang:get_stacktrace()}],
+ {error, {failed_sending_trap, Info}}
+ end.
+
do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs,
LocalEngineID, ExtraInfo, NetIf) ->
VarbindList = make_varbind_list(Vbs),
diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl
index 892dc265f1..dadcf32543 100644
--- a/lib/snmp/src/agent/snmpa_vacm.erl
+++ b/lib/snmp/src/agent/snmpa_vacm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -62,6 +62,13 @@ get_mib_view(ViewType, SecModel, SecName, SecLevel, ContextName) ->
%% Follows the procedure in rfc2275
auth(ViewType, SecModel, SecName, SecLevel, ContextName) ->
+ ?vtrace("auth -> entry with"
+ "~n ViewType: ~p"
+ "~n SecModel: ~p"
+ "~n SecName: ~p"
+ "~n SecLevel: ~p"
+ "~n ContextName: ~p",
+ [ViewType, SecModel, SecName, SecLevel, ContextName]),
% 3.2.1 - Check that the context is known to us
?vdebug("check that the context (~p) is known to us",[ContextName]),
case snmp_view_based_acm_mib:vacmContextTable(get, ContextName,
@@ -74,7 +81,7 @@ auth(ViewType, SecModel, SecName, SecLevel, ContextName) ->
end,
% 3.2.2 - Check that the SecModel and SecName is valid
?vdebug("check that SecModel (~p) and SecName (~p) is valid",
- [SecModel,SecName]),
+ [SecModel, SecName]),
GroupName =
case snmp_view_based_acm_mib:get(vacmSecurityToGroupTable,
[SecModel, length(SecName) | SecName],
@@ -111,6 +118,8 @@ check_auth(Res) -> {ok, Res}.
%% key in the table >= ViewIndex.
%%-----------------------------------------------------------------
get_mib_view(ViewName) ->
+ ?vtrace("get_mib_view -> entry with"
+ "~n ViewName: ~p", [ViewName]),
ViewKey = [length(ViewName) | ViewName],
case snmp_view_based_acm_mib:table_next(vacmViewTreeFamilyTable,
ViewKey) of
@@ -202,6 +211,13 @@ backup(BackupDir) ->
%% Ret: {ok, ViewName} | {error, Reason}
get_view_name(ViewType, GroupName, ContextName, SecModel, SecLevel) ->
+ ?vtrace("get_view_name -> entry with"
+ "~n ViewType: ~p"
+ "~n GroupName: ~p"
+ "~n ContextName: ~p"
+ "~n SecModel: ~p"
+ "~n SecLevel: ~p",
+ [ViewType, GroupName, ContextName, SecModel, SecLevel]),
GroupKey = [length(GroupName) | GroupName],
case get_access_row(GroupKey, ContextName, SecModel, SecLevel) of
undefined ->
@@ -266,9 +282,10 @@ dump_table(true) ->
dump_table(_) ->
ok.
+
dump_table() ->
[{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file),
- TmpName = FName ++ ".tmp",
+ TmpName = unique_table_name(FName),
case ets:tab2file(snmpa_vacm, TmpName) of
ok ->
case file:rename(TmpName, FName) of
@@ -283,6 +300,35 @@ dump_table() ->
[FName, Reason])
end.
+%% This little thing is an attempt to create a "unique" filename
+%% in order to minimize the risk of two processes at the same
+%% time dumping the table.
+unique_table_name(Pre) ->
+ %% We want something that is guaranteed to be unique,
+ %% therefor we use erlang:now() instead of os:timestamp()
+ unique_table_name(Pre, erlang:now()).
+
+unique_table_name(Pre, {_A, _B, C} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY, MM, DD} = Date,
+ {Hour, Min, Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w~.2.0w~.2.0w_~.2.0w~.2.0w~.2.0w_~w",
+ [YYYY, MM, DD, Hour, Min, Sec, round(C/1000)]),
+ unique_table_name2(Pre, FormatDate).
+
+unique_table_name2(Pre, FormatedDate) ->
+ PidPart = unique_table_name_pid(),
+ lists:flatten(io_lib:format("~s.~s~s.tmp", [Pre, PidPart, FormatedDate])).
+
+unique_table_name_pid() ->
+ case string:tokens(pid_to_list(self()), [$<,$.,$>]) of
+ [A, B, C] ->
+ A ++ B ++ C ++ ".";
+ _ ->
+ ""
+ end.
+
%%-----------------------------------------------------------------
%% Alg.
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 219ac62a73..c8e5eec6db 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -22,46 +22,124 @@
%% ----- U p g r a d e -------------------------------------------------------
[
+ {"4.21.6",
+ [
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"4.21.5",
+ [
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"4.21.4",
+ [
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21.3",
[
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.2",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.1",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []}
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
{"4.21",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []}
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
{"4.20.1",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
{load_module, snmpm, soft_purge, soft_purge,
[snmpm_server, snmpm_config, snmp_config]},
@@ -73,21 +151,29 @@
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
+ {update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
+ {update, snmpm_net_if, soft, soft_purge, soft_purge,
[snmp_conf, snmpm_mpd, snmpm_config]}
]
},
{"4.20",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
+ {load_module, snmp_target_mib, soft_purge, soft_purge,
+ [snmpa_mib_lib, snmp_conf]},
{load_module, snmpm, soft_purge, soft_purge,
[snmpm_server, snmpm_config, snmp_config]},
{load_module, snmp_conf, soft_purge, soft_purge, []},
@@ -98,101 +184,137 @@
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
+ {update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
+ {update, snmpm_net_if, soft, soft_purge, soft_purge,
[snmp_conf, snmpm_mpd, snmpm_config]}
]
- },
- {"4.19",
- [
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmpa_usm, soft_purge, soft_purge, []},
- {load_module, snmpm_usm, soft_purge, soft_purge, []},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmp_misc, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_trap, soft_purge, soft_purge,
- [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]},
- {load_module, snmpa_acm, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd, snmp_target_mib]},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_config, snmp_notification_mib]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_notification_mib, soft_purge, soft_purge,
- [snmp_conf, snmp_target_mib]},
- {load_module, snmp_community_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd]},
- {update, snmpa_agent, soft, soft_purge, soft_purge,
- [snmpa_acm, snmpa_mpd, snmpa_trap]}
- ]
}
],
%% ------D o w n g r a d e ---------------------------------------------------
[
+ {"4.21.6",
+ [
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"4.21.5",
+ [
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"4.21.4",
+ [
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21.3",
[
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []}
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.2",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.1",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
{update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
{"4.21",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_mpd, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_target_mib, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
{update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
{"4.20.1",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_target_mib, soft_purge, soft_purge, []},
@@ -207,8 +329,10 @@
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
@@ -218,6 +342,11 @@
},
{"4.20",
[
+ {load_module, snmpa, soft_purge, soft_purge, []},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
+
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
@@ -232,58 +361,16 @@
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
{update, snmpm_net_if, soft, soft_purge, soft_purge,
[snmp_conf, snmpm_mpd, snmpm_config]}
]
- },
- {"4.19",
- [
- {load_module, snmpa_set_lib, soft_purge, soft_purge, []},
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmpa_usm, soft_purge, soft_purge, []},
- {load_module, snmpm_usm, soft_purge, soft_purge, []},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmp_misc, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_trap, soft_purge, soft_purge,
- [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]},
- {load_module, snmpa_acm, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd, snmp_target_mib]},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_config, snmp_notification_mib]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_notification_mib, soft_purge, soft_purge,
- [snmp_conf, snmp_target_mib]},
- {load_module, snmp_community_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {update, snmp_note_store, soft, soft_purge, soft_purge, []},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd]},
- {update, snmpa_agent, soft, soft_purge, soft_purge,
- [snmpa_acm, snmpa_mpd, snmpa_trap]}
- ]
}
]
}.
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index c95346b5a6..e968bc65b1 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.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
@@ -222,7 +222,7 @@ groups() ->
{group, otp_7157}
]
},
- {tickets2, [], [otp8395]},
+ {tickets2, [], [otp8395, otp9884]},
{otp_4394, [], [otp_4394_test]},
{otp_7157, [], [otp_7157_test]
}
@@ -322,6 +322,12 @@ init_per_testcase(otp8395 = Case, Config) when is_list(Config) ->
"~n Config: ~p", [Case, Config]),
Config2 = init_per_testcase2(Case, init_per_suite(Config)),
otp8395({init, Config2});
+init_per_testcase(otp9884 = Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase -> entry with"
+ "~n Case: ~p"
+ "~n Config: ~p", [Case, Config]),
+ Config2 = init_per_testcase2(Case, init_per_suite(Config)),
+ otp9884({init, Config2});
init_per_testcase(otp_7157_test = _Case, Config) when is_list(Config) ->
?DBG("init_per_testcase -> entry with"
"~n Case: ~p"
@@ -349,6 +355,8 @@ init_per_testcase(_Case, Config) when is_list(Config) ->
end_per_testcase(otp8395, Config) when is_list(Config) ->
otp8395({fin, Config});
+end_per_testcase(otp9884, Config) when is_list(Config) ->
+ otp9884({fin, Config});
end_per_testcase(_Case, Config) when is_list(Config) ->
?DBG("end_per_testcase -> entry with"
"~n Case: ~p"
@@ -1321,8 +1329,11 @@ finish_v3(Config) when is_list(Config) ->
lists:keydelete(vsn, 1, C1).
-mt_cases() ->
- [multi_threaded, mt_trap].
+mt_cases() ->
+ [
+ multi_threaded,
+ mt_trap
+ ].
init_mt(Config) when is_list(Config) ->
SaNode = ?config(snmp_sa, Config),
@@ -5235,16 +5246,6 @@ loop_it_2(Oid, N) ->
%%%-----------------------------------------------------------------
-
-
-
-%% These are (ticket) test cases where the initiation has to be done
-%% individually.
-
-
-
-
-
%%-----------------------------------------------------------------
%% Ticket: OTP-1128
%% Slogan: Bug in handling of createAndWait set-requests.
@@ -5885,7 +5886,7 @@ otp_7157_test1(MA) ->
otp8395({init, Config}) when is_list(Config) ->
?DBG("otp8395(init) -> entry with"
"~n Config: ~p", [Config]),
-
+
%% --
%% Start nodes
%%
@@ -5893,7 +5894,7 @@ otp8395({init, Config}) when is_list(Config) ->
{ok, AgentNode} = start_node(agent),
%% {ok, SubAgentNode} = start_node(sub_agent),
{ok, ManagerNode} = start_node(manager),
-
+
%% --
%% Mnesia init
%%
@@ -5901,10 +5902,10 @@ otp8395({init, Config}) when is_list(Config) ->
AgentDbDir = ?config(agent_db_dir, Config),
AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]),
mnesia_init(AgentNode, AgentMnesiaDir),
-
-%% SubAgentDir = ?config(sub_agent_dir, Config),
-%% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]),
-%% mnesia_init(SubAgentNode, SubAgentMnesiaDir),
+
+ %% SubAgentDir = ?config(sub_agent_dir, Config),
+ %% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]),
+ %% mnesia_init(SubAgentNode, SubAgentMnesiaDir),
%% ok = mnesia_create_schema(AgentNode, [AgentNode, SubAgentNode]),
%% ok = mnesia:create_schema([AgentNode, SubAgentNode]),
@@ -5929,12 +5930,12 @@ otp8395({init, Config}) when is_list(Config) ->
%% SubAgentIP = tuple_to_list(SubAgentIP0),
{ok, ManagerIP0} = snmp_misc:ip(ManagerHost),
ManagerIP = tuple_to_list(ManagerIP0),
-
+
%% --
%% Write agent config
%%
-
+
Vsns = [v1],
AgentConfDir = ?config(agent_conf_dir, Config),
ManagerConfDir = ?config(manager_top_dir, Config),
@@ -5958,7 +5959,7 @@ otp8395({init, Config}) when is_list(Config) ->
{manager_node, ManagerNode},
{manager_host, ManagerHost},
{manager_ip, ManagerIP}|Config]),
-
+
%% --
%% Create watchdog
%%
@@ -5970,7 +5971,7 @@ otp8395({init, Config}) when is_list(Config) ->
otp8395({fin, Config}) when is_list(Config) ->
?DBG("otp8395(fin) -> entry with"
"~n Config: ~p", [Config]),
-
+
AgentNode = ?config(agent_node, Config),
ManagerNode = ?config(manager_node, Config),
@@ -5978,11 +5979,11 @@ otp8395({fin, Config}) when is_list(Config) ->
%% Stop agent (this is the nice way to do it,
%% so logs and files can be closed in the proper way).
%%
-
+
AgentSup = ?config(agent_sup, Config),
?DBG("otp8395(fin) -> stop (stand-alone) agent: ~p", [AgentSup]),
stop_stdalone_agent(AgentSup),
-
+
%% -
%% Stop mnesia
%%
@@ -5998,8 +5999,8 @@ otp8395({fin, Config}) when is_list(Config) ->
stop_node(AgentNode),
-%% SubAgentNode = ?config(sub_agent_node, Config),
-%% stop_node(SubAgentNode),
+ %% SubAgentNode = ?config(sub_agent_node, Config),
+ %% stop_node(SubAgentNode),
%% -
@@ -6019,7 +6020,7 @@ otp8395(doc) ->
otp8395(Config) when is_list(Config) ->
?DBG("otp8395 -> entry with"
"~n Config: ~p", [Config]),
-
+
?SLEEP(1000),
%% This is just to dirty trick for the ***old*** test-code
@@ -6037,8 +6038,8 @@ otp8395(Config) when is_list(Config) ->
{ok, LogInfo} = rpc:call(AgentNode, snmpa, log_info, []),
?DBG("otp8395 -> LogInfo: ~p", [LogInfo]),
-%% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]),
-%% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]),
+ %% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]),
+ %% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]),
ok = agent_log_validation(AgentNode),
LTTRes =
@@ -6048,7 +6049,195 @@ otp8395(Config) when is_list(Config) ->
?SLEEP(1000),
?DBG("otp8395 -> done", []),
ok.
-
+
+
+%%-----------------------------------------------------------------
+
+otp9884({init, Config}) when is_list(Config) ->
+ ?DBG("otp9884(init) -> entry with"
+ "~n Config: ~p", [Config]),
+
+ %% --
+ %% Start nodes
+ %%
+
+ {ok, AgentNode} = start_node(agent),
+
+ %% We don't use a manager in this test but the (common) config
+ %% function takes an argument that is derived from this
+ {ok, ManagerNode} = start_node(manager),
+
+ %% --
+ %% Mnesia init
+ %%
+
+ AgentDbDir = ?config(agent_db_dir, Config),
+ AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]),
+ mnesia_init(AgentNode, AgentMnesiaDir),
+
+ mnesia_create_schema(AgentNode, [AgentNode]),
+
+ mnesia_start(AgentNode),
+
+ %% --
+ %% Host & IP
+ %%
+
+ AgentHost = ?HOSTNAME(AgentNode),
+ ManagerHost = ?HOSTNAME(ManagerNode),
+
+ Host = snmp_test_lib:hostname(),
+ Ip = ?LOCALHOST(),
+ {ok, AgentIP0} = snmp_misc:ip(AgentHost),
+ AgentIP = tuple_to_list(AgentIP0),
+ {ok, ManagerIP0} = snmp_misc:ip(ManagerHost),
+ ManagerIP = tuple_to_list(ManagerIP0),
+
+
+ %% --
+ %% Write agent config
+ %%
+
+ Vsns = [v1],
+ ManagerConfDir = ?config(manager_top_dir, Config),
+ AgentConfDir = ?config(agent_conf_dir, Config),
+ AgentTopDir = ?config(agent_top_dir, Config),
+ AgentBkpDir1 = filename:join([AgentTopDir, backup1]),
+ AgentBkpDir2 = filename:join([AgentTopDir, backup2]),
+ ok = file:make_dir(AgentBkpDir1),
+ ok = file:make_dir(AgentBkpDir2),
+ AgentBkpDirs = [AgentBkpDir1, AgentBkpDir2],
+ snmp_agent_test_lib:config(Vsns,
+ ManagerConfDir, AgentConfDir,
+ ManagerIP, AgentIP),
+
+
+ %% --
+ %% Start the agent
+ %%
+
+ Config2 = start_agent([{host, Host},
+ {ip, Ip},
+ {agent_node, AgentNode},
+ {agent_host, AgentHost},
+ {agent_ip, AgentIP},
+ {agent_backup_dirs, AgentBkpDirs}|Config]),
+
+ %% --
+ %% Create watchdog
+ %%
+
+ Dog = ?WD_START(?MINS(1)),
+
+ [{watchdog, Dog} | Config2];
+
+otp9884({fin, Config}) when is_list(Config) ->
+ ?DBG("otp9884(fin) -> entry with"
+ "~n Config: ~p", [Config]),
+
+ AgentNode = ?config(agent_node, Config),
+ ManagerNode = ?config(manager_node, Config),
+
+ %% -
+ %% Stop agent (this is the nice way to do it,
+ %% so logs and files can be closed in the proper way).
+ %%
+
+ AgentSup = ?config(agent_sup, Config),
+ ?DBG("otp9884(fin) -> stop (stand-alone) agent: ~p", [AgentSup]),
+ stop_stdalone_agent(AgentSup),
+
+ %% -
+ %% Stop mnesia
+ %%
+ ?DBG("otp9884(fin) -> stop mnesia", []),
+ mnesia_stop(AgentNode),
+
+
+ %% -
+ %% Stop the agent node
+ %%
+
+ ?DBG("otp9884(fin) -> stop agent node", []),
+ stop_node(AgentNode),
+
+
+ %% SubAgentNode = ?config(sub_agent_node, Config),
+ %% stop_node(SubAgentNode),
+
+
+ %% -
+ %% Stop the manager node
+ %%
+
+ ?DBG("otp9884(fin) -> stop manager node", []),
+ stop_node(ManagerNode),
+
+ Dog = ?config(watchdog, Config),
+ ?WD_STOP(Dog),
+ lists:keydelete(watchdog, 1, Config);
+
+otp9884(doc) ->
+ "OTP-9884 - Simlutaneous backup call should not work. ";
+
+otp9884(Config) when is_list(Config) ->
+ ?DBG("otp9884 -> entry with"
+ "~n Config: ~p", [Config]),
+
+ AgentNode = ?config(agent_node, Config),
+ [AgentBkpDir1, AgentBkpDir2] = ?config(agent_backup_dirs, Config),
+ Self = self(),
+ timer:apply_after(1000,
+ ?MODULE, otp9884_backup, [AgentNode, Self, first, AgentBkpDir1]),
+ timer:apply_after(1000,
+ ?MODULE, otp9884_backup, [AgentNode, Self, second, AgentBkpDir2]),
+ otp9884_await_backup_completion(undefined, undefined),
+
+ ?DBG("otp9884 -> done", []),
+ ok.
+
+
+otp9884_backup(Node, Pid, Tag, Dir) ->
+ io:format("[~w] call backup function~n", [Tag]),
+ Res = rpc:call(Node, snmpa, backup, [Dir]),
+ io:format("[~w] backup result: ~p~n", [Tag, Res]),
+ Pid ! {otp9884_backup_complete, Tag, Res}.
+
+otp9884_await_backup_completion(ok, Second)
+ when ((Second =/= ok) andalso (Second =/= undefined)) ->
+ io:format("otp9884_await_backup_completion -> "
+ "first backup succeed and second failed (~p)~n", [Second]),
+ ok;
+otp9884_await_backup_completion(First, ok)
+ when ((First =/= ok) andalso (First =/= undefined)) ->
+ io:format("otp9884_await_backup_completion -> "
+ "second backup succeed and first failed (~p)~n", [First]),
+ ok;
+otp9884_await_backup_completion(First, Second)
+ when (((First =:= undefined) andalso (Second =:= undefined))
+ orelse
+ ((First =:= undefined) andalso (Second =/= undefined))
+ orelse
+ ((First =/= undefined) andalso (Second =:= undefined))) ->
+ io:format("otp9884_await_backup_completion -> await complete messages~n", []),
+ receive
+ {otp9884_backup_complete, first, Res} ->
+ io:format("otp9884_await_backup_completion -> "
+ "received complete message for first: ~p~n", [Res]),
+ otp9884_await_backup_completion(Res, Second);
+ {otp9884_backup_complete, second, Res} ->
+ io:format("otp9884_await_backup_completion -> "
+ "received complete message for second: ~p~n", [Res]),
+ otp9884_await_backup_completion(First, Res)
+ after 10000 ->
+ %% we have waited long enough
+ throw({error, {timeout, First, Second}})
+ end;
+otp9884_await_backup_completion(First, Second) ->
+ throw({error, {bad_completion, First, Second}}).
+
+
+%%-----------------------------------------------------------------
agent_log_validation(Node) ->
rpc:call(Node, ?MODULE, agent_log_validation, []).
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
index c964b08168..0a147130b0 100644
--- a/lib/snmp/test/snmp_compiler_test.erl
+++ b/lib/snmp/test/snmp_compiler_test.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
@@ -566,14 +566,7 @@ p(F, A) ->
p(TName, F, A) ->
io:format("*** [~w][~s] ***"
- "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]).
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl
index 4498d506f3..3192fe1b40 100644
--- a/lib/snmp/test/snmp_manager_config_test.erl
+++ b/lib/snmp/test/snmp_manager_config_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -2726,14 +2726,7 @@ p(F, A) ->
p(TName, F, A) ->
io:format("*** [~s] ***"
- " ~w -> " ++ F ++ "~n", [format_timestamp(now()),TName|A]).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ " ~w -> " ++ F ++ "~n", [formated_timestamp(),TName|A]).
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index d18f20d359..75c9f7b277 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.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
@@ -6064,7 +6064,7 @@ rcall(Node, Mod, Func, Args) ->
%% Time in milli sec
%% t() ->
-%% {A,B,C} = erlang:now(),
+%% {A,B,C} = os:timestamp(),
%% A*1000000000+B*1000+(C div 1000).
@@ -6078,16 +6078,10 @@ p(F, A) ->
p(TName, F, A) ->
io:format("*** [~w][~s] ***"
- "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]).
+
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
%% p(TName, F, A) ->
%% io:format("~w -> " ++ F ++ "~n", [TName|A]).
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index 54839d989b..e4d58a1253 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. 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
@@ -37,7 +37,7 @@
-export([watchdog/3, watchdog_start/1, watchdog_start/2, watchdog_stop/1]).
-export([del_dir/1]).
-export([cover/1]).
--export([p/2, print/5]).
+-export([p/2, print/5, formated_timestamp/0]).
%% ----------------------------------------------------------------------
@@ -521,15 +521,18 @@ p(F, A) when is_list(F) andalso is_list(A) ->
print(Prefix, Module, Line, Format, Args) ->
io:format("*** [~s] ~s ~p ~p ~p:~p *** " ++ Format ++ "~n",
- [format_timestamp(now()),
+ [formated_timestamp(),
Prefix, node(), self(), Module, Line|Args]).
+formated_timestamp() ->
+ format_timestamp(os:timestamp()).
+
format_timestamp({_N1, _N2, N3} = Now) ->
{Date, Time} = calendar:now_to_datetime(Now),
{YYYY,MM,DD} = Date,
{Hour,Min,Sec} = Time,
FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w ~w",
[YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
lists:flatten(FormatDate).
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index 84bdc6b04f..499cf7abcf 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. 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
@@ -1124,16 +1124,11 @@ d(F,A) -> d(get(debug),F,A).
d(true,F,A) ->
io:format("*** [~s] MGR_DBG *** " ++ F ++ "~n",
- [format_timestamp(now())|A]);
+ [formated_timestamp()|A]);
d(_,_F,_A) ->
ok.
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl
index fc6dedd96d..5525c5c3ec 100644
--- a/lib/snmp/test/snmp_test_mgr_misc.erl
+++ b/lib/snmp/test/snmp_test_mgr_misc.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
@@ -779,16 +779,9 @@ d(F,A) -> d(get(debug),F,A).
d(true,F,A) ->
io:format("*** [~s] MGR_PS_DBG *** " ++ F ++ "~n",
- [format_timestamp(now())|A]);
+ [formated_timestamp()|A]);
d(_,_F,_A) ->
ok.
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
-
+formated_timestamp() ->
+ snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index ee2e633c69..fb1dcb6c41 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -2,7 +2,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
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 4.21.4
-PRE_VSN =
-APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
+SNMP_VSN = 4.21.7
+PRE_VSN =
+APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 2c5096a25f..ed88b3a1af 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2004</year><year>2010</year>
+ <year>2004</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -86,7 +86,7 @@
by calling ssh_connect:session_channel/2.</p>
<p>Options are:</p>
<taglist>
- <tag><c><![CDATA[{user_dir, String}]]></c></tag>
+ <tag><c><![CDATA[{user_dir, string()}]]></c></tag>
<item>
<p>Sets the user directory e.i. the directory containing
ssh configuration files for the user such as
@@ -94,6 +94,18 @@
<c><![CDATA[authorized_key]]></c>. Defaults to the directory normally
referred to as <c><![CDATA[~/.ssh]]></c> </p>
</item>
+ <tag><c><![CDATA[{dsa_pass_phrase, string()}]]></c></tag>
+ <item>
+ <p>If the user dsa key is protected by a pass phrase it can be
+ supplied with this option.
+ </p>
+ </item>
+ <tag><c><![CDATA[{rsa_pass_phrase, string()}]]></c></tag>
+ <item>
+ <p>If the user rsa key is protected by a pass phrase it can be
+ supplied with this option.
+ </p>
+ </item>
<tag><c><![CDATA[{silently_accept_hosts, boolean()}]]></c></tag>
<item>
<p>When true hosts are added to the
@@ -222,6 +234,14 @@
option <c>shell</c> which is much less work than implementing
your own cli channel.
</item>
+ <tag><c><![CDATA[{user_dir, String}]]></c></tag>
+ <item>
+ <p>Sets the user directory e.i. the directory containing
+ ssh configuration files for the user such as
+ <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa, id_dsa]]></c> and
+ <c><![CDATA[authorized_key]]></c>. Defaults to the directory normally
+ referred to as <c><![CDATA[~/.ssh]]></c> </p>
+ </item>
<tag><c><![CDATA[{system_dir, string()}]]></c></tag>
<item>
<p>Sets the system directory, containing the host files
@@ -283,22 +303,6 @@
</func>
<func>
- <name>sign_data(Data, Algorithm) -> Signature | {error, Reason}</name>
- <fsummary> </fsummary>
- <type>
- <v> Data = binary()</v>
- <v> Algorithm = "ssh-rsa"</v>
- <v> Signature = binary()</v>
- <v> Reason = term()</v>
- </type>
- <desc>
- <p>Signs the supplied binary using the SSH key.
- </p>
- </desc>
- </func>
-
-
- <func>
<name>start() -> </name>
<name>start(Type) -> ok | {error, Reason}</name>
<fsummary>Starts the Ssh application. </fsummary>
@@ -356,21 +360,6 @@
</desc>
</func>
- <func>
- <name>verify_data(Data, Signature, Algorithm) -> ok | {error, Reason}</name>
- <fsummary> </fsummary>
- <type>
- <v> Data = binary()</v>
- <v> Algorithm = "ssh-rsa"</v>
- <v> Signature = binary()</v>
- <v> Reason = term()</v>
- </type>
- <desc>
- <p>Verifies the supplied binary against the binary signature.
- </p>
- </desc>
- </func>
-
</funcs>
</erlref>
diff --git a/lib/ssh/src/DSS.asn1 b/lib/ssh/src/DSS.asn1
deleted file mode 100644
index 77aca3808b..0000000000
--- a/lib/ssh/src/DSS.asn1
+++ /dev/null
@@ -1,20 +0,0 @@
-DSS DEFINITIONS EXPLICIT TAGS ::=
-
-BEGIN
-
--- EXPORTS ALL
--- All types and values defined in this module are exported for use
--- in other ASN.1 modules.
-
-DSAPrivateKey ::= SEQUENCE {
- version INTEGER,
- p INTEGER, -- p
- q INTEGER, -- q
- g INTEGER, -- q
- y INTEGER, -- y
- x INTEGER -- x
-}
-
-END
-
-
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index da31d87369..7be97abf66 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-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
@@ -36,7 +36,11 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN)
# Common Macros
# ----------------------------------------------------
+# Behaviour (api) modules are first so they are compiled when
+# the compiler reaches a callback module using them.
MODULES= \
+ ssh_sftpd_file_api \
+ ssh_key_api \
ssh \
ssh_sup \
sshc_sup \
@@ -56,25 +60,22 @@ MODULES= \
ssh_auth\
ssh_bits \
ssh_cli \
- ssh_dsa \
ssh_file \
ssh_io \
ssh_math \
ssh_no_io \
- ssh_rsa \
ssh_sftp \
ssh_sftpd \
ssh_sftpd_file\
- ssh_sftpd_file_api \
ssh_transport \
ssh_userreg \
ssh_xfer
PUBLIC_HRL_FILES= ssh.hrl ssh_userauth.hrl ssh_xfer.hrl
-ERL_FILES= $(MODULES:%=%.erl) $(ASN_ERLS)
+ERL_FILES= $(MODULES:%=%.erl)
-ALL_MODULES= $(MODULES) $(ASN_MODULES)
+ALL_MODULES= $(MODULES)
TARGET_FILES= $(ALL_MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
@@ -87,22 +88,13 @@ APP_TARGET= $(EBIN)/$(APP_FILE)
APPUP_SRC= $(APPUP_FILE).src
APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-ASN_MODULES = PKCS-1 DSS
-ASN_ASNS = $(ASN_MODULES:%=%.asn1)
-ASN_ERLS = $(ASN_MODULES:%=%.erl)
-ASN_HRLS = $(ASN_MODULES:%=%.hrl)
-ASN_DBS = $(ASN_MODULES:%=%.asn1db)
-ASN_TABLES = $(ASN_MODULES:%=%.table)
-
-ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj +inline
-
-INTERNAL_HRL_FILES = $(ASN_HRLS) ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl
+INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-ERL_COMPILE_FLAGS += -pa$(EBIN)
-
+ERL_COMPILE_FLAGS += -pa$(EBIN)\
+ -pz $(ERL_TOP)/lib/public_key/ebin
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
@@ -114,7 +106,6 @@ debug: ERLC_FLAGS += -Ddebug
clean:
rm -f $(TARGET_FILES)
rm -f errs core *~
- rm -f $(ASN_ERLS) $(ASN_HRLS) $(ASN_DBS)
$(TARGET_FILES): ssh.hrl
@@ -127,10 +118,6 @@ $(APP_TARGET): $(APP_SRC) ../vsn.mk
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
sed -e 's;%VSN%;$(VSN);' $< > $@
-%.erl %.hrl: %.asn1
- $(ERLC) $(ASN_FLAGS) $<
-
-$(EBIN)/ssh_file.$(EMULATOR) $(EBIN)/ssh_rsa.$(EMULATOR): $(ASN_HRLS)
docs:
diff --git a/lib/ssh/src/PKCS-1.asn1 b/lib/ssh/src/PKCS-1.asn1
deleted file mode 100644
index e7d6b18c63..0000000000
--- a/lib/ssh/src/PKCS-1.asn1
+++ /dev/null
@@ -1,116 +0,0 @@
-PKCS-1 {
- iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)
- modules(0) pkcs-1(1)
-}
-
--- $Revision: 1.1 $
-
-DEFINITIONS EXPLICIT TAGS ::=
-
-BEGIN
-
--- IMPORTS id-sha256, id-sha384, id-sha512
--- FROM NIST-SHA2 {
--- joint-iso-itu-t(2) country(16) us(840) organization(1)
--- gov(101) csor(3) nistalgorithm(4) modules(0) sha2(1)
--- };
-
-pkcs-1 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1
-}
-
-rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
-
-id-RSAES-OAEP OBJECT IDENTIFIER ::= { pkcs-1 7 }
-
-id-pSpecified OBJECT IDENTIFIER ::= { pkcs-1 9 }
-
-id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 }
-
-md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
-md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
-sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
-sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
-sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
-sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
-
-id-sha1 OBJECT IDENTIFIER ::= {
- iso(1) identified-organization(3) oiw(14) secsig(3)
- algorithms(2) 26
-}
-
-id-md2 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2
-}
-
-id-md5 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5
-}
-
-id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
-
-
-RSAPublicKey ::= SEQUENCE {
- modulus INTEGER, -- n
- publicExponent INTEGER -- e
-}
-
-RSAPrivateKey ::= SEQUENCE {
- version Version,
- modulus INTEGER, -- n
- publicExponent INTEGER, -- e
- privateExponent INTEGER, -- d
- prime1 INTEGER, -- p
- prime2 INTEGER, -- q
- exponent1 INTEGER, -- d mod (p-1)
- exponent2 INTEGER, -- d mod (q-1)
- coefficient INTEGER, -- (inverse of q) mod p
- otherPrimeInfos OtherPrimeInfos OPTIONAL
-}
-
-Version ::= INTEGER { two-prime(0), multi(1) }
- (CONSTRAINED BY {
- -- version must be multi if otherPrimeInfos present --
- })
-
-OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
-
-OtherPrimeInfo ::= SEQUENCE {
- prime INTEGER, -- ri
- exponent INTEGER, -- di
- coefficient INTEGER -- ti
-}
-
-Algorithm ::= SEQUENCE {
- algorithm OBJECT IDENTIFIER,
- parameters ANY DEFINED BY algorithm OPTIONAL
-}
-
-AlgorithmNull ::= SEQUENCE {
- algorithm OBJECT IDENTIFIER,
- parameters NULL
-}
-
-
-RSASSA-PSS-params ::= SEQUENCE {
- hashAlgorithm [0] Algorithm, -- DEFAULT sha1,
- maskGenAlgorithm [1] Algorithm, -- DEFAULT mgf1SHA1,
- saltLength [2] INTEGER DEFAULT 20,
- trailerField [3] TrailerField DEFAULT trailerFieldBC
-}
-
-TrailerField ::= INTEGER { trailerFieldBC(1) }
-
-DigestInfo ::= SEQUENCE {
- digestAlgorithm Algorithm,
- digest OCTET STRING
-}
-
-DigestInfoNull ::= SEQUENCE {
- digestAlgorithm AlgorithmNull,
- digest OCTET STRING
-}
-
-
-END -- PKCS1Definitions
-
diff --git a/lib/ssh/src/prebuild.skip b/lib/ssh/src/prebuild.skip
deleted file mode 100644
index 1d7552d98d..0000000000
--- a/lib/ssh/src/prebuild.skip
+++ /dev/null
@@ -1,2 +0,0 @@
-DSS.asn1db
-PKCS-1.asn1db
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 8a3e15841f..7a58dbe54f 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -3,9 +3,7 @@
{application, ssh,
[{description, "SSH-2 for Erlang/OTP"},
{vsn, "%VSN%"},
- {modules, ['DSS',
- 'PKCS-1',
- ssh,
+ {modules, [ssh,
ssh_app,
ssh_acceptor,
ssh_acceptor_sup,
@@ -21,12 +19,11 @@
ssh_shell,
sshc_sup,
sshd_sup,
- ssh_dsa,
ssh_file,
ssh_io,
+ ssh_key_api,
ssh_math,
ssh_no_io,
- ssh_rsa,
ssh_sftp,
ssh_sftpd,
ssh_sftpd_file,
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index cada109df0..5751f2eaa0 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -23,6 +23,7 @@
-include("ssh.hrl").
-include("ssh_connect.hrl").
+-include_lib("public_key/include/public_key.hrl").
-export([start/0, start/1, stop/0, connect/3, connect/4, close/1, connection_info/2,
channel_info/3,
@@ -30,6 +31,9 @@
stop_listener/1, stop_listener/2, stop_daemon/1, stop_daemon/2,
shell/1, shell/2, shell/3]).
+-deprecated({sign_data, 2, next_major_release}).
+-deprecated({verify_data, 3, next_major_release}).
+
-export([sign_data/2, verify_data/3]).
%%--------------------------------------------------------------------
@@ -89,6 +93,9 @@ connect(Host, Port, Options, Timeout) ->
%% might return undefined as the connection manager
%% could allready have terminated, so we will not
%% match the Manager in this case
+ {_, not_connected, {error, econnrefused}} when DisableIpv6 == false ->
+ do_demonitor(MRef, Manager),
+ connect(Host, Port, [{ip_v6_disabled, true} | Options], Timeout);
{_, not_connected, {error, Reason}} ->
do_demonitor(MRef, Manager),
{error, Reason};
@@ -247,43 +254,6 @@ shell(Host, Port, Options) ->
Error
end.
-
-%%--------------------------------------------------------------------
-%% Function: sign_data(Data, Algorithm) -> binary() |
-%% {error, Reason}
-%%
-%% Data = binary()
-%% Algorithm = "ssh-rsa"
-%%
-%% Description: Use SSH key to sign data.
-%%--------------------------------------------------------------------
-sign_data(Data, Algorithm) when is_binary(Data) ->
- case ssh_file:private_identity_key(Algorithm,[]) of
- {ok, Key} when Algorithm == "ssh-rsa" ->
- ssh_rsa:sign(Key, Data);
- Error ->
- Error
- end.
-
-%%--------------------------------------------------------------------
-%% Function: verify_data(Data, Signature, Algorithm) -> ok |
-%% {error, Reason}
-%%
-%% Data = binary()
-%% Signature = binary()
-%% Algorithm = "ssh-rsa"
-%%
-%% Description: Use SSH signature to verify data.
-%%--------------------------------------------------------------------
-verify_data(Data, Signature, Algorithm) when is_binary(Data), is_binary(Signature) ->
- case ssh_file:public_identity_key(Algorithm, []) of
- {ok, Key} when Algorithm == "ssh-rsa" ->
- ssh_rsa:verify(Key, Data, Signature);
- Error ->
- Error
- end.
-
-
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -336,6 +306,10 @@ handle_options([{connect_timeout, _} = Opt | Rest], SockOpts, Opts) ->
handle_options(Rest, SockOpts, [Opt | Opts]);
handle_options([{user, _} = Opt | Rest], SockOpts, Opts) ->
handle_options(Rest, SockOpts, [Opt | Opts]);
+handle_options([{dsa_pass_phrase, _} = Opt | Rest], SockOpts, Opts) ->
+ handle_options(Rest, SockOpts, [Opt | Opts]);
+handle_options([{rsa_pass_phrase, _} = Opt | Rest], SockOpts, Opts) ->
+ handle_options(Rest, SockOpts, [Opt | Opts]);
handle_options([{password, _} = Opt | Rest], SockOpts, Opts) ->
handle_options(Rest, SockOpts, [Opt | Opts]);
handle_options([{user_passwords, _} = Opt | Rest], SockOpts, Opts) ->
@@ -379,6 +353,50 @@ handle_options([Opt | Rest], SockOpts, Opts) ->
inetopt(true) ->
inet;
inetopt(false) ->
- inet6.
+ case gen_tcp:listen(0, [inet6, {ip, loopback}]) of
+ {ok, Dummyport} ->
+ gen_tcp:close(Dummyport),
+ inet6;
+ _ ->
+ inet
+ end.
+
+%%%
+%% Deprecated
+%%%
+
+%%--------------------------------------------------------------------
+%% Function: sign_data(Data, Algorithm) -> binary() |
+%% {error, Reason}
+%%
+%% Data = binary()
+%% Algorithm = "ssh-rsa"
+%%
+%% Description: Use SSH key to sign data.
+%%--------------------------------------------------------------------
+sign_data(Data, Algorithm) when is_binary(Data) ->
+ case ssh_file:user_key(Algorithm,[]) of
+ {ok, Key} when Algorithm == "ssh-rsa" ->
+ public_key:sign(Data, sha, Key);
+ Error ->
+ Error
+ end.
+%%--------------------------------------------------------------------
+%% Function: verify_data(Data, Signature, Algorithm) -> ok |
+%% {error, Reason}
+%%
+%% Data = binary()
+%% Signature = binary()
+%% Algorithm = "ssh-rsa"
+%%
+%% Description: Use SSH signature to verify data.
+%%--------------------------------------------------------------------
+verify_data(Data, Signature, Algorithm) when is_binary(Data), is_binary(Signature) ->
+ case ssh_file:user_key(Algorithm, []) of
+ {ok, #'RSAPrivateKey'{publicExponent = E, modulus = N}} when Algorithm == "ssh-rsa" ->
+ public_key:verify(Data, sha, Signature, #'RSAPublicKey'{publicExponent = E, modulus = N});
+ Error ->
+ Error
+ end.
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index ac249b05e3..da5750b6c3 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -54,18 +54,6 @@
-define(string(X), << ?STRING(list_to_binary(X)) >> ).
-define(binary(X), << ?STRING(X) >>).
--ifdef(debug).
--define(dbg(Debug, Fmt, As),
- case (Debug) of
- true ->
- io:format([$# | (Fmt)], (As));
- _ ->
- ok
- end).
--else.
--define(dbg(Debug, Fmt, As), ok).
--endif.
-
-define(SSH_CIPHER_NONE, 0).
-define(SSH_CIPHER_3DES, 3).
-define(SSH_CIPHER_AUTHFILE, ?SSH_CIPHER_3DES).
@@ -138,7 +126,8 @@
userauth_quiet_mode, % boolean()
userauth_supported_methods , %
userauth_methods,
- userauth_preference
+ userauth_preference,
+ available_host_keys
}).
-record(alg,
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 9dbd95886e..62d684f4dc 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. 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
@@ -21,8 +21,9 @@
-module(ssh_auth).
--include("ssh.hrl").
+-include_lib("public_key/include/public_key.hrl").
+-include("ssh.hrl").
-include("ssh_auth.hrl").
-include("ssh_transport.hrl").
@@ -36,18 +37,21 @@
%%--------------------------------------------------------------------
%%% Internal application API
%%--------------------------------------------------------------------
-publickey_msg([Cb, #ssh{user = User,
+publickey_msg([Alg, #ssh{user = User,
session_id = SessionId,
service = Service,
opts = Opts} = Ssh]) ->
+
+ Hash = sha, %% Maybe option?!
ssh_bits:install_messages(userauth_pk_messages()),
- Alg = Cb:alg_name(),
- case ssh_file:private_identity_key(Alg, Opts) of
- {ok, PrivKey} ->
- PubKeyBlob = ssh_file:encode_public_key(PrivKey),
+ KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+
+ case KeyCb:user_key(Alg, Opts) of
+ {ok, Key} ->
+ PubKeyBlob = encode_public_key(Key),
SigData = build_sig_data(SessionId,
- User, Service, Alg, PubKeyBlob),
- Sig = Cb:sign(PrivKey, SigData),
+ User, Service, PubKeyBlob, Alg),
+ Sig = ssh_transport:sign(SigData, Hash, Key),
SigBlob = list_to_binary([?string(Alg), ?binary(Sig)]),
ssh_transport:ssh_packet(
#ssh_msg_userauth_request{user = User,
@@ -58,8 +62,8 @@ publickey_msg([Cb, #ssh{user = User,
?binary(PubKeyBlob),
?binary(SigBlob)]},
Ssh);
- _Error ->
- not_ok
+ _Error ->
+ not_ok
end.
password_msg([#ssh{opts = Opts, io_cb = IoCb,
@@ -67,29 +71,43 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb,
ssh_bits:install_messages(userauth_passwd_messages()),
Password = case proplists:get_value(password, Opts) of
undefined ->
- IoCb:read_password("ssh password: ");
+ user_interaction(Opts, IoCb);
PW ->
PW
end,
- ssh_transport:ssh_packet(
- #ssh_msg_userauth_request{user = User,
- service = Service,
- method = "password",
- data =
- <<?BOOLEAN(?FALSE),
- ?STRING(list_to_binary(Password))>>},
- Ssh).
+ case Password of
+ not_ok ->
+ not_ok;
+ _ ->
+ ssh_transport:ssh_packet(
+ #ssh_msg_userauth_request{user = User,
+ service = Service,
+ method = "password",
+ data =
+ <<?BOOLEAN(?FALSE),
+ ?STRING(list_to_binary(Password))>>},
+ Ssh)
+ end.
+
+user_interaction(Opts, IoCb) ->
+ case proplists:get_value(allow_user_interaction, Opts, true) of
+ true ->
+ IoCb:read_password("ssh password: ");
+ false ->
+ not_ok
+ end.
+
%% See RFC 4256 for info on keyboard-interactive
keyboard_interactive_msg([#ssh{user = User,
- service = Service} = Ssh]) ->
+ service = Service} = Ssh]) ->
ssh_bits:install_messages(userauth_keyboard_interactive_messages()),
ssh_transport:ssh_packet(
#ssh_msg_userauth_request{user = User,
service = Service,
method = "keyboard-interactive",
data = << ?STRING(<<"">>),
- ?STRING(<<>>) >> },
+ ?STRING(<<>>) >> },
Ssh).
service_request_msg(Ssh) ->
@@ -103,12 +121,12 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
service = "ssh-connection",
method = "none",
data = <<>>},
- CbFirst = proplists:get_value(public_key_alg, Opts,
- ?PREFERRED_PK_ALG),
- CbSecond = other_cb(CbFirst),
+ FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts,
+ ?PREFERRED_PK_ALG)),
+ SecondAlg = other_alg(FirstAlg),
AllowUserInt = proplists:get_value(allow_user_interaction, Opts,
true),
- Prefs = method_preference(CbFirst, CbSecond, AllowUserInt),
+ Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt),
ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User,
userauth_preference = Prefs,
userauth_methods = none,
@@ -192,12 +210,12 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
?TRUE ->
case verify_sig(SessionId, User, "ssh-connection", Alg,
KeyBlob, SigWLen, Opts) of
- ok ->
+ true ->
{authorized, User,
ssh_transport:ssh_packet(
#ssh_msg_userauth_success{}, Ssh)};
- {error, Reason} ->
- {not_authorized, {User, {error, Reason}},
+ false ->
+ {not_authorized, {User, {error, "Invalid signature"}},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
authentications="publickey,password",
partial_success = false}, Ssh)}
@@ -228,7 +246,6 @@ handle_userauth_info_request(
PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data),
Resps = keyboard_interact_get_responses(IoCb, Opts,
Name, Instr, PromptInfos),
- %%?dbg(true, "keyboard_interactive_reply: resps=~n#~p ~n", [Resps]),
RespBin = list_to_binary(
lists:map(fun(S) -> <<?STRING(list_to_binary(S))>> end,
Resps)),
@@ -263,15 +280,15 @@ userauth_messages() ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-method_preference(Callback1, Callback2, true) ->
- [{"publickey", ?MODULE, publickey_msg, [Callback1]},
- {"publickey", ?MODULE, publickey_msg,[Callback2]},
+method_preference(Alg1, Alg2, true) ->
+ [{"publickey", ?MODULE, publickey_msg, [Alg1]},
+ {"publickey", ?MODULE, publickey_msg,[Alg2]},
{"password", ?MODULE, password_msg, []},
{"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}
];
-method_preference(Callback1, Callback2, false) ->
- [{"publickey", ?MODULE, publickey_msg, [Callback1]},
- {"publickey", ?MODULE, publickey_msg,[Callback2]},
+method_preference(Alg1, Alg2, false) ->
+ [{"publickey", ?MODULE, publickey_msg, [Alg1]},
+ {"publickey", ?MODULE, publickey_msg,[Alg2]},
{"password", ?MODULE, password_msg, []}
].
@@ -295,7 +312,6 @@ user_name(Opts) ->
end.
check_password(User, Password, Opts) ->
- %%?dbg(true, " ~p ~p ~p ~n", [User, Password, Opts]),
case proplists:get_value(pwdfun, Opts) of
undefined ->
Static = get_password_option(Opts, User),
@@ -312,25 +328,22 @@ get_password_option(Opts, User) ->
end.
verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
- case ssh_file:lookup_user_key(User, Alg, Opts) of
- {ok, OurKey} ->
- {ok, Key} = ssh_file:decode_public_key_v2(KeyBlob, Alg),
- case OurKey of
- Key ->
- NewSig = build_sig_data(SessionId,
- User, Service, Alg, KeyBlob),
- <<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen,
- <<?UINT32(AlgLen), _Alg:AlgLen/binary,
- ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig,
- M = alg_to_module(Alg),
- M:verify(OurKey, NewSig, Sig);
- _ ->
- {error, key_unacceptable}
- end;
- Error -> Error
+ {ok, Key} = decode_public_key_v2(KeyBlob, Alg),
+ KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
+
+ case KeyCb:is_auth_key(Key, User, Alg, Opts) of
+ true ->
+ PlainText = build_sig_data(SessionId, User,
+ Service, KeyBlob, Alg),
+ <<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen,
+ <<?UINT32(AlgLen), _Alg:AlgLen/binary,
+ ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig,
+ ssh_transport:verify(PlainText, sha, Sig, Key);
+ false ->
+ {error, key_unacceptable}
end.
-build_sig_data(SessionId, User, Service, Alg, KeyBlob) ->
+build_sig_data(SessionId, User, Service, KeyBlob, Alg) ->
Sig = [?binary(SessionId),
?SSH_MSG_USERAUTH_REQUEST,
?string(User),
@@ -341,6 +354,11 @@ build_sig_data(SessionId, User, Service, Alg, KeyBlob) ->
?binary(KeyBlob)],
list_to_binary(Sig).
+algorithm(ssh_rsa) ->
+ "ssh-rsa";
+algorithm(ssh_dsa) ->
+ "ssh-dss".
+
decode_keyboard_interactive_prompts(NumPrompts, Data) ->
Types = lists:append(lists:duplicate(NumPrompts, [string, boolean])),
pairwise_tuplify(ssh_bits:decode(Data, Types)).
@@ -412,12 +430,28 @@ userauth_pk_messages() ->
binary]} % key blob
].
-alg_to_module("ssh-dss") ->
- ssh_dsa;
-alg_to_module("ssh-rsa") ->
- ssh_rsa.
-
-other_cb(ssh_rsa) ->
- ssh_dsa;
-other_cb(ssh_dsa) ->
- ssh_rsa.
+other_alg("ssh-rsa") ->
+ "ssh-dss";
+other_alg("ssh-dss") ->
+ "ssh-rsa".
+decode_public_key_v2(K_S, "ssh-rsa") ->
+ case ssh_bits:decode(K_S,[string,mpint,mpint]) of
+ ["ssh-rsa", E, N] ->
+ {ok, #'RSAPublicKey'{publicExponent = E, modulus = N}};
+ _ ->
+ {error, bad_format}
+ end;
+decode_public_key_v2(K_S, "ssh-dss") ->
+ case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
+ ["ssh-dss",P,Q,G,Y] ->
+ {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}};
+ _ ->
+ {error, bad_format}
+ end;
+decode_public_key_v2(_, _) ->
+ {error, bad_format}.
+
+encode_public_key(#'RSAPrivateKey'{publicExponent = E, modulus = N}) ->
+ ssh_bits:encode(["ssh-rsa",E,N], [string,mpint,mpint]);
+encode_public_key(#'DSAPrivateKey'{p = P, q = Q, g = G, y = Y}) ->
+ ssh_bits:encode(["ssh-dss",P,Q,G,Y], [string,mpint,mpint,mpint,mpint]).
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index 3f0a06575c..5841f06d70 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.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
@@ -105,16 +105,12 @@ bignum(X) ->
install_messages(Codes) ->
foreach(fun({Name, Code, Ts}) ->
- %% ?dbg(true, "install msg: ~s = ~w ~w~n",
-%% [Name,Code,Ts]),
put({msg_name,Code}, {Name,Ts}),
put({msg_code,Name}, {Code,Ts})
end, Codes).
uninstall_messages(Codes) ->
foreach(fun({Name, Code, _Ts}) ->
- %% ?dbg(true, "uninstall msg: ~s = ~w ~w~n",
-%% [Name,Code,_Ts]),
erase({msg_name,Code}),
erase({msg_code,Name})
end, Codes).
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 7b9e9185bf..cb02d7b824 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. 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
@@ -722,8 +722,6 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = _Other,
want_reply = WantReply}, Connection,
ConnectionPid, _) ->
- ?dbg(true, "ssh_msg ssh_msg_channel_request: Other=~p\n",
- [_Other]),
if WantReply == true ->
FailMsg = channel_failure_msg(ChannelId),
{{replies, [{connection_reply, ConnectionPid, FailMsg}]},
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 00b30e5434..9079089d5d 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.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
@@ -637,16 +637,18 @@ init_ssh(client = Role, Vsn, Version, Options, Socket) ->
{ok, PeerAddr} = inet:peername(Socket),
PeerName = proplists:get_value(host, Options),
+ KeyCb = proplists:get_value(key_cb, Options, ssh_file),
#ssh{role = Role,
c_vsn = Vsn,
c_version = Version,
- key_cb = proplists:get_value(key_cb, Options, ssh_file),
+ key_cb = KeyCb,
io_cb = IOCb,
userauth_quiet_mode = proplists:get_value(quiet_mode, Options, false),
opts = Options,
userauth_supported_methods = AuthMethods,
- peer = {PeerName, PeerAddr}
+ peer = {PeerName, PeerAddr},
+ available_host_keys = supported_host_keys(Role, KeyCb, Options)
};
init_ssh(server = Role, Vsn, Version, Options, Socket) ->
@@ -654,17 +656,48 @@ init_ssh(server = Role, Vsn, Version, Options, Socket) ->
AuthMethods = proplists:get_value(auth_methods, Options,
?SUPPORTED_AUTH_METHODS),
{ok, PeerAddr} = inet:peername(Socket),
-
+ KeyCb = proplists:get_value(key_cb, Options, ssh_file),
+
#ssh{role = Role,
s_vsn = Vsn,
s_version = Version,
- key_cb = proplists:get_value(key_cb, Options, ssh_file),
+ key_cb = KeyCb,
io_cb = proplists:get_value(io_cb, Options, ssh_io),
opts = Options,
userauth_supported_methods = AuthMethods,
- peer = {undefined, PeerAddr}
+ peer = {undefined, PeerAddr},
+ available_host_keys = supported_host_keys(Role, KeyCb, Options)
}.
+supported_host_keys(client, _, _) ->
+ ["ssh-rsa", "ssh-dss"];
+supported_host_keys(server, KeyCb, Options) ->
+ lists:foldl(fun(Type, Acc) ->
+ case available_host_key(KeyCb, Type, Options) of
+ {error, _} ->
+ Acc;
+ Alg ->
+ [Alg | Acc]
+ end
+ end, [],
+ %% Prefered alg last so no need to reverse
+ ["ssh-dss", "ssh-rsa"]).
+
+available_host_key(KeyCb, "ssh-dss"= Alg, Opts) ->
+ case KeyCb:host_key('ssh-dss', Opts) of
+ {ok, _} ->
+ Alg;
+ Other ->
+ Other
+ end;
+available_host_key(KeyCb, "ssh-rsa" = Alg, Opts) ->
+ case KeyCb:host_key('ssh-rsa', Opts) of
+ {ok, _} ->
+ Alg;
+ Other ->
+ Other
+ end.
+
send_msg(Msg, #state{socket = Socket, transport_cb = Transport}) ->
Transport:send(Socket, Msg).
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index 9bfd5270da..f729276e65 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -144,7 +144,7 @@ adjust_window(ConnectionManager, Channel, Bytes) ->
cast(ConnectionManager, {adjust_window, Channel, Bytes}).
close(ConnectionManager, ChannelId) ->
- try call(ConnectionManager, {close, ChannelId}) of
+ try call(ConnectionManager, {close, ChannelId}) of
ok ->
ok;
{error, channel_closed} ->
@@ -604,6 +604,8 @@ call(Pid, Msg, Timeout) ->
exit:{timeout, _} ->
{error, timeout};
exit:{normal, _} ->
+ {error, channel_closed};
+ exit:{noproc,_} ->
{error, channel_closed}
end.
diff --git a/lib/ssh/src/ssh_dsa.erl b/lib/ssh/src/ssh_dsa.erl
deleted file mode 100644
index cb2632beac..0000000000
--- a/lib/ssh/src/ssh_dsa.erl
+++ /dev/null
@@ -1,95 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-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%
-%%
-
-%%
-
-%%% Description: dsa public-key sign and verify
-
--module(ssh_dsa).
-
--export([verify/3]).
--export([sign/2]).
--export([alg_name/0]).
-
--include("ssh.hrl").
-
-%% start() ->
-%% crypto:start().
-
-%% sign_file(File, Opts) ->
-%% start(),
-%% {ok,Bin} = file:read_file(File),
-%% {ok,Key} = ssh_file:private_host_dsa_key(user, Opts),
-%% sign(Key, Bin).
-
-%% verify_file(File, Sig) ->
-%% start(),
-%% {ok,Bin} = file:read_file(File),
-%% {ok,Key} = ssh_file:public_host_key(user, dsa),
-%% verify(Key, Bin, Sig).
-
-sign(_Private=#ssh_key { private={P,Q,G,X} },Mb) ->
- K = ssh_bits:irandom(160) rem Q,
- R = ssh_math:ipow(G, K, P) rem Q,
- Ki = ssh_math:invert(K, Q),
- <<M:160/big-unsigned-integer>> = crypto:sha(Mb),
- S = (Ki * (M + X*R)) rem Q,
- <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>.
-
-
-%% the paramiko client sends a bad sig sometimes,
-%% instead of crashing, we nicely return error, the
-%% typcally manifests itself as Sb being 39 bytes
-%% instead of 40.
-
-verify(Public, Mb, Sb) ->
- case catch xverify(Public, Mb, Sb) of
- {'EXIT', _Reason} ->
- %store({Public, Mb, Sb, _Reason}),
- {error, inconsistent_key};
- ok ->
- %store({Public, Mb, Sb, ok})
- ok
- end.
-
-%% store(Term) ->
-%% {ok, Fd} = file:open("/tmp/dsa", [append]),
-%% io:format(Fd, "~p~n~n~n", [Term]),
-%% file:close(Fd).
-
-
-xverify(_Public=#ssh_key { public={P,Q,G,Y} },Mb,Sb) ->
- <<R0:160/big-unsigned-integer, S0:160/big-unsigned-integer>> = Sb,
- ?ssh_assert(R0 >= 0 andalso R0 < Q andalso
- S0 >= 0 andalso S0 < Q, out_of_range),
- W = ssh_math:invert(S0,Q),
- <<M0:160/big-unsigned-integer>> = crypto:sha(Mb),
- U1 = (M0*W) rem Q,
- U2 = (R0*W) rem Q,
- T1 = ssh_math:ipow(G,U1,P),
- T2 = ssh_math:ipow(Y,U2,P),
- V = ((T1*T2) rem P) rem Q,
- if V == R0 ->
- ok;
- true ->
- {error, inconsistent_key}
- end.
-
-alg_name() ->
- "ssh-dss".
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 12180f56bb..d05fa8e09a 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.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
@@ -23,80 +23,98 @@
-module(ssh_file).
--include("ssh.hrl").
--include("PKCS-1.hrl").
--include("DSS.hrl").
+-behaviour(ssh_key_api).
+-include_lib("public_key/include/public_key.hrl").
-include_lib("kernel/include/file.hrl").
--export([public_host_dsa_key/2,private_host_dsa_key/2,
- public_host_rsa_key/2,private_host_rsa_key/2,
- public_host_key/2,private_host_key/2,
- lookup_host_key/3, add_host_key/3, % del_host_key/2,
- lookup_user_key/3, ssh_dir/2, file_name/3]).
-
--export([private_identity_key/2,
- public_identity_key/2]).
-%% identity_keys/2]).
-
--export([encode_public_key/1, decode_public_key_v2/2]).
+-include("ssh.hrl").
--import(lists, [reverse/1, append/1]).
+-export([host_key/2,
+ user_key/2,
+ is_host_key/4,
+ add_host_key/3,
+ is_auth_key/4]).
--define(DBG_PATHS, true).
-define(PERM_700, 8#700).
-define(PERM_644, 8#644).
+
%% API
-public_host_dsa_key(Type, Opts) ->
- File = file_name(Type, "ssh_host_dsa_key.pub", Opts),
- read_public_key_v2(File, "ssh-dss").
-
-private_host_dsa_key(Type, Opts) ->
- File = file_name(Type, "ssh_host_dsa_key", Opts),
- read_private_key_v2(File, "ssh-dss").
-
-public_host_rsa_key(Type, Opts) ->
- File = file_name(Type, "ssh_host_rsa_key.pub", Opts),
- read_public_key_v2(File, "ssh-rsa").
-
-private_host_rsa_key(Type, Opts) ->
- File = file_name(Type, "ssh_host_rsa_key", Opts),
- read_private_key_v2(File, "ssh-rsa").
-
-public_host_key(Type, Opts) ->
- File = file_name(Type, "ssh_host_key", Opts),
- case read_private_key_v1(File,public) of
- {error, enoent} ->
- read_public_key_v1(File++".pub");
- Result ->
- Result
- end.
-
-private_host_key(Type, Opts) ->
- File = file_name(Type, "ssh_host_key", Opts),
- read_private_key_v1(File,private).
+%% Used by server
+host_key(Algorithm, Opts) ->
+ File = file_name(system, file_base_name(Algorithm), Opts),
+ %% We do not expect host keys to have pass phrases
+ %% so probably we could hardcod Password = ignore, but
+ %% we keep it as an undocumented option for now.
+ Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore),
+ decode(File, Password).
+is_auth_key(Key, User, Alg, Opts) ->
+ case lookup_user_key(Key, User, Alg, Opts) of
+ {ok, Key} ->
+ true;
+ _ ->
+ false
+ end.
-%% in: "host" out: "host,1.2.3.4.
-add_ip(Host) ->
- case inet:getaddr(Host, inet) of
- {ok, Addr} ->
- case ssh_connection:encode_ip(Addr) of
- false -> Host;
- IPString -> Host ++ "," ++ IPString
- end;
- _ -> Host
- end.
-replace_localhost("localhost") ->
- {ok, Hostname} = inet:gethostname(),
- Hostname;
-replace_localhost(Host) ->
- Host.
+%% Used by client
+is_host_key(Key, PeerName, Algorithm, Opts) ->
+ case lookup_host_key(PeerName, Algorithm, Opts) of
+ {ok, Key} ->
+ true;
+ _ ->
+ false
+ end.
+
+user_key(Algorithm, Opts) ->
+ File = file_name(user, identity_key_filename(Algorithm), Opts),
+ Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore),
+ decode(File, Password).
+
+
+%% Internal functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+file_base_name('ssh-rsa') ->
+ "ssh_host_rsa_key";
+file_base_name('ssh-dss') ->
+ "ssh_host_dsa_key";
+file_base_name(_) ->
+ "ssh_host_key".
+
+decode(File, Password) ->
+ try
+ {ok, decode_ssh_file(read_ssh_file(File), Password)}
+ catch
+ throw:Reason ->
+ {error, Reason};
+ error:Reason ->
+ {error, Reason}
+ end.
+
+read_ssh_file(File) ->
+ {ok, Bin} = file:read_file(File),
+ Bin.
+
+%% Public key
+decode_ssh_file(SshBin, public_key) ->
+ public_key:ssh_decode(SshBin, public_key);
+
+%% Private Key
+decode_ssh_file(Pem, Password) ->
+ case public_key:pem_decode(Pem) of
+ [{_, _, not_encrypted} = Entry] ->
+ public_key:pem_entry_decode(Entry);
+ [Entry] when Password =/= ignore ->
+ public_key:pem_entry_decode(Entry, Password);
+ _ ->
+ throw("No pass phrase provided for private key file")
+ end.
+
%% lookup_host_key
%% return {ok, Key(s)} or {error, not_found}
@@ -106,15 +124,6 @@ lookup_host_key(Host, Alg, Opts) ->
Host1 = replace_localhost(Host),
do_lookup_host_key(Host1, Alg, Opts).
-do_lookup_host_key(Host, Alg, Opts) ->
- case file:open(file_name(user, "known_hosts", Opts), [read]) of
- {ok, Fd} ->
- Res = lookup_host_key_fd(Fd, Host, Alg),
- file:close(Fd),
- Res;
- {error, enoent} -> {error, not_found};
- Error -> Error
- end.
add_host_key(Host, Key, Opts) ->
Host1 = add_ip(replace_localhost(Host)),
@@ -129,383 +138,16 @@ add_host_key(Host, Key, Opts) ->
Error
end.
-%% del_host_key(Host, Opts) ->
-%% Host1 = replace_localhost(Host),
-%% case file:open(file_name(user, "known_hosts", Opts),[write,read]) of
-%% {ok, Fd} ->
-%% Res = del_key_fd(Fd, Host1),
-%% file:close(Fd),
-%% Res;
-%% Error ->
-%% Error
-%% end.
-
-identity_key_filename("ssh-dss") -> "id_dsa";
-identity_key_filename("ssh-rsa") -> "id_rsa".
-
-private_identity_key(Alg, Opts) ->
- Path = file_name(user, identity_key_filename(Alg), Opts),
- read_private_key_v2(Path, Alg).
-
-public_identity_key(Alg, Opts) ->
- Path = file_name(user, identity_key_filename(Alg) ++ ".pub", Opts),
- read_public_key_v2(Path, Alg).
-
-
-read_public_key_v2(File, Type) ->
- case file:read_file(File) of
- {ok,Bin} ->
- List = binary_to_list(Bin),
- case lists:prefix(Type, List) of
- true ->
- List1 = lists:nthtail(length(Type), List),
- K_S = ssh_bits:b64_decode(List1),
- decode_public_key_v2(K_S, Type);
- false ->
- {error, bad_format}
- end;
- Error ->
- Error
- end.
-
-decode_public_key_v2(K_S, "ssh-rsa") ->
- case ssh_bits:decode(K_S,[string,mpint,mpint]) of
- ["ssh-rsa", E, N] ->
- {ok, #ssh_key { type = rsa,
- public = {N,E},
- comment=""}};
- _ ->
- {error, bad_format}
- end;
-decode_public_key_v2(K_S, "ssh-dss") ->
- case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
- ["ssh-dss",P,Q,G,Y] ->
- {ok,#ssh_key { type = dsa,
- public = {P,Q,G,Y}
- }};
- _A ->
- {error, bad_format}
- end;
-decode_public_key_v2(_, _) ->
- {error, bad_format}.
-
-
-read_public_key_v1(File) ->
- case file:read_file(File) of
- {ok,Bin} ->
- List = binary_to_list(Bin),
- case io_lib:fread("~d ~d ~d ~s", List) of
- {ok,[_Sz,E,N,Comment],_} ->
- {ok,#ssh_key { type = rsa,
- public ={N,E},
- comment = Comment }};
- _Error ->
- {error, bad_format}
- end;
- Error ->
- Error
- end.
-
-%% pem_type("ssh-dss") -> "DSA";
-%% pem_type("ssh-rsa") -> "RSA".
-
-read_private_key_v2(File, Type) ->
- case file:read_file(File) of
- {ok, PemBin} ->
- case catch (public_key:pem_decode(PemBin)) of
- [{_, Bin, not_encrypted}] ->
- decode_private_key_v2(Bin, Type);
- Error -> %% Note we do not handle password encrypted keys at the moment
- {error, Error}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
-%% case file:read_file(File) of
-%% {ok,Bin} ->
-%% case read_pem(binary_to_list(Bin), pem_type(Type)) of
-%% {ok,Bin1} ->
-%% decode_private_key_v2(Bin1, Type);
-%% Error ->
-%% Error
-%% end;
-%% Error ->
-%% Error
-%% end.
-
-decode_private_key_v2(Private,"ssh-rsa") ->
- case 'PKCS-1':decode( 'RSAPrivateKey', Private) of
- {ok,RSA} -> %% FIXME Check for two-prime version
- {ok, #ssh_key { type = rsa,
- public = {RSA#'RSAPrivateKey'.modulus,
- RSA#'RSAPrivateKey'.publicExponent},
- private = {RSA#'RSAPrivateKey'.modulus,
- RSA#'RSAPrivateKey'.privateExponent}
- }};
- Error ->
- Error
- end;
-decode_private_key_v2(Private, "ssh-dss") ->
- case 'DSS':decode('DSAPrivateKey', Private) of
- {ok,DSA} -> %% FIXME Check for two-prime version
- {ok, #ssh_key { type = dsa,
- public = {DSA#'DSAPrivateKey'.p,
- DSA#'DSAPrivateKey'.q,
- DSA#'DSAPrivateKey'.g,
- DSA#'DSAPrivateKey'.y},
- private= {DSA#'DSAPrivateKey'.p,
- DSA#'DSAPrivateKey'.q,
- DSA#'DSAPrivateKey'.g,
- DSA#'DSAPrivateKey'.x}
- }};
- _ ->
- {error,bad_format}
- end.
-
-%% SSH1 private key format
-%% <<"SSH PRIVATE KEY FILE FORMATE 1.1\n" 0:8
-%% CipherNum:8, Reserved:32,
-%% NSz/uint32, N/bignum, E/bignum, Comment/string,
-%%
-%% [ R0:8 R1:8 R0:8 R1:8, D/bignum, IQMP/bignum, Q/bignum, P/bignum, Pad(8)]>>
-%%
-%% where [ ] is encrypted using des3 (ssh1 version) and
-%% a posssibly empty pass phrase using md5(passphase) as key
-%%
-
-read_private_key_v1(File, Type) ->
- case file:read_file(File) of
- {ok,<<"SSH PRIVATE KEY FILE FORMAT 1.1\n",0,
- CipherNum,_Resereved:32,Bin/binary>>} ->
- decode_private_key_v1(Bin, CipherNum,Type);
- {ok,_} ->
- {error, bad_format};
- Error ->
- Error
- end.
-
-decode_private_key_v1(Bin, CipherNum, Type) ->
- case ssh_bits:decode(Bin,0,[uint32, bignum, bignum, string]) of
- {Offset,[_NSz,N,E,Comment]} ->
- if Type == public ->
- {ok,#ssh_key { type=rsa,
- public={N,E},
- comment=Comment}};
- Type == private ->
- <<_:Offset/binary, Encrypted/binary>> = Bin,
- case ssh_bits:decode(decrypt1(Encrypted, CipherNum),0,
- [uint32, bignum, bignum,
- bignum, bignum,{pad,8}]) of
- {_,[_,D,IQMP,Q,P]} ->
- {ok,#ssh_key { type=rsa,
- public={N,E},
- private={D,IQMP,Q,P},
- comment=Comment}};
- _ ->
- {error,bad_format}
- end
- end;
- _ ->
- {error,bad_format}
- end.
-
-
-decrypt1(Bin, CipherNum) ->
- decrypt1(Bin, CipherNum,"").
-
-decrypt1(Bin, CipherNum, Phrase) ->
- if CipherNum == ?SSH_CIPHER_NONE; Phrase == "" ->
- Bin;
- CipherNum == ?SSH_CIPHER_3DES ->
- <<K1:8/binary, K2:8/binary>> = erlang:md5(Phrase),
- K3 = K1,
- IV = <<0,0,0,0,0,0,0,0>>,
- Bin1 = crypto:des_cbc_decrypt(K3,IV,Bin),
- Bin2 = crypto:des_cbc_encrypt(K2,IV,Bin1),
- crypto:des_cbc_decrypt(K1,IV,Bin2)
- end.
-
-%% encrypt1(Bin, CipherNum) ->
-%% encrypt1(Bin, CipherNum,"").
-
-%% encrypt1(Bin, CipherNum, Phrase) ->
-%% if CipherNum == ?SSH_CIPHER_NONE; Phrase == "" ->
-%% Bin;
-%% CipherNum == ?SSH_CIPHER_3DES ->
-%% <<K1:8/binary, K2:8/binary>> = erlang:md5(Phrase),
-%% K3 = K1,
-%% IV = <<0,0,0,0,0,0,0,0>>,
-%% Bin1 = crypto:des_cbc_encrypt(K1,IV,Bin),
-%% Bin2 = crypto:des_cbc_decrypt(K2,IV,Bin1),
-%% crypto:des_cbc_encrypt(K3,IV,Bin2)
-%% end.
-
-lookup_host_key_fd(Fd, Host, Alg) ->
- case io:get_line(Fd, '') of
- eof ->
- {error, not_found};
- Line ->
- case string:tokens(Line, " ") of
- [HostList, Alg, KeyData] ->
-%% io:format(" ~p lookup_host_key_fd: HostList ~p Alg ~p KeyData ~p\n",
-%% [Host, HostList, Alg, KeyData]),
- case lists:member(Host, string:tokens(HostList, ",")) of
- true ->
- decode_public_key_v2(ssh_bits:b64_decode(KeyData), Alg);
- false ->
- lookup_host_key_fd(Fd, Host, Alg)
- end;
- _ ->
- lookup_host_key_fd(Fd, Host, Alg)
- end
- end.
-
-
-
-%% del_key_fd(Fd, Host) ->
-%% del_key_fd(Fd, Host, 0, 0).
-
-%% del_key_fd(Fd, Host, ReadPos0, WritePos0) ->
-%% case io:get_line(Fd, '') of
-%% eof ->
-%% if ReadPos0 == WritePos0 ->
-%% ok;
-%% true ->
-%% file:truncate(Fd)
-%% end;
-%% Line ->
-%% {ok,ReadPos1} = file:position(Fd, cur),
-%% case string:tokens(Line, " ") of
-%% [HostList, _Type, _KeyData] ->
-%% case lists:member(Host, string:tokens(HostList, ",")) of
-%% true ->
-%% del_key_fd(Fd, Host, ReadPos1, WritePos0);
-%% false ->
-%% if ReadPos0 == WritePos0 ->
-%% del_key_fd(Fd, Host, ReadPos1, ReadPos1);
-%% true ->
-%% file:position(Fd, WritePos0),
-%% file:write(Fd, Line),
-%% {ok,WritePos1} = file:position(Fd,cur),
-%% del_key_fd(Fd, Host, ReadPos1, WritePos1)
-%% end
-%% end;
-%% _ ->
-%% if ReadPos0 == WritePos0 ->
-%% del_key_fd(Fd, Host, ReadPos1, ReadPos1);
-%% true ->
-%% file:position(Fd, WritePos0),
-%% file:write(Fd, Line),
-%% {ok,WritePos1} = file:position(Fd,cur),
-%% del_key_fd(Fd, Host, ReadPos1, WritePos1)
-%% end
-%% end
-%% end.
-
-
-add_key_fd(Fd, Host, Key) ->
- case Key#ssh_key.type of
- rsa ->
- {N,E} = Key#ssh_key.public,
- DK = ssh_bits:b64_encode(
- ssh_bits:encode(["ssh-rsa",E,N],
- [string,mpint,mpint])),
- file:write(Fd, [Host, " ssh-rsa ", DK, "\n"]);
- dsa ->
- {P,Q,G,Y} = Key#ssh_key.public,
- DK = ssh_bits:b64_encode(
- ssh_bits:encode(["ssh-dss",P,Q,G,Y],
- [string,mpint,mpint,mpint,mpint])),
- file:write(Fd, [Host, " ssh-dss ", DK, "\n"])
- end.
-
-
-%% read_pem(Cs, Type) ->
-%% case read_line(Cs) of
-%% {"-----BEGIN "++Rest,Cs1} ->
-%% case string:tokens(Rest, " ") of
-%% [Type, "PRIVATE", "KEY-----"] ->
-%% read_pem64(Cs1, [], Type);
-%% _ ->
-%% {error, bad_format}
-%% end;
-%% {"",Cs1} when Cs1 =/= "" ->
-%% read_pem(Cs1,Type);
-%% {_,""} ->
-%% {error, bad_format}
-%% end.
-
-%% read_pem64(Cs, Acc, Type) ->
-%% case read_line(Cs) of
-%% {"-----END "++Rest,_Cs1} ->
-%% case string:tokens(Rest, " ") of
-%% [Type, "PRIVATE", "KEY-----"] ->
-%% {ok,ssh_bits:b64_decode(append(reverse(Acc)))};
-%% Toks ->
-%% error_logger:format("ssh: TOKENS=~p\n", [Toks]),
-%% {error, bad_format}
-%% end;
-%% {B64, Cs1} when Cs1 =/= "" ->
-%% read_pem64(Cs1, [B64|Acc], Type);
-%% _What ->
-%% {error, bad_format}
-%% end.
-
-
-%% read_line(Cs) -> read_line(Cs,[]).
-%% read_line([$\r,$\n|T], Acc) -> {reverse(Acc), T};
-%% read_line([$\n|T], Acc) -> {reverse(Acc), T};
-%% read_line([C|T], Acc) -> read_line(T,[C|Acc]);
-%% read_line([], Acc) -> {reverse(Acc),[]}.
-
-lookup_user_key(User, Alg, Opts) ->
+lookup_user_key(Key, User, Alg, Opts) ->
SshDir = ssh_dir({remoteuser,User}, Opts),
- case lookup_user_key_f(User, SshDir, Alg, "authorized_keys", Opts) of
+ case lookup_user_key_f(Key, User, SshDir, Alg, "authorized_keys", Opts) of
{ok, Key} ->
{ok, Key};
_ ->
- lookup_user_key_f(User, SshDir, Alg, "authorized_keys2", Opts)
- end.
-
-lookup_user_key_f(_User, [], _Alg, _F, _Opts) ->
- {error, nouserdir};
-lookup_user_key_f(_User, nouserdir, _Alg, _F, _Opts) ->
- {error, nouserdir};
-lookup_user_key_f(_User, Dir, Alg, F, _Opts) ->
- FileName = filename:join(Dir, F),
- case file:open(FileName, [read]) of
- {ok, Fd} ->
- Res = lookup_user_key_fd(Fd, Alg),
- file:close(Fd),
- Res;
- {error, Reason} ->
- {error, {{openerr, Reason}, {file, FileName}}}
- end.
-
-lookup_user_key_fd(Fd, Alg) ->
- case io:get_line(Fd, '') of
- eof ->
- {error, not_found};
- Line ->
- case string:tokens(Line, " ") of
- [Alg, KeyData, _] ->
- %% io:format("lookup_user_key_fd: HostList ~p Alg ~p KeyData ~p\n",
- %% [HostList, Alg, KeyData]),
- decode_public_key_v2(ssh_bits:b64_decode(KeyData), Alg);
- _Other ->
- %%?dbg(false, "key_fd Other: ~w ~w\n", [Alg, _Other]),
- lookup_user_key_fd(Fd, Alg)
- end
+ lookup_user_key_f(Key, User, SshDir, Alg, "authorized_keys2", Opts)
end.
-encode_public_key(#ssh_key{type = rsa, public = {N, E}}) ->
- ssh_bits:encode(["ssh-rsa",E,N],
- [string,mpint,mpint]);
-encode_public_key(#ssh_key{type = dsa, public = {P,Q,G,Y}}) ->
- ssh_bits:encode(["ssh-dss",P,Q,G,Y],
- [string,mpint,mpint,mpint,mpint]).
-
%%
%% Utils
%%
@@ -537,11 +179,130 @@ ssh_dir(user, Opts) ->
ssh_dir(system, Opts) ->
proplists:get_value(system_dir, Opts, "/etc/ssh").
+
file_name(Type, Name, Opts) ->
FN = filename:join(ssh_dir(Type, Opts), Name),
- %%?dbg(?DBG_PATHS, "file_name: ~p\n", [FN]),
FN.
+
+
+%% in: "host" out: "host,1.2.3.4.
+add_ip(Host) ->
+ case inet:getaddr(Host, inet) of
+ {ok, Addr} ->
+ case ssh_connection:encode_ip(Addr) of
+ false -> Host;
+ IPString -> Host ++ "," ++ IPString
+ end;
+ _ -> Host
+ end.
+
+replace_localhost("localhost") ->
+ {ok, Hostname} = inet:gethostname(),
+ Hostname;
+replace_localhost(Host) ->
+ Host.
+
+do_lookup_host_key(Host, Alg, Opts) ->
+ case file:open(file_name(user, "known_hosts", Opts), [read, binary]) of
+ {ok, Fd} ->
+ Res = lookup_host_key_fd(Fd, Host, Alg),
+ file:close(Fd),
+ {ok, Res};
+ {error, enoent} -> {error, not_found};
+ Error -> Error
+ end.
+
+identity_key_filename("ssh-dss") ->
+ "id_dsa";
+identity_key_filename("ssh-rsa") ->
+ "id_rsa".
+
+identity_pass_phrase("ssh-dss") ->
+ dsa_pass_phrase;
+identity_pass_phrase('ssh-dss') ->
+ dsa_pass_phrase;
+identity_pass_phrase('ssh-rsa') ->
+ rsa_pass_phrase;
+identity_pass_phrase("ssh-rsa") ->
+ rsa_pass_phrase.
+
+lookup_host_key_fd(Fd, Host, KeyType) ->
+ case io:get_line(Fd, '') of
+ eof ->
+ {error, not_found};
+ Line ->
+ case public_key:ssh_decode(Line, known_hosts) of
+ [{Key, Attributes}] ->
+ handle_host(Fd, Host, proplists:get_value(hostnames, Attributes), Key, KeyType);
+ [] ->
+ lookup_host_key_fd(Fd, Host, KeyType)
+ end
+ end.
+
+handle_host(Fd, Host, HostList, Key, KeyType) ->
+ Host1 = host_name(Host),
+ case lists:member(Host1, HostList) and key_match(Key, KeyType) of
+ true ->
+ Key;
+ false ->
+ lookup_host_key_fd(Fd, Host, KeyType)
+ end.
+
+host_name(Atom) when is_atom(Atom) ->
+ atom_to_list(Atom);
+host_name(List) ->
+ List.
+
+key_match(#'RSAPublicKey'{}, "ssh-rsa") ->
+ true;
+key_match({_, #'Dss-Parms'{}}, "ssh-dss") ->
+ true;
+key_match(_, _) ->
+ false.
+
+add_key_fd(Fd, Host,Key) ->
+ SshBin = public_key:ssh_encode([{Key, [{hostnames, [Host]}]}], known_hosts),
+ file:write(Fd, SshBin).
+
+lookup_user_key_f(_, _User, [], _Alg, _F, _Opts) ->
+ {error, nouserdir};
+lookup_user_key_f(_, _User, nouserdir, _Alg, _F, _Opts) ->
+ {error, nouserdir};
+lookup_user_key_f(Key, _User, Dir, _Alg, F, _Opts) ->
+ FileName = filename:join(Dir, F),
+ case file:open(FileName, [read, binary]) of
+ {ok, Fd} ->
+ Res = lookup_user_key_fd(Fd, Key),
+ file:close(Fd),
+ Res;
+ {error, Reason} ->
+ {error, {{openerr, Reason}, {file, FileName}}}
+ end.
+
+lookup_user_key_fd(Fd, Key) ->
+ case io:get_line(Fd, '') of
+ eof ->
+ {error, not_found};
+ Line ->
+ case public_key:ssh_decode(Line, auth_keys) of
+ [{AuthKey, _}] ->
+ case is_auth_key(Key, AuthKey) of
+ true ->
+ {ok, Key};
+ false ->
+ lookup_user_key_fd(Fd, Key)
+ end;
+ [] ->
+ lookup_user_key_fd(Fd, Key)
+ end
+ end.
+
+is_auth_key(Key, Key) ->
+ true;
+is_auth_key(_,_) ->
+ false.
+
default_user_dir()->
{ok,[[Home|_]]} = init:get_argument(home),
UserDir = filename:join(Home, ".ssh"),
diff --git a/lib/ssh/src/ssh_key_api.erl b/lib/ssh/src/ssh_key_api.erl
new file mode 100644
index 0000000000..8085c12e21
--- /dev/null
+++ b/lib/ssh/src/ssh_key_api.erl
@@ -0,0 +1,45 @@
+%%
+%% %CopyrightBegin%
+%%
+%% 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
+%% 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(ssh_key_api).
+
+-include_lib("public_key/include/public_key.hrl").
+-include("ssh.hrl").
+
+-type ssh_algorithm() :: string().
+-type file_error() :: file:posix() | badarg | system_limit | terminated.
+
+-callback host_key(Algorithm :: ssh_algorithm(), Options :: list()) ->
+ {ok, [{public_key(), Attributes::list()}]} | public_key()
+ | {error, string()}.
+
+-callback user_key(Algorithm :: ssh_algorithm(), Options :: list()) ->
+ {ok, [{public_key(), Attributes::list()}]} | public_key()
+ | {error, string()}.
+
+-callback is_host_key(Key :: public_key(), PeerName :: string(),
+ Algorithm :: ssh_algorithm(), Options :: list()) ->
+ boolean().
+
+-callback add_host_key(Host :: string(), Key :: public_key(), Options :: list()) ->
+ ok | {error, file_error()}.
+
+-callback is_auth_key(Key :: public_key(), User :: string(),
+ Algorithm :: ssh_algorithm(), Options :: list()) ->
+ boolean().
diff --git a/lib/ssh/src/ssh_rsa.erl b/lib/ssh/src/ssh_rsa.erl
deleted file mode 100644
index 77c411b09f..0000000000
--- a/lib/ssh/src/ssh_rsa.erl
+++ /dev/null
@@ -1,298 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-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%
-%%
-
-%%
-
-%%% Description: rsa public-key sign and verify
-
--module(ssh_rsa).
-
--export([verify/3, sign/2]).
--export([alg_name/0]).
-
--include("ssh.hrl").
--include("PKCS-1.hrl").
-
-
--define(MGF(Seed,Len), mgf1((Seed),(Len))).
--define(HASH(X), crypto:sha((X))).
--define(HLen, 20).
-
-%% start() ->
-%% crypto:start().
-
-%% sign_file(File) ->
-%% start(),
-%% {ok,Bin} = file:read_file(File),
-%% {ok,Key} = ssh_file:private_host_rsa_key(user),
-%% sign(Key, Bin).
-
-%% verify_file(File, Sig) ->
-%% start(),
-%% {ok,Bin} = file:read_file(File),
-%% {ok,Key} = ssh_file:public_host_rsa_key(user),
-%% verify(Key, Bin, Sig).
-
-sign(Private,Mb) ->
- rsassa_pkcs1_v1_5_sign(Private,Mb).
-
-verify(Public,Mb,Sb) ->
- rsassa_pkcs1_v1_5_verify(Public,Mb,Sb).
-
-
-
-%% Integer to octet string
-i2osp(X, XLen) ->
- ssh_bits:i2bin(X, XLen).
-
-%% Octet string to Integer
-os2ip(X) ->
- ssh_bits:bin2i(X).
-
-%% decrypt1, M = message representative
-%% rsaep(#ssh_key { public={N,E}}, M) ->
-%% ?ssh_assert(M >= 0 andalso M =< N-1, out_of_range),
-%% ssh_math:ipow(M, E, N).
-
-%% encrypt1, C = cipher representative
-%% rsadp(#ssh_key { public={N,_}, private={_,D}}, C) ->
-%% ?ssh_assert(C >= 0 andalso C =< N-1, out_of_range),
-%% ssh_math:ipow(C, D, N).
-
-%% sign1, M = message representative
-rsasp1(#ssh_key { public={N,_}, private={_,D}}, M) ->
- ?ssh_assert((M >= 0 andalso M =< N-1), out_of_range),
- ssh_math:ipow(M, D, N).
-
-%% verify1, S =signature representative
-rsavp1(#ssh_key { public={N,E}}, S) ->
- ?ssh_assert(S >= 0 andalso S =< N-1, out_of_range),
- ssh_math:ipow(S, E, N).
-
-
-%% M messaage
-%% rsaes_oaep_encrypt(Public, M) ->
-%% rsaes_oaep_encrypt(Public, M, <<>>).
-
-%% rsaes_oaep_encrypt(Public=#ssh_key { public={N,_E}}, M, L) ->
-%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long),
-%% K = (ssh_bits:isize(N)+7) div 8,
-%% MLen = size(M),
-%% %% LLen = size(L),
-%% ?ssh_assert(MLen =< K - 2*?HLen - 2, message_to_long),
-%% LHash = ?HASH(L),
-%% PS = ssh_bits:fill_bits(K - MLen - 2*?HLen - 2, 0),
-%% DB = <<LHash/binary, PS/binary, 16#01, M/binary>>,
-%% Seed = ssh_bits:random(?HLen),
-%% DbMask = ?MGF(Seed, K - ?HLen - 1),
-%% MaskedDB = ssh_bits:xor_bits(DB, DbMask),
-%% SeedMask = ?MGF(MaskedDB, ?HLen),
-%% MaskedSeed = ssh_bits:xor_bits(Seed, SeedMask),
-%% EM = <<16#00, MaskedSeed/binary, MaskedDB/binary>>,
-%% Mc = os2ip(EM),
-%% C = rsaep(Public, Mc),
-%% i2osp(C, K).
-
-%% rsaes_oaep_decrypt(Key, C) ->
-%% rsaes_oaep_decrypt(Key, C, <<>>).
-
-%% rsaes_oaep_decrypt(Private=#ssh_key { public={N,_},private={_,_}},Cb,L) ->
-%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long),
-%% K = (ssh_bits:isize(N)+7) div 8,
-%% ?ssh_assert(K == 2*?HLen + 2, decryption_error),
-%% C = os2ip(Cb),
-%% M = rsadp(Private, C),
-%% EM = i2osp(M, K),
-%% LHash = ?HASH(L),
-%% MLen = K - ?HLen -1,
-%% case EM of
-%% <<16#00, MaskedSeed:?HLen/binary, MaskedDB:MLen>> ->
-%% SeedMask = ?MGF(MaskedDB, ?HLen),
-%% Seed = ssh_bits:xor_bits(MaskedSeed, SeedMask),
-%% DbMask = ?MGF(Seed, K - ?HLen - 1),
-%% DB = ssh_bits:xor_bits(MaskedDB, DbMask),
-%% PSLen = K - MLen - 2*?HLen - 2,
-%% case DB of
-%% <<LHash:?HLen, _PS:PSLen/binary, 16#01, M/binary>> ->
-%% M;
-%% _ ->
-%% exit(decryption_error)
-%% end;
-%% _ ->
-%% exit(decryption_error)
-%% end.
-
-
-%% rsaes_pkcs1_v1_5_encrypt(Public=#ssh_key { public={N,_}}, M) ->
-%% K = (ssh_bits:isize(N)+7) div 8,
-%% MLen = size(M),
-%% ?ssh_assert(MLen =< K - 11, message_to_long),
-%% PS = ssh_bits:random(K - MLen - 3),
-%% EM = <<16#00,16#02,PS/binary,16#00,M/binary>>,
-%% Mc = os2ip(EM),
-%% C = rsaep(Public, Mc),
-%% i2osp(C, K).
-
-
-%% rsaes_pkcs1_v1_5_decrypt(Private=#ssh_key { public={N,_},private={_,_}},
-%% Cb) ->
-%% K = (ssh_bits:isize(N)+7) div 8,
-%% CLen = size(Cb),
-%% ?ssh_assert(CLen == K andalso K >= 11, decryption_error),
-%% C = os2ip(Cb),
-%% M = rsadp(Private, C),
-%% EM = i2osp(M, K),
-%% PSLen = K - CLen - 3,
-%% case EM of
-%% <<16#00, 16#02, _PS:PSLen/binary, 16#00, M>> ->
-%% M;
-%% _ ->
-%% exit(decryption_error)
-%% end.
-
-%% rsassa_pss_sign(Private=#ssh_key { public={N,_},private={_,_}},Mb) ->
-%% ModBits = ssh_bits:isize(N),
-%% K = (ModBits+7) div 8,
-%% EM = emsa_pss_encode(Mb, ModBits - 1),
-%% M = os2ip(EM),
-%% S = rsasp1(Private, M),
-%% i2osp(S, K).
-
-%% rsassa_pss_verify(Public=#ssh_key { public={N,_E}},Mb,Sb) ->
-%% ModBits = ssh_bits:isize(N),
-%% K = (ModBits+7) div 8,
-%% ?ssh_assert(size(Sb) == K, invalid_signature),
-%% S = os2ip(Sb),
-%% M = rsavp1(Public,S),
-%% EMLen = (ModBits-1+7) div 8,
-%% EM = i2osp(M, EMLen),
-%% emsa_pss_verify(Mb, EM, ModBits-1).
-
-
-rsassa_pkcs1_v1_5_sign(Private=#ssh_key { public={N,_},private={_,_D}},Mb) ->
- K = (ssh_bits:isize(N)+7) div 8,
- EM = emsa_pkcs1_v1_5_encode(Mb, K),
- M = os2ip(EM),
- S = rsasp1(Private, M),
- i2osp(S, K).
-
-rsassa_pkcs1_v1_5_verify(Public=#ssh_key { public={N,_E}}, Mb, Sb) ->
- K = (ssh_bits:isize(N)+7) div 8,
- ?ssh_assert(size(Sb) == K, invalid_signature),
- S = os2ip(Sb),
- M = rsavp1(Public, S),
- EM = i2osp(M, K),
- %?dbg(true, "verify K=~p S=~w ~n#M=~w~n#EM=~w~n", [K, S, M, EM]),
- case emsa_pkcs1_v1_5_encode(Mb, K) of
- EM -> ok;
- _S ->
- {error, invalid_signature}
- end.
-
-
-emsa_pkcs1_v1_5_encode(M, EMLen) ->
- H = ?HASH(M),
- %% Must use speical xxNull types here!
- Alg = #'AlgorithmNull' { algorithm = ?'id-sha1',
- parameters = <<>> },
- {ok,TCode} = 'PKCS-1':encode('DigestInfoNull',
- #'DigestInfoNull'{ digestAlgorithm = Alg,
- digest = H }),
- T = list_to_binary(TCode),
- TLen = size(T),
- ?ssh_assert(EMLen >= TLen + 11, message_to_short),
- PS = ssh_bits:fill_bits(EMLen - TLen - 3, 16#ff),
- <<16#00, 16#01, PS/binary, 16#00, T/binary>>.
-
-
-%% emsa_pss_encode(M, EMBits) ->
-%% emsa_pss_encode(M, EMBits, 0).
-
-%% emsa_pss_encode(M, EMBits, SLen) ->
-%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long),
-%% EMLen = (EMBits + 7) div 8,
-%% MHash = ?HASH(M),
-%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, encoding_error),
-%% Salt = ssh_bits:random(SLen),
-%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
-%% MHash, Salt],
-%% H = ?HASH(M1),
-%% PS = ssh_bits:fill_bits(EMLen-SLen-?HLen-2, 0),
-%% DB = <<PS/binary, 16#01, Salt/binary>>,
-%% DbMask = ?MGF(H, EMLen - ?HLen -1),
-%% MaskedDB = ssh_bits:xor_bits(DB, DbMask),
-%% ZLen = 8*EMLen - EMBits,
-%% NZLen = (8 - (ZLen rem 8)) rem 8,
-%% <<_:ZLen, NZ:NZLen, MaskedDB1/binary>> = MaskedDB,
-%% MaskedDB2 = <<0:ZLen, NZ:NZLen, MaskedDB1/binary>>,
-%% <<MaskedDB2/binary, H/binary, 16#BC>>.
-
-
-%% emsa_pss_verify(M, EM, EMBits) ->
-%% emsa_pss_verify(M, EM, EMBits, 0).
-
-%% emsa_pss_verify(M, EM, EMBits, SLen) ->
-%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long),
-%% EMLen = (EMBits + 7) div 8,
-%% MHash = ?HASH(M),
-%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, inconsistent),
-%% MaskLen = (EMLen - ?HLen - 1)-1,
-%% ZLen = 8*EMLen - EMBits,
-%% NZLen = (8 - (ZLen rem 8)) rem 8,
-%% case EM of
-%% <<0:ZLen,Nz:NZLen,MaskedDB1:MaskLen/binary, H:?HLen/binary, 16#BC>> ->
-%% MaskedDB = <<0:ZLen,Nz:NZLen,MaskedDB1/binary>>,
-%% DbMask = ?MGF(H, EMLen - ?HLen - 1),
-%% DB = ssh_bits:xor_bits(MaskedDB, DbMask),
-%% PSLen1 = (EMLen - SLen - ?HLen - 2) - 1,
-%% PS = ssh_bits:fill_bits(PSLen1, 0),
-%% case DB of
-%% <<_:ZLen,0:NZLen,PS:PSLen1/binary,16#01,Salt:SLen/binary>> ->
-%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
-%% MHash, Salt],
-%% case ?HASH(M1) of
-%% H -> ok;
-%% _ -> exit(inconsistent)
-%% end;
-%% _ ->
-%% exit(inconsistent)
-%% end;
-%% _ ->
-%% exit(inconsistent)
-%% end.
-
-
-
-%% Mask generating function MGF1
-%% mgf1(MGFSeed, MaskLen) ->
-%% T = mgf1_loop(0, ((MaskLen + ?HLen -1) div ?HLen) - 1, MGFSeed, ""),
-%% <<R:MaskLen/binary, _/binary>> = T,
-%% R.
-
-%% mgf1_loop(Counter, N, _, T) when Counter > N ->
-%% list_to_binary(T);
-%% mgf1_loop(Counter, N, MGFSeed, T) ->
-%% C = i2osp(Counter, 4),
-%% mgf1_loop(Counter+1, N, MGFSeed, [T, ?HASH([MGFSeed, C])]).
-
-
-
-
-alg_name() ->
- "ssh-rsa".
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index da91817fd7..8cc414f83a 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. 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
@@ -231,8 +231,6 @@ handle_op(?SSH_FXP_REALPATH, ReqId,
case Res of
{ok, AbsPath} ->
NewAbsPath = chroot_filename(AbsPath, State),
- ?dbg(true, "handle_op ?SSH_FXP_REALPATH: RelPath=~p AbsPath=~p\n",
- [RelPath, NewAbsPath]),
XF = State#state.xf,
Attr = #ssh_xfer_attr{type=directory},
ssh_xfer:xf_send_name(XF, ReqId, NewAbsPath, Attr),
@@ -463,7 +461,6 @@ get_handle(Handles, BinHandle) ->
read_dir(State0 = #state{file_handler = FileMod, max_files = MaxLength, file_state = FS0},
XF, ReqId, Handle, RelPath, {cache, Files}) ->
AbsPath = relate_file_name(RelPath, State0),
- ?dbg(true, "read_dir: AbsPath=~p\n", [AbsPath]),
if
length(Files) > MaxLength ->
{ToSend, NewCache} = lists:split(MaxLength, Files),
@@ -484,7 +481,6 @@ read_dir(State0 = #state{file_handler = FileMod, max_files = MaxLength, file_sta
read_dir(State0 = #state{file_handler = FileMod, max_files = MaxLength, file_state = FS0},
XF, ReqId, Handle, RelPath, _Status) ->
AbsPath = relate_file_name(RelPath, State0),
- ?dbg(true, "read_dir: AbsPath=~p\n", [AbsPath]),
{Res, FS1} = FileMod:list_dir(AbsPath, FS0),
case Res of
{ok, Files} when MaxLength == 0 orelse MaxLength > length(Files) ->
@@ -516,7 +512,6 @@ get_attrs(_RelPath, [], _FileMod, FS, Acc) ->
{lists:reverse(Acc), FS};
get_attrs(RelPath, [F | Rest], FileMod, FS0, Acc) ->
Path = filename:absname(F, RelPath),
- ?dbg(true, "get_attrs fun: F=~p\n", [F]),
case FileMod:read_link_info(Path, FS0) of
{{ok, Info}, FS1} ->
Attrs = ssh_sftp:info_to_attr(Info),
@@ -560,7 +555,6 @@ stat(ReqId, RelPath, State0=#state{file_handler=FileMod,
file_state=FS0}, F) ->
AbsPath = relate_file_name(RelPath, State0),
XF = State0#state.xf,
- ?dbg(false, "stat: AbsPath=~p\n", [AbsPath]),
{Res, FS1} = FileMod:F(AbsPath, FS0),
State1 = State0#state{file_state = FS1},
case Res of
@@ -605,6 +599,8 @@ decode_4_access_flag(add_subdirectory) ->
[read];
decode_4_access_flag(append_data) ->
[append];
+decode_4_access_flag(write_attributes) ->
+ [write];
decode_4_access_flag(_) ->
[read].
@@ -619,8 +615,7 @@ open(Vsn, ReqId, Data, State) when Vsn =< 3 ->
<<?UINT32(BLen), BPath:BLen/binary, ?UINT32(PFlags),
_Attrs/binary>> = Data,
Path = binary_to_list(BPath),
- Flags = ssh_xfer:decode_open_flags(Vsn, PFlags) -- [creat, excl, trunc],
- ?dbg(true, "open: Flags=~p\n", [Flags]),
+ Flags = ssh_xfer:decode_open_flags(Vsn, PFlags),
do_open(ReqId, State, Path, Flags);
open(Vsn, ReqId, Data, State) when Vsn >= 4 ->
<<?UINT32(BLen), BPath:BLen/binary, ?UINT32(Access),
@@ -628,7 +623,6 @@ open(Vsn, ReqId, Data, State) when Vsn >= 4 ->
Path = binary_to_list(BPath),
FlagBits = ssh_xfer:decode_open_flags(Vsn, PFlags),
AcessBits = ssh_xfer:decode_ace_mask(Access),
- ?dbg(true, "open: Fl=~p\n", [FlagBits]),
%% TODO: This is to make sure the Access flags are not ignored
%% but this should be thought through better. This solution should
%% be considered a hack in order to buy some time. At least
@@ -638,15 +632,12 @@ open(Vsn, ReqId, Data, State) when Vsn >= 4 ->
AcessFlags = decode_4_acess(AcessBits),
Flags = lists:append(lists:umerge(
[[decode_4_flags(FlagBits)] | AcessFlags])),
-
- ?dbg(true, "open: Flags=~p\n", [Flags]),
-
do_open(ReqId, State, Path, Flags).
do_open(ReqId, State0, Path, Flags) ->
#state{file_handler = FileMod, file_state = FS0, root = Root} = State0,
XF = State0#state.xf,
- F = [raw, binary | Flags],
+ F = [binary | Flags],
%% case FileMod:is_dir(Path) of %% This is version 6 we still have 5
%% true ->
%% ssh_xfer:xf_send_status(State#state.xf, ReqId,
@@ -895,14 +886,11 @@ set_stat(Attr, Path,
State0 = #state{file_handler=FileMod, file_state=FS0}) ->
{DecodedAttr, _Rest} =
ssh_xfer:decode_ATTR((State0#state.xf)#ssh_xfer.vsn, Attr),
- ?dbg(true, "set_stat DecodedAttr=~p\n", [DecodedAttr]),
Info = ssh_sftp:attr_to_info(DecodedAttr),
{Res1, FS1} = FileMod:read_link_info(Path, FS0),
case Res1 of
{ok, OldInfo} ->
NewInfo = set_file_info(Info, OldInfo),
- ?dbg(true, "set_stat Path=~p\nInfo=~p\nOldInfo=~p\nNewInfo=~p\n",
- [Path, Info, OldInfo, NewInfo]),
{Res2, FS2} = FileMod:write_file_info(Path, NewInfo, FS1),
State1 = State0#state{file_state = FS2},
{Res2, State1};
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index de3e29e2f1..6140c87f6e 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -23,10 +23,11 @@
-module(ssh_transport).
--include("ssh_transport.hrl").
+-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/inet.hrl").
+-include("ssh_transport.hrl").
-include("ssh.hrl").
--include_lib("kernel/include/inet.hrl").
-export([connect/5, accept/4]).
-export([versions/2, hello_version_msg/1]).
@@ -38,17 +39,8 @@
handle_kex_dh_gex_group/2, handle_kex_dh_gex_reply/2,
handle_new_keys/2, handle_kex_dh_gex_request/2,
handle_kexdh_reply/2,
- unpack/3, decompress/2, ssh_packet/2, pack/2, msg_data/1]).
-
-%% debug flagso
--define(DBG_ALG, true).
--define(DBG_KEX, true).
--define(DBG_CRYPTO, false).
--define(DBG_PACKET, false).
--define(DBG_MESSAGE, true).
--define(DBG_BIN_MESSAGE, true).
--define(DBG_MAC, false).
--define(DBG_ZLIB, true).
+ unpack/3, decompress/2, ssh_packet/2, pack/2, msg_data/1,
+ sign/3, verify/4]).
versions(client, Options)->
Vsn = proplists:get_value(vsn, Options, ?DEFAULT_CLIENT_VERSION),
@@ -212,24 +204,24 @@ key_exchange_init_msg(Ssh0) ->
{SshPacket, Ssh} = ssh_packet(Msg, Ssh0),
{Msg, SshPacket, Ssh}.
-kex_init(#ssh{role = Role, opts = Opts}) ->
+kex_init(#ssh{role = Role, opts = Opts, available_host_keys = HostKeyAlgs}) ->
Random = ssh_bits:random(16),
Compression = case proplists:get_value(compression, Opts, none) of
zlib -> ["zlib", "none"];
none -> ["none", "zlib"]
end,
- kexinit_messsage(Role, Random, Compression).
+ kexinit_messsage(Role, Random, Compression, HostKeyAlgs).
key_init(client, Ssh, Value) ->
Ssh#ssh{c_keyinit = Value};
key_init(server, Ssh, Value) ->
Ssh#ssh{s_keyinit = Value}.
-kexinit_messsage(client, Random, Compression) ->
+kexinit_messsage(client, Random, Compression, HostKeyAlgs) ->
#ssh_msg_kexinit{
cookie = Random,
kex_algorithms = ["diffie-hellman-group1-sha1"],
- server_host_key_algorithms = ["ssh-rsa", "ssh-dss"],
+ server_host_key_algorithms = HostKeyAlgs,
encryption_algorithms_client_to_server = ["aes128-cbc","3des-cbc"],
encryption_algorithms_server_to_client = ["aes128-cbc","3des-cbc"],
mac_algorithms_client_to_server = ["hmac-sha1"],
@@ -240,11 +232,11 @@ kexinit_messsage(client, Random, Compression) ->
languages_server_to_client = []
};
-kexinit_messsage(server, Random, Compression) ->
+kexinit_messsage(server, Random, Compression, HostKeyAlgs) ->
#ssh_msg_kexinit{
cookie = Random,
kex_algorithms = ["diffie-hellman-group1-sha1"],
- server_host_key_algorithms = ["ssh-dss"],
+ server_host_key_algorithms = HostKeyAlgs,
encryption_algorithms_client_to_server = ["aes128-cbc","3des-cbc"],
encryption_algorithms_server_to_client = ["aes128-cbc","3des-cbc"],
mac_algorithms_client_to_server = ["hmac-sha1"],
@@ -300,7 +292,6 @@ install_messages('diffie-hellman-group-exchange-sha1') ->
key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) ->
{G, P} = dh_group1(),
{Private, Public} = dh_gen_key(G, P, 1024),
- %%?dbg(?DBG_KEX, "public: ~p~n", [Public]),
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0),
{ok, SshPacket,
Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}};
@@ -320,7 +311,6 @@ key_exchange_first_msg('diffie-hellman-group-exchange-sha1', Ssh0) ->
handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) ->
{G, P} = dh_group1(),
{Private, Public} = dh_gen_key(G, P, 1024),
- %%?dbg(?DBG_KEX, "public: ~p~n", [Public]),
K = ssh_math:ipow(E, Private, P),
{Key, K_S} = get_host_key(Ssh0),
H = kex_h(Ssh0, K_S, E, Public, K),
@@ -329,8 +319,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) ->
f = Public,
h_sig = H_SIG
}, Ssh0),
- %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]),
- %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]),
+
{ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}},
shared_secret = K,
exchanged_hash = H,
@@ -338,7 +327,6 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) ->
handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) ->
{Private, Public} = dh_gen_key(G,P,1024),
- %%?dbg(?DBG_KEX, "public: ~p ~n", [Public]),
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0),
{ok, SshPacket,
@@ -362,8 +350,7 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey, f = F,
#ssh{keyex_key = {{Private, Public}, {_G, P}}} = Ssh0) ->
K = ssh_math:ipow(F, Private, P),
H = kex_h(Ssh0, HostKey, Public, F, K),
- %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]),
- %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]),
+
case verify_host_key(Ssh0, HostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -396,8 +383,7 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey,
Ssh0) ->
K = ssh_math:ipow(F, Private, P),
H = kex_h(Ssh0, HostKey, Min, NBits, Max, P, G, Public, F, K),
- %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]),
- %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]),
+
case verify_host_key(Ssh0, HostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -423,83 +409,68 @@ sid(#ssh{session_id = Id}, _) ->
%%
get_host_key(SSH) ->
#ssh{key_cb = Mod, opts = Opts, algorithms = ALG} = SSH,
- Scope = proplists:get_value(key_scope, Opts, system),
- case ALG#alg.hkey of
- 'ssh-rsa' ->
- case Mod:private_host_rsa_key(Scope, Opts) of
- {ok,Key=#ssh_key { public={N,E}} } ->
- %%?dbg(true, "x~n", []),
- {Key,
- ssh_bits:encode(["ssh-rsa",E,N],[string,mpint,mpint])};
- Error ->
- %%?dbg(true, "y~n", []),
- exit(Error)
- end;
- 'ssh-dss' ->
- case Mod:private_host_dsa_key(Scope, Opts) of
- {ok,Key=#ssh_key { public={P,Q,G,Y}}} ->
- {Key, ssh_bits:encode(["ssh-dss",P,Q,G,Y],
- [string,mpint,mpint,mpint,mpint])};
- Error ->
- exit(Error)
- end;
- _ ->
- exit({error, bad_key_type})
+
+ case Mod:host_key(ALG#alg.hkey, Opts) of
+ {ok, #'RSAPrivateKey'{modulus = N, publicExponent = E} = Key} ->
+ {Key,
+ ssh_bits:encode(["ssh-rsa",E,N],[string,mpint,mpint])};
+ {ok, #'DSAPrivateKey'{y = Y, p = P, q = Q, g = G} = Key} ->
+ {Key, ssh_bits:encode(["ssh-dss",P,Q,G,Y],
+ [string,mpint,mpint,mpint,mpint])};
+ Result ->
+ exit({error, {Result, unsupported_key_type}})
end.
-sign_host_key(Ssh, Private, H) ->
- ALG = Ssh#ssh.algorithms,
- Module = case ALG#alg.hkey of
- 'ssh-rsa' ->
- ssh_rsa;
- 'ssh-dss' ->
- ssh_dsa
- end,
- case catch Module:sign(Private, H) of
- {'EXIT', Reason} ->
- error_logger:format("SIGN FAILED: ~p\n", [Reason]),
- {error, Reason};
- SIG ->
- ssh_bits:encode([Module:alg_name() ,SIG],[string,binary])
- end.
+sign_host_key(_Ssh, #'RSAPrivateKey'{} = Private, H) ->
+ Hash = sha, %% Option ?!
+ Signature = sign(H, Hash, Private),
+ ssh_bits:encode(["ssh-rsa", Signature],[string, binary]);
+sign_host_key(_Ssh, #'DSAPrivateKey'{} = Private, H) ->
+ Hash = sha, %% Option ?!
+ RawSignature = sign(H, Hash, Private),
+ ssh_bits:encode(["ssh-dss", RawSignature],[string, binary]).
verify_host_key(SSH, K_S, H, H_SIG) ->
ALG = SSH#ssh.algorithms,
case ALG#alg.hkey of
'ssh-rsa' ->
- case ssh_bits:decode(K_S,[string,mpint,mpint]) of
- ["ssh-rsa", E, N] ->
- ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
- Public = #ssh_key { type=rsa, public={N,E} },
- case catch ssh_rsa:verify(Public, H, SIG) of
- {'EXIT', Reason} ->
- error_logger:format("VERIFY FAILED: ~p\n", [Reason]),
- {error, bad_signature};
- ok ->
- known_host_key(SSH, Public, "ssh-rsa")
- end;
- _ ->
- {error, bad_format}
- end;
+ verify_host_key_rsa(SSH, K_S, H, H_SIG);
'ssh-dss' ->
- case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
- ["ssh-dss",P,Q,G,Y] ->
- ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
- Public = #ssh_key { type=dsa, public={P,Q,G,Y} },
- case catch ssh_dsa:verify(Public, H, SIG) of
- {'EXIT', Reason} ->
- error_logger:format("VERIFY FAILED: ~p\n", [Reason]),
- {error, bad_signature};
- ok ->
- known_host_key(SSH, Public, "ssh-dss")
- end;
- _ ->
- {error, bad_host_key_format}
- end;
+ verify_host_key_dss(SSH, K_S, H, H_SIG);
_ ->
{error, bad_host_key_algorithm}
end.
+verify_host_key_rsa(SSH, K_S, H, H_SIG) ->
+ case ssh_bits:decode(K_S,[string,mpint,mpint]) of
+ ["ssh-rsa", E, N] ->
+ ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
+ Public = #'RSAPublicKey'{publicExponent = E, modulus = N},
+ case verify(H, sha, SIG, Public) of
+ false ->
+ {error, bad_signature};
+ true ->
+ known_host_key(SSH, Public, "ssh-rsa")
+ end;
+ _ ->
+ {error, bad_format}
+ end.
+
+verify_host_key_dss(SSH, K_S, H, H_SIG) ->
+ case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
+ ["ssh-dss",P,Q,G,Y] ->
+ ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
+ Public = {Y, #'Dss-Parms'{p = P, q = Q, g = G}},
+ case verify(H, sha, SIG, Public) of
+ false ->
+ {error, bad_signature};
+ true ->
+ known_host_key(SSH, Public, "ssh-dss")
+ end;
+ _ ->
+ {error, bad_host_key_format}
+ end.
+
accepted_host(Ssh, PeerName, Opts) ->
case proplists:get_value(silently_accept_hosts, Opts, false) of
true ->
@@ -511,14 +482,10 @@ accepted_host(Ssh, PeerName, Opts) ->
known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh,
Public, Alg) ->
PeerName = peer_name(Peer),
- case Mod:lookup_host_key(PeerName, Alg, Opts) of
- {ok, Public} ->
+ case Mod:is_host_key(Public, PeerName, Alg, Opts) of
+ true ->
ok;
- {ok, BadPublic} ->
- error_logger:format("known_host_key: Public ~p BadPublic ~p\n",
- [Public, BadPublic]),
- {error, bad_public_key};
- {error, not_found} ->
+ false ->
case accepted_host(Ssh, PeerName, Opts) of
yes ->
Mod:add_host_key(PeerName, Public, Opts);
@@ -621,7 +588,6 @@ install_alg(SSH) ->
alg_setup(SSH) ->
ALG = SSH#ssh.algorithms,
- %%?dbg(?DBG_ALG, "ALG: setup ~p ~n", [ALG]),
SSH#ssh{kex = ALG#alg.kex,
hkey = ALG#alg.hkey,
encrypt = ALG#alg.encrypt,
@@ -638,7 +604,6 @@ alg_setup(SSH) ->
}.
alg_init(SSH0) ->
- %%?dbg(?DBG_ALG, "ALG: init~n", []),
{ok,SSH1} = send_mac_init(SSH0),
{ok,SSH2} = recv_mac_init(SSH1),
{ok,SSH3} = encrypt_init(SSH2),
@@ -648,7 +613,6 @@ alg_init(SSH0) ->
SSH6.
alg_final(SSH0) ->
- %%?dbg(?DBG_ALG, "ALG: final ~n", []),
{ok,SSH1} = send_mac_final(SSH0),
{ok,SSH2} = recv_mac_final(SSH1),
{ok,SSH3} = encrypt_final(SSH2),
@@ -669,19 +633,15 @@ select(CL, SL) ->
[] -> undefined;
[ALG|_] -> ALG
end,
- %%?dbg(?DBG_ALG, "ALG: select: ~p ~p = ~p~n", [CL, SL, C]),
C.
ssh_packet(#ssh_msg_kexinit{} = Msg, Ssh0) ->
BinMsg = ssh_bits:encode(Msg),
Ssh = key_init(Ssh0#ssh.role, Ssh0, BinMsg),
- %%?dbg(?DBG_MESSAGE, "SEND_MSG: ~p~n", [Msg]),
pack(BinMsg, Ssh);
ssh_packet(Msg, Ssh) ->
BinMsg = ssh_bits:encode(Msg),
- %%?dbg(?DBG_MESSAGE, "SEND_MSG: ~p~n", [Msg]),
- %%?dbg(?DBG_BIN_MESSAGE, "Encoded: ~p~n", [BinMsg]),
pack(BinMsg, Ssh).
pack(Data0, #ssh{encrypt_block_size = BlockSize,
@@ -732,17 +692,20 @@ msg_data(PacketData) ->
_:PaddingLen/binary>> = PacketData,
Data.
+sign(SigData, Hash, #'DSAPrivateKey'{} = Key) ->
+ DerSignature = public_key:sign(SigData, Hash, Key),
+ #'Dss-Sig-Value'{r = R, s = S} = public_key:der_decode('Dss-Sig-Value', DerSignature),
+ <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>;
+sign(SigData, Hash, Key) ->
+ public_key:sign(SigData, Hash, Key).
-%% Send a disconnect message
-%% terminate(S, SSH, Code, Message) ->
-%% M = #ssh_msg_disconnect{code=Code,
-%% description = Message,
-%% language = "en"},
-%% send_msg(S, SSH, M),
-%% gen_tcp:close(S),
-%% {error, M}.
+verify(PlainText, Hash, Sig, {_, #'Dss-Parms'{}} = Key) ->
+ <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>> = Sig,
+ Signature = public_key:der_encode('Dss-Sig-Value', #'Dss-Sig-Value'{r = R, s = S}),
+ public_key:verify(PlainText, Hash, Signature, Key);
+verify(PlainText, Hash, Sig, Key) ->
+ public_key:verify(PlainText, Hash, Sig, Key).
-
%% public key algorithms
%%
%% ssh-dss REQUIRED sign Raw DSS Key
@@ -761,9 +724,6 @@ msg_data(PacketData) ->
%%
%%
-
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Encryption
%%
@@ -833,19 +793,13 @@ encrypt(#ssh{encrypt = none} = Ssh, Data) ->
encrypt(#ssh{encrypt = '3des-cbc',
encrypt_keys = {K1,K2,K3},
encrypt_ctx = IV0} = Ssh, Data) ->
- %%?dbg(?DBG_CRYPTO, "encrypt: IV=~p K1=~p, K2=~p, K3=~p ~n",
- %% [IV0,K1,K2,K3]),
Enc = crypto:des3_cbc_encrypt(K1,K2,K3,IV0,Data),
- %%?dbg(?DBG_CRYPTO, "encrypt: ~p -> ~p ~n", [Data, Enc]),
IV = crypto:des_cbc_ivec(Enc),
{Ssh#ssh{encrypt_ctx = IV}, Enc};
encrypt(#ssh{encrypt = 'aes128-cbc',
encrypt_keys = K,
encrypt_ctx = IV0} = Ssh, Data) ->
- %%?dbg(?DBG_CRYPTO, "encrypt: IV=~p K=~p ~n",
- %% [IV0,K]),
Enc = crypto:aes_cbc_128_encrypt(K,IV0,Data),
- %%?dbg(?DBG_CRYPTO, "encrypt: ~p -> ~p ~n", [Data, Enc]),
IV = crypto:aes_cbc_ivec(Enc),
{Ssh#ssh{encrypt_ctx = IV}, Enc}.
@@ -893,18 +847,12 @@ decrypt(#ssh{decrypt = none} = Ssh, Data) ->
decrypt(#ssh{decrypt = '3des-cbc', decrypt_keys = Keys,
decrypt_ctx = IV0} = Ssh, Data) ->
{K1, K2, K3} = Keys,
- %%?dbg(?DBG_CRYPTO, "decrypt: IV=~p K1=~p, K2=~p, K3=~p ~n",
- %%[IV0,K1,K2,K3]),
Dec = crypto:des3_cbc_decrypt(K1,K2,K3,IV0,Data),
- %%?dbg(?DBG_CRYPTO, "decrypt: ~p -> ~p ~n", [Data, Dec]),
IV = crypto:des_cbc_ivec(Data),
{Ssh#ssh{decrypt_ctx = IV}, Dec};
decrypt(#ssh{decrypt = 'aes128-cbc', decrypt_keys = Key,
decrypt_ctx = IV0} = Ssh, Data) ->
- %%?dbg(?DBG_CRYPTO, "decrypt: IV=~p Key=~p ~n",
- %% [IV0,Key]),
Dec = crypto:aes_cbc_128_decrypt(Key,IV0,Data),
- %%?dbg(?DBG_CRYPTO, "decrypt: ~p -> ~p ~n", [Data, Dec]),
IV = crypto:aes_cbc_ivec(Data),
{Ssh#ssh{decrypt_ctx = IV}, Dec}.
@@ -936,7 +884,6 @@ compress(#ssh{compress = none} = Ssh, Data) ->
{Ssh, Data};
compress(#ssh{compress = zlib, compress_ctx = Context} = Ssh, Data) ->
Compressed = zlib:deflate(Context, Data, sync),
- %%?dbg(?DBG_ZLIB, "deflate: ~p -> ~p ~n", [Data, Compressed]),
{Ssh, list_to_binary(Compressed)}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -960,7 +907,6 @@ decompress(#ssh{decompress = none} = Ssh, Data) ->
{Ssh, Data};
decompress(#ssh{decompress = zlib, decompress_ctx = Context} = Ssh, Data) ->
Decompressed = zlib:inflate(Context, Data),
- %%?dbg(?DBG_ZLIB, "inflate: ~p -> ~p ~n", [Data, Decompressed]),
{Ssh, list_to_binary(Decompressed)}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1039,7 +985,6 @@ hash(SSH, Char, N, HASH) ->
K1 = HASH([K, H, Char, SessionID]),
Sz = N div 8,
<<Key:Sz/binary, _/binary>> = hash(K, H, K1, N-128, HASH),
- %%?dbg(?DBG_KEX, "Key ~s: ~s ~n", [Char, fmt_binary(Key, 16, 4)]),
Key.
hash(_K, _H, Ki, N, _HASH) when N =< 0 ->
@@ -1055,6 +1000,7 @@ kex_h(SSH, K_S, E, F, K) ->
[string,string,binary,binary,binary,
mpint,mpint,mpint]),
crypto:sha(L).
+
kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
L = if Min==-1; Max==-1 ->
@@ -1075,7 +1021,7 @@ kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
Prime, Gen, E,F,K], Ts)
end,
crypto:sha(L).
-
+
mac_key_size('hmac-sha1') -> 20*8;
mac_key_size('hmac-sha1-96') -> 20*8;
mac_key_size('hmac-md5') -> 16*8;
@@ -1105,9 +1051,6 @@ dh_gen_key(G, P, _Bits) ->
Public = ssh_math:ipow(G, Private, P),
{Private,Public}.
-%% trim(Str) ->
-%% lists:reverse(trim_head(lists:reverse(trim_head(Str)))).
-
trim_tail(Str) ->
lists:reverse(trim_head(lists:reverse(Str))).
@@ -1116,48 +1059,3 @@ trim_head([$\t|Cs]) -> trim_head(Cs);
trim_head([$\n|Cs]) -> trim_head(Cs);
trim_head([$\r|Cs]) -> trim_head(Cs);
trim_head(Cs) -> Cs.
-
-%% Retrieve session_id from ssh, needed by public-key auth
-%get_session_id(SSH) ->
-% {ok, SessionID} = call(SSH, get_session_id),
-
-%% DEBUG utils
-%% Format integers and binaries as hex blocks
-%%
-%% -ifdef(debug).
-%% fmt_binary(B, BlockSize, GroupSize) ->
-%% fmt_block(fmt_bin(B), BlockSize, GroupSize).
-
-%% fmt_block(Bin, BlockSize, GroupSize) ->
-%% fmt_block(Bin, BlockSize, 0, GroupSize).
-
-
-%% fmt_block(Bin, 0, _I, _G) ->
-%% binary_to_list(Bin);
-%% fmt_block(Bin, Sz, G, G) when G =/= 0 ->
-%% ["~n#" | fmt_block(Bin, Sz, 0, G)];
-%% fmt_block(Bin, Sz, I, G) ->
-%% case Bin of
-%% <<Block:Sz/binary, Tail/binary>> ->
-%% if Tail == <<>> ->
-%% [binary_to_list(Block)];
-%% true ->
-%% [binary_to_list(Block), " " | fmt_block(Tail, Sz, I+1, G)]
-%% end;
-%% <<>> ->
-%% [];
-%% _ ->
-%% [binary_to_list(Bin)]
-%% end.
-
-%% %% Format integer or binary as hex
-%% fmt_bin(X) when integer(X) ->
-%% list_to_binary(io_lib:format("~p", [X]));
-%% fmt_bin(X) when binary(X) ->
-%% Sz = size(X)*8,
-%% <<Y:Sz/unsigned-big>> = X,
-%% %%Fmt = "~"++integer_to_list(size(X)*2)++"~p",
-%% list_to_binary(io_lib:format("~p", [Y])).
-
-%% -endif.
-
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index c9631a73b1..d5b6dd03d1 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. 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
@@ -298,8 +298,6 @@ xf_send_names(#ssh_xfer{cm = CM, channel = Channel, vsn = Vsn},
Size = 1 + 4 + 4 + Len,
ToSend = [<<?UINT32(Size), ?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(Count)>>,
Data],
- %%?dbg(true, "xf_send_names: Size=~p size(ToSend)=~p\n",
- %% [Size, size(list_to_binary(ToSend))]),
ssh_connection:send(CM, Channel, ToSend).
xf_send_status(XF, ReqId, ErrorCode) ->
@@ -353,7 +351,6 @@ xf_reply(_XF, <<?SSH_FXP_DATA, ?UINT32(ReqID),
{data, ReqID, Data};
xf_reply(XF, <<?SSH_FXP_NAME, ?UINT32(ReqID),
?UINT32(Count), AData/binary>>) ->
- %%?dbg(true, "xf_reply ?SSH_FXP_NAME: AData=~p\n", [AData]),
{name, ReqID, decode_names(XF#ssh_xfer.vsn, Count, AData)};
xf_reply(XF, <<?SSH_FXP_ATTRS, ?UINT32(ReqID),
AData/binary>>) ->
@@ -579,7 +576,6 @@ encode_attr_flags(Vsn, Flags) ->
end, Flags).
encode_file_type(Type) ->
- %%?dbg(true, "encode_file_type(~p)\n", [Type]),
case Type of
regular -> ?SSH_FILEXFER_TYPE_REGULAR;
directory -> ?SSH_FILEXFER_TYPE_DIRECTORY;
@@ -660,15 +656,12 @@ encode_ATTR(Vsn, A) ->
{extended, A#ssh_xfer_attr.extensions}],
0, []),
Type = encode_file_type(A#ssh_xfer_attr.type),
- %%?dbg(true, "encode_ATTR: Vsn=~p A=~p As=~p Flags=~p Type=~p",
- %% [Vsn, A, As, Flags, Type]),
Result = list_to_binary([?uint32(Flags),
if Vsn >= 5 ->
?byte(Type);
true ->
(<<>>)
end, As]),
- %% ?dbg(true, " Result=~p\n", [Result]),
Result.
@@ -722,7 +715,6 @@ encode_As(_Vsn, [], Flags, Acc) ->
decode_ATTR(Vsn, <<?UINT32(Flags), Tail/binary>>) ->
- %%?dbg(true, "decode_ATTR: Vsn=~p Flags=~p Tail=~p\n", [Vsn, Flags, Tail]),
{Type,Tail2} =
if Vsn =< 3 ->
{?SSH_FILEXFER_TYPE_UNKNOWN, Tail};
@@ -751,7 +743,6 @@ decode_ATTR(Vsn, <<?UINT32(Flags), Tail/binary>>) ->
Tail2).
decode_As(Vsn, [{AName, AField}|As], R, Flags, Tail) ->
- %%?dbg(false, "decode_As: Vsn=~p AName=~p AField=~p Flags=~p Tail=~p\n", [Vsn, AName, AField, Flags, Tail]),
case AName of
size when ?is_set(?SSH_FILEXFER_ATTR_SIZE, Flags) ->
<<?UINT64(X), Tail2/binary>> = Tail,
@@ -762,7 +753,6 @@ decode_As(Vsn, [{AName, AField}|As], R, Flags, Tail) ->
ownergroup when ?is_set(?SSH_FILEXFER_ATTR_OWNERGROUP, Flags),Vsn>=5 ->
<<?UINT32(Len), Bin:Len/binary, Tail2/binary>> = Tail,
X = binary_to_list(Bin),
- %%?dbg(true, "ownergroup X=~p\n", [X]),
decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2);
permissions when ?is_set(?SSH_FILEXFER_ATTR_PERMISSIONS,Flags),Vsn>=5->
@@ -824,13 +814,11 @@ decode_names(Vsn, I, <<?UINT32(Len), FileName:Len/binary,
?UINT32(LLen), _LongName:LLen/binary,
Tail/binary>>) when Vsn =< 3 ->
Name = binary_to_list(FileName),
- %%?dbg(true, "decode_names: ~p\n", [Name]),
{A, Tail2} = decode_ATTR(Vsn, Tail),
[{Name, A} | decode_names(Vsn, I-1, Tail2)];
decode_names(Vsn, I, <<?UINT32(Len), FileName:Len/binary,
Tail/binary>>) when Vsn >= 4 ->
Name = binary_to_list(FileName),
- %%?dbg(true, "decode_names: ~p\n", [Name]),
{A, Tail2} = decode_ATTR(Vsn, Tail),
[{Name, A} | decode_names(Vsn, I-1, Tail2)].
@@ -839,8 +827,6 @@ encode_names(Vsn, NamesAndAttrs) ->
encode_name(Vsn, {Name,Attr}, Len) when Vsn =< 3 ->
NLen = length(Name),
- %%?dbg(true, "encode_name: Vsn=~p Name=~p Attr=~p\n",
- %% [Vsn, Name, Attr]),
EncAttr = encode_ATTR(Vsn, Attr),
ALen = size(EncAttr),
NewLen = Len + NLen*2 + 4 + 4 + ALen,
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 1820924ed6..145d5d2ad6 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-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,6 @@ VSN=$(GS_VSN)
MODULES= \
ssh_test_lib \
- ssh_SUITE \
ssh_basic_SUITE \
ssh_to_openssh_SUITE \
ssh_sftp_SUITE \
diff --git a/lib/ssh/test/ssh_SUITE.erl b/lib/ssh/test/ssh_SUITE.erl
deleted file mode 100644
index 953c9080f9..0000000000
--- a/lib/ssh/test/ssh_SUITE.erl
+++ /dev/null
@@ -1,72 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-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%
-%%
-
-%%
-%%%----------------------------------------------------------------
-%%% Purpose:ssh application test suite.
-%%%-----------------------------------------------------------------
--module(ssh_SUITE).
--include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
-
-% Default timetrap timeout (set in init_per_testcase).
--define(default_timeout, ?t:minutes(1)).
--define(application, ssh).
-
-% Test server specific exports
--export([all/0,groups/0,init_per_group/2,end_per_group/2]).
--export([init_per_testcase/2, end_per_testcase/2]).
-
-% Test cases must be exported.
--export([app_test/1]).
--define(cases, [app_test]).
-
-%%
-%% all/1
-%%
-all() ->
- [app_test].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-end_per_testcase(_Case, Config) ->
- Dog=?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-%
-% Test cases starts here.
-%
-app_test(suite) ->
- [];
-app_test(doc) ->
- ["Application consistency test."];
-app_test(Config) when is_list(Config) ->
- ?t:app_test(?application),
- ok.
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 5ea0d98980..9c13180159 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_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
@@ -41,9 +41,6 @@
init_per_suite(Config) ->
case catch crypto:start() of
ok ->
- Dir = ?config(priv_dir, Config),
- {ok, _} = ssh_test_lib:get_id_keys(Dir),
- ssh_test_lib:make_dsa_files(Config),
Config;
_Else ->
{skip, "Crypto could not be started!"}
@@ -55,10 +52,9 @@ init_per_suite(Config) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
-end_per_suite(Config) ->
- Dir = ?config(priv_dir, Config),
+end_per_suite(_Config) ->
+ ssh:stop(),
crypto:stop(),
- ssh_test_lib:remove_id_keys(Dir),
ok.
%%--------------------------------------------------------------------
@@ -75,7 +71,6 @@ end_per_suite(Config) ->
%% Description: Initialization before each test case
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
- ssh_test_lib:known_hosts(backup),
ssh:start(),
Config.
@@ -87,9 +82,16 @@ init_per_testcase(_TestCase, Config) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, _Config) ->
+
+end_per_testcase(TestCase, Config) when TestCase == server_password_option;
+ TestCase == server_userpassword_option ->
+ UserDir = filename:join(?config(priv_dir, Config), nopubkey),
+ ssh_test_lib:del_dirs(UserDir),
+ end_per_testcase(Config);
+end_per_testcase(TestCase, Config) ->
+ end_per_testcase(Config).
+end_per_testcase(_Config) ->
ssh:stop(),
- ssh_test_lib:known_hosts(restore),
ok.
%%--------------------------------------------------------------------
@@ -101,31 +103,72 @@ end_per_testcase(_TestCase, _Config) ->
%% Description: Returns a list of all test cases in this test suite
%%--------------------------------------------------------------------
all() ->
- [exec, exec_compressed, shell, daemon_already_started,
- server_password_option, server_userpassword_option,
- known_hosts].
+ [app_test,
+ {group, dsa_key},
+ {group, rsa_key},
+ {group, dsa_pass_key},
+ {group, rsa_pass_key},
+ daemon_already_started,
+ server_password_option, server_userpassword_option].
groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
+ [{dsa_key, [], [exec, exec_compressed, shell, known_hosts]},
+ {rsa_key, [], [exec, exec_compressed, shell, known_hosts]},
+ {dsa_pass_key, [], [pass_phrase]},
+ {rsa_pass_key, [], [pass_phrase]}
+ ].
+
+init_per_group(dsa_key, Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa(DataDir, PrivDir),
+ Config;
+init_per_group(rsa_key, Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_rsa(DataDir, PrivDir),
+ Config;
+init_per_group(rsa_pass_key, Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_rsa_pass_pharse(DataDir, PrivDir, "Password"),
+ [{pass_phrase, {rsa_pass_phrase, "Password"}}| Config];
+init_per_group(dsa_pass_key, Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa_pass_pharse(DataDir, PrivDir, "Password"),
+ [{pass_phrase, {dsa_pass_phrase, "Password"}}| Config];
+init_per_group(_, Config) ->
+ Config.
-end_per_group(_GroupName, Config) ->
- Config.
+end_per_group(dsa_key, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(PrivDir),
+ Config;
+end_per_group(rsa_key, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_rsa(PrivDir),
+ Config;
+end_per_group(dsa_pass_key, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(PrivDir),
+ Config;
+end_per_group(rsa_pass_key, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_rsa(PrivDir),
+ Config;
+end_per_group(_, Config) ->
+ Config.
%% Test cases starts here.
%%--------------------------------------------------------------------
-sign_and_verify_rsa(doc) ->
- ["Test api function ssh:sign_data and ssh:verify_data"];
-
-sign_and_verify_rsa(suite) ->
+app_test(suite) ->
[];
-sign_and_verify_rsa(Config) when is_list(Config) ->
- Data = ssh:sign_data(<<"correct data">>, "ssh-rsa"),
- ok = ssh:verify_data(<<"correct data">>, Data, "ssh-rsa"),
- {error,invalid_signature} = ssh:verify_data(<<"incorrect data">>, Data,"ssh-rsa").
-
+app_test(doc) ->
+ ["Application consistency test."];
+app_test(Config) when is_list(Config) ->
+ ?t:app_test(ssh),
+ ok.
exec(doc) ->
["Test api function ssh_connection:exec"];
@@ -135,11 +178,15 @@ exec(suite) ->
exec(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- SystemDir = ?config(data_dir, Config),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
ConnectionRef =
ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
{user_interaction, false}]),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
success = ssh_connection:exec(ConnectionRef, ChannelId0,
@@ -177,13 +224,16 @@ exec_compressed(suite) ->
exec_compressed(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- SystemDir = ?config(data_dir, Config),
- {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
{compression, zlib},
{failfun, fun ssh_test_lib:failfun/2}]),
ConnectionRef =
ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
{user_interaction, false}]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
success = ssh_connection:exec(ConnectionRef, ChannelId,
@@ -208,13 +258,15 @@ shell(suite) ->
shell(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- SystemDir = ?config(data_dir, Config),
- {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
test_server:sleep(500),
IO = ssh_test_lib:start_io_server(),
- Shell = ssh_test_lib:start_shell(Port, IO),
+ Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
receive
ErlShellStart ->
test_server:format("Erlang shell start: ~p~n", [ErlShellStart])
@@ -278,9 +330,13 @@ daemon_already_started(suite) ->
daemon_already_started(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+
{Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
{error, eaddrinuse} = ssh_test_lib:daemon(Port, [{system_dir, SystemDir},
+ {user_dir, UserDir},
{failfun,
fun ssh_test_lib:failfun/2}]),
ssh:stop_daemon(Pid).
@@ -291,9 +347,12 @@ server_password_option(doc) ->
server_password_option(suite) ->
[];
server_password_option(Config) when is_list(Config) ->
- UserDir = ?config(data_dir, Config), % to make sure we don't use
- SysDir = ?config(data_dir, Config), % public-key-auth
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
{password, "morot"}]),
ConnectionRef =
@@ -321,9 +380,12 @@ server_userpassword_option(doc) ->
server_userpassword_option(suite) ->
[];
server_userpassword_option(Config) when is_list(Config) ->
- UserDir = ?config(data_dir, Config), % to make sure we don't use
- SysDir = ?config(data_dir, Config), % public-key-auth
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, PrivDir},
{user_passwords, [{"vego", "morot"}]}]),
ConnectionRef =
@@ -362,16 +424,16 @@ known_hosts(suite) ->
[];
known_hosts(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
- UserDir = ?config(priv_dir, Config),
-
- {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ PrivDir = ?config(priv_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{user_dir, PrivDir},{system_dir, SystemDir},
{failfun, fun ssh_test_lib:failfun/2}]),
- KnownHosts = filename:join(UserDir, "known_hosts"),
+ KnownHosts = filename:join(PrivDir, "known_hosts"),
file:delete(KnownHosts),
{error, enoent} = file:read_file(KnownHosts),
ConnectionRef =
- ssh_test_lib:connect(Host, Port, [{user_dir, UserDir},
+ ssh_test_lib:connect(Host, Port, [{user_dir, PrivDir},
{user_interaction, false},
silently_accept_hosts]),
{ok, _Channel} = ssh_connection:session_channel(ConnectionRef, infinity),
@@ -382,7 +444,30 @@ known_hosts(Config) when is_list(Config) ->
[HostAndIp, Alg, _KeyData] = string:tokens(Line, " "),
[Host, _Ip] = string:tokens(HostAndIp, ","),
"ssh-" ++ _ = Alg,
- ssh:stop_daemon(Pid).
+ ssh:stop_daemon(Pid).
+
+pass_phrase(doc) ->
+ ["Test that we can use keyes protected by pass phrases"];
+
+pass_phrase(suite) ->
+ [];
+
+pass_phrase(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+ PhraseArg = ?config(pass_phrase, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ PhraseArg,
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+ {ok, _ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
%% Internal functions
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_dsa b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa
new file mode 100644
index 0000000000..d306f8b26e
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
+APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
+/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
+kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
+JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
+OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
+uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
+Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
+ZU8w8Q+H7z0j+a+70x2iAw==
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa
new file mode 100644
index 0000000000..9d7e0dd5fb
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU
+DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl
+zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB
+AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V
+TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3
+CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK
+SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p
+z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd
+WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39
+sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3
+xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ
+dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x
+ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak=
+-----END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index c96b6de3ea..7644db155d 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.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
@@ -24,14 +24,12 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
-include_lib("kernel/include/file.hrl").
% Default timetrap timeout
-define(default_timeout, ?t:minutes(1)).
--define(SFPD_PORT, 9999).
-define(USER, "Alladin").
-define(PASSWD, "Sesame").
@@ -46,18 +44,12 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- case {catch crypto:start(),catch ssh:start()} of
- {ok,ok} ->
- Dir = ?config(priv_dir, Config),
- {ok, _} = ssh_test_lib:get_id_keys(Dir),
- ssh_test_lib:make_dsa_files(Config),
+ case (catch crypto:start()) of
+ ok ->
+ ssh:start(),
Config;
- {ok,_} ->
- {skip,"Could not start ssh!"};
- {_,ok} ->
- {skip,"Could not start crypto!"};
- {_,_} ->
- {skip,"Could not start crypto and ssh!"}
+ _ ->
+ {skip,"Could not start crypto!"}
end.
%%--------------------------------------------------------------------
@@ -67,9 +59,8 @@ init_per_suite(Config) ->
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
end_per_suite(Config) ->
+ ssh:stop(),
crypto:stop(),
- Dir = ?config(priv_dir, Config),
- ssh_test_lib:remove_id_keys(Dir),
Config.
%%--------------------------------------------------------------------
@@ -90,27 +81,30 @@ init_per_testcase(_Case, Config) ->
TmpConfig0 = lists:keydelete(watchdog, 1, Config),
TmpConfig = lists:keydelete(sftp, 1, TmpConfig0),
Dog = test_server:timetrap(?default_timeout),
- Dir = ?config(priv_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
SysDir = ?config(data_dir, Config),
Host = ssh_test_lib:hostname(),
- Sftp = case (catch ssh_sftp:start_channel(Host,
- [{user_dir, Dir},
- {user_interaction, false},
+ %% Run test against openssh server if available
+ Sftp = case (catch ssh_sftp:start_channel(Host,
+ [{user_interaction, false},
{silently_accept_hosts, true}])) of
{ok, ChannelPid, Connection} ->
+ test_server:format("Running against openssh"),
{ChannelPid, Connection};
- _Error ->
- {_Sftpd, _Host, _Port} =
- ssh_test_lib:daemon(Host, ?SFPD_PORT,
- [{system_dir, SysDir},
+ _Error -> %% Start own sftp
+ test_server:format("Running against erlang ssh"),
+ {_Sftpd, Host1, Port} =
+ ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, PrivDir},
{user_passwords,
[{?USER, ?PASSWD}]},
{failfun,
fun ssh_test_lib:failfun/2}]),
- Result = (catch ssh_sftp:start_channel(Host, ?SFPD_PORT,
+ Result = (catch ssh_sftp:start_channel(Host1, Port,
[{user, ?USER},
{password, ?PASSWD},
+ {user_dir, PrivDir},
{user_interaction, false},
{silently_accept_hosts, true}])),
{ok, ChannelPid, Connection} = Result,
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa
deleted file mode 100644
index 7e3f885f5d..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICWwIBAAKBgQDLKYTdRnGzphcN+pF8UuI3sYB7rxZUHbOT87K3vh8XOLkDOsS3
-8VREtNS8Wb3uYXsRtyDoUvrLIDnyllOfJSDupWLr4ibckUZd/nhFAaC6WryVmH6k
-GlQLLp9KU+vcn2DwYeo14gbwHYDB3pmv4CWAlnO1m/BkX4aLz1zC314OkQIBIwKB
-gD/Z2UzboBPjvhpWEHeHw3CW3zzQoJ4X9pw2peH57IOkHOPCA0/A3/hWFvleCH4e
-owWRU3w3ViKVGYbBh/7RJ5rllN+ENUmVn536srJTxLKUtvb5jRGj3W6EWgAGHSUB
-hm83Kt9Lb5hprL7dPrNGvSseBm/LQSfBQ4vUUyiVRKGPAkEA/rPxWoLdBBP+FZtE
-fGzz9izPM6Fe6o8ZGNZIlRBProOhgEvvIqdgzQWObgLVVrw+M/YApPpiYS3PEmWj
-b2b+jwJBAMwyYeL6coKTl8swDu8HvLnshgUFJFTtHhOTXsKtXQNI1b24xhUrB3Sb
-X8fmoByyRNRpOfvg4Jdqi3Z6KfIcsN8CQQDEfC83McBw3DkJWoVKCugVrYnmACSm
-USH9N5cT6AL0VupNB2C0VTwL37cEaJXyc/V4ipLIaWHV8CNl9qKmZWVJAkEAurG4
-lQI8zyfbPW3EgsU+1d+QeZ5NGnJkpC73jWtNudwxIn0M4CdXRgpmMxwAGjyWs5No
-Nr75OfsDKn5SPHIAywJAKrtONlOizgDiG3EvAXZlwFtOb+HkQ7lrFwczrQu9m7yi
-brSAcnTrLKI6CrR33b/QJLvb9C/HTEZojFABGq8M7A==
------END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub
deleted file mode 100644
index 77f57de4af..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAyymE3UZxs6YXDfqRfFLiN7GAe68WVB2zk/Oyt74fFzi5AzrEt/FURLTUvFm97mF7Ebcg6FL6yyA58pZTnyUg7qVi6+Im3JFGXf54RQGgulq8lZh+pBpUCy6fSlPr3J9g8GHqNeIG8B2Awd6Zr+AlgJZztZvwZF+Gi89cwt9eDpE= jakob@balin
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl
index bfe54a3e75..6e4480ee9d 100644
--- a/lib/ssh/test/ssh_sftpd_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_SUITE.erl
@@ -1,7 +1,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
@@ -53,16 +53,18 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- case {catch ssh:stop(),catch crypto:start()} of
- {ok,ok} ->
- ssh_test_lib:make_dsa_files(Config),
+ case (catch crypto:start()) of
+ ok ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa(DataDir, PrivDir),
+ %% to make sure we don't use public-key-auth
+ %% this should be tested by other test suites
+ UserDir = filename:join(?config(priv_dir, Config), nopubkey),
+ file:make_dir(UserDir),
Config;
- {ok,_} ->
- {skip,"Could not start ssh!"};
- {_,ok} ->
- {skip,"Could not start crypto!"};
- {_,_} ->
- {skip,"Could not start crypto and ssh!"}
+ _ ->
+ {skip,"Could not start crypto!"}
end.
%%--------------------------------------------------------------------
@@ -71,7 +73,12 @@ init_per_suite(Config) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ SysDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(SysDir),
+ UserDir = filename:join(?config(priv_dir, Config), nopubkey),
+ file:del_dir(UserDir),
+ ssh:stop(),
crypto:stop(),
ok.
@@ -91,15 +98,18 @@ end_per_suite(_Config) ->
init_per_testcase(TestCase, Config) ->
ssh:start(),
prep(Config),
- SysDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ClientUserDir = filename:join(PrivDir, nopubkey),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+
{ok, Sftpd} =
- ssh_sftpd:listen(?SFPD_PORT, [{system_dir, SysDir},
+ ssh_sftpd:listen(?SFPD_PORT, [{system_dir, SystemDir},
+ {user_dir, PrivDir},
{user_passwords,[{?USER, ?PASSWD}]},
{pwdfun, fun(_,_) -> true end}]),
Cm = ssh_test_lib:connect(?SFPD_PORT,
- [{system_dir, SysDir},
- {user_dir, SysDir},
+ [{user_dir, ClientUserDir},
{user, ?USER}, {password, ?PASSWD},
{user_interaction, false},
{silently_accept_hosts, true},
@@ -542,7 +552,7 @@ set_attributes(Config) when is_list(Config) ->
{ok, FileInfo} = file:read_file_info(FileName),
OrigPermissions = FileInfo#file_info.mode,
- Permissions = 8#400, %% User read-only
+ Permissions = 8#600, %% User read-write-only
Flags = ?SSH_FILEXFER_ATTR_PERMISSIONS,
diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/id_dsa b/lib/ssh/test/ssh_sftpd_SUITE_data/id_dsa
new file mode 100644
index 0000000000..d306f8b26e
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_SUITE_data/id_dsa
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
+APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
+/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
+kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
+JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
+OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
+uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
+Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
+ZU8w8Q+H7z0j+a+70x2iAw==
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
index 2209af05d5..4c469ed5f7 100644
--- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl
+++ b/lib/ssh/test/ssh_sftpd_erlclient_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
@@ -28,7 +28,6 @@
-include_lib("kernel/include/file.hrl").
--define(SSHD_PORT, 9999).
-define(USER, "Alladin").
-define(PASSWD, "Sesame").
-define(SSH_MAX_PACKET_SIZE, 32768).
@@ -48,13 +47,14 @@ init_per_suite(Config) ->
case catch crypto:start() of
ok ->
DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"),
c:c(FileAlt),
FileName = filename:join(DataDir, "test.txt"),
{ok, FileInfo} = file:read_file_info(FileName),
ok = file:write_file_info(FileName,
FileInfo#file_info{mode = 8#400}),
- ssh_test_lib:make_dsa_files(Config),
+ ssh_test_lib:setup_dsa(DataDir, PrivDir),
Config;
_Else ->
{skip,"Could not start ssh!"}
@@ -66,7 +66,11 @@ init_per_suite(Config) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ UserDir = filename:join(?config(priv_dir, Config), nopubkey),
+ file:del_dir(UserDir),
+ SysDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(SysDir),
crypto:stop(),
ok.
@@ -85,7 +89,8 @@ end_per_suite(_Config) ->
%%--------------------------------------------------------------------
init_per_testcase(TestCase, Config) ->
ssh:start(),
- DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ SystemDir = filename:join(PrivDir, system),
Options =
case atom_to_list(TestCase) of
@@ -93,50 +98,39 @@ init_per_testcase(TestCase, Config) ->
Spec =
ssh_sftpd:subsystem_spec([{file_handler,
ssh_sftpd_file_alt}]),
- [{user_passwords,[{?USER, ?PASSWD}]},
- {pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ [{system_dir, SystemDir},
+ {user_dir, PrivDir},
{subsystems, [Spec]}];
"root_dir" ->
Privdir = ?config(priv_dir, Config),
Root = filename:join(Privdir, root),
file:make_dir(Root),
Spec = ssh_sftpd:subsystem_spec([{root,Root}]),
- [{user_passwords,[{?USER, ?PASSWD}]},
- {pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ [{system_dir, SystemDir},
+ {user_dir, PrivDir},
{subsystems, [Spec]}];
"list_dir_limited" ->
Spec =
ssh_sftpd:subsystem_spec([{max_files,1}]),
- [{user_passwords,[{?USER, ?PASSWD}]},
- {pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ [{system_dir, SystemDir},
+ {user_dir, PrivDir},
{subsystems, [Spec]}];
_ ->
- [{user_passwords,[{?USER, ?PASSWD}]},
- {pwdfun, fun(_,_) -> true end},
- {user_dir, DataDir},
- {system_dir, DataDir}]
+ [{user_dir, PrivDir},
+ {system_dir, SystemDir}]
end,
- {Sftpd, Host, _Port} = ssh_test_lib:daemon(any, ?SSHD_PORT, Options),
+ {Sftpd, Host, Port} = ssh_test_lib:daemon(Options),
{ok, ChannelPid, Connection} =
- ssh_sftp:start_channel(Host, ?SSHD_PORT,
+ ssh_sftp:start_channel(Host, Port,
[{silently_accept_hosts, true},
- {user, ?USER}, {password, ?PASSWD},
- {pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ {user_dir, PrivDir},
{timeout, 30000}]),
TmpConfig = lists:keydelete(sftp, 1, Config),
NewConfig = lists:keydelete(sftpd, 1, TmpConfig),
- [{sftp, {ChannelPid, Connection}}, {sftpd, Sftpd} | NewConfig].
+ [{port, Port}, {sftp, {ChannelPid, Connection}}, {sftpd, Sftpd} | NewConfig].
%%--------------------------------------------------------------------
%% Function: end_per_testcase(TestCase, Config) -> _
@@ -216,6 +210,8 @@ quit_OTP_6349(suite) ->
quit_OTP_6349(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
FileName = filename:join(DataDir, "test.txt"),
+ UserDir = ?config(priv_dir, Config),
+ Port = ?config(port, Config),
{Sftp, _} = ?config(sftp, Config),
@@ -226,11 +222,10 @@ quit_OTP_6349(Config) when is_list(Config) ->
Host = ssh_test_lib:hostname(),
timer:sleep(5000),
- {ok, NewSftp, _Conn} = ssh_sftp:start_channel(Host, ?SSHD_PORT,
+ {ok, NewSftp, _Conn} = ssh_sftp:start_channel(Host, Port,
[{silently_accept_hosts, true},
{pwdfun, fun(_,_) -> true end},
- {system_dir, DataDir},
- {user_dir, DataDir},
+ {user_dir, UserDir},
{user, ?USER}, {password, ?PASSWD}]),
{ok, <<_/binary>>} = ssh_sftp:read_file(NewSftp, FileName),
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_dsa b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_dsa
new file mode 100644
index 0000000000..d306f8b26e
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_dsa
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
+APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
+/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
+kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
+JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
+OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
+uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
+Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
+ZU8w8Q+H7z0j+a+70x2iAw==
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 425fae22c1..26bbdf5c5c 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -68,15 +68,14 @@ daemon(Host, Port, Options) ->
Error
end.
-
-
+start_shell(Port, IOServer, UserDir) ->
+ spawn_link(?MODULE, init_shell, [Port, IOServer, [{user_dir, UserDir}]]).
start_shell(Port, IOServer) ->
- spawn_link(?MODULE, init_shell, [Port, IOServer]).
+ spawn_link(?MODULE, init_shell, [Port, IOServer, []]).
-init_shell(Port, IOServer) ->
+init_shell(Port, IOServer, UserDir) ->
Host = hostname(),
- UserDir = get_user_dir(),
Options = [{user_interaction, false}, {silently_accept_hosts,
true}] ++ UserDir,
group_leader(IOServer, self()),
@@ -95,13 +94,10 @@ init_io_server(TestCase) ->
loop_io_server(TestCase, Buff0) ->
receive
{input, TestCase, Line} ->
- %io:format("~p~n",[{input, TestCase, Line}]),
loop_io_server(TestCase, Buff0 ++ [Line]);
{io_request, From, ReplyAs, Request} ->
- %io:format("request -> ~p~n",[Request]),
{ok, Reply, Buff} = io_request(Request, TestCase, From,
ReplyAs, Buff0),
- %io:format("reply -> ~p~n",[Reply]),
io_reply(From, ReplyAs, Reply),
loop_io_server(TestCase, Buff);
{'EXIT',_, _} ->
@@ -139,12 +135,18 @@ reply(TestCase, Result) ->
receive_exec_result(Msg) ->
test_server:format("Expect data! ~p", [Msg]),
receive
+ {ssh_cm,_,{data,_,1, Data}} ->
+ test_server:format("StdErr: ~p~n", [Data]),
+ receive_exec_result(Msg);
Msg ->
test_server:format("1: Collected data ~p", [Msg]),
expected;
Other ->
+ test_server:format("Other ~p", [Other]),
{unexpected_msg, Other}
end.
+
+
receive_exec_end(ConnectionRef, ChannelId) ->
Eof = {ssh_cm, ConnectionRef, {eof, ChannelId}},
ExitStatus = {ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}},
@@ -181,27 +183,21 @@ inet_port()->
gen_tcp:close(Socket),
Port.
-
-%% copy private keys to given dir from ~/.ssh
-get_id_keys(DstDir) ->
- 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_id_keys(Dir) ->
- file:delete(filename:join(Dir, "id_rsa")),
- file:delete(filename:join(Dir, "id_dsa")).
-
-copyfile(SrcDir, DstDir, Fn) ->
- file:copy(filename:join(SrcDir, Fn),
- filename:join(DstDir, Fn)).
-
+setup_ssh_auth_keys(RSAFile, DSAFile, Dir) ->
+ Entries = ssh_file_entry(RSAFile) ++ ssh_file_entry(DSAFile),
+ AuthKeys = public_key:ssh_encode(Entries , auth_keys),
+ AuthKeysFile = filename:join(Dir, "authorized_keys"),
+ file:write_file(AuthKeysFile, AuthKeys).
+
+ssh_file_entry(PubFile) ->
+ case file:read_file(PubFile) of
+ {ok, Ssh} ->
+ [{Key, _}] = public_key:ssh_decode(Ssh, public_key),
+ [{Key, [{comment, "Test"}]}];
+ _ ->
+ []
+ end.
+
failfun(_User, {authmethod,none}) ->
ok;
failfun(User, Reason) ->
@@ -222,463 +218,123 @@ known_hosts(BR) ->
file:rename(B, KnownHosts)
end.
-
-get_user_dir() ->
- case os:type() of
- {win32, _} ->
- [{user_dir, filename:join([os:getenv("HOME"), ".ssh"])}];
- _ ->
- []
- end.
-
-
-make_dsa_cert_files(Config) ->
- make_dsa_cert_files("", Config).
-
-make_dsa_cert_files(RoleStr, Config) ->
-
- CaInfo = {CaCert, _} = make_cert([{key, dsa}]),
- {Cert, CertKey} = make_cert([{key, dsa}, {issuer, CaInfo}]),
- CaCertFile = filename:join([?config(data_dir, Config),
- RoleStr, "dsa_cacerts.pem"]),
- CertFile = filename:join([?config(data_dir, Config),
- RoleStr, "dsa_cert.pem"]),
- KeyFile = filename:join([?config(data_dir, Config),
- RoleStr, "dsa_key.pem"]),
+setup_dsa(DataDir, UserDir) ->
+ file:copy(filename:join(DataDir, "id_dsa"), filename:join(UserDir, "id_dsa")),
+ System = filename:join(UserDir, "system"),
+ file:make_dir(System),
+ file:copy(filename:join(DataDir, "ssh_host_dsa_key"), filename:join(System, "ssh_host_dsa_key")),
+ file:copy(filename:join(DataDir, "ssh_host_dsa_key.pub"), filename:join(System, "ssh_host_dsa_key.pub")),
+ setup_dsa_known_host(DataDir, UserDir),
+ setup_dsa_auth_keys(DataDir, UserDir).
- der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]),
- der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]),
- der_to_pem(KeyFile, [CertKey]),
- {CaCertFile, CertFile, KeyFile}.
-
-make_dsa_files(Config) ->
- make_dsa_files(Config, rfc4716_public_key).
-make_dsa_files(Config, Type) ->
- {DSA, EncodedKey} = ssh_test_lib: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},
+setup_rsa(DataDir, UserDir) ->
+ file:copy(filename:join(DataDir, "id_rsa"), filename:join(UserDir, "id_rsa")),
+ System = filename:join(UserDir, "system"),
+ file:make_dir(System),
+ file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key")),
+ file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key.pub")),
+ setup_rsa_known_host(DataDir, UserDir),
+ setup_rsa_auth_keys(DataDir, UserDir).
+
+clean_dsa(UserDir) ->
+ del_dirs(filename:join(UserDir, "system")),
+ file:delete(filename:join(UserDir,"id_dsa")),
+ file:delete(filename:join(UserDir,"known_hosts")),
+ file:delete(filename:join(UserDir,"authorized_keys")).
+
+clean_rsa(UserDir) ->
+ del_dirs(filename:join(UserDir, "system")),
+ file:delete(filename:join(UserDir,"id_rsa")),
+ file:delete(filename:join(UserDir,"known_hosts")),
+ file:delete(filename:join(UserDir,"authorized_keys")).
+
+setup_dsa_pass_pharse(DataDir, UserDir, Phrase) ->
+ {ok, KeyBin} = file:read_file(filename:join(DataDir, "id_dsa")),
+ setup_pass_pharse(KeyBin, filename:join(UserDir, "id_dsa"), Phrase),
+ System = filename:join(UserDir, "system"),
+ file:make_dir(System),
+ file:copy(filename:join(DataDir, "ssh_host_dsa_key"), filename:join(System, "ssh_host_dsa_key")),
+ file:copy(filename:join(DataDir, "ssh_host_dsa_key.pub"), filename:join(System, "ssh_host_dsa_key.pub")),
+ setup_dsa_known_host(DataDir, UserDir),
+ setup_dsa_auth_keys(DataDir, UserDir).
+
+setup_rsa_pass_pharse(DataDir, UserDir, Phrase) ->
+ {ok, KeyBin} = file:read_file(filename:join(DataDir, "id_rsa")),
+ setup_pass_pharse(KeyBin, filename:join(UserDir, "id_rsa"), Phrase),
+ System = filename:join(UserDir, "system"),
+ file:make_dir(System),
+ file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key")),
+ file:copy(filename:join(DataDir, "ssh_host_rsa_key.pub"), filename:join(System, "ssh_host_rsa_key.pub")),
+ setup_rsa_known_host(DataDir, UserDir),
+ setup_rsa_auth_keys(DataDir, UserDir).
+
+setup_pass_pharse(KeyBin, OutFile, Phrase) ->
+ [{KeyType, _,_} = Entry0] = public_key:pem_decode(KeyBin),
+ Key = public_key:pem_entry_decode(Entry0),
+ Salt = crypto:rand_bytes(8),
+ Entry = public_key:pem_entry_encode(KeyType, Key,
+ {{"DES-CBC", Salt}, Phrase}),
+ Pem = public_key:pem_encode([Entry]),
+ file:write_file(OutFile, Pem).
+
+setup_dsa_known_host(SystemDir, UserDir) ->
+ {ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_dsa_key.pub")),
+ [{Key, _}] = public_key:ssh_decode(SshBin, public_key),
+ setup_known_hosts(Key, UserDir).
+
+setup_rsa_known_host(SystemDir, UserDir) ->
+ {ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_rsa_key.pub")),
+ [{Key, _}] = public_key:ssh_decode(SshBin, public_key),
+ setup_known_hosts(Key, UserDir).
+
+setup_known_hosts(Key, UserDir) ->
{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}],
-
+ HostNames = [{hostnames,[Hostname, IP]}],
+ KnownHosts = [{Key, HostNames}],
KnownHostsEnc = public_key:ssh_encode(KnownHosts, known_hosts),
- KnownHosts = public_key:ssh_decode(KnownHostsEnc, known_hosts),
-
- PublicKeyEnc = public_key:ssh_encode(PublicKey, Type),
-% PublicKey = public_key:ssh_decode(PublicKeyEnc, 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(UserDir, "known_hosts"),
+ file:write_file(KHFile, KnownHostsEnc).
- 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.
-
-%%--------------------------------------------------------------------
-%% Create and return a der encoded certificate
-%% Option Default
-%% -------------------------------------------------------
-%% digest sha1
-%% validity {date(), date() + week()}
-%% version 3
-%% subject [] list of the following content
-%% {name, Name}
-%% {email, Email}
-%% {city, City}
-%% {state, State}
-%% {org, Org}
-%% {org_unit, OrgUnit}
-%% {country, Country}
-%% {serial, Serial}
-%% {title, Title}
-%% {dnQualifer, DnQ}
-%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
-%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
-%%
-%%
-%% (OBS: The generated keys are for testing only)
-%% make_cert([{::atom(), ::term()}]) -> {Cert::binary(), Key::binary()}
-%%--------------------------------------------------------------------
-make_cert(Opts) ->
- SubjectPrivateKey = get_key(Opts),
- {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts),
- Cert = public_key:pkix_sign(TBSCert, IssuerKey),
- true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok
- {Cert, encode_key(SubjectPrivateKey)}.
-
-%%--------------------------------------------------------------------
-%% Writes cert files in Dir with FileName and FileName ++ Suffix
-%% write_cert(::string(), ::string(), {Cert,Key}) -> ok
-%%--------------------------------------------------------------------
-write_cert(Dir, FileName, Suffix, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) ->
- ok = der_to_pem(filename:join(Dir, FileName),
- [{'Certificate', Cert, not_encrypted}]),
- ok = der_to_pem(filename:join(Dir, FileName ++ Suffix), [Key]).
-
-%%--------------------------------------------------------------------
-%% Creates a rsa key (OBS: for testing only)
-%% the size are in bytes
-%% gen_rsa(::integer()) -> {::atom(), ::binary(), ::opaque()}
-%%--------------------------------------------------------------------
-gen_rsa(Size) when is_integer(Size) ->
- Key = gen_rsa2(Size),
- {Key, encode_key(Key)}.
-
-%%--------------------------------------------------------------------
-%% 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)}.
-
-%%--------------------------------------------------------------------
-%% Verifies cert signatures
-%% verify_signature(::binary(), ::tuple()) -> ::boolean()
-%%--------------------------------------------------------------------
-verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
- Key = decode_key(DerKey),
- case Key of
- #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} ->
- public_key:pkix_verify(DerEncodedCert,
- #'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
- #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-get_key(Opts) ->
- case proplists:get_value(key, Opts) of
- undefined -> make_key(rsa, Opts);
- rsa -> make_key(rsa, Opts);
- dsa -> make_key(dsa, Opts);
- Key ->
- Password = proplists:get_value(password, Opts, no_passwd),
- decode_key(Key, Password)
- end.
-
-decode_key({Key, Pw}) ->
- decode_key(Key, Pw);
-decode_key(Key) ->
- decode_key(Key, no_passwd).
-
-
-decode_key(#'RSAPublicKey'{} = Key,_) ->
- Key;
-decode_key(#'RSAPrivateKey'{} = Key,_) ->
- Key;
-decode_key(#'DSAPrivateKey'{} = Key,_) ->
- Key;
-decode_key(PemEntry = {_,_,_}, Pw) ->
- public_key:pem_entry_decode(PemEntry, Pw);
-decode_key(PemBin, Pw) ->
- [KeyInfo] = public_key:pem_decode(PemBin),
- decode_key(KeyInfo, Pw).
-
-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}.
-
-make_tbs(SubjectKey, Opts) ->
- Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
-
- IssuerProp = proplists:get_value(issuer, Opts, true),
- {Issuer, IssuerKey} = issuer(IssuerProp, Opts, SubjectKey),
-
- {Algo, Parameters} = sign_algorithm(IssuerKey, Opts),
-
- SignAlgo = #'SignatureAlgorithm'{algorithm = Algo,
- parameters = Parameters},
- Subject = case IssuerProp of
- true -> %% Is a Root Ca
- Issuer;
- _ ->
- subject(proplists:get_value(subject, Opts),false)
- end,
-
- {#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1,
- signature = SignAlgo,
- issuer = Issuer,
- validity = validity(Opts),
- subject = Subject,
- subjectPublicKeyInfo = publickey(SubjectKey),
- version = Version,
- extensions = extensions(Opts)
- }, IssuerKey}.
-
-issuer(true, Opts, SubjectKey) ->
- %% Self signed
- {subject(proplists:get_value(subject, Opts), true), SubjectKey};
-issuer({Issuer, IssuerKey}, _Opts, _SubjectKey) when is_binary(Issuer) ->
- {issuer_der(Issuer), decode_key(IssuerKey)};
-issuer({File, IssuerKey}, _Opts, _SubjectKey) when is_list(File) ->
- {ok, [{cert, Cert, _}|_]} = pem_to_der(File),
- {issuer_der(Cert), decode_key(IssuerKey)}.
-
-issuer_der(Issuer) ->
- Decoded = public_key:pkix_decode_cert(Issuer, otp),
- #'OTPCertificate'{tbsCertificate=Tbs} = Decoded,
- #'OTPTBSCertificate'{subject=Subject} = Tbs,
- Subject.
-
-subject(undefined, IsRootCA) ->
- User = if IsRootCA -> "RootCA"; true -> os:getenv("USER") end,
- Opts = [{email, User ++ "@erlang.org"},
- {name, User},
- {city, "Stockholm"},
- {country, "SE"},
- {org, "erlang"},
- {org_unit, "testing dep"}],
- subject(Opts);
-subject(Opts, _) ->
- subject(Opts).
-
-subject(SubjectOpts) when is_list(SubjectOpts) ->
- Encode = fun(Opt) ->
- {Type,Value} = subject_enc(Opt),
- [#'AttributeTypeAndValue'{type=Type, value=Value}]
- end,
- {rdnSequence, [Encode(Opt) || Opt <- SubjectOpts]}.
-
-%% Fill in the blanks
-subject_enc({name, Name}) -> {?'id-at-commonName', {printableString, Name}};
-subject_enc({email, Email}) -> {?'id-emailAddress', Email};
-subject_enc({city, City}) -> {?'id-at-localityName', {printableString, City}};
-subject_enc({state, State}) -> {?'id-at-stateOrProvinceName', {printableString, State}};
-subject_enc({org, Org}) -> {?'id-at-organizationName', {printableString, Org}};
-subject_enc({org_unit, OrgUnit}) -> {?'id-at-organizationalUnitName', {printableString, OrgUnit}};
-subject_enc({country, Country}) -> {?'id-at-countryName', Country};
-subject_enc({serial, Serial}) -> {?'id-at-serialNumber', Serial};
-subject_enc({title, Title}) -> {?'id-at-title', {printableString, Title}};
-subject_enc({dnQualifer, DnQ}) -> {?'id-at-dnQualifier', DnQ};
-subject_enc(Other) -> Other.
-
-
-extensions(Opts) ->
- case proplists:get_value(extensions, Opts, []) of
- false ->
- asn1_NOVALUE;
- Exts ->
- lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)])
- end.
-
-default_extensions(Exts) ->
- Def = [{key_usage,undefined},
- {subject_altname, undefined},
- {issuer_altname, undefined},
- {basic_constraints, default},
- {name_constraints, undefined},
- {policy_constraints, undefined},
- {ext_key_usage, undefined},
- {inhibit_any, undefined},
- {auth_key_id, undefined},
- {subject_key_id, undefined},
- {policy_mapping, undefined}],
- Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end,
- Exts ++ lists:foldl(Filter, Def, Exts).
-
-extension({_, undefined}) -> [];
-extension({basic_constraints, Data}) ->
- case Data of
- default ->
- #'Extension'{extnID = ?'id-ce-basicConstraints',
- extnValue = #'BasicConstraints'{cA=true},
- critical=true};
- false ->
- [];
- Len when is_integer(Len) ->
- #'Extension'{extnID = ?'id-ce-basicConstraints',
- extnValue = #'BasicConstraints'{cA=true, pathLenConstraint=Len},
- critical=true};
+setup_dsa_auth_keys(Dir, UserDir) ->
+ {ok, Pem} = file:read_file(filename:join(Dir, "id_dsa")),
+ DSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))),
+ 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},
+ setup_auth_keys([{{PKey, Dss}, [{comment, "Test"}]}], UserDir).
+
+setup_rsa_auth_keys(Dir, UserDir) ->
+ {ok, Pem} = file:read_file(filename:join(Dir, "id_rsa")),
+ RSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))),
+ #'RSAPrivateKey'{publicExponent = E, modulus = N} = RSA,
+ PKey = #'RSAPublicKey'{publicExponent = E, modulus = N},
+ setup_auth_keys([{ PKey, [{comment, "Test"}]}], UserDir).
+
+setup_auth_keys(Keys, Dir) ->
+ AuthKeys = public_key:ssh_encode(Keys, auth_keys),
+ AuthKeysFile = filename:join(Dir, "authorized_keys"),
+ file:write_file(AuthKeysFile, AuthKeys).
+
+
+del_dirs(Dir) ->
+ case file:list_dir(Dir) of
+ {ok, []} ->
+ file:del_dir(Dir);
+ {ok, Files} ->
+ lists:foreach(fun(File) ->
+ FullPath = filename:join(Dir,File),
+ case filelib:is_dir(FullPath) of
+ true ->
+ del_dirs(FullPath),
+ file:del_dir(FullPath);
+ false ->
+ file:delete(FullPath)
+ end
+ end, Files);
_ ->
- #'Extension'{extnID = ?'id-ce-basicConstraints',
- extnValue = Data}
- end;
-extension({Id, Data, Critical}) ->
- #'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
-
-
-publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
- Public = #'RSAPublicKey'{modulus=N, publicExponent=E},
- Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
- subjectPublicKey = Public};
-publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
- Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
- parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
-
-validity(Opts) ->
- DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
- DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7),
- {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}),
- Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end,
- #'Validity'{notBefore={generalTime, Format(DefFrom)},
- notAfter ={generalTime, Format(DefTo)}}.
-
-sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
- Type = case proplists:get_value(digest, Opts, sha1) of
- sha1 -> ?'sha1WithRSAEncryption';
- sha512 -> ?'sha512WithRSAEncryption';
- sha384 -> ?'sha384WithRSAEncryption';
- sha256 -> ?'sha256WithRSAEncryption';
- md5 -> ?'md5WithRSAEncryption';
- md2 -> ?'md2WithRSAEncryption'
- end,
- {Type, 'NULL'};
-sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
-
-make_key(rsa, _Opts) ->
- %% (OBS: for testing only)
- gen_rsa2(64);
-make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% RSA key generation (OBS: for testing only)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53,
- 47,43,41,37,31,29,23,19,17,13,11,7,5,3]).
-
-gen_rsa2(Size) ->
- P = prime(Size),
- Q = prime(Size),
- N = P*Q,
- Tot = (P - 1) * (Q - 1),
- [E|_] = lists:dropwhile(fun(Candidate) -> (Tot rem Candidate) == 0 end, ?SMALL_PRIMES),
- {D1,D2} = extended_gcd(E, Tot),
- D = erlang:max(D1,D2),
- case D < E of
- true ->
- gen_rsa2(Size);
- false ->
- {Co1,Co2} = extended_gcd(Q, P),
- Co = erlang:max(Co1,Co2),
- #'RSAPrivateKey'{version = 'two-prime',
- modulus = N,
- publicExponent = E,
- privateExponent = D,
- prime1 = P,
- prime2 = Q,
- exponent1 = D rem (P-1),
- exponent2 = D rem (Q-1),
- coefficient = Co
- }
+ ok
end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 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.
-
-extended_gcd(A, B) ->
- case A rem B of
- 0 ->
- {0, 1};
- N ->
- {X, Y} = extended_gcd(B, N),
- {Y, X-Y*(A div B)}
- end.
-
-pem_to_der(File) ->
- {ok, PemBin} = file:read_file(File),
- public_key:pem_decode(PemBin).
-
-der_to_pem(File, Entries) ->
- PemBin = public_key:pem_encode(Entries),
- file:write_file(File, PemBin).
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index f959d50484..dfe526564d 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_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
@@ -42,8 +42,12 @@
init_per_suite(Config) ->
case catch crypto:start() of
ok ->
- ssh_test_lib:make_dsa_files(Config),
- Config;
+ case gen_tcp:connect("localhost", 22, []) of
+ {error,econnrefused} ->
+ {skip,"No openssh deamon"};
+ _ ->
+ Config
+ end;
_Else ->
{skip,"Could not start crypto!"}
end.
@@ -100,26 +104,38 @@ all() ->
false ->
{skip, "openSSH not installed on host"};
_ ->
- [erlang_shell_client_openssh_server,
- erlang_client_openssh_server_exec,
- erlang_client_openssh_server_exec_compressed,
- erlang_server_openssh_client_exec,
- erlang_server_openssh_client_exec_compressed,
- erlang_client_openssh_server_setenv,
- erlang_client_openssh_server_publickey_rsa,
- erlang_client_openssh_server_publickey_dsa,
- erlang_server_openssh_client_pulic_key_dsa,
- erlang_client_openssh_server_password]
+ [{group, erlang_client},
+ {group, erlang_server}
+ ]
end.
groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
+ [{erlang_client, [], [erlang_shell_client_openssh_server,
+ erlang_client_openssh_server_exec,
+ erlang_client_openssh_server_exec_compressed,
+ erlang_client_openssh_server_setenv,
+ erlang_client_openssh_server_publickey_rsa,
+ erlang_client_openssh_server_publickey_dsa,
+ erlang_client_openssh_server_password]},
+ {erlang_server, [], [erlang_server_openssh_client_exec,
+ erlang_server_openssh_client_exec_compressed,
+ erlang_server_openssh_client_pulic_key_dsa]}
+ ].
+
+init_per_group(erlang_server, Config) ->
+ DataDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa_known_host(DataDir, UserDir),
+ Config;
+init_per_group(_, Config) ->
+ Config.
-end_per_group(_GroupName, Config) ->
- Config.
+end_per_group(erlang_server, Config) ->
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(UserDir),
+ Config;
+end_per_group(_, Config) ->
+ Config.
%% TEST cases starts here.
%%--------------------------------------------------------------------
@@ -229,7 +245,9 @@ erlang_server_openssh_client_exec(suite) ->
erlang_server_openssh_client_exec(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
-
+ PrivDir = ?config(priv_dir, Config),
+ KnownHosts = filename:join(PrivDir, "known_hosts"),
+
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{failfun, fun ssh_test_lib:failfun/2}]),
@@ -237,7 +255,10 @@ erlang_server_openssh_client_exec(Config) when is_list(Config) ->
test_server:sleep(500),
Cmd = "ssh -p " ++ integer_to_list(Port) ++
- " -o StrictHostKeyChecking=no "++ Host ++ " 1+1.",
+ " -o UserKnownHostsFile=" ++ KnownHosts ++ " " ++ Host ++ " 1+1.",
+
+ test_server:format("Cmd: ~p~n", [Cmd]),
+
SshPort = open_port({spawn, Cmd}, [binary]),
receive
@@ -258,6 +279,9 @@ erlang_server_openssh_client_exec_compressed(suite) ->
erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ KnownHosts = filename:join(PrivDir, "known_hosts"),
+
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{compression, zlib},
{failfun, fun ssh_test_lib:failfun/2}]),
@@ -265,7 +289,7 @@ erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) ->
test_server:sleep(500),
Cmd = "ssh -p " ++ integer_to_list(Port) ++
- " -o StrictHostKeyChecking=no -C "++ Host ++ " 1+1.",
+ " -o UserKnownHostsFile=" ++ KnownHosts ++ " -C "++ Host ++ " 1+1.",
SshPort = open_port({spawn, Cmd}, [binary]),
receive
@@ -330,24 +354,27 @@ erlang_client_openssh_server_publickey_rsa(suite) ->
[];
erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) ->
{ok,[[Home]]} = init:get_argument(home),
- SrcDir = filename:join(Home, ".ssh"),
- UserDir = ?config(priv_dir, Config),
- case ssh_test_lib:copyfile(SrcDir, UserDir, "id_rsa") of
- {ok, _} ->
- ConnectionRef =
- ssh_test_lib:connect(?SSH_DEFAULT_PORT,
- [{user_dir, UserDir},
- {public_key_alg, ssh_rsa},
- {user_interaction, false},
- silently_accept_hosts]),
- {ok, Channel} =
- ssh_connection:session_channel(ConnectionRef, infinity),
- ok = ssh_connection:close(ConnectionRef, Channel),
- ok = ssh:close(ConnectionRef),
- ok = file:delete(filename:join(UserDir, "id_rsa"));
- {error, enoent} ->
- {skip, "no ~/.ssh/id_rsa"}
+ KeyFile = filename:join(Home, ".ssh/id_rsa"),
+ case file:read_file(KeyFile) of
+ {ok, Pem} ->
+ case public_key:pem_decode(Pem) of
+ [{_,_, not_encrypted}] ->
+ ConnectionRef =
+ ssh_test_lib:connect(?SSH_DEFAULT_PORT,
+ [{public_key_alg, ssh_rsa},
+ {user_interaction, false},
+ silently_accept_hosts]),
+ {ok, Channel} =
+ ssh_connection:session_channel(ConnectionRef, infinity),
+ ok = ssh_connection:close(ConnectionRef, Channel),
+ ok = ssh:close(ConnectionRef);
+ _ ->
+ {skip, {error, "Has pass phrase can not be used by automated test case"}}
+ end;
+ _ ->
+ {skip, "no ~/.ssh/id_rsa"}
end.
+
%%--------------------------------------------------------------------
erlang_client_openssh_server_publickey_dsa(doc) ->
@@ -356,25 +383,26 @@ erlang_client_openssh_server_publickey_dsa(suite) ->
[];
erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) ->
{ok,[[Home]]} = init:get_argument(home),
- SrcDir = filename:join(Home, ".ssh"),
- UserDir = ?config(priv_dir, Config),
- case ssh_test_lib:copyfile(SrcDir, UserDir, "id_dsa") of
- {ok, _} ->
- ConnectionRef =
- ssh_test_lib:connect(?SSH_DEFAULT_PORT,
- [{user_dir, UserDir},
- {public_key_alg, ssh_dsa},
- {user_interaction, false},
- silently_accept_hosts]),
- {ok, Channel} =
- ssh_connection:session_channel(ConnectionRef, infinity),
- ok = ssh_connection:close(ConnectionRef, Channel),
- ok = ssh:close(ConnectionRef),
- ok = file:delete(filename:join(UserDir, "id_dsa"));
- {error, enoent} ->
- {skip, "no ~/.ssh/id_dsa"}
+ KeyFile = filename:join(Home, ".ssh/id_dsa"),
+ case file:read_file(KeyFile) of
+ {ok, Pem} ->
+ case public_key:pem_decode(Pem) of
+ [{_,_, not_encrypted}] ->
+ ConnectionRef =
+ ssh_test_lib:connect(?SSH_DEFAULT_PORT,
+ [{public_key_alg, ssh_dsa},
+ {user_interaction, false},
+ silently_accept_hosts]),
+ {ok, Channel} =
+ ssh_connection:session_channel(ConnectionRef, infinity),
+ ok = ssh_connection:close(ConnectionRef, Channel),
+ ok = ssh:close(ConnectionRef);
+ _ ->
+ {skip, {error, "Has pass phrase can not be used by automated test case"}}
+ end;
+ _ ->
+ {skip, "no ~/.ssh/id_dsa"}
end.
-
%%--------------------------------------------------------------------
erlang_server_openssh_client_pulic_key_dsa(doc) ->
["Validate using dsa publickey."];
@@ -384,6 +412,9 @@ erlang_server_openssh_client_pulic_key_dsa(suite) ->
erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) ->
SystemDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ KnownHosts = filename:join(PrivDir, "known_hosts"),
+
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{public_key_alg, ssh_dsa},
{failfun, fun ssh_test_lib:failfun/2}]),
@@ -391,7 +422,8 @@ erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) ->
test_server:sleep(500),
Cmd = "ssh -p " ++ integer_to_list(Port) ++
- " -o StrictHostKeyChecking=no "++ Host ++ " 1+1.",
+ " -o UserKnownHostsFile=" ++ KnownHosts ++
+ " " ++ Host ++ " 1+1.",
SshPort = open_port({spawn, Cmd}, [binary]),
receive
@@ -399,7 +431,6 @@ erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) ->
ok
after ?TIMEOUT ->
test_server:fail("Did not receive answer")
-
end,
ssh:stop_daemon(Pid).
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index 115527aae0..bc395cb6d5 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -57,7 +57,7 @@ accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
Kernel = self(),
- spawn(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end).
+ spawn_opt(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end, [link, {priority, max}]).
do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
[Name, Address] = splitnode(Node, LongOrShortNames),
@@ -229,9 +229,7 @@ connect_hs_data(Kernel, Node, MyNode, Socket, Timer, Version, Ip, TcpPort, Addre
accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed) ->
common_hs_data(Kernel, MyNode, Socket, Timer, #hs_data{
allowed = Allowed,
- f_address = fun(S, N) ->
- ssl_tls_dist_proxy:get_remote_id(S, N)
- end
+ f_address = fun get_remote_id/2
}).
common_hs_data(Kernel, MyNode, Socket, Timer, HsData) ->
@@ -273,3 +271,11 @@ common_hs_data(Kernel, MyNode, Socket, Timer, HsData) ->
P = proplists:get_value(send_pend, Stats, 0),
{ok, R,W,P}
end}.
+
+get_remote_id(Socket, _Node) ->
+ case ssl_tls_dist_proxy:get_tcp_address(Socket) of
+ {ok, Address} ->
+ Address;
+ {error, _Reason} ->
+ ?shutdown(no_node)
+ end.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 371f475c85..542033e6ce 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.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
@@ -188,14 +188,14 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
ValidationFunAndState =
case VerifyFunAndState of
undefined ->
- {fun(OtpCert, ExtensionOrError, SslState) ->
+ {fun(OtpCert, ExtensionOrVerifyResult, SslState) ->
ssl_certificate:validate_extension(OtpCert,
- ExtensionOrError, SslState)
+ ExtensionOrVerifyResult, SslState)
end, Role};
{Fun, UserState0} ->
- {fun(OtpCert, ExtensionOrError, {SslState, UserState}) ->
+ {fun(OtpCert, {extension, _} = Extension, {SslState, UserState}) ->
case ssl_certificate:validate_extension(OtpCert,
- ExtensionOrError,
+ Extension,
SslState) of
{valid, NewSslState} ->
{valid, {NewSslState, UserState}};
@@ -204,8 +204,11 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
SslState);
{unknown, _} ->
apply_user_fun(Fun, OtpCert,
- ExtensionOrError, UserState, SslState)
- end
+ Extension, UserState, SslState)
+ end;
+ (OtpCert, VerifyResult, {SslState, UserState}) ->
+ apply_user_fun(Fun, OtpCert, VerifyResult, UserState,
+ SslState)
end, {Role, UserState0}}
end,
diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl
index d63eada571..1c61eb7ccc 100644
--- a/lib/ssl/src/ssl_tls_dist_proxy.erl
+++ b/lib/ssl/src/ssl_tls_dist_proxy.erl
@@ -19,7 +19,7 @@
-module(ssl_tls_dist_proxy).
--export([listen/1, accept/1, connect/2, get_remote_id/2]).
+-export([listen/1, accept/1, connect/2, get_tcp_address/1]).
-export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3, ssl_options/2]).
@@ -47,9 +47,6 @@ accept(Listen) ->
connect(Ip, Port) ->
gen_server:call(?MODULE, {connect, Ip, Port}, infinity).
-get_remote_id(Socket, Node) ->
- gen_server:call(?MODULE, {get_remote_id, {Socket,Node}}, infinity).
-
%%====================================================================
%% gen_server callbacks
%%====================================================================
@@ -65,8 +62,8 @@ handle_call({listen, Name}, _From, State) ->
case gen_tcp:listen(0, [{active, false}, {packet,?PPRE}]) of
{ok, Socket} ->
{ok, World} = gen_tcp:listen(0, [{active, false}, binary, {packet,?PPRE}]),
- TcpAddress = get_tcp_address(Socket),
- WorldTcpAddress = get_tcp_address(World),
+ {ok, TcpAddress} = get_tcp_address(Socket),
+ {ok, WorldTcpAddress} = get_tcp_address(World),
{_,Port} = WorldTcpAddress#net_address.address,
{ok, Creation} = erl_epmd:register_node(Name, Port),
{reply, {ok, {Socket, TcpAddress, Creation}},
@@ -87,17 +84,16 @@ handle_call({connect, Ip, Port}, {From, _}, State) ->
receive
{Pid, go_ahead, LPort} ->
Res = {ok, Socket} = try_connect(LPort),
- ok = gen_tcp:controlling_process(Socket, From),
- flush_old_controller(From, Socket),
- {reply, Res, State};
+ case gen_tcp:controlling_process(Socket, From) of
+ {error, badarg} = Error -> {reply, Error, State}; % From is dead anyway.
+ ok ->
+ flush_old_controller(From, Socket),
+ {reply, Res, State}
+ end;
{Pid, Error} ->
{reply, Error, State}
end;
-handle_call({get_remote_id, {Socket,_Node}}, _From, State) ->
- Address = get_tcp_address(Socket),
- {reply, Address, State};
-
handle_call(_What, _From, State) ->
{reply, ok, State}.
@@ -117,14 +113,18 @@ code_change(_OldVsn, St, _Extra) ->
%%% Internal functions
%%--------------------------------------------------------------------
get_tcp_address(Socket) ->
- {ok, Address} = inet:sockname(Socket),
- {ok, Host} = inet:gethostname(),
- #net_address{
+ case inet:sockname(Socket) of
+ {ok, Address} ->
+ {ok, Host} = inet:gethostname(),
+ NetAddress = #net_address{
address = Address,
host = Host,
protocol = proxy,
family = inet
- }.
+ },
+ {ok, NetAddress};
+ {error, _} = Error -> Error
+ end.
accept_loop(Proxy, erts = Type, Listen, Extra) ->
process_flag(priority, max),
@@ -178,8 +178,8 @@ setup_proxy(Ip, Port, Parent) ->
Opts = get_ssl_options(client),
case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}] ++ Opts) of
{ok, World} ->
- {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, binary, {packet,?PPRE}]),
- #net_address{address={_,LPort}} = get_tcp_address(ErtsL),
+ {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, {ip, {127,0,0,1}}, binary, {packet,?PPRE}]),
+ {ok, #net_address{address={_,LPort}}} = get_tcp_address(ErtsL),
Parent ! {self(), go_ahead, LPort},
case gen_tcp:accept(ErtsL) of
{ok, Erts} ->
@@ -194,7 +194,7 @@ setup_proxy(Ip, Port, Parent) ->
setup_connection(World, ErtsListen) ->
process_flag(trap_exit, true),
- TcpAddress = get_tcp_address(ErtsListen),
+ {ok, TcpAddress} = get_tcp_address(ErtsListen),
{_Addr,Port} = TcpAddress#net_address.address,
{ok, Erts} = gen_tcp:connect({127,0,0,1}, Port, [{active, true}, binary, {packet,?PPRE}]),
ssl:setopts(World, [{active,true}, {packet,?PPRE}]),
@@ -223,7 +223,11 @@ loop_conn_setup(World, Erts) ->
loop_conn_setup(World, Erts);
{tcp, Erts, Data} ->
ssl:send(World, Data),
- loop_conn_setup(World, Erts)
+ loop_conn_setup(World, Erts);
+ {tcp_closed, Erts} ->
+ ssl:close(World);
+ {ssl_closed, World} ->
+ gen_tcp:close(Erts)
end.
loop_conn(World, Erts) ->
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 527263363c..590ecf33ca 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_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
@@ -250,6 +250,8 @@ all() ->
no_authority_key_identifier, invalid_signature_client,
invalid_signature_server, cert_expired,
client_with_cert_cipher_suites_handshake,
+ verify_fun_always_run_client,
+ verify_fun_always_run_server,
unknown_server_ca_fail, der_input,
unknown_server_ca_accept_verify_none,
unknown_server_ca_accept_verify_peer,
@@ -3217,6 +3219,105 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+verify_fun_always_run_client(doc) ->
+ ["Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"];
+verify_fun_always_run_client(suite) ->
+ [];
+verify_fun_always_run_client(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ %% If user verify fun is called correctly we fail the connection.
+ %% otherwise we can not tell this case apart form where we miss
+ %% to call users verify fun
+ FunAndState = {fun(_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, [ChainLen]) ->
+ {valid, [ChainLen + 1]};
+ (_, valid_peer, [2]) ->
+ {fail, "verify_fun_was_always_run"};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, [0]},
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState}
+ | ClientOpts]}]),
+ %% Server error may be esslaccept or closed depending on timing
+ %% this is not a bug it is a circumstance of how tcp works!
+ receive
+ {Server, ServerError} ->
+ test_server:format("Server Error ~p~n", [ServerError])
+ end,
+
+ ssl_test_lib:check_result(Client, {error, esslconnect}).
+
+%%--------------------------------------------------------------------
+verify_fun_always_run_server(doc) ->
+ ["Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"];
+verify_fun_always_run_server(suite) ->
+ [];
+verify_fun_always_run_server(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% If user verify fun is called correctly we fail the connection.
+ %% otherwise we can not tell this case apart form where we miss
+ %% to call users verify fun
+ FunAndState = {fun(_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, [ChainLen]) ->
+ {valid, [ChainLen + 1]};
+ (_, valid_peer, [2]) ->
+ {fail, "verify_fun_was_always_run"};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, [0]},
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState} |
+ ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer}
+ | ClientOpts]}]),
+
+ %% Client error may be esslconnect or closed depending on timing
+ %% this is not a bug it is a circumstance of how tcp works!
+ receive
+ {Client, ClientError} ->
+ test_server:format("Client Error ~p~n", [ClientError])
+ end,
+
+ ssl_test_lib:check_result(Server, {error, esslaccept}).
+
%%--------------------------------------------------------------------
unknown_server_ca_fail(doc) ->
["Test that the client fails if the ca is unknown in verify_peer mode"];
@@ -3924,7 +4025,7 @@ renegotiate(Socket, Data) ->
end.
renegotiate_reuse_session(Socket, Data) ->
- %% Make sure session is registerd
+ %% Make sure session is registered
test_server:sleep(?SLEEP),
renegotiate(Socket, Data).
diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index 8fe55ee7a4..06182970e3 100644
--- a/lib/ssl/test/ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -26,7 +26,7 @@
-define(DEFAULT_TIMETRAP_SECS, 240).
--define(AWAIT_SLL_NODE_UP_TIMEOUT, 30000).
+-define(AWAIT_SSL_NODE_UP_TIMEOUT, 30000).
-record(node_handle,
{connection_handler,
@@ -120,6 +120,12 @@ basic(Config) when is_list(Config) ->
pang = net_adm:ping(Node1),
pang = net_adm:ping(Node2),
+ %% SSL nodes should not be able to communicate with the test_server node
+ %% either (and ping should return eventually).
+ TestServer = node(),
+ pang = apply_on_ssl_node(NH1, fun () -> net_adm:ping(TestServer) end),
+ pang = apply_on_ssl_node(NH2, fun () -> net_adm:ping(TestServer) end),
+
%%
%% Check that we are able to communicate over the erlang
%% distribution between the ssl nodes.
@@ -380,7 +386,7 @@ mk_node_cmdline(ListenPort, Name, Args) ->
%%
await_ssl_node_up(Name, LSock) ->
- case gen_tcp:accept(LSock, ?AWAIT_SLL_NODE_UP_TIMEOUT) of
+ case gen_tcp:accept(LSock, ?AWAIT_SSL_NODE_UP_TIMEOUT) of
timeout ->
gen_tcp:close(LSock),
?t:format("Timeout waiting for ssl node ~s to come up~n",
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index f04ab9af50..01fca1f166 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_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
@@ -1446,8 +1446,8 @@ check_sane_openssl_renegotaite(Config) ->
check_sane_openssl_sslv2(Config) ->
case os:cmd("openssl version") of
- "OpenSSL 1.0.0e" ++ _ ->
- {skip, "Known option bug"};
+ "OpenSSL 1.0.0" ++ _ ->
+ {skip, "sslv2 by default turned of in 1.*"};
_ ->
Config
end.
diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml
index 88ce77e0d0..7ce2defb72 100644
--- a/lib/stdlib/doc/src/binary.xml
+++ b/lib/stdlib/doc/src/binary.xml
@@ -505,7 +505,7 @@
<type>
<v>Subject = binary()</v>
<v>Pos = integer() >= 0</v>
- <v>Len = integer() >= 0</v>
+ <v>Len = integer()</v>
</type>
<desc>
<p>The same as <c>part(Subject, {Pos, Len})</c>.</p>
diff --git a/lib/stdlib/doc/src/gb_trees.xml b/lib/stdlib/doc/src/gb_trees.xml
index 65c866efbe..9316d60b1a 100644
--- a/lib/stdlib/doc/src/gb_trees.xml
+++ b/lib/stdlib/doc/src/gb_trees.xml
@@ -132,15 +132,6 @@
</desc>
</func>
<func>
- <name name="lookup" arity="2"/>
- <fsummary>Look up a key in a tree</fsummary>
- <desc>
- <p>Looks up <c><anno>Key</anno></c> in <c><anno>Tree</anno></c>; returns
- <c>{value, <anno>Val</anno>}</c>, or <c>none</c> if <c><anno>Key</anno></c> is not
- present.</p>
- </desc>
- </func>
- <func>
<name name="insert" arity="3"/>
<fsummary>Insert a new key and value in a tree</fsummary>
<desc>
@@ -196,6 +187,15 @@
</desc>
</func>
<func>
+ <name name="lookup" arity="2"/>
+ <fsummary>Look up a key in a tree</fsummary>
+ <desc>
+ <p>Looks up <c><anno>Key</anno></c> in <c><anno>Tree</anno></c>; returns
+ <c>{value, <anno>Val</anno>}</c>, or <c>none</c> if <c><anno>Key</anno></c> is not
+ present.</p>
+ </desc>
+ </func>
+ <func>
<name name="map" arity="2"/>
<fsummary>Return largest key and value</fsummary>
<desc><p>Maps the function F(<anno>K</anno>, <anno>V1</anno>) -> <anno>V2</anno> to all key-value pairs
diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml
index 667d758e29..e6d262466c 100644
--- a/lib/stdlib/doc/src/io.xml
+++ b/lib/stdlib/doc/src/io.xml
@@ -70,7 +70,7 @@
<desc>
<p>Either <c>standard_io</c>, <c>standard_error</c>, a
registered name, or a pid handling IO protocols (returned from
- <seealso marker="file#open/2">file:open/2</seealso>).</p>
+ <seealso marker="kernel:file#open/2">file:open/2</seealso>).</p>
</desc>
</datatype>
<datatype>
diff --git a/lib/stdlib/doc/src/ms_transform.xml b/lib/stdlib/doc/src/ms_transform.xml
index f81f8bda96..ad5f8bd5ac 100644
--- a/lib/stdlib/doc/src/ms_transform.xml
+++ b/lib/stdlib/doc/src/ms_transform.xml
@@ -308,7 +308,7 @@ ets:select(emp_tab, ets:fun2ms(
Erlang code. Also arithmetics is allowed, as well as ordinary guard
bif's. Here's a list of bif's and expressions:</p>
<list type="bulleted">
- <item>The type tests: is_atom, is_constant, is_float, is_integer,
+ <item>The type tests: is_atom, is_float, is_integer,
is_list, is_number, is_pid, is_port, is_reference, is_tuple,
is_binary, is_function, is_record</item>
<item>The boolean operators: not, and, or, andalso, orelse </item>
@@ -318,7 +318,7 @@ ets:select(emp_tab, ets:fun2ms(
<item>The guard bif's: abs, element, hd, length, node, round, size, tl,
trunc, self</item>
<item>The obsolete type test (only in guards):
- atom, constant, float, integer,
+ atom, float, integer,
list, number, pid, port, reference, tuple,
binary, function, record</item>
</list>
diff --git a/lib/stdlib/doc/src/sofs.xml b/lib/stdlib/doc/src/sofs.xml
index 2e7768a1df..37c41501ae 100644
--- a/lib/stdlib/doc/src/sofs.xml
+++ b/lib/stdlib/doc/src/sofs.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2011</year>
+ <year>2001</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -317,7 +317,7 @@
but is to be preferred since it makes it possible to handle this
case even more efficiently. Examples of SetFuns:</p>
<pre>
-{sofs, union}
+fun sofs:union/1
fun(S) -> sofs:partition(1, S) end
{external, fun(A) -> A end}
{external, fun({A,_,C}) -> {C,A} end}
@@ -711,7 +711,7 @@ fun(S) -> sofs:partition(1, S) end
argument.</p>
<pre>
1> <input>F1 = sofs:from_term([{a,[[1,2],[2,3]]},{b,[[]]}]),</input>
-<input>F2 = sofs:family_projection({sofs, union}, F1),</input>
+<input>F2 = sofs:family_projection(fun sofs:union/1, F1),</input>
<input>sofs:to_external(F2).</input>
[{a,[1,2,3]},{b,[]}]</pre>
</desc>
@@ -821,7 +821,7 @@ fun(S) -> sofs:partition(1, S) end
<input>sofs:to_external(F2).</input>
[{a,[1,2,3]},{b,[]}]</pre>
<p><c>family_union(F)</c> is equivalent to
- <c>family_projection({sofs,union},&nbsp;F)</c>.</p>
+ <c>family_projection(fun sofs:union/1,&nbsp;F)</c>.</p>
</desc>
</func>
<func>
@@ -1438,7 +1438,7 @@ true</pre>
1> <input>R1 = sofs:relation([{a,1},{b,2}]),</input>
<input>R2 = sofs:relation([{x,1},{x,2},{y,3}]),</input>
<input>S1 = sofs:from_sets([R1,R2]),</input>
-<input>S2 = sofs:specification({sofs,is_a_function}, S1),</input>
+<input>S2 = sofs:specification(fun sofs:is_a_function/1, S1),</input>
<input>sofs:to_external(S2).</input>
[[{a,1},{b,2}]]</pre>
</desc>
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index cddb55e5c5..33a7f5bb6a 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -127,25 +127,18 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
<p><c>StartFunc</c> defines the function call used to start
the child process. It should be a module-function-arguments
tuple <c>{M,F,A}</c> used as <c>apply(M,F,A)</c>.</p>
- <p> <br></br>
-</p>
<p>The start function <em>must create and link to</em> the child
process, and should return <c>{ok,Child}</c> or
<c>{ok,Child,Info}</c> where <c>Child</c> is the pid of
the child process and <c>Info</c> an arbitrary term which is
ignored by the supervisor.</p>
- <p> <br></br>
-</p>
<p>The start function can also return <c>ignore</c> if the child
process for some reason cannot be started, in which case
- the child specification will be kept by the supervisor but
- the non-existing child process will be ignored.</p>
- <p> <br></br>
-</p>
+ the child specification will be kept by the supervisor
+ (unless it is a temporary child) but the non-existing child
+ process will be ignored.</p>
<p>If something goes wrong, the function may also return an
error tuple <c>{error,Error}</c>.</p>
- <p> <br></br>
-</p>
<p>Note that the <c>start_link</c> functions of the different
behaviour modules fulfill the above requirements.</p>
</item>
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index bf3c7b3504..95ba6b1096 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -947,7 +947,6 @@ type_test(integer) -> is_integer;
type_test(float) -> is_float;
type_test(number) -> is_number;
type_test(atom) -> is_atom;
-type_test(constant) -> is_constant;
type_test(list) -> is_list;
type_test(tuple) -> is_tuple;
type_test(pid) -> is_pid;
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index 20fd247cea..1c69a131f9 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -452,8 +452,10 @@ conj([], _E) ->
conj([{{Name,_Rp},L,R,Sz} | AL], E) ->
NL = neg_line(L),
T1 = {op,NL,'orelse',
- {call,NL,{atom,NL,is_record},[R,{atom,NL,Name},{integer,NL,Sz}]},
- {atom,NL,fail}},
+ {call,NL,
+ {remote,NL,{atom,NL,erlang},{atom,NL,is_record}},
+ [R,{atom,NL,Name},{integer,NL,Sz}]},
+ {atom,NL,fail}},
T2 = case conj(AL, none) of
empty -> T1;
C -> {op,NL,'and',C,T1}
@@ -581,7 +583,9 @@ strict_get_record_field(Line, R, {atom,_,F}=Index, Name, St0) ->
ExpRp = erl_lint:modify_line(ExpR, fun(_L) -> 0 end),
RA = {{Name,ExpRp},Line,ExpR,length(Fs)+1},
St2 = St1#exprec{strict_ra = [RA | St1#exprec.strict_ra]},
- {{call,Line,{atom,Line,element},[I,ExpR]},St2}
+ {{call,Line,
+ {remote,Line,{atom,Line,erlang},{atom,Line,element}},
+ [I,ExpR]},St2}
end.
record_pattern(I, I, Var, Sz, Line, Acc) ->
@@ -593,7 +597,9 @@ record_pattern(_, _, _, _, _, Acc) -> reverse(Acc).
sloppy_get_record_field(Line, R, Index, Name, St) ->
Fs = record_fields(Name, St),
I = index_expr(Line, Index, Name, Fs),
- expr({call,Line,{atom,Line,element},[I,R]}, St).
+ expr({call,Line,
+ {remote,Line,{atom,Line,erlang},{atom,Line,element}},
+ [I,R]}, St).
strict_record_tests([strict_record_tests | _]) -> true;
strict_record_tests([no_strict_record_tests | _]) -> false;
@@ -710,7 +716,8 @@ record_setel(R, Name, Fs, Us0) ->
{'case',Lr,R,
[{clause,Lr,[{tuple,Lr,[{atom,Lr,Name} | Wildcards]}],[],
[foldr(fun ({I,Lf,Val}, Acc) ->
- {call,Lf,{atom,Lf,setelement},[I,Acc,Val]} end,
+ {call,Lf,{remote,Lf,{atom,Lf,erlang},
+ {atom,Lf,setelement}},[I,Acc,Val]} end,
R, Us)]},
{clause,NLr,[{var,NLr,'_'}],[],
[call_error(NLr, {tuple,NLr,[{atom,NLr,badrecord},{atom,NLr,Name}]})]}]}.
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index e5adb84932..a1af0057ca 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -1804,12 +1804,19 @@ guard_test(G, Vt, St0) ->
%% Specially handle record type test here.
guard_test2({call,Line,{atom,Lr,record},[E,A]}, Vt, St0) ->
gexpr({call,Line,{atom,Lr,is_record},[E,A]}, Vt, St0);
-guard_test2({call,_Line,{atom,_La,F},As}=G, Vt, St0) ->
+guard_test2({call,Line,{atom,_La,F},As}=G, Vt, St0) ->
{Asvt,St1} = gexpr_list(As, Vt, St0), %Always check this.
A = length(As),
case erl_internal:type_test(F, A) of
- true when F =/= is_record -> {Asvt,St1};
- _ -> gexpr(G, Vt, St0)
+ true when F =/= is_record, A =/= 2 ->
+ case no_guard_bif_clash(St1, {F,A}) of
+ false ->
+ {Asvt,add_error(Line, {illegal_guard_local_call,{F,A}}, St1)};
+ true ->
+ {Asvt,St1}
+ end;
+ _ ->
+ gexpr(G, Vt, St0)
end;
guard_test2(G, Vt, St) ->
%% Everything else is a guard expression.
@@ -1865,9 +1872,15 @@ gexpr({call,Line,{atom,_Lr,is_record},[E,R]}, Vt, St0) ->
gexpr({call,Line,{remote,_Lr,{atom,_Lm,erlang},{atom,Lf,is_record}},[E,A]},
Vt, St0) ->
gexpr({call,Line,{atom,Lf,is_record},[E,A]}, Vt, St0);
-gexpr({call,_Line,{atom,_Lr,is_record},[E,{atom,_,_Name},{integer,_,_}]},
+gexpr({call,Line,{atom,_Lr,is_record},[E0,{atom,_,_Name},{integer,_,_}]},
Vt, St0) ->
- gexpr(E, Vt, St0);
+ {E,St1} = gexpr(E0, Vt, St0),
+ case no_guard_bif_clash(St0, {is_record,3}) of
+ true ->
+ {E,St1};
+ false ->
+ {E,add_error(Line, {illegal_guard_local_call,{is_record,3}}, St1)}
+ end;
gexpr({call,Line,{atom,_Lr,is_record},[_,_,_]=Asvt0}, Vt, St0) ->
{Asvt,St1} = gexpr_list(Asvt0, Vt, St0),
{Asvt,add_error(Line, illegal_guard_expr, St1)};
@@ -3423,17 +3436,11 @@ obsolete_guard({call,Line,{atom,Lr,F},As}, St0) ->
false ->
deprecated_function(Line, erlang, F, As, St0);
true ->
- St1 = case F of
- constant ->
- deprecated_function(Lr, erlang, is_constant, As, St0);
- _ ->
- St0
- end,
- case is_warn_enabled(obsolete_guard, St1) of
+ case is_warn_enabled(obsolete_guard, St0) of
true ->
- add_warning(Lr,{obsolete_guard, {F, Arity}}, St1);
+ add_warning(Lr,{obsolete_guard, {F, Arity}}, St0);
false ->
- St1
+ St0
end
end;
obsolete_guard(_G, St) ->
diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl
index ee4f0b3a51..08f1873803 100644
--- a/lib/stdlib/src/error_logger_file_h.erl
+++ b/lib/stdlib/src/error_logger_file_h.erl
@@ -104,7 +104,7 @@ code_change(_OldVsn, State, _Extra) ->
%%% ------------------------------------------------------
tag_event(Event) ->
- {erlang:localtime(), Event}.
+ {erlang:universaltime(), Event}.
write_events(Fd, Events) -> write_events1(Fd, lists:reverse(Events)).
@@ -169,23 +169,18 @@ write_event(_, _) ->
maybe_utc(Time) ->
UTC = case application:get_env(sasl, utc_log) of
- {ok, Val} ->
- Val;
+ {ok, Val} -> Val;
undefined ->
%% Backwards compatible:
case application:get_env(stdlib, utc_log) of
- {ok, Val} ->
- Val;
- undefined ->
- false
+ {ok, Val} -> Val;
+ undefined -> false
end
end,
- if
- UTC =:= true ->
- {utc, calendar:local_time_to_universal_time(Time)};
- true ->
- Time
- end.
+ maybe_utc(Time, UTC).
+
+maybe_utc(Time, true) -> {utc, Time};
+maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}.
format_report(Rep) when is_list(Rep) ->
case string_p(Rep) of
@@ -238,7 +233,7 @@ write_time(Time) -> write_time(Time, "ERROR REPORT").
write_time({utc,{{Y,Mo,D},{H,Mi,S}}}, Type) ->
io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
[Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
-write_time({{Y,Mo,D},{H,Mi,S}}, Type) ->
+write_time({local, {{Y,Mo,D},{H,Mi,S}}}, Type) ->
io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n",
[Type,D,month(Mo),Y,t(H),t(Mi),t(S)]).
diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl
index fa13fbb2bd..48e069a407 100644
--- a/lib/stdlib/src/error_logger_tty_h.erl
+++ b/lib/stdlib/src/error_logger_tty_h.erl
@@ -97,7 +97,7 @@ set_group_leader() ->
end.
tag_event(Event) ->
- {erlang:localtime(), Event}.
+ {erlang:universaltime(), Event}.
write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod).
@@ -162,23 +162,18 @@ write_event({_Time, _Error},_IOMod) ->
maybe_utc(Time) ->
UTC = case application:get_env(sasl, utc_log) of
- {ok, Val} ->
- Val;
+ {ok, Val} -> Val;
undefined ->
%% Backwards compatible:
case application:get_env(stdlib, utc_log) of
- {ok, Val} ->
- Val;
- undefined ->
- false
+ {ok, Val} -> Val;
+ undefined -> false
end
end,
- if
- UTC =:= true ->
- {utc, calendar:local_time_to_universal_time(Time)};
- true ->
- Time
- end.
+ maybe_utc(Time, UTC).
+
+maybe_utc(Time, true) -> {utc, Time};
+maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}.
format(IOMod, String) -> format(IOMod, String, []).
format(io_lib, String, Args) -> io_lib:format(String, Args);
@@ -234,7 +229,7 @@ write_time(Time) -> write_time(Time, "ERROR REPORT").
write_time({utc,{{Y,Mo,D},{H,Mi,S}}},Type) ->
io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n",
[Type,D,month(Mo),Y,t(H),t(Mi),t(S)]);
-write_time({{Y,Mo,D},{H,Mi,S}},Type) ->
+write_time({local, {{Y,Mo,D},{H,Mi,S}}},Type) ->
io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n",
[Type,D,month(Mo),Y,t(H),t(Mi),t(S)]).
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index 57734a075c..80866c0806 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -320,7 +320,7 @@ name_to_pid(Name) ->
undefined ->
case global:whereis_name(Name) of
undefined ->
- exit(could_not_find_registerd_name);
+ exit(could_not_find_registered_name);
Pid ->
Pid
end;
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index af07bc988a..f720ec15f5 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -844,7 +844,7 @@ name_to_pid(Name) ->
undefined ->
case global:whereis_name(Name) of
undefined ->
- exit(could_not_find_registerd_name);
+ exit(could_not_find_registered_name);
Pid ->
Pid
end;
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 63b397f3a5..4389fd457c 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -881,7 +881,6 @@ translate_language_element(Atom) ->
end.
old_bool_test(atom,1) -> is_atom;
-old_bool_test(constant,1) -> is_constant;
old_bool_test(float,1) -> is_float;
old_bool_test(integer,1) -> is_integer;
old_bool_test(list,1) -> is_list;
@@ -896,7 +895,6 @@ old_bool_test(record,2) -> is_record;
old_bool_test(_,_) -> undefined.
bool_test(is_atom,1) -> true;
-bool_test(is_constant,1) -> true;
bool_test(is_float,1) -> true;
bool_test(is_integer,1) -> true;
bool_test(is_list,1) -> true;
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 7bacc05ff2..b9fbef9ed0 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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
@@ -337,11 +337,11 @@ obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 ->
%% Added in R14B03.
obsolete_1(docb_gen, _, _) ->
- {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+ {removed,"the DocBuilder application was removed in R15B"};
obsolete_1(docb_transform, _, _) ->
- {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+ {removed,"the DocBuilder application was removed in R15B"};
obsolete_1(docb_xml_check, _, _) ->
- {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+ {removed,"the DocBuilder application was removed in R15B"};
%% Added in R15B
obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
@@ -350,10 +350,18 @@ obsolete_1(ssl, pid, 1) ->
{deprecated,"deprecated (will be removed in R17); is no longer needed"};
obsolete_1(inviso, _, _) ->
{deprecated,"the inviso application has been deprecated and will be removed in R16"};
+
+%% Added in R15B01.
+obsolete_1(gs, _, _) ->
+ {deprecated,"the gs application has been deprecated and will be removed in R16; use the wx application instead"};
+obsolete_1(ssh, sign_data, 2) ->
+ {deprecated,"deprecated (will be removed in R16A); use public_key:pem_decode/1, public_key:pem_entry_decode/1 "
+ "and public_key:sign/3 instead"};
+obsolete_1(ssh, verify_data, 3) ->
+ {deprecated,"deprecated (will be removed in R16A); use public_key:ssh_decode/1, and public_key:verify/4 instead"};
obsolete_1(_, _, _) ->
no.
-
-spec is_snmp_agent_function(atom(), byte()) -> boolean().
is_snmp_agent_function(c, 1) -> true;
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 42ea42f42e..ac5b078c29 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -270,6 +270,8 @@ start_children(Children, SupName) -> start_children(Children, [], SupName).
start_children([Child|Chs], NChildren, SupName) ->
case do_start_child(SupName, Child) of
+ {ok, undefined} when Child#child.restart_type =:= temporary ->
+ start_children(Chs, NChildren, SupName);
{ok, Pid} ->
start_children(Chs, [Child#child{pid = Pid}|NChildren], SupName);
{ok, Pid, _Extra} ->
@@ -325,6 +327,8 @@ handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) ->
#child{mfargs = {M, F, A}} = Child,
Args = A ++ EArgs,
case do_start_child_i(M, F, Args) of
+ {ok, undefined} when Child#child.restart_type =:= temporary ->
+ {reply, {ok, undefined}, State};
{ok, Pid} ->
NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State),
{reply, {ok, Pid}, NState};
@@ -611,12 +615,12 @@ handle_start_child(Child, State) ->
case get_child(Child#child.name, State) of
false ->
case do_start_child(State#state.name, Child) of
+ {ok, undefined} when Child#child.restart_type =:= temporary ->
+ {{ok, undefined}, State};
{ok, Pid} ->
- {{ok, Pid},
- save_child(Child#child{pid = Pid}, State)};
+ {{ok, Pid}, save_child(Child#child{pid = Pid}, State)};
{ok, Pid, Extra} ->
- {{ok, Pid, Extra},
- save_child(Child#child{pid = Pid}, State)};
+ {{ok, Pid, Extra}, save_child(Child#child{pid = Pid}, State)};
{error, What} ->
{{error, {What, Child}}, State}
end;
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 369d8b224e..ca2f18a05a 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1167,15 +1167,22 @@ do_funs(LFH, EFH) ->
[[[0]]], ['F'], LFH, EFH),
%% Tests for a bug found by the Dialyzer - used to crash.
- ?line check(fun() -> Pmod = erl_eval_helper:new(42), Pmod:add(5) end,
- "begin Pmod = erl_eval_helper:new(42), Pmod:add(5) end.",
- 47,
- ['Pmod'], LFH, EFH),
- ?line check(fun() -> Pmod = erl_eval_helper:new(42), B = Pmod:add(7), B end,
- "begin Pmod = erl_eval_helper:new(42), B = Pmod:add(7), B end.",
- 49,
- ['B','Pmod'], LFH, EFH),
-
+ case test_server:is_native(erl_eval) of
+ true ->
+ %% Parameterized modules are not supported by HiPE.
+ ok;
+ false ->
+ check(fun() -> Pmod = erl_eval_helper:new(42), Pmod:add(5) end,
+ "begin Pmod = erl_eval_helper:new(42), Pmod:add(5) end.",
+ 47,
+ ['Pmod'], LFH, EFH),
+ check(fun() -> Pmod = erl_eval_helper:new(42),
+ B = Pmod:add(7), B end,
+ "begin Pmod = erl_eval_helper:new(42), "
+ "B = Pmod:add(7), B end.",
+ 49,
+ ['B','Pmod'], LFH, EFH)
+ end,
ok.
count_down(F, N) when N > 0 ->
diff --git a/lib/stdlib/test/erl_expand_records_SUITE.erl b/lib/stdlib/test/erl_expand_records_SUITE.erl
index f8c1ad783c..8b162cfda0 100644
--- a/lib/stdlib/test/erl_expand_records_SUITE.erl
+++ b/lib/stdlib/test/erl_expand_records_SUITE.erl
@@ -178,6 +178,9 @@ expr(Config) when is_list(Config) ->
true ->
not_ok
end.
+
+ is_record(_, _, _) ->
+ error(wrong_is_record).
">>
],
@@ -366,6 +369,8 @@ strict(Config) when is_list(Config) ->
end
catch error:_ -> ok
end.
+ element(_, _) ->
+ error(wrong_element).
">>
],
?line run(Config, Ts1, [strict_record_tests]),
@@ -380,6 +385,8 @@ strict(Config) when is_list(Config) ->
case foo of
_ when A#r2.a =:= 1 -> ok
end.
+ element(_, _) ->
+ error(wrong_element).
">>
],
?line run(Config, Ts2, [no_strict_record_tests]),
@@ -415,6 +422,11 @@ update(Config) when is_list(Config) ->
t2() ->
R0 = #r{},
#r{_ = R0#r{a = ok}}.
+
+ %% Implicit calls to setelement/3 must go to the BIF,
+ %% not to this function.
+ setelement(_, _, _) ->
+ erlang:error(wrong_setelement_called).
">>
],
?line run(Config, Ts),
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 9041adbe5c..4e93f056ad 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -2631,7 +2631,35 @@ bif_clash(Config) when is_list(Config) ->
binary_part(A,B,C).
">>,
[warn_unused_import],
- {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}}
+ {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}},
+ %% Don't accept call to a guard BIF if there is a local definition
+ %% or an import with the same name. Note: is_record/2 is an
+ %% exception, since it is more of syntatic sugar than a real BIF.
+ {clash21,
+ <<"-export([is_list/1]).
+ -import(x, [is_tuple/1]).
+ -record(r, {a,b}).
+ x(T) when is_tuple(T) -> ok;
+ x(T) when is_list(T) -> ok.
+ y(T) when is_tuple(T) =:= true -> ok;
+ y(T) when is_list(T) =:= true -> ok;
+ y(T) when is_record(T, r, 3) -> ok;
+ y(T) when is_record(T, r, 3) =:= true -> ok;
+ y(T) when is_record(T, r) =:= true -> ok.
+ is_list(_) ->
+ ok.
+ is_record(_, _) ->
+ ok.
+ is_record(_, _, _) ->
+ ok.
+ ">>,
+ [{no_auto_import,[{is_tuple,1}]}],
+ {errors,[{4,erl_lint,{illegal_guard_local_call,{is_tuple,1}}},
+ {5,erl_lint,{illegal_guard_local_call,{is_list,1}}},
+ {6,erl_lint,{illegal_guard_local_call,{is_tuple,1}}},
+ {7,erl_lint,{illegal_guard_local_call,{is_list,1}}},
+ {8,erl_lint,{illegal_guard_local_call,{is_record,3}}},
+ {9,erl_lint,{illegal_guard_local_call,{is_record,3}}}],[]}}
],
?line [] = run(Config, Ts),
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 0e8849b5b3..101828fdef 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -74,7 +74,7 @@
-export([bad_table/1, types/1]).
-export([otp_9423/1]).
--export([init_per_testcase/2]).
+-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
-export([random_test/0]).
@@ -2385,6 +2385,8 @@ setopts_do(Opts) ->
?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{protection,private,false})),
?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,protection)),
?line ets:delete(T),
+ unlink(Heir),
+ exit(Heir, bang),
ok.
bad_table(doc) -> ["All kinds of operations with bad table argument"];
@@ -5645,7 +5647,8 @@ spawn_logger(Procs) ->
true -> exit(Proc, kill);
_ -> ok
end,
- erlang:display(process_info(Proc)),
+ erlang:display({"Waiting for 'DOWN' from", Proc,
+ process_info(Proc), pid_status(Proc)}),
receive
{'DOWN', Mon, _, _, _} ->
ok
@@ -5656,6 +5659,15 @@ spawn_logger(Procs) ->
spawn_logger([From])
end.
+pid_status(Pid) ->
+ try
+ erts_debug:get_internal_state({process_status, Pid})
+ catch
+ error:undef ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ pid_status(Pid)
+ end.
+
start_spawn_logger() ->
case whereis(ets_test_spawn_logger) of
Pid when is_pid(Pid) -> true;
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl
index c9688354b1..a17307b07b 100644
--- a/lib/stdlib/test/ms_transform_SUITE.erl
+++ b/lib/stdlib/test/ms_transform_SUITE.erl
@@ -455,7 +455,6 @@ old_guards(Config) when is_list(Config) ->
?line setup(Config),
Tests = [
{atom,is_atom},
- {constant,is_constant},
{float,is_float},
{integer,is_integer},
{list,is_list},
@@ -490,7 +489,6 @@ old_guards(Config) when is_list(Config) ->
?line [{'$1',[{is_integer,'$1'},
{is_float,'$1'},
{is_atom,'$1'},
- {is_constant,'$1'},
{is_list,'$1'},
{is_number,'$1'},
{is_pid,'$1'},
@@ -502,7 +500,7 @@ old_guards(Config) when is_list(Config) ->
[true]}] =
compile_and_run(RD, <<
"ets:fun2ms(fun(X) when integer(X),"
- "float(X), atom(X), constant(X),"
+ "float(X), atom(X),"
"list(X), number(X), pid(X),"
"port(X), reference(X), tuple(X),"
"binary(X), record(X,a) -> true end)"
@@ -530,7 +528,6 @@ autoimported(Config) when is_list(Config) ->
{self,0},
%{float,1}, see float_1_function/1
{is_atom,1},
- {is_constant,1},
{is_float,1},
{is_integer,1},
{is_list,1},
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index 3b2e637c84..d6d946a28f 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -445,9 +445,17 @@ split_specials(Config) when is_list(Config) ->
ok.
-error_handling(doc) ->
- ["Test that errors are handled correctly by the erlang code."];
-error_handling(Config) when is_list(Config) ->
+%% Test that errors are handled correctly by the erlang code.
+error_handling(_Config) ->
+ case test_server:is_native(re) of
+ true ->
+ %% Exceptions from native code look too different.
+ {skip,"re is native"};
+ false ->
+ error_handling()
+ end.
+
+error_handling() ->
% This test checks the exception tuples manufactured in the erlang
% code to hide the trapping from the user at least when it comes to errors
Dog = ?t:timetrap(?t:minutes(1)),
@@ -455,14 +463,14 @@ error_handling(Config) when is_list(Config) ->
% the trap to re:grun from grun, in the grun function clause
% that handles precompiled expressions
?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:run("apa",{1,2,3,4},[global])),
% An invalid capture list will also cause a badarg late,
% but with a non pre compiled RE, the exception should be thrown by the
% grun function clause that handles RE's compiled implicitly by
% the run/3 BIF before trapping.
?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:run("apa","p",[{capture,[1,{a}]},global])),
% And so the case of a precompiled expression together with
% a compile-option (binary and list subject):
@@ -473,88 +481,88 @@ error_handling(Config) when is_list(Config) ->
[<<"apa">>,
{re_pattern,1,0,_},
[global,unicode]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:run(<<"apa">>,RE,[global,unicode])),
?line {'EXIT',{badarg,[{re,run,
["apa",
{re_pattern,1,0,_},
[global,unicode]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:run("apa",RE,[global,unicode])),
?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[])),
?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[global])),
% The replace errors:
?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:replace("apa",{1,2,3,4},"X",[])),
?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:replace("apa",{1,2,3,4},"X",[global])),
?line {'EXIT',{badarg,[{re,replace,
["apa",
{re_pattern,1,0,_},
"X",
[unicode]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:replace("apa",RE,"X",[unicode])),
?line <<"aXa">> = iolist_to_binary(re:replace("apa","p","X",[])),
?line {'EXIT',{badarg,[{re,replace,
["apa","p","X",[{capture,all,binary}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{capture,all,binary}]))),
?line {'EXIT',{badarg,[{re,replace,
["apa","p","X",[{capture,all}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{capture,all}]))),
?line {'EXIT',{badarg,[{re,replace,
["apa","p","X",[{return,banana}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{return,banana}]))),
?line {'EXIT',{badarg,_}} = (catch re:replace("apa","(p","X",[])),
% Badarg, not compile error.
?line {'EXIT',{badarg,[{re,replace,
["apa","(p","X",[{return,banana}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","(p","X",
[{return,banana}]))),
% And the split errors:
?line [<<"a">>,<<"a">>] = (catch re:split("apa","p",[])),
?line [<<"a">>,<<"p">>,<<"a">>] = (catch re:split("apa",RE,[])),
?line {'EXIT',{badarg,[{re,split,["apa","p",[global]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa","p",[global])),
?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa","p",[{capture,all}])),
?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]],_},
- {?MODULE, error_handling,1,_} | _]}} =
+ {?MODULE, error_handling,0,_} | _]}} =
(catch re:split("apa","p",[{capture,all,binary}])),
?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",{1,2,3,4})),
?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",{1,2,3,4},[])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
[unicode]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",RE,[unicode])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
[{return,banana}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",RE,[{return,banana}])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
[banana]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",RE,[banana])),
?line {'EXIT',{badarg,_}} = (catch re:split("apa","(p")),
%Exception on bad argument, not compilation error
@@ -562,7 +570,7 @@ error_handling(Config) when is_list(Config) ->
["apa",
"(p",
[banana]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa","(p",[banana])),
?t:timetrap_cancel(Dog),
ok.
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index b6019b86f0..a881742f13 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -2388,13 +2388,28 @@ otp_6554(Config) when is_list(Config) ->
comm_err(<<"V = lists:seq(1, 20), case V of a -> ok end.">>),
?line "exception error: no function clause matching" =
comm_err(<<"fun(P) when is_pid(P) -> true end(a).">>),
- ?line "exception error: {function_clause," =
- comm_err(<<"erlang:error(function_clause, [unproper | list]).">>),
+ case test_server:is_native(erl_eval) of
+ true ->
+ %% Native code has different exit reason. Don't bother
+ %% testing them.
+ ok;
+ false ->
+ "exception error: {function_clause," =
+ comm_err(<<"erlang:error(function_clause, "
+ "[unproper | list]).">>),
+ %% Cheating:
+ "exception error: no function clause matching "
+ "erl_eval:do_apply(4)" ++ _ =
+ comm_err(<<"erlang:error(function_clause, [4]).">>),
+ "exception error: no function clause matching "
+ "lists:reverse(" ++ _ =
+ comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>),
+ "exception error: no function clause matching "
+ "lists:reverse(34) (lists.erl, line " ++ _ =
+ comm_err(<<"lists:reverse(34).">>)
+ end,
?line "exception error: function_clause" =
comm_err(<<"erlang:error(function_clause, 4).">>),
- %% Cheating:
- ?line "exception error: no function clause matching erl_eval:do_apply(4)" ++ _ =
- comm_err(<<"erlang:error(function_clause, [4]).">>),
?line "exception error: no function clause matching" ++ _ =
comm_err(<<"fun(a, b, c, d) -> foo end"
" (lists:seq(1,17),"
@@ -2404,10 +2419,6 @@ otp_6554(Config) when is_list(Config) ->
?line "exception error: no function clause matching" =
comm_err(<<"fun(P, q) when is_pid(P) -> true end(a, b).">>),
- ?line "exception error: no function clause matching lists:reverse(" ++ _ =
- comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>),
- ?line "exception error: no function clause matching lists:reverse(34) (lists.erl, line " ++ _ =
- comm_err(<<"lists:reverse(34).">>),
?line "exception error: no true branch found when evaluating an if expression" =
comm_err(<<"if length([a,b]) > 17 -> a end.">>),
?line "exception error: no such process or port" =
diff --git a/lib/stdlib/test/sofs_SUITE.erl b/lib/stdlib/test/sofs_SUITE.erl
index 73b282149a..f11c6ec4d6 100644
--- a/lib/stdlib/test/sofs_SUITE.erl
+++ b/lib/stdlib/test/sofs_SUITE.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
@@ -536,7 +536,7 @@ projection(Conf) when is_list(Conf) ->
from_term([], [[atom]]))),
?line {'EXIT', {badarg, _}} =
(catch projection({external, fun(X) -> X end}, from_term([[a]]))),
- ?line eval(projection({sofs,union},
+ ?line eval(projection(fun sofs:union/1,
from_term([[[1,2],[2,3]], [[a,b],[b,c]]])),
from_term([[1,2,3], [a,b,c]])),
?line eval(projection(fun(_) -> from_term([a]) end,
@@ -628,7 +628,7 @@ substitution(Conf) when is_list(Conf) ->
?line {'EXIT', {badarg, _}} =
(catch substitution({external, fun(X) -> X end}, from_term([[a]]))),
?line eval(substitution(fun(X) -> X end, from_term([], [[atom]])), E),
- ?line eval(substitution({sofs,union},
+ ?line eval(substitution(fun sofs:union/1,
from_term([[[1,2],[2,3]], [[a,b],[b,c]]])),
from_term([{[[1,2],[2,3]],[1,2,3]}, {[[a,b],[b,c]],[a,b,c]}])),
?line eval(substitution(fun(_) -> from_term([a]) end,
@@ -745,7 +745,7 @@ restriction(Conf) when is_list(Conf) ->
?line eval(restriction(Id, S3, E), E),
?line eval(restriction(Id, from_term([], [[atom]]), set([a])),
from_term([], [[atom]])),
- ?line eval(restriction({sofs,union},
+ ?line eval(restriction(fun sofs:union/1,
from_term([[[a],[b]], [[b],[c]],
[[], [a,b]], [[1],[2]]]),
from_term([[a,b],[1,2,3],[b,c]])),
@@ -862,7 +862,7 @@ drestriction(Conf) when is_list(Conf) ->
?line eval(drestriction(Id, S3, E), S3),
?line eval(drestriction(Id, from_term([], [[atom]]), set([a])),
from_term([], [[atom]])),
- ?line eval(drestriction({sofs,union},
+ ?line eval(drestriction(fun sofs:union/1,
from_term([[[a],[b]], [[b],[c]],
[[], [a,b]], [[1],[2]]]),
from_term([[a,b],[1,2,3],[b,c]])),
@@ -1028,7 +1028,7 @@ specification(Conf) when is_list(Conf) ->
end,
?line eval(specification({external,Fun2x}, S2), from_term([[1],[3]])),
- Fun3 = fun(_) -> neither_true_or_false end,
+ Fun3 = fun(_) -> neither_true_nor_false end,
?line {'EXIT', {badarg, _}} =
(catch specification(Fun3, set([a]))),
?line {'EXIT', {badarg, _}} =
@@ -1810,8 +1810,8 @@ partition_3(Conf) when is_list(Conf) ->
S12a = from_term([[[a],[b]], [[b],[c]], [[], [a,b]], [[1],[2]]]),
S12b = from_term([[a,b],[1,2,3],[b,c]]),
- ?line eval(partition({sofs,union}, S12a, S12b),
- lpartition({sofs,union}, S12a, S12b)),
+ ?line eval(partition(fun sofs:union/1, S12a, S12b),
+ lpartition(fun sofs:union/1, S12a, S12b)),
Fun13 = fun(_) -> from_term([a]) end,
S13a = from_term([], [[atom]]),
@@ -1879,12 +1879,9 @@ digraph(Conf) when is_list(Conf) ->
?line {'EXIT', {badarg, _}} =
(catch family_to_digraph(set([a]))),
- ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} =
- (catch family_to_digraph(set([a]), [foo])),
- ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} =
- (catch family_to_digraph(F, [foo])),
- ?line {'EXIT', {cyclic, [{sofs,family_to_digraph,[_,_],_}|_]}} =
- (catch family_to_digraph(family([{a,[a]}]),[acyclic])),
+ digraph_fail(badarg, catch family_to_digraph(set([a]), [foo])),
+ digraph_fail(badarg, catch family_to_digraph(F, [foo])),
+ digraph_fail(cyclic, catch family_to_digraph(family([{a,[a]}]),[acyclic])),
?line G1 = family_to_digraph(E),
?line {'EXIT', {badarg, _}} = (catch digraph_to_family(G1, foo)),
@@ -1927,6 +1924,13 @@ digraph(Conf) when is_list(Conf) ->
?line true = T0 == ets:all(),
ok.
+digraph_fail(ExitReason, Fail) ->
+ {'EXIT', {ExitReason, [{sofs,family_to_digraph,A,_}|_]}} = Fail,
+ case {test_server:is_native(sofs),A} of
+ {false,[_,_]} -> ok;
+ {true,2} -> ok
+ end.
+
constant_function(suite) -> [];
constant_function(doc) -> [""];
constant_function(Conf) when is_list(Conf) ->
@@ -1952,10 +1956,8 @@ misc(Conf) when is_list(Conf) ->
% the "functional" part:
?line eval(union(intersection(partition(1,S), partition(Id,S))),
difference(S, RR)),
-
- %% The function external:foo/1 is undefined.
?line {'EXIT', {undef, _}} =
- (catch projection({external,foo}, set([a,b,c]))),
+ (catch projection(fun external:foo/1, set([a,b,c]))),
ok.
relational_restriction(R) ->
@@ -1968,19 +1970,19 @@ family_specification(doc) -> [""];
family_specification(Conf) when is_list(Conf) ->
E = empty_set(),
%% internal
- ?line eval(family_specification({sofs, is_set}, E), E),
+ ?line eval(family_specification(fun sofs:is_set/1, E), E),
?line {'EXIT', {badarg, _}} =
- (catch family_specification({sofs,is_set}, set([]))),
+ (catch family_specification(fun sofs:is_set/1, set([]))),
?line F1 = from_term([{1,[1]}]),
- ?line eval(family_specification({sofs,is_set}, F1), F1),
+ ?line eval(family_specification(fun sofs:is_set/1, F1), F1),
Fun = fun(S) -> is_subset(S, set([0,1,2,3,4])) end,
?line F2 = family([{a,[1,2]},{b,[3,4,5]}]),
?line eval(family_specification(Fun, F2), family([{a,[1,2]}])),
?line F3 = from_term([{a,[]},{b,[]}]),
- ?line eval(family_specification({sofs,is_set}, F3), F3),
+ ?line eval(family_specification(fun sofs:is_set/1, F3), F3),
Fun2 = fun(_) -> throw(fippla) end,
?line fippla = (catch family_specification(Fun2, family([{a,[1]}]))),
- Fun3 = fun(_) -> neither_true_or_false end,
+ Fun3 = fun(_) -> neither_true_nor_false end,
?line {'EXIT', {badarg, _}} =
(catch family_specification(Fun3, F3)),
@@ -2095,22 +2097,22 @@ family_projection(Conf) when is_list(Conf) ->
?line eval(family_projection(fun(X) -> X end, family([])), E),
?line L1 = [{a,[]}],
- ?line eval(family_projection({sofs,union}, E), E),
- ?line eval(family_projection({sofs,union}, from_term(L1, SSType)),
+ ?line eval(family_projection(fun sofs:union/1, E), E),
+ ?line eval(family_projection(fun sofs:union/1, from_term(L1, SSType)),
family(L1)),
?line {'EXIT', {badarg, _}} =
- (catch family_projection({sofs,union}, set([]))),
+ (catch family_projection(fun sofs:union/1, set([]))),
?line {'EXIT', {badarg, _}} =
- (catch family_projection({sofs,union}, from_term([{1,[1]}]))),
+ (catch family_projection(fun sofs:union/1, from_term([{1,[1]}]))),
?line F2 = from_term([{a,[[1],[2]]},{b,[[3,4],[5]]}], SSType),
- ?line eval(family_projection({sofs,union}, F2),
+ ?line eval(family_projection(fun sofs:union/1, F2),
family_union(F2)),
?line F3 = from_term([{1,[{a,b},{b,c},{c,d}]},{3,[]},{5,[{3,5}]}],
SRType),
- ?line eval(family_projection({sofs,domain}, F3), family_domain(F3)),
- ?line eval(family_projection({sofs,range}, F3), family_range(F3)),
+ ?line eval(family_projection(fun sofs:domain/1, F3), family_domain(F3)),
+ ?line eval(family_projection(fun sofs:range/1, F3), family_range(F3)),
?line eval(family_projection(fun(_) -> E end, family([{a,[b,c]}])),
from_term([{a,[]}])),
@@ -2290,7 +2292,7 @@ partition_family(Conf) when is_list(Conf) ->
?line eval(partition_family(1, E), E),
?line eval(partition_family(2, E), E),
- ?line eval(partition_family({sofs,union}, E), E),
+ ?line eval(partition_family(fun sofs:union/1, E), E),
?line eval(partition_family(1, ER), EF),
?line eval(partition_family(2, ER), EF),
?line {'EXIT', {badarg, _}} = (catch partition_family(1, set([]))),
@@ -2354,7 +2356,7 @@ partition_family(Conf) when is_list(Conf) ->
?line {'EXIT', {badarg, _}} =
(catch partition_family({external, fun(X) -> X end},
from_term([[a]]))),
- ?line eval(partition_family({sofs,union},
+ ?line eval(partition_family(fun sofs:union/1,
from_term([[[1],[1,2]], [[1,2]]])),
from_term([{[1,2], [[[1],[1,2]],[[1,2]]]}])),
?line eval(partition_family(fun(X) -> X end,
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index fa6faa66f2..71b76c093f 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -34,8 +34,10 @@
%% API tests
-export([ sup_start_normal/1, sup_start_ignore_init/1,
- sup_start_ignore_child/1, sup_start_error_return/1,
- sup_start_fail/1, sup_stop_infinity/1,
+ sup_start_ignore_child/1, sup_start_ignore_temporary_child/1,
+ sup_start_ignore_temporary_child_start_child/1,
+ sup_start_ignore_temporary_child_start_child_simple/1,
+ sup_start_error_return/1, sup_start_fail/1, sup_stop_infinity/1,
sup_stop_timeout/1, sup_stop_brutal_kill/1, child_adm/1,
child_adm_simple/1, child_specs/1, extra_return/1]).
@@ -85,8 +87,10 @@ all() ->
groups() ->
[{sup_start, [],
[sup_start_normal, sup_start_ignore_init,
- sup_start_ignore_child, sup_start_error_return,
- sup_start_fail]},
+ sup_start_ignore_child, sup_start_ignore_temporary_child,
+ sup_start_ignore_temporary_child_start_child,
+ sup_start_ignore_temporary_child_start_child_simple,
+ sup_start_error_return, sup_start_fail]},
{sup_stop, [],
[sup_stop_infinity, sup_stop_timeout,
sup_stop_brutal_kill]},
@@ -191,6 +195,59 @@ sup_start_ignore_child(Config) when is_list(Config) ->
[2,1,0,2] = get_child_counts(sup_test).
%%-------------------------------------------------------------------------
+%% Tests what happens if child's init-callback returns ignore for a
+%% temporary child when ChildSpec is returned directly from supervisor
+%% init callback.
+%% Child spec shall NOT be saved!!!
+sup_start_ignore_temporary_child(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, [ignore]},
+ temporary, 1000, worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, temporary,
+ 1000, worker, []},
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, [Child1,Child2]}}),
+
+ [{child2, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ true = is_pid(CPid2),
+ [1,1,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
+%% Tests what happens if child's init-callback returns ignore for a
+%% temporary child when child is started with start_child/2.
+%% Child spec shall NOT be saved!!!
+sup_start_ignore_temporary_child_start_child(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, [ignore]},
+ temporary, 1000, worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, temporary,
+ 1000, worker, []},
+
+ {ok, undefined} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+
+ [{child2, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
+%% Tests what happens if child's init-callback returns ignore for a
+%% temporary child when child is started with start_child/2, and the
+%% supervisor is simple_one_for_one.
+%% Child spec shall NOT be saved!!!
+sup_start_ignore_temporary_child_start_child_simple(Config)
+ when is_list(Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, [ignore]},
+ temporary, 1000, worker, []},
+ {ok, _Pid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child1]}}),
+
+ {ok, undefined} = supervisor:start_child(sup_test, []),
+ {ok, CPid2} = supervisor:start_child(sup_test, []),
+
+ [{undefined, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
%% Tests what happens if init-callback returns a invalid value.
sup_start_error_return(Config) when is_list(Config) ->
process_flag(trap_exit, true),
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 2f0ecd3863..694d39ce9c 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 1.18
+STDLIB_VSN = 1.18.1
diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile
index 50369e633e..bac138e95a 100644
--- a/lib/syntax_tools/src/Makefile
+++ b/lib/syntax_tools/src/Makefile
@@ -26,7 +26,7 @@ EBIN = ../ebin
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
endif
-ERL_COMPILE_FLAGS += +warn_unused_vars +nowarn_shadow_vars +warn_unused_import +warn_missing_spec +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_unused_vars +nowarn_shadow_vars +warn_unused_import # +warn_missing_spec +warn_untyped_record
SOURCES=erl_syntax.erl erl_prettypr.erl erl_syntax_lib.erl \
erl_comment_scan.erl erl_recomment.erl erl_tidy.erl \
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 7f58fda519..32fd3722d6 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -6100,8 +6100,9 @@ implicit_fun_name(Node) ->
arity_qualifier(
set_pos(atom(Atom), Pos),
set_pos(integer(Arity), Pos)));
- {'fun', Pos, {function, Module, Atom, Arity}} ->
+ {'fun', _Pos, {function, Module, Atom, Arity}} ->
%% New in R15: fun M:F/A.
+ %% XXX: Perhaps set position for this as well?
module_qualifier(Module, arity_qualifier(Atom, Arity));
Node1 ->
data(Node1)
diff --git a/lib/toolbar/doc/src/toolbar.xml b/lib/toolbar/doc/src/toolbar.xml
index ad379438fe..3ad0b4eb78 100644
--- a/lib/toolbar/doc/src/toolbar.xml
+++ b/lib/toolbar/doc/src/toolbar.xml
@@ -33,6 +33,11 @@
<module>toolbar</module>
<modulesummary>GUI for Starting Tools and User Contributions</modulesummary>
<description>
+ <warning>
+ <p>
+ The Toolbar application is deprecated and will be removed in R16.
+ </p>
+ </warning>
<p>Toolbar makes it easier to use
the different Erlang tools - and the user contributions - which are provided.
It has a graphical user interface with an icon for each tool.
diff --git a/lib/toolbar/doc/src/toolbar_chapter.xml b/lib/toolbar/doc/src/toolbar_chapter.xml
index a80dc5bd3e..4ea2101218 100644
--- a/lib/toolbar/doc/src/toolbar_chapter.xml
+++ b/lib/toolbar/doc/src/toolbar_chapter.xml
@@ -28,6 +28,11 @@
<rev>A</rev>
<file>toolbar_chapter.xml</file>
</header>
+ <warning>
+ <p>
+ The Toolbar application is deprecated and will be removed in R16.
+ </p>
+ </warning>
<p>Toolbar provides an interface to the various Erlang tools which are available. Toolbar can also provide access to user supplied tools which are included with the Erlang software release. These tools are called GS Contributions.</p>
<p>All tools included in Toolbar must have a configuration file which contains information about the tool, such as its start function and the location of help information. The name of a configuration file must include the suffix <c>.tool</c>.
</p>
diff --git a/lib/toolbar/src/canvasbutton.erl b/lib/toolbar/src/canvasbutton.erl
index 38fce537bb..7613253efe 100644
--- a/lib/toolbar/src/canvasbutton.erl
+++ b/lib/toolbar/src/canvasbutton.erl
@@ -17,6 +17,9 @@
%% %CopyrightEnd%
%%
-module(canvasbutton).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,read,2}}]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
diff --git a/lib/toolbar/src/toolbar.erl b/lib/toolbar/src/toolbar.erl
index 67967172fe..b78df15700 100644
--- a/lib/toolbar/src/toolbar.erl
+++ b/lib/toolbar/src/toolbar.erl
@@ -17,6 +17,7 @@
%% %CopyrightEnd%
%%
-module(toolbar).
+-compile([{nowarn_deprecated_function,{gs,start,1}}]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
diff --git a/lib/toolbar/src/toolbar_graphics.erl b/lib/toolbar/src/toolbar_graphics.erl
index ad390440e3..b442d7ff06 100644
--- a/lib/toolbar/src/toolbar_graphics.erl
+++ b/lib/toolbar/src/toolbar_graphics.erl
@@ -17,6 +17,9 @@
%% %CopyrightEnd%
%%
-module(toolbar_graphics).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,read,2}}]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
diff --git a/lib/toolbar/src/toolbar_toolconfig.erl b/lib/toolbar/src/toolbar_toolconfig.erl
index 6dccb7ba72..6fb56cb1bd 100644
--- a/lib/toolbar/src/toolbar_toolconfig.erl
+++ b/lib/toolbar/src/toolbar_toolconfig.erl
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
-module(toolbar_toolconfig).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in
index 604332a91e..b8c4aed6e2 100644
--- a/lib/tools/c_src/Makefile.in
+++ b/lib/tools/c_src/Makefile.in
@@ -1,19 +1,20 @@
-# ``The contents of this file are subject to the Erlang Public License,
+#
+# %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 via the world wide web at http://www.erlang.org/.
-#
+# 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.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
+#
+# %CopyrightEnd%
#
include $(ERL_TOP)/make/target.mk
@@ -138,15 +139,17 @@ EMEM_LIBS = $(LIBS) \
EMEM_OBJS = $(addprefix $(EMEM_OBJ_DIR)/,$(notdir $(EMEM_SRCS:.c=.o)))
+ERTS_LIB = $(ERL_TOP/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE
+
#
# Misc targets
#
_create_dirs := $(shell mkdir -p $(CREATE_DIRS))
-all: erts_lib $(PROGS) $(DRIVERS)
+all: $(PROGS) $(DRIVERS)
-erts_lib:
+$(ERTS_LIB):
cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
@@ -174,7 +177,7 @@ $(EMEM_OBJ_DIR)/%.o: %.c
# Program targets
#
-$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS)
+$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS) $(ERTS_LIB)
$(PRE_LD) $(LD) $(EMEM_LDFLAGS) -o $@ $(EMEM_OBJS) $(EMEM_LIBS)
#
diff --git a/lib/tools/c_src/erl_memory.c b/lib/tools/c_src/erl_memory.c
index 872d55e789..5239176d03 100644
--- a/lib/tools/c_src/erl_memory.c
+++ b/lib/tools/c_src/erl_memory.c
@@ -1224,7 +1224,7 @@ print_main_footer(em_state *state)
switch (state->info.stop_reason) {
case EMTP_STOP:
- p += sprintf(p, stop_str);
+ p += sprintf(p, "%s", stop_str);
break;
case EMTP_EXIT:
p += sprintf(p, exit_str, state->info.exit_status);
@@ -2339,7 +2339,7 @@ usage(char *sw, char *error)
if (error)
exit(1);
else {
- char *help_str =
+ fprintf(filep,
"\n"
" [] - switch is allowed any number of times\n"
" {} - switch is allowed at most one time\n"
@@ -2370,8 +2370,7 @@ usage(char *sw, char *error)
" " SW_CHAR "o - display operation count values\n"
" " SW_CHAR "p <P> - set listen port to <P>\n"
" " SW_CHAR "t - display info about total values\n"
- " " SW_CHAR "v - verbose output\n";
- fprintf(filep, help_str);
+ " " SW_CHAR "v - verbose output\n");
exit(0);
}
diff --git a/lib/tools/test/fprof_SUITE.erl b/lib/tools/test/fprof_SUITE.erl
index 0da6d4a9ea..f491c1e227 100644
--- a/lib/tools/test/fprof_SUITE.erl
+++ b/lib/tools/test/fprof_SUITE.erl
@@ -191,11 +191,17 @@ tail_seq(Config) when is_list(Config) ->
%%%---------------------------------------------------------------------
-create_file_slow(doc) ->
- ["Tests the create_file_slow benchmark"];
-create_file_slow(suite) ->
- [];
-create_file_slow(Config) when is_list(Config) ->
+%% Tests the create_file_slow benchmark.
+create_file_slow(Config) ->
+ case test_server:is_native(lists) orelse
+ test_server:is_native(file) of
+ true ->
+ {skip,"Native libs -- tracing does not work"};
+ false ->
+ do_create_file_slow(Config)
+ end.
+
+do_create_file_slow(Config) ->
?line Timetrap = ?t:timetrap(?t:seconds(40)),
?line PrivDir = ?config(priv_dir, Config),
?line TraceFile =
diff --git a/lib/tv/doc/src/table_visualizer_chapter.xml b/lib/tv/doc/src/table_visualizer_chapter.xml
index 12efbe643c..dbfd322945 100644
--- a/lib/tv/doc/src/table_visualizer_chapter.xml
+++ b/lib/tv/doc/src/table_visualizer_chapter.xml
@@ -31,6 +31,12 @@
<rev>C</rev>
<file>table_visualizer.xml</file>
</header>
+ <warning>
+ <p>
+ The TV application has been superseded by the Observer application.
+ TV will be removed in R16.
+ </p>
+ </warning>
<p>The TV, TV, is a tool that enables the user to examine
ETS and Mnesia tables on any (connected) node in the currently running Erlang
system. Once a certain table has been opened in the tool, the content may be
diff --git a/lib/tv/doc/src/tv.xml b/lib/tv/doc/src/tv.xml
index 84b9f8c33d..83bbdfc052 100644
--- a/lib/tv/doc/src/tv.xml
+++ b/lib/tv/doc/src/tv.xml
@@ -36,6 +36,12 @@
<module>tv</module>
<modulesummary>TV graphically examines ETS and Mnesia tables. </modulesummary>
<description>
+ <warning>
+ <p>
+ The TV application has been superseded by the Observer application.
+ TV will be removed in R16.
+ </p>
+ </warning>
<p>TV enables the user to examine ETS and Mnesia tables. Once
a certain table has been opened in the tool, the content may be viewed at
various levels of detail. The content viewed may also be sorted, using any
diff --git a/lib/tv/src/tv_db.erl b/lib/tv/src/tv_db.erl
index 201b4c0e6b..179b75c2e6 100644
--- a/lib/tv/src/tv_db.erl
+++ b/lib/tv/src/tv_db.erl
@@ -22,6 +22,10 @@
%%%*********************************************************************
-module(tv_db).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_db_search.erl b/lib/tv/src/tv_db_search.erl
index 7bf5c4c048..6ae999253a 100644
--- a/lib/tv/src/tv_db_search.erl
+++ b/lib/tv/src/tv_db_search.erl
@@ -21,6 +21,18 @@
%%%
%%%*********************************************************************
-module(tv_db_search).
+-compile([{nowarn_deprecated_function,{gs,button,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,entry,3}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,label,3}},
+ {nowarn_deprecated_function,{gs,listbox,3}},
+ {nowarn_deprecated_function,{gs,radiobutton,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_etsread.erl b/lib/tv/src/tv_etsread.erl
index d3240ef513..b3e38f9d45 100644
--- a/lib/tv/src/tv_etsread.erl
+++ b/lib/tv/src/tv_etsread.erl
@@ -25,6 +25,9 @@
-module(tv_etsread).
+-compile([{nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_info.erl b/lib/tv/src/tv_info.erl
index 7bc31e35cd..941286362c 100644
--- a/lib/tv/src/tv_info.erl
+++ b/lib/tv/src/tv_info.erl
@@ -16,6 +16,14 @@
%%
%% %CopyrightEnd%
-module(tv_info).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,listbox,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_ip.erl b/lib/tv/src/tv_ip.erl
index aeec4e8f6d..2d3ada878a 100644
--- a/lib/tv/src/tv_ip.erl
+++ b/lib/tv/src/tv_ip.erl
@@ -16,6 +16,12 @@
%%
%% %CopyrightEnd%
-module(tv_ip).
+-compile([{nowarn_deprecated_function,{gs,canvas,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_main.erl b/lib/tv/src/tv_main.erl
index 36cf92bee3..fbf56971f9 100644
--- a/lib/tv/src/tv_main.erl
+++ b/lib/tv/src/tv_main.erl
@@ -16,6 +16,20 @@
%%
%% %CopyrightEnd%
-module(tv_main).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,frame,3}},
+ {nowarn_deprecated_function,{gs,grid,3}},
+ {nowarn_deprecated_function,{gs,gridline,2}},
+ {nowarn_deprecated_function,{gs,label,3}},
+ {nowarn_deprecated_function,{gs,menu,2}},
+ {nowarn_deprecated_function,{gs,menubar,3}},
+ {nowarn_deprecated_function,{gs,menubutton,2}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,menuitem,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_new_table.erl b/lib/tv/src/tv_new_table.erl
index 3d62b0548b..d31b9a4ee2 100644
--- a/lib/tv/src/tv_new_table.erl
+++ b/lib/tv/src/tv_new_table.erl
@@ -16,6 +16,16 @@
%%
%% %CopyrightEnd%k
-module(tv_new_table).
+-compile([{nowarn_deprecated_function,{gs,button,3}},
+ {nowarn_deprecated_function,{gs,checkbutton,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,entry,3}},
+ {nowarn_deprecated_function,{gs,frame,3}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,radiobutton,3}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_nodewin.erl b/lib/tv/src/tv_nodewin.erl
index 3999d201d8..9030ed930f 100644
--- a/lib/tv/src/tv_nodewin.erl
+++ b/lib/tv/src/tv_nodewin.erl
@@ -16,6 +16,15 @@
%%
%% %CopyrightEnd%
-module(tv_nodewin).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,listbox,3}},
+ {nowarn_deprecated_function,{gs,menu,3}},
+ {nowarn_deprecated_function,{gs,menubar,3}},
+ {nowarn_deprecated_function,{gs,menubutton,3}},
+ {nowarn_deprecated_function,{gs,menuitem,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_pb.erl b/lib/tv/src/tv_pb.erl
index 78a27185dc..fa3dcde919 100644
--- a/lib/tv/src/tv_pb.erl
+++ b/lib/tv/src/tv_pb.erl
@@ -16,6 +16,9 @@
%%
%% %CopyrightEnd%
-module(tv_pb).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,frame,2}}]).
diff --git a/lib/tv/src/tv_pb_funcs.erl b/lib/tv/src/tv_pb_funcs.erl
index 87a4719bbd..0670d2795f 100644
--- a/lib/tv/src/tv_pb_funcs.erl
+++ b/lib/tv/src/tv_pb_funcs.erl
@@ -16,6 +16,12 @@
%%
%% %CopyrightEnd%
-module(tv_pb_funcs).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,canvas,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}}]).
diff --git a/lib/tv/src/tv_pc.erl b/lib/tv/src/tv_pc.erl
index 50214fe06a..fcb7aba3a7 100644
--- a/lib/tv/src/tv_pc.erl
+++ b/lib/tv/src/tv_pc.erl
@@ -25,6 +25,7 @@
-module(tv_pc).
+-compile([{nowarn_deprecated_function,{gs,config,2}}]).
diff --git a/lib/tv/src/tv_pc_menu_handling.erl b/lib/tv/src/tv_pc_menu_handling.erl
index 16195bf91f..5d411b106e 100644
--- a/lib/tv/src/tv_pc_menu_handling.erl
+++ b/lib/tv/src/tv_pc_menu_handling.erl
@@ -25,6 +25,10 @@
-module(tv_pc_menu_handling).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_pd.erl b/lib/tv/src/tv_pd.erl
index ea14bf67b1..6694ea22a3 100644
--- a/lib/tv/src/tv_pd.erl
+++ b/lib/tv/src/tv_pd.erl
@@ -24,6 +24,11 @@
-module(tv_pd).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,destroy,1}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_pd_display.erl b/lib/tv/src/tv_pd_display.erl
index f5a30cb640..dab442e28e 100644
--- a/lib/tv/src/tv_pd_display.erl
+++ b/lib/tv/src/tv_pd_display.erl
@@ -22,6 +22,13 @@
%%%*********************************************************************
-module(tv_pd_display).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,editor,2}},
+ {nowarn_deprecated_function,{gs,entry,3}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,read,2}}]).
diff --git a/lib/tv/src/tv_pd_frames.erl b/lib/tv/src/tv_pd_frames.erl
index 4e091ac9f0..d18dcaf70d 100644
--- a/lib/tv/src/tv_pd_frames.erl
+++ b/lib/tv/src/tv_pd_frames.erl
@@ -16,6 +16,8 @@
%%
%% %CopyrightEnd%
-module(tv_pd_frames).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,frame,2}}]).
diff --git a/lib/tv/src/tv_pd_scale.erl b/lib/tv/src/tv_pd_scale.erl
index c94e57f468..2f98c3183f 100644
--- a/lib/tv/src/tv_pd_scale.erl
+++ b/lib/tv/src/tv_pd_scale.erl
@@ -24,6 +24,8 @@
-module(tv_pd_scale).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,scale,2}}]).
diff --git a/lib/tv/src/tv_pg.erl b/lib/tv/src/tv_pg.erl
index ba8782392b..0b36b18212 100644
--- a/lib/tv/src/tv_pg.erl
+++ b/lib/tv/src/tv_pg.erl
@@ -16,6 +16,7 @@
%%
%% %CopyrightEnd%
-module(tv_pg).
+-compile([{nowarn_deprecated_function,{gs,config,2}}]).
diff --git a/lib/tv/src/tv_pg_gridfcns.erl b/lib/tv/src/tv_pg_gridfcns.erl
index 3d23c8a69f..e47dac28a8 100644
--- a/lib/tv/src/tv_pg_gridfcns.erl
+++ b/lib/tv/src/tv_pg_gridfcns.erl
@@ -16,6 +16,10 @@
%%
%% %CopyrightEnd%
-module(tv_pg_gridfcns).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,read,2}}]).
diff --git a/lib/tv/src/tv_poll_dialog.erl b/lib/tv/src/tv_poll_dialog.erl
index 8d41251266..4bf49f44f1 100644
--- a/lib/tv/src/tv_poll_dialog.erl
+++ b/lib/tv/src/tv_poll_dialog.erl
@@ -22,7 +22,13 @@
%%%*********************************************************************
-module(tv_poll_dialog).
-
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,radiobutton,2}},
+ {nowarn_deprecated_function,{gs,scale,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,2}}]).
-export([start/1, init/2]).
diff --git a/lib/tv/src/tv_pw.erl b/lib/tv/src/tv_pw.erl
index 8b3186e090..bd6d06e241 100644
--- a/lib/tv/src/tv_pw.erl
+++ b/lib/tv/src/tv_pw.erl
@@ -23,6 +23,7 @@
-module(tv_pw).
+-compile([{nowarn_deprecated_function,{gs,config,2}}]).
diff --git a/lib/tv/src/tv_pw_window.erl b/lib/tv/src/tv_pw_window.erl
index 9cb5c879c0..0cd241a031 100644
--- a/lib/tv/src/tv_pw_window.erl
+++ b/lib/tv/src/tv_pw_window.erl
@@ -23,6 +23,10 @@
-module(tv_pw_window).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,menuitem,3}},
+ {nowarn_deprecated_function,{gs,start,0}}]).
diff --git a/lib/tv/src/tv_rec_edit.erl b/lib/tv/src/tv_rec_edit.erl
index e8f663073e..f6c09ebc67 100644
--- a/lib/tv/src/tv_rec_edit.erl
+++ b/lib/tv/src/tv_rec_edit.erl
@@ -16,6 +16,16 @@
%%
%% %CopyrightEnd%
-module(tv_rec_edit).
+-compile([{nowarn_deprecated_function,{gs,button,2}},
+ {nowarn_deprecated_function,{gs,button,3}},
+ {nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,entry,3}},
+ {nowarn_deprecated_function,{gs,frame,2}},
+ {nowarn_deprecated_function,{gs,frame,3}},
+ {nowarn_deprecated_function,{gs,label,2}},
+ {nowarn_deprecated_function,{gs,read,2}},
+ {nowarn_deprecated_function,{gs,start,0}},
+ {nowarn_deprecated_function,{gs,window,3}}]).
diff --git a/lib/tv/src/tv_utils.erl b/lib/tv/src/tv_utils.erl
index fd232bde69..9c7458d302 100644
--- a/lib/tv/src/tv_utils.erl
+++ b/lib/tv/src/tv_utils.erl
@@ -16,6 +16,9 @@
%%
%% %CopyrightEnd%
-module(tv_utils).
+-compile([{nowarn_deprecated_function,{gs,config,2}},
+ {nowarn_deprecated_function,{gs,create,3}},
+ {nowarn_deprecated_function,{gs,destroy,1}}]).
diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile
index c8eb6174c4..03e9f1e1bb 100644
--- a/lib/wx/doc/src/Makefile
+++ b/lib/wx/doc/src/Makefile
@@ -22,7 +22,7 @@
# ----------------------------------------------------
include ../../vsn.mk
include ../../config.mk
-APPLICATION=wxErlang
+APPLICATION=wx
ErlMods = wx.erl wx_object.erl
diff --git a/lib/xmerl/doc/src/xmerl_ug.xmlsrc b/lib/xmerl/doc/src/xmerl_ug.xmlsrc
index 6ee6707e53..9ef8fbb0b9 100644
--- a/lib/xmerl/doc/src/xmerl_ug.xmlsrc
+++ b/lib/xmerl/doc/src/xmerl_ug.xmlsrc
@@ -36,9 +36,9 @@
<title>Features</title>
<p>The <em>xmerl</em> XML parser is able to parse XML documents
according to the XML 1.0 standard. As default it performs
- well-formed parsing,(syntax checks and checks of well-formed
+ well-formed parsing, (syntax checks and checks of well-formed
constraints). Optionally one can also use xmerl as a validating
- parser,(validate according to referenced DTD and validating
+ parser, (validate according to referenced DTD and validating
constraints). By means of for example the xmerl_xs module it is
possible to transform the parsed result to other formats,
e.g. text, HTML, XML etc.</p>
diff --git a/lib/xmerl/src/xmerl_uri.erl b/lib/xmerl/src/xmerl_uri.erl
index a0c6f1c2a7..1864651491 100644
--- a/lib/xmerl/src/xmerl_uri.erl
+++ b/lib/xmerl/src/xmerl_uri.erl
@@ -358,7 +358,7 @@ scan_host(C0) ->
%% Hex3=<?HEX;
%% Hex4=<?HEX ->
%% {C1,lists:reverse(lists:append(IPv6address))};
- {C1,Hostname,[A|_HostF]} ->
+ {C1,Hostname,[_A|_HostF]} ->
{C1,lists:reverse(lists:append(Hostname))}
%% _ ->
%% {error,no_host}