diff options
Diffstat (limited to 'lib')
65 files changed, 944 insertions, 355 deletions
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml index f04bac9fec..23d122f69a 100644 --- a/lib/asn1/doc/src/asn1ct.xml +++ b/lib/asn1/doc/src/asn1ct.xml @@ -356,11 +356,11 @@ File3.asn </pre> </item> </list> - <p>Schematically the following happens for each type in the module: + <p>Schematically the following happens for each type in the module:</p> <code type="none"> {ok, Value} = asn1ct:value(Module, Type), {ok, Bytes} = asn1ct:encode(Module, Type, Value), -{ok, Value} = asn1ct:decode(Module, Type, Bytes).</code></p> +{ok, Value} = asn1ct:decode(Module, Type, Bytes).</code> <p>The <c>test</c> functions utilizes the <c>*.asn1db</c> files for all included modules. If they are located in a different diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index 151159ad69..f446f8ac13 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -99,11 +99,11 @@ be executed by Common Test. A test case is represented by an atom, the name of the test case function. A test case group is represented by a <c>group</c> tuple, where <c>GroupName</c>, - an atom, is the name of the group (defined in <c><seealso marker="#Module:groups-0">groups/0</seealso></c>). + an atom, is the name of the group (defined in <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). Execution properties for groups may also be specified, both for a top level group and for any of its sub-groups. Group execution properties specified here, will override - properties in the group definition (see <c><seealso marker="#Module:groups-0">groups/0</seealso></c>). + properties in the group definition (see <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). (With value <c>default</c>, the group definition properties will be used).</p> @@ -186,8 +186,8 @@ test cases in the suite).</p> <p>The <c>timetrap</c> tag sets the maximum time each - test case is allowed to execute (including <c><seealso marker="#Module:init_per_testcase-2">init_per_testcase/2</seealso></c> - and <c><seealso marker="#Module:end_per_testcase-2">end_per_testcase/2</seealso></c>). If the timetrap time is + test case is allowed to execute (including <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + and <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso>). If the timetrap time is exceeded, the test case fails with reason <c>timetrap_timeout</c>. A <c>TimeFunc</c> function can be used to set a new timetrap by returning a <c>TimeVal</c>. It may also be @@ -203,11 +203,11 @@ in any of the configuration files, all test cases are skipped. For more information about the 'require' functionality, see the reference manual for the function - <c><seealso marker="ct#require-1">ct:require/1/2</seealso></c>.</p> + <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso>.</p> <p>With <c>userdata</c>, it is possible for the user to specify arbitrary test suite related information which can be - read by calling <c><seealso marker="ct#userdata-2">ct:userdata/2</seealso></c>.</p> + read by calling <seealso marker="ct#userdata-2"><c>ct:userdata/2</c></seealso>.</p> <p>The <c>ct_hooks</c> tag specifies which <seealso marker="ct_hooks_chapter">Common Test Hooks</seealso> @@ -266,7 +266,7 @@ <p>This function is called as the last test case in the suite. It is meant to be used for cleaning up after - <c><seealso marker="#Module:init_per_suite-1">init_per_suite/1</seealso></c>. + <seealso marker="#Module:init_per_suite-1"><c>init_per_suite/1</c></seealso>. For information on <c>save_config</c>, please see <seealso marker="dependencies_chapter#save_config">Dependencies between Test Cases and Suites</seealso> in the User's Guide.</p> @@ -313,13 +313,13 @@ return a list of tagged tuples that specify various properties related to the execution of a test case group (i.e. its test cases and sub-groups). Properties set by - <c><seealso marker="#Module:group-1">group/1</seealso></c> override + <seealso marker="#Module:group-1"><c>group/1</c></seealso> override properties with the same key that have been previously set by - <c><seealso marker="#Module:suite-0">suite/0</seealso></c>.</p> + <seealso marker="#Module:suite-0"><c>suite/0</c></seealso>.</p> <p>The <c>timetrap</c> tag sets the maximum time each - test case is allowed to execute (including <c><seealso marker="#Module:init_per_testcase-2">init_per_testcase/2</seealso></c> - and <c><seealso marker="#Module:end_per_testcase-2">end_per_testcase/2</seealso></c>). If the timetrap time is + test case is allowed to execute (including <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + and <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso>). If the timetrap time is exceeded, the test case fails with reason <c>timetrap_timeout</c>. A <c>TimeFunc</c> function can be used to set a new timetrap by returning a <c>TimeVal</c>. It may also be @@ -334,11 +334,11 @@ in any of the configuration files, all test cases in this group are skipped. For more information about the 'require' functionality, see the reference manual for the function - <c><seealso marker="ct#require-1">ct:require/1/2</seealso></c>.</p> + <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso>.</p> <p>With <c>userdata</c>, it is possible for the user to specify arbitrary test case group related information which can be - read by calling <c><seealso marker="ct#userdata-2">ct:userdata/2</seealso></c>.</p> + read by calling <seealso marker="ct#userdata-2"><c>ct:userdata/2</c></seealso>.</p> <p>The <c>ct_hooks</c> tag specifies which <seealso marker="ct_hooks_chapter">Common Test Hooks</seealso> @@ -371,7 +371,7 @@ test case group. It typically contains initializations which are common for all test cases and sub-groups in the group, and which shall only be performed once. <c>GroupName</c> is the name of the - group, as specified in the group definition (see <c><seealso marker="#Module:groups-0">groups/0</seealso></c>). The + group, as specified in the group definition (see <seealso marker="#Module:groups-0"><c>groups/0</c></seealso>). The <c>Config</c> parameter is the configuration data which can be modified here. The return value of this function is given as <c>Config</c> to all test cases and sub-groups in the group. If <c>{skip,Reason}</c> @@ -400,10 +400,10 @@ <p> OPTIONAL </p> <p>This function is called after the execution of a test case group is finished. - It is meant to be used for cleaning up after <c><seealso marker="#Module:init_per_group-2">init_per_group/2</seealso></c>. + It is meant to be used for cleaning up after <seealso marker="#Module:init_per_group-2"><c>init_per_group/2</c></seealso>. By means of <c>{return_group_result,Status}</c>, it is possible to return a status value for a nested sub-group. The status can be retrieved in - <c><seealso marker="#Module:end_per_group-2">end_per_group/2</seealso></c> for the group on the level above. The status will also + <seealso marker="#Module:end_per_group-2"><c>end_per_group/2</c></seealso> for the group on the level above. The status will also be used by Common Test for deciding if execution of a group should proceed in case the property <c>sequence</c> or <c>repeat_until_*</c> is set.</p> @@ -454,7 +454,7 @@ <p> OPTIONAL </p> <p> This function is called after each test case, and can be used - to clean up after <c><seealso marker="#Module:init_per_testcase-2">init_per_testcase/2</seealso></c> and the test case. + to clean up after <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> and the test case. Any return value (besides <c>{fail,Reason}</c> and <c>{save_config,SaveConfig}</c>) is ignored. By returning <c>{fail,Reason}</c>, <c>TestCase</c> will be marked as failed (even though it was actually successful in the sense that it returned @@ -496,15 +496,15 @@ <p>This is the test case info function. It is supposed to return a list of tagged tuples that specify various properties related to the execution of this particular test case. - Properties set by <c><seealso marker="#Module:Testcase-0">Testcase/0</seealso></c> override + Properties set by <seealso marker="#Module:Testcase-0"><c>Testcase/0</c></seealso> override properties that have been previously set for the test case - by <c><seealso marker="#Module:group-1">group/1</seealso></c> or <c><seealso marker="#Module:suite-0">suite/0</seealso></c>.</p> + by <seealso marker="#Module:group-1"><c>group/1</c></seealso> or <seealso marker="#Module:suite-0"><c>suite/0</c></seealso>.</p> <p>The <c>timetrap</c> tag sets the maximum time the test case is allowed to execute. If the timetrap time is exceeded, the test case fails with reason - <c>timetrap_timeout</c>. <c><seealso marker="#Module:init_per_testcase-2">init_per_testcase/2</seealso></c> - and <c><seealso marker="#Module:end_per_testcase-2">end_per_testcase/2</seealso></c> are included in the + <c>timetrap_timeout</c>. <seealso marker="#Module:init_per_testcase-2"><c>init_per_testcase/2</c></seealso> + and <seealso marker="#Module:end_per_testcase-2"><c>end_per_testcase/2</c></seealso> are included in the timetrap time. A <c>TimeFunc</c> function can be used to set a new timetrap by returning a <c>TimeVal</c>. It may also be used to trigger a timetrap timeout by, at some point, returning a @@ -518,15 +518,15 @@ configuration files, the test case is skipped. For more information about the 'require' functionality, see the reference manual for the function - <c><seealso marker="ct#require-1">ct:require/1/2</seealso></c>.</p> + <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso>.</p> <p>If <c>timetrap</c> and/or <c>require</c> is not set, the - default values specified by <c><seealso marker="#Module:suite-0">suite/0</seealso></c> (or - <c><seealso marker="#Module:group-1">group/1</seealso></c>) will be used.</p> + default values specified by <seealso marker="#Module:suite-0"><c>suite/0</c></seealso> (or + <seealso marker="#Module:group-1"><c>group/1</c></seealso>) will be used.</p> <p>With <c>userdata</c>, it is possible for the user to specify arbitrary test case related information which can be - read by calling <c><seealso marker="ct#userdata-3">ct:userdata/3</seealso></c>.</p> + read by calling <seealso marker="ct#userdata-3"><c>ct:userdata/3</c></seealso>.</p> <p>Other tuples than the ones defined will simply be ignored.</p> @@ -554,7 +554,7 @@ <p>This is the implementation of a test case. Here you must call the functions you want to test, and do whatever you need to check the result. If something fails, make sure the - function causes a runtime error, or call <c><seealso marker="ct#fail-1">ct:fail/1/2</seealso></c> + function causes a runtime error, or call <seealso marker="ct#fail-1"><c>ct:fail/1/2</c></seealso> (which also causes the test case process to terminate).</p> <p>Elements from the <c>Config</c> list can e.g. be read @@ -582,7 +582,7 @@ Test Cases and Suites</seealso> in the User's Guide.</p> </desc> </func> - + </funcs> </erlref> diff --git a/lib/common_test/doc/src/config_file_chapter.xml b/lib/common_test/doc/src/config_file_chapter.xml index d90adf8d7b..99e25faf27 100644 --- a/lib/common_test/doc/src/config_file_chapter.xml +++ b/lib/common_test/doc/src/config_file_chapter.xml @@ -80,7 +80,7 @@ test is skipped (unless a default value has been specified, see the <seealso marker="write_test_chapter#info_function">test case info function</seealso> chapter for details). There is also a function - <c><seealso marker="ct#require-1">ct:require/1/2</seealso></c> which can be called from a test case + <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> which can be called from a test case in order to check if a specific variable is available. The return value from this function must be checked explicitly and appropriate action be taken depending on the result (e.g. to skip the test case @@ -90,7 +90,7 @@ info-list should look like this: <c>{require,CfgVarName}</c> or <c>{require,AliasName,CfgVarName}</c>. The arguments <c>AliasName</c> and <c>CfgVarName</c> are the same as the - arguments to <c><seealso marker="ct#require-1">ct:require/1/2</seealso></c> which are described in the + arguments to <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> which are described in the reference manual for <seealso marker="ct">ct</seealso>. <c>AliasName</c> becomes an alias for the configuration variable, and can be used as reference to the configuration data value. @@ -103,7 +103,7 @@ (or test case) and improve readability.</item> </list> <p>To read the value of a config variable, use the function - <c><seealso marker="ct#get_config-1">get_config/1/2/3</seealso></c> + <seealso marker="ct#get_config-1"><c>get_config/1/2/3</c></seealso> which is also described in the reference manual for <seealso marker="ct">ct</seealso>.</p> <p>Example:</p> @@ -121,7 +121,7 @@ <section> <title>Using configuration variables defined in multiple files</title> <p>If a configuration variable is defined in multiple files and you - want to access all possible values, you may use the <c><seealso marker="ct#get_config-3">ct:get_config/3</seealso></c> + want to access all possible values, you may use the <seealso marker="ct#get_config-3"><c>ct:get_config/3</c></seealso> function and specify <c>all</c> in the options list. The values will then be returned in a list and the order of the elements corresponds to the order that the config files were specified at startup. Please see @@ -133,7 +133,7 @@ <marker id="encrypted_config_files"></marker> <p>It is possible to encrypt configuration files containing sensitive data if these files must be stored in open and shared directories.</p> - <p>Call <c><seealso marker="ct#encrypt_config_file-2">ct:encrypt_config_file/2/3</seealso></c> to have Common Test encrypt a + <p>Call <seealso marker="ct#encrypt_config_file-2"><c>ct:encrypt_config_file/2/3</c></seealso> to have Common Test encrypt a specified file using the DES3 function in the OTP <c>crypto</c> application. The encrypted file can then be used as a regular configuration file, in combination with other encrypted files or normal text files. The key @@ -142,7 +142,7 @@ <c>decrypt_file</c> flag/option, or a key file in a predefined location.</p> <p>Common Test also provides decryption functions, - <c><seealso marker="ct#decrypt_config_file-2">ct:decrypt_config_file/2/3</seealso></c>, for recreating the original text + <seealso marker="ct#decrypt_config_file-2"><c>ct:decrypt_config_file/2/3</c></seealso>, for recreating the original text files.</p> <p>Please see the <seealso marker="ct">ct</seealso> reference manual for @@ -152,8 +152,8 @@ <section> <title>Opening connections by using configuration data</title> <p>There are two different methods for opening a connection - by means of the support functions in e.g. <c><seealso marker="ct_ssh">ct_ssh</seealso></c>, <c><seealso marker="ct_ftp">ct_ftp</seealso></c>, - and <c><seealso marker="ct_telnet">ct_telnet</seealso></c>:</p> + by means of the support functions in e.g. <seealso marker="ct_ssh"><c>ct_ssh</c></seealso>, <seealso marker="ct_ftp"><c>ct_ftp</c></seealso>, + and <seealso marker="ct_telnet"><c>ct_telnet</c></seealso>:</p> <list> <item>Using a configuration target name (an alias) as reference.</item> <item>Using the configuration variable as reference.</item> diff --git a/lib/common_test/doc/src/cover_chapter.xml b/lib/common_test/doc/src/cover_chapter.xml index 736486350b..b952df58f1 100644 --- a/lib/common_test/doc/src/cover_chapter.xml +++ b/lib/common_test/doc/src/cover_chapter.xml @@ -94,7 +94,7 @@ <p><c>$ ct_run -dir $TESTOBJS/db -cover $TESTOBJS/db/config/db.coverspec</c></p> <p>You may also pass the cover specification file name in a - call to <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>, by adding a <c>{cover,CoverSpec}</c> + call to <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, by adding a <c>{cover,CoverSpec}</c> tuple to the <c>Opts</c> argument. Also, you can of course enable code coverage in your test specifications (read more in the chapter about @@ -102,8 +102,8 @@ specifications</seealso>).</p> </section> - <marker id="cover_stop"></marker> <section> + <marker id="cover_stop"></marker> <title>Stopping the cover tool when tests are completed</title> <p>By default the Cover tool is automatically stopped when the tests are completed. This causes the original (non cover @@ -120,8 +120,8 @@ <p>The option can be set by using the <c>-cover_stop</c> flag with <c>ct_run</c>, by adding <c>{cover_stop,true|false}</c> to the - Opts argument to <c><seealso - marker="ct#run_test-1">ct:run_test/1</seealso></c>, or by adding + Opts argument to <seealso + marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, or by adding a <c>cover_stop</c> term in your test specification (see chapter about <seealso marker="run_test_chapter#test_specifications">test @@ -189,8 +189,8 @@ specification file for Common Test).</p> </section> - <marker id="cross_cover"/> <section> + <marker id="cross_cover"/> <title>Cross cover analysis</title> <p>The cross cover mechanism allows cover analysis of modules across multiple tests. It is useful if some code, e.g. a library diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index fe871eb516..a706bbf9e6 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -192,12 +192,12 @@ <section> <title>External configuration data and Logging</title> <p>It's possible in the CTH to read configuration data values - by calling <c><seealso marker="ct#get_config-1">ct:get_config/1/2/3</seealso></c> (as explained in the + by calling <seealso marker="ct#get_config-1"><c>ct:get_config/1/2/3</c></seealso> (as explained in the <seealso marker="config_file_chapter#require_config_data"> External configuration data</seealso> chapter). The config variables in question must, as always, first have been <c>required</c> by means of a suite-, group-, or test case info function, - or the <c><seealso marker="ct#require-1">ct:require/1/2</seealso></c> function. Note that the latter can also be used + or the <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> function. Note that the latter can also be used in CT hook functions.</p> <p>The CT hook functions may call any of the logging functions available in the <c>ct</c> interface to print information to the log files, or to @@ -252,13 +252,13 @@ {ok, Handle} -> {[{db_handle, Handle} | Config], CTHState#state{ handle = Handle }} end.</code> - <note>If using multiple CTHs, the first part of the return tuple will be + <note><p>If using multiple CTHs, the first part of the return tuple will be used as input for the next CTH. So in the case above the next CTH might get <c>{fail,Reason}</c> as the second parameter. If you have many CTHs which interact, it might be a good idea to not let each CTH return <c>fail</c> or <c>skip</c>. Instead return that an action should be taken through the <c>Config</c> list and implement a CTH which at the end takes - the correct action. </note> + the correct action.</p></note> </section> @@ -301,9 +301,9 @@ post_end_per_testcase(_TC, Config, Return, CTHState) -> %% Do nothing if tc does not crash. {Return, CTHState}.</code> - <note>Recovering from a testcase failure using CTHs should only be done as + <note><p>Recovering from a testcase failure using CTHs should only be done as a last resort. If used wrongly it could become very difficult to - determine which tests pass or fail in a test run</note> + determine which tests pass or fail in a test run</p></note> </section> diff --git a/lib/common_test/doc/src/ct_master_chapter.xml b/lib/common_test/doc/src/ct_master_chapter.xml index 9e848e99bb..1d2d64a166 100644 --- a/lib/common_test/doc/src/ct_master_chapter.xml +++ b/lib/common_test/doc/src/ct_master_chapter.xml @@ -220,6 +220,7 @@ <p>The default <seealso marker="ct_slave">ct_slave</seealso> callback module, which is part of the Common Test application, has the following features: + </p> <list> <item>Starting Erlang target nodes on local or remote hosts (ssh is used for communication). @@ -237,7 +238,6 @@ Functions can be given as a list of {Module, Function, Arguments} tuples. </item> </list> - </p> <p>Note that it is possible to specify an <c>eval</c> term for the node as well as <c>startup_functions</c> in the <c>node_start</c> options list. In this case first the node will be started, then the <c>startup_functions</c> are diff --git a/lib/common_test/doc/src/ct_run.xml b/lib/common_test/doc/src/ct_run.xml index c87c765ae7..d857b20d88 100644 --- a/lib/common_test/doc/src/ct_run.xml +++ b/lib/common_test/doc/src/ct_run.xml @@ -36,8 +36,6 @@ OS command line. </comsummary> - <marker id="top"></marker> - <description> <p>The <c>ct_run</c> program is automatically installed with Erlang/OTP and Common Test (please see the Installation chapter in the Common @@ -48,7 +46,7 @@ particular mode.</p> <p>There is an interface function that corresponds to this program, - called <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>, for starting Common Test from the Erlang + called <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, for starting Common Test from the Erlang shell (or an Erlang program). Please see the <c>ct</c> man page for details.</p> @@ -83,9 +81,9 @@ <p>it prints all valid start flags to stdout.</p> </description> - <marker id="ct_run"></marker> <section> + <marker id="ct_run"></marker> <title>Run tests from command line</title> <pre> ct_run [-dir TestDir1 TestDir2 .. TestDirN] | diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml index 10a9b52d39..3cc21f28de 100644 --- a/lib/common_test/doc/src/event_handler_chapter.xml +++ b/lib/common_test/doc/src/event_handler_chapter.xml @@ -64,7 +64,7 @@ <marker id="usage"></marker> <title>Usage</title> <p>Event handlers may be installed by means of an <c>event_handler</c> - start flag (<c>ct_run</c>) or option (<c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>), where the + start flag (<c>ct_run</c>) or option (<seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>), where the argument specifies the names of one or more event handler modules. Example:</p> <p><c>$ ct_run -suite test/my_SUITE -event_handler handlers/my_evh1 @@ -78,7 +78,7 @@ example).</p> <p>An event_handler tuple in the argument <c>Opts</c> has the following - definition (see also <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c> in the reference manual):</p> + definition (see also <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> in the reference manual):</p> <pre> {event_handler,EventHandlers} @@ -224,8 +224,9 @@ <c>end_per_testcase</c> for the case failed. </p></item> + <item> <marker id="tc_auto_skip"></marker> - <item><c>#event{name = tc_auto_skip, data = {Suite,Func,Reason}}</c> + <c>#event{name = tc_auto_skip, data = {Suite,Func,Reason}}</c> <p><c>Suite = atom()</c>, the name of the suite.</p> <p><c>Func = atom()</c>, the name of the test case or configuration function.</p> <p><c>Reason = {failed,FailReason} | @@ -251,8 +252,9 @@ the <c>tc_done</c> event. </p></item> + <item> <marker id="tc_user_skip"></marker> - <item><c>#event{name = tc_user_skip, data = {Suite,TestCase,Comment}}</c> + <c>#event{name = tc_user_skip, data = {Suite,TestCase,Comment}}</c> <p><c>Suite = atom()</c>, name of the suite.</p> <p><c>TestCase = atom()</c>, name of the test case.</p> <p><c>Comment = string()</c>, reason for skipping the test case.</p> @@ -308,7 +310,7 @@ manager can look like.</p> <note><p>To ensure that printouts to standard out (or printouts made with - <c><seealso marker="ct#log-2">ct:log/2/3</seealso></c> or <c><seealso marker="ct:pal-2">ct:pal/2/3</seealso></c>) get written to the test case log + <seealso marker="ct#log-2"><c>ct:log/2/3</c></seealso> or <seealso marker="ct:pal-2"><c>ct:pal/2/3</c></seealso>) get written to the test case log file, and not to the Common Test framework log, you can syncronize with the Common Test server by matching on the <c>tc_start</c> and <c>tc_done</c> events. In the period between these events, all IO gets directed to the diff --git a/lib/common_test/doc/src/getting_started_chapter.xml b/lib/common_test/doc/src/getting_started_chapter.xml index 3cf04bb1a2..0b42445540 100644 --- a/lib/common_test/doc/src/getting_started_chapter.xml +++ b/lib/common_test/doc/src/getting_started_chapter.xml @@ -61,13 +61,11 @@ <title>Test case execution</title> <p>Execution of test cases is handled this way:</p> - <p> <image file="tc_execution.gif"> <icaption> Successful vs unsuccessful test case execution. </icaption> </image> - </p> <p>For each test case that Common Test is told to execute, it spawns a dedicated process on which the test case function in question starts @@ -90,7 +88,7 @@ <p>As you can understand from the illustration above, Common Test requires that a test case generates a runtime error to indicate failure (e.g. by causing a bad match error or by calling <c>exit/1</c>, preferrably - through the <c><seealso marker="ct#fail-1">ct:fail/1,2</seealso></c> help function). A succesful execution is + through the <seealso marker="ct#fail-1"><c>ct:fail/1,2</c></seealso> help function). A succesful execution is indicated by means of a normal return from the test case function. </p> </section> @@ -100,13 +98,15 @@ <p>As you've seen in the basics chapter, the test suite module implements <seealso marker="common_test">callback functions</seealso> (mandatory or optional) for various purposes, e.g: + </p> <list> <item>Init/end configuration function for the test suite</item> <item>Init/end configuration function for a test case</item> <item>Init/end configuration function for a test case group</item> <item>Test cases</item> </list> - The configuration functions are optional and if you don't need them for + <p> + The configuration functions are optional and if you don't need them for your test, a test suite with one simple test case could look like this: </p> <pre> @@ -136,13 +136,11 @@ "lower level"). The data flow looks like this: </p> - <p> <image file="config.gif"> <icaption> Config data flow in the suite. </icaption> </image> - </p> <p> Here's an example of a test suite which uses configuration functions @@ -203,13 +201,11 @@ shows the log file structure: </p> - <p> <image file="html_logs.gif"> <icaption> HTML log file structure. </icaption> </image> - </p> </section> <section> diff --git a/lib/common_test/doc/src/install_chapter.xml b/lib/common_test/doc/src/install_chapter.xml index 89c497962d..4ef4e6de94 100644 --- a/lib/common_test/doc/src/install_chapter.xml +++ b/lib/common_test/doc/src/install_chapter.xml @@ -56,13 +56,13 @@ shell script version run_test, however, this script needs to be generated first, according to the instructions below.</p> - <p><note>Before reading on, please note that since Common Test version + <note><p>Before reading on, please note that since Common Test version 1.5, the run_test shell script is no longer required for starting tests with Common Test from the OS command line. The ct_run program (descibed above) is the new recommended command line interface for Common Test. The shell script exists mainly for legacy reasons and may not be updated in future releases of Common Test. It may even be removed. - </note></p> + </p></note> <p>Optional step to generate a shell script for starting Common Test:</p> <p>To generate the run_test shell script, navigate to the diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml index afaed29626..657a72ef8c 100644 --- a/lib/common_test/doc/src/run_test_chapter.xml +++ b/lib/common_test/doc/src/run_test_chapter.xml @@ -105,8 +105,8 @@ RPC from a remote node.</p> </section> - <marker id="ct_run"></marker> <section> + <marker id="ct_run"></marker> <title>Running tests from the OS command line</title> <p>The <c>ct_run</c> program can be used for running tests from @@ -225,15 +225,15 @@ <p>Common Test provides an Erlang API for running tests. The main (and most flexible) function for specifying and executing tests is called - <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>. + <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>. This function takes the same start parameters as - the <c><seealso marker="run_test_chapter#ct_run">ct_run</seealso></c> + the <seealso marker="run_test_chapter#ct_run"><c>ct_run</c></seealso> program described above, only the flags are instead given as options in a list of key-value tuples. E.g. a test specified with <c>ct_run</c> like:</p> <p><c>$ ct_run -suite ./my_SUITE -logdir ./results</c></p> - <p>is with <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c> specified as:</p> + <p>is with <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> specified as:</p> <p><c>1> ct:run_test([{suite,"./my_SUITE"},{logdir,"./results"}]).</c></p> <p>The function returns the test result, represented by the tuple: @@ -245,7 +245,7 @@ <section> <title>Releasing the Erlang shell</title> <p>During execution of tests, started with - <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>, + <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, the Erlang shell process, controlling stdin, will remain the top level process of the Common Test system of processes. The result is that the Erlang shell is not available for interaction during @@ -260,19 +260,19 @@ <c>ct:run_test/1</c> returns the pid of this process rather than the test result - which instead is printed to tty at the end of the test run.</p> <note><p>Note that in order to use the - <c><seealso marker="ct#break-1">ct:break/1/2</seealso></c> and - <c><seealso marker="ct#continue-0">ct:continue/0/1</seealso></c> functions, + <seealso marker="ct#break-1"><c>ct:break/1/2</c></seealso> and + <seealso marker="ct#continue-0"><c>ct:continue/0/1</c></seealso> functions, <c>release_shell</c> <em>must</em> be set to <c>true</c>.</p></note> </section> <p>For detailed documentation about - <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>, + <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, please see the - <c><seealso marker="ct#run_test-1">ct</seealso></c> manual page.</p> + <seealso marker="ct#run_test-1"><c>ct</c></seealso> manual page.</p> </section> - <marker id="group_execution"></marker> <section> + <marker id="group_execution"></marker> <title>Test case group execution</title> <p>With the <c>ct_run</c> flag, or <c>ct:run_test/1</c> option <c>group</c>, @@ -442,9 +442,9 @@ for trying out various operations during test suite development.</p> <p>To invoke the interactive shell mode, you can start an Erlang shell - manually and call <c><seealso marker="ct#install-1">ct:install/1</seealso></c> to install any configuration + manually and call <seealso marker="ct#install-1"><c>ct:install/1</c></seealso> to install any configuration data you might need (use <c>[]</c> as argument otherwise), then - call <c><seealso marker="ct#start_interactive-0">ct:start_interactive/0</seealso></c> to start Common Test. If you use + call <seealso marker="ct#start_interactive-0"><c>ct:start_interactive/0</c></seealso> to start Common Test. If you use the <c>ct_run</c> program, you may start the Erlang shell and Common Test in the same go by using the <c>-shell</c> and, optionally, the <c>-config</c> and/or <c>-userconfig</c> flag. Examples: @@ -463,8 +463,8 @@ <p>If any functions using "required config data" (e.g. ct_telnet or ct_ftp functions) are to be called from the erlang shell, config - data must first be required with <c><seealso marker="ct#require-1"> - ct:require/1/2</seealso></c>. This is + data must first be required with <seealso marker="ct#require-1"><c> + ct:require/1/2</c></seealso>. This is equivalent to a <c>require</c> statement in the <seealso marker="write_test_chapter#suite">Test Suite Info Function</seealso> or in the <seealso @@ -491,11 +491,11 @@ is not supported.</p> <p>If you wish to exit the interactive mode (e.g. to start an - automated test run with <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>), call the function - <c><seealso marker="ct#stop_interactive-0">ct:stop_interactive/0</seealso></c>. This shuts down the + automated test run with <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>), call the function + <seealso marker="ct#stop_interactive-0"><c>ct:stop_interactive/0</c></seealso>. This shuts down the running <c>ct</c> application. Associations between configuration names and data created with <c>require</c> are - consequently deleted. <c><seealso marker="ct#start_interactive-0">ct:start_interactive/0</seealso></c> will get you + consequently deleted. <seealso marker="ct#start_interactive-0"><c>ct:start_interactive/0</c></seealso> will get you back into interactive mode, but the previous state is not restored.</p> </section> @@ -503,7 +503,7 @@ <title>Step by step execution of test cases with the Erlang Debugger</title> <p>By means of <c>ct_run -step [opts]</c>, or by passing the - <c>{step,Opts}</c> option to <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>, it is possible + <c>{step,Opts}</c> option to <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>, it is possible to get the Erlang Debugger started automatically and use its graphical interface to investigate the state of the current test case and to execute it step by step and/or set execution breakpoints.</p> @@ -527,17 +527,17 @@ with <c>dir</c>.</p> </section> - <marker id="test_specifications"></marker> <section> + <marker id="test_specifications"></marker> <title>Test Specifications</title> <section> <title>General description</title> <p>The most flexible way to specify what to test, is to use a so called test specification. A test specification is a sequence of Erlang terms. The terms are normally declared in one or more text files - (see <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c>), but + (see <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso>), but may also be passed to Common Test on the form of a list (see - <c><seealso marker="ct#run_testspec-1">ct:run_testspec/1</seealso></c>). + <seealso marker="ct#run_testspec-1"><c>ct:run_testspec/1</c></seealso>). There are two general types of terms: configuration terms and test specification terms.</p> <p>With configuration terms it is possible to e.g. label the test @@ -989,7 +989,7 @@ <c>ct_run</c>. This forces Common Test to ignore unrecognizable terms. Note that in this mode, Common Test is not able to check the specification for errors as efficiently as if the scanner runs in default mode. - If <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c> is used + If <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> is used for starting the tests, the relaxed scanner mode is enabled by means of the tuple: <c>{allow_user_terms,true}</c></p> </section> @@ -999,7 +999,7 @@ <title>Running tests from the Web based GUI</title> <p>The web based GUI, VTS, is started with the - <c><seealso marker="run_test_chapter#ct_run">ct_run</seealso></c> + <seealso marker="run_test_chapter#ct_run"><c>ct_run</c></seealso> program. From the GUI you can load config files, and select directories, suites and cases to run. You can also state the config files, directories, suites and cases on the command line diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index cc8d913994..a33b22ac39 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -129,8 +129,8 @@ </p> </section> - <marker id="per_testcase"/> <section> + <marker id="per_testcase"/> <title>Init and end per test case</title> <p>Each test suite module can contain the optional configuration functions @@ -173,7 +173,7 @@ </p> <p>The <c>end_per_testcase/2</c> function is called even after a - test case terminates due to a call to <c><seealso marker="ct#abort_current_testcase-1">ct:abort_current_testcase/1</seealso></c>, + test case terminates due to a call to <seealso marker="ct#abort_current_testcase-1"><c>ct:abort_current_testcase/1</c></seealso>, or after a timetrap timeout. However, <c>end_per_testcase</c> will then execute on a different process than the test case function, and in this situation, <c>end_per_testcase</c> will @@ -243,8 +243,8 @@ <note><p>The test case function argument <c>Config</c> should not be confused with the information that can be retrieved from - configuration files (using <c><seealso marker="ct#get_config-1"> - ct:get_config/1/2</seealso></c>). The Config argument + configuration files (using <seealso marker="ct#get_config-1"><c> + ct:get_config/1/2</c></seealso>). The Config argument should be used for runtime configuration of the test suite and the test cases, while configuration files should typically contain data related to the SUT. These two types of configuration data are handled @@ -303,7 +303,7 @@ <item> <p> Use this to specify arbitrary data related to the testcase. This - data can be retrieved at any time using the <c><seealso marker="ct#userdata-3">ct:userdata/3</seealso></c> + data can be retrieved at any time using the <seealso marker="ct#userdata-3"><c>ct:userdata/3</c></seealso> utility function. </p> </item> @@ -348,8 +348,8 @@ </taglist> <p>See the <seealso marker="config_file_chapter#require_config_data">Config files</seealso> - chapter and the <c><seealso marker="ct#require-1"> - ct:require/1/2</seealso></c> function in the + chapter and the <seealso marker="ct#require-1"><c> + ct:require/1/2</c></seealso> function in the <seealso marker="ct">ct</seealso> reference manual for more information about <c>require</c>.</p> @@ -826,14 +826,16 @@ Common Test to create one dedicated private directory per test case and execution instead. This is accomplished by means of the flag/option: <c>create_priv_dir</c> (to be used with the - <c>ct_run</c> program, the <c><seealso marker="ct#run_test-1">ct:run_test/1</seealso></c> function, or + <c>ct_run</c> program, the <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso> function, or as test specification term). There are three possible values for this option: + </p> <list> <item><c>auto_per_run</c></item> <item><c>auto_per_tc</c></item> <item><c>manual_per_tc</c></item> </list> + <p> The first value indicates the default priv_dir behaviour, i.e. one private directory created per test run. The two latter values tell Common Test to generate a unique test directory name @@ -842,7 +844,7 @@ become very inefficient for test runs with many test cases and/or repetitions. Therefore, in case the manual version is instead used, the test case must tell Common Test to create priv_dir when it needs it. - It does this by calling the function <c><seealso marker="ct#make_priv_dir-0">ct:make_priv_dir/0</seealso></c>. + It does this by calling the function <seealso marker="ct#make_priv_dir-0"><c>ct:make_priv_dir/0</c></seealso>. </p> <note><p>You should not depend on current working directory for @@ -890,7 +892,7 @@ <p>It is also possible to dynamically set/reset a timetrap during the excution of a test case, or configuration function. This is done by calling - <c><seealso marker="ct#timetrap-1">ct:timetrap/1</seealso></c>. This function cancels the current timetrap + <seealso marker="ct#timetrap-1"><c>ct:timetrap/1</c></seealso>. This function cancels the current timetrap and starts a new one (that stays active until timeout, or end of the current function).</p> @@ -903,12 +905,12 @@ <p>If a test case needs to suspend itself for a time that also gets multipled by <c>multiply_timetraps</c> (and possibly also scaled up if - <c>scale_timetraps</c> is enabled), the function <c><seealso marker="ct#sleep-1">ct:sleep/1</seealso></c> + <c>scale_timetraps</c> is enabled), the function <seealso marker="ct#sleep-1"><c>ct:sleep/1</c></seealso> may be used (instead of e.g. <c>timer:sleep/1</c>).</p> <p>A function (<c>fun/0</c> or <c>MFA</c>) may be specified as timetrap value in the suite-, group- and test case info function, as - well as argument to the <c><seealso marker="ct#timetrap-1">ct:timetrap/1</seealso></c> function. Examples:</p> + well as argument to the <seealso marker="ct#timetrap-1"><c>ct:timetrap/1</c></seealso> function. Examples:</p> <p><c>{timetrap,{my_test_utils,timetrap,[?MODULE,system_start]}}</c></p> <p><c>ct:timetrap(fun() -> my_timetrap(TestCaseName, Config) end)</c></p> diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 266ca73417..7c797be03e 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -1883,7 +1883,7 @@ verify_suites(TestSuites) -> atom_to_list( Suite)), io:format(user, - "Suite ~w not found" + "Suite ~w not found " "in directory ~ts~n", [Suite,TestDir]), {Found,[{DS,[Name]}|NotFound]} diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml index ddaae2655d..f1238f27a6 100644 --- a/lib/compiler/doc/src/compile.xml +++ b/lib/compiler/doc/src/compile.xml @@ -859,6 +859,10 @@ pi() -> 3.1416. {ErrorLine, Module, ErrorDescriptor} </code> + <p><c>ErrorLine</c> will be the atom <c>none</c> if the error does + not correspond to a specific line (e.g. if the source file does + not exist).</p> + <p>A string describing the error is obtained with the following call:</p> <code> diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml index 33b32a3dce..837fcf4368 100644 --- a/lib/compiler/doc/src/notes.xml +++ b/lib/compiler/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -96,7 +96,7 @@ <item> <p> Forbid multiple values in Core Erlang sequence arguments. - Thanks to Jos� Valim and Anthony Ramine.</p> + Thanks to José Valim and Anthony Ramine.</p> <p> Own Id: OTP-10818</p> </item> @@ -195,7 +195,7 @@ <p> <c>compile:forms/2</c> will now use a {source,SourceFilePath} to set the source returned by - <c>module_info(compile)</c> (Thanks to Jos� Valim)</p> + <c>module_info(compile)</c> (Thanks to José Valim)</p> <p> Own Id: OTP-10150</p> </item> @@ -307,7 +307,7 @@ <item> <p> Fix typo in `compile' doc: unmatched parenthesis (Thanks - to Ricardo Catalinas Jim�nez)</p> + to Ricardo Catalinas Jiménez)</p> <p> Own Id: OTP-9919</p> </item> @@ -808,7 +808,7 @@ (Thanks to Paul Fisher.)</p> <p>Using filter expressions containing <c>andalso</c> or <c>orelse</c> in a list comprehension could cause a - compiler crash. (Thanks to Martin Engstr�m.)</p> + compiler crash. (Thanks to Martin Engström.)</p> <p> Own Id: OTP-8054</p> </item> diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 2ca403de54..802e3dfa2f 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -41,7 +41,8 @@ -type option() :: atom() | {atom(), term()} | {'d', atom(), term()}. --type err_info() :: {erl_scan:line(), module(), term()}. %% ErrorDescriptor +-type err_info() :: {erl_scan:line() | 'none', + module(), term()}. %% ErrorDescriptor -type errors() :: [{file:filename(), [err_info()]}]. -type warnings() :: [{file:filename(), [err_info()]}]. -type mod_ret() :: {'ok', module()} @@ -1290,10 +1291,10 @@ native_compile_1(St) -> {error,R} -> case IgnoreErrors of true -> - Ws = [{St#compile.ifile,[{?MODULE,{native,R}}]}], + Ws = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}], {ok,St#compile{warnings=St#compile.warnings ++ Ws}}; false -> - Es = [{St#compile.ifile,[{?MODULE,{native,R}}]}], + Es = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}], {error,St#compile{errors=St#compile.errors ++ Es}} end catch @@ -1302,7 +1303,7 @@ native_compile_1(St) -> case IgnoreErrors of true -> Ws = [{St#compile.ifile, - [{?MODULE,{native_crash,R,Stk}}]}], + [{none,?MODULE,{native_crash,R,Stk}}]}], {ok,St#compile{warnings=St#compile.warnings ++ Ws}}; false -> erlang:raise(Class, R, Stk) @@ -1349,7 +1350,7 @@ save_binary(#compile{module=Mod,ofile=Outfile, save_binary_1(St); _ -> Es = [{St#compile.ofile, - [{?MODULE,{module_name,Mod,Base}}]}], + [{none,?MODULE,{module_name,Mod,Base}}]}], {error,St#compile{errors=St#compile.errors ++ Es}} end end. @@ -1363,20 +1364,20 @@ save_binary_1(St) -> ok -> {ok,St}; {error,RenameError} -> - Es0 = [{Ofile,[{?MODULE,{rename,Tfile,Ofile, - RenameError}}]}], + Es0 = [{Ofile,[{none,?MODULE,{rename,Tfile,Ofile, + RenameError}}]}], Es = case file:delete(Tfile) of ok -> Es0; {error,DeleteError} -> Es0 ++ [{Ofile, - [{?MODULE,{delete_temp,Tfile, - DeleteError}}]}] + [{none,?MODULE,{delete_temp,Tfile, + DeleteError}}]}] end, {error,St#compile{errors=St#compile.errors ++ Es}} end; {error,_Error} -> - Es = [{Tfile,[{compile,write_error}]}], + Es = [{Tfile,[{none,compile,write_error}]}], {error,St#compile{errors=St#compile.errors ++ Es}} end. @@ -1419,6 +1420,9 @@ report_warnings(#compile{options=Opts,warnings=Ws0}) -> false -> ok end. +format_message(F, P, [{none,Mod,E}|Es]) -> + M = {none,io_lib:format("~ts: ~s~ts\n", [F,P,Mod:format_error(E)])}, + [M|format_message(F, P, Es)]; format_message(F, P, [{{Line,Column}=Loc,Mod,E}|Es]) -> M = {{F,Loc},io_lib:format("~ts:~w:~w ~s~ts\n", [F,Line,Column,P,Mod:format_error(E)])}, @@ -1428,12 +1432,17 @@ format_message(F, P, [{Line,Mod,E}|Es]) -> [F,Line,P,Mod:format_error(E)])}, [M|format_message(F, P, Es)]; format_message(F, P, [{Mod,E}|Es]) -> + %% Not documented and not expected to be used any more, but + %% keep a while just in case. M = {none,io_lib:format("~ts: ~s~ts\n", [F,P,Mod:format_error(E)])}, [M|format_message(F, P, Es)]; format_message(_, _, []) -> []. %% list_errors(File, ErrorDescriptors) -> ok +list_errors(F, [{none,Mod,E}|Es]) -> + io:fwrite("~ts: ~ts\n", [F,Mod:format_error(E)]), + list_errors(F, Es); list_errors(F, [{{Line,Column},Mod,E}|Es]) -> io:fwrite("~ts:~w:~w: ~ts\n", [F,Line,Column,Mod:format_error(E)]), list_errors(F, Es); @@ -1441,6 +1450,8 @@ list_errors(F, [{Line,Mod,E}|Es]) -> io:fwrite("~ts:~w: ~ts\n", [F,Line,Mod:format_error(E)]), list_errors(F, Es); list_errors(F, [{Mod,E}|Es]) -> + %% Not documented and not expected to be used any more, but + %% keep a while just in case. io:fwrite("~ts: ~ts\n", [F,Mod:format_error(E)]), list_errors(F, Es); list_errors(_F, []) -> ok. diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl index 1e8983f594..67d37ff1fc 100644 --- a/lib/compiler/src/core_lint.erl +++ b/lib/compiler/src/core_lint.erl @@ -68,7 +68,7 @@ | {'undefined_function', fa(), fa()} | {'tail_segment_not_at_end', fa()}. --type error() :: {module(), err_desc()}. +-type error() :: {'none', module(), err_desc()}. -type warning() :: {module(), term()}. %%----------------------------------------------------------------------- @@ -162,7 +162,7 @@ return_status(St) -> %% add_warning(ErrorDescriptor, State) -> State' %% Note that we don't use line numbers here. -add_error(E, St) -> St#lint{errors=[{?MODULE,E}|St#lint.errors]}. +add_error(E, St) -> St#lint{errors=[{none,?MODULE,E}|St#lint.errors]}. %%add_warning(W, St) -> St#lint{warnings=[{none,core_lint,W}|St#lint.warnings]}. diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index 5f1c108f7c..2b2b8bf550 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -1875,7 +1875,7 @@ format_error(bad_segment_size) -> add_warning(none, Term, Anno, #kern{ws=Ws}=St) -> File = get_file(Anno), - St#kern{ws=[{File,[{?MODULE,Term}]}|Ws]}; + St#kern{ws=[{File,[{none,?MODULE,Term}]}|Ws]}; add_warning(Line, Term, Anno, #kern{ws=Ws}=St) -> File = get_file(Anno), St#kern{ws=[{File,[{Line,?MODULE,Term}]}|Ws]}. diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 97777568b6..be01ea713d 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -139,8 +139,8 @@ forms_2(Config) when is_list(Config) -> module_mismatch(Config) when is_list(Config) -> ?line DataDir = ?config(data_dir, Config), ?line File = filename:join(DataDir, "wrong_module_name.erl"), - ?line {error,[{"wrong_module_name.beam", - [{compile,{module_name,arne,"wrong_module_name"}}]}], + {error,[{"wrong_module_name.beam", + [{none,compile,{module_name,arne,"wrong_module_name"}}]}], []} = compile:file(File, [return]), ?line error = compile:file(File, [report]), diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index abc9ab6a72..a5a4e62a42 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -299,7 +299,7 @@ unused_multiple_values_error(Config) when is_list(Config) -> Opts = [no_copt,clint,return,from_core,{outdir,PrivDir} |test_lib:opt_opts(?MODULE)], {error,[{unused_multiple_values_error, - [{core_lint,{return_mismatch,{hello,1}}}]}], + [{none,core_lint,{return_mismatch,{hello,1}}}]}], []} = c:c(Core, Opts), ok. diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml index aef7ef8619..5f1d411db2 100644 --- a/lib/debugger/doc/src/notes.xml +++ b/lib/debugger/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -84,7 +84,7 @@ <item> <p> Fix Debugger settings dialog due to changed behavior in - wxFileDialog (Thanks to H�kan Mattsson)</p> + wxFileDialog (Thanks to Håkan Mattsson)</p> <p> Own Id: OTP-10621</p> </item> @@ -126,7 +126,7 @@ <item> <p> Fixed disappearing breakpoints bug, reported by Ricardo - Catalinas Jim�nez.</p> + Catalinas Jiménez.</p> <p> Own Id: OTP-9950</p> </item> @@ -147,7 +147,7 @@ occurrences of "Ok" to "OK" in the code, variable names and strings. This improves the consistency of the code and follows the GTK UI where "OK" is always used.(Thanks - to Ricardo Catalinas Jim�nez)</p> + to Ricardo Catalinas Jiménez)</p> <p> Own Id: OTP-9699</p> </item> diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index fc5c284bf2..34b40c3a29 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -651,8 +651,9 @@ make_opts(Opts, Defs) -> [{K, opt(K,V)} || {K,V} <- Known]. -opt(spawn_opt, L) -> - is_list(L); +opt(spawn_opt, L) + when is_list(L) -> + L; opt(K, false = B) when K /= sequence -> diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl index 2b99ecc59c..282276827f 100644 --- a/lib/diameter/src/base/diameter_peer_fsm.erl +++ b/lib/diameter/src/base/diameter_peer_fsm.erl @@ -741,7 +741,7 @@ rejected(N, T, S) -> rejected({N, []}, T, S). failed_avp(RC, [{RC, Avp} | _]) -> - [{'Failed-AVP', [{'AVP', [Avp]}]}]; + [{'Failed-AVP', [[{'AVP', [Avp]}]]}]; failed_avp(RC, [_ | Es]) -> failed_avp(RC, Es); failed_avp(_, [] = No) -> diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 9dd8aafc61..47e03cd0a0 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -673,7 +673,8 @@ service_options(Opts) -> {use_shared_peers, get_value(use_shared_peers, Opts)}, {restrict_connections, proplists:get_value(restrict_connections, Opts, - ?RESTRICT)}]. + ?RESTRICT)}, + {spawn_opt, proplists:get_value(spawn_opt, Opts, [])}]. %% The order of options is significant since we match against the list. mref(false = No) -> diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml index 12f93ab400..d2ec82efc8 100644 --- a/lib/edoc/doc/src/notes.xml +++ b/lib/edoc/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -219,7 +219,7 @@ <list> <item> <p> Add encoding when parsing Wiki text. EDoc used to - fail on strings such as "���". (Thanks to Richard + fail on strings such as "äåö". (Thanks to Richard Carlsson.) </p> <p> Own Id: OTP-9109</p> diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml index abd3a663bd..2ae5f93165 100644 --- a/lib/erl_docgen/doc/src/notes.xml +++ b/lib/erl_docgen/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -120,7 +120,7 @@ have it installed.</p> <p> Also adds minor cosmetic changes to the CSS. (Thanks to - Ricardo Catalinas Jim�nez)</p> + Ricardo Catalinas Jiménez)</p> <p> Own Id: OTP-9918</p> </item> diff --git a/lib/erl_docgen/priv/dtd/common.dtd b/lib/erl_docgen/priv/dtd/common.dtd index fdc02c55a1..f999ef8ea4 100644 --- a/lib/erl_docgen/priv/dtd/common.dtd +++ b/lib/erl_docgen/priv/dtd/common.dtd @@ -67,7 +67,7 @@ <!-- References --> -<!ELEMENT seealso (#PCDATA) > +<!ELEMENT seealso (#PCDATA|c|em)* > <!ATTLIST seealso marker CDATA #REQUIRED > <!ELEMENT url (#PCDATA) > <!ATTLIST url href CDATA #REQUIRED > diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml index 2fdc839c7b..930b24c26a 100644 --- a/lib/erl_interface/doc/src/notes.xml +++ b/lib/erl_interface/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -262,7 +262,7 @@ <item> <p> Initialize <c>to</c> and <c>to_name</c> in - <c>erl_receive_msg</c>. (Thanks to G�ran Larsson)</p> + <c>erl_receive_msg</c>. (Thanks to Göran Larsson)</p> <p> Own Id: OTP-9241</p> </item> diff --git a/lib/et/doc/src/notes.xml b/lib/et/doc/src/notes.xml index d45d0a89bf..a34dd4a541 100644 --- a/lib/et/doc/src/notes.xml +++ b/lib/et/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -43,7 +43,7 @@ <item> <p> Use erlang:demonitor(Ref, [flush]) where applicable. - Thanks to Lo�c Hoguin.</p> + Thanks to Loïc Hoguin.</p> <p> Own Id: OTP-11039</p> </item> @@ -82,7 +82,7 @@ <list> <item> <p> - Fix typo in ET doc (Thanks to Ricardo Catalinas Jim�nez)</p> + Fix typo in ET doc (Thanks to Ricardo Catalinas Jiménez)</p> <p> Own Id: OTP-10119</p> </item> diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml index b3c41bd396..86e10a06fc 100644 --- a/lib/hipe/doc/src/notes.xml +++ b/lib/hipe/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -37,7 +37,7 @@ <item> <p> Fix the title of hipe_app documentation page. Thanks to - Lo�c Hoguin.</p> + Loïc Hoguin.</p> <p> Own Id: OTP-10904</p> </item> @@ -76,7 +76,7 @@ <p> Fix bug in hipe compiled code related to the handling of <c>is_number/1</c>. (Thanks to Sebastian Egner and - Johannes Wei�l for minimal test code and Kostis for quick + Johannes Weißl for minimal test code and Kostis for quick patch)</p> <p> Own Id: OTP-10897</p> diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index f6bb2cca49..42183b8cc5 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -616,7 +616,7 @@ <p>[httpd] Fix httpd directory traversal on Windows. Directory traversal was possible on Windows where backward slash is used as directory separator. </p> - <p>Andr�s Veres-Szentkir�lyi.</p> + <p>András Veres-Szentkirályi.</p> <p>Own Id: OTP-9561</p> </item> @@ -724,7 +724,7 @@ <item> <p>[httpd] Improved error messages. </p> - <p>Ricardo Catalinas Jim�nez</p> + <p>Ricardo Catalinas Jiménez</p> <p>Own Id: OTP-9157</p> </item> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 254dfbf034..fd62f778a2 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -722,6 +722,59 @@ fe80::204:acff:fe17:bf38 <p>Received <c>Packet</c> is delivered as defined by Mode.</p> </item> + <tag><c>{netns, Namespace :: file:filename_all()}</c></tag> + <item> + <p>Set a network namespace for the socket. The <c>Namespace</c> + parameter is a filename defining the namespace for example + <c>"/var/run/netns/example"</c> typically created by the command + <c>ip netns add example</c>. This option must be used in a + function call that creates a socket i.e + <seealso marker="gen_tcp#connect/3"> + gen_tcp:connect/3,4</seealso>, + <seealso marker="gen_tcp#listen/2"> + gen_tcp:listen/2</seealso>, + <seealso marker="gen_udp#open/1"> + gen_udp:open/1,2</seealso> or + <seealso marker="gen_sctp#open/0"> + gen_sctp:open/0-2</seealso>. + </p> + <p>This option uses the Linux specific syscall + <c>setns()</c> such as in Linux kernel 3.0 or later + and therefore only exists when the runtime system + has been compiled for such an operating system. + </p> + <p> + The virtual machine also needs elevated privileges either + running as superuser or (for Linux) having the capability + <c>CAP_SYS_ADMIN</c> according to the documentation for setns(2). + However, during testing also <c>CAP_SYS_PTRACE</c> + and <c>CAP_DAC_READ_SEARCH</c> has proven to be necessary. + Example:<code> +setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp +</code> + Note also that the filesystem containing the virtual machine + executable (<c>beam.smp</c> in the example above) has to be local, + mounted without the <c>nosetuid</c> flag, + support extended attributes and that + the kernel has to support file capabilities. + All this runs out of the box on at least Ubuntu 12.04 LTS, + except that SCTP sockets appears to not support + network namespaces. + </p> + <p>The <c>Namespace</c> is a file name and is encoded + and decoded as discussed in + <seealso marker="file">file</seealso> + except that the emulator flag <c>+fnu</c> is ignored and + <seealso marker="#getopts/2">getopts/2</seealso> + for this option will return a binary for the filename + if the stored filename can not be decoded, + which should only happen if you set the option using a binary + that can not be decoded with the emulator's filename encoding: + <seealso marker="file#native_name_encoding/0"> + file:native_name_encoding/0</seealso>. + </p> + </item> + <tag><c>list</c></tag> <item> <p>Received <c>Packet</c> is delivered as a list.</p> diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index 0175c38397..6b703b7c2b 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -390,7 +390,7 @@ <p> Fixed issue where using controlling_process/2 with self() as the second argument caused the port to leak if self() - crashes. (Thanks to Ricardo Catalinas Jim�nez)</p> + crashes. (Thanks to Ricardo Catalinas Jiménez)</p> <p> Own Id: OTP-10094</p> </item> @@ -532,7 +532,7 @@ Various typographical errors corrected in documentation for the global, error_logger, etop, lists, ets and supervisor modules and in the c_portdriver and kernel_app - documentation. (Thanks to Ricardo Catalinas Jim�nez)</p> + documentation. (Thanks to Ricardo Catalinas Jiménez)</p> <p> Own Id: OTP-9987</p> </item> @@ -727,7 +727,7 @@ Fixes net_kernel:get_net_ticktime() doc</p> <p> Adds missing description when `ignored' is returned. - (Thanks to Ricardo Catalinas Jim�nez )</p> + (Thanks to Ricardo Catalinas Jiménez )</p> <p> Own Id: OTP-9713</p> </item> @@ -913,7 +913,7 @@ <item> <p> Fix typo in doc of rpc:pmap/3 (Thanks to Ricardo - Catalinas Jim�nez)</p> + Catalinas Jiménez)</p> <p> Own Id: OTP-9168</p> </item> diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index e676ca997d..0a0e6003ee 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -85,7 +85,7 @@ chunk_name(Architecture) -> %%======================================================================== -spec load_native_code(Mod, binary()) -> 'no_native' | {'module', Mod} - when is_subtype(Mod, atom()). + when Mod :: atom(). %% @doc %% Loads the native code of a module Mod. %% Returns {module,Mod} on success (for compatibility with @@ -148,8 +148,8 @@ version_check(Version, Mod) when is_atom(Mod) -> %%======================================================================== --spec load_module(Mod, binary(), _) -> 'bad_crc' | {'module',Mod} - when is_subtype(Mod,atom()). +-spec load_module(Mod, binary(), _) -> 'bad_crc' | {'module', Mod} + when Mod :: atom(). load_module(Mod, Bin, Beam) -> erlang:system_flag(multi_scheduling, block), try @@ -169,8 +169,8 @@ load_module(Mod, Bin, Beam, OldReferencesToPatch) -> %%======================================================================== --spec load(Mod, binary()) -> 'bad_crc' | {'module',Mod} - when is_subtype(Mod,atom()). +-spec load(Mod, binary()) -> 'bad_crc' | {'module', Mod} when Mod :: atom(). + load(Mod, Bin) -> erlang:system_flag(multi_scheduling, block), try @@ -204,15 +204,17 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> bad_crc; true -> %% Create data segment - {ConstAddr,ConstMap2} = create_data_segment(ConstAlign, ConstSize, ConstMap), + {ConstAddr,ConstMap2} = + create_data_segment(ConstAlign, ConstSize, ConstMap), %% Find callees for which we may need trampolines. CalleeMFAs = find_callee_mfas(Refs), %% Write the code to memory. - {CodeAddress,Trampolines} = enter_code(CodeSize, CodeBinary, CalleeMFAs, Mod, Beam), + {CodeAddress,Trampolines} = + enter_code(CodeSize, CodeBinary, CalleeMFAs, Mod, Beam), %% Construct CalleeMFA-to-trampoline mapping. TrampolineMap = mk_trampoline_map(CalleeMFAs, Trampolines), %% Patch references to code labels in data seg. - patch_consts(LabelMap, ConstAddr, CodeAddress), + ok = patch_consts(LabelMap, ConstAddr, CodeAddress), %% Find out which functions are being loaded (and where). %% Note: Addresses are sorted descending. {MFAs,Addresses} = exports(ExportMap, CodeAddress), @@ -221,7 +223,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> ok = remove_refs_from(MFAs), %% Patch all dynamic references in the code. %% Function calls, Atoms, Constants, System calls - patch(Refs, CodeAddress, ConstMap2, Addresses, TrampolineMap), + ok = patch(Refs, CodeAddress, ConstMap2, Addresses, TrampolineMap), %% Tell the system where the loaded funs are. %% (patches the BEAM code to redirect to native.) case Beam of @@ -322,7 +324,7 @@ trampoline_map_get(MFA, Map) -> gb_trees:get(MFA, Map). trampoline_map_lookup(_, []) -> []; % archs not using trampolines trampoline_map_lookup(Primop, Map) -> case gb_trees:lookup(Primop, Map) of - {value,X} -> X; + {value, X} -> X; _ -> [] end. @@ -369,7 +371,7 @@ offsets_to_addresses(Os, Base) -> find_closure_patches([{Type,Refs} | Rest]) -> case ?EXT2PATCH_TYPE(Type) of load_address -> - find_closure_refs(Refs,Rest); + find_closure_refs(Refs, Rest); _ -> find_closure_patches(Rest) end; @@ -404,16 +406,17 @@ export_funs([FunDef | Addresses]) -> hipe_bifs:set_native_address(MFA, Address, IsClosure), export_funs(Addresses); export_funs([]) -> - true. + ok. export_funs(Mod, Beam, Addresses, ClosuresToPatch) -> - Fs = [{F,A,Address} || #fundef{address=Address, mfa={_M,F,A}} <- Addresses], - code:make_stub_module(Mod, Beam, {Fs,ClosuresToPatch}). + Fs = [{F,A,Address} || #fundef{address=Address, mfa={_M,F,A}} <- Addresses], + Mod = code:make_stub_module(Mod, Beam, {Fs,ClosuresToPatch}), + ok. %%======================================================================== %% Patching %% @spec patch(refs(), BaseAddress::integer(), ConstAndZone::term(), -%% Addresses::term(), TrampolineMap::term()) -> term() +%% Addresses::term(), TrampolineMap::term()) -> 'ok'. %% @type refs()=[{RefType::integer(), Reflist::reflist()} | refs()] %% %% @type reflist()= [{Data::term(), Offsets::offests()}|reflist()] @@ -426,7 +429,7 @@ export_funs(Mod, Beam, Addresses, ClosuresToPatch) -> %% patch([{Type,SortedRefs}|Rest], CodeAddress, ConstMap2, Addresses, TrampolineMap) -> - ?debug_msg("Patching ~w at [~w+offset] with ~w\n", + ?debug_msg("Patching ~w at [~w+offset] with ~w\n", [Type,CodeAddress,SortedRefs]), case ?EXT2PATCH_TYPE(Type) of call_local -> @@ -437,7 +440,7 @@ patch([{Type,SortedRefs}|Rest], CodeAddress, ConstMap2, Addresses, TrampolineMap patch_all(Other, SortedRefs, CodeAddress, {ConstMap2,CodeAddress}, Addresses) end, patch(Rest, CodeAddress, ConstMap2, Addresses, TrampolineMap); -patch([], _, _, _, _) -> true. +patch([], _, _, _, _) -> ok. %%---------------------------------------------------------------- %% Handle a 'call_local' or 'call_remote' patch. @@ -459,14 +462,14 @@ patch_call([{DestMFA,Offsets}|SortedRefs], BaseAddress, Addresses, RemoteOrLocal end, patch_call(SortedRefs, BaseAddress, Addresses, RemoteOrLocal, TrampolineMap); patch_call([], _, _, _, _) -> - true. + ok. patch_bif_call_list([Offset|Offsets], BaseAddress, BifAddress, Trampoline) -> CallAddress = BaseAddress+Offset, ?ASSERT(assert_local_patch(CallAddress)), patch_call_insn(CallAddress, BifAddress, Trampoline), patch_bif_call_list(Offsets, BaseAddress, BifAddress, Trampoline); -patch_bif_call_list([], _, _, _) -> []. +patch_bif_call_list([], _, _, _) -> ok. patch_mfa_call_list([Offset|Offsets], BaseAddress, DestMFA, DestAddress, Addresses, RemoteOrLocal, Trampoline) -> CallAddress = BaseAddress+Offset, @@ -474,7 +477,7 @@ patch_mfa_call_list([Offset|Offsets], BaseAddress, DestMFA, DestAddress, Address ?ASSERT(assert_local_patch(CallAddress)), patch_call_insn(CallAddress, DestAddress, Trampoline), patch_mfa_call_list(Offsets, BaseAddress, DestMFA, DestAddress, Addresses, RemoteOrLocal, Trampoline); -patch_mfa_call_list([], _, _, _, _, _, _) -> []. +patch_mfa_call_list([], _, _, _, _, _, _) -> ok. patch_call_insn(CallAddress, DestAddress, Trampoline) -> %% This assertion is false when we're called from redirect/2. @@ -487,7 +490,7 @@ patch_call_insn(CallAddress, DestAddress, Trampoline) -> patch_all(Type, [{Dest,Offsets}|Rest], BaseAddress, ConstAndZone, Addresses)-> patch_all_offsets(Type, Dest, Offsets, BaseAddress, ConstAndZone, Addresses), patch_all(Type, Rest, BaseAddress, ConstAndZone, Addresses); -patch_all(_, [], _, _, _) -> true. +patch_all(_, [], _, _, _) -> ok. patch_all_offsets(Type, Data, [Offset|Offsets], BaseAddress, ConstAndZone, Addresses) -> @@ -497,7 +500,7 @@ patch_all_offsets(Type, Data, [Offset|Offsets], BaseAddress, patch_offset(Type, Data, Address, ConstAndZone, Addresses), ?debug_msg("Patching done\n",[]), patch_all_offsets(Type, Data, Offsets, BaseAddress, ConstAndZone, Addresses); -patch_all_offsets(_, _, [], _, _, _) -> true. +patch_all_offsets(_, _, [], _, _, _) -> ok. %%---------------------------------------------------------------- %% Handle any patch type except 'call_local' or 'call_remote'. diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 5749027acd..27f085c3aa 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -200,7 +200,14 @@ send(Socket, Packet) -> Options :: [socket_setopt()]. setopts(Socket, Opts) -> - prim_inet:setopts(Socket, Opts). + SocketOpts = + [case Opt of + {netns,NS} -> + {netns,filename2binary(NS)}; + _ -> + Opt + end || Opt <- Opts], + prim_inet:setopts(Socket, SocketOpts). -spec getopts(Socket, Options) -> {'ok', OptionValues} | {'error', posix()} when @@ -209,7 +216,18 @@ setopts(Socket, Opts) -> OptionValues :: [socket_setopt()]. getopts(Socket, Opts) -> - prim_inet:getopts(Socket, Opts). + case prim_inet:getopts(Socket, Opts) of + {ok,OptionValues} -> + {ok, + [case OptionValue of + {netns,Bin} -> + {netns,binary2filename(Bin)}; + _ -> + OptionValue + end || OptionValue <- OptionValues]}; + Other -> + Other + end. -spec getifaddrs(Socket :: socket()) -> {'ok', [string()]} | {'error', posix()}. @@ -641,6 +659,14 @@ con_opt([Opt | Opts], R, As) -> {tcp_module,_} -> con_opt(Opts, R, As); inet -> con_opt(Opts, R, As); inet6 -> con_opt(Opts, R, As); + {netns,NS} -> + BinNS = filename2binary(NS), + case prim_inet:is_sockopt_val(netns, BinNS) of + true -> + con_opt(Opts, R#connect_opts { fd = [{netns,BinNS}] }, As); + false -> + {error, badarg} + end; {Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As); _ -> {error, badarg} end; @@ -699,6 +725,14 @@ list_opt([Opt | Opts], R, As) -> {tcp_module,_} -> list_opt(Opts, R, As); inet -> list_opt(Opts, R, As); inet6 -> list_opt(Opts, R, As); + {netns,NS} -> + BinNS = filename2binary(NS), + case prim_inet:is_sockopt_val(netns, BinNS) of + true -> + list_opt(Opts, R#listen_opts { fd = [{netns,BinNS}] }, As); + false -> + {error, badarg} + end; {Name,Val} when is_atom(Name) -> list_add(Name, Val, R, Opts, As); _ -> {error, badarg} end; @@ -745,6 +779,14 @@ udp_opt([Opt | Opts], R, As) -> {udp_module,_} -> udp_opt(Opts, R, As); inet -> udp_opt(Opts, R, As); inet6 -> udp_opt(Opts, R, As); + {netns,NS} -> + BinNS = filename2binary(NS), + case prim_inet:is_sockopt_val(netns, BinNS) of + true -> + list_opt(Opts, R#udp_opts { fd = [{netns,BinNS}] }, As); + false -> + {error, badarg} + end; {Name,Val} when is_atom(Name) -> udp_add(Name, Val, R, Opts, As); _ -> {error, badarg} end; @@ -814,6 +856,17 @@ sctp_opt([Opt|Opts], Mod, R, As) -> {sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with inet -> sctp_opt (Opts, Mod, R, As); % Done with inet6 -> sctp_opt (Opts, Mod, R, As); % Done with + {netns,NS} -> + BinNS = filename2binary(NS), + case prim_inet:is_sockopt_val(netns, BinNS) of + true -> + sctp_opt( + Opts, Mod, + R#sctp_opts { fd = [{netns,BinNS}] }, + As); + false -> + {error, badarg} + end; {Name,Val} -> sctp_opt (Opts, Mod, R, As, Name, Val); _ -> {error,badarg} end; @@ -858,6 +911,39 @@ add_opt(Name, Val, Opts, As) -> end. +%% Passthrough all unknown - catch type errors later +filename2binary(List) when is_list(List) -> + OutEncoding = file:native_name_encoding(), + try unicode:characters_to_binary(List, unicode, OutEncoding) of + Bin when is_binary(Bin) -> + Bin; + _ -> + List + catch + error:badarg -> + List + end; +filename2binary(Bin) -> + Bin. + +binary2filename(Bin) -> + InEncoding = file:native_name_encoding(), + case unicode:characters_to_list(Bin, InEncoding) of + Filename when is_list(Filename) -> + Filename; + _ -> + %% For getopt/setopt of netns this should only happen if + %% a binary with wrong encoding was used when setting the + %% option, hence the user shall eat his/her own medicine. + %% + %% I.e passthrough here too for now. + %% Future usecases will most probably not want this, + %% rather Unicode error or warning + %% depending on emulator flag instead. + Bin + end. + + translate_ip(any, inet) -> {0,0,0,0}; translate_ip(loopback, inet) -> {127,0,0,1}; translate_ip(any, inet6) -> {0,0,0,0,0,0,0,0}; @@ -1070,7 +1156,7 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) -> Result -> Result end. --spec open(Fd :: integer(), +-spec open(Fd_or_OpenOpts :: integer() | list(), Addr :: ip_address(), Port :: port_number(), Opts :: [socket_setopt()], @@ -1080,8 +1166,14 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) -> Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) when Fd < 0 -> - case prim_inet:open(Protocol, Family, Type) of +open(FdO, Addr, Port, Opts, Protocol, Family, Type, Module) + when is_integer(FdO), FdO < 0; + is_list(FdO) -> + OpenOpts = + if is_list(FdO) -> FdO; + true -> [] + end, + case prim_inet:open(Protocol, Family, Type, OpenOpts) of {ok,S} -> case prim_inet:setopts(S, Opts) of ok -> @@ -1104,7 +1196,8 @@ open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) when Fd < 0 -> Error -> Error end; -open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module) -> +open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module) + when is_integer(Fd) -> fdopen(Fd, Opts, Protocol, Family, Type, Module). bindx(S, [Addr], Port0) -> diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 67a99913a1..18a4a61b2f 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -143,6 +143,7 @@ -define(INET_LOPT_TCP_SEND_TIMEOUT_CLOSE, 35). -define(INET_LOPT_MSGQ_HIWTRMRK, 36). -define(INET_LOPT_MSGQ_LOWTRMRK, 37). +-define(INET_LOPT_NETNS, 38). % Specific SCTP options: separate range: -define(SCTP_OPT_RTOINFO, 100). -define(SCTP_OPT_ASSOCINFO, 101). diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 46c8c0b88b..ed43749cc0 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -38,10 +38,10 @@ gethostnative_debug_level/0, gethostnative_debug_level/1, getif/1, getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1, - parse_strict_address/1]). + parse_strict_address/1, simple_netns/1]). -export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1, - kill_gethost/0, parallell_gethost/0]). + kill_gethost/0, parallell_gethost/0, test_netns/0]). -export([init_per_testcase/2, end_per_testcase/2]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -53,7 +53,7 @@ all() -> t_gethostnative, gethostnative_parallell, cname_loop, gethostnative_debug_level, gethostnative_soft_restart, getif, getif_ifr_name_overflow, getservbyname_overflow, - getifaddrs, parse_strict_address]. + getifaddrs, parse_strict_address, simple_netns]. groups() -> [{parse, [], [parse_hosts, parse_address]}]. @@ -1099,3 +1099,96 @@ toupper([C|Cs]) when is_integer(C) -> end; toupper([]) -> []. + + +simple_netns(Config) when is_list(Config) -> + {ok,U} = gen_udp:open(0), + case inet:setopts(U, [{netns,""}]) of + ok -> + jog_netns_opt(U), + ok = gen_udp:close(U), + %% + {ok,L} = gen_tcp:listen(0, []), + jog_netns_opt(L), + ok = gen_tcp:close(L), + %% + {ok,S} = gen_sctp:open(), + jog_netns_opt(S), + ok = gen_sctp:close(S); + {error,einval} -> + {skip,"setns() not supported"} + end. + +jog_netns_opt(S) -> + %% This is just jogging the option mechanics + ok = inet:setopts(S, [{netns,""}]), + {ok,[{netns,""}]} = inet:getopts(S, [netns]), + ok = inet:setopts(S, [{netns,"/proc/self/ns/net"}]), + {ok,[{netns,"/proc/self/ns/net"}]} = inet:getopts(S, [netns]), + ok. + + +%% Manual test to be run outside test_server in an emulator +%% started by root, in a machine with setns() support... +test_netns() -> + DefaultIF = v1, + DefaultIP = {192,168,1,17}, + Namespace = "test", + NamespaceIF = v2, + NamespaceIP = {192,168,1,18}, + %% + DefaultIPString = inet_parse:ntoa(DefaultIP), + NamespaceIPString = inet_parse:ntoa(NamespaceIP), + cmd("ip netns add ~s", + [Namespace]), + cmd("ip link add name ~w type veth peer name ~w netns ~s", + [DefaultIF,NamespaceIF,Namespace]), + cmd("ip netns exec ~s ip addr add ~s/30 dev ~w", + [Namespace,NamespaceIPString,NamespaceIF]), + cmd("ip netns exec ~s ip link set ~w up", + [Namespace,NamespaceIF]), + cmd("ip addr add ~s/30 dev ~w", + [DefaultIPString,DefaultIF]), + cmd("ip link set ~w up", + [DefaultIF]), + try test_netns( + {DefaultIF,DefaultIP}, + filename:join("/var/run/netns/", Namespace), + {NamespaceIF,NamespaceIP}) of + Result -> + io:put_chars(["#### Test done",io_lib:nl()]), + Result + after + cmd("ip link delete ~w type veth", + [DefaultIF]), + cmd("ip netns delete ~s", + [Namespace]) + end. + +test_netns({DefaultIF,DefaultIP}, Namespace, {NamespaceIF,NamespaceIP}) -> + {ok,ListenSocket} = gen_tcp:listen(0, [{active,false}]), + {ok,[{addr,DefaultIP}]} = inet:ifget(ListenSocket, DefaultIF, [addr]), + {ok,ListenPort} = inet:port(ListenSocket), + {ok,ConnectSocket} = + gen_tcp:connect( + DefaultIP, ListenPort, [{active,false},{netns,Namespace}], 3000), + {ok,[{addr,NamespaceIP}]} = inet:ifget(ConnectSocket, NamespaceIF, [addr]), + {ok,ConnectPort} = inet:port(ConnectSocket), + {ok,AcceptSocket} = gen_tcp:accept(ListenSocket, 0), + {ok,AcceptPort} = inet:port(AcceptSocket), + {ok,{NamespaceIP,ConnectPort}} = inet:peername(AcceptSocket), + {ok,{DefaultIP,AcceptPort}} = inet:peername(ConnectSocket), + ok = gen_tcp:send(ConnectSocket, "data"), + ok = gen_tcp:close(ConnectSocket), + {ok,"data"} = gen_tcp:recv(AcceptSocket, 4, 1000), + {error,closed} = gen_tcp:recv(AcceptSocket, 1, 1000), + ok = gen_tcp:close(AcceptSocket), + ok = gen_tcp:close(ListenSocket). + +cmd(Cmd, Args) -> + cmd(io_lib:format(Cmd, Args)). +%% +cmd(CmdString) -> + io:put_chars(["# ",CmdString,io_lib:nl()]), + io:put_chars([os:cmd(CmdString++" ; echo ' =>' $?")]), + ok. diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index 790f5d92b5..99a26dd281 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -115,7 +115,7 @@ <item> <p> Remove support for the query keyword and query - expressions. Thanks to Lo�c Hoguin.</p> + expressions. Thanks to Loïc Hoguin.</p> <p> Own Id: OTP-10729</p> </item> @@ -352,7 +352,7 @@ "-f" is a non-standard chmod option which at least SGI IRIX and HP UX do not support. As the only effect of the "-f" flag is to suppress warning messages, it can be - safely omitted. (Thanks to Holger Wei�)</p> + safely omitted. (Thanks to Holger Weiß)</p> <p> Own Id: OTP-9170</p> </item> diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml index 34e87374a2..998a4e4f9f 100644 --- a/lib/observer/doc/src/notes.xml +++ b/lib/observer/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -139,7 +139,7 @@ <p> Start position was lost after a 'Found' -> 'Not found' search sequence leading an undefined position in the next - search. Thanks to Peti G�mori</p> + search. Thanks to Peti Gömori</p> <p> Own Id: OTP-10218</p> </item> diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml index ebbacb2327..a1c6f999e0 100644 --- a/lib/odbc/doc/src/notes.xml +++ b/lib/odbc/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -272,7 +272,7 @@ <item> <p> ODBC now handles the types SQL_WCHAR and SQL_WVARCHAR. - Thanks to Juhani R�nkimies. ODBC also has a new + Thanks to Juhani Ränkimies. ODBC also has a new connection option to return all strings as binaries and also expect strings to be binaries in the param_query function. These changes provides some unicode support.</p> @@ -282,7 +282,7 @@ <item> <p> Now supports SQL_TYPE_TIMESTAMP on the format {{YY, MM, - DD}, {HH, MM, SS}}. Thanks to Juhani R�nkimies.</p> + DD}, {HH, MM, SS}}. Thanks to Juhani Ränkimies.</p> <p> *** POTENTIAL INCOMPATIBILITY ***</p> <p> diff --git a/lib/odbc/doc/src/odbc.xml b/lib/odbc/doc/src/odbc.xml index a984bf4485..48b105d1e4 100644 --- a/lib/odbc/doc/src/odbc.xml +++ b/lib/odbc/doc/src/odbc.xml @@ -213,12 +213,13 @@ Note that this information is probably of little use when writing database-independent code, but can be of assistance in providing more sophisticated error handling when dealing with a known underlying database. + </p> <list type="bulleted"> <item><c>ODBCErrorCode</c> is the ODBC error string returned by the ODBC driver.</item> <item><c>NativeErrorCode</c> is the numberic error code returned by the underlying database. The possible values and their meanings are dependent on the database being used.</item> <item><c>Reason</c> is as per the <c>Reason</c> field when extended errors are not enabled.</item> - </list></p> + </list> </desc> </func> <func> diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl index 74ae2c96e6..2a16388929 100644 --- a/lib/odbc/test/odbc_connect_SUITE.erl +++ b/lib/odbc/test/odbc_connect_SUITE.erl @@ -77,6 +77,8 @@ end_per_group(_GroupName, Config) -> %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) when is_list(Config) -> + file:write_file(filename:join([proplists:get_value(priv_dir,Config), + "..","..","..","ignore_core_files"]),""), case odbc_test_lib:skip() of true -> {skip, "ODBC not supported"}; diff --git a/lib/os_mon/c_src/Makefile.in b/lib/os_mon/c_src/Makefile.in index 51569f6ec9..f84ccf7c87 100644 --- a/lib/os_mon/c_src/Makefile.in +++ b/lib/os_mon/c_src/Makefile.in @@ -84,6 +84,7 @@ debug opt: $(TARGET_FILES) clean: rm -f $(TARGET_FILES) + rm -rf $(OBJDIR) rm -f core *~ docs: diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c index 7372d5b0e8..e9fd75a32c 100644 --- a/lib/os_mon/c_src/cpu_sup.c +++ b/lib/os_mon/c_src/cpu_sup.c @@ -29,6 +29,7 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <string.h> #if defined(__sun__) #include <kstat.h> @@ -120,7 +121,9 @@ typedef struct { static void util_measure(unsigned int **result_vec, int *result_sz); +#if defined(__sun__) static unsigned int misc_measure(char* name); +#endif static void send(unsigned int data); static void sendv(unsigned int data[], int ints); static void error(char* err_msg); @@ -140,7 +143,9 @@ int main(int argc, char** argv) { int rc; int sz; unsigned int *rv; +#if defined(__linux__) unsigned int no_of_cpus = 0; +#endif #if defined(__sun__) kstat_ctl = kstat_open(); @@ -288,10 +293,10 @@ static unsigned int misc_measure(char* name) { if(!entry) return -1; - if(entry->data_type != KSTAT_DATA_ULONG) + if(entry->data_type != KSTAT_DATA_UINT32) return -1; - return entry->value.ul; + return entry->value.ui32; } diff --git a/lib/os_mon/test/cpu_sup_SUITE.erl b/lib/os_mon/test/cpu_sup_SUITE.erl index d04adbb6d3..e0382cb0c7 100644 --- a/lib/os_mon/test/cpu_sup_SUITE.erl +++ b/lib/os_mon/test/cpu_sup_SUITE.erl @@ -88,6 +88,7 @@ load_api(Config) when is_list(Config) -> ?line N = cpu_sup:nprocs(), ?line true = is_integer(N), ?line true = N>0, + ?line true = N<1000000, %% avg1() ?line Load1 = cpu_sup:avg1(), diff --git a/lib/percept/doc/src/notes.xml b/lib/percept/doc/src/notes.xml index 795dd98545..391f4d6d47 100644 --- a/lib/percept/doc/src/notes.xml +++ b/lib/percept/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -295,7 +295,7 @@ <list> <item> <p>Performance enhancement for the egd render engine - (Thanks to Magnus Tho�ng).</p> + (Thanks to Magnus Thoäng).</p> <p> Own Id: OTP-7616</p> </item> diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml index 598d3333f8..1728515cb4 100644 --- a/lib/reltool/doc/src/notes.xml +++ b/lib/reltool/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -61,7 +61,7 @@ even if the application was explicitly excluded in the config. This has been changed and will only produce a warning. If the application is not explicitly excluded it - will still cause reltool to fail. Thanks to H�kan + will still cause reltool to fail. Thanks to Håkan Mattsson!</p> <p> Own Id: OTP-10988</p> diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml index 2281ac4a49..db35eba436 100644 --- a/lib/runtime_tools/doc/src/notes.xml +++ b/lib/runtime_tools/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -69,7 +69,7 @@ <item> <p> Fix Table Viewer refresh crash on no more existing ets - tables (Thanks to Peti G�mori)</p> + tables (Thanks to Peti Gömori)</p> <p> Own Id: OTP-10635</p> </item> diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 21c417f0c1..7514c52dda 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -34,6 +34,73 @@ <section> + <title>SNMP Development Toolkit 4.24.2</title> + <p>Version 4.24.2 supports code replacement in runtime from/to + version 4.24.1, 4.24, 4.23.1 and 4.23. </p> + + <section> + <title>Improvements and new features</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[agent] Improved documentation for the functions for + loading and unloading mibs, + see <seealso marker="snmpa#load_mibs">load_mibs</seealso> and + <seealso marker="snmpa#unload_mibs">unload_mibs</seealso> for + more info. </p> + <p>Also added new functions for loading and unloading a single mib, + see <seealso marker="snmpa#load_mib">load_mib</seealso> and + <seealso marker="snmpa#unload_mib">unload_mib</seealso> for + more info. </p> + <p>Own Id: OTP-11216</p> + </item> + + </list> + + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>[agent] + see <seealso marker="snmpa#load_mibs">load_mibs</seealso> and + <seealso marker="snmpa#unload_mibs">unload_mibs</seealso>. </p> + <p>Own Id: OTP-11216</p> + </item> + + </list> +--> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>[manager] The old Addr-and-Port based API functions, previously + long deprecated and marked for deletion in R16B, has now been + removed. </p> + <p>Own Id: OTP-10027</p> + </item> + + </list> +--> + </section> + + </section> <!-- 4.24.2 --> + + + <section> <title>SNMP Development Toolkit 4.24.1</title> <p>Version 4.24.1 supports code replacement in runtime from/to version 4.24, 4.23.1 and 4.23. </p> @@ -147,7 +214,7 @@ <seealso marker="snmpa_mib_storage">mib storage</seealso>. At present there are three simple modules (<c>snmpa_mib_storage_ets</c>, <c>snmpa_mib_storage_dets</c> and - <c>snmpa_mib_storage_mnesia</c>) implement�ng this behaviour, + <c>snmpa_mib_storage_mnesia</c>) implementing this behaviour, provided with the app. </p> <p>A config option for the (agent) <seealso marker="snmp_config#agent_mib_storage">mib storage</seealso> diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index 86fde03205..77146f3a89 100644 --- a/lib/snmp/doc/src/snmpa.xml +++ b/lib/snmp/doc/src/snmpa.xml @@ -245,29 +245,75 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} This function is used to convert to the old (pre-4.4) info format. </p> + <marker id="load_mib"></marker> + </desc> + </func> + + <func> + <name>load_mib(Mib) -> ok | {error, Reason}</name> + <name>load_mib(Agent, Mib) -> ok | {error, Reason}</name> + <fsummary>Load single MIB into the agent</fsummary> + <type> + <v>Agent = pid() | atom()</v> + <v>MibName = string()</v> + <v>Reason = already_loaded | term()</v> + </type> + <desc> + <p>Load a single <c>Mib</c> into an agent. The <c>MibName</c> + is the name of the Mib, including the path to where the compiled + mib is found. For example: </p> + <code type="none"> + Dir = code:priv_dir(my_app) ++ "/mibs/", + snmpa:load_mib(snmp_master_agent, Dir ++ "MY-MIB"). + </code> + <marker id="load_mibs"></marker> </desc> </func> <func> <name>load_mibs(Mibs) -> ok | {error, Reason}</name> - <name>load_mibs(Agent,Mibs) -> ok | {error, Reason}</name> + <name>load_mibs(Mibs, Force) -> ok | {error, Reason}</name> + <name>load_mibs(Agent, Mibs) -> ok | {error, Reason}</name> + <name>load_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name> <fsummary>Load MIBs into the agent</fsummary> <type> <v>Agent = pid() | atom()</v> <v>Mibs = [MibName]</v> + <v>Force = boolean()</v> <v>MibName = string()</v> - <v>Reason = term()</v> + <v>Reason = {'load aborted at', MibName, InternalReason}</v> + <v>InternalReason = already_loaded | term()</v> </type> <desc> - <p>Loads <c>Mibs</c> into an agent. If the agent cannot load - all MIBs, it will indicate where loading was aborted. The - <c>MibName</c> is the name of the Mib, including the path to - where the compiled mib is found. For example,</p> - <code type="none"> + <p>Load <c>Mibs</c> into an agent. If the agent cannot load all + MIBs (the default value of the <c>Force</c> argument is <c>false</c>), + it will indicate where loading was aborted. The <c>MibName</c> + is the name of the Mib, including the path to where the compiled + mib is found. For example,</p> + <code type="none"> Dir = code:priv_dir(my_app) ++ "/mibs/", snmpa:load_mibs(snmp_master_agent, [Dir ++ "MY-MIB"]). </code> + <p>If <c>Force = true</c> then the agent will continue attempting + to load each mib even after failing to load a previous mib. Use with + care. </p> + + <marker id="unload_mib"></marker> + </desc> + </func> + + <func> + <name>unload_mib(Mib) -> ok | {error, Reason}</name> + <name>unload_mib(Agent, Mib) -> ok | {error, Reason}</name> + <fsummary>Unload single MIB from the agent</fsummary> + <type> + <v>Agent = pid() | atom()</v> + <v>MibName = string()</v> + <v>Reason = not_loaded | term()</v> + </type> + <desc> + <p>Unload a single <c>Mib</c> from an agent. </p> <marker id="unload_mibs"></marker> </desc> @@ -275,16 +321,25 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <func> <name>unload_mibs(Mibs) -> ok | {error, Reason}</name> - <name>unload_mibs(Agent,Mibs) -> ok | {error, Reason}</name> + <name>unload_mibs(Mibs, Force) -> ok | {error, Reason}</name> + <name>unload_mibs(Agent, Mibs) -> ok | {error, Reason}</name> + <name>unload_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name> <fsummary>Unload MIBs from the agent</fsummary> <type> <v>Agent = pid() | atom()</v> <v>Mibs = [MibName]</v> + <v>Force = boolean()</v> <v>MibName = string()</v> + <v>Reason = {'unload aborted at', MibName, InternalReason}</v> + <v>InternalReason = not_loaded | term()</v> </type> <desc> - <p>Unloads MIBs into an agent. If it cannot unload all MIBs, - it will indicate where unloading was aborted. </p> + <p>Unload <c>Mibs</c> from an agent. If it cannot unload all MIBs + (the default value of the <c>Force</c> argument is <c>false</c>), + it will indicate where unloading was aborted. </p> + <p>If <c>Force = true</c> then the agent will continue attempting + to unload each mib even after failing to unload a previous mib. + Use with care. </p> <marker id="which_mibs"></marker> </desc> diff --git a/lib/snmp/doc/src/snmpa_mib_data.xml b/lib/snmp/doc/src/snmpa_mib_data.xml index ff07a03b98..c1ea0a91f9 100644 --- a/lib/snmp/doc/src/snmpa_mib_data.xml +++ b/lib/snmp/doc/src/snmpa_mib_data.xml @@ -380,7 +380,7 @@ <desc> <p>Perform a code-change (upgrade or downgrade). </p> <p>See - <seealso marker="gen_server">gen_server</seealso> + <seealso marker="stdlib:gen_server">gen_server</seealso> for more info regarding the <c>Vsn</c> and <c>Extra</c> arguments. </p> </desc> diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl index 14b93439df..a95e41ea42 100644 --- a/lib/snmp/src/agent/snmpa.erl +++ b/lib/snmp/src/agent/snmpa.erl @@ -39,8 +39,10 @@ enum_to_int/2, enum_to_int/3, info/0, info/1, old_info_format/1, - load_mibs/1, load_mibs/2, - unload_mibs/1, unload_mibs/2, + load_mib/1, load_mib/2, + load_mibs/1, load_mibs/2, load_mibs/3, + unload_mib/1, unload_mib/2, + unload_mibs/1, unload_mibs/2, unload_mibs/3, which_mibs/0, which_mibs/1, whereis_mib/1, whereis_mib/2, dump_mibs/0, dump_mibs/1, @@ -300,19 +302,75 @@ backup(Agent, BackupDir) -> dump_mibs() -> snmpa_agent:dump_mibs(snmp_master_agent). dump_mibs(File) -> snmpa_agent:dump_mibs(snmp_master_agent, File). + +load_mib(Mib) -> + load_mib(snmp_master_agent, Mib). + +-spec load_mib(Agent :: pid() | atom(), Mib :: string()) -> + ok | {error, Reason :: already_loaded | term()}. + +load_mib(Agent, Mib) -> + case load_mibs(Agent, [Mib]) of + {error, {'load aborted at', Mib, Reason}} -> + {error, Reason}; + Else -> + Else + end. + load_mibs(Mibs) -> - load_mibs(snmp_master_agent, Mibs). + load_mibs(snmp_master_agent, Mibs, false). load_mibs(Agent, Mibs) when is_list(Mibs) -> - snmpa_agent:load_mibs(Agent, Mibs). + snmpa_agent:load_mibs(Agent, Mibs, false); +load_mibs(Mibs, Force) + when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) -> + load_mibs(snmp_master_agent, Mibs, Force). + +-spec load_mibs(Agent :: pid() | atom(), + Mibs :: [MibName :: string()], + Force :: boolean()) -> + ok | {error, {'load aborted at', MibName :: string(), InternalReason :: already_loaded | term()}}. + +load_mibs(Agent, Mibs, Force) + when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) -> + snmpa_agent:load_mibs(Agent, Mibs, Force). + + +unload_mib(Mib) -> + unload_mib(snmp_master_agent, Mib). + +-spec unload_mib(Agent :: pid() | atom(), Mib :: string()) -> + ok | {error, Reason :: not_loaded | term()}. + +unload_mib(Agent, Mib) -> + case unload_mibs(Agent, [Mib]) of + {error, {'unload aborted at', Mib, Reason}} -> + {error, Reason}; + Else -> + Else + end. unload_mibs(Mibs) -> - unload_mibs(snmp_master_agent, Mibs). + unload_mibs(snmp_master_agent, Mibs, false). unload_mibs(Agent, Mibs) when is_list(Mibs) -> - snmpa_agent:unload_mibs(Agent, Mibs). + snmpa_agent:unload_mibs(Agent, Mibs); +unload_mibs(Mibs, Force) + when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) -> + unload_mibs(snmp_master_agent, Mibs, Force). + +-spec unload_mibs(Agent :: pid() | atom(), + Mibs :: [MibName :: string()], + Force :: boolean()) -> + ok | {error, {'unload aborted at', MibName :: string(), InternalReason :: not_loaded | term()}}. + +unload_mibs(Agent, Mibs, Force) + when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) -> + snmpa_agent:unload_mibs(Agent, Mibs, Force). + which_mibs() -> which_mibs(snmp_master_agent). which_mibs(Agent) -> snmpa_agent:which_mibs(Agent). + whereis_mib(Mib) -> whereis_mib(snmp_master_agent, Mib). whereis_mib(Agent, Mib) when is_atom(Mib) -> diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index c267ce5a70..9bed6e554e 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -28,7 +28,8 @@ %% External exports -export([start_link/4, start_link/5, stop/1]). -export([subagent_set/2, - load_mibs/2, unload_mibs/2, which_mibs/1, whereis_mib/2, info/1, + load_mibs/3, unload_mibs/3, + which_mibs/1, whereis_mib/2, info/1, register_subagent/3, unregister_subagent/2, send_notification/3, register_notification_filter/5, @@ -71,7 +72,8 @@ handle_pdu/8, worker/2, worker_loop/1, do_send_trap/7, do_send_trap/8]). %% <BACKWARD-COMPAT> --export([handle_pdu/7]). +-export([handle_pdu/7, + load_mibs/2, unload_mibs/2]). %% </BACKWARD-COMPAT> -include("snmpa_internal.hrl"). @@ -528,12 +530,22 @@ subagent_set(SubAgent, Arguments) -> %% Called by administrator (not agent; deadlock would occur) +%% <BACKWARD-COMPAT> load_mibs(Agent, Mibs) -> - call(Agent, {load_mibs, Mibs}). + load_mibs(Agent, Mibs, false). +%% </BACKWARD-COMPAT> + +load_mibs(Agent, Mibs, Force) -> + call(Agent, {load_mibs, Mibs, Force}). %% Called by administrator (not agent; deadlock would occur) +%% <BACKWARD-COMPAT> unload_mibs(Agent, Mibs) -> - call(Agent, {unload_mibs, Mibs}). + unload_mibs(Agent, Mibs, false). +%% </BACKWARD-COMPAT> + +unload_mibs(Agent, Mibs, Force) -> + call(Agent, {unload_mibs, Mibs, Force}). which_mibs(Agent) -> call(Agent, which_mibs). @@ -1216,13 +1228,25 @@ handle_call({unregister_subagent, SubTreeOid}, _From, S) -> end, {reply, Reply, S}; +%% <BACKWARD-COMPAT> handle_call({load_mibs, Mibs}, _From, S) -> ?vlog("load mibs ~p", [Mibs]), {reply, snmpa_mib:load_mibs(get(mibserver), Mibs), S}; +%% </BACKWARD-COMPAT> + +handle_call({load_mibs, Mibs, Force}, _From, S) -> + ?vlog("[~w] load mibs ~p", [Force, Mibs]), + {reply, snmpa_mib:load_mibs(get(mibserver), Mibs, Force), S}; +%% <BACKWARD-COMPAT> handle_call({unload_mibs, Mibs}, _From, S) -> ?vlog("unload mibs ~p", [Mibs]), {reply, snmpa_mib:unload_mibs(get(mibserver), Mibs), S}; +%% </BACKWARD-COMPAT> + +handle_call({unload_mibs, Mibs, Force}, _From, S) -> + ?vlog("[~w] unload mibs ~p", [Force, Mibs]), + {reply, snmpa_mib:unload_mibs(get(mibserver), Mibs, Force), S}; handle_call(which_mibs, _From, S) -> ?vlog("which mibs", []), diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl index 031309b990..5b523447c5 100644 --- a/lib/snmp/src/agent/snmpa_mib.erl +++ b/lib/snmp/src/agent/snmpa_mib.erl @@ -26,7 +26,7 @@ %% External exports -export([start_link/3, stop/1, lookup/2, next/3, which_mib/2, which_mibs/1, whereis_mib/2, - load_mibs/2, unload_mibs/2, + load_mibs/3, unload_mibs/3, register_subagent/3, unregister_subagent/2, info/1, info/2, verbosity/2, dump/1, dump/2, backup/2, @@ -39,6 +39,10 @@ which_cache_size/1 ]). +%% <BACKWARD-COMPAT> +-export([load_mibs/2, unload_mibs/2]). +%% </BACKWARD-COMPAT> + %% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -182,19 +186,32 @@ next(MibServer, Oid, MibView) -> %%---------------------------------------------------------------------- %% Purpose: Loads mibs into the mib process. %% Args: Mibs is a list of Filenames (compiled mibs). +%% Force is a boolean %% Returns: ok | {error, Reason} %%---------------------------------------------------------------------- + +%% <BACKWARD-COMPAT> load_mibs(MibServer, Mibs) -> - call(MibServer, {load_mibs, Mibs}). + load_mibs(MibServer, Mibs, false). +%% </BACKWARD-COMPAT> + +load_mibs(MibServer, Mibs, Force) -> + call(MibServer, {load_mibs, Mibs, Force}). %%---------------------------------------------------------------------- %% Purpose: Loads mibs into the mib process. %% Args: Mibs is a list of Filenames (compiled mibs). +%% Force is a boolean %% Returns: ok | {error, Reason} %%---------------------------------------------------------------------- +%% <BACKWARD-COMPAT> unload_mibs(MibServer, Mibs) -> - call(MibServer, {unload_mibs, Mibs}). + unload_mibs(MibServer, Mibs, false). +%% </BACKWARD-COMPAT> + +unload_mibs(MibServer, Mibs, Force) -> + call(MibServer, {unload_mibs, Mibs, Force}). %%---------------------------------------------------------------------- @@ -323,10 +340,6 @@ do_init(Prio, Mibs, Opts) -> %% Returns: {ok, NewMibData} | {'aborted at', Mib, NewData, Reason} %% Args: Operation is load_mib | unload_mib. %%---------------------------------------------------------------------- -mib_operations(Mod, Operation, Mibs, Data, MeOverride, TeOverride) -> - mib_operations(Mod, Operation, Mibs, Data, MeOverride, TeOverride, false). - - mib_operations(_Mod, _Operation, [], Data, _MeOverride, _TeOverride, _Force) -> {ok, Data}; mib_operations(Mod, Operation, [Mib|Mibs], Data0, MeOverride, TeOverride, Force) -> @@ -451,18 +464,23 @@ handle_call({next, Oid, MibView}, _From, ?vdebug("next -> Reply: ~p", [Reply]), {reply, Reply, NewState}; -handle_call({load_mibs, Mibs}, _From, +%% <BACKWARD-COMPAT> +handle_call({load_mibs, Mibs}, From, State) -> + handle_call({load_mibs, Mibs, false}, From, State); +%% </BACKWARD-COMPAT> + +handle_call({load_mibs, Mibs, Force}, _From, #state{data = Data, teo = TeOverride, meo = MeOverride, cache = Cache, data_mod = Mod} = State) -> - ?vlog("load mibs ~p",[Mibs]), + ?vlog("[~w] load mibs ~p", [Force, Mibs]), %% Invalidate cache NewCache = maybe_invalidate_cache(Cache), {NData, Reply} = case (catch mib_operations(Mod, load_mib, Mibs, Data, - MeOverride, TeOverride)) of + MeOverride, TeOverride, Force)) of {'aborted at', Mib, NewData, Reason} -> ?vlog("aborted at ~p for reason ~p",[Mib,Reason]), {NewData, {error, {'load aborted at', Mib, Reason}}}; @@ -472,19 +490,24 @@ handle_call({load_mibs, Mibs}, _From, Mod:sync(NData), {reply, Reply, State#state{data = NData, cache = NewCache}}; -handle_call({unload_mibs, Mibs}, _From, +%% <BACKWARD-COMPAT> +handle_call({unload_mibs, Mibs}, From, State) -> + handle_call({unload_mibs, Mibs, false}, From, State); +%% </BACKWARD-COMPAT> + +handle_call({unload_mibs, Mibs, Force}, _From, #state{data = Data, teo = TeOverride, meo = MeOverride, cache = Cache, data_mod = Mod} = State) -> - ?vlog("unload mibs ~p",[Mibs]), + ?vlog("[~w] unload mibs ~p", [Force, Mibs]), %% Invalidate cache NewCache = maybe_invalidate_cache(Cache), %% Unload mib(s) {NData, Reply} = case (catch mib_operations(Mod, unload_mib, Mibs, Data, - MeOverride, TeOverride)) of + MeOverride, TeOverride, Force)) of {'aborted at', Mib, NewData, Reason} -> ?vlog("aborted at ~p for reason ~p", [Mib,Reason]), {NewData, {error, {'unload aborted at', Mib, Reason}}}; diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 16b626111b..6edcf7e833 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -29,12 +29,22 @@ %% {add_module, snmpm_net_if_mt} [ + {"4.24.1", + [ + {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []} + ] + }, {"4.24", [ {load_module, snmp_conf, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []} + {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []} ] }, {"4.23.1", [{restart_application, snmp}]}, @@ -47,12 +57,22 @@ %% {remove, {snmpm_net_if_mt, soft_purge, soft_purge}} [ + {"4.24.1", + [ + {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []} + ] + }, {"4.24", [ {load_module, snmp_conf, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []} + {load_module, snmpa, soft_purge, soft_purge, [snmpa_agent]}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_agent]}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []} ] }, {"4.23.1", [{restart_application, snmp}]}, diff --git a/lib/snmp/test/snmp_agent_mibs_test.erl b/lib/snmp/test/snmp_agent_mibs_test.erl index 248fe7d83e..f7dae64e3f 100644 --- a/lib/snmp/test/snmp_agent_mibs_test.erl +++ b/lib/snmp/test/snmp_agent_mibs_test.erl @@ -238,6 +238,8 @@ start_and_stop(Config) when is_list(Config) -> load_unload(suite) -> []; load_unload(Config) when is_list(Config) -> + ?DBG("load_unload -> start", []), + Prio = normal, Verbosity = log, MibDir = ?config(data_dir, Config), @@ -253,8 +255,10 @@ load_unload(Config) when is_list(Config) -> ?line ok = load_mibs(MibsPid, MibDir, ["Test2"]), ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["Test2"]), - ?DBG("load_unload -> load one already loaded mib", []), - ?line {error, _} = load_mibs(MibsPid, MibDir, ["Test2"]), + ?DBG("load_unload -> try load one *already loaded* mib", []), + EMib = join(MibDir, "Test2"), + ?line {error, {'load aborted at', EMib, already_loaded}} = + load_mibs(MibsPid, MibDir, ["Test2"]), ?DBG("load_unload -> load 2 not already loaded mibs", []), ?line ok = load_mibs(MibsPid, MibDir, ["TestTrap", "TestTrapv2"]), @@ -266,7 +270,8 @@ load_unload(Config) when is_list(Config) -> ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["TestTrap", "TestTrapv2"]), ?DBG("load_unload -> try unload two loaded mibs and one not loaded", []), - ?line {error, _} = unload_mibs(MibsPid, ["TestTrap","Test2","TestTrapv2"]), + ?line {error, {'unload aborted at', "Test2", not_loaded}} = + unload_mibs(MibsPid, ["TestTrap","Test2","TestTrapv2"]), ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["TestTrapv2"]), ?DBG("load_unload -> unload the remaining loaded mib", []), @@ -279,6 +284,7 @@ load_unload(Config) when is_list(Config) -> ?DBG("load_unload -> stop symbolic store", []), ?line sym_stop(), + ?DBG("load_unload -> done", []), ok. @@ -691,10 +697,16 @@ mibs_info(Pid) -> load_mibs(Pid, Dir, Mibs0) -> Mibs = [join(Dir, Mib) || Mib <- Mibs0], - snmpa_mib:load_mibs(Pid, Mibs). + Res = snmpa_mib:load_mibs(Pid, Mibs), + %% ?DBG("load_mibs -> " + %% "~n Res: ~p", [Res]), + Res. unload_mibs(Pid, Mibs) -> - snmpa_mib:unload_mibs(Pid, Mibs). + Res = snmpa_mib:unload_mibs(Pid, Mibs), + %% ?DBG("unload_mibs -> " + %% "~n Res: ~p", [Res]), + Res. verify_loaded_mibs(Pid, Dir, ExpectedMibs0) -> ExpectedMibs = [join(Dir, Mib) || Mib <- ExpectedMibs0], diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index 6fe97ccd25..7e683e315a 100644 --- a/lib/snmp/test/snmp_agent_test.erl +++ b/lib/snmp/test/snmp_agent_test.erl @@ -554,7 +554,7 @@ init_per_suite(Config0) when is_list(Config0) -> %% Mib-dirs MibDir = snmp_test_lib:lookup(data_dir, Config2), - StdMibDir = filename:join([code:priv_dir(snmp), "mibs"]), + StdMibDir = join([code:priv_dir(snmp), "mibs"]), Config3 = [{mib_dir, MibDir}, {std_mib_dir, StdMibDir} | Config2], @@ -748,21 +748,21 @@ init_per_testcase2(Case, Config) -> CaseTopDir = snmp_test_lib:init_testcase_top_dir(Case, Config), %% Create agent top-dir(s) - AgentTopDir = filename:join([CaseTopDir, agent]), + AgentTopDir = join([CaseTopDir, agent]), ok = file:make_dir(AgentTopDir), - AgentConfDir = filename:join([AgentTopDir, config]), + AgentConfDir = join([AgentTopDir, config]), ok = file:make_dir(AgentConfDir), - AgentDbDir = filename:join([AgentTopDir, db]), + AgentDbDir = join([AgentTopDir, db]), ok = file:make_dir(AgentDbDir), - AgentLogDir = filename:join([AgentTopDir, log]), + AgentLogDir = join([AgentTopDir, log]), ok = file:make_dir(AgentLogDir), %% Create sub-agent top-dir(s) - SubAgentTopDir = filename:join([CaseTopDir, sub_agent]), + SubAgentTopDir = join([CaseTopDir, sub_agent]), ok = file:make_dir(SubAgentTopDir), %% Create manager top-dir(s) - ManagerTopDir = filename:join([CaseTopDir, manager]), + ManagerTopDir = join([CaseTopDir, manager]), ok = file:make_dir(ManagerTopDir), [{case_top_dir, CaseTopDir}, @@ -1738,19 +1738,19 @@ init_case(Config) -> load_master(Mib) -> ?DBG("load_master -> entry with" "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]). + snmpa:unload_mib(snmp_master_agent, Mib), % Unload for safety + ok = snmpa:load_mib(snmp_master_agent, join(get(mib_dir), Mib)). load_master_std(Mib) -> ?DBG("load_master_std -> entry with" "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]). + snmpa:unload_mib(snmp_master_agent, Mib), % Unload for safety + ok = snmpa:load_mib(snmp_master_agent, join(get(std_mib_dir), Mib)). unload_master(Mib) -> ?DBG("unload_master -> entry with" "~n Mib: ~p", [Mib]), - ok = snmpa:unload_mibs(snmp_master_agent, [Mib]). + ok = snmpa:unload_mib(snmp_master_agent, Mib). loaded_mibs() -> ?DBG("loaded_mibs -> entry",[]), @@ -2155,11 +2155,11 @@ subagent(Config) when is_list(Config) -> try_test(unreg_test), ?P1("Loading previous subagent mib in master and testing..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]), + ?line ok = snmpa:load_mib(MA, join(MibDir, "Klas1")), try_test(load_test), ?P1("Unloading previous subagent mib in master and testing..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]), + ?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas1")), try_test(unreg_test), ?P1("Testing register subagent..."), rpc:call(SaNode, snmp, register_subagent, @@ -2355,11 +2355,11 @@ sa_register(Config) when is_list(Config) -> ?P1("Unloading Klas1..."), ?DBG("sa_register -> unload mibs", []), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), + snmpa:unload_mib(SA, join(MibDir, "Klas1")), ?P1("Loading SA-MIB..."), ?DBG("sa_register -> unload mibs", []), - snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]), + snmpa:load_mib(SA, join(MibDir, "SA-MIB")), ?P1("register subagent..."), ?DBG("sa_register -> register subagent", []), @@ -2578,7 +2578,7 @@ next_across_sa(Config) when is_list(Config) -> ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), ?P1("Loading another subagent mib (Klas1)..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]), + ?line ok = snmpa:load_mib(SA, MibDir ++ "Klas1"), ?P1("register subagent..."), rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]), @@ -2590,7 +2590,7 @@ next_across_sa(Config) when is_list(Config) -> try_test(next_across_sa_test), ?P1("Unloading mib (Klas1)"), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), + snmpa:unload_mib(SA, join(MibDir, "Klas1")), rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), try_test(unreg_test), @@ -2631,25 +2631,25 @@ undo(Config) when is_list(Config) -> ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), ?P1("Load Klas3 & Klas4..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]), + ?line ok = snmpa:load_mib(MA, join(MibDir, "Klas3")), + ?line ok = snmpa:load_mib(MA, join(MibDir, "Klas4")), ?P1("Testing undo phase at master agent..."), try_test(undo_test), try_test(api_test2), ?P1("Unload Klas3..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]), + ?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas3")), ?P1("Testing bad return values from instrum. funcs..."), try_test(bad_return), ?P1("Unload Klas4..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]), + ?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas4")), ?P1("Testing undo phase at subagent..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]), + ?line ok = snmpa:load_mib(SA, join(MibDir, "Klas3")), + ?line ok = snmpa:load_mib(SA, join(MibDir, "Klas4")), ?line ok = snmpa:register_subagent(MA, ?klas3, SA), ?line ok = snmpa:register_subagent(MA, ?klas4, SA), try_test(undo_test), @@ -6247,8 +6247,8 @@ otp_4394_config(AgentConfDir, MgrDir, Ip0) -> "OTP-4394 test"), ?line case update_usm(Vsn, AgentConfDir) of true -> - ?line copy_file(filename:join(AgentConfDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), + ?line copy_file(join(AgentConfDir, "usm.conf"), + join(MgrDir, "usm.conf")), ?line update_usm_mgr(Vsn, MgrDir); false -> ?line ok @@ -6407,11 +6407,11 @@ otp8395({init, Config}) when is_list(Config) -> %% AgentDbDir = ?config(agent_db_dir, Config), - AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]), + AgentMnesiaDir = join([AgentDbDir, "mnesia"]), mnesia_init(AgentNode, AgentMnesiaDir), %% SubAgentDir = ?config(sub_agent_dir, Config), - %% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]), + %% SubAgentMnesiaDir = join([SubAgentDir, "mnesia"]), %% mnesia_init(SubAgentNode, SubAgentMnesiaDir), %% ok = mnesia_create_schema(AgentNode, [AgentNode, SubAgentNode]), @@ -6541,7 +6541,7 @@ otp8395(Config) when is_list(Config) -> ?SLEEP(1000), AgentNode = ?config(agent_node, Config), AgentLogDir = ?config(agent_log_dir, Config), - OutFile = filename:join([AgentLogDir, "otp8395.txt"]), + OutFile = join([AgentLogDir, "otp8395.txt"]), {ok, LogInfo} = rpc:call(AgentNode, snmpa, log_info, []), ?DBG("otp8395 -> LogInfo: ~p", [LogInfo]), @@ -6579,7 +6579,7 @@ otp9884({init, Config}) when is_list(Config) -> %% AgentDbDir = ?config(agent_db_dir, Config), - AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]), + AgentMnesiaDir = join([AgentDbDir, "mnesia"]), mnesia_init(AgentNode, AgentMnesiaDir), mnesia_create_schema(AgentNode, [AgentNode]), @@ -6609,8 +6609,8 @@ otp9884({init, Config}) when is_list(Config) -> 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]), + AgentBkpDir1 = join([AgentTopDir, backup1]), + AgentBkpDir2 = join([AgentTopDir, backup2]), ok = file:make_dir(AgentBkpDir1), ok = file:make_dir(AgentBkpDir2), AgentBkpDirs = [AgentBkpDir1, AgentBkpDir2], @@ -7105,7 +7105,7 @@ display_log(Config) -> {value, {_, Node}} -> LogDir = Dir, Mibs = [], - OutFile = filename:join(LogDir, "snmpa_log.txt"), + OutFile = join(LogDir, "snmpa_log.txt"), p("~n" "=========================" " < Audit Trail Log > " @@ -7252,6 +7252,14 @@ lists_key1search(Key, List) when is_atom(Key) -> %% regs() -> %% lists:sort(registered()). +%% ------ + +join(Parts) -> + filename:join(Parts). + +join(Dir, File) -> + filename:join(Dir, File). + %% ------ diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl index 7e4b713e56..122289c28e 100644 --- a/lib/snmp/test/snmp_agent_test_lib.erl +++ b/lib/snmp/test/snmp_agent_test_lib.erl @@ -139,31 +139,31 @@ init_all(Config) when is_list(Config) -> SuiteTopDir = ?config(snmp_suite_top_dir, Config), ?DBG("init_all -> SuiteTopDir ~p", [SuiteTopDir]), - AgentDir = filename:join(SuiteTopDir, "agent/"), + AgentDir = join(SuiteTopDir, "agent/"), ?line ok = file:make_dir(AgentDir), ?DBG("init_all -> AgentDir ~p", [AgentDir]), - AgentDbDir = filename:join(AgentDir, "db/"), + AgentDbDir = join(AgentDir, "db/"), ?line ok = file:make_dir(AgentDbDir), ?DBG("init_all -> AgentDbDir ~p", [AgentDbDir]), - AgentLogDir = filename:join(AgentDir, "log/"), + AgentLogDir = join(AgentDir, "log/"), ?line ok = file:make_dir(AgentLogDir), ?DBG("init_all -> AgentLogDir ~p", [AgentLogDir]), - AgentConfDir = filename:join(AgentDir, "conf/"), + AgentConfDir = join(AgentDir, "conf/"), ?line ok = file:make_dir(AgentConfDir), ?DBG("init_all -> AgentConfDir ~p", [AgentConfDir]), - MgrDir = filename:join(SuiteTopDir, "mgr/"), + MgrDir = join(SuiteTopDir, "mgr/"), ?line ok = file:make_dir(MgrDir), ?DBG("init_all -> MgrDir ~p", [MgrDir]), - SaDir = filename:join(SuiteTopDir, "sa/"), + SaDir = join(SuiteTopDir, "sa/"), ?line ok = file:make_dir(SaDir), ?DBG("init_all -> SaDir ~p", [SaDir]), - SaDbDir = filename:join(SaDir, "db/"), + SaDbDir = join(SaDir, "db/"), ?line ok = file:make_dir(SaDbDir), ?DBG("init_all -> SaDbDir ~p", [SaDbDir]), @@ -183,11 +183,11 @@ init_all(Config) when is_list(Config) -> ?DBG("init_all -> application mnesia: set_env dir",[]), ?line application_controller:set_env(mnesia, dir, - filename:join(AgentDbDir, "Mnesia1")), + join(AgentDbDir, "Mnesia1")), ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]), ?line rpc:call(SaNode, application_controller, set_env, - [mnesia, dir, filename:join(SaDir, "Mnesia2")]), + [mnesia, dir, join(SaDir, "Mnesia2")]), ?DBG("init_all -> create mnesia schema",[]), ?line ok = mnesia:create_schema([SaNode, node()]), @@ -253,7 +253,7 @@ init_case(Config) when is_list(Config) -> MibDir = ?config(mib_dir, Config), put(mib_dir, MibDir), - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", + StdM = join(code:priv_dir(snmp), "mibs") ++ "/", put(std_mib_dir, StdM), MgrDir = ?config(mgr_dir, Config), @@ -341,7 +341,7 @@ run(Mod, Func, Args, Opts) -> Crypto = ?CRYPTO_START(), ?DBG("run -> Crypto: ~p", [Crypto]), catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", + StdM = join(code:priv_dir(snmp), "mibs") ++ "/", Vsn = get(vsn), ?DBG("run -> config:" "~n M: ~p" @@ -763,7 +763,7 @@ start_subagent(SaNode, RegTree, Mib) -> MA = whereis(snmp_master_agent), ?DBG("start_subagent -> MA: ~p", [MA]), MibDir = get(mib_dir), - Mib1 = join(MibDir,Mib), + Mib1 = join(MibDir, Mib), Mod = snmpa_supervisor, Func = start_sub_agent, Args = [MA, RegTree, [Mib1]], @@ -800,28 +800,25 @@ mibs(StdMibDir,MibDir) -> join(MibDir, "Test2.bin"), join(MibDir, "TestTrapv2.bin")]. -join(D,F) -> - filename:join(D,F). - %% --- various mib load/unload functions --- load_master(Mib) -> ?DBG("load_master -> entry with" "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]). + snmpa:unload_mib(snmp_master_agent, Mib), % Unload for safety + ok = snmpa:load_mib(snmp_master_agent, join(get(mib_dir), Mib)). load_master_std(Mib) -> ?DBG("load_master_std -> entry with" "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]). + snmpa:unload_mib(snmp_master_agent, Mib), % Unload for safety + ok = snmpa:load_mibs(snmp_master_agent, join(get(std_mib_dir), Mib)). unload_master(Mib) -> ?DBG("unload_master -> entry with" "~n Mib: ~p", [Mib]), - ok = snmpa:unload_mibs(snmp_master_agent, [Mib]). + ok = snmpa:unload_mib(snmp_master_agent, Mib). loaded_mibs() -> ?DBG("loaded_mibs -> entry",[]), @@ -1383,8 +1380,8 @@ config(Vsns, MgrDir, AgentConfDir, MIp, AIp) -> "test"), ?line case update_usm(Vsns, AgentConfDir) of true -> - ?line copy_file(filename:join(AgentConfDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), + ?line copy_file(join(AgentConfDir, "usm.conf"), + join(MgrDir, "usm.conf")), ?line update_usm_mgr(Vsns, MgrDir); false -> ?line ok @@ -1403,9 +1400,9 @@ delete_files(Config) -> delete_files(_AgentFiles, []) -> ok; delete_files(AgentDir, [DirName|DirNames]) -> - Dir = filename:join(AgentDir, DirName), + Dir = join(AgentDir, DirName), {ok, Files} = file:list_dir(Dir), - lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end, + lists:foreach(fun(FName) -> file:delete(join(Dir, FName)) end, Files), delete_files(AgentDir, DirNames). @@ -1481,8 +1478,8 @@ update_usm_mgr(Vsns, Dir) -> end. rewrite_usm_mgr(Dir, ShaKey, DesKey) -> - ?line ok = file:rename(filename:join(Dir,"usm.conf"), - filename:join(Dir,"usm.old")), + ?line ok = file:rename(join(Dir,"usm.conf"), + join(Dir,"usm.old")), Conf = [{"agentEngine", "newUser", "newUser", zeroDotZero, usmHMACSHAAuthProtocol, "", "", usmDESPrivProtocol, "", "", "", ShaKey, DesKey}, @@ -1492,8 +1489,8 @@ rewrite_usm_mgr(Dir, ShaKey, DesKey) -> ok = snmp_config:write_agent_usm_config(Dir, "", Conf). reset_usm_mgr(Dir) -> - ?line ok = file:rename(filename:join(Dir,"usm.old"), - filename:join(Dir,"usm.conf")). + ?line ok = file:rename(join(Dir,"usm.old"), + join(Dir,"usm.conf")). update_community([v3], _Dir) -> @@ -1526,7 +1523,7 @@ write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) -> rewrite_target_addr_conf(Dir, NewPort) -> ?DBG("rewrite_target_addr_conf -> entry with" "~n NewPort: ~p", [NewPort]), - TAFile = filename:join(Dir, "target_addr.conf"), + TAFile = join(Dir, "target_addr.conf"), case file:read_file_info(TAFile) of {ok, _} -> ok; @@ -1546,8 +1543,8 @@ rewrite_target_addr_conf(Dir, NewPort) -> ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]), - ?line ok = file:rename(filename:join(Dir,"target_addr.conf"), - filename:join(Dir,"target_addr.old")), + ?line ok = file:rename(join(Dir,"target_addr.conf"), + join(Dir,"target_addr.old")), ?line ok = snmp_config:write_agent_target_addr_config(Dir, "", NewAddrs). @@ -1565,8 +1562,8 @@ rewrite_target_addr_conf2(_NewPort,O) -> O. reset_target_addr_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir, "target_addr.old"), - filename:join(Dir, "target_addr.conf")). + ?line ok = file:rename(join(Dir, "target_addr.old"), + join(Dir, "target_addr.conf")). write_target_params_conf(Dir, Vsns) -> F = fun(v1) -> {"target_v1", v1, v1, "all-rights", noAuthNoPriv}; @@ -1578,14 +1575,14 @@ write_target_params_conf(Dir, Vsns) -> rewrite_target_params_conf(Dir, SecName, SecLevel) when is_list(SecName) andalso is_atom(SecLevel) -> - ?line ok = file:rename(filename:join(Dir,"target_params.conf"), - filename:join(Dir,"target_params.old")), + ?line ok = file:rename(join(Dir,"target_params.conf"), + join(Dir,"target_params.old")), Conf = [{"target_v3", v3, usm, SecName, SecLevel}], snmp_config:write_agent_target_params_config(Dir, "", Conf). reset_target_params_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_params.old"), - filename:join(Dir,"target_params.conf")). + ?line ok = file:rename(join(Dir,"target_params.old"), + join(Dir,"target_params.conf")). write_notify_conf(Dir) -> Conf = [{"standard trap", "std_trap", trap}, @@ -1648,6 +1645,9 @@ rpc(Node, F, A) -> rpc:call(Node, snmpa, F, A). +join(Dir, File) -> + filename:join(Dir, File). + %% await_pdu(To) -> %% await_response(To, pdu). %% diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index e987649e11..2164121e86 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -18,6 +18,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 4.24.1 +SNMP_VSN = 4.24.2 PRE_VSN = APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index 299dd5058a..6b7ff7b238 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -138,7 +138,7 @@ <item> <p> Fix link to documentation for ssh:connect/3,4. Thanks to - Martin H�ssler.</p> + Martin Hässler.</p> <p> Own Id: OTP-10862</p> </item> diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml index 38cd44def6..2c1daf10ba 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -126,20 +126,20 @@ </item> <item> <p> - Optimizations to gen mechanism. Thanks to Lo�c Hoguin.</p> + Optimizations to gen mechanism. Thanks to Loïc Hoguin.</p> <p> Own Id: OTP-11025</p> </item> <item> <p> - Optimizations to gen.erl. Thanks to Lo�c Hoguin.</p> + Optimizations to gen.erl. Thanks to Loïc Hoguin.</p> <p> Own Id: OTP-11035</p> </item> <item> <p> Use erlang:demonitor(Ref, [flush]) where applicable. - Thanks to Lo�c Hoguin.</p> + Thanks to Loïc Hoguin.</p> <p> Own Id: OTP-11039</p> </item> @@ -194,7 +194,7 @@ </item> <item> <p> - Improve erl_lint performance. Thanks to Jos� Valim.</p> + Improve erl_lint performance. Thanks to José Valim.</p> <p> Own Id: OTP-11143</p> </item> @@ -297,7 +297,7 @@ <p> Two adjacent * used as a single pattern will match all files and zero or more directories and subdirectories. - (Thanks to Jos� Valim)</p> + (Thanks to José Valim)</p> <p> Own Id: OTP-10431</p> </item> @@ -535,7 +535,7 @@ Fix filename:nativename/1 on Win32</p> <p> Don't choke on paths given as binary argument on Win32. - Thanks to Jan Kl�tzke</p> + Thanks to Jan Klötzke</p> <p> Own Id: OTP-10188</p> </item> @@ -644,7 +644,7 @@ <item> <p> Fix the type spec from the doc of binary:part/3 (Thanks - to Ricardo Catalinas Jim�nez)</p> + to Ricardo Catalinas Jiménez)</p> <p> Own Id: OTP-9920</p> </item> @@ -3209,7 +3209,7 @@ It is now possible to hibernate a gen_server/gen_event/gen_fsm. In gen_server and gen_fsm, hibernation is triggered by returning the atom - 'hibernate'�instead of a timeout value. In the gen_event + 'hibernate' instead of a timeout value. In the gen_event case hibernation is triggered by a event handler returning a tuple with an extra element containing the atom 'hibernate'.</p> diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 8f07750b9b..f599881c07 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -1953,12 +1953,10 @@ expr({string,_Line,_S}, _Vt, St) -> {[],St}; expr({nil,_Line}, _Vt, St) -> {[],St}; expr({cons,_Line,H,T}, Vt, St) -> expr_list([H,T], Vt, St); -expr({lc,_Line,E,Qs}, Vt0, St0) -> - {Vt,St} = handle_comprehension(E, Qs, Vt0, St0), - {vtold(Vt, Vt0),St}; %Don't export local variables -expr({bc,_Line,E,Qs}, Vt0, St0) -> - {Vt,St} = handle_comprehension(E, Qs, Vt0, St0), - {vtold(Vt,Vt0),St}; %Don't export local variables +expr({lc,_Line,E,Qs}, Vt, St) -> + handle_comprehension(E, Qs, Vt, St); +expr({bc,_Line,E,Qs}, Vt, St) -> + handle_comprehension(E, Qs, Vt, St); expr({tuple,_Line,Es}, Vt, St) -> expr_list(Es, Vt, St); expr({record_index,Line,Name,Field}, _Vt, St) -> @@ -2012,8 +2010,7 @@ expr({'fun',Line,Body}, Vt, St) -> %%No one can think funs export! case Body of {clauses,Cs} -> - {Bvt, St1} = fun_clauses(Cs, Vt, St), - {vtupdate(Bvt, Vt), St1}; + fun_clauses(Cs, Vt, St); {function,F,A} -> %% BifClash - Fun expression %% N.B. Only allows BIFs here as well, NO IMPORTS!! @@ -2111,12 +2108,12 @@ expr({'try',Line,Es,Scs,Ccs,As}, Vt, St0) -> {Evt0,St1} = exprs(Es, Vt, St0), TryLine = {'try',Line}, Uvt = vtunsafe(vtnames(vtnew(Evt0, Vt)), TryLine, []), - Evt1 = vtupdate(Uvt, vtupdate(Evt0, Vt)), - {Sccs,St2} = icrt_clauses(Scs++Ccs, TryLine, Evt1, St1), + Evt1 = vtupdate(Uvt, vtsubtract(Evt0, Uvt)), + {Sccs,St2} = icrt_clauses(Scs++Ccs, TryLine, vtupdate(Evt1, Vt), St1), Rvt0 = Sccs, Rvt1 = vtupdate(vtunsafe(vtnames(vtnew(Rvt0, Vt)), TryLine, []), Rvt0), Evt2 = vtmerge(Evt1, Rvt1), - {Avt0,St} = exprs(As, Evt2, St2), + {Avt0,St} = exprs(As, vtupdate(Evt2, Vt), St2), Avt1 = vtupdate(vtunsafe(vtnames(vtnew(Avt0, Vt)), TryLine, []), Avt0), Avt = vtmerge(Evt2, Avt1), {Avt,St}; @@ -2150,10 +2147,11 @@ expr({remote,Line,_M,_F}, _Vt, St) -> %% {UsedVarTable,State} expr_list(Es, Vt, St) -> - foldl(fun (E, {Esvt,St0}) -> - {Evt,St1} = expr(E, Vt, St0), - {vtmerge(Evt, Esvt),St1} - end, {[],St}, Es). + {Vt1,St1} = foldl(fun (E, {Esvt,St0}) -> + {Evt,St1} = expr(E, Vt, St0), + {vtmerge_pat(Evt, Esvt),St1} + end, {[],St}, Es), + {vtmerge(vtnew(Vt1, Vt), vtold(Vt1, Vt)),St1}. record_expr(Line, Rec, Vt, St0) -> St1 = warn_invalid_record(Line, Rec, St0), @@ -2310,7 +2308,7 @@ check_fields(Fs, Name, Fields, Vt, St0, CheckFun) -> check_field({record_field,Lf,{atom,La,F},Val}, Name, Fields, Vt, St, Sfs, CheckFun) -> case member(F, Sfs) of - true -> {Sfs,{Vt,add_error(Lf, {redefine_field,Name,F}, St)}}; + true -> {Sfs,{[],add_error(Lf, {redefine_field,Name,F}, St)}}; false -> {[F|Sfs], case find_field(F, Fields) of @@ -2843,7 +2841,9 @@ icrt_export(Csvt, Vt, In, St) -> Uvt = vtmerge(Evt, Unused), %% Make exported and unsafe unused variables unused in subsequent code: Vt2 = vtmerge(Uvt, vtsubtract(Vt1, Uvt)), - {Vt2,St}. + %% Forget about old variables which were not used: + Vt3 = vtmerge(vtnew(Vt2, Vt), vt_no_unused(vtold(Vt2, Vt))), + {Vt3,St}. handle_comprehension(E, Qs, Vt0, St0) -> {Vt1, Uvt, St1} = lc_quals(Qs, Vt0, St0), @@ -2856,7 +2856,11 @@ handle_comprehension(E, Qs, Vt0, St0) -> %% Local variables that have not been shadowed. {_,St} = check_unused_vars(Vt2, Vt0, St4), Vt3 = vtmerge(vtsubtract(Vt2, Uvt), Uvt), - {Vt3,St}. + %% Don't export local variables. + Vt4 = vtold(Vt3, Vt0), + %% Forget about old variables which were not used. + Vt5 = vt_no_unused(Vt4), + {Vt5,St}. %% lc_quals(Qualifiers, ImportVarTable, State) -> %% {VarTable,ShadowedVarTable,State} @@ -2920,7 +2924,7 @@ fun_clauses(Cs, Vt, St) -> {Cvt,St1} = fun_clause(C, Vt, St0), {vtmerge(Cvt, Bvt0),St1} end, {[],St#lint{recdef_top = false}}, Cs), - {Bvt,St2#lint{recdef_top = OldRecDef}}. + {vt_no_unused(vtold(Bvt, Vt)),St2#lint{recdef_top = OldRecDef}}. fun_clause({clause,_Line,H,G,B}, Vt0, St0) -> {Hvt,Binvt,St1} = head(H, Vt0, [], St0), % No imported pattern variables @@ -3181,6 +3185,8 @@ vt_no_unsafe(Vt) -> [V || {_,{S,_U,_L}}=V <- Vt, _ -> true end]. +vt_no_unused(Vt) -> [V || {_,{_,U,_L}}=V <- Vt, U =/= unused]. + %% vunion(VarTable1, VarTable2) -> [VarName]. %% vunion([VarTable]) -> [VarName]. %% vintersection(VarTable1, VarTable2) -> [VarName]. diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 4dc7a44064..48ddeac478 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -151,7 +151,16 @@ unused_vars_warn_basic(Config) when is_list(Config) -> {22,erl_lint,{unused_var,'N'}}, {23,erl_lint,{shadowed_var,'N','fun'}}, {28,erl_lint,{unused_var,'B'}}, - {29,erl_lint,{unused_var,'B'}}]}}], + {29,erl_lint,{unused_var,'B'}}]}}, + {basic2, + <<"-record(r, {x,y}). + f({X,Y}) -> {Z=X,Z=Y}; + f([H|T]) -> [Z=H|Z=T]; + f(#r{x=X,y=Y}) -> #r{x=A=X,y=A=Y}. + g({M, F}) -> (Z=M):(Z=F)(); + g({M, F, Arg}) -> (Z=M):F(Z=Arg). + h(X, Y) -> (Z=X) + (Z=Y).">>, + [warn_unused_vars], []}], ?line [] = run(Config, Ts), ok. @@ -537,7 +546,29 @@ unused_vars_warn_rec(Config) when is_list(Config) -> end. ">>, [warn_unused_vars], - {warnings,[{22,erl_lint,{unused_var,'Same'}}]}}], + {warnings,[{22,erl_lint,{unused_var,'Same'}}]}}, + {rec2, + <<"-record(r, {a,b}). + f(X, Y) -> #r{a=[K || K <- Y], b=[K || K <- Y]}. + g(X, Y) -> #r{a=lists:map(fun (K) -> K end, Y), + b=lists:map(fun (K) -> K end, Y)}. + h(X, Y) -> #r{a=case Y of _ when is_list(Y) -> Y end, + b=case Y of _ when is_list(Y) -> Y end}. + i(X, Y) -> #r{a=if is_list(Y) -> Y end, b=if is_list(Y) -> Y end}. + ">>, + [warn_unused_vars], + {warnings,[{2,erl_lint,{unused_var,'X'}}, + {3,erl_lint,{unused_var,'X'}}, + {5,erl_lint,{unused_var,'X'}}, + {7,erl_lint,{unused_var,'X'}}]}}, + {rec3, + <<"-record(r, {a}). + t() -> X = 1, #r{a=foo, a=bar, a=qux}. + ">>, + [warn_unused_vars], + {error,[{2,erl_lint,{redefine_field,r,a}}, + {2,erl_lint,{redefine_field,r,a}}], + [{2,erl_lint,{unused_var,'X'}}]}}], ?line [] = run(Config, Ts), ok. @@ -1075,7 +1106,24 @@ unsafe_vars_try(Config) when is_list(Config) -> {10,erl_lint,{unsafe_var,'Ra',{'try',3}}}, {10,erl_lint,{unsafe_var,'Rc',{'try',3}}}, {10,erl_lint,{unsafe_var,'Ro',{'try',3}}}], - []}}], + []}}, + {unsafe_try5, + <<"bang() -> + case 1 of + nil -> + Acc = 2; + _ -> + try + Acc = 3, + Acc + catch _:_ -> + ok + end + end, + Acc. + ">>, + [], + {errors,[{13,erl_lint,{unsafe_var,'Acc',{'try',6}}}],[]}}], ?line [] = run(Config, Ts), ok. diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml index 05049d7107..422d4538a6 100644 --- a/lib/tools/doc/src/notes.xml +++ b/lib/tools/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -103,7 +103,7 @@ <item> <p> Fix a bug in cover when used with no_auto_import. Thanks - to Jos� Valim.</p> + to José Valim.</p> <p> Own Id: OTP-10778</p> </item> @@ -138,7 +138,7 @@ <item> <p> Add separate face for exported functions (Thanks to - Thomas J�rvstrand)</p> + Thomas Järvstrand)</p> <p> Own Id: OTP-10637</p> </item> @@ -223,7 +223,7 @@ </item> <item> <p> - Documentation fixes (Thanks to Ricardo Catalinas Jim�nez + Documentation fixes (Thanks to Ricardo Catalinas Jiménez )</p> <p> Own Id: OTP-10121</p> diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml index a6e89d32a9..6ecae3752b 100644 --- a/lib/wx/doc/src/notes.xml +++ b/lib/wx/doc/src/notes.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -39,7 +39,7 @@ <p> Add {silent_start, boolean()} option to wx:new/1 in order to be able to suppress error messages during startup of - wx. (Thanks to H�kan Mattsson)</p> + wx. (Thanks to Håkan Mattsson)</p> <p> Own Id: OTP-10585</p> </item> |