QEMU 串行标准输出在 archlinux guest 上出现分歧

QEMU serial std output diverges on archlinux guest

我正在尝试 bootstrap QEMU 中新下载的 ISO 的一些安装自动化。我创建了一个干净的 img 来安装并启动 QEMU,如下所示:

$ qemu-img create -f qcow2 out/main.img 15G
$ qemu-system-x86_64
  -m 8G \
  -serial stdio \
  -cdrom out/linux.iso \
  -drive file=out/main.img,if=virtio \
  -netdev user,id=net0 \
  -device e1000,netdev=net0

我可以看到 Arch 启动了。起初显示和终端是同步的,但在 GRUB 启动屏幕之后它们很快就不同了。

我不确定我缺少哪一部分才能让它工作。我见过一些人建议将 -append "root=/dev/sda console=ttyS0" 添加到您的 QEMU 参数中,但是(据我所知)虽然它要求您从 ISO 中提取内核和 initram(这应该很容易安装和 copy/pasting 正确的文件),但它也希望您已经在 /dev/sda 上安装了系统(这就是我正在尝试 bootstrap)。

此时我不知道接下来要搜索什么,如何在我当前的终端中获得完整的终端会话而不仅仅是在我的显示中?

在这种情况下,正如评论的那样;这不是 QEMU 问题。 QEMU 正在做它应该做的事情,但必须告诉 Arch 使用串行控制台作为其主要通信方式。

关于如何做到这一点的两个示例

bash 通过控制台
pipe_dir="$(mktemp -d)"
mkfifo "${pipe_dir}/pipe.in" "${pipe_dir}/pipe.out"
function cleanup {
    rm -rfv "${pipe_dir}"
}
trap cleanup EXIT

qemu-system-x86_64 \
  -m 8G \
  -display none \
  -serial stdio \
  -drive file=./out/linux.iso,index=0,media=cdrom \
  -drive file=./out/main.img,if=virtio &

sleep 2s
printf "\t" > "${pipe_dir}/pipe.in"
sleep 2s
printf " console=ttyS0,115200" > "${pipe_dir}/pipe.in"
sleep 2s
echo  > "${pipe_dir}/pipe.in"

# Whatever other interactions you want go here...

wait
期待通过控制台
set timeout -1
spawn qemu-system-x86_64 \
  -m 8G \
  -display none \
  -serial stdio \
  -drive file=./out/linux.iso,index=0,media=cdrom \
  -drive file=./out/main.img,if=virtio

sleep 1
send \t
sleep 1
send " console=ttyS0,115200"
sleep 1
send \n

理论上这应该没问题,但实际上我仍然难以与控制台交互并发送字符以正确登录。我确定我可能有更多的用户错误。

一个更好的解决方案(再次与 Arch 相关,而不是 QEMU 具体)是使用包含我的 SSH public 密钥的 cloud-init 脚本。与 VM 的交互稳定、可靠且易于重现。

bash 与 cloud-init/ssh
$ touch ./out/meta-data
$ cat > ./out/user-data <<EOF
#cloud-config
users:
  - name: root
    ssh_authorized_keys:
        - $(cat ${HOME}/.ssh/id_ed25519.pub)
EOF
$ xorriso -as genisoimage -output ./out/cloud-init.iso \
    -volid CIDATA -joliet -rock ./out/meta-data ./out/user-data
$ qemu-system-x86_64 \
    -m 8G \
    -drive file=./out/linux.iso,index=0,media=cdrom \
    -drive file=./out/cloud-init.iso,index=1,media=cdrom \
    -drive file=./out/main.img,if=virtio \
    -net user,hostfwd=tcp::10022-:22 \
    -net nic &

$ function qemu-ssh {
    ssh -q -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o "UserKnownHostsFile /dev/null" -p 10022 root@localhost ${@}
  }

$ printf 'Waiting for SSH to go live (this will take a while)...'
$ until qemu-ssh exit; do
    printf '.'
  done

# This convenience function starts an interactive
# session when supplied with no additional arguments
# but your automation can go here
$ qemu-ssh