[erlang-questions] limitations of erlang:open_port() and os:cmd()

Bengt Kleberg <>
Mon Nov 1 17:38:39 CET 2010


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:
> 



More information about the erlang-questions mailing list