C++代写 | OS代写 | 操作系统代做 | shell代写 | oop | assignment代做 | 代做lab – shell Lab – Writing Your Own Linux Shell

shell Lab: Writing Your Own Linux Shell

C++代写 | OS代写 | 操作系统代做 | shell代写 | oop | assignment代做 | 代做lab – 这个题目属于一个OS的代写任务, 通过C++写一个linux shell的模拟程序app,涉及了操作系统信号传递等代写的内容, 该题目是值得借鉴的OS代写的题目

app代写 代写app 移动开发

1 Introduction

The purpose of this assignment is to help you become more familiar with the concepts of process control and signalling. Youll do this by writing a simple Linux shell program,tsh(tiny shell), that supports a simple form of job control and I/O redirection. Please read the whole writeup before starting.

2 Hand Out Instructions

Create your GitHub Classroom repository . Then do the following on either an Andrew Linux or a Shark machine:

  • Clone the repository that you just created using theg IT clonecommand.Do not download and extract the zip file from GitHub.
  • Type your name and Andrew ID in the header comment at the top oftsh.c.
  • Type the commandmaketo compile and link the driver, the trace interpreter, and the test routines.

Looking at thetsh.cfile, you will see that it contains a skeleton of a simple Linuxshell. It will not, of course, function as a shell if you compile and run it now. To help you get started, weve provided you with a helper file,tshhelper.{c,h}, which contains the implementation of routines that manipulate a job list, and a command line parser. Read the header file carefully to understand how to use it in your shell.

Your assignment is to complete the remaining empty functions listed below. As a sanity check for you, weve listed the approximate number of lines of code for eachof these functions in our reference solution (which includes lots of comments thats a good thing).

  • eval: Main routine that parses, interprets, and executes the command line. [300 lines, including helper functions]
  • sigchldhandler: HandlesSIGCHLDsignals. [80 lines]
  • siginthandler: HandlesSIGINTsignals (sent byCtrl-C). [15 lines]
  • sigtstphandler: HandlesSIGTSTPsignals (sent byCtrl-Z). [15 lines]

When you wish to test your shell, typemaketo recompile it. To run it, typetshto the command line:

linux> ./tsh
tsh> [type commands to your shell here]

3 General Overview of Linux Shells

Ashellis an interactive command-line interpreter that runs programs on behalf of the user. A shell repeat- edly prints a prompt, waits for acommand lineonstdin, and then carries out some action, as directed by the contents of the command line.

The command line is a sequence of ASCII text words delimited by whitespace. The first word in the command line is either the name of a built-in command or the pathname of an executable file. The remaining words are command-line arguments:

  • If the first word is a built-in command, the shell immediatelyexecutes the command in the current process.
  • Otherwise, the word is assumed to be the pathname of an executable program. In this case, the shell forks a child process, then loads and runs the program in the context of the child.

The child processes created as a result of interpreting a single command line are known collectively as a job. In general, a job can consist of multiple child processes connected by Linux pipes. However, the shell you write in this lab need not support pipes.

If the command line ends with an ampersand &, then the job runs in thebackground, which means that the shell does not wait for the job to terminate before printing the prompt and awaiting the next command line. Otherwise, the job runs in theforeground, which means that the shell waits for the job to terminate before awaiting the next command line. Thus, at any point in time, at most one job can be running in the foreground. However, an arbitrary number of jobs can run in the background.

For example, typing the command line

tsh> jobs

causes the shell to execute the built-injobscommand. Typing the command line

tsh> /bin/ls -l -d

runs the/bin/lsprogram in the foreground. By convention, the shell will ensure that when/bin/ls begins executing its main routine

int main(int argc, char*argv[])

theargcandargvarguments have the following values:

argc == 3
argv[0] == "/bin/ls"
argv[1] == "-l"
argv[2] == "-d"

On the other hand, typing the command line

tsh> /bin/ls -l -d &

