Unixy Question

Matts on 2005-02-23T20:08:14

So my question is this:

Given stdin (read only) and stdout (write only) [*] is there a way to create a single read/write filehandle that reads from stdin and writes to stdout? And tie() doesn't count as I need this to pass to poll().

[*] Unless you're djb, but that's just freaky


er,

nicholas on 2005-02-23T20:25:55

This would be without using Inline::C to compile a new kernel module, I take it?

a.k.a. no idea, and I'm not convinced that it's possible. (so someone prove me wrong, please)

fd 0 already does this for ttys

jmason on 2005-02-23T20:36:13

If it's a terminal you're attached to, I seem to recall that fd 0 can be written to, and fd 1 can be read from, just fine. Not sure if that's linux-specific or a common UNIX idiom though.

However, if you can't make that assumption -- ie if fd 0/1 may have been redirected to a non-tty source/sink, no, I don't think it's possible. :(

Re:fd 0 already does this for ttys

merlyn on 2005-02-24T00:30:22

It wasn't true in Unix V7, so there's at least some old school of thought that would subscribe to that theory.

socketpair(), possibly

Dom2 on 2005-02-23T22:16:44

I think that some systems make socketpair(2) bidirectional fd's. It appears that way on my FreeBSD box, but I don't know about others. Hmmm, even pipe(2) appears bidirectional on FreeBSD actually.

-Dom

Re:

Aristotle on 2005-02-24T00:42:06

As near as I can tell, yes, but only if STDIN and STDOUT are opened on the same thing (ie the only difference between them is the mode). Don't ask me how to get such a filehandle.

What do you need this for?

Re:

Matts on 2005-02-24T01:20:35

I don't *need* it, but I'm writing an app that works as either a poll() server, a forking server, or an inetd style server (where stdin is the read half of the socket, and stdout is the write half).

In fork/inetd mode the app still uses poll() internally (for various reasons) so it'd be nice to be able to just use the same code for each. Instead in inetd mode I have to pull a line off the read handle, and ask the write handle to process it and create the output.

This is all rather hard to explain in english, so here's the code:
    while (1) {
        my $line = $input->get_line;
        last if !defined($line);
        my $output = $out->process_line($line);
        $out->write($output) if $output;
        $input->watch_read(1);
    }
See it'd be nicer if this could all just be one variable, which is how it works in forkserver mode. However mostly I was curious as to whether it could be done.

would this do?

daved on 2005-02-24T05:06:35

#! /usr/bin/perl -wT

use FileHandle();
use strict;

my ($fileHandle) = new FileHandle();
open($fileHandle, "+>/dev/fd/0") || die("Whoops:$!\n");
unless ($fileHandle->print("Hello\n")) {
        die("Failed to write:$!\n");
}
my ($buffer);
unless ($fileHandle->read($buffer, 1)) {
        die("Failed to read:$!\n");
}

Re:would this do?

Matts on 2005-02-24T14:53:10

No, because although it opens fd0 for reading, the data isn't coming in on fd0 - it's coming in on fd1.

Matt.

Re:would this do?

daved on 2005-02-24T22:03:31

interesting. cos it worked (wrote to stdout and read from stdin) on the terminals that i was working on in solaris and linux. and on linux /dev/fd/0 and /dev/fd/1 are symlinks that point to the same file.

Re:would this do?

Matts on 2005-02-25T13:52:43

I might give it a go. I'm remembering that the stdin/stdout in an inetd/tcpserver situation are just built from dup2()ing the same filehandle twice onto those two separate file descriptors, so it might just work.

Of course I've now spent a few days building a work around :-)