#!/bin/bash SCRIPT="$0" OPTION="$1" VM="$2" DIR="qemu" USER="user" HOST="localhost" CORES="4" MEMORY="4G" DEVICE="virtio-net-pci,netdev=net0" HDA_URL="https://cloud.debian.org/images/cloud/trixie/latest" X64="X64" A64="A64" NAMES=("$X64" "$A64") declare -A QEMU=( [$X64]="qemu-system-x86_64" [$A64]="qemu-system-aarch64" ) declare -A HDA=( [$X64]="debian-13-nocloud-amd64.qcow2" [$A64]="debian-13-nocloud-arm64.qcow2" ) declare -A BIOS=( [$X64]="/usr/share/edk2/ovmf/OVMF_CODE.fd" [$A64]="/usr/share/edk2/aarch64/QEMU_EFI.fd" ) declare -A SSH_PORTS=( [$X64]="2222" [$A64]="2223" ) declare -A PID_FILES=( [$X64]="$X64.pid" [$A64]="$A64.pid" ) declare -A MACHINES=( [$X64]="pc" [$A64]="virt" ) vm_netdev() { echo -n "user,id=net0,hostfwd=tcp::${SSH_PORTS[$1]}-:22" } vm_init() { if [[ ! -d "$DIR" ]] then mkdir $DIR fi cd $DIR if [[ ! -d "$USER" ]] then mkdir $USER ssh-keygen -t ed25519 -f "$USER/$USER" -N "" fi for H in ${HDA[@]} do if [[ ! -f "$H" ]] then wget "$HDA_URL/$H" fi done } vm_setup() { local PUB=$(cat "$DIR/$USER/$USER.pub") local HEADER="COPY AND RUN IN QEMU:" echo $HEADER echo " sed -i 's/GRUB_TIMEOUT=5/GRUB_TIMEOUT_STYLE=hidden\nGRUB_TIMEOUT=0/' /etc/default/grub; update-grub; sed -i 's/^%sudo\s\+ALL=(ALL:ALL)\sALL$/%sudo ALL=(ALL:ALL) NOPASSWD:ALL/' /etc/sudoers; adduser --disabled-password --gecos "" --shell /bin/bash $USER; adduser $USER sudo; su - $USER" echo $HEADER echo " mkdir .ssh; cd .ssh; echo \"$PUB\" > authorized_keys; chmod 600 authorized_keys; cd ~" echo $HEADER echo " sudo apt update; sudo apt upgrade; sudo apt install ssh make gcc gdb; sudo poweroff" } vm_check() { if [[ "$1" != "$X64" && "$1" != "$A64" ]] then echo "Usage $SCRIPT $OPTION $X64|$A64" return 1 fi return 0 } vm_boot() { local PID_FILE="${PID_FILES[$1]}" if [[ -f "$PID_FILE" ]] then echo "VM $1 is running" return fi local CMD=( "${QEMU[$1]}" "-M" "${MACHINES[$1]}" "-cpu" "max" "-m" "$MEMORY" "-smp" "$CORES" "-device" "$DEVICE" "-netdev" "$(vm_netdev $1)" "-bios" "${BIOS[$1]}" "-hda" "${HDA[$1]}" "-pidfile" "$PID_FILE" ) for ARG in "${@:2}" do CMD+=("$ARG") done "${CMD[@]}" echo "Starting VM $1" } vm_cli() { cd $DIR vm_check $VM if [[ $? != 0 ]] then return fi vm_boot $VM "-nographic" } vm_start() { cd $DIR vm_check $VM if [[ $? == 0 ]] then vm_boot $VM "-display" "none" "-daemonize" return fi for NAME in "${NAMES[@]}" do vm_boot $NAME "-display" "none" "-daemonize" done } vm_cmd() { vm_check $1 if [[ $? != 0 ]] then return fi ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$USER@$HOST" -p "${SSH_PORTS[$1]}" $2 } vm_ssh() { cd $DIR ssh-add "$USER/$USER" &> /dev/null vm_cmd $VM } vm_sync() { echo "TODO ${FUNCNAME[0]}" } vm_test() { echo "TODO ${FUNCNAME[0]}" } vm_stop() { local ACTION="$1" cd $DIR if [[ "$ACTION" != "KILL" ]] then ssh-add "$USER/$USER" &> /dev/null fi for NAME in "${NAMES[@]}" do local PID_FILE="${PID_FILES[$NAME]}" if [[ -f "$PID_FILE" ]] then if [[ "$ACTION" == "KILL" ]] then kill $(cat $PID_FILE) echo "VM $NAME force stop" else vm_cmd $NAME "sudo poweroff" echo "VM $NAME powering off" fi fi done } vm_clean() { if [[ ! -d "$DIR" ]] then return fi local CHOICE read -n 1 -r -s -p "Are you sure? y/n " CHOICE if [[ "$CHOICE" != "y" ]] then echo return fi rm -r $DIR echo -e "\nRemoved $DIR directory" } vm_help() { echo "See TESTING" echo "Usage $SCRIPT -init|-setup|-cli|-start|-ssh|-sync|-test|-stop|-kill|-clean|-help" } case $OPTION in -init) vm_init ;; -setup) vm_setup ;; -cli) vm_cli ;; -start) vm_start ;; -ssh) vm_ssh ;; -sync) vm_sync ;; -test) vm_test ;; -stop) vm_stop ;; -kill) vm_stop "KILL" ;; -clean) vm_clean ;; *) vm_help ;; esac