RCR for child execution

I’m not sure if I understand what you care, but at least I want you to
know it’s the field I want to fix/change before the final 1.8.0
release.

I think the best description of the problem I have come up with so far is:
http://ruby-talk.com/cgi-bin/scat.rb/ruby/ruby-talk/71191

Separation of ruby stdout/stderr from C/C++ stdout/stderr is what I want.
I run Ruby in the same thread as C++ (ruby embedded into C++).
This separation is working fine, as long as I don’t use system or
backquote.

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 ???

If I understand you correctly, I think it is
an operating system issue rather than a Ruby
issue.

I sympathize with what you’re trying to do,
but I don’t know how to make it work.

Hal

···

----- Original Message -----
From: “Simon Strandgaard” 0bz63fz3m1qt3001@sneakemail.com
Newsgroups: comp.lang.ruby
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, May 12, 2003 6:00 AM
Subject: Re: RCR for child execution

On Mon, 12 May 2003 18:32:47 +0900, Yukihiro Matsumoto wrote:

But rb_stdout IS stdout!!! I am not sure how to make this clearer…

  • rb_stdout is a Ruby IO object (ok so far?)
  • It contains an open file which is the Unix stdout. That is how it is
    created.

Brian.

···

On Mon, May 12, 2003 at 08:00:56PM +0900, 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!!!

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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#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

···

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 ???

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
====================================

Hi,

In message “Re: RCR for child execution”

Separation of ruby stdout/stderr from C/C++ stdout/stderr is what I want.
I run Ruby in the same thread as C++ (ruby embedded into C++).
This separation is working fine, as long as I don’t use system or
backquote.

Hmm, but still stdin is stdin. The redirectable output port is
$defout and $deferr (which is just added).

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 ???

