FreeBSD 5.4 to FreeBSD 6.0 binary upgrade

My earlier instructions on performing a binary upgrade from FreeBSD 4.8 to FreeBSD 4.11 and binary upgrade from FreeBSD 5.3 to FreeBSD 5.4 proved quite popular, so I thought I'd prepare a similar set of instructions for upgrading to FreeBSD 6.0.

This upgrade is more tricky than the earlier "minor version" upgrades, since you have to be running a 6.0 kernel before you can install binaries for 6.0, and you have to replace everything which used 5.4 libraries before you can delete them safely.

What follows are the steps I used to upgrade my FreeBSD 5.4-RELEASE systems to FreeBSD 6.0-RELEASE.

N.B. I only install the "base" "dict", "doc", and "manpages" distributions here -- I don't want the "catpages", "games", "info", "ports", "proflibs", or "src" distributions. If you want a different set of distributions, change the lists in steps 7, 8, 12, 13, and 16.

N.B. #2 This will obviously result in a system which is running a GENERIC kernel. If you need support for hardware or kernel options which aren't in that kernel, follow the instructions in src/UPDATING to upgrade via source.

  1. If you haven't done so already, install FreeBSD Update and portupgrade.

    cd /usr/ports/security/freebsd-update && make install clean
    cp /usr/local/etc/freebsd-update.conf.sample /usr/local/etc/freebsd-update.conf
    cd /usr/ports/sysutils/portupgrade && make install clean
  2. Using FreeBSD Update, generate a list of files from the base system which have been locally modified. We might not want to overwrite these.

    freebsd-update -v IDS | tail +8 | grep . > /root/base-modified
  3. Edit this list and delete files for which you don't want to keep your local changes. You'll almost certainly want to delete any lines starting with /usr/, but you'll probably want to keep the lines which start with /etc/ or /var/log/.

    ee /root/base-modified
    (or use vi or any other text editor you have installed.)

  4. Generate a list of files installed which belong to the old RELEASE. We'll be using this list to make sure we don't leave old files lying around after the upgrade.

    cut -f 1 -d '$' /usr/local/freebsd-update/work/md5all | uniq |
    	while read X; do
    		if [ -f $X ]; then echo $X; fi;
    	done | sort > /root/base-old
  5. Add the new _dhcp user and group.

    pw groupadd _dhcp -g 65
    pw useradd _dhcp -u 65 -c "dhcp programs" -d /var/empty -s /usr/sbin/nologin
    echo "_dhcp: root" >> /etc/mail/aliases
  6. Download an ISO image for the new release, verify its hash, and mount it.

    fetch -o /usr/disc1.iso	\
    md5 /usr/disc1.iso
    (the hash printed should be cfe3c1a2b4991edd6a294ca9b422b9d5.)
    mdconfig -a -t vnode -f /usr/disc1.iso -u 9
    mount -t cd9660 -o ro /dev/md9 /mnt
  7. Copy the base system components off the ISO image (this is necessary because we won't be able to mount the ISO after rebooting into the new kernel.)

    for dist in base dict doc manpages; do
    	cat /mnt/6.0-RELEASE/${dist}/${dist}.?? > /usr/${dist}.tgz
  8. For the files which have been locally modified, extract the new versions to a temporary directory.

    mkdir /usr/release
    for dist in base dict doc manpages; do
    	tar -xpzf /usr/${dist}.tgz -I /root/base-modified -C /usr/release
  9. For each of the configuration files which have been locally modified, compare the existing and new versions to see if there are any changes between FreeBSD 5.4 and 6.0 which you need to add into the configuration files on your system.

    grep ^/etc /root/base-modified | while read f; do
    	diff -u ${f} /usr/release${f}
    done | more
  10. Clear the immutable flag on files from the base system to make sure that we can overwrite or delete them.

    xargs chflags noschg < /root/base-old
  11. Extract the new kernel and modules, and reboot.

    tar -Uxpzf /usr/base.tgz -X /root/base-modified -C / /boot/
    shutdown -r now
    The system will now be in an inconsistent state, running a 6.0 kernel together with a 5.4 userland. Programs which interact directly with kernel internals (w, ps, top, mdconfig, etc.) will not work!

  12. Extract the new release (minus locally modified files which we don't want to overwrite), and reboot again to get into a fully functional FreeBSD 6.0 system.
    for dist in base dict doc manpages; do
    /rescue/tar -Uxpzf /usr/${dist}.tgz -X /root/base-modified -C /
    shutdown -r now
  13. Generate a list of files which belong to the new release, and compare this to the list of files which were in the old release, so that we can clean up the garbage left behind, and delete everything apart from libraries (which need to be left for the benefit of applications installed from the ports tree for now).

    for dist in base dict doc manpages; do
    	tar -tzf /usr/${dist}.tgz
    done | lam -s '/' - | sort -u - /root/base-modified > /root/base-new
    comm -13 /root/base-new /root/base-old | grep -v /lib/ | xargs rm
  14. UPDATE, 2006-04-14: Due to some database format changes between FreeBSD 5.4 and FreeBSD 6.0, it's a good idea to rebuild portupgrade now, before rebuilding everything else.

    portupgrade -fR portupgrade

  15. Recompile all applications installed from the ports tree.

    portupgrade -af
    If you have any other compiled programs installed, you should also recompile them at this point.

  16. Clean up (including removal of old libraries which are now unneeded).

    comm -13 /root/base-new /root/base-old | grep /lib/ | xargs rm
    rm -r /usr/release
    rm /usr/disc1.iso
    rm /usr/base.tgz /usr/dict.tgz /usr/doc.tgz /usr/manpages.tgz
    rm /root/base-modified /root/base-old /root/base-new
  17. If you have portsnap installed from the ports tree, you should uninstall it and move its data directory.
    cd /usr/ports/sysutils/portsnap && make deinstall
    rmdir /var/db/portsnap && mv /usr/local/portsnap /var/db/portsnap