473,416 Members | 1,570 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,416 software developers and data experts.

problem with implementing pipe

I am trying to implement the UNIX pipe command using C but with the
"->" operator. Everything works fine with 1 pipe, but when I try to
use 2 or more, it hangs up when reading the pipe_in filestream. If
ANYONE could offer ANY suggestion as to why this is happening it would
be much appreciated.

Thanks in advance!

#define MAX_PIPES 5
#define MAX_CMD_LEN 255

#include <string.h>
#include <stdio.h>

// global vars

char piped_cmds [MAX_PIPES][MAX_CMD_LEN] ;
int numPipes ;

// fcn prototypes

int pipeCmds (int cmd1, int cmd2) ;
char *stripFirstChar (char *str) ;
char *stripLastChar (char *str) ;
void splitPipes (char *toSplit) ;
int isPipe (char *cmd) ;

int main () {
int i ;
char command [] = "ps aux -> grep greg -> wc" ;
//char command [] = "cat .bash_profile -> tail -15 -> tail -10 ->
tail -5 -> tail -3" ;
//char command [] = "ps aux -> grep greg -> grep 5 -> grep 3 -> less"
;
char *noPipe = "ps aux" ;

//numPipes = 0 ;
if (isPipe (command)) {
splitPipes (command) ;
for (i = 0; i < numPipes - 1; i++) {
if (!pipeCmds (i, i + 1))
printf ("Pipe failed\n") ;
else
printf ("Pipe succeeded\n") ;

}
}
printf ("Exit\n") ;
}

int pipeCmds (int cmd1, int cmd2) {
FILE *pipe_in ;
FILE *pipe_out ;
char *my_string ;
int nbytes = 100;
int bytes_read;
char readbuf[MAX_CMD_LEN];

printf ("Piping [%i] %s -> [%i] %s\n", cmd1, piped_cmds [cmd1], cmd2,
piped_cmds [cmd2]) ;
// open pipes
pipe_in = popen (piped_cmds [cmd1], "r") ;
printf ("Input pipe open\n") ;
pipe_out = popen (piped_cmds [cmd2], "w") ;
printf ("Output pipe open\n") ;

if ((!pipe_in) || (!pipe_out)) {
fprintf (stderr, "One or both pipes failed.\n") ;
return 0 ;
}

printf ("Transferring file contents...\n") ;
// while(fgets(readbuf, 250, pipe_in))
// fputs(readbuf, pipe_out);
while (!feof (pipe_in)) {
printf ("Reading input pipe...\n") ;
/****************program hangs here**************************/
fgets (readbuf, MAX_CMD_LEN, pipe_in);
if(feof(pipe_in))
break;
printf("%s", readbuf) ;
fputs (readbuf, pipe_out) ;
}

pclose (pipe_in) ;
pclose (pipe_out) ;
printf ("Pipes closed\n") ;

return 1 ;
}

char *stripFirstChar (char *str) {
str++ ;
return str ;
}

char *stripLastChar (char *str) {
char *temp = str ;
while (*temp != '\0') {
temp++ ;
}
temp-- ;
*temp = '\0' ;
//printf ("\"%s\"\n", temp) ;
return str ;
}

void splitPipes (char *toSplit) {
char *tokenPtr = NULL ;
int i ;

for (tokenPtr = strtok (toSplit, "->"); tokenPtr != NULL;
tokenPtr = strtok (NULL, "->"))
{
strcpy (piped_cmds [numPipes], tokenPtr) ;
numPipes++ ;
}

for (i = 1; i < numPipes; i++) {
strcpy (piped_cmds [i], stripFirstChar (piped_cmds [i])) ;
}

for (i = 0; i < numPipes - 1; i++) {
strcpy (piped_cmds [i], stripLastChar (piped_cmds [i])) ;
}

for (i = 0; i < numPipes; i++) {
printf ("[%i] \"%s\"\n", i, piped_cmds [i]) ;
}
}

int isPipe (char *cmd) {

if (strchr (cmd, '>')) {
printf ("%s contains at least 1 pipe\n", cmd) ;
return 1 ;
}
else
printf ("%s contains no pipes\n", cmd) ;
return 0 ;
}
Nov 14 '05 #1
7 3679
In article <7e**************************@posting.google.com >,
dj*********@snowboard.com (Greg) wrote:
I am trying to implement the UNIX pipe command using C but with the
"->" operator. Everything works fine with 1 pipe, but when I try to
use 2 or more, it hangs up when reading the pipe_in filestream. If
ANYONE could offer ANY suggestion as to why this is happening it would
be much appreciated.
When you have 3 commands in the pipe, you're running piped_cmds[1]
twice: first when you call pipeCmds(0, 1), then again when you call
pipeCmds(1, 2). And when you run it the second time, the command is
trying to read from your standard input rather than the output of the
first command.

