I'm writing a simple pipe program that will ask for two commands then run the programs as if they were entered into bash as cmd1 | cmd2. Then it should loop and ask again until one of the commands is quit.
I've already written this much:
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<signal.h>
using namespace std;
int main(int argc, char *argv[])
{
int pid1, pid2, errchk;
int pip[2];
char cmd1[128];
char cmd2[128];
int i = 0;
int status;
errchk = pipe(pip);//make pipe
if(errchk == -1)//check for error in pipe
{
perror("pipe");
exit(1);
}
while(i<3)
{
i++;
//Enter commands here
cout<<"Enter cmd1: ";
cin>>cmd1;
cout<<"Enter cmd2: ";
cin>>cmd2;
//if a command is quit... quit
if(strcmp(cmd1,"quit")==0 || strcmp(cmd2,"quit") == 0)
{
cout<<"Quitting...\n";
exit(1);
}
pid1 = fork();
cout<<"first fork makes pids: "<<pid1<<endl;
if(pid1 < 0)
{
perror("fork");
exit(1);
}
else if(pid1 == 0) //MAIN CHILD
{
cout<<"In main child with pid: "<<pid1<<endl;
pid2 = fork();
cout<<"second fork makes pids: "<<pid2<<endl;
if(pid2 == 0)//SUB CHILD 2 to run cmd2
{
cout<<"In child of second fork"<<endl;
close(0);
close(pip[1]);
dup(pip[0]);
execvp(cmd2,argv);//execute command2 and die
}
else if(pid2 > 0)//SUB CHILD 1 to run cmd1
{
cout<<"In parent of second fork"<<endl;
close(1);
close(pip[0]);
dup(pip[1]);
execvp(cmd1,argv);//execute command1 and die
}
}
else if(pid1 > 0) //MAIN PARENT
{
wait(NULL);//wait for cmd1
wait(NULL);//wait for cmd2
cout<<"DONE executing"<<endl; //keep going
}
}
return 0;
}
When I run it and enter ls and wc
The output I get is:
Enter cmd1: ls
Enter cmd2: wc
first fork makes pids: 5785
first fork makes pids: 0
In main child with pid: 0
second fork makes pids: 5786
In parent of second fork
second fork makes pids: 0
In child of second fork
DONE executing
5 5 54
The main problem I have is that I should have Done executing come after ls|wc not the other way around.
I'm thinking the wait(NULL) isn't working but I'm not sure.
Please advise.
And Thank you.
You have:
parent
1. child1
2. child2
2. exec()
1. exec()
When you exec in child1, child2 gets reparented to init, and you can no longer wait for child2 to terminate.
So we need to do a little bit of refactoring to get something looking like:
parent
1. child1
1. exec()
2. child2
2. exec()
wait() x 2
Basing this on your own code, with the refactoring to accomplish something like the look-alike code (some comments in-line):
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<signal.h>
using namespace std;
int main(int argc, char *argv[])
{
int pid1, pid2, errchk;
int pip[2];
char cmd1[128];
char cmd2[128];
int status;
while(true)
{
errchk = pipe(pip);//make pipe
if(errchk == -1)//check for error in pipe
{
perror("pipe");
exit(1);
}
//Enter commands here
cout<<"Enter cmd1: ";
cin>>cmd1;
cout<<"Enter cmd2: ";
cin>>cmd2;
//if a command is quit... quit
if(strcmp(cmd1,"quit")==0 || strcmp(cmd2,"quit") == 0)
{
cout<<"Quitting...\n";
exit(1);
}
pid1 = fork();
cout<<"first fork makes pids: "<<pid1<<endl;
if(pid1 < 0)
{
perror("fork");
exit(1);
}
if (pid1 == 0) // in child
{
cout<<"In child of first fork"<<endl;
close(pip[0]); // close read-end of pipe
close(0); // close stdin
close(1); // close stdout
dup2(pip[1], 1); // write-end of pipe is stdout of cmd1
argv[0] = cmd1; // make it look like the command in the ps output
execvp(cmd1,argv);//execute command1 and die
fprintf(stderr, "execvp(1): `%s': %s\n", cmd1, strerror(errno));
return 0;
}
pid2 = fork();
cout<<"second fork makes pids: "<<pid2<<endl;
if (pid2 < 0)
{
perror("fork2");
exit(1);
}
if (pid2 == 0)
{
cout<<"In child of second fork"<<endl;
close(pip[1]); // close write-end of pipe
close(0); // close stdin
dup2(pip[0], 0); // read-end of pipe is stdin of cmd2
argv[0] = cmd2; // update ps output
execvp(cmd2,argv);//execute command2 and die
fprintf(stderr, "execvp(1): `%s': %s\n", cmd2, strerror(errno));
return 0;
}
if(pid1 > 0) //MAIN PARENT
{
// close remaining pipe handles in parent
close(pip[0]);
close(pip[1]);
wait(0);//wait for one command to run
wait(0);//wait for a second command to run
cout<<"DONE executing"<<endl; //keep going
}
}
return 0;
}
Related
I know wait(NULL) waits for all child process to terminate. But while working with fork(),execv()/execvp() and wait(), it seems wait(NULL) is not waiting for all the child processed to terminate.
I was trying to understand the unexpected behaviour of the wait(NULL) system call in my code.
I tried to recreate the same situation with a different but smaller code, it is shown below.
#include <unistd.h>
#include <filesystem>
#include <sys/wait.h>
#include <bits/stdc++.h>
#include <fcntl.h>
using namespace std;
int main ()
{
int pid;
int fd[2];
char command[] = "square";
//constructing a pipe
if(pipe(fd)==-1)
cout<<"Pipe1 Failed";
//first fork
pid = fork();
if(pid<0)
{
cout<<"fork failed";
}
else if(pid == 0)
{
cout<<"inside child 1\n";
close(0);
//opening input file at fd = 0
if(open("input",O_RDONLY) != 0)
cerr<<"Failed input open\n";
//connecting write end of pipe to first child process
dup2(fd[1],1);
close(fd[1]);
close(fd[0]);
char *args[] = {command,NULL};
//calling exec system call
execv(command,args);
cerr<<"execv1 failed\n";
exit(0);
}
//second fork
pid = fork();
if(pid<0)
{
cout<<"fork failed";
}
else if(pid == 0)
{
cout<<"inside child 2\n";
//connecting read end of the pipe to second child process
dup2(fd[0],0);
close(fd[0]);
close(fd[1]);
char *args[] = {command,NULL};
//calling exec system call
execv(command,args);
cerr<<"execv2 failed\n";
exit(0);
}
wait(NULL);
cout<<"After wait\n";
return 0;
}
What this code effectively tries to do is something like ./square < input | ./square in bash. input is a file that contains a number (it was 5 when I ran the code), square is a function that takes an integer input and prints its square (n*n).
The code of square is
#include<stdio.h>
int main()
{
int n;
scanf("%d",&n);
printf("%d",n*n);
return 0;
}
The final output I was expecting is (with input file containing number 5)
inside child 1
inside child 2
625
After wait
But the final output I am getting is
inside child 1
inside child 2
After wait
625
Output image
Can somebody help me figure out what is happening here or where my understanding is wrong.
NOTE: I used g++ compiler to compile this C++ codes.
Thanks in advance.
wait(NULL) doesn't wait for all children to exit. wait(&wstatus) waits for one child, and puts its exit status into the int wstatus. wait(NULL) waits for one child, and ignores its exit status.
Citation: man 2 wait
I wrote a program which stops the time of a child process calling execvp(). The next task is to occasionally stop the child process for a given time and continue it.
pid_t child = fork();
if(child == 0){
// In child process
execvp(); // e.g. sleep 10
} else {
// In parent process
kill(child, SIGSTOP);
// Do stuff
kill(child, SIGCONT);
}
What i think is happening here is, that kill(child, SIGSTOP) is pausing the child process but not the execvp() process within it. Is there a way to get the pid of the execvp() process and stop it directly?
Edit example:
int main(int argsc, char *argv[]) {
int status;
// Fork for processB
pid_t processB = fork();
if (processB == 0) {
system("~/loop.sh");
} else {
for (;;) {
sleep(5);
kill(processB, SIGSTOP);
std::cout << "Should have stopped counting" << std::endl;
sleep(3);
kill(processB, SIGCONT);
// If loop process ended, exit watchDog
if (waitpid(processB, &status, WNOHANG) == processB)
_exit(1);
}
}
return 0;
}
Loop.sh
counter=0;
while :;
counter=$((counter+1));
do echo $counter;
sleep 1;
done
return 0;
I wanted to do this problem but I cannot take input message:
Create a program that does the following:
1.Create a parent and a child process
2.The parent process reads a number from keyboard and sends it to the child
3.The child calculates if the given number is prime or not and prints the result on screen
This is my code:
#include <iostream>
#include <unistd.h> // for fork()
#include <string.h> // for strerror()
#include <sys/wait.h>
#include <sys/types.h>
using namespace std;
bool isprime(int number);
int main()
{
int num;
pid_t pid;
int fd[2];
char buffer[100];
pipe(fd);
pid = fork();
//parent process
if (pid > 0)
{
cin>>num;
write(fd[1], &num, sizeof(num));
close(fd[1]);
int status;
//Do not check for errors here
wait(&status);
}
//child process
else if (pid == 0)
{
read(fd[0], buffer, 100);
close(fd[0]);
if (isprime(num))
{
cout<<"number is prime";
}
else
{
cout<<"number is not prime";
}
return EXIT_SUCCESS;
}
else
{
cout << "fork() failed (" << strerror(errno) << ")" << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
bool isprime(int number)
{
if (number < 2)
return false;
if (number == 2)
return true;
for (int i = 2; (i*i) <= number; i++)
{
// Take the rest of the division
if ((number % i) == 0)
return false;
}
return true;
}
this my result of run
Using a pipe along with fork is not that hard, but you must respect some rules:
each part should close the handle that it does not use. Not doing it is a key for future problems
starting from the fork, changes in one process are not reflected in the other one
Your code should become:
...
//parent process
if (pid > 0)
{
close(fd[0]); // close the part that only the other process will use
cin>>num;
write(fd[1], &num, sizeof(num));
close(fd[1]);
int status;
//Do not check for errors here
wait(&status);
}
//child process
else if (pid == 0)
{
close(fd[1]); // close the part used by the other process
read(fd[0], &num, sizeof(num)); // read into num what the parent has written
close(fd[0]);
...
In real world code, you should check that every read is successfull (both from cin and from the pipe...)
I'm coding a mock shell and I'm currently working on coding pipes with dup2. Here is my code:
bool Pipe::execute() {
int fds[2]; //will hold file descriptors
pipe(fds);
int status;
int errorno;
pid_t child;
child = fork();
if (-1 == child) {
perror("fork failed");
}
if (child == 0) {
dup2(fds[1], STDOUT_FILENO);
close(fds[0]);
close(fds[1]);
this->component->lchild->execute();
_exit(1);
}
else if (child > 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
this->component->rchild->execute();
waitpid(child, &status, 0);
if ( WIFEXITED(status) ) {
//printf("child exited with = %d\n",WEXITSTATUS(status));
if ( WEXITSTATUS(status) == 0) {
cout << "pipe parent finishing" << endl;
return true;
}
}
return false;
}
}
The this->component->lchild->execute(); and this->component->rchild->execute(); run execvp on the corresponding commands. I've confirmed that each of these return by printing out a statement in the parent process. However, in my Pipe::execute(), it seems like the child process does not finish because the cout statement in the parent process is never printed and I get a segmentation fault after the prompt ($) is initialized (see picture). Here is the main function that initializes the prompt after each execution:
int main()
{
Prompt new_prompt;
while(1) {
new_prompt.initialize();
}
return 0;
}
and here is the initialize() function:
void Prompt::initialize()
{
cout << "$ ";
std::getline(std::cin, input);
parse(input);
run();
input.clear();
tokens.clear();
fflush(stdout);
fflush(stdin);
return;
}
It seems like ls | sort runs fine, but then when the prompt is initialized, a blank line is read into input by getline. I've tried using cin.clear(), cin.ignore, and the fflush and clear() lines above. This blank string is "parsed" and then the run() function is called, which tries to dereference a null pointer. Any ideas on why/where this blank line is being entered into getline? and how do I resolve this? Thank you!
UPDATE: The parent process in the pipe is now finishing. I've also noticed that I'm getting seg faults also for my I/O redirection classes (> and <). I think I'm not flushing the stream or closing the file descriptors correctly...
Here is my execute() function for lchild and rchild:
bool Command::execute() {
int status;
int errorno;
pid_t child;
vector<char *> argv;
for (unsigned i=0; i < this->command.size(); ++i) {
char * cstr = const_cast<char*>(this->command.at(i).c_str());
argv.push_back(cstr);
}
argv.push_back(NULL);
child = fork();
if (-1 == child) {
perror("fork failed");
}
if (child == 0) {
errorno = execvp(*argv.data(), argv.data());
_exit(1);
} else if (child > 0) {
waitpid(child, &status, 0);
if ( WIFEXITED(status) ) {
//printf("child exited with = %d\n",WEXITSTATUS(status));
if ( WEXITSTATUS(status) == 0) {
//cout << "command parent finishing" << endl;
return true;
}
}
return false;
}
}
Here is the bug:
else if (child > 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
this->component->rchild->execute();
You are closing stdin for the parent, not just the right child. After this the stdin of the parent process is the same as that of the right child.
After that
std::getline(std::cin, input);
Tries to read the output of the left child, rather than the original stdin. By that point the left child had finished and that end of the pipe had been closed. This makes reading stdin fail, and leave input unchanged in its original state.
Edit: Your design has a minor and a major flaws. The minor flaw is that you don't need the fork in Pipe::execute. The major flaw is that the child should be the one who redirects streams and closes the descriptors.
Simply pass input and output parameters through fork() and let the child dup2 these. Don't forget to make it also close unrelated pipe ends. If you don't, the left child will finish but its output pipe will continue living in other processes. As long as other copies of that descriptor live, the right child will never get EOF while reading its pipe end - and week block forever.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
using namespace std;
//first comannd to execute
void first(int pipeA[], char * command[]){
//redirect STDOUT to pipe[1] and close the pipe[0] we are not using
dup2(pipeA[1], 1);
close(pipeA[0]);
execvp(command[0], command);
printf(" first error ");
exit(127);
}
void second(int pipeA[], char * command2[]){
//redirect STDIN to pipe[0] and close the pipe[1] that we are not using
dup2(pipeA[0], 0);
close(pipeA[1]);
//This doesnt seem to be doing anything at times
execvp(command2[0], command2);
perror(" second error ");
exit(127);
}
int main(void)
{
char buf[1024];
char * command[1024];// this one is the first input usually 'cat file.txt'
//Use only one or the other, sort never works and 'grep U' works sometimes
char * command2[] = {(char *)"sort", (char *) NULL};// this is wants to sort the above 'command[1024]' and its use in the second function
//char * command2[] = {(char *)"grep",(char *)"U",(char *) NULL};// this is wants to grep the above 'command[1024]' and its use in the second function
//variables for forks and waits
pid_t pid;
pid_t pid2;
int status;
int status2;
//see if || exists not in use currently
bool pipeExists = false;
//create pipe
int pipeA[2];
pipe(pipeA);
//first line and ask for input,
cout<< "command: ";
while (fgets(buf,1024,stdin) != NULL)
{
buf[strlen(buf) -1] = 0;
//Save input into buf and tokenized? it
//NOT YET CATCHING ||, im only debugging and usually use use 'cat file.txt'
int number =0;
char * ptr;
ptr = strtok(buf, " ");
while(ptr != NULL){
command[number] = ptr;
ptr = strtok(NULL, " ");
number++;
}
//***************************************************************
//1. do the pipes go here or after the children?
//They seem to be working here but im not really sure where they should be
close(pipeA[0]);
close(pipeA[1]);
//create first child
if ((pid = fork()) <0)
printf("fork error");
else if (pid == 0)
{ /* child */
//create second child INSIDE ORIGINAL CHILD
//2. Is this correct? or is there not supposed to be grandchildren?
if ((pid2 = fork()) <0)
printf("fork 2 error");
else if (pid == 0)
{ /* child */
second(pipeA, command2);
printf("couldn't execute: %s");
exit(127);
}
//first command from buf
first(pipeA, command);
printf("couldn't execute: %s");
exit(127);
//3. Do I wait for this child aswell?
if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
printf("waitpid error");
}
/* parent */
if ( (pid = waitpid(pid, &status, 0)) < 0)
printf("waitpid error");
printf("Command :");
//***************************************************************
//***************************************************************
//SECOND WAY OF DOING IT
// THIS WAY IT TRIGGERS WAITPID ERRORS.
/*
close(pipeA[0]);
close(pipeA[1]);
//create first child
if ((pid = fork()) <0)
printf("fork error");
else if (pid == 0)
{
first(pipeA, command);
printf("couldn't execute: %s");
exit(127);
}
//create second child INSIDE ORIGINAL CHILD
if ((pid2 = fork()) <0)
printf("fork 2 error");
else if (pid == 0)
{
second(pipeA, command2);
printf("couldn't execute: %s");
exit(127);
}
//3. Do I wait for this child aswell?
if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
printf("waitpid error");
if ( (pid = waitpid(pid, &status, 0)) < 0)
printf("waitpid error");
printf("Command :");
*/
//***************************************************************
}
exit(0);
}
Pretty much what the code shows here with its questions.
I need to create a microshell that takes in a command ("cat file.txt") and execute it with execvp() and pipe it to another process and either "sort" or "grep U" or anyother.
It's just that my processes won't run correctly at time or wont display anything. I have closed pipes all over the place and nothing has happen.
Solution by OP.
This is the code that works for microshell.
I ended up with creating two processes in the original parents process.
Moving some variables inside the while loop and resetting them to work again. Also create the pipe everytime the code runs and close the pipes.
Created a waitpid() for both processes not just one.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
using namespace std;
//This function will execute the users first command.
//It takes in a pipe the command array and a boolean to check for piping
//If a pipe exists then the boolean is true and will dup() the STDOUT into the write part of the pipe
//We close unecessary parts of the pipe and execvp() the command in the command array
//there it some error checkink in case the command doesn't execute
void first_command(int pipeA[], char * command[], bool pipeExists){
if(pipeExists){
dup2(pipeA[1], 1);
close(pipeA[0]);
}
execvp(command[0], command);
printf("can not execute first command. \n");
exit(127);
}
//This function is only called in the main is a piping exists
//It takes in a pipe and a command array
//It dup() the STDIN from the read end of the pipe and closes the unsued end
//It will execute the command accorind to what was provided in the the pipe
void second_command(int pipeA[], char * command2[]){
dup2(pipeA[0], 0);
close(pipeA[1]);
execvp(command2[0], command2);
printf("can not execute second command. \n");
exit(127);
}
int main(void)
{
//this variable will take in the line of input submitted by the user
char buf[1024];
//PIDs for the two child processes
pid_t pid;
pid_t pid2;
//these will be use to check the status of each child in the parent process
int status;
int status2;
//initializes the pipe
int pipeA[2];
//out put the first line to ask user for input
cout<< "480shel> ";
//stay inside the loop and keep asking the user for input until the user quits the program
while (fgets(buf,1024,stdin) != NULL){
//initialize a boolean to check if user wants to pipe something, set to false by default until we check with user
bool pipeExists = false;
//initialize this arrays to NULL so anything that store in them gets cleared out.
//these arrays will hold the commands that the user wants to carry out.
char * command[1024] = {NULL, NULL, NULL};
char * command2[1024] = {NULL, NULL, NULL};
//Important to delete mark the last byte as 0 in our input
buf[strlen(buf) -1] = 0;
//initialize this number to zero to start save the tokens at this index
int index = 0;
//a char * to hold the token saved by strtok
char * ptr;
ptr = strtok(buf, " ");
//Loop through 'buf' and save tokens accordingly
while(ptr != NULL){
//If ptr is equal to q or quit then user want to exit program
if(strcmp( ptr, "q" ) == 0){
exit(0);
}
if(strcmp( ptr, "quit" ) == 0){
exit(0);
}
//if ptr is equal to || user wants to pipe something and we change pipeExists to true
if(strcmp( ptr, "||" ) == 0){
pipeExists = true;
index= 0;
ptr = strtok(NULL, " ");
}
//enter here while user doesnt want to user pipes
if(!pipeExists){
command[index] = ptr;
ptr = strtok(NULL, " ");
index++;
}
//enter here if user want to use pipes
if(pipeExists){
command2[index] = ptr;
ptr = strtok(NULL, " ");
index++;
}
}
//if pipes exists then initialize it
if(pipeExists){
pipe(pipeA);
}
//create first child
if ((pid = fork()) == 0) {
//pass in the pipe, commands and pipe to function to execute
first_command(pipeA, command, pipeExists);
}
else if(pid < 0){
//error with child
cerr<<"error forking first child"<<endl;
}
// if pipe exists create a second process to execute the second part of the command
if(pipeExists){
//create second child
if ((pid2 = fork()) == 0) {
second_command(pipeA, command2);
}
else if(pid2 < 0){
//error with second child
cerr<<"error forking second child"<<endl;
}
}
//if the pipe was created then we close its ends
if(pipeExists){
close(pipeA[0]);
close(pipeA[1]);
}
//wait for the first child that ALWAYS executes
if ( (pid = waitpid(pid, &status, 0)) < 0)
cerr<<"error waiting for first child"<<endl;
//wait for the second child bu only if user wanted to created to use piping
if(pipeExists){
if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
cerr<<"error waiting for second child"<<endl;
}
cerr<<"480shell> ";
}//endwhile
exit(0);
}