LINUX.ORG.RU

послать ctrl+C (SIGINT) на slave pty

 , forkpty,


0

1

Как послать SIGINT через терминал? В инете вычитал что достаточно отослать ^C и всё заработает, но это не так. Код (под вторым питоном тоже работает):

#!/usr/bin/env python3
from __future__ import print_function
import shlex
import time
import pty
import os

def osexec(cmd):
  cmd = shlex.split(cmd)
  os.execlp(cmd[0], *cmd)

pid, fd = pty.fork()
if pid == 0:
  osexec('perf stat -x, sleep 10')
time.sleep(1)
os.write(fd, b'^C')
raw_data = os.read(fd, 65535)
print("OUT:",raw_data.decode())

Ожидаемый вывод:

sleep: Interrupt
1.260884,task-clock
1,context-switches
0,cpu-migrations
...

Попой чую нужен какой-нить ioctl. Почему я не делаю просто kill -INT: похоже что грёбаный perf различает сигналы от терминала и от юзера (по SI_KERNEL|SI_USER) и ведёт себя по-разному. Отсюда и костыли в коде с эмуляцией терминала вместо subprocess.Popen.

★★★★★

Ответ на: комментарий от true_admin

я теоретик(в плохом смысле) не пользовался поэтому не знаю.

qulinxao ★★☆ ()
Ответ на: комментарий от anonymous

а ты уверен, что ^C ловит perf, а не sleep?

В данном случае ^C это вообще не сигнал, а просто ввод с «клавиатуры».

Если sleep поймает SIGINT то он выйдёт, а за ним и perf с выводом отладочной информации (но, на самом деле, если сигнал получит perf то он его передаст потомку). Собстно, перехватить вывод perf это и есть главная задача.

true_admin ★★★★★ ()
Ответ на: комментарий от tailgunner

Всё, я понял. Действительно можно тупо послать ^C. А ошибка была в том что надо после ^C сделать несколько read(pty_fd). Первый read вернёт лишь «^C», а второй уже остальное. Это нормально? Я был уверен что read возвращает всё что есть в буфере.

true_admin ★★★★★ ()
Ответ на: комментарий от anonymous

у тебя проблема с pty

не-не, с ним всё нормально. Но надо ещё дождать завершения дочернего процесса.

true_admin ★★★★★ ()
Ответ на: комментарий от tailgunner

Я дурак, надо дождаться завершения дочернего процесса и всё будет хорошо.

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

Действительно можно тупо послать ^C

Именно такую строку? У меня не работает, только код.

anonymous ()
Ответ на: комментарий от true_admin

Гм, по ссылке нет ничего про ^C.

Если посылать ^C, то perf завершается только после 10-ти секунд. \x03 — выходит сразу.

anonymous ()
Ответ на: комментарий от anonymous

по ссылке нет ничего про ^C.

Чёрт, не та ссылка. Короче, вот код из одного из топиков на stackoverflow, у меня работает:

ux32vd@~$ cat /tmp/test2.py
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, b'^C')
print('results:', os.read(fd, 1024).decode())
ux32vd@~$ python3 /tmp/test2.py
results: Sun Apr  7 22:21:18 CEST 2013
Sun Apr  7 22:21:19 CEST 2013
Sun Apr  7 22:21:20 CEST 2013
^C
ux32vd@~$ 

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

у меня работает

Гы-гы, это потому что waitpid отсутсвует. '^C' это просто '^' и 'С', терминалу от него ни холодно, ни жарко.

anonymous ()

А вот так ещё можно убрать ^C из вывода:

#disable echo
flags = termios.tcgetattr(fd)
flags[3] &= ~termios.ECHO
termios.tcsetattr(fd, termios.TCSADRAIN, flags)

По-моему, есть более прямые решения которые отключают только вывод управляющих последовательностей, но мне лень сейчас читать маны.

true_admin ★★★★★ ()
Ответ на: комментарий от anonymous

терминалу от него ни холодно, ни жарко.

ты код запускал или только предполагаешь? Я вот тоже не верил что это работает пока не запустил.

true_admin ★★★★★ ()
Ответ на: комментарий от anonymous

К тому же, тебя должно насторожить то, что в сишном варианте пишется один символ. Я даже не знаю кто и на каком уровне может проинтерпретировать ^C.

anonymous ()
Ответ на: комментарий от anonymous

Покажи свой вывод этого скрипта.

И про запуск perf с ^C я тоже писал.

У меня оно 100% работает потому что в реальности я его не на sleep 1 натравливаю, а на пид моих иксов которые всё время работают. Вот ещё пруф что оно не само умирает:

ux32vd@~$ sudo strace -f -p `pidof perf`
Process 28011 attached
restart_syscall(<... resuming interrupted call ...>) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
..

Вопрос как ^C превращается в ctrl+C очень интересен.

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

Покажи свой вывод этого скрипта.

С waitpid он блокируется навечно, без — никаких намеков на эхо от ^C нет.

select(0, NULL, NULL, NULL, {3, 0})     = 0 (Timeout)
write(3, "^C", 2)                       = 2

Вот кусок strace. То есть виноват не питон. Могу предположить что твой terminfo может дополнительные последовательности понимать.

anonymous ()
Ответ на: комментарий от anonymous

Во, нашел как достать последовательность прерывания для терминала:

>>> import termios
>>> import sys
>>> termios.tcgetattr(sys.stdin)[-1][termios.VINTR]
b'\x03'
anonymous ()
Ответ на: комментарий от anonymous

Какой у тебя терминал? Я запускаю из urxvt. Однако как-то вызвать SIGINT через набор последовательности «^C» с клавы или через echo/echo -e у меня не получилось.

ux32vd@~$ env | grep TERM
TERM=xterm
TERMINFO=/usr/share/terminfo
COLORTERM=rxvt-xpm

Вот, кстати, откуда я тот код взял: http://stackoverflow.com/questions/2195885/how-to-send-ctrl-c-control-charact...

true_admin ★★★★★ ()
Ответ на: комментарий от anonymous

Всё, я всё понял. Код с stackoverflow некорректен, там прога выходит потому что закрывается управляющий терминал, а не потому что ^C послали. Пойду заминусую тот код.

А мой код работал потому что я вбил туда '\x03' и забыл об этом.

Жаль, чуда не произошло.

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

Жаль, чуда не произошло.

xDDDD

anonymous ()
Ответ на: комментарий от anonymous

... о скольнам отрытий чудный .... готовит просвященья путь.

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