Another problem with your design is that the third command in the
pipeline isn't even started until the first command finishes. If the
first command is an infinite loop (like "tail -f filename"), the third
command will never be run.

Thanks in advance!

#define MAX_PIPES 5
#define MAX_CMD_LEN 255

#include <string.h>
#include <stdio.h>

// global vars

char piped_cmds [MAX_PIPES][MAX_CMD_LEN] ;
int numPipes ;

// fcn prototypes

int pipeCmds (int cmd1, int cmd2) ;
char *stripFirstChar (char *str) ;
char *stripLastChar (char *str) ;
void splitPipes (char *toSplit) ;
int isPipe (char *cmd) ;

int main () {
int i ;
char command [] = "ps aux -> grep greg -> wc" ;
//char command [] = "cat .bash_profile -> tail -15 -> tail -10 ->
tail -5 -> tail -3" ;
//char command [] = "ps aux -> grep greg -> grep 5 -> grep 3 -> less"
;
char *noPipe = "ps aux" ;

//numPipes = 0 ;
if (isPipe (command)) {
splitPipes (command) ;
for (i = 0; i < numPipes - 1; i++) {
if (!pipeCmds (i, i + 1))
printf ("Pipe failed\n") ;
else
printf ("Pipe succeeded\n") ;

}
}
printf ("Exit\n") ;
}

int pipeCmds (int cmd1, int cmd2) {
FILE *pipe_in ;
FILE *pipe_out ;
char *my_string ;
int nbytes = 100;
int bytes_read;
char readbuf[MAX_CMD_LEN];

printf ("Piping [%i] %s -> [%i] %s\n", cmd1, piped_cmds [cmd1], cmd2,
piped_cmds [cmd2]) ;
// open pipes
pipe_in = popen (piped_cmds [cmd1], "r") ;
printf ("Input pipe open\n") ;
pipe_out = popen (piped_cmds [cmd2], "w") ;
printf ("Output pipe open\n") ;

if ((!pipe_in) || (!pipe_out)) {
fprintf (stderr, "One or both pipes failed.\n") ;
return 0 ;
}

printf ("Transferring file contents...\n") ;
// while(fgets(readbuf, 250, pipe_in))
// fputs(readbuf, pipe_out);
while (!feof (pipe_in)) {
printf ("Reading input pipe...\n") ;
/****************program hangs here**************************/
fgets (readbuf, MAX_CMD_LEN, pipe_in);
if(feof(pipe_in))
break;
printf("%s", readbuf) ;
fputs (readbuf, pipe_out) ;
}

pclose (pipe_in) ;
pclose (pipe_out) ;
printf ("Pipes closed\n") ;

return 1 ;
}

char *stripFirstChar (char *str) {
str++ ;
return str ;
}

char *stripLastChar (char *str) {
char *temp = str ;
while (*temp != '\0') {
temp++ ;
}
temp-- ;
*temp = '\0' ;
//printf ("\"%s\"\n", temp) ;
return str ;
}

void splitPipes (char *toSplit) {
char *tokenPtr = NULL ;
int i ;

for (tokenPtr = strtok (toSplit, "->"); tokenPtr != NULL;
tokenPtr = strtok (NULL, "->"))
{
strcpy (piped_cmds [numPipes], tokenPtr) ;
numPipes++ ;
}

for (i = 1; i < numPipes; i++) {
strcpy (piped_cmds [i], stripFirstChar (piped_cmds [i])) ;
}

for (i = 0; i < numPipes - 1; i++) {
strcpy (piped_cmds [i], stripLastChar (piped_cmds [i])) ;
}

for (i = 0; i < numPipes; i++) {
printf ("[%i] \"%s\"\n", i, piped_cmds [i]) ;
}
}

int isPipe (char *cmd) {

if (strchr (cmd, '>')) {
printf ("%s contains at least 1 pipe\n", cmd) ;
return 1 ;
}
else
printf ("%s contains no pipes\n", cmd) ;
return 0 ;
}


