13

在 Linux 上,是否有可能以某种方式在外部禁用程序的信号发送……也就是说,不修改它们的源代码?

语境:

我正在 Linux 上的 bash 脚本中调用 C(以及 Java)程序。我不希望我的 bash 脚本和脚本启动的其他程序(作为前台进程)有任何中断。

虽然我可以使用...

trap '' INT

...在我的 bash 脚本中禁用 Ctrl C 信号,这仅在程序控件恰好位于 bash 代码中时才有效。也就是说,如果我在 C 程序运行时按 Ctrl C,C 程序就会中断并退出!这个 C 程序正在执行一些关键操作,因此我不希望它被中断。我无权访问该 C 程序的源代码,因此 C 程序内部的信号处理是不可能的。

#!/bin/bash

trap 'echo You pressed Ctrl C' INT 

# A C program to emulate a real-world, long-running program,
# which I don't want to be interrupted, and for which I 
# don't have the source code!
#
# File: y.c
# To build: gcc -o y y.c
#
# #include <stdio.h>
# int main(int argc, char *argv[]) {
#  printf("Performing a critical operation...\n");
#    for(;;); // Do nothing forever.
#  printf("Performing a critical operation... done.\n");
# }

./y

问候,

/HS

4

5 回答 5

13

进程信号掩码是继承的exec,因此您可以简单地编写一个小包装程序来阻止SIGINT和执行目标:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        sigset_t sigs;

        sigemptyset(&sigs);
        sigaddset(&sigs, SIGINT);
        sigprocmask(SIG_BLOCK, &sigs, 0);

        if (argc > 1) {
                execvp(argv[1], argv + 1);
                perror("execv");
        } else {
                fprintf(stderr, "Usage: %s <command> [args...]\n", argv[0]);
        }
        return 1;
}

如果你把这个程序编译成noint,你只需执行./noint ./y.

正如注释中的临时注释,信号处置也是继承的,因此您可以让包装器忽略信号而不是阻止它:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        struct sigaction sa = { 0 };

        sa.sa_handler = SIG_IGN;
        sigaction(SIGINT, &sa, 0);

        if (argc > 1) {
                execvp(argv[1], argv + 1);
                perror("execv");
        } else {
                fprintf(stderr, "Usage: %s <command> [args...]\n", argv[0]);
        }
        return 1;
}

(当然对于腰带和大括号的方法,你可以同时做)。

于 2010-12-23T02:58:31.640 回答
3

“trap”命令是这个进程的本地命令,从不应用于子进程。

要真正捕获信号,您必须使用LD_PRELOAD钩子来破解它。这是一项非常重要的任务(您必须在内部编译一个可加载的_init(), sigaction()),所以我不会在此处包含完整的代码。您可以在Phack Volume 0x0b, Issue 0x3a, Phile #0x03上找到 SIGSEGV 的示例。

或者,试试nohupandtail技巧。

nohup  your_command &
tail -F nohup.out
于 2010-12-23T02:12:36.890 回答
0

上面解释的解决方案对我不起作用,即使链接 Caf 提出的两个命令也是如此。

但是,我终于成功地以这种方式获得了预期的行为:

#!/bin/zsh
setopt MONITOR
TRAPINT() { print AAA }

print 1
( ./child & ; wait)
print 2

如果我在运行时按 Ctrl-C child,它将等待它退出,然后将打印 AAA 和 2.child将不会收到任何信号。

子shell 用于防止显示PID。

抱歉……虽然问题是针对 bash 的,但这是针对 zsh 的,但我对 bash 的了解不足以提供等效的脚本。

于 2014-07-09T18:30:15.863 回答
0

我建议您的 C(和 Java)应用程序需要重写,以便它可以处理异常,如果确实需要中断,电源故障等会发生什么......

我失败了,J-16 是对的。用户是否需要与流程交互,或者只查看输出(他们甚至需要查看输出吗?)

于 2010-12-23T02:50:02.753 回答
0

这是为阻止它的程序启用诸如 Ctrl+C 之类的信号的示例代码。

fixControlC.c

#include <stdio.h>
#include <signal.h>
int sigaddset(sigset_t *set, int signo) {
    printf("int sigaddset(sigset_t *set=%p, int signo=%d)\n", set, signo);
    return 0;
}

编译它:

gcc -fPIC -shared -o fixControlC.so fixControlC.c

运行:

LD_LIBRARY_PATH=. LD_PRELOAD=fixControlC.so mysqld
于 2015-07-02T09:31:59.880 回答