I’m not sure what you meant by “BOOM”. Even when Ruby is embedded in
the program, it’s still in the same process. The spawned process
inherits stdin etc. from the parent process, even when it’s created
from within Ruby. It’s UNIX way. I can’t change it. The only way I
can think of to avoid “BOOM” is (if I understand correctly) to remove
“system”, “exec” and “`” methods.

						matz.

Separation of ruby stdout/stderr from C/C++ stdout/stderr is what I want.

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 ???

It can’t be fixed easily; if rb_stdout were pointing at a StringIO object,
then this cannot be represented as a Unix fd.

Agree this will be a major patch and it will make heavy use of pipes.

I mean, I’m guessing you want something like ‘$deferr’ like ‘$defout’,
right? So that rb_warn sends to $deferr, and you can map this variable to
point to some other object?

I see no reason to introduce a ‘$deferr’… But this could be possible
sideeffect of this.
rb_warn outputs to stderr, perhaps it should output to rb_stderr ?

OK, but what do you want to happen here?

 $deferr = StringIO.new(x)
 system("ls /nonexistent")

I don’t feel comfortable with ‘$deferr’… so I cannot tell.

What do you want instead? That Ruby should create two new pipes, pass these
to the child as stdout/stderr; then read any data generated on those pipes,
and pass them to $defout.write and $deferr.write respectively?

yes… this is very much what I want.

The problems I can see with this are:

  • It adds overhead even for the 99% of cases where this is not needed

I understand your concern, maybe this will add overhead.
But normal Ruby users don’t have to suffer from it. During build of Ruby
there can be generated a ruby-embedding library which you can link with if
you are embedding ruby into C/C++.

  • It doesn’t follow the Unix API model, therefore violates POLS:
    “system” should not create pipes to the child. “popen” should.

Disagree!
What is POLS ?
where can I read more about the standard Unix API model ?

But there are more fundamental problems. Firstly, your Ruby function can
call C at any time: it’s as easy to embed C in Ruby as Ruby in C. What
happens when the C function does a write to stdout or stderr? You can’t
possibily intercept it without modifying the C. What if the C in turn calls
system() to run a child process, and the child process writes to stderr?
Hard luck, it gets written to your main program’s stderr.

Then the output of cause should go to stdout.

OK… there is 2 sides of this issue.
A) a C extension for ruby… in your C code you are outputting to
stdour/stderr. This output should be redirected to Rubys
rb_stdout/rb_stderr.
If you from C call system, then the output likewise should be redirected
to rb_stdout/rb_stderr.

B) the C program into which you embeds Ruby. If your C code is outputting
to stdout/stderr. Then it should go to stdout/stderr.
If you from C call system, then the output likewise should go to
stdout/stderr.

No problems here. Admitted (A) & (B) can easily be confused.

No scepticism == no democrazy :slight_smile:

···

On Mon, 12 May 2003 17:31:44 +0900, Brian Candler wrote:

On Mon, May 12, 2003 at 07:16:51AM +0900, Simon Strandgaard wrote:


Simon Strandgaard

Im trying to make it easier to embed ruby into existing C/C++
applications. I think this issue is very important in order to get Ruby more
widespread.

···

On Mon, 12 May 2003 21:12:15 +0900, Hal E. Fulton wrote:

From: “Simon Strandgaard” 0bz63fz3m1qt3001@sneakemail.com

Separation of ruby stdout/stderr from C/C++ stdout/stderr is what I want.
I run Ruby in the same thread as C++ (ruby embedded into C++).
This separation is working fine, as long as I don’t use system or
backquote.

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 ???

If I understand you correctly, I think it is
an operating system issue rather than a Ruby
issue.


Simon Strandgaard

Hi,

···

In message “Re: RCR for child execution” on 03/05/12, Brian Candler B.Candler@pobox.com writes:

I mean, I’m guessing you want something like ‘$deferr’ like ‘$defout’,
right? So that rb_warn sends to $deferr, and you can map this variable to
point to some other object?

This is exactly what I did today. all error messages and output from
newly added method “warn” will be directed to $deferr, which default
value is STDERR.

But still, I’m not sure this solves Simon’s problem.

						matz.

:wink: Me having installed Human Brain 0.3 alpha.

[snip filedescriptors]

Yes I know that fork() doesn’t take an explicit argument where you can
specify which stdout/stderr the child should inherit.
But this can be accomplished by a small hack.

void system(command) {
backup_stdout = stdout;
stdout = rb_stdout;
pid = fork();
if(pid != 0) {
execv(command);
stdout = backup_stdout;
}

Assignment to stdout/stderr is not legal… of couse reopen should be used.

[snip example]

Thanks for your fine example… But it won’t work!!
I am sharing a bunch of classes between C++ and Ruby, within the same
thread. Your code is 2 differnt processes!
I don’t want to marshall all my classes via a pipe between C++ and Ruby.

···

On Mon, 12 May 2003 17:21:25 +0000, ahoward wrote:

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.


Simon Strandgaard

OK… I’ll try explain what BOOM means :slight_smile:

BOOM = system+backquote outputs to stdout/stderr, interfering with the
output of the C/C++ application.

This interference is what to avoid. I want to be able to
redirect Rubys output elsewhere: logfile/statusbox/text-buffer.

At the same time I want to use normal ruby code (system, backquote…).

Its has been suggested that I instead of system/backquote, uses popen.
But I don’t consider it to be normal ruby code!

The problem is fairly simple, but I doubt anyone understands me ???

···

On Tue, 13 May 2003 04:04:23 +0900, Yukihiro Matsumoto wrote:

Hi,

In message “Re: RCR for child execution”

Separation of ruby stdout/stderr from C/C++ stdout/stderr is what I want.
I run Ruby in the same thread as C++ (ruby embedded into C++).
This separation is working fine, as long as I don’t use system or
backquote.

Hmm, but still stdin is stdin. The redirectable output port is
$defout and $deferr (which is just added).

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 ???

I’m not sure what you meant by “BOOM”. Even when Ruby is embedded in
the program, it’s still in the same process. The spawned process
inherits stdin etc. from the parent process, even when it’s created
from within Ruby. It’s UNIX way. I can’t change it. The only way I
can think of to avoid “BOOM” is (if I understand correctly) to remove
“system”, “exec” and “`” methods.


