最近在看6.S081的实验,希望这次别半途而废吧。
sleep
简单的解析命令行参数,然后调用user.h
里面sleep
函数即可。这道题应该只是让人熟悉一下环境。
- 记得要修改
Markfile
来编译 sleep 命令。
./grade-lab-util sleep
可以快速的运行测试。
pingpong
这一题要实现通过pipe
的进程间通信,虽然只是简单的pingpong
。但也有需要注意的点:
- 因为两个进程需要相互发信息,所以需要两个
pipe
,如果只有一个pipe
的话,第一个进程向pipe
写完后,需要读取第二个进程发过来的pong
,这时就会出现两个进程同时读管道的情况,进而导致
primes
这道题是想让我们用pipe
和fork
来实现一个CSP
风格的程序,从给出的链接可以找到要是程序的核心伪代码和图例:
简单来讲就是,第一个进程先创建一个子进程,并使用管道和子进程通信,然后父进程向管道写入2
到35
的数字。子进程执行下面操作:
- 从与父进程之间的管道读取数字
- 如果没读到(
read
返回0
),则退出
- 如果读到了,则输出该数字
p
,并创建新的子进程,同时创建与新进程间的管道,子进程跳转到1
。
- 从与父进程之间的管道读取数字
n
,并判断n
是否能够被p
整除,如果不能则向与子进程的管道中写入该数字。当读不到数字时就退出。
上面的流程其实没有提及到管道的关闭和父进程的wait
操作,但是这些对于程序的正确性是非常重要的,如果没有及时关闭不必要的读端和写端,会导致操作系统文件描述符耗尽,从而创建管道失败。而如果父进程在结束前没有wait
的话,会导致子进程的输出与shell
的输出混在一起。
实现代码如下:
find
这道题要求实现一个简易的find
命令,虽然看上去听复杂的,但是基本上将ls
里面的代码修改一下即可搞定。
所以我们可以先分析一下user/ls.c
的代码,这个程序的核心在于ls
函数中的实现,所以我们只看这个即可。
ls 的实现
首先是用open
打开给定路径,然后用fstat
来获取文件的一下属性:
其中st
是一个struct stat
类型的变量,它的定义可以在kernel/stat.h
中找到:
从stat
中我们可以获取到文件类型,通过这个我们就可以来判断当前打开的是目录还是文件了,如果是文件则输出文件信息,如果是目录则解析目录中所包含的文件,并逐个输出文件信息,解析目录的代码如下:
上面的代码的核心在于通过while
循环来从目录的文件描述符中读取目录项,目录项的是一个struct dirent
结构体,可以从kernel/fs.h
找到相关的定义:
其中inum
是inode
编号。
find 实现
find
和ls
的实现基本一致,区别点在于:
- 当打开的是文件时,需要与输入
pattern
进行比较,来决定是否输出
- 当打开的是目录时,需要递归调用
find
函数
- 由于与
pattern
进行比较是文件名,而不是路径,所以为了简便,find 的三个参数分别为path
,filename
,pattern
。
xargs
在解决这道题前,我们先了解一下xargs
的使用。
xargs 基本使用
我们知道在shell
中可以使用|
将两个命令的输出和输入连接在一起,比如说cat text.txt | more
,这可以让我们将多个简单的程序连接在一起实现复杂的功能。而有时候,我们希望将第一个命令的输出作为第二个命令的命令行参数来调用。比如说我们有一个文件cmd.txt
包含以下内容:
我们希望用which
命令来查询cmd.txt
中每行命令所在的路径。如果我们直接通过|
来连接cat cmd.txt
和which
的话,会没有任何输出,这是因为which
命令是从命令行参数中读取要查询的命令名,而不是从标准输入中读取。这种时候,我们就可以用xargs
来将标准输入转化为命令行参数了:
xargs 的使用格式xargs [options] [command [initial-arguments]]
echo "world\nos" | xargs echo hello
会被转化成echo hello world
和echo hello os
来执行。
xargs
因为题目给出了这里的xargs
是类似于xargs -n 1
的执行效果就好了,这其实就降低了难度了,因为它其实限制了xargs
一次只会传入一个参数,我们逐字符读取输入,然后判断是否为\n
,如果不是就将该字符暂存,如果是就将这之前保存字符串添加到原本命令行参数的后面,并调用fork
和exec
执行即可。
但是其实正常xargs
好像也没太大问题,即支持一行中有多个参数,只是需要在解析时考虑多一个
和\t
即可。
uptime
貌似是只需要调用uptime
的返回值即可?
grep with regular expressions
因为给出了提示,在user/grep.c
里面有关于正则表达式的代码,所以可以直接把那部分代码拷贝过来,然后将strcmp
修改成对应的match
即可。
正则表达式match
代码实现如下:
sh
not print $ when processing shell command from a file
一开始挺懵的,要判断sh
的输入是否从文件中来,后来发现它提供了一个fstat
的系统调用,函数头为int fstat(int fd, struct stat*)
,而这里的struct stat
可以从kernel/stat.h
中找到:
通过fstat
,我们可以判断一个文件描述符是否为设备,而从user/init.c
中可以看到sh
的标准输入正式从设备console
中来的,所以我们在sh
程序的开始判断一次即可。如果是终端,则每次getcmd
都输出$
,如果不是,则每次都不输出。