如何在调用系统后启用ctrl-c/ctrl + break?

Mar*_*tin 2 c unix linux shell system

我编写了一个从内部调用系统命令的程序:

#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;
}
Run Code Online (Sandbox Code Playgroud)

但是,当它运行时,CTRL + C和CTRL + BREAK不再起作用,似乎被忽略.

我正在尝试编写一个程序,在后台执行一些涉及shell的操作,但我也希望能够在用户想要破解时突破程序.

有没有办法让它按我想要的方式工作?我应该改变架构来执行某种fork/exec吗?

Bri*_*ell 5

POSIX规范system():

系统()函数将忽略SIGINT和SIGQUIT信号,并阻止SIGCHLD信号,同时等待命令来终止.如果这可能导致应用程序错过可能已将其杀死的信号,则应用程序应检查system()的返回值,并在命令因接收到信号而终止时采取适合应用程序的任何操作.

因此,为了正确响应信号,您需要检查返回值system().

system()以waitpid()指定的格式返回命令语言解释器的终止状态

以及waitpid()参考文档的文档wait(),它们指示您使用以下宏来查找进程退出的原因:

  • WIFEXITED(stat_val)
    如果正常终止的子进程返回状态,则求值为非零值.
  • WEXITSTATUS(stat_val)
    如果WIFEXITED(stat_val)的值不为零,则此宏计算为子进程传递给_exit()或exit()的状态参数的低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;
}
Run Code Online (Sandbox Code Playgroud)

如果你运行它,你得到:

$ ./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