WSL2 终端无法启动

未解之谜

尝试打印了进程树,截出卡住的一段

/init
  /init
    -bash
      bash
        sudo ps -efH
    /bin/sh /etc/update-motd.d/50-landscape-sysinfo
      /bin/sh /etc/update-motd.d/50-landscape-sysinfo
        /usr/bin/python3 /usr/bin/landscape-sysinfo
          [who] <defunct>

只要运行 sudolandscape-sysinfo(被 motd 触发)都会卡住,Ctrl+C 无效,甚至想要 wsl --shutdown 也是卡很久。重启 WSL 肯定能好,但这明显是问题。

其他人也有遇到过,

曾经我验证过和 Docker 的 Resource Save Mode 有关,但这次没有开 Docker Desktop。

dmesg 中大段的错误信息可以看出和 IO 调用有关

[18215.114929] WSL (1 - ) ERROR: WriteToFile:3301: write(/sys/fs/cgroup/memory.reclaim, 34132500) failed -1 11  
[18246.034203] WSL (1 - ) ERROR: WriteToFile:3301: write(/sys/fs/cgroup/memory.reclaim, 33673666) failed -1 11  
[18277.146404] WSL (1 - ) ERROR: WriteToFile:3301: write(/sys/fs/cgroup/memory.reclaim, 33407139) failed -1 11  
[18308.415826] WSL (1 - ) ERROR: WriteToFile:3301: write(/sys/fs/cgroup/memory.reclaim, 33548574) failed -1 11

搜一下果然有人遇到过

里面提到了当 “autoMemoryReclaim”(自动内存回收) 设置为 Gradual(慢速释放) 有这个问题,看了下我的确实如此。先改成 DropCache 试试

在 PowerShell Function 中使同步地 Dot Source 作用于全局

我想实现的是一个 Lazy Loader,在首次执行的时候初始化,降低一些命令行工具对终端启动性能的影响。对应的 Bash 版本长这样

##### nvm (node version manager) #####
# placeholder nvm shell function
# On first use, it will set nvm up properly which will replace the `nvm`
# shell function with the real one
# take from web-cache of: https://peterlyons.com/problog/2018/01/zsh-lazy-loading
function nvm() {
  echo "🚨 nvm not loaded! Loading now..." >&2
  unset -f nvm
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
  nvm "$@" # invoke the real nvm function now
}

也就是想要 function F { . script.ps1 } 能影响 Global Scope,一般来说 dot source 只会作用于 local 范围,也就是函数作用域,离开函数就消失了,无法给全局作用域添加函数。

之前实现的 fsackur/ProfileAsync: Load your powershell profile asynchronously, so you can get to the prompt faster. 是异步的,不太适用这种情况。用到的 Runspace 替换技术太复杂了

实际上如 Question about dot sourcing inside functions : r/PowerShell 所说,只需要定义个 Module,然后在函数中 Import-Module 即可。

X-CMD.psm1
# A simple module that only do dot source.
# By Import-Module this, all functions in the module will be available in the global scope.
# https://www.reddit.com/r/PowerShell/comments/1dz56cx/question_about_dot_sourcing_inside_functions/
 
# https://cn.x-cmd.com/start/windows
if (Test-Path "$Home\.x-cmd.root\local\data\pwsh\_index.ps1") {
    . "$Home\.x-cmd.root\local\data\pwsh\_index.ps1"
}; # boot up x-cmd.
 
function x {
    Write-Host "🚨 x not loaded! Loading now..."
    Remove-Item -Path "Function:x"
    Import-Module -Name "X-CMD.psm1" -Force -DisableNameChecking
    x @args
}

跨网段 WS-Discovery

是因为我的 Synology 部署在另一个网段,本地网络的 WS-Discovery 广播发不到它上面,导致 Windows 无法在网络面板发现设备。

估计得启动组播路由,用 igmpproxy,然而设备上的启动一直提示 MC-Router API already in use; Errno(98): Address already in use,总之就是没成功。

试了试 OpenWrt 的版本,运行没问题啊。看代码也分析不出原因,看来得自己编一个版本。下面的 编译 RT-AX86U asuswrt-merlin 固件 就是在干这个,不过最后失败了。

2025-09-09 Windows 网络发现使用 WS-Discovery 在 239.255.255.250:3702 上发送多播包,并且只对同一子网的包给出回应。

编译 RT-AX86U asuswrt-merlin 固件

在 NTFS 上 Git Checkout 失败

先是克隆成功,但是检出失败,搜索一下就有解决方案,设置 core.protectNTFS=false

另外有人说设置 core.longpaths true,我试了没效果

