From 795607321cce0848213ad2f808b751801bc75832 Mon Sep 17 00:00:00 2001
From: Siri Hansen <siri@erlang.org>
Date: Mon, 4 Jul 2011 12:03:41 +0200
Subject: Update code path for all applications that have new versions in a
 release

If a new version of an application did not include any erlang module
changes, the code path of the application was not updasted unless a
'load_object_code' instruction was added for the application. This
would be a problem if e.g. only some files in the priv dir were
changed, since calls to code:lib_dir or code:priv_dir would then point
to the old location of the application. This has been corrected - now
code:replace_path/2 will be called for all applications that are
changed (i.e. when the application's vsn is changed in the .rel file).
---
 lib/sasl/src/release_handler.erl                   | 40 +++++++++--
 lib/sasl/src/release_handler_1.erl                 | 32 ++++-----
 lib/sasl/test/release_handler_SUITE.erl            | 82 +++++++++++++++++++---
 .../test/release_handler_SUITE_data/Makefile.src   |  8 +++
 .../test/release_handler_SUITE_data/lib/README     |  9 +++
 .../release_handler_SUITE_data/lib/a-1.0/src/a.app |  8 ---
 .../lib/a-1.2/ebin/a.app                           |  8 +++
 .../lib/a-1.2/ebin/a.appup                         |  3 +
 .../release_handler_SUITE_data/lib/a-1.2/priv/file |  0
 .../release_handler_SUITE_data/lib/a-1.2/src/a.erl | 54 ++++++++++++++
 .../lib/a-1.2/src/a_sup.erl                        | 37 ++++++++++
 11 files changed, 244 insertions(+), 37 deletions(-)
 create mode 100644 lib/sasl/test/release_handler_SUITE_data/lib/README
 delete mode 100644 lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app
 create mode 100644 lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app
 create mode 100644 lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.appup
 create mode 100644 lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/priv/file
 create mode 100644 lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a.erl
 create mode 100644 lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a_sup.erl

(limited to 'lib/sasl')

diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index eb29787103..ab54b1d00b 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -291,7 +291,8 @@ check_script(Script, LibDirs) ->
     release_handler_1:check_script(Script, LibDirs).
 
 %%-----------------------------------------------------------------
-%% eval_script(Script, Apps, LibDirs, Opts) -> {ok, UnPurged} |
+%% eval_script(Script, Apps, LibDirs, NewLibs, Opts) ->
+%%                                             {ok, UnPurged} |
 %%                                             restart_new_emulator |
 %%                                             {error, Error}
 %%                                             {'EXIT', Reason}
@@ -299,9 +300,13 @@ check_script(Script, LibDirs) ->
 %% net_kernel:monitor_nodes(true) before calling this function.
 %% No!  No other process than the release_handler can ever call this
 %% function, if sync_nodes is used.
-%%-----------------------------------------------------------------
-eval_script(Script, Apps, LibDirs, Opts) ->
-    catch release_handler_1:eval_script(Script, Apps, LibDirs, Opts).
+%%
+%% LibDirs is a list of all applications, while NewLibs is a list of
+%% applications that have changed version between the current and the
+%% new release.
+%% -----------------------------------------------------------------
+eval_script(Script, Apps, LibDirs, NewLibs, Opts) ->
+    catch release_handler_1:eval_script(Script, Apps, LibDirs, NewLibs, Opts).
 
 %%-----------------------------------------------------------------
 %% Func: create_RELEASES(Root, RelFile, LibDirs) -> ok | {error, Reason}
@@ -405,6 +410,7 @@ eval_appup_script(App, ToVsn, ToDir, Script) ->
     Res = release_handler_1:eval_script(Script,
 					[], % [AppSpec]
 					[{App, ToVsn, ToDir}],
+					[{App, ToVsn, ToDir}],
 					[]), % [Opt]
     case Res of
 	{ok, _Unpurged} ->
@@ -906,7 +912,9 @@ do_install_release(#state{start_prg = StartPrg,
 		    EnvBefore = application_controller:prep_config_change(),
 		    Apps = change_appl_data(RelDir, Release, Masters),
 		    LibDirs = Release#release.libs,
-		    case eval_script(Script, Apps, LibDirs, Opts) of
+		    NewLibs = get_new_libs(LatestRelease#release.libs,
+					   Release#release.libs),
+		    case eval_script(Script, Apps, LibDirs, NewLibs, Opts) of
 			{ok, []} ->
 			    application_controller:config_change(EnvBefore),
 			    mon_nodes(false),
@@ -1946,3 +1954,25 @@ safe_write_file_m(File, Data, Masters) ->
 			   filename:basename(File),
 			   filename:basename(Backup)}})
     end.
