LINUX.ORG.RU

Как переназначить обработчик при нажатии ^C для ВСЕХ программ, запущенных из интерактивного shell'а?

 ,


0

0

Как сделать, чтобы при нажатии CTRL+C не происходил посыл SIGINT, а выполнялся мой обработчик? Например, чтобы выполнялся kill -9 -$$.
Т.е. мне надо переназначить обработку для вообще ВСЕХ программ, всяких nano, lynx, less, и вообще всего запускаемого в интерактивном режиме; ну кроме самого текущего интерпретатора и терминала (при этом должно действовать на всех остальных потомков), т.е., возможно, с каким-то списком исключений.

Это маразм, когда нет возможности гарантированно остановить работу исполняющейся программы и всех её потомков. Постоянно сталкиваешься с хернёй, когда скрипт или программа (например rsync) не реагирует на ^C. Я один раз даже столкнулся с тем, что ping, запущенный в скрипте, не отриогировал на SIGINT.
Нужно 100% рабочее решение, гарантирующее моментальное прекращение работы ЛЮБОЙ программы и всех её потомков.

trap из bash не работает.
bind не получилось настроить.

★★★★★

Последнее исправление: teod0r (всего исправлений: 2)

Чёто типа такого

dron@gnu:~$ mkdir src
dron@gnu:~$ cd src
dron@gnu:~/src$ apt source bash
Чтение списков пакетов… Готово
ВНИМАНИЕ: работа над пакетом «bash» ведётся в системе управления версиями «Bzr»:
http://bazaar.launchpad.net/~doko/+junk/pkg-bash-debian
Используйте:
bzr branch http://bazaar.launchpad.net/~doko/+junk/pkg-bash-debian
для получения последних (возможно, невыпущенных) обновлений пакета.
Необходимо скачать 5 897 kB архивов исходного кода.
Пол:1 http://ftp.ru.debian.org/debian testing/main bash 5.1-3 (dsc) [2 296 B]
Пол:2 http://ftp.ru.debian.org/debian testing/main bash 5.1-3 (tar) [5 803 kB]
Пол:3 http://ftp.ru.debian.org/debian testing/main bash 5.1-3 (diff) [92,2 kB]
Получено 5 897 kB за 1с (4 828 kB/s)       
dpkg-source: инфо: извлечение bash в bash-5.1
dpkg-source: инфо: распаковывается bash_5.1.orig.tar.xz
dpkg-source: инфо: распаковывается bash_5.1-3.debian.tar.xz
dpkg-source: инфо: using patch list from debian/patches/series
dpkg-source: инфо: накладывается bash51-001.diff
dpkg-source: инфо: накладывается bash51-002.diff
dpkg-source: инфо: накладывается bash51-003.diff
dpkg-source: инфо: накладывается bash51-004.diff
dpkg-source: инфо: накладывается bash51-005.diff
dpkg-source: инфо: накладывается bash51-006.diff
dpkg-source: инфо: накладывается bash51-007.diff
dpkg-source: инфо: накладывается bash51-008.diff
dpkg-source: инфо: накладывается bashbug-editor.diff
dpkg-source: инфо: накладывается deb-bash-config.diff
dpkg-source: инфо: накладывается deb-examples.diff
dpkg-source: инфо: накладывается man-arithmetic.diff
dpkg-source: инфо: накладывается man-fignore.diff
dpkg-source: инфо: накладывается man-bashrc.diff
dpkg-source: инфо: накладывается man-bashlogout.diff
dpkg-source: инфо: накладывается man-nocaseglob.diff
dpkg-source: инфо: накладывается man-test.diff
dpkg-source: инфо: накладывается man-test2.diff
dpkg-source: инфо: накладывается rbash-manpage.diff
dpkg-source: инфо: накладывается bash-default-editor.diff
dpkg-source: инфо: накладывается input-err.diff
dpkg-source: инфо: накладывается exec-redirections-doc.diff
dpkg-source: инфо: накладывается bash-aliases-repeat.diff
dpkg-source: инфо: накладывается use-system-texi2html.diff
dpkg-source: инфо: накладывается bzero.diff
dpkg-source: инфо: накладывается man-macro-warnings.diff
dpkg-source: инфо: накладывается man-vx-opts.diff
dron@gnu:~/src$ ack "CTRL \('C'\)" ./
bash-5.1/lib/readline/search.c
285:    c = CTRL ('C');  

bash-5.1/lib/readline/vi_mode.c
1999:  if (c == '\033' || c == CTRL ('C'))
dron@gnu:~/src$ 

Ковыряй свой шелл и патчи исходники :3

LINUX-ORG-RU ★★★★★
()

ужно 100% рабочее решение, гарантирующее моментальное прекращение работы ЛЮБОЙ программы и всех её потомков.

gg.c

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

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

    signal(SIGINT, SIG_IGN);
    while(true)
    {
        sleep(1);
        printf("Fuck SIGINT!!!!! OLOLOLOLO. Muahahahaha you luuuseeeeerr ahahah .i. fuck you :)\n");
    }
    return 0;
}
dron@gnu:~$ 


dron@gnu:~$ gcc gg.c ; ./a.out 
Fuck SIGINT!!!!! OLOLOLOLO. Muahahahaha you luuuseeeeerr ahahah .i. fuck you :)
Fuck SIGINT!!!!! OLOLOLOLO. Muahahahaha you luuuseeeeerr ahahah .i. fuck you :)
^C^C^CFuck SIGINT!!!!! OLOLOLOLO. Muahahahaha you luuuseeeeerr ahahah .i. fuck you :)
^C^C^C^CFuck SIGINT!!!!! OLOLOLOLO. Muahahahaha you luuuseeeeerr ahahah .i. fuck you :)
^CFuck SIGINT!!!!! OLOLOLOLO. Muahahahaha you luuuseeeeerr ahahah .i. fuck you :)
^C^C^C^C^CFuck SIGINT!!!!! OLOLOLOLO. Muahahahaha you luuuseeeeerr ahahah .i. fuck you :)
^C^CFuck SIGINT!!!!! OLOLOLOLO. Muahahahaha you luuuseeeeerr ahahah .i. fuck you :)

Так что killall.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от bug

Если stty

А если mv?

stty это программа для настройки терминала. /bin/stty

И у меня Ctrl+u не работает, хотя он в настройках и забинден на kill. (UPD: это не SIGKILL, этот kill относится к операциям редактирования строки - удалению символов)

Ctrl+\ (SIGQUIT) работает, он чуть более действенный чем SIGINT, но его тоже могут игнорить.

В любом случае терминальные настройки любая прога тоже может переназначить, но это делают ещё реже.

Если хочешь чтобы уж точно работало - патчи терминальный движок в ядре, это он за это отвечает. Хотя и от этого хитрая прога может увернуться, но не думаю что такие есть, а если и есть то не думаю что стоит ими пользоваться.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 4)
Ответ на: комментарий от firkax

по сути это действительно связано именно с терминалом, а не с интерпретатором и даже не с обработчиком сигналов. потому что должна быть определённая реакция на ввод (комбинация клавиш и т.п.), а не на какой не сигнал. потому что может быть запущен какой-нибудь nano или lynx, которому плевать на интерпретатор, его запустивший и у них свои обработчики комбинации CTRL+C (привет nano). ввод должен обрабатывать имеено терминал, именно комбинацию клавиш, и вызывать обработчик ввода, НЕ сигнала. НО. могут быть ситуации, когда нужно прибить не самый родительский процесс из сессии (screen, tmux, chroot), а начиная с какой-то определённой вложенности. походу, не всё так определённо.
может, есть какие-то временные готовые решения до патчинга ядра? там через какой-нибудь readline или inputrc, или какие там есть механизмы, не шарю в этом. пытался настроить через команду bind — не получилось: пока нахожусь в bash — функция работает, но стоит запустить lynx или даже sleep — им пофиг, у них свой обработчик срабатывает на комбинацию клавиш

teod0r ★★★★★
() автор топика
Последнее исправление: teod0r (всего исправлений: 1)
Ответ на: комментарий от teod0r

Надо разделять три сущности:

  1. гуи-эмулятор терминала (xterm, gnome-terminal итд) - это программа, которая шлёт в консоль (со своей стороны) все нажатые кнопки, и рисует на экране то что с консоли приходит. Комбинацию Ctrl+C и остальные он шлёт так же как и всё остальное, никаких специальных обрабоок не делает.

  2. ядерный драйвер консоли (не знаю как он там называется) - в данном контексте представлен двумя открытыми «файловыми» потоками: один подсоединён к эмулятору терминала, второй - (обычно) к stdin/stdout/stderr запущеной в терминале проги; в первом приближении можно считать это просто двум концами локального коннекта, но есть отличия: например, если эмулятор прислал ctrl+c, драйвер не шлёт его проге как нажатую кнопку, а вместо этого шлёт SIGINT.

  3. сама прога, bash это или что-то ещё - значения не имеет - все они могут переназначить SIGINT на другое Ctrl+hotkey (тогда Ctrl+C будет слаться как нажатый символ), вообще убрать hotkey или сделать нестандартный обработчик к SIGINT - для всего этого не требуется никаких спец. прав.

bash тут отличается только тем, что SIGINT он игнорирует, а при запуске дочерних прог - снимает (для них) игнор

Так что никакой юзерспейс за это не отвечает, отвечает именно ядро (п.2). Ну, ты можешь конечно в эмуляторе терминала (п.1) сделать костыль, который сам будет перехватывать Ctrl+C, не слать его ядру и делать что-то своё. Делать это надо будет в коде x11-приложения, никаких readline и прочих консольных библиотек там разумеется нет. Делать что-то в п.3 бесполезно, запущеная прога сама там всем управляет, твои костыли просто некуда сувать.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от teod0r

могут быть ситуации, когда нужно прибить не самый родительский процесс из сессии (screen, tmux, chroot), а начиная с какой-то определённой вложенности. походу, не всё так определённо.

И да, выбрать кому слать сигнал - отдельная проблема. А ещё, родительский процесс сессии это обычно шелл (bash например). В стандартной реализации решена просто: сигнал шлётся всем кто приписан к терминалу. Шелл сам сообщает «мне не надо» (signal(SIGINT,SIG_IGN);), проги обычно такое не делают. А вот отличить шелл от проги, которая нелегитимно заигнорила SIGINT, в общем случае довольно сложная задача. Хотя костыльную реалзацию сделать несложно: если имя бинарника = /bin/*sh и заигнорен SIGINT - считаем процесс интерактивным шеллом и не убиваем, остальным шлём SIGKILL.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
21 января 2022 г.
Ответ на: комментарий от anonymous

а в urxvt как-нибудь можно назначить, например на META+z или ALT+z, чтобы что-то запускалось, что будет пришибать всех потомков текущего интерактивного шелла?

teod0r ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.