--
Barry Margolin, ba****@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
Nov 14 '05 #2
In comp.unix.programmer Greg <dj*********@snowboard.com> wrote:
I am trying to implement the UNIX pipe command using C but with the
"->" operator. Everything works fine with 1 pipe, but when I try to
use 2 or more, it hangs up when reading the pipe_in filestream. If
<snipped code because of its length>

What you do in your program for A -> B -> C is basically

1. create a new process running A
2. create a new process running B
3. read input from first process, running A
4. write what you just read to second process, running B
5. kill both processes

and then

6. create a new process running B
7. create a new process running C
8. read input from third process, running B
9. write what you read to fourth process, running C
10. kill both processes

So its roughly as if you would write on the command line
A | B; B | C


And, of courrse, that's not a pipe at all. There are two processes
running B that are completely independent of each other. But with
a pipe you would have only a single one in the middle, getting the
output of the process running A and its output being fed to the
third process. running C. So your program can't work because the
second instance of a process running B has nothing to output since
it never gets any input - that went to the first B process and the
output of that was simply thrown away.

You can't implement what you try to do with jsut popen(). At least
for B you need to manually fork() and exec() a new process with its
standard input _and_ output redirected to be able to both send data
to it and read them simultaneously (popen() allows this only for
either stdin or stdout redirected, but not both).

Another thing with your program that's not working is your use of
feof(). This function only returns something meaningful _after_
you have read from a FILE*, i.e. its purpose is to find out why
a previous read failed (or returned less than expected). You can't
use it to figure out if the next read would fail because of EOF,
that's not what it's meant for and so it must not be called before
you have tried to read something.
Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #3
Je***********@physik.fu-berlin.de wrote in message news:<2r*************@uni-berlin.de>...
In comp.unix.programmer Greg <dj*********@snowboard.com> wrote:
I am trying to implement the UNIX pipe command using C but with the
"->" operator. Everything works fine with 1 pipe, but when I try to
use 2 or more, it hangs up when reading the pipe_in filestream. If


<snipped code because of its length>

What you do in your program for A -> B -> C is basically

1. create a new process running A
2. create a new process running B
3. read input from first process, running A
4. write what you just read to second process, running B
5. kill both processes

and then

6. create a new process running B
7. create a new process running C
8. read input from third process, running B
9. write what you read to fourth process, running C
10. kill both processes

So its roughly as if you would write on the command line
A | B; B | C


And, of courrse, that's not a pipe at all. There are two processes
running B that are completely independent of each other. But with
a pipe you would have only a single one in the middle, getting the
output of the process running A and its output being fed to the
third process. running C. So your program can't work because the
second instance of a process running B has nothing to output since
it never gets any input - that went to the first B process and the
output of that was simply thrown away.

You can't implement what you try to do with jsut popen(). At least
for B you need to manually fork() and exec() a new process with its
standard input _and_ output redirected to be able to both send data
to it and read them simultaneously (popen() allows this only for
either stdin or stdout redirected, but not both).

Another thing with your program that's not working is your use of
feof(). This function only returns something meaningful _after_
you have read from a FILE*, i.e. its purpose is to find out why
a previous read failed (or returned less than expected). You can't
use it to figure out if the next read would fail because of EOF,
that's not what it's meant for and so it must not be called before
you have tried to read something.
Regards, Jens


Thanks for your quick response!

Would I be able to store the output of the process B to a temporary
FILE * variable and return that, and then call the function
redirecting this temporary variable into the next process in the pipe?

Or would an alternative be to write the function differently for the
2nd, 3rd, and 4th pipes using the temporary FILE *?
Nov 14 '05 #4
On Wed, 29 Sep 2004 11:43:44 +0000, Greg wrote:
Thanks for your quick response!

Would I be able to store the output of the process B to a temporary
FILE * variable and return that, and then call the function
redirecting this temporary variable into the next process in the pipe?

Or would an alternative be to write the function differently for the
2nd, 3rd, and 4th pipes using the temporary FILE *?


Maybe the best way to do it would be recursevly. so if you have A -> B ->
C you parse it as (A -> B) -> C. That means when someone calls your
Programm as A -> B -> C it will call itself with A -> B and then pass the
result of this proces to C. This recursion makes it a lot simpler,
although you'll have to spawn a lot of processes when the chain becomes
longer.

Till
--
Please add "Salt and Peper" to the subject line to bypass my spam filter

