Skip to content

Instantly share code, notes, and snippets.

@sumerman
Created September 22, 2011 18:54
Show Gist options
  • Save sumerman/1235669 to your computer and use it in GitHub Desktop.
Save sumerman/1235669 to your computer and use it in GitHub Desktop.
This escript determines which Erlang process is listening upon given network port
#!/usr/bin/env escript
%%! -name port_inspector
-module(port_inspector).
-export([inspect/0, main/1]).
%%
%% Info Collection Routines
%%
inspect() ->
PDesc = lists:map(fun(P) -> erlang:port_info(P) ++ [sock_info(P)] end, erlang:ports()),
OnlyNet = lists:filter(fun(D) -> proplists:get_value(socket, D) /= undefined end, PDesc),
lists:map(
fun(D) ->
LI = lists:map(fun proc_info/1, proplists:get_value(links, D, [])),
[proplists:lookup(socket, D), {links_info, LI}]
end, OnlyNet).
sock_info(Port) ->
{socket, sock_info_(Port)}.
sock_info_(Port) ->
case (catch inet:sockname(Port)) of
{ok, SockInf} ->
SockInf;
_ ->
undefined
end.
proc_info(Pid) ->
[{pid, Pid}] ++ erlang:process_info(Pid, [initial_call, current_function, dictionary]).
%%
%% RPC Stuff
%%
remote(NodeName, Fun, Args) ->
Node = build_node(NodeName),
ok = ping_node(Node),
{module, _} = push_script(Node),
rpc:call(Node, ?MODULE, Fun, Args).
push_script(Node) ->
SelfFile = escript:script_name(),
{ok, Sec} = escript:extract(SelfFile, [compile_source]),
Bin = proplists:get_value(source, Sec),
rpc:call(Node, code, load_binary, [?MODULE, SelfFile, Bin]).
build_node(NodeName) ->
case is_full_nodename(NodeName) of
false -> node_by_name(NodeName);
_ -> NodeName
end.
is_full_nodename(NodeName) ->
lists:any(fun(C)-> C==$@ end, atom_to_list(NodeName)).
node_by_name(NodeName) ->
{ok, Host} = inet:gethostname(),
NodeString = atom_to_list(NodeName) ++ "@" ++ Host,
list_to_atom(NodeString).
ping_node(Node) ->
case net_adm:ping(Node) of
pong -> ok;
_ ->
io:format("There is no node with this name~n"),
error
end.
%%
%% Main
%%
parse_options(OptStrings) ->
{Keys, Vals} = lists:partition(fun([$-|_]) -> true; (_) -> false end, OptStrings),
KeyAtoms = lists:map(fun([$-|N]) -> list_to_atom(N) end, Keys),
lists:zip(KeyAtoms, Vals).
validate_options(Opts) ->
V = [proplists:get_value(node, Opts)],
case lists:any(fun(undefined) -> true; (_) -> false end, V) of
true -> usage();
_ -> {ok, Opts}
end.
process_result(Res, Opts) ->
case proplists:lookup(port, Opts) of
{port, PStr} ->
Port = list_to_integer(PStr),
lists:filter(fun(D) ->
{_, P} = proplists:get_value(socket, D, {{0,0,0,0},0}),
P == Port
end, Res);
_ ->
Res
end.
set_cookie(Opts) ->
case proplists:lookup(cookie, Opts) of
{cookie, Cookie} ->
erlang:set_cookie(node(), list_to_atom(Cookie));
_ ->
false
end.
main(OptStrings) ->
{ok, Opts} = validate_options(parse_options(OptStrings)),
{node, Node} = proplists:lookup(node, Opts),
set_cookie(Opts),
io:format("Running on: ~p...\t~n",[Node]),
Res = process_result(remote(list_to_atom(Node), inspect, []), Opts),
io:format("Result: ~p ~n done.~n", [Res]).
usage() ->
io:format(
"Usage: ~s -node <[email protected]> [-port <only_this_port>] [-cookie <erlang_cookie>] ~n",
[escript:script_name()]),
halt(0).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment