Assignment 3, due Feb. 3
Part of
the homework for 22C:112, Spring 2012
|
The C standard library provides the strncpy() and strncat() routine to copy and concatenate strings. So, you can write: write:
char filename[100]; filename[100] = '\000'; strncpy( filename, "/bin/", 99 ); strncat( filename, argv[0], 99 );
With this code, if argv[0] was "echo", filename will end up being "/bin/echo".
a) Why set filename[100] to NUL and then why limit the copied and concatenated strings to 99 characters? This is purely a question about C. (0.5 points)
First, there are some bugs here. In the call to strncat(). The call should have been:
strncat( filename, argv[0], 99-strlen(filename));This is because the limit on strncat is not the buffer size, but the maximum amount by which the length of the string may be extended.
The second bug is that the assignment to filename[100] should have been an assignment to filename[99]. These were my errors, so you are not required to have found them.
Now, to the issue: In a 100 character buffer, one must be reserved to hold the trailing null. If strncpy() or strncat() are asked to copy too many characters, they simply truncate the string, and it is not clear from the documentation that they are guaranteed to put a null at the end.
b) Write a new version of launch() that has a hard-coded search path, trying these directories in sequence: /bin/ and then /usr/bin/, and then ./ (the current directory). Note that this can be done by changing one line and adding well under 15 lines of new code to the original. (1.0 points)
void launch(){ if (fork() == 0) { /*child*/ char buf[100]; buf[99] = '\000'; strcpy(buf, "/bin/"); strncat(buf, argv[0], 99-strlen(buf)); execve(buf, argv, NULL); strcpy(buf, "/usr/bin/"); strncat(buf, argv[0], 99-strlen(buf)); execve(buf, argv, NULL); strcpy(buf, "./"); strncat(buf, argv[0], 99-strlen(buf)); execve(buf, argv, NULL); printf("no such command\n"); } else { /*parent*/ wait( NULL ); } }
a) What was the most interesting feature linking the OS-8 command-language interpreter to its I/O drivers (including support for a rudimentary file system)? (0.5 points)
A rudimentary I/O redirection mechanism using the ASSIGN directive to the command line intrpreter.
b) Did OS/8 impose any discipline on the user's use of memory? Contrast this with the rudimentary system described in the lecture notes for Jan. 30. (0.5 points)
The system "owned" the top 128 words of fields 0 and 1 of memory. Aside from that, it imposed nothing on applications.
A Question: Why is relocation still valuable? (0.5 points)
Relocation may no longer be needed at load time, but it is still needed to allow linking of separately compiled routines.
Modify the mush.c Minimally Usable SHell so that it uses the search path found in the environment variable PATH. When running in any of the standard shells, you can examine this using the shell command echo $PATH.
The value of the variable PATH is a string consisting of a number of substrings delimited by colons. A typical but unusually short path might look like this:
/bin:/usr/bin:/usr/local/bin:.
Assuming that the user types in cmd as a shell command, the above path means that the shell should try to exec each of the following programs, in sequence, until one of them worked:
/bin/cmd /usr/bin/cmd /usr/local/bin/cmd ./cmd
Only if none of the above can be exec'd should the shell give up and report an error message indicating that the command is undefined.
To implement this, your modified version of mush must call getenv("PATH") to get the value of the environment variable. Note that this returns a pointer to the string in the environment data structure, it does not make a working copy. You can look up the documentation for getenv() (and all other library routines) using the man command. For example, try the man getenv shell command
You will probably want to make a working copy of the path, using strcpy() or strncpy() into an appropriate sized buffer. A safe way to allocate a buffer large enough is to use malloc() to allocate a buffer the right size for the path, where a call to strlen() was used to find the length of the string holding the path. The following is a safe way to make a working copy of the path, assuming appropriate declarations:
workpath = strcpy( malloc( strlen(path)+1, path );Once you have a working copy, you can chop it into substrings using logic similar to that used by parseargv() in mush.
Finally, you should modify the launch() routine in mush so that it tries to exec each of the components in the path, in turn. To do this, it will have to concatenate each component with a / character, and the value of argv[0]. The strncat() or strcat() library routine can be used for this does this. Note that these concatenation routines do not allocate a new buffer, so if you want to concatenate, you must first make sure that you have a buffer big enough to hold the result.
Note that your solution will be graded on two different issues:
You are not responsible for improving the (awful) quality of the parts of mush you have been given, but you must make sure that all of the code you add is written very well. The programming guidelines in the Manual of style for C programmers should be followed in all code you add, and in modifying the program header to reflect changes you have made.
Submit your solution using the coursework submission tools documented at:
-- http://www.divms.uiowa.edu/help/msstart/submit.html
In short, you will type the shell command submit, with no arguments, and when it prompts for a file name, you will type mush.c, and then an extra carriage return to indicate that there is only one file in your submission. When it prompts for a course, type c_112 and finally, when it prompts for an assignment directory, enter mp2.