系统代写 |计算机代写


普渡大学 CS 252 Systems Programming


咨询 Alpha 小助手,获取更多课业帮助


Part 1: Monday, September 23 11:59pm

Goals

The goal is to build a shell interpreter combining behavior from common shells like Bash and csh. Some skeleton code is provided.

Deadlines

Part 1: Monday, September 23 11:59pm

Part 2: Wednesday, October 2 11:59pm

Part 3: Friday, October 11 11:59pm

All extra credit parts are due with the final submission.


Testing

Much of the shell will be graded using automatic testing. To run tests:

./testall partN (where N = 1, 2, or 3) runs tests for a specific part.

./testall with no arguments runs all tests.


The Assignment - Part 1

1. Login and Build:

Log in to a CS department machine (lab machine or data.cs.purdue.edu ), navigate to a preferred directory, and run

git clone ~cs252/repos/$USER/proj3.git and cd proj3 .

Build the shell by typing make and start it by typing ./shell .

2. Parsing and Executing Commands

Scanner and Parser:

Use Lex and Yacc to write a scanner and parser for the shell. The command.h file implements a data structure representing a shell command. The struct single_command represents an argument list for a single command, and the struct command represents a list of simple commands (which can be just one single_command ). It also has fields for input, output, and error redirection.

Look through the Makefile to understand how the program is built. C source code files are generated from shell.l and shell.y and then compiled.

Accepting more complex commands:

Modify shell.l and shell.y to support the grammar:

cmd [arg]* [ | cmd [arg]* ]* [ [> filename] [< filename] [2> filename]

[ >& filename] [>> filename] [>>& filename] ]* [&]

Test with commands like ls , ls -al , ls -al aaa bbb cc , ls -al aaa bbb cc > outfile , etc.


3. Executing Commands

Single command process creation and execution:

For each single command, create a new process using fork() and call execvp() to execute the executable. If the command is not in the background, the shell waits for the last single command to finish using waitpid() . Refer to the man pages for function details. The file

ls_grep.c is an example of process creation and redirection.


After this, commands like ls -al and ls -al /etc & should be executable.

File redirection:

If the command specifies IO redirection files, create them as necessary. Use dup2() to change file descriptors (0 for standard input, 1 for output, 2 for error).

Examples: ls -al > out , cat -q cat 2> dog , etc.


Notes:

2> redirects stderr to the specified file.

>& redirects both stdout and stderr to the specified file.

>> appends stdout to the specified file.

>>& appends both stdout and stderr to the specified file.


Pipes:

Use pipe() to create a pipe for inter-process communication. Redirect the output of one command to the input of the next using dup2() .

See the example in ls_grep.c .

Commands like ls -al | grep command and ls -al | grep command | grep command.o > out should work.

isatty():


When the shell uses a file as standard input, it should not print a prompt. Use isatty() to determine if the input is from a file or terminal. This is required for the automated tests to pass.

Exit: Implement a special command exit that exits the shell when run. It should be parsed by the shell and cause the shell to exit without creating a new process.


Standard rules apply:

Follow the coding standards on the course website.

The shell must compile and run on lab Linux machines.

Do not look at others' source code or work with other students.


Part 2: Wednesday, October 2 11:59pm


1. ctrl-C

Make the shell behave like bash with respect to ctrl-C . When ctrl-C is pressed while a command is running, it should interrupt and usually terminate the command. If ctrl-C is typed when no command is running, the current prompt is discarded and a fresh prompt is printed. See crtlc.c for an example of detecting and ignoring the SIGINT signal and the sigaction() man page.


2. Zombie Elimination

Set up a signal handler to catch the SIGCHLD signals sent when a child process finishes. The signal handler should call waitpid() to clean up zombie child processes. The shell should also print the process ID of the child when a background process exits in the form “[PID] exited.


3. Quotes

Add support for quotes in the shell. Arguments with spaces surrounded by quotes should be treated as a single argument. For example, myshell> ls "command.cc Makefile" should list command.cc and Makefile if they exist. The quotes should be removed before using the

argument.


4. Escaping

Allow the escape character. Any character after \ can be part of an argument, including special characters like quotation marks and ampersands. For example, myshell> echo \"Hello between quotes\" should print "Hello between quotes", and myshell> echo this is an ampersand \& this is an ampersand & should print the correct text with the ampersand.


5. Builtin Functions

Implement the following builtin commands:

printenv : Prints the environment variables of the shell. The environment variables are stored in char **environ , a null-terminated array of strings. Refer to the environ man page. setenv A B : Sets the environment variable A to value B. unsetenv A : Un-sets environment variable A .

source A : Runs file A line-by-line as if it were typed into the shell by a user. cd A : Changes the current directory to A . If no directory is specified, defaults to the home directory. Refer to the chdir() man page. These built-ins should be used like other commands, including with redirection and piping.


6 “.shellrc” When the shell starts, it should attempt to run “source.shellrc” equivalent.


Part 3: Friday, October 11 11:59pm

Moar Features - Part 3

1. Subshells

Implement subshells. Any argument of the form (expr 1 + 1) becomes echo 2 , and echo a b > dir; ls $(cat dir) lists the contents of directories a and b`.


Steps:

Extract the command between ”$(“ and ”)” in shell.l .

Invoke the shell as a child process and provide the extracted command as input using two pipes to communicate (one to write the command to the child and one to read the output from the child). Place the output obtained from the subshell into the scanner’s buffer using yy_unput(int c) in reverse order. Do not use popen() or a temporary file for interprocess communication.


2. Environment variable expansion

Implement environment variable expansion. When a string of the form ${var} appears in an argument, it will be expanded to the value corresponding to the variable var in the environment table. Also implement special expansions like ${$} (PID of the shell process), ${?} (return code of the last executed simple command), ${!} (PID of the last background process), ${!!} (run the last command again), ${_} (last argument in the previous command excluding redirects), ${SHELL} (path of the shell executable, can use realpath() to expand the relative path).

3. Tilde expansion

When ~ appears by itself or before $"/" it will be expanded to the home directory of the current user. If ~ appears before a word, the characters after ~ up to the first $"/" will be expanded to the home directory of the user with that login. Tilde expansion should not happen within double quotes.

4. Wildcarding

Implement wildcarding as follows:

First, handle wildcarding only within the current directory:

Before inserting a new argument in the current simple command, check if it contains a wildcard character (* or?). If so, insert the file names that match the wildcard (include their absolute paths). Use opendir and readdir to get all entries of the current directory. Use regcomp and regexec to find the entries that match the wildcard (convert from wildcards to regular expressions as needed, see regular.cc example). Commands like echo * , echo *.c , echo shell.? should work. Then make it work for any path (examples: echo */* , echo */*/* ). Do not use the glob() call.