From 251ecbd529cfdd1c34e98e77a188a740cc59b6b0 Mon Sep 17 00:00:00 2001 From: "Manuel Amador (Rudd-O)" Date: Fri, 28 Oct 2016 05:47:59 +0000 Subject: [PATCH] Clean up specfile unit activation aspect. Up until today, Qubes OS would insist on either masking or disabling or activating units that should get their state properly changed but only on first package install (when the template is built). This commit adds the possibility of having two types of unit presets: * Initial presets: these are only changed state during first package installs. * Upgrade presets: these get their state changed during first package installs as well as during upgrades. All the maintainer has to do is abide by the instructions in the preset file. Nothing else is necessary. Namely, this allows users to enable SSHD on their templates or standalone VMs and still keep it enabled even after the qubes-core-vm-systemd package is upgraded. Matt really wanted that, and so did I, so now we can do it! :-) --- rpm_spec/core-vm.spec | 195 +++++++++++++++++++++++++--------- vm-systemd/75-qubes-vm.preset | 35 ++++-- 2 files changed, 171 insertions(+), 59 deletions(-) diff --git a/rpm_spec/core-vm.spec b/rpm_spec/core-vm.spec index 6fcb2ce..ea3eadc 100644 --- a/rpm_spec/core-vm.spec +++ b/rpm_spec/core-vm.spec @@ -21,10 +21,88 @@ # %define qubes_services qubes-core qubes-core-netvm qubes-core-early qubes-firewall qubes-netwatcher qubes-iptables qubes-updates-proxy qubes-qrexec-agent qubes-dvm +%define qubes_preset_file 75-qubes-vm.preset %{!?version: %define version %(cat version)} %{!?backend_vmm: %define backend_vmm %(echo $BACKEND_VMM)} +%define scriptletfuns is_static() { \ + [ -f "%{_unitdir}/$1" ] && ! grep -q '^[[].nstall]' "%{_unitdir}/$1" \ +} \ + \ +is_masked() { \ + if [ ! -L %{_sysconfdir}/systemd/system/"$1" ] \ + then \ + return 1 \ + fi \ + target=`readlink %{_sysconfdir}/systemd/system/"$1" 2>/dev/null` || : \ + if [ "$target" = "/dev/null" ] \ + then \ + return 0 \ + fi \ + return 1 \ +} \ +\ +mask() { \ + ln -sf /dev/null %{_sysconfdir}/systemd/system/"$1" \ +} \ +\ +unmask() { \ + if ! is_masked "$1" \ + then \ + return 0 \ + fi \ + rm -f %{_sysconfdir}/systemd/system/"$1" \ +} \ +\ +preset_units() { \ + local represet= \ + cat "$1" | while read action unit_name \ + do \ + if [ "$action" = "#" -a "$unit_name" = "Units below this line will be re-preset on package upgrade" ] \ + then \ + represet=1 \ + continue \ + fi \ + echo "$action $unit_name" | grep -q '^[[:space:]]*[^#;]' || continue \ + [ -n "$action" -a -n "$unit_name" ] || continue \ + if [ "$2" = "initial" -o "$represet" = "1" ] \ + then \ + if [ "$action" = "disable" ] && is_static "$unit_name" \ + then \ + if ! is_masked "$unit_name" \ + then \ + # We must effectively mask these units, even if they are static. \ + mask "$unit_name" \ + fi \ + elif [ "$action" = "enable" ] && is_static "$unit_name" \ + then \ + if is_masked "$unit_name" \ + then \ + # We masked this static unit before, now we unmask it. \ + unmask "$unit_name" \ + fi \ + systemctl --no-reload preset "$unit_name" >/dev/null 2>&1 || : \ + else \ + systemctl --no-reload preset "$unit_name" >/dev/null 2>&1 || : \ + fi \ + fi \ + done \ +} \ +\ +restore_units() { \ + grep '^[[:space:]]*[^#;]' "$1" | while read action unit_name \ + do \ + if is_static "$unit_name" && is_masked "$unit_name" \ + then \ + # If the unit had been masked by us, we must unmask it here. \ + # Otherwise systemctl preset will fail badly. \ + unmask "$unit_name" \ + fi \ + systemctl --no-reload preset "$unit_name" >/dev/null 2>&1 || : \ + done \ +} \ + Name: qubes-core-vm Version: %{version} Release: 1%{dist} @@ -554,7 +632,7 @@ The Qubes core startup configuration for SystemD init. /lib/systemd/system/qubes-update-check.timer /lib/systemd/system/qubes-updates-proxy.service /lib/systemd/system/qubes-qrexec-agent.service -/lib/systemd/system-preset/75-qubes-vm.preset +/lib/systemd/system-preset/%qubes_preset_file /lib/modules-load.d/qubes-core.conf /lib/modules-load.d/qubes-misc.conf /usr/lib/qubes/init/qubes-iptables @@ -582,68 +660,83 @@ The Qubes core startup configuration for SystemD init. %post systemd -PRESET_FAILED=0 -if [ $1 -eq 1 ]; then - /bin/systemctl --no-reload preset-all > /dev/null 2>&1 && PRESET_FAILED=0 || PRESET_FAILED=1 +changed= + +%scriptletfuns + +if [ $1 -eq 1 ] +then + preset_units %{_presetdir}/%qubes_preset_file initial + changed=true else - services="qubes-dvm qubes-misc-post qubes-firewall qubes-mount-dirs" - services="$services qubes-netwatcher qubes-network qubes-sysinit" - services="$services qubes-iptables qubes-updates-proxy qubes-qrexec-agent" - for srv in $services; do - /bin/systemctl --no-reload preset $srv.service - done - /bin/systemctl --no-reload preset qubes-update-check.timer + preset_units %{_presetdir}/%qubes_preset_file upgrade + changed=true # Upgrade path - now qubes-iptables is used instead - if [ -f /lib/systemd/system/iptables.service ]; then - /bin/systemctl --no-reload preset iptables.service - fi - if [ -f /lib/systemd/system/ip6tables.service ]; then - /bin/systemctl --no-reload preset ip6tables.service - fi + for svc in iptables ip6tables + do + if [ -f "$svc".service ] + then + systemctl --no-reload preset "$svc".service + changed=true + fi + done fi -# Set default "runlevel" -rm -f /etc/systemd/system/default.target -ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target - -grep '^[[:space:]]*[^#;]' /lib/systemd/system-preset/75-qubes-vm.preset | while read action unit_name; do - case "$action" in - (disable) - if [ -f /lib/systemd/system/$unit_name ]; then - if ! fgrep -q '[Install]' /lib/systemd/system/$unit_name; then - # forcibly disable - ln -sf /dev/null /etc/systemd/system/$unit_name - fi - fi - ;; - *) - # preset-all is not available in fc20; so preset each unit file listed in 75-qubes-vm.preset - if [ $1 -eq 1 -a "${PRESET_FAILED}" -eq 1 ]; then - systemctl --no-reload preset "${unit_name}" > /dev/null 2>&1 || true - fi - ;; - esac -done +if [ $1 -eq 1 ] +then + # First install. + # Set default "runlevel". + # FIXME: this ought to be done via kernel command line. + # The fewer deviations of the template from the seed + # image, the better. + rm -f %{_sysconfdir}/systemd/system/default.target + ln -s %{_unitdir}/multi-user.target %{_sysconfdir}/systemd/system/default.target + changed=true +fi # remove old symlinks -if [ -L /etc/systemd/system/sysinit.target.wants/qubes-random-seed.service ]; then - rm /etc/systemd/system/sysinit.target.wants/qubes-random-seed.service +if [ -L %{_sysconfdir}/systemd/system/sysinit.target.wants/qubes-random-seed.service ] +then + rm -f %{_sysconfdir}/systemd/system/sysinit.target.wants/qubes-random-seed.service + changed=true fi -if [ -L /etc/systemd/system/multi-user.target.wants/qubes-mount-home.service ]; then - rm /etc/systemd/system/multi-user.target.wants/qubes-mount-home.service +if [ -L %{_sysconfdir}/systemd/system/multi-user.target.wants/qubes-mount-home.service ] +then + rm -f %{_sysconfdir}/systemd/system/multi-user.target.wants/qubes-mount-home.service + changed=true fi -/bin/systemctl daemon-reload +if [ "x$changed" != "x" ] +then + systemctl daemon-reload +fi -exit 0 +%preun systemd + +if [ $1 -eq 0 ] ; then + # Run this only during uninstall. + # Save the preset file to later use it to re-preset services there + # once the Qubes OS preset file is removed. + mkdir -p %{_rundir}/qubes-uninstall + cp -f %{_presetdir}/%qubes_preset_file %{_rundir}/qubes-uninstall/ +fi %postun systemd -#Do not run this part on upgrades -if [ "$1" != 0 ] ; then - exit 0 +changed= + +%scriptletfuns + +if [ -d %{_rundir}/qubes-uninstall ] +then + # We have a saved preset file (or more). + # Re-preset the units mentioned there. + restore_units %{_rundir}/qubes-uninstall/%qubes_preset_file + rm -rf %{_rundir}/qubes-uninstall + changed=true fi -for srv in qubes-dvm qubes-sysinit qubes-misc-post qubes-mount-dirs qubes-netwatcher qubes-network qubes-qrexec-agent; do - /bin/systemctl disable $srv.service -do +if [ "x$changed" != "x" ] +then + systemctl daemon-reload +fi diff --git a/vm-systemd/75-qubes-vm.preset b/vm-systemd/75-qubes-vm.preset index 7562503..555c2ba 100644 --- a/vm-systemd/75-qubes-vm.preset +++ b/vm-systemd/75-qubes-vm.preset @@ -14,13 +14,38 @@ # Qubes currently does not provide a way to permanently prevent such units from # being masked. # +# Maintainer information: +# +# * All units listed here are preset during first install of the *-systemd RPM. +# For those units which are disabled here, but don't have an install section +# (static units), we mask them during that install. +# * All units listed here that find themselves below the comment titled +# "# Units below this line will be re-preset on package upgrade" +# are preset both during install and during upgrade. This allows you to add +# new units here and have them become active when the user's machine upgrades +# their *-systemd RPM built by this project. +# +# Hi, Matt! I see you did great with this conversion to systemd presets! +# Thank you! Skyler sends you her regards from Europe! +# - Rudd-O +# # https://groups.google.com/d/topic/qubes-users/dpM_GHfmEOk/discussion -disable alsa-store.service -disable alsa-restore.service disable avahi.service disable avahi-daemon.service disable avahi-daemon.socket + +# Fedora only services +disable rpcbind.service +disable sendmail.service +disable sm-client.service +disable sshd.service +disable backuppc.service + +# Units below this line will be re-preset on package upgrade + +disable alsa-store.service +disable alsa-restore.service disable hwclock-save.service disable mdmonitor.service disable plymouth-start.service @@ -33,7 +58,6 @@ disable colord.service disable systemd-timesyncd.service # Fedora only services -disable backuppc.service disable cpuspeed.service disable dnf-makecache.timer disable fedora-autorelabel.service @@ -50,10 +74,6 @@ disable mdmonitor-takeover.service disable multipathd.service disable openct.service disable rngd.service -disable rpcbind.service -disable sendmail.service -disable sm-client.service -disable sshd.service disable tcsd.service enable qubes-sysinit.service @@ -61,7 +81,6 @@ enable qubes-early-vm-config.service enable qubes-db.service enable qubes-gui-agent.service enable qubes-update-check.timer -enable qubes-update-check.timer enable qubes-misc-post.service enable qubes-updates-proxy.service enable qubes-dvm.service