[PATCH 3/3] Inhibit the screen saver on live installs (#928825)

David Shea dshea at redhat.com
Wed Mar 19 18:04:55 UTC 2014


---
 anaconda                            | 15 ++++++++
 data/liveinst/console.apps/liveinst |  4 +-
 pyanaconda/anaconda.py              |  4 ++
 pyanaconda/safe_dbus.py             | 44 ++++++++++++++++++++++
 pyanaconda/screensaver.py           | 73 +++++++++++++++++++++++++++++++++++++
 5 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100644 pyanaconda/screensaver.py

diff --git a/anaconda b/anaconda
index 4f600eb..3d01944 100755
--- a/anaconda
+++ b/anaconda
@@ -78,6 +78,11 @@ def exitHandler(rebootData, storage, exitCode=None):
                 loop.controllable = True
             dev.deactivate(recursive=True)
 
+    if anaconda.dbus_inhibit_id:
+        from pyanaconda.screensaver import uninhibit_screensaver
+        uninhibit_screensaver(anaconda.dbus_session_connection, anaconda.dbus_inhibit_id)
+        anaconda.dbus_inhibit_id = None
+
     if not flags.imageInstall and not flags.livecdInstall \
        and not flags.dirInstall:
         from pykickstart.constants import KS_SHUTDOWN, KS_WAIT
@@ -861,8 +866,18 @@ if __name__ == "__main__":
         flags.noverifyssl = True
 
     if opts.liveinst:
+        from pyanaconda.safe_dbus import dbus_get_session_connection, DBusCallError
+        from pyanaconda.screensaver import inhibit_screensaver
+
         flags.livecdInstall = True
 
+        try:
+            anaconda.dbus_session_connection = dbus_get_session_connection()
+        except DBusCallError as e:
+            log.info("Unable to connect to DBus session bus: %s", e)
+        else:
+            anaconda.dbus_inhibit_id = inhibit_screensaver(anaconda.dbus_session_connection)
+
     if opts.module:
         for mod in opts.module:
             anaconda.extraModules.append(mod.split(":"))
diff --git a/data/liveinst/console.apps/liveinst b/data/liveinst/console.apps/liveinst
index 7c31081..900ac59 100644
--- a/data/liveinst/console.apps/liveinst
+++ b/data/liveinst/console.apps/liveinst
@@ -3,4 +3,6 @@ PROGRAM=/usr/sbin/liveinst
 SESSION=true
 # has to be here otherwise consolehelper switches off the waiting cursor too early
 STARTUP_NOTIFICATION_NAME="Starting Install to Hard Drive"
-DOMAIN=anaconda
\ No newline at end of file
+DOMAIN=anaconda
+# DBus session connections fail when running setuid unless we pass this through
+KEEP_ENV_VARS=DBUS_SESSION_BUS_ADDRESS
diff --git a/pyanaconda/anaconda.py b/pyanaconda/anaconda.py
index cd12d79..66706f1 100644
--- a/pyanaconda/anaconda.py
+++ b/pyanaconda/anaconda.py
@@ -76,6 +76,10 @@ class Anaconda(object):
         # *sigh* we still need to be able to write this out
         self.xdriver = None
 
+        # Data for inhibiting the screensaver
+        self.dbus_session_connection = None
+        self.dbus_inhibit_id = None
+
     @property
     def bootloader(self):
         if not self._bootloader:
diff --git a/pyanaconda/safe_dbus.py b/pyanaconda/safe_dbus.py
index 22a7a04..e9ddfbb 100644
--- a/pyanaconda/safe_dbus.py
+++ b/pyanaconda/safe_dbus.py
@@ -20,12 +20,15 @@
 
 """Module providing thread-safe and mainloop-safe DBus operations."""
 
+import os
 from gi.repository import GLib, Gio
 from pyanaconda.constants import DEFAULT_DBUS_TIMEOUT
 
 DBUS_PROPS_IFACE = "org.freedesktop.DBus.Properties"
 DBUS_SYSTEM_BUS_ADDR = Gio.dbus_address_get_for_bus_sync(Gio.BusType.SYSTEM,
                                                          None)
+DBUS_SESSION_BUS_ADDR = Gio.dbus_address_get_for_bus_sync(Gio.BusType.SESSION,
+                                                          None)
 
 class SafeDBusError(Exception):
     """Class for exceptions defined in this module."""
@@ -131,3 +134,44 @@ def dbus_get_property_safe_sync(service, obj_path, iface, prop_name,
         raise DBusPropertyError(msg)
 
     return ret
+
+def dbus_get_session_connection():
+    """
+    Get a connection handle for the per-user-login-session message bus.
+
+    !!! RUN THIS EARLY !!! like, before any other threads start. Connections to
+    the session bus must be made with the effective UID of the login user,
+    which in live installs is not the UID of anaconda. This means we need to
+    call seteuid in this method, and doing that after threads have started will
+    probably do something weird.
+
+    Live installs use consolehelper to run as root, which sets the original
+    UID in $USERHELPER_UID.
+
+    :return: the session connection handle
+    :rtype: Gio.DBusConnection
+    :raise DBusCallError: if some DBus related error appears
+    :raise OSError: if unable to set the effective UID
+    """
+
+    old_euid = None
+    if "USERHELPER_UID" in os.environ:
+        old_euid = os.geteuid()
+        os.seteuid(int(os.environ["USERHELPER_UID"]))
+
+    try:
+        connection = Gio.DBusConnection.new_for_address_sync(
+                       DBUS_SESSION_BUS_ADDR,
+                       Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT|
+                       Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
+                       None, None)
+    except GLib.GError as gerr:
+        raise DBusCallError("Unable to connect to session bus: %s", gerr)
+    finally:
+        if old_euid is not None:
+            os.seteuid(old_euid)
+
+    if connection.is_closed():
+        raise DBusCallError("Connection is closed")
+
+    return connection
diff --git a/pyanaconda/screensaver.py b/pyanaconda/screensaver.py
new file mode 100644
index 0000000..ce62e5a
--- /dev/null
+++ b/pyanaconda/screensaver.py
@@ -0,0 +1,73 @@
+#
+# screensaver.py - Screensaver management methods and data
+#
+# Copyright (C) 2014 Red Hat, Inc.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): David Shea <dshea at redhat.com>
+#
+
+from pyanaconda.safe_dbus import dbus_call_safe_sync, DBusCallError
+from gi.repository import GLib
+
+import logging
+log = logging.getLogger("anaconda")
+
+SCREENSAVER_SERVICE = "org.freedesktop.ScreenSaver"
+SCREENSAVER_PATH    = "/org/freedesktop/ScreenSaver"
+SCREENSAVER_IFACE   = "org.freedesktop.ScreenSaver"
+
+SCREENSAVER_INHIBIT_METHOD   = "Inhibit"
+SCREENSAVER_UNINHIBIT_METHOD = "UnInhibit"
+
+SCREENSAVER_APPLICATION = "anaconda"
+SCREENSAVER_REASON      = "Installing"
+
+def inhibit_screensaver(connection):
+    """
+    Inhibit the screensaver idle timer.
+
+    :param connection: A handle for the session message bus
+    :type connection: Gio.DBusConnection
+    :return: The inhibit ID or None
+    :rtype: int or None
+    """
+
+    try:
+        inhibit_id = dbus_call_safe_sync(SCREENSAVER_SERVICE, SCREENSAVER_PATH, SCREENSAVER_IFACE,
+                SCREENSAVER_INHIBIT_METHOD, GLib.Variant('(ss)',
+                    (SCREENSAVER_APPLICATION, SCREENSAVER_REASON)),
+                connection)
+        return inhibit_id[0]
+    except DBusCallError as e:
+        log.info("Unable to inhibit the screensaver: %s", e)
+
+    return None
+
+def uninhibit_screensaver(connection, inhibit_id):
+    """
+    Re-enable the screensaver idle timer.
+
+    :param connection: A handle for the session message bus
+    :type connection: Gio.DBusConnection
+    :param inhibit_id: The ID returned by the inhibit method
+    :type inhibit_id: int
+    """
+
+    try:
+        dbus_call_safe_sync(SCREENSAVER_SERVICE, SCREENSAVER_PATH, SCREENSAVER_IFACE,
+                SCREENSAVER_UNINHIBIT_METHOD, GLib.Variant('(u)', (inhibit_id,)), connection)
+    except DBusCallError as e:
+        log.info("Unable to uninhibit the screensaver: %s", e)
-- 
1.8.5.3



More information about the anaconda-patches mailing list