Как отправить управляющий символ Ctrl-C или сообщение о зависании терминала в дочерний процесс?
У меня есть дочерний процесс, который работает в псевдотерминале. Родительский процесс не запускается с правами root, но дочерний процесс выполняется через su или sudo. Из-за этого невозможно отправить сигнал дочернему процессу, чтобы заставить его выйти. Я хочу заставить его выйти одним из следующих способов:
- эмуляция Ctrl-C.
- Эмулирует отключение терминала.
Как мне это сделать? У меня уже есть pty master fd, и я пробовал что-то вроде этого:
write(master, &termios.c_cc[VINTR], 1)
но он ничего не делает.
Ответы
Ответ 1
В конце концов я пошел со следующим решением:
После форматирования вместо exec'ing sudo немедленно, я выполняю() вспомогательный дочерний процесс, который, в свою очередь, вилки и execs sudo и вызывает waitpid на нем. Итак, иерархия процессов выглядит так:
original process <---- runs as user
|
+-- helper process <---- runs as user, session leader,
| has own pty, in pty foreground process group
|
+--- sudo <---- runs as root
Убив вспомогательный процесс, у pty больше нет процесса переднего плана. Это заставит ОС отправлять SIGHUP во всю группу процессов переднего плана, независимо от пользователя, поэтому sudo также SIGHUP'ed.
Ответ 2
Мне кажется, что если у вас действительно есть pty (если вы не имеете в виду что-то еще по псевдотерминалу), все, что вам нужно сделать, это отправить Control-C в этот FD. В качестве доказательства этого я передаю следующий код в Python (но достаточно близко к C, требуемому для этого):
import pty, os, sys, time
pid, fd = pty.fork()
if pid == 0:
os.execv('/bin/sh', ['/bin/sh', '-c',
'while true; do date; sleep 1; done'])
sys.exit(0)
time.sleep(3)
os.write(fd, '^C')
print 'results:', os.read(fd, 1024)
Это разворачивает процесс под pty, который запускает бесконечный цикл печати
Дата. Затем родитель ждет 3 секунды и отправляет элемент управления-C.
В результате получается следующий результат:
guin:/tmp$ time python /tmp/foo
results: Fri Feb 5 08:28:09 MST 2010
Fri Feb 5 08:28:10 MST 2010
Fri Feb 5 08:28:11 MST 2010
python /tmp/foo 0.02s user 0.01s system 1% cpu 3.042 total
guin:/tmp$
Он проработал чуть более 3 секунд, распечатал дату 3 раза и вышел.
Ответ 3
Существует два способа добиться этого:
- От дочернего процесса, поймайте сигнал SIGCHLD и обработайте его, вы можете _exit (0) закончить дочерний процесс
- Там есть программа под названием ptree. Вы можете обмануть это, сделав это так... в псевдокоде:
obtain the parent pid.
using _popen("ptree %d", parent_pid)
for each entry of child process
system ("kill -1 %d", child_process_pid)
Вот два, которые приходят на ум... извините, если он не поможет вам,
Надеюсь, это поможет,
С наилучшими пожеланиями,
Том.
Ответ 4
Закрытие мастера должно сигнализировать о зависании с группой управления процессом подчиненного устройства.
Ответ 5
Я думаю, вам нужно использовать ioctl
для вставки символа прерывания вместо write
. К сожалению, механизм для этого не кажется переносимым. Для Linux это выглядит так:
ioctl(master, TIOCSTI, &termios.c_cc[VINTR]);
Ответ 6
Первое, что я проверил, - это сделать его управляющим терминалом на подчиненной стороне. Оказывается, это более сложный, чем я помню, поскольку ptys, возможно, не стал контролировать по умолчанию. Эта ссылка для Linux, другие системы должны делать то или другое в зависимости от их SysV и BSD-ness, но похоже, что TIOCSCTTY - хорошая ставка, чтобы попробовать.
Во-вторых, я бы проверял, устанавливаете ли вы ISIG в своих терминах; если нет, VINTR и VQUIT не будут работать.
Конечно, если другой конец ловит SIGINT и SIGQUIT, у вас появятся другие проблемы.