如何设置 QEMU 输出到控制台并使用 Shell 脚本自动化

原文:How to Setup QEMU Output to Console and Automate Using Shell Script

Preface

While struggling to automate QEMU guest (communicate and control with the shell scripts), I faced with a lot of incomplete, partially working solutions around the internet. Now I've got a pretty decent collection of working recipes to tune up a QEMU guest, so I decided to organize all that stuff here, and it could be definitely useful for anyone else. Each scenario has been tested on the binaries, links on which I put below in the annex: Binaries used in examples, so you could check it out on your own.

Contents

  1. Input/output to the host terminal
  2. Early boot messages in the host terminal
  3. Input/output through a named pipe (file)
  4. Automate QEMU guest using expect tool
  5. Automate QEMU guest using ssh
  6. Binaries used in examples

1. Input/output to the host terminal

-serial stdio

qemu-system-x86_64 -serial stdio wheezy.qcow2

-serial stdio redirects the virtual serial port to the host's terminal input/output. You will see a welcome string after a successful boot.

-nographic

qemu-system-x86_64 -nographic wheezy.qcow2

-nographic does the same as "-serial stdio" and also hides a QEMU's graphical window.

Cautions:

  1. You will not see any early boot logs in the host's console. To get them, see Early boot messages in the host terminal below.

  2. To exit the guest system without GUI, using stdio redirected to the terminal, login as a root (user:

    root

    , password:

    root

    ) and shutdown the system (wait after that for a while):

    # Guest
    shutdown -h now

2. Early boot messages in the host terminal

console=ttyS0

If you want to see early boot logs, you should pass console=ttyS0 parameter to a Linux kernel command line:

qemu-system-x86_64 -nographic -kernel vmlinuz -hda wheezy.img -append "root=/dev/sda console=ttyS0"

or

qemu-system-x86_64 -serial stdio -kernel vmlinuz -hda wheezy.img -append "root=/dev/sda console=ttyS0"

or

qemu-system-x86_64 -serial stdio wheezy.qcow2
# 1. Wait for a GRUB menu to show.
# 2. Press `e`.
# 3. Find the line starting with "linux".
# 4. Add "console=ttyS0".

*qemu-system-x86_64 -serial stdio -kernel vmlinuz -hda wheezy.img -append "root=/dev/sda console=ttyS0"*:

  • -serial stdio or -nographic redirects input/output to the current terminal.
  • -append "root=/dev/sda console=ttyS0": console=ttyS0 forces the guest kernel to send output to the first UART serial port ttyS0, which is redirected to the host by the -serial stdio option, and root=/dev/sda points the kernel to use a /dev/sda device to load the wheezy.img.

