Skip to content

Instantly share code, notes, and snippets.

@archaelus
Created August 20, 2013 22:26
Show Gist options
  • Save archaelus/6288153 to your computer and use it in GitHub Desktop.
Save archaelus/6288153 to your computer and use it in GitHub Desktop.
Eshell V5.5.5 (abort with ^G)
(ssae@127.0.0.1)1> ssae:rebuild_module("../racer.zip", "ebin/ssae.beam", "ebin/evil/ssae.beam").
ok
(ssae@127.0.0.1)2> code:load_abs("ebin/evil/ssae").
{module,ssae}
(ssae@127.0.0.1)3> nl(ssae).
abcast
(ssae@127.0.0.1)4> beam_lib:chunks("ebin/evil/ssae.beam", ["SSAE"]).
{ok,{ssae,[{"SSAE",
<<80,75,3,4,10,0,0,0,0,0,66,181,59,55,0,0,0,0,0,0,0,0,...>>}]}}
(ssae@127.0.0.1)5> nl(ssae).
abcast
(ssae@127.0.0.1)6> code:which(ssae).
"/path_to/ssae/ebin/ssae.beam"
(ssae@127.0.0.1)7> ssae:rebuild_module("../racer.zip", "ebin/ssae.beam", "ebin/evil/ssae.beam").
ok
(ssae@127.0.0.1)8> code:load_abs("ebin/evil/ssae").
{error,not_purged}
=ERROR REPORT==== 28-Sep-2007::00:11:55 ===
Loading of /path_to/ssae/ebin/evil/ssae.beam failed: not_purged
=ERROR REPORT==== 28-Sep-2007::00:11:55 ===
Module ssae must be purged before loading
(ssae@127.0.0.1)9> code:purge(ssae).
false
(ssae@127.0.0.1)10> code:load_abs("ebin/evil/ssae").
{module,ssae}
(ssae@127.0.0.1)11> code:which(ssae).
"/path_to/ssae/ebin/evil/ssae.beam"
(ssae@127.0.0.1)12> ssae:zip_file_names().
["racer/",
"racer/.git/",
"racer/.git/COMMIT_EDITMSG~",
"racer/.git/HEAD",
"racer/.git/config",
"racer/.git/description",
"racer/.git/hooks/",
"racer/.git/hooks/applypatch-msg",
"racer/.git/hooks/commit-msg",
"racer/.git/hooks/post-commit",
"racer/.git/hooks/post-receive",
"racer/.git/hooks/post-update",
"racer/.git/hooks/pre-applypatch",
"racer/.git/hooks/pre-commit",
"racer/.git/hooks/pre-rebase",
"racer/.git/hooks/update",
"racer/.git/index",
"racer/.git/info/",
"racer/.git/info/exclude",
"racer/.git/logs/",
"racer/.git/logs/HEAD",
"racer/.git/logs/refs/",
"racer/.git/logs/refs/heads/",
"racer/.git/logs/refs/heads/master",
"racer/.git/objects/",
"racer/.git/objects/1a/",
"racer/.git/objects/1a/c1ff5971dbf3eb947c5090f35ff399c81910d3",
"racer/.git/objects/20/",
[...]|...]
(ssae@127.0.0.1)13> ssae:use().
error_handler
(ssae@127.0.0.1)14> re:module_info().
[{exports,[{parse,1},
{match,2},
{first_match,2},
{smatch,2},
{first_smatch,2},
{matches,2},
{sub,3},
{gsub,3},
{split,2},
{tt,2},
{loadf,1},
{module_info,0},
{module_info,1}]},
{imports,[]},
{attributes,[{vsn,[77891265686719082290801561385576450333]}]},
{compile,[{options,[{cwd,"/path_to/racer"},
{outdir,"/path_to/racer/ebin"},
{i,"/Library/DarwinPorts/lib/erlang/lib/stdlib-1.14.5/include"},
{i,"/path_to/racer/../eunit/include"},
{i,"/path_to/racer/include"},
debug_info]},
{version,"4.4.5"},
{time,{2007,9,25,1,40,13}},
{source,"/path_to/racer/src/re.erl"}]}]
(ssae@127.0.0.1)15> code:which(re).
"ssae://racer/ebin/re.beam"
(ssae@127.0.0.1)16>
%% @copyright Geoff Cant
%% @author Geoff Cant <nem@erlang.geek.nz>
%% @version {@vsn}, {@date} {@time}
%% @doc Silly standalone erlang.
%%
%% Created because people keep whining that standalone erlang is long dead.
%%
%% Use: 1) Create a zip file full of erlang code you want to use (precompiled). (e.g. zip -r code.zip /path/to/code)
%% 2) code:ensure_loaded(ssae).
%% 3) ssae:rebuild_module("code.zip", code:which(ssae), "evil/ssae.ebin").
%% 4) code:load_abs("evil/ssae").
%% 5) ssae:use().
%% 6) You can now call module you put in code.zip.
%% 7) You encounter a bug, ssae eats all your ram, your machine dies in swapdeath.
%%
%% @end
-module(ssae).
-export([undefined_function/3, undefined_lambda/3]).
-compile(export_all).
use() ->
process_flag(error_handler, ?MODULE).
undefined_function(Module, Func, Args) ->
%% Try the code server first. SSAE is a really expensive loader
%% and relies on stuff that SSAE itself can't load.(it used up all
%% my ram and died a painful swapdeath.)
case code:ensure_loaded(Module) of
{module, Module} ->
error_handler:undefined_function(Module, Func, Args);
_Error ->
case ensure_loaded(Module) of
{module, Module} -> apply(Module, Func, Args);
_Else -> crash(Module, Func, Args)
end
end.
undefined_lambda(Module, Fun, Args) ->
%% Try the code server first. SSAE is a really expensive loader
%% and relies on stuff that SSAE itself can't load.(it used up all
%% my ram and died a painful swapdeath.)
case code:ensure_loaded(Module) of
{module, Module} ->
%% There is no need (and no way) to test if the fun is present.
%% apply/2 will not call us again if the fun is missing.
error_handler:undefined_lambda(Module, Fun, Args);
_Error ->
case ensure_loaded(Module) of
{module, Module} -> apply(Fun, Args);
_Else -> crash(Module, Fun, Args)
end
end.
ensure_loaded(Mod) ->
try {Name, Path, Bin} = find_module(Mod),
code:load_binary(Name, "ssae://" ++ Path, Bin)
catch
throw:Error ->
{error, Error}
end.
find_module(Name) when is_atom(Name) ->
Zip = zip(),
case lists:keysearch(Name, 1, beam_files(zip_file_names(Zip))) of
{value, {Name, Path}} ->
find_module(Name, Path, file(Path, Zip), Zip);
false -> throw({ssae_nosuch_file, Name})
end.
find_module(Name, Path, Bin, Zip) when is_binary(Zip) ->
Info = beam_lib:info(Bin),
case lists:keysearch(module, 1, Info) of
{value, {module, Name}} ->
{Name, Path, Bin};
{value, {module, Else}} ->
throw({ssae_wrong_module, "ssae://" ++ Path, Else});
Else -> throw({ssae_module_info, Else})
end.
file(Path) -> file(Path, zip()).
file(Path, Zip) ->
case zip:extract(Zip, [memory, {file_list, [Path]}]) of
{ok, [{Path, Bin}]} -> Bin;
Else -> throw({ssae_zip_err, Else})
end.
zip_file_names() -> zip_file_names(zip()).
zip_file_names(Bin) ->
{ok, Contents} = zip:list_dir(Bin),
[Name || {zip_file, Name, _info, _, _sz_uncomp, _sz} <- Contents].
beam_files() -> beam_files(zip_file_names()).
beam_files(NameList) ->
Xtn = code:objfile_extension(),
Files = lists:filter(fun (N) ->
0 =/= string:str(N,Xtn) end,
NameList),
[{list_to_atom(filename:basename(N, Xtn)), N} || N <- Files].
zip() ->
File = code:which(?MODULE),
{ok, {_, [{"SSAE", Bin}]}} = beam_lib:chunks(File, ["SSAE"]),
Bin.
crash(Fun, Args) ->
crash({Fun,Args}).
crash(M, F, A) ->
crash({M,F,A}).
crash(MFA) ->
try erlang:error(undef)
catch
error:undef ->
erlang:raise(error, undef, [MFA|tl(erlang:get_stacktrace())])
end.
rebuild_module(Zip, Beam, OutputFile) ->
{ok, Bin} = add_zip_to_beam(Zip, Beam),
file:write_file(OutputFile, Bin).
add_zip_to_beam(Zip, Beam) when is_list(Zip) ->
{ok, Bin} = file:read_file(Zip),
add_zip_to_beam(Bin, Beam);
add_zip_to_beam(Zip, Beam) when is_binary(Zip), is_list(Beam) ->
{ok, _, Chunks} = beam_lib:all_chunks(Beam),
add_zip_to_beam_chunks(Zip, Chunks).
add_zip_to_beam_chunks(Zip, Chunks) ->
beam_lib:build_module([{"SSAE", Zip} | Chunks]).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment