Wofür ist D-Bus praktisch nützlich?

Wofür ist D-Bus praktisch nützlich?

dbussoll „eine einfache Möglichkeit für Anwendungen bieten, miteinander zu kommunizieren“.

Aber ich bin mir immer noch nicht sicher, wofür es praktisch nützlich ist. Ich habe noch nie eine Situation erlebt, in der es dbusnützlich ist. Ich sehe nur Warnungen, dass bei einer dbusKomponente Fehler aufgetreten sind, z. B. wenn ich Terminator von der Befehlszeile aus starte (damit ich Fehler sehen kann):

Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files

Ich habe den obigen Fehler behoben, indem ich NO_AT_BRIDGE=1zu hinzugefügt habe /etc/environment. Ich habe keine Ahnung, was das bewirkt.

Fast alle GUI-Anwendungen scheinen mit verknüpft zu sein dbus. Einige können ohne gestartet werden dbus, z. B.:

terminator --no-dbus

Ich sehe keinen Unterschied im Verhalten. Was soll aufhören zu funktionieren, wenn terminatorohne gestartet wird dbus?

Außerdem habe ich versucht, verschiedene DBus-Komponenten zu deaktivieren, um zu sehen, was nicht mehr funktioniert:

Ich habe es gelöscht, /etc/X11/Xsession.d/95dbus_update-activation-envnur um zu sehen, was passiert. Es enthielt den folgenden Code:

if [ -n "$DBUS_SESSION_BUS_ADDRESS" ] && [ -x "/usr/bin/dbus-update-activation-environment" ]; then
  # subshell so we can unset environment variables
  (
    # unset login-session-specifics
    unset XDG_SEAT
    unset XDG_SESSION_ID
    unset XDG_VTNR

    # tell dbus-daemon --session to put the Xsession's environment in activated services' environments
    dbus-update-activation-environment --verbose --all
  )
fi

Soweit ich das beurteilen kann, funktioniert alles gleich. Was war der Zweck des obigen Skripts?

In welcher Situation wäre es sinnvoll, wenn meine Anwendungen über miteinander kommunizieren würden dbus?

Gibt es Anwendungen, die ohne nicht funktionieren dbus?

Mein System ist Debian Buster und ich verwende eine reine Openbox-Umgebung (ohne Desktop-Umgebung wie Gnome oder KDE).

Antwort1

dbustut genau das, was Sie gesagt haben: Es ermöglicht eine bidirektionale Kommunikation zwischen Anwendungen.


Für Ihr konkretes Beispiel, das Sie erwähnt haben terminator. VonTerminator-Manpage, wir sehen:

--new-tab
    If this is specified and Terminator is already running, DBus 
    will be used to spawn a new tab in the first Terminator window.

Wenn Sie dies also von einem anderen Terminal aus tun (Konsole, Xterm, Gnome-Terminal):

$ terminator &
$ terminator --new-tab &

Sie werden sehen, dass der erste Befehl ein neues Fenster öffnet. Der zweite Befehl öffnet eine neue Registerkarte im ersten Fenster. Dies geschieht, indem der zweite Prozess dbus verwendet, um den ersten Prozess zu finden, ihn auffordert, eine neue Registerkarte zu öffnen und dann beendet wird.

Wenn Sie dies von einem anderen Terminal aus tun:

$ terminator --no-dbus &
$ terminator --new-tab &

Sie werden sehen, dass der erste Befehl ein neues Fenster öffnet. Der zweite Befehl kann den Dbus des ersten Fensters nicht finden und öffnet daher ein neues Fenster. Ich habe Terminator installiert, um dies zu testen, und es stimmt.

Außerdem vermute ich, dass Polkit betroffen wäre. Polkit verwendet dbus, um die Berechtigungen für GUI-Anwendungen zu erhöhen. Es ist wie das sudoder GUI-Welt. Wenn Sie in Gnome sind und sehen, dass der gesamte Bildschirm abgedeckt wird, während Sie nach dem Administratorkennwort gefragt werden, ist das Polkit in Aktion. Ich vermute, dass Sie diese Eingabeaufforderung in keiner GUI-Anwendung erhalten, die Sie starten, terminatorwenn Sie haben --no-dbus. Die Authentifizierung schlägt entweder fehl oder es wird auf eine Terminalauthentifizierung zurückgegriffen. Von terminatortry pkexec ls. Das wird lsmit erhöhten Berechtigungen ausgeführt. Sehen Sie nach, ob es mit und ohne die Option anders ist --no-dbus. Ich habe keinen Polkit-Agenten in meinem Fenstermanager (i3), also kann ich das nicht testen.