runs the/bin/lsprogram in the background.

Linux shells support the notion ofjob control, which allows users to move jobs back and forth between background and foreground, and to change the process state (running, stopped, or terminated) of the pro- cesses in a job. For example,

  • TypingCtrl-Ccauses aSIGINTsignal to be delivered to each process in the foreground job.The default action forSIGINTis to terminate the process.
  • Similarly, typingCtrl-Zcauses aSIGTSTPsignal to be delivered to each process in the foreground job. The default action forSIGTSTPis to place a process in the stopped state, where it remains until it is awakened by the receipt of aSIGCONTsignal.

Linux shells also provide various built-in commands that support job control. For example:

  • jobs: List the running and stopped background jobs.
  • bg job: Change a stopped background job into a running background job.
  • fg job: Change a stopped or running background job into a running foreground job.

Linux shells also support the notion ofI/O redirection, which allows users to redirectstdinandstdout to files. For example, typing the command line

tsh> /bin/ls > foo

redirects the output oflsto a file calledfoo. Similarly,

tsh> /bin/cat < foo

will redirect the input of the/bin/catcommand to thefoocommand, which will print the contents of the filefoo.

4 ThetshSpecification

Yourtshshell should have the following features:

  • The prompt should be the string tsh> .
  • The command line typed by the user should consist of anameand zero or more arguments, all sepa- rated by one or more spaces. Ifnameis a built-in command, thentshshould handle it immediately. Otherwise,tshshould assume thatnameis the path of an executable file, which it should load and run in the context of an initial child process. (In this context, the termjobrefers to this initial child process). If you are running system programs likels, you will need to enter the full path (in this case /bin/ls), because your shell will not support search paths.
  • tshneed not support pipes (|), butMUSTsupport I/O redirection (< and >). For example:
tsh> /bin/cat < foo > bar
Your shell must support both input and output redirection inthe same command line.
  • TypingCtrl-CorCtrl-Zshould cause your shell to send aSIGINTorSIGTSTPsignal, respec- tively, to the current foreground job, as well as any descendants of that job (e.g., any child processes that it forked). If there is no foreground job, then the signal should have no effect.
  • Each job can be identified by either a process ID (PID) or a job ID (JID). The latter is a positive integer assigned bytsh. JIDs are denoted on the command line with the prefix %. For example, %5 denotes a JID of 5, and 5 denotes a PID of 5.
  • If the command line ends with an ampersand (&), thentshshould run the job in the background. Otherwise, it should run the job in the foreground. When starting a background job,tshshould print out the command line, prepended with the job ID and the process ID. For example:
[1] (32757) /bin/ls &
  • tshshould support the following built-in commands:
    • Thequitcommand terminates the shell.
    • Thejobscommand lists all background jobs.
    • Thebg jobcommand restartsjobby sending it aSIGCONTsignal, and then runs it in the background. Thejobargument can be either a PID or a JID.
    • Thefg jobcommand restartsjobby sending it aSIGCONTsignal, and then runs it in the foreground. Thejobargument can be either a PID or a JID.
  • Your shell should be able to redirect the output from the built-injobscommand. For example,
tsh> jobs > foo
should write the output ofjobsto thefoofile. The reference shell supports output redirection for
all built-ins, but you are only required to implement it forjobs.
  • tshshould reap all of its zombie children. If any job terminatesor stops because it receives a signal that it didnt catch, thentshshould recognize that event and print a message with the jobs JID and PID, and the offending signal number. For example,
Job [1] (1778) terminated by signal 2
Job [2] (1836) stopped by signal 20

5 Checking Your Work

Running your shell.The best way to check your work is to run your shell from the command line. Your initial testing should be done manually from the command line. Run your shell, type commands to it, and see if you can break it. Use it to run real programs!

