From cf591a4cd52a4c47ac215c885bfa77baf5b430e5 Mon Sep 17 00:00:00 2001 From: Marek Marczykowski Date: Tue, 10 Jan 2012 12:10:16 +0100 Subject: [PATCH] vm/init: introduce SystemD startup scripts --- rpm_spec/core-vm.spec | 105 ++++++++++++++++++++++++ vm-systemd/NetworkManager.service | 3 + vm-systemd/cups.service | 3 + vm-systemd/misc-post.sh | 60 ++++++++++++++ vm-systemd/network-proxy-setup.sh | 14 ++++ vm-systemd/ntpd.service | 3 + vm-systemd/prepare-dvm.sh | 30 +++++++ vm-systemd/qubes-dvm.service | 12 +++ vm-systemd/qubes-firewall.service | 10 +++ vm-systemd/qubes-meminfo-writer.service | 12 +++ vm-systemd/qubes-misc-post.service | 11 +++ vm-systemd/qubes-netwatcher.service | 11 +++ vm-systemd/qubes-network.service | 14 ++++ vm-systemd/qubes-qrexec-agent.service | 10 +++ vm-systemd/qubes-sysinit.service | 11 +++ vm-systemd/qubes-sysinit.sh | 50 +++++++++++ 16 files changed, 359 insertions(+) create mode 100644 vm-systemd/NetworkManager.service create mode 100644 vm-systemd/cups.service create mode 100755 vm-systemd/misc-post.sh create mode 100755 vm-systemd/network-proxy-setup.sh create mode 100644 vm-systemd/ntpd.service create mode 100755 vm-systemd/prepare-dvm.sh create mode 100644 vm-systemd/qubes-dvm.service create mode 100644 vm-systemd/qubes-firewall.service create mode 100644 vm-systemd/qubes-meminfo-writer.service create mode 100644 vm-systemd/qubes-misc-post.service create mode 100644 vm-systemd/qubes-netwatcher.service create mode 100644 vm-systemd/qubes-network.service create mode 100644 vm-systemd/qubes-qrexec-agent.service create mode 100644 vm-systemd/qubes-sysinit.service create mode 100755 vm-systemd/qubes-sysinit.sh diff --git a/rpm_spec/core-vm.spec b/rpm_spec/core-vm.spec index 49f715c0..15926cb8 100644 --- a/rpm_spec/core-vm.spec +++ b/rpm_spec/core-vm.spec @@ -84,6 +84,13 @@ install -D misc/fstab $RPM_BUILD_ROOT/etc/fstab install -d $RPM_BUILD_ROOT/etc/init.d install vm-init.d/* $RPM_BUILD_ROOT/etc/init.d/ +install -d $RPM_BUILD_ROOT/lib/systemd/system $RPM_BUILD_ROOT/usr/lib/qubes/init +install -m 0755 vm-systemd/*.sh $RPM_BUILD_ROOT/usr/lib/qubes/init/ +install -m 0644 vm-systemd/qubes-*.service $RPM_BUILD_ROOT/lib/systemd/system/ +install -m 0644 vm-systemd/NetworkManager.service $RPM_BUILD_ROOT/usr/lib/qubes/init/ +install -m 0644 vm-systemd/cups.service $RPM_BUILD_ROOT/usr/lib/qubes/init/ +install -m 0644 vm-systemd/ntpd.service $RPM_BUILD_ROOT/usr/lib/qubes/init/ + install -D -m 0440 misc/qubes.sudoers $RPM_BUILD_ROOT/etc/sudoers.d/qubes install -D misc/qubes.repo $RPM_BUILD_ROOT/etc/yum.repos.d/qubes.repo install -D misc/serial.conf $RPM_BUILD_ROOT/usr/lib/qubes/serial.conf @@ -382,6 +389,7 @@ Group: Qubes Requires: upstart Requires: qubes-core-vm Provides: qubes-core-vm-init-scripts +Conflicts: qubes-core-vm-systemd %description sysvinit The Qubes core startup configuration for SysV init (or upstart). @@ -437,3 +445,100 @@ if [ "$1" = 0 ] ; then chkconfig qubes_firewall off chkconfig qubes_netwatcher off fi + +%package systemd +Summary: Qubes unit files for SystemD init style +License: GPL v2 only +Group: Qubes +Requires: systemd +Requires: qubes-core-vm +Provides: qubes-core-vm-init-scripts +Conflicts: qubes-core-vm-sysvinit + +%description systemd +The Qubes core startup configuration for SystemD init. + +%files systemd +%defattr(-,root,root,-) +/lib/systemd/system/qubes-dvm.service +/lib/systemd/system/qubes-meminfo-writer.service +/lib/systemd/system/qubes-qrexec-agent.service +/lib/systemd/system/qubes-misc-post.service +/lib/systemd/system/qubes-firewall.service +/lib/systemd/system/qubes-netwatcher.service +/lib/systemd/system/qubes-network.service +/lib/systemd/system/qubes-sysinit.service +%dir /usr/lib/qubes/init +/usr/lib/qubes/init/prepare-dvm.sh +/usr/lib/qubes/init/network-proxy-setup.sh +/usr/lib/qubes/init/misc-post.sh +/usr/lib/qubes/init/qubes-sysinit.sh +/usr/lib/qubes/init/NetworkManager.service +/usr/lib/qubes/init/cups.service +/usr/lib/qubes/init/ntpd.service +%ghost %attr(0644,root,root) /etc/systemd/system/NetworkManager.service +%ghost %attr(0644,root,root) /etc/systemd/system/cups.service + +%post systemd + +for srv in qubes-dvm qubes-meminfo-writer qubes-qrexec-agent qubes-sysinit qubes-misc-post qubes-netwatcher qubes-network; do + /bin/systemctl enable $srv.service +done + +# Install overriden services only when original exists +for srv in cups NetworkManager ntpd; do + if [ -f /lib/systemd/system/$srv.service ]; then + cp /usr/lib/qubes/init/$srv.service /etc/systemd/system/$srv.service + fi +done + +# Set default "runlevel" +rm -f /etc/systemd/system/default.target +ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target + +# Services to disable +#echo "--> Turning off unnecessary services..." +# FIXME: perhaps there is more elegant way to do this? +for f in /etc/init.d/* +do + srv=`basename $f` + [ $srv = 'functions' ] && continue + [ $srv = 'killall' ] && continue + [ $srv = 'halt' ] && continue + [ $srv = 'single' ] && continue + [ $srv = 'reboot' ] && continue + [ $srv = 'qubes_gui' ] && continue + chkconfig $srv off +done + +DISABLE_SERVICES="alsa-store alsa-restore auditd backuppc cpuspeed crond dbus-org.freedesktop.Avahi" +DISABLE_SERVICES="$DISABLE_SERVICES fedora-autorelabel fedora-autorelabel-mark ipmi hwclock-load hwclock-save" +DISABLE_SERVICES="$DISABLE_SERVICES mdmonitor multipathd openct rpcbind mcelog fedora-storage-init fedora-storage-init-late" +DISABLE_SERVICES="$DISABLE_SERVICES plymouth-start plymouth-read-write plymouth-quit plymouth-quit-wait" +for srv in $DISABLE_SERVICES; do + if [ -f /lib/systemd/system/$srv.service ]; then + if fgrep -q '[Install]' /lib/systemd/system/$srv.service; then + /bin/systemctl disable $srv.service + else + # forcibly disable + ln -sf /dev/null /etc/systemd/system/$srv.service + fi + fi +done + +rm -f /etc/systemd/system/getty.target.wants/getty@tty*.service + +# Enable some services +/bin/systemctl enable iptables.service +/bin/systemctl enable rsyslog.service + +%postun systemd + +#Do not run this part on upgrades +if [ "$1" != 0 ] ; then + exit 0 +fi + +for srv in qubes-dvm qubes-meminfo-writer qubes-qrexec-agent qubes-sysinit qubes-misc-post qubes-netwatcher qubes-network; do + /bin/systemctl disable $srv.service +do diff --git a/vm-systemd/NetworkManager.service b/vm-systemd/NetworkManager.service new file mode 100644 index 00000000..bf1e4864 --- /dev/null +++ b/vm-systemd/NetworkManager.service @@ -0,0 +1,3 @@ +.include /lib/systemd/system/NetworkManager.service +[Unit] +ConditionPathExists=/var/run/qubes-service/network-manager diff --git a/vm-systemd/cups.service b/vm-systemd/cups.service new file mode 100644 index 00000000..73e2796e --- /dev/null +++ b/vm-systemd/cups.service @@ -0,0 +1,3 @@ +.include /lib/systemd/system/cups.service +[Unit] +ConditionPathExists=/var/run/qubes-service/cups diff --git a/vm-systemd/misc-post.sh b/vm-systemd/misc-post.sh new file mode 100755 index 00000000..9ebdf2e0 --- /dev/null +++ b/vm-systemd/misc-post.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# Set IP address again (besides action in udev rules); this is needed by +# DispVM (to override DispVM-template IP) and in case when qubes_ip was +# called by udev before loading evtchn kernel module - in which case +# xenstore-read fails +INTERFACE=eth0 /usr/lib/qubes/setup_ip + +if [ -e /dev/xvdb ] ; then + mount /rw + + if ! [ -d /rw/home ] ; then + echo + echo "--> Virgin boot of the VM: Linking /home to /rw/home" + + mkdir -p /rw/config + touch /rw/config/rc.local + + mkdir -p /rw/home + cp -a /home.orig/user /home + + mkdir -p /rw/usrlocal + cp -a /usr/local.orig/* /usr/local + + touch /var/lib/qubes/first_boot_completed + fi +fi + +[ -x /rw/config/rc.local ] && /rw/config/rc.local + +if ! [ -f /home/user/.gnome2/nautilus-scripts/.scripts_created ] ; then + echo "Creating symlinks for nautilus actions..." + su user -c 'mkdir -p /home/user/.gnome2/nautilus-scripts' + su user -c 'ln -s /usr/lib/qubes/qvm-copy-to-vm.gnome /home/user/.gnome2/nautilus-scripts/"Copy to other AppVM"' + su user -c 'ln -s /usr/bin/qvm-open-in-dvm /home/user/.gnome2/nautilus-scripts/"Open in DisposableVM"' + su user -c 'touch /home/user/.gnome2/nautilus-scripts/.scripts_created' +fi + +if ! [ -f /home/user/.gnome2/nautilus-scripts/.scripts_created2 ] ; then + # as we have recently renamed tools, the symlinks would need to be fixed for older templates + su user -c 'ln -sf /usr/lib/qubes/qvm-copy-to-vm.gnome /home/user/.gnome2/nautilus-scripts/"Copy to other AppVM"' + su user -c 'ln -sf /usr/bin/qvm-open-in-dvm /home/user/.gnome2/nautilus-scripts/"Open in DisposableVM"' + su user -c 'touch /home/user/.gnome2/nautilus-scripts/.scripts_created2' +fi + +# Start services which haven't own proper systemd unit: + +# Start AppVM specific services +if [ ! -f /etc/systemd/system/cups.service ]; then + if [ -f /var/run/qubes-service/cups ]; then + /sbin/service cups start + # Allow also notification icon + sed -i -e '/^NotShowIn=.*QUBES/s/;QUBES//' /etc/xdg/autostart/print-applet.desktop + else + # Disable notification icon + sed -i -e '/QUBES/!s/^NotShowIn=.*/\1QUBES;/' /etc/xdg/autostart/print-applet.desktop + fi +fi + +exit 0 diff --git a/vm-systemd/network-proxy-setup.sh b/vm-systemd/network-proxy-setup.sh new file mode 100755 index 00000000..c12e1d3a --- /dev/null +++ b/vm-systemd/network-proxy-setup.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +# Setup gateway for all the VMs this netVM is serviceing... +network=$(/usr/bin/xenstore-read qubes_netvm_network 2>/dev/null) +if [ "x$network" != "x" ]; then + gateway=$(/usr/bin/xenstore-read qubes_netvm_gateway) + netmask=$(/usr/bin/xenstore-read qubes_netvm_netmask) + secondary_dns=$(/usr/bin/xenstore-read qubes_netvm_secondary_dns) + modprobe netbk 2> /dev/null || modprobe xen-netback + echo "NS1=$gateway" > /var/run/qubes/qubes_ns + echo "NS2=$secondary_dns" >> /var/run/qubes/qubes_ns + /usr/lib/qubes/qubes_setup_dnat_to_ns + echo "1" > /proc/sys/net/ipv4/ip_forward +fi diff --git a/vm-systemd/ntpd.service b/vm-systemd/ntpd.service new file mode 100644 index 00000000..21e93db3 --- /dev/null +++ b/vm-systemd/ntpd.service @@ -0,0 +1,3 @@ +.include /lib/systemd/system/ntpd.service +[Unit] +ConditionPathExists=/var/run/qubes-service/ntpd diff --git a/vm-systemd/prepare-dvm.sh b/vm-systemd/prepare-dvm.sh new file mode 100755 index 00000000..86b6a74b --- /dev/null +++ b/vm-systemd/prepare-dvm.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +possibly_run_save_script() +{ + ENCODED_SCRIPT=$(xenstore-read qubes_save_script) + if [ -z "$ENCODED_SCRIPT" ] ; then return ; fi + echo $ENCODED_SCRIPT|perl -e 'use MIME::Base64 qw(decode_base64); local($/) = undef;print decode_base64()' >/tmp/qubes_save_script + chmod 755 /tmp/qubes_save_script + Xorg -config /etc/X11/xorg-preload-apps.conf :0 & + sleep 2 + DISPLAY=:0 su - user -c /tmp/qubes_save_script + killall Xorg +} + +if xenstore-read qubes_save_request 2>/dev/null ; then + ln -sf /home_volatile /home + possibly_run_save_script + touch /etc/this_is_dvm + dmesg -c >/dev/null + free | grep Mem: | + (read a b c d ; xenstore-write device/qubes_used_mem $c) + # we're still running in DispVM template + echo "Waiting for save/restore..." + # ... wait until qubes_restore.c (in Dom0) recreates VM-specific keys + while ! xenstore-read qubes_restore_complete 2>/dev/null ; do + usleep 10 + done + echo Back to life. +fi + diff --git a/vm-systemd/qubes-dvm.service b/vm-systemd/qubes-dvm.service new file mode 100644 index 00000000..b26834e3 --- /dev/null +++ b/vm-systemd/qubes-dvm.service @@ -0,0 +1,12 @@ +[Unit] +Description=Prepare Qubes DispVM Template +ConditionPathExists=/var/run/qubes-service/qubes-dvm + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/qubes/init/prepare-dvm.sh +StandardOutput=syslog + +[Install] +WantedBy=multi-user.target diff --git a/vm-systemd/qubes-firewall.service b/vm-systemd/qubes-firewall.service new file mode 100644 index 00000000..df765dcd --- /dev/null +++ b/vm-systemd/qubes-firewall.service @@ -0,0 +1,10 @@ +[Unit] +Description=Qubes firewall updater +ConditionPathExists=/var/run/qubes-service/qubes-firewall + +[Service] +ExecStart=/usr/sbin/qubes_firewall +StandardOutput=syslog + +[Install] +WantedBy=multi-user.target diff --git a/vm-systemd/qubes-meminfo-writer.service b/vm-systemd/qubes-meminfo-writer.service new file mode 100644 index 00000000..fdb504d5 --- /dev/null +++ b/vm-systemd/qubes-meminfo-writer.service @@ -0,0 +1,12 @@ +[Unit] +Description=Qubes memory information reporter +ConditionPathExists=/var/run/qubes-service/meminfo-writer + +[Service] +Type=forking +ExecStart=/usr/lib/qubes/meminfo-writer 30000 100000 /var/run/meminfo-writer.pid +PIDFile=/var/run/meminfo-writer.pid +StandardOutput=syslog + +[Install] +WantedBy=multi-user.target diff --git a/vm-systemd/qubes-misc-post.service b/vm-systemd/qubes-misc-post.service new file mode 100644 index 00000000..2dc90513 --- /dev/null +++ b/vm-systemd/qubes-misc-post.service @@ -0,0 +1,11 @@ +[Unit] +Description=Qubes misc post-boot actions +After=qubes-dvm.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/qubes/init/misc-post.sh + +[Install] +WantedBy=multi-user.target diff --git a/vm-systemd/qubes-netwatcher.service b/vm-systemd/qubes-netwatcher.service new file mode 100644 index 00000000..d784ba70 --- /dev/null +++ b/vm-systemd/qubes-netwatcher.service @@ -0,0 +1,11 @@ +[Unit] +Description=Qubes network monitor +ConditionPathExists=/var/run/qubes-service/qubes-netwatcher +After=qubes-firewall.service + +[Service] +ExecStart=/usr/sbin/qubes_netwatcher +StandardOutput=syslog + +[Install] +WantedBy=multi-user.target diff --git a/vm-systemd/qubes-network.service b/vm-systemd/qubes-network.service new file mode 100644 index 00000000..28373db0 --- /dev/null +++ b/vm-systemd/qubes-network.service @@ -0,0 +1,14 @@ +[Unit] +Names=qubes_firewall.service +Description=Qubes network forwarding setup +ConditionPathExists=/var/run/qubes-service/qubes-network + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStartPre=/sbin/ethtool -K eth0 sg off +ExecStart=/usr/lib/qubes/init/network-proxy-setup.sh +StandardOutput=syslog + +[Install] +WantedBy=network.target diff --git a/vm-systemd/qubes-qrexec-agent.service b/vm-systemd/qubes-qrexec-agent.service new file mode 100644 index 00000000..759e4b45 --- /dev/null +++ b/vm-systemd/qubes-qrexec-agent.service @@ -0,0 +1,10 @@ +[Unit] +Description=Qubes remote exec agent +After=qubes-dvm.service + +[Service] +ExecStart=/usr/lib/qubes/qrexec_agent +StandardOutput=syslog + +[Install] +WantedBy=multi-user.target diff --git a/vm-systemd/qubes-sysinit.service b/vm-systemd/qubes-sysinit.service new file mode 100644 index 00000000..ea3b84e0 --- /dev/null +++ b/vm-systemd/qubes-sysinit.service @@ -0,0 +1,11 @@ +[Unit] +Description=Init Qubes Services settings + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/qubes/init/qubes-sysinit.sh +StandardOutput=syslog + +[Install] +WantedBy=sysinit.target diff --git a/vm-systemd/qubes-sysinit.sh b/vm-systemd/qubes-sysinit.sh new file mode 100755 index 00000000..57cc2a3a --- /dev/null +++ b/vm-systemd/qubes-sysinit.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +# List of services enabled by default (in case of absence of xenstore entry) +DEFAULT_ENABLED_NETVM="network-manager qubes-network" +DEFAULT_ENABLED_PROXYVM="meminfo-writer qubes-network qubes-firewall qubes-netwatcher" +DEFAULT_ENABLED_APPVM="meminfo-writer" +DEFAULT_ENABLED="meminfo-writer" + +XS_READ=/usr/bin/xenstore-read +XS_LS=/usr/bin/xenstore-ls + +read_service() { + $XS_READ qubes-service/$1 2> /dev/null +} + +mkdir -p /var/run/qubes +mkdir -p /var/run/qubes-service +mkdir -p /var/run/xen-hotplug + +# Set permissions to /proc/xen/xenbus, so normal user can use xenstore-read +chmod 666 /proc/xen/xenbus + +# Set default services depending on VM type +TYPE=`$XS_READ qubes_vm_type 2> /dev/null` +[ "$TYPE" == "AppVM" ] && DEFAULT_ENABLED=$DEFAULT_ENABLED_APPVM +[ "$TYPE" == "NetVM" ] && DEFAULT_ENABLED=$DEFAULT_ENABLED_NETVM +[ "$TYPE" == "ProxyVM" ] && DEFAULT_ENABLED=$DEFAULT_ENABLED_PROXYVM + +# Enable default services +for srv in $DEFAULT_ENABLED; do + touch /var/run/qubes-service/$srv +done + +# Enable services +for srv in `$XS_LS qubes-service 2>/dev/null |grep ' = "1"'|cut -f 1 -d ' '`; do + touch /var/run/qubes-service/$srv +done + +# Disable services +for srv in `$XS_LS qubes-service 2>/dev/null |grep ' = "0"'|cut -f 1 -d ' '`; do + rm -f /var/run/qubes-service/$srv +done + +# Set the hostname +name=`$XS_READ name` +if [ -n "$name" ]; then + hostname $name + (grep -v "\<$name\>" /etc/hosts; echo "127.0.0.1 $name") > /etc/hosts +fi +