Simon Strandgaard

I mean, I’m guessing you want something like ‘$deferr’ like ‘$defout’,
right? So that rb_warn sends to $deferr, and you can map this variable to
point to some other object?

I see no reason to introduce a ‘$deferr’… But this could be possible
sideeffect of this.
rb_warn outputs to stderr, perhaps it should output to rb_stderr ?

It’s the same thing at the moment, because rb_stderr just encapsulates
stderr.

When you do
$stderr = File.new(“/tmp/foo”)
then the underlying Unix stderr is reopened to point to /tmp/foo. Try it. So
they are always kept in sync.

  • It doesn’t follow the Unix API model, therefore violates POLS:
    “system” should not create pipes to the child. “popen” should.

Disagree!
What is POLS ?
where can I read more about the standard Unix API model ?

“The Principle of Least Surprise”

For the Unix API model, the best introduction and reference I have found is
the Stevens book.

Brian.

···

On Mon, May 12, 2003 at 09:01:19PM +0900, Simon Strandgaard wrote:

Well, as you probably know, my vote is strongly against. Ruby embeds very
well at the moment, thank you very much.

If you want a version of Ruby’s “system” command which captures
stderr/stdout into a string, you can write your own easily. I suggested
the shorthand

%X{command}

to run a command and capture both stdout and stderr into a string (the RCR
from which this thread gets its subject)

But trying to intercept all stdout/stderr of a portion of your program (i.e.
the Ruby part) in general requires you either to change stdout/stderr and
restore it afterwards, or to fork and change it to a pipe, because the
“Ruby” part may write directly to the underlying stdout/stderr, not to
$stdout or $defout.

I really cannot see where the problem lies. We could play this game all day:
you give me an example where you think it would be useful for Ruby to have
this magic, and I can show how you can do it without.

Brian.

···

On Tue, May 13, 2003 at 12:23:17AM +0900, Simon Strandgaard wrote:

Im trying to make it easier to embed ruby into existing C/C++
applications. I think this issue is very important in order to get Ruby more
widespread.

Assignment to stdout/stderr is not legal… of couse reopen should be used.

But then you cannot get back the original thing which stdout/stderr was
connected to (e.g. if it were a pipe, or an unnamed file)

It might be possible to dup() them to a spare descriptor, dup2() the new fd
onto fd1/2, and then dup2() the copy back again. I’ve not tried that.

Thanks for your fine example… But it won’t work!!
I am sharing a bunch of classes between C++ and Ruby, within the same
thread. Your code is 2 differnt processes!
I don’t want to marshall all my classes via a pipe between C++ and Ruby.

So don’t.

I’m sorry, but you really do seem to have missed the point of embedding:
that your C/Ruby amalgamation is a single program.

The other important point is: Unix provides a default execution environment
where your program gets these character streams “stdin”, “stdout”, “stderr”,
but you are under no obligation to use them. People write GUI programs in C
all the time, just by calling GTk or Qt or whatever, and ignore the
existence of stdin/stdout/stderr altogether. If you want to embed Ruby into
something like that, then you write your Ruby to behave in a similar way.

Would you really expect to embed a C library like ‘ncurses’ or ‘gettext’
into a graphical C program and expect it to work? Of course not. Where would
it get its keystrokes from? Nowhere, unless you fork off a child and map
your GUI’s keystrokes and display to the child’s stdin and stdout.

Hence it makes little sense to embed a Ruby program written to use
stdin/stdout directly into a C program, unless you spawn a process to
communicate with it.

You might want to consider ‘stdin’ for a bit. Suppose the Ruby code you
embed into your program says:

puts “Press any key to continue”
gets

What would you have it do then?

Brian.

···

On Tue, May 13, 2003 at 03:04:01AM +0900, Simon Strandgaard wrote:

But the process you run with system/backquote is not Ruby, and therefore its
output is not Ruby’s output. It’s a completely different program, run using
fork + exec, but run in the same Unix environment as your main program (as
it should be: fork simply duplicates the existing process)

