Assignment 3, due Sept. 13

Part of the homework for 22C:112, Fall 2013
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

On all assignments, your name must be legible as it appears on your University ID card! Assignments are due at the start of class on the day indicated (usually Friday). Exceptions will be by advance arrangement unless there is what lawyers call "an act of God" (something outside your control). Homework must be turned in on paper, either in class or in the teaching assistant's mailbox. Never push late work under someone's door!

  1. Background: Look at the code for the minimally usable shell, mush.c distributed here:

    http://www.cs.uiowa.edu/~jones/opsys/notes/mush.txt

    a) As written, the code only allows blanks (that is ' ') as delimiters between the arguments of a shell command. What routine would need to be changed and how many lines of code would you need to add or change in order to make the code permit both blanks and tabs (that is, '\t') as delimiters. Do not give the code, just give the routine name and number of lines. (0.5 points)

    b) The call to execve in launch() passes NULL as its third parameter (the environment). How would you change this so that it passes the environment that was passed to the caller? Hint: You might want to use man execve and man environ to learn more. Do not give variable definitions. Just give the modified code for the execve statement. (0.5 points)

  2. Background: Consider this fragment of bash shell script:
    if [ -x thisfile ]
    then
        thisfile
    else
        if [ -x thatfile ]
        then
            thatfile
        else
            echo failure
        fi
    fi
    exit
    

    In bash, the [ -x f ] predicate returns true if its argument f is the name of an executable file.

    A problem: Write equivalent C code, using execve() to launch either thisfile or thatfile or output the error message failure. Hint: This can be done in 4 lines of reasonably formatted C code; examine how launch() in mush.c works. code would it take> (1.0 points)

  3. Background: Consider the C standard library routines fseek() and ftell(); these are implemented by middleware on top of the Linux kernel call lseek(). The man shell command documents all of these. Note that the C standard library routines fputc() and fgetc() could be implemented as follows, where file variables are simply pointers to the integer file descriptor (a very bad design):
    int fputc( int c, FILE *f ) {
         write( *f, &(unsigned char)c, 1 );
         return c;
    }
    
    int fgetc( FILE *f ) {
         unsigned char c;
         if (read( *f, &c, 1 ) == 1) return (int) c;
         return EOF; /* if it did not return a character */
    }
    

    A Problem: Write very brief (and equally stupid) C implementations for fseek() and ftell(). Do not handle error conditions. The body of each of your routines is likely to be just one line. (1 point)

 

Machine Problem II

Due Monday, Sep. 23

You will have to modify a version of mush.c. The first and most obvious thing to do is get a copy of mush and make sure you can compile and test it.

Note that mush has more defects than features. It has no built-in commands. The exit command is the most obvious of these. Without an exit command, you have to break out of mush using the Control-C keypress. There is no search path, so instead of typing echo hello world you have to type /bin/echo hello world -- explicitly telling it where the binary is stored. As mentioned in the homework 3 problem 1, there are other missing features.

Of the above, the only problem you should solve for this machine problem is to pass the environment that was passed to mush onward to any programs it launches.

Your primary job is to make the shell understand the search path. Homework 2 problem 2 is central to understanding how to do this.

You will have to use something like this to get the value of the path variable from the environment:

char * path;
path = getenv( "PATH" );

Note that the components of the path are separated by colons (you can see your path with the shell command echo $PATH). You cannot safely edit the path in place, because that would destroy the path passed on to launched programs. Here is a safe way to make a copy of a string:

copy = strcpy( malloc( strlen( original ) ), original );

Suppose the user typed the com command and you want to see if this is in the directory direct. What you need to do is concatenate the two, with a slash between them. Here is code to safely concatenate a left string to a right string into a result string:

result = strcat( strcpy( malloc( strlen( left )
                               + strlen( right )
                               + 1 /* allows for null terminator */
                               )
                       , src1
                       )
                 src2
               );

You may need to look up and understand the man page for each routine you use.

Your solution should conform, as much as is reasonable, to the manual of style. Your solution must be in a file named mp2.c and you should submit it using the coursework submission tools, as for mp1 but in the mp2 directory for the course.

Comments

Many students have asked: How can I test it? How will the result behave differently?

First: Passing the environment to the launched application will make the entire environment available. Compare typing the env command to the default tcsh shell with typing the /bin/env command in mush. Without passing the environment to the launched application, the latter produces no output. With passing the environment, they should produce identical output.

Second: Interpreting the search path means that you should no longer need to type, for example, /bin/env to launch the env command. You should still be able to type just env, exactly as it works in tcsh. Of course, you should still be able to type /bin/env or ./mush.

What about compiler warnings? Many of these indicate real errors. Therefore, you should take warnings seriously.