i have a homework for my university in which i must have a main process and 3 child processes. I must read an expression in the main process from the user and then pass it through an anonymous pipe at p1 process with redirection of standard input. Then i must modify it and pass it with another pipe to p2. Then the same thing happens with p3 with another pipe. Finally i must return the final expression from p3 to main process using another pipe. When i create p1,p2,p3 processes in the main process by calling fork, i use execlp to run the code of each of these process.
What i managed to do until now(apart from each process' logic which was really complicated), is to send the expression of the user from the main process to p1 process. Inside the code of p1 in the main process, i redirected to the input of the p1 to the read end of the first pipe and i successfully read the expression from main process.
My problem is with the other processes. I really got stuck on how to correctly redirect the inputs and outputs of each pipe to communicate with all processes. I really would appreciate any help here.
Thank you in advance.
in this EXAMPLE you can see the execlp() function and the fork() function:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
pid_t pid;
char *pathvar;
char newpath[1000];
pathvar = getenv("PATH");
strcpy(newpath, pathvar);
strcat(newpath, ":u/userid/bin");
setenv("PATH", newpath);
if ((pid = fork()) == -1)
perror("fork error");
else if (pid == 0) {
execlp("newShell", "newShell", NULL);
printf("Return not expected. Must be an execlp error.n");
}
}
Here you can see how to make a pipe between two process:
/*
“ls -R | grep <pat>” where <pat> is a pattern
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv [])
{
int pipe1[2];
int pid1;
int pid2;
char stringa[100];
pipe(pipe1); // creo la pipe
if((pid1=fork())==0)
{
close(pipe1[0]);
dup2(pipe1[1],1);
close(pipe1[1]);
execlp("ls","ls","-R",NULL);
}
if((pid2=fork())==0)
{
close(pipe1[1]);
dup2(pipe1[0],0);
close(pipe1[0]);
execlp("grep","grep",argv[1],NULL);
}
close(pipe1[0]);
close(pipe1[1]);
waitpid(pid1,NULL,0);
waitpid(pid2,NULL,0);
exit(0);
}
From your description I think you want to chain forking. E.g. instead of having main fork three times to create p1, p2 and p3, instead let main fork once to create p1, then let p1 fork once to create p2 which also forks once to create p3.
Related
This question already has answers here:
Pipe two or more shell commands in C using a loop
(1 answer)
Implementation of multiple pipes in C
(6 answers)
Combining two commands with a pipe
(1 answer)
Connecting n commands with pipes in a shell?
(2 answers)
Closed 18 days ago.
I need to create a program that execute in the shell this command with two pipes and three process: ls | sort | grep r. The code I have done is this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#define WRITE 1
#define READ 0
int main(int argc, char** argv)
{
int fd1[2],fd2[2];
pid_t pid1,pid2;
if( (pid1 = fork()) < 0)
{
perror("fork");
exit(-1);
}
if( pipe(fd1) < 0)
{
perror("pipe 1");
exit(-1);
}
if( pipe(fd2) < 0)
{
perror("pipe 2");
exit(-1);
}
if( pid1 == 0 )
pid2 = fork();
if(pid1>0)
{
close(fd2[READ]);
close(fd2[WRITE]);
close(fd1[READ]);
dup2(fd1[WRITE],STDOUT_FILENO);
close(fd1[WRITE]);
execlp("ls","ls",NULL);
perror("ls");
exit(-1);
}
if(pid2>0)
{
close(fd1[WRITE]);
dup2(fd1[READ],STDIN_FILENO);
close(fd1[READ]);
close(fd2[READ]);
dup2(fd2[WRITE],STDOUT_FILENO);
close(fd2[WRITE]);
execlp("sort","sort",NULL);
perror("sort");
exit(-1);
}
if(pid2==0)
{
close(fd1[READ]);
close(fd1[WRITE]);
close(fd2[WRITE]);
dup2(fd2[READ],STDIN_FILENO);
close(fd2[READ]);
execlp("grep","grep","r",NULL);
perror("grep");
exit(-1);
}
}
Probably I have wrong with the communication with this two pipe because I'm learning how they works only today. So sorry If I wrong some important thing about pipe. I hope if somebody that can help me with this and explain what I wrong. Thanks.
You created the pipes after the 1st fork (but before the 2nd).
Which means that you called pipe 4 times, 2 times in each process that exist after the 1st fork.
So fd1 and fd2 have one set of values for main process (the one for which pid1>0, aka the one that executes ls), and another for the child and grandchild processes (the 2nd fork is done after the creation of the pipes, so no problem here: the two processes that executes sort and grep do share the same file descriptors).
So for the sort | grep part, no problem. The output of sort is fd2[1], while the input of grep is fd2[0], as you want, fd2 being the result of the same pipe call, that was executed before the 2nd fork, and therefore shared between those 2 processes.
But for the ls | sort part, what you are doing is exactly as if you did something like
if(fork()){
int fd[2];
pipe(fd);
close(fd[0]);
dup2(fd[1], 1);
printf("Hello\n");
exit(0);
}else{
int fd[2];
pipe(fd);
close(fd[1]);
dup2(fd[0], 0);
char s[100];
scanf("%s", s);
printf("Should be hello=%s\n", s);
exit(0);
}
Wouldn't work as expected. There is no relationship whatsoever between the fd of the two processes.
So you need to create the pipes before the fork.
At least, the pipes that you intend to share among the processes that will be created by this fork.
I think I know why you did this strange thing. Because of another caveat with 3 process pipe chain: we often see people creating all their pipe before forking twice, having problem making their code work. For another reason: they usually forget that their pipe exist in 3 process, and they need to close all those they don't use. Even in processes that have nothing to do with fd1, both end of fd1 must be closed.
Edit:
Another strange thing you did, is closing even fd1[WRITE] even in the process where you want to use it (just after dup2). You can't do that. It is not like after dup2 you can close the original pipe because you would have a copy, or something like that. It is a copy of a descriptor to the same file. If you close the file, it is closed for the copy too.
A rewrite of your code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#define WRITE 1
#define READ 0
int main(int argc, char** argv)
{
int fd1[2], fd2[2];
pid_t pid1,pid2;
if( pipe(fd1) < 0)
{
perror("pipe 1");
exit(-1);
}
if( (pid1 = fork()) < 0)
{
perror("fork");
exit(-1);
}
if( pid1 == 0 ){
if( pipe(fd2) < 0)
{
perror("pipe 2");
exit(-1);
}
pid2 = fork();
}
if(pid1>0)
{
// I need to close fd1[READ] that I don't use (and that "sort" will use)
// I must keep fd1[WRITE] that I use
// I leave fd2[READ/WRITE] alone, since that variable is unitialized here (I've called "pipe(fd2)" only in the case
// pid1==0 which it is not here)
close(fd1[READ]);
dup2(fd1[WRITE],STDOUT_FILENO);
execlp("ls","ls",NULL);
perror("ls");
exit(-1);
}
if(pid2>0)
{
// I need to read fd1, but not write it (it is ls that need to write it).
// So before doing anything, I close fd1[WRITE]. Must I must keep the other end, fd1[READ] open
close(fd1[WRITE]);
dup2(fd1[READ],STDIN_FILENO);
// Likewise, I need to write on fd2[WRITE], and have "grep" read on the other end.
// So I close fd2[READ] this side, and keep fd2[WRITE] open
close(fd2[READ]);
dup2(fd2[WRITE],STDOUT_FILENO);
execlp("sort","sort",NULL);
perror("sort");
exit(-1);
}
if(pid2==0)
{
// Last process. It needs to read fd2[READ], that I keep open, and don't need to write on fd2[WRITE] (that is "sort" job)
// so I close fd2[WRITE]
// I don't really case for fd1
// Situation is not exactly symetrical that for 1st process and fd2 tho. Because for 1st process, fd2 what not even initialized.
// While here, even if we don't need it, fd1 has been created by our grandfather. We shared it from our father, that shared it from its father
// So, since we use none of fd1, we need to close both.
close(fd1[READ]);
close(fd1[WRITE]);
close(fd2[WRITE]);
dup2(fd2[READ],STDIN_FILENO);
execlp("grep","grep","r",NULL);
perror("grep");
exit(-1);
}
}
Note that this is not the only solution. I could have created pipe(fd2) unconditionally before even the 1st fork, and then close both fd2[0] and fd2[1] in the "ls" process. That would have been ok too.
The points are:
If you want to write on a fd[1] in a process, and read what have been written, from another process, on fd[0], then those process must share the same fd values, issued by the same pipe call; so pragmatically, that means that pipe(fd) must have been called before the fork that separated those two processes
Don't close the fd?[?] that you use. Even if you use them only through another fd on which you dup2 the fd?[?].
Close any fd?[?] that exist in a process, that is that have been created by a pipe call (you must mentally keep tracks of which process have which fd) and you don't need.
i have run this code and found out that the parent process reads first then child process writes. i want to know why this is happening? Additionally i also want to know how can i use two pipes in this program.i just want the concept, any code will be appreciated.Thanks
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
main()
{
int fd[2];
pid_t childpid;
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
printf("\nChild writes\n\n");
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
printf("parent reads\n\n");
}
return 0;
}
For you queries :-
The parent process reads first then child process writes. i want to know why this is happening?
After fork() both process work independently, so which process will be scheduled first, it's depend on scheduler.
How can i use two pipes in this program?
open two pipe, one for parents and one for child process. because pipe are unidirectional.
int fd[2];
int fd1[2];
parents will write on fd[1] child will read from fd[0]
child will write on fd1[1] parents will read from fd1[0]
I have an app that spawns a child process. That child process outputs information about what it's doing by printing to stdout. The parent process does the same (i.e. prints to stdout).
In the child process I can write to stdout with some text prepended, but I have to add that to every single location I print across many source files.
I thought it might be smarter to have the parent process prepend output from the child process that it forks/exec's. I don't want to redirect the output because seeing the output inline with the parent process is beneficial. How do I do this? I'm using fork/exec in the parent.
Do I have to read the output and prepend each line manually or is there a simpler approach?
Update:
Thanks to Barmar. Here is how I'm doing it. I also could read byte by byte in the parent process from the pipe until line end. But I chose not to use that approach for reasons of complexity in my single threaded lua+C app.
// Crude example of output filtering using sed to
// prepend child process output text
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <libgen.h>
#include <string.h>
pid_t spawn(int fd[2], const char* path)
{
printf("Create child\n");
pid_t pid = fork();
switch(pid){
case -1:
printf("Create process failed");
return -1;
case 0:
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execl(path, path, NULL);
return 0;
default:
return pid;
}
}
pid_t spawnOutputFilter(int fd[2])
{
printf("Create sed\n");
pid_t pid = fork();
switch(pid){
case -1:
printf("Create sed failed");
return -1;
case 0:
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execlp("sed", "sed", "s/^/Engine: /", (char *)NULL);
return -1;
default:
return pid;
}
}
int main(int argc, char* argv[])
{
if (argc > 1){
int options;
int fd[2];
pipe(fd);
pid_t pid = spawn(fd, argv[1]);
pid_t sed_pid = spawnOutputFilter(fd);
close(fd[0]);
close(fd[1]);
waitpid(pid, NULL, 0);
waitpid(sed_pid, NULL, 0);
}
return 0;
}
You could create a second child process that performs
execlp("sed", "sed", "s/^/PREFIX: /", (char *)NULL);
Connect the first child's stdout to this process's stdin with a pipe.
I thought it might be smarter to have the parent process prepend output from the child process.
I guess it depends on how you judge "smart". It might be simpler to just make the child prepend the desired text to its outputs.
I don't want to redirect the output because seeing the output inline with the parent process is beneficial. What's the best way to do this?
When two processes share an open file, both access it independently, regardless of the nature of the relationship between those processes. Thus, if your child inherits the parent's stdout, the parent has no mechanism even to notice that the child is sending output, much less to modify that output.
If you want the parent to handle this, you would need to pass the child's output through the parent. You could do that by creating a pipe, and associating the child's stdout with the write end of that pipe. The parent would then need to monitor the read end, and forward suitably-modified outputs to its own stdout. The parent would probably want to create a separate thread for that purpose.
Additionally, if the child sometimes produces multi-line outputs that you want prefixed as a group, rather than per-line, then you'd probably need to build and use some kind of protocol for demarcating message boundaries, which would make the whole parent-moderation idea pretty pointless.
Couldn't you define #define printf(a) printf("your text:" a).
Other alternative I can think of is using dup
You open the same log file in your child process and dup your stdout to new file descriptor.
I'm having problems understanding the right use of the pipe in UNIX Systems.
I have a main process which create a child process. The child process must run a different program from the father, he has to make some operation and then the child must communicate to the father the results.
However in the child process I have to print on the terminal the partial results of these operations.
I'm trying with a test program to do so, but I'm a bit stuck right now. This is the main test program
TEST.C
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int mypipe[2];
pid_t pid;
char readbuffer[6];
pipe(mypipe);
if((pid = fork()) == 0){
close(mypipe[0]);
dup2(mypipe[1], STDOUT_FILENO);
execlp("./proc", "./proc", NULL);
} else {
wait(-1);
close(mypipe[1]);
read(mypipe[0], readbuffer, sizeof(readbuffer));
printf("%s", readbuffer);
}
}
And the c file of the ./proc program is this:
PROC.C
#include <stdio.h>
int main(int argc, char* argv[]){
printf("check\n");
return 0;
}
With this solution, the proc program can't print anything on the terminal. How do I make the proc program to print on the terminal AND on the pipe so the main program can read from there???
Thank you!
Even when you redirect stdout to the parent program, you can still use stderr. Just call fprintf(stderr, ...) instead of printf(...) when you want to print to the console.
If you want your "proc" program to print in terminal for log/debug infos, u can use fprintf and stderr:
fprintf(stderr, "What you need to print\n");
You can also see where your program is writing, use strace
My question sounds the same as this but it isn't:
Start a process in the background in Linux with C
I know how to do fork() but not how to send a process to the background. My program should work like a simple command unix shell that supports pipes and background processes. I could do pipe and fork but I don't know how to send a process to the background with & like the last line of the program:
~>./a.out uname
SunOS
^C
my:~>./a.out uname &
How to achieve the background process?
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define TIMEOUT (20)
int main(int argc, char *argv[])
{
pid_t pid;
if(argc > 1 && strncmp(argv[1], "-help", strlen(argv[1])) == 0)
{
fprintf(stderr, "Usage: Prog [CommandLineArgs]\n\nRunSafe takes as arguments:\nthe program to be run (Prog) and its command line arguments (CommandLineArgs) (if any)\n\nRunSafe will execute Prog with its command line arguments and\nterminate it and any remaining childprocesses after %d seconds\n", TIMEOUT);
exit(0);
}
if((pid = fork()) == 0) /* Fork off child */
{
execvp(argv[1], argv+1);
fprintf(stderr,"Failed to execute: %s\n",argv[1]);
perror("Reason");
kill(getppid(),SIGKILL); /* kill waiting parent */
exit(errno); /* execvp failed, no child - exit immediately */
}
else if(pid != -1)
{
sleep(TIMEOUT);
if(kill(0,0) == 0) /* are there processes left? */
{
fprintf(stderr,"\Attempting to kill remaining (child) processes\n");
kill(0, SIGKILL); /* send SIGKILL to all child processes */
}
}
else
{
fprintf(stderr,"Failed to fork off child process\n");
perror("Reason");
}
}
The solution in plain English appears to be here:
How do I exec() a process in the background in C?
Catch SIGCHLD and in the the handler, call wait().
Am I on the right track?
Q: How do I send a process to the background?
A: In general, exactly what you're already doing: fork()/exec().
Q: What's not working as you expect?
I suspect maybe you also want a "nohup" (to completely disassociate the child from the parent).
The key to doing this is to run "setsid()" in the child process:
How to use fork() to daemonize a child process independant of it's parent?
http://www.enderunix.org/docs/eng/daemon.php