WSL(Windows Subsystem for Linux)早期是不支持systemd的。后来WSL增加了systemd支持之后,之前安装过的发行版需要在发行版内/etc/wsl.conf文件中增加systemd=true设置才能启用systemd。我使用了很久的Ubuntu发行版启用systemd之后却遇到了一个问题:缺少/run/user/<uid>目录,导致部分软件运行失败。如果手动创建这个文件夹,在WSL重启之后这个文件夹就会自动消失,令人十分烦恼。而此时全新安装的Ubuntu 24.04 LTS、Ubuntu 22.04 LTS、Ubuntu 20.04 LTS这些WSL发行版,虽然默认启用了systemd,但也能正确创建/run/user/<uid>目录。说明这不是WSL本身的问题,而是发行版自身状态有问题。

查阅手册(man user@.service)发现,/run/user/<uid>目录是由user-runtime-dir@<uid>.service这个systemd服务创建的。使用systemctl命令查询发现,该服务在故障的发行版中处于不活动(inactive)状态,而在正常发行版中处于活动(active)状态:

# 故障的发行版
$ systemctl status user-runtime-dir@1000.service
○ user-runtime-dir@1000.service - User Runtime Directory /run/user/1000
     Loaded: loaded (/usr/lib/systemd/system/user-runtime-dir@.service; static)
     Active: inactive (dead) since Tue 2025-04-08 18:15:40 CST; 15min ago
   Duration: 1min 57.566s
       Docs: man:user@.service(5)
    Process: 767 ExecStart=/usr/lib/systemd/systemd-user-runtime-dir start 1000 (code=exited, status=0/SUCCESS)
    Process: 972 ExecStop=/usr/lib/systemd/systemd-user-runtime-dir stop 1000 (code=exited, status=0/SUCCESS)
   Main PID: 767 (code=exited, status=0/SUCCESS)
...
# 正常的发行版
$ systemctl status user-runtime-dir@1002.service
● user-runtime-dir@1002.service - User Runtime Directory /run/user/1002
     Loaded: loaded (/usr/lib/systemd/system/user-runtime-dir@.service; static)
     Active: active (exited) since Tue 2025-04-08 18:31:45 CST; 6s ago
       Docs: man:user@.service(5)
    Process: 376 ExecStart=/usr/lib/systemd/systemd-user-runtime-dir start 1002 (code=exited, status=0/SUCCESS)
   Main PID: 376 (code=exited, status=0/SUCCESS)
...

通过systemctl list-dependencies命令可以了解到,该服务被session-1.scope依赖,而这个依赖它的scope自身却处于失败(failed)状态,导致这个user-runtime-dir服务由于不被任何单元依赖而自动停止,从而删除了我们的/run/user/<uid>文件夹:

$ systemctl list-dependencies --reverse --all user-runtime-dir@1000.service
× ├─session-1.scope
○ └─user@1000.service
×   └─session-1.scope

通过journalctl查询日志,发现了这些异常日志:

systemd-networkd-wait-online[322]: Timeout occurred while waiting for network connectivity.

systemd[1]: systemd-networkd-wait-online.service: Main process exited, code=exited, status=1/FAILURE

systemd[1]: systemd-networkd-wait-online.service: Failed with result ’exit-code'.

systemd[1]: Failed to start systemd-networkd-wait-online.service - Wait for Network to be Configured.

这一段是说systemd-networkd-wait-online.service服务启动失败。这是systemd-networkd中用于等待网络连接的服务。理论上WSL不需要发行版内的systemd-networkd来管理网络状态,而是由Windows来管理。在正常的发行版中检查发现,这个服务是处于禁用状态的。

systemd[1]: session-1.scope: PID 638 vanished before we could move it to target cgroup ‘/user.slice/user-1000.slice/session before we could move it to target cgroup ‘/user.slice/user-1000.slice/session-1.scope’, skipping: No such process

systemd[1]: session-1.scope: No PIDs left to attach to the scope’s control group, refusing.

systemd[1]: session-1.scope: Failed with result ‘resources’.

这一段大概意思是,由于进程638已经退出,session-1.scope启动失败。638是login进程,此处并不明确login进程退出的原因。

GitHubLaunchPad上的网友提示,直接禁用systemd-networkd服务可解决systemd-networkd-wait-online.service超时的问题。尝试使用systemctl命令禁用该服务:

sudo systemctl disable systemd-networkd

之后在Windows命令行中退出WSL:

wsl --shutdown

再次启动原本有问题的发行版,发现/run/user/<uid>目录已经自动创建,且user-runtime-dir@<uid>.service也已经处于活动状态。而这时session-1.scope失败的问题也自动解决了。