--- /dev/null
+#!/usr/bin/env python
+import argparse
+import pexpect
+import serial
+import sys
+import time
+from pexpect import fdpexpect, TIMEOUT
+
+parser = argparse.ArgumentParser(description='Connect to serial console ' +
+ 'to execute stuff')
+parser.add_argument('--port', required=True,
+ help='serial console device to connect ' +
+ 'to (e.g. /dev/pts/X)')
+parser.add_argument('--hostname', default="buster",
+ help='hostname of the system for login process ' +
+ '(default: buster)')
+parser.add_argument('--user', default="root",
+ help='user name to use for login (default: root)')
+parser.add_argument('--password', default="grml",
+ help='password for login (default: grml)')
+parser.add_argument('--tries', default="12", type=int,
+ help='Number of retries for finding the login prompt')
+parser.add_argument('--poweroff', action="store_true", default=False,
+ help='send "poweroff" command after all other commands')
+parser.add_argument('command', nargs='+',
+ help='command to execute after logging in')
+
+
+
+def print_ser_lines(ser):
+ for line in ser.readlines():
+ print("<<", line) # line will be a binary string
+
+
+def write_ser_line(ser, text):
+ print(">>", text)
+ ser.write(("%s\n" % text).encode())
+ ser.flush()
+
+
+def login(ser, hostname, user, password, timeout=5):
+
+ child = fdpexpect.fdspawn(ser.fileno())
+ child.sendline("\n")
+
+ try:
+ child.expect("%s@%s" % (user, hostname), timeout=timeout)
+ return
+ except:
+ pass
+
+ print("Waiting for login prompt...")
+ child.expect("%s login:" % hostname, timeout=timeout)
+ print("Logging in...")
+ write_ser_line(ser, user)
+ time.sleep(1)
+ write_ser_line(ser, password)
+ time.sleep(1)
+
+ print("Waiting for shell prompt...")
+ child.expect("%s@%s" % (user, hostname), timeout=timeout)
+
+
+def main():
+ args = parser.parse_args()
+ hostname = args.hostname
+ password = args.password
+ port = args.port
+ user = args.user
+ commands = args.command
+
+ ser = serial.Serial(port, 115200)
+ ser.flushInput()
+ ser.flushOutput()
+
+ success = False
+ for i in range(args.tries):
+ try:
+ print("Logging into %s via serial console [try %s]" % (port, i))
+ login(ser, hostname, user, password)
+ success = True
+ break
+ except Exception as except_inst:
+ print("Login failure (try %s):" % (i, ), except_inst, file=sys.stderr)
+ time.sleep(5)
+
+ if success:
+ write_ser_line(ser, "")
+ ser.timeout = 5
+ print_ser_lines(ser)
+ print("Running commands...")
+ for command in commands:
+ write_ser_line(ser, command)
+ print_ser_lines(ser)
+ if args.poweroff:
+ print("Sending final poweroff command...")
+ write_ser_line(ser, "poweroff")
+ ser.flush()
+ # after poweroff, the serial device will probably vanish. do not attempt reading from it anymore.
+
+ if not success:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()