pacman: install /var/lib/pacman as symlink, not dir + child symlink

User reported on a freshly flashed R36S:

    archr:~ # pacman
    error: failed to initialize alpm library:
    (root: /, dbpath: /var/lib/pacman/)
    could not find or read directory

The package.mk created /var/lib/pacman as a real directory in
post_makeinstall_target (mkdir -p), then in post_install ran
`ln -sf /storage/.pacman/db ${INSTALL}/var/lib/pacman`. When LINK is
an existing directory, ln -sf does not replace it — it creates
LINK/$(basename TARGET). So the installed image ended up with:

  /var/lib/pacman/                ← real, empty dir (rootfs, ro)
  /var/lib/pacman/db -> /storage/.pacman/db   ← child symlink

Pacman reads dbpath=/var/lib/pacman/ from pacman.conf, looks for
local/ and sync/ inside it, finds nothing, and bails.

Fix: install /var/lib/pacman directly as a symlink to
/storage/.pacman/db in one shot, no intermediate mkdir. Same for
/var/cache/pacman/pkg. Move both into post_makeinstall_target so the
file layout is decided in one place; post_install now only enables
the pacman-init service.

Runtime escape hatch on already-installed systems (since the rootfs
is squashfs-ro and can't be patched):

    mount --bind /storage/.pacman/db /var/lib/pacman
    mount --bind /storage/.pacman/cache /var/cache/pacman/pkg

This commit fixes the build so the next image flashes correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Douglas Teles
2026-06-24 01:30:02 -03:00
parent 2bb9ebb50a
commit 6ce926d537
@@ -36,9 +36,22 @@ post_makeinstall_target() {
cp ${PKG_DIR}/config/mirrorlist ${INSTALL}/etc/pacman.d/mirrorlist
cp ${PKG_DIR}/config/makepkg.conf ${INSTALL}/etc/makepkg.conf
# Create pacman state directories (symlinked to /storage at runtime)
mkdir -p ${INSTALL}/var/lib/pacman
mkdir -p ${INSTALL}/var/cache/pacman/pkg
# /var/lib/pacman is a symlink directly into the rw storage overlay.
# Earlier versions did `mkdir -p /var/lib/pacman` here and then
# `ln -sf /storage/.pacman/db /var/lib/pacman` in post_install, but
# `ln -sf TARGET LINK` when LINK is an existing directory creates
# LINK/$(basename TARGET) instead of replacing LINK — so we ended up
# with /var/lib/pacman/db as a symlink (correct destination) inside
# an empty real /var/lib/pacman directory in the read-only rootfs,
# while pacman went looking for /var/lib/pacman/local and
# /var/lib/pacman/sync and reported "could not find or read directory".
mkdir -p ${INSTALL}/var/lib
ln -sf /storage/.pacman/db ${INSTALL}/var/lib/pacman
# /var/cache/pacman keeps the package cache. Same shape as above.
mkdir -p ${INSTALL}/var/cache/pacman
ln -sf /storage/.pacman/cache ${INSTALL}/var/cache/pacman/pkg
mkdir -p ${INSTALL}/var/log
# Remove unnecessary files
@@ -54,10 +67,4 @@ post_makeinstall_target() {
post_install() {
enable_service pacman-init.service
# Create /storage symlinks for pacman mutable state
mkdir -p ${INSTALL}/var/lib
ln -sf /storage/.pacman/db ${INSTALL}/var/lib/pacman
mkdir -p ${INSTALL}/var/cache/pacman
ln -sf /storage/.pacman/cache ${INSTALL}/var/cache/pacman/pkg
}