From: ahoward Date: 2003-05-13T01:43:26+09:00 Subject: Re: RCR for child execution On Mon, 12 May 2003, Simon Strandgaard wrote: > Using system or backquote, then it goes BOOM. The problem as I see it is > localized in Rubys code - not mine! Ruby spawns a child which inherits > stdout/stderr. This child should instead inherit rb_stdout/rb_stderr > instead!!! Can this issue be fixed on Ruby ??? this is not correct thinking. consider this: a) fd's (STDIN_FILENO, STDOUT_FILENO) are managed by *the kernel*!! neither C nor ruby has any affect on them where child processes are concerned. b) FILE *'s (stdin, stdout, rb_stdout, etc) exist in a library which wrap (but do not 'contain', as they are still in *kernel* space/mngment) fd's with a buffer. because these buffers exist as a library they are like any other *user* code that you've written - the os can never magically transport them to a child process when a fork, backtick, etc occurs because it has NO KNOWLEDEGE of them. so you are left with this delima - any redirection which is to be inherited across a fork/exec (system, backtick, explicit fork, etc) MUST take place at the file descriptor (kernel - unix, win, whatever) level and this affects the entire calling process(es). any tinkering with FILE *'s, iostreams, io objects in c, c--, or ruby will *never* have the intended affect unless you happen to luck out (or know what you are doing) and somehow call methods which themselves affect the underlying fd's. considering how confusing io can be, it's almost certainly the case that simply understanding how fd's work at the c level is the safest and surest thing to do. in a nutshell, you must affect the fds (1, 2) before executing ruby, but leave them alone (or restore) them in the calling (c--) process, for example here is a c program which redirects all stdout and stderr from a child ruby process into a pipe, without affecting the stdout and stderr of the parent process, and then reads from that pipe to display it to the terminal - i think something like this will be in order for your c++ application: ~/eg/ruby/redirect > cat redirect.c #include #include #include #include #include "ruby.h" /* gcc redirect.c -I /usr/local/ruby-1.6.6/ /usr/local/ruby-1.6.6/libruby.a -lm -ldl -lcrypt */ int main (argc, argv) int argc; char **argv; { int fd[2]; pid_t pid; char *script; int c; assert ((script = argv[1]) != NULL); assert (pipe (fd) == 0); assert ((pid = fork ()) != -1); if (pid == 0) { assert (close (fd[0]) != -1); assert (dup2 (fd[1], STDOUT_FILENO) != -1); assert (dup2 (fd[1], STDERR_FILENO) != -1); ruby_init (); ruby_script (script); rb_load_file (script); ruby_run (); } else { write (STDOUT_FILENO, "RUBYOUT:\n", 9); assert (close (fd[1]) != -1); while (read (fd[0], &c, 1) && write (STDOUT_FILENO, &c, 1)); assert (close (fd[0]) != -1); } return (EXIT_SUCCESS); } ~/eg/ruby/redirect > cat redirected.rb `ls #{__FILE__}` `ls non-existent-file` system 'ls #{__FILE__}' system 'ls non-existent-file' STDOUT.puts 42 STDERR.puts 42 $defout.puts 42 $stdout.puts 42 $stderr.puts 42 puts 42 ~/eg/ruby/redirect > gcc redirect.c -I /usr/local/ruby-1.6.6/ /usr/local/ruby-1.6.6/libruby.a -lm -ldl -lcrypt ~eg/ruby/redirect > a.out redirected.rb RUBYOUT: ls: non-existent-file: No such file or directory a.out redirect.c redirected.rb ls: non-existent-file: No such file or directory 42 42 42 42 42 42 -a -- ==================================== | Ara Howard | NOAA Forecast Systems Laboratory | Information and Technology Services | Data Systems Group | R/FST 325 Broadway | Boulder, CO 80305-3328 | Email: ara.t.howard@fsl.noaa.gov | Phone: 303-497-7238 | Fax: 303-497-7259 ====================================