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