• Courses
S19 1x-x13计算机系统
• lingqiuk@andrew.cmu.edu
◦ Profile
◦ TPZ Logout
◦ CMU Logout
•
• 写上去
Shell Lab 编写自己的Linux shell!
还剩6天1小时
• 提交密码 35730f8044cf4f0b509dfe676dae811e 复制
•
• 介绍
• 后勤
• 分发说明
• Linux Shell概述
• `tsh`规范
• 检查你的工作
• 警告
• 提示
• 评估
• 交给指令
• 结论
• 附录:跟踪文件
• 附录:CS:APP库
介绍
此任务的目的是帮助您更熟悉过程控制和信号的概念。您将通过编写一个简单的Linux shell程序tsh(小外壳)来实现这一点,该程序支持简单形式的作业控制和I / O重定向。请在开始之前阅读整篇文章。
后勤
这是一个单独的项目。您可以在Shark机器或Linux Andrew机器上执行此实验。
分发说明
shell实验所需的材料将在GitHub Classroom上提供,该链接在本文结尾处提供。点击链接,选择您的电子邮件,然后接受分配。它将使用初始提交为您创建存储库。您可以通过SSH克隆来自GitHub的repo,然后开始分配。如果您需要分步指南,请参阅Linux / Git bootcamp幻灯片。然后,在Shark机器上执行以下操作:
• 编辑文件tsh.c以在标题注释中包含您的姓名和Andrew ID。
• 键入命令make以编译和链接驱动程序,跟踪解释程序和测试例程。
查看tsh.c(tiny shell)文件,您将看到它包含一个简单Linux shell的框架。当然,如果你现在编译并运行它,它将不会作为shell运行。为了帮助您入门,我们为您提供了一些帮助文件,tsh_helper.{c,h}其中包含操作作业列表和命令行解析器的例程的实现tsh_exec.{c,h},并且可以帮助您实现内置命令map,unmap以及launch。仔细阅读头文件,了解如何在shell中使用它。
您的任务是完成下面列出的剩余空函数。作为一个完整性检查,我们在参考解决方案中列出了每个函数的大致代码行数(其中包含大量注释 – 这是一件好事)。不要忘记创建辅助函数,以使代码更易于阅读和更模块化。
• eval:解析,解释和执行命令行的主例程。[300行,包括辅助函数]
• sigchld_handler:处理SIGCHLD信号。[80行]
• sigint_handler:处理SIGINT信号(发送者ctrl-c)。[15行]
• sigtstp_handler:处理SIGTSTP信号(发送者ctrl-z)。[15行]
如果要测试shell,请键入make以重新编译它。要运行它,请键入tsh命令行:
linux> ./tsh
tsh> [在这里为你的shell输入命令]
Linux Shell概述
甲壳是运行代表用户的节目的交互式命令行解释。甲壳反复打印的提示,等待一个命令行上stdin,然后执行一些动作,所指示的命令行的内容。
命令行是由空格分隔的ASCII文本字序列。命令行中的第一个单词是内置命令的名称或可执行文件的路径名。其余的单词是命令行参数:
• 如果第一个单词是内置命令,则shell会立即在当前进程中执行该命令。
• 否则,该单词被假定为可执行程序的路径名。在这种情况下,shell会分叉子进程,然后在子进程的上下文中加载和运行程序。
由于解释单个命令行而创建的子进程被统称为作业。通常,作业可以包含由Linux管道连接的多个子进程。但是,您在本实验中编写的shell不需要支持管道。
如果命令行以&“ &”结尾,则作业在后台运行,这意味着shell在打印提示并等待下一个命令行之前不会等待作业终止。否则,作业在前台运行,这意味着shell在等待下一个命令行之前等待作业终止。因此,在任何时间点,最多一个作业可以在前台运行。但是,可以在后台运行任意数量的作业。
例如,键入命令行
tsh>jobs
导致shell执行内置jobs命令。键入命令行
tsh>/bin/ls -l -d
/bin/ls在前台运行程序。按照惯例,shell将确保在/bin/ls开始执行其主程序时
int main(int argc, char *argv[])
在argc和argv参数有以下值:
argc == 3
argv[0] == “/bin/ls”
argv[1]== “-l”
argv[2]== “-d”
或者,键入命令行
tsh>/bin/ls -l -d &
/bin/ls在后台运行该程序。
Linux shell支持作业控制的概念,它允许用户在后台和前台之间来回移动作业,以及更改作业中进程的进程状态(运行,停止或终止)。例如,
• 键入ctrl-c会导致SIGINT信号传递到前台作业中的每个进程。SIGINT的默认操作是终止进程。
• 类似地,键入ctrl-z会导致SIGTSTP信号传递到前台作业中的每个进程。SIGTSTP的默认操作是将进程置于停止状态,直到它被收到SIGCONT信号唤醒为止。
Linux shell还提供各种支持作业控制的内置命令。例如:
• jobs:列出正在运行和已停止的后台作业。
• bgjob:将已停止的作业更改为正在运行的后台作业。
• fgjob:将已停止的作业或正在运行的后台作业更改为正在运行的前台作业。
Linux shell还支持I / O重定向的概念,允许用户重定向stdin和stdout磁盘文件。例如,键入命令行
tsh>/bin/ls > foo
将输出重定向ls到名为的文件foo。同样的,
tsh>/bin/cat < foo
将/bin/cat命令的输入重定向到命令,该foo命令将打印文件的内容foo。
`tsh`规范
您的tshshell应具有以下功能:
• 提示符应为字符串“ tsh>”。
• 用户键入的命令行应包含一个name零个或多个参数,所有参数都由一个或多个空格分隔。如果name是内置命令,tsh则应立即处理。否则,tsh应该假设它name是可执行文件的路径,它在初始子进程的上下文中加载和运行(在此上下文中,术语作业指的是此初始子进程)。如果您正在运行类似的系统程序ls,则需要输入完整路径(在本例中/bin/ls),因为您的shell没有搜索路径。
• tsh不需要支持管道(|),但必须支持I / O重定向(“ <”和“ >”),例如:
tsh>/bin/cat < foo > bar
您的shell必须在同一命令行中同时支持输入和输出重定向。
• 键入ctrl-c 或ctrl-z应该使shell分别向当前前台作业发送SIGINT或SIGTSTP信号,以及该作业的任何后代(例如,它分叉的任何子进程)。如果没有前台作业,则信号应该没有效果。
• 每个作业都可以通过进程ID(PID)或作业ID(JID)来标识,JID是由…分配的正整数tsh。JID应该在命令行上用前缀’ %’表示。例如,“ %5”表示JID 5,“ 5”表示PID 5。
• 如果命令行以&符号结尾&,tsh则应在后台运行作业。否则,它应该在前台运行作业。启动后台作业时,tsh应打印出命令行,前面加上作业ID和进程ID。例如:
[1] (32757) /bin/ls &
• tsh 应该支持以下内置命令:
◦ 该quit命令终止shell。
◦ 该jobs命令列出所有尚未退出的作业。
◦ 该bgid命令将id表示的作业更改为正在运行的后台作业。的ID参数可以是一个或JID PID(见上文)。这可能涉及通过向其发送SIGCONT信号然后在后台运行它来重新启动已停止的作业。
◦ 该fgid命令将id表示的作业更改为正在运行的前台作业。的ID参数可以是一个或JID PID(见上文)。这可能涉及通过向其发送SIGCONT信号然后在前台运行它或者将后台作业移动到前台来重新启动已停止的作业。
◦ 该map.extension program命令将文件扩展名(带有“。”)绑定到程序program。如果未指定任何参数,则它将输出(以与jobs命令类似的方式)当前活动的所有映射的列表。如果已经映射了扩展,它应该打印一个适当的错误(使用该maperror函数)。
• 使用map命令时,“。” 的文件扩展名是必要的。
tsh> map .txt /bin/cat
此命令将扩展名绑定.txt到可执行文件/bin/cat。映射扩展时可以提供更多参数。例如:
tsh> map .c /bin/cat -n
此命令将扩展结合.c到/bin/cat一起的说法-n,这意味着标志-n时将被添加/bin/cat启动C文件。换一种说法,
tsh> launch blah.c
将等同于
tsh> /bin/cat -n blah.c
• 给予unmap命令的扩展名必须是现有扩展名。如果取消映射不存在的扩展名,则应显示错误消息。例如,
tsh> unmap .fake
.fake: No existing mapping for extension.
• 该launch命令将尝试解析给定文件名的扩展名。如果给定的文件名有扩展名,tsh将搜索其绑定的可执行文件。如果映射关系存在,tsh将启动绑定的可执行文件以打开给定文件。如果此扩展名没有映射关系,或者文件名没有扩展名,tsh则会打印错误。
◦ 该unmap.extension命令从绑定的可执行文件中取消绑定文件扩展名。Unmap没有参数或者参数不是当前映射的扩展名是一个错误。
◦ 该launchfile命令尝试解析扩展名file,并启动绑定的可执行文件以将其打开。如果文件没有扩展名或文件扩展名不是已知映射,则应返回错误。
• 您的shell应该能够像引用shell那样重定向内置命令的输出。例如,
tsh>jobs>foo
tsh>map>blah
应该写输出jobs到foo文件中,并输出map(活动映射列表)的blah文件。
但是,这个学期我们只会测试这个jobs命令。
• tsh应该收获所有的僵尸孩子。如果任何作业因为收到无法捕获的信号而终止,tsh则应识别此事件并打印带有作业PID和违规信号描述的消息。例如,
Job [1] (1778) terminated by signal 2
Job [2] (1836) stopped by signal 20
检查你的工作
运行你的shell。检查工作的最佳方法是从命令行运行shell。您的初始测试应该从命令行手动完成。运行你的shell,输入命令,看看你是否可以打破它。用它来运行真正的程序!
参考方案。Linux可执行文件tshref是shell的参考解决方案。运行此程序以解决有关shell应如何运行的任何问题。你的shell应该发出与参考解决方案相同的输出 – 当然,除了PID之外,它会从一次运行变为另一次运行。(参见评估部分。)
一旦您确信shell正常工作,那么您就可以开始使用我们提供的一些工具来帮助您更彻底地检查您的工作。这些是自动提交者在您提交信用工作时将使用的工具。
跟踪口译员。我们提供了一组跟踪文件(trace * .txt)来验证shell的正确性(本讲义末尾的附录部分简要描述了每个跟踪文件)。每个跟踪文件都会测试一个shell功能。例如,您的shell是否识别特定的内置命令?它是否对用户输入ctrl-c?做出了正确的响应?
该runtrace程序(跟踪解释器)解释一组由单个跟踪文件中指定的外壳命令:
linux> ./runtrace -h
Usage: runtrace -f
Options:
-h Print this message
-s
-f
-V Be more verbose
关于跟踪文件的巧妙之处在于,如果以交互方式运行shell,它们将生成相同的输出(标识跟踪的初始注释除外)。例如:
linux> ./runtrace -f traces/trace05.txt -s ./tsh
#
# trace05.txt – Run a background job.
#
tsh> ./myspin1 &
[1] (15849) ./myspin1 &
tsh> quit
较低编号的跟踪文件执行非常简单的测试,而编号较高的跟踪文件执行的测试越来越复杂。附录包含每个跟踪文件的描述,以及跟踪文件中使用的每个命令。
请注意,runtrace创建一个临时目录runtrace.tmp,用于存储重定向命令的输出,然后删除它。但是,如果由于某种原因未删除目录,则runtrace拒绝运行。在这种情况下,可能需要手动删除此目录。
壳牌司机。在用于runtrace单独测试每个跟踪文件上的shell之后,您就可以使用shell驱动程序测试shell了。该sdriver程序用于runtrace在每个跟踪文件上运行shell,将输出与参考shell生成的输出进行比较,并显示diff它们是否不同。
linux> ./sdriver -h
Usage: sdriver [-hV] [-s
Options
-h Print this message.
-i
-s
-t
-V Be more verbose.
在没有任何参数的情况下运行驱动程序会在所有跟踪文件上测试shell。为了帮助检测代码中的竞争条件,驱动程序多次运行每个跟踪。您将需要通过每个测试以获得特定跟踪的信用:
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
1. Running trace01.txt…
2. Running trace01.txt…
3. Running trace01.txt…
Running 3 iters of trace02.txt
1. Running trace02.txt…
2. Running trace02.txt…
3. Running trace02.txt…
…
Running 3 iters of trace33.txt
1. Running trace33.txt…
2. Running trace33.txt…
3. Running trace33.txt…
Running 3 iters of trace34.txt
1. Running trace34.txt…
2. Running trace34.txt…
3. Running trace34.txt…
Score: 35/35 correct traces
使用可选-i参数来控制驱动程序运行每个跟踪文件的次数:
linux> ./sdriver -i 1
Running trace00.txt…
Running trace01.txt…
Running trace02.txt…
Running trace03.txt…
…
Running trace33.txt…
Running trace34.txt…
Score: 35/35 correct traces
使用可选-t参数来测试单个跟踪文件:
linux> ./sdriver -t 06
Running trace06.txt…
Success: The test and reference outputs for trace06.txt matched!
使用可选-V参数获取有关测试的更多信息:
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
警告
• 尽早开始!给自己留出足够的时间来调试解决方案,因为shell中的细微问题很难找到并修复。
• 教科书中有很多有用的代码片段。可以将它们用于您的程序,但请确保您了解您正在使用的每一行代码。请不要在你不理解的代码之上构建你的shell!
• 与子进程的竞争条件。请记住,您不能对分叉后父母和子女的执行顺序做出任何假设。特别是,当父节点从父节点返回时,您不能假设子节点仍然在运行fork。实际上,我们的驱动程序具有代码,该代码有意地按照父和子在分叉后执行的顺序引入非确定性。
• 信号处理程序中的竞争条件。请记住,信号处理程序与程序同时运行并可以在任何地方中断它,除非您明确阻止接收信号。驾驶员使用技术来放大由竞争条件引起的不正确行为的发生。
对工作清单上的竞争条件要特别小心。为了避免竞争条件,您应该阻止任何可能导致信号处理程序在您访问或修改作业列表时运行的信号。为了强制执行此操作,我们在辅助函数中构建了检查代码,tsh_helper.c以确保阻止这些信号。
• 请记住,简单地多次传递测试并不能证明shell的正确性。如果您的代码中存在竞争条件,我们将扣除正确性分数(最多20%!),因此通过彻底检查,在我们做之前找到它们符合您的最佳利益。
• 保存/恢复错误。信号处理程序应始终正确保存/恢复全局变量,errno以确保它不被破坏,如教科书的第8.5.5节所述。驱动程序显式检查,如果errno已损坏,它将打印警告。
• 忙等待。禁止在等待信号时旋转紧密循环(例如“while(1);”)。这样做会浪费CPU周期。通过sleep在紧密循环内调用来解决这个问题也不合适。相反,您应该使用该sigsuspend函数,该函数将一直睡眠直到收到信号。有关更多信息,请参阅教科书或演讲幻灯片。
• 收获子进程。当你的孩子的孩子死亡时,他们必须在有限的时间内收获。这意味着,你应该不等待运行的前台进程完成或用户输入收割之前要输入。
你不应该waitpid在多个地方打电话。这将为您提供许多潜在的竞争条件,并使您的外壳变得不必要复杂。
• 异步信号安全。许多常用功能,包括printf,不是异步信号安全的; 即,不应从信号处理程序中调用它们。在信号处理程序中,您必须确保只调用本身是异步信号安全的系统调用和库函数。
对于printf具体功能,CS:APP库提供sio_printf作为一个异步信号安全的替代品,你可能希望在你的shell使用。(有关异步信号安全的信息,请参阅教科书中的第8.5.5节,有关CS:APP库提供的功能的信息,请参阅附录。)
• 不要使用tcsetpgrp操纵终端组的任何系统调用(例如); 这些将破坏自动编程。
提示
• 阅读并理解教科书中第8章(例外控制流程)和第10章(系统级I / O)的每个单词。
• 在开始之前,请仔细阅读代码tsh.c和API文档tsh_helper.h。了解高级控制流程; 熟悉定义的全局变量和辅助例程。tsh帮助程序维护一个您应该使用的作业列表,但不公开其实现。您应该使用提供的功能来访问作业列表。
• 通过直接键入命令来玩shell。不要错误地立即运行跟踪发生器和驱动程序。在使用自动化工具进行测试之前,对shell的工作原理有一些熟悉和直觉。
• 只有在您直接从命令行测试shell并且相信它是正确的之后才开始使用runtrace和驱动程序进行测试。
• 使用跟踪文件来指导shell的开发。首先trace00.txt,确保shell生成与引用shell 相同的输出。然后继续跟踪文件trace01.txt,依此类推。
• 的waitpid,kill,fork,execve,setpgid,sigprocmask,和sigsuspend功能会非常方便。WUNTRACED和WNOHANG选项waitpid也很有用。使用man和您的教科书了解有关这些功能的更多信息。
• 实现信号处理程序时,请务必使用“ ”而不是“ ” 函数发送SIGINT并向SIGTSTP整个前台进程组发送信号。驱动程序专门测试此错误。-pidpidkill
• 分配的一个棘手部分是在shell等待前台作业完成时决定eval和sigchld_handler函数之间的工作分配。
• 在eval中,父母必须使用sigprocmask阻止SIGCHLD,SIGINT和SIGTSTP信号,它叉前的孩子,然后解除这些信号,再次使用sigprocmask它通过调用增加了孩子的作业列表之后addjob。由于孩子继承了父母的被阻挡的载体,孩子必须确保在执行新程序之前解锁这些信号。孩子还应该恢复shell忽略的信号的默认处理程序。
父母需要以这种方式阻止信号,以避免竞争条件(例如,在父母呼叫之前,孩子被sigchld_handler(并因此从工作列表中删除)收入)。教科书的第8.5.6节详细介绍了这些竞争条件以及如何明确阻止信号。addjob
• 程序如top,less,vi,和emacs做终端设置奇怪的事情。不要从shell运行这些程序。用简单的基于文本的程序,如坚持/bin/cat,/bin/ls,/bin/ps,和/bin/echo。
• 从标准Linux shell运行shell时,shell正在前台进程组中运行。如果您的shell然后创建子进程,则默认情况下该子进程也将是前台进程组的成员。由于键入会ctrl-c向前台组中的每个进程发送一个SIGINT,因此键入ctrl-c将向您的shell发送一个SIGINT,以及您的shell创建的每个进程,这显然是不正确的。
以下是解决方法:在子进程应该调用fork之前,但之前execve,子进程应该调用setpgid(0, 0),这将子进程放入一个新的进程组,其组ID与子进程的PID相同。这可确保前台进程组中只有一个进程shell。键入时ctrl-c,shell应捕获生成的SIGINT,然后将其转发到相应的前台作业(或更准确地说,包含前台作业的进程组)。
• 您的shell需要适当地处理错误条件,这取决于正在处理的错误。例如,如果malloc失败,那么你的shell也可以退出; 另一方面,您的shell不应该因为用户输入的文件名无效而退出。(请参阅样式分级部分。)参考shell使用该perror函数在适用时打印错误消息,您需要使用它。(man 3 perror)。
评估
您的分数将根据以下分布计算出最多120分:
105正确性:35个跟踪文件,每个3个点。此外,如果您的解决方案通过了跟踪但实际上并不正确(您破解了让它通过跟踪的方法),我们将在读取您的代码时扣除正确性点。
我们将要寻找的最常见的事情是你经常使用这个sleep电话而已经过的竞争条件。通常,即使我们删除了所有sleep调用,您的代码也不应该有比赛。
15个 风格点。我们希望您遵循课程网站上发布的风格指南。例如,我们希望您检查EVERY系统调用和库函数的返回值,并适当地处理任何错误条件。
我们希望您将诸如eval之类的大型函数分解为更小的辅助函数,以增强可读性并避免重复代码。我们也希望你写好评。关于评论的一些建议:
• 使用描述shell的描述性块注释开始您的程序文件。
• 使用块注释开始每个例程,描述其在高级别的角色。
• 使用块注释来排列相关的代码行。
• 保持你的行在80个字符以内。
• 不要简单地评论每一行。
您还应该遵循其他良好风格的指导原则,例如使用一致的缩进样式(不要混合空格和制表符!),使用描述性变量名称,并使用空格分组逻辑相关的代码块。
将使用您的讲义目录中包含的相同驱动程序和跟踪文件,在64位Linux计算机(Autolab服务器)上测试您的解决方案shell的正确性。你的shell应该在这些跟踪上产生与引用shell 相同的输出,只有两个例外:
• PID可以(并且将)是不同的。
• The output of the /bin/ps commands in trace26.txt and trace27.txt will be different from run to run. However, the running states of any mysplit processes in the output of the /bin/ps command should be identical.
The driver deals with all of these subtleties when it checks for correctness.
Hand In Instructions
• Make sure you have included your name and Andrew ID in the header comment of tsh.c.
• Unlike other courses you may have taken in the past, in this course you may handin your work as often as you like until the due date of the lab. To receive credit, you will need to upload a handin.tar file using the Autolab option “Handin your work.” You can also run the 213-handin script from your terminal. The handin.tar will contain two files : your tsh.c file and a key.txt file. More details about the key.txt to follow. If you choose to manually submit the handin.tar, ensure that you submit handin.tar to autolab, and not just the tsh.c file.
• To create the handin.tar, execute the following commands :
linux> make
•
• After you hand in, it takes a minute or two for the driver to run through multiple iterations of each trace file.
• Instead of downloading the handin.tar, you may use a built-in 213-handin script. Create handin.tar and then follow these instructions:
linux> 213-handin tshlab
•
You should see “Successfully submitted!” get printed, and you can then check your results on Autolab.
Note: If it is your first time using the 213-handin command, make sure to add the 15213 bin folder to your path environment variable with the following:
linux> echo ‘export PATH=”$PATH:/afs/cs.cmu.edu/academic/class/15213-s18/bin”‘ >> ~/.bashrc
•
In order to execute the instructions in the .bashrc, you will need to restart your session or type
linux> source ~/.bashrc
•
• As with all our lab assignments, we’ll be using a sophisticated cheat checker that compares handins from this year and previous years. Please don’t copy another student’s code. Start early, and if you get stuck, come see your instructors for help.
• Good luck!
Conclusion
Congratulations, you finished reading the Shell lab writeup!
You can now get the handout from github classroom here: https://classroom.github.com/a/kkezZ2SK . Please remember to use GIT and commit early and often!
Please click the blue Submission Password button at the top of the page to get your unique submission key. Then, add your key to the key.txt file like so, before you start coding
andrewid
github id
key
For example, if your andrew ID is bovikAndrew, GitHub id is bovikGithub and your key is abcdef1234567890, then your key.txt would look like:
bovikAndrew
bovikGithub
abcdef1234567890
NOTE: If the blue Submission Password button does not appear near the top of the page, please refresh this page.
Good luck on Shell lab!
Appendix: Trace Files
The trace driver runs an instance of your shell in a child process and communicates with the shell interactively 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/echo program, which not only tests the shell’s 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 string tsh> ./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 in wrapper.c.
A wrapper is a function injected at link time around calls to a function. For instance, where your code calls fork, the linker will replace this call with an invocation of __wrap_fork, which in turn calls the real fork function. Some of those wrappers are configured to signal the driver and resume execution only when signaled. 
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 level picture 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. 
* These traces will not be used for autograding, but you can still run them, to test those areas of your shell.
Appendix: CS:APP library
The csapp.c file 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 in csapp.c is wrapped versions of many of the functions you will use. These are named with an upper-case character as the first letter. For example, Fork is the wrapped version of the fork syscall. 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 of csapp.c is that it provides the SIO series of functions, which are async-signal-safe functions you can use to print output. The main function of interest is the sio_printf function that you can use to print formatted output, which you can use the same way you use the printf function. However, it only implements a subset of the format strings, which are as follows:
• Integer formats: %d, %i, %u, %x, %o, with optional size specifiers l or z
• Other formats: %c, %s, %%, %p
For this lab, we have removed the sio_puts and sio_putl functions that are used in the textbook. Instead, we encourage you to use the sio_printf family of functions for async-signal-safe I/O, which should help you write more readable code.
×
Error
You do not have the permissions to access this

Original text
Contribute a better translation