From: Brian Candler Date: 2003-05-30T18:07:01+09:00 Subject: Re: output redirection within mod_ruby On Fri, May 30, 2003 at 05:32:13PM +0900, Ian Macdonald wrote: > I have a script that runs under mod_ruby with Apache 2.0.40. At a > certain point, it needs to invoke Kernel.system. For reasons of > security, I pass this method multiple arguments, so that it doesn't hand > off the whole thing to the shell, as then I'd need to worry about > sanitising the tainted data. > > Unfortunately, the output of the binary called by system does not get > sent to the browser, even though the binary sends its output to stdout. > Presumably, mod_ruby is discarding the output. > > Is there any way around this phenomenon? I think that you have to capture the output of the command yourself. Your Unix stdout cannot be captured by Apache unless your applicaton is a separate process (which is true of a CGI or FastCGI application, but not true of mod_ruby where your code is in the same process as the Apache worker) There was a thread about capturing the output of system() a few days ago. Here is a better version: system2() is like system() but returns three items (stdout string, stderr string, exit status), and system3() has an extra initial parameter for a string to pass to stdin. It's based very much on 'open3.rb' from the Ruby standard library. module Kernel private def system3(inp_data, cmd, *args) pw = IO::pipe pr = IO::pipe pe = IO::pipe pid = fork do pw[1].close pr[0].close pe[0].close STDIN.reopen(pw[0]) STDOUT.reopen(pr[1]) STDERR.reopen(pe[1]) exec(cmd, *args) end pw[0].close pr[1].close pe[1].close out_data = err_data = nil t1 = Thread.new do pw[1].write inp_data if inp_data pw[1].close end t2 = Thread.new do out_data = pr[0].read pr[0].close end t3 = Thread.new do err_data = pe[0].read pe[0].close end wpid, wstatus = Process.waitpid2(pid) t1.join t2.join t3.join return out_data, err_data, wstatus end def system2(cmd, *args) system3(nil, cmd, *args) end end # Example: # a, b, c = system2("ls","/dev/null","/nonexistent") # p a,b,c # >> "/dev/null\n" # >> "ls: /nonexistent: No such file or directory\n" # >> 256 (= exit code 1 from ls)