systemd/postmarketos-base-systemd: fix preset template instance handling

This fixes a bug where template presets with a specified instance were
not being handled. The install script previously parsed the entire line,
including the instance(s) and ran 'systemctl preset' on it all, e.g.
'systemctl preset unudhcpd@.service usb0'.

The script will now:

- detect lines that contain a template + instance(s)
- diff the instances
- run preset on template@instance for all added or removed instances

Template presets that don't have any instances specified in the preset
file (because they have a DefaultInstance= set) are treated just like
any other unit since we can run preset on those and it enables the
template with the default instance.

Signed-off-by: Clayton Craft <craftyguy@postmarketos.org>
Part-of: <https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/9026>
This commit is contained in:
Clayton Craft 2026-07-27 10:42:24 -07:00 committed by The Friendly Meow (merge) Bot
parent 6d00e47c78
commit 1b20c249cf
No known key found for this signature in database
2 changed files with 64 additions and 11 deletions

View file

@ -1,7 +1,7 @@
# pmbootstrap installs this, if systemd is selected in "pmbootstrap init".
maintainer="Clayton Craft <clayton@craftyguy.net>"
pkgname=postmarketos-base-systemd
pkgver=85
pkgver=86
pkgrel=0
pkgdesc="Meta package for running postmarketOS with systemd"
url="https://postmarketos.org"

View file

@ -100,18 +100,71 @@ check_and_apply_presets() {
local old_ifs=$IFS
IFS=$'\n'
for entry in $entries; do
if policy_changed "$preset_path" "$entry"; then
if ! policy_changed "$preset_path" "$entry"; then
continue
fi
echo "unit policy has changed for $entry"
if echo "$entry" | grep -q '*'; then
if echo "$entry" | grep -qF '*'; then
echo " wildcards are not supported yet, skipping"
else
continue
fi
# Handle template units with instance arguments, e.g. "unudhcpd@.service usb0"
# See systemd.preset(5) "Enable multiple template instances"
case "$entry" in
*@.*)
# Only act if there are instances listed after the template name
instances="${entry#* }"
if [ "$instances" = "$entry" ]; then
# handle templates listed without instances in the preset just like any other
# unit, this assumes they have a DefaultInstance= set
break
fi
template="${entry%% *}"
if [ ! -f "/usr/lib/systemd/$type/$template" ]; then
echo " no unit file found, skipping"
continue
fi
# e.g. "unudhcpd@" and "service"
base="${template%.*}"
suffix="${template##*.}"
# extract instance lists from new and old preset files for diffing
new_instances=""
if [ -f "$preset_path" ]; then
new_instances="$(grep " $template " "$preset_path" | sed "s/.* $template //")"
fi
old_instances=""
if [ -f "$preset_path.old" ]; then
old_instances="$(grep " $template " "$preset_path.old" | sed "s/.* $template //")"
fi
# only preset instances that were added or removed should be preset
# note: IFS is changed to split on words, so we can pick up multiple instances
# that might be listed after the template
local saved_ifs="$IFS"
IFS=' '
for inst in $new_instances $old_instances; do
if echo " $new_instances " | grep -qF " $inst " && \
echo " $old_instances " | grep -qF " $inst "; then
continue
fi
systemctl --no-reload preset $extra_args "${base}${inst}.${suffix}"
done
IFS="$saved_ifs"
# done processing this line
continue
;;
esac
if [ -f "/usr/lib/systemd/$type/$entry" ]; then
systemctl --no-reload preset $extra_args "$entry"
else
echo " no unit file found, skipping"
fi
fi
fi
done
IFS="$old_ifs"
}