You can redirect Ruby’s output elsewhere ($defout), but it’s the child’s
output that you are asking about.

Now, you can always replace ‘system’ with a function with runs a child,
captures its output, and forwards it to a Ruby IO object. Matz suggested
putting something like ‘system2’ in the the Ruby library for this purpose.

But then you say that you want to do this without modifying existing Ruby
code. You can always replace ‘system’ and ‘backtick’ with your own versions
if you wish. But I still don’t think it makes sense.

The environment in which a Unix program runs looks, at its simplest, like
this:

             MAIN
···

On Tue, May 13, 2003 at 05:45:45AM +0900, Simon Strandgaard wrote:

BOOM = system+backquote outputs to stdout/stderr, interfering with the
output of the C/C++ application.

This interference is what to avoid. I want to be able to
redirect Rubys output elsewhere: logfile/statusbox/text-buffer.

           +---------------------------------+
           >                                 >
           > FD                              |

stdin -------> | 0 |
stdout<------- | 1 |
stderr<------- | 2 |
> >
> >
±--------------------------------+

It can ignore stdin/stdout/stderr of course - as it would if it were a GUI
program, say.

Now, from this main program, you want to call a function, which happens to
be written in Ruby.

It must be true that either:

  • This function makes no use of stdin/stdout/stderr at all. In that case
    there is no problem, agreed?

  • This function does communicate on stdin/stdout/stderr.

So I think you are saying in the second case you want to run it in a
‘sandbox’, a simulated Unix environment where it gets its own private
stdin/stdout/stderr:

           +---------------------------------+
           >                                 >
           >               +-----------+     |

stdin -------> | 0 obj0–>| 0 Sandbox | |
stdout<------- | 1 obj1<–| 1 | |
stderr<------- | 2 obj2<–| 2 | |
> ±----------+ |
> >
±--------------------------------+

I think you are asking for the Ruby interpreter to be the sandbox itself,
and to trap every single possible case where output might be written to
stdout/stderr, and have it redirect to Ruby IO calls instead. In the general
case, this is simply not possible whilst the Sandbox is in the same process
as you, because it shares fd0/1/2 with the the main program (because both
Ruby and C are part of the same program), and therefore the program has a
way to write to fd0/1/2.

Rewriting ‘system’ and backtick would catch some cases, but certainly not
all.

The only way to guarantee trapping of all output on fd 1 in the Sandbox into
some string object ‘obj1’ is to do it at the Unix API layer. This means
creating a new pipe and pass one end of it to the code running in the
Sandbox as fd 1. This then forces you to use a separate process, because
it must be possible for the Sandbox to be doing work and writing to one end
of the pipe whilst the main program is reading the other end of the pipe.
(You could also use native threads, but Ruby doesn’t play safely with
threads)

So to summarise:

Case 1: the Ruby code doesn’t use stdout/stderr at all

Solution 1:
Trivial, nothing to do.
(Most well-written libraries will be in this category)

Case 2: the Ruby code writes to stdout/stderr from Ruby, but does not in
turn run any C or external programs which would write directly to Unix fd
1/2 (which includes exec’ing another program using fork/exec, system,
backtick etc)

Solution 2:
Just reset $defout and now $deferr (thanks, Matz!)

Case 3: the Ruby code calls other programs (via embedded C calls or exec)
which in turn write directly to Unix stdout/stderr

Solution 3a:
Modify the Ruby code so that it captures that output itself at the
appropriate points (e.g. using IO.popen) if possible
or
Solution 3b:
When you call the Ruby code, first fork a subprocess which gets a whole
new stdin/stdout/stderr on pipes (and therefore any C or external
programs it calls will also communicate on those pipes). That’s the
solution ‘capture_output’ I gave before.

The problem is fairly simple, but I doubt anyone understands me ???

If I do understand you, then you are asking for something impossible. I
think you would realise this if you understood the Unix execution
environment a little better.

Regards,

