Linux System mit D-Bus herunterfahren

Code-Stücke können hier veröffentlicht werden.
Antworten
Ubuntuxer
User
Beiträge: 42
Registriert: Donnerstag 17. April 2008, 15:49

Ich möchte euch eine Möglichkeit zeigen unter Linux den Computer ohne Root-Rechte herunterzufahren. Diese Lösung müsste mit jeder Distribution funktionieren.

Code: Alles auswählen

#!/usr/bin/env python
 
import sys, dbus

def shutdown():
    bus = dbus.SystemBus()
    try:
        remote_object = bus.get_object('org.freedesktop.Hal',
                                    '/org/freedesktop/Hal/devices/computer')
        props = remote_object.Shutdown(dbus_interface='org.freedesktop.Hal.Device.SystemPowerManagement')
    except dbus.exceptions.DBusException, e:
        print e
 
if __name__ == "__main__":
    shutdown()
tordmor
User
Beiträge: 100
Registriert: Donnerstag 20. November 2008, 10:29
Wohnort: Stuttgart

:shock:

Das hat sogar als user nobody funktioniert.
http://www.felix-benner.com
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

tordmor hat geschrieben::shock:
Naja, irgendwie muss man als Benutzer in der grafischen Oberfläche ja herunterfahren können. Das ist halt der Grund, warum dort nicht nach dem Passwort gefragt wird.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

User oder nobody ist doch irgendwie was anderes, oder?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
lunar

nobody ist ein Benutzerkonto wie jedes andere. Ein spezielles "Gast"-Konto wie unter Windows gibt es nicht, nobody ist nur eine Konvention für Dienste, die keine Rechte benötigen, und hat per se nicht weniger Rechte als ein "normales" Konto.

Im Allgemeinen ist HAL auch nicht der Weg zum Herunterfahren, sondern nur der allerletzte Ausweg. Grundsätzlich muss das nicht funktionieren, denn eigentlich ist die systemweite Sitzungsverwaltung imho heute Sache von ConsoleKit. Zudem umgeht es sämtliche Sitzungsverwaltung der laufenden Desktop-Umgebung, so dass unter Umständen bei der nächsten Anmeldung die Sitzung nicht korrekt wiederhergestellt werden kann.

Man sollte also vorher immer mindestens die Sitzungsverwaltungsdienste von Gnome (org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.RequestShutdown) und KDE (org.kde.ksmserver /KSMServer org.kde.KSMServerInterface.logout) versuchen.
Ubuntuxer
User
Beiträge: 42
Registriert: Donnerstag 17. April 2008, 15:49

Ich hab nun mal Lunars Verbesserungsvorschlag umgesetzt:

Code: Alles auswählen

#!/usr/bin/env python

import sys, dbus
import os

def shutdown():
    session = os.environ['DESKTOP_SESSION']
    if (session == 'gnome'):
        try:
            bus = dbus.SessionBus()
            remote_object = bus.get_object('org.gnome.SessionManager',
                                        '/org/gnome/SessionManager')
            props = remote_object.Shutdown(dbus_interface='org.gnome.SessionManager.RequestShutdown')
        except dbus.exceptions.DBusException, e:
            print e
    elif (session == 'kde'):
        try:
            bus = dbus.SessionBus()
            remote_object = bus.get_object('org.kde.ksmserver', '/KSMServer')
            props = remote_object.Shutdown(dbus_interface='org.kde.KSMServerInterface.logout')
        except dbus.exceptions.DBusException, e:
            print e
    else:
        try:
            bus = dbus.SystemBus()
            remote_object = bus.get_object('org.freedesktop.Hal',
                                        '/org/freedesktop/Hal/devices/computer')
            props = remote_object.Shutdown(dbus_interface='org.freedesktop.Hal.Device.SystemPowerManagement')
        except dbus.exceptions.DBusException, e:
            print e

if __name__ == "__main__":
    shutdown()

EDIT: Das Code-Beispiel funktioniert nicht richtig.
Zuletzt geändert von Ubuntuxer am Montag 12. April 2010, 14:01, insgesamt 1-mal geändert.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

vielleicht besser mit .get() auf os.environ zugreifen

Warum die klammern bei if ?

Warum Exception Abfangen, wenn sieh eh nur ausgegeben werden?

Code kann man zusammen legen, schau dir mal an, worin die IFs sich wirklich unterscheiden ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Ubuntuxer
User
Beiträge: 42
Registriert: Donnerstag 17. April 2008, 15:49

Ich steh grad auf dem Schlauch, welchen Code kann ich sinnvoll zusammenlegen? :oops:
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Nur als Hinweis, bei mir ergibt

Code: Alles auswählen

