diff --git a/init/functions b/init/functions index 76413e4..5cf08db 100644 --- a/init/functions +++ b/init/functions @@ -29,9 +29,9 @@ systemd_version_changed() { under_systemd || return systemd_pkg_version=`systemctl --version|head -n 1` if dmesg | grep -q "$systemd_pkg_version running in system mode."; then - return 0 + return 1 fi - return 1 + return 0 } possibly_run_save_script() { diff --git a/rpm_spec/core-vm.spec b/rpm_spec/core-vm.spec index 79bcfe6..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} @@ -549,11 +627,12 @@ The Qubes core startup configuration for SystemD init. /lib/systemd/system/qubes-network.service /lib/systemd/system/qubes-iptables.service /lib/systemd/system/qubes-sysinit.service +/lib/systemd/system/qubes-early-vm-config.service /lib/systemd/system/qubes-update-check.service /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 @@ -581,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 54dbcfa..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,17 +74,13 @@ 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 +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 diff --git a/vm-systemd/qubes-early-vm-config.service b/vm-systemd/qubes-early-vm-config.service new file mode 100644 index 0000000..fa9dbd3 --- /dev/null +++ b/vm-systemd/qubes-early-vm-config.service @@ -0,0 +1,13 @@ +[Unit] +Description=Early Qubes VM settings +DefaultDependencies=no +Before=sysinit.target +After=local-fs.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/qubes/init/qubes-early-vm-config.sh + +[Install] +WantedBy=sysinit.target diff --git a/vm-systemd/qubes-early-vm-config.sh b/vm-systemd/qubes-early-vm-config.sh new file mode 100755 index 0000000..999bb90 --- /dev/null +++ b/vm-systemd/qubes-early-vm-config.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# This is invoked by qubes-early-vm-config.service. +# It happens after local-fs.target is reached +# but before sysinit.target is reached. + +# Source Qubes library. +. /usr/lib/qubes/init/functions + +# Set the hostname +if ! is_protected_file /etc/hostname ; then + name=`qubesdb-read /name` + if [ -n "$name" ]; then + hostname $name + if [ -e /etc/debian_version ]; then + ipv4_localhost_re="127\.0\.1\.1" + else + ipv4_localhost_re="127\.0\.0\.1" + fi + sed -i "s/^\($ipv4_localhost_re\(\s.*\)*\s\).*$/\1${name}/" /etc/hosts + sed -i "s/^\(::1\(\s.*\)*\s\).*$/\1${name}/" /etc/hosts + fi +fi + +# Set the timezone +if ! is_protected_file /etc/timezone ; then + timezone=`qubesdb-read /qubes-timezone 2> /dev/null` + if [ -n "$timezone" ]; then + ln -sf ../usr/share/zoneinfo/"$timezone" /etc/localtime + if [ -e /etc/debian_version ]; then + echo "$timezone" > /etc/timezone + elif test -d /etc/sysconfig ; then + echo "# Clock configuration autogenerated based on Qubes dom0 settings" > /etc/sysconfig/clock + echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock + fi + fi +fi diff --git a/vm-systemd/qubes-sysinit.sh b/vm-systemd/qubes-sysinit.sh index 9db4661..c1ee760 100755 --- a/vm-systemd/qubes-sysinit.sh +++ b/vm-systemd/qubes-sysinit.sh @@ -60,35 +60,6 @@ for srv in `qubesdb-multiread /qubes-service/ 2>/dev/null |grep ' = 0'|cut -f 1 rm -f /var/run/qubes-service/$srv done -# Set the hostname -if ! is_protected_file /etc/hostname ; then - name=`qubesdb-read /name` - if [ -n "$name" ]; then - hostname $name - if [ -e /etc/debian_version ]; then - ipv4_localhost_re="127\.0\.1\.1" - else - ipv4_localhost_re="127\.0\.0\.1" - fi - sed -i "s/^\($ipv4_localhost_re\(\s.*\)*\s\).*$/\1${name}/" /etc/hosts - sed -i "s/^\(::1\(\s.*\)*\s\).*$/\1${name}/" /etc/hosts - fi -fi - -# Set the timezone -if ! is_protected_file /etc/timezone ; then - timezone=`qubesdb-read /qubes-timezone 2> /dev/null` - if [ -n "$timezone" ]; then - ln -sf ../usr/share/zoneinfo/"$timezone" /etc/localtime - if [ -e /etc/debian_version ]; then - echo "$timezone" > /etc/timezone - elif test -d /etc/sysconfig ; then - echo "# Clock configuration autogenerated based on Qubes dom0 settings" > /etc/sysconfig/clock - echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock - fi - fi -fi - # Prepare environment for other services echo > /var/run/qubes-service-environment