diff --git a/Makefile b/Makefile index 82e1e0b..e3b1a03 100644 --- a/Makefile +++ b/Makefile @@ -86,9 +86,15 @@ install-systemd-dropins: install -m 0644 vm-systemd/user/$${dropin}.d/*.conf $(DESTDIR)/$(DROPIN_DIR)/user/$${dropin}.d/ ;\ done -install-systemd: +install-init: + install -d $(DESTDIR)$(LIBDIR)/qubes/init + # FIXME: do a source code move vm-systemd/*.sh to init/ + # since those scripts are shared between sysvinit and systemd. + install -m 0755 init/*.sh vm-systemd/*.sh $(DESTDIR)$(LIBDIR)/qubes/init/ + install -m 0644 init/functions $(DESTDIR)$(LIBDIR)/qubes/init/ + +install-systemd: install-init install -d $(DESTDIR)$(SYSLIBDIR)/systemd/system{,-preset} $(DESTDIR)$(LIBDIR)/qubes/init $(DESTDIR)$(SYSLIBDIR)/modules-load.d - install -m 0755 vm-systemd/*.sh $(DESTDIR)$(LIBDIR)/qubes/init/ install -m 0644 vm-systemd/qubes-*.service $(DESTDIR)$(SYSLIBDIR)/systemd/system/ install -m 0644 vm-systemd/qubes-*.timer $(DESTDIR)$(SYSLIBDIR)/systemd/system/ install -m 0644 vm-systemd/75-qubes-vm.preset $(DESTDIR)$(SYSLIBDIR)/systemd/system-preset/ @@ -98,15 +104,17 @@ install-systemd: install -D -m 0644 vm-systemd/qubes-core-agent-linux.tmpfiles \ $(DESTDIR)/usr/lib/tmpfiles.d/qubes-core-agent-linux.conf -install-sysvinit: +install-sysvinit: install-init install -d $(DESTDIR)/etc/init.d + install vm-init.d/qubes-sysinit $(DESTDIR)/etc/init.d/ + install vm-init.d/qubes-core-early $(DESTDIR)/etc/init.d/ install vm-init.d/qubes-core $(DESTDIR)/etc/init.d/ - install vm-init.d/qubes-core-appvm $(DESTDIR)/etc/init.d/ install vm-init.d/qubes-core-netvm $(DESTDIR)/etc/init.d/ install vm-init.d/qubes-firewall $(DESTDIR)/etc/init.d/ install vm-init.d/qubes-netwatcher $(DESTDIR)/etc/init.d/ install vm-init.d/qubes-qrexec-agent $(DESTDIR)/etc/init.d/ install vm-init.d/qubes-updates-proxy $(DESTDIR)/etc/init.d/ + install vm-init.d/qubes-dvm $(DESTDIR)/etc/init.d/ install -D vm-init.d/qubes-core.modules $(DESTDIR)/etc/sysconfig/modules/qubes-core.modules install -D vm-init.d/qubes-misc.modules $(DESTDIR)/etc/sysconfig/modules/qubes-misc.modules install network/qubes-iptables $(DESTDIR)/etc/init.d/ @@ -164,13 +172,6 @@ install-common: install -g user -m 2775 -d $(DESTDIR)/var/lib/qubes/dom0-updates install -D -m 0644 misc/qubes-master-key.asc $(DESTDIR)/usr/share/qubes/qubes-master-key.asc - if [ -r misc/dispvm-dotfiles.$(DIST).tbz ] ; \ - then \ - install misc/dispvm-dotfiles.$(DIST).tbz $(DESTDIR)/etc/dispvm-dotfiles.tbz ; \ - else \ - install misc/dispvm-dotfiles.tbz $(DESTDIR)/etc/dispvm-dotfiles.tbz ; \ - fi; - install misc/dispvm-prerun.sh $(DESTDIR)$(LIBDIR)/qubes/dispvm-prerun.sh install misc/close-window $(DESTDIR)$(LIBDIR)/qubes/close-window diff --git a/archlinux/PKGBUILD.install b/archlinux/PKGBUILD.install index 4af2b3f..25720eb 100644 --- a/archlinux/PKGBUILD.install +++ b/archlinux/PKGBUILD.install @@ -104,10 +104,10 @@ update_qubesconfig() { # Location of files which contains list of protected files mkdir -p /etc/qubes/protected-files.d - PROTECTED_FILE_LIST='/etc/qubes/protected-files.d' + . /usr/lib/qubes/init/functions # qubes-core-vm has been broken for some time - it overrides /etc/hosts; restore original content - if ! grep -rq "^/etc/hosts$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + if ! is_protected_file /etc/hosts ; then if ! grep -q localhost /etc/hosts; then cat < /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 `hostname` @@ -118,7 +118,7 @@ EOF # ensure that hostname resolves to 127.0.0.1 resp. ::1 and that /etc/hosts is # in the form expected by qubes-sysinit.sh - if ! grep -rq "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + if ! is_protected_file /etc/hostname ; then for ip in '127\.0\.0\.1' '::1'; do if grep -q "^${ip}\(\s\|$\)" /etc/hosts; then sed -i "/^${ip}\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts diff --git a/debian/control b/debian/control index 866913c..6c522a6 100644 --- a/debian/control +++ b/debian/control @@ -37,6 +37,8 @@ Depends: ncurses-term, net-tools, psmisc, + procps, + util-linux, python2.7, python-gi, python-xdg, diff --git a/debian/qubes-core-agent.postinst b/debian/qubes-core-agent.postinst index bfde8c8..8d82112 100755 --- a/debian/qubes-core-agent.postinst +++ b/debian/qubes-core-agent.postinst @@ -78,11 +78,11 @@ case "${1}" in /usr/lib/qubes/qubes-fix-nm-conf.sh # Location of files which contains list of protected files - PROTECTED_FILE_LIST='/etc/qubes/protected-files.d' + . /usr/lib/qubes/init/functions # ensure that hostname resolves to 127.0.1.1 resp. ::1 and that /etc/hosts is # in the form expected by qubes-sysinit.sh - if ! grep -rq "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + if ! is_protected_file /etc/hostname ; then for ip in '127\.0\.1\.1' '::1'; do if grep -q "^${ip}\(\s\|$\)" /etc/hosts; then sed -i "/^${ip}\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts || true @@ -95,7 +95,7 @@ case "${1}" in # remove hostname from 127.0.0.1 line (in debian the hostname is by default # resolved to 127.0.1.1) - if ! grep -rq "^/etc/hosts$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + if ! is_protected_file /etc/hosts ; then sed -i "/^127\.0\.0\.1\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts || true fi diff --git a/init/control-printer-icon.sh b/init/control-printer-icon.sh new file mode 100755 index 0000000..53aa11c --- /dev/null +++ b/init/control-printer-icon.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Source Qubes library. +. /usr/lib/qubes/init/functions + +if ! is_fully_persistent && test -f /etc/xdg/autostart/print-applet.desktop ; then + if qsvc cups ; then + # 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=\(.*\)/NotShowIn=QUBES;\1/' /etc/xdg/autostart/print-applet.desktop + fi +fi diff --git a/init/functions b/init/functions new file mode 100644 index 0000000..76413e4 --- /dev/null +++ b/init/functions @@ -0,0 +1,117 @@ +#!/bin/bash + +# Location of files which contains list of protected files +PROTECTED_FILE_LIST='/etc/qubes/protected-files.d' + +qsvc() { + # Returns whether a service is enabled. + # Usage: qsvc + # + # Must only be used after qubes-sysinit has started. + # See qsvc_early for more information. + local count=100 + while [ ! -e /var/run/qubes-service-environment ] ; do + if [ "$count" = "0" ] ; then + echo "qsvc: Warning: qubes-sysinit has not finished executing yet" >&2 + break + fi + sleep 0.1 + count=$(( count - 1 )) + done + [ -e /var/run/qubes-service/"$1" ] +} + +under_systemd() { + pidof systemd >/dev/null 2>&1 +} + +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 + fi + return 1 +} + +possibly_run_save_script() { + ENCODED_SCRIPT=$(qubesdb-read /qubes-save-script) + if [ -z "$ENCODED_SCRIPT" ] ; then return ; fi + tmpfile=$(mktemp /tmp/qubes-save-script.XXXXXXXXX) + echo $ENCODED_SCRIPT|perl -e 'use MIME::Base64 qw(decode_base64); local($/) = undef;print decode_base64()' >"$tmpfile" + chmod 755 "$tmpfile" + DISPLAY=:0 su - user -c "$tmpfile" + ret=$? + rm -f "$tmpfile" + return $ret +} + +have_qubesdb() { + # Tests whether qubesdb-read exists and can be executed. + type qubesdb-read >/dev/null 2>&1 +} + +have_qrexec_agent() { + # Tests whether qrexec-agent exists and can be executed. + PATH=/usr/lib/qubes type qrexec-agent >/dev/null 2>&1 +} + +qubes_vm_type() { + qubesdb-read /qubes-vm-type +} + +is_netvm() { + [ "$(qubes_vm_type)" = "NetVM" ] +} + +is_appvm() { + [ "$(qubes_vm_type)" = "AppVM" ] +} + +is_proxyvm() { + [ "$(qubes_vm_type)" = "ProxyVM" ] +} + +is_templatevm() { + [ "$(qubes_vm_type)" = "TemplateVM" ] +} + +is_dispvm() { + [ "$(qubes_vm_type)" = "DisposableVM" ] +} + +is_fully_persistent() { + [ "$(qubesdb-read /qubes-vm-persistence)" = "full" ] +} + +is_rwonly_persistent() { + [ "$(qubesdb-read /qubes-vm-persistence)" = "rw-only" ] +} + +is_updateable() { + [ "$(qubesdb-read /qubes-vm-updateable)" = "True" ] +} + +reload_random_seed() { + qubesdb-read /qubes-random-seed | base64 -d > /dev/urandom + qubesdb-rm /qubes-random-seed +} + +is_protected_file() { + grep -Fxrq --exclude='*.rpmsave' --exclude='*~' --exclude='*.rpmnew' --exclude='*.rpmold' -- "${1}" "$PROTECTED_FILE_LIST" 2>/dev/null +} + +umount_retry() { + local count=5 + while mountpoint -q "$1" ; do + if umount "$1" ; then break ; fi + echo "Something prevents unmounting $1:" >&2 + fuser -vmM "$1" >&2 + if [ "$count" = "0" ] ; then + return 1 + fi + sleep 5 + count=$(( count - 1 )) + done + return 0 +} diff --git a/init/setup-dvm-home.sh b/init/setup-dvm-home.sh new file mode 100755 index 0000000..2e70ff0 --- /dev/null +++ b/init/setup-dvm-home.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +echo "Setting up DVM home" >&2 + +touch /etc/this-is-dvm + +# If the user has customized DispVM settings, use its home instead of default skel +[ -e /home_volatile/user/.qubes-dispvm-customized ] && already_customized=yes || already_customized=no +[ -e /rw/home/user/.qubes-dispvm-customized ] && wants_customization=yes || wants_customization=no +if [ "$wants_customization" = "yes" -a "$already_customized" = "no" ] ; then + echo "Customizing /home from /rw/home/user" >&2 + rm -rf /home_volatile/user + cp -af /rw/home/user /home_volatile/user + chown -R user.user /home_volatile/user +fi diff --git a/init/setup-rw.sh b/init/setup-rw.sh new file mode 100755 index 0000000..90201af --- /dev/null +++ b/init/setup-rw.sh @@ -0,0 +1,105 @@ +#!/bin/sh + +if mountpoint -q /rw ; then + # This means /rw is mounted now. + echo "Checking /rw" >&2 + + if ! [ -d /rw/config ] ; then + echo "Virgin boot of the VM: populating /rw/config" >&2 + + mkdir -p /rw/config + touch /rw/config/rc.local + cat > /rw/config/rc.local < /rw/config/qubes-firewall-user-script < /rw/config/suspend-module-blacklist <&2 + cp -af /usr/local.orig /rw/usrlocal + else + echo "Virgin boot of the VM: creating /rw/usrlocal" >&2 + mkdir -p /rw/usrlocal + fi + fi + + if ! [ -d /rw/home ] ; then + echo "Virgin boot of the VM: populating /rw/home" >&2 + mkdir -p /rw/home + fi + + # Chown home if users' UIDs have changed - can be the case on template switch. + for pair in $(getent passwd | awk -F : '/\/home/ { print $1":"$3":"$4":"$6 } ') ; do + user=$(echo "$pair" | awk -F : ' { print $1 } ') + uid=$(echo "$pair" | awk -F : ' { print $2 } ') + gid=$(echo "$pair" | awk -F : ' { print $3 } ') + homedir=$(echo "$pair" | awk -F : ' { print $4 } ') + if ! test -d /rw"$homedir" ; then + if [ "$homedir" == "/home/user" -a -d /home.orig/"$user" ] ; then + echo "Virgin boot of the VM: populating /rw$homedir from /home.orig/$user" >&2 + cp -af /home.orig/"$user" /rw"$homedir" + else + echo "Virgin boot of the VM: populating /rw$homedir from /etc/skel" >&2 + cp -af /etc/skel /rw"$homedir" + fi + chown -R "$uid" /rw"$homedir" & + chgrp -R "$gid" /rw"$homedir" & + chmod 700 /rw"$homedir" & + wait + fi + homedir_uid=$(ls -dn /rw"$homedir" | awk '{print $3}') + homedir_gid=$(ls -dn /rw"$homedir" | awk '{print $4}') + if [ "$uid" -ne "$homedir_uid" ]; then + echo "Virgin boot of the VM: adjusting ownership on /rw$homedir to $uid" >&2 + find /rw/"$homedir" -uid "$homedir_uid" -print0 | xargs -0 echo chown "$uid" + fi + if [ "$gid" -ne "$homedir_gid" ]; then + echo "Virgin boot of the VM: adjusting groupship on /rw$homedir to $gid" >&2 + find /rw/"$homedir" -gid "$homedir_gid" -print0 | xargs -0 echo chgrp "$gid" + fi + done + + echo "Finished checking /rw" >&2 +fi + +# Old Qubes versions had symlink /home -> /rw/home; now we use mount --bind +if [ -L /home ]; then + rm /home + mkdir /home +fi + +if [ ! -e /var/lib/qubes/first-boot-completed ]; then + touch /var/lib/qubes/first-boot-completed +fi diff --git a/init/setup-rwdev.sh b/init/setup-rwdev.sh new file mode 100755 index 0000000..07547ca --- /dev/null +++ b/init/setup-rwdev.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +set -e + +if [ -e /dev/xvdb ] ; then + # The private /dev/xvdb device is present. + + # check if private.img (xvdb) is empty - all zeros + private_size_512=`blockdev --getsz /dev/xvdb` + if dd if=/dev/zero bs=512 count=$private_size_512 2>/dev/null | diff /dev/xvdb - >/dev/null; then + # the device is empty, create filesystem + echo "Virgin boot of the VM: creating private.img filesystem" >&2 + mkfs.ext4 -m 0 -q /dev/xvdb || exit 1 + fi + + tune2fs -m 0 /dev/xvdb + echo "Virgin boot of the VM: marking private.img as clean" >&2 + fsck.ext4 -fp /dev/xvdb + echo "Virgin boot of the VM: enlarging private.img" >&2 + if ! content=$(resize2fs /dev/xvdb 2>&1) ; then + echo "resize2fs /dev/xvdb failed:" >&2 + echo "$content" >&2 + fi + +fi diff --git a/misc/dispvm-dotfiles.tbz b/misc/dispvm-dotfiles.tbz deleted file mode 100644 index 42f0e27..0000000 Binary files a/misc/dispvm-dotfiles.tbz and /dev/null differ diff --git a/misc/dispvm-prerun.sh b/misc/dispvm-prerun.sh index 297750b..9273ece 100755 --- a/misc/dispvm-prerun.sh +++ b/misc/dispvm-prerun.sh @@ -1,22 +1,24 @@ #!/bin/sh +# This script must be run as the `user` user. +# It is customarily launched from prepare-dvm.sh. + +# At this point, the DispVM home directory customizations +# undertaken by mount-dirs.sh have taken place. +# We know this because dispvm-prerun.sh executes after +# local-fs.target, and mount-dirs.sh runs before it. + +me=$( basename "$0" ) apps="/usr/libexec/evinced" -#If user have customized DispVM settings, use its home instead of default dotfiles -if [ ! -e /home/user/.qubes-dispvm-customized ]; then - if [ -e /rw/home/user/.qubes-dispvm-customized ]; then - cp -af /rw/home/user /home/ - else - cat /etc/dispvm-dotfiles.tbz | tar -xjf- --overwrite -C /home/user --owner user 2>&1 >/tmp/dispvm-dotfiles-errors.log - fi -fi +echo "$me started." >&2 for app in $apps ; do - echo "Launching: $app..." - $app >>/tmp/dispvm_prerun_errors.log 2>&1 & + echo "Launching $app" >&2 + $app & done -echo "Sleeping..." +echo "Waiting for I/O to quiesce" >&2 PREV_IO=0 while true; do IO=`vmstat -D | awk '/read|write/ {IOs+=$1} END {print IOs}'` @@ -27,11 +29,9 @@ while true; do sleep 2 done -ps aufwwx > /tmp/dispvm-prerun-proclist.log - -echo "Closing windows..." +echo "Closing windows" >&2 /usr/lib/qubes/close-window `xwininfo -root -children|tail -n +7 |awk '{print $1}'` sleep 1 fuser -vkm /rw -echo done. +echo "$me finished." >&2 diff --git a/misc/qubes-trigger-sync-appmenus.sh b/misc/qubes-trigger-sync-appmenus.sh index 3df1d1d..5d01986 100755 --- a/misc/qubes-trigger-sync-appmenus.sh +++ b/misc/qubes-trigger-sync-appmenus.sh @@ -1,7 +1,8 @@ -#!/bin/sh +#!/bin/bash -UPDATEABLE=`qubesdb-read /qubes-vm-updateable` +# Source Qubes library. +. /usr/lib/qubes/init/functions -if [ "$UPDATEABLE" = "True" ]; then +if is_updateable ; then /usr/lib/qubes/qrexec-client-vm dom0 qubes.SyncAppMenus /bin/sh /etc/qubes-rpc/qubes.GetAppmenus fi diff --git a/network/qubes-firewall b/network/qubes-firewall index 5c1bfe9..8ee2df1 100755 --- a/network/qubes-firewall +++ b/network/qubes-firewall @@ -23,8 +23,8 @@ while true; do TRIGGER=reload else # Wait for changes in qubesdb file - /usr/bin/qubesdb-watch $XENSTORE_IPTABLES - TRIGGER=$(/usr/bin/qubesdb-read $XENSTORE_IPTABLES) + qubesdb-watch $XENSTORE_IPTABLES + TRIGGER=$(qubesdb-read $XENSTORE_IPTABLES) fi if ! [ "$TRIGGER" = "reload" ]; then continue ; fi diff --git a/network/qubes-nmhook b/network/qubes-nmhook index 42d2dbb..0bd1736 100755 --- a/network/qubes-nmhook +++ b/network/qubes-nmhook @@ -1,9 +1,13 @@ #!/bin/sh + +# Source Qubes library. +. /usr/lib/qubes/init/functions + /usr/lib/qubes/qubes-setup-dnat-to-ns -# Tinyproxy does not reload DNS servers -if [ -x /bin/systemctl ]; then - /bin/systemctl --no-block try-restart qubes-updates-proxy.service +# FIXME: Tinyproxy does not reload DNS servers. +if under_systemd ; then + systemctl --no-block try-restart qubes-updates-proxy.service else - /usr/sbin/service qubes-updates-proxy try-restart + service qubes-updates-proxy try-restart fi diff --git a/network/setup-ip b/network/setup-ip index 1ac0f03..1717d30 100755 --- a/network/setup-ip +++ b/network/setup-ip @@ -1,13 +1,9 @@ #!/bin/sh -# setup-ip is potentially invoked before qubes-sysinit.sh is done, therefore -# we perform our qubesdb reads here instead of relying on qvm-service -# files under /var/run/qubes-service/ -disablegw=`qubesdb-read /qubes-service/disable-default-route 2> /dev/null` -disabledns=`qubesdb-read /qubes-service/disable-dns-server 2> /dev/null` +# Source Qubes library. +. /usr/lib/qubes/init/functions -# Location of files which contains list of protected files -PROTECTED_FILE_LIST='/etc/qubes/protected-files.d' +have_qubesdb || exit 0 ip=`/usr/bin/qubesdb-read /qubes-ip 2> /dev/null` if [ x$ip != x ]; then @@ -18,7 +14,7 @@ if [ x$ip != x ]; then /sbin/ethtool -K $INTERFACE sg off /sbin/ethtool -K $INTERFACE tx off # If NetworkManager is enabled, let it configure the network - if [ -f /var/run/qubes-service/network-manager ]; then + if qsvc network-manager ; then nm_config=/etc/NetworkManager/system-connections/qubes-uplink-$INTERFACE cat > $nm_config <<__EOF__ [802-3-ethernet] @@ -39,10 +35,10 @@ method=ignore method=manual may-fail=false __EOF__ - if [ "x$disabledns" != "x1" ]; then + if ! qsvc disable-dns-server ; then echo "dns=$primary_dns;$secondary_dns" >> $nm_config fi - if [ "x$disablegw" != "x1" ]; then + if ! qsvc disable-default-route ; then echo "addresses1=$ip;32;$gateway" >> $nm_config else echo "addresses1=$ip;32" >> $nm_config @@ -58,7 +54,7 @@ __EOF__ if [ "x$disablegw" != "x1" ]; then /sbin/route add default gw $gateway fi - if ! grep -rq "^/etc/resolv[.]conf$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + if ! is_protected_file /etc/resolv.conf ; then echo > /etc/resolv.conf if [ "x$disabledns" != "x1" ]; then echo "nameserver $primary_dns" > /etc/resolv.conf diff --git a/network/show-hide-nm-applet.sh b/network/show-hide-nm-applet.sh index 46b4846..40b2233 100644 --- a/network/show-hide-nm-applet.sh +++ b/network/show-hide-nm-applet.sh @@ -2,7 +2,9 @@ type nm-applet > /dev/null 2>&1 || exit 0 +# Source Qubes library. +. /usr/lib/qubes/init/functions + # Hide nm-applet when network-manager is disabled -nm_enabled=false -[ -f /var/run/qubes-service/network-manager ] && nm_enabled=true +qsvc network-manager && nm_enabled=true || nm_enabled=false gsettings set org.gnome.nm-applet show-applet $nm_enabled diff --git a/network/update-proxy-configs b/network/update-proxy-configs index fe6781a..328b2b0 100755 --- a/network/update-proxy-configs +++ b/network/update-proxy-configs @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # The Qubes OS Project, http://www.qubes-os.org # @@ -21,6 +21,9 @@ # # +# Source Qubes library. +. /usr/lib/qubes/init/functions + BEGIN_MARKER="### QUBES BEGIN ###" END_MARKER="### QUBES END ###" @@ -71,7 +74,7 @@ EOF ### helper functions end # Determine whether the proxy should be used -if [ -f /var/run/qubes-service/yum-proxy-setup -o -f /var/run/qubes-service/updates-proxy-setup ]; then +if qsvc yum-proxy-setup || qsvc updates-proxy-setup ; then PROXY_ADDR="http://10.137.255.254:8082/" PROXY_CONF_ENTRY="proxy=$PROXY_ADDR" else diff --git a/qubes-rpc/prepare-suspend b/qubes-rpc/prepare-suspend index e3e1f8f..f5f3721 100755 --- a/qubes-rpc/prepare-suspend +++ b/qubes-rpc/prepare-suspend @@ -1,4 +1,7 @@ -#!/bin/sh +#!/bin/bash + +# Source Qubes library. +. /usr/lib/qubes/init/functions action=$1 [ -z "$action" ] && action=suspend @@ -12,7 +15,7 @@ if [ -r /rw/config/suspend-module-blacklist ]; then fi if [ x"$action" = x"suspend" ]; then - if [ -f /var/run/qubes-service/network-manager ]; then + if qsvc network-manager ; then dbus-send --system --print-reply \ --dest=org.freedesktop.NetworkManager \ /org/freedesktop/NetworkManager \ @@ -38,11 +41,11 @@ else for mod in `cat /var/run/qubes/suspend-modules-loaded`; do modprobe $mod done - if [ -f /var/run/qubes-service/network-manager ]; then + if qsvc network-manager ; then dbus-send --system --print-reply \ --dest=org.freedesktop.NetworkManager \ /org/freedesktop/NetworkManager \ org.freedesktop.NetworkManager.Sleep boolean:false || \ - { [ -x /bin/systemctl ] && systemctl start NetworkManager.service; } || service qubes-core-netvm start + { under_systemd && systemctl start NetworkManager.service; } || service qubes-core-netvm start fi fi diff --git a/rpm_spec/core-vm.spec b/rpm_spec/core-vm.spec index c20f300..79bcfe6 100644 --- a/rpm_spec/core-vm.spec +++ b/rpm_spec/core-vm.spec @@ -20,6 +20,8 @@ # # +%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 + %{!?version: %define version %(cat version)} %{!?backend_vmm: %define backend_vmm %(echo $BACKEND_VMM)} @@ -49,6 +51,10 @@ Requires: net-tools Requires: nautilus-python Requires: qubes-utils >= 3.1.3 Requires: initscripts +Requires: gawk +# for dispvm-prerun.sh +Requires: procps-ng +Requires: util-linux # for qubes-desktop-run Requires: pygobject3-base Requires: dbus-python @@ -191,10 +197,10 @@ fi # Location of files which contains list of protected files mkdir -p /etc/qubes/protected-files.d -PROTECTED_FILE_LIST='/etc/qubes/protected-files.d' +. /usr/lib/qubes/init/functions # qubes-core-vm has been broken for some time - it overrides /etc/hosts; restore original content -if ! grep -rq "^/etc/hosts$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then +if ! is_protected_file /etc/hosts ; then if ! grep -q localhost /etc/hosts; then cat < /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 `hostname` @@ -205,7 +211,7 @@ fi # ensure that hostname resolves to 127.0.0.1 resp. ::1 and that /etc/hosts is # in the form expected by qubes-sysinit.sh -if ! grep -rq "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then +if ! is_protected_file /etc/hostname ; then for ip in '127\.0\.0\.1' '::1'; do if grep -q "^${ip}\(\s\|$\)" /etc/hosts; then sed -i "/^${ip}\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts @@ -324,7 +330,6 @@ rm -f %{name}-%{version} /etc/NetworkManager/dispatcher.d/30-qubes-external-ip /etc/NetworkManager/dispatcher.d/qubes-nmhook %config(noreplace) /etc/X11/xorg-preload-apps.conf -/etc/dispvm-dotfiles.tbz /etc/dhclient.d/qubes-setup-dnat-to-ns.sh /etc/fstab /etc/pki/rpm-gpg/RPM-GPG-KEY-qubes* @@ -425,6 +430,9 @@ rm -f %{name}-%{version} /usr/lib/yum-plugins/yum-qubes-hooks.py* /usr/lib/dracut/dracut.conf.d/30-qubes.conf /usr/lib/NetworkManager/conf.d/30-qubes.conf +%dir /usr/lib/qubes/init +/usr/lib/qubes/init/*.sh +/usr/lib/qubes/init/functions %dir /usr/lib/qubes-bind-dirs.d /usr/lib/qubes-bind-dirs.d/30_cron.conf /usr/lib64/python2.7/site-packages/qubes/xdg.py* @@ -464,8 +472,10 @@ Conflicts: qubes-core-vm-systemd The Qubes core startup configuration for SysV init (or upstart). %files sysvinit +/etc/init.d/qubes-sysinit +/etc/init.d/qubes-core-early /etc/init.d/qubes-core -/etc/init.d/qubes-core-appvm +/etc/init.d/qubes-dvm /etc/init.d/qubes-core-netvm /etc/init.d/qubes-firewall /etc/init.d/qubes-netwatcher @@ -495,22 +505,13 @@ done chkconfig rsyslog on chkconfig haldaemon on chkconfig messagebus on -chkconfig --add qubes-core || echo "WARNING: Cannot add service qubes-core!" -chkconfig qubes-core on || echo "WARNING: Cannot enable service qubes-core!" -chkconfig --add qubes-core-netvm || echo "WARNING: Cannot add service qubes-core-netvm!" -chkconfig qubes-core-netvm on || echo "WARNING: Cannot enable service qubes-core-netvm!" -chkconfig --add qubes-core-appvm || echo "WARNING: Cannot add service qubes-core-appvm!" -chkconfig qubes-core-appvm on || echo "WARNING: Cannot enable service qubes-core-appvm!" -chkconfig --add qubes-firewall || echo "WARNING: Cannot add service qubes-firewall!" -chkconfig qubes-firewall on || echo "WARNING: Cannot enable service qubes-firewall!" -chkconfig --add qubes-netwatcher || echo "WARNING: Cannot add service qubes-netwatcher!" -chkconfig qubes-netwatcher on || echo "WARNING: Cannot enable service qubes-netwatcher!" -chkconfig --add qubes-iptables || echo "WARNING: Cannot add service qubes-iptables!" -chkconfig qubes-iptables on || echo "WARNING: Cannot enable service qubes-iptables!" -chkconfig --add qubes-updates-proxy || echo "WARNING: Cannot add service qubes-updates-proxy!" -chkconfig qubes-updates-proxy on || echo "WARNING: Cannot enable service qubes-updates-proxy!" -chkconfig --add qubes-qrexec-agent || echo "WARNING: Cannot add service qubes-qrexec-agent!" -chkconfig qubes-qrexec-agent on || echo "WARNING: Cannot enable service qubes-qrexec-agent!" +for svc in %qubes_services ; do + if [ "$1" = 1 ] ; then + chkconfig --add $svc || echo "WARNING: Cannot add service $svc!" + else + chkconfig $svc resetpriorities || echo "WARNING: Cannot reset priorities of service $svc!" + fi +done # TODO: make this not display the silly message about security context... sed -i s/^id:.:initdefault:/id:3:initdefault:/ /etc/inittab @@ -518,13 +519,9 @@ sed -i s/^id:.:initdefault:/id:3:initdefault:/ /etc/inittab %preun sysvinit if [ "$1" = 0 ] ; then # no more packages left - chkconfig qubes-core off - chkconfig qubes-core-netvm off - chkconfig qubes-core-appvm off - chkconfig qubes-firewall off - chkconfig qubes-netwatcher off - chkconfig qubes-updates-proxy off - chkconfig qubes-qrexec-agent off + for svc in %qubes_services ; do + chkconfig --del $svc + done fi %package systemd @@ -559,16 +556,7 @@ The Qubes core startup configuration for SystemD init. /lib/systemd/system-preset/75-qubes-vm.preset /lib/modules-load.d/qubes-core.conf /lib/modules-load.d/qubes-misc.conf -%dir /usr/lib/qubes/init -/usr/lib/qubes/init/prepare-dvm.sh -/usr/lib/qubes/init/network-proxy-setup.sh /usr/lib/qubes/init/qubes-iptables -/usr/lib/qubes/init/misc-post.sh -/usr/lib/qubes/init/misc-post-stop.sh -/usr/lib/qubes/init/mount-dirs.sh -/usr/lib/qubes/init/qubes-random-seed.sh -/usr/lib/qubes/init/qubes-sysinit.sh -/usr/lib/qubes/init/bind-dirs.sh /lib/systemd/system/chronyd.service.d/30_qubes.conf /lib/systemd/system/crond.service.d/30_qubes.conf /lib/systemd/system/cups.service.d/30_qubes.conf diff --git a/vm-init.d/qubes-core b/vm-init.d/qubes-core index 69625f5..437bff9 100755 --- a/vm-init.d/qubes-core +++ b/vm-init.d/qubes-core @@ -1,154 +1,49 @@ #!/bin/bash # # chkconfig: 345 90 90 -# description: Executes Qubes core scripts at VM boot +# description: Executes supplementary Qubes core scripts at VM boot # # Source function library. . /etc/rc.d/init.d/functions +# Source Qubes library. +. /usr/lib/qubes/init/functions + start() { - echo -n $"Executing Qubes Core scripts:" + have_qubesdb || return - # Set permissions to /proc/xen/xenbus, so normal user can access xenstore - chmod 666 /proc/xen/xenbus - # Set permissions to files needed by gui-agent - chmod 666 /proc/u2mfn - - mkdir -p /var/run/xen-hotplug - mkdir -p /var/run/qubes - chgrp qubes /var/run/qubes - chmod 0775 /var/run/qubes - - # Load random seed from dom0 - qubesdb-read /qubes-random-seed | base64 -d > /dev/urandom - qubesdb-rm /qubes-random-seed - - # Location of files which contains list of protected files - PROTECTED_FILE_LIST='/etc/qubes/protected-files.d' - - # Set the hostname - if ! grep -rq "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then - name=$(/usr/bin/qubesdb-read /name) - if ! [ -f /etc/this-is-dvm ] ; then - # we don't want to set hostname for DispVM - # because it makes some of the pre-created dotfiles invalid (e.g. .kde/cache-) - # (let's be frank: nobody's gonna use xterm on DispVM) - hostname $name - sed -i "s/^\(127\.0\.0\.1[\t ].*\) \($name \)\?\(.*\)/\1\2 $name/" /etc/hosts + # Start AppVM specific services + for svc in cups ntpd ; do + if qsvc $svc && test -e /etc/init.d/$svc ; then + /sbin/service $svc start fi - fi - - # Set the timezone - if ! grep -rq "^/etc/timezone$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then - timezone=`/usr/bin/qubesdb-read /qubes-timezone 2> /dev/null` - if [ -n "$timezone" ]; then - ln -f /usr/share/zoneinfo/$timezone /etc/localtime - echo "# Clock configuration autogenerated based on Qubes dom0 settings" > /etc/sysconfig/clock - echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock - fi - fi - - /usr/lib/qubes/update-proxy-configs - - # 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 - # qubesdb-read fails - INTERFACE=eth0 /usr/lib/qubes/setup-ip - - if [ -e /dev/xvdb ] ; then - # check if private.img (xvdb) is empty - all zeros - private_size_512=`blockdev --getsz /dev/xvdb` - if dd if=/dev/zero bs=512 count=$private_size_512 | diff /dev/xvdb - >/dev/null; then - # the device is empty, create filesystem - echo "--> Virgin boot of the VM: creating filesystem on private.img" - mkfs.ext4 -m 0 -q /dev/xvdb || exit 1 - fi - - mount /rw - resize2fs /dev/xvdb 2> /dev/null || echo "'resize2fs /dev/xvdb' failed" - - if ! [ -d /rw/home ] ; then - echo - echo "--> Virgin boot of the VM: Linking /home to /rw/home" - - mkdir -p /rw/config - cat > /rw/config/rc.local < /rw/config/qubes-firewall-user-script < /rw/config/suspend-module-blacklist </dev/null`" -o \ - -n "`ls -A /usr/local/lib64 2>/dev/null`" ]; then - ldconfig - fi - - [ -x /rw/config/rc.local ] && /rw/config/rc.local + done + echo -n $"Finagling printer icon:" + /usr/lib/qubes/init/control-printer-icon.sh success - echo "" + echo - start_ntpd=$(/usr/bin/qubesdb-read /qubes-service/ntpd 2> /dev/null) - if [ "$start_ntpd" == "1" ]; then - /sbin/service ntpd start + if qsvc meminfo-writer ; then + MEM_CHANGE_THRESHOLD_KB=30000 + MEMINFO_DELAY_USEC=100000 + echo -n $"Starting Qubes memory information service:" + /usr/lib/qubes/meminfo-writer $MEM_CHANGE_THRESHOLD_KB $MEMINFO_DELAY_USEC /var/run/meminfo-writer.pid + success + echo "" fi - return 0 + + echo -n $"Executing Qubes misc post scripts:" + /usr/lib/qubes/init/misc-post.sh && success || failure + echo } stop() { - su -c 'mkdir -p /home_volatile/user/.local/share/applications' user - su -c 'cp -a /usr/share/applications/defaults.list /home_volatile/user/.local/share/applications/' user - if [ -r '/home/user/.local/share/applications/defaults.list' ]; then - su -c 'cat /home/user/.local/share/applications/defaults.list >> /home_volatile/user/.local/share/applications/defaults.list' user - fi - return 0 + have_qubesdb || return + + /usr/lib/qubes/init/misc-post-stop.sh } case "$1" in diff --git a/vm-init.d/qubes-core-appvm b/vm-init.d/qubes-core-appvm deleted file mode 100755 index 2270381..0000000 --- a/vm-init.d/qubes-core-appvm +++ /dev/null @@ -1,104 +0,0 @@ -#!/bin/bash -# -# chkconfig: 345 85 85 -# description: Executes Qubes core scripts at AppVM boot -# -# Source function library. -. /etc/rc.d/init.d/functions - -possibly_run_save_script() -{ - ENCODED_SCRIPT=$(qubesdb-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 & - while ! [ -S /tmp/.X11-unix/X0 ]; do sleep 0.5; done - DISPLAY=:0 su - user -c /tmp/qubes-save-script - killall Xorg -} - -start() -{ - type=$(/usr/bin/qubesdb-read /qubes-vm-type) - if [ "$type" != "AppVM" -a "$type" != "DisposableVM" -a "$type" != "TemplateVM" ]; then - # This script runs only on AppVMs - return 0 - fi - - # Start AppVM specific services - start_cups=$(/usr/bin/qubesdb-read /qubes-service/cups 2> /dev/null) - if [ "$start_cups" != "0" ]; 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=\(.*\)/NotShowIn=QUBES;\1/' /etc/xdg/autostart/print-applet.desktop - - fi - - echo -n $"Executing Qubes Core scripts for AppVM:" - - if qubesdb-read /qubes-save-request 2>/dev/null ; then - if [ -L /home ]; then - rm /home - mkdir /home - fi - mount --bind /home_volatile /home - touch /etc/this-is-dvm - mount /rw - possibly_run_save_script - umount /rw - dmesg -c >/dev/null - free | grep Mem: | - (read a b c d ; qubesdb-write /qubes-used-mem $c) - # give dom0 time to read some entries, when done it will shutdown qubesdb, - # so wait for it - qubesdb-watch /stop-qubesdb - # just to make sure - systemctl stop qubes-db.service - - # we're still running in DispVM template - echo "Waiting for save/restore..." - # the service will start only after successful restore - systemctl start qubes-db.service - echo Back to life. - - # Reload random seed - qubesdb-read /qubes-random-seed | base64 -d > /dev/urandom - qubesdb-rm /qubes-random-seed - - fi - - start_meminfo_writer=$(/usr/bin/qubesdb-read /qubes-service/meminfo-writer 2>/dev/null) - if [ "$start_meminfo_writer" != "0" ]; then - MEM_CHANGE_THRESHOLD_KB=30000 - MEMINFO_DELAY_USEC=100000 - /usr/lib/qubes/meminfo-writer $MEM_CHANGE_THRESHOLD_KB $MEMINFO_DELAY_USEC /var/run/meminfo-writer.pid - fi - - success - echo "" - return 0 -} - -stop() -{ - return 0 -} - -case "$1" in - start) - start - ;; - stop) - stop - ;; - *) - echo $"Usage: $0 {start|stop}" - exit 3 - ;; -esac - -exit $RETVAL diff --git a/vm-init.d/qubes-core-early b/vm-init.d/qubes-core-early new file mode 100755 index 0000000..12ad472 --- /dev/null +++ b/vm-init.d/qubes-core-early @@ -0,0 +1,44 @@ +#!/bin/bash +# +# chkconfig: 345 84 84 +# description: Executes early necessary Qubes core scripts at VM boot +# +# Source function library. +. /etc/rc.d/init.d/functions + +# Source Qubes library. +. /usr/lib/qubes/init/functions + +start() +{ + have_qubesdb || return + + echo -n $"Setting up Qubes persistent file systems:" + /usr/lib/qubes/init/mount-dirs.sh && success || failure + echo + + echo -n $"Executing Qubes random seed scripts:" + /usr/lib/qubes/init/qubes-random-seed.sh && success || failure + echo + +} + +stop() +{ + return 0 +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + *) + echo $"Usage: $0 {start|stop}" + exit 3 + ;; +esac + +exit $RETVAL diff --git a/vm-init.d/qubes-core-netvm b/vm-init.d/qubes-core-netvm index b3d7bd1..d96db37 100755 --- a/vm-init.d/qubes-core-netvm +++ b/vm-init.d/qubes-core-netvm @@ -6,38 +6,21 @@ # Source function library. . /etc/rc.d/init.d/functions +# Source Qubes library. +. /usr/lib/qubes/init/functions + start() { - if ! [ -x /usr/bin/qubesdb-read ] ; then - echo "ERROR: /usr/bin/qubesdb-read not found!" - exit 1 - fi + have_qubesdb || return - type=$(/usr/bin/qubesdb-read /qubes-vm-type) - if [ "$type" == "NetVM" ]; then + if is_netvm; then /usr/lib/qubes/network-manager-prepare-conf-dir /sbin/service NetworkManager start fi echo -n $"Executing Qubes Core scripts NetVM:" - - # Setup gateway for all the VMs this netVM is serviceing... - network=$(/usr/bin/qubesdb-read /qubes-netvm-network 2>/dev/null) - if [ "x$network" != "x" ]; then - gateway=$(/usr/bin/qubesdb-read /qubes-netvm-gateway) - netmask=$(/usr/bin/qubesdb-read /qubes-netvm-netmask) - primary_dns=$(/usr/bin/qubesdb-read /qubes-netvm-primary-dns || echo $gateway) - secondary_dns=$(/usr/bin/qubesdb-read /qubes-netvm-secondary-dns) - modprobe netbk 2> /dev/null || modprobe xen-netback - echo "NS1=$primary_dns" > /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 - - success - echo "" - return 0 + /usr/lib/qubes/init/network-proxy-setup && success || failure + echo } stop() diff --git a/vm-init.d/qubes-dvm b/vm-init.d/qubes-dvm new file mode 100755 index 0000000..f93635c --- /dev/null +++ b/vm-init.d/qubes-dvm @@ -0,0 +1,43 @@ +#!/bin/bash +# +# chkconfig: 345 91 91 +# description: Executes Qubes core scripts at AppVM boot +# +# This must run after GUI agent has started. Hence 91. +# +# Source function library. +. /etc/rc.d/init.d/functions + +# Source Qubes library. +. /usr/lib/qubes/init/functions + +start() +{ + have_qubesdb || return + + if qsvc qubes-dvm; then + echo -n $"Preparing Qubes DVM:" + /usr/lib/qubes/init/prepare-dvm.sh && success || failure + echo + fi +} + +stop() +{ + return 0 +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + *) + echo $"Usage: $0 {start|stop}" + exit 3 + ;; +esac + +exit $RETVAL diff --git a/vm-init.d/qubes-firewall b/vm-init.d/qubes-firewall index 4b17649..30a74a2 100755 --- a/vm-init.d/qubes-firewall +++ b/vm-init.d/qubes-firewall @@ -1,32 +1,34 @@ #!/bin/bash # -# chkconfig: 345 91 91 +# chkconfig: 345 92 92 # description: Starts Qubes Firewall monitor # # Source function library. . /etc/rc.d/init.d/functions +# Source Qubes library. +. /usr/lib/qubes/init/functions + PIDFILE=/var/run/qubes/qubes-firewall.pid start() { - type=$(/usr/bin/qubesdb-read /qubes-vm-type) - start_firewall=$(/usr/bin/qubesdb-read /qubes-service/qubes-firewall 2> /dev/null) - if [ -z "$start_firewall" ] && [ "$type" == "ProxyVM" ] || [ "$start_firewall" == "1" ]; then + have_qubesdb || return + + if qsvc qubes-firewall ; then echo -n $"Starting Qubes Firewall monitor:" /sbin/ethtool -K eth0 sg off /usr/sbin/qubes-firewall & success echo "" fi - return 0 } stop() { if [ -r $PIDFILE ]; then echo -n "Stopping Qubes Firewall monitor:" - kill -9 $(cat $PIDFILE) 2>/dev/null && success || failure + kill -9 $(cat $PIDFILE) 2>/dev/null && success || failure echo "" fi return 0 diff --git a/vm-init.d/qubes-netwatcher b/vm-init.d/qubes-netwatcher index 316c271..7c047bf 100755 --- a/vm-init.d/qubes-netwatcher +++ b/vm-init.d/qubes-netwatcher @@ -1,25 +1,27 @@ #!/bin/bash # -# chkconfig: 345 92 92 +# chkconfig: 345 93 93 # description: Starts Qubes Network monitor # # Source function library. . /etc/rc.d/init.d/functions +# Source Qubes library. +. /usr/lib/qubes/init/functions + PIDFILE=/var/run/qubes/qubes-netwatcher.pid start() { - type=$(/usr/bin/qubesdb-read /qubes-vm-type) - start_netwatcher=$(/usr/bin/qubesdb-read /qubes-service/qubes-netwatcher 2>/dev/null) - if [ -z "$start_netwatcher" ] && [ "$type" == "ProxyVM" ] || [ "$start_netwatcher" == "1" ]; then + have_qubesdb || return + + if qsvc qubes-netwatcher ; then echo -n $"Starting Qubes Network monitor:" /sbin/ethtool -K eth0 sg off /usr/sbin/qubes-netwatcher & success echo "" fi - return 0 } stop() diff --git a/vm-init.d/qubes-qrexec-agent b/vm-init.d/qubes-qrexec-agent index 7fecd51..47ea0a1 100755 --- a/vm-init.d/qubes-qrexec-agent +++ b/vm-init.d/qubes-qrexec-agent @@ -6,21 +6,23 @@ # Source function library. . /etc/rc.d/init.d/functions +# Source Qubes library. +. /usr/lib/qubes/init/functions + start() { + have_qrexec_agent || return echo -n $"Starting Qubes RPC agent:" - /usr/lib/qubes/qrexec-agent 2>/var/log/qubes/qrexec-agent.log & - success echo "" - return 0 } stop() { - killproc qrexec-agent + have_qrexec_agent || return + killproc qrexec-agent } case "$1" in diff --git a/vm-init.d/qubes-sysinit b/vm-init.d/qubes-sysinit new file mode 100755 index 0000000..d8636aa --- /dev/null +++ b/vm-init.d/qubes-sysinit @@ -0,0 +1,34 @@ +#!/bin/bash +# +# chkconfig: 345 80 80 +# description: Executes Qubes system initialization scripts at VM boot +# + +# Source function library. +. /etc/rc.d/init.d/functions + +start() +{ + echo -n $"Executing Qubes system initialization scripts:" + /usr/lib/qubes/init/qubes-sysinit.sh && success || failure ; echo +} + +stop() +{ + return 0 +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + *) + echo $"Usage: $0 {start|stop}" + exit 3 + ;; +esac + +exit $RETVAL diff --git a/vm-init.d/qubes-updates-proxy b/vm-init.d/qubes-updates-proxy index 7bbc52e..8bf4c01 100755 --- a/vm-init.d/qubes-updates-proxy +++ b/vm-init.d/qubes-updates-proxy @@ -2,7 +2,7 @@ # # tinyproxy Startup script for the tinyproxy server as Qubes updates proxy # -# chkconfig: - 85 15 +# chkconfig: 345 85 15 # description: small, efficient HTTP/SSL proxy daemon # # processname: tinyproxy @@ -16,6 +16,9 @@ # Source function library. . /etc/rc.d/init.d/functions +# Source Qubes library. +. /usr/lib/qubes/init/functions + # Source networking configuration. . /etc/sysconfig/network @@ -32,9 +35,9 @@ pidfile="/var/run/tinyproxy-updates/tinyproxy.pid" lockfile=/var/lock/subsys/tinyproxy-updates start() { - type=`/usr/bin/qubesdb-read /qubes-vm-type` - start_updates_proxy=`/usr/bin/qubesdb-read /qubes-service/qubes-updates-proxy 2>/dev/null` - if [ -z "$start_updates_proxy" ] && [ "$type" != "NetVM" ] || [ "$start_updates_proxy" != "1" ]; then + have_qubesdb || return + + if qsvc qubes-updates-proxy ; then # Yum proxy disabled exit 0 fi diff --git a/vm-systemd/bind-dirs.sh b/vm-systemd/bind-dirs.sh index c364e8c..d02fad5 100755 --- a/vm-systemd/bind-dirs.sh +++ b/vm-systemd/bind-dirs.sh @@ -23,21 +23,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -set -x +# Source Qubes library. +. /usr/lib/qubes/init/functions prerequisite() { - qubes_vm_persistence="$(qubesdb-read /qubes-vm-persistence)" - if [ ! "$qubes_vm_persistence" = "rw-only" ]; then + if ! is_rwonly_persistent ; then true "No TemplateBasedVM detected. Exiting." exit 0 fi - if [ -f "/var/run/qubes-service/qubes-dvm" ]; then - # https://github.com/QubesOS/qubes-issues/issues/1328#issuecomment-169483029 - # Do none of the following in a DispVM. - # During DispVM savefile generation, 'qubesdb-read /qubes-vm-persistence' - # outputs 'rw'. - exit 0 - fi } init() { @@ -96,7 +89,8 @@ bind_dirs() { # Initially copy over data directories to /rw if rw directory does not exist. if [ -d "$fso_ro" ] || [ -f "$fso_ro" ]; then if ! [ -d "$fso_rw" -o -f "$fso_rw" ]; then - cp --verbose --archive --recursive --parents "$fso_ro" "$rw_dest_dir" + echo "Initializing $rw_dest_dir with files from $fso_ro" >&2 + cp --archive --recursive --parents "$fso_ro" "$rw_dest_dir" fi else true "$fso_ro is neither a directory nor a file or does not exist, skipping." @@ -104,6 +98,7 @@ bind_dirs() { fi # Bind the fso. + echo "Bind mounting $fso_rw onto $fso_ro" >&2 mount --bind "$fso_rw" "$fso_ro" done } diff --git a/vm-systemd/cups.service.d/30_qubes.conf b/vm-systemd/cups.service.d/30_qubes.conf index 54104ad..d332eb6 100644 --- a/vm-systemd/cups.service.d/30_qubes.conf +++ b/vm-systemd/cups.service.d/30_qubes.conf @@ -1,3 +1,6 @@ [Unit] ConditionPathExists=/var/run/qubes-service/cups After=qubes-sysinit.service + +[Service] +ExecStartPost=/usr/lib/qubes/init/control-printer-icon.sh diff --git a/vm-systemd/misc-post.sh b/vm-systemd/misc-post.sh index d02ff5d..cd550e3 100755 --- a/vm-systemd/misc-post.sh +++ b/vm-systemd/misc-post.sh @@ -1,5 +1,8 @@ #!/bin/sh +# Source Qubes library. +. /usr/lib/qubes/init/functions + /usr/lib/qubes/update-proxy-configs if [ -n "`ls -A /usr/local/lib 2>/dev/null`" -o \ @@ -13,14 +16,6 @@ fi # qubesdb-read fails INTERFACE=eth0 /usr/lib/qubes/setup-ip -[ -x /rw/config/rc.local ] && /rw/config/rc.local - -# Start services which haven't own proper systemd unit: - -if [ ! -f /usr/lib/systemd/system/cups.service ]; then - if [ -f /var/run/qubes-service/cups ]; then - /usr/sbin/service cups start - fi +if [ -x /rw/config/rc.local ] ; then + /rw/config/rc.local fi - -exit 0 diff --git a/vm-systemd/mount-dirs.sh b/vm-systemd/mount-dirs.sh old mode 100644 new mode 100755 index 0871d15..0507a57 --- a/vm-systemd/mount-dirs.sh +++ b/vm-systemd/mount-dirs.sh @@ -1,93 +1,22 @@ #!/bin/sh -# check if private.img (xvdb) is empty - all zeros -private_size_512=`blockdev --getsz /dev/xvdb` -if dd if=/dev/zero bs=512 count=$private_size_512 2>/dev/null | diff /dev/xvdb - >/dev/null; then - # the device is empty, create filesystem - echo "--> Virgin boot of the VM: creating filesystem on private.img" - mkfs.ext4 -m 0 -q /dev/xvdb || exit 1 -fi +# Source Qubes library. +. /usr/lib/qubes/init/functions -tune2fs -m 0 /dev/xvdb -mount /rw -resize2fs /dev/xvdb 2> /dev/null || echo "'resize2fs /dev/xvdb' failed" +set -e -if ! [ -d /rw/home ] ; then - echo - echo "--> Virgin boot of the VM: Populating /rw/home" +/usr/lib/qubes/init/setup-rwdev.sh +if [ -e /dev/xvdb ] ; then mount /rw ; fi +/usr/lib/qubes/init/setup-rw.sh - mkdir -p /rw/config - touch /rw/config/rc.local - cat > /rw/config/rc.local < /rw/config/qubes-firewall-user-script < /rw/config/suspend-module-blacklist < /rw/home; now we use mount --bind -if [ -L /home ]; then - rm /home - mkdir /home -fi - -if [ -e /var/run/qubes-service/qubes-dvm ]; then +if qsvc qubes-dvm; then + /usr/lib/qubes/init/setup-dvm-home.sh + echo "Mounting /home_volatile onto /home" >&2 mount --bind /home_volatile /home - touch /etc/this-is-dvm - - #If user have customized DispVM settings, use its home instead of default dotfiles - if [ ! -e /home/user/.qubes-dispvm-customized ]; then - if [ -e /rw/home/user/.qubes-dispvm-customized ]; then - cp -af /rw/home/user /home/ - else - cat /etc/dispvm-dotfiles.tbz | tar -xjf- --overwrite -C /home/user --owner user 2>&1 >/tmp/dispvm-dotfiles-errors.log - fi - fi else + echo "Mounting /home" >&2 mount /home + # https://github.com/QubesOS/qubes-issues/issues/1328#issuecomment-169483029 + # Do none of the following in a DispVM. + /usr/lib/qubes/init/bind-dirs.sh fi - -/usr/lib/qubes/init/bind-dirs.sh diff --git a/vm-systemd/prepare-dvm.sh b/vm-systemd/prepare-dvm.sh index 36359fc..48f25f9 100755 --- a/vm-systemd/prepare-dvm.sh +++ b/vm-systemd/prepare-dvm.sh @@ -1,24 +1,30 @@ #!/bin/bash -possibly_run_save_script() -{ - ENCODED_SCRIPT=$(qubesdb-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 - DISPLAY=:0 su - user -c /tmp/qubes-save-script -} +# Source Qubes library. +. /usr/lib/qubes/init/functions -echo user | /bin/sh /etc/qubes-rpc/qubes.WaitForSession +set -e + +echo "Waiting for user session to quiesce." >&2 +echo user | /bin/sh /etc/qubes-rpc/qubes.WaitForSession || : + +echo "Possibly running save script." >&2 possibly_run_save_script -umount /rw -dmesg -c >/dev/null + +echo "Unmounting /rw filesystem." >&2 +umount_retry /rw || echo "Giving up and proceeding. Warning: this may not work." >&2 + +dmesg -C qubesdb-watch /qubes-restore-complete & watch_pid=$! free | grep Mem: | (read label total used free shared buffers cached; qubesdb-write /qubes-used-mem $(( $used + $cached )) ) + # we're still running in DispVM template -echo "Waiting for save/restore..." -qubesdb-read /qubes-restore-complete || wait $watch_pid -echo Back to life. -systemctl restart systemd-random-seed.service +echo "Waiting for restore signal." >&2 +qubesdb-read /qubes-restore-complete >/dev/null || wait $watch_pid +echo "Restore complete." >&2 + +# Reload random seed +echo "Reloading random seed." >&2 +reload_random_seed diff --git a/vm-systemd/qubes-dvm.service b/vm-systemd/qubes-dvm.service index 294eba3..f791341 100644 --- a/vm-systemd/qubes-dvm.service +++ b/vm-systemd/qubes-dvm.service @@ -1,14 +1,14 @@ [Unit] Description=Prepare Qubes DispVM Template ConditionPathExists=/var/run/qubes-service/qubes-dvm -After=systemd-readahead-replay.service +After=systemd-readahead-replay.service qubes-gui-agent.service +Wants=qubes-gui-agent.service Before=xendriverdomain.service [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 index 9229f5b..14f2091 100644 --- a/vm-systemd/qubes-firewall.service +++ b/vm-systemd/qubes-firewall.service @@ -5,7 +5,6 @@ After=qubes-network.service [Service] ExecStart=/usr/sbin/qubes-firewall -StandardOutput=syslog [Install] WantedBy=multi-user.target diff --git a/vm-systemd/qubes-iptables.service b/vm-systemd/qubes-iptables.service index 065347d..e528775 100644 --- a/vm-systemd/qubes-iptables.service +++ b/vm-systemd/qubes-iptables.service @@ -5,8 +5,6 @@ Description=Qubes base firewall settings Type=oneshot RemainAfterExit=yes ExecStart=/usr/lib/qubes/init/qubes-iptables start -StandardOutput=syslog -StandardError=syslog [Install] WantedBy=basic.target diff --git a/vm-systemd/qubes-mount-dirs.service b/vm-systemd/qubes-mount-dirs.service index 7979c47..dd7d834 100644 --- a/vm-systemd/qubes-mount-dirs.service +++ b/vm-systemd/qubes-mount-dirs.service @@ -1,16 +1,19 @@ [Unit] Description=Initialize and mount /rw and /home -After=qubes-sysinit.service +# There is a dependency on dev-xvdb.device because +# mount-dirs.sh calls setup-rwdev.sh which +# must happen only when /dev/xvdb has appeared. +After=qubes-sysinit.service dev-xvdb.device DefaultDependencies=no -Before=local-fs.target qubes-gui-agent.service +Before=local-fs.target rw.mount home.mount qubes-gui-agent.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/lib/qubes/init/mount-dirs.sh -# Fedora and Debian have different paths for fuser -ExecStop=/bin/sh -c 'fuser -kMm /home' ; /bin/umount /home -ExecStopPost=-/bin/umount /rw +# There is no need for an ExecStop because systemd +# cleans up mount units in the right order, killing +# processes as needed. [Install] WantedBy=multi-user.target diff --git a/vm-systemd/qubes-netwatcher.service b/vm-systemd/qubes-netwatcher.service index e25359d..8097bdc 100644 --- a/vm-systemd/qubes-netwatcher.service +++ b/vm-systemd/qubes-netwatcher.service @@ -5,7 +5,6 @@ After=network-pre.target 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 index 4cb5412..c5aa410 100644 --- a/vm-systemd/qubes-network.service +++ b/vm-systemd/qubes-network.service @@ -8,7 +8,6 @@ After=network-pre.target qubes-iptables.service Type=oneshot RemainAfterExit=yes ExecStart=/usr/lib/qubes/init/network-proxy-setup.sh -StandardOutput=syslog [Install] WantedBy=multi-user.target diff --git a/vm-systemd/qubes-qrexec-agent.service b/vm-systemd/qubes-qrexec-agent.service index 99a50d0..ed0f338 100644 --- a/vm-systemd/qubes-qrexec-agent.service +++ b/vm-systemd/qubes-qrexec-agent.service @@ -5,7 +5,6 @@ After=qubes-dvm.service xendriverdomain.service [Service] ExecStartPre=/bin/sh -c '[ -e /dev/xen/evtchn ] || modprobe xen_evtchn' ExecStart=/usr/lib/qubes/qrexec-agent -StandardOutput=syslog [Install] WantedBy=multi-user.target diff --git a/vm-systemd/qubes-random-seed.sh b/vm-systemd/qubes-random-seed.sh index 78fddca..7a37c88 100755 --- a/vm-systemd/qubes-random-seed.sh +++ b/vm-systemd/qubes-random-seed.sh @@ -1,7 +1,9 @@ #!/bin/bash +# Source Qubes library. +. /usr/lib/qubes/init/functions + set -e set -o pipefail -qubesdb-read /qubes-random-seed | base64 -d > /dev/urandom -qubesdb-rm /qubes-random-seed +reload_random_seed diff --git a/vm-systemd/qubes-sysinit.service b/vm-systemd/qubes-sysinit.service index 7e8a6ae..815e56d 100644 --- a/vm-systemd/qubes-sysinit.service +++ b/vm-systemd/qubes-sysinit.service @@ -8,7 +8,6 @@ After=proc-xen.mount systemd-modules-load.service qubes-db.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 index a46ac18..9db4661 100755 --- a/vm-systemd/qubes-sysinit.sh +++ b/vm-systemd/qubes-sysinit.sh @@ -1,4 +1,7 @@ -#!/bin/sh +#!/bin/bash + +# Source Qubes library. +. /usr/lib/qubes/init/functions # List of services enabled by default (in case of absence of qubesdb entry) DEFAULT_ENABLED_NETVM="network-manager qubes-network qubes-update-check qubes-updates-proxy" @@ -7,18 +10,7 @@ DEFAULT_ENABLED_APPVM="meminfo-writer cups qubes-update-check" DEFAULT_ENABLED_TEMPLATEVM="$DEFAULT_ENABLED_APPVM updates-proxy-setup" DEFAULT_ENABLED="meminfo-writer" -QDB_READ=qubesdb-read -QDB_LS=qubesdb-multiread - -# Location of files which contains list of protected files -PROTECTED_FILE_LIST='/etc/qubes/protected-files.d' - -read_service() { - $QDB_READ /qubes-service/$1 2> /dev/null -} - -systemd_pkg_version=`systemctl --version|head -n 1` -if ! dmesg | grep -q "$systemd_pkg_version running in system mode."; then +if systemd_version_changed ; then # Ensure we're running right version of systemd (the one started by initrd may be different) systemctl daemon-reexec fi @@ -48,11 +40,10 @@ chgrp qubes /proc/xen/privcmd chmod 666 /proc/u2mfn # Set default services depending on VM type -TYPE=`$QDB_READ /qubes-vm-type 2> /dev/null` -[ "$TYPE" = "AppVM" ] && DEFAULT_ENABLED=$DEFAULT_ENABLED_APPVM && touch /var/run/qubes/this-is-appvm -[ "$TYPE" = "NetVM" ] && DEFAULT_ENABLED=$DEFAULT_ENABLED_NETVM && touch /var/run/qubes/this-is-netvm -[ "$TYPE" = "ProxyVM" ] && DEFAULT_ENABLED=$DEFAULT_ENABLED_PROXYVM && touch /var/run/qubes/this-is-proxyvm -[ "$TYPE" = "TemplateVM" ] && DEFAULT_ENABLED=$DEFAULT_ENABLED_TEMPLATEVM && touch /var/run/qubes/this-is-templatevm +is_appvm && DEFAULT_ENABLED=$DEFAULT_ENABLED_APPVM && touch /var/run/qubes/this-is-appvm +is_netvm && DEFAULT_ENABLED=$DEFAULT_ENABLED_NETVM && touch /var/run/qubes/this-is-netvm +is_proxyvm && DEFAULT_ENABLED=$DEFAULT_ENABLED_PROXYVM && touch /var/run/qubes/this-is-proxyvm +is_templatevm && DEFAULT_ENABLED=$DEFAULT_ENABLED_TEMPLATEVM && touch /var/run/qubes/this-is-templatevm # Enable default services for srv in $DEFAULT_ENABLED; do @@ -60,18 +51,18 @@ for srv in $DEFAULT_ENABLED; do done # Enable services -for srv in `$QDB_LS /qubes-service/ 2>/dev/null |grep ' = 1'|cut -f 1 -d ' '`; do +for srv in `qubesdb-multiread /qubes-service/ 2>/dev/null |grep ' = 1'|cut -f 1 -d ' '`; do touch /var/run/qubes-service/$srv done # Disable services -for srv in `$QDB_LS /qubes-service/ 2>/dev/null |grep ' = 0'|cut -f 1 -d ' '`; do +for srv in `qubesdb-multiread /qubes-service/ 2>/dev/null |grep ' = 0'|cut -f 1 -d ' '`; do rm -f /var/run/qubes-service/$srv done # Set the hostname -if ! grep -rq "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then - name=`$QDB_READ /name` +if ! is_protected_file /etc/hostname ; then + name=`qubesdb-read /name` if [ -n "$name" ]; then hostname $name if [ -e /etc/debian_version ]; then @@ -85,13 +76,13 @@ if ! grep -rq "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then fi # Set the timezone -if ! grep -rq "^/etc/timezone$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then - timezone=`$QDB_READ /qubes-timezone 2> /dev/null` +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 + ln -sf ../usr/share/zoneinfo/"$timezone" /etc/localtime if [ -e /etc/debian_version ]; then echo "$timezone" > /etc/timezone - else + 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 @@ -101,7 +92,7 @@ fi # Prepare environment for other services echo > /var/run/qubes-service-environment -debug_mode=`$QDB_READ /qubes-debug-mode 2> /dev/null` +debug_mode=`qubesdb-read /qubes-debug-mode 2> /dev/null` if [ -n "$debug_mode" -a "$debug_mode" -gt 0 ]; then echo "GUI_OPTS=-vv" >> /var/run/qubes-service-environment fi