$ git clone https://github.com/RMerl/asuswrt-merlin.ng.git --depth=1
警告:克隆成功,但是检出失败。 您可以通过 'git status' 检查哪些已被检出,然后使用命令 'git restore --source=HEAD' 重试
 
$ git checkout -f HEAD
错误:无效路径 'release/src-rt-5.02L.07p2axhnd/kernel/linux-4.1/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c'
 
$ git config core.protectNTFS false

再是 unable to create symlink ,估计和 ReFS 不支持这个文件名有关?

$ git checkout -f HEAD
错误:unable to create symlink release/src/router/udev/test/sys/bus/pci/devices/0000:00:09.0: Invalid argument
错误:unable to create symlink release/src/router/udev/test/sys/bus/pci/devices/0000:00:1e.0: Invalid argument
错误:unable to create symlink release/src/router/udev/test/sys/bus/pci/devices/0000:02:05.0: Invalid argument
错误:unable to create symlink release/src/router/udev/test/sys/bus/pci/drivers/aic7xxx/0000:02:05.0: Invalid argument
错误:unable to create symlink release/src/router/udev/test/sys/bus/scsi/devices/0:0:0:0: Invalid argument
错误:unable to create symlink release/src/router/udev/test/sys/bus/scsi/drivers/sd/0:0:0:0: Invalid argument
致命错误:cannot create directory at 'release/src/router/udev/test/sys/devices/pci0000:00': Invalid argument

最后是在 WSL2 下建了个内存盘才成的,还得是 Linux 亲爹好使。

编译固件

先用代理拉取代码,切换到当前固件版本,为设备编译

拉一遍源码 1.5GB 实在太慢了,有请 稀疏检出

sudo mount -o size=16G -t tmpfs none /mnt/tmpfs
cd /mnt/tmpfs
 
git clone https://gh-proxy.com/https://github.com/RMerl/asuswrt-merlin.ng.git --branch=3004.388.9_2 --filter=tree:0 --no-checkout --depth=1 --sparse
cd asuswrt-merlin.ng
 
git sparse-checkout add tools
git sparse-checkout add release/src
git sparse-checkout add release/src-rt
git sparse-checkout add release/src-rt-5.02L.07p2axhnd
git sparse-checkout add release/image
git checkout
 
docker run
cd release/src-rt-5.02L.07p2axhnd
make rt-ax86u

然后就坐着等吧,起码半小时。也不要开多核心,会异常。看到这个就说明成功了

Done! Image 962118GW has been built in /build/release/src-rt-5.02L.07p2axhnd/targets/962118GW.

如果没有切换到发布 tag 版本,直接使用 master 会遇到编译失败 undefined reference to 'ip_set_nfnl_put'。毕竟仓库的 master 是非稳定分支,注意一下就好。

发现 MCPD

源码调试以后确认是有进程已经占用了 IGMP 的位置,尝试 netstat -anp | grep 'raw' 发现叫 mcpd 的进程很可疑,查了一下它的配置文件,确实是负责 IGMP 的。

然而 mcpd 在代码库里是以 预编译二进制 的形式分发的 😦,也没个文档。
还好万能的 GitHub 搜索关键字还是有结果的,在 RT-AC1200G+ 的固件里找到了 MCPD源代码

git clone https://gh-proxy.com/https://github.com/clockzhong/ASUSWRT_RT-AC1200GPlus.git --filter=tree:0 --no-checkout --depth=1 --sparse
cd ASUSWRT_RT-AC1200GPlus/
git sparse-checkout add release/src/router/mcpd/
git sparse-checkout add release/src/router/mcpctl/
git checkout
 
cd ..
cp -r ASUSWRT_RT-AC1200GPlus/release/src/router/mcpd/* asuswrt-merlin.ng/release/src-rt-5.02L.07p2axhnd/router-sysdep.rt-ax86u/mcpd/

别高兴的太早,想要编译 mcpctl 还少了头文件 mcpctl.h,还好也能在网上找到 rikka0w0/Arris-CM8200B-Reverse-Engineering

git clone https://gh-proxy.com/https://github.com/rikka0w0/Arris-CM8200B-Reverse-Engineering.git --filter=tree:0 --no-checkout --depth=1 --sparse
cd Arris-CM8200B-Reverse-Engineering
git sparse-checkout add docs/asuswrt-merlin.ng/release/src-rt-5.02hnd/userspace/
git checkout
 
cd ..
cp -r Arris-CM8200B-Reverse-Engineering/docs/asuswrt-merlin.ng/release/src-rt-5.02hnd/userspace/private asuswrt-merlin.ng/release/src-rt-5.02L.07p2axhnd/userspace/

编译 MCPD

  1. 先把添加进来的文件复制到 router-sysdep 正确的位置,用编译固件的命令做,不用完整编译完,看到有结果就好
  2. 编译环境没能找到头文件和依赖的位置,图省事手动强制指定一下
cd /build/release/src-rt-5.02L.07p2axhnd
make rt-ax86u
 
cat << EOF >> router-sysdep/mcpd/Makefile.fullsrc
CFLAGS += -I/build/release/src-rt-5.02L.07p2axhnd/shared/opensource/include/bcm963xx/
LIBS += -L/build/release/src-rt-5.02L.07p2axhnd/router-sysdep/bcmmcast
LIBS += -L/build/release/src-rt-5.02L.07p2axhnd/router-sysdep/bridgeutil
EOF
 
BUILD_DIR=$(pwd) make -C router-sysdep mcpd-clean
BUILD_DIR=$(pwd) make -C router-sysdep mcpd
 
file router-sysdep/mcpd/mcpd

接下来就复制到设备上,把旧进程 kill 掉运行。

Segmentation fault

然而无法正常启动

开启 core dump

$ ulimit
0
 
$ ulimit -c unlimited
 
$ cat /proc/sys/kernel/core_pattern  
/tmp/core-%e-%g-%p-%s-%t-%u
 
$ ls /tmp/core-mcpd*
/tmp/core-mcpd-0-6396-11-1756451569-0
 
$ ulimit -c 0

GDB 缺少 libexpat.so.1

 
$ ldd /opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/usr/bin/arm-linux-gdb
        linux-gate.so.1 (0xf7ed5000)
        libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xf7ec1000)
        libncurses.so.6 => /opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libncurses.so.6 (0xf7e79000)
        libexpat.so.1 => not found
        liblzma.so.5 => /opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/liblzma.so.5 (0xf7e28000)
        librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xf7e1c000)
        libstdc++.so.6 => /lib32/libstdc++.so.6 (0xf7c47000)
        libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xf7b42000)
        libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xf7b23000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7934000)
        /lib/ld-linux.so.2 (0xf7ed7000)
        libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xf790f000)
$ file /opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/*
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libattr.la:        libtool library file, ASCII text
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libattr.so:        symbolic link to libattr.so.1
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libattr.so.1:      symbolic link to libattr.so.1.1.0
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libattr.so.1.1.0:  ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, with debug_info, not stripped
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libcc1.a:          current ar archive
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libcc1.la:         libtool library file, ASCII text
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libcc1.so:         symbolic link to libcc1.so.0.0.0
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libcc1.so.0:       symbolic link to libcc1.so.0.0.0
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libcc1.so.0.0.0:   ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libexpat.la:       libtool library file, ASCII text
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libexpat.so:       symbolic link to libexpat.so.1.6.6
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libexpat.so.1:     symbolic link to libexpat.so.1.6.6
/opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libexpat.so.1.6.6: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, with debug_info, not stripped
 
$ sudo apt-get install libexpat-dev:i386 -y
$ ldd /opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/usr/bin/arm-linux-gdb
        linux-gate.so.1 (0xf7ed5000)
        libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xf7ec1000)
        libncurses.so.6 => /opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/libncurses.so.6 (0xf7e79000)
        libexpat.so.1 => /lib/i386-linux-gnu/libexpat.so.1 (0xf7e4c000)
        liblzma.so.5 => /opt/toolchains/crosstools-arm-gcc-5.5-linux-4.1-glibc-2.26-binutils-2.28.1/lib/liblzma.so.5 (0xf7e28000)
        librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xf7e1c000)
        libstdc++.so.6 => /lib32/libstdc++.so.6 (0xf7c47000)
        libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xf7b42000)
        libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xf7b23000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7934000)
        /lib/ld-linux.so.2 (0xf7ed7000)
        libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xf790f000)

GDB 调试

arm-linux-gdb router-sysdep/mcpd/mcpd core-mcpd-0-6396-11-1756451569-0

socat 验证 UDP 组播转发

Server Session - which provide resopnse when receive from multicasting address
socat UDP4-RECVFROM:6666,ip-add-membership=224.1.0.1:192.168.9.1,fork EXEC:hostname
Client Session - which send UDP datagram to multicasting address
socat STDIO UDP4-DATAGRAM:224.1.0.1:6666,range=192.168.9.0/24

在路由器上运行发现怎么都不产生响应。

暂时休息

时间花好几天了,硬靠土法调试这条路不好走,先转个方向。

Git Clone and Cd to it

git clone http://repo_url.git && cd "!$:t:r"