[erlang-questions] Erlang ssh shell question

Mattsson, Tommy tommy.mattsson@REDACTED
Mon Dec 3 14:30:43 CET 2018


Hi Hans!

I've started to look into this. I did a trace using redbug and as far as I can tell I don't end up in the section with the comment "The F communicates via standard io:write/read." but rather end up in the section with the comment "%% Exec called and the shell is the default shell (= Erlang shell).".

This was assuming that the I/O not coming back for the exec case is a bug.


My redbug output:

% 14:10:33 <22297.5495.0>({ssh_client_channel,init,1})
% ssh_cli:handle_ssh_msg({ssh_cm,<22297.4959.0>,
        {exec,1,false, "sshtest:sshIO()."}},
        {state,undefined,undefined,undefined,undefined,undefined, {shell,start,[]}, undefined})

Which means, as far as I can tell, that no I/O is given back (there is no I/O handling from what I can see in the function ssh_clki:exec_in_erlang_default_shell/1.

Thanks for any help I can get ��
Best regards,
Tommy Mattsson



________________________________
From: Hans Nilsson R <hans.r.nilsson@REDACTED>
Sent: Tuesday, November 6, 2018 10:43 AM
To: Mattsson, Tommy; Per Hedeland
Cc: erlang-questions@REDACTED
Subject: Re: [erlang-questions] Erlang ssh shell question

Hi Tommy and Hi Per too :)

Sorry for my sloppy reading of your first mail, but now I think I understand you.

To start an Erlang server executing "shell" or "exec" commands you just start a normal server (= daemon):
Erlang/OTP 21 [erts-10.1.1] [source-3094642] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

2> ssh:daemon(1236, [{system_dir,"XXX"}]).  % (will get ~/.ssh as user_dir where ~ is the home of the user that started erl)

and elsewhere in a bash:

~$ ssh -p 1236 localhost
Eshell V10.1.1  (abort with ^G)
1> io:write(hej).
hejok
2> exit().
~$

or, for "exec":

~$ ssh -p 1236 localhost 1+2.
3
~$

etc.


Now as I understand, you want to do I/O in the command and expect:

~$ ssh -p 1236 localhost 'io:write(hejsan).'
hejsan
~$

but you get:

~$ ssh -p 1236 localhost 'io:write(hejsan).'
ok
~$

and hejsan is written in the shell of the server started above.


You could start your own exec command interpreter with the option 'exec' to the server:

(See http://erlang.org/doc/man/ssh.html#type-exec_daemon_option
 but NOTE: ERROR in that one.....
  should be
      {exec, {direct, 'exec_fun/1'() | 'exec_fun/2'() | 'exec_fun/3'()} }
 )

Example:
9> ssh:daemon(1237, [{system_dir,"XXX"}, {exec, {direct,  fun(Cmd) -> {ok, {got,Cmd}} end  }}]).

and from a separate bash shell:

~$ ssh -p 1237 localhost 'io:write(hejsan).'
{got,"io:write(hejsan)."}~$

This gives a clue on what to do:
"Just" write something executing the command grabbing the output and return it in that {direct,fun(Cmd)...} as a string...

Now I think that not returning I/O from an exec command is a bug. However I can't look into that now and probably not on this side of christmas.
IF you should like to dig into this, the central function is ssh_cli:handle_ssh_msg/2 line 114.  The clause with the head:
    handle_ssh_msg({ssh_cm, ConnectionHandler,  {exec, ChannelId, WantReply, Cmd}}, S0) ->

There are comments in that code which could give you some clues.  There is also a comment with "The F communicates via standard io:write/read.".
That makes me belive that I accidently changed some functionality when I restructured this part. I will look into that too, but not now.

I hope you got some ideas, and just ask if you wonder about something. And Pull Requests are welcome!

/Hans

