Upgrading Debian From i386 To amd64
AKA Upgrading Debian From 32-bit To 64-bit

*****WARNING*****

This procedure is, in every possible respect, a bad idea. If it eats your firstborn, please don't come crying to me.

You probably don't need a complete backup of your data to do this safely, but you DO, without question, need boot media that has lots of things on it, like dpkg, for when you fry your system. The expected result of this procedure is a machine on which nothing works, where "nothing" includes "ls".

Seriously; the official documentation specifically declares this procedure to be impossible, which should give you some idea of how bad an idea this is.

*****WARNING*****

Target Audience

Sysadmins that have a 32-bit system that they'd really like to be 64-bit without re-doing all their configuration.

This really is for professional-level sysadmins; I don't suggest that anyone who hasn't seen a Debian box through a few manual broken-apt recoveries with dpkg, and libc upgrades, and kernel upgrades, even consider this.

Smart admins do all the config with cfengine, so this isn't an issue, but I didn't know that when I made this machine. :D

Preparation

Kernel

To make this work, you MUST have a 64-bit kernel installed. Seriously; you can't imagine how badly you'll fuck your system if you follow these steps without a 64-bit kernel.

If "uname -a" doesn't end with "x86_64 GNU/Linux", stop RIGHT NOW and fix it.

If you don't know how to upgrade your kernel, stop reading this. It's not for you.

Statically-Linked Shell And Stuff

To assist possible recovery issues, I strongly suggest apt-getting busybox and running it as a shell ("/bin/busybox ash") in a separate window. Make sure ls and cp and so on work even with PATH=''

List Your Packages

Run dpkg --get-selections and save it to a safe place. You'll want to know what you had installed when apt-get starts trying to make shit up.

Manual Package Downloads

Since both apt-get and dpkg think you're on an i386 machine, 64-bit kernel or no, you're going to have to get yourself some packages.

32-bit Compatibility Libraries

Unless the idea of every binary on your system suddenly ceasing to function sounds like your idea of a good time, you're going to need the 32-bit compatibility libraries for amd64, and you're going to need them before you upgrade libc. Start with the ia32-libs package (i.e. http://packages.debian.org/testing/libs/ia32-libs, but replace "testing" with your actual version) and download the amd64 version of it and ALL its dependencies.

You should now have a directory that looks like this:

ia32-libs_1.19_amd64.deb
lib32asound2_1.0.14a-1_amd64.deb
lib32gcc1_4.2-20070609-1_amd64.deb
lib32ncurses5_5.6-3_amd64.deb
lib32stdc++6_4.2-20070609-1_amd64.deb
lib32z1_1.2.3-15_amd64.deb
libc6-i386_2.5-9_amd64.deb
lsb-release_3.1-23.1_all.deb

dpkg, apt-get, and friends

Grab amd64 versions of dpkg, apt-get, and all their dependencies. You may not end up installing them all manually, but having them around can't hurt. Also grap apt-listchanges and apt-utils.

apt_0.6.46.4-0.1_amd64.deb
binutils_2.17cvs20070426-8_amd64.deb
bzip2_1.0.3-6_amd64.deb
coreutils_5.97-5.3_amd64.deb
cpio_2.7-3_amd64.deb
debianutils_2.21_amd64.deb
dpkg_1.14.4_amd64.deb
ed_0.2-20_amd64.deb
gcc-4.2-base_4.2-20070609-1_amd64.deb
libacl1_2.2.42-1_amd64.deb
libasound2_1.0.14a-1_amd64.deb
libattr1_2.4.32-1.1_amd64.deb
libbz2-1.0_1.0.3-6_amd64.deb
libc6_2.5-9_amd64.deb
libdb4.4_4.4.20-8_amd64.deb
libgcc1_4.2-20070609-1_amd64.deb
libgdbm3_1.8.3-3_amd64.deb
libgpmg1_1.19.6-25_amd64.deb
libncurses5_5.6-3_amd64.deb
libreadline5_5.2-3_amd64.deb
libselinux1_2.0.15-2_amd64.deb
libsepol1_2.0.3-1_amd64.deb
libstdc++6_4.2-20070609-1_amd64.deb
make_3.81-3_amd64.deb
ncurses-bin_5.6-3_amd64.deb
patch_2.5.9-4_amd64.deb
perl-base_5.8.8-7_amd64.deb
perl_5.8.8-7_amd64.deb
sed_4.1.5-2_amd64.deb

The Actual Installation

Please note that order is very important. Read everything before starting. If this order doesn't seem eminently sensible to you, you may want to stop here.

32-bit Compatibility Libraries Install

First is the install of the 32-bit compat libc. This is the fun step:

dpkg --force-depends --force-architecture --force-overwrite -i libc6-i386_2.5-9_amd64.deb

Yes, you really do need all those. When you're done, /lib/ld-linux.so.2 should be a symlink into /emul/ia32-linux, like this:

lrwxrwxrwx 1 root root 34 Jun 26 08:57 /lib/ld-linux.so.2 -> /emul/ia32-linux/lib/ld-linux.so.2*

If it's not (it wasn't for me) run:

