1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
void eval(char *cmdline)
{
pid_t pid = 0;
int state, bg_or_not, builtin_or_not, is_available_cmd;
char *args[MAXARGS];
char *first_cmd;
sigset_t blockset;
const char *err_msg = "%s: Command not found\n";
/* 使用一个字符串数组来存储所有可以接受的命令 */
/* 偷懒使用这样的硬编码方式,肯定有更好的在路径查询函数,比如查询 '/bin/echo' 是否存在 */
/* 更新:这个函数就是C库函数 access, 这个硬编码套路留着以博一笑 :) */
/* const char *available_cmds[5]={"./myint", "./myspin", "./mysplit", "./mystop", "/bin/echo"}; */
/* 创建空的信号集合 */
sigemptyset(&blockset);
/* 添加指定信号到集合中 */
sigaddset(&blockset, SIGCHLD);
bg_or_not = parseline(cmdline, args);
first_cmd = args[0];
builtin_or_not = builtin_cmd(args);
if(!builtin_or_not)
{
is_available_cmd = access(first_cmd, 00);
/* 硬编码套路 */
/* for(i=0;i<5;i++) */
/* { */
/* if(!strcmp(first_cmd, available_cmds[i])) */
/* { */
/* is_available_cmd = 1; */
/* break; */
/* } */
/* } */
if(is_available_cmd==-1)
{
printf(err_msg, first_cmd);
return;
}
/* 阻塞对应信号,最后一个参数是 NULL 是因为不需要保存之前的集合为备份 */
sigprocmask(SIG_BLOCK, &blockset, NULL);
pid = fork();
if(pid>0)
{
if(bg_or_not)
{
state = BG;
}
else
{
state = FG;
}
addjob(jobs, pid, state, cmdline);
/* 在执行完 addjob 之后需要在父进程中取消阻塞 */
sigprocmask(SIG_UNBLOCK, &blockset, NULL);
if(state==FG)
{
/* 如果是 foreground job, 需要等待其完成 */
waitfg(pid);
}
else
{
printf("[%d] (%d) %s", maxjid(jobs), pid, cmdline);
}
}
if(pid==0)
{
/* lab pdf 中的提示,后台子进程需要更改自己的组号 */
/* 因为 ./tsh 执行时其实就是一个 foreground process */
/* 任何本程序派生的子进程默认都在 foreground process group 里 */
setpgid(0, 0);
/* 子进程继承了父进程的阻塞状态,必须在 execve 前取消阻塞 */
sigprocmask(SIG_UNBLOCK, &blockset, NULL);
execve(args[0], args, environ);
}
}
return;
}
|