%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2008-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 %% 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% %% %% %%---------------------------------------------------------------------- %% Purpose: Print some info of a running ssh aplication. %%---------------------------------------------------------------------- -module(ssh_info). -compile(export_all). print() -> try supervisor:which_children(ssh_sup) of _ -> io:nl(), print_general(), io:nl(), underline("Client part", $=), print_clients(), io:nl(), underline("Server part", $=), print_servers(), io:nl(), %% case os:type() of %% {unix,_} -> %% io:nl(), %% underline("Linux part", $=), %% underline("Listening"), %% catch io:format(os:cmd("netstat -tpln")), %% io:nl(), %% underline("Other"), %% catch io:format(os:cmd("netstat -tpn")); %% _ -> ok %% end, underline("Supervisors", $=), walk_sups(ssh_sup), io:nl() catch _:_ -> io:format("Ssh not found~n",[]) end. %%%================================================================ print_general() -> {_Name, Slogan, Ver} = lists:keyfind(ssh,1,application:which_applications()), underline(io_lib:format("~s ~s", [Slogan, Ver]), $=), io:format('This printout is generated ~s. ~n',[datetime()]). %%%================================================================ print_clients() -> try lists:foreach(fun print_client/1, supervisor:which_children(sshc_sup)) catch C:E -> io:format('***FAILED: ~p:~p~n',[C,E]) end. print_client({undefined,Pid,supervisor,[ssh_connection_handler]}) -> {{Local,Remote},_Str} = ssh_connection_handler:get_print_info(Pid), io:format(" Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]); print_client(Other) -> io:format(" [[Other 1: ~p]]~n",[Other]). %%%================================================================ print_servers() -> try lists:foreach(fun print_server/1, supervisor:which_children(sshd_sup)) catch C:E -> io:format('***FAILED: ~p:~p~n',[C,E]) end. print_server({{server,ssh_system_sup,LocalHost,LocalPort},Pid,supervisor,[ssh_system_sup]}) when is_pid(Pid) -> io:format('Local=~s (~p children)~n',[fmt_host_port({LocalHost,LocalPort}), ssh_acceptor:number_of_connections(Pid)]), lists:foreach(fun print_system_sup/1, supervisor:which_children(Pid)); print_server(Other) -> io:format(" [[Other 2: ~p]]~n",[Other]). print_system_sup({Ref,Pid,supervisor,[ssh_subsystem_sup]}) when is_reference(Ref), is_pid(Pid) -> lists:foreach(fun print_channels/1, supervisor:which_children(Pid)); print_system_sup({{ssh_acceptor_sup,LocalHost,LocalPort}, Pid,supervisor, [ssh_acceptor_sup]}) when is_pid(Pid) -> io:format(" [Acceptor for ~s]~n",[fmt_host_port({LocalHost,LocalPort})]); print_system_sup(Other) -> io:format(" [[Other 3: ~p]]~n",[Other]). print_channels({{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) -> lists:foreach(fun print_channel/1, supervisor:which_children(Pid)); print_channels(Other) -> io:format(" [[Other 4: ~p]]~n",[Other]). print_channel({Ref,Pid,worker,[ssh_channel]}) when is_reference(Ref), is_pid(Pid) -> {{ConnManager,ChannelID}, Str} = ssh_channel:get_print_info(Pid), {{Local,Remote},StrM} = ssh_connection_handler:get_print_info(ConnManager), io:format(' ch ~p: ~s ~s',[ChannelID, StrM, Str]), io:format(" Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]); print_channel(Other) -> io:format(" [[Other 5: ~p]]~n",[Other]). %%%================================================================ -define(inc(N), (N+4)). walk_sups(StartPid) -> io:format("Start at ~p, ~s.~n",[StartPid,dead_or_alive(StartPid)]), walk_sups(children(StartPid), _Indent=?inc(0)). walk_sups([H={_,Pid,SupOrWorker,_}|T], Indent) -> indent(Indent), io:format('~200p ~p is ~s~n',[H,Pid,dead_or_alive(Pid)]), case SupOrWorker of supervisor -> walk_sups(children(Pid), ?inc(Indent)); _ -> ok end, walk_sups(T, Indent); walk_sups([], _) -> ok. dead_or_alive(Name) when is_atom(Name) -> case whereis(Name) of undefined -> "**UNDEFINED**"; Pid -> dead_or_alive(Pid) end; dead_or_alive(Pid) when is_pid(Pid) -> case process_info(Pid) of undefined -> "**DEAD**"; _ -> "alive" end. indent(I) -> io:format('~*c',[I,$ ]). children(Pid) -> Parent = self(), Helper = spawn(fun() -> Parent ! {self(),supervisor:which_children(Pid)} end), receive {Helper,L} when is_list(L) -> L after 2000 -> catch exit(Helper, kill), [] end. %%%================================================================ underline(Str) -> underline(Str, $-). underline(Str, LineChar) -> Len = lists:flatlength(Str), io:format('~s~n',[Str]), line(Len,LineChar). line(Len, Char) -> io:format('~*c~n', [Len,Char]). datetime() -> %% Adapt to new OTP 18 erlang time API and be back-compatible TimeStamp = try erlang:timestamp() catch error:undef -> erlang:now() end, {{YYYY,MM,DD}, {H,M,S}} = calendar:now_to_universal_time(TimeStamp), lists:flatten(io_lib:format('~4w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w UTC',[YYYY,MM,DD, H,M,S])). fmt_host_port({{A,B,C,D},Port}) -> io_lib:format('~p.~p.~p.~p:~p',[A,B,C,D,Port]); fmt_host_port({Host,Port}) -> io_lib:format('~s:~p',[Host,Port]). nyi() -> io:format('Not yet implemented~n',[]), nyi.