Background Jobs in C (implementing & in a toy shell) - c++

I want to make it so when a user attaches a - after a command it will be executed in the background. For some reason if I execute a command normally it will wait, then if I execute a command in the background it will work but then if I execute a command normally it won't wait for it. I am sure I am just doing something small-ish wrong. Any ideas:
void executeSystemCommand(char *strippedCommand, char *background, int argc, char **args) {
char pathToExecute[80];
// Check if command will be executed in the background
int shellArgs;
bool bg;
if (!strcmp(background, "-")) {
bg = true;
shellArgs = argc -1;
} else {
bg = false;
shellArgs = argc;
}
// Save the linux commands in a new array
char *executableCommands[shellArgs+1];
int j;
for (j = 0; j < shellArgs+1; j++) {
executableCommands[j] = args[j];
}
executableCommands[shellArgs] = NULL;
// Check the $PATH
const char delimiters[] = ":";
char *token, *cp;
char *forLater;
int count = 0;
char *path;
path = getenv("PATH");
// All of this just breaks up the path into separate strings
cp = strdup(path);
forLater = strdup(path);
token = strtok (cp, delimiters);
while ((token = strtok (NULL, delimiters)) != NULL) {
count++;
}
char **argv;
int size = count+1;
argv = (char**) malloc (size);
count = 0;
token = strtok (forLater, delimiters);
argv[0] = (char*) malloc (50);
argv[0] = token;
strcpy(argv[0],token);
while ((token = strtok (NULL, delimiters)) != NULL) {
count++;
argv[count] = (char*) malloc (50);
argv[count] = token;
}
// This goes through the path to see if the linux command they entered
// Ex: sleep exists in one of those files and saves it to a var
int i;
bool weHaveIt = false;
int ac;
for (i = 0; i < count; i++) {
char str[80];
strcpy(str, argv[i]);
strcat(str, "/");
strcat(str, args[0]);
ac = access(str, F_OK);
if (ac == 0) {
weHaveIt = true;
strcpy(pathToExecute, str);
break;
}
}
if (!weHaveIt) {
printf("That is not a valid command. SORRY!\n");
return;
}
executableCommands[0] = pathToExecute;
int status;
// Get the array for
// If user wants command to be a background process
if (bg) {
int background_process_id;
pid_t fork_return;
fork_return = fork();
if (fork_return == 0) {
background_process_id = getpid();
addJobToTable(strippedCommand, background_process_id);
setpgid(0, 0);
execve(executableCommands[0], executableCommands, NULL);
exit(0);
} else {
return;
}
} else {
int background_process_id;
pid_t fork_return;
fork_return = fork();
if (fork_return == 0) {
background_process_id = getpid();
status = execve(executableCommands[0], executableCommands, NULL);
exit(0);
} else {
wait(&status);
return;
}
}
}

The call to wait made for the third job returns immediately because the second job has finished and is waiting to be handled (also called "zombie"). You could check the return value of wait(&status), which is the PID of the process that has exited, and make sure it is the process you were waiting for. If it's not, just call wait again.
Alternatively use waitpid, which waits for a specific process:
/* Wait for child. was: wait(&status) */
waitpid(fork_return, &status, 0);
If you do this you should implement a signal handler for SIGCHLD to handle finished background jobs to prevent the accumulation of "zombie" child processes.
In addition to that, in the background job case, the branch where fork() returns 0 you are already in the new process, so the call to addJobToTable happens in the wrong process. Also, you should check the return values of all the calls; otherwise something may be failing and you don't know it. So the code for running a job in the background should look more like this:
if (fork_return == 0) {
setpgid(0, 0);
if (execve(executableCommands[0], executableCommands, NULL) == -1) {
perror("execve");
exit(1);
}
} else if (fork_return != -1) {
addJobToTable(strippedCommand, fork_return);
return;
} else {
perror("fork"); /* fork failed */
return;
}

Every child process created with fork() will exit when the parent process exits.
if (fork_return == 0) {
/* child process, do stuff */
} else {
/* parent process, exit immediately */
return;
}
Explanation
fork spawns a new process as a child process of the current process (parent). Whenever a process in Unix-like operating systems terminates all of its child processes are going to be terminated too. If they have child processes on their own, then these will get terminated too.
Solution
On most shells you can start a process in background if you add an ampersand & to the end of the line:
myApplication arg1 arg2 arg3 ... argN &

Related

Creating a history function for a Unix Shell