Mit dbus kenne ich mich hauptsächlich im Zusammenhang mit systemd aus, daher wird sich der Rest meiner Antwort daraus ergeben.

Gibt es Anwendungen, die ohne nicht funktionieren dbus?

Ja. Nehmen Sie systemctl. systemctl statusstellt eine Abfrage an "org.freedesktop.systemd1"und präsentiert diese Ihnen. systemctl startruft eine dbus-Methode auf und übergibt die Einheit als Argument an diese Methode. systemdempfängt den Aufruf und führt die Aktion aus.

Wenn Sie als Reaktion auf den Zustandswechsel einer systemd-Einheit (z. B. foo.service) Maßnahmen ergreifen möchten, können Sie einen Dateideskriptor für die Schnittstelle org.freedesktop.DBus.Propertiesmit Pfad /org/freedesktop/systemd1/unit/foo_2eserviceund Mitglied abrufen PropertiesChanged. Richten Sie einen inotifyauf diesem FD ein und Sie haben plötzlich eine Möglichkeit, auf das Starten, Stoppen, Fehlschlagen usw. eines Dienstes zu reagieren.

Wenn Sie sich ansehen möchten, was auf dem Systemd-DBus für eine bestimmte Einheit (z. B. ssh.service) verfügbar ist, versuchen Sie diesen Befehl:

busctl introspect \
    org.freedesktop.systemd1 \
    /org/freedesktop/systemd1/unit/ssh_2eservice
