Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Cannot read from pipe connected to standard input

Posted on 2014-10-07
7
309 Views
Last Modified: 2014-10-13
Ah hello.

I am experimenting with Linux pipes, and how we can set them to be standard file descriptors.  I am trying to read input from a pipe and display it in my program (called testApp) as follows:

int main(int argc, char *argv[])
{
	int pfd[2];
	int j, dummy, dummy2;
	char buf[1024];

	if (pipe(pfd) == -1)
		return -1;

	if (pfd[1] != STDIN_FILENO)
	{ 
		/* Defensive check */
		if (dup2(pfd[1], STDIN_FILENO) == -1)
			return -1;
		if (close(pfd[1]) == -1)
			return -1;
	}
	do
	{
		dummy2 = read(pfd[0], buf, sizeof (buf));
		buf[dummy2] = '\0';
		printf("Read %i bytes from standard input (%s)", dummy2, buf);
	} while (dummy2 != -1);
	
	return 0;
}

Open in new window


I want to be able to call this using a command such as the following:

ps -a | ./myProg

Open in new window


I can see that I have set up the pipe properly from the following:

me@me-VirtualBox:$ ls -l /proc/8967/fd
total 0
l-wx------ 1 me me 64 Oct  7 13:03 0 -> pipe:[93037]
lrwx------ 1 me me 64 Oct  7 13:03 1 -> /dev/pts/1
lrwx------ 1 me me 64 Oct  7 13:03 2 -> /dev/pts/1
lr-x------ 1 me me 64 Oct  7 13:03 3 -> pipe:[93037]

Open in new window

However, when I run the command above from a terminal, my program just sits there.
 
(Note that I know I could achieve this just by reading from stdin, but I want to understand why I cannot do it with pipes)

1) What is wrong with my code?

Now, I thought I might have called dup2() incorrectly, so I changed it to

if (dup2(STDIN_FILENO, pfd[1]) == -1) /* was dup2(pfd[1], STDIN_FILENO)*/

Open in new window


Then, when I run my program, I just get "Read 0 bytes from standard input ()" repeatedly output.

2) What is going on here?

TIA
0
Comment
Question by:mrwad99
  • 4
  • 2
7 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 40366101
You are 'dup()' ing 'pfd[1]' and then trying to read from 'pfd[0]' - I guess that is not what you actually want to do.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 40366108
I think it is though...here is my thinking.

The write end of my pipe (pfd[1]) is connected to standard input.  So when the command

ls | ./testapp

will send the output of ls to the standard input of ./testapp, which is the write end of my pipe,  Hence I then read from pfd[0] (the read end) expecting to see the output from ls appear on it.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 40376028
I've requested that this question be deleted for the following reason:

No solution.
0
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 
LVL 34

Expert Comment

by:Duncan Roe
ID: 40376029
You need to leave more than 3 days before giving up on a Q - the Call to Experts only just went out.
I think I see what you were hoping to do, but it's never going to work.
The reason you read no bytes from your pipe is that no process wrote any bytes to the other end. Here's why:
- You issue the command ps -a | ./myProg. This causes the shell to create a pipe with one end being file unit 1 of ps and the other end being file unit 0 of ./myProg.
 - ./myProg issues dup2(pfd[1], STDIN_FILENO). This closes ./myProg's existing file unit 0. The shell's pipe disappears and ps terminates with errno==EPIPE (assuming it caught the preceding fatal SIGPIPE signal)
0
 
LVL 19

Author Comment

by:mrwad99
ID: 40376704
Thanks Duncan.  I didn't realise it took so long for the neglected question alert to go out.  I thought after five days (2014-10-07 to 2014-10-12) I wouldn't get anything.  My mistake.

OK.  

I think I understand what you are saying, but can you humour me and just verify my understanding please (might sound strange but putting it in my own words proves to myself that I do understand what is happening :))

At the time my program is started by the shell, my program has fd 0, which is standard input.  This is the fd that lives at the read end of the pipe created by the shell.  Because I close that (in order to have standard input re-opened as the write end of the pipe I create in my program) the data that was sent down it by the shell is lost without being read (because that pipe is now "broken" as it only has one open end).

I am then left with the pipe created in my program that is having nothing sent to it.  I can however send stuff to this pipe and get the output I originally expected if I do something like

echo Hi > /proc/<myProg PID>/fd/0

Open in new window


(Haha, just as I finished typing that I decided to run my program again, accidentally doing so with the output from ls not ps.  It seems that ls gives a more informative result compared to ps which is in line with your comment about EPIPE:

$ ls -l | ./myProg
ls: write error: Broken pipe

Open in new window

)

1) Is all this correct?
2) So overall, I cannot achieve what I am after using pipes, and if I wanted to do this I would just read from standard input.  Correct?

Thanks in advance.
0
 
LVL 34

Accepted Solution

by:
Duncan Roe earned 500 total points
ID: 40376805
Yes, pretty much. Nice experiment with /proc - you are writing to fd 0 which is open for writing so hey, it works.
Your summary in point 2 is right - just read from standard input.
0
 
LVL 19

Author Closing Comment

by:mrwad99
ID: 40376823
Thank you very much Duncan :)
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question