2013-03-04 6 views
6

나는 실패했을 때 반복 명령을위한 간단한 래퍼 스크립트를 작성하여 retry.py이라고합니다. 그러나 나는 자식 명령의 출력을보고 싶기 때문에 몇 가지 pty 트릭을 가져와야했습니다. 이것은 rsync와 같은 프로그램에서는 정상적으로 작동하지만 scp와 같은 프로그램에서는 진행률 측정기 같은 것을 보여주기위한 추가 테스트를 적용합니다. 나는 래퍼 스크립트 불구하고 실행할 때 실패pty에서 실행중인 프로세스의 터미널 포 그라운드 프로세스 그룹을 어떻게 설정합니까?

getpgrp() == tcgetpgrp(STDOUT_FILENO); 

:

SCP가 코드가 광범위하게하는 시험이있다.

./tty_tests 
isatty reports 1 
pgrps are 13619 and 13619 

과 : 나는 tcsetpgrp를을 (사용하려고했습니다

./retry.py -v -- ./tty_tests 
command is ['./tty_tests'] 
isatty reports 1 
pgrps are 13614 and -1 
child finished: rc = 0 
Ran command 1 times 

)을 PTY의 FD 년대하지만상의 IOCTL로 끝 내 간단한 tty_test.c 테스트 케이스와 함께 볼 수 있듯이 ptys에 대해 -EINVAL이됩니다. 가능하다면 항상 파이썬 서브 프로세스 기계를 사용하는 것을 선호 할 것입니다. 또는 수동으로 포크/execve'ing이 필요하게 될까요?

from argparse import ArgumentParser 
import os 
import signal 
import subprocess 
import itertools 

# your argumentparser stuff goes here 

def become_tty_fg(): 
    os.setpgrp() 
    hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN) 
    tty = os.open('/dev/tty', os.O_RDWR) 
    os.tcsetpgrp(tty, os.getpgrp()) 
    signal.signal(signal.SIGTTOU, hdlr) 

if __name__ == "__main__": 
    args = parser.parse_args() 

    if args.verbose: print "command is %s" % (args.command) 
    if args.invert and args.limit==None: 
     sys.exit("You must define a limit if you have inverted the return code test") 

    for run_count in itertools.count(): 
     return_code = subprocess.call(args.command, close_fds=True, 
             preexec_fn=become_tty_fg) 
     if args.test == True: break 
     if run_count >= args.limit: break 
     if args.invert and return_code != 0: break 
     elif not args.invert and return_code == 0: break 

    print "Ran command %d times" % (run_count) 

setpgrp() 호출이 같은 세션에서 새로운 프로세스 그룹을 생성합니다

답변

9

난 당신이 하위 프로세스에 완전히 새로운 PTY를 제공 할 필요가없는 경우 당신이 당신의 프로그램을 깎다 수 있다고 생각 새 프로세스가 사용자로부터 ctrl-c/ctrl-z/etc를 수신 할 것이므로 재시도 스크립트는 그렇지 않습니다. 그런 다음 tcsetpgrp()은 새 프로세스 그룹을 제어 tty의 전경 그룹으로 만듭니다. 새로운 프로세스는 setpgrp() 이후 백그라운드 프로세스 그룹에 있었기 때문에 SIGTTOU을 얻었습니다. 일반적으로 프로세스가 중지되므로 SIGTTOU을 무시할 수 있습니다. 서브 프로세스가 예기치 않은 신호 테이블에 혼동 될 가능성을 최소화하기 위해 SIGTTOU 핸들러를 원래의 상태로 되돌립니다.

하위 프로세스가 이제 tty의 포어 그라운드 그룹에 있으므로 tcgetpgrp()와 getpgrp()가 동일하고 isatty (1)가 true가됩니다 (retry.py에서 상속받은 stdout이 실제로 a tty). 서브 프로세스와 tty 사이에 트래픽을 프록시 할 필요가 없기 때문에 모든 select 이벤트 처리 및 fcntl-nonblocking 설정을 처리 할 수 ​​있습니다.

+0

나는 그것을 시도했지만 아무런 효과가 없다. retry.py -v - ~/mysrc/retry.git/tty_tests 명령은 [ '/home/ajb/mysrc/retry.git/tty_tests '] isatty 보고서 1 pgrps는 28268이고 -1은 입니다. rc = 0 Ran 명령 1 회 – stsquad

+0

완전한 코드를 붙여 넣을 수 있습니까? –

+0

OH! 방금 retry.py에 대한 링크를 제공 한 것으로 나타났습니다. 나는 그저 stackoverflow가 도움이되고 호스트 이름처럼 보일 수있는 링크를 만드는 것이라고 생각했다. 내가 한번 볼게. –