bash Linux 程序的外部禁用信号

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4515274/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 23:09:15  来源:igfitidea点击:

Externally disabling signals for a Linux program

linuxbashsignalsexternalbash-trap

提问by Harry

On Linux, is it possible to somehow disable signaling for programs externally... that is, without modifying their source code?

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

Context:

语境:

I'm calling a C (and also a Java) program from within a bash script on Linux. I don't want any interruptions for my bash script, and for the other programs that the script launches (as foreground processes).

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

While I can use a...

虽然我可以使用...

trap '' INT

... in my bash script to disable the Ctrl C signal, this works only when the program control happens to be in the bash code. That is, if I press Ctrl C while the C program is running, the C program gets interrupted and it exits! This C program is doing some critical operation because of which I don't want it be interrupted. I don't have access to the source code of this C program, so signal handling inside the C program is out of question.

...在我的 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

Regards,

问候,

/HS

/HS

回答by caf

The process signal mask is inherited across exec, so you can simply write a small wrapper program that blocks SIGINTand executes the target:

进程信号掩码是跨 继承的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;
}

If you compile this program to noint, you would just execute ./noint ./y.

如果将此程序编译为noint,则只需执行./noint ./y

As ephemient notes in comments, the signal disposition is also inherited, so you can have the wrapper ignore the signal instead of blocking it:

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

#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;
}

(and of course for a belt-and-braces approach, you could do both).

(当然,对于腰带和大括号方法,您可以两者都做)。

回答by J-16 SDiZ

The "trap" command is local to this process, never applies to children.

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

To really trap the signal, you have to hack it using a LD_PRELOADhook. This is non-trival task (you have to compile a loadable with _init(), sigaction()inside), so I won't include the full code here. You can find an example for SIGSEGV on Phack Volume 0x0b, Issue 0x3a, Phile #0x03.

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

Alternativlly, try the nohupand tailtrick.

或者,尝试nohuptail技巧。

nohup  your_command &
tail -F nohup.out

回答by richo

I would suggest that your C (and Java) application needs rewriting so that it can handle an exception, what happens if it really does need to be interrupted, power fails, etc...

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

I that fails, J-16 is right on the money. Does the user need to interract with the process, or just see the output (do they even need to see the output?)

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

回答by calandoa

The solutions explained above are not working for me, even by chaining the both commands proposed by Caf.

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

However, I finally succeeded in getting the expected behavior this way :

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

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

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

If I press Ctrl-C while childis running, it will wait that it exits, then will print AAA and 2. childwill not receive any signals.

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

The subshell is used to prevent the PID from being shown.

子外壳用于防止显示 PID。

And sorry... this is for zsh though the question is for bash, but I do not know bash enough to provide an equivalent script.

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

回答by lama12345

This is example code of enabling signals like Ctrl+C for programs which block it.

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

fixControlC.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;
}

Compile it:

编译它:

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

Run it:

运行:

LD_LIBRARY_PATH=. LD_PRELOAD=fixControlC.so mysqld