CPSC 457: Operating Systems

Professor Carey Williamson

Fall 2008

Assignment 1 (30 marks) Due: October 2, 2008 (11:59pm)

The purpose of this assignment is to provide you some experience as a user of a Linux operating system, via some shell programming, as well as via some C programming (and system calls) to implement your very own simple shell. You can do your development and testing either in a regular Linux environment, or in a UML environment (your choice).

Shell Programming: Big Files (5 marks)

Write a Linux shell script biggies that reports information about big files. Starting from the directory in which it is invoked, this script should find the N largest files (in bytes) that reside at or beneath that directory in the Linux file system. The value of N is an optional command line parameter, with default value 10. That is, "biggies 1" will report the largest file, "biggies 5" will report the top 5 largest files, "biggies 20" will report the top 20 largest files, and "biggies" with no argument will report the top 10 largest files.

Print the resulting file names and sizes in (decreasing) sorted order by size, with the largest file first. Use an output format similar to that generated by "ls -l". Ties for any placing in the top N can be printed in arbitrary order. If fewer than N files exist at or beneath that directory in the file system, then print only as many files as are in existence. Note that only regular files should be considered for this list, not directories, devices, or special files. Error messages for files or directories that are not readable should be suppressed.

Provide brief documentation (perhaps as comments in your shell file) explaining how to run your script, and how it works. As sample output, show the results from running "biggies" in your home directory, as well as the output that it produces on /usr in your Linux or UML environment.

Shell Programming: Old Files (5 marks)

Write a Linux shell script oldies that reports information about old files. Starting from the directory in which it is invoked, this script should find the N oldest files (in terms of the last file modification date recorded by the Linux file system) that reside at or beneath that directory in the Linux file system. The value of N is an optional command line parameter, with default value 10. That is, "oldies 1" will report the oldest file, "oldies 5" will report the top 5 oldest files, "oldies 20" will report the top 20 oldest files, and "oldies" with no argument will report the top 10 oldest files.

Print the resulting file names and sizes in (decreasing) sorted order by age, with the oldest file first. Use an output format similar to that generated by "ls -l". Ties for any placing in the top N can be printed in arbitrary order. If fewer than N files exist at or beneath that directory in the file system, then print only as many files as are in existence. Note that only regular files should be considered for this list, not directories, devices, or special files. Error messages for files or directories that are not readable should be suppressed.

Provide brief documentation (perhaps as comments in your shell file) explaining how to run your script, and how it works. As sample output, show the results from running "biggies" in your home directory, as well as the output that it produces on /usr in your Linux or UML environment.

(Note: The "oldies" script will be somewhat harder than "biggies". If you can solve it, then great. But if you get stuck, don't beat your brains out. Just hand in what you have, and annotate it with a description of what you are TRYING to do, even if you don't get it to work exactly right on Linux.)

C Programming: My Shell (20 marks)

One of the beauties of the Unix world is that there are many user shells to choose from for your command line interface (e.g., C shell, Korn shell, Bourne shell, Bourne-again shell). Even better yet, if you don't like any of them, you can write your very own shell.

In this question, you will write your own version of the shell called myshell. Along the way, you should learn a lot about C programming, I/O, processes, signals, interrupts, concurrency, and debugging.

The implementation of this shell will proceed in stages, starting from a simple, primitive shell like "smallsh" (from the Unix System Programming book by Haviland et al.), and then gradually adding functionality to the shell, including special character handling, environment information, I/O redirection, signal handling, and perhaps even pipes.

You are encouraged (but not required) to do your work in incremental steps (e.g., completing part 1 before moving on to part 2, and so on), and to save a working version of your shell at each step (e.g., "myshell1" for part 1, "myshell2" for part 2, and so on), so that if things really get messed up (and they will!), you always have a clean working version as a backup.

When you are all done, you only need to hand in the final product "myshell", documenting it accordingly, and showing that it has all the functionality described below in parts 1 through 5. (If you only get partway through implementing all of the functionality listed here, then hand in what you have, and document accordingly.)

Part 1 (2 marks): Write a C program "myshell" based on the sample code provided here for "smallsh": smallsh.c smallsh.h userinput.c processline.c runcommand.c (new version), and Makefile You can copy the code and coding structure as much as you wish, but some porting may be necessary to make this simple shell work in your Linux or UML environment. Please make use of a Makefile and multiple source code files. Show that your shell can properly execute typical Linux commands, and that your shell exits gracefully.

Part 2 (3 marks): Extend your "myshell" so that it correctly interprets comments, as indicated by a leading '#' character. Show that your shell can properly execute typical Linux commands, as well as simple shell programs that you have written (e.g., biggies).

Part 3 (5 marks): Extend your "myshell" to support a "cd" (change directory) command. Given one argument specifying the name of a directory, cd changes the current working directory of the currently executing shell. Given no arguments, cd changes the current working directory of the shell to the user's home directory (by default). If the target directory does not exist, or the permissions do not allow you to cd there, then an error message should result.

Part 4 (5 marks): Extend your "myshell" to support I/O redirection for standard input and standard output. (Don't worry about standard error.) That is, the "<" character indicates that the next item on the command line should be interpreted as an input file (with an appropriate error message if it does not exist), and the ">" character indicates that the output of the command should be written to the indicated file (created if needed) rather than writing the output to the screen.

Part 5 (5 marks): Extend your "myshell" to handle signals (i.e., interrupts) more like a real Linux shell handles them. In particular, the "control-C" keyboard interrupt should be able to terminate a foreground process that was started by "myshell", without killing "myshell" itself, and background processes started from within "myshell" should not be terminated by either SIGINT or SIGQUIT generated from the keyboard. If you feel adventurous (not required), you can also try to support the "suspend" keyboard interrupt (usually control-Z), which can be used in conjunction with "bg" and "fg" to control foreground and background execution of processes started from within "myshell".

Bonus (5 marks): Extend your "myshell" to support the traditional UNIX "pipe" ('|') feature. Demonstrate that it works by showing some examples in your documentation (e.g., cat myshell.h | grep define | wc -l)