Smart Shell, Part I

You may work alone or with one other classmate on this assignment, and each person is expected to contribute equally to the effort.

Introduction

The PATH environment

Shell is the term often used for the command line interpreter of an operating system (particularly for Unix systems). That is, the shell is a program that displays a prompt, reads and parses the user input command line, executes the command and then prompts for more user input when it has finished.

To be able to execute a command, the shell needs to find where the command is located first (in which folder or directory). For this, the shell uses an environment variable called $PATH that defines search paths for a command. The path environment is a list of directories, separated by colon ':'. To see the contents of your $PATH variable in Unix, type at the shell prompt:

    echo $PATH 
You should see something similar to this:

    /bin:/usr/bin:/opt/gnu/bin:/usr/gnu/bin
This information is used as follows. When you type in a command at the shell prompt, the shell looks for the executable file in the current directory first. If not found, the shell looks in the directories defined by the search paths in order: /bin first, then /usr/bin, and so on, until either the command is found or the search paths are exhausted. If the command is found, the shell executes it. If not found, the shell simply displays the message "Command not found".

Note that: If the command name starts with the character '/' (root directory) or '.' (current directory), the search path is not used, because the path is explicitly mentioned.

What To Do

In your systems directory, create a new directory called smartshell and a C program file called smartshell.c. Using good program design practices, create one or more functions to implement the following:
  1. When the program starts running, it waits for user input

  2. Handle whatever the user typed each time the user hits the Enter key (use fgets to read user input)

  3. If the user types quit, exit the program (use strncmp to compare the first four characters in the user input with "quit")

  4. If the user types path, print out a list of each of the values (or directories) of the current PATH environment variable, one per line. To do so, use the getenv library function to obtain a pointer to the string representing the $PATH variable. Copy this string into a local buffer, then use the function strtok to extract individual tokens from the string. The delimiter in this case is the colon character.

    One specific implementation requirement is to save the paths in an array of strings before printing them out. This will come in handy when we will build more shell functionality in future assignments. Incorporate in your shell a function

        void tokenize_PATH();
    
    that creates an array of strings, with each string representing one path from the PATH environment variable. For example, if the $PATH variable has the value shown above, then this function allocates memory for a global variable searchpaths as shown below:

        

    To implement the tokenize_PATH function, use the functions InitArray and Insert from the previous assignment. Then step 4 of this assignment reduces to simply calling PrintAll. Do NOT copy these functions into your smartshell.c file. Just include the line

        #include "stringarray.h"
    
    at the beginning of your smartshell.c code.

  5. Make sure you deallocate the memory dynamically allocated for your search paths (use RemoveAll) just before your program finishes executing.

  6. Proceed to this step only after you have thoroughly tested the previous steps and made sure that they work as expected.

    If the user types where filename, consider in turn each directory listed in searchpaths and check if the indicated filename is in that directory. Once you reach a directory containing the file, print the complete path to filename and look no further. For example, if the user types in

        where gcc
    your shell should print our something like
        /opt/gnu/bin/gcc
    If none of the PATH directories (listed in searchpath) contains the file, print "filename not found" (substituting the actual name of the file for the word filename). Your where command should behave exactly like the Unix which command.

    To implement this feature, declare a pointer

        char * fname; 
    and set it to point to filename in the user command (use strtok twice). For more practice with dynamic memory management, build the complete path for the file in a dynamically allocated buffer
        char *fullpath; 
    by looping through searchpaths and using each entry i as follows:

  7. To compile, use the command
        gcc smartshell.c stringarray.c -o xsmartshell
    
    The two source files will be linked into one executable file called xsmartshell.

    To simplify your development process, you may use this Makefile and simply type in make at the shell prompt to compile your code. This saves you from typing in a long command line every time you need to compile your code.

    Makefiles are special format files that help build and manage projects composed of multiple modules. The key point to remember is that you need to insert a TAB character (not spaces) before each command in the Makefile. If interested, you may read more about using make and writing Makefiles.

Important Notes

Submission Instructions

In your smartshell directory create a text file named readme (not readme.txt, or README, or Readme, etc.) that contains:
  1. Your name(s) and assignment number.
  2. The machine you used to complete the assignment (i.e, tanner or your own machine). If you used your own machine, please be ready to demo your code to your TA or your instructor at any time upon request.
  3. A description of whatever help (if any) you received from others outside of class.
  4. An indication of how much time you spent doing the assignment outside of class.
  5. Your assessment of the assignment: Did it help you to learn? What did it help you to learn? Do you have any suggestions for improvement? Etc.
  6. Any information that will help us to grade your work in the most favorable light. In particular you should describe all known bugs.
Descriptions of your code should not be in the readme file. Instead they should be integrated into your code as comments. Your readme file should be a plain text file. Do not create your readme file using Microsoft Word or any other word processor.

Turn in a printout copy of the readme and smartshell.c files, and a sample output (one printout per team). If you work on the department Unix system, you will need to copy and paste your code into a text or a Word document in Windows, since you cannot print directly from Unix.

Leave the source code for all exercises in your directory systems/smartshell. Do not make any changes to these files after the due date for this assignment. If you wish to continue working on these exercises after the due date, make a copy of your directory smartshell using the following Unix command:

    cp -r ~/systems/smartshell ~/systems/smartshell-copy
A new directory called smartshell-copy will be created in your systems directory. You may now make any changes you want to the files in your smartshell-copy directory, at any time.

Grading

No credit will be given for code that does not compile.
100     Total points possible
 
20 Program compiles and runs without crashing
20 Each command does something resembling the specified action
50 Each command works correctly and completely
  5 You have added some extra "bells and whistles" (use your imagination)
  5 Your readme file is present

Have fun!