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

set -e
export LANG=C

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

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"
    # 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 [ ${#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
[Trigger]
Operation = Upgrade
Type = Package
Target = *

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

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

Сам HOOK нужно положить в /usr/share/libalpm/hooks/.

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