Перехватывать и игнорировать сигнал

#python #ssh #signals

#python #ssh #сигналы

Вопрос:

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

 ssh -t -t host "command to run"
  

Я попробовал это со следующим скриптом:

 #!/bin/bash

ssh -t -t host "program $@"
  

и когда я запускаю это с терминала, это работает нормально, но когда proofgeneral запускает этот скрипт и отправляет ему SIGINT, это просто приводит к завершению программы (я предполагаю, что он не может выделить терминал?).

У меня получился следующий беспорядок в коде:

 CTRL_C = "<CTRL-C>"

def endpoint(proc, handler):
    signal.signal(2, signal.SIG_IGN)

    inp = ""
    out = ""
    err = ""

    inp_from_fd = sys.stdin.fileno()
    inp_to_fd   = proc.stdin.fileno()
    out_from_fd = proc.stdout.fileno()
    out_to_fd   = sys.stdout.fileno()
    err_from_fd = proc.stderr.fileno()
    err_to_fd   = sys.stderr.fileno()

    while True:
       try:
           ins,outs,_ = select.select([inp_from_fd, out_from_fd, err_from_fd],
                                      [inp_to_fd, out_to_fd, err_to_fd],
                                      [])
           for fd in ins:
               if fd == inp_from_fd:
                   k   = os.read(fd, 1024)
                   if k == "":
                       os.close(proc.stdin.fileno())
                       return
                   inp = inp   k
               elif fd == out_from_fd:
                   k   = os.read(fd, 1024)
                   out = out   k
               elif fd == err_from_fd:
                   k   = os.read(fd, 1024)
                   err = err   k
               else:
                   assert False
           for fd in outs:
               if fd == inp_to_fd:
                   while CTRL_C in inp:
                       proc.send_signal(2)
                       p = inp.find(CTRL_C)
                       inp = inp[0:p]   inp[p len(CTRL_C):]
                   k = os.write(fd, inp)
                   inp = inp[k:]
               elif fd == out_to_fd:
                   k = os.write(fd, out)
                   out = out[k:]
               elif fd == err_to_fd:
                   k = os.write(fd, err)
                   err = err[k:]
               else:
                   assert False
       except select.error:
           pass
       except KeyboardInterrupt:
           handler()
       except IOError, e:
           pass

def usage(args):
    print "must specify --client or --server" 

if __name__ == '__main__':
    if len(sys.argv) == 1:
        usage(sys.argv)
    elif sys.argv[1] == '--server':
        proc = subprocess.Popen(sys.argv[2:],
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        def INT():
            proc.stdin.write(CTRL_C)
            proc.stdin.flush()
        endpoint(proc, INT)
    elif '--client' in sys.argv:
        proc = subprocess.Popen(sys.argv[2:],
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        import time
        time.sleep(1)
        def INT():
            pass
        endpoint(proc, INT)
    else:
        usage(sys.argv)
  

который я вызываю, используя что-то вроде:

 remote.py --client ssh -t -t host "remote.py --server <program-to-run> <args>"
  

Есть ли что-то, что я делаю неправильно здесь для обработки сигнала? Я попытался поместить печать в обработчик signal 2, и он ее печатает, но это также приводит к отключению ssh (я получаю «Убит сигналом 2». печатается на консоли). Перенаправляет ли python сигнал своим дочерним элементам? Есть ли способ обойти это? Есть ли более простой способ сделать это?

Спасибо за любые указания.

Ответ №1:

os.setpgrp (посмотрите на справочную страницу setpgrp) в противном случае сигнал передается дочерним элементам