Some checks are pending
Build NFDOS ISO / build (push) Waiting to run
607 lines
24 KiB
Python
607 lines
24 KiB
Python
import os
|
||
import sys
|
||
import subprocess
|
||
import time
|
||
from pathlib import Path
|
||
from rich.console import Console
|
||
from glob import glob
|
||
# Import menus do TUI
|
||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
from tui import menu_python, menu_iso, menu_libs # pylint: disable=wrong-import-position, import-error
|
||
|
||
console = Console()
|
||
|
||
def corrigir_kernel_headers(linux_dir, env):
|
||
"""
|
||
Corrige headers incompatíveis com C23 em vários caminhos.
|
||
Adiciona guards para typedef bool / enum { false, true }.
|
||
"""
|
||
console.print("[yellow]→ Patching kernel headers for C23 compatibility...[/]")
|
||
|
||
header_candidates = [
|
||
"include/linux/stddef.h",
|
||
"include/linux/types.h",
|
||
"include/uapi/linux/stddef.h",
|
||
"include/uapi/linux/types.h",
|
||
"arch/x86/include/asm/stddef.h",
|
||
"arch/x86/include/asm/types.h",
|
||
]
|
||
|
||
# Antes de aplicar os patches:
|
||
safe_run(["make", "prepare"], env=env)
|
||
safe_run(["make", "scripts"], env=env)
|
||
|
||
for relpath in header_candidates:
|
||
path = linux_dir / relpath
|
||
if not path.exists():
|
||
continue
|
||
|
||
content = path.read_text()
|
||
patched = False
|
||
|
||
# Corrige enum false/true
|
||
if "false" in content and "__bool_true_false_are_defined" not in content:
|
||
content = content.replace(
|
||
"enum {\n false = 0,\n true = 1\n};",
|
||
"#ifndef __bool_true_false_are_defined\n"
|
||
"enum {\n false = 0,\n true = 1\n};\n"
|
||
"#define __bool_true_false_are_defined 1\n#endif"
|
||
)
|
||
patched = True
|
||
|
||
# Corrige typedef _Bool
|
||
if "typedef _Bool" in content and "__STDC_VERSION__" not in content:
|
||
content = content.replace(
|
||
"typedef _Bool bool;",
|
||
"#ifndef __cplusplus\n"
|
||
"# if __STDC_VERSION__ < 202000L\n"
|
||
"typedef _Bool bool;\n"
|
||
"# endif\n"
|
||
"#endif"
|
||
)
|
||
patched = True
|
||
|
||
if patched:
|
||
path.write_text(content)
|
||
console.print(f"[green]✔ Patched:[/] {relpath}")
|
||
|
||
# Corrige Makefile do boot
|
||
boot_makefile = linux_dir / "arch/x86/boot/Makefile"
|
||
if boot_makefile.exists():
|
||
with open(boot_makefile, "a") as f:
|
||
f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
|
||
console.print("[cyan]→ Applied local Makefile override for boot code (C23 fix)[/]")
|
||
|
||
# Corrige Makefile do boot/compressed
|
||
boot_compr_makefile = linux_dir / "arch/x86/boot/compressed/Makefile"
|
||
if boot_compr_makefile.exists():
|
||
with open(boot_compr_makefile, "a") as f:
|
||
f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
|
||
console.print("[cyan]→ Applied local Makefile override for boot/compressed code (C23 fix)[/]")
|
||
|
||
# Corrige Makefile do EFI stub
|
||
efi_makefile = linux_dir / "drivers/firmware/efi/libstub/Makefile"
|
||
if efi_makefile.exists():
|
||
with open(efi_makefile, "a") as f:
|
||
f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
|
||
console.print("[cyan]→ Applied local Makefile override for EFI stub (C23 fix)[/]")
|
||
|
||
def corrigir_kernel_overrides(cross_compile):
|
||
env = {
|
||
**os.environ,
|
||
"ARCH": "x86_64",
|
||
"CROSS_COMPILE": cross_compile,
|
||
"LOCALVERSION": "-nfdos",
|
||
}
|
||
|
||
console.print("[yellow]→ Aplicando overrides de configuração...[/yellow]")
|
||
|
||
# Essenciais do sistema base
|
||
essentials = [
|
||
"CONFIG_PRINTK",
|
||
"CONFIG_TTY",
|
||
"CONFIG_SERIAL_8250",
|
||
"CONFIG_SERIAL_8250_CONSOLE",
|
||
"CONFIG_SERIAL_EARLYCON",
|
||
"CONFIG_DEVTMPFS",
|
||
"CONFIG_DEVTMPFS_MOUNT",
|
||
"CONFIG_BLK_DEV_INITRD",
|
||
"CONFIG_TMPFS",
|
||
"CONFIG_PROC_FS",
|
||
"CONFIG_SYSFS",
|
||
# EXT4 base + alias para ext2
|
||
"CONFIG_EXT4_FS",
|
||
"CONFIG_EXT4_USE_FOR_EXT2",
|
||
"CONFIG_MCORE2",
|
||
#"CONFIG_EXT4_FS_POSIX_ACL",
|
||
#"CONFIG_EXT4_FS_SECURITY",
|
||
]
|
||
|
||
# VirtIO (para bloco, rede, PCI)
|
||
virtio = [
|
||
"CONFIG_PCI",
|
||
"CONFIG_VIRTIO",
|
||
"CONFIG_VIRTIO_MENU",
|
||
"CONFIG_VIRTIO_PCI",
|
||
"CONFIG_VIRTIO_PCI_LEGACY",
|
||
"CONFIG_VIRTIO_BLK",
|
||
"CONFIG_VIRTIO_NET",
|
||
"CONFIG_VIRTIO_CONSOLE",
|
||
"CONFIG_VIRTIO_INPUT",
|
||
"CONFIG_VIRTIO_MMIO",
|
||
"CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES",
|
||
"CONFIG_BLK_MQ_VIRTIO",
|
||
"CONFIG_BLOCK",
|
||
"CONFIG_BLK_DEV",
|
||
"CONFIG_BLOCK_LEGACY_AUTOLOAD",
|
||
"CONFIG_EXPORTFS_BLOCK_OPS",
|
||
"CONFIG_MSDOS_PARTITION", # assegura parsing de tabela de partições
|
||
]
|
||
|
||
# Debug e early printk
|
||
debug = [
|
||
"CONFIG_DEBUG_KERNEL",
|
||
"CONFIG_EARLY_PRINTK",
|
||
"CONFIG_SERIAL_8250_PNP",
|
||
"CONFIG_DEBUG_INFO_NONE", # evita symbols extras
|
||
]
|
||
|
||
# Desativa gráficos e Garante compatibilidade máxima de CPU (para manter o kernel leve, limpo e evitar CR4 panics)
|
||
disable_graphics = [
|
||
"CONFIG_VT",
|
||
"CONFIG_VT_CONSOLE",
|
||
"CONFIG_VGA_CONSOLE",
|
||
"CONFIG_FRAMEBUFFER_CONSOLE",
|
||
"CONFIG_DUMMY_CONSOLE",
|
||
"CONFIG_FB",
|
||
"CONFIG_DRM",
|
||
"CONFIG_DRM_I915",
|
||
"CONFIG_LOGO",
|
||
"CONFIG_X86_PAE",
|
||
"CONFIG_X86_5LEVEL",
|
||
"CONFIG_RANDOMIZE_BASE",
|
||
"CONFIG_RETPOLINE",
|
||
"CONFIG_SMAP",
|
||
"CONFIG_SMEP",
|
||
"CONFIG_PAGE_TABLE_ISOLATION",
|
||
]
|
||
|
||
# Habilita todos os conjuntos
|
||
for opt in essentials + virtio + debug:
|
||
safe_run(["scripts/config", "--enable", opt], env=env)
|
||
|
||
# garante que o driver não é módulo
|
||
for opt in [
|
||
"CONFIG_VIRTIO_BLK=m",
|
||
"CONFIG_VIRTIO_PCI=m",
|
||
"CONFIG_VIRTIO_PCI_LEGACY=m",
|
||
]:
|
||
safe_run(["scripts/config", "--disable", opt], env=env)
|
||
|
||
# Desativa o que não precisamos
|
||
for opt in disable_graphics:
|
||
safe_run(["scripts/config", "--disable", opt], env=env)
|
||
|
||
# Formatos binários básicos
|
||
for opt in [
|
||
"CONFIG_BINFMT_ELF",
|
||
"CONFIG_BINFMT_SCRIPT",
|
||
]:
|
||
safe_run(["scripts/config", "--enable", opt], env=env)
|
||
|
||
# Regera configuração coerente
|
||
safe_run(["make", "olddefconfig"], env=env)
|
||
|
||
console.print("[green]✔ Overrides aplicados com sucesso.[/green]")
|
||
|
||
|
||
def safe_run(cmd, **kwargs):
|
||
"""Executa um comando e mostra logs legíveis no TUI."""
|
||
console.print(f"[dim]{' '.join(cmd) if isinstance(cmd, list) else cmd}[/dim]")
|
||
subprocess.run(cmd, check=True, **kwargs)
|
||
|
||
def limpar_rootfs(nfdos_dir):
|
||
rootfs = nfdos_dir / "rootfs"
|
||
initramfs = nfdos_dir / "initramfs.cpio.gz"
|
||
if rootfs.exists():
|
||
console.print("[yellow]🧹 Limpando RootFS anterior...[/yellow]")
|
||
safe_run(f"rm -rf {rootfs}", shell=True)
|
||
if initramfs.exists():
|
||
console.print("[yellow]🧹 Removendo initramfs anterior...[/yellow]")
|
||
safe_run(f"rm -f {initramfs}", shell=True)
|
||
|
||
def run():
|
||
while True:
|
||
console.clear()
|
||
console.rule("[bold yellow]Kernel / BusyBox / Python[/bold yellow]")
|
||
console.print("1. Obter código-fonte do Kernel Linux")
|
||
console.print("2. Compilar Kernel com Toolchain NFDOS")
|
||
console.print("3. Obter e compilar BusyBox")
|
||
console.print("4. Compilar Python estatico com Toolchain NFDOS")
|
||
console.print("5. Obter e compilar Bibliotecas do Neurotron")
|
||
console.print("6. Montar RootFS e gerar imagem bootável")
|
||
console.print("7. Gerar imagem ISO e iniciar o NFDOS no QEMU")
|
||
console.print("0. Voltar")
|
||
|
||
choice = console.input("\n[cyan]nfdos> [/cyan]")
|
||
|
||
base_dir = Path(__file__).resolve().parents[1]
|
||
kernel_dir = base_dir / "_nfdos" / "kernel"
|
||
linux_dir = kernel_dir / "linux"
|
||
nfdos_dir = base_dir / "_nfdos"
|
||
busybox_dir = nfdos_dir / "busybox"
|
||
rootfs_dir = nfdos_dir / "rootfs"
|
||
toolchain_prefix = Path.home() / "x-tools" / "x86_64-nfdos-linux-musl"
|
||
cross_compile = f"{toolchain_prefix}/bin/x86_64-nfdos-linux-musl-"
|
||
|
||
linux_repo = "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
|
||
busybox_repo = "git://busybox.net/busybox.git"
|
||
|
||
env = {
|
||
**os.environ,
|
||
"ARCH": "x86_64",
|
||
"CROSS_COMPILE": cross_compile,
|
||
"CFLAGS": "-std=gnu11 -fcommon -Wno-error",
|
||
"LOCALVERSION": "-nfdos",
|
||
"KCFLAGS": "-std=gnu11 -fcommon -Wno-error",
|
||
"HOSTCFLAGS": "-std=gnu11 -fcommon -Wno-error",
|
||
"KBUILD_CFLAGS": "-std=gnu11 -fcommon -Wno-error",
|
||
"KBUILD_AFLAGS": "-std=gnu11 -fcommon",
|
||
"KBUILD_CPPFLAGS": "-std=gnu11 -fcommon",
|
||
"KCFLAGS_FOR_HOST": "-std=gnu11 -Wno-error",
|
||
}
|
||
|
||
if choice == "1":
|
||
kernel_dir.mkdir(parents=True, exist_ok=True)
|
||
os.chdir(kernel_dir)
|
||
console.print("[yellow]Baixando código-fonte do Kernel Linux...[/yellow]")
|
||
if not linux_dir.exists():
|
||
safe_run(["git", "clone", "--depth=1", "--branch", "v6.12", linux_repo, "linux"])
|
||
else:
|
||
os.chdir(linux_dir)
|
||
safe_run(["git", "pull"])
|
||
console.print("[green]✔ Kernel atualizado![/green]")
|
||
|
||
elif choice == "2":
|
||
os.chdir(linux_dir)
|
||
console.print("[cyan]Compilando Kernel Linux...[/cyan]")
|
||
|
||
# Verificação do compilador
|
||
if not Path(cross_compile + "gcc").exists():
|
||
console.print("[red]✗ Toolchain não encontrada![/red]")
|
||
console.print(f"Esperado: {cross_compile}gcc")
|
||
time.sleep(2)
|
||
continue
|
||
|
||
# Passo 1 — Limpar tudo antes de começar
|
||
safe_run(["make", "mrproper"], env=env)
|
||
|
||
# Passo 2 — Baixar configuração base mínima
|
||
safe_run(["make", "allnoconfig"], env=env)
|
||
|
||
# Passo 3 — Aplicar patches C23 aos headers
|
||
corrigir_kernel_headers(linux_dir, env)
|
||
|
||
# Passo 4 — Aplicar overrides minimalistas (serial-only, sem VGA)
|
||
corrigir_kernel_overrides(cross_compile)
|
||
|
||
# Passo 5 — Regerar dependências e .config
|
||
safe_run(["make", "olddefconfig"], env=env)
|
||
|
||
# Passo 6 — Compilar
|
||
safe_run(["make", "-j", str(os.cpu_count())], env=env)
|
||
|
||
console.print("[green]✔ Kernel compilado com sucesso![/green]")
|
||
|
||
elif choice == "3":
|
||
busybox_dir.mkdir(parents=True, exist_ok=True)
|
||
os.chdir(busybox_dir)
|
||
console.print("[yellow]📦 Baixando e compilando BusyBox...[/yellow]")
|
||
|
||
if not (busybox_dir / ".git").exists():
|
||
safe_run(["git", "clone", "--depth=1", busybox_repo, "-b", "master", "."], env=env)
|
||
|
||
# 🧹 Limpeza preventiva se houver restos de builds anteriores
|
||
if (busybox_dir / ".config").exists():
|
||
console.print("[cyan]🧼 Limpando build antigo (make mrproper)...[/cyan]")
|
||
safe_run(["make", "mrproper"], env=env)
|
||
|
||
console.print("[cyan]🧩 Gerando configuração base (defconfig)...[/cyan]")
|
||
safe_run(["make", "defconfig"], env=env)
|
||
|
||
console.print("[cyan]🧠 Aplicando overrides de configuração (persistência + EXT4)...[/cyan]")
|
||
|
||
config_updates = {
|
||
"CONFIG_STATIC": "y",
|
||
"CONFIG_MKFS": "y",
|
||
"CONFIG_FEATURE_MKFS_EXT2": "y",
|
||
"CONFIG_FEATURE_MKFS_EXT3": "y",
|
||
"CONFIG_FEATURE_MKFS_EXT4": "y",
|
||
"CONFIG_MOUNT": "y",
|
||
"CONFIG_UMOUNT": "y",
|
||
"CONFIG_BLKID": "y",
|
||
"CONFIG_LSBLK": "y",
|
||
"CONFIG_FSCK": "y",
|
||
"CONFIG_FEATURE_MOUNT_HELPERS": "y",
|
||
"CONFIG_FEATURE_MOUNT_FSTAB": "y",
|
||
"CONFIG_FEATURE_VOLUMEID": "y",
|
||
"CONFIG_FEATURE_VOLUMEID_EXT": "y",
|
||
"CONFIG_FEATURE_VOLUMEID_FAT": "y",
|
||
"CONFIG_FEATURE_VOLUMEID_EXFAT": "y",
|
||
"CONFIG_FEATURE_VOLUMEID_NTFS": "y",
|
||
"CONFIG_FEATURE_VOLUMEID_LINUXSWAP": "y",
|
||
"CONFIG_FEATURE_VOLUMEID_BTRFS": "y",
|
||
"CONFIG_FEATURE_VOLUMEID_XFS": "y",
|
||
"CONFIG_FEATURE_VOLUMEID_ISO9660": "y",
|
||
}
|
||
|
||
for key, value in config_updates.items():
|
||
safe_run([
|
||
"sed", "-i",
|
||
f"s/^# {key} is not set/{key}={value}/; t; s/^{key}=.*/{key}={value}/; t; $a\\{key}={value}",
|
||
".config"
|
||
], env=env)
|
||
|
||
# 🧠 Shell e utilitários básicos
|
||
safe_run(["sed", "-i", "s/^CONFIG_TC=.*/# CONFIG_TC is not set/", ".config"], env=env)
|
||
safe_run(["sed", "-i", "s/^# CONFIG_ASH is not set/CONFIG_ASH=y/", ".config"], env=env)
|
||
safe_run(["sed", "-i", "s/^# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set/CONFIG_ASH_OPTIMIZE_FOR_SIZE=y/", ".config"], env=env)
|
||
safe_run(["sed", "-i", "s/^# CONFIG_FEATURE_SH_STANDALONE is not set/CONFIG_FEATURE_SH_STANDALONE=y/", ".config"], env=env)
|
||
|
||
console.print("[yellow]🔧 Regerando configuração coerente (make oldconfig)...[/yellow]")
|
||
safe_run(["make", "oldconfig"], env=env)
|
||
|
||
console.print("[yellow]🔨 Compilando BusyBox (estático, com EXT4 e ferramentas de disco)...[/yellow]")
|
||
safe_run(["make", "-j", str(os.cpu_count())], env=env)
|
||
safe_run(["make", "install"], env=env)
|
||
|
||
console.print("[green]✔ BusyBox compilado e instalado com sucesso![/green]")
|
||
|
||
|
||
elif choice == "4":
|
||
menu_python.run()
|
||
|
||
elif choice == "5":
|
||
menu_libs.run()
|
||
|
||
elif choice == "6":
|
||
os.chdir(nfdos_dir)
|
||
console.print("[cyan]Montando RootFS e gerando imagem bootável...[/cyan]")
|
||
|
||
limpar_rootfs(nfdos_dir)
|
||
|
||
rootfs_dir = nfdos_dir / "rootfs"
|
||
rootfs_dir.mkdir(exist_ok=True)
|
||
|
||
# Estrutura de diretórios básica
|
||
for d in ["bin", "sbin", "etc", "proc", "sys", "usr/bin", "usr/sbin", "opt/kernel"]:
|
||
(rootfs_dir / d).mkdir(parents=True, exist_ok=True)
|
||
|
||
# Garante os device nodes no initramfs
|
||
safe_run(f"mkdir -p {rootfs_dir}/dev", shell=True)
|
||
safe_run(f"sudo mknod -m 600 {rootfs_dir}/dev/console c 5 1", shell=True)
|
||
safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/null c 1 3", shell=True)
|
||
safe_run(f"sudo mknod -m 600 {rootfs_dir}/dev/ttyS0 c 4 64", shell=True)
|
||
safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/random c 1 8", shell=True)
|
||
safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/urandom c 1 9", shell=True)
|
||
|
||
# Copiar o BusyBox instalado para o rootfs
|
||
console.print("[blue]🔗 Copiando BusyBox para o rootfs...[/blue]")
|
||
safe_run(f"cp -a {busybox_dir}/_install/* {rootfs_dir}/", shell=True)
|
||
safe_run(["chmod", "-R", "755", str(rootfs_dir / "bin")])
|
||
console.print("[green]✔ BusyBox incluído no rootfs![/green]")
|
||
|
||
# Inserir a Lib Python (TODO: No NFDOS V0.2 build “fully frozen”)
|
||
safe_run(f"mkdir -p {rootfs_dir}/usr/lib/python3.13", shell=True)
|
||
safe_run(f"rsync -av --exclude='test' --exclude='idlelib' --exclude='tkinter' \
|
||
{nfdos_dir}/cpython/Lib/ {rootfs_dir}/usr/lib/python3.13/", shell=True)
|
||
|
||
# --- Copiar binário Python estático para o RootFS ---
|
||
python_bin = nfdos_dir / "python"
|
||
usr_bin = rootfs_dir / "usr" / "bin"
|
||
usr_bin.mkdir(parents=True, exist_ok=True)
|
||
|
||
if python_bin.exists():
|
||
console.print("[yellow]→ Adicionando Python estático ao RootFS...[/yellow]")
|
||
safe_run(f"cp {python_bin} {usr_bin}/python3", shell=True)
|
||
else:
|
||
console.print("[red]⚠ Python estático não encontrado em nfdos/python — compilar antes.[/red]")
|
||
|
||
# Inserir Neurotron (se existir)
|
||
opt_kernel = rootfs_dir / "opt" / "kernel"
|
||
opt_kernel.mkdir(parents=True, exist_ok=True)
|
||
|
||
# ============================================
|
||
# Instalar Neurotron nativamente no RootFS
|
||
# ============================================
|
||
|
||
neurotron_src = kernel_dir / "neurotron" / "src"
|
||
neurotron_data = kernel_dir / "neurotron" / "data"
|
||
neurotron_bin = kernel_dir / "neurotron" / "neurotron" # gerado pelo autotools
|
||
|
||
neurotron_root = opt_kernel / "neurotron"
|
||
neurotron_root.mkdir(parents=True, exist_ok=True)
|
||
|
||
if neurotron_src.exists():
|
||
console.print("[yellow]→ Instalando código-fonte do Neurotron...[/yellow]")
|
||
safe_run(f"cp -r {neurotron_src} {neurotron_root}/", shell=True)
|
||
else:
|
||
console.print("[red]✗ Código-fonte do Neurotron não encontrado.[/red]")
|
||
|
||
if neurotron_data.exists():
|
||
console.print("[yellow]→ Instalando diretório data/ do Neurotron...[/yellow]")
|
||
safe_run(f"cp -r {neurotron_data} {neurotron_root}/", shell=True)
|
||
|
||
# Instalar binário /usr/bin/neurotron
|
||
usr_bin = rootfs_dir / "usr" / "bin"
|
||
usr_bin.mkdir(parents=True, exist_ok=True)
|
||
|
||
if neurotron_bin.exists():
|
||
console.print("[yellow]→ Instalando wrapper /usr/bin/neurotron[/yellow]")
|
||
safe_run(f"cp {neurotron_bin} {usr_bin}/neurotron", shell=True)
|
||
safe_run(f"chmod +x {usr_bin}/neurotron", shell=True)
|
||
else:
|
||
console.print("[red]✗ Wrapper 'neurotron' não encontrado — corre 'make' em kernel/neurotron[/red]")
|
||
|
||
# Instalar terminais
|
||
lterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "l"
|
||
lterm_dir.mkdir(parents=True, exist_ok=True)
|
||
safe_run(f"cp {nfdos_dir}/linux {lterm_dir}/", shell=True)
|
||
|
||
xterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "x"
|
||
xterm_dir.mkdir(parents=True, exist_ok=True)
|
||
safe_run(f"cp {nfdos_dir}/xterm {xterm_dir}/", shell=True)
|
||
|
||
vterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "v"
|
||
vterm_dir.mkdir(parents=True, exist_ok=True)
|
||
safe_run(f"cp {nfdos_dir}/vt100 {vterm_dir}/", shell=True)
|
||
|
||
# Instalar libs externas do Neurotron (se existirem)
|
||
libs_dir = nfdos_dir / "libs"
|
||
site_packages = rootfs_dir / "usr/lib/python3.13/site-packages"
|
||
site_packages.mkdir(parents=True, exist_ok=True)
|
||
|
||
lib_files = []
|
||
for ext in ("*.whl", "*.tar.gz", "*.zip", "*.tgz"):
|
||
lib_files.extend(glob(f"{libs_dir}/{ext}"))
|
||
|
||
if lib_files:
|
||
libs_str = " ".join(lib_files)
|
||
console.print("[cyan]→ Instalando bibliotecas externas do Neurotron...[/cyan]")
|
||
safe_run(
|
||
f"pip install --no-deps --target={site_packages} {libs_str}",
|
||
shell=True
|
||
)
|
||
else:
|
||
console.print("[yellow]⚠️ Nenhuma biblioteca externa encontrada em libs/.[/yellow]")
|
||
|
||
|
||
# Script init com chamada ao Neurotron
|
||
init_file = rootfs_dir / "init"
|
||
initramfs_file = nfdos_dir / "initramfs.cpio.gz"
|
||
|
||
safe_run(f"cd {rootfs_dir} && cp ../init .", shell=True) # TODO: usar f.write para automatizar o init
|
||
safe_run(["chmod", "+x", str(init_file)])
|
||
|
||
# Gerar initramfs
|
||
console.print("[blue]Gerando initramfs.cpio.gz...[/blue]")
|
||
if initramfs_file.exists():
|
||
safe_run(f"rm {initramfs_file}", shell=True)
|
||
safe_run(f"cd {rootfs_dir} && find . | cpio -H newc -o | gzip > {initramfs_file}", shell=True)
|
||
console.print("[green]✔ RootFS criado e compactado![/green]")
|
||
|
||
# 🧠 Validação do init antes de gerar o initramfs
|
||
console.print("[blue]🔍 Verificando integridade do init...[/blue]")
|
||
|
||
# Garante que o init existe
|
||
if not init_file.exists():
|
||
console.print(f"[red]✗ Ficheiro init não encontrado em {init_file}[/red]")
|
||
raise SystemExit(1)
|
||
|
||
# Mostra onde ele está dentro do initramfs
|
||
safe_run(f'cd {nfdos_dir} && lsinitramfs initramfs.cpio.gz | grep -E "(^|/)init$"', shell=True)
|
||
|
||
# Mostra tipo e encoding
|
||
console.print("[cyan]→ Verificando tipo de ficheiro...[/cyan]")
|
||
safe_run(f'file {init_file}', shell=True)
|
||
|
||
# Mostra primeiras linhas (para confirmar shebang)
|
||
console.print("[cyan]→ Conteúdo inicial do init (máx 10 linhas)...[/cyan]")
|
||
safe_run(f'head -n 10 {init_file}', shell=True)
|
||
|
||
# Sanitização: remove BOM e CRLF
|
||
console.print("[blue]→ Removendo BOM e CRLF (normalização universal)...[/blue]")
|
||
safe_run(f"sed -i '1s/^\\xEF\\xBB\\xBF//' {init_file}", shell=True)
|
||
safe_run(f"sed -i 's/\\r$//' {init_file}", shell=True)
|
||
|
||
# Confirma permissões
|
||
console.print("[cyan]→ Ajustando permissões de execução...[/cyan]")
|
||
safe_run(f'chmod 0755 {init_file}', shell=True)
|
||
|
||
# Segunda verificação do tipo
|
||
console.print("[green]✔ Ficheiro final após normalização:[/green]")
|
||
safe_run(f'file {init_file}', shell=True)
|
||
|
||
# Validação do shebang e encoding
|
||
console.print("[blue]→ Testando assinatura e line endings...[/blue]")
|
||
safe_run(f"head -n1 {init_file} | od -c", shell=True)
|
||
safe_run(f"grep -Ua 'bin/sh' {init_file} | head -n1", shell=True)
|
||
|
||
console.print("[green]✔ init validado e pronto para inclusão no initramfs[/green]")
|
||
|
||
# Criar disco (se não existir)
|
||
data_disk = nfdos_dir / "nfdos_data.img"
|
||
if not data_disk.exists():
|
||
console.print("[cyan]💽 Criando disco persistente (hipocampo físico)...[/cyan]")
|
||
safe_run(f"dd if=/dev/zero of={data_disk} bs=1M count=512", shell=True)
|
||
else:
|
||
console.print("[green]✔ Disco persistente já existe.[/green]")
|
||
|
||
|
||
time.sleep(5)
|
||
|
||
|
||
# Testar no QEMU
|
||
bz_image = linux_dir / "arch" / "x86" / "boot" / "bzImage"
|
||
data_disk = nfdos_dir / "nfdos_data.img"
|
||
|
||
if bz_image.exists():
|
||
console.print("\n[bold blue]Iniciando QEMU (modo kernel direto)...[/bold blue]")
|
||
|
||
# 🔒 Pergunta ao utilizador se deve permitir formatação automática do disco
|
||
console.print(
|
||
"\n[yellow]O Neurotron detetará o disco físico e poderá formatá-lo se estiver vazio.[/yellow]"
|
||
)
|
||
console.print(
|
||
"[bright_yellow]Deseja permitir formatação automática do disco?[/bright_yellow] "
|
||
"([green]y[/green]/[red]N[/red]): ",
|
||
end=""
|
||
)
|
||
choice = input().strip().lower()
|
||
|
||
allow_format = choice in ("y", "yes", "sim", "s")
|
||
|
||
# 🧠 Monta a linha base do QEMU
|
||
kernel_params = (
|
||
"console=ttyS0 earlyprintk=serial,ttyS0,115200 "
|
||
"keep_bootcon loglevel=8"
|
||
)
|
||
|
||
# 🧩 Injeta flag de formatação se permitido
|
||
if allow_format:
|
||
kernel_params += " nfdos_force_format=1"
|
||
console.print("[green]✔ Formatação automática permitida neste boot.[/green]")
|
||
else:
|
||
console.print("[cyan]ℹ Formatação automática desativada (modo seguro).[/cyan]")
|
||
|
||
qemu_cmd = (
|
||
f"qemu-system-x86_64 "
|
||
f"-machine q35,accel=kvm "
|
||
f"-cpu qemu64 "
|
||
f"-kernel {bz_image} "
|
||
f"-initrd {nfdos_dir}/initramfs.cpio.gz "
|
||
f"-append '{kernel_params}' "
|
||
f"-drive file={data_disk},if=virtio,format=raw "
|
||
f"-m 1024 "
|
||
f"-nographic "
|
||
f"-no-reboot"
|
||
)
|
||
|
||
# 🚀 Executa o QEMU
|
||
safe_run(qemu_cmd, shell=True)
|
||
|
||
else:
|
||
console.print("[red]✗ bzImage não encontrado! Compile o kernel primeiro.[/red]")
|
||
|
||
|
||
elif choice == "7":
|
||
menu_iso.run()
|
||
|
||
elif choice == "0":
|
||
break
|
||
else:
|
||
console.print("[red]Opção inválida![/red]")
|
||
|
||
time.sleep(1)
|
||
|