Browse Source

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!

:-)
Manuel Amador (Rudd-O) 7 years ago
parent
commit
251ecbd529
2 changed files with 171 additions and 59 deletions
  1. 144 51
      rpm_spec/core-vm.spec
  2. 27 8
      vm-systemd/75-qubes-vm.preset

+ 144 - 51
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

+ 27 - 8
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