Solved

Piping between processes

Posted on 2003-10-28
9
714 Views
Last Modified: 2008-02-01
Hi,

I'm a novice at C Programming in Unix and need to do a project where I have to execute the command ps -ef | grep username | wc -l to do this I have to write a C code in unix that creates a separate process for each of the commands and then pipes the input and output.

The requirement is that a parent spawns a child process which then spawns another child process. The last child process will execute ps -ef and pass output via pipe to its parent which will execute grep username on the output received and then pass the result to the original parent process which will run wc -l on the results received and output a number on the screen.

Here is what I have so far, the code compiles but I get no output. Please help!!!

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

int pipe_a[2];
int pipe_b[2];

void closeall()
{
        close(pipe_a[0]);
        close(pipe_a[1]);
        close(pipe_b[0]);
        close(pipe_b[1]);
}

int main()
{
        pipe(pipe_a);
        pipe(pipe_b);

        if (!fork())
        {
                dup2(pipe_a[1], 1);
                closeall();
                execl"wc", "-l", 0);
        }
        else if (!fork())
        {
                dup2(pipe_a[0], 0);
                dup2(pipe_b[1], 1);
                closeall();
                execl("grep", "root", 0);
        }
        else
        {
                dup2(pipe_b[0], 0);
                closeall();
                execl("ps", "-ef", 0);
        }

        // never gets here
        return 0;
}

Thanks!!
0
Comment
Question by:r5ur5
[X]
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
  • 3
  • 3
  • 2
  • +1
9 Comments
 
LVL 45

Expert Comment

by:Kent Olsen
ID: 9635607

Hi r5ur5,

Just because you've opened the pipe doesn't mean data is flowing up and down it.  You still have to read/write the pipe.

You  might also look at popen() to execute the command and pipe the output back to the parent task.


Kent
0
 

Author Comment

by:r5ur5
ID: 9635832
Hi Kent,

Thanks for such a quick response, can you please point out to me where I need to implement read/write I've gone insane in trying to figure this out. Also, how would I know for sure that the last child is the one implementing ps -ef and then its parent executes the grep cmd and then the orginial parent process initiates its wc  command?

r5ur5
0
 
LVL 45

Expert Comment

by:Kent Olsen
ID: 9635902

There was a good discussion of piping over at this thread:

http://www.experts-exchange.com/Programming/Programming_Languages/C/Q_20670632.html


It's probably easier to read it first, then sort out the questions.

Kent
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Expert Comment

by:mtmike
ID: 9636052
Code structure is basically ok, but you're not using the system calls entirely right.

The execl() function expects an absolute path. So 'execl("/bin/ps", ...)' will work but 'execl("ps", ...) will not. Use execlp() if you want the system to search for the file. Also, the first argument parameter should be the executable name as in 'execlp("ps", "ps", "-ef", 0)'.

The fork call returns the pid of the forked child in the parent and zero in the child or -1 on error. The test '!fork()' means 'Is this the child?'. You want to execute "wc" in the original parent.

When creating a pipe, p[0] is for reading and p[1] is for writing. Just like stdin (0) is for reading and stdout (1) is for writing.

I don't think you need to use read/writes, the spawned processes will do that for you.
0
 

Author Comment

by:r5ur5
ID: 9636340
Mtmike,

Thanks for the response, I have made some changes to the code now its compiling as before and showing some ouput as well. The output is however that of "ps -ef". Here is the modified version I hope this makes some sense.

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

int pipe_a[2];
int pipe_b[2];

void closeall()
{
        close (pipe_a[0]);
        close (pipe_a[1]);
        close (pipe_b[0]);
        close (pipe_b[1]);
}

