任务内容
1.使用fork,exec,wait实现mybash
查找资料:
fork函数
通过fork()系统调用我们可以创建一个和当前进程印象一样的新进程.我们通常将新进程称为子进程,而当前进程称为父进程.而子进程继承了父进程的整个地址空间,其中包括了进程上下文,堆栈地址,内存信息进程控制块(PCB)等.通过man手册我们可以轻松知道fork()包含的头文件<sys/types.h>和<unistd.h>,功能就是创建一个子进程.函数原型:pid_t fork(void),pid_t是带一个代表经常号pid的数据结构.如果创建成功一个子进程,对于父进程来说是返回子进程的ID.而对于子进程来说就是返回0.而返回-1代表创建子进程失败.
exec函数
在fork后的子进程中使用exec函数族,可以装入和运行其它程序(子进程替换原有进程,和父进程做不同的事)。exec函数族可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段。在执行完后,原调用进程的内容除了进程号外,其它全部被新程序的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。
wait函数
int wait(int* statloc);
int waitpid(pid_t pid, int* statloc, int options);
这两个函数的区别如下:1. 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞;2. waitpid()并不等待在其调用之后的第一个终止的子进程,它有若干个选项,可以控制它所等待的进程;
2.写出伪代码,产品代码和测试代码
伪代码
#include<stdio.h>
int main(){
读取命令行输入内容;
判断是否为bash中的命令;
判断是否新建子进程并执行;
执行命令结束;
}
mybash.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<string.h>
int main()
{
while(1)
{
printf("20165336mybash:");
fflush(stdout);
char buffer[1024];
int read_size = read(1, buffer, sizeof(buffer));
if (read_size > 0)
{
buffer[read_size - 1] = 0;
}
char* bash_argv[32] = {NULL};
int bash_index = 0;
char* start = buffer;
while (*start != '\0')
{
while (*start != '\0' && isspace(*start))
{
*start = '\0';
start++;
}
bash_argv[bash_index++] = start;
while (*start != '\0' && !isspace(*start))
{
start++;
}
}
pid_t pid = vfork();
if (pid < 0)
{
printf("vfork failure\n");
exit(1);
}
else if (pid == 0)
{
int i = 0;
int flag = 0;
for (; bash_argv[i] != NULL; ++i )
{
if (strcmp(">", bash_argv[i]) == 0)
{
flag = 1;
break;
}
}
int copyFd;
bash_argv[i] = NULL;
if (flag)
{
if (bash_argv[i+1] == NULL)
{
printf("command error\n");
exit(1);
}
close(1);
int fd = open(bash_argv[i+1], O_WRONLY | O_CREAT, 0777);
copyFd = dup2(1, fd);
}
execvp(bash_argv[0], bash_argv);
if (flag)
{
close(1);
dup2(copyFd, 1);
}
exit(1);
}
else
{
int status = 0;
int ret = waitpid(pid, &status, 0);
if (ret == pid)
{
if (WIFEXITED(status))
{
printf("exitCode is %d\n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))
{
printf("signal is %d\n", WTERMSIG(status));
}
}
}
}
return 0;
}