In der neuen Version von systemd v221 führen wir die SD -Bus- API ein , die mit der stabilen Version von systemd geliefert wird . sd-bus ist unsere minimale D-Bus IPC C- Bibliothek , die sowohl klassischen Socket-basierten D-Bus als auch kdbus als Backend unterstützt . Die Bibliothek ist seit einiger Zeit Teil von systemd, wurde jedoch nur intern verwendet, da wir Änderungen an der API frei vornehmen wollten, ohne externe Benutzer zu beeinträchtigen. Ab Version 221 sind wir jedoch zuversichtlich, eine stabile API erstellt zu haben.
In diesem Beitrag gebe ich einen Überblick über die SD-Bus-Bibliothek, eine kurze Zusammenfassung der Grundlagen von D-Bus und seiner Konzepte sowie einige einfache Beispiele für das Schreiben von D-Bus-Clients und -Diensten.
Was ist D-Bus?
Beginnen wir mit einer kurzen Erinnerung daran, was D-Bus wirklich ist. Es ist ein leistungsstarkes Allzweck-IPC-System für Linux und andere Betriebssysteme. Es definiert Konzepte wie Busse, Objekte, Schnittstellen, Methoden, Signale, Eigenschaften. Es bietet Ihnen eine detaillierte Zugriffskontrolle, ein umfangreiches System, einfache Erkennung, Selbstdiagnose, Überwachung, zuverlässiges Multicasting, Dienststart, Datei-Deskriptor-Übertragungen und vieles mehr. Es gibt Bindungen für viele der Programmiersprachen, die unter Linux verwendet werden.
D-Bus ist seit über 10 Jahren eine Kernkomponente von Linux-Systemen. Es ist bei weitem das am weitesten verbreitete lokale IPC-System auf hoher Ebene unter Linux. Systemd ist seit seiner Gründung das IPC-System, in dem es seine Schnittstellen verfügbar macht. Und noch vor systemd war es das IPC-System, das Upstart für seine Schnittstellen verwendete. Es wird von GNOME, KDE und vielen Systemkomponenten verwendet.
D-Bus , . , . , , , - , . ( kdbus .)
D-Bus IPC AF_UNIX. TCP/IP. , D-Bus TCP . D-Bus , ssh, . systemd , API .
D-Bus: , , AF_UNIX FIFO UNIX . , D-Bus -: AF_UNIX/FIFO D-Bus , TCP HTTP/REST. , AF_UNIX/FIFO , D-Bus , , , , .
10- D-Bus , , , - ( , kdbus, sd-bus), , , . IPC, , D-Bus, , , D-Bus.
: D-Bus . Linux IPC, . , D-Bus , , , .
sd-bus?
, sd-bus, D-Bus .
D-Bus: libdbus, D-Bus, GDBus, GLib, GNOME.
libdbus , . , . , API , API , . , , . , (, OOM , ) , Windows UNIX.
GDBus - . GLib/GObject libdbus. GDBus , libdbus. libdbus, , GObject D-Bus GObject. D-Bus GVariant, GLib. GLib, , D-Bus , libdbus.
sd-bus , libdbus, GDBus. libdbus GDBus: , , , , , , , GDBus/GLib/GObject/GVariant. systemd, OOM. , , kdbus D-Bus («dbus1»). , kdbus, dbus1, - , . libdbus GDBus, sd-bus, Linux Linux , . , ( ): libdbus, GDBus . ( ), . , : , kdbus , , , libdbus GDBus.
, , API :
GLib/GObject, GDBus .
, Linux, Windows, Mac OS UNIX, GDBus ( GLib/GObject), libdbus ( ).
sd-bus.
( C++, . : Qt, QtDBus API D-Bus, libdbus.)
D-Bus
D-Bus . , . . :
- , IPC. : , , ; , , , . ( , , , , , , , .)
- , IPC API . . ,
org.freedesktop.NetworkManager
- , API- NetworkManager,org.freedesktop.login1
- , API-systemd-logind
.
- , IPC API . , , , . , . .
- . , , - . - , , . , D-Bus , , . :
/org/freedesktop/login1
- «»org.freedesktop.login1
(, , systemd-logind). , . , ,systemd-logind
/org/freedesktop/login1/session
, :/org/freedesktop/login1/session/_7
,/org/freedesktop/login1/session./_55
. , .
, , . - , ( ), . D-Bus , , Java, . , . , . (, , , , .) , , , . ,
org.freedesktop.DBus.Introspectable
,org.freedesktop.DBus.Peer
org.freedesktop.DBus.Properties
.
. «» «», - , Java. D-Bus , . D-Bus . , , . ( ) CamelCase. ,
systemd-logind
ActivateSession
org.freedesktop.login1.Manager
,/org/freedesktop/login1
org.freedesktop.login1
.
, ( , , . ). , . . , ,
s
u
32- , ,as
a(sb)
, . . D-Bus, .ActivateSession
( , ,s
) ( , , ). , , . .
- , D-Bus. , . . , , . , , - . , . / --, -- ( , , --). :
systemd-logind
SessionNew
- , ,SessionRemoved
, .
- , D-Bus. , , C#. . , , . :
systemd-logind
Docked
b
( ). ,systemd-logind
, - ( ).
D-Bus . , . . , -, HTTP REST. HTTP- D-Bus:
HTTP-, . , VPN. , , . «» D-Bus.
HTTP- . .
HTTP- URL-. URL-, ( , «/») D-Bus.
«» URL- ( , , , ), , . D-Bus .
, HTTP- «?», D-Bus.
, HTTP- D-Bus . , , , .
. , , .
systemd busctl, D-Bus. , . ( --user, ):
$ busctl NAME PID PROCESS USER CONNECTION UNIT SESSION DESCRIPTION :1.1 1 systemd root :1.1 - - - :1.11 705 NetworkManager root :1.11 NetworkManager.service - - :1.14 744 gdm root :1.14 gdm.service - - :1.4 708 systemd-logind root :1.4 systemd-logind.service - - :1.7200 17563 busctl lennart :1.7200 session-1.scope 1 - […] org.freedesktop.NetworkManager 705 NetworkManager root :1.11 NetworkManager.service - - org.freedesktop.login1 708 systemd-logind root :1.4 systemd-logind.service - - org.freedesktop.systemd1 1 systemd root :1.1 - - - org.gnome.DisplayManager 744 gdm root :1.14 gdm.service - - […]
( , ).
, . , ":1.11". D-Bus . , , , . , IP-. , , busctl, . , ( ; , ). DNS, , IP- , , . , , IP-, , . ( , , , IP- , ).
, . , (, , systemd).
. , org.freedesktop.login1:
$ busctl tree org.freedesktop.login1 └─/org/freedesktop/login1 ├─/org/freedesktop/login1/seat │ ├─/org/freedesktop/login1/seat/seat0 │ └─/org/freedesktop/login1/seat/self ├─/org/freedesktop/login1/session │ ├─/org/freedesktop/login1/session/_31 │ └─/org/freedesktop/login1/session/self └─/org/freedesktop/login1/user ├─/org/freedesktop/login1/user/_1000 └─/org/freedesktop/login1/user/self
, ? , , : TAB, . D-Bus!
, . . , , , :
$ busctl introspect org.freedesktop.login1 /org/freedesktop/login1/session/_31
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.login1.Session interface - - -
.Activate method - - -
.Kill method si - -
.Lock method - - -
.PauseDeviceComplete method uu - -
.ReleaseControl method - - -
.ReleaseDevice method uu - -
.SetIdleHint method b - -
.TakeControl method b - -
.TakeDevice method uu hb -
.Terminate method - - -
.Unlock method - - -
.Active property b true emits-change
.Audit property u 1 const
.Class property s "user" const
.Desktop property s "" const
.Display property s "" const
.Id property s "1" const
.IdleHint property b true emits-change
.IdleSinceHint property t 1434494624206001 emits-change
.IdleSinceHintMonotonic property t 0 emits-change
.Leader property u 762 const
.Name property s "lennart" const
.Remote property b false const
.RemoteHost property s "" const
.RemoteUser property s "" const
.Scope property s "session-1.scope" const
.Seat property (so) "seat0" "/org/freedesktop/login1/seat... const
.Service property s "gdm-autologin" const
.State property s "active" -
.TTY property s "/dev/tty1" const
.Timestamp property t 1434494630344367 const
.TimestampMonotonic property t 34814579 const
.Type property s "x11" const
.User property (uo) 1000 "/org/freedesktop/login1/user/_1... const
.VTNr property u 1 const
.Lock signal - - -
.PauseDevice signal uus - -
.ResumeDevice signal uuh - -
.Unlock signal - - -
, busctl , , TAB. , , , systemd-logind
. , . . . , . . .
. : - :
# busctl call org.freedesktop.login1 /org/freedesktop/login1/session/_31 org.freedesktop.login1.Session Lock
, , : . - , - , TAB. Lock
, . , , Enter , ( , systemd-logind. GNOME , KDE ).
Lock
, . , . , systemd :
# busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager StartUnit ss "cups.service" "replace"
o "/org/freedesktop/systemd1/job/42684"
, , ( , , ). - . , , . StartUnit systemd , , . . , : ( o ), .
busctl
. , D-Bus ( .cap
Wireshark!) . , sd-bus, busctl
, , .
busctl
( ) API sd-bus. , sd-bus. , . kdbus, D-Bus, !
sd-bus
! , sd-bus.
API sd-bus sd-bus.h.
, .
kdbus, dbus1 .
ssh .
. 34 , PID .
, , , .
, , .
D-Bus UNIX ( ), D-Bus Linux.
, . .
sd-bus
. :
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
int main(int argc, char *argv[]) {
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *m = NULL;
sd_bus *bus = NULL;
const char *path;
int r;
/* Connect to the system bus */
r = sd_bus_open_system(&bus);
if (r < 0) {
fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
goto finish;
}
/* Issue the method call and store the respons message in m */
r = sd_bus_call_method(bus,
"org.freedesktop.systemd1", /* service to contact */
"/org/freedesktop/systemd1", /* object path */
"org.freedesktop.systemd1.Manager", /* interface name */
"StartUnit", /* method name */
&error, /* object to return error in */
&m, /* return message on success */
"ss", /* input signature */
"cups.service", /* first argument */
"replace"); /* second argument */
if (r < 0) {
fprintf(stderr, "Failed to issue method call: %s\n", error.message);
goto finish;
}
/* Parse the response message */
r = sd_bus_message_read(m, "o", &path);
if (r < 0) {
fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
goto finish;
}
printf("Queued service job as %s.\n", path);
finish:
sd_bus_error_free(&error);
sd_bus_message_unref(m);
sd_bus_unref(bus);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
bus-client.c
, :
$ gcc bus-client.c -o bus-client `pkg-config --cflags --libs libsystemd`
bus-client
, . root, StartUnit
:
# ./bus-client
Queued service job as /org/freedesktop/systemd1/job/3586.
. , . busctl
, . , . , D-Bus sd-bus. , , , sd-bus.
sd-bus
, - . , . . , : 64- , 64- .
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <systemd/sd-bus.h>
static int method_multiply(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
int64_t x, y;
int r;
/* Read the parameters */
r = sd_bus_message_read(m, "xx", &x, &y);
if (r < 0) {
fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));
return r;
}
/* Reply with the response */
return sd_bus_reply_method_return(m, "x", x * y);
}
static int method_divide(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
int64_t x, y;
int r;
/* Read the parameters */
r = sd_bus_message_read(m, "xx", &x, &y);
if (r < 0) {
fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));
return r;
}
/* Return an error on division by zero */
if (y == 0) {
sd_bus_error_set_const(ret_error, "net.poettering.DivisionByZero", "Sorry, can't allow division by zero.");
return -EINVAL;
}
return sd_bus_reply_method_return(m, "x", x / y);
}
/* The vtable of our little object, implements the net.poettering.Calculator interface */
static const sd_bus_vtable calculator_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Multiply", "xx", "x", method_multiply, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Divide", "xx", "x", method_divide, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
int main(int argc, char *argv[]) {
sd_bus_slot *slot = NULL;
sd_bus *bus = NULL;
int r;
/* Connect to the user bus this time */
r = sd_bus_open_user(&bus);
if (r < 0) {
fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
goto finish;
}
/* Install the object */
r = sd_bus_add_object_vtable(bus,
&slot,
"/net/poettering/Calculator", /* object path */
"net.poettering.Calculator", /* interface name */
calculator_vtable,
NULL);
if (r < 0) {
fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r));
goto finish;
}
/* Take a well-known service name so that clients can find us */
r = sd_bus_request_name(bus, "net.poettering.Calculator", 0);
if (r < 0) {
fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
goto finish;
}
for (;;) {
/* Process requests */
r = sd_bus_process(bus, NULL);
if (r < 0) {
fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
goto finish;
}
if (r > 0) /* we processed a request, try to process another one, right-away */
continue;
/* Wait for the next request to process */
r = sd_bus_wait(bus, (uint64_t) -1);
if (r < 0) {
fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
goto finish;
}
}
finish:
sd_bus_slot_unref(slot);
sd_bus_unref(bus);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
bus-service.c
, :
$ gcc bus-service.c -o bus-service `pkg-config --cflags --libs libsystemd`
:
$ ./bus-service
. , , , . : , . : , , , . , --user busctl. .
$ busctl --user tree net.poettering.Calculator └─/net/poettering/Calculator
, , , , . , :
$ busctl --user introspect net.poettering.Calculator /net/poettering/Calculator NAME TYPE SIGNATURE RESULT/VALUE FLAGS net.poettering.Calculator interface - - - .Divide method xx x - .Multiply method xx x - 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 - -
, sd-bus . , , , ! , «xx» ( 64- ) «x». ! ?
$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Multiply xx 5 7 x 35
! 5 7, 35! :
$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Divide xx 99 17 x 5
! ! ! :
$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Divide xx 43 0
Sorry, can't allow division by zero.
! . , , .
, . , , , , , . D-Bus sd-bus, ...
Hoffe, dieser Beitrag war hilfreich für Sie. Wenn Sie daran interessiert sind, SD-Bus für Ihre eigenen Programme zu verwenden, hoffe ich, dass es Ihnen hilft. Wenn Sie weitere Fragen haben, schauen Sie sich die (unvollständigen) Manpages an und fragen Sie uns im IRC oder auf der systemd-Mailingliste. Wenn Sie weitere Beispiele benötigen, werfen Sie einen Blick auf den systemd-Quellbaum. Alle vielen Busdienste von systemd verwenden SD-Bus in großem Umfang.