Fixing a broken libc6 upgrade on debian sid

Earlier today, I decided to uninstall apache in favour of nginx. As per usual, I ran apt-get to do this, which also wanted to upgrade libc6 (:i386 and :amd64). This turned out to be a much more involved process than I expected!

After removing the old version of libc6, apt called dpkg-deb to extract the new version. This failed, saying that libz.so.1 could not be found. Running any command not built into zsh then gave a similar error, usually with libselinux.so.1.

Some googling returned a couple of suggestions; however, the person with the most similar issue, had been unable to fix it and had ended up reinstalling. I had better luck, and what follows is an account of what I did.

Getting a Useable Shell

First, reboot into a system rescue cd (I used sysresccd, but pretty much anything should be fine). I’m not completely convinced that this was necessary, but it won’t hurt.

Next, mount all system partitions under /mnt. For me, this involved running


# cd /mnt
# mkdir root
# mount /dev/sda6 root; mount /dev/sda5 root/home; mount /dev/sda4 root/var; mount /dev/sda2 root/boot

Finally, you’ll need to chroot into /mnt/root. You’re meant to copy /etc/hosts and /etc/resolv.conf in first, but I never do and it’s never caused me any issues. Bash and zsh will probably refuse to run due to the libc6 issues, but sh should work fine.


# chroot root /bin/sh

You can now run


# /sbin/ldconfig

to link the libraries and let you run things more complicated than echo again.

Removing the Old libc6
Here is where I naively tried to upgrade libc6 again with apt. This kicked up the same issue as before, and if you do the same thing you’ll need to run ldconfig again.

As Michael pointed out, the issue is that libc6 wipes ld.so.cache on pre-installation, as well as pre-removal. A comment on Michael’s blog suggested to pass in LD_LIBRARY_PATH to apt-get install -f, which may work for you, but for me just made apt complain it couldn’t find rm at the same point as before.

Instead, comment out the following line (66 for me) of the pre-removal scripts at /var/lib/dpkg/info/libc6:amd64.prerm and /var/lib/dpkg/info/libc6:i386.prerm:

rm -f /etc/ld.so.cache

For good measure, I threw in an /sbin/ldconfig at various places in libc6:*.prerm as well as libc6:*postrm, but I don’t know if this was strictly necessary.

You should now be able to run


# dpkg --force-all -r libc6:i386
# dpkg --force-all -r libc6:amd64

to remove the existing libc6s.

Installing the New libc6
By all logic, you should now be able to run


# LD_LIBRARY_PATH=/lib/x86_64-linux-gnu/ apt-get install libc6:amd64
# LD_LIBRARY_PATH=/lib/i386-linux-gnu/ apt-get install libc6:i386

but this still threw up the same libz.so.1 errors for me.

Instead, download the latest libc6 amd64 and i386 debs from packages.debian.org, and place them inside separate, empty directories in the chroot. Run


# ar xv dpkg -i libc6_2.17-2_amd64.deb
# tar -xzf control.tar.gz

and edit preinst. Around lines 476-477, you need to comment out the following 2 lines


# rm -f /etc/ld.so.cache
# rm -f /var/cache/ldconfig/aux-cache

You can new recompress the deb with


tar zcvf control md5sums postinst prerm && ar rcv abc_patch.deb debian-binary control.tar.gz data.tar.gz

and install it with


LD_LIBRARY_PATH=/lib/x86_64-linux-gnu/ dpkg -i libc6_2.17-2_amd64.deb

Now, repeat the process with the i386 deb, although you’ll need to change the LD_LIBRARY_PATH in the final step to be


LD_LIBRARY_PATH=/lib/i386-linux-gnu/

Remarks
You can now run apt to fix any broken dependencies that there’ll inevitably be with libc6-dev, etc.

All in all, this is a problem I’d usually expect from arch rather than debian (even unstable)!