Предотвращение распространения SIGINT к Родительскому процессу

Да, шаблон \x00 соответствия к пустому байту.

Пример:

$ printf "\0\n\0\n" > file
$ sed -e 's/\x00/test/' -i file
$ cat file
test
test
$  
9
23.05.2017, 15:39
3 ответа

(Вдохновленный ответом Gilles)

С ISIG набор флага, единственный путь к Child сценарий для получения SIGINT без его родительского получения SIGINT чтобы это было в своей собственной группе процесса. Это может быть выполнено с set -m опция.

Если Вы включаете -m опция в Child сценарий оболочки, это выполнит управление заданиями, не будучи интерактивным. Это заставит это выполнять материал в отдельной группе процесса, препятствуя тому, чтобы родитель получил SIGINT когда INTR символ читается.

Вот описание POSIX -m опция:

-m Эта опция должна поддерживаться если поддержка внедрения опция User Portability Utilities. Все задания должны быть выполнены в их собственных группах процесса. Сразу, прежде чем оболочка выпускает подсказку после завершения фонового задания, сообщение, сообщая, что статус выхода фонового задания должен быть записан в стандартную погрешность. Если задание переднего плана остановится, то оболочка должна записать сообщение в стандартную погрешность к тому эффекту, отформатированному, как описано утилитой заданий. Кроме того, если состояние смен работы кроме выхода (например, если это останавливается для ввода или вывода или останавливается сигналом SIGSTOP), оболочка должна сразу записать подобное сообщение до записи следующей подсказки. Эта опция включена по умолчанию для интерактивных оболочек.

-m опция подобна -i, но это не изменяет поведение оболочки почти так же как -i делает.

Пример:

  • Parent сценарий:

    #!/bin/sh
    
    trap 'echo "PARENT: caught SIGINT; exiting"; exit 1' INT
    
    echo "PARENT: pid=$$"
    echo "PARENT: Spawning child..."
    ./Child
    echo "PARENT: child returned"
    echo "PARENT: exiting normally"
    
  • Child сценарий:

    #!/bin/sh -m
    #         ^^        
    # notice the -m option above!
    
    trap 'echo "CHILD: caught SIGINT; exiting"; exit 1' INT
    
    echo "CHILD: pid=$$"
    echo "CHILD: hit enter to exit"
    read foo
    echo "CHILD: exiting normally"
    

Это - то, что происходит, когда Вы поражаете Control+C в то время как Child ожидает входа:

$ ./Parent
PARENT: pid=12233
PARENT: Spawning child...
CHILD: pid=12234
CHILD: hit enter to exit
^CCHILD: caught SIGINT; exiting
PARENT: child returned
PARENT: exiting normally

Заметьте как родитель SIGINT обработчик никогда не выполняется.

С другой стороны, если Вы изменили бы Parent вместо Child, можно сделать это:

  • Parent сценарий:

    #!/bin/sh
    
    trap 'echo "PARENT: caught SIGINT; exiting"; exit 1' INT
    
    echo "PARENT: pid=$$"
    echo "PARENT: Spawning child..."
    sh -m ./Child  # or 'sh -m -c ./Child' if Child isn't a shell script
    echo "PARENT: child returned"
    echo "PARENT: exiting normally"
    
  • Child сценарий (нормальный; никакая потребность в -m):

    #!/bin/sh
    
    trap 'echo "CHILD: caught SIGINT; exiting"; exit 1' INT
    
    echo "CHILD: pid=$$"
    echo "CHILD: hit enter to exit"
    read foo
    echo "CHILD: exiting normally"
    

Альтернативные идеи

  1. Измените другие процессы в группе приоритетного процесса для игнорирования SIGINT на время Child. Это не рассматривает Ваш вопрос, но это может получить Вас, что Вы хотите.
  2. Изменить Child кому:
    1. Использовать stty -g создать резервную копию текущих терминальных настроек.
    2. Выполненный stty -isig не сгенерировать сигналы с INTR, QUIT, и SUSP персонажи.
    3. В фоновом режиме считайте терминальный вход и отправьте сигналы сами как соответствующие (например, работайте kill -QUIT 0 когда Управление +\читается, kill -INT $$ когда Control+C читается). Это не тривиально, и не может быть возможно заставить это работать гладко если Child сценарий или что-либо, что это выполняет, предназначены, чтобы быть интерактивными.
    4. Восстановите терминальные настройки прежде, чем выйти (идеально от прерывания на EXIT).
  3. То же как № 2 кроме вместо выполнения stty -isig, ожидайте пользователя для удара, Входят или некоторый другой неспециальный ключ перед уничтожением Child.
  4. Запишите свое собственное setpgid утилита в C, Python, Perl, и т.д. что можно использовать для вызова setpgid(). Вот является сырая нефть C реализацией:

    #define _XOPEN_SOURCE 700
    #include <unistd.h>
    #include <signal.h>
    
    int
    main(int argc, char *argv[])
    {
        // todo: add error checking
        void (*backup)(int);
        setpgid(0, 0);
        backup = signal(SIGTTOU, SIG_IGN);
        tcsetpgrp(0, getpid());
        signal(SIGTTOU, backup);
        execvp(argv[1], argv + 1);
        return 1;
    }
    

    Использование в качестве примера от Child:

    #!/bin/sh
    
    [ "${DID_SETPGID}" = true ] || {
        # restart self after calling setpgid(0, 0)
        exec env DID_SETPGID=true setpgid "$0" "$@"
        # exec failed if control reached this point
        exit 1
    }
    unset DID_SETPGID
    
    # do stuff here
    
10
27.01.2020, 20:05

Как глава, которую Вы цитируете из POSIX, объясняет, SIGINT отправляется целой группе приоритетного процесса. Поэтому, чтобы не уничтожать родителя программы, примите меры, чтобы это работало в его собственной группе процесса.

Оболочки не предоставляют доступ к setpgrp через встроенную или синтаксическую конструкцию, но существует косвенный способ достигнуть его, который должен выполнить оболочку в интерактивном режиме. (Благодаря Stéphane Gimenez для приема.)

ksh -ic '
  … the part that needs to be interruptible without bothering the parent …
'
4
27.01.2020, 20:05
  • 1
    +1 для умной мысли, хотя остерегаются этого изменения поведения оболочки, когда это - интерактивная оболочка (по крайней мере, оболочка POSIX делает; я не знаком с деталями ksh). Примеры: ${ENV} получен, оболочка сразу не выйдет, когда она встретится с ошибкой, SIGQUIT и SIGTERM проигнорированы. –  Richard Hansen 30.06.2013, 02:06

Ну, от вопроса о Переполнении стека Вы сослались на него, ясно указывает, что родитель должен быть настроен для обработки сигнала.

Во-вторых, ссылка POSIX ясно указывает, что, "Если ISIG установлен, символ INTR должен быть отброшен при обработке".

Таким образом, это - две опции. Третье должно было бы выполнить ребенка в своей собственной группе процесса.

1
27.01.2020, 20:05
  • 1
    Спасибо за Ваш ответ. Я также должен выяснить способ сделать, чтобы пользователь вышел из сценария. Существует ли способ установить ISIG, и в то же время допускают некоторое Сочетание клавиш CONTRL (CTRL-Q может быть) выходить из сценария оболочки, не отправляя сигналы породить и аналогично? Кроме того, Вы могли сказать мне, как я мог выполнить ребенка в другой группе процесса, чем ее родитель? –  Guddu 28.06.2013, 08:42

Теги

Похожие вопросы