Link to home
Start Free TrialLog in
Avatar of r5ur5
r5ur5

asked on

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!!
Avatar of Kent Olsen
Kent Olsen
Flag of United States of America image


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
Avatar of r5ur5
r5ur5

ASKER

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

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

https://www.experts-exchange.com/questions/20670632/How-can-I-call-command-line-and-send-data-to-and-get-output-text-from-it-from-within-a-C-C-program.html


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

Kent
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.
Avatar of r5ur5

ASKER

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!! :-)
SOLUTION
Avatar of mtmike
mtmike

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of r5ur5

ASKER

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