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

Matthias Lang matthias@REDACTED
Fri Oct 29 12:40:41 CEST 2010


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


More information about the erlang-questions mailing list