操作系统源码阅读 - 3 : 自定义命令
阅读源码,帮助理解操作系统。
上一篇: 操作系统源码阅读 - 2 : 基础命令与操作系统接口
head命令
在xv6系统上实现head命令。head命令用来显示开头某个数量的文字区块。在自定义实现中,head命令一共有三种形式。
head filename
head [-number] filename
head [-n] number filename
函数实现
具体实现上,考虑抽象为一个函数head(int fd, int number),用来实现读取文件描述符为fd的文件的前number行内容并输出。同时,在main()函数中,分别分析head命令的三种模式,并依次调用head()函数。实现文件为head.c,核心代码如下:
char buf[512];
void head(int fd,int line)
{
int n, i;
int tag = 0;
while((n = read(fd,buf, sizeof(buf))) > 0)
{
for(i = 0;i < n;i ++)
{
if(buf[i] == '\n')
{
tag = tag + 1;
if(tag == line)
{
i = i + 1;
break;
}
}
}
if(write(1,buf, i) != i)
{
printf(1, "head: write error\n");
exit();
}
if(tag == line)
{
break;
}
}
if(n < 0)
{
printf(1,"head: read error\n");
exit();
}
}
int main(int argc, char * argv[])
{
int fd;
int line;
if(argc < 2)
{
printf(1,"head: no parameters\n");
exit();
}
else if (argc == 2)
{
if((fd = open(argv[1],0)) < 0)
{
printf(1,"head: cannot open %s\n", argv[1]);
exit();
}
line = 10;
head(fd,line);
close(fd);
exit();
}
else if (argc == 3)
{
if(argv[1][0]!= '-')
{
printf(1,"head: wrong parameters\n");
exit();
}
else
{
line = 0;
for(int i = 1;argv[1][i] != '\0';i ++)
{
int tem = (argv[1][i] - '0');
line = line*10 + tem;
}
if((fd = open(argv[2],0)) < 0)
{
printf(1,"head: cannot open %s\n", argv[2]);
exit();
}
head(fd,line);
close(fd);
}
exit();
}
else
{
if(argv[1][0]!= '-'||argv[1][1]!='n'||argv[1][2]!='\0')
{
printf(1,"head: wrong parameters\n");
exit();
}
else
{
line = 0;
for(int i = 0;argv[2][i] != '\0';i ++)
{
int tem = (argv[2][i] - '0');
line = line*10 + tem;
}
if((fd = open(argv[3],0)) < 0)
{
printf(1,"head: cannot open %s\n", argv[3]);
exit();
}
head(fd,line);
close(fd);
}
exit();
}
}
参考cat命令的实现即可。
修改Makefile文件
实现head.c文件之后,需要将该文件添加到Makefile文件的编译序列中,具体修改如下:
UPROGS=\
_cat\
_echo\
_forktest\
_grep\
_head\
_init\
_kill\
_ln\
_ls\
_mkdir\
_rm\
_sh\
_stressfs\
_usertests\
_wc\
_zombie\
## 添加_head\。当os运行时,通过ls命令可以找到head程序。
EXTRA=\
mkfs.c ulib.c user.h cat.c echo.c forktest.c grep.c head.c kill.c\
ln.c ls.c mkdir.c rm.c stressfs.c usertests.c wc.c zombie.c\
printf.c umalloc.c\
README dot-bochsrc *.pl toc.* runoff runoff1 runoff.list\
.gdbinit.tmpl gdbutil\
## 添加head.c。将head.c添加到编译队列
之后,按流程进行编译,运行即可。实验结果如下: