c++ Process hangs when piping between two child processes - c++

I am trying to pipe data from one child process to another. When I run this, it hangs. If I don't make it wait for the first child process, it goes back to the top of the loop prompting for commands without giving the expected output, and when I prompt it to quit, it dumps all of the output I was expecting. I had it working with just one child process, but then the second execvp killed the parent process, and I didn't get back to the top of the loop prompting for more commands.
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, const char * argv[]) {
bool quit=0;
char quitArray[] = "quit";
int pipeReturnValue, fork1ReturnValue, fork2ReturnValue, pipefd[2], checkForQuit;
//Enter a loop where each iteration prompts for two single-line inputs
while (!quit) {
//Get command 1
char command1[128];
printf("Enter command 1: ");
fgets(command1,128,stdin);
command1[strlen(command1) -1] = 0;
//Exit if user enters quit
checkForQuit = strncmp(command1, quitArray, 4);
if (checkForQuit == 0) {
exit(0);
}
//Get command 2
char command2[128];
printf("Enter command 2: ");
fgets(command2,128,stdin);
command2[strlen(command2) -1] = 0;
//Exit if user enters quit
checkForQuit = strncmp(command2, quitArray, 4);
if (checkForQuit == 0) {
exit(0);
}
//Open pipe
pipeReturnValue = pipe(pipefd);
if (pipeReturnValue < 0) {
perror("Pipe failed");
exit(1);
}
//Fork 1
fork1ReturnValue = fork();
if(fork1ReturnValue < 0) {
perror("Fork failed");
exit(1);
}
else if (fork1ReturnValue == 0) {
//Fork 2
fork2ReturnValue = fork();
if (fork2ReturnValue < 0) {
perror("Fork 2 failed");
}
else if (fork2ReturnValue == 0) {
//close read end of pipe
close(pipefd[0]);
//parse command 1 arguments
//store tokens in array
char *arguments[6] = {};
arguments[0] = strtok(command1, " ");
int tokenCounter = 0;
while (arguments[tokenCounter] != NULL) {
tokenCounter++;
arguments[tokenCounter] = strtok(NULL, " ");
}
//dup stdo to pipe
dup2(pipefd[1], 1);
//execute arguments
execvp(arguments[0], arguments);
}
else {
wait(&fork2ReturnValue);
//close write end of pipe
close(pipefd[1]);
//parse command 2 arguments
//store tokens in array
char *arguments[6] = {};
arguments[0] = strtok(command2, " ");
int tokenCounter = 0;
while (arguments[tokenCounter] != NULL) {
tokenCounter++;
arguments[tokenCounter] = strtok(NULL, " ");
}
//dup stdin to pipe
dup2(pipefd[0], 0);
//exec
execvp(arguments[0], arguments);
}
}
else {
wait(&fork1ReturnValue);
}
}
return 0;
}

I finally figured it out. I needed to open the pipe after the first fork rather than before.
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, const char * argv[]) {
bool quit=0;
char command1[128],
command2[128],
quitArray[] = "quit";
int pipeReturnValue,
fork1ReturnValue,
fork2ReturnValue,
checkForQuit,
pipefd[2];
//Loop where each iteration prompts for two single-line inputs
while (!quit) {
//Get command 1
printf("Enter command 1: ");
fgets(command1,128,stdin);
command1[strlen(command1) -1] = 0;
//Exit if user enters quit
checkForQuit = strncmp(command1, quitArray, 4);
if (checkForQuit == 0) {
quit = 1;
exit(0);
}
//Get command 2 and trim trailing new line character
printf("Enter command 2: ");
fgets(command2,128,stdin);
command2[strlen(command2) -1] = 0;
//Exit if user enters quit
checkForQuit = strncmp(command2, quitArray, 4);
if (checkForQuit == 0) {
quit = 1;
exit(0);
}
//Fork to create 1st child process, return error if fork fails
fork1ReturnValue = fork();
if(fork1ReturnValue < 0) {
perror("Fork 1 failed");
exit(1);
}
//Open pipe, return error if fork fails
pipeReturnValue = pipe(pipefd);
if (pipeReturnValue < 0) {
perror("Pipe failed");
exit(1);
}
//First child process
else if (fork1ReturnValue == 0) {
//Fork to create 2nd child process, return error if fork fails
fork2ReturnValue = fork();
if (fork2ReturnValue < 0) {
perror("Fork 2 failed");
}
//Second child process
else if (fork2ReturnValue == 0) {
//close read end of pipe
close(pipefd[0]);
//Parse command 1 arguments, store tokens in an array
char *arguments[6] = {};
arguments[0] = strtok(command1, " ");
int tokenCounter = 0;
while (arguments[tokenCounter] != NULL) {
tokenCounter++;
arguments[tokenCounter] = strtok(NULL, " ");
}
//Dup standard output to write side of pipe
dup2(pipefd[1], 1);
//Execute arguments from command 1
execvp(arguments[0], arguments);
}
//First child code continued
else {
//Wait for child 2 to to terminate
wait(&fork2ReturnValue);
//Close write end of pipe
close(pipefd[1]);
//Parse command 2 arguments, store tokens in array
char *arguments[6] = {};
arguments[0] = strtok(command2, " ");
int tokenCounter = 0;
while (arguments[tokenCounter] != NULL) {
tokenCounter++;
arguments[tokenCounter] = strtok(NULL, " ");
}
//dup standard input to read side of pipe
dup2(pipefd[0], 0);
//Execute arguments from command 2
execvp(arguments[0], arguments);
}
}
//Parent process continued
else {
//Wait for child 1 to terminate
wait(&fork1ReturnValue);
}
//return to top of loop
}
return 0;
}

