aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--HOWTO/OTP-PATCH-APPLY.md144
-rw-r--r--erts/aclocal.m424
-rw-r--r--erts/emulator/beam/io.c5
-rw-r--r--lib/ssl/doc/src/ssl.xml18
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache.xml2
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache_api.xml16
-rw-r--r--lib/stdlib/doc/src/zip.xml8
-rw-r--r--lib/stdlib/src/zip.erl46
-rw-r--r--lib/stdlib/test/zip_SUITE.erl42
-rw-r--r--lib/tools/src/tags.erl9
-rwxr-xr-xotp_patch_apply480
-rw-r--r--system/doc/installation_guide/Makefile6
-rw-r--r--system/doc/installation_guide/part.xml1
-rw-r--r--system/doc/installation_guide/xmlfiles.mk3
-rw-r--r--system/doc/system_principles/versions.xml5
16 files changed, 750 insertions, 60 deletions
diff --git a/.gitignore b/.gitignore
index 18a54c21ca..07b66c3e2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -381,6 +381,7 @@ JAVADOC-GENERATED
/system/doc/installation_guide/INSTALL.xml
/system/doc/installation_guide/INSTALL-CROSS.xml
/system/doc/installation_guide/INSTALL-WIN32.xml
+/system/doc/installation_guide/OTP-PATCH-APPLY.xml
/system/doc/installation_guide/MARKDOWN.xml
# test_server
diff --git a/HOWTO/OTP-PATCH-APPLY.md b/HOWTO/OTP-PATCH-APPLY.md
new file mode 100644
index 0000000000..2aa31629ef
--- /dev/null
+++ b/HOWTO/OTP-PATCH-APPLY.md
@@ -0,0 +1,144 @@
+Patching OTP Applications
+=========================
+
+Introduction
+------------
+
+This document describes the process of patching an existing OTP
+installation with one or more Erlang/OTP applications of newer versions
+than already installed. The tool `otp_patch_apply` is available for this
+specific purpose. It resides in the top directory of the Erlang/OTP
+source tree.
+
+The `otp_patch_apply` tool utilizes the [runtime_dependencies][] tag in
+the [application resource file][]. This information is used to determine
+if the patch can be installed in the given Erlang/OTP installation
+directory.
+
+Read more about the [version handling][] introduced in Erlang/OTP release
+17, which also describes how to determine if an installation includes one
+or more patched applications.
+
+If you want to apply patches of multiple OTP applications that resides
+in different OTP versions, you have to apply these patches in multiple
+steps. It is only possible to apply multiple OTP applications from the
+same OTP version at once.
+
+Prerequisites
+-------------
+
+It's assumed that the reader is familiar with
+[building and installing Erlang/OTP][]. To be able to patch an
+application, the following must exist:
+
+* An Erlang/OTP installation.
+
+* An Erlang/OTP source tree containing the updated applications that
+ you want to patch into the existing Erlang/OTP installation.
+
+Using otp\_patch\_apply
+-----------------------
+
+> *WARNING*: Patching applications is a one-way process.
+> Create a backup of your OTP installation directory before
+> proceeding.
+
+First of all, build the OTP source tree at `$ERL_TOP` containing
+the updated applications.
+
+> *NOTE*: Before applying a patch you need to do a *full* build
+> of OTP in the source directory.
+
+If you are building in `git` you first need to generate the
+`configure` scripts:
+
+ $ ./otp_build autoconf
+
+Configure and build all applications in OTP:
+
+ $ configure
+ $ make
+
+or
+
+ $ ./otp_build configure
+ $ ./otp_build boot -a
+
+If you have installed documentation in the OTP installation, also
+build the documentation:
+
+ $ make docs
+
+After the successful build it's time to patch. The source tree directory,
+the directory of the installation and the applications to patch are given
+as arguments to `otp_patch_apply`. The dependencies of each application
+are validated against the applications in the installation and the other
+applications given as arguments. If a dependency error is detected, the
+script will be aborted.
+
+The `otp_patch_apply` syntax:
+
+ $ otp_patch_apply -s <Dir> -i <Dir> [-l <Dir>] [-c] [-f] [-h] \
+ [-n] [-v] <App1> [... <AppN>]
+
+ -s <Dir> -- OTP source directory that contains build results.
+ -i <Dir> -- OTP installation directory to patch.
+ -l <Dir> -- Alternative OTP source library directory path(s)
+ containing build results of OTP applications.
+ Multiple paths should be colon separated.
+ -c -- Cleanup (remove) old versions of applications
+ patched in the installation.
+ -f -- Force patch of application(s) even though
+ dependencies are not fulfilled (should only be
+ considered in a test environment).
+ -h -- Print help then exit.
+ -n -- Do not install documentation.
+ -v -- Print version then exit.
+ <AppX> -- Application to patch.
+
+ Environment Variable:
+ ERL_LIBS -- Alternative OTP source library directory path(s)
+ containing build results of OTP applications.
+ Multiple paths should be colon separated.
+
+> *NOTE*: The complete build environment is required while running
+> `otp_patch_apply`.
+
+> *NOTE*: All source directories identified by `-s` and `-l` should
+> contain build results of OTP applications.
+
+For example, if the user wants to install patched versions of `mnesia`
+and `ssl` built in `/home/me/git/otp` into the OTP installation
+located in `/opt/erlang/my_otp` type
+
+ $ otp_patch_apply -s /home/me/git/otp -i /opt/erlang/my_otp \
+ mnesia ssl
+
+> *NOTE*: If the list of applications contains core applications,
+> i.e `erts`, `kernel`, `stdlib` or `sasl`, the `Install` script in
+> the patched Erlang/OTP installation must be rerun.
+
+The patched applications are appended to the list of installed
+applications. Take a look at
+`<InstallDir>/releases/OTP-REL/installed_application_versions`.
+
+Sanity check
+------------
+
+The application dependencies can be checked using the Erlang shell.
+Application dependencies are verified among installed applications by
+`otp_patch_apply`, but these are not necessarily those actually loaded.
+By calling `system_information:sanity_check()` one can validate
+dependencies among applications actually loaded.
+
+ 1> system_information:sanity_check().
+ ok
+
+Please take a look at the reference of [sanity_check()][] for more
+information.
+
+[application resource file]: kernel:app
+[runtime_dependencies]: kernel:app#runtime_dependencies
+[building and installing Erlang/OTP]: INSTALL.md
+[version handling]: ../system_principles/versions
+[sanity_check()]: runtime_tools:system_information#sanity_check-0
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index 264a1726db..670907a41d 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -246,31 +246,31 @@ lbl1:
return 1;
lbl2:
return 2;
-],ac_cv_prog_emu_cc=$CC,ac_cv_prog_emu_cc=no)
+],ac_cv_prog_emu_cc="$CC",ac_cv_prog_emu_cc=no)
-if test $ac_cv_prog_emu_cc = no; then
+if test "$ac_cv_prog_emu_cc" = no; then
for ac_progname in emu_cc.sh gcc-4.2 gcc; do
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
ac_dummy="$PATH"
for ac_dir in $ac_dummy; do
test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_progname; then
- ac_cv_prog_emu_cc=$ac_dir/$ac_progname
+ if test -f "$ac_dir/$ac_progname"; then
+ ac_cv_prog_emu_cc="$ac_dir/$ac_progname"
break
fi
done
IFS="$ac_save_ifs"
- if test $ac_cv_prog_emu_cc != no; then
+ if test "$ac_cv_prog_emu_cc" != no; then
break
fi
done
fi
-if test $ac_cv_prog_emu_cc != no; then
- save_CC=$CC
+if test "$ac_cv_prog_emu_cc" != no; then
+ save_CC="$CC"
save_CFLAGS=$CFLAGS
save_CPPFLAGS=$CPPFLAGS
- CC=$ac_cv_prog_emu_cc
+ CC="$ac_cv_prog_emu_cc"
CFLAGS=""
CPPFLAGS=""
AC_TRY_COMPILE([],[
@@ -291,17 +291,17 @@ if test $ac_cv_prog_emu_cc != no; then
return 1;
lbl2:
return 2;
- ],ac_cv_prog_emu_cc=$CC,ac_cv_prog_emu_cc=no)
+ ],ac_cv_prog_emu_cc="$CC",ac_cv_prog_emu_cc=no)
CC=$save_CC
CFLAGS=$save_CFLAGS
CPPFLAGS=$save_CPPFLAGS
fi
])
-if test $ac_cv_prog_emu_cc = no; then
+if test "$ac_cv_prog_emu_cc" = no; then
AC_DEFINE(NO_JUMP_TABLE,[],[Defined if no found C compiler can handle jump tables])
- EMU_CC=$CC
+ EMU_CC="$CC"
else
- EMU_CC=$ac_cv_prog_emu_cc
+ EMU_CC="$ac_cv_prog_emu_cc"
fi
AC_SUBST(EMU_CC)
])
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index dc4c6fc350..9377237475 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -4085,6 +4085,9 @@ erts_port_control(Process* c_p,
size,
&resp_bufp,
&resp_size);
+
+ control_flags = prt->control_flags;
+
finalize_imm_drv_call(&try_call_state);
if (tmp_alloced)
erts_free(ERTS_ALC_T_TMP, bufp);
@@ -4092,8 +4095,6 @@ erts_port_control(Process* c_p,
return ERTS_PORT_OP_BADARG;
}
- control_flags = prt->control_flags;
-
hsz = port_control_result_size(control_flags,
resp_bufp,
&resp_size,
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index c9b02d44ec..47100c0d81 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -94,7 +94,7 @@
{log_alert, boolean()} | {server_name_indication, hostname() | disable}
</c></p>
- <p><c>transportoption() = {cb_info, {CallbackModule::atom(), DataTag::atom(), ClosedTag::atom(), ErrTag:atom()}}
+ <p><c>transportoption() = {cb_info, {CallbackModule :: atom(), DataTag :: atom(), ClosedTag :: atom(), ErrTag:atom()}}
- defaults to {gen_tcp, tcp, tcp_closed, tcp_error}. Can be used to customize
the transport layer. The callback module must implement a reliable transport
protocol and behave as gen_tcp and in addition have functions corresponding to
@@ -303,20 +303,20 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() | {revo
</taglist>
</item>
- <tag>{crl_check, boolean() | peer | best_effort )</tag>
+ <tag>{crl_check, boolean() | peer | best_effort }</tag>
<item>
Perform CRL (Certificate Revocation List) verification
<seealso marker="public_key:public_key#pkix_crl_validate-3">
- public_key:pkix_crls_validate/3</seealso>, during the
+ (public_key:pkix_crls_validate/3)</seealso> on all the certificates during the path validation
<seealso
- marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3 </seealso>
- invokation on all the certificates in the peer certificate chain. Defaults to
- false.
-
+ marker="public_key:public_key#pkix_path_validation-3">(public_key:pkix_path_validation/3)
+ </seealso>
+ of the certificate chain. Defaults to false.
+
<p><c>peer</c> - check is only performed on
the peer certificate.</p>
- <p><c>best_effort</c> - if certificate revokation status can not be determined
+ <p><c>best_effort</c> - if certificate revocation status can not be determined
it will be accepted as valid.</p>
<p>The CA certificates specified for the connection will be used to
@@ -326,7 +326,7 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() | {revo
<seealso marker="ssl:ssl_crl_cache_api">ssl_crl_cache_api(3)</seealso>.</p>
</item>
- <tag>{crl_cache, {Module::atom, {DbHandle::internal | term(), Args::list()}}</tag>
+ <tag>{crl_cache, {Module :: atom(), {DbHandle :: internal | term(), Args :: list()}}}</tag>
<item>
<p>Module defaults to ssl_crl_cache with <c> DbHandle </c> internal and an
empty argument list. The following arguments may be specified for the internal cache.</p>
diff --git a/lib/ssl/doc/src/ssl_crl_cache.xml b/lib/ssl/doc/src/ssl_crl_cache.xml
index 1ed76d3e2a..b291c7b633 100644
--- a/lib/ssl/doc/src/ssl_crl_cache.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache.xml
@@ -29,7 +29,7 @@
<p>
Implements an internal CRL (Certificate Revocation List) cache.
In addition to implementing the <seealso
- marker="ssl_cache_crl_api"> ssl_cache_crl_api</seealso>
+ marker="ssl_cache_crl_api"> ssl_cache_crl_api</seealso> behaviour
the following functions are available.
</p>
</description>
diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml
index 24365c9f59..3f518496be 100644
--- a/lib/ssl/doc/src/ssl_crl_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml
@@ -27,13 +27,15 @@
<modulesummary>API for a SSL/TLS CRL (Certificate Revocation List) cache.</modulesummary>
<description>
<p>
- When SSL/TLS performs certificate path validation according to
- <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> it should
- also perform CRL validation checks. To enable the CRL checks the application
- needs access to CRLs. A database of CRLs can be set up in many different ways.
- This module provides an API to integrate an arbitrary CRL cache with the erlang
- ssl application. It is also used by the application itself to provide a simple
- default implementation of a CRL cache.
+ When SSL/TLS performs certificate path validation according to
+ <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url>
+ it should also perform CRL validation checks. To enable the CRL
+ checks the application needs access to CRLs. A database of CRLs
+ can be set up in many different ways. This module provides the
+ behavior of the API needed to integrate an arbitrary CRL cache
+ with the erlang ssl application. It is also used by the
+ application itself to provide a simple default implementation of
+ a CRL cache.
</p>
</description>
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index 48b376743d..d201e81a79 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -135,6 +135,12 @@
<p>These options are described in <seealso marker="#zip_options">create/3</seealso>.</p>
</desc>
</datatype>
+ <datatype>
+ <name name="handle"/>
+ <desc>
+ <p>As returned by <seealso marker="#zip_open/2">zip_open/2</seealso>.</p>
+ </desc>
+ </datatype>
</datatypes>
<funcs>
<func>
@@ -430,6 +436,8 @@
means that subsequently reading files from the archive will be
faster than unzipping files one at a time with <c>unzip</c>.</p>
<p>The archive must be closed with <c>zip_close/1</c>.</p>
+ <p>The <c><anno>ZipHandle</anno></c> will be closed if the
+ process which originally opened the archive dies.</p>
</desc>
</func>
<func>
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index b768c6d0b9..44e75ff15b 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -214,7 +214,9 @@
-type zip_comment() :: #zip_comment{}.
-type zip_file() :: #zip_file{}.
--export_type([create_option/0, filename/0]).
+-opaque handle() :: pid().
+
+-export_type([create_option/0, filename/0, handle/0]).
%% Open a zip archive with options
%%
@@ -500,7 +502,7 @@ do_list_dir(F, Options) ->
-spec(t(Archive) -> ok when
Archive :: file:name() | binary() | ZipHandle,
- ZipHandle :: pid()).
+ ZipHandle :: handle()).
t(F) when is_pid(F) -> zip_t(F);
t(F) when is_record(F, openzip) -> openzip_t(F);
@@ -524,7 +526,7 @@ do_t(F, RawPrint) ->
-spec(tt(Archive) -> ok when
Archive :: file:name() | binary() | ZipHandle,
- ZipHandle :: pid()).
+ ZipHandle :: handle()).
tt(F) when is_pid(F) -> zip_tt(F);
tt(F) when is_record(F, openzip) -> openzip_tt(F);
@@ -1114,15 +1116,19 @@ local_file_header_from_info_method_name(#file_info{mtime = MTime},
file_name_length = length(Name),
extra_field_length = 0}.
+server_init(Parent) ->
+ %% we want to know if our parent dies
+ process_flag(trap_exit, true),
+ server_loop(Parent, not_open).
%% small, simple, stupid zip-archive server
-server_loop(OpenZip) ->
+server_loop(Parent, OpenZip) ->
receive
{From, {open, Archive, Options}} ->
case openzip_open(Archive, Options) of
{ok, NewOpenZip} ->
From ! {self(), {ok, self()}},
- server_loop(NewOpenZip);
+ server_loop(Parent, NewOpenZip);
Error ->
From ! {self(), Error}
end;
@@ -1130,43 +1136,47 @@ server_loop(OpenZip) ->
From ! {self(), openzip_close(OpenZip)};
{From, get} ->
From ! {self(), openzip_get(OpenZip)},
- server_loop(OpenZip);
+ server_loop(Parent, OpenZip);
{From, {get, FileName}} ->
From ! {self(), openzip_get(FileName, OpenZip)},
- server_loop(OpenZip);
+ server_loop(Parent, OpenZip);
{From, list_dir} ->
From ! {self(), openzip_list_dir(OpenZip)},
- server_loop(OpenZip);
+ server_loop(Parent, OpenZip);
{From, {list_dir, Opts}} ->
From ! {self(), openzip_list_dir(OpenZip, Opts)},
- server_loop(OpenZip);
+ server_loop(Parent, OpenZip);
{From, get_state} ->
From ! {self(), OpenZip},
- server_loop(OpenZip);
+ server_loop(Parent, OpenZip);
+ {'EXIT', Parent, Reason} ->
+ openzip_close(OpenZip),
+ exit({parent_died, Reason});
_ ->
{error, bad_msg}
end.
-spec(zip_open(Archive) -> {ok, ZipHandle} | {error, Reason} when
Archive :: file:name() | binary(),
- ZipHandle :: pid(),
+ ZipHandle :: handle(),
Reason :: term()).
zip_open(Archive) -> zip_open(Archive, []).
-spec(zip_open(Archive, Options) -> {ok, ZipHandle} | {error, Reason} when
Archive :: file:name() | binary(),
- ZipHandle :: pid(),
+ ZipHandle :: handle(),
Options :: [Option],
Option :: cooked | memory | {cwd, CWD :: file:filename()},
Reason :: term()).
zip_open(Archive, Options) ->
- Pid = spawn(fun() -> server_loop(not_open) end),
- request(self(), Pid, {open, Archive, Options}).
+ Self = self(),
+ Pid = spawn_link(fun() -> server_init(Self) end),
+ request(Self, Pid, {open, Archive, Options}).
-spec(zip_get(ZipHandle) -> {ok, [Result]} | {error, Reason} when
- ZipHandle :: pid(),
+ ZipHandle :: handle(),
Result :: file:name() | {file:name(), binary()},
Reason :: term()).
@@ -1174,14 +1184,14 @@ zip_get(Pid) when is_pid(Pid) ->
request(self(), Pid, get).
-spec(zip_close(ZipHandle) -> ok | {error, einval} when
- ZipHandle :: pid()).
+ ZipHandle :: handle()).
zip_close(Pid) when is_pid(Pid) ->
request(self(), Pid, close).
-spec(zip_get(FileName, ZipHandle) -> {ok, Result} | {error, Reason} when
FileName :: file:name(),
- ZipHandle :: pid(),
+ ZipHandle :: handle(),
Result :: file:name() | {file:name(), binary()},
Reason :: term()).
@@ -1190,7 +1200,7 @@ zip_get(FileName, Pid) when is_pid(Pid) ->
-spec(zip_list_dir(ZipHandle) -> {ok, Result} | {error, Reason} when
Result :: [zip_comment() | zip_file()],
- ZipHandle :: pid(),
+ ZipHandle :: handle(),
Reason :: term()).
zip_list_dir(Pid) when is_pid(Pid) ->
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
index a57641ef62..d168a9d9bc 100644
--- a/lib/stdlib/test/zip_SUITE.erl
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -23,7 +23,7 @@
bad_zip/1, unzip_from_binary/1, unzip_to_binary/1,
zip_to_binary/1,
unzip_options/1, zip_options/1, list_dir_options/1, aliases/1,
- openzip_api/1, zip_api/1, unzip_jar/1,
+ openzip_api/1, zip_api/1, open_leak/1, unzip_jar/1,
compress_control/1,
foldl/1]).
@@ -38,7 +38,7 @@ all() ->
[borderline, atomic, bad_zip, unzip_from_binary,
unzip_to_binary, zip_to_binary, unzip_options,
zip_options, list_dir_options, aliases, openzip_api,
- zip_api, unzip_jar, compress_control, foldl].
+ zip_api, open_leak, unzip_jar, compress_control, foldl].
groups() ->
[].
@@ -318,8 +318,46 @@ zip_api(Config) when is_list(Config) ->
%% Clean up.
delete_files([Names]),
+ ok.
+
+open_leak(doc) ->
+ ["Test that zip doesn't leak processes and ports where the "
+ "controlling process dies without closing an zip opened with "
+ "zip:zip_open/1."];
+open_leak(suite) -> [];
+open_leak(Config) when is_list(Config) ->
+ %% Create a zip archive
+ Zip = "zip.zip",
+ {ok, Zip} = zip:zip(Zip, [], []),
+
+ %% Open archive in a another process that dies immediately.
+ ZipSrv = spawn_zip(Zip, [memory]),
+
+ %% Expect the ZipSrv process to die soon after.
+ true = spawned_zip_dead(ZipSrv),
+
+ %% Clean up.
+ delete_files([Zip]),
+
ok.
+spawn_zip(Zip, Options) ->
+ Self = self(),
+ spawn(fun() -> Self ! zip:zip_open(Zip, Options) end),
+ receive
+ {ok, ZipSrv} ->
+ ZipSrv
+ end.
+
+spawned_zip_dead(ZipSrv) ->
+ Ref = monitor(process, ZipSrv),
+ receive
+ {'DOWN', Ref, _, ZipSrv, _} ->
+ true
+ after 1000 ->
+ false
+ end.
+
unzip_options(doc) ->
["Test options for unzip, only cwd and file_list currently"];
unzip_options(suite) ->
diff --git a/lib/tools/src/tags.erl b/lib/tools/src/tags.erl
index e3cc51cdb2..e25db2eb1b 100644
--- a/lib/tools/src/tags.erl
+++ b/lib/tools/src/tags.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -297,15 +297,16 @@ word_char(_) -> false.
%% Check the options `outfile' and `outdir'.
open_out(Options) ->
+ Opts = [write, {encoding, unicode}],
case lists:keysearch(outfile, 1, Options) of
{value, {outfile, File}} ->
- file:open(File, [write]);
+ file:open(File, Opts);
_ ->
case lists:keysearch(outdir, 1, Options) of
{value, {outdir, Dir}} ->
- file:open(filename:join(Dir, "TAGS"), [write]);
+ file:open(filename:join(Dir, "TAGS"), Opts);
_ ->
- file:open("TAGS", [write])
+ file:open("TAGS", Opts)
end
end.
diff --git a/otp_patch_apply b/otp_patch_apply
new file mode 100755
index 0000000000..947aa1e6ee
--- /dev/null
+++ b/otp_patch_apply
@@ -0,0 +1,480 @@
+#!/bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2014. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+version="1.0.1"
+
+force=
+lib_path=
+orig_dir=
+sdir=
+idir="/broken/path/here"
+cleanup=no
+install_docs=yes
+
+invalid_src="does not seem to be a valid OTP source tree"
+not_built="Source in has not been built"
+doc_not_built="Documentation has not been built. Either build the
+documentation and re-run 'otp_patch_apply', or re-run 'otp_patch_apply'
+with the '-n' switch."
+
+print_usage()
+{
+ cat <<EOF
+otp_patch_apply -s <Dir> -i <Dir> [-l <Dir>] [-c] [-f] [-h] [-n] [-v] \\
+ <App1> [... <AppN>]
+
+ -s <Dir> -- OTP source directory that contain build results.
+ -i <Dir> -- OTP installation directory to patch.
+ -l <Dir> -- Alternative OTP source library directory path(s) containing
+ build results of OTP applications. Multiple paths should be
+ colon separated.
+ -c -- Cleanup (remove) old versions of applications patched
+ in the installation.
+ -f -- Force patch of application(s) even though dependencies are
+ not fullfilled.
+ -h -- Print this help then exit.
+ -n -- Do not install documentation.
+ -v -- Print version then exit.
+ <AppX> -- Application to patch.
+
+Environment Variable:
+ ERL_LIBS -- Alternative OTP source library directory path(s) containing
+ build results of OTP applications. Multiple paths should be
+ colon separated.
+
+NOTE:
+ * Complete build environment is required while running otp_patch_apply.
+ * Before applying a patch you need to build all of OTP in the source
+ directory.
+ * All source directories identified by -s and -l should contain build
+ results of OTP applications.
+
+Version: $version
+
+EOF
+
+}
+
+error()
+{
+ echo "ERROR:" "$@" 1>&2
+ exit 1
+}
+
+usage_error()
+{
+ echo "ERROR:" "$@" 1>&2
+ echo "" 1>&2
+ print_usage 1>&2
+ exit 1
+}
+
+usage()
+{
+ print_usage
+ exit 0
+}
+
+alt_lib_path()
+{
+ app=$1
+ save_ifs=$IFS
+ IFS=:
+
+ cd "$orig_dir" || error "Cannot change directory to $orig_dir"
+
+ for lib in $lib_path; do
+ # Want absolute path
+ case "$lib" in
+ /*)
+ ;;
+ *)
+ cd "$lib" || error "Cannot change directory to $lib"
+ lib=`pwd`
+ cd "$orig_dir" || error "Cannot change directory to $orig_dir"
+ esac
+ if [ -d "$lib/$app" ]; then
+ echo "$lib/$app"
+ IFS=$save_ifs
+ return 0
+ fi
+ done
+
+ IFS=$save_ifs
+
+ return 1
+}
+
+prog_in_mod_path()
+{
+ chk_path="/bin:$PATH"
+ PROG=$1
+ save_ifs=$IFS
+ IFS=:
+ if [ "X$TARGET" = "Xwin32" ]; then
+ for p in $chk_path; do
+ if [ -f "$p/$PROG.exe" ]; then
+ IFS=$save_ifs
+ echo "$p/$PROG.exe"
+ return 0
+ fi
+ done
+ else
+ for p in $chk_path; do
+ if [ -x "$p/$PROG" ]; then
+ IFS=$save_ifs
+ echo "$p/$PROG"
+ return 0
+ fi
+ done
+ fi
+ IFS=$save_ifs
+ return 1
+}
+
+find_prog()
+{
+ prog_in_mod_path "$1"
+ if [ $? -ne 0 ]; then
+ echo "$1"
+ fi
+ return 0
+}
+
+# Parse arguments
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ "-s")
+ shift
+ if [ ! $# -gt 0 ]; then
+ usage_error "Missing OTP source directory"
+ fi
+ sdir="$1";;
+ "-i")
+ shift
+ if [ ! $# -gt 0 ]; then
+ usage_error "Missing OTP install directory"
+ fi
+ idir="$1";;
+ "-l")
+ shift
+ if [ ! $# -gt 0 ]; then
+ usage_error "Missing OTP library directory"
+ fi
+ if [ "x$lib_path" = "x" ]; then
+ lib_path="$1"
+ else
+ lib_path="$lib_path:$1"
+ fi;;
+ "-f")
+ force="-force";;
+ "-c")
+ cleanup=yes;;
+ "-h")
+ usage;;
+ "-n")
+ install_docs=no;;
+ "-v")
+ echo "otp_patch_apply version $version"
+ exit 0;;
+ *)
+ app="$1"
+ applications="$applications $app";;
+ esac
+ shift
+done
+
+# Check that we got mandatory arguments
+test "x$sdir" != "x" || usage_error "Missing OTP source directory"
+test "x$idir" != "x" || usage_error "Missing OTP install directory"
+test "x$applications" != "x" || usage_error "Missing applications"
+
+orig_dir=`pwd`
+
+# Check that the source directory seems sane
+cd "$sdir" 2>/dev/null || error "Cannot change directory to $sdir"
+
+# Want absolute path
+case "$sdir" in
+ /*) ;;
+ *) sdir=`pwd`;;
+esac
+
+export ERL_TOP="$sdir"
+test -f "$sdir/otp_build" || error "$ERL_TOP" $invalid_src
+test -f "$sdir/OTP_VERSION" || error "$ERL_TOP" $invalid_src
+test -f "$sdir/otp_versions.table" || error "$ERL_TOP" $invalid_src
+test -f "$sdir/erts/autoconf/config.guess" || error "$ERL_TOP" $invalid_src
+test -f "$sdir/make/verify_runtime_dependencies" || error "$ERL_TOP" $invalid_src
+test -x "$sdir/bootstrap/bin/erl" || error $not_built
+test -x "$sdir/bootstrap/bin/erlc" || error $not_built
+test -x "$sdir/bootstrap/bin/escript" || error $not_built
+test -f "$sdir/make/otp_built" || error $not_built
+
+if [ $install_docs = yes ]; then
+ test -f "$sdir/make/otp_doc_built" || usage_error $doc_not_built
+fi
+
+otp_rel=`sed 's|\([0-9]*\).*|\1|' < $ERL_TOP/OTP_VERSION` || \
+ error "Failed to read $ERL_TOP/OTP_VERSION"
+
+case "$otp_rel" in
+ 1[7-9]|[2-9][0-9]) ;; # ok; release 17-99
+ *) error "Invalid OTP release: $otp_rel";;
+esac
+
+export PATH="$ERL_TOP/bootstrap/bin:$PATH"
+erlc="$ERL_TOP/bootstrap/bin/erlc"
+erl="$ERL_TOP/bootstrap/bin/erl"
+
+erl_otp_rel=`$erl -noshell -noinput -eval "io:format(\"~s~n\", [erlang:system_info(otp_release)]), erlang:halt(0)"` || \
+ error "Failed to execute: $erl"
+
+test "$otp_rel" = "$erl_otp_rel" || error "Inconsistent source: $sdir"
+
+app_dirs=
+for app in $applications; do
+ case "$app" in
+ "erts")
+ dir="$ERL_TOP/erts";;
+ *)
+ dir="$ERL_TOP/lib/$app";;
+ esac
+ if [ ! -d "$dir" ]; then
+ dir=`alt_lib_path "$app"`
+ if [ $? -ne 0 ]; then
+ error "Application missing in source: $app"
+ fi
+ fi
+ app_dirs="$app_dirs $dir"
+done
+
+cd "$orig_dir" 2>/dev/null || error "Cannot change directory to $orig_dir"
+
+# Check that the install directory seems sane
+cd "$idir" 2>/dev/null || error "Cannot change directory to $idir"
+
+# Want absolute path
+case "$idir" in
+ /*) ;;
+ *) idir=`pwd`;;
+esac
+
+test -d "$idir/releases/$otp_rel" || \
+ error "No OTP-$otp_rel installation present in $idir"
+
+cd "$ERL_TOP" 2>/dev/null || error "Cannot change directory to $ERL_TOP"
+
+# Some tools we use
+rm=`find_prog rm`
+rmdir=`find_prog rmdir`
+cp=`find_prog cp`
+mv=`find_prog mv`
+mkdir=`find_prog mkdir`
+
+# Setup build stuff
+if [ "x$TARGET" = "x" ]; then
+ TARGET=`$ERL_TOP/erts/autoconf/config.guess`
+fi
+BUILDSYS=$TARGET
+if [ -z "$MAKE" ]; then
+ case $TARGET in
+ win32)
+ MAKE=make;;
+ *)
+ prog_in_mod_path gmake >/dev/null
+ if [ $? -eq 0 ]; then
+ MAKE=gmake
+ else
+ MAKE=make
+ fi;;
+ esac
+fi
+if [ X`$MAKE is_cross_configured` = Xyes ]; then
+ TARGET=`$MAKE target_configured`
+elif [ "x$OVERRIDE_TARGET" != "x" -a "x$OVERRIDE_TARGET" != "xwin32" ]; then
+ TARGET=$OVERRIDE_TARGET
+fi
+
+# Check for cleanup
+inst_app_vers="$idir/releases/$otp_rel/installed_application_versions"
+rm_app_vers=
+if [ $cleanup = yes ]; then
+ $mv "$inst_app_vers" "${inst_app_vers}.save" || \
+ error "Failed to save $inst_app_vers"
+ for app in $applications; do
+ tmp=`grep "$app-*" "${inst_app_vers}.save"`
+ rm_app_vers="$rm_app_vers $tmp"
+ done
+ $cp "${inst_app_vers}.save" "$inst_app_vers"
+ for rm_app_ver in $rm_app_vers; do
+ $cp "$inst_app_vers" "${inst_app_vers}.tmp"
+ grep -v $rm_app_ver "${inst_app_vers}.tmp" > "$inst_app_vers"
+ done
+ $rm -f "${inst_app_vers}.tmp"
+fi
+
+# Verify runtime dependencies
+$ERL_TOP/make/verify_runtime_dependencies -release "$otp_rel" \
+ -source "$ERL_TOP" -target "$idir" $force $applications || {
+ test ! -f "${inst_app_vers}.save" || \
+ $mv "${inst_app_vers}.save" "$inst_app_vers"
+ exit 1
+}
+
+# Update OTP_VERSION in installation
+otp_version=`cat "$idir/releases/$otp_rel/OTP_VERSION"` || {
+ test ! -f "${inst_app_vers}.save" || \
+ $mv "${inst_app_vers}.save" "$inst_app_vers"
+ error "Not able to read $idir/releases/$otp_rel/OTP_VERSION"
+}
+
+{
+ echo "$otp_version" | sed "s|^\([^\*]*\)\**|\1\*\*|g" > \
+ "$idir/releases/$otp_rel/OTP_VERSION"
+} 2>/dev/null || {
+ test ! -f "${inst_app_vers}.save" || \
+ $mv "${inst_app_vers}.save" "$inst_app_vers"
+ error "Not able to update $idir/releases/$otp_rel/OTP_VERSION"
+}
+
+# Do actual cleanup
+if [ "x$rm_app_vers" != "x" ]; then
+ for app_ver in $rm_app_vers; do
+ case x"$app_ver" in
+ x)
+ ;;
+ xerts-*)
+ $rm -rf "$idir/$app_ver" ;;
+ x*)
+ $rm -rf "$idir/lib/$app_ver" ;;
+ esac
+ done
+ $rm -f "${inst_app_vers}.save"
+fi
+
+# Install application from built source
+for app_dir in $app_dirs; do
+ (cd "$app_dir" && \
+ $MAKE MAKE="$MAKE" TARGET=$TARGET RELEASE_ROOT="$idir" \
+ RELEASE_PATH="$idir" TESTROOT="$idir" release) || exit 1
+done
+
+if [ $install_docs = yes ]; then
+# Documentation have been built and should be installed
+
+ for app_dir in $app_dirs; do
+ (cd "$app_dir" && \
+ $MAKE MAKE="$MAKE" RELEASE_ROOT="$idir" RELEASE_PATH="$idir" \
+ TESTROOT="$idir" release_docs) || exit 1
+ done
+
+ (cd "$sdir/system/doc/top" && $MAKE clean)
+
+ (cd "$sdir/system/doc/top" && \
+ $MAKE MAKE="$MAKE" RELEASE_ROOT="$idir" RELEASE_PATH="$idir" \
+ TESTROOT="$idir" release_docs) || exit 1
+
+ echo ""
+ echo "*"
+ echo "* NOTE! In order to update pre-formatted man pages you"
+ echo "* need to run the 'Install' script located in:"
+ echo "* $idir"
+ echo "*"
+fi
+
+# If erts, kernel, stdlib or sasl is included, find versions
+for app in $applications; do
+ case "$app" in
+ erts)
+ erts_vsn=`grep '^VSN' erts/vsn.mk | sed "s|^VSN.*=[^0-9]*\([0-9].*\)$|\1|g"`
+ update_rel=true;;
+ kernel)
+ kernel_vsn=`sed "s|^KERNEL_VSN[^=]*=[^0-9]*\([0-9].*\)$|\1|g" lib/kernel/vsn.mk`
+ update_rel=true;;
+ stdlib)
+ stdlib_vsn=`sed "s|^STDLIB_VSN[^=]*=[^0-9]*\([0-9].*\)$|\1|g" lib/stdlib/vsn.mk`
+ update_rel=true;;
+ sasl)
+ sasl_vsn=`sed "s|^SASL_VSN[^=]*=[^0-9]*\([0-9].*\)$|\1|g" lib/sasl/vsn.mk`
+ update_rel=true;;
+ *)
+ ;;
+ esac
+done
+
+# and find the old versions for those not included
+if [ "X$update_rel" != "X" ]; then
+ if [ "X$erts_vsn" = "X" ]; then
+ erts_vsns=`ls -d "$idir"/erts-* | sed "s|$idir/erts-\([0-9\.].*\)|\1|g"`
+ erts_vsn=`echo "$erts_vsns" | sort -t '.' -g | tail -n 1`
+ fi
+ if [ "X$kernel_vsn" = "X" ]; then
+ kernel_vsns=`ls -d "$idir"/lib/kernel-* | sed "s|$idir/lib/kernel-\([0-9\.].*\)|\1|g"`
+ kernel_vsn=`echo "$kernel_vsns" | sort -t '.' -g | tail -n 1`
+ fi
+ if [ "X$stdlib_vsn" = "X" ]; then
+ stdlib_vsns=`ls -d "$idir"/lib/stdlib-* | sed "s|$idir/lib/stdlib-\([0-9\.].*\)|\1|g"`
+ stdlib_vsn=`echo "$stdlib_vsns" | sort -t '.' -g | tail -n 1`
+ fi
+ if [ "X$sasl_vsn" = "X" ]; then
+ sasl_vsns=`ls -d "$idir"/lib/sasl-* | sed "s|$idir/lib/sasl-\([0-9\.].*\)|\1|g"`
+ sasl_vsn=`echo "$sasl_vsns" | sort -t '.' -g | tail -n 1`
+ fi
+
+ # Generate .rel, .script and .boot - to tmp dir
+ start_clean="{release, {\"Erlang/OTP\",\"$otp_rel\"}, {erts, \"$erts_vsn\"}, [{kernel,\"$kernel_vsn\"}, {stdlib,\"$stdlib_vsn\"}]}."
+ start_sasl="{release, {\"Erlang/OTP\",\"$otp_rel\"}, {erts, \"$erts_vsn\"}, [{kernel,\"$kernel_vsn\"}, {stdlib,\"$stdlib_vsn\"}, {sasl,\"$sasl_vsn\"}]}."
+
+ tmp_dir="$idir/tmp";
+ if [ ! -d "$tmp_dir" ]; then
+ $mkdir "$tmp_dir"
+ fi
+ echo "$start_sasl" > "$tmp_dir/start_sasl.rel"
+ echo "$start_clean" > "$tmp_dir/start_clean.rel"
+ echo "$start_clean" > "$tmp_dir/no_dot_erlang.rel"
+
+ $erlc -I"$idir"/lib/*/ebin -o"$tmp_dir" "$tmp_dir/start_sasl.rel" || exit 1
+ $erlc -I"$idir"/lib/*/ebin -o"$tmp_dir" +no_warn_sasl "$tmp_dir/start_clean.rel" || exit 1
+ $erlc -I"$idir"/lib/*/ebin -o"$tmp_dir" +no_warn_sasl +no_dot_erlang "$tmp_dir/no_dot_erlang.rel" || exit 1
+
+ # Generate RELEASES file
+ "$erl" -noinput +B -eval "release_handler:create_RELEASES(\"%ERL_ROOT%\", \"$tmp_dir\", \"$tmp_dir/start_sasl.rel\", []), halt()" || exit 1
+
+ # If all good so far, move generated files into target area
+ $mv "$tmp_dir/RELEASES" "$idir/releases/RELEASES.src"
+ $mv "$tmp_dir"/* "$idir/releases/$otp_rel"
+ $rmdir "$tmp_dir"
+
+ # Remove old start scripts (forces a new run of Install)
+ $rm -f "$idir"/releases/RELEASES
+ $rm -f "$idir"/bin/*.script
+ $rm -f "$idir"/bin/*.boot
+ $rm -f "$idir"/bin/erl
+
+ echo ""
+ echo "*"
+ echo "* NOTE! In order to get a runnable OTP system again you"
+ echo "* need to run the 'Install' script located in:"
+ echo "* $idir"
+ echo "*"
+fi
+
diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile
index 83210bd21f..a4ef6c9d7c 100644
--- a/system/doc/installation_guide/Makefile
+++ b/system/doc/installation_guide/Makefile
@@ -58,7 +58,8 @@ XML_FILES = \
GENERATED_XML_FILES = \
INSTALL.xml \
INSTALL-CROSS.xml \
- INSTALL-WIN32.xml
+ INSTALL-WIN32.xml \
+ OTP-PATCH-APPLY.xml
# ----------------------------------------------------
@@ -73,7 +74,8 @@ REDIRECT_HTML_DIR = $(HTMLDIR)/source
REDIRECT_HTML_FILES = \
$(REDIRECT_HTML_DIR)/INSTALL.html \
$(REDIRECT_HTML_DIR)/INSTALL-CROSS.html \
- $(REDIRECT_HTML_DIR)/INSTALL-WIN32.html
+ $(REDIRECT_HTML_DIR)/INSTALL-WIN32.html \
+ $(REDIRECT_HTML_DIR)/OTP-PATCH-APPLY.html
# ----------------------------------------------------
# FLAGS
diff --git a/system/doc/installation_guide/part.xml b/system/doc/installation_guide/part.xml
index 96a43d744b..5b1b3833cd 100644
--- a/system/doc/installation_guide/part.xml
+++ b/system/doc/installation_guide/part.xml
@@ -36,4 +36,5 @@
<xi:include href="INSTALL.xml"/>
<xi:include href="INSTALL-CROSS.xml"/>
<xi:include href="INSTALL-WIN32.xml"/>
+ <xi:include href="OTP-PATCH-APPLY.xml"/>
</part>
diff --git a/system/doc/installation_guide/xmlfiles.mk b/system/doc/installation_guide/xmlfiles.mk
index c443334cd7..a18c82bc25 100644
--- a/system/doc/installation_guide/xmlfiles.mk
+++ b/system/doc/installation_guide/xmlfiles.mk
@@ -20,4 +20,5 @@ INST_GUIDE_CHAPTER_FILES = \
install-binary.xml \
INSTALL.xml \
INSTALL-CROSS.xml \
- INSTALL-WIN32.xml
+ INSTALL-WIN32.xml \
+ OTP-PATCH-APPLY.xml
diff --git a/system/doc/system_principles/versions.xml b/system/doc/system_principles/versions.xml
index 25eb90f626..a0f13774ce 100644
--- a/system/doc/system_principles/versions.xml
+++ b/system/doc/system_principles/versions.xml
@@ -63,8 +63,9 @@
<c>filename:join([<seealso marker="kernel:code#root_dir/0">code:root_dir()</seealso>, "releases", <seealso marker="erts:erlang#system_info_otp_release"> erlang:system_info(otp_release)</seealso>, "OTP_VERSION"]).</c></p>
<p>If the version read from the <c>OTP_VERSION</c> file in a
development system has a <c>**</c> suffix, the system has been
- patched using the <c>otp_patch_apply</c> tool available to
- licensed customers. In this case, the system consists of application
+ patched using the
+ <seealso marker="../installation_guide/OTP-PATCH-APPLY"><c>otp_patch_apply</c></seealso>
+ tool. In this case, the system consists of application
versions from multiple OTP versions. The version preceding the <c>**</c>
suffix corresponds to the OTP version of the base system that
has been patched. Notice that if a development system is updated by