NAME                                TYPE      SIGNATURE       RESULT/VALUE                             FLAGS
org.freedesktop.DBus.Introspectable interface -               -                                        -
.Introspect                         method    -               s                                        -
org.freedesktop.DBus.Peer           interface -               -                                        -
.GetMachineId                       method    -               s                                        -
.Ping                               method    -               -                                        -
org.freedesktop.DBus.Properties     interface -               -                                        -
.Get                                method    ss              v                                        -
.GetAll                             method    s               a{sv}                                    -
.Set                                method    ssv             -                                        -
.PropertiesChanged                  signal    sa{sv}as        -                                        -
org.freedesktop.systemd1.Service    interface -               -                                        -
.AttachProcesses                    method    sau             -                                        -
.GetProcesses                       method    -               a(sus)                                   -
.AllowedCPUs                        property  ay              0                                        -
.AllowedMemoryNodes                 property  ay              0                                        -
.AmbientCapabilities                property  t               0                                        const
.AppArmorProfile                    property  (bs)            false ""                                 const
.BindPaths                          property  a(ssbt)         0                                        const
.BindReadOnlyPaths                  property  a(ssbt)         0                                        const
.BlockIOAccounting                  property  b               false                                    -
.BlockIODeviceWeight                property  a(st)           0                                        -
.BlockIOReadBandwidth               property  a(st)           0                                        -
.BlockIOWeight                      property  t               18446744073709551615                     -
.BlockIOWriteBandwidth              property  a(st)           0                                        -
.BusName                            property  s               ""                                       const
.CPUAccounting                      property  b               false                                    -
.CPUAffinity                        property  ay              0                                        const
.CPUAffinityFromNUMA                property  b               false                                    const
.CPUQuotaPerSecUSec                 property  t               18446744073709551615                     -
.CPUQuotaPeriodUSec                 property  t               18446744073709551615                     -
.CPUSchedulingPolicy                property  i               0                                        const
.CPUSchedulingPriority              property  i               0                                        const
.CPUSchedulingResetOnFork           property  b               false                                    const
.CPUShares                          property  t               18446744073709551615                     -
.CPUUsageNSec                       property  t               18446744073709551615                     -
.CPUWeight                          property  t               18446744073709551615                     -
.CacheDirectory                     property  as              0                                        const
.CacheDirectoryMode                 property  u               493                                      const
.CapabilityBoundingSet              property  t               18446744073709551615                     const
.CleanResult                        property  s               "success"                                emits-change
.ConfigurationDirectory             property  as              0                                        const
.ConfigurationDirectoryMode         property  u               493                                      const
.ControlGroup                       property  s               "/system.slice/ssh.service"              -
.ControlPID                         property  u               0                                        emits-change
.CoredumpFilter                     property  t               51                                       const
.DefaultMemoryLow                   property  t               0                                        -
.DefaultMemoryMin                   property  t               0                                        -
.Delegate                           property  b               false                                    -
.DelegateControllers                property  as              0                                        -
.DeviceAllow                        property  a(ss)           0                                        -
.DevicePolicy                       property  s               "auto"                                   -
.DisableControllers                 property  as              0                                        -
.DynamicUser                        property  b               false                                    const
.EffectiveCPUs                      property  ay              0                                        -
.EffectiveMemoryNodes               property  ay              0                                        -
.Environment                        property  as              0                                        const
.EnvironmentFiles                   property  a(sb)           1 "/etc/default/ssh" true                const
.ExecCondition                      property  a(sasbttttuii)  0                                        emits-invalidation
.ExecConditionEx                    property  a(sasasttttuii) 0                                        emits-invalidation
.ExecMainCode                       property  i               0                                        emits-change
.ExecMainExitTimestamp              property  t               0                                        emits-change
.ExecMainExitTimestampMonotonic     property  t               0                                        emits-change
.ExecMainPID                        property  u               835                                      emits-change
.ExecMainStartTimestamp             property  t               1597235861087584                         emits-change
.ExecMainStartTimestampMonotonic    property  t               5386565                                  emits-change
.ExecMainStatus                     property  i               0                                        emits-change
.ExecReload                         property  a(sasbttttuii)  2 "/usr/sbin/sshd" 2 "/usr/sbin/sshd" "… emits-invalidation
.ExecReloadEx                       property  a(sasasttttuii) 2 "/usr/sbin/sshd" 2 "/usr/sbin/sshd" "… emits-invalidation
.ExecStart                          property  a(sasbttttuii)  1 "/usr/sbin/sshd" 3 "/usr/sbin/sshd" "… emits-invalidation
.ExecStartEx                        property  a(sasasttttuii) 1 "/usr/sbin/sshd" 3 "/usr/sbin/sshd" "… emits-invalidation
.ExecStartPost                      property  a(sasbttttuii)  0                                        emits-invalidation
.ExecStartPostEx                    property  a(sasasttttuii) 0                                        emits-invalidation
.ExecStartPre                       property  a(sasbttttuii)  1 "/usr/sbin/sshd" 2 "/usr/sbin/sshd" "… emits-invalidation
.ExecStartPreEx                     property  a(sasasttttuii) 1 "/usr/sbin/sshd" 2 "/usr/sbin/sshd" "… emits-invalidation
.ExecStop                           property  a(sasbttttuii)  0                                        emits-invalidation
.ExecStopEx                         property  a(sasasttttuii) 0                                        emits-invalidation
.ExecStopPost                       property  a(sasbttttuii)  0                                        emits-invalidation
.ExecStopPostEx                     property  a(sasasttttuii) 0                                        emits-invalidation
.FileDescriptorStoreMax             property  u               0                                        const
.FinalKillSignal                    property  i               9                                        const
.GID                                property  u               4294967295                               emits-change
.Group                              property  s               ""                                       const
.GuessMainPID                       property  b               true                                     const
.IOAccounting                       property  b               false                                    -
.IODeviceLatencyTargetUSec          property  a(st)           0                                        -
.IODeviceWeight                     property  a(st)           0                                        -
.IOReadBandwidthMax                 property  a(st)           0                                        -
.IOReadBytes                        property  t               18446744073709551615                     -
.IOReadIOPSMax                      property  a(st)           0                                        -
.IOReadOperations                   property  t               18446744073709551615                     -
.IOSchedulingClass                  property  i               0                                        const
.IOSchedulingPriority               property  i               0                                        const
.IOWeight                           property  t               18446744073709551615                     -
.IOWriteBandwidthMax                property  a(st)           0                                        -
.IOWriteBytes                       property  t               18446744073709551615                     -
.IOWriteIOPSMax                     property  a(st)           0                                        -
.IOWriteOperations                  property  t               18446744073709551615                     -
.IPAccounting                       property  b               false                                    -
.IPAddressAllow                     property  a(iayu)         0                                        -
.IPAddressDeny                      property  a(iayu)         0                                        -
.IPEgressBytes                      property  t               18446744073709551615                     -
.IPEgressFilterPath                 property  as              0                                        -
.IPEgressPackets                    property  t               18446744073709551615                     -
.IPIngressBytes                     property  t               18446744073709551615                     -
.IPIngressFilterPath                property  as              0                                        -
.IPIngressPackets                   property  t               18446744073709551615                     -
.IgnoreSIGPIPE                      property  b               true                                     const
.InaccessiblePaths                  property  as              0                                        const
...skipping...
.CollectMode                        property  s               "inactive"                               const
.ConditionResult                    property  b               true                                     emits-change
.ConditionTimestamp                 property  t               1597235861034899                         emits-change
.ConditionTimestampMonotonic        property  t               5333881                                  emits-change
.Conditions                         property  a(sbbsi)        1 "ConditionPathExists" false true "/et… emits-invalidation
.ConflictedBy                       property  as              0                                        const
.Conflicts                          property  as              1 "shutdown.target"                      const
.ConsistsOf                         property  as              0                                        const
.DefaultDependencies                property  b               true                                     const
.Description                        property  s               "OpenBSD Secure Shell server"            const
.Documentation                      property  as              2 "man:sshd(8)" "man:sshd_config(5)"     const
.DropInPaths                        property  as              0                                        const
.FailureAction                      property  s               "none"                                   const
.FailureActionExitStatus            property  i               -1                                       const
.Following                          property  s               ""                                       -
.FragmentPath                       property  s               "/lib/systemd/system/ssh.service"        const
.FreezerState                       property  s               "running"                                emits-change
.Id                                 property  s               "ssh.service"                            const
.IgnoreOnIsolate                    property  b               false                                    const
.InactiveEnterTimestamp             property  t               0                                        emits-change
.InactiveEnterTimestampMonotonic    property  t               0                                        emits-change
.InactiveExitTimestamp              property  t               1597235861039525                         emits-change
.InactiveExitTimestampMonotonic     property  t               5338505                                  emits-change
.InvocationID                       property  ay              16 90 215 118 165 228 162 72 57 179 144… emits-change
.Job                                property  (uo)            0 "/"                                    emits-change
.JobRunningTimeoutUSec              property  t               18446744073709551615                     const
.JobTimeoutAction                   property  s               "none"                                   const
.JobTimeoutRebootArgument           property  s               ""                                       const
.JobTimeoutUSec                     property  t               18446744073709551615                     const
.JoinsNamespaceOf                   property  as              0                                        const
.LoadError                          property  (ss)            "" ""                                    const
.LoadState                          property  s               "loaded"                                 const
.Names                              property  as              2 "ssh.service" "sshd.service"           const
.NeedDaemonReload                   property  b               false                                    const
.OnFailure                          property  as              0                                        const
.OnFailureJobMode                   property  s               "replace"                                const
.PartOf                             property  as              0                                        const
.Perpetual                          property  b               false                                    const
.PropagatesReloadTo                 property  as              0                                        const
.RebootArgument                     property  s               ""                                       const
.Refs                               property  as              0                                        -
.RefuseManualStart                  property  b               false                                    const
.RefuseManualStop                   property  b               false                                    const
.ReloadPropagatedFrom               property  as              0                                        const
.RequiredBy                         property  as              0                                        const
.Requires                           property  as              3 "system.slice" "-.mount" "sysinit.tar… const
.RequiresMountsFor                  property  as              1 "/run/sshd"                            const
.Requisite                          property  as              0                                        const
.RequisiteOf                        property  as              0                                        const
.SourcePath                         property  s               ""                                       const
.StartLimitAction                   property  s               "none"                                   const
.StartLimitBurst                    property  u               5                                        const
.StartLimitIntervalUSec             property  t               10000000                                 const
.StateChangeTimestamp               property  t               1597235861208937                         emits-change
.StateChangeTimestampMonotonic      property  t               5507917                                  emits-change
.StopWhenUnneeded                   property  b               false                                    const
.SubState                           property  s               "running"                                emits-change
.SuccessAction                      property  s               "none"                                   const
.SuccessActionExitStatus            property  i               -1                                       const
.Transient                          property  b               false                                    const
.TriggeredBy                        property  as              0                                        const
.Triggers                           property  as              0                                        const
.UnitFilePreset                     property  s               "enabled"                                -
.UnitFileState                      property  s               "enabled"                                -
.WantedBy                           property  as              1 "multi-user.target"                    const
.Wants                              property  as              0                                        const

