I am writing my shell and this is the piece of code. Can anyone please explain why I am not reaching in the end of following function i.e OUT is not printed.I have read shell related article but they don't seem to help.
commandargs() function returns formatted string i.e removing spaces and storing arguments. My 2 nights are wasted doing debugging only.
It works fine and output is correct but program execution stops after this function.
int shellpipe(char **arg)
{
// pid_t childpid;
int status;
int pfd[2];
pid_t cpid;
char c;
char **p=commandargs(arg[0]);
char **q=commandargs(arg[1]);
cout<<"q0";//not printed
if ( pipe(pfd) < 0){
perror("pipe");
return 1;
}
cpid = fork();
if( cpid == 0 )
{
/* CHILD 1*/
close(0);
dup2(pfd[0], 0);
close(pfd[1]);
if (execvp(q[0],q)==-1)
perror("Executing Error");
exit(0);
} else if ( cpid > 0){
/* PARENT */
close(1);
dup2(pfd[1], 1);
close(pfd[0]);
if (execvp(p[0],p)==-1)
perror("Executing Error");
close(pfd[1]);
close(1);
wait(&status);
}else{
/* ERROR */
perror("fork");
return 1;
}
cout<<"Out";//control don't reach here
}
"Out" isn't printed because the output stream is already closed. It might also be that the child process never finishes, but this would require a closer look on the argument strings.
Related
I have a problem with Pipelines on a Shell that I want to create in C++. I'm trying to pipeline firstly between two commands and when I run the program, it pipelines as it should be, but it does not end my file or program to come back to the command line. It's an infinite loop of entering everything without showing an error.
The code for the pipeline is the following:
if(countpipes!=0)
{
pid_t pid;
int pipefd[2];
pipe(pipefd);
for(int j=0; j<commands.size(); j++)
{ //cout<<endl<<"IT of "<<j<<" "<<commands[j]<<endl;
vector<string> all_commands = split(commands[j]);
vector<string> next_commands;
if(j!=commands.size()-1)
{ //cout<<"Piped once"<<endl;
pipe(pipefd);
}
if(j+1<commands.size())
{
next_commands = split(commands[j+1]);
}
char* arguments[all_commands.size()+1];
arguments[all_commands.size()] = NULL;
for (int k = 0; k < all_commands.size(); k++)
{
arguments[k] = (char*)all_commands[k].c_str();
}
char* next_arguments[next_commands.size()+1];
next_arguments[next_commands.size()] = NULL;
for (int l = 0; l < next_commands.size(); l++)
{
next_arguments[l] = (char*)next_commands[l].c_str();
}
pid = fork();
//cout<<"Child: "<<pid<<endl;
if (pid < 0) {
// Showing an error
perror("fork");
exit(1);
}
if (pid == 0) {
// Child Process
if(j==0)
{
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
int result2;
result2 = execvp(arguments[0], arguments);
if(result2 < 0)
{
perror("execvp");
exit(1);
}
}
else
{
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
int result;
result = execvp(arguments[0], arguments);
if (result < 0) {
perror("execvp");
exit(1);
}
}
}
else {
//cout<<"Wait pid"<<endl;
wait(NULL);
//cout<<"Wait after pid"<<endl;
}
}
}
I'm using a vector of strings that takes each of the commands. The final output for the pipeline looks like this and lets me introduce any text I want forever: https://imgur.com/LBvQRjF
The way you have your fork/exec set up, each child will only be connected to one pipe -- the first child connected (stdout) to the write end of a pipe, and each subsequent child connected (stdin) to the read end of a pipe. This will not work for 3+ children in a pipeline, as the middle children need to be connected to two (different) pipes -- stdin to the read end of one pipe and stdout to the write end of another.
You are not closing the pipe ends in the parent, so any child that is reading from a pipe will never see an EOF -- even when the previous child that is writing to the pipe exits, the parent will still have the write end open.
You also seem to be creating a next_agruments argv that you then never use, which is useless and probably indicates some confusion in your design.
pseudo-code for what you want:
int prev_out = -1, pipefds[2];
for (each command in the pipeline) {
if (not last command)
pipe(pipefds);
if ((child[i++] = fork()) == 0) {
// child
if (prev_out >= 0)
dup2(prev_out, 0);
if (not last command) {
dup2(pipefd[1], 1);
close(pipefd[0]); }
execvp(...
} else {
// parent
if (prev_out >= 0)
close(prev_out);
if (not last command) {
close(pipefd[1]);
prev_out = pipe_fd[0]; }
}
}
// now wait for the children.
You need a pipe between each pair of children connecting them. You need to close ALL the pipe fds in the parent after forking the children. You don't want to wait for any of the children until you've created all of them.
I have a really strange bug and I don't know why this is happening, I'm trying to create a shell and if I want to call in multiple execvp's it does not work. It works if I just pass in echo hello, but if I have echo hello for the first execvp and echo hello world for the second execvp, the second execvp will print "hello echo hello world".
void testexecute(char** arglist){
int k;
int status=0;
pid_t child_pid;
child_pid=fork();
cout<<"This is our child_pid number "<<child_pid<<endl;
if (child_pid == -1){
// error, failed to fork()
}
else if (child_pid > 0){
int status;
waitpid(child_pid, &status, 0);
cout<<"Our status here be "<<status<<endl;
return status;
}
else {
// we are the child
if(execvp(arglist[0],arglist)==-1)
{
_exit(EXIT_FAILURE); // exec never returns
}
else
{
cout<<"Second else has reached "<<endl;
exit(0);
}
}
}
int main() {
char *argv[] = {"echo","testing","these","functions"};
char *argvlist2[]= {"echo"," testssss","1","2"};
testexecute(argvlist2);
testexecute(argv);
return 0;
}
When I run this code this is my output
testssss 1 2
testing these functions echo testssss 1 2
I tried checking the contents of the arguments inside testexecute and it passes in the correct argument, so I don't know why it is also passing in the previous argument into execvp().
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);
}
I'm trying to implement the ||, &&, and ; operators in a bash shell I am making. What I am trying to do, is use a int as a flag that would be set to 1 if it was successful or 0 if it was not. My issue is that even if I enter an invalid operation such as ls -apples it sets the flag to 1. I also get the error message
ls: invalid option -- 'e'
Try 'ls --help' for more information
so I think that means it technically is executing?
How do I keep track of whether execvp took a invalid operation?
Here is my code:
pid_t pid;
pid_t waitId;
int status;
//forks into two processes
pid = fork();
//There was an error during fork
if (pid < 0)
{
successFlag = 0;
perror("There was an error");
}
else if (pid == 0)
{
//must be cast because our function expects a char *const argv[]
if (execvp(command[0], (char**)command) < 0)
{
//error at execvp
successFlag = 0;
perror("There was an error executing the process");
}
exit(EXIT_FAILURE);
}
else
{
do
{
waitId = waitpid(pid, &status, WUNTRACED | WCONTINUED);
if(waitId == -1){
successFlag = 0;
perror("Error in parent process");
exit(EXIT_FAILURE);
}
}
while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
//use this flag to determine whether the process was a success
successFlag = 1;
The solution was to look at the number that status returns. The sign would tell you whether it was successful or not.