[erlang-questions] open_port confusing (concerning qmail-inject)

Kevin q2h46uw02@REDACTED
Thu Apr 30 01:12:08 CEST 2009


Hello, qmail-inject is just a command line program that takes a message 
from stdin and dumps it into the mail queue

example to deliver a very short message to kevin@REDACTED:

prompt> echo "subject:it worked" | qmail-inject kevin@REDACTED


If successful it exits with a code of 0, all other numbers are errors.


I'm writing an erlang function that will eventually, **line-by-line**, 
feed a message to qmail-inject.

Here is my attempt:

start() ->

    From = "somebody@REDACTED",
    To = "kevin@REDACTED",
    Command = "/var/qmail/bin/qmail-inject -a -f " ++ From ++ " " ++ To,
    Port = open_port({spawn, Command}, [stream, exit_status]),

    Port ! {self(), {command, "Subject:It worked!\n"}},
    Port ! {self(), {command, "From:from@REDACTED\n"}},
    Port ! {self(), {command, "To:to@REDACTED\n"}},
    Port ! {self(), close},

    receive
        {Port, {exit_status, 0}} -> %% exited without a result
            {ok, worked};
        {Port, {exit_status, R}} -> %% dig program missing?
            {error, inject_error, R};
        Unknown -> Unknown
    end.


I was confused by the docs for port_command and port_close so I just 
stuck with the standard erlang message passing.

It works fine, but because I'm a little obsessive and I tried hiding the 
qmail-inject program by renaming it and breaking the whole thing.

By playing around I figured out the behavior of a broken command:

14> open_port({spawn, "/asdf"}, [stream, exit_status]).             
#Port<0.444>
15> flush().                                          
Shell got {#Port<0.444>,{exit_status,126}}

Ok, so I now see I can received the message of a broken command.

And here is a successful command:

16> open_port({spawn, "/usr/local/bin/date"}, [stream, exit_status]).
#Port<0.445>
17> flush().                                                        
Shell got {#Port<0.445>,{data,"Wed Apr 29 18:56:27 EDT 2009\n"}}
Shell got {#Port<0.445>,{exit_status,0}}
ok


But with a command like qmail-inject, there is nothing to flush until 
the message is finished, and I'm assuming it will
be sent when send it a close signal.  And with all this flushing, is 
there a chance of a race condition?

17> open_port({spawn, "/usr/local/bin/date"}, [stream, exit_status]).
#Port<0.1830>
18> flush().
ok
19>

So how do I tell if the port successfully opened to a waiting 
qmail-inject without blocking on a message that will only
come until after I fed it the message and closed the port?  And then be 
certain that the qmail-inject program returned
a success code of 0?  And avoid race conditions?

I would take my grandma 5 minutes to figure out how to open a pipe to a 
command line program in a scripting language like perl or ruby, but here 
I don't even know if I'm going in the right direction.

Thanks for any help,
Kevin








More information about the erlang-questions mailing list