Reference solution.The 64-bit Linux executabletshrefis the reference solution for the shell. Run this program (on a 64-bit machine) to resolve any questions you have about how your shell should behave. Your shell should emit output that is identical to the reference solution except for PIDs, which change from run to run. (See the Evaluation section.)

Once you are confident that your shell is working, then you canbegin to use some tools that we have provided to help you check your work more thoroughly. These are the same tools that the autograder will use when you submit your work for credit.

Trace interpreter. We have provided a set of trace files (trace*.txt) that validate the correctness of your shell. Each trace file tests a different shell feature. For example, does your shell recognize a particular built-in command? Does it respond correctly to the user typing aCtrl-C?

Theruntraceprogram (the trace interpreter) interprets a set of shell commands in a single trace file:

linux> ./runtrace -h
Usage: runtrace -f <file> -s <shellprog> [-hV]
Options:
-h Print this message
-s <shell> Shell program to test (default ./tsh)
-f <file> Trace file
-V Be more verbose

The neat thing about the trace files is that they generate the same output you would have gotten had you run your shell interactively (except for an initial comment that identifies the trace). For example:

linux> ./runtrace -f trace05.txt -s ./tsh
#
# trace05.txt - Run a background job.
#
tsh> ./myspin1 &
[1] (15849) ./myspin1 &
tsh> quit

The lower-numbered trace files do very simple tests, while the higher-numbered trace files do increasingly more complicated tests. The appendix contains a description of each of the trace files, as well as each of the commands used in the trace files.

Please note thatruntracecreates a temporary directoryruntrace.tmp, which is used to store the output of redirecting commands, and deletes it afterwards. However, if for some reason the directory is not deleted, thenruntracewill refuse to run. In this case, it may be necessary to deletethis directory manually.

Shell driver.After you have usedruntraceto test your shell on each trace file individually, then you are ready to test your shell with the shell driver. Thesdriverprogram usesruntraceto run your shell on each trace file, compares its output to the output produced bythe reference shell, and displays thediffif they differ.

linux> ./sdriver -h
Usage: sdriver [-hV] [-s <shell> -t <tracenum> -i <iters>]
Options
-h Print this message.
-i <iters> Run each trace <iters> times (default 4)
-s <shell> Name of test shell (default ./tsh)
-t <n> Run trace <n> only (default all)
-V Be more verbose.

Running the driver without any arguments tests your shell onall of the trace files. To help detect race conditions in your code, the driver runs each trace multipletimes. You will need to pass each of the runs to get credit for a particular trace:

linux> ./sdriver
Running 3 iters of trace00.txt
  1. Running trace00.txt…
  2. Running trace00.txt…
  3. Running trace00.txt… Running 3 iters of trace01.txt
  4. Running trace01.txt…
  5. Running trace01.txt…
  6. Running trace01.txt… Running 3 iters of trace02.txt
  7. Running trace02.txt…
  8. Running trace02.txt…
  9. Running trace02.txt…
...
Running 3 iters of trace30.txt
  1. Running trace30.txt…
  2. Running trace30.txt…
  3. Running trace30.txt… Running 3 iters of trace31.txt
  4. Running trace31.txt…
  5. Running trace31.txt…
  6. Running trace31.txt…
Summary: 32/32 correct traces

Use the optional-iargument to control the number of times the driver runs each trace file:

linux> ./sdriver -i 1
Running trace00.txt...
Running trace01.txt...
Running trace02.txt...
...
Running trace30.txt...
Running trace31.txt...
Summary: 32/32 correct traces

Use the optional-targument to test a single trace file:

linux> ./sdriver -t 06
Running trace06.txt...
Success: The test and reference outputs for trace06.txt matched!

Use the optional-Vargument to get more information about the test:

linux> ./sdriver -t 06 -V
Running trace06.txt...
Success: The test and reference outputs for trace06.txt matched!
Test output:
#
# trace06.txt - Run a foreground job and a background job.
#
tsh> ./myspin1 &
[1] (10276) ./myspin1 &
tsh> ./myspin2 1
Reference output:
#
# trace06.txt - Run a foreground job and a background job.
#
tsh> ./myspin1 &
[1] (10285) ./myspin1 &
tsh> ./myspin2 1