Here is what my program currently looks like. I have to add history functionality that gets stored in a file 'mysh.history'. Currently I expect my output to simply append each user command in my shell to the file.
first line of output
first line of output
It only appends the first input into the shell instance. I think my problem lies with my understanding of the fork() process but I'm not sure what is going on. Any suggestions?
#define MYSH_BUFFERSIZE 64
#define MYSH_DELIM " \t\n"
fstream file;
// custom function declarations
int mysh_exit(char **args);
int mysh_add_history(char **args);
int mysh_history(char **);
char byebye[] = "byebye";
char exit_program[] = "exit";
char history[] = "history";
// contains names of all custom shell commands implemented
char *lookup_str[] = {byebye, exit_program, history};
// holds references to all commands in lookup_str[]
// order or commands must match each other
int (*lookup_func[])(char **) = {
&mysh_exit,
&mysh_exit,
&mysh_history
};
/* custom shell commands implementations BEGIN*/
// Without the argument, it prints out the recently typed commands (with their
// arguments), in reverse order, with numbers
// If the argument ā€œ-cā€ is passed, it clears the list of recently typed commands.
void clear_history()
{
file.close();
file.open("mysh.history", ios::trunc);
}
int mysh_add_history(char *line)
{
// if exists then append to the history
if (access("mysh.history", F_OK) == 0)
{
file.open("mysh.history", ios::app);
}
// otherwise create mysh.history and start writing
else
{
file.open("mysh.history", ios::out);
}
file << line << "\n";
return 0;
}
int mysh_history(char **)
{
return 0;
}
int mysh_exit(char **args)
{
return 0;
}
int num_commands()
{
return sizeof(lookup_str) / sizeof(char *);
}
/* custom shell functions END*/
/* main shell processes BEGIN*/
// returns the tokens (arguments) array after tokenizing line from mysh_read_line()
char **mysh_split_args(char *line)
{
int buffer_size = MYSH_BUFFERSIZE;
int current_pos = 0;
char **tokens = (char **)malloc(buffer_size * sizeof(char *));
char *tok;
if (!tokens)
{
printf("mysh: memory allocation error\n");
exit(EXIT_FAILURE);
}
tok = strtok(line, MYSH_DELIM);
while (tok != NULL)
{
tokens[current_pos] = tok;
current_pos++;
if (current_pos >= buffer_size)
{
buffer_size += MYSH_BUFFERSIZE;
tokens = (char **)realloc(tokens, buffer_size * sizeof(char *));
if (!tokens)
{
printf("mysh: memory allocation error\n");
exit(EXIT_FAILURE);
}
}
tok = strtok(NULL, MYSH_DELIM);
}
tokens[current_pos] = NULL;
return tokens;
}
// mysh_read_line allocates MYSH_BUFFER_SIZE of memory to the intial buffer
// it reallocates memory as needed with getLine() function
// returns line to be processed and tokenized by mysh_split_args()
char *mysh_read_line(void)
{
char *line = NULL;
size_t buffersize = 0;
// getLine() also needs to check for EOF after in the case of text files being read.
if (getline(&line, &buffersize, stdin) == -1)
{
if (feof(stdin))
{
exit(EXIT_SUCCESS);
}
else
{
printf("failed to read line\n");
exit(EXIT_FAILURE);
}
}
return line;
}
// args passed comes from mysh_split_args()
int mysh_launch_process(char **args)
{
pid_t pid;
pid_t wpid;
int state;
pid = fork();
// if we enter child process
if (pid == 0)
{
if (execvp(args[0], args) == -1)
{
printf("error in mysh\n");
}
exit(EXIT_FAILURE);
}
// forking failed
else if (pid < 0)
{
printf("error in mysh\n");
}
else
{
// if we enter parent process
do
{
wpid = waitpid(pid, &state, WUNTRACED);
} while (!WIFEXITED(state) && !WIFSIGNALED(state));
}
return 1;
}
// calls mysh_launch_process() and handles programs being called
int mysh_execute(char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i = 0; i < num_commands(); i++)
{
if (strcmp(args[0], lookup_str[i]) == 0)
{
if (strcmp(args[0], "history") == 0 && strcmp(args[1], "-c"))
{
clear_history();
}
return (*lookup_func[i])(args);
}
}
return mysh_launch_process(args);
}
void mysh_loop(void)
{
char *line;
char **args;
int state;
do
{
printf("# ");
line = mysh_read_line();
mysh_add_history(line);
args = mysh_split_args(line);
state = mysh_execute(args);
free(line);
free(args);
} while (state);
}
int main(int argc, char **argv)
{
// run main program loop
mysh_loop();
file.close();
return EXIT_SUCCESS;
}
/* main shell processes END*/```

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.

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
}

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

Using execv to do basic I/O

I'm trying to use execv() to allow me to read into an output file, outputfile.txt, from the terminal. The problem I'm having is that it won't work at all and I don't know if I'm using it correctly.
My code so far:
void my_shell() {
char* args[2];
args[0] = "/usr/bin/tee";
args[1] = "outputfile.txt";
execv(args[0], &args[0]);
}
int main() {
cout << "%";
//string input;
pid_t pid, waitPID;
int status = 0;
pid = fork();
if (pid == 0) {
my_shell();
}
else if (pid < 0) {
cout << "Unable to fork" << endl;
exit(-1);
}
while ((waitPID = wait(&status)) > 0) {
}
return 0;
}
What it's doing right now is that nothing is happening at all. The program forks fine, but what's in my_shell isn't doing anything at all. What am I doing wrong?
You're missing the NULL terminator to args.
void my_shell() {
char* args[3];
args[0] = "/usr/bin/tee";
args[1] = "outputfile.txt";
args[2] = NULL;
execv(args[0], args);
}