Related

Multiple Pipes, C++

I've been stuck on an issue with my program and just hoping for any help at this point :(
or guidance towards the right direction. In my code, I'm implenting a mini shell in c++ where the user can pipe 2 or more processes together, yet an issue keeps coming up whenever I execute it. Only the first and last commands actually execute so say I run:
cat b.txt | sort | tail -2
only cat b.txt and tail -2 would execute.
Here is my attempt at the whole program, also referenced to this which helped me tremendously with the setup.
#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 variable will take in the line of input submitted by the user
char buf[1024];
//PIDs for the two child processes
pid_t pid[300];
//these will be use to check the status of each child in the parent process
int status;
int status2;
int pid_num = 1;
//initializes the pipe
int pipeA[2] = {-1,-1};
int g = 0;
void first_command(int pipeA[], char * command[], bool pipeExists){
if(pipeExists){
dup2(pipeA[1], 1);
close(pipeA[0]);
}
// this will run command[0] as the file to execute, and command as the arg
execvp(command[0], command);
printf("Can not execute FIRST command, please enter a valid command \n");
exit(127);
}
void other_command(int pipeA[], char * command0[], int index){
dup2(pipeA[0], 0);
close(pipeA[1]);
execvp(command0[0], command0);
printf("Can not execute SECOND command, please enter a valid command\n");
exit(127);
}
void main_func() {
//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 *command0[1024] = {NULL, NULL, NULL};
char *command1[] = {NULL, NULL, NULL};
char *command2[] = {NULL, NULL, NULL};
char *command3[] = {NULL, NULL, NULL};
char ** my_commands[] = {
command0,
command1,
command2,
command3,
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 the user types exit at any moment, the program will exit gracefully and terminate
if(strcmp( ptr, "exit" ) == 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){
command0[index] = ptr;
ptr = strtok(NULL, " ");
index++;
}
g++;
printf("%s %i\n", ptr, g);
}
for (int s = 0; my_commands[s] != NULL; s++) {
cout << command0[s] << " \n" << endl;
}
//if pipes exists then initialize it
if(pipeExists){
pipe(pipeA);
}
//create first child
if ((pid[0] = fork()) == 0) {
//pass in the pipe, commands and pipe to function to execute
first_command(pipeA, command, pipeExists);
}
else if(pid[0] < 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){
for(int f = 0; my_commands[f] != NULL; f++) {
//create second child
if ((pid[f] = fork()) == 0) {
other_command(pipeA, command0, index);
}
else if(pid[f] < 0){
//error with second child
cerr<<"error forking child "<< pid_num << endl;
}
}
pid_num++;
}
//if the pipe was created then we close its ends
if(pipeExists){
for(int z = 0; z < pid_num; z++) {
close(pipeA[z]);
}
}
//wait for the first child that ALWAYS executes
if ( (pid[0] = waitpid(pid[0], &status, 0)) < 0)
cerr<<"error waiting for first child"<<endl;
//wait for the second child but only if user wanted to created to use piping
if(pipeExists){
for(int j = 1; j < pid_num; j++) {
if ( (pid[j] = waitpid(pid[j], &status2, 0)) < 0){
printf("Status: %d", pid[j]);
cerr<<"error waiting for child " << j <<endl;
}
}
}
pid_num = 1;
}//endwhile
}

