I don't know what is wrong in this code. There are multiple errors with its output. This program is supposed to imitate a UNIX shell. It can run any command fine as long as it does not contain any pipes. However, when I include pipes, funny things start to occur.
For example: When I type in sort < myshell1,c | grep main | cat > o.txt
it creates an extra process. You can see this because in the code, perror(in)
gets executed 4 times (as per GDB):
COP4338$ sort < myshell1.c | grep main | cat > o.txt
Detaching after fork from child process 16465.
Process ID: 16465
Process ID: 0
in: Success
Detaching after fork from child process 16466.
Process ID: 16466
Process ID: 0
in: Success
Something happened in i != numcommands - 1: Success
Detaching after fork from child process 16468.
Process ID: 16468
COP4338$ Process ID: 0
in: Success
ELSE STATEMENT!
Detaching after fork from child process 17403.
in: Bad address
And then, the program goes to a new line and doesnt print COP4338$: like it should. Undefined behavior is exhibited. My guess as to why this is happening is because that 4th process is also continuing and thus heading back to main(), just like the parent, but I can't pinpoint why it is even being created.
Undefined behavior is also exhibited when I try to run ls -l | cat > o.txt
This is what GDB outputs:
As far as trying to fix the issue, I have yet to know for sure what is causing this. I have tried to use gdb debugger to debug the 3rd child process by typing "set follow-fork-mode child" and using a breakpoint at the 1st line of the 3rd child process and nothing happens. I can only debug the 1st child process by doing this.
/* This code was written by Dr. Raju Rangaswami and was expanded upon as per the instructions in Assignment3, by Michael Duboc(PID: 5706538)*/
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ARGS 20
#define BUFSIZ 1024
int get_args(char* cmdline, char* args[])
{
int i = 0;
/* if no args */
if((args[0] = strtok(cmdline, "\n\t ")) == NULL)
return 0;
while((args[++i] = strtok(NULL, "\n\t ")) != NULL)
{
if(i >= MAX_ARGS)
{
printf("Too many arguments!\n");
exit(1);
}
}
/* the last one is always NULL */
return i;
}
int customStrCpy(char** line1, char* line2)
{
int strlen1 = strlen(*line1), strlen2 = strlen(line2);
if(strlen1 < strlen2)
{
//Creates a dynamically allocated array that is big enough to store the contents of line2.
*line1 = calloc(strlen2, sizeof(char));
}
strcpy(*line1, line2);
}
void adjustArray(char* args[], int args_itr, int* nargs)
{
int i, j;
for(i = 0; i < 2; i++)
{
for(j = args_itr; j < (*nargs) - 1; j++)
{
customStrCpy(&args[j],args[j+1]);
}
args[(*nargs) - 1] = 0;
(*nargs)--;
}
}
int process(int* greaterthan, int* d_greaterthan, char* args_pipe[], int*
nargs_p, int* fileno_out, int* fileno_in, int* lessthan, FILE** fout,
FILE** fin)
{
int greaterthan_strcmp = strcmp(args_pipe[args_itr], ">");
int d_greaterthan_strcmp = strcmp(args_pipe[args_itr], ">>");
if(greaterthan_strcmp == 0 || d_greaterthan_strcmp == 0)
{
if(greaterthan_strcmp == 0)
*fout = fopen(args_pipe[args_itr + 1], "w");
else
*fout = fopen(args_pipe[args_itr + 1], "a");
*fileno_out = fileno(*fout);
*greaterthan = 1;
adjustArray(args_pipe, args_itr, nargs_p);
args_itr--;
int print_arr;
for(print_arr = 0; print_arr
(sizeof(args_pipe)/sizeof(args_pipe[0])); print_arr++)
printf("%s ",args_pipe[print_arr]);
printf("\n");
}
else if(strcmp(args_pipe[args_itr], "<") == 0)
{
*fin = fopen(args_pipe[args_itr + 1], "r");
*fileno_in = fileno(*fin);
*lessthan = 1;
adjustArray(args_pipe, args_itr, nargs_p);
args_itr--;
}
}
return 0;
}
void execute(char* cmdline)
{
int pid, async, lessthan = 0;
int greaterthan = 0, pipef = 0, d_greaterthan = 0;
int args_itr, pipe_flag = 0;
int flag_count = 0, fileno_in, fileno_out;
char* args_pipe[MAX_ARGS];/*5 and 3 are test numbers.*/
char* args[MAX_ARGS];
int nargs = get_args(cmdline, args);
if(nargs <= 0) return;
if(!strcmp(args[0], "quit") || !strcmp(args[0], "exit"))
{
exit(0);
}
/* check if async call */
if(!strcmp(args[nargs-1], "&")) { async = 1; args[--nargs] = 0; }
else async = 0;
FILE* fout = stdout;
FILE* fin = stdin;
for(args_itr = 0; args_itr < nargs; args_itr++)
{
if(!strcmp(args[args_itr], "|")) {pipe_flag = 1; flag_count++;}
}
if(pipe_flag)
{
int num_commands = flag_count + 1, i = 0, j = 0;
int fd[num_commands][2];
for(i = 0; i < flag_count; i++) {pipe(fd[i]);}
for(i = 0; i < num_commands; i++)
{
int nargs_p = 0, args_pipe_itr = 0;
while(j < nargs && strcmp(args[j], "|"))
{//Possibly make into for loop.
args_pipe[args_pipe_itr] = args[j];
args_pipe_itr++;
j++;
nargs_p++;
}
j++;
int pid = fork();
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
printf("Process ID: %d\n", pid);
if(pid < 0)
{
perror("Error forking!");
return;
}
else if(pid > 0) {continue;}
else //pid == 0
{
perror("in");
if(i == 0)
{
process(&greaterthan, &d_greaterthan, &args_pipe[i] ,&nargs_p, &fileno_out, &fileno_in, &lessthan, &fout, &fin);
printf("Lessthan = %d", lessthan);
if(lessthan) dup2(fileno_in, STDIN_FILENO);
dup2(fd[i][1], STDOUT_FILENO);
}
else if(i != num_commands - 1)
{
dup2(fd[i - 1][1], STDIN_FILENO);
//process(&greaterthan, &d_greaterthan, &args_pipe[i] ,&nargs_p, &fileno_out, &fileno_in, &lessthan, &fout, &fin);
dup2(fd[i][1], STDOUT_FILENO);
}
else
{
dup2(fd[i - 1][1], STDIN_FILENO);
process(&greaterthan, &d_greaterthan, &args_pipe[i] ,&nargs_p, &fileno_out, &fileno_in, &lessthan, &fout, &fin);
printf("greaterthan = %d", greaterthan);
printf("d_greaterthan = %d", d_greaterthan);
if(greaterthan || d_greaterthan) dup2(fileno_out, STDOUT_FILENO);
}
int close_pipes;
for(close_pipes = 0; close_pipes < flag_count; close_pipes++)
{
//close(fd[i][0]); close(fd[i][1]); JUST, WHY?!? THIS IS WHAT HAPPENS WHEN YOU DON'T THINK!
close(fd[close_pipes][0]);
close(fd[close_pipes][1]);
}
if(fout != stdout) fclose(fout);
if(fin != stdin) fclose(fin);
execvp(args_pipe[0], args_pipe);
perror("Something happened.");
exit(-1);
}//end child.
}
for(i = 0; i < flag_count; i++) {close(fd[i][0]); close(fd[i][1]);}
return;
}
}
int main (int argc, char* argv [])
{
for(;;)
{
printf("COP4338$ ");
if(fgets(cmdline, BUFSIZ, stdin) == NULL)
{
perror("fgets failed");
exit(1);
}
execute(cmdline);
int corpse;
int status;
while(corpse = wait(%status)) > 0)
perror(pid %d exited with status: 0x%.4X\n, corpse, status);
}
}
The program is supposed to print out "int main (int argc, char* argv [])
" to o.txt, but o.txt doesn't get changed at all.
For those that are curious, the function process() scans through a string of arguments which constitute a command and sets flags depending on the symbols that the program sees.