On 11/6/18 9:24 AM, Mattsson, Tommy wrote:
> Hi Per and Hans,
>
> Thank you both for your replies! ��
> Per is correct, I want to execute "ssh <host> <cmd>" from a regular shell (bash, etc.) and have it connect to the Erlang SSH shell that I started on <host> and give me output like there was "echo test1", "echo test2" in a bash script.
>
>
> I will look into if I can make use of the exec functionality for the Erlang SSH server. I looked at it earlier but it seemed to me that its intended use was for an Erlang SSH client connecting to an Erlang SSH server so I dismissed that as an option.
>
> If all else fails I could look into the ssh_cli option and see if I can have an Erlang SSH shell handle I/O differently than the default.
>
>
> Best regards,
>
> Tommy
>
> ________________________________
> From: Per Hedeland <per@REDACTED>
> Sent: Friday, November 2, 2018 11:30:33 AM
> To: Hans Nilsson R; Mattsson, Tommy
> Cc: erlang-questions@REDACTED
> Subject: Re: [erlang-questions] Erlang ssh shell question
>
> Hi Tommy! (and Hans:-)
>
> Hans, I *think* you are misunderstanding Tommy's question. More
> speculation below, since I haven't actually verified how ssh(3)
> works... When using e.g. the OpenSSH client,
>
> $ ssh <host>
>
> makes a "shell" request per
> https://tools.ietf.org/html/rfc4254#section-6.5 , while
>
> $ ssh <host> <cmd>
>
> makes an "exec" request. I think Tommy is happy with how "shell" works,
> but you seem to be changing it to a pretty boring implementation.:-) And
> I think Tommy's question is about "exec" not associating 'standard_io'
> with the SSH channel - thus if you use "exec" to call a function that
> prints something, the output is lost.
>
> I'm not sure there is anything "wrong" with that though - for an SSH
> server running "directly" on *nix, it is obvious that "exec" should
> associate stdio with the SSH channel, since <cmd> is *nix shell command,
> and it's pretty fundamental that you want any output (and exit code)
> that it produces. But for the Erlang/OTP SSH server, <cmd> is
> (apparently) an Erlang function call, and sending only what the call
> returns (in text form) back through the channel is not unreasonable per
> se.
>
> But maybe there could be an option to ssh:daemon() to make it do the
> same thing with 'standard_io' for "exec" as it does for "shell" - I
> can't see one in the man page. And I can't think of a way that the
> called function could set it up. But I assume that it's possible to
> do-it-all yourself via the 'ssh_cli' option.
>
> --Per
>
> On 2018-11-02 10:37, Hans Nilsson R wrote:
>> Hi,
>>
>> Try
>>
>> 5> ssh:daemon(1234, [{system_dir,...}, {shell,fun(Usr,Hst) -> spawn(fun() -> io:format("Hello ~p ~p~n",[Usr,Hst]), L1 = io:get_line("&& "), io:format("Got ~p~n", [L1]) end) end}]).
>> {ok,<0.110.0>}
>> 6>
>>
>> Sorry for the one-liner. The fun() a bit edited, I hope I got it right:
>>
>>     fun(Usr,Hst) ->
>>            spawn(fun() ->
>>                     io:format("Hello ~p ~p~n",[Usr,Hst]),
>>                     L1 = io:get_line("&& "),
>>                     io:format("Got ~p~n", [L1])
>>                  end)
>>     end
>>
>>
>> Note the option shell and the spawn, it is essential.
>> You don't need the subsystem option.  The user_dir option defaults to the $HOME/.ssh of the user that started erl.
>>
>> Now in bash:
>>
>> ~$ ssh -p 1234 localhost
>> Hello "USERNAME" {{127,0,0,1},60088}
>> && some command
>> Got "some command\n"
>> Connection to localhost closed.
>> ~$
>>
>> Hope this helps.
>> /Hans
>>
>>
>>
>> On 11/2/18 10:05 AM, Mattsson, Tommy wrote:
>>> Hi,
>>>
>>> First time writer here on the erlang questions list :)
>>>
>>>
>>> I am wondering if anyone knows about how the erlang ssh handles I/O? More details can be found below.
>>>
>>>
>>> Erlang version: 21.0
>>>
>>>
>>>
>>> Start of SSH server on testing (Windows) machine:
>>>
>>> application:ensure_all_started(ssh),
>>> Options = [{system_dir, filename:join(SSHPath, "daemon")}, {user_dir, ?DIR}, {subsystems, [ssh_sftpd:subsystem_spec([{cwd, SSHPath}])]}],
>>>
>>> ssh:daemon(?ipaddr, ?port, Options]).
>>>
>>> Test module:
>>> -module(sshtest).
>>> sshIO() ->
>>>    io:format("test1~n"),
>>>    io:format("test2\n"),
>>>   test3.
>>>
>>>
>>> Test run from my own machine:
>>>> ssh $IPADDR 'sshtest:sshIO().'
>>> test3
>>>
>>>
>>> For some reason any io:format/io:fwrite does not travel back over the SSH connection. If I connect to some Linux machine that already has a (non-erlang) SSH server running and I try to run some random bash script then any echo I have in the script will travel back over the SSH connection.
>>>
>>> A test I did with a bash script towards a Linux server,
>>> Bash script (~/test.sh):
>>>
>>> echo "test1"
>>>
>>> echo "test2"
>>>
>>> echo "test3"
>>>
>>>
>>> Test run from my own machine:
>>>> ssh $IPADDR ./test.sh
>>>
>>> test1
>>>
>>> test2
>>>
>>> test3
>>>
>>> This is how I'd like it to work.
>>>
>>>
>>> I have been googling and reading the documentation for the ssh and related modules to no avail in regards to finding a solution to this problem.
>>>
>>> Other than this I/O problem the ssh connection works perfectly for me =
>
>>>
>>> Hopefully someone here on the list has some insight into how this works.
>>>
>>> Thankful for any help I can get :)
>>> Best regards,
>>>
>>> Tommy
>>>
>>>
>>>
>>>
>>>
>>>
>>> _______________________________________________
>>> erlang-questions mailing list
>>> erlang-questions@REDACTED
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>
>>
>>
>>
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20181203/ea0f3363/attachment.htm>


More information about the erlang-questions mailing list