Nov 14 '05 #5
In comp.unix.programmer Greg <dj*********@snowboard.com> wrote:
Would I be able to store the output of the process B to a temporary
FILE * variable and return that, and then call the function
redirecting this temporary variable into the next process in the pipe?


The problem is that, as long as you insist on using popen() you
won't get at the output from B. popen() only allows to redirect
either stdin or stdout, so if you use popen() for sending data
into the B you have no way to get at the data it outputs and that
you would have to pass on to C. Redirecting the output of B
into a temporary file and then start C with its input redirected
to that file is only a rather awkward solution. It would be
basically be following command in the shell

A | B > tmp_file; C < tmp_file; rm tmp_file

And you would have to create another temporary file for each
further process in the chain of programs. So why not using real
pipes the OS is supplying you with?

The basic steps are

1. Create a pipe, using pipe(2)
2. fork(2) and in the child process close the read end side of
the pipe and redirect STDOUT_FILENO to the write end side,
using e.f. dup2(2).
3. exec(2) the program A in the child.

Back to the parent process:

4. Close the write end side of the pipe
5. Create another pipe
6. fork() and in the new child redirect STDIN_FILENO to the read
of the first pipe. Close the read end of the second pipe and
redirect STDOUT_FILENO to its write end.
7. exec(2) the program B in the new child.

And again back to the parent process:

8. Close the read end of the first and the write end side of the
second pipe
7. Create another child using fork.
8. In the child redirect STDIN_FILENO to the read end side of the
second pipe.
9. exec(2) the program C in the new child.

And, finally again in the parent

10. close the read end side of the second pipe.

That's more or less what the shell does when you create pipes
from the command line. What is done in the first and the third
section is basically what popen() can do for you. What you don't
get from popen() is what happens in the middle section. And if
you need more than 1 process in the middle you have to repeat
that section for each of the processes, i.e. if you want to have

A | B | C | D | E

you need that middle section for B, C and D.

Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #6
Je***********@physik.fu-berlin.de wrote an off-topic response to an
off-topic question in clc:

[snip]

Please keep your postings on this subject in comp.unix.programmer and
out of comp.lang.c. You *do* have an obligation not to perpetuate
conversations that are off-topic in newsgroups to which you post.

[follow-ups set]
Nov 14 '05 #7
Greg wrote wrote an off-topic response to an off-topic question in clc:

[snip]

Please keep your postings on this subject in comp.unix.programmer and
out of comp.lang.c. You *do* have an obligation not to perpetuate
conversations that are off-topic in newsgroups to which you post.

[follow-ups set]
Nov 14 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Gandalf | last post by:
Hi All! I don't know if this is a Python problem or not. Here is a snippet: import os TERM='\n\r\n\r' cmd = 'cu -l /dev/cuaa0 -s9600' pop = os.popen4(cmd,1) pop.write('AT'+TERM) # Ping modem
5
by: richard | last post by:
I have a simple test to pass information from a client to a server using named pipe. what I really want is: when I type a line on the client, the server will output the line immediately. but to my...
2
by: Xah Lee | last post by:
Python Doc Problem Example: os.system Xah Lee, 2005-09 today i'm trying to use Python to call shell commands. e.g. in Perl something like output=qx(ls) in Python i quickly located the...
1
by: Jon | last post by:
Hi there. I'm trying to create a query (or two) that I can use to produce a spreadsheet but I'm having a bit of trouble. I'm using Access 2000. My db is set up like this: Table1: Intrusive...
2
by: Jwhal | last post by:
I'm having trouble querying one table with multiple entries. I'm not sure if or what kind of joins I need to do this, or if it should be a make table followed by an append, then an update, or what....
0
by: Stewart Midwinter | last post by:
I have a Tkinter app running on cygwin. It includes a Test menu item that does nothing more than fetch a directory listing and display it in a Toplevel window (I'd use a tkMessageBox showinfo...
2
by: Dhika Cikul | last post by:
Hello, I'm new in Python, i don't know my subject is correct or wrong. I have problem with my script. I want to change password with passwd password in python without user submitted anything...
3
by: Rob Hoelz | last post by:
Hello everyone, I've been trying to roll my own popen(), but I've run into problems. Would anyone care to look at my code and tell me what I'm doing wrong? Here's my code: #include...
10
by: krustymonkey | last post by:
I'm wondering if anyone can help with a workaround for a problem I currently have. I'm trying to set up a prefork tcp server. Specifically, I'm setting up a server that forks children and has them...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.