Created
May 23, 2018 21:29
-
-
Save baude/9353c6cf83643863efc32d9460ef5cfb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socket, argparse | |
import select, sys, os, tty, atexit, termios, signal, shutil | |
import fcntl, termios, struct | |
# Create the socket | |
sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) | |
# parsing args for using this as a cli .... dwalsh hates the idea so you can | |
# nuke this when folding into the mix | |
parser = argparse.ArgumentParser() | |
parser.add_argument('container', help='container name or id') | |
args = parser.parse_args() | |
# Setup the dir where the sockets live ... you have to use this path | |
# even though there are other paths, you gotta use this one or the path | |
# will be too long and wont work but also wont tell you why. | |
sockets_dir = os.path.join("/var/run/libpod/socket/", args.container) | |
# This is the UDS where all the IO goes | |
socket_path = os.path.join(sockets_dir, "attach") | |
# This is the control socket where resizing events are sent to conmon | |
control_socket_path = os.path.join(sockets_dir, "ctl") | |
def reset_fd(my_fd, old_settings): | |
""" | |
resets an fd to the old settings (whatever it was before we took control). this should be done | |
on any exit | |
:param my_fd: | |
:param old_settings: | |
:return: | |
""" | |
termios.tcsetattr(my_fd, termios.TCSADRAIN, old_settings) | |
os.close(my_fd) | |
def error_print(*args, **kwargs): | |
""" | |
dumps a proper error message to stdout for an error. only used for socket lose at this time. | |
:param args: | |
:param kwargs: | |
:return: none | |
""" | |
print(*args, file=sys.stderr, **kwargs) | |
def terminal_size(): | |
""" | |
determines the height and width of a window when it is resized. | |
:return: width and height of the terminal window | |
""" | |
h, w, hp, wp = struct.unpack('HHHH', | |
fcntl.ioctl(1, termios.TIOCGWINSZ, | |
struct.pack('HHHH', 0, 0, 0, 0))) | |
return w, h | |
def resize_handler(signum, frame): | |
""" | |
sends the resizing of the window to the conmon fifo socket. the format of the message needs to be: | |
"%d %d %d\n", 1, size.Height, size.Width) | |
the parameters to this def are not used but are required. leave alone. | |
This def should be called when a signal is caught for the window resizing. | |
:param signum: | |
:param frame: | |
:return: nothing | |
""" | |
control_socket = open(control_socket_path, 'w') | |
w, h = terminal_size() | |
control_socket.write("{} {} {}\n".format(1, h, w)) | |
control_socket.close() | |
# catch any resizing events and send the resize info | |
# to the control fifo "socket" | |
signal.signal(signal.SIGWINCH, resize_handler) | |
# connect | |
sock.connect(socket_path) | |
# prime stdin | |
stdin = os.open("/dev/stdin", os.O_RDWR) | |
# save off the old settings for stdin | |
old_settings = termios.tcgetattr(stdin) | |
# if we quit, clean up and reset the console or bad things happen | |
# that involve kittens and puppies | |
atexit.register(reset_fd, stdin, old_settings) | |
# always send a resize on connection because if someone else used it before, it will be | |
# stuck on their size. | |
resize_handler(0,0) | |
# set stdin to raw | |
tty.setraw(stdin) | |
# iterator for where we can get stuff ... i.e. the container and keyboard | |
inputs = [sock, stdin] | |
# we dont want to block on the outputs, so we none | |
outputs = [] | |
while inputs: | |
try: | |
# really the magic is here, iterate on input sources | |
readable, writable, exceptional = select.select(inputs, outputs, inputs) | |
for r in readable: | |
# This iterator is the UDS container socket | |
if isinstance(r, socket.socket): | |
# should closely resemble conmons read size | |
# scoop some data | |
data = r.recv(8192) | |
# knock off the first byte ... it tells us where it came from. we dont care really | |
foo = data[1:] | |
# write this to stdout | |
os.write(1, foo) | |
# This is the keyboard basically | |
if isinstance(r, int): | |
# should closely resemble conmons read size | |
# scoop some data | |
data = os.read(stdin, 8192) | |
# if control-], bail | |
if 29 in data: # Bail on ctrl-[ | |
sys.exit(0) | |
# send the input back on the UDS socket | |
sock.send(data) | |
except BrokenPipeError: | |
error_print("socket quit on container end") | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment