[SOLVED] 代写 shell 1. 介绍

30 $

File Name: 代写_shell_1._介绍.zip
File Size: 207.24 KB

SKU: 8967138248 Category: Tags: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

Or Upload Your Assignment Here:


1. 介绍
对于此任务,您将使用C来实现一个名为GMSH(GMU Shell)的简单shell程序。 一旦运行,GMSH将能够接受/执行来自用户的命令并执行基本的作业管理。 这项作业将帮助您熟悉类Unix操作系统中的流程管理和作业控制原理。 我们关于进程,信号和Unix-IO以及教科书Ch8(尤其是8.4和8.5)和10.3的讲座将为该项目提供良好的参考。

2. 项目概况
典型的shell程序从终端接收用户输入的逐行命令。 Shell将支持一组内置命令,这些命令将直接由Shell执行。 但是,如果用户输入不是内置命令,则Shell将把输入解释为要执行的程序的名称以及要传递给它的参数。 在这种情况下,shell将派生一个新的子进程并在该子进程的上下文中执行该程序。

Shell程序通常还提供作业控制。 通常,用户命令(是否内置)将作为前台作业执行,这意味着shell程序将在读取下一个命令之前等待命令完成。 但是,如果用户命令以与号“&”结尾,则该命令将在后台启动,并且shell程序将立即返回到提示符以接受下一个命令。 shell程序通常提供一些内置命令,供用户查看后台作业列表或在后台和前台之间切换作业。

对于此任务,您的Shell实现应能够执行以下操作:
•接受用户的单行命令;
•执行内置命令(下面支持的命令的详细列表);
•使用提供的参数加载并运行用户指定的程序;
•执行基本的工作控制;
•支持基本文件重定向。
我们将在下面的示例中更详细地描述它们中的每一个。

2.0 记录功能的使用
为了保持输出格式的一致性,必须在适当的时间调用提供的日志记录功能,以从Shell程序生成正确的输出。 生成的输出还将用于评分。 文件logging.c和logging.h提供了供您调用的功能。 大多数日志功能都要求您提供一个进程ID(pid)和相关的命令行(cmd)来进行调用。 我们将在下面解释更多详细信息并指定如何使用它们。

2.1 解析用户命令
一旦启动,shell程序将显示提示并等待用户输入命令。 来自用户的每一行都被视为命令。 记录要求:
•您必须调用log_prompt()来打印提示。

每个命令必须遵循以下(简化)规则:
•行中的每个项目必须用一个或多个空格分隔;
•它必须以内置命令或要执行的程序名称开头,并带有该程序的完整路径;
•(可选)它可以包含用户想要提供的任何参数;
•(可选)它可以指定文件重定向选项,但最多输入一个文件,最多输出一个文件;
•(可选)它可以以“&”结尾,以指示命令应启动后台作业。

您的Shell程序需要能够解析输入行,识别命令和参数,检查是否需要准备任何文件以及确定该作业是否是后台作业。 假设:您可以假定所有用户输入都是有效的命令行(无需在程序中进行格式检查)。 您还可以假定每命令行最大字符数为100,每行最大参数个数为50。

请记住,fgets在从用户那里读取后将在缓冲区中保留“ n”字符。 如果您不注意这一点,则exec会导致命令错误。 (例如,当系统尝试查找命令时,“ / usr / bin / ls n”与“ / usr / bin / ls”不同)。

解析用户输入时,请使用strtok为您处理输入的标记化。 用户输入的所有部分都将由空格分隔符分隔。 在标记输入时,请考虑可能出现的项目的顺序。 您的解析器将需要处理内置命令,带或不带参数的非内置命令以及每种重定向类型的选项。 请记住,一个命令可能在同一命令中同时使用重定向和重定向!
2.2 非内置命令
如果用户命令不是Shell内置命令,则必须将其解释为要由Shell代表用户加载并执行的程序。 它可以是前台作业,也可以是后台作业。 当shell程序启动前台作业时,它必须等待该作业完成,然后才能向用户显示提示并接受下一个命令。 但是,当启动后台作业时,shell无需等待,可以立即接受下一个命令。

