Внешнее отключение сигналов для программы Linux

в Linux можно как-то отключить сигнализацию для программ внешне... то есть без изменения исходного кода?

контекст:

Я вызываю C (а также Java) программа из сценария bash в Linux. Я не хочу прерываний для моего сценария bash и для других программ, которые запускает скрипт (как процессы переднего плана).

пока я могу использовать ля...

trap '' INT

... в моем сценарии bash для отключения сигнала Ctrl C это работает только тогда, когда элемент управления программой находится в коде bash. То есть, если я нажимаю Ctrl C во время работы программы 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

5 ответов


маска сигнала процесса наследуется через 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;
}

(и, конечно, для подхода пояса и брекетов, вы могли бы сделать оба).


команда "ловушка" локальна для этого процесса, никогда не применяется к детям.

чтобы действительно поймать сигнал, вы должны взломать его с помощью LD_PRELOAD крюк. Это нетривиальная задача (вы должны скомпилировать загружаемый с помощью _init(), sigaction() внутри), поэтому я не буду включать полный код здесь. Вы можете найти пример для SIGSEGV на Phack Volume 0x0b, выпуск 0x3a, Phile #0x03.

Alternativlly, попробовать nohup и tail трюк.

nohup  your_command &
tail -F nohup.out

Я бы предположил, что ваше приложение C (и Java) нуждается в перезаписи, чтобы оно могло обрабатывать исключение, что произойдет, если его действительно нужно прервать, сбой питания и т. д...

Я, который терпит неудачу, J-16 прямо на деньги. Нужно ли пользователю взаимодействовать с процессом или просто видеть вывод (Нужно ли вообще видеть вывод?)


решения, объясненные выше, не работают для меня, даже путем цепочки обеих команд, предложенных Caf.

тем не менее, мне наконец удалось получить ожидаемое поведение таким образом :

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

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

Если я нажму Ctrl-C в то время как child работает, он будет ждать, что он выйдет, затем напечатает AAA и 2. child не будет принимать никаких сигналов.

subshell используется для предотвращения отображения PID.

и к сожалению... это для zsh хотя вопрос для bash, но я не знаю, хватит Баш аналогичным сценарием.


Это пример кода включения сигналов, таких как 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