#! /usr/bin/env python2 import os import pexpect import re import sys import time def run(cmd): '''Run command, log to stdout, no timeout, return the status code.''' print('run: ' + cmd) (output, rc) = pexpect.run( cmd, withexitstatus=1, encoding='utf-8', logfile=sys.stdout, timeout=None ) if rc != 0: print('simple.py: Command failed with return code: ' + rc) exit(rc) download_path = 'https://download.freebsd.org/ftp/releases/VM-IMAGES/12.0-RELEASE/amd64/Latest' image_file = 'FreeBSD-12.0-RELEASE-amd64.qcow2' image_file_xz = image_file + '.xz' if not os.path.isfile(image_file_xz): run('curl -o %s %s/%s' % (image_file_xz, download_path, image_file_xz)) if not os.path.isfile(image_file): # Reset image file to initial state run('xz --decompress --keep --force --verbose ' + image_file_xz) #cmd = 'qemu-system-x86_64 -snapshot -monitor none -display curses -chardev stdio,id=char0 ' + image_file cmd = 'qemu-system-x86_64 -snapshot -nographic ' + image_file print('interact with: ' + cmd) child = pexpect.spawn( cmd, timeout=90, # FreeBSD takes roughly 60 seconds to boot maxread=1, ) child.logfile = sys.stdout def expect(pattern): result = child.expect([pexpect.TIMEOUT, pattern]) if result == 0: print("timeout: %d reached when waiting for: %s" % (child.timeout, pattern)) exit(1) return result - 1 if False: # This does not work: the prompt is not visible, then timeout expect('login: ') else: # Workaround, tested to work: expect(re.escape('FreeBSD/amd64 (freebsd)')) # Line before prompt time.sleep(1) # MUCH longer than actually needed, just to be safe child.sendline('root') expect('# ') child.sendline('ls -l') expect('# ') child.sendline('poweroff') while child.isalive(): pass child.close print(child.exitstatus, child.signalstatus)