Restoring a wiped out dpkg status file
2009.08.13 18:23 by Leo Antunes - 5 CommentsUPDATE: Nevermind, nothing to see here, move along… Steve Kemp helpfully pointed out to me the obvious thing I had missed: status-old isn’t the only backup, there’s /var/backups/dpkg.status.*! Oops… doubly stupid.
After seeing madduck’s post and feeling my dpkg was certainly not as quick as it used to be, I decided to try the suggested status-file cleanup.
Since madduck is an old-time Debian developer (actually just one year longer than I am, but certainly way more active) I just assumed he’d have better understanding of dpkg’s inner workings than I do, so I blindly – and wrongly – copy-pasted his code and managed to erase my dpkg status file.
No backups were made out of sheer trust-induced stupidity and the status-old file was somehow also nuked, probably because of something I ran before noticing the problem.
It’s obviously not his fault that I didn’t pay attention to what I was doing, but by then I had royally messed up my machine, basically nuking dpkg, so I had to come up with this ugly little script to try and rebuild the status file.
If someone else managed to do the same absurd mistake, this could help.
#!/bin/bash ls -1 /var/lib/dpkg/info/*.list | sed -r 's/.*\/(.*).list$/\1/' | while read PACKAGE; do echo Package: $PACKAGE if [ -d /usr/share/doc/$PACKAGE ]; then if [ -f /usr/share/doc/$PACKAGE/changelog.Debian.gz ]; then VERSION=`zcat /usr/share/doc/$PACKAGE/changelog.Debian.gz | head -1 | sed -r 's/.*\((.*?)\).*/\1/'` elif [ -f /usr/share/doc/$PACKAGE/changelog.Debian ]; then # downfall of the ia32-* hack VERSION=`head -1 /usr/share/doc/$PACKAGE/changelog.Debian | sed -r 's/.*\((.*?)\).*/\1/'` elif [ -f /usr/share/doc/$PACKAGE/changelog.gz ]; then VERSION=`zcat /usr/share/doc/$PACKAGE/changelog.gz | head -1 | sed -r 's/.*\((.*?)\).*/\1/'` else VERSION=0 # force upgrade, probably locally-built fi echo Status: install ok installed echo Version: ${VERSION} STRIP_FIELDS="Version|Package|Size|Filename|MD5sum|SHA1|SHA256|Tag|Task" CONFFILES_LIST=conffiles else echo Status: deinstall ok config-files STRIP_FIELDS="Package|Size|Filename|MD5sum|SHA1|SHA256|Tag|Task" # in this case we treat all remaining files as conffiles # (if there are no docs, there's no .conffiles either) CONFFILES_LIST=list fi if [ -s /var/lib/dpkg/info/${PACKAGE}.${CONFFILES_LIST} ]; then echo Conffiles: cat /var/lib/dpkg/info/${PACKAGE}.${CONFFILES_LIST} | while read CONFFILE; do if [ -f $CONFFILE ]; then echo " $CONFFILE `md5sum $CONFFILE | awk '{ print $1 }'`"; fi done fi # "grep-available --invert-show" doesn't work as expected, so we grep the fields out (grep-aptavail --mmap -P $PACKAGE -X || (echo package $PACKAGE not found, leaving minimal entry 1>&2 ; echo -e "Version: 0+borkdstatus\n")) | grep -Ev "^($STRIP_FIELDS):" done
Known limitations:
- Needs root access to create some conffile md5sums
- Can’t detect virtual packages, like nvidia-kernel-* stuff and probably everything created with module-assistant. A reinstall of the created packages in /usr/src/*.deb should suffice
- Some packages do some version black-magic in the changelog (gcc-defaults comes to mind). I couldn’t find a better way to get the actual installed version, but a dist-upgrade after restoring the file should just re-install the affected packages.
- Won’t correctly detect packages in an intermediary state like “unpacked, but not configured” (haven’t tested this)
- Can’t detect purged packages at all, though this shouldn’t be a problem
Did I miss something? Is there a tool or a dpkg option that does this in a smarter/easier way?