Operating Systems--Spring 2005

    Home | | Schedule | | Assignments | | Lecture Notes

    Project 2: Processes


    Solution to tshell.cc

    //********************************************************
    // tshell.cc
    //    Author: Constance Royden
    //    Date: February 25, 2005
    //    Class: CSCI 399-02 Operating Systems, Professor Royden
    //    Assignment: Project 2
    //    Purpose: Implements a tiny shell to run UNIX commands
    //*******************************************************
    
    #include <iostream.h>
    #include <string.h>
    #include <sys/wait.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include "parser.h"
    
    void processCommand(char[ ]);
    
    int main(void)
    {
      char pwd[50];           //String for working directory
      char commandLine[100];  //Command line entered by user
    
      strcpy(pwd, getenv("PWD"));
     
      cout << "Welcome to tsh!" << endl;
      cout << "Type quit to quit." << endl << endl;
    
      cout << "tsh:" << pwd << "> ";
      cin.getline(commandLine, 100);
    
      while (strcmp(commandLine, "quit") != 0) {
        processCommand(commandLine);
        cout << "tsh:" << pwd << "> ";
        cin.getline(commandLine, 100);
      }
    
      return 0;
    }
      
    //********************************************************
    // void processCommand(char commandLine[ ]) 
    // Purpose: Process user's command.  Parse input.  Execute command.
    // Precondition:  Command line has been read in and is a UNIX command line
    // Postcondition: Forks a process and executes command
    // Note:  I left in the cout statements that I used for debugging
    //        (although they are now commented out).
    //******************************************************
    void processCommand(char commandLine[ ]) {
      Parser parser;             //Object for data on parsed command
      int cpid = 0;              // pid of first forked process
      int cpid2 = 0;             // pid of second forked process (if pipe)
      int status = 0;            // status of child process when exits
      int cpid_done = 0;         // pid of child that finished.
      int inputFileD = 0;        //input file descriptor
      int outputFileD = 0;       //output file descriptor
      int fd[2];                 //descriptor array for pipe
    
      //  cout << "Processing " << commandLine << endl;
      parser.ParseLine(commandLine);
    
      //Deal with input and output files if any
      if (parser.inFile) {
        //cout << "Opening input file." << endl;
        inputFileD = open(parser.inputFile, O_RDONLY);
      }
      if (parser.outFile) {
        //cout << "Opening output file." << endl;
        outputFileD = open(parser.outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0700);
      }
    
      //Create pipe if more than 1 comand
      if (parser.numCommands > 0) {
        //cout << "Creating pipe. " << endl;
        pipe(fd);
      }
    
      //Create first child
      cpid = fork( );
      if (cpid == 0 ) {         //child process
        //cout << "Child process.  Executing: " << parser.commands[0].cmd << endl;
        if (parser.inFile) {
          //cout << "First child redirecting input from " << parser.inputFile << endl;
          dup2(inputFileD, 0);
          close(inputFileD);
        } 
        if ((parser.outFile) && (parser.numCommands == 0)) {
          //cout << "First child redirecting output to " << parser.outputFile << endl;
          dup2(outputFileD, 1);
          close(outputFileD);
        }
        if (parser.numCommands > 0) {
          //cout << "First child opening pipe for output." << endl;
          close(fd[0]);
          dup2(fd[1], 1);
          close(fd[1]);
        }
        
        execvp(parser.commands[0].cmd, parser.commands[0].args);
    
      } else {
        if ( parser.numCommands > 0) {
          //cout << "Forking second child process." << endl;
          cpid2 = fork( );
          if (cpid2 == 0) {
            //cout << "Second child executing: " << parser.commands[1].cmd << endl;
    	    if ((parser.outFile)){
    	        //cout << "Second cild redirecting output to " << parser.outputFile << endl;
    	        dup2(outputFileD, 1);
    	        close(outputFileD);
    	    }
    	    //cout << "Second child opening pipe for input. " << endl;
    	    close(fd[1]);
    	    dup2(fd[0], 0);
    	    close(fd[0]);
    
    	    execvp(parser.commands[1].cmd, parser.commands[1].args);
          }
        }
        //cout << "first cpid " << cpid << endl;
        //cout << "second cpid " << cpid2 << endl;
        close(fd[0]);
        close(fd[1]);
        if (!parser.backgrounded) {
           cpid_done = waitpid(cpid,&status, 0);
           if (parser.numCommands > 0) {
                cpid_done = waitpid(cpid2, &status, 0);
           }
        }
        //cout << "Parent process.  Done with process: " << cpid_done << endl;
    
      }
     
      return;
    }
    
    


    Home | | Schedule | | Assignments | | Lecture Notes


    Constance Royden--croyden@mathcs.holycross.edu
    Computer Science 346--Operating Systems
    Date Created: January 9, 2004
    Last Modified: February 10, 2005
    Page Expires: January 8, 2006