Brian.

I mean, I’m guessing you want something like ‘$deferr’ like ‘$defout’,
right? So that rb_warn sends to $deferr, and you can map this variable to
point to some other object?

I see no reason to introduce a ‘$deferr’… But this could be possible
sideeffect of this.
rb_warn outputs to stderr, perhaps it should output to rb_stderr ?

It’s the same thing at the moment, because rb_stderr just encapsulates
stderr.

“at the moment”… agree. This is what I hope will get changed in Ruby
in the future.

  • It doesn’t follow the Unix API model, therefore violates POLS:
    “system” should not create pipes to the child. “popen” should.

Disagree!
What is POLS ?
where can I read more about the standard Unix API model ?

“The Principle of Least Surprise”

I know that principle… I just didn’t recognized the abbreviation.

I think that Ruby “at the moment” violates POLS, because everything is
hardcoded to use stdout/stderr.
It makes much more sense inheriting rb_stdout/rb_stderr instead.

···

On Tue, 13 May 2003 00:49:34 +0900, Brian Candler wrote:

On Mon, May 12, 2003 at 09:01:19PM +0900, Simon Strandgaard wrote:


Simon Strandgaard

Hi,

···

In message “Re: RCR for child execution” on 03/05/13, Brian Candler B.Candler@pobox.com writes:

If you want a version of Ruby’s “system” command which captures
stderr/stdout into a string, you can write your own easily. I suggested
the shorthand

%X{command}

to run a command and capture both stdout and stderr into a string (the RCR
from which this thread gets its subject)

I don’t like this notation. But I like the idea of spawning child
with its stdin/out/err replaced. It should be something like

system2(in, out, err, “command”)

but it needs better name.

						matz.

Its actually only “one thing” that im trying to accomplish (I know you don’t like
it)… this “one thing” has resulted in many threads

···

On Tue, 13 May 2003 04:02:09 +0900, Brian Candler wrote:

I really cannot see where the problem lies. We could play this game all day:
you give me an example where you think it would be useful for Ruby to have
this magic, and I can show how you can do it without.


Simon Strandgaard

this does not work after a ruby_run - i do not know why.

-a

···

On Tue, 13 May 2003, Brian Candler wrote:

It might be possible to dup() them to a spare descriptor, dup2() the new fd
onto fd1/2, and then dup2() the copy back again. I’ve not tried that.

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
====================================

Assignment to stdout/stderr is not legal… of couse reopen should be used.

But then you cannot get back the original thing which stdout/stderr was
connected to (e.g. if it were a pipe, or an unnamed file)

It might be possible to dup() them to a spare descriptor, dup2() the new fd
onto fd1/2, and then dup2() the copy back again. I’ve not tried that.

This was what I tried earlier…
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/71135

But I don’t know how I should do it with freopen ?? So I used assignment!

Thanks for your fine example… But it won’t work!!
I am sharing a bunch of classes between C++ and Ruby, within the same
thread. Your code is 2 differnt processes!
I don’t want to marshall all my classes via a pipe between C++ and Ruby.

So don’t.

I’m sorry, but you really do seem to have missed the point of embedding:
that your C/Ruby amalgamation is a single program.

I don’t get your point here ???

Hence it makes little sense to embed a Ruby program written to use
stdin/stdout directly into a C program, unless you spawn a process to
communicate with it.

Yes a thread which redirect IO is necessary… I said earlier that I had
left the code out for this IO-thread, because it would only complicate things
further.

You might want to consider ‘stdin’ for a bit. Suppose the Ruby code you
embed into your program says:

I have left out stdin because it only complicates things too much. This
must of cause also be considered.

···

On Tue, 13 May 2003 05:04:26 +0900, Brian Candler wrote:

On Tue, May 13, 2003 at 03:04:01AM +0900, Simon Strandgaard wrote:


Simon Strandgaard

perhaps i too am misunderstanding, but it does not seem like what simon is
asking for is impossible - there is another option:

