Pacman Fix up

What happens when pacman fails when you’re trying to recover from uninstalling a package that pacman needs?

1023 % sudo pacman -Syu
[sudo] password for bediger: 
pacman: error while loading shared libraries: libicuuc.so.78: cannot open shared object file: No such file or directory

Well, I’ll tell you what, you go through the stages of grief rapidly.

1024 % ldd $(which pacman) | grep not                            # /var/cache/pacman/pkg
        libicuuc.so.78 => not found

Prelude

I got my machine to this embarrassing state by doing:

$ cd /var/cache/pacman/pkg
$ sudo pacman -U icu-78.1-1-x86_64.pkg.tar.zst

I did this to try to fix a PostgreSQL problem. I didn’t want to migrate my gitea data to PostgreSQL version 18. I did the migration anyway, after fixing this problem. The migration worked, that’s good.

Fix

pacman won’t run because it’s missing a dynamically loaded library, a file from a package you just used pacman to uninstall. Everything else seems to work. I know! Put the missing .so files back by hand. I haven’t cleared the pacman cache in ages, the package file is still in the cache directory.

$ cd
$ mkdir icu
$ cd icu
$ cp /var/cache/pacman/pkg/icu-78.1-1-x86_64.pkg.tar.zst .
$ unzstd icu-78.1-1-x86_64.pkg.tar.zst
$ tar xf icu-78.1-1-x86_64.pkg.tar usr/lib
$ cp usr/lib/libicuuc.so.78* /usr/lib

pacman -Syu now failed because the dynamic loader couldn’t find libicudata.so.78.

$ cd $HOME/icu
$ cp usr/lib/libicudata.so.78 /usr/lib

Did pacman work after this? No, it didn’t, for another weird reason.

1027 % sudo pacman -Syu
:: Synchronizing package databases...
 core is up to date
 extra is up to date
:: Starting full system upgrade...
warning: smokeping: ignoring package upgrade (2.8.2-3 => 2.9.0-1)
resolving dependencies...
looking for conflicting packages...

Packages (3) icu-78.1-1  postgresql-18.0-2  postgresql-libs-18.0-2

Total Installed Size:  119.40 MiB
Net Upgrade Size:        4.16 MiB

:: Proceed with installation? [Y/n] 
(3/3) checking keys in keyring                        [############################] 100%
(3/3) checking package integrity                      [############################] 100%
(3/3) loading package files                           [############################] 100%
(3/3) checking for file conflicts                     [############################] 100%
error: failed to commit transaction (conflicting files)
icu: /usr/lib/libicudata.so.78 exists in filesystem
icu: /usr/lib/libicuuc.so.78 exists in filesystem
icu: /usr/lib/libicuuc.so.78.1 exists in filesystem
Errors occurred, no packages were upgraded.

I finally encouraged pacman to do the upgrade with extreme prejudice:

$ sudo pacman -Su --overwrite "*"
...
$ sudo pacman -Q -i icu
Name            : icu
Version         : 78.1-1
Description     : International Components for Unicode library
Architecture    : x86_64

The --overwrite "*" had me a little worried. Would Linux allow a pacman process to overwrite shared library files that the pacman process itself had mapped in it’s address space? This struck me as a little different than deleting a file for which a process had an open file descriptor. It worked, now I have to re-evaluate how I think about open file descriptors versus files that are mapped in an address space.

Linux does use a file descriptor to do the mapping:

void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);

int filedes has to hold a file descriptor resulting from an open(2) system call. Maybe deleting or overwriting a memory mapped file isn’t that different. I hope I don’t have to find out more.