Hatred's Log Place

DON'T PANIC!

Mar 12, 2018 - 3 minute read -

Проверка целостности AUR пакетов после обновления

Время от времени, после обновления основной системы, обновляются библиотеки и некоторые пакеты, собранные вручную ломаются. Ниже представлена небольшая задумка автоматической проверки таких пакетов после обновления.

Для начала сделаем скрипт, который будет пробегаться по пакетам, которых нет в репозиториях и применять к ним некоторый набор действий, который позволит понять, что пакет поломан.

Сам критерий простой: ldd на ELF файле и удостовериться, что нет вхождений ‘not found’.

Кроме того, мы можем достаточно быстро проверить факт того, что пакет вообще был выброшен, если его нет ни в репозиториях, ни в AUR. К таким пакетам так же будут отнесены все пакеты, поставленные вручную локально.

Итак, для начала скрипт проверки (aur-check):

#!/usr/bin/env bash

# Ref to the /etc/makepkg.conf PACKAGER
PACKAGE_USER="Alexander Drozdov"

set -e
export LANG=C

packages=$(pacman -Qmq)
orphaned=""
declare -A broken
declare -A distro

aur_info_cower() {
	cower -iq --timeout=30 -- $packages | grep '^Name' | awk '{print $3}' 
}

aur_info_auracle() {
	auracle info -F '{name}' -- $packages
}

aur_info_yay_pacaur() {
	$1 -Siq --aur -- $packages | grep '^Name' | awk '{print $3}'
}

aur_info_yay() {
	aur_info_yay_pacaur yay
}

aur_info_pacaur() {
	aur_info_yay_pacaur pacaur
}

aur_info_detect_backend() {
	set +e
	which auracle > /dev/null 2>&1 && aur_info_backend="auracle" && return
	which cower > /dev/null 2>&1 && aur_info_backend="cower" && return
	which yay > /dev/null 2>&1 && aur_info_backend="yay" && return
	which pacaur > /dev/null 2>&1 && aur_info_backend="pacaur" && return
	set -e
}

check_orphaned() {
    list1=$(mktemp -p /tmp -u XXXXXXXX)
    list2=$(mktemp -p /tmp -u XXXXXXXX)
    trap "rm -f $list1 $list2" RETURN QUIT
    pacman -Qmq > $list1
	eval "aur_info_${aur_info_backend}" > $list2
	orphaned=$(diff -u $list1 $list2 | grep '^-' | grep -v '^---' | sed 's|^-||')
}

# detect tool to ask AUR package info
aur_info_detect_backend

# Check for orphaned packages
[ -n "$aur_info_backend" ] && check_orphaned

# Check integrity
for pkg in $packages
do
    echo "    => $pkg"

    # Check that package previously maintained by Distro
    dist_check=$(pacman -Qi $pkg | grep '^Packager' | grep -v "$PACKAGE_USER\|Unknown Packager")
    if [ -n "$dist_check" ]; then
        distro[$pkg]=1
    fi

    # Basic check for package breaks, mostly call ldd for libs and binaries
    files=$(pacman -Qlq $pkg)
    for file in $files
    do
        # Check only executables and skip directories. 
        # Also, skip packages from /opt/ prefix, most of them is a 
        # binary distributed and need a LD_PRELOAD_PATH to be configured
        # right
        if [ -x "$file" -a "${file:0:5}" != "/opt/" ]; then
            is_elf=$(file $file | grep ELF || true)
            if [ -n "$is_elf" ]; then
                # Apply check
                tmp=$(mktemp /tmp/XXXXXXXXXXXXXXXXXX)
                ldd "$file" > "$tmp" 2>&1 || true
                is_broken=$(cat "$tmp" | grep '=> not found' || true)
                if [ -n "$is_broken" ]; then
                    broken[$pkg]=1
                    echo "       $file:"
                    cat "$tmp" | grep '=> not found' | ts '       '
                fi
                rm -f "$tmp"
            fi
        fi
    done
done

if [ -n "$orphaned" ]; then
    echo "Orphaned packages summary:"
    for pkg in $orphaned
    do
        echo "    $pkg"
    done
fi

if [ ${#distro[@]} -gt 0 ]; then
    echo "Previously maintained by the Distro summary:"
    for pkg in ${!distro[*]}
    do
        echo "    $pkg"
    done
fi

if [ ${#broken[@]} -gt 0 ]; then
    echo "Broken packages summary:"
    for pkg in ${!broken[*]}
    do
        echo "    $pkg"
    done
fi

Поместите его в /usr/local/bin/.

Будет определённое неудобство при недоступности сети, при проверке брошенных пакетов (запрос к AUR). Я думаю исправить это в будущем.

А теперь HOOK для libaplm (99-99-aur.hook):

# /usr/share/libalpm/hooks/99-99-aur.hook
# /etc/pacman.d/hooks/99-99-aur.hook
[Trigger]
Operation = Upgrade
Type = Package
Target = *

[Action]
Description = "Check non-repo packages integrity"
Depends = auracle
When = PostTransaction
Exec = /usr/local/bin/aur-check

Обратите внимание, я настроил запуск проверки только на операции обновления пакетов, так как установка дополнительного пакета не должна ломать существующие, а удаление должно корректно отследиться через механизм зависимостей. А если этого не произошло, то стоит обратить внимание разработчика пакета на эти нюансы.

Сам HOOK нужно положить в /etc/pacman.d/hooks/ (/usr/share/libalpm/hooks/ предназначен для установки хуков через пакетный менеджер).

Сам скрипт и хук оформил в виде GitHub Gist: AUR basic integrity check