oepydevshell-internal.py 3.1 KB

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