Skip to content
Snippets Groups Projects
check-dbus-services 5.79 KiB
#!/bin/sh

# Check that all activatable D-Bus services use systemd, and that they
# can be started
#
# Copyright © 2015-2016 Collabora Ltd.
#
# SPDX-License-Identifier: MPL-2.0
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

set -e

any_failed=0
failed=0
xfailed=0
skipped=0

# pass NAME [MESSAGE...]
# Record a test as passed
pass () {
    name="$1"
    shift
    # highlight in green, for easier manual testing
    printf "\033[32mvvvvvvvvvvvvvvvvvvvv\n"
    # keep the result on its own logical line so LAVA can parse it
    echo "RESULT:pass:$name: $*"
    # reset after this line
    printf "^^^^^^^^^^^^^^^^^^^^\033[0m\n"
}

# fail NAME [MESSAGE...]
# Record a test as failed
fail () {
    name="$1"
    shift
    # like pass(), but red
    printf "\033[31mvvvvvvvvvvvvvvvvvvvv\n"
    echo "RESULT:fail:$name: $*"
    printf "^^^^^^^^^^^^^^^^^^^^\033[0m\n"
    any_failed=1
    failed=1
}

# xfail NAME [MESSAGE...]
# Record a test as an expected failure
xfail () {
    name="$1"
    shift
    # like pass(), but purple
    printf "\033[35mvvvvvvvvvvvvvvvvvvvv\n"
    echo "RESULT:xfail:$name: $*"
    printf "^^^^^^^^^^^^^^^^^^^^\033[0m\n"
    xfailed=1
}

# skip NAME [MESSAGE...]
# Record a test as skipped
skip () {
    name="$1"
    shift
    # like pass(), but blue
    printf "\033[34mvvvvvvvvvvvvvvvvvvvv\n"
    echo "RESULT:skip:$name: $*"
    printf "^^^^^^^^^^^^^^^^^^^^\033[0m\n"
    skipped=1
}

# run_verbose COMMAND [ARGS...]
# Run COMMAND ARGS and exit with the same status, diagnosing the command
# and its exit status.
run_verbose () {
    echo "+ $*"
    e=0
    "$@" || e=$?
    echo "-> $e"
    return $e
}

if [ "$(id -u)" = 0 ]; then
    bus=system
    systemd=system
    dir=system-services
    systemd_dir="/lib/systemd/$systemd"
else
    bus=session
    systemd=user
    dir=services
    systemd_dir="/usr/lib/systemd/$systemd"
fi

systemctl="systemctl --full --no-ask-password --no-pager --$systemd"

cd "/usr/share/dbus-1/$dir"

# Make sure systemd and dbus-daemon are up to date with any recently-installed
# services or configuration
run_verbose $systemctl daemon-reload
run_verbose gdbus call --$bus -d org.freedesktop.DBus -o /org/freedesktop/dbus \
    -m org.freedesktop.DBus.ReloadConfig

# Positive tests: services that we actually want have got it right

for service in *.service; do
    failed=0
    xfailed=0
    skipped=0

    name="${bus}_${service}"

    if [ "${service}" = "org.freedesktop.systemd1.service" ]; then
        # silently skip: this is not really activatable
        continue
    fi

    if [ "${service}" = "org.apertis.ApertisTests.FailToActivate.service" ]; then
        # silently skip: this is tested a bit later
        continue
    fi

    echo "---------------------------------------------------------------"

    if ! bus_name="$(grep "^Name=" "$service")"; then
        fail "$name" "name not configured"
        continue
    fi

    if ! systemd_service="$(grep "^SystemdService=" "$service")"; then
        if [ "$bus" = session ]; then
            # TODO: port the session services, too (T284)
            xfail "$name" "systemd service not configured"
        else
            fail "$name" "systemd service not configured"
        fi
    fi

    systemd_service="${systemd_service#SystemdService=}"
    bus_name="${bus_name#Name=}"

    if [ "$service" != "${bus_name}.service" ]; then
        if [ "$bus" = system ]; then
            # on the system bus this is fatally bad
            # https://lintian.debian.org/tags/dbus-system-service-wrong-name.html
            fail "$name" "filename does not match Name=${bus_name}"
        else
            # on the session bus this is undesirable but OK
            # https://lintian.debian.org/tags/dbus-session-service-wrong-name.html
            echo "WARNING:$name: filename does not match Name=${bus_name}"
        fi
    fi

    if [ -n "$systemd_service" ] &&
        ! { [ -e "$systemd_dir/$systemd_service" ] ||
            [ -e "/etc/systemd/${systemd}/$systemd_service" ]; }; then
        fail "$name" "matching systemd service $systemd_service not found"
    fi

    if [ "${bus}:${bus_name}" = "system:org.freedesktop.thermald" ] &&
            systemd-detect-virt --quiet; then
        skip "$name" "thermald does not make sense in a virtual machine"
    elif ! run_verbose gdbus call --$bus -d "$bus_name" -o / \
            -m org.freedesktop.DBus.Peer.Ping; then
        fail "$name" "could not ping $bus_name"
    fi

    # The exit code from this does not necessarily tell us anything about it;
    # it will be nonzero if an on-demand service has exited.
    if [ -n "$systemd_service" ]; then
        run_verbose $systemctl status "$systemd_service" || true
    fi

    if [ "$failed" = 0 ] && [ "$xfailed" = 0 ] && [ "$skipped" = 0 ]; then
        pass "$name"
    fi
done

echo "---------------------------------------------------------------"
# Negative tests: services that have got it wrong do not activate

failed=0
xfailed=0
skipped=0

bus_name="org.apertis.ApertisTests.FailToActivate"
service="${bus_name}.service"
name="${bus}_FailToActivate"

# check that it would have succeeded if legacy activation worked
if ! [ -x "/usr/bin/dbus-test-tool" ]; then
    fail "$name" "dbus-test-tool not found"
elif ! [ -e "$service" ]; then
    fail "$name" "$(pwd)/$service not found"
elif run_verbose gdbus call --$bus -d "$bus_name" -o / -m org.freedesktop.DBus.Peer.Ping; then
    # TODO: treat this as a failure after we enforce that
    # traditional activation is not allowed (T282)
    xfail "$name" "$bus_name should not have been activatable"
else
    pass "$name"
fi

echo "---------------------------------------------------------------"
systemd-cgls --no-pager | sed -e 's/^/# /'

exit "$any_failed"

# vim:set sw=4 sts=4 et: