WSL 1 で Ubuntu のパッケージ管理がうまく動作しない問題


先に結論:WSL 2 を使おう。

Windows 10 に WSL で Ubuntu を入れて使っていたが、新しいマシンをセットアップしたところ、どこかの時点で WSL 1 だと困ったことになっていた。
以下、winver コマンドの表示は バージョン 21H1 (OS ビルド 19043.1081) の環境で、
例えば Ubuntu 18.04 LTS (1804.2019.522.0) をインストールして以下を実行する。

$ sudo -i
# apt update
# apt install base-files
Reading package lists... Done
Building dependency tree
Reading state information... Done
Correcting dependencies... Done
The following additional packages will be installed:
  base-files motd-news-config
The following NEW packages will be installed:
  motd-news-config
The following packages will be upgraded:
  base-files
1 upgraded, 1 newly installed, 0 to remove and 212 not upgraded.
2 not fully installed or removed.
Need to get 0 B/64.9 kB of archives.
After this operation, 44.0 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
(Reading database ... 28635 files and directories currently installed.)
Preparing to unpack .../base-files_10.1ubuntu2.10_amd64.deb ...
Unpacking base-files (10.1ubuntu2.10) over (10.1ubuntu2.4) ...
dpkg: error processing archive /var/cache/apt/archives/base-files_10.1ubuntu2.10_amd64.deb (--unpack):
 unable to install new version of '/etc/os-release': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/usr/share/doc/base-files/FAQ': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/usr/share/common-licenses/LGPL': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/usr/share/common-licenses/GPL': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/usr/share/common-licenses/GFDL': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/etc/os-release': No such device or address
Errors were encountered while processing:
 /var/cache/apt/archives/base-files_10.1ubuntu2.10_amd64.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)

再実行すると以下のようになる

# apt install base-files
Reading package lists... Done
Building dependency tree
Reading state information... Done
You might want to run 'apt --fix-broken install' to correct these.
The following packages have unmet dependencies:
 ubuntu-server : Depends: motd-news-config but it is not going to be installed
                 Recommends: grub-legacy-ec2
E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).

--fix-broken で試すと以下のように、再現性がある。

# apt --fix-broken install
Reading package lists... Done
Building dependency tree
Reading state information... Done
Correcting dependencies... Done
The following package was automatically installed and is no longer required:
  libfreetype6
Use 'apt autoremove' to remove it.
The following additional packages will be installed:
  base-files motd-news-config
The following NEW packages will be installed:
  motd-news-config
The following packages will be upgraded:
  base-files
1 upgraded, 1 newly installed, 0 to remove and 213 not upgraded.
2 not fully installed or removed.
Need to get 0 B/64.9 kB of archives.
After this operation, 44.0 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
(Reading database ... 28645 files and directories currently installed.)
Preparing to unpack .../base-files_10.1ubuntu2.10_amd64.deb ...
Unpacking base-files (10.1ubuntu2.10) over (10.1ubuntu2.4) ...
dpkg: error processing archive /var/cache/apt/archives/base-files_10.1ubuntu2.10_amd64.deb (--unpack):
 unable to install new version of '/etc/os-release': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/usr/share/doc/base-files/FAQ': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/usr/share/common-licenses/LGPL': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/usr/share/common-licenses/GPL': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/usr/share/common-licenses/GFDL': No such device or address
dpkg: error while cleaning up:
 unable to restore backup version of '/etc/os-release': No such device or address
Errors were encountered while processing:
 /var/cache/apt/archives/base-files_10.1ubuntu2.10_amd64.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)

/etc/os-release が無いなどというわけもない。

# ls -l /etc/os-release
lrwxrwxrwx 1 root root 21 Feb  5  2019 /etc/os-release -> ../usr/lib/os-release

困ったが、幸い strace が最初から入っているので、何が起きているか確認できた。

# strace -fttTyyy -o /tmp/trace.txt apt --fix-broken install -y

os-release に注目しながら結果を読むと、エラーが発生している場所が分かった。
最後の行が ENXIO (No such device or address) になっている。

# grep /etc/os-release /tmp/trace.txt  | grep dpkg-new
619   17:27:51.467655 rmdir("/etc/os-release.dpkg-new") = -1 ENOTDIR (Not a directory) <0.000019>
619   17:27:51.467786 lstat("/etc/os-release.dpkg-new", {st_mode=S_IFLNK|0777, st_size=21, ...}) = 0 <0.000040>
619   17:27:51.467934 unlink("/etc/os-release.dpkg-new") = 0 <0.000399>
619   17:27:51.469266 symlink("../usr/lib/os-release", "/etc/os-release.dpkg-new") = 0 <0.000384>
619   17:27:51.469789 lchown("/etc/os-release.dpkg-new", 0, 0) = 0 <0.000044>
619   17:27:51.469951 utimensat(AT_FDCWD, "/etc/os-release.dpkg-new", [{tv_sec=1625300869, tv_nsec=0} /* 2021-07-03T17:27:49+0900 */, {tv_sec=1597345187, tv_nsec=0} /* 2020-08-14T03:59:47+0900 */], AT_SYMLINK_NOFOLLOW) = 0 <0.000116>
619   17:27:51.684648 rename("/etc/os-release.dpkg-new", "/etc/os-release") = -1 ENXIO (No such device or address) <0.001998>

シンボリックリンクのファイルを宛先にして rename が行われるとエラーになるようだ。
これは apt を使わなくても、簡単に再現する。原因はこれだろう。

# touch file
# ln -s file link1
# ln -s file link2
# ls -l
total 0
-rw-r--r-- 1 root root 0 Jul  3 17:31 file
lrwxrwxrwx 1 root root 4 Jul  3 17:31 link1 -> file
lrwxrwxrwx 1 root root 4 Jul  3 17:31 link2 -> file

# mv link2 link1
mv: cannot move 'link2' to 'link1': No such device or address
# ls -l
total 0
-rw-r--r-- 1 root root 0 Jul  3 17:31 file
lrwxrwxrwx 1 root root 4 Jul  3 17:31 link1 -> file
lrwxrwxrwx 1 root root 4 Jul  3 17:31 link2 -> file

ググると Issue が見つかる。
https://github.com/microsoft/WSL/issues/6362

というわけで、WSL 1 では回避できそうもないので、WSL 2 を使うことにする。