Other options:

  • -kernel vmlinuz loads the kernel from the local "./vmlinuz" file.
  • -hda wheezy.img is a raw image which is suitable for booting with vmlinuz binary (wheezy.qcow2 won't be recognized in the block device).

3. Input/output through a named pipe (file)

Create a named pipe

mkfifo /tmp/guest.in /tmp/guest.out

Start QEMU

qemu-system-x86_64 -serial pipe:/tmp/guest -kernel vmlinuz -hda wheezy.img -append "root=/dev/sda console=ttyS0"

-serial pipe:/tmp/guest redirects a guest's output to a /tmp/guest.out and allows to send input from host to guest via /tmp/guest.in.

Take an output from the guest

cat /tmp/guest.out

Send a command to the guest

When login screen appears, send a login string:

printf "root\n" > /tmp/guest.in

Wait until some string

Wait until SSH Daemon starts.

while read line; do
echo "${line}"
if [[ ${line} == *"Secure Shell server: sshd"* ]]; then
break;
fi
done < /tmp/quest.out

4. Automate QEMU guest using expect tool

Install "expect" tool

sudo apt install expect

Create an expect script

example.exp:

#!/usr/bin/expect -f

# Wait enough (forever) until a long-time boot
set timeout -1 # Start the guest VM
spawn qemu-system-x86_64 -serial stdio wheezy.qcow2 expect "login: "
send "root\n" expect "Password: "
send "root\n" expect "# "
send "shutdown -h now"

Original script is found there: https://stacoverflow.com/questions/314613/qemu-guest-automation, but be careful, symbol of quotes “ (which is not a ") in the original stackoverflow answer cannot be recognized by the expect utility (send "root\n").

Execute "expect" script

chmod +x example.exp
./example.exp

5. Automate QEMU guest using ssh

Set up port forwarding

qemu-system-x86_64 -netdev user,id=net0,hostfwd=tcp::10022-:22 -device e1000,netdev=net0 wheezy.qcow2

Connect via ssh

ssh root@localhost -p 10022 'uptime; ls; echo Test;'
  • To apply server's public key automatically use

    -o "StrictHostKeyChecking no"

    :

    ssh root@localhost -p 10022 -o "StrictHostKeyChecking no" 'uptime; ls; echo Test;'

Troubleshooting

  1. QEMU guest has to be able to recognize a network card device (NIC, Network Interface Card):

    -netdev user,id=net0 -device e1000,netdev=net0

    .

    # Without port forwarding
    qemu-system-x86_64 -netdev user,id=net0 -device e1000,netdev=net0 wheezy.qcow2
  2. Boot and check that the new interface has appeared on the guest system:

    # Guest
    ifconfig -a

    Linux kernel on the guest must support a network card emulated by QEMU. In the opposite case the guest won't get a new Ethernet interface. After booting you should find "eth0" (running broadcast device, not loopback) on the guest. It depends solely on the guest Linux kernel and on the kernel modules.

  3. Check the

    10022

    port on the host:

    # Host
    netstat -tanp | grep 10022
    tcp 0 0 0.0.0.0:10022 0.0.0.0:* LISTEN 16589/qemu-system-x
  4. Check the

    22

    port on the guest:

    # Guest
    netstat -tanp | grep 22
    tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 2430/sshd
  5. You can forward

    telnet

    port

    23

    and verify the connection:

    qemu-system-x86_64 -netdev user,id=net0,hostfwd=tcp::10023-:23 -device e1000,netdev=net0 wheezy.qcow2
    1. Guest (server):

      # Guest
      nc -v -l -p 23
      Listening on [0.0.0.0] (family 0, port 23)
    2. Host (client):

      # Host
      echo asdf | nc localhost 10023

Establish passwordless login via ssh

  1. Generate host SSH keys:

    # Host
    ssh-keygen -b 2048 -t rsa -q -N "" -f ./qemukey
  2. Set up a public key to the guest as a trusted (authorized) key.

    1. Via

      ssh-copy-id
      • You need a root with password. You the guest root is passwordless, go to the guest system and set up the password:

        # Guest
        sudo passwd
      • Send the generated public key:

        # Host
        ssh-copy-id -p 10022 -i ~/.ssh/qemukey root@localhost
      • Reset the password in the guest system:

        # Guest
        sudo passwd -l root
    2. Manually

      • Send a public key via

        scp

        :

        # Host
        scp -P 10022 ./qemukey.pub root@localhost:/root/.ssh/
      • Login to the guest and set up new authorized key:

        # Guest
        cat /root/.ssh/qemukey.pub >> /root/.ssh/authorized_keys
        /etc/init.d/ssh restart
      • Or mount device locally, put the public key to the .ssh directory, and concatenate to authorized_keys.

  3. Fix the

    /etc/ssh/sshd_config

    on the guest:

    PasswordAuthentication no
    PermitRootLogin without-password
  4. Restart SSH daemon on the guest:

    # Guest
    /etc/init.d/ssh restart
  5. Connect via ssh:

    # Host
    ssh root@localhost -p 10022 -i ./qemukey

    Viola! You don't need the password and you can automate the remote QEMU guest.


Binaries used in the examples

  1. wheezy.qcow2 (i386)
    bootable Debian "Wheezy" image a QEMU copy-on-write format. Login/password: "root"/"root", and "user"/"user".
    wget https://people.debian.org/~aurel32/qemu/i386/debian_wheezy_i386_standard.qcow2 -O wheezy.qcow2
  2. wheezy.img (i386)
    non-bootable Debian "Wheezy" image (without kernel) to use with own kernel (

    -kernel vmlinuz

    ).

    wget https://storage.googleapis.com/syzkaller/wheezy.img
  3. vmlinuz (i386)
    compressed bootable Linux kernel. Options:
    1. Build from the scratch: Build Android Kernel and Run on QEMU with Minimal Environment: Step by Step.

    2. Download from Ubuntu repository (

      WARNING!

      Port forwarding will NOT work):

      wget http://security.ubuntu.com/ubuntu/pool/main/l/linux-signed-azure/linux-image-4.15.0-1036-azure_4.15.0-1036.38~14.04.2_amd64.deb
      ar x linux-image-4.15.0-1036-azure_4.15.0-1036.38~14.04.2_amd64.deb
      tar xf data.tar.xz ./boot/vmlinuz-4.15.0-1036-azure
      cp ./boot/vmlinuz-4.15.0-1036-azure ./vmlinuz
    3. You can try your host's linux kernel passing one to the QEMU guest (

      WARNING!

      You could have problems either with port forwarding, or with a block device):

      sudo cp /boot/vmlinuz-$(uname -r) ./

    WARNING!

    Ubuntu's

    vmlinuz

    doesn't contain drivers for QEMU emulated network card devices (NIC). Debian's

    vmlinuz

    doesn't have prebuilt drivers to load a raw image from

    /dev/sda

    device.

