Add a libvirt/KVM test environment and fix the gcc-12 warning it found
build / build (clang, ) (push) Failing after 6s
build / build (gcc, ) (push) Failing after 6s
build / build (gcc, --enable-io-failure-emulation) (push) Failing after 6s
build / build (gcc, --enable-warnings) (push) Failing after 5s

The VM harness (tests/vm/) builds and exercises the tools on real Debian and
Alpine guests, driving the serial console (no sshd/cloud-init dependency).

Results on Debian 12 (glibc 2.36, gcc 12.2): 12/12 checks pass, 0 warnings
with -Wall -Wextra, including a real 128M -> 256M resize and the rollback
save/restore/reject paths.

Results on Alpine 3.20 (musl 1.2.5): the build cannot start. configure stops
at "reiserfsprogs requires a method to add printf modifiers" because
reiserfscore/prints.c depends on glibc's register_printf_specifier(3) and
<printf.h>, which musl does not provide. This is pre-existing and out of
scope here; measured at 341 use sites across 20+ files, all routed through
reiserfs_warning()/reiserfs_info(). Documented in tests/vm/RESULTS.md.

Fix the one real defect the harness surfaced:

fsck/semantic_check.c: check_check_regular_file() is called with NULL for
new_ih (line 466), so the block that would fill *new_ih is unreachable and
check_semantic_pass() never returns RELOCATED through that path. The
"case RELOCATED:" arm still reads relocated_ih.ih_key, which gcc 12.2
reports as "may be used uninitialized" (-Wmaybe-uninitialized); gcc 16 does
not, because it proves the path dead. Zero-initialise the struct and say why.

Verified: 0 warnings on gcc 12.2 after the change, and the Debian battery
stays at 12/12.
This commit is contained in:
lgcosta committed 2026-11-12 00:11:31 -03:00
1 parent 293e6a7280
commit 5a7382185b
8 files changed
+628 -1

No files matched your search

