Quantcast

limitations of erlang:open_port() and os:cmd()

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

limitations of erlang:open_port() and os:cmd()

Matthias Lang
Hi,

I know of a few limitations when running external programs from
Erlang, and I know a few workarounds.

Does anyone know of limitations and/or workarounds I don't know about?
Would be interesting to hear about them.

The limitations I know of are:

  1. There's no way to do flow control.
  2. There's no way to kill a misbehaving process
  3. There's no way to send eof _and_ get the process' exit status

Expanding on those:

--------------------
1. There's no way to do flow control

Example:
    1> os:cmd("cat /dev/zero").
    Crash dump was written to: erl_crash.dump
    eheap_alloc: Cannot allocate 1048656 bytes of memory (of type "heap_frag").

Workaround 1.1:
    1> os:cmd("cat /dev/zero | netcat -l -p 49152").
    User switch command --> s --> c
    1> {ok, S} = gen_tcp:connect("localhost", 49152, [{active, once}]).
    {ok,#Port<0.607>}
    2> flush().
    Shell got {tcp,#Port<0.607>, [0,0,0,0,0,0,0,0,0,0

Suckage: depends on netcat, I'm not sure which process' exit status you get

--------------------
2. There's no way to kill a misbehaving process

Example:
   1> os:cmd("wc /dev/zero").

Workaround 2.1:
   Write a wrapper program which echoes the unix pid before exec()ing
   the actual command.

Workaround 2.2:
   Write a wrapper program which forks() and copies IO to the child,
   terminating the child on eof.

Suckage: you have to write a wrapper

--------------------
3. There's no way to send eof _and_ get the process' exit status

Example:
   1> {ok, Bin} = file:read_file("/tmp/mml.tgz").
   {ok,<<31,139,8,0,100,129,202,76,0,3,236,93,9,120,20,85,
   2>  P = open_port({spawn, "tar -xzf -"}, [exit_status, binary]).
   #Port<0.535>
   3> port_command(P, Bin).
   true
   4> flush().
   ok
   5> port_close(P).
   true
   6> flush().
   ok

Workaround 3.1:
   Abuse strace, using knowledge of the unix pid gained somehow:

      os:cmd("strace -p 7974 -e trace=process").

Workaround 3.2:
   Go via netcat again, e.g.

   2>  P = open_port({spawn, "netcat -l -p 49152 | tar -xzf -"}, [exit_status, binary]).
   3> {ok, S} = gen_tcp:connect("localhost", 49152, []).
   4> gen_tcp:send(S, Bin), gen_tcp:close(S), flush().

Suckage: probably only works on unix, requires netcat



Matt

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:[hidden email]

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: limitations of erlang:open_port() and os:cmd()

Bengt Kleberg
Greetings,

This is probably not what you want, but the shell rc
(http://doc.cat-v.org/plan_9/4th_edition/papers/rc) has multiple exit
status from a pipe. Like this:
"Rc captures command exit status in the variable $status. For a simple
command the value of $status is just as described above. For a pipeline
$status is set to the concatenation of the statuses of the pipeline
components with | characters for separators."


bengt

On Fri, 2010-10-29 at 12:40 +0200, Matthias Lang wrote:

> Hi,
>
> I know of a few limitations when running external programs from
> Erlang, and I know a few workarounds.
>
> Does anyone know of limitations and/or workarounds I don't know about?
> Would be interesting to hear about them.
>
> The limitations I know of are:
>
>   1. There's no way to do flow control.
>   2. There's no way to kill a misbehaving process
>   3. There's no way to send eof _and_ get the process' exit status
>
> Expanding on those:
>
> --------------------
> 1. There's no way to do flow control
>
> Example:
>     1> os:cmd("cat /dev/zero").
>     Crash dump was written to: erl_crash.dump
>     eheap_alloc: Cannot allocate 1048656 bytes of memory (of type "heap_frag").
>
> Workaround 1.1:
>     1> os:cmd("cat /dev/zero | netcat -l -p 49152").
>     User switch command --> s --> c
>     1> {ok, S} = gen_tcp:connect("localhost", 49152, [{active, once}]).
>     {ok,#Port<0.607>}
>     2> flush().
>     Shell got {tcp,#Port<0.607>, [0,0,0,0,0,0,0,0,0,0
>
> Suckage: depends on netcat, I'm not sure which process' exit status you get
>
> --------------------
> 2. There's no way to kill a misbehaving process
>
> Example:
>    1> os:cmd("wc /dev/zero").
>
> Workaround 2.1:
>    Write a wrapper program which echoes the unix pid before exec()ing
>    the actual command.
>
> Workaround 2.2:
>    Write a wrapper program which forks() and copies IO to the child,
>    terminating the child on eof.
>
> Suckage: you have to write a wrapper
>
> --------------------
> 3. There's no way to send eof _and_ get the process' exit status
>
> Example:
>    1> {ok, Bin} = file:read_file("/tmp/mml.tgz").
>    {ok,<<31,139,8,0,100,129,202,76,0,3,236,93,9,120,20,85,
>    2>  P = open_port({spawn, "tar -xzf -"}, [exit_status, binary]).
>    #Port<0.535>
>    3> port_command(P, Bin).
>    true
>    4> flush().
>    ok
>    5> port_close(P).
>    true
>    6> flush().
>    ok
>
> Workaround 3.1:
>    Abuse strace, using knowledge of the unix pid gained somehow:
>
>       os:cmd("strace -p 7974 -e trace=process").
>
> Workaround 3.2:
>    Go via netcat again, e.g.
>
>    2>  P = open_port({spawn, "netcat -l -p 49152 | tar -xzf -"}, [exit_status, binary]).
>    3> {ok, S} = gen_tcp:connect("localhost", 49152, []).
>    4> gen_tcp:send(S, Bin), gen_tcp:close(S), flush().
>
> Suckage: probably only works on unix, requires netcat
>
>
>
> Matt
>
> ________________________________________________________________
> erlang-questions (at) erlang.org mailing list.
> See http://www.erlang.org/faq.html
> To unsubscribe; mailto:[hidden email]
>


________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:[hidden email]

Loading...