1*4882a593Smuzhiyun#!/usr/bin/env python3 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun 6*4882a593Smuzhiyunimport os 7*4882a593Smuzhiyunimport sys 8*4882a593Smuzhiyunimport time 9*4882a593Smuzhiyunimport select 10*4882a593Smuzhiyunimport fcntl 11*4882a593Smuzhiyunimport termios 12*4882a593Smuzhiyunimport readline 13*4882a593Smuzhiyunimport signal 14*4882a593Smuzhiyun 15*4882a593Smuzhiyundef nonblockingfd(fd): 16*4882a593Smuzhiyun fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK) 17*4882a593Smuzhiyun 18*4882a593Smuzhiyundef echonocbreak(fd): 19*4882a593Smuzhiyun old = termios.tcgetattr(fd) 20*4882a593Smuzhiyun old[3] = old[3] | termios.ECHO | termios.ICANON 21*4882a593Smuzhiyun termios.tcsetattr(fd, termios.TCSADRAIN, old) 22*4882a593Smuzhiyun 23*4882a593Smuzhiyundef cbreaknoecho(fd): 24*4882a593Smuzhiyun old = termios.tcgetattr(fd) 25*4882a593Smuzhiyun old[3] = old[3] &~ termios.ECHO &~ termios.ICANON 26*4882a593Smuzhiyun termios.tcsetattr(fd, termios.TCSADRAIN, old) 27*4882a593Smuzhiyun 28*4882a593Smuzhiyunif len(sys.argv) != 3 or sys.argv[1] in ('-h', '--help'): 29*4882a593Smuzhiyun print('oepydevshell-internal.py: error: the following arguments are required: pty, pid\n' 30*4882a593Smuzhiyun 'Usage: oepydevshell-internal.py pty pid\n\n' 31*4882a593Smuzhiyun 'OpenEmbedded oepydevshell-internal.py - internal script called from meta/classes/devshell.bbclass\n\n' 32*4882a593Smuzhiyun 'arguments:\n' 33*4882a593Smuzhiyun ' pty pty device name\n' 34*4882a593Smuzhiyun ' pid parent process id\n\n' 35*4882a593Smuzhiyun 'options:\n' 36*4882a593Smuzhiyun ' -h, --help show this help message and exit\n') 37*4882a593Smuzhiyun sys.exit(2) 38*4882a593Smuzhiyun 39*4882a593Smuzhiyunpty = open(sys.argv[1], "w+b", 0) 40*4882a593Smuzhiyunparent = int(sys.argv[2]) 41*4882a593Smuzhiyun 42*4882a593Smuzhiyunnonblockingfd(pty) 43*4882a593Smuzhiyunnonblockingfd(sys.stdin) 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun 46*4882a593Smuzhiyunhistfile = os.path.expanduser("~/.oepydevshell-history") 47*4882a593Smuzhiyunreadline.parse_and_bind("tab: complete") 48*4882a593Smuzhiyuntry: 49*4882a593Smuzhiyun readline.read_history_file(histfile) 50*4882a593Smuzhiyunexcept IOError: 51*4882a593Smuzhiyun pass 52*4882a593Smuzhiyun 53*4882a593Smuzhiyuntry: 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun i = "" 56*4882a593Smuzhiyun o = "" 57*4882a593Smuzhiyun # Need cbreak/noecho whilst in select so we trigger on any keypress 58*4882a593Smuzhiyun cbreaknoecho(sys.stdin.fileno()) 59*4882a593Smuzhiyun # Send our PID to the other end so they can kill us. 60*4882a593Smuzhiyun pty.write(str(os.getpid()).encode('utf-8') + b"\n") 61*4882a593Smuzhiyun while True: 62*4882a593Smuzhiyun try: 63*4882a593Smuzhiyun writers = [] 64*4882a593Smuzhiyun if i: 65*4882a593Smuzhiyun writers.append(sys.stdout) 66*4882a593Smuzhiyun (ready, _, _) = select.select([pty, sys.stdin], writers , [], 0) 67*4882a593Smuzhiyun try: 68*4882a593Smuzhiyun if pty in ready: 69*4882a593Smuzhiyun readdata = pty.read() 70*4882a593Smuzhiyun if readdata: 71*4882a593Smuzhiyun i = i + readdata.decode('utf-8') 72*4882a593Smuzhiyun if i: 73*4882a593Smuzhiyun # Write a page at a time to avoid overflowing output 74*4882a593Smuzhiyun # d.keys() is a good way to do that 75*4882a593Smuzhiyun sys.stdout.write(i[:4096]) 76*4882a593Smuzhiyun sys.stdout.flush() 77*4882a593Smuzhiyun i = i[4096:] 78*4882a593Smuzhiyun if sys.stdin in ready: 79*4882a593Smuzhiyun echonocbreak(sys.stdin.fileno()) 80*4882a593Smuzhiyun o = input().encode('utf-8') 81*4882a593Smuzhiyun cbreaknoecho(sys.stdin.fileno()) 82*4882a593Smuzhiyun pty.write(o + b"\n") 83*4882a593Smuzhiyun except (IOError, OSError) as e: 84*4882a593Smuzhiyun if e.errno == 11: 85*4882a593Smuzhiyun continue 86*4882a593Smuzhiyun if e.errno == 5: 87*4882a593Smuzhiyun sys.exit(0) 88*4882a593Smuzhiyun raise 89*4882a593Smuzhiyun except EOFError: 90*4882a593Smuzhiyun sys.exit(0) 91*4882a593Smuzhiyun except KeyboardInterrupt: 92*4882a593Smuzhiyun os.kill(parent, signal.SIGINT) 93*4882a593Smuzhiyun 94*4882a593Smuzhiyunexcept SystemExit: 95*4882a593Smuzhiyun pass 96*4882a593Smuzhiyunexcept Exception as e: 97*4882a593Smuzhiyun import traceback 98*4882a593Smuzhiyun print("Exception in oepydehshell-internal: " + str(e)) 99*4882a593Smuzhiyun traceback.print_exc() 100*4882a593Smuzhiyun time.sleep(5) 101*4882a593Smuzhiyunfinally: 102*4882a593Smuzhiyun readline.write_history_file(histfile) 103