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

时间:2010-09-22 16:56:36

标签: c linux unix 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;
}

但是,当它运行时,CTRL + C和CTRL + BREAK不再有效,似乎被忽略。

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

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

3 个答案:

答案 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()函数应忽略SIGINTSIGQUIT信号,并在等待命令终止时阻止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;
}

从表面上看,这似乎可以满足我的需求。