--- 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@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)