diff options
Diffstat (limited to 'lib/sasl/src/release_handler.erl')
-rw-r--r-- | lib/sasl/src/release_handler.erl | 163 |
1 files changed, 121 insertions, 42 deletions
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index 48feac1a21..7635b1ef78 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ %% External exports -export([start_link/0, - create_RELEASES/1, create_RELEASES/2, create_RELEASES/4, + create_RELEASES/1, create_RELEASES/2, create_RELEASES/3, create_RELEASES/4, unpack_release/1, check_install_release/1, check_install_release/2, install_release/1, install_release/2, new_emulator_upgrade/2, @@ -43,7 +43,13 @@ -export([do_write_release/3, do_copy_file/2, do_copy_files/2, do_copy_files/1, do_rename_files/1, do_remove_files/1, remove_file/1, do_write_file/2, do_write_file/3, - do_ensure_RELEASES/1]). + do_ensure_RELEASES/1, + consult/2, + root_dir_relative_read_file_info/1, + root_dir_relative_read_file/1, + root_dir_relative_rename_file/2, + root_dir_relative_make_dir/1, + root_dir_relative_ensure_dir/1]). -record(state, {unpurged = [], root, @@ -134,9 +140,9 @@ %% %% It is configurable where the start file is located, and what it %% is called. -%% The paramater is {sasl, start_prg} = File +%% The parameter is {sasl, start_prg} = File %% It is also configurable where the releases directory is located. -%% Default is $ROOT/releases. $RELDIR overrids, and +%% Default is $ROOT/releases. $RELDIR overrides, and %% {sasl, releases_dir} overrides both. %%----------------------------------------------------------------- start_link() -> @@ -162,7 +168,7 @@ unpack_release(ReleaseName) -> %% Purpose: Checks the relup script for the specified version. %% The release must be unpacked. %% Options = [purge] - all old code that can be soft purged -%% will be purged if all checks succeeds. This can be usefull +%% will be purged if all checks succeeds. This can be useful %% in order to reduce time needed in the following call to %% install_release. %% Returns: {ok, FromVsn, Descr} | {error, Reason} @@ -298,7 +304,7 @@ remove_release(Vsn) -> %% .rel. %% The release dir will be created. The necessary files can %% be installed by calling install_file/2. -%% The release_handler remebers where all libs are located. +%% The release_handler remembers where all libs are located. %% If remove_release is called later, %% those libs are removed as well (if no other releases uses %% them). @@ -378,6 +384,8 @@ create_RELEASES([Root, RelFile | LibDirs]) -> create_RELEASES(Root, RelFile) -> create_RELEASES(Root, filename:join(Root, "releases"), RelFile, []). +create_RELEASES(RelDir, RelFile, LibDirs) -> + create_RELEASES("", RelDir, RelFile, LibDirs). create_RELEASES(Root, RelDir, RelFile, LibDirs) -> case catch check_rel(Root, RelFile, LibDirs, false) of {error, Reason } -> @@ -397,7 +405,8 @@ create_RELEASES(Root, RelDir, RelFile, LibDirs) -> %% located under Dir/ebin %% Purpose: Upgrade to the version in Dir according to an appup file %%----------------------------------------------------------------- -upgrade_app(App, NewDir) -> +upgrade_app(App, NewDir1) -> + NewDir = root_dir_relative_path(NewDir1), try upgrade_script(App, NewDir) of {ok, NewVsn, Script} -> eval_appup_script(App, NewVsn, NewDir, Script) @@ -435,7 +444,8 @@ downgrade_app(App, OldVsn, OldDir) -> {error, Reason} end. -upgrade_script(App, NewDir) -> +upgrade_script(App, NewDir1) -> + NewDir = root_dir_relative_path(NewDir1), OldVsn = ensure_running(App), OldDir = code:lib_dir(App), {NewVsn, Script} = find_script(App, NewDir, OldVsn, up), @@ -489,7 +499,8 @@ ensure_running(App) -> end. find_script(App, Dir, OldVsn, UpOrDown) -> - Appup = filename:join([Dir, "ebin", atom_to_list(App)++".appup"]), + Appup1 = filename:join([Dir, "ebin", atom_to_list(App)++".appup"]), + Appup = root_dir_relative_path(Appup1), case file:consult(Appup) of {ok, [{NewVsn, UpFromScripts, DownToScripts}]} -> Scripts = case UpOrDown of @@ -522,7 +533,7 @@ read_app(App, Vsn, Dir) -> read_appspec(App, Dir) -> AppS = atom_to_list(App), - Path = [filename:join(Dir, "ebin")], + Path = [root_dir_relative_path(filename:join(Dir, "ebin"))], case file:path_consult(Path, AppS++".app") of {ok, AppSpecL, _File} -> AppSpecL; @@ -833,7 +844,9 @@ do_unpack_release(Root, RelDir, ReleaseName, Releases) -> Rel = ReleaseName ++ ".rel", _ = extract_rel_file(filename:join("releases", Rel), Tar, Root), RelFile = filename:join(RelDir, Rel), - Release = check_rel(Root, RelFile, false), + %% Send an empty string as Root as the library locations should + %% appear as paths relative to the root + Release = check_rel("", RelFile, false), #release{vsn = Vsn} = Release, case lists:keysearch(Vsn, #release.vsn, Releases) of {value, _} -> throw({error, {existing_release, Vsn}}); @@ -850,8 +863,8 @@ do_unpack_release(Root, RelDir, ReleaseName, Releases) -> copy_file(RelFile, Dir, false), %% Clean release - _ = file:delete(Tar), - _ = file:delete(RelFile), + _ = root_dir_relative_file_delete(Tar), + _ = root_dir_relative_file_delete(RelFile), {ok, NewReleases, Vsn}. @@ -883,7 +896,19 @@ check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs, check_path(Path, Masters), Path; _ -> - filename:join([Root, "lib", LibName]) + %% If Root is an empty string, + %% we assume that the path is + %% relative to code:root_dir() + %% and save a relative + %% path. This is done to make it + %% easy to create a relocatable + %% RELEASES file. + case string:length(Root) of + 0 -> + filename:join("lib", LibName); + _ -> + filename:join([Root, "lib", LibName]) + end end, {Lib, LibVsn, LibDir} end, @@ -894,7 +919,7 @@ check_rel_data(RelData, _Root, _LibDirs, _Masters) -> throw({error, {bad_rel_data, RelData}}). check_path(Path) -> - check_path_response(Path, file:read_file_info(Path)). + check_path_response(Path, root_dir_relative_read_file_info(Path)). check_path(Path, false) -> check_path(Path); check_path(Path, Masters) -> check_path_master(Masters, Path). @@ -904,7 +929,7 @@ check_path(Path, Masters) -> check_path_master(Masters, Path). %% at one node it should not exist at any other node either. %%----------------------------------------------------------------- check_path_master([Master|Ms], Path) -> - case rpc:call(Master, file, read_file_info, [Path]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file_info, [Path]) of {badrpc, _} -> consult_master(Ms, Path); Res -> check_path_response(Path, Res) end; @@ -1168,7 +1193,7 @@ new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,EVsn,NewVsn, new_emulator_rm_tmp_release(_,_,_,_,Releases,_) -> Releases. -%% Rename the tempoarary service (for erts ugprade) to the real ToVsn +%% Rename the temporary service (for erts ugprade) to the real ToVsn rename_tmp_service(EVsn,TmpVsn,NewVsn) -> FromName = hd(string:lexemes(atom_to_list(node()),"@")) ++ "_" ++ TmpVsn, ToName = hd(string:lexemes(atom_to_list(node()),"@")) ++ "_" ++ NewVsn, @@ -1573,14 +1598,14 @@ memlib(_Lib, []) -> false. %% recursively remove file or directory remove_file(File) -> - case file:read_link_info(File) of + case root_dir_relative_read_link_info(File) of {ok, Info} when Info#file_info.type==directory -> - case file:list_dir(File) of + case root_dir_relative_list_dir(File) of {ok, Files} -> lists:foreach(fun(File2) -> remove_file(filename:join(File,File2)) end, Files), - case file:del_dir(File) of + case root_dir_relative_dir_delete(File) of ok -> ok; {error, Reason} -> throw({error, Reason}) end; @@ -1588,7 +1613,7 @@ remove_file(File) -> throw({error, Reason}) end; {ok, _Info} -> - case file:delete(File) of + case root_dir_relative_file_delete(File) of ok -> ok; {error, Reason} -> throw({error, Reason}) end; @@ -1599,7 +1624,8 @@ remove_file(File) -> do_write_file(File, Str) -> do_write_file(File, Str, []). -do_write_file(File, Str, FileOpts) -> +do_write_file(File1, Str, FileOpts) -> + File = root_dir_relative_path(File1), case file:open(File, [write | FileOpts]) of {ok, Fd} -> io:put_chars(Fd, Str), @@ -1822,13 +1848,13 @@ check_file_masters(_FileName, _Type, []) -> %% Type == regular | directory do_check_file(FileName, Type) -> - case file:read_file_info(FileName) of + case root_dir_relative_read_file_info(FileName) of {ok, Info} when Info#file_info.type==Type -> ok; {error, _Reason} -> throw({error, {no_such_file, FileName}}) end. do_check_file(Master, FileName, Type) -> - case rpc:call(Master, file, read_file_info, [FileName]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file_info, [FileName]) of {ok, Info} when Info#file_info.type==Type -> ok; _ -> throw({error, {no_such_file, {Master, FileName}}}) end. @@ -1871,7 +1897,8 @@ write_releases_1(Dir, NewReleases, Masters) -> write_releases_m(Dir, NewReleases, Masters). do_write_release(Dir, RELEASES, NewReleases) -> - case file:open(filename:join(Dir, RELEASES), [write,{encoding,utf8}]) of + ReleasesFile = root_dir_relative_path(filename:join(Dir, RELEASES)), + case file:open(ReleasesFile, [write,{encoding,utf8}]) of {ok, Fd} -> ok = io:format(Fd, "%% ~s~n~tp.~n", [epp:encoding_to_string(utf8),NewReleases]), @@ -1908,7 +1935,8 @@ write_releases_m(Dir, NewReleases, Masters) -> remove_files(all, [Backup, Change], Masters), ok; {error, {Master, R}} -> - takewhile(Master, Masters, file, rename, + takewhile(Master, Masters, ?MODULE, + root_dir_relative_rename_file, [Backup, RelFile]), remove_files(all, [Backup, Change], Masters), throw({error, {Master, R, move_releases}}) @@ -1959,9 +1987,9 @@ do_copy_file(File, Dir) -> do_copy_file1(File, File2). do_copy_file1(File, File2) -> - case file:read_file(File) of + case root_dir_relative_read_file(File) of {ok, Bin} -> - case file:write_file(File2, Bin) of + case root_dir_relative_write_file(File2, Bin) of ok -> ok; {error, Reason} -> {error, {Reason, File2}} @@ -1995,7 +2023,9 @@ do_copy_files([]) -> %%----------------------------------------------------------------- %% Rename each Src file to Dest file in the list of files. %%----------------------------------------------------------------- -do_rename_files([{Src, Dest}|Files]) -> +do_rename_files([{Src1, Dest1}|Files]) -> + Src = root_dir_relative_path(Src1), + Dest = root_dir_relative_path(Dest1), case file:rename(Src, Dest) of ok -> do_rename_files(Files); Error -> Error @@ -2007,7 +2037,7 @@ do_rename_files([]) -> %% Remove a list of files. Ignore failure. %%----------------------------------------------------------------- do_remove_files([File|Files]) -> - _ = file:delete(File), + _ = root_dir_relative_file_delete(File), do_remove_files(Files); do_remove_files([]) -> ok. @@ -2018,7 +2048,7 @@ do_remove_files([]) -> %% If not create an empty RELEASES file. %%----------------------------------------------------------------- do_ensure_RELEASES(RelFile) -> - case file:read_file_info(RelFile) of + case root_dir_relative_read_file_info(RelFile) of {ok, _} -> ok; _ -> do_write_file(RelFile, "[]. ") end. @@ -2026,11 +2056,16 @@ do_ensure_RELEASES(RelFile) -> %%----------------------------------------------------------------- %% Make a directory, ignore failures (captured later). %%----------------------------------------------------------------- -make_dir(Dir, false) -> +make_dir(Dir1, false) -> + Dir = root_dir_relative_path(Dir1), _ = file:make_dir(Dir), ok; make_dir(Dir, Masters) -> - lists:foreach(fun(Master) -> rpc:call(Master, file, make_dir, [Dir]) end, + lists:foreach(fun(Master) -> rpc:call(Master, + ?MODULE, + root_dir_relative_make_dir, + [Dir]) + end, Masters). %%----------------------------------------------------------------- @@ -2068,7 +2103,7 @@ takewhile(Master, Masters, M, F, A) -> end, Masters), ok. -consult(File, false) -> file:consult(File); +consult(File, false) -> file:consult(root_dir_relative_path(File)); consult(File, Masters) -> consult_master(Masters, File). %%----------------------------------------------------------------- @@ -2077,7 +2112,7 @@ consult(File, Masters) -> consult_master(Masters, File). %% not exist at any other node either. %%----------------------------------------------------------------- consult_master([Master|Ms], File) -> - case rpc:call(Master, file, consult, [File]) of + case rpc:call(Master, ?MODULE, consult, [File, false]) of {badrpc, _} -> consult_master(Ms, File); Res -> Res end; @@ -2085,12 +2120,12 @@ consult_master([], _File) -> {error, no_master}. read_file(File, false) -> - file:read_file(File); + root_dir_relative_read_file(File); read_file(File, Masters) -> read_master(Masters, File). write_file(File, Data, false) -> - case file:write_file(File, Data) of + case root_dir_relative_write_file(File, Data) of ok -> ok; Error -> throw(Error) end; @@ -2101,12 +2136,12 @@ write_file(File, Data, Masters) -> end. ensure_dir(File, false) -> - case filelib:ensure_dir(File) of + case root_dir_relative_ensure_dir(File) of ok -> ok; Error -> throw(Error) end; ensure_dir(File, Masters) -> - case at_all_masters(Masters,filelib,ensure_dir,[File]) of + case at_all_masters(Masters,?MODULE,root_dir_relative_ensure_dir,[File]) of ok -> ok; Error -> throw(Error) end. @@ -2130,7 +2165,7 @@ remove_files(Master, Files, Masters) -> %% not exist at any other node either. %%----------------------------------------------------------------- read_master([Master|Ms], File) -> - case rpc:call(Master, file, read_file, [File]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file, [File]) of {badrpc, _} -> read_master(Ms, File); Res -> Res end; @@ -2275,7 +2310,7 @@ safe_write_file_m(File, Data, FileOpts, Masters) -> %% %% 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 +%% handled here - instead it must be explicitly indicated by the %% 'update_paths' option to release_handler:install_release/2 if the %% code path shall be updated then. %% ----------------------------------------------------------------- @@ -2299,3 +2334,47 @@ get_releases_with_status([ {_, _, _, ReleaseStatus } = Head | Tail], get_releases_with_status(Tail, Status, [Head | Acc]); get_releases_with_status([_ | Tail], Status, Acc) -> get_releases_with_status(Tail, Status, Acc). + +root_dir_relative_read_link_info(File) -> + file:read_link_info(root_dir_relative_path(File)). + +root_dir_relative_list_dir(File) -> + file:list_dir(root_dir_relative_path(File)). + +root_dir_relative_file_delete(File) -> + file:delete(root_dir_relative_path(File)). + +root_dir_relative_dir_delete(File) -> + file:del_dir(root_dir_relative_path(File)). + +root_dir_relative_path(Pathname) -> + case filename:pathtype(Pathname) of + relative -> + filename:join(code:root_dir(), Pathname); + _ -> + Pathname + end. + +root_dir_relative_write_file(File, Bin) -> + file:write_file(root_dir_relative_path(File), Bin). + +%% The root_dir_relative* functions below are exported so that they +%% can be called on other nodes with rpc + +root_dir_relative_read_file_info(Path) -> + file:read_file_info(root_dir_relative_path(Path)). + +root_dir_relative_read_file(File) -> + file:read_file(root_dir_relative_path(File)). + +root_dir_relative_rename_file(Source1, Destination1) -> + Source = root_dir_relative_path(Source1), + Destination = root_dir_relative_path(Destination1), + file:rename(Source, Destination). + +root_dir_relative_make_dir(Dir) -> + file:make_dir(root_dir_relative_path(Dir)). + +root_dir_relative_ensure_dir(Dir) -> + filelib:ensure_dir(root_dir_relative_path(Dir)). + |