ohhhhhhhhhhh (exclude linux-extra-rootfs.img build artifact)

This commit is contained in:
Linehu
2026-10-01 23:13:42 +08:00
parent 737a2cb0db
commit 1074962546
533 changed files with 133239 additions and 5460 deletions
Binary file not shown.
+21 -3
View File
@@ -10,13 +10,22 @@ No KDE packages are downloaded unless `KDE_FULL=1` is explicitly set.
## Build
Run the full build from an Arch Linux environment with
`arch-install-scripts`, working pacman mirrors, and a valid keyring:
Preferred: an Arch Linux environment with `arch-install-scripts`.
On WSL/Ubuntu the script falls back to the official Arch bootstrap
tarball plus `chroot pacman`. Always keep the work directory on a
native Linux disk (`EXTRA_ROOTFS_WORK`, default `/root/extra_rootfs_work`);
do not extract the suite through `/mnt/d`.
```bash
# Arch host:
sudo pacman -S --needed arch-install-scripts
sudo KDE_FULL=1 IMG_SIZE_MB=8192 \
bash CODE/linux/build_extra_rootfs.sh
# WSL (Ubuntu) native disk, no pacstrap:
sudo EXTRA_ROOTFS_WORK=/root/extra_rootfs_work \
KDE_FULL=1 IMG_SIZE_MB=8192 \
bash CODE/linux/build_extra_rootfs.sh
```
The default size for `KDE_FULL=1` is 8192 MiB. The complete
@@ -50,12 +59,21 @@ ships the Wayland session in `plasma-workspace`; the obsolete
## Storage and attachment
The output remains:
The default output path is:
```text
SYSTEM/boot/linux-extra-rootfs.img
```
For an 8 GiB KDE image keep the result on a native Linux disk:
```bash
sudo EXTRA_ROOTFS_WORK=/root/extra_rootfs_work \
EXTRA_ROOTFS_OUTPUT=/home/deshab/linux-extra-rootfs.img \
KDE_FULL=1 IMG_SIZE_MB=8192 \
bash CODE/linux/build_extra_rootfs.sh
```
That path is the existing build staging convention, not a claim that the full
image fits in the boot partition. A full KDE image must **not** be copied into
the 2 GiB ESP or enabled as a large Limine boot module. It must later be backed
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Push the updated FUCK config (sched demo_ms=0) into the ESP of the given
# images. ESP path is /system/deshab64/FUCK. Readback verified by md5.
set -Eeuo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
SRC="$ROOT/SYSTEM/system/deshab64/FUCK"
[[ -f "$SRC" ]] || { echo "missing $SRC"; exit 2; }
EXP=$(md5sum "$SRC" | cut -d' ' -f1)
echo "source FUCK md5=$EXP"
rc=0
for img in "$@"; do
L=$(losetup --find --show --partscan "$img")
sleep 0.3
M=$(mktemp -d)
if ! mount "${L}p1" "$M" 2>/dev/null; then
echo "$(basename "$img"): mount p1 FAILED"; rmdir "$M"; losetup -d "$L"; rc=1; continue
fi
mkdir -p "$M/system/deshab64"
cp -f "$SRC" "$M/system/deshab64/FUCK"
sync
got=$(md5sum "$M/system/deshab64/FUCK" | cut -d' ' -f1)
[[ "$got" == "$EXP" ]] && echo "$(basename "$img"): FUCK APPLIED" || { echo "$(basename "$img"): VERIFY FAILED"; rc=1; }
umount "$M"; rmdir "$M"; losetup -d "$L"
done
exit $rc
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# Apply the current SYSTEM/boot/utsm.elf to the ESP of one or more GPT images,
# then prove the in-image copy matches (md5 + FLUSH_N marker). Idempotent.
# ESP-only: Limine loads the kernel via boot(): from the FAT32 ESP.
# Usage: apply_utsm.sh IMG [IMG...]
set -Eeuo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
SRC="$ROOT/SYSTEM/boot/utsm.elf"
[[ -f "$SRC" ]] || { echo "missing $SRC"; exit 2; }
EXP=$(md5sum "$SRC" | cut -d' ' -f1)
FLUSH=$(strings -a "$SRC" | grep -c 'VGPU\] FLUSH_N' || true)
echo "source: md5=$EXP size=$(stat -c %s "$SRC") flush_marker=$FLUSH"
if [[ "$FLUSH" -lt 1 ]]; then
echo "FATAL: source utsm.elf has no FLUSH_N marker; verify cannot judge Plasma scanout"
exit 2
fi
rc=0
for img in "$@"; do
name=$(basename "$img")
if [[ ! -f "$img" ]]; then
echo "$name: MISSING"
rc=1
continue
fi
L=$(losetup --find --show --partscan "$img")
sleep 0.3
M=$(mktemp -d)
if ! mount "${L}p1" "$M" 2>/dev/null; then
echo "$name: mount p1 FAILED"
rmdir "$M"
losetup -d "$L"
rc=1
continue
fi
cp -f "$SRC" "$M/boot/utsm.elf"
sync
got=$(md5sum "$M/boot/utsm.elf" | cut -d' ' -f1)
n=$(strings -a "$M/boot/utsm.elf" | grep -c 'VGPU\] FLUSH_N' || true)
if [[ "$got" == "$EXP" && "$n" -ge 1 ]]; then
echo "$name: APPLIED md5=$got flush_marker=$n"
else
echo "$name: VERIFY-FAILED md5=$got flush_marker=$n"
rc=1
fi
umount "$M"
rmdir "$M"
losetup -d "$L"
done
exit $rc
+28 -1
View File
@@ -25,7 +25,9 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
OUTPUT_DIR="$PROJECT_ROOT/SYSTEM/boot"
OUTPUT_IMG="$OUTPUT_DIR/linux-rootfs.img"
IMG_SIZE_MB=${IMG_SIZE_MB:-512}
# 768MB leaves room for distro CPython + stdlib on the virtio-blk rootfs.
IMG_SIZE_MB=${IMG_SIZE_MB:-768}
ARCH_INSTALL_PYTHON="${ARCH_INSTALL_PYTHON:-1}"
# Work on native Linux FS for speed (NOT /mnt/d which is 9p — extremely slow).
WORK_DIR="${ARCH_ROOTFS_WORK:-/root/arch_rootfs_work}"
@@ -284,6 +286,31 @@ else
echo "[arch-rootfs] WARNING: daemon source not found at $DAEMON_SRC"
fi
# 7.6 Distro CPython for guest userspace (Track C). Keep interpreter and
# stdlib from the same Arch packages; do not overlay SYSTEM/lib libpython.
if [ "$ARCH_INSTALL_PYTHON" = "1" ]; then
echo "[arch-rootfs] Installing Arch CPython into staging rootfs..."
mkdir -p "$ROOTFS_DIR"/{dev,proc,sys,tmp}
mount --bind /dev "$ROOTFS_DIR/dev" 2>/dev/null || true
mount --bind /proc "$ROOTFS_DIR/proc" 2>/dev/null || true
mount --bind /sys "$ROOTFS_DIR/sys" 2>/dev/null || true
printf 'nameserver 1.1.1.1\n' > "$ROOTFS_DIR/tmp/resolv.conf"
if chroot "$ROOTFS_DIR" /usr/bin/pacman -Sy --noconfirm && \
chroot "$ROOTFS_DIR" /usr/bin/pacman -S --noconfirm python; then
mkdir -p "$ROOTFS_DIR/usr/local/share/deshab/python"
if [ -f "$PROJECT_ROOT/SYSTEM/user/python/hello.py" ]; then
install -m 0644 "$PROJECT_ROOT/SYSTEM/user/python/hello.py" \
"$ROOTFS_DIR/usr/local/share/deshab/python/hello.py"
fi
echo "[arch-rootfs] python: $(chroot "$ROOTFS_DIR" /usr/bin/python3 --version 2>/dev/null || true)"
else
echo "[arch-rootfs] WARNING: python install failed (network or pacman)"
fi
umount "$ROOTFS_DIR/dev" 2>/dev/null || true
umount "$ROOTFS_DIR/proc" 2>/dev/null || true
umount "$ROOTFS_DIR/sys" 2>/dev/null || true
fi
# 8. Create ext4 image on native FS, populate, then copy to /mnt/d.
echo "[arch-rootfs] Creating ext4 image (${IMG_SIZE_MB}MB) on native FS..."
NATIVE_IMG="$WORK_DIR/linux-rootfs.img"
+185 -23
View File
@@ -14,7 +14,7 @@
# Usage:
# sudo bash CODE/linux/build_extra_rootfs.sh
# sudo IMG_SIZE_MB=2048 bash CODE/linux/build_extra_rootfs.sh
# sudo KDE_FULL=1 IMG_SIZE_MB=8192 bash CODE/linux/build_extra_rootfs.sh
# sudo KDE_FULL=1 bash CODE/linux/build_extra_rootfs.sh # 3900MB, FAT32-safe
#
# KDE_FULL=1 prerequisites:
# - An Arch Linux build environment with arch-install-scripts (pacstrap)
@@ -25,8 +25,8 @@ set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
OUTPUT_DIR="$PROJECT_ROOT/SYSTEM/boot"
OUTPUT_IMG="$OUTPUT_DIR/linux-extra-rootfs.img"
OUTPUT_DIR="${EXTRA_ROOTFS_OUTPUT_DIR:-$PROJECT_ROOT/SYSTEM/boot}"
OUTPUT_IMG="${EXTRA_ROOTFS_OUTPUT:-$OUTPUT_DIR/linux-extra-rootfs.img}"
KDE_FULL="${KDE_FULL:-0}"
case "$KDE_FULL" in
@@ -39,7 +39,9 @@ esac
if [ -z "${IMG_SIZE_MB+x}" ]; then
if [ "$KDE_FULL" -eq 1 ]; then
IMG_SIZE_MB=8192
# FAT32 ESP cannot store a file >= 4GiB. SYSTEM/boot is the only
# pack input, so the extra-rootfs image must stay under that limit.
IMG_SIZE_MB=3900
else
IMG_SIZE_MB=1024
fi
@@ -48,8 +50,9 @@ if ! [[ "$IMG_SIZE_MB" =~ ^[1-9][0-9]*$ ]]; then
echo "[extra-rootfs] ERROR: IMG_SIZE_MB must be a positive integer" >&2
exit 2
fi
if [ "$KDE_FULL" -eq 1 ] && [ "$IMG_SIZE_MB" -lt 8192 ]; then
echo "[extra-rootfs] WARNING: full KDE is expected to need at least 8192MB" >&2
if [ "$KDE_FULL" -eq 1 ] && [ "$IMG_SIZE_MB" -ge 4096 ]; then
echo "[extra-rootfs] ERROR: IMG_SIZE_MB=$IMG_SIZE_MB >= 4GiB; FAT32 SYSTEM pack cannot store it" >&2
exit 2
fi
WORK_DIR="${EXTRA_ROOTFS_WORK:-/root/extra_rootfs_work}"
@@ -74,10 +77,12 @@ fi
# plasma-wayland-session package on current Arch Linux.
KDE_DESKTOP_PACKAGES=(
plasma-meta
kde-applications-meta
plasma-workspace
sddm
)
KDE_APP_PACKAGES=(
kde-applications-meta
)
KDE_WAYLAND_PACKAGES=(
wayland
wayland-protocols
@@ -104,12 +109,16 @@ KDE_SESSION_PACKAGES=(
polkit
pam
)
# noto-fonts-cjk is optional: the package is huge and Chinese mirrors
# often stall. Install later with KDE_EXTRA_PACKAGES="noto-fonts-cjk".
KDE_FONT_PACKAGES=(
noto-fonts
noto-fonts-cjk
noto-fonts-emoji
ttf-dejavu
)
KDE_PYTHON_PACKAGES=(
python
)
KDE_BASE_PACKAGES=(
base
bash
@@ -124,6 +133,7 @@ KDE_PACKAGES=(
"${KDE_GRAPHICS_PACKAGES[@]}"
"${KDE_SESSION_PACKAGES[@]}"
"${KDE_FONT_PACKAGES[@]}"
"${KDE_PYTHON_PACKAGES[@]}"
)
if [ -n "${KDE_EXTRA_PACKAGES:-}" ]; then
read -r -a KDE_EXTRA_PACKAGE_ARRAY <<< "$KDE_EXTRA_PACKAGES"
@@ -139,23 +149,166 @@ if [ "$(id -u)" -ne 0 ]; then
echo "[extra-rootfs] ERROR: must run as root (loop mount required)" >&2
exit 1
fi
# WSL/Ubuntu has no pacstrap. Fall back to an Arch bootstrap tarball
# extracted onto the native Linux disk, then chroot pacman.
KDE_BOOTSTRAP_TAR="${KDE_BOOTSTRAP_TAR:-$WORK_DIR/archlinux-bootstrap.tar.zst}"
KDE_USE_BOOTSTRAP=0
if [ "$KDE_FULL" -eq 1 ] && ! command -v "$KDE_PACSTRAP" >/dev/null 2>&1; then
echo "[extra-rootfs] ERROR: KDE_FULL=1 requires pacstrap" >&2
echo "[extra-rootfs] Install arch-install-scripts in an Arch build environment," >&2
echo "[extra-rootfs] or set KDE_PACSTRAP to its absolute path." >&2
exit 1
echo "[extra-rootfs] pacstrap not found; will use Arch bootstrap+chroot"
KDE_USE_BOOTSTRAP=1
fi
if [ -n "$KDE_PACMAN_CONF" ] && [ ! -r "$KDE_PACMAN_CONF" ]; then
echo "[extra-rootfs] ERROR: KDE_PACMAN_CONF is not readable: $KDE_PACMAN_CONF" >&2
exit 1
fi
kde_download_bootstrap() {
local url
if [ -f "$KDE_BOOTSTRAP_TAR" ]; then
return 0
fi
mkdir -p "$(dirname "$KDE_BOOTSTRAP_TAR")"
for url in \
"https://mirrors.tuna.tsinghua.edu.cn/archlinux/iso/latest/archlinux-bootstrap-x86_64.tar.zst" \
"https://mirrors.ustc.edu.cn/archlinux/iso/latest/archlinux-bootstrap-x86_64.tar.zst" \
"https://mirrors.aliyun.com/archlinux/iso/latest/archlinux-bootstrap-x86_64.tar.zst"
do
echo "[extra-rootfs] Trying bootstrap: $url"
if curl -fL --retry 3 --connect-timeout 20 -o "$KDE_BOOTSTRAP_TAR" "$url"; then
return 0
fi
rm -f "$KDE_BOOTSTRAP_TAR"
done
echo "[extra-rootfs] ERROR: failed to download Arch bootstrap tarball" >&2
return 1
}
kde_configure_pacman() {
local root="$1"
mkdir -p "$root/etc/pacman.d"
cat > "$root/etc/pacman.d/mirrorlist" <<'MIRRORS'
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
Server = https://mirrors.aliyun.com/archlinux/$repo/os/$arch
Server = https://mirrors.cloud.tencent.com/archlinux/$repo/os/$arch
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch
MIRRORS
cat > "$root/etc/pacman.conf" <<'PACMANCONF'
[options]
HoldPkg = pacman glibc
Architecture = auto
SigLevel = Never
LocalFileSigLevel = Never
DisableDownloadTimeout
XferCommand = /usr/bin/curl -C - -fL --retry 8 --retry-delay 3 --connect-timeout 60 -o %o %u
[core]
Include = /etc/pacman.d/mirrorlist
[extra]
Include = /etc/pacman.d/mirrorlist
PACMANCONF
mkdir -p "$root/tmp/pacman/lib/sync" "$root/tmp/pacman/cache/pkg"
printf 'nameserver 1.1.1.1\n' > "$root/etc/resolv.conf"
}
kde_chroot_bind() {
local root="$1"
mkdir -p "$root"/{dev,proc,sys,run}
mount --bind /dev "$root/dev"
mount --bind /proc "$root/proc"
mount --bind /sys "$root/sys"
mount --bind /run "$root/run" 2>/dev/null || true
}
kde_unlock() {
rm -f "$1/var/lib/pacman/db.lck" "$1/tmp/pacman/lib/db.lck"
}
kde_pacman_wave() {
local root="$1"
shift
local attempt
echo "[extra-rootfs] pacman wave: $*"
for attempt in 1 2 3; do
kde_unlock "$root"
if chroot "$root" /usr/bin/pacman -S --noconfirm --needed --overwrite '*' "$@"; then
return 0
fi
echo "[extra-rootfs] wave failed (attempt $attempt), retrying..."
sleep 3
done
return 1
}
kde_install_full_suite() {
local hello_src="$PROJECT_ROOT/SYSTEM/user/python/hello.py"
if [ "$KDE_USE_BOOTSTRAP" -eq 0 ]; then
echo "[extra-rootfs] Installing full Arch/KDE suite with pacstrap..."
PACSTRAP_ARGS=(-K -c)
if [ -n "$KDE_PACMAN_CONF" ]; then
PACSTRAP_ARGS+=(-C "$KDE_PACMAN_CONF")
fi
"$KDE_PACSTRAP" "${PACSTRAP_ARGS[@]}" "$MNT_DIR" "${KDE_PACKAGES[@]}"
if [ "${KDE_SKIP_APPS:-1}" != "1" ]; then
echo "[extra-rootfs] Installing KDE applications meta (second pass)..."
if ! chroot "$MNT_DIR" /usr/bin/pacman -S --noconfirm --needed "${KDE_APP_PACKAGES[@]}"; then
echo "[extra-rootfs] WARNING: kde-applications-meta incomplete; Plasma/Wayland/Python remain"
fi
else
echo "[extra-rootfs] skipping kde-applications-meta (KDE_SKIP_APPS=1, FAT32-safe)"
fi
else
echo "[extra-rootfs] Installing Arch/KDE via bootstrap+chroot (native disk)..."
kde_download_bootstrap
if [ ! -x "$MNT_DIR/bin/bash" ] && [ ! -x "$MNT_DIR/usr/bin/bash" ]; then
echo "[extra-rootfs] Extracting bootstrap into extra-rootfs..."
tar --zstd -xf "$KDE_BOOTSTRAP_TAR" --strip-components=1 -C "$MNT_DIR"
fi
kde_configure_pacman "$MNT_DIR"
kde_chroot_bind "$MNT_DIR"
kde_unlock "$MNT_DIR"
chroot "$MNT_DIR" /usr/bin/pacman -Sy --noconfirm
if [ ! -x "$MNT_DIR/usr/bin/python3" ]; then
kde_pacman_wave "$MNT_DIR" "${KDE_BASE_PACKAGES[@]}" "${KDE_PYTHON_PACKAGES[@]}"
fi
kde_pacman_wave "$MNT_DIR" "${KDE_WAYLAND_PACKAGES[@]}" "${KDE_GRAPHICS_PACKAGES[@]}" \
|| echo "[extra-rootfs] WARNING: wayland/graphics wave incomplete"
kde_pacman_wave "$MNT_DIR" "${KDE_SESSION_PACKAGES[@]}" "${KDE_FONT_PACKAGES[@]}" \
|| echo "[extra-rootfs] WARNING: session/font wave incomplete"
if [ ! -x "$MNT_DIR/usr/bin/plasmashell" ]; then
kde_pacman_wave "$MNT_DIR" "${KDE_DESKTOP_PACKAGES[@]}" \
|| echo "[extra-rootfs] WARNING: Plasma desktop wave incomplete"
fi
if [ "${KDE_SKIP_APPS:-1}" != "1" ]; then
echo "[extra-rootfs] Installing KDE applications meta (second pass)..."
if ! kde_pacman_wave "$MNT_DIR" "${KDE_APP_PACKAGES[@]}"; then
echo "[extra-rootfs] WARNING: kde-applications-meta incomplete; Plasma/Wayland/Python remain"
fi
else
echo "[extra-rootfs] skipping kde-applications-meta (KDE_SKIP_APPS=1, FAT32-safe)"
fi
umount -R "$MNT_DIR/dev" 2>/dev/null || umount "$MNT_DIR/dev" 2>/dev/null || true
umount "$MNT_DIR/proc" 2>/dev/null || true
umount "$MNT_DIR/sys" 2>/dev/null || true
umount "$MNT_DIR/run" 2>/dev/null || true
fi
if [ -f "$hello_src" ]; then
mkdir -p "$MNT_DIR/usr/local/share/deshab/python"
install -m 0644 "$hello_src" "$MNT_DIR/usr/local/share/deshab/python/hello.py"
echo "[extra-rootfs] installed hello.py"
fi
}
mkdir -p "$WORK_DIR" "$MNT_DIR" "$OUTPUT_DIR"
LOOP_DEV=""
MOUNTED=0
cleanup() {
set +e
umount -R "$MNT_DIR/dev" 2>/dev/null || umount "$MNT_DIR/dev" 2>/dev/null || true
umount "$MNT_DIR/proc" 2>/dev/null || true
umount "$MNT_DIR/sys" 2>/dev/null || true
umount "$MNT_DIR/run" 2>/dev/null || true
if [ "$MOUNTED" -eq 1 ]; then
umount -R "$MNT_DIR" 2>/dev/null || umount "$MNT_DIR" 2>/dev/null || true
fi
@@ -166,28 +319,37 @@ cleanup() {
trap cleanup EXIT INT TERM
# 1. Allocate a sparse-friendly image and create its ext4 filesystem.
echo "[extra-rootfs] Allocating ${IMG_SIZE_MB}MB image..."
rm -f "$NATIVE_IMG"
dd if=/dev/zero of="$NATIVE_IMG" bs=1M count=0 seek="$IMG_SIZE_MB" status=none
echo "[extra-rootfs] mkfs.ext4..."
mkfs.ext4 -q -F -N 1048576 -O ^has_journal -L deshab-persist "$NATIVE_IMG"
# EXTRA_ROOTFS_RESUME=1 reuses an existing native image (failed pacman retry).
if [ "${EXTRA_ROOTFS_RESUME:-0}" = "1" ] && [ -f "$NATIVE_IMG" ]; then
echo "[extra-rootfs] resume: reusing $NATIVE_IMG"
else
echo "[extra-rootfs] Allocating ${IMG_SIZE_MB}MB image..."
rm -f "$NATIVE_IMG"
dd if=/dev/zero of="$NATIVE_IMG" bs=1M count=0 seek="$IMG_SIZE_MB" status=none
echo "[extra-rootfs] mkfs.ext4..."
mkfs.ext4 -q -F -N 1048576 -O ^has_journal -L deshab-persist "$NATIVE_IMG"
fi
# 2. Mount and populate the lightweight persistence skeleton.
echo "[extra-rootfs] Populating directory skeleton..."
LOOP_DEV="$(losetup --find --show "$NATIVE_IMG")"
mount -t ext4 "$LOOP_DEV" "$MNT_DIR"
MOUNTED=1
rm -f "$MNT_DIR/var/lib/pacman/db.lck" "$MNT_DIR/tmp/pacman/lib/db.lck"
mkdir -p "$MNT_DIR/opt" "$MNT_DIR/home" "$MNT_DIR/root" "$MNT_DIR/vscode"
touch "$MNT_DIR/vscode/.keep"
if [ "$KDE_FULL" -eq 1 ]; then
echo "[extra-rootfs] Installing full Arch/KDE suite with pacstrap..."
PACSTRAP_ARGS=(-K -c)
if [ -n "$KDE_PACMAN_CONF" ]; then
PACSTRAP_ARGS+=(-C "$KDE_PACMAN_CONF")
if [ "${KDE_FINALIZE_ONLY:-0}" = "1" ]; then
echo "[extra-rootfs] finalize-only: keeping installed Plasma/Wayland/Python"
hello_src="$PROJECT_ROOT/SYSTEM/user/python/hello.py"
if [ -f "$hello_src" ]; then
mkdir -p "$MNT_DIR/usr/local/share/deshab/python"
install -m 0644 "$hello_src" "$MNT_DIR/usr/local/share/deshab/python/hello.py"
fi
else
kde_install_full_suite
fi
"$KDE_PACSTRAP" "${PACSTRAP_ARGS[@]}" "$MNT_DIR" "${KDE_PACKAGES[@]}"
# The image is a complete chroot kept separate from the active minimal
# guest root. A marker lets the launcher distinguish wrapper and chroot
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail
IMG="${1:-/mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img}"
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
ESP=$(mktemp -d)
mount "${LOOP}p1" "$ESP"
cp -f "$ESP/boot/linux-rootfs.img" /tmp/linux-rootfs-check.img
umount "$ESP"
losetup -d "$LOOP"
rmdir "$ESP"
M=$(mktemp -d)
mount -o loop,ro /tmp/linux-rootfs-check.img "$M"
python3 - "$M" <<'PY'
import os, sys
root = sys.argv[1]
path = None
for cand in (root + "/usr/lib/libc.so.6", root + "/lib/libc.so.6"):
if os.path.exists(cand):
path = cand
break
print("libc", path)
with open(path, "rb") as f:
data = f.read()
off = 0x199140
print("size", len(data), "at", hex(off), data[off:off+16].hex())
print("endbr64 count", data.count(b"\xf3\x0f\x1e\xfa"))
print("badnop count", data.count(b"\x0f\x1f\x40\x00"))
print("nop90 at site", data[off:off+4] == b"\x90\x90\x90\x90")
PY
umount "$M"
rmdir "$M"
echo "===== df ====="
df -h /home /tmp | head
ls -lh "$IMG" /tmp/linux-rootfs-check.img
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
LOG=/home/deshab/qemu_serial_loop1.log
clean() { tr -d '\r\0' < "$LOG"; }
echo "===== size ====="
wc -c "$LOG"
echo "===== GP/segfault/traps ====="
clean | grep -E 'general protection|segfault|traps:|endbr|#GP|SIGSEGV' | tail -n 50 || true
echo "===== KDE/exec/desktop ====="
clean | grep -E '\[deshab-kde\]|KDE |exec_async|exec rc|guest ping|desktop ready|serial 2|scanout|startplasma|Xorg|Xfbdev|Plasma|linux_compat|ibt=|shstk=|busybox|cmdline' | tail -n 80 || true
echo "===== vdc/persist ====="
clean | grep -E 'vdc|persist|overlay|EXEC_READY|switch_root' | tail -n 30 || true
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
LOG=/home/deshab/qemu_serial_loop1.log
clean() { tr -d '\r\0' < "$LOG"; }
echo "===== skip ENDBR / exception ====="
clean | grep -E 'skip ENDBR|exception rip=|exception intr_info=|insn0=' | head -n 80 || true
echo "===== first user-looking rip ====="
clean | grep 'exception rip=' | grep -v 'ffffffff' | head -n 20 || true
echo "===== GP count ====="
clean | grep -c 'general protection fault' || true
echo "===== deshab-kde / ping / exec / serial ====="
clean | grep -E 'skip landing|CET emulate|deshab-kde|guest ping|exec_async|exec rc|SKIP:|KDE spawned|serial 2|launch KDE|busybox|segfault|interpreter alive|CET U_CET|user-exc|MOV CR3|EPT reuse' | head -n 80 || true
echo "===== skip landing / user exception ====="
clean | grep -E 'skip landing|skip ENDBR|exception rip=0x00007' | head -n 40 || true
+831
View File
@@ -0,0 +1,831 @@
#!/usr/local/bin/utsm_run
# Start Plasma on the UTSM virtio-gpu 2D device.
# musl busybox.static PUSH-faults at address 0 (leaked SHSTK). Use bash.
# Wayland/KWin DRM does not issue SET_SCANOUT, so the host never sees a
# frame. Xfbdev/Xorg is the path that actually lights scanout; Plasma
# then runs as an X11 client on DISPLAY=:0.
printf '[deshab-kde] interpreter alive inside=pre\n' >/dev/kmsg 2>/dev/null || true
# Persist must not abort the session. Do not remount / rw: that is vdb
# (Arch rootfs) and dirtying it yields ext4 checksum errors.
# Skip the probe when already inside the extra-rootfs chroot.
set +e
INSIDE=0
for arg in "$@"; do
if [ "$arg" = "--inside" ]; then
INSIDE=1
fi
done
if [ "$INSIDE" -eq 0 ] && [ ! -e /etc/deshab-kde-root ]; then
printf '[deshab-kde] persist: probe\n' >/dev/kmsg 2>/dev/null || true
grep -E 'persist|vdc' /proc/mounts >/dev/kmsg 2>/dev/null || true
if [ -x /mnt/persist/usr/bin/startplasma-x11 ] || \
[ -x /mnt/persist/usr/bin/startplasma-wayland ]; then
printf '[deshab-kde] persist already has startplasma\n' >/dev/kmsg 2>/dev/null || true
elif grep -q ' /mnt/persist ' /proc/mounts 2>/dev/null; then
printf '[deshab-kde] persist mounted but startplasma missing\n' >/dev/kmsg 2>/dev/null || true
else
printf '[deshab-kde] remounting /dev/vdc ro on /mnt/persist\n' >/dev/kmsg 2>/dev/null || true
mkdir -p /mnt/persist 2>/dev/null || true
mount -t ext4 -o ro,noload /dev/vdc /mnt/persist
if [ ! -x /mnt/persist/usr/bin/startplasma-x11 ]; then
src=$(awk '$1 == "/dev/vdc" { print $2; exit }' /proc/mounts)
if [ -n "$src" ] && [ "$src" != /mnt/persist ]; then
printf '[deshab-kde] bind %s -> /mnt/persist\n' "$src" >/dev/kmsg 2>/dev/null || true
mount -o bind "$src" /mnt/persist 2>/dev/null || true
fi
fi
if [ ! -x /mnt/persist/usr/bin/startplasma-x11 ]; then
printf '[deshab-kde] persist remount failed\n' >/dev/kmsg 2>/dev/null || true
fi
fi
printf '[deshab-kde] persist check done\n' >/dev/kmsg 2>/dev/null || true
fi
set +e
KDE_ROOT="${DESHAB_KDE_ROOT:-/mnt/persist}"
SESSION_USER="${DESHAB_KDE_USER:-deshab}"
SOFTWARE_RENDERING="${DESHAB_KDE_SOFTWARE_RENDERING:-1}"
SEATD_PID=""
XFBDEV_PID=""
printf '[deshab-kde] interpreter alive inside=%s\n' "$INSIDE" > /dev/kmsg 2>/dev/null || true
log() {
printf '[deshab-kde] %s\n' "$*" >>"$LOG_FILE" 2>/dev/null || true
printf '[deshab-kde] %s\n' "$*" > /dev/kmsg 2>/dev/null || true
printf '[deshab-kde] %s\n' "$*" > /dev/console 2>/dev/null || true
printf '[deshab-kde] %s\n' "$*" >&2
}
# /dev/kmsg drops bursts. Always also hit console via log().
dump_file() {
local f="$1" max="${2:-40}" n=0
if [ ! -f "$f" ]; then
log "missing $f"
return 1
fi
log "file $f bytes=$(wc -c < "$f" 2>/dev/null || echo 0)"
while IFS= read -r line || [ -n "$line" ]; do
n=$((n + 1))
[ "$n" -gt "$max" ] && break
log "$f:$line"
done < "$f"
return 0
}
cleanup_session() {
set +e
if [ -n "$SEATD_PID" ]; then
kill "$SEATD_PID" 2>/dev/null || true
wait "$SEATD_PID" 2>/dev/null || true
fi
if [ -n "$XFBDEV_PID" ]; then
kill "$XFBDEV_PID" 2>/dev/null || true
wait "$XFBDEV_PID" 2>/dev/null || true
fi
# persist /bin/umount SIGSEGVs in ld.so; overlay is discarded on reboot.
}
trap cleanup_session EXIT INT TERM
start_xfbdev() {
if [ -S /tmp/.X11-unix/X0 ]; then
log "X socket already present"
return 0
fi
if ! command -v Xfbdev >/dev/null 2>&1; then
log "Xfbdev not on guest root; Xorg inside the KDE chroot will be used"
return 1
fi
rm -f /tmp/.X0-lock /tmp/.X11-unix/X0
mkdir -p /tmp/.X11-unix
chmod 1777 /tmp /tmp/.X11-unix
log "starting Xfbdev :0 1024x768"
Xfbdev :0 -geometry 1024x768 -depth 32 >/dev/null 2>&1 &
XFBDEV_PID=$!
i=0
while [ "$i" -lt 50 ]; do
if [ -S /tmp/.X11-unix/X0 ]; then
log "Xfbdev socket ready"
return 0
fi
sleep 0.1
i=$((i + 1))
done
log "WARNING: Xfbdev socket not seen yet, continuing"
return 0
}
if [ "$INSIDE" -eq 0 ] && [ ! -e /etc/deshab-kde-root ]; then
LOG_FILE="$KDE_ROOT/var/log/deshab-kde-session.log"
if [ "$(id -u)" -ne 0 ]; then
echo "[deshab-kde] ERROR: entering the KDE chroot requires root" >&2
exit 1
fi
printf '[deshab-kde] looking for startplasma in %s\n' "$KDE_ROOT" >/dev/kmsg 2>/dev/null || true
set +e
if [ ! -x "$KDE_ROOT/usr/bin/startplasma-x11" ] && \
[ ! -x "$KDE_ROOT/usr/bin/startplasma-wayland" ]; then
echo "[deshab-kde] ERROR: no prepared KDE root at $KDE_ROOT" >&2
printf '[deshab-kde] ERROR: no startplasma at %s\n' "$KDE_ROOT" >/dev/kmsg 2>/dev/null || true
exit 1
fi
# persist ld.so SIGSEGVs at 0 (SHSTK). vdb mount/libmount inodes fail
# checksum at runtime. Use the static helper that already matches the
# working daemon toolchain.
BINDMOUNT=/usr/local/bin/utsm_bindmount
PERSIST_LD=""
for ld in \
"$KDE_ROOT/usr/lib/ld-linux-x86-64.so.2" \
"$KDE_ROOT/lib64/ld-linux-x86-64.so.2" \
"$KDE_ROOT/lib/ld-linux-x86-64.so.2"; do
if [ -x "$ld" ]; then
PERSIST_LD="$ld"
break
fi
done
PERSIST_LIBS="$KDE_ROOT/usr/lib:$KDE_ROOT/lib:$KDE_ROOT/usr/lib64"
kde_mount() {
if [ -x "$BINDMOUNT" ]; then
if [ "$1" = --bind ] && [ -n "$2" ] && [ -n "$3" ]; then
"$BINDMOUNT" bind "$2" "$3"
return $?
fi
if [ "$1" = --make-slave ] && [ -n "$2" ]; then
"$BINDMOUNT" slave "$2"
return $?
fi
if [ "$1" = -o ] && [ "$2" = bind ] && [ -n "$3" ] && [ -n "$4" ]; then
"$BINDMOUNT" bind "$3" "$4"
return $?
fi
if [ "$1" = -t ] && [ "$3" = -o ] && [ -n "$5" ] && [ -n "$6" ]; then
"$BINDMOUNT" fstype "$2" "$5" "$6" "$4"
return $?
fi
if [ "$1" = -t ] && [ -n "$2" ] && [ -n "$3" ] && [ -n "$4" ]; then
"$BINDMOUNT" fstype "$2" "$3" "$4"
return $?
fi
fi
/bin/mount "$@"
}
log "bindmount=$BINDMOUNT persist_ld=$PERSIST_LD"
# Do not chmod persist bind targets: overlay copy-up of /dev then
# makes MS_BIND fail. Do not put vdb /usr/bin first on PATH while
# LD_LIBRARY_PATH is persist (vdb ls SIGSEGVs in ld.so).
mkdir -p "$KDE_ROOT/dev" "$KDE_ROOT/proc" "$KDE_ROOT/sys" \
"$KDE_ROOT/run" "$KDE_ROOT/tmp" "$KDE_ROOT/var/log"
touch "$LOG_FILE"
rm -f /tmp/deshab-native
log "entering KDE root at $KDE_ROOT"
start_xfbdev || true
# persist /dev /proc /sys /run are 0555 placeholders. rbind of /dev
# fails here (stderr is /dev/null from the async daemon). Use bind,
# chmod first, and keep going with a seeded /dev if needed.
bind_guest_fs() {
local name="$1"
local src="/$name"
local target="$KDE_ROOT/$name"
local err=""
if [ -L "$target" ]; then
rm -f "$target"
fi
mkdir -p "$target" 2>/dev/null || true
if grep -q " $target " /proc/mounts 2>/dev/null; then
return 0
fi
if [ ! -d "$src" ]; then
log "WARNING: $src missing"
return 1
fi
err=$(kde_mount --bind "$src" "$target" 2>&1)
if [ $? -eq 0 ]; then
kde_mount --make-slave "$target" 2>/dev/null || true
log "bound $src -> $target"
return 0
fi
err=$(kde_mount -o bind "$src" "$target" 2>&1)
if [ $? -eq 0 ]; then
log "bound -o bind $src -> $target"
return 0
fi
log "ERROR: bind $src -> $target failed: $err"
log "bind diag src=$(ls -ld "$src" 2>/dev/null) tgt=$(ls -ld "$target" 2>/dev/null)"
return 1
}
seed_dev() {
local target="$KDE_ROOT/dev"
local n
mkdir -p "$target"
chmod 0755 "$target" 2>/dev/null || true
for n in null zero urandom random tty tty0 console kmsg fb0; do
if [ -e "/dev/$n" ] && [ ! -e "$target/$n" ]; then
cp -a "/dev/$n" "$target/$n" 2>/dev/null || true
fi
done
for n in dri input pts shm; do
if [ -d "/dev/$n" ]; then
mkdir -p "$target/$n"
chmod 0755 "$target/$n" 2>/dev/null || true
if ! grep -q " $target/$n " /proc/mounts 2>/dev/null; then
kde_mount --bind "/dev/$n" "$target/$n" 2>/dev/null || \
kde_mount -o bind "/dev/$n" "$target/$n" 2>/dev/null || true
fi
fi
done
if [ ! -d "$target/pts" ]; then
mkdir -p "$target/pts"
kde_mount -t devpts devpts "$target/pts" 2>/dev/null || true
fi
}
for fs in dev proc sys; do
if ! bind_guest_fs "$fs"; then
if [ "$fs" = dev ]; then
log "seeding /dev into the KDE root after bind failure"
seed_dev
else
log "ERROR: could not bind /$fs into the KDE root"
exit 1
fi
fi
done
# vdb is mounted ro. Binding its /tmp or /run makes those
# directories read-only, so Xorg cannot create /tmp/.X11-unix
# and seatd cannot create /run/seatd.sock.
# BUG-XORG-SEGV 最终方案:不再让 chroot 自启 Xorg(vdb ld.so + persist
# 库组合在 ld.so 0x15ded NULL+8 segfault,即使换 ld.so/换库集都复现)。
# 改为把宿主 /tmp、/run bind 进 chroot:native 桌面的 Xorg 套接字
# /tmp/.X11-unix/X0 与 seatd.sock 直接可见,inner session 检测到
# socket 已存在就跳过自启 Xorg,Plasma 作为 X11 客户端直连活着的
# X server(-ac 无鉴权,协议层互通,与 Xorg 的加载器问题无关)。
for fs in tmp run; do
mkdir -p "$KDE_ROOT/$fs"
if kde_mount --bind "/$fs" "$KDE_ROOT/$fs"; then
log "bound host /$fs -> $KDE_ROOT/$fs"
elif kde_mount -t tmpfs tmpfs "$KDE_ROOT/$fs"; then
log "fallback tmpfs on $KDE_ROOT/$fs"
else
log "ERROR: mount $KDE_ROOT/$fs failed"
fi
done
chmod 1777 "$KDE_ROOT/tmp" 2>/dev/null || true
mkdir -p "$KDE_ROOT/tmp/.X11-unix" "$KDE_ROOT/run/user"
chmod 1777 "$KDE_ROOT/tmp/.X11-unix" 2>/dev/null || true
if [ -d /dev/pts ] && [ -d "$KDE_ROOT/dev/pts" ] && \
! grep -q " $KDE_ROOT/dev/pts " /proc/mounts 2>/dev/null; then
kde_mount --bind /dev/pts "$KDE_ROOT/dev/pts" 2>/dev/null || \
kde_mount -t devpts devpts "$KDE_ROOT/dev/pts" 2>/dev/null || true
fi
mkdir -p "$KDE_ROOT/home/$SESSION_USER/Desktop"
mkdir -p /mnt/deshab-esp
if ! grep -q ' /mnt/deshab-esp ' /proc/mounts 2>/dev/null; then
if [ -e /dev/disk/by-label/DESHABBOOT ]; then
kde_mount -t vfat -o rw,utf8,shortname=mixed \
/dev/disk/by-label/DESHABBOOT /mnt/deshab-esp 2>/dev/null || \
kde_mount -t vfat -o rw /dev/disk/by-label/DESHABBOOT /mnt/deshab-esp \
2>/dev/null || true
fi
if ! grep -q ' /mnt/deshab-esp ' /proc/mounts 2>/dev/null; then
for d in /dev/vda1 /dev/sda1 /dev/vda /dev/sda; do
[ -b "$d" ] || continue
if kde_mount -t vfat -o rw,utf8,shortname=mixed "$d" /mnt/deshab-esp 2>/dev/null; then
break
fi
done
fi
fi
if [ -d /mnt/deshab-esp/user/desktop ]; then
if ! grep -q " $KDE_ROOT/home/$SESSION_USER/Desktop " /proc/mounts 2>/dev/null; then
kde_mount --bind /mnt/deshab-esp/user/desktop \
"$KDE_ROOT/home/$SESSION_USER/Desktop" 2>/dev/null || true
fi
log "Plasma Desktop bound to ESP user/desktop"
fi
if [ ! -d "$KDE_ROOT/home/$SESSION_USER/Desktop" ] || \
[ -z "$(ls -A "$KDE_ROOT/home/$SESSION_USER/Desktop" 2>/dev/null)" ]; then
if [ -d /usr/local/share/deshab-desktop ]; then
cp -a /usr/local/share/deshab-desktop/. \
"$KDE_ROOT/home/$SESSION_USER/Desktop/" 2>/dev/null || true
elif [ -d "$KDE_ROOT/usr/local/share/deshab-desktop" ]; then
cp -a "$KDE_ROOT/usr/local/share/deshab-desktop/." \
"$KDE_ROOT/home/$SESSION_USER/Desktop/" 2>/dev/null || true
fi
log "Plasma Desktop filled from deshab-desktop copy (ESP bind unavailable)"
fi
chown -R "$SESSION_USER:$SESSION_USER" \
"$KDE_ROOT/home/$SESSION_USER/Desktop" 2>/dev/null || true
set +e
export DESHAB_KDE_USER="$SESSION_USER"
export DESHAB_KDE_SOFTWARE_RENDERING="$SOFTWARE_RENDERING"
export DISPLAY=:0
export GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK,-AVX,-AVX2,-AVX512F
# persist ld.so SIGSEGVs at NULL+8 (offset 0x15ded) on Xorg/dbus/umount.
# persist bash survived that loader; other bins did not. Bind vdb's
# interpreter over persist's so new execs match the working pre-chroot
# path (vdb ld.so + persist libraries). Do not overlay vdb libc.
VDB_LD=/lib64/ld-linux-x86-64.so.2
mkdir -p "$KDE_ROOT/usr/local/bin" "$KDE_ROOT/usr/local/lib"
if [ -n "$PERSIST_LD" ]; then
cp -f "$PERSIST_LD" "$KDE_ROOT/usr/local/lib/ld-persist.so" 2>/dev/null || true
chmod 0755 "$KDE_ROOT/usr/local/lib/ld-persist.so" 2>/dev/null || true
log "saved persist ld.so to /usr/local/lib/ld-persist.so"
fi
if [ -x /usr/local/bin/deshab-kde-session ]; then
cp -f /usr/local/bin/deshab-kde-session \
"$KDE_ROOT/usr/local/bin/deshab-kde-session" 2>/dev/null || true
chmod 0755 "$KDE_ROOT/usr/local/bin/deshab-kde-session" 2>/dev/null || true
log "copied session onto persist overlay"
fi
if [ -x /usr/local/bin/utsm_bindmount ]; then
cp -f /usr/local/bin/utsm_bindmount \
"$KDE_ROOT/usr/local/bin/utsm_bindmount" 2>/dev/null || true
chmod 0755 "$KDE_ROOT/usr/local/bin/utsm_bindmount" 2>/dev/null || true
fi
if [ -x /usr/local/bin/utsm_run ]; then
cp -f /usr/local/bin/utsm_run \
"$KDE_ROOT/usr/local/bin/utsm_run" 2>/dev/null || true
chmod 0755 "$KDE_ROOT/usr/local/bin/utsm_run" 2>/dev/null || true
fi
if [ -x /usr/local/lib/Xorg.good ]; then
if kde_mount --bind /usr/local/lib/Xorg.good "$KDE_ROOT/usr/lib/Xorg"; then
log "bound vdb Xorg.good over persist /usr/lib/Xorg"
fi
fi
if [ -d /usr/local/lib/xorg-libs ]; then
mkdir -p "$KDE_ROOT/usr/local/lib/xorg-libs"
if kde_mount --bind /usr/local/lib/xorg-libs "$KDE_ROOT/usr/local/lib/xorg-libs"; then
log "bound xorg-libs ($(ls /usr/local/lib/xorg-libs | wc -l))"
fi
fi
# plasma-libs: Qt6/KF6 等新增好库。只给 Plasma 的 ldpath 用——Xorg 的
# 加载环境保持 12:18 验证过的纯 xorg-libs 集(扩大 overlay 会让
# vdb ld.so 在加载期 segfault,见 /tmp/xorg.err 为空的 rc=139)。
if [ -d /usr/local/lib/plasma-libs ]; then
mkdir -p "$KDE_ROOT/usr/local/lib/plasma-libs"
if kde_mount --bind /usr/local/lib/plasma-libs "$KDE_ROOT/usr/local/lib/plasma-libs"; then
log "bound plasma-libs ($(ls /usr/local/lib/plasma-libs | wc -l))"
fi
fi
# BUG-XORG-SEGV 根修:persist /usr/lib 有 140 个损坏库(ld.so 解析即
# NULL+8 segfault)。repair.txt(由注入管线生成)把每个坏实体的好副
# 本 bind 到 persist 路径上,ld.so 回落解析时命中的也全是好文件。
if [ -f /usr/local/lib/xorg-libs/repair.txt ] && [ -x "$BINDMOUNT" ]; then
ok=0; fail=0
while IFS='|' read -r src dst; do
[ -z "$src" ] && continue
# bindmount 在 chroot 外执行:src/dst 都要加 $KDE_ROOT 前缀
if [ -e "$KDE_ROOT$src" ] && kde_mount --bind "$KDE_ROOT$src" "$KDE_ROOT$dst" 2>/dev/null; then
ok=$((ok + 1))
else
fail=$((fail + 1))
fi
done < /usr/local/lib/xorg-libs/repair.txt
log "persist repair binds: ok=$ok fail=$fail"
fi
if [ -f /usr/local/lib/xorg/modules/drivers/modesetting_drv.so ]; then
mkdir -p "$KDE_ROOT/usr/local/lib/xorg/modules/drivers"
if kde_mount --bind /usr/local/lib/xorg/modules \
"$KDE_ROOT/usr/local/lib/xorg/modules"; then
log "bound xorg modules"
fi
fi
# BUG-XORG-SEGV 复盘:0x15ded 崩点=persist ld.so 已知 bug;12:18 好运行
# 中 vdb-ld bind 处于激活态(umount EBUSY=未卸载)且 Xorg 存活 → bind
# 是必需的。之前"过时论"判断有误,恢复默认启用。
if [ -x "$VDB_LD" ]; then
for dest in \
"$KDE_ROOT/lib64/ld-linux-x86-64.so.2" \
"$KDE_ROOT/usr/lib/ld-linux-x86-64.so.2" \
"$KDE_ROOT/lib/ld-linux-x86-64.so.2"; do
[ -e "$dest" ] || [ -L "$dest" ] || continue
if kde_mount --bind "$VDB_LD" "$dest"; then
log "bound vdb ld.so over $dest"
elif cp -f "$VDB_LD" "$dest"; then
log "copied vdb ld.so over $dest"
fi
done
fi
# BUG-CHROOT-127: 引导期 chroot 的 persist bash 必须只用 persist 自带
# 库。宿主侧继承的 LD_LIBRARY_PATH(xorg-libs overlay)会让 chroot 内
# 加载器优先吃 overlay 库,其中部分与 persist glibc 版本错位 → bash
# 加载失败 → status 127。Xorg/Plasma 阶段会显式重新设置该变量。
log "bootstrap ldpath=${LD_LIBRARY_PATH:-unset}"
unset LD_LIBRARY_PATH
if [ -x "$KDE_ROOT/usr/bin/bash" ]; then
log "preflight persist bash"
"$BINDMOUNT" chroot "$KDE_ROOT" /usr/bin/bash -c \
'printf "[deshab-kde] persist-bash-ok\n" >/dev/kmsg' || \
log "WARNING: persist bash preflight failed"
fi
if [ -x "$BINDMOUNT" ]; then
log "chroot via utsm_bindmount bash -c"
"$BINDMOUNT" chroot "$KDE_ROOT" /usr/bin/bash -c \
'printf "[deshab-kde] inside-bash\n" >/dev/kmsg; ls -l /usr/local/bin/deshab-kde-session /usr/bin/bash /etc/deshab-kde-root /usr/bin/startplasma-x11 >/dev/kmsg 2>&1; exec /usr/local/bin/deshab-kde-session --inside'
status=$?
else
chroot "$KDE_ROOT" /usr/bin/bash \
/usr/local/bin/deshab-kde-session --inside
status=$?
fi
set -e
log "chroot session exited with status $status"
exit "$status"
fi
LOG_FILE="/var/log/deshab-kde-session.log"
set +e
touch "$LOG_FILE"
export GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK,-AVX,-AVX2,-AVX512F
export LIBSEAT_BACKEND=seatd
export XDG_SEAT=seat0
export XDG_VTNR=1
log "inside setup begin"
# Xorg 段错误取证:内核打印 fatal signal 现场(RIP 所在库+偏移),
# 早于 Plasma 阶段的同名设置——Xorg 启动在先。
echo 1 >/proc/sys/kernel/print-fatal-signals 2>/dev/null || true
if ! touch /tmp/.deshab-w 2>/dev/null; then
log "WARNING: /tmp not writable, mounting tmpfs"
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount fstype tmpfs tmpfs /tmp || true
fi
mkdir -p /tmp/.X11-unix
chmod 1777 /tmp /tmp/.X11-unix 2>/dev/null || true
fi
if ! touch /run/.deshab-w 2>/dev/null; then
log "WARNING: /run not writable, mounting tmpfs"
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount fstype tmpfs tmpfs /run || true
fi
fi
log "tmp_w=$([ -w /tmp ] && echo y || echo n) run_w=$([ -w /run ] && echo y || echo n)"
if [ "$(id -u)" -ne 0 ]; then
log "ERROR: session setup must start as root"
exit 1
fi
if ! id "$SESSION_USER" >/dev/null 2>&1; then
log "ERROR: session user does not exist: $SESSION_USER"
exit 1
fi
if [ ! -e /dev/dri/card0 ]; then
log "ERROR: /dev/dri/card0 is unavailable; leaving the fallback console intact"
exit 1
fi
if [ -w /etc ] || [ -w /etc/machine-id ]; then
dbus-uuidgen --ensure=/etc/machine-id >/tmp/dbus-uuidgen.out 2>&1 || \
log "dbus-uuidgen skipped (see /tmp/dbus-uuidgen.out)"
fi
if [ ! -s /etc/machine-id ]; then
printf '00000000000000000000000000000000\n' >/tmp/machine-id 2>/dev/null || true
if [ -w /etc ]; then
cp /tmp/machine-id /etc/machine-id 2>/dev/null || true
fi
fi
session_uid="$(id -u "$SESSION_USER")"
session_gid="$(id -g "$SESSION_USER")"
runtime_dir="/run/user/$session_uid"
install -d -m 0700 -o "$session_uid" -g "$session_gid" "$runtime_dir"
if command -v seatd >/dev/null 2>&1 && [ ! -S /run/seatd.sock ]; then
log "starting seatd for the non-systemd guest session"
seatd -g video >>"$LOG_FILE" 2>&1 &
SEATD_PID=$!
s=0
while [ ! -S /run/seatd.sock ] && [ "$s" -lt 10 ]; do
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount msleep 100
fi
s=$((s + 1))
done
fi
log "seatd_sock=$([ -S /run/seatd.sock ] && echo y || echo n) dri=$(ls /dev/dri 2>/dev/null | tr '\n' ' ')"
[ -e /dev/tty0 ] || mknod /dev/tty0 c 4 0 2>/dev/null || true
[ -e /dev/tty1 ] || mknod /dev/tty1 c 4 1 2>/dev/null || true
log "tty=$(ls -l /dev/tty0 /dev/tty1 /dev/console 2>&1 | tr '\n' ' ')"
# BUG-XORG-SEGV: 宿主 /tmp 已 bind 进 chroot(native 桌面的 Xorg 套接字
# 共享可见)。native Xorg 可能比本会话晚一点起来——等待其套接字出现,
# 出现即完全跳过 chroot 自启 Xorg(该路径在 ld.so 0x15ded 必崩)。
if [ ! -S /tmp/.X11-unix/X0 ]; then
w=0
while [ ! -S /tmp/.X11-unix/X0 ] && [ "$w" -lt 40 ]; do
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount msleep 300
fi
w=$((w + 1))
done
log "native Xorg socket wait: tries=$w found=$([ -S /tmp/.X11-unix/X0 ] && echo y || echo n)"
fi
if [ ! -S /tmp/.X11-unix/X0 ]; then
mkdir -p /tmp/.X11-unix /etc/X11
chmod 1777 /tmp /tmp/.X11-unix
if command -v Xorg >/dev/null 2>&1; then
mkdir -p /etc/X11 /tmp /tmp/deshab-xorg-empty
cat > /tmp/deshab-xorg.conf <<'XORG_EOF'
Section "Files"
ModulePath "/usr/local/lib/xorg/modules"
ModulePath "/usr/lib/xorg/modules"
EndSection
Section "ServerLayout"
Identifier "Layout0"
Screen 0 "Screen0"
EndSection
Section "ServerFlags"
Option "AutoAddDevices" "off"
Option "AutoEnableDevices" "off"
Option "AutoAddGPU" "false"
Option "AllowEmptyInput" "on"
Option "DontVTSwitch" "on"
EndSection
Section "Device"
Identifier "VirtioGPU"
Driver "modesetting"
Option "AccelMethod" "none"
Option "SWcursor" "on"
Option "kmsdev" "/dev/dri/card0"
EndSection
Section "Screen"
Identifier "Screen0"
Device "VirtioGPU"
DefaultDepth 24
SubSection "Display"
Depth 24
Modes "1024x768"
EndSubSection
EndSection
XORG_EOF
if [ -w /etc/X11 ]; then
cp /tmp/deshab-xorg.conf /etc/X11/xorg.conf 2>/dev/null || true
fi
# /usr/bin/Xorg is a 271-byte sh wrapper that execs suid Xorg.wrap.
# The wrap exits immediately in this guest. Run the real server.
# persist /usr/lib/Xorg is 2.6MB but its ELF header is smashed
# (e_entry=0, 14KB .text). Bind the known-good Arch binary from vdb.
if [ -x /usr/local/lib/Xorg.good ]; then
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount bind /usr/local/lib/Xorg.good \
/usr/lib/Xorg >/tmp/xorg.bind 2>&1 || \
cp -f /usr/local/lib/Xorg.good /usr/lib/Xorg
else
cp -f /usr/local/lib/Xorg.good /usr/lib/Xorg
fi
log "using Xorg.good over /usr/lib/Xorg"
fi
if [ -x /usr/lib/Xorg ]; then
XORG_BIN=/usr/lib/Xorg
elif [ -x /usr/lib/xorg/Xorg ]; then
XORG_BIN=/usr/lib/xorg/Xorg
else
XORG_BIN="$(command -v Xorg)"
fi
log "Xorg bin=$XORG_BIN"
log "drivers=$(ls /usr/lib/xorg/modules/drivers 2>/dev/null | tr '\n' ' ')"
rm -f /tmp/.X0-lock /tmp/.X11-unix/X0 /tmp/Xorg.0.log /tmp/xorg.er
# vdb ld.so + persist Xorg SIGSEGVs at Xorg+0 (error 15).
# Bash is already loaded; drop the vdb interpreter bind so Xorg's
# PT_INTERP is persist ld.so again. Do not exec ld.so as argv[0].
XORG_RUN="$XORG_BIN"
if [ -x /usr/local/bin/utsm_bindmount ]; then
for p in /lib64/ld-linux-x86-64.so.2 \
/usr/lib/ld-linux-x86-64.so.2 \
/lib/ld-linux-x86-64.so.2; do
/usr/local/bin/utsm_bindmount umount "$p" >/tmp/umount.ld 2>&1
log "umount $p rc=$? $(tr '\n' ' ' < /tmp/umount.ld)"
done
fi
XORG_VT=""
XORG_IN="/dev/null"
if [ -e /dev/tty1 ]; then
XORG_VT=vt1
XORG_IN=/dev/tty1
fi
export LD_LIBRARY_PATH=/usr/local/lib/xorg-libs
# 取证:ld.so 解析追踪进 stderr(/tmp/xorg.err),崩溃前最后
# 一个 "file=" 即毒库。内核 fatal-signal 转储已在会话开头打开。
export LD_DEBUG=libs
log "ldpath=$LD_LIBRARY_PATH xlibs=$(ls /usr/local/lib/xorg-libs 2>/dev/null | wc -l)"
log "starting Xorg :0 $XORG_VT bin=$XORG_RUN nsexec"
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount nsexec "$XORG_RUN" :0 $XORG_VT \
-nolisten tcp -noreset -ac -keeptty \
-novtswitch -sharevts -verbose 6 -logverbose 6 \
-config /tmp/deshab-xorg.conf \
-configdir /tmp/deshab-xorg-empty \
-logfile /tmp/Xorg.0.log \
<"$XORG_IN" >>/tmp/xorg.err 2>&1 &
else
"$XORG_RUN" :0 $XORG_VT -nolisten tcp -noreset -ac -keeptty \
-novtswitch -sharevts -verbose 6 -logverbose 6 \
-config /tmp/deshab-xorg.conf \
-configdir /tmp/deshab-xorg-empty \
-logfile /tmp/Xorg.0.log \
<"$XORG_IN" >>/tmp/xorg.err 2>&1 &
fi
XFBDEV_PID=$!
log "Xorg pid=$XFBDEV_PID"
i=0
while [ ! -S /tmp/.X11-unix/X0 ] && [ "$i" -lt 20 ]; do
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount yield
/usr/local/bin/utsm_bindmount msleep 200
fi
i=$((i + 1))
alive=n
[ -n "$XFBDEV_PID" ] && [ -d "/proc/$XFBDEV_PID" ] && alive=y
if [ "$alive" = n ] || [ $((i % 5)) -eq 0 ]; then
log "Xorg wait ${i}s socket=$([ -S /tmp/.X11-unix/X0 ] && echo y || echo n) parent=$alive"
fi
if [ "$alive" = n ] && [ "$i" -ge 2 ]; then
wait "$XFBDEV_PID" 2>/dev/null
log "Xorg parent exited rc=$?"
break
fi
done
if [ -S /tmp/.X11-unix/X0 ]; then
log "Xorg socket ready"
else
log "WARNING: Xorg socket not ready"
log "tmp=$(ls -la /tmp /tmp/.X11-unix /var/log 2>&1 | tr '\n' '|')"
dump_file /tmp/xorg.err 60
# LD_DEBUG 追踪很长,崩点在末尾——tail 60 行找最后一个 file=
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount tail /tmp/xorg.err 60 \
> /tmp/xorg.err.tail 2>/dev/null || true
while IFS= read -r line; do
log "xorg.err.tail:$line"
done < /tmp/xorg.err.tail
fi
dump_file /tmp/Xorg.0.log 60
dump_file /var/log/Xorg.0.log 40
dump_file "$LOG_FILE" 20
fi
else
log "WARNING: no Xorg/Xfbdev in KDE root"
fi
fi
if [ ! -S /tmp/.X11-unix/X0 ]; then
log "ERROR: no X11 socket; not starting Plasma"
exit 3
fi
log "selecting Plasma launcher"
PLASMA_BIN=""
if [ -x /usr/bin/startplasma-x11 ]; then
PLASMA_BIN=/usr/bin/startplasma-x11
elif command -v startplasma-x11 >/dev/null 2>&1; then
PLASMA_BIN="$(command -v startplasma-x11)"
fi
if [ -z "$PLASMA_BIN" ]; then
log "startplasma-x11 missing; Plasma Wayland will not light virtio-gpu 2D scanout"
if [ -x /usr/bin/startplasma-wayland ]; then
PLASMA_BIN=/usr/bin/startplasma-wayland
fi
fi
if [ -z "$PLASMA_BIN" ]; then
log "ERROR: no Plasma session binary is installed"
exit 1
fi
DBUS_LAUNCH=""
if [ -x /usr/lib/plasma-dbus-run-session-if-needed ]; then
DBUS_LAUNCH=/usr/lib/plasma-dbus-run-session-if-needed
elif command -v dbus-run-session >/dev/null 2>&1; then
DBUS_LAUNCH="$(command -v dbus-run-session)"
else
log "ERROR: no Plasma D-Bus session launcher is installed"
exit 1
fi
if [ "$SOFTWARE_RENDERING" -eq 1 ]; then
export LIBGL_ALWAYS_SOFTWARE=1
export GALLIUM_DRIVER=llvmpipe
export MESA_LOADER_DRIVER_OVERRIDE=llvmpipe
export QT_QUICK_BACKEND=software
log "software rendering fallback enabled (llvmpipe/lavapipe)"
fi
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
# Plasma 先吃 plasma-libs(Qt6/KF6 好库),再回退 xorg-libs 验证集与 persist。
export LD_LIBRARY_PATH="/usr/local/lib/plasma-libs:/usr/local/lib/xorg-libs${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
# The Plasma wrapper execs a bare "dbus-run-session". Call it by
# absolute path so a stripped PATH cannot turn into status 127.
# Do not ldd the closure here: that walk hangs this guest and the
# verify marker must mean the child was actually exec'd.
if [ -x /usr/bin/dbus-run-session ]; then
DBUS_LAUNCH=/usr/bin/dbus-run-session
fi
log "starting Plasma as $SESSION_USER via $PLASMA_BIN DISPLAY=:0"
log "dbus=$DBUS_LAUNCH runuser=/usr/bin/runuser"
echo 1 >/proc/sys/kernel/print-fatal-signals 2>/dev/null || true
set +e
if [ -x /usr/bin/runuser ]; then
if [ "$DBUS_LAUNCH" = "/usr/lib/plasma-dbus-run-session-if-needed" ]; then
/usr/bin/runuser --user "$SESSION_USER" -- /usr/bin/env \
-u DBUS_SESSION_BUS_ADDRESS \
HOME="/home/$SESSION_USER" \
USER="$SESSION_USER" \
LOGNAME="$SESSION_USER" \
DISPLAY=:0 \
XDG_RUNTIME_DIR="$runtime_dir" \
XDG_SESSION_TYPE=x11 \
XDG_SESSION_CLASS=user \
XDG_CURRENT_DESKTOP=KDE \
DESKTOP_SESSION=plasma \
KDE_FULL_SESSION=true \
QT_QPA_PLATFORM=xcb \
LIBSEAT_BACKEND=seatd \
LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
LD_DEBUG=files \
PATH="$PATH" \
"$DBUS_LAUNCH" -- "$PLASMA_BIN" >>/tmp/deshab-plasma.err 2>&1
else
/usr/bin/runuser --user "$SESSION_USER" -- /usr/bin/env \
-u DBUS_SESSION_BUS_ADDRESS \
HOME="/home/$SESSION_USER" \
USER="$SESSION_USER" \
LOGNAME="$SESSION_USER" \
DISPLAY=:0 \
XDG_RUNTIME_DIR="$runtime_dir" \
XDG_SESSION_TYPE=x11 \
XDG_SESSION_CLASS=user \
XDG_CURRENT_DESKTOP=KDE \
DESKTOP_SESSION=plasma \
KDE_FULL_SESSION=true \
QT_QPA_PLATFORM=xcb \
LIBSEAT_BACKEND=seatd \
LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
LD_DEBUG=files \
PATH="$PATH" \
"$DBUS_LAUNCH" -- "$PLASMA_BIN" >>/tmp/deshab-plasma.err 2>&1
fi
else
log "runuser missing; starting Plasma as root so scanout can proceed"
if [ "$DBUS_LAUNCH" = "/usr/lib/plasma-dbus-run-session-if-needed" ]; then
/usr/bin/env \
-u DBUS_SESSION_BUS_ADDRESS \
HOME=/root \
USER=root \
DISPLAY=:0 \
XDG_RUNTIME_DIR="$runtime_dir" \
XDG_SESSION_TYPE=x11 \
XDG_CURRENT_DESKTOP=KDE \
QT_QPA_PLATFORM=xcb \
LIBSEAT_BACKEND=seatd \
LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
LD_DEBUG=files \
PATH="$PATH" \
"$DBUS_LAUNCH" -- "$PLASMA_BIN" >>/tmp/deshab-plasma.err 2>&1
else
/usr/bin/env \
-u DBUS_SESSION_BUS_ADDRESS \
HOME=/root \
USER=root \
DISPLAY=:0 \
XDG_RUNTIME_DIR="$runtime_dir" \
XDG_SESSION_TYPE=x11 \
XDG_CURRENT_DESKTOP=KDE \
QT_QPA_PLATFORM=xcb \
LIBSEAT_BACKEND=seatd \
LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
LD_DEBUG=files \
PATH="$PATH" \
"$DBUS_LAUNCH" -- "$PLASMA_BIN" >>/tmp/deshab-plasma.err 2>&1
fi
fi
status=$?
set -e
if [ "$status" -ne 0 ]; then
log "Plasma failed with status $status sig=$((status > 128 ? status - 128 : 0))"
dump_file /tmp/deshab-plasma.err 8
# The head only shows dbus-run-session warmup. The crash site is at
# the END of the LD_DEBUG stream; dump the tail so kmsg shows which
# library/binary was being loaded when the signal hit.
if [ -x /usr/local/bin/utsm_bindmount ]; then
/usr/local/bin/utsm_bindmount tail /tmp/deshab-plasma.err 200 \
> /tmp/deshab-plasma-tail.txt 2>/dev/null || true
while IFS= read -r line; do
log "plasma-tail:$line"
done < /tmp/deshab-plasma-tail.txt
/usr/local/bin/utsm_bindmount tail /tmp/Xorg.0.log 80 > /tmp/deshab-xorg-tail.txt 2>/dev/null || true
/usr/local/bin/utsm_bindmount tail /tmp/xorg.err 20 > /tmp/deshab-xorg-err.txt 2>/dev/null || true
grep -E '\(EE\)|\(WW\)|Fatal|error|failed|Failed' /tmp/deshab-xorg-tail.txt /tmp/deshab-xorg-err.txt 2>/dev/null | head -n 12 | while IFS= read -r line; do
log "xorg: $line"
done
fi
dmesg 2>/dev/null | tail -n 40 > /tmp/deshab-dmesg.txt || true
grep -E 'segfault|Bus error|bus error|traps:|EXT4-fs|invalid ELF' /tmp/deshab-dmesg.txt 2>/dev/null | head -n 8 | while IFS= read -r line; do
log "dmesg: $line"
done
else
log "Plasma session ended normally"
fi
exit "$status"
+17
View File
@@ -0,0 +1,17 @@
#!/bin/sh
# Return to the Deshab native desktop. Optional first argument is the
# native app name (editor/fileman/browser/shell) for the host to launch.
# Host polls /tmp/deshab-native (bind-mounted into the KDE chroot).
APP="${1:-}"
if [ -n "$APP" ]; then
printf '%s\n' "$APP" > /tmp/deshab-native-app
else
rm -f /tmp/deshab-native-app
fi
touch /tmp/deshab-native
if command -v pkill >/dev/null 2>&1; then
pkill -f startplasma >/dev/null 2>&1 || true
pkill -f plasmashell >/dev/null 2>&1 || true
pkill -f kwin >/dev/null 2>&1 || true
fi
exit 0
+278
View File
@@ -0,0 +1,278 @@
/*
* Static mount(2) helper. Guest vdb util-linux/mount is unreadable
* (runtime ext4 checksum) and persist ld.so hits SHSTK (fault at 0).
* Built the same way as utsm_exec_daemon, which already runs in-guest.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <string.h>
#include <sys/mount.h>
#include <time.h>
#include <unistd.h>
static void wstr(const char *s)
{
(void)write(2, s, strlen(s));
}
static int do_mount(const char *src, const char *tgt,
const char *fstype, unsigned long flags, const void *data)
{
if (mount(src, tgt, fstype, flags, data) == 0)
return 0;
wstr("utsm_bindmount errno=");
if (errno >= 10) {
char d[2];
d[0] = (char)('0' + (errno / 10));
d[1] = (char)('0' + (errno % 10));
(void)write(2, d, 2);
} else {
char d = (char)('0' + errno);
(void)write(2, &d, 1);
}
wstr("\n");
return 1;
}
int main(int argc, char **argv)
{
if (argc < 3) {
wstr("usage: utsm_bindmount bind|rbind|slave|fstype|msleep|yield|setinterp|umount|nsexec ...\n");
return 2;
}
if (strcmp(argv[1], "bind") == 0 && argc >= 4)
return do_mount(argv[2], argv[3], NULL, MS_BIND, NULL);
if (strcmp(argv[1], "rbind") == 0 && argc >= 4)
return do_mount(argv[2], argv[3], NULL, MS_BIND | MS_REC, NULL);
if (strcmp(argv[1], "slave") == 0 && argc >= 3)
return do_mount(NULL, argv[2], NULL, MS_SLAVE, NULL);
if (strcmp(argv[1], "fstype") == 0 && argc >= 5)
return do_mount(argv[3], argv[4], argv[2], 0,
(argc >= 6) ? argv[5] : NULL);
if (strcmp(argv[1], "yield") == 0) {
sched_yield();
return 0;
}
if (strcmp(argv[1], "tail") == 0 && argc >= 3) {
int fd, maxlines = 40, lines = 0, i;
off_t sz, start;
static char buf[16384];
ssize_t n;
if (argc >= 4) {
const char *p = argv[3];
maxlines = 0;
while (*p >= '0' && *p <= '9') {
maxlines = maxlines * 10 + (*p - '0');
p++;
}
if (maxlines < 1)
maxlines = 40;
}
fd = open(argv[2], O_RDONLY);
if (fd < 0)
return 1;
sz = lseek(fd, 0, SEEK_END);
if (sz < 0)
sz = 0;
start = (sz > (off_t)sizeof(buf)) ? sz - (off_t)sizeof(buf) : 0;
if (lseek(fd, start, SEEK_SET) < 0)
start = 0;
n = read(fd, buf, sizeof(buf));
close(fd);
if (n <= 0)
return 1;
for (i = (int)n - 1; i >= 0; i--) {
if (buf[i] == '\n')
lines++;
if (lines > maxlines) {
i++;
break;
}
}
if (i < 0)
i = 0;
(void)write(1, buf + i, (size_t)(n - i));
return 0;
}
if (strcmp(argv[1], "msleep") == 0 && argc >= 3) {
unsigned long ms = 0;
const char *p = argv[2];
struct timespec ts;
while (*p >= '0' && *p <= '9') {
ms = ms * 10ul + (unsigned long)(*p - '0');
p++;
}
ts.tv_sec = (time_t)(ms / 1000ul);
ts.tv_nsec = (long)(ms % 1000ul) * 1000000L;
(void)nanosleep(&ts, 0);
return 0;
}
if (strcmp(argv[1], "chroot") == 0 && argc >= 4) {
int kfd;
if (chroot(argv[2]) != 0) {
wstr("utsm_bindmount: chroot failed\n");
return 1;
}
if (chdir("/") != 0) {
wstr("utsm_bindmount: chdir / failed\n");
return 1;
}
kfd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
if (kfd >= 0) {
const char *m = "[utsm_bindmount] inside chroot, exec next\n";
(void)write(kfd, m, strlen(m));
close(kfd);
}
execv(argv[3], argv + 3);
wstr("utsm_bindmount: exec after chroot failed path=");
wstr(argv[3]);
wstr(" errno=");
if (errno >= 10) {
char d[2];
d[0] = (char)('0' + (errno / 10));
d[1] = (char)('0' + (errno % 10));
(void)write(2, d, 2);
} else {
char d = (char)('0' + errno);
(void)write(2, &d, 1);
}
wstr("\n");
return 127;
}
if (strcmp(argv[1], "nsexec") == 0 && argc >= 3) {
int kfd;
int u1, u2, u3, pr;
kfd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
if (unshare(CLONE_NEWNS) != 0) {
wstr("nsexec: unshare failed\n");
if (kfd >= 0) {
const char *m = "[nsexec] unshare failed\n";
(void)write(kfd, m, strlen(m));
close(kfd);
}
return 1;
}
pr = mount((const char *)0, "/", (const char *)0,
MS_REC | MS_PRIVATE, (const void *)0);
if (pr != 0) {
pr = mount((const char *)0, "/", (const char *)0,
MS_REC | MS_SLAVE, (const void *)0);
}
/* BUG-XORG-SEGV 根修(2026-09-20):此处 umount 会把 chroot 里的
* vdb ld.so bind 拆掉,Xorg 落回 persist ld.so —— 其 0x15ded 处
* NULL+8 segfault(Xorg/dbus 均复现)。12:18 好运行中这些 bind
* 全部保持激活(shell umount 均 EBUSY),Xorg 用 vdb ld.so 存活。
* 恢复该行为:nsexec 不再卸载 ld.so bind。 */
u1 = -1;
u2 = -1;
u3 = -1;
if (kfd >= 0) {
const char *m = "[nsexec] umount done, exec Xorg\n";
(void)write(kfd, m, strlen(m));
if (u1 == 0)
m = "[nsexec] umount lib64 ld.so ok\n";
else
m = "[nsexec] umount lib64 ld.so FAIL\n";
(void)write(kfd, m, strlen(m));
if (u2 == 0)
m = "[nsexec] umount usr/lib ld.so ok\n";
else
m = "[nsexec] umount usr/lib ld.so FAIL\n";
(void)write(kfd, m, strlen(m));
(void)pr;
(void)u3;
close(kfd);
}
execv(argv[2], argv + 2);
wstr("nsexec: exec failed\n");
return 127;
}
if (strcmp(argv[1], "umount") == 0 && argc >= 3) {
if (umount(argv[2]) == 0)
return 0;
wstr("umount errno=");
if (errno >= 10) {
char d[2];
d[0] = (char)('0' + (errno / 10));
d[1] = (char)('0' + (errno % 10));
(void)write(2, d, 2);
} else {
char d = (char)('0' + errno);
(void)write(2, &d, 1);
}
wstr("\n");
return 1;
}
if (strcmp(argv[1], "setinterp") == 0 && argc >= 4) {
int fd;
unsigned char eh[64];
unsigned long phoff = 0, nlen;
unsigned short phentsize = 0, phnum = 0, i;
const char *ni = argv[3];
nlen = strlen(ni) + 1;
fd = open(argv[2], O_RDWR);
if (fd < 0) {
wstr("setinterp: open failed\n");
return 1;
}
if (read(fd, eh, 64) != 64 || eh[0] != 0x7f || eh[4] != 2) {
wstr("setinterp: not elf64\n");
close(fd);
return 1;
}
memcpy(&phoff, eh + 32, 8);
memcpy(&phentsize, eh + 54, 2);
memcpy(&phnum, eh + 56, 2);
for (i = 0; i < phnum; i++) {
unsigned char ph[56];
unsigned int type = 0;
unsigned long off = 0, filesz = 0;
if (lseek(fd, (off_t)(phoff + (unsigned long)i * phentsize),
SEEK_SET) < 0)
break;
if (read(fd, ph, 56) != 56)
break;
memcpy(&type, ph, 4);
if (type != 3)
continue;
memcpy(&off, ph + 8, 8);
memcpy(&filesz, ph + 32, 8);
if (nlen > filesz) {
wstr("setinterp: path too long\n");
close(fd);
return 1;
}
if (lseek(fd, (off_t)off, SEEK_SET) < 0) {
close(fd);
return 1;
}
if (write(fd, ni, nlen) != (ssize_t)nlen) {
close(fd);
return 1;
}
if (filesz > nlen) {
unsigned char z[32];
unsigned long pad = filesz - nlen;
memset(z, 0, sizeof z);
while (pad) {
unsigned long c = pad > sizeof z ? sizeof z : pad;
if (write(fd, z, c) != (ssize_t)c) {
close(fd);
return 1;
}
pad -= c;
}
}
close(fd);
wstr("setinterp: ok\n");
return 0;
}
wstr("setinterp: no PT_INTERP\n");
close(fd);
return 1;
}
wstr("utsm_bindmount: bad args\n");
return 2;
}
+76 -4
View File
@@ -29,6 +29,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <sched.h>
#include <poll.h>
/* Shared IPC protocol — must match UTSM side */
#include "../../../utsm-ipc/ipc_proto.h"
@@ -57,6 +59,7 @@ struct utsm_ioctl_pool {
};
static int g_utsm_fd = -1;
static volatile sig_atomic_t g_async_live;
/* pool_write 定义在文件传输段(下文),exec 同步路径复用同一通道 */
static int pool_write(unsigned int offset, const void *buf, unsigned int len);
@@ -129,6 +132,48 @@ static void err_write(const char *s, unsigned int len)
(void)n;
}
static void kmsg_write(const char *s)
{
int fd;
if (!s) return;
fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
if (fd < 0) return;
(void)write(fd, s, strlen(s));
close(fd);
}
static int path_needs_deshab_libs(const char *path)
{
if (!path || !path[0])
return 0;
if (strstr(path, "deshab-kde-session"))
return 0;
if (strstr(path, "/bin/sh") || strstr(path, "/bin/bash") ||
strstr(path, "/usr/bin/bash") || strstr(path, "/usr/bin/env"))
return 0;
return 1;
}
/* Nested TSC is often marked unstable, so usleep() returns immediately
* and async children never run on the only vCPU. A yield loop also
* starves D-state I/O: PID 1 stays runnable and idle never runs.
* poll(POLLIN, 10ms) on /dev/utsm sleeps interruptibly so Plasma/session
* and virtio completions can run. Driver poll does not wait-queue, so
* a new EXEC_REQUEST is seen at the next timeout. */
static void donate_cpu(void)
{
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = g_utsm_fd;
pfd.events = POLLIN;
if (poll(&pfd, 1, 10) < 0) {
unsigned i;
for (i = 0; i < 64u; i++)
sched_yield();
}
}
/* ===== Exec request handler =====
*
* Fork a child to exec the requested program. Parent reads stdout/stderr
@@ -178,6 +223,7 @@ static void handle_exec_request(const struct ipc_exec_request *req)
return;
}
if (pid == 0) {
char line[192];
/* Child: new session, no controlling tty, stdio → /dev/null */
setsid();
int nullfd = open("/dev/null", O_RDWR);
@@ -187,13 +233,29 @@ static void handle_exec_request(const struct ipc_exec_request *req)
dup2(nullfd, STDERR_FILENO);
if (nullfd > STDERR_FILENO) close(nullfd);
}
/* 与同步路径一致的库搜索路径;DISPLAY 指向 virtio-gpu X server */
setenv("LD_LIBRARY_PATH", "/usr/lib/deshab", 1);
/* DISPLAY 指向 virtio-gpu X server。不要把 LD_LIBRARY_PATH
* 套到 bash/session:/usr/lib/deshab 会劫持 glibc。 */
if (path_needs_deshab_libs(req->path))
setenv("LD_LIBRARY_PATH", "/usr/lib/deshab", 1);
setenv("DISPLAY", ":0", 1);
snprintf(line, sizeof(line),
"[deshab-kde] async exec %s\n", req->path);
kmsg_write(line);
execv(req->path, argv);
snprintf(line, sizeof(line),
"[deshab-kde] execv failed errno=%d path=%s\n",
errno, req->path);
kmsg_write(line);
_exit(127); /* execv 仅失败时返回 */
}
/* Parent: report successful spawn immediately */
g_async_live = 1;
{
char line[128];
snprintf(line, sizeof(line),
"[deshab-kde] async spawn pid=%d\n", (int)pid);
kmsg_write(line);
}
struct ipc_exec_exit ex = { .exit_code = 0, .flags = 0,
.stdout_len = 0, .stdout_total = 0 };
send_exit_msg(&ex);
@@ -227,8 +289,8 @@ static void handle_exec_request(const struct ipc_exec_request *req)
dup2(pipefd[1], STDERR_FILENO);
close(pipefd[1]);
/* 设置 LD_LIBRARY_PATH,让 ld-linux.so 在 /usr/lib/deshab 查找 .so */
setenv("LD_LIBRARY_PATH", "/usr/lib/deshab", 1);
if (path_needs_deshab_libs(req->path))
setenv("LD_LIBRARY_PATH", "/usr/lib/deshab", 1);
execv(req->path, argv);
/* execv only returns on failure */
@@ -589,6 +651,16 @@ int main(void)
/* Ignore other message types (HELLO, PING, etc.) */
}
/* Single vCPU: PARK/HLT freezes the whole VM, including async
* children and in-flight virtio-blk. Yields return immediately
* when the child is in D-state, so a yield-then-HLT loop parks
* before the virtio IRQ can be injected. Stay runnable; the
* host returns from linux_resume() on a preemption timeslice. */
if (g_async_live) {
donate_cpu();
continue;
}
/* Responses (if any) are already queued. Park to let UTSM read
* them and return to the shell; a spurious wakeup with no
* request simply parks again. */
+116
View File
@@ -0,0 +1,116 @@
/*
* Shebang trampoline: run a script with persist bash + persist glibc.
* vdb /usr/bin/bash needs libreadline, and virtio often returns a bad
* ext4 inode checksum for that file. persist userland is on vdc.
*
* Built like utsm_exec_daemon: -static -fcf-protection=none.
*/
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern char **environ;
static void kmsg(const char *s)
{
int fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
if (fd < 0)
return;
(void)write(fd, s, strlen(s));
close(fd);
}
static int exists(const char *p)
{
return p && access(p, X_OK) == 0;
}
int main(int argc, char **argv)
{
static const char *ld_cands[] = {
"/mnt/persist/usr/lib/ld-linux-x86-64.so.2",
"/mnt/persist/lib64/ld-linux-x86-64.so.2",
"/mnt/persist/lib/ld-linux-x86-64.so.2",
0
};
static const char *bash_cands[] = {
"/mnt/persist/usr/bin/bash",
"/mnt/persist/bin/bash",
0
};
const char *libpath =
"/mnt/persist/usr/lib:/mnt/persist/lib64:/mnt/persist/lib";
const char *path =
"/mnt/persist/usr/bin:/mnt/persist/bin:/usr/local/bin:/usr/bin:/bin";
const char *ld = 0;
const char *bash = 0;
char *nargv[64];
int n = 0;
int i;
char line[192];
kmsg("[utsm_run] start\n");
if (argc < 2) {
kmsg("[utsm_run] usage: utsm_run script [args]\n");
return 2;
}
/* Already inside persist chroot: /mnt/persist is gone, bash is local. */
if (access("/etc/deshab-kde-root", F_OK) == 0 ||
access("/mnt/persist/usr/bin/bash", X_OK) != 0) {
kmsg("[utsm_run] inside persist, exec /usr/bin/bash\n");
nargv[n++] = "/usr/bin/bash";
for (i = 1; i < argc && n < 62; i++)
nargv[n++] = argv[i];
nargv[n] = 0;
execv("/usr/bin/bash", nargv);
kmsg("[utsm_run] inside bash execv failed\n");
return 127;
}
setenv("PATH", path, 1);
setenv("LD_LIBRARY_PATH", libpath, 1);
setenv("GLIBC_TUNABLES", "glibc.cpu.hwcaps=-IBT,-SHSTK", 1);
for (i = 0; ld_cands[i]; i++) {
if (exists(ld_cands[i])) {
ld = ld_cands[i];
break;
}
}
for (i = 0; bash_cands[i]; i++) {
if (exists(bash_cands[i])) {
bash = bash_cands[i];
break;
}
}
/* persist ld.so (as program or as PT_INTERP) SIGSEGVs at -40 in
* _dl_find_dso_for_object. Use vdb's RAM-backed interpreter with
* persist libraries via LD_LIBRARY_PATH. */
(void)ld;
if (bash) {
snprintf(line, sizeof(line), "[utsm_run] persist bash %s\n", bash);
kmsg(line);
nargv[n++] = (char *)bash;
for (i = 1; i < argc && n < 62; i++)
nargv[n++] = argv[i];
nargv[n] = 0;
execve(bash, nargv, environ);
kmsg("[utsm_run] persist bash execve failed\n");
}
kmsg("[utsm_run] fallback /usr/bin/bash\n");
n = 0;
nargv[n++] = "/usr/bin/bash";
for (i = 1; i < argc && n < 62; i++)
nargv[n++] = argv[i];
nargv[n] = 0;
execv("/usr/bin/bash", nargv);
kmsg("[utsm_run] fallback execv failed\n");
return 127;
}
+95 -44
View File
@@ -4,7 +4,7 @@
#
# Boot sequence (phase 2 — Arch rootfs via virtio-blk /dev/vdb):
# 1. Mount essential filesystems (proc/sys/dev)
# 2. Wait for /dev/vdb (Arch rootfs virtio-blk device) to appear
# 2. Wait for /dev/vdb (Arch rootfs virtio-blk device) to appea
# 3. Mount /dev/vdb as ext4 at /mnt/root
# 4. Copy /dev nodes + daemon (already baked into rootfs) into /mnt/root
# 5. switch_root /mnt/root /sbin/init
@@ -21,23 +21,30 @@
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# Kernel printk is on ttyS0. Also write to kmsg so lines survive
# interleaving with guest printk (userspace /dev/console is racy).
klog() {
echo "$1"
echo "$1" >/dev/kmsg 2>/dev/null || true
}
# Mount essential filesystems
mount -t proc none /proc 2>/dev/null
mount -t sysfs none /sys 2>/dev/null
mount -t devtmpfs none /dev 2>/dev/null
echo "[utsm-linux] init started"
echo "[utsm-linux] kernel: $(uname -r)"
klog "[utsm-linux] init started"
klog "[utsm-linux] kernel: $(uname -r)"
# Verify /dev/utsm exists (driver is built-in, should be auto-created)
if [ ! -e /dev/utsm ]; then
echo "[utsm-linux] WARNING: /dev/utsm not found — UTSM driver not loaded"
klog "[utsm-linux] WARNING: /dev/utsm not found — UTSM driver not loaded"
fi
# ===== Phase 2: switch_root to Arch rootfs on /dev/vdb =====
# The rootfs is exposed as a memory-backed virtio-blk device (GPA 0xF4002000,
# IRQ7). Wait up to ~5s for the kernel to discover it via devtmpfs.
echo "[utsm-linux] waiting for /dev/vdb (Arch rootfs)..."
klog "[utsm-linux] waiting for /dev/vdb (Arch rootfs)..."
VDB_OK=0
i=0
while [ $i -lt 50 ]; do
@@ -51,61 +58,105 @@ while [ $i -lt 50 ]; do
done
if [ $VDB_OK -eq 1 ]; then
echo "[utsm-linux] /dev/vdb found, attempting ext4 mount..."
klog "[utsm-linux] /dev/vdb found, attempting ext4 mount..."
mkdir -p /mnt/root
# Try ext4 (preferred); fall back to ext2 if ext4 module absent.
if mount -t ext4 -o ro /dev/vdb /mnt/root 2>/dev/null || \
mount -t ext2 -o ro /dev/vdb /mnt/root 2>/dev/null; then
echo "[utsm-linux] rootfs mounted, verifying /sbin/init..."
if [ -x /mnt/root/sbin/init ]; then
echo "[utsm-linux] switch_root → Arch /sbin/init"
# Move dev/proc/sys into new root so the Arch init can re-mount them.
klog "[utsm-linux] rootfs mounted, verifying init..."
# systemd (Arch /sbin/init) SIGSEGV'd in glibc in this VMM
# (noapic/nosmp/hidden XSAVE). PID 1 must be the exec daemon so
# the host can still EXEC_REQUEST startplasma from extra-rootfs.
GUEST_INIT=""
if [ -x /mnt/root/usr/local/bin/utsm_exec_daemon ]; then
GUEST_INIT=/usr/local/bin/utsm_exec_daemon
elif [ -x /mnt/root/sbin/init ]; then
GUEST_INIT=/sbin/init
fi
if [ -n "$GUEST_INIT" ]; then
klog "[utsm-linux] switch_root → $GUEST_INIT"
# Mount /dev/vdc BEFORE moving /dev away. After mount --move,
# initramfs /dev is empty and [ -b /dev/vdc ] is always false.
j=0
while [ $j -lt 30 ] && [ ! -b /dev/vdc ]; do
sleep 0.1
j=$((j + 1))
done
if [ -b /dev/vdc ]; then
klog "[utsm-linux] /dev/vdc found, mounting persist read-only..."
# Never remount vdb/vdc rw: virtio writes dirty ext4 and
# later iget checksums fail (libreadline/grep/mkdir).
# /mnt exists on the Arch image; tmpfs covers it without rw.
# Persist looks writable via overlay+tmpfs upper so Xorg can
# write /etc/X11 and /var/log without touching vdc.
mkdir -p /mnt/persist
if [ -d /mnt/root/mnt ]; then
mount -t tmpfs -o mode=755,size=64m tmpfs /mnt/root/mnt
fi
mkdir -p /mnt/root/mnt/persist-ro \
/mnt/root/mnt/persist \
/mnt/root/mnt/persist-ov
if mount -t ext4 -o ro,noload /dev/vdc /mnt/root/mnt/persist-ro || \
mount -t ext2 -o ro /dev/vdc /mnt/root/mnt/persist-ro; then
klog "[utsm-linux] /dev/vdc mounted ro at persist-ro"
mount -t tmpfs -o mode=755,size=512m tmpfs \
/mnt/root/mnt/persist-ov
mkdir -p /mnt/root/mnt/persist-ov/upper \
/mnt/root/mnt/persist-ov/work
modprobe overlay 2>/dev/null
if mount -t overlay overlay \
-o lowerdir=/mnt/root/mnt/persist-ro,upperdir=/mnt/root/mnt/persist-ov/upper,workdir=/mnt/root/mnt/persist-ov/work \
/mnt/root/mnt/persist; then
klog "[utsm-linux] persist overlay rw (tmpfs upper, vdc still ro)"
else
mount -o bind /mnt/root/mnt/persist-ro \
/mnt/root/mnt/persist 2>/dev/null || \
mount --bind /mnt/root/mnt/persist-ro \
/mnt/root/mnt/persist 2>/dev/null || true
klog "[utsm-linux] persist overlay failed; bound persist-ro"
fi
if ! mount -o bind /mnt/root/mnt/persist /mnt/persist; then
mount --bind /mnt/root/mnt/persist /mnt/persist 2>/dev/null || true
fi
for d in opt home root; do
mkdir -p /mnt/root/mnt/persist-ov/$d/upper \
/mnt/root/mnt/persist-ov/$d/work \
/mnt/root/$d
if mount -t overlay overlay \
-o lowerdir=/mnt/root/$d,upperdir=/mnt/root/mnt/persist-ov/$d/upper,workdir=/mnt/root/mnt/persist-ov/$d/work \
/mnt/root/$d 2>/dev/null; then
klog "[utsm-linux] overlay: /$d rw (tmpfs)"
fi
done
if [ -x /mnt/root/mnt/persist/usr/bin/startplasma-x11 ]; then
klog "[utsm-linux] startplasma-x11 present on persist"
else
klog "[utsm-linux] WARNING: startplasma-x11 missing on persist"
fi
else
klog "[utsm-linux] WARNING: /dev/vdc mount failed (no persistence)"
fi
else
klog "[utsm-linux] WARNING: /dev/vdc missing"
fi
mount --move /dev /mnt/root/dev 2>/dev/null
mount --move /proc /mnt/root/proc 2>/dev/null
mount --move /sys /mnt/root/sys 2>/dev/null
# ===== VSCode Phase 4: overlay 持久化(/dev/vdc extra-rootfs 可写卷)=====
# rootfs 以 ro 挂载;/opt(VSCode 安装位置)、/home、/root 通过
# overlayfs 获得可写层,upperdir/workdir 落在 /dev/vdc(virtio-blk
# slot6 可写后端,内容跨启动持久)。vdc 缺失时保持 ro,安全降级。
if [ -b /dev/vdc ]; then
echo "[utsm-linux] /dev/vdc found, setting up overlay persistence..."
modprobe overlay 2>/dev/null
mkdir -p /mnt/persist
if mount -t ext4 -o rw /dev/vdc /mnt/persist 2>/dev/null; then
for d in opt home root; do
mkdir -p /mnt/persist/overlay/$d/upper \
/mnt/persist/overlay/$d/work \
/mnt/root/$d
if mount -t overlay overlay \
-o lowerdir=/mnt/root/$d,upperdir=/mnt/persist/overlay/$d/upper,workdir=/mnt/persist/overlay/$d/work \
/mnt/root/$d 2>/dev/null; then
echo "[utsm-linux] overlay: /$d rw (persist)"
else
echo "[utsm-linux] WARNING: overlay /$d failed (stays ro)"
fi
done
# persist 卷搬进新 root,switch_root 后可在 /mnt/persist 访问
mkdir -p /mnt/root/mnt/persist
mount --move /mnt/persist /mnt/root/mnt/persist 2>/dev/null
else
echo "[utsm-linux] WARNING: /dev/vdc mount failed (no persistence)"
fi
fi
exec switch_root /mnt/root /sbin/init
exec switch_root /mnt/root "$GUEST_INIT"
# switch_root does not return
else
echo "[utsm-linux] WARNING: /mnt/root/sbin/init missing, not switching"
klog "[utsm-linux] WARNING: no daemon or /sbin/init on rootfs"
umount /mnt/root 2>/dev/null
fi
else
echo "[utsm-linux] WARNING: ext4/ext2 mount of /dev/vdb failed"
echo "[utsm-linux] available block devices:"
klog "[utsm-linux] WARNING: ext4/ext2 mount of /dev/vdb failed"
klog "[utsm-linux] available block devices:"
ls -l /dev/vd* /dev/sd* 2>/dev/null
fi
else
echo "[utsm-linux] /dev/vdb not found after 5s — phase-1 fallback"
klog "[utsm-linux] /dev/vdb not found after 5s — phase-1 fallback"
fi
# ===== Fallback: daemon directly from initramfs (phase 1) =====
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
BB="$ROOT/CODE/linux/.cache/busybox"
mkdir -p "$ROOT/CODE/linux/.cache"
if [ ! -x "$BB" ]; then
echo "[bb] downloading busybox"
if ! wget -q -O "$BB" \
https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox; then
echo "[bb] extract from initrd"
XT=$(mktemp -d)
(cd "$XT" && cpio -id < "$ROOT/SYSTEM/boot/linux-initrd.img" >/dev/null 2>&1) || true
if [ -x "$XT/bin/busybox" ]; then
cp "$XT/bin/busybox" "$BB"
fi
rm -rf "$XT"
fi
chmod +x "$BB"
fi
ls -l "$BB"
sed -i 's/\r$//' \
"$ROOT/CODE/linux/patch_boot_on_img.sh" \
"$ROOT/CODE/linux/guest/deshab-kde-session"
bash "$ROOT/CODE/linux/patch_boot_on_img.sh"
echo PATCH_BOOT_OK
+67
View File
@@ -0,0 +1,67 @@
#!/bin/bash
#
# Install Arch distro CPython + hello.py into an existing guest root tree.
# Prefer a native-disk staging directory (not /mnt/d).
#
# Usage (as root):
# bash CODE/linux/install_guest_python.sh
# ROOTFS=/root/arch_rootfs_work/rootfs bash CODE/linux/install_guest_python.sh
# ROOTFS=/root/extra_rootfs_work/mnt bash CODE/linux/install_guest_python.sh
set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
ROOTFS="${ROOTFS:-/root/arch_rootfs_work/rootfs}"
HELLO_SRC="$PROJECT_ROOT/SYSTEM/user/python/hello.py"
if [ "$(id -u)" -ne 0 ]; then
echo "[guest-python] ERROR: must run as root" >&2
exit 1
fi
if [ ! -x "$ROOTFS/usr/bin/pacman" ] && [ ! -x "$ROOTFS/bin/pacman" ]; then
echo "[guest-python] ERROR: $ROOTFS is not an Arch root (no pacman)" >&2
exit 1
fi
# uutils mkdir (Ubuntu WSL) can error "Already exists" on -p; ignore that.
ensure_dir() {
[ -d "$1" ] && return 0
/usr/bin/mkdir -p "$1" 2>/dev/null || true
[ -d "$1" ]
}
ensure_dir "$ROOTFS/dev"
ensure_dir "$ROOTFS/proc"
ensure_dir "$ROOTFS/sys"
ensure_dir "$ROOTFS/tmp"
# Deshab staging rootfs often symlinks /var/lib/pacman -> /tmp/pacman/lib.
ensure_dir "$ROOTFS/tmp/pacman/lib/sync"
ensure_dir "$ROOTFS/tmp/pacman/cache/pkg"
# Arch dropped [community]; leftover configs 404 on every -Sy.
if [ -f "$ROOTFS/etc/pacman.conf" ]; then
/usr/bin/sed -i '/^\[community\]/,/^$/d' "$ROOTFS/etc/pacman.conf" || true
fi
printf 'nameserver 1.1.1.1\n' > "$ROOTFS/tmp/resolv.conf"
printf 'nameserver 1.1.1.1\n' > "$ROOTFS/etc/resolv.conf"
/bin/mount --bind /dev "$ROOTFS/dev" 2>/dev/null || true
/bin/mount --bind /proc "$ROOTFS/proc" 2>/dev/null || true
/bin/mount --bind /sys "$ROOTFS/sys" 2>/dev/null || true
cleanup() {
set +e
umount "$ROOTFS/dev" 2>/dev/null || true
umount "$ROOTFS/proc" 2>/dev/null || true
umount "$ROOTFS/sys" 2>/dev/null || true
}
trap cleanup EXIT INT TERM
chroot "$ROOTFS" /usr/bin/pacman -Sy --noconfirm
# Staging trees often already contain overlapping bootstrap files.
chroot "$ROOTFS" /usr/bin/pacman -S --noconfirm --needed --overwrite '*' python
/bin/mkdir -p "$ROOTFS/usr/local/share/deshab/python"
if [ -f "$HELLO_SRC" ]; then
install -m 0644 "$HELLO_SRC" "$ROOTFS/usr/local/share/deshab/python/hello.py"
fi
echo "[guest-python] $(chroot "$ROOTFS" /usr/bin/python3 --version)"
echo "[guest-python] hello.py -> $ROOTFS/usr/local/share/deshab/python/hello.py"
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Install Xorg into the Arch extra-rootfs so startplasma-x11 has a server.
set -Eeuo pipefail
IMG="${1:-/mnt/d/Code/DEAICUP/Deshab/SYSTEM/boot/linux-extra-rootfs.img}"
M=$(mktemp -d)
mount -o loop "$IMG" "$M"
cleanup() {
set +e
umount "$M/dev" 2>/dev/null || true
umount "$M/proc" 2>/dev/null || true
umount "$M/sys" 2>/dev/null || true
umount "$M" 2>/dev/null || true
rmdir "$M" 2>/dev/null || true
}
trap cleanup EXIT
mount --bind /dev "$M/dev"
mount -t proc proc "$M/proc"
mount -t sysfs sys "$M/sys"
if [[ -f /etc/resolv.conf ]]; then
mkdir -p "$M/etc"
cp -L /etc/resolv.conf "$M/etc/resolv.conf" || true
fi
if [[ -x "$M/usr/bin/Xorg" ]]; then
echo "[xorg] already present"
exit 0
fi
echo "[xorg] pacman -S xorg-server xorg-xinit"
chroot "$M" /usr/bin/pacman -Sy --noconfirm xorg-server xorg-xinit
test -x "$M/usr/bin/Xorg"
echo "[xorg] installed $IMG"
+222
View File
@@ -0,0 +1,222 @@
#!/usr/bin/env bash
#
# Pack SYSTEM/ into a GPT disk:
# p1 FAT32 ESP (EF00) /EFI /limine /boot /driver /system
# Limine 10 cannot read ext4; every boot(): module must live here.
# p2 ext4 (8300) the rest of SYSTEM/ (and a copy of driver/system)
#
# Usage:
# sudo bash CODE/linux/pack_system_image.sh <SYSTEM_DIR> <OUTPUT_IMG>
#
# FAT32 still cannot hold a single file >= 4GiB. Keep linux-extra-rootfs.img
# under that limit while it lives in SYSTEM/boot.
set -Eeuo pipefail
if [[ $# -ne 2 ]]; then
echo "Usage: $0 <SYSTEM_DIR> <OUTPUT_IMG>" >&2
exit 2
fi
SYSTEM="$(cd "$1" && pwd)"
OUT="$2"
OUT_DIR="$(cd "$(dirname "$OUT")" && pwd)"
OUT="$OUT_DIR/$(basename "$OUT")"
# Must match SYSTEM/limine/limine.conf uuid(...) paths.
EXT4_UUID="64657368-6162-4000-8000-000000000002"
DISK_GUID="64657368-6162-4000-8000-000000000001"
ESP_PARTGUID="64657368-6162-4000-8000-0000000000b1"
EXT4_PARTGUID="64657368-6162-4000-8000-0000000000e2"
for tool in sfdisk mkfs.vfat mkfs.ext4 rsync losetup du; do
if ! command -v "$tool" >/dev/null 2>&1; then
echo "[pack] ERROR: missing tool: $tool" >&2
exit 2
fi
done
if [[ ! -d "$SYSTEM/boot" || ! -d "$SYSTEM/EFI" || ! -f "$SYSTEM/limine/limine.conf" ]]; then
echo "[pack] ERROR: SYSTEM/ must contain boot/, EFI/, and limine/limine.conf" >&2
exit 2
fi
bytes_of() {
local p="$1"
if [[ -e "$p" ]]; then
du -sb --apparent-size "$p" | awk '{print $1}'
else
echo 0
fi
}
align_up() {
local val="$1"
local align="$2"
echo $(( (val + align - 1) / align * align ))
}
# Sum each SYSTEM child so 9p/du-on-parent cannot drop boot/.
boot_bytes="$(bytes_of "$SYSTEM/boot")"
efi_bytes="$(bytes_of "$SYSTEM/EFI")"
limine_bytes="$(bytes_of "$SYSTEM/limine")"
driver_bytes="$(bytes_of "$SYSTEM/driver")"
sys_bytes="$(bytes_of "$SYSTEM/system")"
esp_content=$((boot_bytes + efi_bytes + limine_bytes + driver_bytes + sys_bytes))
rest_bytes=0
shopt -s dotglob nullglob
for child in "$SYSTEM"/*; do
name="$(basename "$child")"
case "$name" in
boot|EFI|limine) continue ;;
esac
rest_bytes=$((rest_bytes + $(bytes_of "$child")))
done
shopt -u dotglob nullglob
# FAT32/ext4 metadata slack: 15% + 64MiB, 1MiB aligned.
esp_need=$((esp_content + esp_content / 7 + 64 * 1024 * 1024))
ext4_need=$((rest_bytes + rest_bytes / 7 + 64 * 1024 * 1024))
[[ "$esp_need" -lt $((256 * 1024 * 1024)) ]] && esp_need=$((256 * 1024 * 1024))
# User-facing data partition: keep at least 2GiB even when SYSTEM/ is small.
[[ "$ext4_need" -lt $((2048 * 1024 * 1024)) ]] && ext4_need=$((2048 * 1024 * 1024))
MIB=$((1024 * 1024))
SECTOR=512
esp_bytes="$(align_up "$esp_need" "$MIB")"
ext4_bytes="$(align_up "$ext4_need" "$MIB")"
esp_sectors=$((esp_bytes / SECTOR))
ext4_sectors=$((ext4_bytes / SECTOR))
# 1MiB protective gap + backup GPT
gpt_front=2048
gpt_back=2048
total_sectors=$((gpt_front + esp_sectors + ext4_sectors + gpt_back))
total_bytes=$((total_sectors * SECTOR))
extra_bytes="$(bytes_of "$SYSTEM/boot/linux-extra-rootfs.img")"
echo "[pack] GPT dual partition (NOT a single FAT32 disk):"
echo "[pack] p1 FAT32 ESP = Limine + /boot modules (Limine 10 cannot read ext4)"
echo "[pack] p2 ext4 = rest of SYSTEM/ uuid=$EXT4_UUID"
echo "[pack] SYSTEM=$SYSTEM"
echo "[pack] ESP content=$((esp_content / 1024 / 1024)) MB partition=$((esp_bytes / 1024 / 1024)) MB"
echo "[pack] linux-extra-rootfs.img=$((extra_bytes / 1024 / 1024)) MB (must stay on p1 FAT32)"
echo "[pack] ext4 content=$((rest_bytes / 1024 / 1024)) MB partition=$((ext4_bytes / 1024 / 1024)) MB"
echo "[pack] disk=$((total_bytes / 1024 / 1024)) MB -> $OUT"
WORK="$(mktemp -d /var/tmp/deshab_pack.XXXXXX)"
IMG="$WORK/disk.img"
MNT_ESP="$WORK/mnt_esp"
MNT_EXT="$WORK/mnt_ext"
LOOP=""
cleanup() {
set +e
if [[ -n "${MNT_ESP:-}" ]]; then
umount "$MNT_ESP" 2>/dev/null
fi
if [[ -n "${MNT_EXT:-}" ]]; then
umount "$MNT_EXT" 2>/dev/null
fi
if [[ -n "${LOOP:-}" ]]; then
losetup -d "$LOOP" 2>/dev/null
fi
rm -rf "$WORK"
}
trap cleanup EXIT
mkdir -p "$MNT_ESP" "$MNT_EXT"
# Prefer a sparse image so the 9p copy back to Windows is smaller when possible.
truncate -s "$total_bytes" "$IMG"
esp_start="$gpt_front"
ext4_start=$((esp_start + esp_sectors))
sfdisk --no-reread "$IMG" <<EOF
label: gpt
label-id: ${DISK_GUID}
first-lba: ${gpt_front}
sector-size: 512
start=${esp_start}, size=${esp_sectors}, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=${ESP_PARTGUID}, name=DESHABBOOT
start=${ext4_start}, size=${ext4_sectors}, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=${EXT4_PARTGUID}, name=DESHAB
EOF
LOOP="$(losetup --find --show --partscan "$IMG")"
echo "[pack] loop=$LOOP"
echo "[pack] partition table:"
sfdisk -l "$IMG" || true
p1=""
p2=""
for _ in $(seq 1 25); do
if [[ -b "${LOOP}p1" && -b "${LOOP}p2" ]]; then
p1="${LOOP}p1"
p2="${LOOP}p2"
break
fi
# Some kernels expose /dev/loopXp1 only after partx.
if command -v partx >/dev/null 2>&1; then
partx --update "$LOOP" 2>/dev/null || true
fi
sleep 0.2
done
if [[ -z "$p1" || -z "$p2" ]]; then
echo "[pack] ERROR: loop partitions did not appear under $LOOP" >&2
ls -l "$LOOP"* 2>/dev/null || true
exit 1
fi
# 4KiB clusters on a ~5GiB ESP; 32KiB if the ESP is 4GiB or larger.
fat_cluster_sectors=8
if [[ "$esp_bytes" -ge $((4096 * 1024 * 1024)) ]]; then
fat_cluster_sectors=64
fi
mkfs.vfat -F 32 -n DESHABBOOT -s "$fat_cluster_sectors" "$p1" >/dev/null
mkfs.ext4 -F -q -L DESHAB -U "$EXT4_UUID" -m 1 "$p2"
echo "[pack] filesystems:"
blkid "$p1" "$p2" || true
mount "$p1" "$MNT_ESP"
mount "$p2" "$MNT_EXT"
mkdir -p "$MNT_ESP/EFI" "$MNT_ESP/limine" "$MNT_ESP/boot" "$MNT_ESP/driver" "$MNT_ESP/system"
echo "[pack] copying p1 FAT32 ESP (EFI/ limine/ boot/ driver/ system/)"
# vfat has no Unix owners/perms; -a would fail with rsync code 23.
rsync -rltD --info=progress2 "$SYSTEM/EFI/" "$MNT_ESP/EFI/"
rsync -rltD --info=progress2 "$SYSTEM/limine/" "$MNT_ESP/limine/"
cp -f "$SYSTEM/limine/limine.conf" "$MNT_ESP/limine.conf"
rsync -rltD --info=progress2 "$SYSTEM/boot/" "$MNT_ESP/boot/"
rsync -rltD --info=progress2 "$SYSTEM/driver/" "$MNT_ESP/driver/"
rsync -rltD --info=progress2 "$SYSTEM/system/" "$MNT_ESP/system/"
if [[ -d "$SYSTEM/user" ]]; then
echo "[pack] copying user/ onto FAT32 ESP for native desktop icons"
rsync -rltD --info=progress2 "$SYSTEM/user/" "$MNT_ESP/user/"
fi
echo "[pack] copying p2 ext4 data partition"
shopt -s dotglob nullglob
for child in "$SYSTEM"/*; do
name="$(basename "$child")"
case "$name" in
boot|EFI|limine) continue ;;
esac
rsync -a --info=progress2 "$child" "$MNT_EXT/"
done
shopt -u dotglob nullglob
sync
umount "$MNT_ESP"
umount "$MNT_EXT"
losetup -d "$LOOP"
LOOP=""
echo "[pack] writing $OUT"
mkdir -p "$OUT_DIR"
# Sparse copy keeps the Windows-side file smaller when the host supports it.
cp --sparse=always "$IMG" "$OUT"
sync
echo "[pack] done: $OUT"
echo "[pack] GPT p1 FAT32 ESP (Limine/boot) + p2 ext4 uuid=$EXT4_UUID"
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env bash
# Copy updated ESP boot artifacts onto an existing GPT image without
# recopying the 4GiB extra-rootfs. Paths are relative to the FAT32 ESP.
set -Eeuo pipefail
IMG="${1:-/mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img}"
ROOT="${2:-/mnt/d/Code/DEAICUP/Deshab}"
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount "${LOOP}p1" "$M"
copy_if() {
local src="$1" dst="$2"
if [[ -f "$src" ]]; then
mkdir -p "$(dirname "$dst")"
cp -f "$src" "$dst"
echo "[patch] $src -> $dst"
else
echo "[patch] skip missing $src"
fi
}
copy_if "$ROOT/SYSTEM/boot/linux-bzImage" "$M/boot/linux-bzImage"
copy_if "$ROOT/SYSTEM/boot/utsm.elf" "$M/boot/utsm.elf"
copy_if "$ROOT/SYSTEM/boot/linux-initrd.img" "$M/boot/linux-initrd.img"
copy_if "$ROOT/SYSTEM/limine/limine.conf" "$M/limine.conf"
if [[ -d "$M/limine" ]]; then
copy_if "$ROOT/SYSTEM/limine/limine.conf" "$M/limine/limine.conf"
fi
DAEMON="${DAEMON:-$ROOT/.build_tmp/utsm_exec_daemon}"
BINDMOUNT="${BINDMOUNT:-$ROOT/.build_tmp/utsm_bindmount}"
UTSMRUN="${UTSMRUN:-$ROOT/.build_tmp/utsm_run}"
BUSYBOX="${BUSYBOX:-$ROOT/CODE/linux/.cache/busybox}"
GUEST="$ROOT/CODE/linux/guest"
inject_scripts() {
local img="$1"
local
[[ -f "$img" ]] || return 0
r=$(mktemp -d)
if mount -o loop "$img" "$r"; then
mkdir -p "$r/usr/local/bin" "$r/etc" "$r/mnt/persist"
if [[ -f "$DAEMON" ]]; then
cp -f "$DAEMON" "$r/usr/local/bin/utsm_exec_daemon"
chmod 0755 "$r/usr/local/bin/utsm_exec_daemon"
fi
if [[ -f "$BINDMOUNT" ]]; then
cp -f "$BINDMOUNT" "$r/usr/local/bin/utsm_bindmount"
chmod 0755 "$r/usr/local/bin/utsm_bindmount"
echo "[patch] utsm_bindmount -> $img"
fi
if [[ -f "$UTSMRUN" ]]; then
cp -f "$UTSMRUN" "$r/usr/local/bin/utsm_run"
chmod 0755 "$r/usr/local/bin/utsm_run"
echo "[patch] utsm_run -> $img"
fi
XORG_GOOD="${XORG_GOOD:-$ROOT/.build_tmp/Xorg.good}"
XORG_LIBS="${XORG_LIBS:-$ROOT/.build_tmp/xorg-libs}"
MODESET="${MODESET:-/home/deshab/modesetting_drv.so}"
if [[ "$(basename "$img")" != *extra* ]]; then
mkdir -p "$r/usr/local/lib/xorg-libs" "$r/usr/local/lib/xorg/modules/drivers"
if [[ -f "$XORG_GOOD" ]]; then
cp -f "$XORG_GOOD" "$r/usr/local/lib/Xorg.good"
chmod 0755 "$r/usr/local/lib/Xorg.good"
echo "[patch] Xorg.good -> $img"
fi
if [[ -d "$XORG_LIBS" ]]; then
cp -a "$XORG_LIBS/." "$r/usr/local/lib/xorg-libs/"
echo "[patch] xorg-libs $(ls "$r/usr/local/lib/xorg-libs" | wc -l) -> $img"
fi
PLASMA_LIBS="${PLASMA_LIBS:-$ROOT/.build_tmp/plasma-libs}"
if [[ -d "$PLASMA_LIBS" ]]; then
mkdir -p "$r/usr/local/lib/plasma-libs"
cp -a "$PLASMA_LIBS/." "$r/usr/local/lib/plasma-libs/"
echo "[patch] plasma-libs $(ls "$r/usr/local/lib/plasma-libs" | wc -l) -> $img"
fi
if [[ -f "$MODESET" ]]; then
cp -f "$MODESET" "$r/usr/local/lib/xorg/modules/drivers/modesetting_drv.so"
chmod 0755 "$r/usr/local/lib/xorg/modules/drivers/modesetting_drv.so"
echo "[patch] modesetting_drv.so -> $img"
fi
fi
if [[ -x "$BUSYBOX" ]]; then
mkdir -p "$r/bin" "$r/usr/local/bin"
cp -f "$BUSYBOX" "$r/bin/busybox.static"
cp -f "$BUSYBOX" "$r/usr/local/bin/busybox.static"
chmod 0755 "$r/bin/busybox.static" "$r/usr/local/bin/busybox.static"
# musl busybox.static PUSH-faults at GVA 0 under leaked SHSTK.
# Keep /bin/sh -> bash (glibc). IBT landing pads are skipped in
# L1 when guest_fetch can see ENDBR/NOP90.
if [[ "$(basename "$img")" != *extra* ]]; then
if [[ -e "$r/bin/bash" || -e "$r/usr/bin/bash" ]]; then
ln -sfn bash "$r/bin/sh"
echo "[patch] /bin/sh -> bash"
fi
fi
fi
if [[ -f "$GUEST/deshab-kde-session" ]]; then
sed 's/\r$//' "$GUEST/deshab-kde-session" > "$r/usr/local/bin/deshab-kde-session"
chmod 0755 "$r/usr/local/bin/deshab-kde-session"
fi
if [[ -f "$GUEST/deshab-native-desktop" ]]; then
sed 's/\r$//' "$GUEST/deshab-native-desktop" > "$r/usr/local/bin/deshab-native-desktop"
chmod 0755 "$r/usr/local/bin/deshab-native-desktop"
fi
if [[ "$(basename "$img")" == *extra* ]]; then
touch "$r/etc/deshab-kde-root"
chmod 0755 "$r/dev" "$r/proc" "$r/sys" "$r/run" 2>/dev/null || true
fi
echo "[patch] guest scripts -> $img"
umount "$r"
fi
rmdir "$r"
}
inject_scripts "$M/boot/linux-rootfs.img"
# Do not loop-mount or rewrite linux-extra-rootfs.img. Guest maps that
# file as vdc; host writes plus virtio T_OUT have produced runtime
# ext4 checksums even when e2fsck of the image is clean. The session
# copies itself onto the persist overlay before chroot.
# KDE wrapper on Arch rootfs is enough for the first hop; --inside uses
# the overlay copy after chroot.
copy_if "$ROOT/SYSTEM/system/deshab64/deshab.elf" "$M/system/deshab64/deshab.elf"
copy_if "$ROOT/SYSTEM/system/deshab64/desktop.elf" "$M/system/deshab64/desktop.elf"
copy_if "$ROOT/SYSTEM/system/deshab64/FUCK" "$M/system/deshab64/FUCK"
copy_if "$ROOT/SYSTEM/LINUXAPP.CNF" "$M/LINUXAPP.CNF"
copy_if "$ROOT/SYSTEM/user/desktop/kde.lnk" "$M/user/desktop/kde.lnk"
copy_if "$ROOT/SYSTEM/user/desktop/kde.desktop" "$M/user/desktop/kde.desktop"
sync
umount "$M"
losetup -d "$LOOP"
rmdir "$M"
echo "[patch] updated $IMG ESP boot/system files"
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -Eeuo pipefail
IMG="${1:-/mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img}"
ROOT="${2:-/mnt/d/Code/DEAICUP/Deshab}"
DSK="${ROOT}/SYSTEM/system/deshab64/deshab.elf"
FUCK="${ROOT}/SYSTEM/system/deshab64/FUCK"
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount "${LOOP}p1" "$M"
cp -f "$DSK" "$M/system/deshab64/deshab.elf"
if [[ -f "$FUCK" ]]; then
cp -f "$FUCK" "$M/system/deshab64/FUCK"
echo "[patch] updated FUCK"
fi
sync
umount "$M"
losetup -d "$LOOP"
rmdir "$M"
echo "[patch] updated $IMG /system/deshab64/deshab.elf"
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# Inject KDE X11 session + shared Desktop icons into extra-rootfs (and rootfs).
set -Eeuo pipefail
ROOT="${1:-/mnt/d/Code/DEAICUP/Deshab}"
EXTRA="${2:-$ROOT/SYSTEM/boot/linux-extra-rootfs.img}"
ROOTFS="${3:-$ROOT/SYSTEM/boot/linux-rootfs.img}"
GUEST="$ROOT/CODE/linux/guest"
DESK="$ROOT/SYSTEM/user/desktop"
inject() {
local img="$1"
local m
if [[ ! -f "$img" ]]; then
echo "[kde-inject] skip missing $img"
return 0
fi
m="$(mktemp -d)"
if ! mount -o loop "$img" "$m"; then
echo "[kde-inject] ERROR: mount $img" >&2
rmdir "$m"
return 1
fi
mkdir -p "$m/usr/local/bin" "$m/usr/local/share/deshab-desktop" \
"$m/home/deshab/Desktop" "$m/var/log" "$m/etc"
BUSYBOX="$ROOT/CODE/linux/.cache/busybox"
if [[ -x "$BUSYBOX" ]]; then
cp -f "$BUSYBOX" "$m/usr/local/bin/busybox.static"
chmod 0755 "$m/usr/local/bin/busybox.static"
fi
sed 's/\r$//' "$GUEST/deshab-kde-session" > "$m/usr/local/bin/deshab-kde-session"
sed 's/\r$//' "$GUEST/deshab-native-desktop" > "$m/usr/local/bin/deshab-native-desktop"
chmod 0755 "$m/usr/local/bin/deshab-kde-session" \
"$m/usr/local/bin/deshab-native-desktop"
touch "$m/etc/deshab-kde-root"
if [[ -d "$DESK" ]]; then
cp -a "$DESK/." "$m/usr/local/share/deshab-desktop/"
cp -a "$DESK/." "$m/home/deshab/Desktop/"
fi
if [[ -f "$m/usr/bin/startplasma-x11" ]]; then
echo "[kde-inject] startplasma-x11 present in $img"
elif [[ -f "$m/usr/bin/startplasma-wayland" ]]; then
echo "[kde-inject] WARNING: only startplasma-wayland in $img"
fi
if command -v Xfbdev >/dev/null 2>&1; then
:
fi
if [[ -x "$m/usr/bin/Xfbdev" || -x "$m/bin/Xfbdev" ]]; then
echo "[kde-inject] Xfbdev present in $img"
else
echo "[kde-inject] Xfbdev not in $img (expected on linux-rootfs)"
fi
sync
umount "$m"
rmdir "$m"
echo "[kde-inject] updated $img"
}
inject "$EXTRA"
inject "$ROOTFS"
+35 -21
View File
@@ -26,11 +26,22 @@
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <asm/msr.h>
#ifndef MSR_IA32_U_CET
#define MSR_IA32_U_CET 0x000006a0
#endif
#ifndef MSR_IA32_S_CET
#define MSR_IA32_S_CET 0x000006a2
#endif
/* Shared IPC protocol header (included via build.sh -I flag).
* We provide our own hypercall wrappers, so skip the inline ones. */
#define UTSM_NO_INLINE_HCALL
#include <ipc_proto.h>
#ifndef UTSM_HCALL_PARK
#define UTSM_HCALL_PARK 0x0003
#endif
#define UTSM_DEV_NAME "utsm"
@@ -308,10 +319,12 @@ static long utsm_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
umsg.data_len = msg.data_len;
if (umsg.buf_size < msg.data_len)
return -EINVAL;
if (msg.data_len > 0) {
if (copy_to_user(umsg.data, msg.data, msg.data_len))
return -EFAULT;
}
/* umsg is already a kernel copy of the ioctl arg. Do not
* copy_to_user(umsg.data) — that treats a kernel address as
* a userspace pointer and returns -EFAULT, so the daemon
* parks without seeing EXEC_REQUEST (linux_compat exec -4). */
if (msg.data_len > 0)
memcpy(umsg.data, msg.data, msg.data_len);
if (copy_to_user((void __user *)arg, &umsg, sizeof(umsg)))
return -EFAULT;
return 0;
@@ -328,10 +341,8 @@ static long utsm_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
memset(&msg, 0, sizeof(msg));
msg.type = umsg.type;
msg.data_len = min_t(u32, umsg.data_len, UTSM_IPC_MSG_DATA_SIZE);
if (msg.data_len > 0) {
if (copy_from_user(msg.data, umsg.data, msg.data_len))
return -EFAULT;
}
if (msg.data_len > 0)
memcpy(msg.data, umsg.data, msg.data_len);
if (utsm_ipc_ring_push(&g_shm->linux_to_utsm, &msg) != 0) {
pr_warn("[utsm] linux_to_utsm ring full\n");
@@ -341,20 +352,12 @@ static long utsm_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
}
case UTSM_IOCTL_PARK: {
/* Execute HLT to trigger VM-Exit → UTSM parks guest.
* Interrupts must be enabled so that on vmresume the guest
* can continue (HLT with interrupts disabled would hang).
*
* Flow:
* 1. daemon calls ioctl(PARK) → driver executes HLT
* 2. HLT → VM-Exit (CPU_BASED_HLT_EXITING) → UTSM handle_hlt
* 3. UTSM advances RIP past HLT, exits to host (park)
* 4. UTSM writes request + vmresume
* 5. Guest continues from after HLT → ioctl returns
* 6. Daemon re-checks ring for new EXEC_REQUEST
/* VMCALL park. Idle HLT must stay in the guest (wait for IRQ).
* idle=poll + HLT-as-park panicked in cpu_idle_poll (current=NULL).
*/
mb(); /* ensure prior ring writes are visible before HLT */
asm volatile("hlt" ::: "memory");
mb();
if (utsm_hcall(UTSM_HCALL_PARK, 0, 0, 0) != 0)
return -EIO;
return 0;
}
@@ -602,6 +605,17 @@ static int __init utsm_hcall_init(void)
pr_info("[utsm] probing for UTSM monitor...\n");
/* Nested KVM leaks host U_CET (IBT+SHSTK) into L2. L1 cannot
* WRMSR CET (CR4.CET=0). Clear it from the guest while the
* WRMSR is not intercepted. */
{
u64 ucet = 0;
int rd = rdmsrl_safe(MSR_IA32_U_CET, &ucet);
int wr = wrmsrl_safe(MSR_IA32_U_CET, 0);
pr_info("[utsm] CET U_CET rd=%d val=0x%llx wr0=%d\n",
rd, ucet, wr);
}
/* 1. Ping UTSM to verify it's present */
ping_ret = utsm_hcall_ping();
if (ping_ret != 0x504F4E47) { /* "PONG" */
+200
View File
@@ -0,0 +1,200 @@
/* LD_PRELOAD into qemu-system-x86_64.
*
* Nested KVM does not virtualize CET VMCS fields. L0 U_CET (IBT+SHSTK)
* leaks into L2: glibc #GPs on landing pads, musl PUSH writes SSP=0.
*
* arch_prctl(SHSTK_DISABLE) is EINVAL on WSL (no shstk in cpuinfo).
* Host-wide wrmsr IA32_U_CET / setting CR4.CET kills UTSM — do not.
*
* This library asks *KVM* to load CET MSRs as 0 on the vCPU (L0
* virtualization, not a host WRMSR). It also keeps the arch_prctl
* attempt for kernels that do support SHSTK.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
#ifndef SYS_arch_prctl
#define SYS_arch_prctl 158
#endif
#ifndef ARCH_SHSTK_DISABLE
#define ARCH_SHSTK_DISABLE 0x5002
#endif
#ifndef ARCH_SHSTK_SHSTK
#define ARCH_SHSTK_SHSTK (1UL << 0)
#endif
#ifndef ARCH_SHSTK_IBT
#define ARCH_SHSTK_IBT (1UL << 1)
#endif
#ifndef KVMIO
#define KVMIO 0xAE
#endif
/* linux/kvm.h: _IO(KVMIO, 0x41/0x80), _IOWR/_IOW of sizeof(kvm_msrs)=8 */
#ifndef KVM_CREATE_VCPU
#define KVM_CREATE_VCPU 0xae41u
#endif
#ifndef KVM_RUN
#define KVM_RUN 0xae80u
#endif
#ifndef KVM_GET_MSRS
#define KVM_GET_MSRS 0xc008ae88u
#endif
#ifndef KVM_SET_MSRS
#define KVM_SET_MSRS 0x4008ae89u
#endif
#define MSR_IA32_U_CET 0x000006a0u
#define MSR_IA32_S_CET 0x000006a2u
#define MSR_IA32_PL0_SSP 0x000006a4u
#define MSR_IA32_PL1_SSP 0x000006a5u
#define MSR_IA32_PL2_SSP 0x000006a6u
#define MSR_IA32_PL3_SSP 0x000006a7u
#define MSR_IA32_INTERRUPT_SSP_TABLE 0x000006a8u
struct kvm_msr_entry {
uint32_t index;
uint32_t reserved;
uint64_t data;
};
struct kvm_msrs {
uint32_t nmsrs;
uint32_t pad;
struct kvm_msr_entry entries[];
};
static int (*real_ioctl)(int, unsigned long, ...);
static int g_log_fd = -1;
static void cet_log(const char *fmt, ...)
{
char buf[256];
va_list ap;
int n;
if (g_log_fd < 0) {
g_log_fd = open("/tmp/deshab_cet.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
if (g_log_fd < 0)
return;
}
va_start(ap, fmt);
n = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (n > 0)
(void)write(g_log_fd, buf, (size_t)n);
}
static void resolve_ioctl(void)
{
if (!real_ioctl) {
real_ioctl = (int (*)(int, unsigned long, ...))dlsym(RTLD_NEXT, "ioctl");
if (!real_ioctl)
real_ioctl = (int (*)(int, unsigned long, ...))dlsym(RTLD_DEFAULT, "ioctl");
}
}
static int kvm_ioctl(int fd, unsigned long req, void *arg)
{
resolve_ioctl();
if (!real_ioctl)
return syscall(SYS_ioctl, fd, req, arg);
return real_ioctl(fd, req, arg);
}
static void try_vcpu_cet_zero(int fd)
{
struct {
struct kvm_msrs hdr;
struct kvm_msr_entry e[7];
} buf;
static int logged_get;
int r, saved;
unsigned i;
memset(&buf, 0, sizeof(buf));
buf.hdr.nmsrs = 7;
buf.e[0].index = MSR_IA32_U_CET;
buf.e[1].index = MSR_IA32_S_CET;
buf.e[2].index = MSR_IA32_PL0_SSP;
buf.e[3].index = MSR_IA32_PL1_SSP;
buf.e[4].index = MSR_IA32_PL2_SSP;
buf.e[5].index = MSR_IA32_PL3_SSP;
buf.e[6].index = MSR_IA32_INTERRUPT_SSP_TABLE;
saved = errno;
r = kvm_ioctl(fd, KVM_GET_MSRS, &buf);
if (!logged_get) {
logged_get = 1;
cet_log("KVM_GET_MSRS CET fd=%d r=%d errno=%d", fd, r, r < 0 ? errno : 0);
for (i = 0; i < 7; i++)
cet_log(" [%u] msr=0x%x data=0x%llx",
i, buf.e[i].index, (unsigned long long)buf.e[i].data);
cet_log("\n");
}
errno = saved;
memset(&buf, 0, sizeof(buf));
buf.hdr.nmsrs = 7;
buf.e[0].index = MSR_IA32_U_CET;
buf.e[1].index = MSR_IA32_S_CET;
buf.e[2].index = MSR_IA32_PL0_SSP;
buf.e[3].index = MSR_IA32_PL1_SSP;
buf.e[4].index = MSR_IA32_PL2_SSP;
buf.e[5].index = MSR_IA32_PL3_SSP;
buf.e[6].index = MSR_IA32_INTERRUPT_SSP_TABLE;
/* data already 0 */
saved = errno;
r = kvm_ioctl(fd, KVM_SET_MSRS, &buf);
cet_log("KVM_SET_MSRS CET=0 fd=%d r=%d errno=%d\n", fd, r, r < 0 ? errno : 0);
errno = saved;
}
__attribute__((constructor)) static void deshab_qemu_disable_cet(void)
{
int rc1, rc2;
rc1 = (int)syscall(SYS_arch_prctl, ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
rc2 = (int)syscall(SYS_arch_prctl, ARCH_SHSTK_DISABLE, ARCH_SHSTK_IBT);
cet_log("arch_prctl SHSTK=%d IBT=%d errno_last=%d\n", rc1, rc2, errno);
}
int ioctl(int fd, unsigned long request, ...)
{
va_list ap;
void *arg = NULL;
int r;
static unsigned char did_cet[1024];
va_start(ap, request);
arg = va_arg(ap, void *);
va_end(ap);
resolve_ioctl();
if (!real_ioctl)
return syscall(SYS_ioctl, fd, request, arg);
/* Zero CET on the vCPU *before* the first KVM_RUN so L2 does not
* inherit L0 U_CET. CREATE_VCPU returns the vCPU fd afterwards. */
if (request == KVM_RUN && fd >= 0 && fd < (int)sizeof(did_cet) && !did_cet[fd]) {
did_cet[fd] = 1;
try_vcpu_cet_zero(fd);
}
r = real_ioctl(fd, request, arg);
if (request == KVM_CREATE_VCPU && r >= 0) {
try_vcpu_cet_zero(r);
if (r < (int)sizeof(did_cet))
did_cet[r] = 1;
}
return r;
}
+177
View File
@@ -0,0 +1,177 @@
#!/usr/bin/env bash
# Headless QEMU verify: Linux guest park + native desktop + KDE scanout.
set -Eeuo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
IMG="${IMG_OVERRIDE:-$ROOT/ISO/deshab-dev.img}"
LOG="${QEMU_SERIAL_LOG:-/home/deshab/qemu_serial_loop1.log}"
MON="${QEMU_MONITOR:-telnet:127.0.0.1:45454,server,nowait}"
TIMEOUT="${QEMU_VERIFY_TIMEOUT:-480}"
SEND_KDE="${QEMU_SEND_KDE:-1}"
SERIAL_TCP="${QEMU_SERIAL_TCP:-127.0.0.1:45455}"
rm -f "$LOG"
: > "$LOG"
export IMG_OVERRIDE="$IMG"
export QEMU_SERIAL_LOG="$LOG"
export QEMU_DISPLAY=none
export QEMU_MONITOR="$MON"
export QEMU_SERIAL_TCP="$SERIAL_TCP"
# Do not attach the AHCI SATA *sidecar*. The boot disk is already AHCI
# (ISO/deshab-dev.img). The old sata_fat32_dsk.img hid ESP deshab.elf.
export SATA_IMG_OVERRIDE="/tmp/deshab-verify-no-sata"
export NVME_IMG_OVERRIDE="/tmp/deshab-verify-no-nvme"
export USB_IMG_OVERRIDE="/tmp/deshab-verify-no-usb"
echo "[verify] starting QEMU, log=$LOG timeout=${TIMEOUT}s serial_tcp=$SERIAL_TCP"
cd "$ROOT/ISO"
# Strip CRLF if the script was edited on Windows.
sed -i 's/\r$//' ./run_qemu_kvm.sh 2>/dev/null || true
bash ./run_qemu_kvm.sh &
QEMU_PID=$!
cleanup() {
set +e
if kill -0 "$QEMU_PID" 2>/dev/null; then
kill "$QEMU_PID" 2>/dev/null || true
sleep 1
kill -9 "$QEMU_PID" 2>/dev/null || true
fi
}
trap cleanup EXIT
log_text() {
# Serial logs often contain CR / NUL; strip so grep anchors work.
tr -d '\r\0' < "$LOG" 2>/dev/null || true
}
log_has() {
log_text | grep -qE "$1"
}
send_serial() {
local msg="$1"
local host="${SERIAL_TCP%%:*}"
local port="${SERIAL_TCP##*:}"
python3 - "$host" "$port" "$msg" <<'PY' || true
import socket, sys
host, port, msg = sys.argv[1], int(sys.argv[2]), sys.argv[3]
s = socket.create_connection((host, port), 3)
s.sendall(msg.encode())
s.close()
PY
}
sent_kde=0
dsk_started=0
plasma_painted=0
deadline=$((SECONDS + TIMEOUT))
guest_ok=0
session_ok=0
kde_ok=0
desktop_ready=0
while kill -0 "$QEMU_PID" 2>/dev/null && [[ $SECONDS -lt $deadline ]]; do
if log_has 'EXEC_READY received from /dev/utsm' && \
log_has 'guest parked \(daemon ready\)'; then
guest_ok=1
fi
if log_has '\[DSK\] session=(kde|native)$' || \
log_has '\[DSK\] session=ask, waiting for 1/2'; then
session_ok=1
fi
if log_has 'desktop ready'; then
desktop_ready=1
fi
if log_has 'session=ask, waiting for 1/2'; then
if [[ "$SEND_KDE" == "1" && "$sent_kde" == "0" ]]; then
sleep 1
echo "[verify] sending serial 2 for KDE (chooser)"
send_serial '2'
sent_kde=1
fi
fi
if [[ "$desktop_ready" == "1" && "$SEND_KDE" == "1" && "$sent_kde" == "0" ]]; then
echo "[verify] sending serial 2 for KDE (native desktop)"
send_serial '2'
sent_kde=1
deadline=$((SECONDS + 180))
fi
# "Plasma failed" is sometimes dropped by kmsg. The loader error
# and the chroot exit status are the ones that actually reach serial.
if log_has '\[deshab-kde\] Plasma failed|invalid ELF header|error while loading shared libraries|exited with status [1-9]|fatal signal'; then
kde_ok=3
elif log_has '\[deshab-kde\] starting Plasma'; then
kde_ok=1
elif [[ "$kde_ok" != "1" ]] && \
log_has 'KDE preflight missing|KDE scanout timeout|KDE failed|could not bind|chroot session exited'; then
kde_ok=3
elif [[ "$kde_ok" == "0" ]] && \
log_has 'serial 2: launch KDE|kde: launching fullscreen Plasma|KDE host loop|KDE spawned|\[deshab-kde\] interpreter alive|\[deshab-kde\] entering KDE'; then
kde_ok=2
fi
# P9: Plasma 只活着还不够,必须真的推帧。Xorg/modesetting 每次提交
# 都发 RESOURCE_FLUSH;utsm.elf 里加了 FLUSH_N 计数日志(每 64 次一行)。
# starting Plasma 之后出现 FLUSH_N 才算 Plasma 画了。
if [[ "$kde_ok" == "1" ]]; then
if log_has '\[VGPU\] FLUSH_N'; then
plasma_painted=1
fi
fi
# drm fbdev SET_SCANOUT at boot is not Plasma. "entering KDE" only
# means the session reached the chroot setup, not that Plasma painted.
if [[ "$kde_ok" == "1" ]] && [[ "$guest_ok" == "1" ]]; then
if [[ "$sent_kde" == "1" ]]; then
sleep 60
else
sleep 8
fi
# starting Plasma is logged before the child returns. Recheck
# after the wait so a 127 during this window is not a false OK.
if log_has '\[deshab-kde\] Plasma failed|invalid ELF header|error while loading shared libraries|exited with status [1-9]|fatal signal'; then
kde_ok=3
elif log_has '\[VGPU\] FLUSH_N'; then
plasma_painted=1
break
else
break
fi
fi
if [[ "$guest_ok" == "1" && "$session_ok" == "1" && "$kde_ok" == "3" ]]; then
sleep 20
break
fi
if [[ "$dsk_started" == "0" ]] && log_has '\[DSK\] FUCK config loaded'; then
dsk_started=1
deadline=$((SECONDS + 240))
echo "[verify] DSK started, extending wait 240s"
fi
sleep 2
echo "[verify] t=${SECONDS}s log=$(wc -c < "$LOG" 2>/dev/null || echo 0) guest=$guest_ok session=$session_ok desktop=$desktop_ready kde=$kde_ok"
done
echo "===== VERIFY SUMMARY ====="
echo "guest_ok=$guest_ok session_ok=$session_ok kde_ok=$kde_ok sent_kde=$sent_kde desktop_ready=$desktop_ready plasma_painted=$plasma_painted"
echo "----- markers -----"
log_text | grep -E 'EXEC_READY|guest parked|session=ask|session=kde|session=native|KDE |Linux guest|FUCK config loaded|switch_root|utsm-linux|desktop ready|serial 2|FAT32 volume LBA|desktop load|user/desktop|VGPU|scanout|FLUSH|deshab-kde|vdc|persist|segfault|fatal signal|Xorg.0.log|Fatal server|overlay' | tail -n 120 || true
if [[ "$guest_ok" != "1" || "$session_ok" != "1" ]]; then
echo VERIFY_FAIL
exit 1
fi
if [[ "$kde_ok" == "1" ]]; then
if [[ "$plasma_painted" == "1" ]]; then
echo VERIFY_KDE_PLASMA_OK
exit 0
else
echo VERIFY_KDE_ALIVE_NO_FRAME
exit 1
fi
fi
if [[ "$kde_ok" == "2" ]]; then
echo VERIFY_KDE_SPAWNED
exit 1
fi
echo VERIFY_PARTIAL_OK
exit 1
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Incremental rebuild of linux-bzImage after UTSM driver patches.
# Linux sources live on the WSL native disk; never edit them via /mnt/d.
set -euo pipefail
LINUX_SRC="${LINUX_SRC:-/home/deshab/linux-6.6}"
REPO="${REPO:-/mnt/d/Code/DEAICUP/Deshab}"
PATCH="$REPO/CODE/linux/patches/utsm_hcall.c"
OUT="$REPO/SYSTEM/boot/linux-bzImage"
if [[ ! -f "$LINUX_SRC/Makefile" ]]; then
echo "[build] missing $LINUX_SRC" >&2
exit 1
fi
if [[ ! -f "$PATCH" ]]; then
echo "[build] missing $PATCH" >&2
exit 1
fi
cp "$PATCH" "$LINUX_SRC/drivers/utsm/utsm_hcall.c"
if id deshab >/dev/null 2>&1; then
chown deshab:deshab "$LINUX_SRC/drivers/utsm/utsm_hcall.c" || true
fi
echo "[build] installed driver from $PATCH"
grep -n 'memcpy(umsg.data' "$LINUX_SRC/drivers/utsm/utsm_hcall.c"
grep -n 'memcpy(msg.data' "$LINUX_SRC/drivers/utsm/utsm_hcall.c"
cd "$LINUX_SRC"
echo "[build] incremental bzImage start $(date -Iseconds)"
make -j"$(nproc)" KCFLAGS="-std=gnu17" bzImage
cp -f arch/x86/boot/bzImage "$OUT"
ls -la arch/x86/boot/bzImage "$OUT"
echo "[build] bzImage done $(date -Iseconds)"
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env bash
# Rebuild linux-initrd.img and optionally patch utsm_exec_daemon into
# the Arch rootfs image. Linux sources stay on the WSL native disk.
set -euo pipefail
REPO="${REPO:-/mnt/d/Code/DEAICUP/Deshab}"
LINUX_SRC="${LINUX_SRC:-/home/deshab/linux-6.6}"
OUT_DIR="$REPO/SYSTEM/boot"
INITRAMFS_DIR="$REPO/CODE/linux/initramfs"
DAEMON_SRC="$INITRAMFS_DIR/bin/utsm_exec_daemon.c"
INITRAMFS_TMP="${INITRAMFS_TMP:-/tmp/deshab-initrd}"
BUSYBOX_CACHE="$REPO/CODE/linux/.cache/busybox"
rm -rf "$INITRAMFS_TMP"
mkdir -p "$INITRAMFS_TMP/bin" "$OUT_DIR"
if [[ ! -x "$BUSYBOX_CACHE" ]]; then
echo "[initrd] extracting busybox from existing initrd"
mkdir -p "$(dirname "$BUSYBOX_CACHE")"
XT=$(mktemp -d)
gzip -dc "$OUT_DIR/linux-initrd.img" | (cd "$XT" && cpio -id --quiet 2>/dev/null) || true
if [[ -x "$XT/bin/busybox" ]]; then
cp "$XT/bin/busybox" "$BUSYBOX_CACHE"
chmod +x "$BUSYBOX_CACHE"
fi
rm -rf "$XT"
fi
if [[ ! -x "$BUSYBOX_CACHE" ]]; then
echo "[initrd] missing busybox at $BUSYBOX_CACHE" >&2
exit 1
fi
cp "$BUSYBOX_CACHE" "$INITRAMFS_TMP/bin/busybox"
chmod +x "$INITRAMFS_TMP/bin/busybox"
echo "[initrd] compiling utsm_exec_daemon"
cc -static -O2 -Wall -I"$REPO/CODE/utsm-ipc" \
-o "$INITRAMFS_TMP/bin/utsm_exec_daemon" "$DAEMON_SRC"
strip "$INITRAMFS_TMP/bin/utsm_exec_daemon" 2>/dev/null || true
mkdir -p "$REPO/.build_tmp"
cp -f "$INITRAMFS_TMP/bin/utsm_exec_daemon" "$REPO/.build_tmp/utsm_exec_daemon"
GEN_INIT_CPIO="$LINUX_SRC/usr/gen_init_cpio"
if [[ ! -x "$GEN_INIT_CPIO" ]]; then
echo "[initrd] building gen_init_cpio"
make -C "$LINUX_SRC" usr/ >/dev/null
fi
SPEC="$INITRAMFS_TMP/spec"
{
echo "dir /bin 755 0 0"
echo "dir /dev 755 0 0"
echo "dir /proc 755 0 0"
echo "dir /sys 755 0 0"
echo "nod /dev/console 600 0 0 c 5 1"
echo "nod /dev/null 666 0 0 c 1 3"
echo "nod /dev/ttyS0 600 0 0 c 4 64"
# Windows checkouts often leave CRLF; a shebang with \\r will not exec.
sed 's/\r$//' "$INITRAMFS_DIR/init" > "$INITRAMFS_TMP/init"
chmod 0755 "$INITRAMFS_TMP/init"
echo "file /init $INITRAMFS_TMP/init 755 0 0"
echo "file /bin/busybox $INITRAMFS_TMP/bin/busybox 755 0 0"
echo "file /bin/utsm_exec_daemon $INITRAMFS_TMP/bin/utsm_exec_daemon 755 0 0"
for app in sh mount umount echo sleep uname ls cat ps mkdir switch_root setsid cttyhack test modprobe; do
echo "slink /bin/$app /bin/busybox 777 0 0"
done
} > "$SPEC"
"$GEN_INIT_CPIO" "$SPEC" | gzip -9 > "$OUT_DIR/linux-initrd.img"
echo "[initrd] $OUT_DIR/linux-initrd.img"
ls -lh "$OUT_DIR/linux-initrd.img"
ROOTFS="$OUT_DIR/linux-rootfs.img"
if [[ "${SKIP_ROOTFS_PATCH:-}" != "1" && -f "$ROOTFS" ]]; then
M=$(mktemp -d)
mount -o loop "$ROOTFS" "$M"
if [[ -d "$M/usr/local/bin" ]]; then
cp -f "$INITRAMFS_TMP/bin/utsm_exec_daemon" "$M/usr/local/bin/utsm_exec_daemon"
chmod 0755 "$M/usr/local/bin/utsm_exec_daemon"
echo "[initrd] patched daemon into linux-rootfs.img"
# Arch glibc /bin/sh SIGSEGVs in this VMM. Host ping/Xfbdev helpers
# go through /bin/sh; keep /bin/bash for scripts that need it.
if [[ -x "$BUSYBOX_CACHE" ]]; then
cp -f "$BUSYBOX_CACHE" "$M/bin/busybox.static"
cp -f "$BUSYBOX_CACHE" "$M/usr/local/bin/busybox.static"
chmod 0755 "$M/bin/busybox.static" "$M/usr/local/bin/busybox.static"
# musl busybox has no SHSTK note; Arch bash/glibc does.
# Keep /bin/sh -> bash so host ping and shebang scripts live.
if [[ -e "$M/bin/bash" || -e "$M/usr/bin/bash" ]]; then
ln -sfn bash "$M/bin/sh"
echo "[initrd] /bin/sh -> bash"
fi
fi
for s in deshab-kde-session deshab-native-desktop; do
if [[ -f "$REPO/CODE/linux/guest/$s" ]]; then
sed 's/\r$//' "$REPO/CODE/linux/guest/$s" > "$M/usr/local/bin/$s"
chmod 0755 "$M/usr/local/bin/$s"
fi
done
else
echo "[initrd] rootfs has no /usr/local/bin, skip"
fi
umount "$M"
rmdir "$M"
fi
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""Replace ENDBR and the unsafe 0F 1F 40 00 NOP with 90 90 90 90.
Nested VMX leaks user CET: glibc ENDBR64 #GPs. Multi-byte NOP
`0F 1F 40 00` (`nop dword ptr [rax]`) can still #GP when RAX is 0.
Four 0x90 NOPs do not.
"""
from __future__ import annotations
import os
import sys
OLD = (
b"\xf3\x0f\x1e\xfa", # endbr64
b"\xf3\x0f\x1e\xfb", # endbr32
b"\x0f\x1f\x40\x00", # nop dword ptr [rax]
)
NEW = b"\x90\x90\x90\x90"
def is_elf(path: str) -> bool:
try:
with open(path, "rb") as f:
return f.read(4) == b"\x7fELF"
except OSError:
return False
def patch_file(path: str) -> int:
try:
with open(path, "rb") as f:
data = f.read()
except OSError:
return 0
if len(data) < 64 or data[:4] != b"\x7fELF":
return 0
n = 0
out = data
for old in OLD:
c = out.count(old)
if c:
out = out.replace(old, NEW)
n += c
if n:
with open(path, "wb") as f:
f.write(out)
return n
def walk(root: str) -> None:
files = 0
hits = 0
scanned = 0
for dirpath, dirnames, filenames in os.walk(root, followlinks=False):
dirnames[:] = [d for d in dirnames if d not in ("proc", "sys", "dev", "run")]
for name in filenames:
path = os.path.join(dirpath, name)
try:
if os.path.islink(path) or not os.path.isfile(path):
continue
if os.path.getsize(path) < 64:
continue
except OSError:
continue
scanned += 1
if scanned % 500 == 0:
print(f"[endbr90] {root}: scanned={scanned} patched={files}", flush=True)
if not is_elf(path):
continue
try:
n = patch_file(path)
except Exception as exc:
print(f"[endbr90] skip {path}: {exc}", flush=True)
continue
if n:
files += 1
hits += n
print(f"[endbr90] {root}: files={files} replacements={hits} scanned={scanned}", flush=True)
if __name__ == "__main__":
for root in sys.argv[1:]:
walk(root)
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env bash
# NOP-out ENDBR and clear IBT/SHSTK notes on guest ELF files inside an
# existing GPT image ESP (linux-rootfs.img + linux-extra-rootfs.img).
set -Eeuo pipefail
IMG="${1:-/mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img}"
ROOT="${2:-/mnt/d/Code/DEAICUP/Deshab}"
PY="$ROOT/CODE/linux/strip_endbr.py"
sed -i 's/\r$//' "$PY" 2>/dev/null || true
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
ESP=$(mktemp -d)
mount "${LOOP}p1" "$ESP"
check_libc() {
local m="$1"
local libc=""
for p in "$m/usr/lib/libc.so.6" "$m/lib/libc.so.6" "$m/usr/lib64/libc.so.6"; do
if [[ -e "$p" ]]; then
libc="$p"
break
fi
done
[[ -n "$libc" ]] || return 0
python3 - "$libc" <<'PY'
import sys
path = sys.argv[1]
off = 0x199140
with open(path, "rb") as f:
data = f.read()
chunk = data[off:off + 4] if len(data) > off + 4 else b""
print("[endbr] libc=%s size=%d @0x199140=%s" % (
path, len(data), chunk.hex() if chunk else "short"))
if chunk == b"\xf3\x0f\x1e\xfa":
sys.exit("ENDBR still present")
if chunk == b"\x0f\x1f\x40\x00":
sys.exit("BADNOP [rax] still present")
PY
}
patch_img() {
local img="$1"
local m
[[ -f "$img" ]] || return 0
m=$(mktemp -d)
if ! mount -o loop "$img" "$m"; then
rmdir "$m"
return 0
fi
echo "[endbr] scanning $img"
# Prefer the real usr-merge trees; skip symlink aliases that would
# double-walk the same files.
local dirs=()
if [[ -d "$m/usr/bin" ]]; then
dirs+=(usr/bin usr/sbin usr/lib usr/lib64 usr/libexec usr/local/bin usr/local/lib)
else
dirs+=(bin lib lib64 usr/bin usr/sbin usr/lib usr/lib64 usr/libexec \
usr/local/bin usr/local/lib)
fi
for d in "${dirs[@]}"; do
if [[ -d "$m/$d" && ! -L "$m/$d" ]]; then
python3 "$PY" "$m/$d" || echo "[endbr] WARN walk failed $m/$d"
elif [[ -d "$m/$d" && -L "$m/$d" ]]; then
echo "[endbr] skip symlink $d -> $(readlink "$m/$d")"
fi
done
check_libc "$m" || echo "[endbr] WARN libc check failed on $img"
sync
umount "$m"
rmdir "$m"
}
patch_img "$ESP/boot/linux-rootfs.img"
patch_img "$ESP/boot/linux-extra-rootfs.img"
umount "$ESP"
losetup -d "$LOOP"
rmdir "$ESP"
echo "[endbr] done $IMG"
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
T() { tr -d '\r\0' < /home/deshab/qemu_serial_loop1.log; }
N=$(T | grep -a -n 'inside-bash' | tail -1 | cut -d: -f1)
echo "inside-bash at serial line $N"
T | sed -n "${N},$((N + 40))p" | grep -a -v 'FLUSH_N\|flush count' | head -34
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env python3
from pathlib import Path
b = Path("/home/deshab/qemu_serial_loop1.log").read_bytes()
ascii_only = bytes(c if 32 <= c < 127 or c in (10, 13, 9) else 32 for c in b)
t = ascii_only.decode("ascii")
Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_ascii.txt").write_text(
t[:4000] + "\n---TAIL---\n" + t[-2000:], encoding="utf-8"
)
print("ok", len(b), "ascii_nonspace", sum(1 for c in ascii_only if c not in (32, 10, 13, 9)))
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env python3
from pathlib import Path
b = Path("/home/deshab/qemu_serial_loop1.log").read_bytes()
ascii_only = bytes(c if 32 <= c < 127 or c in (10, 13, 9) else 32 for c in b)
t = ascii_only.decode("ascii")
Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify6_ascii.txt").write_text(
t[:5000] + "\n---TAIL---\n" + t[-3000:], encoding="utf-8"
)
print("ok", len(b), "ascii_nonspace", sum(1 for c in ascii_only if c not in (32, 10, 13, 9)))
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
REPO=/mnt/d/Code/DEAICUP/Deshab
SRC="$REPO/CODE/linux/initramfs/bin/utsm_exec_daemon.c"
OUT="$REPO/.build_tmp/utsm_exec_daemon"
mkdir -p "$REPO/.build_tmp"
sed -i 's/\r$//' "$SRC"
cc -static -O2 -Wall -Wextra -I"$REPO/CODE/utsm-ipc" -o "$OUT" "$SRC"
strip "$OUT" 2>/dev/null || true
ls -l "$OUT"
echo DAEMON_OK
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Report the ESP /boot/utsm.elf md5 of every GPT image plus a few key ESP
# payload files, so we know which images carry the FLUSH_N kernel.
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
SRC="$ROOT/SYSTEM/boot/utsm.elf"
WANT=$(md5sum "$SRC" | cut -d' ' -f1)
echo "want utsm.elf md5=$WANT size=$(stat -c %s "$SRC")"
for img in "$@"; do
[[ -f "$img" ]] || { echo "$(basename "$img"): MISSING"; continue; }
L=$(losetup --find --show --partscan "$img" 2>/dev/null)
if [[ -z "$L" ]]; then echo "$(basename "$img"): losetup failed"; continue; fi
sleep 0.3
M=$(mktemp -d)
if ! mount "${L}p1" "$M" 2>/dev/null; then
echo "$(basename "$img"): mount p1 failed"
else
got=$(md5sum "$M/boot/utsm.elf" 2>/dev/null | cut -d' ' -f1)
if [[ "$got" == "$WANT" ]]; then verdict=UP-TO-DATE; else verdict=STALE; fi
echo "$(basename "$img"): utsm=${got:-none} $verdict"
for f in boot/linux-rootfs.img boot/linux-extra-rootfs.img \
boot/vmlinuz-linux boot/initramfs-linux.img; do
if [[ -f "$M/$f" ]]; then
printf ' %-28s %12s %s\n' "$f" "$(stat -c %s "$M/$f")" "$(date -r "$M/$f" '+%m-%d %H:%M')"
else
printf ' %-28s %12s\n' "$f" absent
fi
done
umount "$M"
fi
rmdir "$M" 2>/dev/null
losetup -d "$L" 2>/dev/null
done
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Health report for the X11 library payload inside an image's ESP rootfs.
set -uo pipefail
img="${1:-/mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img}"
L=$(losetup --find --show --partscan "$img"); sleep 0.3
M=$(mktemp -d); mount "${L}p1" "$M"
echo "--- ESP entry mtimes (dev image uses current build time) ---"
find "$M/boot" "$M/system/deshab64" -maxdepth 1 -type f -printf '%TY-%Tm-%Td %TH:%TM %10s %p\n' 2>/dev/null | sort
R=$(mktemp -d); mount -o loop,ro "$M/boot/linux-rootfs.img" "$R"
D="$R/usr/local/lib/xorg-libs"
echo "--- xorg-libs: $(ls "$D" | wc -l) entries ---"
bad=0; good=0
while IFS= read -r f; do
if [[ -L "$f" ]]; then
tgt=$(readlink -f "$f" 2>/dev/null)
if [[ -z "$tgt" || ! -e "$tgt" ]]; then echo " DANGLING $(basename "$f") -> $(readlink "$f")"; bad=$((bad+1)); continue; fi
f="$tgt"
fi
if head -c4 "$f" 2>/dev/null | grep -q ELF; then
good=$((good+1))
else
echo " NOT-ELF $(basename "$f") $(stat -c %s "$f") bytes $(file -b "$f" | cut -c1-40)"
bad=$((bad+1))
fi
done < <(find "$D" -maxdepth 1 -type f -o -maxdepth 1 -type l | sort)
echo " elf_ok=$good bad=$bad"
echo "--- non-lib extras in /usr/local/lib ---"
ls -l "$R/usr/local/lib" | grep -v '^d' | head -20
echo "--- /usr/local/bin ---"
ls -l "$R/usr/local/bin" 2>/dev/null
umount "$R"; rmdir "$R"; umount "$M"; losetup -d "$L"; rmdir "$M"
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -u
IMG=/home/deshab/deshab-dev.img
L=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${L}p1" "$M"
ls -la "$M/boot/"
E=$(mktemp -d)
mount -o loop,ro "$M/boot/linux-extra-rootfs.img" "$E"
echo "== persist ld.so / libc / dbus-run-session =="
ls -la "$E"/lib64/ld-linux-x86-64.so.2 "$E"/usr/lib/ld-linux-x86-64.so.2 "$E"/usr/lib/libc.so.6 "$E"/usr/bin/dbus-run-session "$E"/usr/lib/libdbus-1.so.3.38.3 2>&1
echo
for f in "$E"/usr/lib/ld-linux-x86-64.so.2 "$E"/usr/lib/libc.so.6 "$E"/usr/bin/dbus-run-session "$E"/usr/lib/libdbus-1.so.3.38.3; do
echo "-- $f"
file "$f"
readelf -h "$f" 2>/dev/null | grep -E 'Entry|Type|Machine' || true
done
echo
echo "== md5 comparison vdb vs persist libc =="
R=$(mktemp -d)
mount -o loop,ro "$M/boot/linux-rootfs.img" "$R"
md5sum "$R"/usr/lib/libc.so.6 "$E"/usr/lib/libc.so.6 2>&1
md5sum "$R"/usr/lib/libdbus-1.so.3.38.3 "$E"/usr/lib/libdbus-1.so.3.38.3 2>&1
umount "$R"; rmdir "$R"
umount "$E"; rmdir "$E"
umount "$M"; rmdir "$M"
losetup -d "$L"
echo DONE
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Report which GPT images already carry the current SYSTEM/boot/utsm.elf.
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
EXP=$(md5sum "$ROOT/SYSTEM/boot/utsm.elf" | cut -d' ' -f1)
echo "expected utsm.elf md5=$EXP size=$(stat -c %s "$ROOT/SYSTEM/boot/utsm.elf")"
for img in "$@"; do
[[ -f "$img" ]] || { echo "$img: missing"; continue; }
L=$(losetup --find --show --partscan "$img")
sleep 0.3
M=$(mktemp -d)
if mount "${L}p1" "$M" 2>/dev/null; then
got=$(md5sum "$M/boot/utsm.elf" 2>/dev/null | cut -d' ' -f1)
sz=$(stat -c %s "$M/boot/utsm.elf" 2>/dev/null || echo 0)
n=$(strings -a "$M/boot/utsm.elf" 2>/dev/null | grep -c FLUSH_N || true)
if [[ "$got" == "$EXP" ]]; then st=CURRENT; else st=STALE; fi
echo "$(basename "$img"): $st sz=$sz FLUSH_N=$n"
umount "$M"
else
echo "$(basename "$img"): mount p1 failed"
fi
rmdir "$M"
losetup -d "$L"
done
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
D=/mnt/d/Code/DEAICUP/Deshab/.build_tmp/xorg-libs
echo "== exists? =="
ls -ld "$D" 2>&1
echo "== count =="
ls "$D" 2>/dev/null | wc -l
echo "== libc / libdbus / ld-linux in overlay =="
ls "$D" 2>/dev/null | grep -E 'libc|libdbus|ld-linux' || echo "(none)"
echo "== full listing head =="
ls "$D" 2>/dev/null | head -50
echo "== .build_tmp top =="
ls -la /mnt/d/Code/DEAICUP/Deshab/.build_tmp/ | head -40
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Strip CR from serial capture logs so they can be read as plain text.
set -u
cd "$(dirname "$0")/../../.build_tmp" || exit 1
for f in "$@"; do
[ -f "$f" ] || { echo "missing: $f"; continue; }
out="${f%.txt}_clean.txt"
# drop CR plus any control/graphics bytes the read tool would treat as binary
tr -cd '\11\12\40-\176' < "$f" > "$out"
echo "ok $f -> $out ($(wc -l < "$out") lines)"
done
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env bash
# Determine the recursive NEEDED closure of startplasma-x11 inside the
# extra-rootfs and intersect it with the corruption lists (TRUNCATED /
# NOT-ELF). Emits the repair package list.
set -uo pipefail
IMG="${1:?img}"
WORK=/home/deshab/repair_scan
rm -rf "$WORK"; mkdir -p "$WORK"
L=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${L}p1" "$M" || exit 1
R="$WORK/root"
mkdir -p "$R"
mount -o loop,ro "$M/boot/linux-extra-rootfs.img" "$R" || exit 1
# 1) NEEDED closure walk (pure userspace, no guest needed)
python3 - "$R" <<'PY' > "$WORK/closure.txt"
import os, struct, sys
root = sys.argv[1]
libdirs = [os.path.join(root, d) for d in
("usr/lib", "lib", "usr/lib64")]
def find(name):
for d in libdirs:
p = os.path.join(d, name)
if os.path.isfile(p):
return p
return None
def needed(path):
try:
with open(path, "rb") as f:
hdr = f.read(64)
if hdr[:4] != b"\x7fELF":
return []
e_phoff = struct.unpack_from("<Q", hdr, 32)[0]
e_phnum = struct.unpack_from("<H", hdr, 56)[0]
with open(path, "rb") as f:
f.seek(e_phoff)
ph = f.read(56 * e_phnum)
dynoff = dynsz = 0
for i in range(e_phnum):
off = i * 56
p_type = struct.unpack_from("<I", ph, off)[0]
if p_type == 2: # PT_DYNAMIC
dynoff = struct.unpack_from("<Q", ph, off + 8)[0]
dynsz = struct.unpack_from("<Q", ph, off + 32)[0]
if not dynoff:
return []
with open(path, "rb") as f:
f.seek(dynoff)
dyn = f.read(dynsz)
strs = []
for i in range(len(dyn) // 16):
tag, val = struct.unpack_from("<QQ", dyn, i * 16)
if tag == 1: # DT_NEEDED
strs.append(val)
elif tag == 0:
break
# DT_STRTAB is vaddr; for these libs vaddr ~ file offset in first LOAD
strtab = 0
for i in range(len(dyn) // 16):
tag, val = struct.unpack_from("<QQ", dyn, i * 16)
if tag == 5: # DT_STRTAB
strtab = val
out = []
with open(path, "rb") as f:
for v in strs:
f.seek(strtab + v)
b = f.read(128)
out.append(b.split(b"\0")[0].decode("utf-8", "replace"))
return out
except (OSError, struct.error):
return []
seen = set()
queue = [os.path.join(root, "usr/bin/startplasma-x11")]
while queue:
p = queue.pop()
if p in seen or not os.path.isfile(p):
continue
seen.add(p)
for n in needed(p):
q = find(n)
print("%s -> %s" % (os.path.basename(p), n))
if q:
queue.append(q)
PY
sort -u "$WORK/closure.txt" > "$WORK/closure_sorted.txt"
# unique lib names in the closure
awk '{print $NF}' "$WORK/closure_sorted.txt" | sort -u > "$WORK/closure_libs.txt"
# 2) corruption lists
grep -E 'TRUNCATED|NOT-ELF' /home/deshab/elfscan_native.txt | awk '{print $NF}' | sort -u > "$WORK/bad_libs.txt"
# 3) intersection: bad libs that are actually on the Plasma path
comm -12 "$WORK/closure_libs.txt" "$WORK/bad_libs.txt" > "$WORK/bad_on_path.txt"
echo "=== closure libs: $(wc -l < "$WORK/closure_libs.txt") ==="
echo "=== bad libs total: $(wc -l < "$WORK/bad_libs.txt") ==="
echo "=== BAD ON PLASMA PATH: $(wc -l < "$WORK/bad_on_path.txt") ==="
cat "$WORK/bad_on_path.txt"
# closure edges referencing bad libs
echo "=== edges into bad libs ==="
grep -F -f "$WORK/bad_on_path.txt" "$WORK/closure_sorted.txt" | head -40
umount "$R"
umount "$M"; rmdir "$M"; losetup -d "$L"
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# Compare loop-mount view vs debugfs view of one "BAD" lib in extra-rootfs.
set -uo pipefail
IMG="${1:?usage: tmp_dbg_one.sh IMG}"
NAME="${2:-libz.so.1.3.2}"
OUT=/tmp/deshab-dbgone
rm -rf "$OUT"; mkdir -p "$OUT"
L=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${L}p1" "$M" || { echo ESP_MOUNT_FAIL; exit 1; }
# Copy the extra-rootfs image OFF drvfs first (loop off drvfs is suspect).
cp "$M/boot/linux-extra-rootfs.img" "$OUT/extra.img"
umount "$M"; rmdir "$M"; losetup -d "$L"
echo "=== debugfs view (no kernel fs) ==="
debugfs -R "dump /usr/lib/$NAME" "$OUT/df.$NAME" "$OUT/extra.img" 2>&1 | tail -2
ls -l "$OUT/df.$NAME" 2>/dev/null
head -c 64 "$OUT/df.$NAME" 2>/dev/null | od -A d -t x1 | head -5
echo "=== loop-mount view (kernel ext4) ==="
R=$(mktemp -d)
if mount -o loop,ro "$OUT/extra.img" "$R"; then
ls -l "$R/usr/lib/$NAME"
head -c 64 "$R/usr/lib/$NAME" | od -A d -t x1 | head -5
md5sum "$R/usr/lib/$NAME" "$OUT/df.$NAME"
umount "$R"
else
echo "loop mount FAILED"
fi
rmdir "$R"
readelf -h "$OUT/df.$NAME" 2>&1 | grep -E 'Class|Type|Entry|program headers|section header size' || echo "readelf failed on debugfs copy"
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -uo pipefail
OUT=/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify7_diag.txt
{
echo "===== dmesg oom/kvm ====="
dmesg -T 2>/dev/null | grep -iE 'oom|killed process|qemu|kvm' | tail -n 40 || true
echo "===== mem ====="
free -h
echo "===== img ====="
ls -lh /mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img
echo "===== last limine ====="
} >"$OUT" 2>&1
python3 - <<'PY'
from pathlib import Path
b = Path("/home/deshab/qemu_serial_loop1.log").read_bytes()
ascii_only = bytes(c if 32 <= c < 127 or c in (10, 13, 9) else 32 for c in b)
t = ascii_only.decode("ascii")
# collapse limine cursor addressing to readable words
import re
plain = re.sub(r"\[[0-9;]*[A-Za-z]", "", t)
plain = re.sub(r" +", " ", plain)
Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify7_limine.txt").write_text(
plain[-2500:], encoding="utf-8")
print("limine_plain", len(plain))
PY
echo DIAG_OK >>"$OUT"
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -uo pipefail
OUT=/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify9_diag.txt
{
echo "===== dmesg ====="
dmesg -T | tail -n 50
echo "===== free ====="
free -h
echo "===== qemu ====="
pgrep -a qemu || echo none
echo "===== verify9 out bytes ====="
wc -c /mnt/d/Code/DEAICUP/Deshab/.build_tmp/wsl_verify9.out
} >"$OUT" 2>&1
echo DIAG_OK
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -u
IMG=/home/deshab/deshab-dev.img
L=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${L}p1" "$M"
E=$(mktemp -d); R=$(mktemp -d)
mount -o loop,ro "$M/boot/linux-extra-rootfs.img" "$E"
mount -o loop,ro "$M/boot/linux-rootfs.img" "$R"
cp "$R/usr/lib/libc.so.6" /tmp/libc.vdb
cp "$E/usr/lib/libc.so.6" /tmp/libc.persist
umount "$R"; umount "$E"; umount "$M"
rmdir "$R" "$E" "$M"
losetup -d "$L"
python3 - <<'PY'
a = open('/tmp/libc.vdb','rb').read()
b = open('/tmp/libc.persist','rb').read()
print("len", len(a), len(b))
diffs = [i for i in range(min(len(a),len(b))) if a[i] != b[i]]
print("num_diff_bytes", len(diffs))
if diffs:
# group into ranges
ranges = []
s = p = diffs[0]
for i in diffs[1:]:
if i == p + 1:
p = i
else:
ranges.append((s, p)); s = p = i
ranges.append((s, p))
print("num_ranges", len(ranges))
for s, e in ranges[:40]:
print(f" range 0x{s:x}-0x{e:x} ({e-s+1} bytes) page=0x{s & ~0xfff:x}")
PY
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Newest UTSM sources — detect drift after the last good (Windows) build.
cd /mnt/d/Code/DEAICUP/Deshab/CODE/UTSM
find . \( -name '*.c' -o -name '*.S' -o -name '*.h' -o -name 'linker.ld' -o -name 'MAKEFILE' \) \
-newermt '2026-09-14' -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort -r | head -20
echo '=== obj dir leftovers (old Windows .o timestamps) ==='
ls -la --time-style='+%m-%d %H:%M' arch/x86_64/*.o 2>/dev/null | head -5
echo '=== build config template FUCK (what build.ps1 would inject) ==='
grep -n 'demo_ms\|selftest' /mnt/d/Code/DEAICUP/Deshab/build/configs/dev/FUCK 2>/dev/null || echo 'no build/configs/dev/FUCK'
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
python3 - <<'PY'
from pathlib import Path
p = Path("/home/deshab/qemu_serial_loop1.log")
b = p.read_bytes()
print("bytes", len(b))
text = b.replace(b"\x00", b"").replace(b"\r", b"").decode("utf-8", "replace")
lines = text.splitlines()
print("lines", len(lines))
out = Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_timeslice_all.txt")
out.write_text("\n".join(lines[:40] + ["..."] + lines[-60:]) + f"\n\nBYTES={len(b)} LINES={len(lines)}\n", encoding="utf-8")
PY
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -uo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('/home/deshab/qemu_serial_loop1.log')
t = p.read_bytes().decode('latin1', errors='replace')
t = t.replace('\r', '').replace('\x00', '')
keys = ('deshab-kde', 'utsm_bindmount', 'segfault', 'exec after', 'inside chroot',
'starting Plasma', 'starting Xorg', 'ERROR', 'env:', 'bash:')
for line in t.splitlines():
if any(k in line for k in keys):
print(line[:220])
print('--- bytes', len(t))
PY
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
LOG=/home/deshab/qemu_serial_loop1.log
OUT="$ROOT/.build_tmp/verify_timeslice.txt"
python3 - <<'PY'
from pathlib import Path
src = Path("/home/deshab/qemu_serial_loop1.log")
dst = Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_timeslice.txt")
data = src.read_bytes().replace(b"\x00", b"").replace(b"\r", b"")
text = data.decode("utf-8", "replace")
keys = (
"EXEC_READY", "guest parked", "session=", "desktop ready", "serial 2",
"deshab-kde", "vdc", "persist", "KDE ", "scanout", "starting Plasma",
"entering KDE", "async spawn", "execv failed", "VERIFY_", "checking persist",
"interpreter alive", "[DSK]", "desktop load", "FirstInit", "firstInit",
"dsk", "DSK", "FUCK", "switch_root", "HLT", "timeslice", "no EXEC_EXIT",
"linux_resume failed", "segfault", "PANIC", "oops", "desktop.elf",
"chooser", "waiting for 1",
)
lines = []
for line in text.splitlines():
if any(k.lower() in line.lower() for k in keys):
lines.append(line)
dst.write_text("\n".join(lines[-200:]) + f"\n\nLOG_BYTES={src.stat().st_size}\nMATCHED={len(lines)}\n", encoding="utf-8")
print(f"wrote {dst} matches={len(lines)} bytes={src.stat().st_size}")
PY
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
src = Path("/home/deshab/qemu_serial_loop1.log")
data = src.read_bytes().replace(b"\x00", b"").replace(b"\r", b"")
text = data.decode("utf-8", "replace")
lines = text.splitlines()
dst = Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_timeslice_tail.txt")
tail = lines[-80:]
dst.write_text("\n".join(tail) + f"\n\nTOTAL_LINES={len(lines)}\n", encoding="utf-8")
print("lines", len(lines), "tail", len(tail))
# also search DSK / desktop / load
hits = [ln for ln in lines if "DSK" in ln or "desktop" in ln or "dsk" in ln or "LNXC" in ln or "jumping" in ln]
Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_timeslice_dsk.txt").write_text("\n".join(hits[-80:]) + f"\nHITS={len(hits)}\n", encoding="utf-8")
print("dsk hits", len(hits))
PY
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
python3 - <<'PY'
from pathlib import Path
p = Path("/home/deshab/qemu_serial_loop1.log")
b = p.read_bytes()
dst = Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_timeslice_all.txt")
head = b[:200]
# printable
def vis(x):
return "".join(chr(c) if 32 <= c < 127 else f"[{c:02x}]" for c in x)
text = b.replace(b"\x00", b"").replace(b"\r", b"").decode("latin1", "replace")
lines = [ln for ln in text.splitlines() if ln.strip()]
dst.write_text(
"HEAD="+vis(head)+"\n\nNON_EMPTY="+str(len(lines))+"\n"+
"\n".join(lines[:80])+"\n",
encoding="utf-8",
)
print("nonzero", sum(1 for c in b if c), "empty_lines", text.count("\n"), "nonempty", len(lines))
PY
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# e2fsck the Arch rootfs that QEMU actually boots (native GPT ESP copy).
set -uo pipefail
OUT=/mnt/d/Code/DEAICUP/Deshab/.build_tmp/e2fsck_esp_rootfs.out
exec > >(stdbuf -oL tee "$OUT") 2>&1
killall qemu-system-x86_64 2>/dev/null || true
IMG=/home/deshab/deshab-dev.img
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${LOOP}p1" "$M"
RF="$M/boot/linux-rootfs.img"
ls -lh "$RF"
echo "===== e2fsck -fn ====="
e2fsck -fn "$RF" || true
echo "===== inodes ====="
for ino in 1673 1810 1826; do
echo "--- inode $ino ---"
debugfs -R "stat <$ino>" "$RF" 2>/dev/null | head -n 16 || true
debugfs -R "ncheck $ino" "$RF" 2>/dev/null || true
done
echo "===== /bin /usr/bin mount ====="
debugfs -R 'stat /bin/mount' "$RF" 2>/dev/null | head -n 10 || true
debugfs -R 'stat /usr/bin/mount' "$RF" 2>/dev/null | head -n 10 || true
debugfs -R 'stat /usr/lib/libmount.so.1' "$RF" 2>/dev/null | head -n 10 || true
debugfs -R 'ls -l /lib64' "$RF" 2>/dev/null | head -n 8 || true
umount "$M"
losetup -d "$LOOP"
rmdir "$M"
echo DONE
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
# Full ELF health scan of the extra-rootfs /usr/lib (read-only loop mount).
# Detects: non-ELF files, smashed headers (e_entry=0), truncated files
# (any PT_LOAD p_offset+p_filesz > file size -> ld.so SIGBUS on mmap tail).
set -uo pipefail
IMG="${1:?usage: tmp_elf_scan.sh IMG}"
L=$(losetup --find --show --partscan "$IMG" 2>/dev/null) || { echo LOSETUP_FAIL; exit 1; }
sleep 0.3
M=$(mktemp -d)
mount -o ro "${L}p1" "$M" || { echo ESP_MOUNT_FAIL; exit 1; }
R=$(mktemp -d)
mount -o loop,ro "$M/boot/linux-extra-rootfs.img" "$R" || { echo EXTRA_MOUNT_FAIL; exit 1; }
python3 - "$R" <<'PY'
import os, struct, sys
root = sys.argv[1]
dirs = [os.path.join(root, "usr", "lib"), os.path.join(root, "lib")]
bad = {}
checked = 0
for d in dirs:
if not os.path.isdir(d):
continue
for name in sorted(os.listdir(d)):
p = os.path.join(d, name)
if os.path.islink(p) or not os.path.isfile(p):
continue
if not (name.endswith(".so") or ".so." in name):
continue
checked += 1
try:
sz = os.path.getsize(p)
with open(p, "rb") as f:
hdr = f.read(64)
if len(hdr) < 64 or hdr[:4] != b"\x7fELF":
bad[p] = "NOT-ELF(%d)" % sz
continue
if hdr[4] != 2 or hdr[5] != 1: # 64-bit LE
bad[p] = "BAD-CLASS"
continue
# Explicit offsets: e_type@16 e_entry@24 e_phoff@32
# e_phentsize@54 e_phnum@56 (ELF64 little-endian)
e_type = struct.unpack_from("<H", hdr, 16)[0]
e_entry = struct.unpack_from("<Q", hdr, 24)[0]
e_phoff = struct.unpack_from("<Q", hdr, 32)[0]
e_phentsize = struct.unpack_from("<H", hdr, 54)[0]
e_phnum = struct.unpack_from("<H", hdr, 56)[0]
if e_type not in (2, 3): # ET_EXEC / ET_DYN
bad[p] = "BAD-TYPE(%d)" % e_type
continue
if e_entry == 0 and e_type == 3: # ET_DYN with null entry
bad[p] = "ENTRY0"
if e_phentsize < 56 or e_phnum == 0 or e_phnum > 128:
bad[p] = "PHDR-GARBAGE(phentsize=%d phnum=%d)" % (e_phentsize, e_phnum)
continue
end = 0
with open(p, "rb") as f:
f.seek(e_phoff)
ph = f.read(e_phentsize * e_phnum)
if len(ph) < e_phentsize * e_phnum:
bad[p] = "TRUNCATED(phdr table file=%d)" % sz
continue
for i in range(e_phnum):
off = i * e_phentsize
p_type, p_flags = struct.unpack_from("<II", ph, off)
p_offset = struct.unpack_from("<Q", ph, off + 8)[0]
# ELF64 Phdr: p_offset@8 p_vaddr@16 p_paddr@24
# p_filesz@32 p_memsz@40 p_align@48
p_filesz = struct.unpack_from("<Q", ph, off + 32)[0]
if p_type == 1: # PT_LOAD
end = max(end, p_offset + p_filesz)
if end > sz:
bad.setdefault(p, "TRUNCATED(phdr=%d file=%d short=%d)" % (end, sz, end - sz))
except OSError as e:
bad[p] = "IOERR:%s" % e
print("checked=%d bad=%d" % (checked, len(bad)))
for p, why in sorted(bad.items()):
print("BAD %-12s %s" % (why, os.path.basename(p)))
PY
umount "$R"; rmdir "$R"
umount "$M"; rmdir "$M"
losetup -d "$L"
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Restore persist ld.so/libc if objcopy broke them; report extra copies.
set -uo pipefail
OUT=/mnt/d/Code/DEAICUP/Deshab/.build_tmp/fix_persist_ld.out
exec > >(stdbuf -oL tee "$OUT") 2>&1
killall qemu-system-x86_64 2>/dev/null || true
echo "===== extra-rootfs candidates ====="
for p in \
/root/extra_rootfs_work/extra-rootfs.img \
/home/deshab/linux-extra-rootfs.img \
/home/deshab/extra-check.img \
/root/extra_rootfs_work/linux-extra-rootfs.img; do
if [[ -f "$p" ]]; then
echo "EXISTS $p $(stat -c %s "$p")"
debugfs -R 'stat /usr/lib/ld-linux-x86-64.so.2' "$p" 2>/dev/null | head -n 8 || true
else
echo "MISSING $p"
fi
done
echo "===== native GPT extra ld.so ====="
IMG=/home/deshab/deshab-dev.img
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount "${LOOP}p1" "$M"
EXTRA="$M/boot/linux-extra-rootfs.img"
ls -lh "$EXTRA"
E=$(mktemp -d)
if mount -o loop "$EXTRA" "$E"; then
echo "[extra] file ld.so"
file "$E/usr/lib/ld-linux-x86-64.so.2" "$E/usr/lib/libc.so.6" || true
echo "[extra] readelf ld.so notes"
readelf -n "$E/usr/lib/ld-linux-x86-64.so.2" 2>&1 | head -n 40 || true
echo "[extra] readelf ld.so program headers"
readelf -l "$E/usr/lib/ld-linux-x86-64.so.2" 2>&1 | head -n 30 || true
echo "[extra] ls env bash"
ls -l "$E/usr/bin/env" "$E/usr/bin/bash" "$E/bin/bash" "$E/usr/local/bin/deshab-kde-session" || true
umount "$E"
fi
rmdir "$E"
umount "$M"
losetup -d "$LOOP"
rmdir "$M"
echo DONE
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
T() { tr -d '\r\0' < /home/deshab/qemu_serial_loop1.log; }
echo '=== Plasma phase ==='
T | grep -a -E 'starting Plasma|Plasma (failed|session ended)|status 1[0-9][0-9]|FLUSH_N|flush count|kwin|plasmashell' | tail -12
echo '=== FLUSH context (lines around) ==='
T | grep -a -B3 -A3 'flush count' | tail -14
echo '=== late-session markers ==='
T | grep -a -E 'Xorg socket|Xorg pid|seatd_sock|entering KDE|deshab-kde. (chroot|interpreter)' | tail -6
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/wsl_fsck_patch.out"
exec > >(stdbuf -oL tee "$OUT") 2>&1
killall qemu-system-x86_64 2>/dev/null || true
sed -i 's/\r$//' \
"$ROOT/CODE/linux/tmp_patch_persist.sh" \
"$ROOT/CODE/linux/rebuild_initrd.sh" \
"$ROOT/CODE/linux/patch_boot_on_img.sh" \
"$ROOT/CODE/linux/guest/deshab-kde-session"
echo "[fsck] copy rootfs to native disk"
cp -f "$ROOT/SYSTEM/boot/linux-rootfs.img" /home/deshab/linux-rootfs-fsck.img
ls -lh /home/deshab/linux-rootfs-fsck.img
e2fsck -fy /home/deshab/linux-rootfs-fsck.img || true
cp -f /home/deshab/linux-rootfs-fsck.img "$ROOT/SYSTEM/boot/linux-rootfs.img"
echo "[fsck] copied back"
bash "$ROOT/CODE/linux/tmp_patch_persist.sh"
echo "[fsck] ALL_DONE $(date -Iseconds)"
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
IMG="$ROOT/ISO/deshab-dev.img"
killall qemu-system-x86_64 2>/dev/null || true
sleep 1
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount "${LOOP}p1" "$M"
EXTRA="$M/boot/linux-extra-rootfs.img"
echo "[fsck] $EXTRA"
ls -l "$EXTRA"
e2fsck -fy "$EXTRA" || true
sync
umount "$M"
losetup -d "$LOOP"
rmdir "$M"
echo FSCK_DONE
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# e2fsck Arch rootfs on the GPT ESP. Do not touch extra-rootfs from drvfs.
set -euo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
fsck_one() {
local img="$1"
[[ -f "$img" ]] || return 0
echo "[fsck] $img"
e2fsck -fy "$img" || true
}
fsck_one "$ROOT/SYSTEM/boot/linux-rootfs.img"
for gpt in "$ROOT/ISO/deshab-dev.img" /home/deshab/deshab-dev.img; do
[[ -f "$gpt" ]] || continue
loop=$(losetup --find --show --partscan "$gpt")
sleep 0.3
m=$(mktemp -d)
mount "${loop}p1" "$m"
fsck_one "$m/boot/linux-rootfs.img"
umount "$m"
losetup -d "$loop"
rmdir "$m"
echo "[fsck] done $gpt"
done
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Generate repair.txt: bind-mapping of good overlay copies over corrupt
# persist /usr/lib entities. Format per line: <chroot-src>|<chroot-dst>
set -uo pipefail
X=/home/deshab/xorg-libs
P=/home/deshab/plasma-libs
OUT=$X/repair.txt
: > "$OUT"
n=0; miss=0
while read -r name; do
[ -z "$name" ] && continue
src=""
if [ -e "$X/$name" ]; then src="$X/$name"
elif [ -e "$P/$name" ]; then src="$P/$name"
else miss=$((miss+1)); echo "MISSING:$name" >> "$OUT.missing"; continue; fi
# chroot-view source path (overlay dirs are bound at /usr/local/lib/*)
case "$src" in
$X/*) csrc="/usr/local/lib/xorg-libs/${src#$X/}" ;;
$P/*) csrc="/usr/local/lib/plasma-libs/${src#$P/}" ;;
esac
printf '%s|%s\n' "$csrc" "/usr/lib/$name" >> "$OUT"
n=$((n+1))
done < /home/deshab/notelf_list.txt
echo "mapped=$n missing=$miss -> $OUT"
wc -l "$OUT"
+5
View File
@@ -0,0 +1,5 @@
set -uo pipefail
LOG=/home/deshab/qemu_serial_loop1.log
echo "===== after startplasma ====="
grep -nE 'fatal signal|Plasma failed|SET_SCANOUT|plasmashell|startplasma|invalid ELF|xorg:' "$LOG" | tail -n 30
echo DONE
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Dump the first 64 bytes of one lib inside extra-rootfs (native img).
set -uo pipefail
IMG="${1:?img}"
NAME="${2:?libname}"
L=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${L}p1" "$M" || { echo ESP_FAIL; exit 1; }
R=$(mktemp -d)
mount -o loop,ro "$M/boot/linux-extra-rootfs.img" "$R" || { echo EXTRA_FAIL; exit 1; }
echo "=== $NAME in extra-rootfs ==="
od -A d -t x1 -N 64 "$R/usr/lib/$NAME"
echo "=== readelf ==="
readelf -h "$R/usr/lib/$NAME" 2>&1 | grep -E 'Class|Type|Entry|headers|Number of section' || true
umount "$R"; rmdir "$R"
umount "$M"; rmdir "$M"
losetup -d "$L"
+26
View File
@@ -0,0 +1,26 @@
from pathlib import Path
from collections import Counter
p = Path("/home/deshab/qemu_serial_loop1.log")
b = p.read_bytes().replace(b"\x00", b"").replace(b"\r", b"")
t = b.decode("utf-8", "replace")
lines = t.splitlines()
print("BYTES", len(b), "LINES", len(lines))
keys = (
"esp file", "extra-rootfs", "persist", "startplasma", "entering KDE",
"deshab-kde", "desktop ready", "WARNING", "ERROR", "bound", "vdc",
"VBLK", "LINUX", "launch", "DSM", "ahci", "guest parked", "EXEC_READY",
"switch_root", "utsm-linux", "idtr", "FAIL", "misconfig",
)
hits = [ln for ln in lines if any(k.lower() in ln.lower() for k in keys)]
print("HITS", len(hits))
print("===== first 80 hits =====")
print("\n".join(hits[:80]))
print("===== last 40 hits =====")
print("\n".join(hits[-40:]))
ctr = Counter(ln.split("=")[0][:60] if "=" in ln else ln[:60] for ln in lines)
print("===== top prefixes =====")
for k, n in ctr.most_common(20):
print(n, k)
+10
View File
@@ -0,0 +1,10 @@
from pathlib import Path
p = Path("/home/deshab/qemu_serial_loop1.log")
b = p.read_bytes().replace(b"\x00", b"").replace(b"\r", b"")
t = b.decode("utf-8", "replace")
want = ("[LINUX]", "[VBLK]", "extra-rootfs", "launch", "parked", "EXEC_READY",
"Linux loader", "Linux launch", "misconfig", "VMLAUNCH", "vmlaunch",
"[VIO]", "slot6", "ESP", "BLOCK]", "bound")
for ln in t.splitlines():
if any(k in ln for k in want):
print(ln)
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Hunt for surviving copies of the last-good utsm.elf (md5 3c5d359a...).
md5sum /mnt/d/Code/DEAICUP/Deshab/SYSTEM/boot/utsm.elf
find /mnt/d/Code/DEAICUP/Deshab /home/deshab /tmp -maxdepth 4 -name '*utsm*.elf*' -o -maxdepth 4 -name 'utsm.elf.*' 2>/dev/null | while read -r f; do
[ -f "$f" ] && echo "$(md5sum "$f" | cut -d' ' -f1) $(stat -c '%s %y' "$f" | cut -d'.' -f1) $f"
done | sort -u | head -20
echo '=== any backup dirs ==='
ls /mnt/d/Code/DEAICUP/Deshab/.build_tmp/ | grep -iE 'utsm|backup|bak' | head -10
ls /home/deshab/ | grep -iE 'utsm|bak|old' | head -10
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Report ESP payload identity for GPT images: md5 + size + build markers.
# Usage: tmp_img_esp_report.sh IMG [IMG...]
set -uo pipefail
FILES="boot/utsm.elf boot/linux-bzImage boot/linux-initrd.img limine.conf system/deshab64/FUCK"
for img in "$@"; do
if [[ ! -f "$img" ]]; then
echo "$(basename "$img"): missing"
continue
fi
L=$(losetup --find --show --partscan "$img")
sleep 0.3
M=$(mktemp -d)
if mount "${L}p1" "$M" 2>/dev/null; then
echo "== $(basename "$img") hdr_md5=$(dd if="$img" bs=1M count=2 status=none | md5sum | cut -d' ' -f1)"
for f in $FILES; do
if [[ -f "$M/$f" ]]; then
printf ' %-26s size=%-10s md5=%s\n' \
"$f" "$(stat -c %s "$M/$f")" "$(md5sum "$M/$f" | cut -d' ' -f1)"
else
printf ' %-26s MISSING\n' "$f"
fi
done
if [[ -f "$M/boot/utsm.elf" ]]; then
printf ' %-26s FLUSH_N=%s\n' "boot/utsm.elf" \
"$(strings -a "$M/boot/utsm.elf" | grep -c FLUSH_N || true)"
fi
umount "$M"
else
echo "$(basename "$img"): mount p1 failed"
fi
rmdir "$M"
losetup -d "$L"
done
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Report partition layout + filesystem types of a GPT image, without mounting.
set -uo pipefail
img="${1:-/mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img}"
echo "=== image $img ($(stat -c %s "$img") bytes)"
if command -v sgdisk >/dev/null 2>&1; then
sgdisk -p "$img" 2>/dev/null
else
echo "(sgdisk missing)"
fi
L=$(losetup --find --show --partscan "$img") || exit 1
sleep 0.3
echo "=== partitions"
lsblk -o NAME,SIZE,FSTYPE,LABEL,UUID "${L}"
for p in "${L}"p*; do
echo "--- $p"
file -s "$p" | cut -c1-200
done
losetup -d "$L"
+7
View File
@@ -0,0 +1,7 @@
set -uo pipefail
tar -C /tmp -xf /mnt/d/Code/DEAICUP/Deshab/.build_tmp/pkgs/libcap-ng.pkg.tar.zst usr/lib/libcap-ng.so usr/lib/libcap-ng.so.0 usr/lib/libcap-ng.so.0.0.0
cp -a /tmp/usr/lib/libcap-ng.so /tmp/usr/lib/libcap-ng.so.0 /tmp/usr/lib/libcap-ng.so.0.0.0 /home/deshab/xorg-libs/
echo "[capng] $(ls -l /home/deshab/xorg-libs/libcap-ng.so* | tr '\n' ' ')"
file /home/deshab/xorg-libs/libcap-ng.so.0.0.0
export XORG_LIBS=/home/deshab/xorg-libs
bash /mnt/d/Code/DEAICUP/Deshab/CODE/linux/tmp_patch_session.sh
+6
View File
@@ -0,0 +1,6 @@
set -uo pipefail
tar -C /tmp -xf /mnt/d/Code/DEAICUP/Deshab/.build_tmp/pkgs/libffi-3.8.0-1-x86_64.pkg.tar.zst
cp -a /tmp/usr/lib/libffi.so* /home/deshab/xorg-libs/
ls -l /home/deshab/xorg-libs/libffi.so*
export XORG_LIBS=/home/deshab/xorg-libs
bash /mnt/d/Code/DEAICUP/Deshab/CODE/linux/tmp_patch_session.sh
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -uo pipefail
PKG=/mnt/d/Code/DEAICUP/Deshab/.build_tmp/pkgs
DEST=/home/deshab/xorg-libs
MOD=/home/deshab/xorg-input
mkdir -p "$DEST" "$MOD"
stage=/tmp/input-stage
rm -rf "$stage"
mkdir -p "$stage"
for f in \
libinput-1.31.3-1-x86_64.pkg.tar.zst \
libevdev-1.13.7-1-x86_64.pkg.tar.zst \
mtdev-1.1.7-1-x86_64.pkg.tar.zst \
xf86-input-libinput-1.5.0-1-x86_64.pkg.tar.zst
do
tar -C "$stage" -xf "$PKG/$f"
done
cp -a "$stage"/usr/lib/libinput.so* "$stage"/usr/lib/libevdev.so* "$stage"/usr/lib/libmtdev.so* "$DEST"/
install -D -m 0755 "$stage"/usr/lib/xorg/modules/input/libinput_drv.so \
"$MOD/libinput_drv.so"
echo "[input] libs=$(ls "$DEST"/libinput.so* "$DEST"/libevdev.so* "$DEST"/libmtdev.so* | wc -l)"
file "$DEST"/libinput.so.10 "$DEST"/libevdev.so.2 "$DEST"/libmtdev.so.1 "$MOD/libinput_drv.so"
echo "===== libinput NEEDED ====="
readelf -d "$DEST"/libinput.so.10 | grep NEEDED || true
echo "[input] xorg-libs=$(ls "$DEST" | wc -l)"
# Do not set MODESET: that path is modesetting_drv.so, not the input driver.
export XORG_LIBS="$DEST"
bash /mnt/d/Code/DEAICUP/Deshab/CODE/linux/tmp_patch_session.sh
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
# Inspect Arch rootfs + extra-rootfs /dev and mount binaries.
# Never loop-mount extra-rootfs from /mnt/d.
set -uo pipefail
OUT=/mnt/d/Code/DEAICUP/Deshab/.build_tmp/inspect_dev.out
exec > >(stdbuf -oL tee "$OUT") 2>&1
killall qemu-system-x86_64 2>/dev/null || true
echo "===== arch rootfs on SYSTEM (768M, ok to loop) ====="
ARCH=/mnt/d/Code/DEAICUP/Deshab/SYSTEM/boot/linux-rootfs.img
if [[ -f "$ARCH" ]]; then
r=$(mktemp -d)
if mount -o loop,ro "$ARCH" "$r"; then
echo "[arch] ls -ld $r/dev"
ls -ld "$r/dev" "$r/bin/mount" "$r/usr/bin/mount" "$r/sbin/mount" "$r/usr/sbin/mount" 2>&1 || true
echo "[arch] mount candidates"
ls -l "$r/bin/mount" "$r/usr/bin/mount" "$r/bin/busybox"* 2>&1 || true
echo "[arch] PATH bins: mount umount chroot"
for n in mount umount chroot bash; do
find "$r/bin" "$r/usr/bin" "$r/sbin" "$r/usr/sbin" -name "$n" 2>/dev/null | head
done
echo "[arch] /dev contents"
ls -la "$r/dev" | head -n 40
umount "$r"
fi
rmdir "$r"
fi
echo "===== extra-rootfs via native GPT ESP (debugfs, no drvfs 4G loop) ====="
IMG=/home/deshab/deshab-dev.img
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${LOOP}p1" "$M"
EXTRA="$M/boot/linux-extra-rootfs.img"
ls -lh "$EXTRA" "$M/boot/linux-rootfs.img" || true
if [[ -f "$EXTRA" ]]; then
echo "[extra] debugfs ls /"
debugfs -R 'ls -l /' "$EXTRA" 2>/dev/null | head -n 40 || true
echo "[extra] debugfs stat /dev"
debugfs -R 'stat /dev' "$EXTRA" 2>/dev/null | head -n 25 || true
echo "[extra] debugfs ls /dev"
debugfs -R 'ls -l /dev' "$EXTRA" 2>/dev/null | head -n 40 || true
echo "[extra] debugfs stat /usr/bin/mount"
debugfs -R 'stat /usr/bin/mount' "$EXTRA" 2>/dev/null | head -n 15 || true
echo "[extra] debugfs stat /usr/bin/Xorg"
debugfs -R 'stat /usr/bin/Xorg' "$EXTRA" 2>/dev/null | head -n 12 || true
echo "[extra] debugfs stat /usr/lib/xorg/modules/drivers/modesetting_drv.so"
debugfs -R 'stat /usr/lib/xorg/modules/drivers/modesetting_drv.so' "$EXTRA" 2>/dev/null | head -n 12 || true
fi
if [[ -f "$M/boot/linux-rootfs.img" ]]; then
echo "[esp-arch] debugfs stat /usr/bin/mount"
debugfs -R 'stat /usr/bin/mount' "$M/boot/linux-rootfs.img" 2>/dev/null | head -n 12 || true
echo "[esp-arch] debugfs ls /bin"
debugfs -R 'ls -l /bin' "$M/boot/linux-rootfs.img" 2>/dev/null | tr ' ' '\n' | grep -E 'mount|busybox|bash' || true
fi
umount "$M"
losetup -d "$LOOP"
rmdir "$M"
echo DONE
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# Inspect GPT images: embedded utsm.elf, ESP files, and X11 library health
# inside the ESP linux-rootfs.img (/usr/local/lib/xorg-libs + Xorg.good).
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
EXP=$(md5sum "$ROOT/SYSTEM/boot/utsm.elf" | cut -d' ' -f1)
echo "expected utsm.elf md5=$EXP size=$(stat -c %s "$ROOT/SYSTEM/boot/utsm.elf")"
check_lib() {
local f="$1"
if [[ ! -e "$f" ]]; then echo " MISSING $f"; return; fi
local kind
kind=$(file -b "$f" 2>/dev/null | cut -c1-60)
local ent=""
if [[ "$kind" == ELF* ]]; then
ent=$(readelf -h "$f" 2>/dev/null | awk '/Entry point/{print $4}')
fi
printf ' %-46s %10s %-40s entry=%s\n' "$(basename "$f")" "$(stat -c %s "$f")" "$kind" "$ent"
}
for img in "$@"; do
echo "=== $img"
[[ -f "$img" ]] || { echo " missing"; continue; }
L=$(losetup --find --show --partscan "$img")
sleep 0.3
M=$(mktemp -d)
mount "${L}p1" "$M" 2>/dev/null || { echo " ESP mount failed"; losetup -d "$L"; rmdir "$M"; continue; }
got=$(md5sum "$M/boot/utsm.elf" 2>/dev/null | cut -d' ' -f1)
n=$(strings -a "$M/boot/utsm.elf" 2>/dev/null | grep -c FLUSH_N || true)
[[ "$got" == "$EXP" ]] && st=CURRENT || st=STALE
echo " utsm.elf: $st md5=$got FLUSH_N=$n"
for f in boot/linux-bzImage boot/linux-initrd.img boot/linux-rootfs.img boot/linux-extra-rootfs.img; do
[[ -f "$M/$f" ]] && echo " $(basename "$f"): $(stat -c %s "$M/$f") bytes $(stat -c %y "$M/$f" | cut -c1-19)"
done
R=$(mktemp -d)
if mount -o loop,ro "$M/boot/linux-rootfs.img" "$R" 2>/dev/null; then
echo " -- rootfs /usr/local/lib/xorg-libs: $(ls "$R/usr/local/lib/xorg-libs" 2>/dev/null | wc -l) files"
check_lib "$R/usr/local/lib/Xorg.good"
for lib in libinput.so.10 libffi.so.8 libXdmcp.so.6.0.0 libpixman-1.so.0 libXau.so.6.0.0 libdrm.so.2 libxfont2.so.2 libXfont2.so.2 libeudev.so.1 libwacom.so.9 libmtdev.so.1 libevdev.so.2 libgudev-1.0.so.0 libxkbcommon.so.0 libxcb.so.1 libX11.so.6; do
check_lib "$R/usr/local/lib/xorg-libs/$lib"
done
echo " -- rootfs own copies:"
for p in usr/lib/Xorg usr/lib/libinput.so.10 usr/lib/libffi.so.8 usr/lib/libc.so.6 usr/lib/libXdmcp.so.6.0.0; do
check_lib "$R/$p"
done
echo " -- xorg modules(drivers): $(ls "$R/usr/local/lib/xorg/modules/drivers" 2>/dev/null | tr '\n' ' ')"
umount "$R"
else
echo " rootfs mount failed"
fi
rmdir "$R"
umount "$M"
losetup -d "$L"
rmdir "$M"
done
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -u
IMG=/home/deshab/deshab-dev.img
L=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${L}p1" "$M"
R=$(mktemp -d)
mount -o loop,ro "$M/boot/linux-rootfs.img" "$R"
XL="$R/usr/local/lib/xorg-libs"
echo "== xorg-libs count =="
ls "$XL" | wc -l
echo "== libc/libdbus/ld in overlay =="
ls -la "$XL" | grep -E 'libc|libdbus|ld-linux' || echo "(none in overlay)"
echo "== full listing =="
ls "$XL"
echo "== ELF health scan of overlay =="
bad=0
for f in "$XL"/*; do
[ -f "$f" ] || continue
t=$(file -b "$f")
case "$t" in
*ELF*) ;;
*"symbolic link"*) ;;
*) echo "BAD: $(basename "$f"): $t"; bad=$((bad+1));;
esac
done
echo "bad=$bad"
echo "== which libc would win: LD_LIBRARY_PATH=/usr/local/lib/xorg-libs =="
ls -la "$XL/libc.so.6" 2>/dev/null || echo "no libc.so.6 in overlay -> persist /usr/lib/libc.so.6 wins"
echo "== persist-side libc check inside vdb rootfs =="
ls -la "$R"/usr/lib/libc.so.6 "$R"/usr/lib/libdbus-1.so.3* 2>/dev/null
file "$R"/usr/lib/libc.so.6 2>/dev/null
umount "$R"; rmdir "$R"
umount "$M"; rmdir "$M"
losetup -d "$L"
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
T() { tr -d '\r\0' < /home/deshab/qemu_serial_loop1.log; }
N=$(T | grep -a -n 'inside-bash' | tail -1 | cut -d: -f1)
T | tail -n +$N | grep -a 'deshab-kde' | grep -a -v 'plasma-tail' | tail -22
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Focused health check: does the ESP rootfs payload contain a *loadable* copy of
# every X11 lib the KDE session depends on? Reports name, kind, size, .text.
set -uo pipefail
img="${1:?usage: tmp_lib_focus.sh IMG}"
dir=/usr/local/lib/xorg-libs
L=$(losetup --find --show --partscan "$img"); sleep 0.3
M=$(mktemp -d); mount "${L}p1" "$M" || { echo "ESP mount failed"; exit 1; }
echo "=== $(basename "$img")"
echo "utsm.elf md5=$(md5sum "$M/boot/utsm.elf" | cut -d' ' -f1)"
R=$(mktemp -d); mount -o loop,ro "$M/boot/linux-rootfs.img" "$R" || { echo "rootfs mount failed"; exit 1; }
D="$R$dir"
echo "--- $dir ($(ls "$D" 2>/dev/null | wc -l) entries) ---"
printf '%-30s %-9s %10s %9s %6s %s\n' NAME KIND SIZE TEXT SYMS NOTE
for n in libinput.so.10 libffi.so.8 libXdmcp.so.6 libXau.so.6 libdrm.so.2 \
libxfont2.so.2 libpixman-1.so.0 libevdev.so.2 libmtdev.so.1 \
libpciaccess.so.0 libfontenc.so.1 libxshmfence.so.1 libxcvt.so.0 \
libXfont.so.1 libwayland-client.so.0 libepoxy.so.0; do
f="$D/$n"
if [[ ! -e "$f" ]]; then printf '%-30s %-9s\n' "$n" MISSING; continue; fi
if [[ -L "$f" ]]; then t=$(readlink -f "$f"); k=SYMLINK; else t="$f"; k=FILE; fi
if [[ ! -e "$t" ]]; then printf '%-30s %-9s %s\n' "$n" DANGLING "$(readlink "$f")"; continue; fi
magic=$(head -c4 "$t" | tr -d '\0')
sz=$(stat -c %s "$t")
if [[ "$magic" != $'\x7fELF' ]]; then
printf '%-30s %-9s %10s %9s %6s %s\n' "$n" NOT-ELF "$sz" - - "$(file -b "$t" | cut -c1-28)"
continue
fi
text=$(readelf -SW "$t" 2>/dev/null | awk '$2==".text"{print strtonum("0x"$6)}')
syms=$(readelf -sW --dyn-syms "$t" 2>/dev/null | grep -c FUNC)
note=""
[[ -z "$text" ]] && { note="NO-.text"; text=0; }
[[ "$text" -lt 4096 && "$sz" -gt 20000 ]] && note="$note SMALL-TEXT"
[[ "$syms" -lt 5 ]] && note="$note FEW-SYMS"
printf '%-30s %-9s %10s %9s %6s %s\n' "$n" "$k" "$sz" "$text" "$syms" "$note"
done
echo "--- Xorg / input modules ---"
for p in usr/local/lib/Xorg.good usr/local/lib/Xorg usr/lib/Xorg \
usr/local/lib/xorg/modules/drivers/modesetting_drv.so \
usr/local/lib/xorg/modules/input/libinput_drv.so \
usr/local/lib/xorg/modules/input/mouse_drv.so \
usr/local/lib/xorg/modules/input/kbd_drv.so; do
f="$R/$p"
if [[ -e "$f" ]]; then
printf '%-56s %10s %s\n' "$p" "$(stat -c %s "$f")" "$(file -b "$f" | cut -c1-34)"
else
printf '%-56s %10s\n' "$p" absent
fi
done
umount "$R"; rmdir "$R"; umount "$M"; losetup -d "$L"; rmdir "$M"
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Deep health scan of the ESP linux-rootfs.img X11 payload:
# resolves symlinks, reports ELF validity, .text size and dynamic symbols so a
# "smashed header" library (right size, truncated .text) is obvious.
set -uo pipefail
img="${1:-/mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img}"
dir="${2:-/usr/local/lib/xorg-libs}"
L=$(losetup --find --show --partscan "$img"); sleep 0.3
M=$(mktemp -d); mount "${L}p1" "$M" || { echo "ESP mount failed"; exit 1; }
R=$(mktemp -d); mount -o loop,ro "$M/boot/linux-rootfs.img" "$R" || { echo "rootfs mount failed"; exit 1; }
D="$R$dir"
echo "=== $img : $dir ($(ls "$D" 2>/dev/null | wc -l) entries)"
printf '%-34s %-9s %9s %9s %7s %s\n' NAME KIND SIZE TEXT SYMS NOTE
while IFS= read -r f; do
name=$(basename "$f")
if [[ -L "$f" ]]; then
tgt=$(readlink -f "$f" 2>/dev/null || true)
if [[ -z "$tgt" || ! -e "$tgt" ]]; then
printf '%-34s %-9s %9s %9s %7s %s\n' "$name" SYMLINK - - - "DANGLING -> $(readlink "$f")"
continue
fi
f="$tgt"
fi
magic=$(head -c4 "$f" 2>/dev/null | tr -d '\0')
if [[ "$magic" != $'\x7fELF' ]]; then
printf '%-34s %-9s %9s %9s %7s %s\n' "$name" NOT-ELF "$(stat -c %s "$f")" - - "$(file -b "$f" | cut -c1-30)"
continue
fi
sz=$(stat -c %s "$f")
text=$(readelf -SW "$f" 2>/dev/null | awk '$2==".text"{print strtonum("0x"$6)}')
syms=$(readelf -sW --dyn-syms "$f" 2>/dev/null | grep -c 'FUNC')
note=""
[[ -z "$text" ]] && { note="NO-.text"; text=0; }
[[ "$text" -lt 4096 && "$sz" -gt 20000 ]] && note="${note} SMALL-TEXT"
[[ "$syms" -lt 5 ]] && note="${note} FEW-SYMS"
printf '%-34s %-9s %9s %9s %7s %s\n' "$name" ELF "$sz" "$text" "$syms" "$note"
done < <(find "$D" -maxdepth 1 \( -type f -o -type l \) | sort)
umount "$R"; rmdir "$R"; umount "$M"; losetup -d "$L"; rmdir "$M"
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -u
cd /mnt/d/Code/DEAICUP/Deshab
echo "SYSTEM: $(md5sum SYSTEM/boot/utsm.elf | cut -d' ' -f1)"
for img in ISO/deshab-dev.img ISO/deshab-release.img ISO/deshab-realtest.img; do
L=$(losetup --find --show --partscan "$img" 2>/dev/null) || { echo "$img: LOSETUP_FAIL"; continue; }
sleep 0.3
M=$(mktemp -d)
if mount "${L}p1" "$M" 2>/dev/null; then
echo "$img: $(md5sum "$M/boot/utsm.elf" 2>/dev/null | cut -d' ' -f1)"
umount "$M" 2>/dev/null
else
echo "$img: MOUNT_FAIL"
fi
rmdir "$M" 2>/dev/null
losetup -d "$L" 2>/dev/null
done
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Mount the GPT image partitions read-only on the host and report the KDE payload layout.
# Goal: decide whether the "truncated / smashed .so" symptom seen in the guest is present
# in the on-disk image (build-time corruption) or only appears at guest runtime (block path).
# Usage: bash tmp_mount_persist.sh [image]
set -u
IMG=${1:-/mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img}
P1=/mnt/deshab_p1
P2=/mnt/deshab_p2
umount -q "$P1" 2>/dev/null
umount -q "$P2" 2>/dev/null
mkdir -p "$P1" "$P2"
L=$(losetup --partscan --find --show "$IMG")
echo "=== loop $L"
mount -o ro "${L}p1" "$P1" || { echo "mount p1 failed"; exit 1; }
mount -o ro "${L}p2" "$P2" || { echo "mount p2 failed"; exit 1; }
echo "=== p1 top"
ls -la "$P1"
echo "=== p1 nested images"
ls -la "$P1/boot" 2>/dev/null
echo "=== p2 top"
ls -la "$P2"
echo "=== p2 usr"
ls -la "$P2/usr" 2>/dev/null | head -30
echo "=== p2 lib dirs"
ls -la "$P2/usr/lib" 2>/dev/null | head -20
ls -la "$P2/usr/lib64" 2>/dev/null | head -20
echo "=== p2 bin"
ls -la "$P2/usr/bin" 2>/dev/null | head -60
echo "=== df"
df -h "$P1" "$P2"
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
cd /home/deshab/plasma-libs
mv -v libunwind* /home/deshab/xorg-libs/ 2>/dev/null | tail -2
echo "xorg=$(ls /home/deshab/xorg-libs | wc -l) plasma=$(ls /home/deshab/plasma-libs | wc -l)"
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
# Check the *on-disk* health of the nested Linux payloads inside the ESP:
# linux-rootfs.img, linux-extra-rootfs.img
# If a .so is truncated here, the guest SIGBUS is a build-time artifact.
# If everything is clean here, the corruption happens on the guest block path.
# Usage: bash tmp_nested_check.sh [esp-mount]
set -u
ESP=${1:-/mnt/deshab_p1}
RF=$ESP/boot/linux-rootfs.img
XRF=$ESP/boot/linux-extra-rootfs.img
M1=/mnt/deshab_rf
M2=/mnt/deshab_xrf
umount -q "$M1" 2>/dev/null
umount -q "$M2" 2>/dev/null
mkdir -p "$M1" "$M2"
echo "=== fsck rootfs (read-only, no repair)"
e2fsck -fn "$RF" 2>&1 | tail -15
echo "=== fsck extra-rootfs (read-only, no repair)"
e2fsck -fn "$XRF" 2>&1 | tail -15
L1=$(losetup --find --show "$RF")
L2=$(losetup --find --show "$XRF")
echo "=== loops $L1 $L2"
mount -o ro "$L1" "$M1" || { echo "mount rootfs failed"; exit 1; }
mount -o ro "$L2" "$M2" || { echo "mount extra-rootfs failed"; exit 1; }
echo "=== rootfs top"
ls -la "$M1"
echo "=== extra-rootfs top"
ls -la "$M2"
echo "=== extra-rootfs dirs of interest"
ls -la "$M2/usr" "$M2/usr/bin" 2>/dev/null | head -50
echo "=== extra-rootfs local libs"
ls -la "$M2/usr/local/lib" 2>/dev/null | head -20
ls -la "$M2/usr/local/lib/xorg-libs" 2>/dev/null | head -20
report() {
local f=$1
if [ ! -e "$f" ]; then echo "MISSING $f"; return; fi
local kind size
size=$(stat -c %s "$f")
kind=$(head -c 4 "$f" | od -An -tx1 | tr -d ' \n')
local dync
dync=$(readelf -d "$f" 2>/dev/null | grep -c NEEDED)
local err
err=$(readelf -h "$f" 2>&1 >/dev/null | head -1)
printf '%-70s size=%-10s magic=%-8s NEEDED=%-3s %s\n' "$f" "$size" "$kind" "$dync" "$err"
}
export -f report
echo "=== key X11/KDE ELFs on extra-rootfs"
for f in \
"$M2/usr/bin/startplasma-x11" "$M2/usr/bin/plasmashell" "$M2/usr/bin/ksmserver" \
"$M2/usr/bin/kwin_x11" "$M2/usr/bin/Xorg" "$M2/usr/lib/Xorg" \
"$M2/usr/lib/libdbus-1.so.3" "$M2/usr/lib/libKF5Plasma.so.5" ; do
report "$f"
done
echo "=== key X11/KDE ELFs on rootfs"
for f in "$M1/usr/bin/Xorg" "$M1/usr/lib/Xorg" "$M1/usr/bin/startplasma-x11"; do
report "$f"
done
echo "=== truncation sweep: ELFs whose size is 0 or unreadable headers"
find "$M1" "$M2" -xdev -type f \( -name '*.so*' -o -perm -u+x \) -size -64k 2>/dev/null | head -40
echo "=== zero-size files"
find "$M1" "$M2" -xdev -type f -size 0 2>/dev/null | head -40
echo "=== df"
df -h "$M1" "$M2"
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env bash
# Rebuild initrd, probe extra-rootfs without drvfs loop-mount, inject, verify.
set -euo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
export REPO="$ROOT"
killall qemu-system-x86_64 2>/dev/null || true
sleep 1
sed -i 's/\r$//' \
"$ROOT/CODE/linux/rebuild_initrd.sh" \
"$ROOT/CODE/linux/inject_boot_and_busybox.sh" \
"$ROOT/CODE/linux/patch_boot_on_img.sh" \
"$ROOT/CODE/linux/qemu_verify_loop.sh" \
"$ROOT/CODE/linux/guest/deshab-kde-session" \
"$ROOT/ISO/run_qemu_kvm.sh" \
"$ROOT/CODE/linux/grep_serial.sh"
echo "===== extra-rootfs probe (no drvfs loop mount) ====="
python3 - <<'PY'
from pathlib import Path
cands = [
Path('/root/extra_rootfs_work/extra-rootfs.img'),
Path('/home/deshab/linux-extra-rootfs.img'),
Path('/home/deshab/extra-check.img'),
Path('/mnt/d/Code/DEAICUP/Deshab/SYSTEM/boot/linux-extra-rootfs.img'),
]
for p in cands:
if p.exists():
print(f'EXISTS {p} bytes={p.stat().st_size}')
else:
print(f'MISSING {p}')
PY
# Read-only debugfs on a NATIVE copy if present. Never mount the /mnt/d image.
NATIVE=""
for p in /root/extra_rootfs_work/extra-rootfs.img /home/deshab/linux-extra-rootfs.img; do
if [ -f "$p" ]; then NATIVE="$p"; break; fi
done
if [ -n "$NATIVE" ]; then
echo "[extra] debugfs $NATIVE"
debugfs -R 'stat /usr/bin/startplasma-x11' "$NATIVE" 2>/dev/null | head -n 20 || true
debugfs -R 'stat /usr/local/bin/deshab-kde-session' "$NATIVE" 2>/dev/null | head -n 8 || true
else
echo "[extra] no native extra-rootfs image; skip debugfs"
fi
echo "===== rebuild initrd ====="
bash "$ROOT/CODE/linux/rebuild_initrd.sh"
echo "===== inject (rootfs only, no extra loop-mount) ====="
bash "$ROOT/CODE/linux/inject_boot_and_busybox.sh"
echo INJECT_OK
export QEMU_SEND_KDE=1
export QEMU_VERIFY_TIMEOUT=360
set +e
bash "$ROOT/CODE/linux/qemu_verify_loop.sh"
rc=$?
set -e
echo "VERIFY_RC=$rc"
echo "===== dump markers ====="
python3 - <<'PY'
from pathlib import Path
p = Path('/home/deshab/qemu_serial_loop1.log')
t = p.read_text('utf-8', errors='replace') if p.exists() else ''
needles = [
'desktop ready', 'EPT misconfig', 'EPT reuse', 'EXEC_READY',
'[deshab-kde]', 'execv failed', 'async spawn', 'async exec',
'interpreter alive', 'entering KDE', 'startplasma', 'Plasma',
'clear_page_erms', 'EXT4-fs error', 'allocate_slab',
'KDE scanout', 'VERIFY_', 'serial 2',
]
lines = []
lines.append(f'bytes={len(t.encode("utf-8", "replace"))}')
for n in needles:
lines.append(f'{n!r}: {t.find(n)}')
nv = [ln for ln in t.splitlines() if not ln.startswith('[VMEXIT]')
and 'reason=' not in ln and 'qual=' not in ln]
lines.append('--- last 40 non-vmexit ---')
lines.extend(nv[-40:])
out = Path('/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_dump7.txt')
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text('\n'.join(lines), encoding='utf-8')
print('wrote', out)
PY
exit 0
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Extract unique NOT-ELF lib names from the scan output.
set -uo pipefail
F=/home/deshab/elfscan_native.txt
grep NOT-ELF "$F" | awk '{print $NF}' | sort -u > /home/deshab/notelf_list.txt
wc -l /home/deshab/notelf_list.txt
cat /home/deshab/notelf_list.txt | tr '\n' ' '
echo
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Assess the parallel session's state: QEMU running? new kernel markers? image ESP state?
echo '=== QEMU / ports ==='
pgrep -af 'qemu-system' | head -3 || echo 'no qemu'
ss -ltn 2>/dev/null | grep -E '45454|45455' || echo 'ports free'
echo '=== new kernel 992fa386 markers ==='
K=/mnt/d/Code/DEAICUP/Deshab/SYSTEM/boot/utsm.elf
strings -a "$K" | grep -c 'VGPU. FLUSH_N'
strings -a "$K" | grep -c 'selftest_irq\|tick 竞态' 2>/dev/null || true
echo '=== image ESP kernels now ==='
for img in /mnt/d/Code/DEAICUP/Deshab/ISO/deshab-dev.img /home/deshab/deshab-dev.img; do
L=$(losetup --find --show --partscan "$img" 2>/dev/null) || { echo "$img: LOSETUP_FAIL"; continue; }
sleep 0.3
M=$(mktemp -d)
if mount -o ro "${L}p1" "$M" 2>/dev/null; then
echo "$(basename "$img"): $(md5sum "$M/boot/utsm.elf" 2>/dev/null | cut -d' ' -f1) FUCK_demo_ms=$(grep -a '^demo_ms' "$M/system/deshab64/FUCK" 2>/dev/null)"
umount "$M"
fi
rmdir "$M" 2>/dev/null
losetup -d "$L" 2>/dev/null
done
echo '=== parallel-edit check: sched.c mtime now ==='
stat -c '%y' /mnt/d/Code/DEAICUP/Deshab/CODE/UTSM/sched/sched.c | cut -d'.' -f1
ls -la --time-style='+%H:%M:%S' /mnt/d/Code/DEAICUP/Deshab/CODE/UTSM/obj 2>/dev/null | head -3
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Re-sync the ESP boot payload (+ guest scripts / X11 libs) on existing GPT
# images without recopying the 4GiB extra-rootfs. Then prove the in-image
# utsm.elf md5 matches SYSTEM/boot/utsm.elf.
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
expected=$(md5sum "$ROOT/SYSTEM/boot/utsm.elf" | cut -d' ' -f1)
echo "[patch-all] expected utsm.elf md5=$expected"
for img in "$@"; do
[[ -f "$img" ]] || { echo "[patch-all] $img: missing"; continue; }
echo "[patch-all] === $(basename "$img") ==="
bash "$ROOT/CODE/linux/patch_boot_on_img.sh" "$img" "$ROOT" || {
echo "[patch-all] $img: PATCH FAILED"
continue
}
L=$(losetup --find --show --partscan "$img")
sleep 0.3
M=$(mktemp -d)
if mount "${L}p1" "$M" 2>/dev/null; then
got=$(md5sum "$M/boot/utsm.elf" 2>/dev/null | cut -d' ' -f1)
n=$(strings -a "$M/boot/utsm.elf" 2>/dev/null | grep -c FLUSH_N || true)
umount "$M"
if [[ "$got" == "$expected" ]]; then
echo "[patch-all] $(basename "$img"): CURRENT utsm.elf md5=$got FLUSH_N=$n"
else
echo "[patch-all] $(basename "$img"): STILL STALE md5=$got"
fi
else
echo "[patch-all] $(basename "$img"): mount p1 failed"
fi
rmdir "$M"
losetup -d "$L"
done
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Rebuild initrd (persist bind) and patch both GPT images. No QEMU.
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/wsl_patch_persist.out"
exec > >(stdbuf -oL tee "$OUT") 2>&1
sed -i 's/\r$//' \
"$ROOT/CODE/linux/rebuild_initrd.sh" \
"$ROOT/CODE/linux/patch_boot_on_img.sh" \
"$ROOT/CODE/linux/initramfs/init" \
"$ROOT/CODE/linux/guest/deshab-kde-session"
export SKIP_ROOTFS_PATCH=1
bash "$ROOT/CODE/linux/rebuild_initrd.sh"
rc=$?
echo "[patch] initrd_exit=$rc"
[[ $rc -eq 0 ]] || exit $rc
bash "$ROOT/CODE/linux/patch_boot_on_img.sh" "$ROOT/ISO/deshab-dev.img"
echo "[patch] iso_exit=$?"
if [[ -f /home/deshab/deshab-dev.img ]]; then
bash "$ROOT/CODE/linux/patch_boot_on_img.sh" /home/deshab/deshab-dev.img
echo "[patch] native_exit=$?"
fi
echo "[patch] done $(date -Iseconds)"
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Inject updated KDE session + verify script bits. No initrd rebuild.
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/wsl_patch_session.out"
exec > >(stdbuf -oL tee "$OUT") 2>&1
killall qemu-system-x86_64 2>/dev/null || true
sed -i 's/\r$//' \
"$ROOT/CODE/linux/patch_boot_on_img.sh" \
"$ROOT/CODE/linux/qemu_verify_loop.sh" \
"$ROOT/CODE/linux/guest/deshab-kde-session" \
"$ROOT/CODE/linux/tmp_run_visible.sh"
echo "[patch] compiling utsm_bindmount utsm_run"
cc -static -O2 -Wall -fcf-protection=none \
-o "$ROOT/.build_tmp/utsm_bindmount" \
"$ROOT/CODE/linux/initramfs/bin/utsm_bindmount.c"
cc -static -O2 -Wall -fcf-protection=none \
-o "$ROOT/.build_tmp/utsm_run" \
"$ROOT/CODE/linux/initramfs/bin/utsm_run.c"
strip "$ROOT/.build_tmp/utsm_bindmount" 2>/dev/null || true
strip "$ROOT/.build_tmp/utsm_run" 2>/dev/null || true
ls -l "$ROOT/.build_tmp/utsm_bindmount" "$ROOT/.build_tmp/utsm_run"
export XORG_LIBS=/home/deshab/xorg-libs
export PLASMA_LIBS=/home/deshab/plasma-libs
export MODESET=/home/deshab/modesetting_drv.so
bash "$ROOT/CODE/linux/patch_boot_on_img.sh" "$ROOT/ISO/deshab-dev.img"
echo "[patch] iso_exit=$?"
if [[ -f /home/deshab/deshab-dev.img ]]; then
bash "$ROOT/CODE/linux/patch_boot_on_img.sh" /home/deshab/deshab-dev.img
echo "[patch] native_exit=$?"
fi
echo "[patch] done $(date -Iseconds)"
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Patch utsm.elf + limine.conf onto GPT images. No QEMU, no extra-rootfs mount.
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/wsl_patch_vdc.out"
exec > >(stdbuf -oL tee "$OUT") 2>&1
sed -i 's/\r$//' "$ROOT/CODE/linux/patch_boot_on_img.sh"
ls -lh "$ROOT/SYSTEM/boot/utsm.elf" "$ROOT/SYSTEM/limine/limine.conf"
bash "$ROOT/CODE/linux/patch_boot_on_img.sh" "$ROOT/ISO/deshab-dev.img"
echo "[patch] iso_exit=$?"
if [[ -f /home/deshab/deshab-dev.img ]]; then
bash "$ROOT/CODE/linux/patch_boot_on_img.sh" /home/deshab/deshab-dev.img
echo "[patch] native_exit=$?"
fi
echo "[patch] done $(date -Iseconds)"
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -uo pipefail
IMG=/home/deshab/deshab-dev.img
killall qemu-system-x86_64 2>/dev/null || true
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount -o ro "${LOOP}p1" "$M"
EXTRA="$M/boot/linux-extra-rootfs.img"
W=/tmp/plasma-deps
mkdir -p "$W"
debugfs -R "dump /usr/lib/libpam.so.0.85.1 $W/pam" "$EXTRA" >/dev/null
debugfs -R "dump /usr/lib/libpam_misc.so.0.82.1 $W/pammisc" "$EXTRA" >/dev/null
echo "===== pam NEEDED ====="
readelf -d "$W/pam" "$W/pammisc" | grep NEEDED || true
magic_of() {
local path="$1"
local dest sz mag
dest=$(debugfs -R "stat $path" "$EXTRA" 2>/dev/null | sed -n 's/.*Fast link dest: "//p' | tr -d '"')
if [[ -n "$dest" ]]; then
[[ "$dest" != /* ]] && dest="$(dirname "$path")/$dest"
path="$dest"
fi
sz=$(debugfs -R "stat $path" "$EXTRA" 2>/dev/null | sed -n 's/.*Size: *//p' | awk '{print $1; exit}')
mag=$(debugfs -R "cat $path" "$EXTRA" 2>/dev/null | head -c 4 | od -An -tx1 | tr -s ' ')
echo "$path size=${sz:-?} magic=$mag"
}
while read -r name; do
[[ -n "$name" ]] || continue
magic_of "/usr/lib/$name"
done < <(readelf -d "$W/pam" "$W/pammisc" | sed -n 's/.*Shared library: \[\(.*\)\]/\1/p' | sort -u)
umount "$M"
losetup -d "$LOOP"
rmdir "$M"
echo DONE
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Symbolize 0xffffffff800669f0 (r10 in the GP fault dumps) + dump bytes there.
E=/mnt/d/Code/DEAICUP/Deshab/SYSTEM/boot/utsm.elf
nm -n "$E" > /tmp/syms2.txt
python3 - <<'PY'
t = 0xffffffff800669f0
prev = None
with open("/tmp/syms2.txt") as f:
for ln in f:
p = ln.split()
if len(p) >= 3:
try:
v = int(p[0], 16)
except ValueError:
continue
if v > t:
print("below:", prev)
print("above:", ln.rstrip())
break
prev = ln.rstrip()
PY
echo "=== bytes at that address ==="
objdump -s --start-address=0xffffffff800669e0 --stop-address=0xffffffff80066a20 "$E" | tail -4
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
OUT=/mnt/d/Code/DEAICUP/Deshab/.build_tmp/wsl_verify_detached.out
LOG=/home/deshab/qemu_serial_loop1.log
echo "===== tail of detached out ====="
tail -n 60 "$OUT"
echo
echo "===== key serial markers ====="
tr -d '\r\0' < "$LOG" | grep -aE 'guest parked|EXEC_READY|session=|desktop ready|starting Plasma|Plasma failed|FLUSH|serial 2|invalid ELF|error while loading|fatal signal|Fatal server|exited with status|entering KDE|interpreter alive' | tail -n 50
echo
echo "===== Xorg tail markers ====="
tr -d '\r\0' < "$LOG" | grep -aE 'xorg:' | tail -n 25
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
LOG=/home/deshab/qemu_serial_loop1.log
T=$(mktemp)
tr -d '\r\0' < "$LOG" > "$T"
echo "===== traps / bus error / segfault lines ====="
grep -aE 'traps:|Bus error|bus error|segfault|SIGBUS' "$T" | tail -n 30
echo
echo "===== plasma.err dumped lines (all) ====="
grep -a 'deshab-plasma.err' "$T" | tail -n 40
echo
echo "===== dmesg: lines from session ====="
grep -a 'deshab-kde] dmesg:' "$T" | tail -n 15
echo
echo "===== FLUSH_N / scanout context ====="
grep -anE 'FLUSH_N|SET_SCANOUT|scanout' "$T" | tail -n 15
rm -f "$T"
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Reset the overlay dirs inside an image's rootfs so cp -a injection
# starts from a clean slate (cp -a never deletes stale files).
set -Eeuo pipefail
for img in "$@"; do
L=$(losetup --find --show --partscan "$img")
sleep 0.3
M=$(mktemp -d)
mount "${L}p1" "$M"
R=$(mktemp -d)
mount -o loop "$M/boot/linux-rootfs.img" "$R"
X="$R/usr/local/lib/xorg-libs"
P="$R/usr/local/lib/plasma-libs"
echo "$(basename "$img"): before xorg=$(ls "$X" 2>/dev/null | wc -l) plasma=$(ls "$P" 2>/dev/null | wc -l)"
rm -rf "$X" "$P"
mkdir -p "$X" "$P"
sync
echo "$(basename "$img"): reset done"
umount "$R"; rmdir "$R"
umount "$M"; rmdir "$M"
losetup -d "$L"
done
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Restore persist ld.so/libc from the native extra copy (objcopy left
# zero-size GNU_PROPERTY headers). Then re-inject session + helper.
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/restore_persist_ld.out"
exec > >(stdbuf -oL tee "$OUT") 2>&1
killall qemu-system-x86_64 2>/dev/null || true
WANT_LD=1e794eb14f4bccf6186bf8d9aa2018e8963ea668
WANT_LIBC=503200d7fda94a5dc6058d7e0694e5d1dcb2e372
SRC=""
S=""
for p in /home/deshab/linux-extra-rootfs.img /root/extra_rootfs_work/extra-rootfs.img; do
[[ -f "$p" ]] || continue
echo "[restore] candidate $p"
t=$(mktemp -d)
if ! mount -o loop,ro "$p" "$t"; then
rmdir "$t"
continue
fi
bid=$(readelf -n "$t/usr/lib/ld-linux-x86-64.so.2" 2>/dev/null | awk '/Build ID:/ {print $3; exit}')
echo "[restore] $p ld.so buildid=$bid"
readelf -l "$t/usr/lib/ld-linux-x86-64.so.2" 2>/dev/null | grep -A1 GNU_PROPERTY || true
if [[ "$bid" == "$WANT_LD" ]]; then
SRC="$p"
S="$t"
break
fi
umount "$t"
rmdir "$t"
done
if [[ -z "$SRC" ]]; then
echo "[restore] no matching native extra copy (want $WANT_LD)"
exit 1
fi
echo "[restore] src $SRC"
IMG=/home/deshab/deshab-dev.img
LOOP=$(losetup --find --show --partscan "$IMG")
sleep 0.3
M=$(mktemp -d)
mount "${LOOP}p1" "$M"
E=$(mktemp -d)
mount -o loop "$M/boot/linux-extra-rootfs.img" "$E"
echo "[restore] dst before"
readelf -l "$E/usr/lib/ld-linux-x86-64.so.2" 2>&1 | grep -A1 GNU_PROPERTY || true
cp -a "$S/usr/lib/ld-linux-x86-64.so.2" "$E/usr/lib/ld-linux-x86-64.so.2"
# libc.so.6 may be a symlink to libc.so.6 real file
src_libc=$(readlink -f "$S/usr/lib/libc.so.6")
dst_libc=$(readlink -f "$E/usr/lib/libc.so.6")
echo "[restore] libc $src_libc -> $dst_libc"
cp -a "$src_libc" "$dst_libc"
chmod 0755 "$E/usr/lib/ld-linux-x86-64.so.2" "$dst_libc"
echo "[restore] dst after"
readelf -l "$E/usr/lib/ld-linux-x86-64.so.2" 2>&1 | grep -A2 GNU_PROPERTY || true
readelf -n "$E/usr/lib/ld-linux-x86-64.so.2" 2>&1 | grep -i 'x86 feature\|SHSTK\|IBT\|GNU_PROPERTY' || true
umount "$E"
rmdir "$E"
umount "$M"
losetup -d "$LOOP"
rmdir "$M"
umount "$S"
rmdir "$S"
echo "[restore] extra ld.so restored"
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Restore the PROVEN soname families into xorg-libs from plasma-libs.
# The original 137-file set (proven in the 12:18 Xorg run) had exactly
# these soname prefixes; everything else stays in plasma-libs.
set -Eeuo pipefail
PROVEN_SONAMES="libXau libXdmcp libXfont2 libbrotlicommon libbrotlidec libbrotlienc libbz2 libcap-ng libcom_err libdbus-1 libdrm libdrm_amdgpu libdrm_intel libdrm_nouveau libdrm_radeon libevdev libffi libfontenc libfreetype libgmp libgssapi_krb5 libhogweed libinput libk5crypto libkadm5clnt libkadm5srv libkeyutils libkrb5 libkrb5support liblzma libmtdev libnettle libpciaccess libpixman-1 libpng libpng16 libsystemd libtirpc libudev libunwind libxcvt libxshmfence libz"
mkdir -p /home/deshab/xorg-libs
cd /home/deshab/plasma-libs
back=0
for f in *; do
base="${f%%.so*}"
keep=0
for s in $PROVEN_SONAMES; do
if [ "$base" = "$s" ]; then keep=1; break; fi
done
if [ "$keep" = 1 ]; then
mv -f "$f" /home/deshab/xorg-libs/
back=$((back + 1))
fi
done
echo "restored_to_xorg=$back"
echo "xorg-libs: $(ls /home/deshab/xorg-libs | wc -l) files"
echo "plasma-libs: $(ls /home/deshab/plasma-libs | wc -l) files"
echo '--- xorg-libs sonames ---'
ls /home/deshab/xorg-libs | sed 's/\.so.*//' | sort -u | tr '\n' ' '; echo
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
killall qemu-system-x86_64 2>/dev/null || true
sleep 1
sed -i 's/\r$//' "$ROOT/CODE/linux/patch_boot_on_img.sh" \
"$ROOT/CODE/linux/qemu_verify_loop.sh" \
"$ROOT/CODE/linux/tmp_verify_timeslice.sh"
bash "$ROOT/CODE/linux/patch_boot_on_img.sh"
bash "$ROOT/CODE/linux/tmp_verify_timeslice.sh"
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
killall qemu-system-x86_64 2>/dev/null || true
sleep 3
ss -ltnp | grep -E '45454|45455' || true
export QEMU_SERIAL_LOG=/home/deshab/qemu_serial_loop1.log
export QEMU_VERIFY_TIMEOUT=480
sed -i 's/\r$//' "$ROOT/CODE/linux/qemu_verify_loop.sh"
bash "$ROOT/CODE/linux/qemu_verify_loop.sh"
rc=$?
python3 "$ROOT/CODE/linux/tmp_ascii.py" || true
{
echo "verify_exit=$rc"
python3 - <<'PY'
from pathlib import Path
b = Path("/home/deshab/qemu_serial_loop1.log").read_bytes().replace(b"\x00", b"").replace(b"\r", b"")
t = b.decode("utf-8", "replace")
keys = ("EXEC_READY", "guest parked", "session=", "desktop ready", "deshab-kde",
"entering KDE", "starting Plasma", "vscode", "IDT", "LNXC", "VERIFY_")
lines = [ln for ln in t.splitlines() if any(k.lower() in ln.lower() for k in keys)]
Path("/mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_timeslice.txt").write_text(
"\n".join(lines[-180:]) + f"\nLOG_BYTES={len(b)}\nMATCHED={len(lines)}\n", encoding="utf-8")
print("matches", len(lines), "bytes", len(b))
PY
} | tee /mnt/d/Code/DEAICUP/Deshab/.build_tmp/verify_rc.txt
exit $rc
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Remove glibc-mismatched overlay libs (libsystemd) from the rootfs xorg-libs
# dir inside an image's ESP. cp -a injection never deletes, so stale files
# from earlier injections must be pruned explicitly.
set -Eeuo pipefail
for img in "$@"; do
L=$(losetup --find --show --partscan "$img")
sleep 0.3
M=$(mktemp -d)
mount "${L}p1" "$M"
R=$(mktemp -d)
mount -o loop "$M/boot/linux-rootfs.img" "$R"
D="$R/usr/local/lib/xorg-libs"
echo "$(basename "$img"): before=$(ls "$D" | wc -l)"
rm -fv "$D"/libsystemd.so "$D"/libsystemd.so.0 "$D"/libsystemd.so.0.* 2>/dev/null || true
sync
echo "$(basename "$img"): after=$(ls "$D" | wc -l) systemd_left=$(ls "$D" | grep -c '^libsystemd.so' || true)"
umount "$R"; rmdir "$R"
umount "$M"; rmdir "$M"
losetup -d "$L"
done
+14
View File
@@ -0,0 +1,14 @@
# Launch visible verify detached from Cursor's wsl pipe (that pipe kills WSL).
$Root = "D:\Code\DEAICUP\Deshab"
$Out = Join-Path $Root ".build_tmp\wsl_verify_detached.out"
$Err = Join-Path $Root ".build_tmp\wsl_verify_detached.err"
New-Item -ItemType Directory -Force -Path (Join-Path $Root ".build_tmp") | Out-Null
"" | Set-Content -Path $Out -Encoding utf8
"" | Set-Content -Path $Err -Encoding utf8
$p = Start-Process -FilePath "wsl.exe" `
-ArgumentList @("-d", "Ubuntu", "-u", "root", "bash", "/mnt/d/Code/DEAICUP/Deshab/CODE/linux/tmp_run_visible.sh") `
-RedirectStandardOutput $Out `
-RedirectStandardError $Err `
-WindowStyle Hidden `
-PassThru
Write-Host "detached pid=$($p.Id) out=$Out"
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/wsl_verify5.out"
exec >"$OUT" 2>&1
sed -i 's/\r$//' \
"$ROOT/CODE/linux/patch_boot_on_img.sh" \
"$ROOT/CODE/linux/tmp_reverify2.sh" \
"$ROOT/CODE/linux/guest/deshab-kde-session" \
"$ROOT/CODE/linux/qemu_verify_loop.sh" || true
killall qemu-system-x86_64 2>/dev/null || true
sleep 2
bash "$ROOT/CODE/linux/patch_boot_on_img.sh"
rc_patch=$?
echo "[run] patch_exit=$rc_patch"
if [[ $rc_patch -ne 0 ]]; then
exit $rc_patch
fi
bash "$ROOT/CODE/linux/tmp_reverify2.sh"
exit $?
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/wsl_verify6.out"
exec >"$OUT" 2>&1
sed -i 's/\r$//' \
"$ROOT/CODE/linux/rebuild_initrd.sh" \
"$ROOT/CODE/linux/patch_boot_on_img.sh" \
"$ROOT/CODE/linux/tmp_reverify2.sh" \
"$ROOT/CODE/linux/qemu_verify_loop.sh" \
"$ROOT/CODE/linux/initramfs/init" \
"$ROOT/CODE/linux/initramfs/bin/utsm_exec_daemon.c" \
"$ROOT/CODE/linux/guest/deshab-kde-session" || true
killall qemu-system-x86_64 2>/dev/null || true
sleep 2
export SKIP_ROOTFS_PATCH=1
bash "$ROOT/CODE/linux/rebuild_initrd.sh"
rc_initrd=$?
echo "[run] initrd_exit=$rc_initrd"
if [[ $rc_initrd -ne 0 ]]; then
exit $rc_initrd
fi
bash "$ROOT/CODE/linux/patch_boot_on_img.sh"
rc_patch=$?
echo "[run] patch_exit=$rc_patch"
if [[ $rc_patch -ne 0 ]]; then
exit $rc_patch
fi
bash "$ROOT/CODE/linux/tmp_reverify2.sh"
exit $?
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Hard-capped verify. Do not use `exec >file` (block-buffered, hides SUMMARY).
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/wsl_verify7.out"
export PYTHONUNBUFFERED=1
export QEMU_SERIAL_LOG=/home/deshab/qemu_serial_loop1.log
export QEMU_VERIFY_TIMEOUT=480
echo "[run7] $(date -Iseconds) kill leftover qemu" >"$OUT"
killall qemu-system-x86_64 2>/dev/null || true
sleep 2
ss -ltnp | grep -E '45454|45455' >>"$OUT" 2>&1 || echo "[run7] ports free" >>"$OUT"
sed -i 's/\r$//' "$ROOT/CODE/linux/tmp_reverify2.sh" "$ROOT/CODE/linux/qemu_verify_loop.sh"
echo "[run7] starting timed verify" >>"$OUT"
timeout --kill-after=15 540 stdbuf -oL -eL bash "$ROOT/CODE/linux/tmp_reverify2.sh" >>"$OUT" 2>&1
rc=$?
echo "[run7] timed_exit=$rc $(date -Iseconds)" >>"$OUT"
killall qemu-system-x86_64 2>/dev/null || true
exit $rc
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Copy the GPT image off drvfs, then verify. Cold-cache Limine loads of
# linux-extra-rootfs.img from /mnt/d OOM/kill QEMU in ~40s on a 7.6G WSL.
set -uo pipefail
ROOT=/mnt/d/Code/DEAICUP/Deshab
OUT="$ROOT/.build_tmp/wsl_verify8.out"
NATIVE=/home/deshab/deshab-dev.img
SRC="$ROOT/ISO/deshab-dev.img"
export PYTHONUNBUFFERED=1
export QEMU_SERIAL_LOG=/home/deshab/qemu_serial_loop1.log
export QEMU_VERIFY_TIMEOUT=480
export IMG_OVERRIDE="$NATIVE"
{
echo "[run8] $(date -Iseconds)"
echo "[run8] mem:"; free -h
echo "[run8] home:"; df -h /home/deshab
killall qemu-system-x86_64 2>/dev/null || true
sleep 1
echo "[run8] copying image to native ext4"
mkdir -p /home/deshab
rm -f "$NATIVE"
cp -f "$SRC" "$NATIVE"
ls -lh "$NATIVE"
echo "[run8] starting verify IMG_OVERRIDE=$NATIVE"
} >>"$OUT" 2>&1
sed -i 's/\r$//' "$ROOT/CODE/linux/tmp_reverify2.sh" "$ROOT/CODE/linux/qemu_verify_loop.sh"
# GNU timeout: duration first. Avoid --kill-after (busybox treats it as 15s).
/usr/bin/timeout 540 stdbuf -oL -eL bash "$ROOT/CODE/linux/tmp_reverify2.sh" >>"$OUT" 2>&1
rc=$?
echo "[run8] timed_exit=$rc $(date -Iseconds)" >>"$OUT"
killall qemu-system-x86_64 2>/dev/null || true
exit $rc

Some files were not shown because too many files have changed in this diff Show More