Daran können Sie erkennen, dass die DBus-Schnittstelle ziemlich leistungsstark ist.

Sie fragen sich vielleicht: Warum kommunizieren diese Anwendungen nicht einfach über Sockets oder Dateien?

DBus stellt eine gemeinsame Schnittstelle bereit. Sie benötigen keine unterschiedliche Logik, um Methoden aufzurufen oder Eigenschaften basierend auf der Anwendung zu überprüfen, mit der Sie kommunizieren. Sie müssen nur den Namen des Pfads kennen.

Ich habe es systemdals Beispiel verwendet, weil ich es so am besten verstehe, aber auf den meisten Desktops gibt es unzählige Verwendungsmöglichkeiten für dbus. Von der Authentifizierung bis zu den Anzeigeeinstellungen ist alles auf dbus verfügbar.

Antwort2

Es gibt bereits eine großartige, ausführliche Antwort zu D-Bus von @Stewart, aber ich möchte sie um eine allgemeine Idee zum Design von D-Bus ergänzen.

Die „traditionelle“ Art der Interprozesskommunikation (IPC) auf UNIX- und Linux-Systemen verwendet direkt Sockets, d. h. Prozess A öffnet sich /var/run/a.socketund Prozess B liest/schreibt. Dies funktioniert recht gut für eng verknüpfte Programme, die für die Kommunikation untereinander konzipiert wurden.