a process can redirect fd 1 and 2, call some methods (possibly which spawn
sub-processes), and restore fd 1 and 2. i quite realize the entire
broken-pipe argument against this but considering simon’s application - it
seems like this is moot (or at least not cared about).

AFAICT ruby does something odd which prevents this - 50 ‘i love ruby’ stickers
to whomever can figure out why this short c program does not work for ruby!

it works for other types of output routines - what is ruby doing here?:

file: redirect2.c

----CUT----
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include “ruby.h”

/*
gcc redirect2.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];
int f;
int __out, __err;
pid_t pid;
char *script;
int c;

assert ((script = argv[1]) != NULL || (script = “redirected.rb”));

/* save */
assert ((__out = dup (STDOUT_FILENO)) != -1);
assert ((__err = dup (STDERR_FILENO)) != -1);

/* redirect */
assert (pipe (fd) == 0);
assert (dup2 (fd[1], STDOUT_FILENO) != -1);
assert (dup2 (fd[1], STDERR_FILENO) != -1);

/* sandboxed */

/* THIS WORKS… */
system ("ls "FILE);
system (“ls no-exist”);
write (STDOUT_FILENO, “redirected out\n”, 15);
write (STDERR_FILENO, “redirected err\n”, 15);

/* THIS WILL NOT… /
/

ruby_init ();
ruby_script (script);
rb_load_file (script);
ruby_run ();
*/

/* restore */
assert (dup2 (__out, STDOUT_FILENO) != -1);
assert (dup2 (__err, STDERR_FILENO) != -1);

/* display */
write (STDOUT_FILENO, “REDIRECTED:\n”, 12);
assert (close (fd[1]) != -1);
while (read (fd[0], &c, 1) && write (STDOUT_FILENO, &c, 1));
assert (close (fd[0]) != -1);

return (EXIT_SUCCESS);
}

/*

···

On Tue, 13 May 2003, Brian Candler wrote:

The problem is fairly simple, but I doubt anyone understands me ???

If I do understand you, then you are asking for something impossible. I
think you would realise this if you understood the Unix execution
environment a little better.

  • file: 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
*/
----CUT----

notice the part which does not work has been commented out.

-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
====================================

BOOM = system+backquote outputs to stdout/stderr, interfering with the
output of the C/C++ application.

This interference is what to avoid. I want to be able to
redirect Rubys output elsewhere: logfile/statusbox/text-buffer.

But the process you run with system/backquote is not Ruby, and therefore its
output is not Ruby’s output. It’s a completely different program, run using
fork + exec, but run in the same Unix environment as your main program (as
it should be: fork simply duplicates the existing process)

This is exactly the my situation im in.

You can redirect Ruby’s output elsewhere ($defout), but it’s the child’s
output that you are asking about.

True

Now, you can always replace ‘system’ with a function with runs a child,
captures its output, and forwards it to a Ruby IO object.

True… But this is only a patch-work, not a “nice” solution.
Still rb_warn and friends outputs to stderr.
I am searching for the nice solution :slight_smile:

Matz suggested
putting something like ‘system2’ in the the Ruby library for this purpose.

A ‘system2’ call is not future-safe… maybe some day one wants to control
the sheduling priority of the process to be spawned.
I think a ‘System’ class could be more future-safe.

sys = System.new(“command” => “xmms”, “prio” => “realtime”, “out” => myhandler)
sleep 20
sys.kill(9) # killing children ruthless!!

I just read Ara Howards suggestion for a ‘spawn’… This is even better :slight_smile:

Neither ‘system2’ nor a System class would require any changes to the Core
of ruby. It could easily be implemented as a Ruby/C extension.
My problem is slight different and would require changes to Rubys Core.

[snip the remaining thread]

A short break… Getting something to eat…
The remaining part looks good, I like the diagrams and we starting to
understand eachother :slight_smile:

···

On Tue, 13 May 2003 08:39:34 +0900, Brian Candler wrote:

On Tue, May 13, 2003 at 05:45:45AM +0900, Simon Strandgaard wrote:


Simon Strandgaard