diff --git a/files.systemd b/files.systemd index a53901b8..c49c7460 100644 --- a/files.systemd +++ b/files.systemd @@ -465,6 +465,7 @@ %{_systemd_util_dir}/systemd-timedated %{_systemd_util_dir}/systemd-timesyncd %{_systemd_util_dir}/systemd-update-done +%{_systemd_util_dir}/systemd-update-helper %{_systemd_util_dir}/systemd-update-utmp %{_systemd_util_dir}/systemd-user-runtime-dir %{_systemd_util_dir}/systemd-user-sessions diff --git a/systemd-update-helper b/systemd-update-helper new file mode 100644 index 00000000..3cc7909b --- /dev/null +++ b/systemd-update-helper @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This helper is aimed at being used by the systemd rpm macros only. +# +set -eu +set -o pipefail + +command="${1:?}" +shift + +command -v systemctl >/dev/null || exit 0 + +case "$command" in + mark-install-system-units) + mkdir -p /run/systemd/rpm/needs-preset + + for unit in "$@" ; do + if [ ! -e /usr/lib/systemd/system/"$unit" ]; then + touch /run/systemd/rpm/needs-preset/"$unit" + fi + done + ;; + + install-system-units) + units=() + + for unit in "$@" ; do + if [ -e /run/systemd/rpm/needs-preset/"$unit" ]; then + rm /run/systemd/rpm/needs-preset/"$unit" + units+=("$unit") + fi + done + + [ ${#units[*]} -gt 0 ] && + systemctl --no-reload preset "${units[@]}" + ;; + + mark-install-user-units) + mkdir -p /run/systemd/rpm/needs-user-preset + + for unit in "$@" ; do + if [ ! -e /usr/lib/systemd/user/"$unit" ]; then + touch /run/systemd/rpm/needs-user-preset/"$unit" + fi + done + ;; + + install-user-units) + units=() + + for unit in "$@" ; do + if [ -e /run/systemd/rpm/needs-user-preset/"$unit" ]; then + rm /run/systemd/rpm/needs-user-preset/"$unit" + units+=("$unit") + fi + done + + [ ${#units[*]} -gt 0 ] && + systemctl --no-reload preset --global "$@" || : + ;; + + remove-system-units) + if [ -d /run/systemd/system ]; then + systemctl --no-reload disable --now --no-warn "$@" + else + systemctl --no-reload disable --no-warn "$@" + fi + ;; + + remove-user-units) + systemctl --global disable --no-warn "$@" + + [ -d /run/systemd/system ] || exit 0 + + users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p') + for user in $users; do + SYSTEMD_BUS_TIMEOUT=15s \ + systemctl --user -M "$user@" disable --now --no-warn "$@" & + done + wait + ;; + + mark-restart-system-units) + [ -d /run/systemd/system ] || exit 0 + + for unit in "$@"; do + systemctl set-property "$unit" Markers=+needs-restart & + done + wait + ;; + + mark-restart-user-units) + [ -d /run/systemd/system ] || exit 0 + + users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p') + for user in $users; do + for unit in "$@"; do + SYSTEMD_BUS_TIMEOUT=15s \ + systemctl --user -M "$user@" set-property "$unit" Markers=+needs-restart & + done + done + wait + ;; + + system-reload-restart|system-reload|system-restart) + if [ -n "$*" ]; then + echo >&2 "Unexpected arguments for '$command': $*" + exit 2 + fi + + [ -d /run/systemd/system ] || exit 0 + + if [[ "$command" =~ reload ]]; then + systemctl daemon-reload + fi + + if [[ "$command" =~ restart ]]; then + systemctl reload-or-restart --marked + fi + ;; + + user-reload-restart|user-reload|user-restart|user-reexec) + if [ -n "$*" ]; then + echo >&2 "Unexpected arguments for '$command': $*" + exit 2 + fi + + [ -d /run/systemd/system ] || exit 0 + + users=$(systemctl list-units 'user@*' --legend=no | sed -n -r 's/.*user@([0-9]+).service.*/\1/p') + + if [[ "$command" =~ reexec ]]; then + for user in $users; do + SYSTEMD_BUS_TIMEOUT=15s \ + systemctl --user -M "$user@" daemon-reexec & + done + wait + fi + + if [[ "$command" =~ reload ]]; then + for user in $users; do + SYSTEMD_BUS_TIMEOUT=15s \ + systemctl --user -M "$user@" daemon-reload & + done + wait + fi + + if [[ "$command" =~ restart ]]; then + for user in $users; do + SYSTEMD_BUS_TIMEOUT=15s \ + systemctl --user -M "$user@" reload-or-restart --marked & + done + wait + fi + ;; + + *) + echo >&2 "Unknown verb '$command'" + exit 3 + ;; +esac diff --git a/systemd.changes b/systemd.changes index 9b62d34d..3d4edde1 100644 --- a/systemd.changes +++ b/systemd.changes @@ -1,3 +1,34 @@ +------------------------------------------------------------------- +Tue May 9 13:59:56 UTC 2023 - Franck Bui + +- Provide (Lua-based) file triggers and adapt systemd.spec accordingly (boo#1133764) + + More specifically, file triggers handle automatically installations or updates + of files for sysusers, tmpfiles, hwdb, journal catalog, udev rules, sysctl and + binfmt. + + Therefore it makes a bunch of systemd rpm macros (such as %udev_hwdb_update, + %udev_rules_update, %journal_catalog_update, %tmpfiles_create, + %sysusers_create and so on) not needed anymore. However before considering + simplifying your spec files beware that these changes are not available in SLE + yet and will probably never reach the current releases (latest one being + SLE15-SP5 as of this writing). + + Macros dealing with unit restart/enabling (such as %systemd_pre, + %service_add_pre, %service_del_postun, ...) are still needed though. However + reloading of systemd instances (and thus restarting of units) are delayed + until the very end of the package install/update transaction and is now done + only once. + + Nevertheless to fully take advantage of file triggers, users have to activate + a specific zypper transaction backend which is still considered as + experimental, see bsc#1041742 for details. + +- Provide a (slighlty) customized version of systemd-update-helper. Some of the + systemd rpm macros rely now on the helper and delegate their work to it. Hence + we don't need to rebuild all packages anymore when the content of the rpm + macros must be updated/fixed. + ------------------------------------------------------------------- Tue May 9 12:37:31 UTC 2023 - Franck Bui diff --git a/systemd.spec b/systemd.spec index 7d8f15a9..d8a69e1e 100644 --- a/systemd.spec +++ b/systemd.spec @@ -68,7 +68,7 @@ %bcond_without testsuite %endif # Kept to ease migrations toward SLE -%bcond_with filetriggers +%bcond_without filetriggers %bcond_with split_usr Name: systemd%{?mini} @@ -168,11 +168,13 @@ Obsoletes: systemd-analyze < 201 Source0: systemd-v%{version}%{archive_version}.tar.xz Source1: systemd-rpmlintrc Source2: systemd-user +Source3: systemd-update-helper %if %{with sysvcompat} Source4: systemd-sysv-install %endif Source5: tmpfiles-suse.conf Source6: baselibs.conf +Source7: triggers.systemd Source11: after-local.service Source14: kbd-model-map.legacy @@ -758,6 +760,7 @@ rm %{buildroot}%{_sbindir}/resolvconf rm %{buildroot}%{_mandir}/man1/resolvconf.1* %endif +install -m0755 -D %{SOURCE3} %{buildroot}/%{_systemd_util_dir}/systemd-update-helper %if %{with sysvcompat} install -m0755 -D %{SOURCE4} %{buildroot}/%{_systemd_util_dir}/systemd-sysv-install %endif @@ -1062,7 +1065,6 @@ fi %{_systemd_util_dir}/rpm/fixlet-systemd-post.sh $1 || : %postun -# daemon-reload is implied by systemd_postun_with_restart %systemd_postun_with_restart systemd-journald.service %systemd_postun_with_restart systemd-timesyncd.service # Avoid restarting logind until fixed upstream (issue #1163) @@ -1083,8 +1085,10 @@ fi %post -n udev%{?mini} %regenerate_initrd_post +%if %{without filetriggers} %udev_hwdb_update %tmpfiles_create systemd-pstore.conf +%endif %systemd_post remote-cryptsetup.target %systemd_post systemd-pstore.service @@ -1134,7 +1138,9 @@ fi %endif %post container +%if %{without filetriggers} %tmpfiles_create systemd-nspawn.conf +%endif %if %{with machined} %systemd_post machines.target %ldconfig @@ -1182,8 +1188,10 @@ fi %post network %if %{with networkd} +%if %{without filetriggers} %sysusers_create systemd-network.conf %tmpfiles_create systemd-network.conf +%endif %systemd_post systemd-networkd.service %systemd_post systemd-networkd-wait-online.service %endif @@ -1218,7 +1226,9 @@ fi %systemd_pre systemd-portabled.service %post portable +%if %{without filetriggers} %tmpfiles_create portables.conf +%endif %systemd_post systemd-portabled.service %preun portable @@ -1251,6 +1261,11 @@ fi %systemd_postun systemd-userdbd.service systemd-userdbd.socket %endif +# File trigger definitions +%if %{without filetriggers} +%include %{SOURCE7} +%endif + %files %defattr(-,root,root) %include %{SOURCE200} diff --git a/triggers.systemd b/triggers.systemd new file mode 100644 index 00000000..0aeea905 --- /dev/null +++ b/triggers.systemd @@ -0,0 +1,126 @@ +# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# Copyright © 2018 Neal Gompa + +# The contents of this are an example to be copied into systemd.spec. +# +# Minimum rpm version supported: 4.14.0 + +%transfiletriggerin -P 900900 -p -- /usr/lib/systemd/system /etc/systemd/system +-- This script will run after any package is initially installed or +-- upgraded. We care about the case where a package is initially +-- installed, because other cases are covered by the *un scriptlets, +-- so sometimes we will reload needlessly. +pid = posix.fork() +if pid == 0 then + assert(posix.exec("/usr/lib/systemd/systemd-update-helper", "system-reload-restart")) +elseif pid > 0 then + posix.wait(pid) +end + +%transfiletriggerin -P 900899 -p -- /usr/lib/systemd/user /etc/systemd/user +pid = posix.fork() +if pid == 0 then + assert(posix.exec("/usr/lib/systemd/systemd-update-helper", "user-reload-restart")) +elseif pid > 0 then + posix.wait(pid) +end + +%transfiletriggerpostun -P 1000100 -p -- /usr/lib/systemd/system /etc/systemd/system +-- On removal, we need to run daemon-reload after any units have been +-- removed. +-- On upgrade, we need to run daemon-reload after any new unit files +-- have been installed, but before %postun scripts in packages get +-- executed. +pid = posix.fork() +if pid == 0 then + assert(posix.exec("/usr/lib/systemd/systemd-update-helper", "system-reload")) +elseif pid > 0 then + posix.wait(pid) +end + +%transfiletriggerpostun -P 1000100 -p -- /usr/lib/systemd/system /etc/systemd/system +-- Execute daemon-reload in user managers. +pid = posix.fork() +if pid == 0 then + assert(posix.exec("/usr/lib/systemd/systemd-update-helper", "user-reload")) +elseif pid > 0 then + posix.wait(pid) +end + +%transfiletriggerpostun -P 10000 -p -- /usr/lib/systemd/system /etc/systemd/system +-- We restart remaining system services that should be restarted here. +pid = posix.fork() +if pid == 0 then + assert(posix.exec("/usr/lib/systemd/systemd-update-helper", "system-restart")) +elseif pid > 0 then + posix.wait(pid) +end + +%transfiletriggerpostun -P 9999 -p -- /usr/lib/systemd/user /etc/systemd/user +-- We restart remaining user services that should be restarted here. +pid = posix.fork() +if pid == 0 then + assert(posix.exec("/usr/lib/systemd/systemd-update-helper", "user-restart")) +elseif pid > 0 then + posix.wait(pid) +end + +%transfiletriggerin -P 100700 -p -- /usr/lib/sysusers.d +-- This script will process files installed in /usr/lib/sysusers.d to create +-- specified users automatically. The priority is set such that it +-- will run before the tmpfiles file trigger. +assert(rpm.execute("systemd-sysusers")) + +%if %{without bootstrap} +%transfiletriggerin -P 1000700 -n udev -p -- /usr/lib/udev/hwdb.d +-- This script will automatically invoke hwdb update if files have been +-- installed or updated in /usr/lib/udev/hwdb.d. +assert(rpm.execute("systemd-hwdb", "update")) +%endif + +%transfiletriggerin -P 1000700 -p -- /usr/lib/systemd/catalog +-- This script will automatically invoke journal catalog update if files +-- have been installed or updated in /usr/lib/systemd/catalog. +assert(rpm.execute("journalctl", "--update-catalog")) + +%transfiletriggerin -P 1000700 -p -- /usr/lib/binfmt.d +-- This script will automatically apply binfmt rules if files have been +-- installed or updated in /usr/lib/binfmt.d. +if posix.access("/run/systemd/system") then + pid = posix.fork() + if pid == 0 then + assert(posix.exec("/usr/lib/systemd/systemd-binfmt")) + elseif pid > 0 then + posix.wait(pid) + end +end + +%transfiletriggerin -P 1000600 -p -- /usr/lib/tmpfiles.d +-- This script will process files installed in /usr/lib/tmpfiles.d to create +-- tmpfiles automatically. The priority is set such that it will run +-- after the sysusers file trigger, but before any other triggers. +assert(rpm.execute("systemd-tmpfiles", "--create")) + +%if %{without bootstrap} +%transfiletriggerin -P 1000600 -n udev -p -- /usr/lib/udev/rules.d +-- This script will automatically update udev with new rules if files +-- have been installed or updated in /usr/lib/udev/rules.d. +if posix.access("/run/udev/control") then + assert(rpm.execute("udevadm", "control", "--reload")) +end +%endif + +%transfiletriggerin -P 1000500 -p -- /usr/lib/sysctl.d +-- This script will automatically apply sysctl rules if files have been +-- installed or updated in /usr/lib/sysctl.d. +if posix.access("/run/systemd/system") then + pid = posix.fork() + if pid == 0 then + assert(posix.exec("/usr/lib/systemd/systemd-sysctl")) + elseif pid > 0 then + posix.wait(pid) + end +end