Home | | Schedule | | Assignments | | Lecture Notes
//********************************************************
// 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;
}
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