Möglicherweise möchten Sie jedoch eine Kommunikation zwischen den Prozessen zweier Programme ermöglichen, wobei Programm B beim Schreiben von Programm A noch nicht einmal existierte. D-Bus versucht, dieses Problem zu lösen, indem es Protokolle für die Kommunikation und Diensterkennung bereitstellt. Auf diese Weise muss nur die Schnittstelle b beim Schreiben von A vorhanden sein und Prozess B implementiert die Schnittstelle b.

Man könnte D-Bus daher als einen IPC-„Manager“ beschreiben.

In der Vergangenheit verwendeten Befehlszeilenschnittstellentools (CLI) normalerweise auch einen IPC-Manager, die Shell, um über Pipes mit beliebigen Programmen zu kommunizieren. Das Problem bei diesem Ansatz ist, dass er keine Datenvalidierung, standardisierten Protokolle usw. bietet. Er ist daher nur für Power-User verwendbar. GUI-Tools sollten dies im Allgemeinen „unsichtbar“ tun. Immer mehr CLI-Tools verwenden jedoch D-Bus, quasi als Alternative zu sudo(1). Sie können also als nicht privilegierter Benutzer „execute“ ausführen systemctl poweroffund werden zur Authentifizierung aufgefordert (dies kann mit der UAC unter Windows verglichen werden). Abhängig von Ihrem Polkit-Anbieter kann dies sogar eine GUI-Eingabeaufforderung sein. Zumindest theoretisch ist dieser Ansatz flexibler und ermöglicht feinkörnigere Berechtigungen und funktioniert ohne Setuid-Binärdateien (wie sudo). Dies kann als Sicherheitsfunktion angesehen werden.

Natürlich führt es als Abstraktion eine gewisse Komplexität ein (zumindest in den Abhängigkeiten der Programme). Je mehr Programme es jedoch (vernünftig) nutzen, desto weniger belastend ist dies. Ob Sie D-Bus und die aktuelle Entwicklung mögen, kann ich Ihnen nicht sagen. Moderne Betriebssysteme neigen jedoch dazu, viele wichtige Dienste außerhalb des Kernels bereitzustellen (und verschieben jetzt historische Kernel-Inhalte wieder, mikrokernelartig), da die Anforderungen der heutigen Computertechnik komplexer sind. Wenn Sie also „nur“ ein „einfaches“ Terminal möchten, könnte dies alles als „aufgebläht“ angesehen werden, aber die Industrie verlangt es aus gutem Grund und immer mehr Entwickler erkennen die Vorteile der Verwendung von D-Bus. Es ist der heutige Ersatz für die gute alte Pipe in Ihrer Shell (nicht die Systemschnittstelle, die D-Bus tatsächlich verwendet pipe()usw.).

