簡體   English   中英

如何在調用系統后啟用ctrl-c / ctrl + break?

[英]How can I enable ctrl-c / ctrl+break after calling 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嗎?

system()POSIX規范

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

根據IEEE Std 1003.1-2008(POSIX)

  • system()函數的行為應該像使用fork() ,...創建子進程一樣

  • system()函數應忽略SIGINTSIGQUIT信號 ,並在等待命令終止時阻塞SIGCHLD信號。 如果這可能導致應用程序錯過可能已將其殺死的信號,則應用程序應檢查system()的返回值,並在命令因接收到信號而終止時采取適合應用程序的任何操作。

  • 在子進程終止之前, system()函數不會返回。

來自San Jacinto的評論:

system()基本上是forks,阻塞父節點,並根據POSIX規范鏈接忽略子節點中的某些信號。 您可以通過首先為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;
}

從表面上看,這似乎是我所需要的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM