Solved

Cannot read from pipe connected to standard input

Posted on 2014-10-07
7
305 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

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

 
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

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

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

Suggested Solutions

Have you ever been frustrated by having to click seven times in order to retrieve a small bit of information from the web, always the same seven clicks, scrolling down and down until you reach your target? When you know the benefits of the command l…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

776 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