关键词 >
homework 3
发布时间:2020-04-20
Introduction
The goal of this assignment is to become familiar with low-level Unix/POSIX system calls related to processes, file access, and interprocess communication (pipes and redirection). You will write a basic shell which supports a few basic operations to understand the basics of how th e bash shell terminal works.Takeaways
After completing this homework assignment, you should:- Understand process execution, pipes, and forks
- Have an advanced understanding of Unix commands and the command line
- Have gained experience with C libraries and system calls
- Have enbanced your C programming abilities
Hints and Tips
- Refer to the Lecture Slide examples in Module2 Part2 Slides ECF Signals.pdf for specific examples of how a signal handler is used. Refer to Lecture Slide examples in Module2 Part3. Slides System IO.pdf for examples and explanations of redirection and pipes.
- Check the return codes of all system calls. This will help you catch errors. Examples of how to write error handling wrapper functions are in the lecture notes. Utilizing this type of coding practice will help you to catch errors as you program. However, your shell should not exit on error as shown in the examples.
- Your shell should NEVER crash. We will be deducting points for cach time your program crashes during grading. Make sure that your code handles invalid input gracefully.
- All grading for this assignment will be performed via Gradescope. This means that all of your error messages must use the defined ERROR strings in icssh. h. All output will expect to be in a very specific format. Any extra newlines, spaces, or debugging messages may cause test cases to fail. Use the -DDEBUG flag discussed in the extended debugging document (Resources section of Module 1) to avoid printing your debugging output all the time.
- To debug using gdb, you will need to instruct the debugger on which process to follow, parent or child, upon fork. Information about the gdb settings can be found here.
- The readline library, which is used to add "quality of life" features for the user typing in commands, does not free all of its internal allocated data structures upon exit of the program. We have created a suppression file to ignore these error when valgrind is run. Use the following valgrind flags:
--memcheck: leak- check=full -- show-reachable=yes --suppressions=rsrc/ icssh. supp
Getting Started
Download the base code for this assignment: hw3。tar. The structure is:![](/Uploads/20200422/5e9ffca3d3ac6.png)
For this assignment, we have created the following base files for your use
- Makefile - A file which defines how to cormpile and link a program for the command-line utility make. The makefile targets are all, debug, and clean. This will build the executable bin/53shell
- include/ - Header files for each part of the assignment. All headers include header guards. Do not modify any of the provided header fles. Declare any of your own helper functions in helpers .h.
- 1ib/ - Pre-compiled libraries for linking with your programs. Source code is not provided for these functions. Descriptions of these functions are provided in the associated header files.
- src/ - Your shell implementations MUST go in these fles. Place any helper functions you want to create in helpers.c
Restrictions & Important Information
The provided base code will compile and run a simple shell program. It demonstrates the basic concept of a shell program. However, it lacks some important features:
- There is a limit of 32 distinct arguments per program (argc <= 32). Also, each argument string can be at most 63 characters in length.
- Any printed error messages or print statements in this document MUST BE exactly as stated - USE THE MACROS provided in icssh.h. We will be grep-ing (man_ grep) your output for these strings during grading. If the strings are not found, you will not be awarded points.
- Executables may be stored anywhere on your computer. For example, the program cat may be located in /bin/cat while grep may be located in /usr/bin/grep. You never have to specifically type /bin/cat though. The reason for this is that the execvp() syscall your shell will automatically search common paths for programs. As such your shell can only run programs which are located within one of the directories in the list specified by the PATH environment variable or the current directory (where your shell program was run from).
- In general, you may use almost any standard library function or system call to complete this homework. There is one important exception: you may not use the system( 3) function. This function is efectively a wrapper for a shell and using it would defeat the purpose of the whole assignment. Speaking more broadly, any library function or system call that is effetively a wrapper for another shell is prohibited in this assignment. Using any of these functions will result in an automatic zero for the assignment.
icssh. c file provides a basic shell which supports the following basic functionalities:
- Installs a SIGSEGV signal handler.
- Prints a command prompt and waits for user input: <53she11>$
- Reads in the user command string (job commands) from the user via STDIN (User must press enter)
- Tokenize and parse the entered job command into a linked list data structure, job_ info, of separate process commands
- Only valid job commands will be returmed. All invalid commands will print an error message and returm NULL.
- The provided tokenizer will treat all characters between double-quotes as a single token.
- For each valid command entered, the function debug_ print_ job will print the values of the returmed linked list data structure.
- If the command is a built-in, execute the built in functionality.
- The shell will terminate if the user types the built- in command, exit. ) If itis not a built-in command, fork a child process and attempt to run the entered command using execvp(). The parent process waits for termination of the child process before accepting another command.
- Repeatedly take commands from the user, until the user enters exit.
Before you begin your implementation, examine the provided basecode in icssh.c. Compile (using the makefile) the program and play with the basic implementation to understand how it works.
![](/Uploads/20200422/5e9ffe438909e.png)
- ls
- 1s -a
- more rsrc/test . txt
- echo "hello world!"
- cat < rsrc/test. txt
- echo < rsrc/test.txt > rsrc/out.txt &
- echo 2> rsr/err.txt < rsrc/test.txt > rsrc/out.txt
- echo "hello world"
- grep he11o &
- cat rsrc/test. txt
- grep There| WC -1 > rsrc/out2. txt
- echo "hello\nhello\nhello\n" 2> err.txt| grep There 2> err2.txt| wc -1 >
- rsrc/out2.txt
Invalid commands, such as some of the following, will not be parsed into the job_ info data structure. And the provided base code will print an error message and the function validate_ input will return a NULL pointer.
- a.out -a .
- echo < rsrc/test.txt < a.txt
- cat rsrc/test. txt
- grep There > b.txt
- WC -1 > rsrc/out2.txt
- cat rsrc/test. txt
- grep There < b.txt
- WC -1
![](/Uploads/20200422/5e9ffef8b3d1b.png)
Shell Implementation Requirements
In this homework, the goal is to add features to the base shell program to make it more useful and practical. Below are the requirements:- Support for built-in shell commands
- Support for a foreground and background processes simultaneously
- Support for I/O redirection (STDIN, STDOUT, STDERR) and piping between two programs
Part 1: Built-in Shell Commands
A built- in command is executed directly in the shell itself (parent), rather than by the execution of an extemal program which is loaded and run by a child. The command exit which is implemented in the provided basecode is an example. If the first argument of any job command is a built-in, the built-in is run, ignoring any additional arguments.
1. Add the ability to change directories with the built-in cd command. See man_ chdir and this example. Change the current working directory to the specified directory (S cd dir). If directory is not supplied, the value of the HOME environment variable is used (S cd). Any additional arguments following the directory are ignored. Investigate how chdir works with paths which include ' .' and
If the directory change is successful, the absolute pathname (see man getcwd) of the new working directory is written to STDOUT. If the directory change is unsuccessful, print to STDERR the define statement DIR_ ERR, which is defined as " DIRECTORY ERROR: Directory does not exist. \n"
2. The command (<53she11>$ estatus) prints the exit status of the most recently reaped program (aka child process).
An example:
![](/Uploads/20200422/5e9fffbb0ec20.png)
![](/Uploads/20200422/5ea0004dc3e42.png)
Part 2: Background Jobs
A background job executes without blocking the shell from taking additional job commands. This means the command is run and the shell does not wait for it to finish before retuming to the user with a new prompt. This is accomplished by spawning a child process to execute the command/program and not waiting for the child to terminate. The standard operator to specify the command to be run as a background process is &. Only when this operator is added to the job command as the very last token will the shell recognize it as an indicator for background processes. The job_ _info struct returmed by the tokenizer will set the bg field to 1 (yes) if the job command is a background job. An example:![](/Uploads/20200422/5ea0014368cc4.png)
You may use any data structure you wish. We suggest a linked list implementation. You can create your own or use the implementation we have provided in basecode. The data structure should maintain the list of background processes in sorted order based on the time the command was executed (bgentry_ _t seconds field).
![](/Uploads/20200422/5ea0036c04f59.png)
![](/Uploads/20200422/5ea0040295511.png)
Add a new built-in command (<53she1l>$ bglist) which prints the list of background jobs currently running from oldest to newest. A print function for each background job entry is provided, print_ bgentry (see hw3/include/icssh. h for description). This function prints to STDERR.
For example, if there were three background processes running, bglist will print in the following format.
Part 3: Handling Signals
Review section 8.5 in your textbook before atempting this section of the assignment. Addionally, refer to the Lecture notes on signals.Implement the fllowing:
1. A SIGCHLD handler (as described in the background processes section)
2. Modify the exccution of the built-in exit command in the provided basecode to kill all running background jobs before termination of the shell (see man kill). Print BG_ TERM for each of the killed processes. Reap all child and parent resources before exiting the parent.
Part 4: Redirection
The shell must support the following Unix I/O redirection options: >, 2>,and <. Consult with this webpage and/or here to review IO redirection usage. We summarize briefly here.One of the most powerful features of a Unix shell is the ability to compose a series of simple applications to create a complex workflow. The feature that enables this composition is output redirection. Basic redirection is accomplished by three special characters: <, >, and| (explained in the next section).
The < operator indicates that you are to take standard input from the specifed file:
![](/Uploads/20200422/5ea0088d1d9cb.png)
The》operator indicates that you are to write standard output to the specified fle:
![](/Uploads/20200422/5ea008c4cc7c1.png)
Next we have the 2> operator. While the > operator redirects standard output to a file, 2> will redirect the output of STDERR to a file. For instance, in the following example, if the executable printToStderr prints text to standard error, then it will be redirected to the file output . txt.
![](/Uploads/20200422/5ea0092844e00.png)
For all of the examples above, you can run them in your VM bash terminal to observe the expected functionality.
In order to implement this functionality in your shell, you will need to do the following items (stated in no particular order):
- open/create the required input or output files
- fork() a child process and execvp() the command, and
- use dup( ) or dup2() (see man dup) to make copies and set the proper file descriptors
![](/Uploads/20200422/5ea00a2c63050.png)
Invalid file combination.\n" in hw3/ include/icssh.h
![](/Uploads/20200422/5ea00a5774bc9.png)
Your shell must also support piping. For this assignment, you will support one or two pipe operators in a single command (more for extra credit - see the end of the document). For simplicity, your program does not need to support a pipe along with any redirection operators in a single command. If you are new to the concept of piping start with this link.
The pipe operator, l, connects the standard output of the first program to the standard input of the next program. For example,
the echo program will print the string to standard out which is then fed to the grep program on standard in. For example,
this example does the same as the previous example but passes the STDOUT of the grep command to STDIN of the WC program (see man WC).
To accomplish this you will need to use pipe()/ pipe2() (see man. pipe ). The basic steps, using the first example above, are as follows:
- create a single pipe to connect echo to grep
- fork() two times, one for each command/program (echo and grep)
- the child for echo must connect its STDOUT file descriptor to the write end of the pipe
- the child for grep must connect its STDIN file descriptor to the read end of the pipe
- the each child runs their command
Extra Credit
For this assignment we have included Extra Credit options. If you complete one or more of these options, you MUST indicate that you have done so via the HW#3 Canvas Survey. If it is not indicated on the Survey, it WILL NOT be graded.- (2 pts) Add support to change directory to the previous directory, cd - (See Bash for example of how this operates)
- (2 pts) Create a new builtin command, asci53, which prints to the terminal a creative UCI or ICS53 ASCII art logo to STDOUT.
- (5 pts) Support mutiple pipe operators (2+) in a single command.
- (5 pts) Support 2+ pipe operators with any valid combination of redirection operators.
![](/Uploads/20200422/5ea00de13d1ca.png)
Note that any combination of redirection that OVERLAPS with the pipe operations is considered an RD_ ERR error. You will need to check for these combinations within the job_ _info structure.
For example, in the first case shown below rsrc/text . txt cannot be used as STDIN to a.out and for STDOUT to grep. In the second case, again the same file cannot be used for multiple redirections.
- (5 pts) Implement the built-in command, fg. This command is used to bring background jobs to the foreground. The fg command has the following usages:
- <53she11>$ fg this brings the most recently started background job to the foreground.
- <53she1l>$ fg pid where pid is the pid of the background process to bring to the foreground. If the provided pid does not exist, print to STDERR the PID_ ERR string (found in icssh.h)
- If in either situation there is no background process, then print PID_ ERR.
- More information about this command can be found (here).