Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Unattended updates for Devuan Ceres, 2021 edition

This is an update to Unattended software updates on Devuan (2018). I use Devuan Ceres, which is the rolling release of Devuan (Debian without systemd): It's the equivalent of Debian Sid. One of the by-products of it being a rolling release is that it on occasion changes release names (from Beowulf to Chimaera, for example). To handle updating the packages when that occurs, you have to run a dist-upgrade, which can get tricky. My whole script for updating unattended (which is a misnomer) follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/bin/sh
# File: update-devuan.sh
# Location: /mnt/public/Support/Platforms/devuan
# Author: bgstack15
# Startdate: 2019-07-01 18:48
# Title: The command to run for mostly-unattended updates on Devuan
# Purpose: Mostly-unattended apt-get dist-upgrade
# History:
#    2019-12-15 add the y/n if dist-upgrade will remove packages
#    2020-02-26 add --allow-downgrades for the libqt5core5a which was customized for freefilesync or similar
# Usage:
# Reference:
# Improve:
# Documentation:

export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

test "${1}" = "preseed" && extrastring="--allow-downgrades"

mkdir -p ~/log
myupdate() {
   sudo apt-get update ;
   sudo DEBIAN_FRONTEND=noninteractive apt-get -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-overwrite" upgrade ;
   ___remove_count="$( yes no | sudo apt-get dist-upgrade 2>&1 | grep -oiE '[0-9]+ to remove' | grep -oE '[0-9]*' )"
   ___do_run="no"
   if test "${___remove_count}" = "0" ;
   then
      ___do_run="yes"
   else
      ___to_remove="$( yes no | sudo apt-get dist-upgrade 2>&1 | awk 'BEGIN{a=0} /^[ \s]/{ if(a==1)print;} /^[a-zA-Z]/ {if(/REMOVED/ || /NEW /){a=1;print} else {a=0}}' )"
      echo "${___to_remove}" 1>&2
      echo "WARNING: are you sure you want to do this [yN]? " 1>&2
      test -z "${extrastring}" && { read response ; } || ___do_run="yes"
      if test "$( echo "${response}" | cut -c1 2>/dev/null | tr '[A-Z]' '[a-z]' )" = "y" ; then ___do_run="yes" ; fi
   fi
   if test "${___do_run}" = "yes" ;
   then
      sudo DEBIAN_FRONTEND=noninteractive apt-get -q ${extrastring} -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-overwrite" dist-upgrade ;__f=$? ; 
   fi
   date ; return ${__f} ;
} ; myupdate 2>&1 | tee -a ~/log/apt-get.upgrade.$( date "+%F" ).log

I open up GNU screen (screen -S updates) and run it.

./update-devuan.sh

It handles the regular upgrade process just fine. It will then parse the output of a dry-run of apt-get dist-upgrade for any removals. If there are zero removed packages, it will plow right into dist-upgrading. If there are any removals, it will pause and wait for input. So it's not entirely unattended , but it is at a good pause point if any manual approval is required before re-running the whole operation. I suppose one could learn how to insert these Dpkg::Options into apt.conf or dpkg.conf or somewhere, but I'm not sure that I would want them around permanently, ergo the long invocations here. How do you, my readers, do you update your systems (mostly) unattended?

Comments