Reputation: 47
Premise: Implement a C++ program that prompts the user for 2 commands. Each input string should be a UNIX command, with arguments allowed. For example, input 1 could be "ls -l" and input 2 could be "wc -l". The program will then create a pipe, and two child processes. The first child process will run the command specified in the first input. It will output to the pipe instead of standard output. The second child process will run the command specified in the second input. It will take its input from the pipe rather than standard input. The parent process will wait on its two children to complete, then the whole thing will repeat. Execution will stop when "quit" is entered as the first command.
I believe I am almost done with the program but I am getting having trouble figuring out how to get the user input executed in the pipe, and I end up with syntax errors.
Here is my code so far:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
using namespace std;
int main() {
//Declare Variables
char first, second[80];
int rs, pipefd[2];
int pid1, pid2;
char *command1[80], *command2[80];
//Asking for the commands
cout << "Please enter your first command(incl. args) or quit: ";
cin >> first;
//Do the program while the first answer isn't quit
while(first[0] != 'quit') {
//Copy first answer into first command
strcpy(command1, ((char*)first);
//Just skip to end of program if first command is quit
cout << "Please enter your second command(incl. args): ";
cin >> second;
//Copy second answer into second command
strcpy(command2, ((char*)first);
//pipe
rs = pipe(pipefd);
//if pipe fails to be made
if(rs == -1){
perror("Fail to create a pipe");
exit(EXIT_FAILURE);
}
//Fork for the two processes
pid1 = fork();
if (pid1 != 0){
pid2 = fork();
}
if(pid1 == -1){
perror("Fail to create a pipe");
exit(EXIT_FAILURE);
}
if(pid2 == -1){
perror("Fail to create a pipe");
exit(EXIT_FAILURE);
}
if (pid1 == 0) { // 1st child process
// close write end of pipe
close(pipefd[0]);
// duplicate
dup2(pipefd[1], 1);
//execute the input argument
execvp(command1[0], command1);
}
if (pid1 == 0) { // 2st child process
// close write end of pipe
close(pipefd[0]);
// duplicate
dup2(pipefd[1], 1);
//execute the input argument
execvp(command2[0], command2);
}
else { // parent process
// close read end of pipe
close(pipefd[0]);
// wait for child processes
wait(&pid1);
wait(&pid2);
}
//Asking for the commands
cout << "Please enter your first command(incl. args) or quit: ";
cin >> first;
}; //end of while()
return 0;
}
Any help/hints would be appreciated for this is due in the near future and I would love to finally have this beast tackled.
Edit: Adding errors gotten
In function int main()':
z1674058.cxx:26:33: error: expected ')' before ';' token
z1674058.cxx:33:33: error: expected ')' before ';' token
Upvotes: 0
Views: 1134
Reputation: 362087
// close write end of pipe
close(pipefd[0]);
// duplicate
dup2(pipefd[1], 1);
You have these same two lines in both child #1 and child #2. The two children should do opposite operations here. One of them should be closing pipefd[1]
and duping pipefd[0]
to stdin.
You've also got some string-handling bugs.
char first, second[80];
This doesn't declare two 80-character arrays. It declares one char
and one char[80]
. I suspect this is why you put in the (char *)
cast here—to silence a compiler error:
strcpy(command1, ((char*)first);
Don't do that. Don't use casts to shut the compiler up. The cast is covering up a serious error.
char *command1[80], *command2[80];
These declarations are also incorrect. This declares two arrays of 80 char *
s apiece. That is, two arrays containing 80 strings each. I'll leave it up to you to figure out how to fix this...
Upvotes: 3