int main()
{
        int pid_in;
        pipe(pipe_a);
        pipe(pipe_b);

        if ((pid_in = fork()) !=0)
        {
                dup2(pipe_a[1], 1);
                closeall();
                execlp("wc", "wc", "-l", 0);
        }
        else if ((pid_in = fork()) !=0)
        {
                dup2(pipe_a[0], 0);
                dup2(pipe_b[1], 1);
                closeall();
                execlp("grep", "grep", "root", 0);
        }
        else
        {
                dup2(pipe_b[0], 0);
                closeall();
                execlp("ps", "ps", "-ef", 0);
        }

        return 0;
}

The fork() call is working fine, the original PPID is 1164 which spawns the Parent with ID 1411 (wc -l) and that spawns the child PID 1412 (grep root) and that spawns the child 1413 (ps -ef) however the output that comes on screen is that of ps -ef and gets stuck after the last line until I do a Ctrl-C to kill the program.

Thanks for all the help!! :-)
0
 
LVL 5

Assisted Solution

by:mtmike
mtmike earned 250 total points
ID: 9636431
> When creating a pipe, p[0] is for reading and p[1] is for writing. Just like stdin (0) is for reading and stdout (1) is for writing.

Swap all the 0/1s in the dup2 calls:

        if ((pid_in = fork()) !=0)
        {
                dup2(pipe_a[0], 0);
                closeall();
                execlp("wc", "wc", "-l", 0);
        }
        else if ((pid_in = fork()) !=0)
        {
                dup2(pipe_a[1], 1);
                dup2(pipe_b[0], 0);
                closeall();
                execlp("grep", "grep", "root", 0);
        }
        else
        {
                dup2(pipe_b[1], 1);
                closeall();
                execlp("ps", "ps", "-ef", 0);
        }

Should work then.
0
 
LVL 45

Accepted Solution

by:
Kent Olsen earned 250 total points
ID: 9636528

Hi r5ur5,

I don't know where my head was when I first replied.  My apologies, I didn't explain at all.


But you still have the same problem that you had originally.  The pipes aren't being read/written because execl() overlays (replaces) the current task with the command that you want to execute, which doesn't know anything about the pipes that you've set up.  The pipes get "hung" and you have to ctrl-C out of the program.


You're only wanting to do I/O in one direction (pipe the data from child 2 to child 1, then pipe its result to the parent) so popen() is easier that pipe().  (You don't have to open and manage a pipe that you have no intention of using.)

Start by removing all of the pipe() and dup2() calls.  The main() function could be something like this:

int main()
{
        if (!fork())
        {
               popen ("wc", "w");
        }
        else if (!fork())
        {
                popen ("grep root", "w");
        }
        else
        {
                popen ("ps -ef", "w");
        }

        // never gets here   (It will now!)
        return 0;
}


Kent
0
 

Author Comment

by:r5ur5
ID: 9637642
Mtmike/kdo,

Both solutions worked for me, thanks a million guys!!! I appreciate your prompt replies on my query.

I'm sure I'll have many more issues in the coming days.

Thanks!
r5ur5
0
 

Expert Comment

by:nsuresh_rasr1
ID: 9639702
Hi,
i too had a problem like this. I would like to give a sample program that would be very useful to you & others when u are using 2 or more pipes. It does for last|sort|more. Hope this will be useful to u.

/**************Code*************************/

#include <stdio.h>

main() {

int pipefd[2],pipefd1[2];
int pid,pid1;

pipe(pipefd);
pipe(pipefd1);

if((pid=fork()) < 0) {

perror("fork");
}
if(pid==0) {

close(pipefd[0]);
dup2(pipefd[1],1);
execlp("last","last",(char*)0);
}

if((pid1=fork()) < 0) {
perror("fork");
}

if(pid1 ==0)
{
close(pipefd[1]);
dup2(pipefd[0],0);
close(pipefd1[0]);
dup2(pipefd1[1],1);
execlp("sort","sort",(char*)0);
}

close(pipefd[0]);
close(pipefd[1]);
close(pipefd1[1]);
dup2(pipefd1[0],0);
execlp("more","more",(char*)0);

return 0;
}
any comments mail me,
nsuresh_rasr@yahoo.com

0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

751 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