LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-02-2007, 06:31 PM   #1
gd2shoe
Member
 
Registered: Jun 2004
Location: Northern CA
Distribution: Debian
Posts: 835

Rep: Reputation: 49
Smile Redirecting non-standard file descriptors


On a normal executable, the system will prepare file descriptors 0, 1, and 2 for stdin, stdout and stderr. This allows for shell commands such as:
Code:
myBin < myInputFile > myOutputFile 2> myErrorLogFile
I have several questions regarding non-standard file descriptors. For example, is this valid (I believe I have heard of programs doing this):
Code:
myBin 3< WeirdInputFile
(Does not produce errors in the shell)

How would you access such a thing in C++ (or C for that matter)? How can you query the OS to see if a given file descriptor (here 3) is open already when execution starts? I would prefer to work with <iostream> classes, but am willing to deal with C functions if I need to.

Background: I am working on a project for school. Besides being curious about this topic, I think this would simplify my testing code. The instructor is emphasizing drivers and stubs, and stubs would be much easier if each could read from it's own stream. Something like:
Code:
myBin < test42.in > test42.myout 2>test42.myerr 3< test42.firststub 4< test42.secondsstub 5< test42.thirdstub
diff test42.out test1.myout
diff test42.err test1.myerr
(And no, I think I will be using one at a time in addition to stdin for almost every possible case, but may want more once or twice.)