Antwort3

Im traditionellen Unix gibt es normalerweise wenig Kommunikation zwischen laufenden Programmen. Jedes Programm läuft in einem völlig separaten Adressraum und interagiert nur mit dem Kernel. Dieses Modell ist einfach und robust, aber die Zugriffsberechtigungen sind für Desktopumgebungen meist zu grob, und die Implementierung einer feinkörnigen Zugriffskontrolle ist in vielen Fällen zu komplex.

Ein Beispiel, bei dem der Kernel die Zugriffskontrolle verfeinert, ist das Dateisystem. Nicht privilegierte Programme können eine Schreibanforderung an den Kernel senden, die in eine Schreibanforderung an die Festplatte übersetzt wird, ohne die Trennung zwischen Programmen zu verletzen. Dies ist jedoch eine ziemlich komplexe Ebene, und die Kontrolle ist für moderne Desktops, an die Benutzer möglicherweise einen USB-Stick anschließen möchten, immer noch nicht fein genug.

Für andere Funktionen, beispielsweise den Zugriff auf die Soundkarte, implementiert der Kernel nur ein einfaches Zugriffsmodell: Sobald ein Programm Zugriff auf die Soundkarte hat, kann es Ton wiedergeben und aufnehmen sowie die Mixersteuerung manipulieren, und es gibt keinen Mechanismus zum Widerrufen dieses Zugriffs außer der Beendigung des Programms.

In einer Desktop-Umgebung würden wir uns ein feineres Modell wünschen: Der Browser sollte das Mikrofon und die Webcam nur nach entsprechender Rückfrage beim Benutzer verwenden können. Wenn sich ein Benutzer abmeldet, sollten alle laufenden Programme den Mikrofonzugriff verlieren. Wenn der Benutzer jedoch eine Berechnung über Nacht ausführen möchte, sollte dies weiterhin möglich sein.

Das X Window-System ist ein guter Präzedenzfall für die Durchführung der Zugriffskontrolle in einem Benutzerprogramm. Die Darstellung eines Fensters erfolgt durch Senden einer Anforderung an ein anderes Programm, das den endgültigen angezeigten Bildschirminhalt berechnet. Ob die Anforderung in eine sichtbare Änderung des Bildschirminhalts umgesetzt wird, hängt von den aktuellen Zugriffskontrolleinstellungen ab: Wenn ein Fenster nach vorne gezogen wird, erhält dieses Programm Schreibzugriff auf einen Bereich des Bildschirms. Wenn es nach hinten gezogen wird, wird dieser Zugriff aufgehoben.

Desktopumgebungen stellen heutzutage viele dieser Vermittlerprogramme bereit, sodass für jede Funktion ein Kommunikationsprotokoll und eine Methode zum Öffnen eines Handles für dieses Programm vorhanden sein muss.

dbus bietet ein generisches Protokoll und einen Broker-Dienst, bei dem Programme eine Verbindung zu einem Programm anfordern können, das Zugriffskontrolle für bestimmte Funktionen bietet. Wenn das Zielprogramm bereits ausgeführt wird, leitet der Broker die Anforderungen einfach weiter. Wenn es nicht bereits ausgeführt wird, startet der Broker das Programm bei Bedarf, sofern er weiß, wie das geht.

Die entsprechende Funktionalität unter Windows ist COM/DCOM in Kombination mit der Registrierung.

Antwort4

Unter XFCE scheint alles noch zu funktionieren (einige Desktops, z. B. Gnome, sind möglicherweiseabhängiger vondbus). Ich führe Apps aus überFeuergefängnisDer Verlust der vermeintlichen Sicherheitsvorteile dbusist also kein wirklicher Grund zur Sorge.

Die folgenden Linux-Distributionen scheinen ohne dbus& problemlos zu laufen systemd:

Es wird kleinere Probleme geben, aber mit einigermaßen Fachkenntnis lassen sie sich leicht beheben.

verwandte Informationen