CSC-4730 / P1 / myshell.cpp
myshell.cpp
Raw
//Kai Kuebler and Caleb Collar

#include <iostream>
#include <getopt.h>
#include <string>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <cstring>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;

int main(int argc, char * argv[]) {
	
	bool HandleOptions(int argc, char ** argv, string &, string &, string &, string &, string &, string &);

	string d_arg;
	string i_arg;
	string o_arg;
	string a_arg;
	string arg_one;
	string arg_two;

	if (!HandleOptions(argc, argv, d_arg, i_arg, o_arg, a_arg, arg_one, arg_two)) {
		cout << "Missing required command line option -1" << endl; 
		return 1;
	}

	if(d_arg.length() > 0){
		if(chdir(d_arg.c_str()) == 0);
		else{
			cerr << "Path does not exist, or is not a directory" << endl;
			return 1;
		}
	}

	int pipefds[2];
	if(arg_two.length() > 0){
		if(pipe(pipefds) < 0){
			cerr << "Pipe failed." << endl;
			return 1;
		}
	}
	
    int PID = fork();
    if (PID < 0) {
        cerr << "Fork failure." << endl;
    }
    else if (PID == 0) {
        //child
        if (i_arg.length() > 0){
            if (fopen(i_arg.c_str(), "r")) {
                //fclose(file);
				if (arg_two.length() > 0){ //if -2 is on the command line, then the pipe will be on the open file table, so this file's index will be two greater (i.e. 5) on said table
					close(STDIN_FILENO);
                	dup(5);
               		close(5);
				}
				else{ //no pipe on the open file table, so this file will be after the default calues in the open file table
                	close(STDIN_FILENO);
                	dup(3);
               		close(3);
				}
            }
            else {
            	cerr << "Could not open redirected input file: no such file or directory" << endl;
            	return 1;
            }
        }

		if(o_arg.length() > 0 && arg_two.length() <= 0){
			 if(fopen(o_arg.c_str(), "w")) {
				 close(STDOUT_FILENO);
				 dup(3);
				 close(3);
			 }
			 else{
				 cerr << "Path is invalid or file could not be opened" << endl;
				 return 1;
			 }
		}

		if(a_arg.length() > 0 && arg_two.length() <= 0){
			 if(fopen(a_arg.c_str(), "a")) {
				 close(STDOUT_FILENO);
				 dup(3);
				 close(3);
			 }
			 else{
				 cerr << "Path is invalid or file could not be opened" << endl;
				 return 1;
			 }
		}

        
		if(arg_two.length() > 0){
			close(3); //or pipefds[0]
			close(STDOUT_FILENO);
			dup(4);
			close(4);
		}

        char* args[2];
        args[0] = strdup(arg_one.c_str());
        args[1] = NULL;
        if(execvp(args[0], args) == -1){
			cerr << "Prog 1 exec failed." << endl;
			return 1;
		}
		
    }
    else {
        //parent
		int c2PID;
		if(arg_two.length() > 0){
			c2PID = fork();
			 if (c2PID < 0) {
        		cerr << "Fork failure." << endl;
   			 }
			else if (c2PID == 0){
				//child 2
				close(4);
				close(STDIN_FILENO);
				dup(3);
				close(3);

				if(o_arg.length() > 0){
					if(fopen(o_arg.c_str(), "w")) {
						close(STDOUT_FILENO);
						dup(3);
						close(3);
					}
					else{
						cerr << "Path is invalid or file could not be opened" << endl;
						return 1;
					}
				}

				if(a_arg.length() > 0){
					if(fopen(a_arg.c_str(), "a")) {
						close(STDOUT_FILENO);
						dup(3);
						close(3);
					}
					else{
						cerr << "Path is invalid or file could not be opened" << endl;
						return 1;
					}
				}

				char* args[2];
        		args[0] = strdup(arg_two.c_str());
        		args[1] = NULL;
        		if(execvp(args[0], args) == -1){
					cerr << "Prog 2 exec failed." << endl;
					return 1;
				}
			}
			else{
				//parent
			}
		}

		int status2;
		int childTwoPID;
        int status;
        //wait on child return needs to properly reflect exit status (currently only 0)
		close(3);
		close(4);
        int childOnePID = waitpid(PID, &status, 0);
		if (arg_two.length() > 0){
			//waitr for child 2
			childTwoPID = waitpid(c2PID, &status2, 0);
		}
		if (arg_two.length() > 0){
			cout << "Child 2: " << childTwoPID << " Returns: " << WEXITSTATUS(status2) << endl;
		}
		cout << "Child 1: " << childOnePID << " Returns: " << WEXITSTATUS(status) << endl;

    }

	return 0;
}

bool HandleOptions(int argc, char ** argv, string & d_arg, string & i_arg, string & o_arg, string & a_arg, string & arg_one, string & arg_two) {
	int c;

	while ((c = getopt(argc, argv, "d:i:o:a:1:2:pv")) != -1) {
		switch (c) {
			default:
			case 'd':
				d_arg = string(optarg);
				break;

			case 'i':
				i_arg = string(optarg);
				break;

			case 'o':
				o_arg = string(optarg);
				if(a_arg.length() > 0){
					a_arg = "";
				}
				break;

			case 'a':
				a_arg = string(optarg);
				if(o_arg.length() > 0){
					o_arg = "";
				}
				break;

			case '1':
				arg_one = string(optarg);
				break;

			case '2':
				arg_two = string(optarg);
				break;

			case 'p':
				char cwd [PATH_MAX];
				cout << getcwd(cwd, sizeof(cwd)) << endl;
				break;

			case 'v':
				break;
		}
	}
	return arg_one.size() > 0;
}