+4 -1
View File
@@ -551,7 +551,10 @@ static int check_semantic_pass(struct reiserfs_key *key,
for (i = pos_in_item; i < get_ih_entry_count(&tmp_ih);
i++, deh++) {
struct item_head relocated_ih;
/* Only meaningful when check_check_regular_file() returns
RELOCATED; that path currently passes NULL for new_ih,
so this stays zero-initialised. */
struct item_head relocated_ih = { 0 };
int ret = OK;
if (name) {
+85
View File
@@ -0,0 +1,85 @@
# Ambiente de testes em VM
Este documento descreve o ambiente de validação do reiserfsprogs em máquinas
virtuais (libvirt/KVM), usado para exercitar o build e as ferramentas em
distribuições diferentes da máquina de desenvolvimento.
O ambiente é **efêmero**: as VMs ficam em `/var/tmp/vmtest` e não fazem parte
do repositório. Os scripts que o reproduzem estão em `tests/vm/`.
## Requisitos do host
| Componente | Verificação |
|---|---|
| KVM | `ls -l /dev/kvm` |
| libvirt (user session) | `virsh -c qemu:///session list --all` |
| `virt-install`, `qemu-img` | `which virt-install qemu-img` |
| `guestfs-tools` (offline) | `which virt-customize` |
| `mkisofs` ou `xorriso` | `which mkisofs xorriso` |
No Fedora: `sudo dnf install libvirt-daemon-kvm qemu-kvm virt-install
guestfs-tools genisoimage`.
O ambiente usa **qemu:///session** (sem root). Não requer a rede `default`
do libvirt: a conectividade vem do backend `passt` em modo *user*.
## Topologia
```mermaid
graph LR
H[host] -->|qemu:///session| D[rfs-debian<br/>Debian 12 · gcc]
H -->|qemu:///session| A[rfs-alpine<br/>Alpine 3.20 · gcc/musl]
D -->|passt :2222| S[ssh opcional]
A -->|passt| S
H -->|attach-disk| V[vdb: fontes + run_tests.sh]
```
Cada VM recebe:
* imagem cloud (qcow2) redimensionada para 8 GiB;
* um disco de dados `vdb` (ext4) com `rfs-src.tar.gz` e `run_tests.sh`;
* acesso por **console serial** (pty do libvirt), que é o canal de
automação usado — independente de rede.
## Por que console serial e não SSH
Nas imagens cloud o `sshd` demora a subir e o `cloud-init` nem sempre aplica
a senha (o datasource NoCloud exige rótulo `cidata` e o CD precisa estar no
Barramento certo). O console serial está disponível assim que o getty sobe e
é suficiente para: autenticar, copiar arquivos (já estão no `vdb`) e rodar
qualquer comando. Por isso o `tests/vm/guestcmd.py` dirige o pty.
## Ciclo de uso
```sh
cd tests/vm
# 1. preparar imagens e VMs (uma vez)
./setup_env.sh
# 2. rodar a bateria em uma VM
./run_in_vm.sh rfs-alpine
./run_in_vm.sh rfs-debian
# 3. destruir tudo
./teardown_env.sh
```
## O que a bateria cobre (`tests/vm/run_tests.sh`)
Executado **dentro** do guest, sobre o código extraído do `vdb`:
1. `autogen.sh && configure --enable-warnings && make -j` — build limpo;
2. contagem de warnings (esperado: 0);
3. `mkreiserfs` em imagem de 64 MiB;
4. `reiserfsck --check` (esperado: *No corruptions found*);
5. `debugreiserfs -S` (superblock consistente);
6. `reiserfstune -l` (troca de label);
7. `resize_reiserfs` 128 MiB → 256 MiB;
8. `reiserfsck` pós-resize;
9. rollback: `-R` grava, `--rollback-fsck-changes` restaura, arquivo
inválido é rejeitado.
## Resultados obtidos
Ver `tests/vm/RESULTS.md`.
+124
View File
@@ -0,0 +1,124 @@
# Resultados dos testes em VM
Bateria executada com `tests/vm/run_in_vm.sh` em duas distribuições, ambas em
KVM (`qemu:///session`), com o código de `293e6a7`.
## Ambiente
| | Debian 12 (bookworm) | Alpine 3.20.3 |
|---|---|---|
| Kernel | 6.1.0-54-cloud-amd64 | 6.6.49-0-virt |
| libc | glibc 2.36 | **musl 1.2.5** |
| gcc | 12.2.0 | 13.2.1 |
| init | systemd + cloud-init | OpenRC + cloud-init |
## Resultado por item
| # | Teste | Debian | Alpine |
|---|---|---|---|
| 1 | `autogen.sh` | passa | passa |
| 1 | `configure --enable-warnings` | passa | **falha** (ver abaixo) |
| 1 | `make -j` | passa, **0 warnings** | não alcançado |
| 2 | `mkreiserfs` | passa | não alcançado |
| 3 | `reiserfsck --check` | passa | não alcançado |
| 4 | `debugreiserfs -S` | passa | não alcançado |
| 5 | `reiserfstune -l` | passa | não alcançado |
| 6 | `resize_reiserfs` 128→256 MiB | passa | não alcançado |
| 7 | `fsck` pós-resize | passa | não alcançado |
| 8 | rollback: grava | passa | não alcançado |
| 8 | rollback: restaura | passa | não alcançado |
| 8 | rollback: magic inválida rejeitada | passa | não alcançado |
| 8 | rollback: arquivo inexistente rejeitado | passa | não alcançado |
**Debian: 12/12.** Alpine: bloqueado no item 1.
## Achado 1 (bloqueante): não compila em musl
O `configure` do Alpine falha com:
```
checking for register_printf_modifier... no
checking for register_printf_specifier... no
configure: error: reiserfsprogs requires a method to add printf modifiers
```
Causa: `reiserfscore/prints.c` usa `register_printf_specifier(3)`, extensão
**glibc-only** (`<printf.h>`). O musl não fornece `printf.h` nem essas
funções. O `configure.ac` trata isso como erro fatal explícito — o
comportamento é correto, mas o projeto **não compila fora da glibc**.
Alcance medido:
| Especificador | Uso |
|---|---|
| `%k` | 139 |
| `%K` | 106 |
| `%H` | 52 |
| `%M` | 25 |
| `%b` | 9 |
| `%U` | 4 |
| `%y` | 2 |
| `%30H`, `%20y`, `%20k`, `%20K` | 4 |
| **total** | **341** |
Todos passam por `reiserfs_warning()` / `reiserfs_info()`. Portar exigiria
substituir o mecanismo por funções de formatação explícitas (por exemplo
`char *format_key(const struct reiserfs_key *)` com `%s`), uma mudança de API
interna ampla — não um ajuste local.
**Impacto prático**: reiserfsprogs fica restrito à glibc. Como o único uso
atual da ferramenta é resgate de dados, isso importa: live images de
recuperação baseadas em Alpine/musl não conseguem compilar o projeto.
## Achado 2 (corrigido nesta rodada): warning real no gcc 12
O gcc 12.2 do Debian acusou, duas vezes:
```
../include/reiserfs_fs.h:63:54: warning: ‘relocated_ih’ may be used uninitialized
```
O gcc 16 do host não acusa. Investigação:
* `fsck/semantic_check.c:620` passa `&relocated_ih` para
`check_semantic_pass()`;
* o bloco que escreveria `*new_ih` está **comentado** (linhas 471–486);
* a chamada em `check_check_regular_file()` (linha 466) passa
`NULL` como `new_ih`, com o comentário `/* relocate ? new_ih : */ NULL`;
* portanto `RELOCATED` nunca é retornado por esse caminho e
`case RELOCATED:` (linha 665) leria `relocated_ih` não inicializado.
Não é alcançável hoje, mas é uma leitura potencial de lixo de pilha atrás de
um `#case` que o compilador não consegue descartar. Correção: inicialização
explícita `= { 0 }` com comentário explicando por que permanece zero.
Verificado: **0 warnings no gcc 12.2 após a correção**.
Em `fsck/semantic_rebuild.c` o caminho equivalente é seguro: o bloco
`if (relocate) { ... *new_ih = *ih; retval = RELOCATED; }` está ativo
(linhas 808–822), então `new_ih` é escrito antes do `case RELOCATED:`
(linha 999).
## Achado 3: limitação do ambiente (não do código)
Nas imagens cloud o `cloud-init` não aplicou a senha do usuário: o datasource
NoCloud exige o rótulo `cidata` e o CD correto, e o `sshd` demora a subir.
O console serial, porém, fica disponível assim que o getty sobe — por isso o
`tests/vm/guestcmd.py` dirige o pty e é o canal de automação usado. Isso não
afeta o produto; afeta apenas como os testes são conduzidos.
Além disso, a rede user-mode (`passt`) não entrega DHCP nem DNS por padrão: a
interface sobe como `enp1s0` mas fica sem IP. Foi necessário configurar IP e
resolver manualmente para instalar pacotes nas VMs.
## Como reproduzir
```sh
cd tests/vm
./setup_env.sh # imagens + VMs (uma vez)
./run_in_vm.sh rfs-debian # build + bateria completa
./run_in_vm.sh rfs-alpine # deve falhar no configure (esperado)
./teardown_env.sh
```
Detalhes do ambiente, topologia e limitações: `tests/vm/README.md`.
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env python3
"""Roda um comando no guest atraves do console serial do libvirt.
O console serial e o unico canal garantido nas imagens cloud minimas: nao
depende de sshd, de cloud-init nem de rede. Este script sincroniza com o
prompt, autentica (root/rfstest) e executa o comando, lendo a saida do pty
em blocos pequenos para evitar a sobreposicao de eco que ocorre em comandos
longos.
Uso:
guestcmd.py <dominio> '<comando>'
guestcmd.py <dominio> -f <arquivo> # executa um script local
"""
import base64
import os
import re
import select
import subprocess
import sys
import time
USER = "root"
PASSWORD = "rfstest"
def console_pty(domain):
xml = subprocess.run(["virsh", "dumpxml", domain],
capture_output=True, text=True).stdout
m = (re.search(r"<console[^>]*>\s*<source path='([^']+)'", xml)
or re.search(r"<serial[^>]*>\s*<source path='([^']+)'", xml))
if not m:
sys.exit(f"console serial nao encontrada para {domain}")
return m.group(1)
class Console:
def __init__(self, path):
self.fd = os.open(path, os.O_RDWR | os.O_NOCTTY)
def send(self, s):
os.write(self.fd, s.encode())
def drain(self, seconds):
buf = b""
end = time.time() + seconds
while time.time() < end:
r, _, _ = select.select([self.fd], [], [], 0.3)
if not r:
continue
try:
chunk = os.read(self.fd, 65536)
except OSError:
break
if not chunk:
break
buf += chunk
return buf
def login(self):
self.send("\n")
time.sleep(1.0)
snap = self.drain(2.5).decode(errors="replace").lower()
if "login:" not in snap:
return # ja autenticado
self.send(USER + "\n")
self.drain(3.0)
self.send(PASSWORD + "\n")
time.sleep(2.0)
self.drain(2.0)
def run(self, command, timeout=120.0):
"""Executa e devolve a saida, sincronizando por marcador no pty."""
out_path = "/tmp/.guestcmd.out"
self.send(f"rm -f {out_path}; ( {command} ) > {out_path} 2>&1; "
f"echo __GC_DONE__\n")
deadline = time.time() + timeout
while time.time() < deadline:
if b"__GC_DONE__" in self.drain(2.0):
break
else:
return "(timeout)\n"
# tamanho em bytes
self.send(f"wc -c < {out_path}\n")
time.sleep(1.2)
raw = self.drain(2.0).decode(errors="replace")
nums = re.findall(r"\d+", raw)
size = int(nums[-1]) if nums else 0
# ler em blocos base64 (evita eco/sobreposicao)
data = b""
while len(data) < size:
self.send(f"dd if={out_path} bs=1 skip={len(data)} count=150 "
f"2>/dev/null | base64 -w0; echo\n")
time.sleep(0.8)
enc = self.drain(2.0).decode(errors="replace")
token = "".join(re.findall(r"[A-Za-z0-9+/=]{4,}", enc))
if not token:
break
try:
data += base64.b64decode(token + "=" * (-len(token) % 4))
except Exception:
break
return data.decode(errors="replace")
def main():
if len(sys.argv) < 3:
sys.exit(__doc__)
domain = sys.argv[1]
console = Console(console_pty(domain))
console.login()
if sys.argv[2] == "-f":
with open(sys.argv[3]) as fh:
script = fh.read().replace("'", "'\\''")
command = f"sh -c '{script}'"
else:
command = sys.argv[2]
sys.stdout.write(console.run(command))
sys.stdout.write("\n")
if __name__ == "__main__":
main()
+51
View File
@@ -0,0 +1,51 @@
#!/bin/sh
# Envia o codigo-fonte e o script de teste para dentro de uma VM e executa.
#
# Uso: run_in_vm.sh <dominio>
# Requer: guestcmd.py (mesmo diretorio), mkisofs, libvirt.
set -e
DOMAIN=${1:?uso: run_in_vm.sh <dominio>}
HERE=$(cd "$(dirname "$0")" && pwd)
REPO=$(cd "$HERE/../.." && pwd)
WORK=${WORK:-/var/tmp/vmtest}
echo "== empacotando o codigo-fonte =="
tar czf "$WORK/rfs-src.tar.gz" -C "$REPO" \
--exclude=.git --exclude='*.o' --exclude='*.lo' --exclude='*.la' \
--exclude='.libs' --exclude=build-aux --exclude=m4 \
--exclude=autom4te.cache --exclude=config.h --exclude=config.log \
--exclude=config.status --exclude=libtool \
--exclude='Makefile' --exclude='Makefile.in' --exclude=configure \
--exclude=aclocal.m4 --exclude='*.8' \
.
echo "== montando o disco de dados =="
rm -rf /tmp/vmdata.$$ && mkdir -p /tmp/vmdata.$$
sudo mount -o loop "$WORK/data.img" /tmp/vmdata.$$
sudo cp "$WORK/rfs-src.tar.gz" "$HERE/run_tests.sh" /tmp/vmdata.$$
sudo umount /tmp/vmdata.$$ && rmdir /tmp/vmdata.$$
echo "== transferindo para $DOMAIN =="
ATTACH=/tmp/vdb.$$.xml
cat > "$ATTACH" <<EOF
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='$WORK/data.img'/>
<target dev='vdb' bus='virtio'/>
</disk>
EOF
virsh attach-device "$DOMAIN" "$ATTACH" --live >/dev/null 2>&1 || true
rm -f "$ATTACH"
echo "== extraindo e rodando os testes =="
"$HERE/guestcmd.py" "$DOMAIN" '
set -e
mkdir -p /mnt/data
mountpoint -q /mnt/data || mount -o ro /dev/vdb /mnt/data
mkdir -p /root/rfs
tar xzf /mnt/data/rfs-src.tar.gz -C /root/rfs
cp /mnt/data/run_tests.sh /root/run_tests.sh
chmod +x /root/run_tests.sh
SRC=/root/rfs sh /root/run_tests.sh
' 900
+134
View File
@@ -0,0 +1,134 @@
#!/bin/sh
# Bateria de testes do reiserfsprogs, executada DENTRO do guest.
# Espera receber o codigo-fonte em $SRC (padrao: /root/rfs).
#
# Uso (dentro da VM):
# SRC=/root/rfs sh run_tests.sh
set -u
SRC=${SRC:-/root/rfs}
PASS=0
FAIL=0
ok() { echo "PASS: $1"; PASS=$((PASS + 1)); }
bad() { echo "FAIL: $1"; FAIL=$((FAIL + 1)); }
cd "$SRC" || { echo "FAIL: $SRC nao existe"; exit 1; }
echo "=== ambiente ==="
uname -srm
(cc --version 2>/dev/null || echo "sem cc") | head -1
ldd --version 2>&1 | head -1
echo
echo "=== 1. bootstrap + build com -Wall -Wextra ==="
make distclean >/dev/null 2>&1
if ./autogen.sh >/tmp/ag.log 2>&1 && ./configure --enable-warnings >/tmp/cfg.log 2>&1 \
&& make -j"$(nproc 2>/dev/null || echo 2)" >/tmp/mk.log 2>&1; then
ok "autogen.sh + configure + make"
else
bad "build"
echo "--- configure ---"; tail -15 /tmp/cfg.log
echo "--- make ---"; tail -25 /tmp/mk.log
echo
echo "RESULTADO: $PASS passaram, $FAIL falharam"
exit 1
fi
# grep -c retorna 1 quando nao ha ocorrencias; capturar so a primeira linha
WARN=$(grep -c "warning:" /tmp/mk.log 2>/dev/null | head -1)
WARN=${WARN:-0}
if [ "$WARN" = "0" ]; then
ok "0 warnings com -Wall -Wextra"
else
bad "$WARN warnings"
grep "warning:" /tmp/mk.log | head -10
fi
echo
echo "=== 2. mkfs ==="
rm -f /tmp/t.img
dd if=/dev/zero of=/tmp/t.img bs=1M count=64 status=none 2>/dev/null
if ./mkreiserfs/mkreiserfs -f -q -l TESTVOL /tmp/t.img >/dev/null 2>&1; then
ok "mkreiserfs"
else
bad "mkreiserfs"
fi
echo
echo "=== 3. reiserfsck --check ==="
if ./fsck/reiserfsck --check -f -q -y /tmp/t.img 2>&1 | grep -q "No corruptions found"; then
ok "reiserfsck --check"
else
bad "reiserfsck --check"
fi
echo
echo "=== 4. debugreiserfs -S ==="
if ./debugreiserfs/debugreiserfs -S /tmp/t.img 2>&1 | grep -q "Filesystem state: consistent"; then
ok "debugreiserfs -S"
else
bad "debugreiserfs -S"
fi
echo
echo "=== 5. reiserfstune -l ==="
if ./tune/reiserfstune -l NEWLABEL -f /tmp/t.img >/dev/null 2>&1; then
ok "reiserfstune -l"
else
bad "reiserfstune -l"
fi
echo
echo "=== 6. resize 128M -> 256M ==="
rm -f /tmp/big.img
dd if=/dev/zero of=/tmp/big.img bs=1M count=128 status=none 2>/dev/null
./mkreiserfs/mkreiserfs -f -q /tmp/big.img >/dev/null 2>&1
truncate -s 256M /tmp/big.img
if ./resize_reiserfs/resize_reiserfs -s +128M -f /tmp/big.img 2>&1 \
| grep -q "Resizing finished successfully"; then
ok "resize_reiserfs"
else
bad "resize_reiserfs"
fi
echo
echo "=== 7. fsck pos-resize ==="
if ./fsck/reiserfsck --check -f -q -y /tmp/big.img 2>&1 | grep -q "No corruptions found"; then
ok "fsck apos resize"
else
bad "fsck apos resize"
fi
echo
echo "=== 8. rollback (save/restore/reject) ==="
cp /tmp/t.img /tmp/rb.img
rm -f /tmp/rb.dat
./fsck/reiserfsck --fix-fixable -y -q -R /tmp/rb.dat /tmp/rb.img >/dev/null 2>&1
if [ -f /tmp/rb.dat ]; then
ok "rollback file criado"
else
bad "rollback file nao criado"
fi
if ./fsck/reiserfsck --rollback-fsck-changes -y -q -R /tmp/rb.dat /tmp/rb.img 2>&1 \
| grep -q "blocks restored"; then
ok "rollback-fsck-changes"
else
bad "rollback-fsck-changes"
fi
head -c 100 /dev/urandom > /tmp/rollback-invalido.dat
if ./fsck/reiserfsck --rollback-fsck-changes -y -q -R /tmp/rollback-invalido.dat /tmp/rb.img 2>&1 \
| grep -q "does not look like a rollback file"; then
ok "rollback com magic invalida rejeitado"
else
bad "rollback com magic invalida aceito"
fi
if ./fsck/reiserfsck --rollback-fsck-changes -y -q -R /tmp/nao-existe.dat /tmp/rb.img 2>&1 \
| grep -q "Cannot stat rollback file"; then
ok "rollback inexistente rejeitado"
else
bad "rollback inexistente aceito"
fi
echo
echo "RESULTADO: $PASS passaram, $FAIL falharam"
[ "$FAIL" -eq 0 ]
+91
View File
@@ -0,0 +1,91 @@
#!/bin/sh
# Prepara o ambiente de VMs: imagens, seed e maquinas virtuais.
# Requer: libvirt (qemu:///session), virt-install, qemu-img, mkisofs.
set -e
HERE=$(cd "$(dirname "$0")" && pwd)
WORK=${WORK:-/var/tmp/vmtest}
CONN=qemu:///session
mkdir -p "$WORK"
cd "$WORK"
fetch() {
url=$1; out=$2
[ -s "$out" ] && { echo " $out ja existe"; return; }
echo " baixando $out"
curl -fsSL -o "$out.part" "$url"
mv "$out.part" "$out"
}
echo "== imagens =="
fetch https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2 debian.qcow2
fetch https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/cloud/nocloud_alpine-3.20.3-x86_64-bios-cloudinit-r0.qcow2 alpine.qcow2
echo "== redimensionando =="
for img in debian.qcow2 alpine.qcow2; do
size=$(qemu-img info --output=json "$img" | grep -oP '"virtual-size":\s*\K[0-9]+')
if [ "${size:-0}" -lt 8589934592 ]; then
qemu-img resize "$img" 8G
else
echo " $img ja tem 8G"
fi
done
echo "== disco de dados (fontes + script de teste) =="
if [ ! -s data.img ]; then
dd if=/dev/zero of=data.img bs=1M count=8 status=none
mkfs.ext4 -q -F data.img
fi
echo "== seed cloud-init =="
cat > user-data <<'EOF'
#cloud-config
hostname: rfs-test
ssh_pwauth: true
disable_root: false
users:
- name: root
lock_passwd: false
plain_text_passwd: rfstest
chpasswd:
expire: false
EOF
cat > meta-data <<'EOF'
instance-id: rfs-test-1
local-hostname: rfs-test
EOF
cat > network-config <<'EOF'
version: 2
ethernets:
eth0:
dhcp4: true
EOF
rm -f seed.iso
mkisofs -output seed.iso -volid cidata -joliet -rock \
user-data meta-data network-config >/dev/null 2>&1
echo "== definindo VMs =="
define_vm() {
name=$1; img=$2; variant=$3; mem=$4
if virsh -c "$CONN" dominfo "$name" >/dev/null 2>&1; then
echo " $name ja existe"
return
fi
virt-install -c "$CONN" \
--name "$name" \
--memory "$mem" --vcpus 2 \
--disk "path=$WORK/$img,format=qcow2,bus=virtio" \
--disk "path=$WORK/seed.iso,device=cdrom" \
--os-variant "$variant" \
--network user,model=virtio \
--graphics none --console pty \
--import --noautoconsole >/dev/null
echo " criada: $name"
}
define_vm rfs-debian debian.qcow2 debian12 2048
define_vm rfs-alpine alpine.qcow2 alpinelinux3.20 1024
echo
echo "Pronto. Use tests/vm/run_in_vm.sh <vm> para testar."
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
# Destrói as VMs do ambiente de teste. Nao remove as imagens baixadas.
set -e
CONN=qemu:///session
for d in rfs-debian rfs-alpine; do
if virsh -c "$CONN" dominfo "$d" >/dev/null 2>&1; then
virsh -c "$CONN" destroy "$d" >/dev/null 2>&1 || true
virsh -c "$CONN" undefine "$d" --remove-all-storage >/dev/null 2>&1 || true
echo "removida: $d"
else
echo "ausente: $d"
fi
done