
dbus
soll „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 dbus
nützlich ist. Ich sehe nur Warnungen, dass bei einer dbus
Komponente 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=1
zu 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 terminator
ohne 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-env
nur 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
dbus
tut 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 sudo
der 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, terminator
wenn Sie haben --no-dbus
. Die Authentifizierung schlägt entweder fehl oder es wird auf eine Terminalauthentifizierung zurückgegriffen. Von terminator
try pkexec ls
. Das wird ls
mit 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 status
stellt eine Abfrage an "org.freedesktop.systemd1"
und präsentiert diese Ihnen. systemctl start
ruft eine dbus-Methode auf und übergibt die Einheit als Argument an diese Methode. systemd
empfä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.Properties
mit Pfad /org/freedesktop/systemd1/unit/foo_2eservice
und Mitglied abrufen PropertiesChanged
. Richten Sie einen inotify
auf 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 systemd
als 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.socket
und 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 poweroff
und 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
- Ich ermöglicheAbonnierendas kaputt gehen soll
dbus
. - ich auchändern Sie die einzigartige
machine-id
dasdbus
bei jedem Booten generiert wird überrc.local
(devuan generiert es auch bei jedem Booten)
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 dbus
ist also kein wirklicher Grund zur Sorge.
Die folgenden Linux-Distributionen scheinen ohne dbus
& problemlos zu laufen systemd
:
- Abonnieren(Debian-basiert)
- artix(Basiert auf Arch Linux)
- antix(Debian-basiert)
Es wird kleinere Probleme geben, aber mit einigermaßen Fachkenntnis lassen sie sich leicht beheben.