Solved

Piping between processes

Posted on 2003-10-28
9
676 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
  • 3
  • 3
  • 2
  • +1
9 Comments
 
LVL 45

Expert Comment

by:Kdo
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:Kdo
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
 
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
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

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:
Kdo 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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Picking random number 8 169
memory mapped I/O query 6 137
Describe order of operation while copying text 11 111
Read file descriptor 3 in C 14 102
This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.

757 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

17 Experts available now in Live!

Get 1:1 Help Now