[SOLVED] C: CS241 Shell

$25

File Name: C:_CS241_Shell.zip
File Size: 131.88 KB

5/5 - (1 vote)

Well, well keep it short, you got fired. Your boss brought you in for a code review and was more than disappointed. Apparently, he wanted a text editor like this one : we didnt get the memo. Now its time to prove your worth. Your boss wanted something fully functional and weve got a great suggestion (NOTE: this is not a suggestion but a required assignment). Youre going to drop a :fire: :fire: shell on him to get rehired. The basic function of a shell is to accept commands as inputs and execute the corresponding programs in response. You will be provided the Log , Vector , and format libraries for your use. Hopefully, this will make things right and you can resume your work at insert hot tech company here . Feel free to refer to the unix shell as a rough reference. If you want to build a kernel that actually uses your shell we cannot offer you some extra credit, but we really cant stop you from doing that.

format.h

Since this MP requires your programs to print a variety of things like error messages, we have provided you with our own highly customized formatting library. You should not be printing out to stdout and stderr at all; instead, all output and errors should be printed using the functions provided in format.c and format.h . In format.h you can find documentation of what each function does and you should use them whenever approriate. This is our way of ensuring that you do not lose points for formatting issues, but it also means that you are responsible for handling any and all errors mentioned in format.c and format.h .

Overview

The shell is responsible for providing a command line for users to execute programs or scripts. You should be very familiar with bash by now, which will be the basis for your own shell. Beyond the basics, your shell will be providing a few extra features, including executing programs in the background, keeping a command history, and running scripts.

Starting your shell

The shell should run in a loop like this executing multiple commands:

  • Print a command prompt
  • Read the command from standard input
  • Print the PID of the process executing the command (with the exception of built-in commands), and run the command

The shell must support the two following arguments:

History

-h takes the filename of the history file. The shell should load in the history file as its history. Upon exit, the exact same history file should be updated, even if cd is used in the shell.

./shell -h <filename>

Even if the the -h flag is not specified, the shell will still keep a history of commands run. Just think of it like private browsing mode for your terminal.

File

-f takes the name of the file to be executed by the shell. The shell will both print and run the commands in the file in sequential order until the end of the file. See the following example file and execution:

commands.txt

cd cs241echo Hey!
./shell -f commands.txt(pid=1234)/home/user$ cd cs241(pid=1234)/home/user/cs241$ echo Hey!Command executed by pid=1235Hey!

The user may supply these arguments together, separately, or not at all, and in any order. Each of these cases must be supported, and the appropriate errors should be printed out if the user supplies invalid arguments.

The getopt function may come in handy. :smile:

Specifics

Prompting

When prompting for a command, the shell will print a prompt in the following format:

(pid=<pid>)<path>$

<pid> is the current process ID, and <path> is a path to the current working directory. Note the lack of a newline at the end of this prompt.

Reading in the Command

The shell will read in a command from stdin (or a file if -f was specified).

Running the Command

The shell should run the command that was read in previously.

If the command is run by a new process, the PID of the process should be printed like this:

Command executed by pid=<pid>

This should be printed before any of the output of the command is printed.

History

Your shell should store the command that was just executed. Every command should be stored unless otherwise noted. We provide to you a log data structure to simplify handling this history, which can be found in log.h .

Catch Ctrl+C

Usually when we do Ctrl+C , the current running program will exit. However, we want the shell to ignore the Ctrl+C signal ( SIGINT ). The shell should not exit upon receiving SIGINT .

Exiting

The shell will exit once it receives a EOF. From the interactive command line, this is sent by typing Ctrl+D on an empty line, and from a script file (as used with the -f flag) this is sent once the end of the file is reached. The history file (if specified) should be saved after EOF is received.

Commands

Shell supports two types of commands: built-in and external (i.e. non-built-in.) While built-in commands are executed without creating a new process, an external command must create a new process to execute the program for that particular command.

Command arguments will be space separated without trailing whitespace. Your shell does not need to support quotes (for example, echo "hello there" ). Keep it simple.

Built-in Commands

cd <path>

Changes the current working directory of the shell to <path> . Paths not starting with / should be followed relative to the current directory. If the directory does not exist, then print the appropriate error.

(pid=1234)/home/user$ cd code(pid=1234)/home/user/code$ cd imaginary_directoryimaginary_directory: No such file or directory(pid=1234)/home/user/code$

!history

Prints out each command in the history, in order. Do not store this command in the history.

(pid=1234)/home/user$ !history0ls -l1pwd2ps(pid=1234)/home/user$

:warning: This command is not stored in history.

#<n>

Prints and executes the nth command in history (chronological order), where n is a non-negative integer. Other values of n will not be tested. Note that the command run should be stored in the history. If n is not a valid index then print the appropriate error and do not store anything in the history. Note that this command is never stored in the history, only the command that is being referenced in the history.

The following example assumes a fresh history:

