Solved

Cannot read from pipe connected to standard input

Posted on 2014-10-07
7
299 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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

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…
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.

744 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

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now