Как отправить управляющий символ Ctrl-C или сообщение о зависании терминала в дочерний процесс? - PullRequest
10 голосов
/ 04 февраля 2010

У меня есть дочерний процесс, который выполняется в псевдотерминале.Родительский процесс не запускается от имени пользователя root, но дочерний процесс выполняется с помощью su или sudo.Из-за этого невозможно отправить сигнал дочернему процессу, чтобы заставить его выйти.Я хочу заставить его выйти одним из следующих способов:

  • , эмулирующим Ctrl-C.
  • , эмулирующим зависание терминала.Я делаю что-нибудь из этого?У меня уже есть pty master fd, и я пробовал что-то вроде этого:
    write(master, &termios.c_cc[VINTR], 1)
    

    , но он ничего не делает.

Ответы [ 6 ]

4 голосов
/ 05 февраля 2010

Мне кажется, что если у вас действительно есть 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 раза ивышел.

2 голосов
/ 10 февраля 2010

В конце концов я выбрал следующее решение:

После разветвления вместо немедленного выполнения sudo вместо этого я выполняю дочерний процесс-помощник, который в свою очередь разветвляется и исполняет sudo и вызывает на нем waitpid,Таким образом, иерархия процессов выглядит следующим образом:

original process          <---- runs as user
  |
  +-- helper process      <---- runs as user, session leader,
         |                      has own pty, in pty's foreground process group
         |
         +--- sudo        <---- runs as root

При уничтожении вспомогательного процесса у pty больше нет процесса переднего плана.Это заставит ОС отправлять SIGHUP всей группе процессов переднего плана, независимо от пользователя, поэтому sudo также поддерживается SIGHUP.

0 голосов
/ 05 февраля 2010

Первое, что я проверю, это то, нужно ли вам сделать это управляющим терминалом на ведомой стороне.Оказывается, это более сложный , чем я помню, с ptys, возможно, не становится управление по умолчанию.Эта ссылка для Linux, другие системы должны делать одну или другую в зависимости от их SysV против BSD-ness, но похоже, что TIOCSCTTY - хорошая ставка, чтобы попробовать.вы устанавливаете ISIG в вашем termios;если нет, VINTR и VQUIT не будут работать.

Конечно, если другой конец ловит SIGINT и SIGQUIT, у вас будут другие проблемы.

0 голосов
/ 04 февраля 2010

Я думаю, вам нужно использовать ioctl для вставки символа прерывания вместо write.К сожалению, механизм для этого не выглядит переносимым.Для Linux это выглядит так:

ioctl(master, TIOCSTI, &termios.c_cc[VINTR]);
0 голосов
/ 04 февраля 2010

Закрытие мастера должно сигнализировать о зависании управляющей группе процессов ведомого.

0 голосов
/ 04 февраля 2010

Для этого есть два способа:

  • Из дочернего процесса, перехватить сигнал SIGCHLD и обработать его, вы можете _exit (0) завершить дочерний процесс
  • Есть программа под названием ptree .Вы можете обмануть это, сделав это следующим образом ... в псевдокоде:
obtain the parent's pid.
using _popen("ptree %d", parent_pid)
for each entry of child process
system ("kill -1 %d", child_process_pid)

Есть два, которые приходят на ум ... извините, если это не поможет вам,

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

...