我编写了一个从内部调用系统命令的程序:
#include <stdlib.h>
int main(void)
{
while(1)
{
system("ls 2>&1 1>/dev/null"); // comment this line out to enable ctrl+break
}
return 0;
}
但是,当它运行时,CTRL + C和CTRL + BREAK不再有效,似乎被忽略。
我正在尝试编写一个程序,在后台执行一些涉及shell的操作,但我也希望能够在用户想要破解时突破程序。
有没有办法让它以我想要的方式工作?我应该改变架构来执行某种fork / exec吗?
答案 0 :(得分:5)
来自POSIX specification for system()
:
system()函数忽略SIGINT和SIGQUIT信号,并在等待命令终止时阻塞SIGCHLD信号。如果这可能导致应用程序错过可能导致其被杀死的信号,则应用程序应检查 system()的返回值,并在命令因应用程序终止时采取适合应用程序的任何操作收到信号。
因此,为了正确响应信号,您需要检查system()
的返回值。
system()以waitpid()
指定的格式返回命令语言解释器的终止状态
waitpid()
的文档引用了wait()
的文档,它指示您使用以下宏来找出进程退出的原因:
- WIFEXITED(stat_val)
如果为正常终止的子进程返回状态,则计算为非零值。- WEXITSTATUS(stat_val)
如果WIFEXITED(stat_val)的值不为零,则此宏计算为子进程传递给_exit()或exit()的status参数的低8位,或子进程从main返回的值()。- WIFSIGNALED(stat_val)
如果由于收到未捕获的信号而终止的子进程返回状态,则计算为非零值(请参阅参考资料)。- WTERMSIG(stat_val)
如果WIFSIGNALED(stat_val)的值不为零,则此宏将计算导致子进程终止的信号编号。- WIFSTOPPED(stat_val)
如果为当前停止的子进程返回状态,则计算为非零值。- WSTOPSIG(stat_val)
如果WIFSTOPPED(stat_val)的值不为零,则此宏将计算导致子进程停止的信号编号。- WIFCONTINUED(stat_val)
如果从作业控制停止继续的子进程返回状态,则计算为非零值。
以下是如何使用此信息的示例,而无需分叉单独的进程。请注意,您实际上不会在父进程中收到信号,但您可以确定发送到子进程的信号:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
while(1)
{
int result = system("ls 2>&1 1>/dev/null");
if (WIFEXITED(result)) {
printf("Exited normally with status %d\n", WEXITSTATUS(result));
} else if (WIFSIGNALED(result)) {
printf("Exited with signal %d\n", WTERMSIG(result));
exit(1);
} else {
printf("Not sure how we exited.\n");
}
}
return 0;
}
如果你运行它,你会得到:
$ ./sys Exited normally with status 0 Exited normally with status 0 Exited normally with status 0 Exited normally with status 0 Exited normally with status 0 Exited normally with status 0 ^CExited with signal 2
答案 1 :(得分:2)
根据IEEE Std 1003.1-2008 (POSIX):
system()
函数的行为就像使用fork()
创建子进程一样,...
system()
函数应忽略SIGINT
和SIGQUIT
信号,并在等待命令终止时阻止SIGCHLD信号。如果这可能导致应用程序错过可能导致其被杀死的信号,则应用程序应检查system()
的返回值,并在命令因接收到信号而终止时采取适合应用程序的任何操作。在子进程终止之前,
system()
函数不会返回。
答案 2 :(得分:1)
上面的San Jacinto的评论:
根据POSIX规范链接,system()基本上是forks,阻塞父节点,并忽略子节点中的某些信号。您可以通过首先为system()创建另一个进程来阻止此操作。这使得原始进程(运行shell的进程的祖父进程)可以自由接受终止信号。
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main(void)
{
pid_t pid;
while(1)
{
pid = fork();
if(pid > 0) // parent
{
wait(0);
}
else if(pid == 0) // child
{
system("ls 2>&1 1>/dev/null");
return 0;
}
else // could not fork
{
return 1;
}
}
return 0;
}
从表面上看,这似乎可以满足我的需求。