+
+%%-----------------------------------------------------------------
+%% Figure out which applications that have changed version between the
+%% two releases. The paths for these applications must always be
+%% updated, even if the relup script does not load any modules. See
+%% OTP-9402.
+%%
+%% A different situation is when the same application version is used
+%% in old and new release, but the path has changed. This is not
+%% handled here - instead it must be explicitely indicated by the
+%% 'update_paths' option to release_handler:install_release/2 if the
+%% code path shall be updated then.
+%% -----------------------------------------------------------------
+get_new_libs([{App,Vsn,LibDir}|CurrentLibs], NewLibs) ->
+    case lists:keyfind(App,1,NewLibs) of
+	{App,NewVsn,_} = LibInfo when NewVsn =/= Vsn ->
+	    [LibInfo | get_new_libs(CurrentLibs,NewLibs)];
+	_ ->
+	    get_new_libs(CurrentLibs,NewLibs)
+    end;
+get_new_libs([],_) ->
+    [].
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index 8d050fb7b0..3d6bc9fbc3 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.erl
@@ -19,7 +19,7 @@
 -module(release_handler_1).
 
 %% External exports
--export([eval_script/3, eval_script/4, check_script/2]).
+-export([eval_script/1, eval_script/5, check_script/2]).
 -export([get_current_vsn/1]). %% exported because used in a test case
 
 -record(eval_state, {bins = [], stopped = [], suspended = [], apps = [],
@@ -37,7 +37,7 @@
 %%                  is kept in case of a downgrade, where the code_change
 %%                  function receives the vsn of the module to downgrade
 %%                  *to*.
-%% newlibs   = [{Lib, Dir}] - list of all new libs; used to change
+%% newlibs   = [{Lib, LibVsn, LibDir}] - list of all new libs; used to change
 %%                            the code path
 %% opts      = [{Tag, Value}] - list of options
 %%-----------------------------------------------------------------
@@ -63,10 +63,11 @@ check_script(Script, LibDirs) ->
 	    {error, {old_processes, Mod}}
     end.
 
-eval_script(Script, Apps, LibDirs) ->
-    eval_script(Script, Apps, LibDirs, []).
+%% eval_script/1 - For testing only - no apps added, just testing instructions
+eval_script(Script) ->
+    eval_script(Script, [], [], [], []).
 
-eval_script(Script, Apps, LibDirs, Opts) ->
+eval_script(Script, Apps, LibDirs, NewLibs, Opts) ->
     case catch check_old_processes(Script) of
 	ok ->
 	    {Before, After} = split_instructions(Script),
@@ -75,6 +76,7 @@ eval_script(Script, Apps, LibDirs, Opts) ->
 				   end,
 				   #eval_state{apps = Apps, 
 					       libdirs = LibDirs,
+					       newlibs = NewLibs,
 					       opts = Opts},
 				   Before) of
 		EvalState2 when is_record(EvalState2, eval_state) ->
