I'm currently having a problem with the third process because it wont work every time when I run the program. And suggestions with the exit() part because is printing multiple child process! Any suggestions?
I would really APPRECIATE it a lot!
main(){
pid_t son;
int i;
for (i=0; i<3; i++){
switch (i){
case 0:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
}else{
wait(NULL);
printf("Child process completed!");
//exit(0);
}
case 1:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
}else{
wait(NULL);
printf("Child process completed!");
//exit(0);
}
case 2:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/wc","wc","wctrial.txt", NULL);
}else{
wait(NULL);
printf("Child process completed!");
//exit(0);
}
}
}
At least I don't see the break at the end of the each case.
In the case of 0 the program will run through all of your cases.
Actually break is the problem that if case 1 execute then 2,3 also will.(but this is not problem that wc not working)
Why wc is not working ?
Because of path of wc command!
In your system path for wc may not is: "/bin/wc"
Search tha path of wc command in your system like:
:~$ whereis wc
wc: /usr/bin/wc
and change
execlp("/bin/wc","wc","wctrial.txt", NULL);
^
as
execlp("/usr/bin/wc","wc","wctrial.txt", NULL);
^
// actually not exactly this but one that appears in your system.
Give it a try!!
Below are my suggestion ,
1st) suggestion would be the clean-up of child process once it is
done, as below,
}else if (son == 0){
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
_exit(0);
}
2nd) do break after each switch statement
3rd) and also validate the path of executable by using "whereis"
command before feeding into execlp routine.
Related
I have the following code:
pid_t childProcessID;
childProcessID = fork();
if (childProcessID == -1) {
printf("fork failed");
exit(EXIT_FAILURE);
}
if (childProcessID == 0) {
printf("reached child\n");
close(STDOUT_FILENO);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
printf("about to execute child command\n");
if (fork() == 0) {
execve(argv1[0], argv1, NULL);
printf("Command not found.");
exit(1);
}
else {
wait(NULL);
}
}
else {
printf("reached parent, but wait for child to finish\n");
waitpid(childProcessID, &child_status, NULL);
printf("child finished\n");
close(STDIN_FILENO);
dup2(fd[0], 0);
close(fd[1]);
printf("About to executed piped command\n");
if (fork() == 0) {
execve(argv2[0], argv2, NULL);
printf("Command not found");
exit(1);
}
else {
wait(NULL);
}
}
When I run my minishell and give it the input nl parse.c | wc -l, My minishell prints out:
reached parent, but wait for child to finish
reached child
And nothing underneath. The program is clearly still running but nothing is being printed. Why is my child not executing the rest of the code? argv1[] and argv[2] are initialized and work fine.
When you do :
dup2(fd[1], STDOUT_FILENO)
This code tells the process to redirect its STDOUT: Standard Output, i.e. the print commands and everything that gets printed on terminal to file descriptor fd[1].
So your child process executes and prints everything as it is supposed to,but not on the terminal. To see the output on terminal, comment the line :
//dup2(fd[1], STDOUT_FILENO)
I'm trying to write a program in C that creates 2 child processes with each one of them executing an execvp.
My problem is that the first child writes too much input into the pipe from which the other child reads.
int main(int argc, char* argv[]){
//unnamed pipe
int pipeFd[2], statusFirst,statusSecond;
pid_t childPidOne,childPidTwo;
if(pipe(pipeFd) < 0){
perror("Pipe error:\n");
exit(EXIT_FAILURE);
}
switch(childPidOne = fork()){
case -1:
perror("First Fork error:\n");
exit(EXIT_FAILURE);
case 0:
printf("First child\n");
close(pipeFd[1]);
if( (execvp(argv[1], &argv[1])) < 0){
perror("First execvp error:\n");
}
printf("End First cild\n");
exit(0);
default:
//Do nothing
break;
}
switch(childPidTwo = fork()){
case -1:
perror("Second Fork error:\n");
exit(EXIT_FAILURE);
case 0:
printf("Second cild\n");
close(pipeFd[0]);
if( (execvp(argv[3], &argv[3])) < 0){
perror("Second execvp error:\n");
}
printf("End Second cild\n");
exit(0);
default:
//Do nothing
break;
}
close(pipeFd[0]);
close(pipeFd[1]);
if( (waitpid(childPidOne,&statusFirst,WUNTRACED | WCONTINUED)) < 0 ){
perror("First waitpid error:\n");
}else{
if (WIFEXITED(statusFirst)) {
printf("First exited, status=%d\n", WEXITSTATUS(statusFirst));
} else if (WIFSIGNALED(statusFirst)) {
printf("First killed by signal %d\n", WTERMSIG(statusFirst));
} else if (WIFSTOPPED(statusFirst)) {
printf("First stopped by signal %d\n", WSTOPSIG(statusFirst));
} else if (WIFCONTINUED(statusFirst)) {
printf("First continued\n");
}
}
if( (waitpid(childPidTwo,&statusSecond,WUNTRACED | WCONTINUED)) < 0 ){
perror("Second waitpid error:\n");
}
if (WIFEXITED(statusSecond)) {
printf("Second exited, status=%d\n", WEXITSTATUS(statusSecond));
} else if (WIFSIGNALED(statusSecond)) {
printf("Second killed by signal %d\n", WTERMSIG(statusSecond));
} else if (WIFSTOPPED(statusSecond)) {
printf("Second stopped by signal %d\n", WSTOPSIG(statusSecond));
} else if (WIFCONTINUED(statusSecond)) {
printf("Second continued\n");
}
exit(0);
return 0;
}
Maybe I have a wrong understanding of how pipe + fork + execvp work so let me tell you what I'm doing in my code:
I create an unnamed pipe - both childs use the same pipe
I'll create two childs by forking them
Since I execute my program like this: ./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL] or just to give you an example:./pipeline echo Hello | wc -m I close the reading site of the pipe
And then call execvp(argv[1], &argv[1])
And this is where the error happens (I guess):
I am never closing the writing side until the second child does because execvp will never return if it succeeds.
And I know that execvp will not close open file descriptors ( it can be closed by using a flag in fcntl as mentioned in What does the FD_CLOEXEC flag do? ).
Example
Let me give you an example.
echo Hello | wc -m
outputs the result
6
Because the system call wc (word count) counts the characters (-m) in a given String
That is correct because hello = 5 + 1 (which is \n or \0 I guess) and that makes 6.
Now, running my program gives the result
56
Or to get more information
echo hello | wc
outputs
1 (line) 1 (word) 6 (characters)
And ./pipeline echo hello | wc
outputs
3 (lines) 9 (word) 56 (characters)
I've searched for days but I can't figure it out.
Any ideas?
Thanks a lot!
Solved it myself.
Forgot to use dup2.
Just type the dup2 command after the close command and you will be fine.
I am using pipe fork and exec, to implement a generic pipe for any two shell programs. I am specifically using ls | grep to test it. It works, the data gets copied over to grep, grep searches for matches and then outputs them to stdout. However after that the program just hangs.
This is my code that is executed when a pipe is detected. I fork, and then fork again because I wish to have the parent process of the first fork continue to run after the exec calls. I believe due to debug code that after the exec() call that executes grep is made that nothing is happening.
if(pipeFlag == 1){
pipe(fd);
PID = fork();
if (PID == 0){//child process
fPID = fork();
if(fPID == 0){//child of child
printf("in child of child\n");
dup2(fd[1], 1);
execvp(command, argv);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(fPID > 0){//parent of 2nd child
printf("in parent of 2nd child\n");
dup2(fd[0], 0);
execvp(command1, argv1);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
if(PID > 0){//parent
wait(PID, 0, 0);
printf("in outer parent\n");
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
Below is my solution to the problem. I'm not sure if it's a permanent solution. I'm not even 100% sure if my reasoning for why this works and the previous code did not isn't. All I did was switch the command that is waiting for input from the pipe(grep) to the parent process, and the command writing output to the pipe(ls) to the child process.
My reasoning for why this works is thus: I was testing with ls | grep, ls was finished writing to the pipe before grep's child process ever got set up, and therefore never closed the pipe and grep never received EOF. By changing their position grep was ready and waiting for ls to write by the time the process running ls is set up. I believe that this is a very imperfect fix, so for anyone who reads this in the future, I hope you can provide a better answer. There are a number of conditions I can think of where this could still mess up, if my reasoning for why it works is correct.
if(pipeFlag == 1){
pipe(fd);
PID = fork();
if (PID == 0){//child process
fPID = fork();
if(fPID == 0){//child of child
printf("in child of child\n");
dup2(fd[0], 0);
execvp(command1, argv1);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(fPID > 0){//parent of 2nd child
printf("in parent of 2nd child\n");
dup2(fd[1], 1);
execvp(command, argv);//needs error checking
printf("mysh: %s: command not found\n", argv[0]);
exit(EXIT_FAILURE);
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
if(PID > 0){//parent
wait(PID, 0, 0);
printf("in outer parent\n");
}
if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
}
I need some help here. I need to execute all three execlp() once I run the program but what happen is that only case 0 is executed.I changed pid to 1 and case1 gets executed and so on. Tried putting it in a for loop but does not work. I changed break to continue but still the same - only one process is executed. Any suggestions?
main(){
pid_t pid;
pid= fork();
int i;
if(pid==0){
for (i=0; i<3; i++){
switch (i){
case 0:
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
break;
case 1:
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
break;
case 2:
execlp("/bin/wc", "wctrial.txt", NULL);
break;
}
}
}else{
wait(NULL);
printf("Child process completed!");
exit(0);
}
}
According to man execlp:
The exec() family of functions replaces the current process image with a new process image.
(emphasis is mine)
Therefore, once you called successfully execlp, the process doesn't re-execute the old code.
case 0:
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
/* shouldn't go here */
break;
If you want to execute the three programs, you can create three processes. For instance (loops unrolled):
pid_t son;
son = fork();
if (son == -1) /* report */
else if (son == 0) execlp("/bin/cat", "cat", "wctrial.txt", NULL);
else wait(NULL);
son = fork();
if (son == -1) /* report */
else if (son == 0) execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
else wait(NULL);
/* ... */
See also Kirilenko's answer. The solution is to use system(..) instead of execlp(..).
Man page here.
Can anyone tell me what's wrong with this? I'm still a newbie with forking. The computer executes the 1st and 2nd but the 3rd which is wc doesn't work. Need help badly. The terminal returns multiple child process completed but no wc.
pid_t son;
int i;
for (i=0; i<=3; i++){
switch (i){
case 0:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
exit(0);
}else{
wait(NULL);
printf("Child process completed!");
}
case 1:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
exit(0);
}else{
wait(NULL);
printf("Child process completed!");
}
case 2:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
printf("Work!");
execlp("usr/bin/wc","wc","-w","wctrial.txt", NULL);
exit(0);
}else{
wait(NULL);
printf("Work!");
printf("Child process completed!");
exit(0);
}
}
}
}
Since feature requests to mark a comment as an answer remain declined, I copy the above solution here.
You forgot the leading slash in the path. – Joachim Pileborg
"usr/bin/wc" should be "/usr/bin/wc" – Basile Starynkevitch