How to fix loop not working using execv and forks

When running this program after the first iteration the program stops. This is because of execv function. What can I do so my loop still continues on until the user types quit.
I have tried creating a fork process before doing the execv in the child process but that does not work.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main(){
int pipefd[2];
int rs;
pid_t cpid;
pid_t cpid2;
rs = pipe(pipefd);
char* args1[256];
char* args2[256];
if (rs < 0){
perror("pipe");
exit(1);
}
char cmd1[256];
char cmd2[256];
char path1[10];
char path2[10];
while(true){
cout << "Command 1";
cin.getline(cmd1,256);
cout << "command 2";
cin.getline(cmd2,256);
if (strcmp(cmd1,"quit") == 0)
break;
if (strcmp(cmd2,"quit") == 0)
break;
char *token;
token = strtok(cmd1," ");
int i=0;
while(token != NULL){
args1[i] = token;
token = strtok(NULL, " ");
i++;
}
args1[i] = NULL;
token = strtok(cmd2," ");
i = 0;
while(token != NULL){
args2[i] = token;
token = strtok(NULL, " ");
i++;
}
args2[i] = NULL;
strcpy(path1,args1[0]);
strcpy(path2,args2[0]);
rs = fork();
if (rs < 0){
perror("Fork");
exit(1);
}
if (rs == 0){//child process
close(pipefd[1]);
close(0);
dup(pipefd[0]);
close(pipefd[0]);
rs = execvp(path2,args2);
if (rs < 0){
perror("execl");
exit(EXIT_FAILURE);
}
}
else{//PARENT PROCESS
close(pipefd[0]);
close(1);
dup(pipefd[1]);
close(pipefd[1]);
wait(&rs);
rs = execvp(path1,args1);
if (rs < 0){
perror("execl");
exit(EXIT_FAILURE);
}
}
};
return 0;
}
After outputting the answer the function should then ask the user for two more commands, This should go on until the user types in quit.
First of all exit(EXIT_FAILURE) is making your program exit.So remove it.
And you can put the possible exception creating code in try {} catch {} block.
In your case like this..
try{
rs = execvp(path1,args1);
if (rs < 0){
perror("execl");
//exit(EXIT_FAILURE);
}
}catch(int y){
continue;//here you can put your handling logic
}
By this you will get the desired output.

C++ microshell, input a command and pipe it to a process using fork(), dup(), pipe(). Is just I don't get the results I want

#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);
}

Fork: Resource temporarily unavailable when running shell with one arg

