• C

Piping between processes

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!!
r5ur5Asked:
Who is Participating?
 
Kent OlsenConnect With a Mentor Data Warehouse Architect / DBACommented:

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
 
Kent OlsenData Warehouse Architect / DBACommented:

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
 
r5ur5Author Commented:
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
Managing Security & Risk at the Speed of Business

Gartner Research VP, Neil McDonald & AlgoSec CTO, Prof. Avishai Wool, discuss the business-driven approach to automated security policy management, its benefits and how to align security policy management with business processes to address today's security challenges.

 
Kent OlsenData Warehouse Architect / DBACommented:

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
 
mtmikeCommented:
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
 
r5ur5Author Commented:
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
 
mtmikeConnect With a Mentor Commented:
> 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
 
r5ur5Author Commented:
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
 
nsuresh_rasr1Commented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.