ohhhhhhhhhhh (exclude linux-extra-rootfs.img build artifact)
This commit is contained in:
Binary file not shown.
+21
-3
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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) =====
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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" */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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)))
|
||||
@@ -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)))
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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)"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)"
|
||||
@@ -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)"
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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 $?
|
||||
@@ -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 $?
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user