6 Warnings

  • Start early! Leave yourself plenty of time to debug your solution, as subtle problems in your shell are hard to find and fix.
  • There are a lot of helpful code snippets in the textbook. It isOK to use them into your program, but make sure you understandevery line of codethat you are using. Please do not build your shell on top of code you do not understand!
  • Race conditions with child processes.Remember that you cannot make any assumptions about the order of execution of the parent and child after forking. In particular, you cannot assume that the child will still be running when the parent returns from thefork. In fact, our driver has code that purposely introduces non-determinism in the order that the parent andchild execute after forking.
  • Race conditions in signal handlers.Remember that signal handlers run concurrently with the pro- gram and can interrupt it anywhere, unless you explicitly block the receipt of the signals. The driver uses techniques to amplify the occurrence of incorrect behaviour caused by race conditions. Be especially careful about race conditions on the job list.To avoid race conditions, you should block any signals that might cause a signal handler to run any time you access or modify the job list. To enforce this, we have built checking code into the helper functions intshhelper.cto make sure these signals are blocked.
  • Remember that simply passing the tests multiple times does not prove the correctness of your shell. We will deduct correctness points (up to 20 percent!) if there are race conditions in your code, so it is in your best interest to find them before we do, through thorough inspection.
  • Saving/restoring errno. Signal handlers should always properly save/restore the global variable errnoto ensure that it is not corrupted, as described in Section 8.5.5 of the textbook. The driver checks for this explicitly, and it will print a warning iferrnohas been corrupted.
  • Busy-waiting.It is forbidden to spin in a tight l oop while waiting for a signal (e.g. while (1);). Doing so is a waste of CPU cycles. Nor is it appropriate to get around this by callingsleepinside a tight loop. Instead, you should use thesigsuspendfunction, which will sleep until a signal is received. Refer to the textbook or lecture slides for more information.
  • Reaping child processes. When children of your shell die, they must be reaped within a bounded amount of time. This means that you shouldnotwait for a running foreground process to finish or for a user input to be entered before reaping. You should not callwaitpidin multiple places. This will set you up for many potential race condi- tions, and will make your shell needlessly complicated.
  • Async-signal-safety.Many commonly used functions, includingprintf, are not async-signal-safe; i.e., they should not be invoked from within signal handlers. Within your signal handlers, you must ensure that you only call syscalls and library functions that are themselves async-signal-safe. For theprintffunction specifically, the CS: app library providessioprintfas an async-signal- safe replacement, which you may wish to use in your shell. (See Section 8.5.5 in the textbook for information on async-signal-safety, and see the appendix for information about the functions provided by the CS:APP library.)
  • Dont use any system calls that manipulate terminal groups (e.g.tcsetpgrp), which will break the autograder.