I am trying to write a microshell in C++ that will take in 1 or 2 args and run them in UNIX. My shell takes two args split by || fine, but when I run only one I get a massive fork error. My shell will look for || as a pipe instead of just |. Thank you in advance!
Some Functional commands are:
cat filename || sort
ls -l || less
Code:
#include <iomanip>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
using namespace std;
void getParms (char[], char* [], char* []);
int main()
{
char command[160];
pid_t pid1 = 1, pid2 = 1;
cout << "myshell> ";
cin.getline(command, 160);
while (strcmp(command, "q") != 0 && strcmp(command, "quit") != 0 && pid1 > 0 && pid2 > 0)
{
char* arg1[6];
char* arg2[6];
char path1[21], path2[21];
int pipefd[2];
arg1[0]=NULL;
arg2[0]=NULL;
getParms(command, arg1, arg2);
if (pipe(pipefd) < 0)
{
perror ("Pipe");
exit (-1);
}
//cerr <<"This is arg2"<<arg2[0]<<endl;
pid1 = fork();
if (pid1 < 0)
{
perror ("Fork");
exit (-1);
}
if (pid1 == 0)
{
//cout<<"Child 1"<<endl;
//cerr<<arg1[0]<<endl;
if(arg2[0] != NULL)
{
close(pipefd[0]);
close(1);
dup(pipefd[1]);
close(pipefd[1]);
}
strcpy(path1, "/bin/");
strcat(path1, arg1[0]);
if (execvp(path1, arg1) < 0)
{
strcpy(path1, "/usr/bin/");
strncat(path1, arg1[0], strlen(arg1[0]));
if (execvp(path1, arg1) < 0)
{
cout<<"Couldn't execute "<<arg1[0]<<endl;
exit (127);
}
}
if(arg2[0]== NULL)
{ // Parent process
close (pipefd[0]); //read
close (pipefd[1]); //write
waitpid(pid1, NULL, 0); // Waits for child2
cout << "myshell> ";
cin.getline(command, 160);
}
}
else if(arg2[0] != NULL)
{
//cerr<<"Child 2"<<endl;
pid2 = fork();
if (pid2 < 0)
{
perror ("Fork");
exit (-1);
}
if (pid2 == 0)
{
close(pipefd[1]);
close(0);
dup(pipefd[0]);
close(pipefd[0]);
strcpy(path2, "/bin/");
strncat(path2, arg2[0], strlen(arg2[0]));
if (execvp(path2, arg2) < 0)
{
strcpy(path2, "/usr/bin/");
strncat(path2, arg2[0], strlen(arg2[0]));
if (execvp(path2, arg2) < 0)
{
cout<<"Couldn't execute "<<arg2[0]<<endl;
exit (127);
}
}
}
else
{ // Parent process
//cerr<<"in last 2 else"<<endl;
close (pipefd[0]); //read
close (pipefd[1]); //write
waitpid(pid2, NULL, 0); // Waits for child2
cout << "myshell> ";
cin.getline(command, 160);
}
}
}
return 0;
}
/****************************************************************
FUNCTION: void getParms (char [], char* [], char* [])
ARGUMENTS: char str[] which holds full command
char* args[] args2[] which will hold the individual commands
RETURNS: N/A
****************************************************************/
void getParms(char str[], char* args[], char* args2[])
{
char* index;
int i= 0;
int j= 0;
index = strtok(str, " ");
//cerr<<"before first while"<<endl;
// While the token isn't NULL or pipe
while (index != NULL && strstr(index,"||") == NULL)
{
args[i] = index;
index = strtok(NULL, " ");
i++;
}
args[i] = (char*) NULL; // makes last element Null
//cerr<<" getParms before ||"<<endl;
if(index != NULL && strcmp(index,"||") != 0)
{
//cerr<<"after checking for ||"<<endl;
index = strtok(NULL," ");
while (index != NULL)
{
args2[j] = index;
index = strtok(NULL," ");
j++;
}
}
//cerr<<"After second IF"<<endl;
args2[j] = (char*) NULL; // makes last element Null
}
Your problem is that the main while loop is not going to any of the if-else statements in which you have the prompt for another command - the same statement is executed over and over. When you use the double pipe it goes to else if(arg2[0] != NULL) and the parent process shows a new prompt.
Try removing both prompts for a command from the main while loop in your if-else statement and move the prompt to the beginning of the loop like this:
//Move these two below into the while loop
//cout << "myshell> ";
//cin.getline(command, 160);
while (strcmp(command, "q") != 0 && strcmp(command, "quit") != 0 && pid1 > 0 && pid2 > 0)
{
cout << "myshell> ";
cin.getline(command, 160);
//...
}
Try not to make such redundant calls of the same thing. If you have a couple of those and you need to change something it can get messy.

Linux - Shell does not redirect outputs

I created a simple shell in Linux using fork() and execvp(). It works fine with cat, ls etc. but when I try to redirect its output like ./hello.o > output.txt it doesn't work.
I am guessing I didn't provide the write path to look for the definitions. My shell is currently searching on /bin/ path where most of the commands are stored.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define ARG_SIZE 100 // MAX LENGTH FOR ARGUMENTS
#define PATH "/bin/" // PATH FOR ARGUMENTS
int main() {
char inputLine[BUFSIZ];
char *argv[ARG_SIZE];
// for path + argv
char programPath[200];
while (1) {
printf("myshell> ");
// check if ctrl + D is pressed
if (fgets(inputLine, BUFSIZ, stdin) == NULL)
break;
inputLine[strlen(inputLine) - 1] = '\0';
// check if exit is typed
if (strcmp(inputLine, "exit") == 0)
break;
int i = 0;
argv[0] = strtok(inputLine, " \n");
for (i = 0; argv[i] && i < ARG_SIZE-1; ++i)
argv[++i] = strtok(NULL, " \n");
// create a fork call
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
// parent
if (pid != 0) {
wait();
// child
} else {
strcat(programPath, argv[0]);
// will not return unless it fails
execvp(programPath, argv);
perror("execvp");
exit(1);
}
}
return 0;
}