core-agent-linux/misc/qubes-download-dom0-updates.sh
Marek Marczykowski-Górecki ca659ef6df
Fix downloading dom0 updates on Debian
When yumdownloader is used, it needs yum.conf. In Qubes 4.1 it isn't
there anymore, so symlink dnf.conf instead.

In Debian case, packages are downloaded directly to packages directory,
doesn't need to be extracted from cache. Redirect error message to
/dev/null for that.
2019-08-07 00:04:47 +02:00

183 lines
5.9 KiB
Bash
Executable File

#!/bin/bash
DOM0_UPDATES_DIR=/var/lib/qubes/dom0-updates
GUI=1
CLEAN=0
CHECK_ONLY=0
OPTS="--installroot $DOM0_UPDATES_DIR"
if [ -f "$DOM0_UPDATES_DIR/etc/dnf/dnf.conf" ]; then
OPTS="$OPTS --config=$DOM0_UPDATES_DIR/etc/yum.conf"
elif [ -f "$DOM0_UPDATES_DIR/etc/yum.conf" ]; then
OPTS="$OPTS --config=$DOM0_UPDATES_DIR/etc/yum.conf"
fi
# DNF uses /etc/yum.repos.d, even when --installroot is specified
OPTS="$OPTS --setopt=reposdir=$DOM0_UPDATES_DIR/etc/yum.repos.d"
PKGLIST=()
YUM_ACTION=
export LC_ALL=C
while [ -n "$1" ]; do
case "$1" in
--doit)
# ignore
;;
--nogui)
GUI=0
;;
--gui)
GUI=1
;;
--clean)
CLEAN=1
;;
--check-only)
CHECK_ONLY=1
;;
--action=*)
YUM_ACTION=${1#--action=}
;;
-*)
OPTS="$OPTS $1"
;;
*)
PKGLIST+=( "${1}" )
if [ -z "$YUM_ACTION" ]; then
YUM_ACTION=install
fi
;;
esac
shift
done
if [ -z "$YUM_ACTION" ]; then
YUM_ACTION=upgrade
fi
YUM="yum"
if type dnf >/dev/null 2>&1; then
YUM="dnf --best --allowerasing --noplugins"
else
# salt in dom0 thinks it's using dnf but we only have yum so need to remove extra options
OPTS="${OPTS/--best --allowerasing/}"
fi
if ! [ -d "$DOM0_UPDATES_DIR" ]; then
echo "Dom0 updates dir does not exists: $DOM0_UPDATES_DIR" >&2
exit 1
fi
mkdir -p $DOM0_UPDATES_DIR/etc
if [ -e /etc/debian_version ]; then
# Default rpm configuration on Debian uses ~/.rpmdb for rpm database (as
# rpm isn't native package manager there)
mkdir -p "$DOM0_UPDATES_DIR$HOME"
ln -nsf "$DOM0_UPDATES_DIR/var/lib/rpm" "$DOM0_UPDATES_DIR$HOME/.rpmdb"
fi
# Rebuild rpm database in case of different rpm version
rm -f $DOM0_UPDATES_DIR/var/lib/rpm/__*
rpm --root=$DOM0_UPDATES_DIR --rebuilddb
if [ "$CLEAN" = "1" ]; then
# shellcheck disable=SC2086
$YUM $OPTS clean all
rm -f "$DOM0_UPDATES_DIR"/packages/*
rm -rf "$DOM0_UPDATES_DIR"/var/cache/*
fi
# just check for updates, but don't download any package
if [ ${#PKGLIST[@]} -eq 0 ] && [ "$CHECK_ONLY" = "1" ]; then
echo "Checking for dom0 updates..." >&2
# shellcheck disable=SC2086
UPDATES_FULL=$($YUM $OPTS check-update)
check_update_retcode=$?
if [ "$check_update_retcode" -eq 1 ]; then
# Exit here if yum have reported an error. Exit code 100 isn't an
# error, it's "updates available" info, so check specifically for exit code 1
exit 1
fi
if [ $check_update_retcode -eq 100 ]; then
echo "Available updates: "
echo "$UPDATES_FULL"
exit 100
else
echo "No new updates available"
if [ "$GUI" = 1 ]; then
zenity --info --text="No new updates available"
fi
exit 0
fi
fi
# now, we will download something
YUM_COMMAND="fakeroot $YUM $YUM_ACTION -y --downloadonly"
# check for --downloadonly option - if not supported (Debian), fallback to
# yumdownloader
if ! $YUM --help | grep -q downloadonly; then
# setup environment for yumdownloader to be happy
if [ ! -e "$DOM0_UPDATES_DIR/etc/yum.conf" ]; then
ln -nsf dnf/dnf.conf "$DOM0_UPDATES_DIR/etc/yum.conf"
fi
if [ "$YUM_ACTION" = "install" ]; then
YUM_COMMAND="yumdownloader --destdir=$DOM0_UPDATES_DIR/packages --resolve"
elif [ "$YUM_ACTION" = "upgrade" ]; then
# shellcheck disable=SC2086
UPDATES_FULL=$($YUM $OPTS check-update "${PKGLIST[@]}")
check_update_retcode=$?
UPDATES_FULL=$(echo "$UPDATES_FULL" | grep -v "^Loaded plugins:\|^Last metadata\|^$")
mapfile -t PKGLIST < <(echo "$UPDATES_FULL" | grep -v "^Obsoleting\|Could not" | cut -f 1 -d ' ')
if [ "$check_update_retcode" -eq 0 ]; then
# exit code 0 means no updates available - regardless of stdout messages
echo "No new updates available"
exit 0
fi
YUM_COMMAND="yumdownloader --destdir=$DOM0_UPDATES_DIR/packages --resolve"
elif [ "$YUM_ACTION" == "list" ] || [ "$YUM_ACTION" == "search" ]; then
# those actions do not download any package, so lack of --downloadonly is irrelevant
YUM_COMMAND="$YUM $YUM_ACTION -y"
elif [ "$YUM_ACTION" == "reinstall" ]; then
# this is just approximation of 'reinstall' action...
mapfile -t PKGLIST < <(rpm --root=$DOM0_UPDATES_DIR -q "${PKGLIST[@]}")
YUM_COMMAND="yumdownloader --destdir=$DOM0_UPDATES_DIR/packages --resolve"
else
echo "ERROR: yum version installed in VM $(hostname) does not suppport --downloadonly option" >&2
echo "ERROR: only 'install' and 'upgrade' actions supported ($YUM_ACTION not)" >&2
if [ "$GUI" = 1 ]; then
zenity --error --text="yum version too old for '$YUM_ACTION' action, see console for details"
fi
exit 1
fi
fi
mkdir -p "$DOM0_UPDATES_DIR/packages"
set -e
if [ "$GUI" = 1 ]; then
( echo "1"
# shellcheck disable=SC2086
$YUM_COMMAND $OPTS "${PKGLIST[@]}"
echo 100 ) | zenity --progress --pulsate --auto-close --auto-kill \
--text="Downloading updates for Dom0, please wait..." --title="Qubes Dom0 updates"
else
# shellcheck disable=SC2086
$YUM_COMMAND $OPTS "${PKGLIST[@]}"
fi
find "$DOM0_UPDATES_DIR/var/cache" -name '*.rpm' -print0 2>/dev/null |\
xargs -0 -r ln -f -t "$DOM0_UPDATES_DIR/packages/"
if ls "$DOM0_UPDATES_DIR"/packages/*.rpm > /dev/null 2>&1; then
cmd="/usr/lib/qubes/qrexec-client-vm dom0 qubes.ReceiveUpdates /usr/lib/qubes/qfile-agent"
qrexec_exit_code=0
$cmd "$DOM0_UPDATES_DIR"/packages/*.rpm || { qrexec_exit_code=$? ; true; };
if [ ! "$qrexec_exit_code" = "0" ]; then
echo "'$cmd $DOM0_UPDATES_DIR/packages/*.rpm' failed with exit code ${qrexec_exit_code}!" >&2
exit "$qrexec_exit_code"
fi
else
echo "No packages downloaded"
fi