Any clues would be appreciated.
(And before you say it, yes I could use normal file IO but that wouldn't satisfy my curiosity. And named pipes are cool too.)
 
Old 04-02-2007, 08:05 PM   #2
wjevans_7d1@yahoo.co
Member
 
Registered: Jun 2006
Location: Mariposa
Distribution: Slackware 9.1
Posts: 938

Rep: Reputation: 31
If there are any C++ experts out there, please jump right in, because when it comes to C++, I am but dust and ashes. But maybe I can help anyway.

This post is divided into two parts: the C part (for whose accuracy I can vouch), and the C++ part.

=== Part 1: the C part.

In C, you can read using low-level system calls open(), close(), read(), and so on. Or you can use high-level library calls fopen(), fclose(), fgets(), and so on. (Don't ever, ever use gets().)

The following program illustrates doing what you want for unit 3:

Code:
#define UNIT_NUMBER 3

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int    argc,
         char **argv
        )
{
  int  read_result;

  char buffer[48];

  FILE *phyle;

  if(argc<2)
  {
    read_result=read(UNIT_NUMBER,buffer,sizeof(buffer)-1);

    if(read_result==-1)
    {
      fprintf(stderr,"for read(), unit %d does not seem to be assigned\n",UNIT_NUMBER);

      exit(1);
    }

    buffer[read_result]=0;

    printf("The first %d bytes are these:\n%s\n",
           sizeof(buffer)-1,
           buffer
          );

    return 0;
  }
  else
  {
    phyle=fdopen(UNIT_NUMBER,"r");

    if(phyle==NULL)
    {
      fprintf(stderr,"for fdopen(), unit %d does not seem to be assigned\n",UNIT_NUMBER);

      exit(1);
    }

    if(fgets(buffer,
             sizeof(buffer),
             phyle
            )
       ==NULL
      )
    {
      fprintf(stderr,"fgets() failed\n");

      exit(1);
    }

    printf("the first line is this:\n%s",
           buffer
          );

    return 0;
  }

} /* main() */
Running that code would work like this:

Code:
evans:~$ cc tuesday.c -o tuesday
evans:~$ tuesday
for read(), unit 3 does not seem to be assigned
evans:~$ tuesday x
for fdopen(), unit 3 does not seem to be assigned
evans:~$ tuesday 3< tuesday.c
The first 47 bytes are these:
#define UNIT_NUMBER 3

#include <stdio.h>
#incl
evans:~$ tuesday x 3< tuesday.c
the first line is this:
#define UNIT_NUMBER 3
evans:~$
=== Part 2: the C++ part.

For C++, I googled:

Code:
C++ "file descriptor"
and got oodles of responses. In the first few, this seemed most promising:

Code:
http://wwwwbs.cs.tu-berlin.de/user-taipan/kraxel/gnuinfo/iostream/Files.html
Hope this helps.

Last edited by wjevans_7d1@yahoo.co; 04-02-2007 at 08:21 PM.
 
Old 04-02-2007, 08:18 PM   #3
gd2shoe
Member
 
Registered: Jun 2004
Location: Northern CA
Distribution: Debian
Posts: 835

Original Poster
Rep: Reputation: 49
It does help. Thank you for taking the time to respond. I'm still looking for the C++ way to do it. Now at least I know I have a way that I can imitate.

Thanks again.
 
Old 04-02-2007, 08:24 PM   #4
wjevans_7d1@yahoo.co
Member
 
Registered: Jun 2006
Location: Mariposa
Distribution: Slackware 9.1
Posts: 938

Rep: Reputation: 31
I have since edited my first response to include a possible C++ approach. We missed by minutes. Sigh.
 
Old 04-07-2007, 03:59 AM   #5
gd2shoe
Member
 
Registered: Jun 2004
Location: Northern CA
Distribution: Debian
Posts: 835

Original Poster
Rep: Reputation: 49
Quote:
The GNU C++ Iostream Library - Files
...
Constructor ifstream::ifstream (int fd)
Make an ifstream for reading from a file that was already open, using file descriptor fd. (This constructor is compatible with other versions of iostreams for posix systems, but is not part of the ansi working paper.)
...
Constructor ofstream:: ofstream (int fd)
Make an ofstream for writing to a file that was already open, using file descriptor fd.
I don't know why I didn't try this earlier. Note that it is not part of the ANSI standard. That would explain why these didn't show up on the other reference pages that I have been using.

Maybe it's too late at night, and I'm not thinking clearly, but I can't get it to compile. Here's my code:

Code:
#include <iostream>

using namespace std;

int main()
{
	istream thirdin(3);

	string buffer;

	while (thirdin >> buffer)
	{
		cout << buffer << endl;
	}
}
And my compile error:
Code:
$ g++ fdStream.cpp
fdStream.cpp: In function ‘int main()’:
fdStream.cpp:7: error: invalid conversion from ‘int’ to ‘std::basic_streambuf<char, std::char_traits<char> >*’
fdStream.cpp:7: error:   initializing argument 1 of ‘std::basic_istream<_CharT, _Traits>::basic_istream(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]’
I'm hoping that I look at this again tomorrow and laugh at a simple mistake. As it stands, it looks like that constructor does not exist!

For reference

Code:
$ g++ -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --with-tune=i686 --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
 
Old 04-08-2007, 08:05 AM   #6
wjevans_7d1@yahoo.co
Member
 
Registered: Jun 2006
Location: Mariposa
Distribution: Slackware 9.1
Posts: 938

Rep: Reputation: 31
I looked at more of the google results. I don't have the time to learn more about C++ at this point (I wish I did), but does this link help?

Code:
http://docs.sun.com/source/819-3704/bas_4928.htm
 
Old 04-08-2007, 09:58 AM   #7
gnashley
Amigo developer
 
Registered: Dec 2003
Location: Germany
Distribution: Slackware
Posts: 4,928

Rep: Reputation: 612Reputation: 612Reputation: 612Reputation: 612Reputation: 612Reputation: 612
Since you are using the latest compiler you will have less luck with backward compatibility when using non-standard code.
 
Old 04-08-2007, 02:27 PM   #8
kaz2100
Senior Member
 
Registered: Apr 2005
Location: Penguin land, with apple, no gates
Distribution: SlackWare > Debian testing woody(32) sarge etch lenny squeeze(+64) wheezy .. bullseye bookworm
Posts: 1,834

Rep: Reputation: 108Reputation: 108
Hya,

May be a little bit off topic. However,
Code:
$thisIsMyprogram 3< thisFileIsWhatIWantToFeedThrough3
$
works with bash, but not tcsh (csh....) At least, with my Penguin, same Penguin, only shell is different, exact same binary.

Happy Penguins!
 
Old 04-08-2007, 08:22 PM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by wjevans_7d1@yahoo.co
If there are any C++ experts out there, please jump right in, because when it comes to C++, I am but dust and ashes. But maybe I can help anyway.
Wow, that is one of the most useful things I've ever encountered. Do you happen to know of it's safe to dup2 to an arbitrary int greater than 2 (provided no other files are open)? That would save me a huge hassle when vfork'ing with alternate file descriptors.

Here is what I am thinking:

Code:
//old

char *command[] = { "program", "program", NULL };

int output_temp = dup(STDOUT_FILENO);
int input_temp  = dup(STDIN_FILENO);

int out_pipes[2];
int in_pipes[2];

pipe(out_pipes);
pipe(in_pipes);

dup2(out_pipes[1], STDOUT_FILENO); //normally need some sort of I/O control starting here
dup2(in_pipes[0], STDIN_FILENO);

if (!vfork()) execv(command[0], command);

dup2(output_temp, STDOUT_FILENO);
dup2(input_temp, STDIN_FILENO);
Code:
//new

char *command[] = { "program", "program", NULL };

int out_pipes[2];
int in_pipes[2];

pipe(out_pipes);
pipe(in_pipes);

dup2(out_pipes[1], 4);
dup2(in_pipes[0], 3);

if (!vfork()) execv(command[0], command); //then command dup2's 3 -> STDIN_FILENO, etc.
Sorry, I haven't tested it since I am Windows'ing it up right now. I will later. Thanks.
ta0kira
 
Old 04-09-2007, 05:48 AM   #10
wjevans_7d1@yahoo.co
Member
 
Registered: Jun 2006
Location: Mariposa
Distribution: Slackware 9.1
Posts: 938

Rep: Reputation: 31
ta0kira, let's discuss that after we've solved gd2shoe's problem. Either that, or post it in a different thread. It's amazing how easy it is for well-meaning people (including me) to hijack a thread without meaning to.

gd2shoe, how's it going? Found an answer yet?
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Increasing File Descriptors Geoffrey_Firmin Slackware 5 04-21-2008 09:48 AM
file descriptors node047 Linux - Newbie 1 03-29-2005 05:47 AM
unix file descriptors versus c FILE pointers nodger Programming 9 11-25-2004 07:02 AM
how to redirecting the standard output in program phil123 Linux - General 3 02-23-2004 12:02 AM
File descriptors odd question ferreter Linux - General 2 02-13-2003 10:21 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:06 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration