Implementing bash operators for shell in c++ - c++

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.

Related

How to read line from terminal and then pass it via exec command to another C++ program?

I am writing a program in C++ which reads text from command line and then passes that to another program which uses this text.
Now, I am reading text in program 1 like so:
std::string line;
std::getline(std::cin, line);
And then I am using forks to open a child process and using execl command to run the executable of the program 2. Now I don't know how to make program 2 read this text and use it.
pid_t pid = fork();
if (pid < 0) {
perror("Fork failed");
exit(1);
}else if (pid == 0) {
// Execute the rgen here after parent is done
execl("./program2",".program2", NULL);
}
The above code works and runs the program 2. However, I just don't know how to pass the text read from terminal.
This is the full code:
int main(int argc, const char * argv[]) {
std::string line;
std::getline(std::cin, line);
pid_t pid = fork();
if (pid < 0) {
perror("Fork failed");
exit(1);
}else if (pid == 0) {
execl(".program2",".program2", NULL);
}
return 0;
}
Any help will be appreciated. Thanks.

Shell Pipeline C++ not ending command

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.

Shell Pipe Implementation single level

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.

Toy shell not piping correctly

I'm not going to lie. This is a homework question. However, as far as I'm concerned, the points are gone baby gone. Right now, I'm just looking for an answer, because I -think- I might be insane.
The goal of this program is to execute the command ps -A | grep (inputstring) | wc -l in a way similar to how the shell does it. So, I spawn the processes, and have them wait on each other. The newest process, the great-grandchild, execlp("ps","ps","-A",NULL) which replaces itself with the ps -A process. Before it execlp, I make sure its standard output is going to the pipe output. The next process in line is wait()ing, and already has itself set up so that the input pipe goes to standard in, and standard out goes to the output pipe, and it will execute grep, and so on.
I'm almost positive I have it set up correctly. And yet... the program does. Not. Work.
#include <stdlib.h>
#include <iostream>
#include <string>
#define MAXLINE 1500
#define READ 0
#define WRITE 1
using namespace std;
int main( int argc, char** argv ) {
//* start of input block
if ( argc != 2 ) {
cout << "Usage: ./a.out arg1" << endl;
return 0;
}
string in = argv[1];
// end of input block */
int pipeA[2], pipeB[2], pid, stat;
// get our first set of pipes
if ( pipe(pipeA) < 0 ) {
cerr << "Pipe error.\n";
exit(-1);
}
if ( pipe(pipeB) < 0 ) {
cerr << "Pipe error.\n";
exit(-1);
}
// make the first fork
if ( (pid = fork() ) < 0 ) { cerr << "Fork error.\n"; exit(-1); }
if ( pid > 0 ) { // parent case
wait(&stat);
} else { // child case
if ( (pid = fork()) < 0 ) { cerr << "Fork Error\n"; exit(-1); }
if ( pid > 0 ) { // child
wait(&stat);
dup2(pipeA[READ],READ);
execlp("wc","wc","-l",NULL);
} else { // grand-child
if ( (pid = fork()) < 0 ) { cerr << "Fork Error\n"; exit(-1); }
if ( pid > 0 ) { // still grand-child
wait(&stat);
dup2(pipeB[READ],READ);
dup2(pipeA[WRITE],WRITE);
close(pipeB[READ]);
execlp("grep","grep",in.c_str(),NULL);
} else { // great grand-child
dup2(pipeB[WRITE],WRITE); // t now goes to pipeB[1]
close(READ);
close(pipeB[READ]);
execlp("ps", "ps", "-A", NULL);
}
}
}
return 0;
}
EDIT: Changed to the two-pipe variant of my code.
I'm virtually certain this is what you're trying to do. Apologies in advance for the sloppy coding. its somewhat late here and I really should be sleeping right now:
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#define READ 0
#define WRITE 1
// ps -A | grep argv[1] | wc -l
int main( int argc, char** argv )
{
// start of input block
if ( argc != 2 )
{
std::cout << "Usage: ./a.out arg1" << std::endl;
return 0;
}
// make local copy of argument
std::string in = argv[1];
int fd1[2], fd2[2], pid;
// allocate two pipe sets
if (pipe(fd1) < 0 || pipe(fd2) < 0)
{
perror("Failed to create pipe.");
return EXIT_FAILURE;
}
// launch first child process.
if ((pid = fork()) < 0)
{
perror("Failed to fork child(1)");
return EXIT_FAILURE;
}
if (pid == 0)
{
// wc -l process.
// stdin = fd2(read)
close(fd1[READ]);
close(fd1[WRITE]);
close(fd2[WRITE]);
dup2(fd2[READ],STDIN_FILENO);
execlp("wc","wc","-l",NULL);
}
// fork again. this time for grep
if ((pid = fork()) < 0)
{
perror("Failed to fork child(2)");
return EXIT_FAILURE;
}
if (pid == 0)
{
// grep argv[1] process.
// stdin = fd1(read)
// stdout = fd2(write)
close(fd1[WRITE]);
close(fd2[READ]);
dup2(fd2[WRITE], STDOUT_FILENO);
dup2(fd1[READ], STDIN_FILENO);
execlp("grep", "grep", in.c_str(), NULL);
}
// fork once more. this time for ps -A
if ((pid = fork()) < 0)
{
perror("Failed to fork child(3)");
return EXIT_FAILURE;
}
if (pid == 0)
{
// ps -A process.
// stdout = fd1(write)
close(fd2[WRITE]);
close(fd2[READ]);
close(fd1[READ]);
dup2(fd1[WRITE], STDOUT_FILENO);
execlp("ps", "ps", "-A", NULL);
}
int stat=0;
wait(&stat);
return EXIT_SUCCESS;
}
On my system, ps -A reports 141 lines, of those 41 have the word System somewhere within, verified by simply running ps -A | grep System | wc -l. The above code generates precisely the same output.
I'm not sure but maybe calling dup2 before waiting on the child would fix the pipe problem.
The reason I'm not sure is that it normally stdin and stdout are bufferized so I suppose that even if you hook your pipe up with them after the child has finish running you should get the same results but maybe (if someone knows the answer to this please correct me) the buffers for stdin and stdout get wiped with the end of the child process.
Also, could you update the code in your question to contain the modified code with two sets of pipes ?

Determine if a process exists from its Process ID

I want to know in my program if a process with a certain ID exists. I implemented the following function to achieve that, which checks if /proc/<PID>/maps exist. However, I notice that even If I kill a function with a given ID, this function still returns 1. Is there any better way of achieving what I'm trying to do and if not what is the problem with this code if any, why is it returning 1 when it should be returning 0.
int proc_exists(pid_t pid)
{
stringstream ss (stringstream::out);
ss << dec << pid;
string path = "/proc/" + ss.str() + "/maps";
ifstream fp( path.c_str() );
if ( !fp )
return 0;
return 1;
}
Use kill() with signal 0:
if (0 == kill(pid, 0))
{
// Process exists.
}
From man kill:
If sig is 0, then no signal is sent, but error checking is still performed; this can be used to check for the existence of a process ID or process group ID.
To overcome the possibility of the process existing as zombie, I used the following:
bool is_pid_running(pid_t pid) {
while(waitpid(-1, 0, WNOHANG) > 0) {
// Wait for defunct....
}
if (0 == kill(pid, 0))
return 1; // Process exists
return 0;
}
It works for me!
bool checkPidRunning(pid_t pid){
if (kill(pid, 0) == -1 && errno == ESRCH) {
return false; // process not exist
}else
return true;
}