如何设置 QEMU 输出到控制台并使用 Shell 脚本自动化的更多相关文章

  1. .NET Core的日志[2]:将日志输出到控制台

    对于一个控制台应用,比如采用控制台应用作为宿主的ASP.NET Core应用,我们可以将记录的日志直接输出到控制台上.针对控制台的Logger是一个类型为ConsoleLogger的对象,Consol ...

  2. 问题:C#控制台程序参数;结果:设置与读取C#控制台应用程序Main函数中的参数args

    设置与读取C#控制台应用程序Main函数中的参数args 在项目属性面版->调试->命令行参数设置.空格分隔.读取:string[] str = Environment.GetComman ...

  3. slf4j日志只输出到控制台,没输出到日志文件

    最近使用SLF4J遇到了一个比较头疼的坑,日志输出到控制台没有问题,但是始终没有输出到日志文件.无论怎麽修改日志配置,始终是老样子. 有一种绝望,是各种百度.google却还是解决不了问题..直到我在 ...

  4. Spark日志,及设置日志输出级别

    Spark日志,及设置日志输出级别 1.全局应用设置 2.局部应用设置日志输出级别 3.Spark log4j.properties配置详解与实例(摘录于铭霏的记事本) 文章内容来源: 作者:大葱拌豆 ...

  5. Eclipse对printf()不能输出到控制台的解决方法

    方案1: 在main 语句中加一条 setbuf(stdout,NULL); 这个即可. 在ecplise下使用cdt开发c程序,发现运行后终端没有输出,停止后会输出,通过在main中添加 setbu ...

  6. Java基础知识强化之集合框架笔记49:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)按照总分从高到低输出到控制台

    1. 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)按照总分从高到低输出到控制台: 分析: A: 定义学生类    B: 创建一个TreeSet集合       C: 总分从高到底如何实现 ...

  7. 安卓调试工具adb返回的png截图,直接输出到控制台的修复问题

    原始出处:www.cnblogs.com/Charltsing/p/adbpngfix.html QQ:564955427 adb由于兼容性问题,会把0a替换成0d0a输出到控制台,这会造成png图片 ...

  8. 终于解决 xUnit.net 测试中无法输出到控制台的问题

    2018-8-2 更新:今天发现在 git bash 中用 dotnet test 运行 xunit 测试可以正常输出到控制台,只是在 PowerShell 与 Windows 命令行中有这个问题. ...

  9. 重定向、feed输出:控制台输出的内容存放到文件

    重定向.feed输出:控制台输出的内容存放到文件 1.重定向 os.system('wget -r -p -np -k http://www.baidu.com/ -o wget.log' ) 2.f ...

  10. java fastjson 设置全局输出name最小化

    1.通过自定义Filter实现 https://github.com/alibaba/fastjson/wiki/SerializeFilter public class JackJsonLowCas ...

随机推荐

  1. 什么是SQL 语句中相关子查询与非相关子查询

    1.什么是SQL子查询 要理解相关子查询和非相关子查询,我们得首先理解什么是子查询,子查询是指在一个查询语句中嵌套的另一个查询语句. 子查询可以嵌套在其他查询语句中,如 SELECT.INSERT.U ...

  2. rubymineIDE配置启动

    debug启动 debug启动 安装插件 报错: 网络问题 下载 ruby-debug-ide-2.3.1 解压到 /home/haima/.rvm/gems/ruby-2.3.8/gems/

  3. RustDesk 自建服务器部署和使用教程

    RustDesk 是一个强大的开源远程桌面软件,是中国开发者的作品,它使用 Rust 编程语言构建,提供安全.高效.跨平台的远程访问体验.可以说是目前全球最火的开源远程桌面软件了,GitHub 星星数 ...

  4. 密码学—重合指数法Python程序

    重合指数(Ic) 计算重合指数就是用来验证在Kasiski测试法中猜测出来的各种密钥长度哪一个才是最接近真实密钥长度的. 计算重合指数步骤 按照Kasiski测试法猜测的密钥长度分组 ↓ 分好组之后将 ...

  5. HTML——input标签

    很多表单元素都是由一个个的 input 元素组成的.它是自闭合标签,根据其 type 属性值的不同分为很多种,例如单行文本框.密码框.单选按钮.复选框.隐藏域.文件上传域.普通按钮.提交按钮以及重置按 ...

  6. 如何用 Unity 做出一只赛博宠物

    推荐的一些学习资料 unity 官方文档:Unity 用户手册 (2019.4LTS) - Unity 手册 视频教程:https://www.bilibili.com/video/BV1zB4y1C ...

  7. WPF+Emgucv实现在图像上画出感兴趣的区域 并进行掩膜获取 得到图像均值 和简单的 漫水填充

    <Grid.RowDefinitions></Grid.RowDefinitions> <Grid> <UniformGrid Columns="2 ...

  8. iOS线程While-True死循环会发生什么

    一.在工作的代码有一段while-True轮训的逻辑,循环中主要的工作是阻塞的IO 代码大概如下: dispatch_async(dispatch_get_global_queue(0, 0), ^{ ...

  9. itest(爱测试) 开源接口测试,敏捷测试管理平台10.1.0发布

    一:itest work 简介 itest work 开源敏捷测试管理,包含极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock,还有压测 ,又有丰富的统计分析,8合1工作站.可按 ...

  10. P7448

    problem & 双倍经验 & blog 低配版本 没有 Ynoi 标志性算法卡常,这点差评. 拆解问题 定义 \(lst_i\) 为上一个和 \(i\) 号点相同的位置. 由于几个 ...