程序是否可以捕获退出系统调用生成的SIGTERM?

时间:2015-11-26 10:22:15

标签: c signals

我的程序如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>

int main()
{
    struct sigaction new_sa;
    struct sigaction old_sa;
    sigfillset(&new_sa.sa_mask);
    new_sa.sa_handler = SIG_IGN;
    new_sa.sa_flags = 0;
    int input;

    if (sigaction(SIGTERM, &new_sa, &old_sa) == 0 && old_sa.sa_handler != SIG_IGN) {
        new_sa.sa_handler = NULL;
        sigaction(SIGTERM, &new_sa, 0);
    }

    printf("Pgm is running\n");
    while (1) {
        printf("Enter input\n");
        scanf("%d", &input);
        if (!input) {
            /* I actually call a libraries API which calls exit()
             * Just calling exit here for simpilicity */
            exit(1);
        }
    }
}

我想处理/忽略退出系统调用生成的SIGTERM。可能吗? 我没办法避免调用exit,因为它实际上是一个试图退出我想要避免的程序的库调用。

3 个答案:

答案 0 :(得分:2)

查看glibc source退出,看起来似乎不可能。但是,如果您正在使用另一个C std库,那可能就是这样。

你可以做at_exit的东西,但是你无法阻止它。

<强> [编辑]

由于this question中的原因,此处的所有内容显然不适用于退出。

如果您使用gnu ld,则可以使用gnu ld __run_exit_handlers选项覆盖exit--wrap,但我还没有尝试过。

如果您可以使用gnu ld,则可以执行--wrap exit,然后在代码中实施__wrap_exit()。如果您想在此之后致电exit,可以通过__real_exit()访问它。 这是一个gnu ld功能,我不确定它有多普遍可用。

答案 1 :(得分:2)

你当然可以抓住.top-info { background: url("http://i.stack.imgur.com/prA95.jpg") no-repeat left 15px; height: 40rem; background-size: contain; border-top: 10px solid transparent; border-image: url("http://i.stack.imgur.com/SUUpP.png") 30 stretch; -webkit-border-image: url("http://i.stack.imgur.com/SUUpP.png") 30 stretch; } 。但这不是问题所在。您想覆盖SIGTERM来电。

这在任何便携式或标准兼容方式下都是不可能的。 exit()定义的函数之一返回其调用方。通常,这是使用gcc中的exit()完成的,而C11为了相同的目的引入了宏__attribute__((noreturn))

尝试从此类函数返回,如_Noreturnundefined behaviour

我能想到的选择很少:

  • 使用您的函数编译并替换:exit()
  • gcc -Dexit=not_exit file.c编写一个钩子函数。有关示例,请参阅here。实现钩子函数可能根本不起作用,因为这个 noreturn 在C11&#39; exit()之前的大多数libc实现中都存在。
  • 使用@evading建议的GNU&lt; ld。我相信这相当于上面的内容,但链接器为你完成了一半的工作。

修改_Noreturn以删除<stdlib.h>功能的_Noreturn(或其等效)属性可能会使其正常工作。这些都不能保证有效。我们已经进入了UB的土地。

其他选项是安装exit()处理程序,如果您想在atexit()之前执行某些操作,这可能很有用。

如果您不调用exit()而是返回错误代码,那么更安全的方法是修改库。在我看来,要么库设计得很糟糕,它会随机随意退出,或者可能是库存退出的一个很好的理由(由于一些不可恢复的错误)并且你的应用程序不应该继续下去,你正试图这样做。

答案 2 :(得分:0)

可能是在fork的子进程中运行库调用。这不会阻止对exit的调用,但如果您想自己处理错误,则可能是一种解决方法。

按照教程Fork, Exec and Process control。如果调用成功,我使用管道发送库调用的结果。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){
  int pipefd[2];
  pipe(pipefd); //Create pipe for communication
  pid_t pid = fork();  
  if (pid == 0){ //Child process
    close(pipefd[0]); // close the read-end of the pipe,
    printf("Run library here\n");
    //    exit(3); if failed
    int val=4; //Result of library call send to parent
    write(pipefd[1], &val, sizeof(val));
    close(pipefd[1]); // close the write-end of the pipe
    exit(EXIT_SUCCESS);
  }
  else if (pid < 0){           
    printf("Failed to fork\n");
  }
  else{//Parent process
    close(pipefd[1]);
    printf("Parent process\n");
    int status=0;
    int pid=wait(&status);
    printf("The pid %d finished with status %d\n",pid,status);        
    if (status==EXIT_SUCCESS){//The library call was successful
      int val=2;
      read(pipefd[0],&val,sizeof(int)); //Read data from pipe and do something with it
      printf("Value %d received\n",val);
    }
    close(pipefd[0]);
  }
  return 0;
}