7 Hints

  • Read and understand every word of Chapter 8 (Exceptional Control Flow) and Chapter 10 (System- level I/O) in the textbook.
  • Read the code intsh.candtshhelper.hcarefully before you start. Understand the high-level control flow; get familiar with the defined global variables and the helper routines. The tsh helper maintains a job list, which you should use, but does not expose its implementation. You should use the provided functions to access the job list.
  • Play with your shell by typing in commands directly. Dont make the mistake of running the trace generator and driver immediately. Develop some familiarity and intuition about how your shell works before testing it with the automated tools.
  • Only after you have tested your shell directly from the command line and are fairly confident that it is correct should you start testing withruntraceand the driver programs.
  • Use the trace files to guide the development of your shell. Starting withtrace00.txt, make sure that your shell producesidenticaloutput as the reference shell. Then move on to trace file trace01.txt, and so on.
  • Thewaitpid,kill,fork,execve,setpgid,sigprocmask, andsigsuspendfunctions will come in handy. TheWUNTRACEDandWNOHANGoptions towaitpidwill also be useful. Use manand your textbook to learn more about each of these functions.
  • When you implement your signal handlers, be sure to sendSIGINTandSIGTSTPsignals to the en- tire foreground process group, using -pid instead of pid in the argument to thekillfunction. The driver program specifically tests for this error.
  • One of the tricky parts of the assignment is deciding on the allocation of work between theevaland sigchldhandlerfunctions when the shell is waiting for a foreground job to finish.
  • Ineval, the parent must usesigprocmaskto blockSIGCHLD,SIGINT, andSIGTSTPsignals before it forks the child, and then unblock these signals, again usingsigprocmaskafter it adds the child to the job list by callingaddjob. Since children inherit theblockedvectors of their parents, the child must be sure to then unblock these signals before itexecs the new program. The child should also restore the default handlers for the signals that are ignored by the shell. The parent needs to block signals in this way in order to avoidrace conditions. For example, the child could be reaped bysigchldhandler(and thus removed from the job list)beforethe parent calls addjob). Section 8.5.6 explains some possible race conditions andhow to avoid them by blocking signals explicitly.
  • Programs such astop,less,vi, andemacsdo strange things with the terminal settings. Dont run these programs from your shell. Stick with simple text-based programs such as/bin/cat, /bin/ls,/bin/ps, and/bin/echo.
  • When you run your shell from the standard Linux shell, your shell is running in the foreground process group. If your shell then creates a child process, by defaultthat child will also be a member of the foreground process group. Since typingCtrl-Csends aSIGINTto every process in the foreground group, typingCtrl-Cwill send aSIGINTto your shell, as well as toeveryprocess created by your shell. Obviously, this isnt correct. Here is the workaround: After thefork, but before theexecve, the child process should call setpgid(0, 0), which puts the child in a new process group whose group ID is identical to the childs PID. This ensures that there will be only one process, your shell, in the foreground process group. When you typeCtrl-C, the shell should catch the resulting SIGINT and then forward it to the process group that contains the foreground job.^1
  • Your shell needs to handle error conditions appropriately,which depends on the error being handled. For example, ifmallocfails, then your shell might as well exit; on the other hand, your shell should not exit just because the user entered an invalid filename. (See the section on style grading.) An additional, ungraded trace filetrace32.txthas been provided that tests the error handling of your shell. However, it is not scored, since your shell does not need to output the same error messages as the reference shell. For error messages, you may find theperrorfunction useful, which is what the reference shell uses.
  • trace23.txtuses builtin commands likebgandfgon job/process ids that are invalid. Your shell should be able to handle this gracefully, and the autograderwill expect to see the same error message from your shell as the reference shell. For example, if job id5 and process id 6 are both invalid, wed expect this output from your shell:
tsh> fg %
%5: No such job
tsh> fg 6
(6): No such process

(^1) With a real shell, the kernel will sendSIGINTorSIGTSTPdirectly to each child process in the terminal foreground process group. The shell manages the membership of this group using thetcsetpgrpfunction, and manages the attributes of the terminal using thetcsetattrfunction. These functions are outside of the scope of the class, and you should not use them, as they will break the autograding scheme.

8 Evaluation

Your score will be computed out of a maximum of 108 points based on the following distribution:

96 Correctness: 32 trace files at 3 pts each. In addition, if yoursolution passes the traces but is not actually correct (you hacked a way to get it to pass the traces), we willdeduct correctness points during our read through of your code. The most common thing we will be looking for is race conditions that you have simply plastered over, often using thesleepcall. In general, your code should not have races, even if we remove all sleepcalls.

12 Style points. We expect you to follow the style guidelines posted on the course website. For example, we expect you to check the return value of EVERY system call and library function, and handle any error conditions appropriately. We expect you to break up large functions such asevalinto smaller helper functions, to enhance readability and avoid duplicating code. We also expect you to write good comments. Some advice about commenting:

  • Do begin your program file with a descriptive block comment that describes your shell.
  • Do begin each routine with a block comment describing its role at a high level.
  • Do preface related lines of code with a block comment.
  • Do keep your lines within 80 characters.
  • Dont simply comment each line.
You should also follow other guidelines of good style, such as using a consistent indenting style (dont
mix spaces and tabs!), using descriptive variable names, and grouping logically related blocks of code
with whitespace.
Finally, you should ensure that you regularly commit your codeandpush it to your GitHub repository.
Some of the style points for this lab will be assigned based onyour usage of Git and your commit
history.
As for every lab, be sure to review the style guide for this class, which you can find at
https://www.cs.cmu.edu/ 213/codeStyle.html.

Your solution shell will be tested for correctness on a 64-bit machine (the Autolab server), using the same driver and trace files that were included in your handout directory. Your shell should produceidentical output on these traces as the reference shell, with only two exceptions:

  • The PIDs can (and will) be different.
  • The output of the/bin/pscommands intrace26.txtandtrace27.txtwill be different from run to run. However, the running states of any mysplitprocesses in the output of the /bin/pscommand should be identical.

The driver deals with all of these subtleties when it checks for correctness.

9 Hand In Instructions

  • Make sure you have included your name and Andrew ID in the header comment oftsh.c.
  • Hand in yourtsh.cfile for credit by uploading it to Autolab. You may hand in as often as you like. You will be graded on thelastversion you hand in.
  • After you hand in, it takes a minute or two for the driver to runthrough multiple iterations of each trace file.
  • As with all our lab assignments, well be using a sophisticated cheat checker. Please dont copy another students code. Start early, and if you get stuck, come see your instructors for help.

Good luck!

Appendix: Trace Files

The trace driver runs an instance of your shell in a child process and communicates with the shell interac- tively in a way that mimics the behavior of a user. To test the behavior of your shell, the trace driver reads in trace files that specify shell line commands that are actually sent to the shell, as well as a few special synchronization commands that are interpreted by the driver when handling the shell process. The trace files may also reference a number of shell test programs to perform various functions, and you may refer to the code and comments of these test programs for more information.

The format of the trace files is as follows:

  • The comment character is#. Everything to the right of it on a line is ignored.
  • Each trace file is written so that the output from the shell shows exactly what the user typed. We do this by using the/bin/echoprogram, which not only tests the shells ability to run programs, but also shows what the user typed. For example:
/bin/echo -e tsh\076 ./myspin1 \ 046
Note: \ 076 is the octal representation of>, and\ 046 is the octal representation of&. These are
special shell metacharacters that need to be escaped in order to be passed to/bin/echo. This
command will echo the stringtsh> ./myspin1 &.
  • There are also a few special commands which are used to synchronize the job (your shell) and the parent process (the driver) and to send Linux signals from the parent to the job. These are handled in your shell by the wrapper functions inwrapper.c. A wrapper is a function injected at link time around calls to afunction. For instance, where your code callsfork, the linker will replace this call with an invocation of wrapfork, which in turn calls the realforkfunction. Some of those wrappers are configured to signal thedriver and resume execution only when signaled.
WAIT Wait for a sync signal from the job over its synchronizing UNIX domain socket.
SIGNAL Send a sync signal to the job over its synchronizing UNIX domain socket.
NEXT Read and print all responses from the shell until you see the next shell prompt.
This command is essential for synchronizing with the shell and mimics the way
people wait until they see the shell prompt until they type the next string. It also
automatically signals the shell when receiving a signal from the shell.
SIGINT Send a SIGINT signal to the job.
SIGTSTP Send a SIGTSTP signal to the job.
SHELLSYNC
function
Sets an environment to indicate that synchronization infunctionis enabled. Cur-
rently supported values offunctionare: kill,getjobpid, andwaitpid.
Seewrapper.cfor details.
SHELLWAIT Wait for a wrapper in the shell to signalruntraceover the shell synchronizing
domain socket.
SHELLSIGNAL Tell the wrapper to resume execution over the shell synchronizing domain socket.
PIDnamefg/bg Calls the shell builtin commandfgorbg, passing the PID of the processname.

