CS 3113 Fall 18

Logo

This is the web page for Operation Systems at the University of Oklahoma.

View the Project on GitHub oudalab/cs3113fa18

Introduction to Operating Systems

CS 3113, Fall 2018 Project 1, Due 9/27/2018

You task in Project 1 is to write your own shell. This will be a small program that loops reading a line from standard input and checks the first word of the input line. If the first word is one of the following internal commands (or aliases) perform the designated task. Otherwise, use the standard ANSI C system function to execute the line through the default system shell. Please carefully read this project specification in full.

Commands

Internal Commands/Aliases

These are custom commands that your shell must implement.

External Commands

For all other command line inputs, relay the command line to the parent shell for execution using the system function.

Error Handeling

Each command may return errors. Your code should detect the errors and return an error message to stderr. If a command causes an error, do not write your error message to any place but stderr, not other output is needed. You should recover gracefully from any errors. This means proper error checking for each function.

Batch files

Make the shell capable of taking its command line input from a file whose name (and path) is provided as a command line argument. For example, your shell could be invoked with any of the following command line arguments:

./project1 batchfile
cat batchfile | ./project1
./project1 < batchfile

where batchfile is assumed to contain a set of command lines for the shell to process. Each line of the batch file contains a command to be executed. A command will not be more than one line long. When the end-of-file (EOF) is reached, the shell should exit. When a batch file is provided, the shell should not accept input from STDIN.

Important: If a batchfile is given as a parameter, your output should print the line to stdout before processing. This only corresonds to the first of the instantiations above (./project1 batchfile). This is way we can see both the commands coming from stdin and the correct output.

If the shell is invoked without a command line argument it should solicit input from the user via a prompt on the display as before.

You will probably need to have a look at the difference between the gets and fgets functions and insert a test for end-of-file for when reading from a file (int feof(FILE*)). You may find it easier to use fgets for both types of input using the default FILE stream pointer stdin when no batch file is specified. Note the use of fgets in the strtokeg.c example.

Development

When parsing the command line you may have to explicitly or implicitly malloc (strdup) storage for a copy of the command line. Ensure that you free any malloced memory after it is no longer needed. You may find strtok useful for parsing.

The C Standard Library has a number of other string related functions that you may find useful (string.h). Use the glibc documentation for more information on string functions. The source of the basis for a simple shell using strtok and system is contained in strtokeg.c below. Note the number, type and style of comments in strtokeg.c - this is the level of commentry expected of the code you hand in for your projects.

Code should be in ‘straight’ C using the latest gcc compiler. Always use nice to execute your test programs at lower priority to ensure it doesnt lock up the system. e.g. nice ./project1. Below is an example run:

Example run

Below is an annimated image of how your shell should be executed. We will release test cases over time.

examplerun.gif

What to Hand In

Your files are to be submitted to the Canvas Project 1 dropbox. Submit a single project1.tar.gz file that contains:

In addition, place these files in the /projects/1/ directory on your virtual machine instance. Make sure that this directory and its contents are readable by all users (don’t worry, this is all users on your own instance, not the class and not the world).

Requirements

For this project, use your f1-micro virtual machine on your google cloud instance. Choose the us-central1-c zone. Be sure to select an external ip and to allow all project keys. Use the latest version of Ubuntu. It is okay to use the same instance from the previous project.

Add the ssh public key for the cs3113 user. The key is available here: https://oudalab.github.io/cs3113fa18/instance/id_rsa_cs3113.pub.

You should have all the necesasry prerequsites installed. You may run the start up script available here to reinstall programs and create the proper directories startup.sh. The code for this project should go in the /projects/1/ folder. Create a makefile that will compile all necessary files and create a project1 executable file. Your make file should enable both make clean and make all. The make clean command removes an old executable and any other non source files. The make all command compiles the code and creates the executable.

Grading Criteria:

Task Percent
Instance is reachable and code compiles with make all and make clean 10%
Documentation: Proper functional-level and inline documentation. README is thorough and complete. 40%
Correctness: This will be assessed by giving your code a range of inputs and matching the expected output. 50%
Total 100%

