Внешнее отключение сигналов для программы Linux - PullRequest
12 голосов
/ 23 декабря 2010

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

Контекст:

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

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

trap '' INT

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

Ответы [ 5 ]

13 голосов
/ 23 декабря 2010

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

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

3 голосов
/ 23 декабря 2010

Команда "trap" является локальной для этого процесса, никогда не применяется к дочерним элементам.

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

Альтернативно, попробуйте трюк nohup и tail.

nohup  your_command &
tail -F nohup.out
0 голосов
/ 02 июля 2015

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

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

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

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

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

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

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

И извините ... это для zsh, хотя вопрос касается bash, но я недостаточно знаю bash, чтобы предоставить эквивалентный скрипт.

0 голосов
/ 23 декабря 2010

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

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

...