The following table describes what each trace file tests on your shell against the reference solution.

NOTE:this table is provided so that you can quickly get a high levelpicture about the testing traces. The explanation here is over-simplified. To understand what exactly each trace file does, you need to read the trace files.

trace00.txt Properly terminate on EOF.
trace01.txt Process built-in quit command.
trace02.txt Run a foreground job that prints an environment variable.
trace03.txt Run a synchronizing foreground job without any arguments.
trace04.txt Run a foreground job with arguments.
trace05.txt Run a background job.
trace06.txt Run a foreground job and a background job.
trace07.txt Use the jobs built-in command.
trace08.txt Check that the shell can correctly handle reaping multiple process
trace09.txt Send fatal SIGINT to foreground job.
trace10.txt Send SIGTSTP to foreground job.
trace11.txt Send fatal SIGTERM (15) to a background job.
trace12.txt Child sends SIGINT to itself.
trace13.txt Child sends SIGTSTP to itself.
trace14.txt Run a background job that kills itself
trace15.txt Forward SIGINT to foreground job only.
trace16.txt Forward SIGTSTP to foreground job only.
trace17.txt Exit the child in the middle of sigint/sigtsp handler
trace18.txt Signal a job right after it has been reaped.
trace19.txt Forward signal to process with surprising signal handlers.
trace20.txt Process bg built-in command (one job).
trace21.txt Process bg built-in command (two jobs).
trace22.txt Check that the fg command waits for the program to finish.
trace23.txt Process fg builtin command (many jobs, with PID and JID, testerror message)
trace24.txt Signal and end a background job in the middle of a fg command
trace25.txt Forward SIGINT to every process in foreground process group.
trace26.txt Forward SIGTSTP to every process in foreground process group.
trace27.txt Restart every stopped process in process group.
trace28.txt I/O redirection (input).
trace29.txt I/O redirection (output)
trace30.txt I/O redirection (input and output).
trace31.txt I/O redirection (input and output, different order, permissions)
trace32.txt Error handling (not scored on Autolab)

NOTE:trace32.txtwill not be graded. Its been included anyway as it may be useful to think about some of the error cases that can be easy to overlook while implementing the rest of the shell.

Appendix: CS:APP library

Thecsapp.cfile contains a number of useful functions described in the textbook. This code will be linked with your code, and so you can make use of any of these functions.

One useful type of function incsapp.cis wrapped versions of many of the functions you will use. These are named with an upper-case character as the first letter. For example,Forkis the wrapped version of the forksyscall. A wrapped function calls its core function and checks for errors. If any error is detected, it prints an error message and exits the program.

This exit-on-failure behavior is acceptable for some,but not all, of the code you will be writing. In particular, if running a certain command in your shell fails, then that should not terminate your entire shell. You must decide when it is appropriate to use the wrapped functions, and make sure to handle errors appropriately when necessary.

Another use ofcsapp.cis that it provides the SIO series of functions, which are async-signal-safe func- tions you can use to print output. The main function of interest is thesioprintffunction that you can use to print formatted output, which you can use the same way you use theprintffunction. However, it only implements a subset of the format strings, which are as follows:

  • Integer formats:%d,%i,%u,%x,%o, with optional size specifierslorz
  • Other formats:%c,%s,%%,%p

For this lab, we haveremovedthesioputsandsioputlfunctions that are used in the textbook. Instead, we encourage you to use thesioprintffamily of functions for async-signal-safe I/O, which should help you write more readable code.