(pid=1234)/home/user$ echo Echo This!Command executed by pid=1235Echo This!(pid=1234)/home/user$ echo Another echoCommand executed by pid=1236Another echo(pid=1234)/home/user$ !history0echo Echo This!1echo Another echo(pid=1234)/home/user$ #1echo Another echoCommand executed by pid=1237Another echo(pid=1234)/home/user$ #9001Invalid Index(pid=1234)/home/user$ !history0echo Echo This!1echo Another echo2echo Another echo(pid=1234)/home/user$

:warning: Print out the command before executing if there is a match.

:warning: This command is not stored in history, only the command being executed (if any).

!<prefix>

Prints and executes the last command that has the specified prefix. Note that the command run should be stored in the history. If no match is found print the appropriate error and do not store anything in the history. Note that this command is never stored in the history, only the command that is being referenced in the history. The following example assumes a fresh history:

(pid=1234)/home/user$ echo Echo This!Command executed by pid=1235Echo This!(pid=1234)/home/user$ echo Another echoCommand executed by pid=1236Another echo(pid=1234)/home/user$ !eecho Another echoCommand executed by pid=1237Another echo(pid=1234)/home/user$ !echo Eecho Echo This!Command executed by pid=1238Echo This!(pid=1234)/home/user$ !dNo Match(pid=1234)/home/user$ !echo Echo This!Command executed by pid=1239Echo This!(pid=1234)/home/user$ !history0echo Echo This!1echo Another echo2echo Another echo3echo Echo This!4echo Echo This!(pid=1234)/home/user$

:warning: Print out the command before executing if there is a match.

:warning: This command is not stored in history, only the command being executed (if any).

Invalid built-in commands

Note that invalid built-in commands should be stored in the history.

(pid=1234)/home/user$ cd /imaginary_directory/imaginary_directory: No such file or directory(pid=1234)/home/user$ !history0cd /imaginary_directory(pid=1234)/home/user$

External Commands

For commands that are not built-in, the shell should consider the command name to be the name of a file that contains executable binary code. Such a code must be executed in a process different from the one executing the shell. You must use fork() , exec() , and wait() .

The fork() , exec() , wait() paradigm is as follows: fork() a child process. The child process must execute the command with exec() , while the parent must wait() for the child to terminate before printing the next prompt. You are responsible of cleaning up all the child processes upon termination of your program. It is important to note that, upon a successful execution of the command, exec() never returns to the child process. exec() only returns to the child process when the command fails to execute successfully. If any of fork() , exec() , or wait() fail, the appropriate error should be printed. For example:

(pid=1234)/home/user$ invalid_command --flag-that-is-ignored also_ignored also_ignoredCommand executed by pid=1235invalid_command: not found(pid=1234)/home/user$

:warning: All external commands should be stored in the history, even ones that are invalid.

Some external commands that you may try to see whether your shell works as it should are:

/bin/lspwdpsecho hello

It is good practice to flush the standard output stream before the fork to be able to correctly display the output.

:bangbang: Please read the disclaimer at the top of the page! We dont want to have to give any failing grades. :bangbang:

&

A command suffixed with & should be run in the background. The shell should be ready to take the next command before the given command has finished running. There may or may not be a single space between the rest of the command and & . For example, pwd& and pwd & are both valid. Additionally, since spawning a background process introduces a race condition, it is okay if the prompt gets misaligned as in the following example:

(pid=1873)/home/user$ pwd &(pid=1873)/home/user$ Command executed by pid=1874/home/userWhen I type, it shows up on this line

While the shell should be usable after calling the command, after the process finishes the parent is still responsible for waiting on the child (hint: catch a signal). Avoid creating zombies!

Grading, Submission, and Other Details

Please fully read details on Academic Honesty . These are shared between all MPs in CS 241.

We will be using Subversion as our hand-in system this semester. Our grading system will checkout your most recent (pre-deadline) commit for grading. Therefore, to hand in your code, all you have to do is commit it to your Subversion repository.

To check out the provided code for shell from the class repository, go to your cs241 directory (the one you checked out for know your tools) and run:

svn up

If you run ls you will now see a shell folder, where you can find this assignment! To commit your changes (send them to us) type:

svn ci -m "shell submission"

Your repository directory can be viewed from a web browser from the following URL: https://subversion.ews.illinois.edu/svn/fa16-cs241/NETID/shell where NETID is your University NetID. It is important to check that the files you expect to be graded are present and up to date in your svn copy.

Compile and Run

Because we have provided Log and Vector as precompiled archive files, please make sure to work on this assignment on your student VM. We cant say what will happen on any other machine when you try to compile the assignment.

To compile the release version of the code run:

make

This will compile your code with some optimizations enabled. If you use a debugger on the release build, it will not be able to show you the original source code, or line numbers, most of the time. Optimizations sometimes expose some bugs in your code that would not show up when no optimizations are enabled, but since optimizations tend to reorder your code while compiling, an optimized version of your code is not optimal for debugging.

To compile your code in debug mode, run make debug instead of make

If you compile in release mode, you will an executable called shell . If you compile in debug mode, you will get an executable call shell-debug .

Reviews

There are no reviews yet.

Only logged in customers who have purchased this product may leave a review.

Shopping Cart
[SOLVED] C: CS241 Shell
$25