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