@@ -214,13 +216,12 @@ check_old_code(Mod) ->
 %%-----------------------------------------------------------------
 eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) ->
     case lists:keysearch(Lib, 1, EvalState#eval_state.libdirs) of
-	{value, {Lib, LibVsn, LibDir}} ->
-	    Ebin = filename:join(LibDir, "ebin"),
+	{value, {Lib, LibVsn, LibDir} = LibInfo} ->
 	    Ext = code:objfile_extension(),
 	    {NewBins, NewVsns} = 
 		lists:foldl(fun(Mod, {Bins, Vsns}) ->
 				    File = lists:concat([Mod, Ext]),
-				    FName = filename:join(Ebin, File),
+				    FName = filename:join([LibDir, "ebin", File]),
 				    case erl_prim_loader:get_file(FName) of
 					{ok, Bin, FName2} ->
 					    NVsns = add_new_vsn(Mod, Bin, Vsns),
@@ -232,7 +233,7 @@ eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) ->
 			    {EvalState#eval_state.bins,
 			     EvalState#eval_state.vsns},
 			    Modules),
-	    NewLibs = [{Lib, Ebin} | EvalState#eval_state.newlibs],
+	    NewLibs = lists:keystore(Lib,1,EvalState#eval_state.newlibs,LibInfo),
 	    EvalState#eval_state{bins = NewBins,
 				 newlibs = NewLibs,
 				 vsns = NewVsns};
@@ -242,15 +243,14 @@ eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) ->
 eval(point_of_no_return, EvalState) ->
     Libs = case get_opt(update_paths, EvalState, false) of
 	       false ->
-		   EvalState#eval_state.newlibs; % [{Lib, Path}]
+		   EvalState#eval_state.newlibs;
 	       true ->
-		   lists:map(fun({Lib, _LibVsn, LibDir}) ->
-				     Ebin= filename:join(LibDir,"ebin"),
-				     {Lib, Ebin}
-			     end,
-			     EvalState#eval_state.libdirs)
+		   EvalState#eval_state.libdirs
 	   end,
-    lists:foreach(fun({Lib, Path}) -> code:replace_path(Lib, Path) end,
+    lists:foreach(fun({Lib, _LibVsn, LibDir}) ->
+			  Ebin = filename:join(LibDir,"ebin"),
+			  code:replace_path(Lib, Ebin)
+		  end,
 		  Libs),
     EvalState;
 eval({load, {Mod, _PrePurgeMethod, PostPurgeMethod}}, EvalState) ->
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 16267ba0d4..d1939694ea 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -55,7 +55,7 @@ win32_cases() ->
 
 %% Cases that can be run on all platforms
 cases() ->
-    [otp_2740, otp_2760, otp_5761, instructions, eval_appup].
+    [otp_2740, otp_2760, otp_5761, otp_9402, instructions, eval_appup].
 
 groups() ->
     [{release,[],
@@ -393,7 +393,7 @@ instructions(Conf) when is_list(Conf) ->
           {stop, [aa]},
           {apply, {?MODULE, no_cc, []}},
           {start, [aa]}],
-    {ok, _} = release_handler_1:eval_script(S1, [], []),
+    {ok, _} = release_handler_1:eval_script(S1),
 
     case whereis(cc) of
         Pid2 when is_pid(Pid2) -> ok;
@@ -403,17 +403,17 @@ instructions(Conf) when is_list(Conf) ->
     %% Make bb run old version of b.
     S2 = [point_of_no_return,
           {remove, {b, soft_purge, soft_purge}}],
-    {ok, [{b, soft_purge}]} = release_handler_1:eval_script(S2, [], []),
+    {ok, [{b, soft_purge}]} = release_handler_1:eval_script(S2),
     check_bstate("first", [FirstBB]),
 
     false = code:is_loaded(b),
-    {error,{old_processes,b}} = release_handler_1:eval_script(S2,[],[]),
+    {error,{old_processes,b}} = release_handler_1:eval_script(S2),
     check_bstate("first", [FirstBB]),
 
     %% Let supervisor restart bb with new code
     S3 = [point_of_no_return,
           {purge, [b]}],
-    {ok, []} = release_handler_1:eval_script(S3, [], []),
+    {ok, []} = release_handler_1:eval_script(S3),
     ok = wait_for(bb),
     check_bstate("second", []),
     SecondBB = whereis(bb),
@@ -446,7 +446,7 @@ instructions(Conf) when is_list(Conf) ->
     %% Let supervisor restart bb yet another time
     S4 = [point_of_no_return,
           {remove, {b, brutal_purge, soft_purge}}],
-    {ok, HopefullyEmpty} = release_handler_1:eval_script(S4, [], []),
+    {ok, HopefullyEmpty} = release_handler_1:eval_script(S4),
     ok = wait_for(bb),
     FourthBB = whereis(bb),
 
@@ -566,8 +566,7 @@ otp_2760(Conf) ->
     %% Execute the relup script and check that app1 is unloaded
     {ok, [{"after", [{_Rel1Vsn, _Descr, Script}], _}]} =
 	file:consult(filename:join(Rel2Dir, "relup")),
-    {ok, []} = rpc:call(Node, release_handler_1, eval_script,
-			      [Script, [], []]),
+    {ok, []} = rpc:call(Node, release_handler_1, eval_script, [Script]),
     false = rpc:call(Node, code, is_loaded, [app1]),
 
     true = stop_node(Node),
@@ -658,6 +657,73 @@ otp_5761(Conf) when is_list(Conf) ->
     true = stop_node(Node),
     ok.
 
+
+%% When a new version of an application is added, but no module is
+%% changed - the path was not updated - i.e. code:priv_dir would point
+%% to the old location.
+otp_9402(Conf) when is_list(Conf) ->
+    %% Set some paths
+    PrivDir = priv_dir(Conf),
+    Dir = filename:join(PrivDir,"otp_9402"),
+    LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+    %% Create the releases
+    Rel1 = create_and_install_fake_first_release(Dir,
+						 [{a,"1.1",LibDir}]),
+    Rel2 = create_fake_upgrade_release(Dir,
+				       "2",
+				       [{a,"1.2",LibDir}],
+				       {Rel1,Rel1,[LibDir]}),
+    Rel1Dir = filename:dirname(Rel1),
+    Rel2Dir = filename:dirname(Rel2),
+
+    %% Start a slave node
+    {ok, Node} = t_start_node(otp_9402, Rel1, filename:join(Rel1Dir,"sys.config")),
+
+    %% Check path
+    Dir1 = filename:join([LibDir, "a-1.1"]),
+    Dir1 = rpc:call(Node, code, lib_dir, [a]),
+    ABeam = code:which(a),
+
+    %% Install second release, with no changed modules
+    {ok, RelVsn2} =
+	rpc:call(Node, release_handler, set_unpacked,
+		 [Rel2++".rel", [{a,"1.2",LibDir}]]),
+    ok = rpc:call(Node, release_handler, install_file,
+		  [RelVsn2, filename:join(Rel2Dir, "relup")]),
+    ok = rpc:call(Node, release_handler, install_file,
+		  [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+    ok = rpc:call(Node, release_handler, install_file,
+		  [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+    %% Install RelVsn2
+    {ok, RelVsn1, []} =
+	rpc:call(Node, release_handler, install_release, [RelVsn2]),
+
+    %% Check path
+    Dir2 = filename:join([LibDir, "a-1.2"]),
+    Dir2 = rpc:call(Node, code, lib_dir, [a]),
+    APrivDir2 = rpc:call(Node, code, priv_dir, [a]),
+    true = filelib:is_regular(filename:join(APrivDir2,"file")),
+
+    %% Just to make sure no modules have been re-loaded
+    ABeam = code:which(a),
+
+    %% Install RelVsn1 again
+    {ok, _OtherVsn, []} =
+	rpc:call(Node, release_handler, install_release, [RelVsn1]),
+
+    %% Check path
+    Dir1 = rpc:call(Node, code, lib_dir, [a]),
+    APrivDir1 = rpc:call(Node, code, priv_dir, [a]),
+    false = filelib:is_regular(filename:join(APrivDir1,"file")),
+
+    %% Just to make sure no modules have been re-loaded
+    ABeam = code:which(a),
+
+    ok.
+
+
 %% Test upgrade and downgrade of applications
 eval_appup(Conf) when is_list(Conf) ->
 
diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
index 85e25fdc2f..abaa08f810 100644
--- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src
+++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
@@ -5,6 +5,8 @@ P2B= \
      P2B/a-2.0/ebin/a_sup.beam
 
 LIB= \
+     lib/a-1.2/ebin/a.beam \
+     lib/a-1.2/ebin/a_sup.beam \
      lib/a-1.1/ebin/a.beam \
      lib/a-1.1/ebin/a_sup.beam \
      lib/a-1.0/ebin/a.beam \
@@ -57,6 +59,12 @@ lib/a-1.1/ebin/a_sup.@EMULATOR@: lib/a-1.1/src/a_sup.erl
 	erlc $(EFLAGS) -olib/a-1.1/ebin lib/a-1.1/src/a_sup.erl
 
 
+lib/a-1.2/ebin/a.@EMULATOR@: lib/a-1.2/src/a.erl
+	erlc $(EFLAGS) -olib/a-1.2/ebin lib/a-1.2/src/a.erl
+lib/a-1.2/ebin/a_sup.@EMULATOR@: lib/a-1.2/src/a_sup.erl
+	erlc $(EFLAGS) -olib/a-1.2/ebin lib/a-1.2/src/a_sup.erl
+
+
 app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1_sup.erl
 	erlc $(EFLAGS) -oapp1_app2/lib1/app1-1.0/ebin app1_app2/lib1/app1-1.0/src/app1_sup.erl
 app1_app2/lib1/app1-1.0/ebin/app1_server.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1_server.erl
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/README b/lib/sasl/test/release_handler_SUITE_data/lib/README
new file mode 100644
index 0000000000..e539580ac0
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/README
@@ -0,0 +1,9 @@
+a-1.0:
+start version
+
+a-1.1:
+can be upgraded to from a-1.0. Module a has changed
+
+a-1.2:
+can be upgraded to from a-1.1.
+No module have changed, but priv dir is added including one 'file'
\ No newline at end of file
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app
deleted file mode 100644
index e938137f67..0000000000
--- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app
+++ /dev/null
@@ -1,8 +0,0 @@
-{application, a,
-	     [{description, "A  CXC 138 11"},
-              {vsn, "1.0"},
-	      {modules, [{a, 1}, {a_sup,1}]},
-	      {registered, [a_sup]},
-	      {applications, [kernel, stdlib]},
-	      {env, [{key1, val1}]},
-	      {mod, {a_sup, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app
new file mode 100644
index 0000000000..b38722f06d
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.app
@@ -0,0 +1,8 @@
+{application, a,
+	     [{description, "A  CXC 138 11"},
+              {vsn, "1.2"},
+	      {modules, [{a, 2}, {a_sup,1}]},
+	      {registered, [a_sup]},
+	      {applications, [kernel, stdlib]},
+	      {env, [{key1, val1}]},
+	      {mod, {a_sup, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.appup
new file mode 100644
index 0000000000..3df0546316
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/ebin/a.appup
@@ -0,0 +1,3 @@
+{"1.2",
+ [{"1.1",[]}],
+ [{"1.1",[]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/priv/file b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/priv/file
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a.erl
new file mode 100644
index 0000000000..c082ad5339
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a.erl
@@ -0,0 +1,54 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%%     $Id$
+%%
+-module(a).
+
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/0, a/0, b/0]).
+%% Internal exports
+-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]).
+
+start_link() -> gen_server:start_link({local, aa}, a, [], []).
+
+a() -> gen_server:call(aa, a).
+b() -> gen_server:call(aa, b).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([]) ->
+    process_flag(trap_exit, true),
+    {ok, {state, bval}}.
+
+handle_call(a, _From, State) ->
+    X = application:get_all_env(a),
+    {reply, X, State};
+
+handle_call(b, _From, State) ->
+    {reply, {ok, element(2, State)}, State}.
+
+handle_info(_, State) ->
+    {noreply, State}.
+
+terminate(_Reason, _State) ->
+    ok.
+
+code_change(1, Extra, State) ->
+    {ok, {state, bval}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a_sup.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a_sup.erl
new file mode 100644
index 0000000000..a141c1767b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.2/src/a_sup.erl
@@ -0,0 +1,37 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%%     $Id$
+%%
+-module(a_sup).
+
+
+-behaviour(supervisor).
+
+%% External exports
+-export([start/2]).
+
+%% Internal exports
+-export([init/1]).
+
+start(_, _) ->
+    supervisor:start_link({local, a_sup}, a_sup, []).
+
+init([]) ->
+    SupFlags = {one_for_one, 4, 3600},
+    Config = {a,
+	      {a, start_link, []},
+	      permanent, 2000, worker, [a]},
+    {ok, {SupFlags, [Config]}}.
-- 
cgit v1.2.3