cheatsheet.zwischenspeicher.info

Some tech documentation and snippets, finally organized.
Posts tagged as apt

APT: Prevent upgrading of particular packages

There are cases in which it is desirable to keep a certain package version, be it a forced downgrade or a custom build. Here I show several ways to achieve this.

The most simple possibility is to mark the package hold in the dpkg status file /var/lib/dpkg/status:

$ echo "PACKAGE_NAME hold" | dpkg set-selections

or, using apt-mark as wrapper:

$ apt-mark hold PACKAGE_NAME

To undo this and return the selected package to apt's default workflow, run

$ echo "PACKAGE_NAME installed" | dpkg set-selections

or, respectively:

$ apt-mark unhold PACKAGE_NAME

This is a very static solution and apt provides a much more flexible way of package handling, called pinning. It is configured in the file /etc/apt/preferences resp. in an arbitrary file in the /etc/apt/preferences.d/ directory.

Pinnig allows prioritization of package versions depending on factors like version number, repository or release name - wildcards and regular expressions are allowed. The most simple configuration for a single package, analog to the dpkg way described above, would look like this:

### File: /etc/apt/preferences 
###       OR
###       /etc/apt/preferences.d/SOMEFILE

Package:        PACKAGE_NAME
Pin:            version PACKAGE_VERSION
Pin-Priority:   1001

See the manpage apt_preferences(5) for a detailed description of all pinning possibilities.

Finally, for local builds it is possible to assign them a local version number, as I have described in this post, and pin, if necessary, based on that.

Auto-upgrade for Debian based systems

A reliable auto-updater for home use. It can be executed e.g. at boot from /etc/rc.local to keep apt based systems up-to-date. Some output will be logged to /var/log/safe-upgrade.log, in case of upgraded or held packages as well as errors a report will be sent to root@localhost.

Update August, 2020: Command line option "--full" for Dist-Upgrade.
Update June, 2022: sleep-loop for delayed connections (dial-up, WiFi).

#!/bin/sh
#
# safe-upgrade.sh
#
# automated "safe-upgrade" for apt-based distributions with logging
# to /var/log/safe-upgrade.log and a mail to root@localhost in case
# of upgraded packages or problems
# optional command line parameter "--full" will run a dist-upgrade

pingtest=debian.org
hostname=`hostname`
logfile=/var/log/safe-upgrade.log
mailto=root@localhost

if [ X"$@" = X"--full" ] ; then
        task=dist-upgrade
else
        task=upgrade
fi

sleep 15
echo ----- `date` ----- >> "$logfile"
ping -c 1 "$pingtest" > /dev/null 2>> "$logfile" ||\
    {
        echo "System upgrade cancelled: No internet connection." |\
        tee -a "$logfile" |\
        mailx -s "$hostname"\ update\ \*\*\*ERROR\*\*\* "$mailto"
        exit 0
    }
DEBIAN_FRONTEND=noninteractive
apt-get -q=2 update 2>&1 |\
    tee -a "$logfile" |\
    mailx -E -s "$hostname"\ update\ \*\*\*ERROR\*\*\* "$mailto"
apt-get "$task" -y -q 2>&1 |\
    grep -ve "^(\{0,1\}Reading" \
         -e "^Building" \
         -e "^Calculating" |\
    tee -a "$logfile" |\
    grep -ve "^0 upgraded.*0 not upgraded\.$" |\
    mailx -E -s "$hostname"\ upgrade\ log "$mailto" &&
echo ----- DONE ----- >> "$logfile"
exit 0

To tame the daily growing log file, add the following lines to /etc/logrotate.conf or into an own file in /etc/logrotate.d/. This will keep compressed archives of the last three months' log files.

### File: /etc/logrotate.conf

/var/log/safe-upgrade.log {
    monthly
    create
    rotate 3
}

If you want the script to be executed by cron, it is necessary to set the $PATH variable - in the script itself, or in the crontab. This example runs every three hours at 45':

### File: root crontab, open to edit with "crontab -e"

# m h  dom mon dow   command
45 */3 * * * PATH='/usr/sbin:/usr/bin:/sbin:/bin' /path/to/safe-upgrade.sh

Hotfixing a Debian package

How to patch and compile a Debian package from its source and avoid future re-installation of the unpatched version by creating a local version number. Example: claws-mail.

Note: Source repositories need to be enabled in the sources.list.

Become root and install the needed software:

$ sudo su
$ apt-get install build-essential apt-src devscripts patch

Create a working directory, here /usr/src/claws-mail and enter it:

$ mkdir /usr/src/claws-mail
$ cd /usr/src/claws-mail

apt-src will download and install the Debian source package itsself as well as all needed development files and tools:

$ apt-src install claws-mail

Enter the source tree, apply the patch (or edit source manually) and use debchange from the "devscripts" package to create a local version number with suffix "local". It is possible to append a short decripive text directly to the debchange command, which will be added to the packages changelog:

$ cd claws-mail-VERSION
$ patch SOURCEFILE DIFF
$ debchange --local local PATCH_DESCRIPTION...

If no changelog text is given, an editor will open the changelog. (Edit, save and) close the file to continue. Now leave the source tree and compile the package:

$ cd ..
$ apt-src -p build claws-mail

This will take a while. When back at the command prompt, the newly built Debian package(s) can be found in the "top level" working directory, ready to install.

$ cd ..
$ dpkg -i ALLTHEDEBS

Finally clean the leftovers of the build process from the source tree:

$ apt-src clean claws-mail

Note: The next official update of the package will automatically overwrite this local version. In case the update does not contain the locally applied patch, update the apt package index and run apt-src again. It will try to bring the patch forward:

$ apt-get update
$ cd /usr/src/claws-mail
$ apt-src -b upgrade claws-mail
$ cd .. && dpkg -i ALLTHEDEBS

If you want to install all of the built packages (or there is only one package going to be built), it is sufficient to run

$ apt-src -i install claws-mail

This will update, patch and compile the sources and finally install the newly built package(s) in one go.