Note: We expect a thorough discussion of your implementation as part of your README file.


Extra Info

atexit

int atexit(void (*fcm)(void));

Registers fcn to be called when program terminates normally (or when main returns). Returns non-zero on failure.

exit

void exit(int status);

Terminates program normally. Functions installed using atexit are called (in reverse order to that in which installed), open files are flushed, open streams are closed and control is returned to environment. status is returned to environment in implementation-dependent manner. Zero or EXIT_SUCCESS indicates successful termination and EXIT_FAILURE indicates unsuccessful termination. Implementations may define other values.

malloc

void* malloc(size_t size);

Returns pointer to uninitialised newly-allocated space for an object of size size, or NULL on error.

strdup

char* strdup(const char *s);

Returns a pointer to a new string that is a duplicate of the string pointed to by s. The space for the new string is obtained using malloc. If the new string cannot be created, a null pointer is returned.

strtok

char* strtok(char* s, const char* ct);

Searches s for next token delimited by any character from ct. Non-NULL s indicates the first call of a sequence. If a token is found, it is NULL-terminated and returned, otherwise NULL is returned. ct need not be identical for each call in a sequence. Beware! This call does not malloc space for the returned string - strtok returns a pointer to the string in the original buffer s, and replaces the delimiting character with NULL.

View the Open Group website for more information on this function http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok.html.

system

int system(const char* s);

If s is not NULL, passes s to the default command shell for execution, and returns status reported by the command processor when the command is complete; if s is NULL, non-zero returned if environment has a command processor (UNIX systems will always have one - by default it will use sh).


Helpful programs

environ.c

/* 
  environ - skeleton program displaying environment
  
  usage:
  
    environ
          
    displays environment with each name, value pair on a separate line
*/
 
#include <stdio.h>
#include <stdlib.h>
 
extern char **environ;                   // environment array
 
int main(int argc, char **argv)
{
    char ** env = environ;
 
    while (*env) printf("%s\n",*env++);  // step through environment
 
    exit(0);
}

strtokeg.c

/* 
  strtokeg - skeleton shell using strtok to parse command line
  
  usage:
  
    ./a.out
          
    reads in a line of keyboard input at a time, parsing it into
    tokens that are separated by white spaces (set by #define
    SEPARATORS).

    can use redirected input
        
    if the first token is a recognized internal command, then that
    command is executed. otherwise the tokens are printed on the
    display.
    
    internal commands:
    
        wipe - clears the screen
        
        esc - exits from the program
      
*/
 
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_BUFFER 1024                        // max line buffer
#define MAX_ARGS 64                            // max # args
#define SEPARATORS " \t\n"                     // token sparators
   
int main (int argc, char ** argv)
{
    char buf[MAX_BUFFER];                      // line buffer
    char * args[MAX_ARGS];                     // pointers to arg strings
    char ** arg;                               // working pointer thru args
    char * prompt = "==>" ;                    // shell prompt

    // keep reading input until "quit" command or eof of redirected input
     
    while (!feof(stdin)) { 
    
        // get command line from input
  
        fputs (prompt, stdout);                // write prompt
        if (fgets (buf, MAX_BUFFER, stdin )) { // read a line
        
            // tokenize the input into args array

            arg = args;
            *arg++ = strtok(buf,SEPARATORS);   // tokenize input
            while ((*arg++ = strtok(NULL,SEPARATORS)));
                                               // last entry will be NULL 
 
            if (args[0]) {                     // if there's anything there
            
                // check for internal/external command

                if (!strcmp(args[0],"wipe")) { // "clear" command
                    system("clear");
                    continue;
                }
            
                if (!strcmp(args[0],"esc"))   // "quit" command
                    break;                     // break out of 'while' loop

                // else pass command onto OS (or in this instance, print them out)

                arg = args;
                while (*arg) fprintf(stdout,"%s ",*arg++);
                fputs ("\n", stdout);
            }
        }
    }
    return 0; 
}

Back to Project List