In [2]: os.environ.get('DESKTOP_SESSION')
Out[2]: 'default'
Arch Linux, KDE 4.4.2, Python 2.6.5

Gruß Whitie
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python
import os
import dbus

DBUS_OBJECTS = {
    'gnome' : {
        'bus'       : 'org.gnome.SessionManager',
        'object'    : '/org/gnome/SessionManager',
        'interface' : 'org.gnome.SessionManager.RequestShutdown',
        'bus_class' : dbus.SessionBus
    },
    'kde' : {
        'bus'       : 'org.kde.ksmserver',
        'object'    : '/KSMServer',
        'interface' : 'org.kde.KSMServerInterface.logout',
        'bus_class' : dbus.SessionBus
    },
    'default' : {
        'bus'       : 'org.freedesktop.Hal',
        'object'    : '/org/freedesktop/Hal/devices/computer',
        'interface' : 'org.freedesktop.Hal.Device.SystemPowerManagement'
        'bus_class' : dbus.SystemBus
    }
}

def shutdown():
    desktop_environment = os.environ['DESKTOP_SESSION']

    environment_data = (DBUS_OBJECTS.get(desktop_environment)
                        or DBUS_OBJECTS['default'])

    bus = environment_data['bus_class']()
    remote_object = bus.get_object(environment_data['bus'], environment_data['object'])

    remote_object.Shutdown(dbus_interface=environment_data['interface'])

if __name__ == "__main__":
    shutdown()
lunar

Es ist völlig unnötig, hier die Umgebungsvariable zu prüfen. Es ist einfacher und zuverlässiger, der Reihe nach alle möglichen Dienste zu probieren, denn eine Sitzungsverwaltung läuft in der Regel nur, wenn eine vollwertige Desktop-Sitzung gestartet wurde.

Davon abgesehen ist DESKTOP_SESSION keine zuverlässige Quelle, weil diese Variable vom Display-Manager gesetzt wird. Wenn, dann sollte man auf die Existenz von "$KDE_FULL_SESSION=true" bzw. "$GNOME_DESKTOP_SESSION_ID" prüfen.

Im Übrigen funktioniert der "logout"-Aufruf für KDE so auch nicht, weil die Methode drei Parameter entgegen nimmt, welche bestimmen, wie das System heruntergefahren werden soll.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Zum "sanften" Rebooten unter Gnome:

Code: Alles auswählen

dbus.SessionBus().get_object('org.gnome.SessionManager',
                             '/org/gnome/SessionManager').RequestReboot()
Analog dazu funktioniert bei mir RequestShutdown. Bei dem vorher gezeigten Code gab's nämlich ne DBusException.
lunar

Das liegt daran, dass meine Vorredner mein Beitrag missverstanden haben. Die Methode heißt natürlich nicht immer "Shutdown" :roll:
Ubuntuxer
User
Beiträge: 42
Registriert: Donnerstag 17. April 2008, 15:49

Das liegt daran, dass meine Vorredner mein Beitrag missverstanden haben. Die Methode heißt natürlich nicht immer "Shutdown"
Ich hab mir jetzt mal die Dokumentation angesehen, das folgende Beispiel sollte funktionieren, auch wenn ich es nicht unter KDE getestet habe.:oops:

Das Zusammenfassen des doppelten Codes über das Dictionary finde ich nicht wirklich praktikabel und sinnvoll. Ich denke es erhöht nicht die lesbarkeit des Codes.

Code: Alles auswählen

#!/usr/bin/env python

import dbus
import os

def shutdown():
    try:
        bus = dbus.SessionBus()
        remote_object = bus.get_object('org.gnome.SessionManager',
                                    '/org/gnome/SessionManager')
        remote_object.RequestShutdown()
    except dbus.exceptions.DBusException:
        pass
    else:
        return
    try:
        bus = dbus.SessionBus()
        remote_object = bus.get_object('org.kde.ksmserver', '/KSMServer')
        remote_object.logout(0, 0, 2, dbus_interface='org.kde.KSMServerInterface')
    except dbus.exceptions.DBusException:
        pass
    else:
        return
    try:
        bus = dbus.SystemBus()
        remote_object = bus.get_object('org.freedesktop.Hal',
                                    '/org/freedesktop/Hal/devices/computer')
        remote_object.Shutdown(dbus_interface='org.freedesktop.Hal.Device.SystemPowerManagement')
    except dbus.exceptions.DBusException:
        print "Shutdown failed."
if __name__ == "__main__":
    shutdown()
lunar

Ich denke doch, dass es sinnvoll ist. Jede Wette, dass Du beim Verfassen dieses Beispiels die einzelnen Abschnitt kopiert, wieder eingefügt und anschließend geändert hast ;)
Antworten