如何设置 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. Oracle和达梦:获取更新随机时间sql

    需求 1.修改数据库中表的创建.更新时间,日期固定,时间随机(日期也可以随机): 2.拿到这些sql去数据库执行就行了. 前提 -- 生成8-12间的随机数(小数) SELECT DBMS_RANDO ...

  2. 【LGR-170-Div.3】洛谷基础赛 #6 & Cfz Round 3 & Caféforces #2

    这套题感觉质量很高,思维含量大概div.2? A.Battle \[x \equiv r(\bmod P) \] \[P \mid x - r \] 因此只有第一次操作是有效的. void solve ...

  3. 从SAP CRM上传设备到SAP ERP

    文档<Step by step to download equipment from ERP with hierarchy>描述了从ERP复制设备到CRM的步骤.默认情况下,ERP中的设备 ...

  4. 羽夏闲谈——TeeWorlds 中文问题

      不久前 削微寒 园友发布了一篇博文 误入 GitHub 游戏区,意外地收获颇丰 ,看到了一个游戏 TeeWorlds .有一说一挺好玩的,下面是那个博客的原图:   官方的下载连接:https:/ ...

  5. leaflet 使用kriging.js实现前端自定义插值

    1.GitHub地址:https://github.com/oeo4b/kriging.js 2.核心代码 var variogram = kriging.train(t, x, y, model, ...

  6. 详解GaussDB(DWS)中的行执行引擎

    本文分享自华为云社区<GaussDB(DWS)行执行引擎详解>,作者:yd_227398895. 1.前言 GaussDB(DWS)包含三大引擎,一是SQL执行引擎,用来解析用户输入的SQ ...

  7. 网络流量分析 | AnaTraf 网络故障排除万用表教程更新: 如何抓取两个 MAC / IP 地址之间的流量?

    AnaTraf 致力于提供国产化网络流量分析.网络可视化.网络故障排除解决方案. AnaTraf 网络万用表是一款实时的网络测量.流量分析工具,用于网络流量监控.识别网络性能瓶颈.快速排查网络问题. ...

  8. 4G EPS 的网络协议栈

    目录 文章目录 目录 前文列表 LTE/EPC 协议栈 E-UTRAN 空中接口协议栈 用户平面协议 PHY 层 MAC 层 RLC 层 PDCP 层 控制平面协议 RRC 层 NAS 层 EPC 核 ...

  9. python基础环境

    刚开始接触并学习一门开发语言,带着不求甚解的想法,其实也挺有好处的:我并不是所有的东西都知道,但是代码跑起来了. 但是时间久了,还是带着这种想法,可能就会遇到一些棘手的问题.比如电脑上不知不觉已经安装 ...

  10. anaconda3部署以及使用详解

    Anaconda3-2019.10-Linux-x86_64.sh 某次执行Python程序,其中两个错误信息如下: ImportError: libcblas.so.3: cannot open s ...