Lua popen3() Implementation

2 minute read

Background

I start playing around with imapfilter this weekend which uses lua for scripting and wanted to basically pipe an email to spamassassin and get the result back. Incredibly simple request I thought. In shell code it would be as simple as:

spamc < ./msg1.txt > msg1.processed.txt

Where msg1.txt is fed to spamc on stdin and then the output from stdout is written to msg1.processed.txt. The message can then be placed in my inbox and handled appropriately.

Lua + POSIX popen()?

POSIX defines popen for one pipe, doesn’t tell you the return status of the command you execute and you must pass the command as a string. Passing the entire command is very annoying if ever want to pass multiple string arguments as now you need to escape them, and becareful doing that as you can code a security hole in the blink of an eye.

Not surprisingly, lua has a simple implementation of the POSIX popen. Unfortunately all you can do is write to the pipe for read from the pipe. That means I can only do spamc < ./msg1.txt or spamc > msg1.processed.txt. This accomplishes nothing productive.

Lua extensions or luarocks?

Maybe I can find something from the Lua extension site: luarocks? Yes! In fact I can, it’s called Lua Process Call (lpc). I played with this on Lua 5.1 and it works, stdin, stdout, and stderr just worked. So I should be happy right? No…

The luarocks package on Ubuntu 13.04 was built against Lua 5.1, and after running luarocks install lpc I have a shared object that only works with Lua 5.1. Sigh, imapfilter uses Lua 5.2. I started re-building luarocks with Lua 5.2 support, and got that working after a while. Then I ran in to problems building lpc against Lua 5.2 as a number of ABI changes breaks it. At this point I could start learning alot more Lua then I care to learn, fork the github repo and fix… but that’s way to painful. Perhaps there is a better way.

Native Lua Implementation?

I started looking closer at the Lua POSIX module included with Ubuntu (package name lua-posix) and realized there isn’t any reason I can’t just implement it in native Lua leveraging the POSIX module. With a little bit of work, and learning more Lua I did just that. Example code is on Github and will hopefully help others:

This implementation provides access to stdin, stdout, and stderr. Additionally it cleans-up its zombie processes with wait() and returns the status code of the forked process. What more could you want? I can’t think of much missing from this. If there are any people with more Lua-foo that I have (which is next to none… or should I say nil?), please feel free to comment on ways to improve this.

Additionally a simple wrapper provides a clean and easy way to access simple commands pipe_multi() while still allowing users to access popen3() to handle the pipes as needed.

Next Steps

Stay tuned for an upcoming entry with imapfilter!

Comments