Compiling rdiff-backup 2.0.5 on Debian 12

Introduction

My backup server ran Debian 11 with rdiff-backup 2.0.5. It had to back up clients running the same OS version (obviously not a problem) and clients running Debian 12 with rdiff-backup 2.2.2, which I solved by using the virtualenv command to download and compile rdiff-backup 2.0.5 and then use that to communicate with the Debian 12 clients.

However, recently, I upgraded my backup server to Debian 12 with rdiff-backup 2.2.2. It still has to back up the same clients, which means it has to back up clients running the same OS version (obviously not a problem) and clients running Debian 11 with rdiff-backup 2.0.5, which I solved, but which was more troublesome than it should have been!

Firstly, I expected virtualenv to have been able to do this, but it could not compile rdiff-backup, producing the errors:

src/_librsyncmodule.c:543:36: error: lvalue required as left operand of assignment
  543 |   Py_TYPE(&_librsync_SigMakerType) = &PyType_Type;
      |                                    ^
src/_librsyncmodule.c:544:38: error: lvalue required as left operand of assignment
  544 |   Py_TYPE(&_librsync_DeltaMakerType) = &PyType_Type;
      |                                      ^

This bug has been reported in a few places (e.g. here and here).

Secondly, I hoped virtualenv could build its own python version, but it seems that virtualenv and other similar tools will build modules against an already-installed python, but they will not build a new python.

Thirdly, I downloaded the sources for the version of python that comes with Debian 11, which was 3.9, and although I could compile that, I could not then use its pip3 to build rdiff-backup.

Finally, I tried debootstrap, which was suprisingly easy!

Procedure

  1. Create a suitable directory to host rdiff-backup 2.0.5, let’s call it $CHROOT_DIR:
    CHROOT_DIR=<whatever>
    mkdir -p $CHROOT_DIR
    
  2. Install debootstrap, if it is not already installed:
    apt-get -y install debootstrap
  3. Populate it with a minimal Debian 11 (bullseye) installation and give it a copy of /proc and /sys so that more commands work:
    debootstrap --arch amd64 bullseye $CHROOT_DIR \
        http://deb.debian.org/debian/ > /dev/null
    mount -t proc proc $CHROOT_DIR/proc
    mount -t sysfs sysfs $CHROOT_DIR/sys
    cp /etc/hosts $CHROOT_DIR/etc/hosts
    #  debootstrap shouldn't have created /etc/mtab 
    #  in the chroot env, but let's be sure!
    rm -f $MY_CHROOT/etc/mtab
    ln -s ../proc/self/mounts $MY_CHROOT/etc/mtab
    
  4. At this point we can install rdiff-backup in the chroot:
    chroot $CHROOT_DIR /bin/bash -c "apt-get -y install rdiff-backup"
    
  5. rdiff-backup refers to python3.9 inside the chroot …
    damson# grep '#!' $CHROOT_DIR/usr/bin/rdiff-backup
    #!/usr/bin/python3
    damson#

    … so – as it stands – it will only work if we chroot into $CHROOT_DIR and run it there, but in such an environment it won’t be able to access any backup media, which are probably mounted outside $CHROOT_DIR! So we need to change that ‘#!‘ path to refer to the python inside $CHROOT_DIR but to refer to it in such a way that we call it from outside $CHROOT_DIR. We do this by running:

    sed -i "s@/usr/bin/python3@$CHROOT_DIR/usr/bin/python3@" $CHROOT_DIR/usr/bin/rdiff-backup
  6. Unmount the copy of /proc and /sys, which are no longer needed:
    umount $CHROOT_DIR/sys
    umount $CHROOT_DIR/proc
  7. Verify that it basically works and reports the right version:
    damson# $CHROOT_DIR/usr/bin/rdiff-backup --version
    rdiff-backup 2.0.5
    damson#
  8. Obviously you should also verify that it actually can successfully back up and restore stuff, which I did, but explaining that is outside the scope of this short procedure.

See also