ln -sf /emul/ia32-linux/lib/ld-linux.so.2 /lib/ld-linux.so.2

Check that it worked; there should be lots of stuff in /emul/ia32-linux, and:

$ ls -l /usr/lib32 /lib32                        
lrwxrwxrwx 1 root root 20 Jun 26 08:56 /lib32 -> /emul/ia32-linux/lib/
lrwxrwxrwx 1 root root 24 Jun 26 08:56 /usr/lib32 -> /emul/ia32-linux/usr/lib/

Run "dpkg --force-architecture -i" for all of the other 32-bit compat libs until they're all installed. Should be uneventful.

64-bit libc Install

While this should be uneventful, I mention it separately because if you're going to fuck your system, this is where it'll happen. Run:

dpkg --force-architecture -i libc6_2.5-9_amd64.deb

dpkg, apt-get, And Friends Install

If you can still "ls" and such in a non-static shell, congratulations. Now "dpkg --force-architecture -i" the packages for apt-get, dpkg, apt-listchanges, and apt-utils. Then keep trying to run each of apt-get, dpkg, apt-listchanges and apt-extracttemplates until they actually run without erroring.

For apt-listchanges, I had to install (in this order):

python2.4-minimal
python2.4
python-apt
zlib1g
libdb-4.4

That last isn't necessary for getting it to just run, but it was necessary to stop "apt-get -f install" from barfing.

At this point, "dpkg --print-architecture" should say amd64, as should most of "dpkg-architecture" if you have that installed, and "apt-get update" (which you should run) should download a bunch of files to /var/lib/apt/lists that have "amd64" in the name. That's good.

Upsetting apt-get

Run "apt-get update" followed by "apt-get -f install". Keep adding packages until "apt-get -f install" doesn't give you any library or ELFCLASS errors.

Having done so, things will probably still be upset, and you may need to do manual dpkg things. Steps I had to take to make "apt-get -f install" run to completion:

dpkg -i /var/cache/apt/archives/libperl5.8_5.8.8-7_amd64.deb

Note that apt-get will Make Shit Up during this process. For example, it tried to give me exim4-daemon-light, which I never had installed (I use exim4-daemon-heavy). This is what the dpkg selections list is for. Hence:

apt-get -f install exim4 exim4-daemon-heavy apache2-mpm-prefork console-tools libconsole

Then there was funkiness because someone broke tex's dependencies. :P

Ugrading Everything Else

Here's the fun part: catching all the things that haven't been gotten yet. First, make a list of remaining i386 packages:

for package in $(grep '[^e]install' dpkg_get_selections.out | awk '{ print $1 }')
do
    dpkg -s $package | grep -q 'Architecture: i386' && echo $package
done >update

Then open up yourself a copy of the update file (so you can fix the many problems that will occur) and run:

apt-get --reinstall install $(cat update | tr '\012' ' ')

Keep editing and running until it works.

If you thought the last step downloaded a lot of packages, you may be surprised by the results of this step.

After all of that's done, you might want to check your currently installed packages for further badness:

for package in $(dpkg -l |  grep '^i' | awk '{ print $2 }')
do
    dpkg -s $package | grep -q 'Architecture: i386' && echo $package
done >update2

With this list, though, you almost certainly want to remove most or all of them: if they weren't installed as a dependency of the other stuff, you almost certainly don't care. Trim local stuff out (like kernel packages) and run:

dpkg -r $(cat update2 | tr '\012' ' ')

That should pretty much do it.