假设:您的shell不需要支持需要对终端进行独占访问的程序(例如,vi)或从终端读取的程序(例如,不带文件输入的wc)。
•将在测试中使用的非内置命令(带或不带参数,带或不带重定向):/ bin / sleep,/ bin / ls,/ bin / pwd
•将在测试中使用的非内置命令(仅用于从文件重定向!):/ bin / wc(例如/bin/wc > /bin/ls ./test -l
total 8
-rw-r–r–. 1 yzhong itefacstaff 32 Nov 17 23:36 temp.txt
-rw-r–r–. 1 yzhong itefacstaff 2512 Nov 17 23:37 trivial.txt
Foreground Job 16952:/bin/ls ./test -l Terminated Normally
GMSH>> /bin/ls ./test -l &
Background Job 17767:/bin/ls ./test -l & Started
GMSH>> total 8
-rw-r–r–. 1 yzhong itefacstaff 32 Nov 17 23:36 temp.txt
-rw-r–r–. 1 yzhong itefacstaff 2512 Nov 17 23:37 trivial.txt
Background Job 17767:/bin/ls ./test -l & Terminated Normally

2.3 基本的内置Shell命令
您的外壳程序必须支持以下内置命令:
•帮助(help):调用时,您的外壳应在终端上打印该外壳的简短说明 包括内置命令及其用法的列表。
记录要求:您必须调用log_help()以打印出预定义的信息。
•退出(quit):被调用时,您的shell应终止。
记录要求:您必须调用log_quit()来打印预定义的信息。然后,您将需要退出Shell程序。 假设:您可以假设 收到此命令后,没有非终止的后台作业。
•fg / bg / jobs / kill:在“作业控制”部分中进行了介绍。

Example Runs:
GMSH>> help
Welcome to GMSH (GMU Shell)!
Built-in Commands: fg, bg, jobs, kill, quit, help.
kill -SIGNAL PID
fg [JOBID]
bg JOBID
GMSH>> quit
Thanks for using GMSH! Good-bye!
zeus-2:~/

2.4 作业控制和相关的内置命令
您的Shell可能同时运行多个作业:0或1个前台作业; 0个或更多后台作业。 您的外壳程序需要维护前台作业的记录(如果有)以及未终止的后台作业的列表。 简单的作业控制任务包括:
•开始时,将为每个后台作业分配一个非负正整数作业ID:如果没有其他未终止的后台作业,则它将获得作业ID 1;否则,它将获得作业ID 1。否则,它采用比任何非终止作业ID高的下一个整数。
•启动时,前台作业会获得一个虚拟的临时作业ID0。如果将前台作业切换为后台,则会按照与上述相同的规则为其分配非负的正作业ID。
•可以在后台和前台之间切换作业(请参见下面的详细信息)。不论切换如何,一旦分配了正的作业ID,作业将保持相同的作业ID,直到终止。
•如果状态发生任何更改(流程已停止,终止,继续等),或者前台作业和后台作业之间有任何切换,则需要更新记录。
•每个作业的记录中都需要包含一些详细信息,包括分配的作业ID,进程ID,作业的执行状态以及启动该作业的初始命令行。您可以假定执行状态为“正在运行”或“已停止”,必须支持一些其他与作业控制有关的内置命令。
•作业:当用户输入作业命令时,您的外壳程序应在终端上打印后台作业列表以及作业ID,进程ID,运行状态和初始命令行。
•记录要求:
您必须首先调用log_job_number(num_jobs)来报告当前有多少后台作业仍处于活动状态(未终止)。
对于每个作业,然后必须调用log_job_details(job_id,pid,state,cmd)报告作业ID,进程ID,执行状态(“正在运行”或“已停止”)以及触发的原始命令行 这份工作。
如果有多个作业,则应按其作业ID的升序打印。
•实施提示:o当子进程的状态发生变化(停止,终止,继续)时,SIGCHLD将发送到父进程。您可以使用waitpid()来指定要监视的情况。您还可以使用不同的宏(WIFEXITED,WIFSTOPPED,WIFSIGNALED,WIFCONTINUEUE等)检查所涉及子进程的状态。
您可以使用sigaction()覆盖默认的信号处理并定义信号到达时采取的操作。请参阅附录以获取更多详细信息。

Example Runs:
GMSH>> /bin/sleep 100 &
Background Job 1168:/bin/sleep 100 & Started
GMSH>> /bin/sleep 10 &
Background Job 1184:/bin/sleep 10 & Started
GMSH>> /bin/sleep 200 &
Background Job 1189:/bin/sleep 200 & Started
GMSH>> jobs
=====3 Jobs=====
1: 1168: Running /bin/sleep 100 &
2: 1184: Running /bin/sleep 10 &
3: 1189: Running /bin/sleep 200 &
GMSH>> Background Job 1184:/bin/sleep 10 & Terminated Normally
GMSH>> jobs
=====2 Jobs=====
1: 1168: Running /bin/sleep 100 &
3: 1189: Running /bin/sleep 200 &
GMSH>> /bin/sleep 400 &
Background Job 1210:/bin/sleep 400 & Started
GMSH>> jobs
=====3 Jobs=====
1: 1168: Running /bin/sleep 100 &
3: 1189: Running /bin/sleep 200 &
4: 1210: Running /bin/sleep 400 &

——————————————————————————————————————————

•kill -SIGNAL PID:被调用时,您的外壳程序应发送一个数字为SIGNAL的信号以使用PID进行处理。
•记录要求:错误,您必须调用log_kill_error(pid,sig)报告失败的尝试。
•实施提示:您可以使用kill()向特定过程发送信号。

Example Runs:
GMSH>> jobs
=====1 jobs=====
1: 30388: Running /bin/sleep 200 &
GMSH>> kill -19 30388
GMSH>> Background Job 30388:/bin/sleep 200 & Stopped
GMSH>> jobs
=====1 jobs=====
1: 30388: Stopped /bin/sleep 200 &

——————————————————————————————————————————

•fg [JOBID]:调用时,您的外壳程序应将指定的后台作业更改为前台,并等待其完成。 如果未指定JOBID,则将具有最高作业ID的后台作业切换为前台。 如果作业先前已停止,请恢复执行。 如果提供的JOBID无效,则不应进行任何更改。

•记录要求:
您必须调用og_job_fg(pid,cmd)来报告已将哪个后台作业切换为前台作业。
如果根本没有后台作业,则必须调用log_no_bg_error()报告问题。
如果找不到指定的作业ID,则必须调用log_fg_notfound_error(job_id)报告该问题。
如果无法恢复指定的作业,则必须调用log_job_fg_fail(int pid,char * cmd)报告该问题。
•实施提示:您可以使用kill()向特定过程发送信号。

Example Runs:
GMSH>> /bin/sleep 10 &
Background Job 9746:/bin/sleep 10 & Started
GMSH>> jobs
=====1 Jobs=====
1: 9746: Running /bin/sleep 10 &
GMSH>> fg
Background Job 9746:/bin/sleep 10 & Moved to Foreground
Foreground Job 9746:/bin/sleep 10 & Terminated Normally
GMSH>> GMSH>> jobs
=====0 jobs=====

GMSH>> jobs
=====2 Jobs=====
1: 10862: Running /bin/sleep 100 &
2: 11693: Running /bin/sleep 300 &
GMSH>> fg 1
Background Job 10862:/bin/sleep 100 & Moved to Foreground
Foreground Job 10862:/bin/sleep 100 & Terminated Normally
GMSH>> jobs
=====1 Jobs=====
2: 11693: Running /bin/sleep 300 &

——————————————————————————————————————————

•bg JOBID:被调用时,您的shell将使用指定的JOBID恢复执行后台作业。 如果提供的JOBID无效或指定的作业已经在运行,则不应进行任何更改。
•记录要求:
您必须调用og_job_bg(pid,cmd)才能报告命令bg已应用于哪个后台作业。
如果找不到指定的作业ID,则必须调用log_bg_notfound_error(job_id)来报告问题。
如果无法恢复指定的作业,则必须调用log_job_bg_fail(int pid,char * cmd)报告该问题。
•实施提示:您可以使用kill()向特定过程发送信号。

Example Runs:
GMSH>> jobs
=====1 Jobs=====
1: 20979: Stopped /bin/sleep 200 &
GMSH>> bg 1
Command bg applied to 20979:/bin/sleep 200 &
GMSH>> Background Job 20979:/bin/sleep 200 & Continued
GMSH>> jobs
=====1 Jobs=====
1: 20979: Running /bin/sleep 200 &

假设:您可以假定始终使用内置命令来指定前台作业。 您还可以假定内置Shell命令没有文件重定向。

2.5 键盘交互
某些特定的键盘组合可以触发将信号发送到前台作业组。 请注意,默认情况下,由这些键盘组合触发的信号将发送到整个前台进程组,默认情况下,该进程组包括Shell程序及其前台作业。 您的程序必须更改该默认行为,以确保信号仅影响前台作业,而不影响Shell程序。 实施提示:
•您可以使用setpgid()更改进程的组ID。 有关更多详细信息,请参见本文档的附录。
•您可以使用sigaction()将默认响应更改为特定信号。
•您的Shell程序可以使用kill()将接收到的信号发送/转发到另一个进程。

对于此任务,您只需要支持两种键盘组合:
•Ctrl-c:应将SIGINT(2)发送到前台作业以终止其执行。
•Ctrl-z:应将SIGTSTP(20)发送到前台作业,以暂停其执行并将其切换为后台作业。

Example Runs:
GMSH>> /bin/sleep 200
^CForeground Job 1340:/bin/sleep 200 Terminated by Signal
GMSH>> jobs
=====0 jobs=====
GMSH>> /bin/sleep 200
^ZForeground Job 1438:/bin/sleep 200 Stopped
GMSH>> jobs
=====1 jobs=====
1: 1438: Stopped /bin/sleep 200
GMSH>>

2.6 文件重定向
如果用户指定一个文件用作程序的输入和/或输出,则您的外壳程序需要将该程序(进程)的标准输入和/或标准输出重定向到指定的文件。 记录要求:
•如果无法打开文件,则必须调用log_file_open_error(file_name)报告问题。 注意:如果出现文件打开错误,请忽略文件重定向,但是您仍然应该执行用户命令(使用普通标准输入和/或标准输出)。
实施提示:
•您可以使用open()打开文件;
•如果文件是通过open()创建的,则它将使用第三个参数来设置该文件的读取/写入/执行权限。 为了简化任务,请确保在需要时使用0600作为open()的第三个参数。 通常,它将文件设置为仅由文件所有者可读和可写。

2.7 信号处理
您可能需要各种信号来覆盖默认处理程序并指定要执行的操作。 您将需要定义信号处理程序以帮助实现上述任务。
记录要求:
•对于子进程的多个可能的状态更改,必须调用相应的日志记录功能以报告更改。 所有这些日志记录功能都需要进程ID pid和所涉及子进程的原始命令行cmd。 它们总结在下表中。
实施提示:
•您需要监视和处理的信号包括:SIGCHLD,SIGINT和SIGTSTP;
•您可以使用sigaction()注册这些处理程序。 注意:教科书介绍了signal()的用法,该方法已被弃用,并由sigaction()代替。 确保您已阅读sigaction()手册,并在编码之前先学习如何使用它。 查看本文档的附录以获取sigaction()的基本思想和示例用法。
•建议不要在信号处理程序中使用任何stdio函数。 如果需要将任何调试语句打印到,请直接使用带有STDOUT_FILENO的usewrite()。 您可以查看提供的logging.c中的示例(例如log_job_fg_term())。

2.8 比赛条件
您将开始在此作业中体验并发编程的乐趣和挑战。 特别是,如果您的设计包括全局作业列表,请警惕可能发生竞争情况。 典型的竞争是在Shell进程在启动或移动作业时更新列表与信号处理程序在进程更改其状态(终止,继续等)时更新同一列表之间进行竞争。 例如,如果不提供同步,则可能有以下顺序:
1. shell(父级)开始一个新作业(子进程),新创建的子级开始运行;
2.在父进程有机会将作业添加到列表之前,子进程终止并触发SIGCHLD到父进程;
3. SIGCHLD处理程序已执行,但看不到列表中的作业,无法执行任何操作;
4.处理程序完成后,外壳程序(父级)恢复正常执行,并在为时已晚时将作业添加到列表中!
我们建议的一种方法是在调用fork()之前阻止SIGCHLD信号(以及可能触发全局列表更新的其他信号),并仅在将作业添加到列表中后才取消阻止它们。 信号的阻塞和非阻塞都可以使用sigprocmask()来实现。 还要注意,子代继承了其父代的阻止集,因此您必须在调用execl()或execv()之前在子代中取消对其的阻止。 可能还存在其他类似情况,您需要临时阻止信号以确保全局列表的更新良好同步。

3. 开始
首先,从获得此文档的同一位置获取起始代码(project3_handout.tar)。 一旦在Zeus上解压讲义(使用tar xvf project3_handout.tar),则p3_handout目录中将包含以下文件:
•shell.c –这是您将要修改(和提交)的唯一文件。 该文件中包含用于框架其余部分调用的功能的存根。 如果愿意,可以随意定义更多功能,但是请将所有代码放入此文件中!
•shell.h –它具有一些基本定义,并包括必要的头文件。
•logging.c –该列表提供了所需的日志功能,您需要在适当的时间调用这些功能。
•logging.h –它具有在logging.c中实现的日志记录功能的原型。
•sigaction_example.c –这是附录中sigaction()的示例程序。
•Makefile –建立分配(并清理)。

Reviews

There are no reviews yet.

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

Shopping Cart
[SOLVED] 代写 shell 1. 介绍
30 $