Browse Source

bus: add basic implementation of a native bus client library

keep-around/ba91431154ad7bac82ddf0a540ec1b40db62d782
Lennart Poettering 10 years ago
parent
commit
de1c301ed1
  1. 2
      .gitignore
  2. 44
      Makefile.am
  3. 4
      configure.ac
  4. 1
      src/libsystemd-bus/Makefile
  5. 322
      src/libsystemd-bus/bus-control.c
  6. 166
      src/libsystemd-bus/bus-error.c
  7. 27
      src/libsystemd-bus/bus-error.h
  8. 22
      src/libsystemd-bus/bus-internal.c
  9. 101
      src/libsystemd-bus/bus-internal.h
  10. 1413
      src/libsystemd-bus/bus-message.c
  11. 120
      src/libsystemd-bus/bus-message.h
  12. 141
      src/libsystemd-bus/bus-signature.c
  13. 31
      src/libsystemd-bus/bus-signature.h
  14. 163
      src/libsystemd-bus/bus-type.c
  15. 34
      src/libsystemd-bus/bus-type.h
  16. 68
      src/libsystemd-bus/busctl.c
  17. 96
      src/libsystemd-bus/sd-bus-protocol.h
  18. 1437
      src/libsystemd-bus/sd-bus.c
  19. 135
      src/libsystemd-bus/sd-bus.h
  20. 129
      src/libsystemd-bus/test-bus-marshal.c
  21. 74
      src/libsystemd-bus/test-bus-signature.c

2
.gitignore

@ -80,6 +80,8 @@
/systemd-user-sessions
/systemd-vconsole-setup
/tags
/test-bus-marshal
/test-bus-signature
/test-calendarspec
/test-catalog
/test-cgroup

44
Makefile.am

@ -1638,6 +1638,50 @@ EXTRA_DIST += \
src/libsystemd-daemon/libsystemd-daemon.pc.in \
src/libsystemd-daemon/libsystemd-daemon.sym
# ------------------------------------------------------------------------------
libsystemd_bus_la_SOURCES = \
src/libsystemd-bus/sd-bus.c \
src/libsystemd-bus/sd-bus.h \
src/libsystemd-bus/sd-bus-protocol.h \
src/libsystemd-bus/bus-control.c \
src/libsystemd-bus/bus-error.c \
src/libsystemd-bus/bus-error.h \
src/libsystemd-bus/bus-internal.c \
src/libsystemd-bus/bus-internal.h \
src/libsystemd-bus/bus-message.c \
src/libsystemd-bus/bus-message.h \
src/libsystemd-bus/bus-signature.c \
src/libsystemd-bus/bus-type.c \
src/libsystemd-bus/bus-type.h
noinst_LTLIBRARIES += \
libsystemd-bus.la
noinst_tests += \
test-bus-marshal \
test-bus-signature
test_bus_marshal_SOURCES = \
src/libsystemd-bus/test-bus-marshal.c
test_bus_marshal_LDADD = \
libsystemd-shared.la \
libsystemd-bus.la \
$(GLIB_LIBS) \
$(DBUS_LIBS)
test_bus_marshal_CFLAGS = \
$(AM_CFLAGS) \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS)
test_bus_signature_SOURCES = \
src/libsystemd-bus/test-bus-signature.c
test_bus_signature_LDADD = \
libsystemd-shared.la \
libsystemd-bus.la
# ------------------------------------------------------------------------------
if ENABLE_GTK_DOC
SUBDIRS += \

4
configure.ac

@ -724,9 +724,11 @@ AM_CONDITIONAL(ENABLE_FIRMWARE, [test "x${FIRMWARE_PATH}" != "x"])
AC_ARG_ENABLE([gudev],
AS_HELP_STRING([--disable-gudev], [disable Gobject libudev support @<:@default=enabled@:>@]),
[], [enable_gudev=yes])
AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0]) ])
AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0 gio-2.0]) ])
AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"])
AS_IF([test "x$enable_gudev" = "xyes"], [ AC_DEFINE(HAVE_GLIB, 1, [Define if glib is available]) ])
# ------------------------------------------------------------------------------
AC_ARG_ENABLE([keymap],
AS_HELP_STRING([--disable-keymap], [disable keymap fixup support @<:@default=enabled@:>@]),

1
src/libsystemd-bus/Makefile

@ -0,0 +1 @@
../Makefile

322
src/libsystemd-bus/bus-control.c

@ -0,0 +1,322 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stddef.h>
#include <errno.h>
#include "strv.h"
#include "sd-bus.h"
#include "bus-internal.h"
#include "bus-message.h"
const char *sd_bus_get_unique_name(sd_bus *bus) {
if (!bus)
return NULL;
return bus->unique_name;
}
int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
uint32_t ret;
int r;
if (!bus)
return -EINVAL;
if (!name)
return -EINVAL;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"RequestName",
&m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "su", name, flags);
if (r < 0)
return r;
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
if (r < 0)
return r;
r = sd_bus_message_read(reply, "u", &ret);
if (r < 0)
return r;
return ret;
}
int sd_bus_release_name(sd_bus *bus, const char *name) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
uint32_t ret;
int r;
if (!bus)
return -EINVAL;
if (!name)
return -EINVAL;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"ReleaseName",
&m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "s", name);
if (r < 0)
return r;
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
if (r < 0)
return r;
r = sd_bus_message_read(reply, "u", &ret);
if (r < 0)
return r;
return ret;
}
int sd_bus_list_names(sd_bus *bus, char ***l) {
_cleanup_bus_message_unref_ sd_bus_message *m1 = NULL, *reply1 = NULL, *m2 = NULL, *reply2 = NULL;
_cleanup_strv_free_ char **a = NULL, **b = NULL;
char **x = NULL;
int r;
if (!bus)
return -EINVAL;
if (!l)
return -EINVAL;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"ListNames",
&m1);
if (r < 0)
return r;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"ListActivatableNames",
&m2);
if (r < 0)
return r;
r = sd_bus_send_with_reply_and_block(bus, m1, (uint64_t) -1, NULL, &reply1);
if (r < 0)
return r;
r = sd_bus_send_with_reply_and_block(bus, m2, (uint64_t) -1, NULL, &reply2);
if (r < 0)
return r;
r = sd_bus_message_read(reply1, "as", &a);
if (r < 0)
return r;
r = sd_bus_message_read(reply2, "as", &b);
if (r < 0)
return r;
x = strv_merge(a, b);
if (!x)
return -ENOMEM;
*l = strv_uniq(x);
return 0;
}
int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
int r;
if (!bus)
return -EINVAL;
if (!name)
return -EINVAL;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"GetNameOwner",
&m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "s", name);
if (r < 0)
return r;
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
if (r < 0)
return r;
return sd_bus_message_read(reply, "s", owner);
}
int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
uint32_t u;
int r;
if (!bus)
return -EINVAL;
if (!name)
return -EINVAL;
if (!uid)
return -EINVAL;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"GetConnectionUnixUser",
&m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "s", name);
if (r < 0)
return r;
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
if (r < 0)
return r;
r = sd_bus_message_read(reply, "u", &u);
if (r < 0)
return r;
*uid = (uid_t) u;
return 0;
}
int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
uint32_t u;
int r;
if (!bus)
return -EINVAL;
if (!name)
return -EINVAL;
if (!pid)
return -EINVAL;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"GetConnectionUnixUser",
&m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "s", name);
if (r < 0)
return r;
r = sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
if (r < 0)
return r;
r = sd_bus_message_read(reply, "u", &u);
if (r < 0)
return r;
if (u == 0)
return -EIO;
*pid = (uid_t) u;
return 0;
}
int sd_bus_add_match(sd_bus *bus, const char *match) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
int r;
if (!bus)
return -EINVAL;
if (!match)
return -EINVAL;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"AddMatch",
&m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "s", match);
if (r < 0)
return r;
return sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
}
int sd_bus_remove_match(sd_bus *bus, const char *match) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
int r;
if (!bus)
return -EINVAL;
if (!match)
return -EINVAL;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"RemoveMatch",
&m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "s", match);
if (r < 0)
return r;
return sd_bus_send_with_reply_and_block(bus, m, (uint64_t) -1, NULL, &reply);
}

166
src/libsystemd-bus/bus-error.c

@ -0,0 +1,166 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include "util.h"
#include "sd-bus.h"
#include "bus-error.h"
void sd_bus_error_free(sd_bus_error *e) {
if (!e)
return;
if (e->need_free) {
free((void*) e->name);
free((void*) e->message);
}
e->name = e->message = NULL;
e->need_free = false;
}
int sd_bus_error_set(sd_bus_error *e, const char *name, const char *format, ...) {
char *n, *m = NULL;
va_list ap;
int r;
if (!e)
return 0;
if (sd_bus_error_is_set(e))
return -EINVAL;
if (!name)
return -EINVAL;
n = strdup(name);
if (!n)
return -ENOMEM;
if (format) {
va_start(ap, format);
r = vasprintf(&m, format, ap);
va_end(ap);
if (r < 0) {
free(n);
return -ENOMEM;
}
}
e->name = n;
e->message = m;
e->need_free = true;
return 0;
}
int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
if (!dest)
return 0;
if (sd_bus_error_is_set(dest))
return -EINVAL;
if (!sd_bus_error_is_set(e))
return 0;
if (e->need_free) {
char *x, *y = NULL;
x = strdup(e->name);
if (!x)
return -ENOMEM;
if (e->message) {
y = strdup(e->message);
if (!y) {
free(x);
return -ENOMEM;
}
}
dest->name = x;
dest->message = y;
dest->need_free = true;
} else
*dest = *e;
return 0;
}
void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
if (!e)
return;
if (sd_bus_error_is_set(e))
return;
e->name = name;
e->message = message;
}
int sd_bus_error_is_set(const sd_bus_error *e) {
if (!e)
return 0;
return e->name || e->message || e->need_free;
}
int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
if (!e)
return 0;
return streq_ptr(e->name, name);
}
int bus_error_to_errno(const sd_bus_error* e) {
/* Better replce this with a gperf table */
if (!e->name)
return -EIO;
if (streq(e->name, "org.freedesktop.DBus.Error.NoMemory"))
return -ENOMEM;
if (streq(e->name, "org.freedesktop.DBus.Error.AuthFailed") ||
streq(e->name, "org.freedesktop.DBus.Error.AccessDenied"))
return -EPERM;
return -EIO;
}
int bus_error_from_errno(sd_bus_error *e, int error) {
if (!e)
return error;
if (error == -ENOMEM)
sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.NoMemory", strerror(-error));
else if (error == -EPERM || error == EACCES)
sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.AccessDenied", strerror(-error));
else
sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Failed", "Operation failed");
return error;
}

27
src/libsystemd-bus/bus-error.h

@ -0,0 +1,27 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-bus.h"
int bus_error_to_errno(const sd_bus_error *e);
int bus_error_from_errno(sd_bus_error *e, int error);

22
src/libsystemd-bus/bus-internal.c

@ -0,0 +1,22 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "bus-internal.h"

101
src/libsystemd-bus/bus-internal.h

@ -0,0 +1,101 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include "hashmap.h"
#include "list.h"
#include "util.h"
#include "sd-bus.h"
#include "bus-error.h"
struct reply_callback {
sd_message_handler_t callback;
void *userdata;
usec_t timeout;
uint64_t serial;
};
struct filter_callback {
sd_message_handler_t callback;
void *userdata;
LIST_FIELDS(struct filter_callback, callbacks);
};
enum bus_state {
BUS_OPENING,
BUS_AUTHENTICATING,
BUS_HELLO,
BUS_RUNNING,
BUS_CLOSED
};
struct sd_bus {
unsigned n_ref;
enum bus_state state;
int fd;
int message_version;
bool can_fds:1;
bool send_hello:1;
void *rbuffer;
size_t rbuffer_size;
sd_bus_message **rqueue;
unsigned rqueue_size;
sd_bus_message **wqueue;
unsigned wqueue_size;
size_t windex;
uint64_t serial;
char *unique_name;
Hashmap *reply_callbacks;
LIST_HEAD(struct filter_callback, filter_callbacks);
union {
struct sockaddr sa;
struct sockaddr_un un;
struct sockaddr_in in;
struct sockaddr_in6 in6;
} sockaddr;
socklen_t sockaddr_size;
sd_id128_t peer;
char *address;
unsigned address_index;
int last_connect_error;
struct iovec auth_iovec[3];
unsigned auth_index;
size_t auth_size;
char *auth_uid;
};

1413
src/libsystemd-bus/bus-message.c

File diff suppressed because it is too large

120
src/libsystemd-bus/bus-message.h

@ -0,0 +1,120 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdbool.h>
#include <byteswap.h>
#include "macro.h"
#include "sd-bus.h"
struct bus_container {
char enclosing;
char *signature;
unsigned index;
uint32_t *array_size;
};
_packed_ struct bus_header {
uint8_t endian;
uint8_t type;
uint8_t flags;
uint8_t version;
uint32_t body_size;
uint32_t serial;
uint32_t fields_size;
};
struct sd_bus_message {
unsigned n_ref;
uint32_t reply_serial;
const char *path;
const char *interface;
const char *member;
const char *destination;
const char *sender;
const char *signature;
sd_bus_error error;
uid_t uid;
gid_t gid;
pid_t pid;
pid_t tid;
bool sealed:1;
bool uid_valid:1;
bool gid_valid:1;
bool free_header:1;
bool free_fields:1;
bool free_body:1;
struct bus_header *header;
void *fields;
void *body;
uint32_t n_fds;
int *fds;
struct bus_container root_container, *sub_containers;
unsigned n_containers;
struct iovec iovec[4];
unsigned n_iovec;
};
#if __BYTE_ORDER == __BIG_ENDIAN
#define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != SD_BUS_BIG_ENDIAN)
#else
#define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != SD_BUS_LITTLE_ENDIAN)
#endif
static inline uint32_t BUS_MESSAGE_BSWAP(sd_bus_message *m, uint32_t u) {
return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_32(u) : u;
}
static inline uint32_t BUS_MESSAGE_SERIAL(sd_bus_message *m) {
return BUS_MESSAGE_BSWAP(m, m->header->serial);
}
static inline uint32_t BUS_MESSAGE_BODY_SIZE(sd_bus_message *m) {
return BUS_MESSAGE_BSWAP(m, m->header->body_size);
}
static inline uint32_t BUS_MESSAGE_FIELDS_SIZE(sd_bus_message *m) {
return BUS_MESSAGE_BSWAP(m, m->header->fields_size);
}
static inline void bus_message_unrefp(sd_bus_message **m) {
sd_bus_message_unref(*m);
}
#define _cleanup_bus_message_unref_ __attribute__((cleanup(bus_message_unrefp)))
int message_parse(sd_bus_message *m);
int message_seal(sd_bus_message *m, uint64_t serial);
void message_dump(sd_bus_message *m);
int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz);

141
src/libsystemd-bus/bus-signature.c

@ -0,0 +1,141 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <util.h>
#include "bus-signature.h"
#include "bus-type.h"
static int signature_element_length_internal(
const char *s,
bool allow_dict_entry,
size_t *l) {
int r;
assert(s);
if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) {
*l = 1;
return 0;
}
if (*s == SD_BUS_TYPE_ARRAY) {
size_t t;
r = signature_element_length_internal(s + 1, true, &t);
if (r < 0)
return r;
*l = t + 1;
return 0;
}
if (*s == SD_BUS_TYPE_STRUCT_BEGIN) {
const char *p = s + 1;
while (*p != SD_BUS_TYPE_STRUCT_END) {
size_t t;
r = signature_element_length_internal(p, false, &t);
if (r < 0)
return r;
p += t;
}
*l = p - s + 1;
return 0;
}
if (*s == SD_BUS_TYPE_DICT_ENTRY_BEGIN && allow_dict_entry) {
const char *p = s + 1;
unsigned n = 0;
while (*p != SD_BUS_TYPE_DICT_ENTRY_END) {
size_t t;
if (n == 0 && !bus_type_is_basic(*p))
return -EINVAL;
r = signature_element_length_internal(p, false, &t);
if (r < 0)
return r;
p += t;
n++;
}
if (n != 2)
return -EINVAL;
*l = p - s + 1;
return 0;
}
return -EINVAL;
}
bool signature_is_single(const char *s) {
int r;
size_t t;
assert(s);
r = signature_element_length(s, &t);
if (r < 0)
return false;
return s[t] == 0;
}
bool signature_is_pair(const char *s) {
assert(s);
if (!bus_type_is_basic(*s))
return false;
return signature_is_single(s + 1);
}
bool signature_is_valid(const char *s, bool allow_dict_entry) {
const char *p;
int r;
assert(s);
p = s;
while (*p) {
size_t t;
r = signature_element_length_internal(p, allow_dict_entry, &t);
if (r < 0)
return false;
p += t;
}
return p - s <= 255;
}
int signature_element_length(const char *s, size_t *l) {
return signature_element_length_internal(s, true, l);
}

31
src/libsystemd-bus/bus-signature.h

@ -0,0 +1,31 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdbool.h>
#include <sys/types.h>
bool signature_is_single(const char *s);
bool signature_is_pair(const char *s);
bool signature_is_valid(const char *s, bool allow_dict_entry);
int signature_element_length(const char *s, size_t *l);

163
src/libsystemd-bus/bus-type.c

@ -0,0 +1,163 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "util.h"
#include "bus-type.h"
bool bus_type_is_valid(char c) {
static const char valid[] = {
SD_BUS_TYPE_BYTE,
SD_BUS_TYPE_BOOLEAN,
SD_BUS_TYPE_INT16,
SD_BUS_TYPE_UINT16,
SD_BUS_TYPE_INT32,
SD_BUS_TYPE_UINT32,
SD_BUS_TYPE_INT64,
SD_BUS_TYPE_UINT64,
SD_BUS_TYPE_DOUBLE,
SD_BUS_TYPE_STRING,
SD_BUS_TYPE_OBJECT_PATH,
SD_BUS_TYPE_SIGNATURE,
SD_BUS_TYPE_ARRAY,
SD_BUS_TYPE_VARIANT,
SD_BUS_TYPE_STRUCT,
SD_BUS_TYPE_DICT_ENTRY,
SD_BUS_TYPE_UNIX_FD
};
return !!memchr(valid, c, sizeof(valid));
}
bool bus_type_is_valid_in_signature(char c) {
static const char valid[] = {
SD_BUS_TYPE_BYTE,
SD_BUS_TYPE_BOOLEAN,
SD_BUS_TYPE_INT16,
SD_BUS_TYPE_UINT16,
SD_BUS_TYPE_INT32,
SD_BUS_TYPE_UINT32,
SD_BUS_TYPE_INT64,
SD_BUS_TYPE_UINT64,
SD_BUS_TYPE_DOUBLE,
SD_BUS_TYPE_STRING,
SD_BUS_TYPE_OBJECT_PATH,
SD_BUS_TYPE_SIGNATURE,
SD_BUS_TYPE_ARRAY,
SD_BUS_TYPE_VARIANT,
SD_BUS_TYPE_STRUCT_BEGIN,
SD_BUS_TYPE_STRUCT_END,
SD_BUS_TYPE_DICT_ENTRY_BEGIN,
SD_BUS_TYPE_DICT_ENTRY_END,
SD_BUS_TYPE_UNIX_FD
};
return !!memchr(valid, c, sizeof(valid));
}
bool bus_type_is_basic(char c) {
static const char valid[] = {
SD_BUS_TYPE_BYTE,
SD_BUS_TYPE_BOOLEAN,
SD_BUS_TYPE_INT16,
SD_BUS_TYPE_UINT16,
SD_BUS_TYPE_INT32,
SD_BUS_TYPE_UINT32,
SD_BUS_TYPE_INT64,
SD_BUS_TYPE_UINT64,
SD_BUS_TYPE_DOUBLE,
SD_BUS_TYPE_STRING,
SD_BUS_TYPE_OBJECT_PATH,
SD_BUS_TYPE_SIGNATURE,
SD_BUS_TYPE_UNIX_FD
};
return !!memchr(valid, c, sizeof(valid));
}
bool bus_type_is_container(char c) {
static const char valid[] = {
SD_BUS_TYPE_ARRAY,
SD_BUS_TYPE_VARIANT,
SD_BUS_TYPE_STRUCT,
SD_BUS_TYPE_DICT_ENTRY
};
return !!memchr(valid, c, sizeof(valid));
}
int bus_type_get_alignment(char c) {
switch (c) {
case SD_BUS_TYPE_BYTE:
case SD_BUS_TYPE_SIGNATURE:
case SD_BUS_TYPE_VARIANT:
return 1;
case SD_BUS_TYPE_INT16:
case SD_BUS_TYPE_UINT16:
return 2;
case SD_BUS_TYPE_BOOLEAN:
case SD_BUS_TYPE_INT32:
case SD_BUS_TYPE_UINT32:
case SD_BUS_TYPE_STRING:
case SD_BUS_TYPE_OBJECT_PATH:
case SD_BUS_TYPE_ARRAY:
case SD_BUS_TYPE_UNIX_FD:
return 4;
case SD_BUS_TYPE_INT64:
case SD_BUS_TYPE_UINT64:
case SD_BUS_TYPE_DOUBLE:
case SD_BUS_TYPE_STRUCT:
case SD_BUS_TYPE_STRUCT_BEGIN:
case SD_BUS_TYPE_DICT_ENTRY:
case SD_BUS_TYPE_DICT_ENTRY_BEGIN:
return 8;
}
return -EINVAL;
}
int bus_type_get_size(char c) {
switch (c) {
case SD_BUS_TYPE_BYTE:
return 1;
case SD_BUS_TYPE_INT16:
case SD_BUS_TYPE_UINT16:
return 2;
case SD_BUS_TYPE_BOOLEAN:
case SD_BUS_TYPE_INT32:
case SD_BUS_TYPE_UINT32:
case SD_BUS_TYPE_UNIX_FD:
return 4;
case SD_BUS_TYPE_INT64:
case SD_BUS_TYPE_UINT64:
case SD_BUS_TYPE_DOUBLE:
return 8;
}
return -EINVAL;
}

34
src/libsystemd-bus/bus-type.h

@ -0,0 +1,34 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdbool.h>
#include "sd-bus.h"
#include "sd-bus-protocol.h"
bool bus_type_is_valid(char c);
bool bus_type_is_valid_in_signature(char c);
bool bus_type_is_basic(char c);
bool bus_type_is_container(char c);
int bus_type_get_alignment(char c);
int bus_type_get_size(char c);

68
src/libsystemd-bus/busctl.c

@ -0,0 +1,68 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-bus.h"
int main(int argc, char *argv[]) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
_cleanup_strv_free_ char **l = NULL;
char **i;
int r;
r = bus_open_system(&bus);
if (r < 0) {
log_error("Failed to connect to bus: %s", strerror(-r));
goto fail;
}
r = sd_bus_list_names(bus, &l);
if (r < 0) {
log_error("Failed to list names: %s", strerror(-r));
goto fail;
}
STRV_FOREACH(i, l) {
_cleanup_free_ char *owner = NULL;
pid_t pid = 0;
uid_t uid;
bool uid_valid;
r = sd_bus_get_owner(bus, *i, &owner);
if (r == -ENXIO)
continue;
r = sd_get_owner_pid(bus, *i, &pid);
if (r == -ENXIO)
continue;
r = sd_get_owner_uid(bus, *i, &pid);
if (r == -ENXIO)
continue;
uid_valid = r >= 0;
printf("%s (%s) %llu %llu\n", *i, owner, (unsigned long long) pid, (unsigned long long) uid);
}
r = 0;
fail:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

96
src/libsystemd-bus/sd-bus-protocol.h

@ -0,0 +1,96 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#ifndef foosdbusprotocolhfoo
#define foosdbusprotocolhfoo
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/* Types of message */
#define SD_BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
enum {
_SD_BUS_MESSAGE_TYPE_INVALID = 0,
SD_BUS_MESSAGE_TYPE_METHOD_CALL,
SD_BUS_MESSAGE_TYPE_METHOD_RETURN,
SD_BUS_MESSAGE_TYPE_METHOD_ERROR,
SD_BUS_MESSAGE_TYPE_SIGNAL,
_SD_BUS_MESSAGE_TYPE_MAX
};
/* Primitive types */
enum {
_SD_BUS_TYPE_INVALID = 0,
SD_BUS_TYPE_BYTE = 'y',
SD_BUS_TYPE_BOOLEAN = 'b',
SD_BUS_TYPE_INT16 = 'n',
SD_BUS_TYPE_UINT16 = 'q',
SD_BUS_TYPE_INT32 = 'i',
SD_BUS_TYPE_UINT32 = 'u',
SD_BUS_TYPE_INT64 = 'x',
SD_BUS_TYPE_UINT64 = 't',
SD_BUS_TYPE_DOUBLE = 'd',
SD_BUS_TYPE_STRING = 's',
SD_BUS_TYPE_OBJECT_PATH = 'o',
SD_BUS_TYPE_SIGNATURE = 'g',
SD_BUS_TYPE_UNIX_FD = 'h',
SD_BUS_TYPE_ARRAY = 'a',
SD_BUS_TYPE_VARIANT = 'v',
SD_BUS_TYPE_STRUCT = 'r', /* not actually used in signatures */
SD_BUS_TYPE_STRUCT_BEGIN = '(',
SD_BUS_TYPE_STRUCT_END = ')',
SD_BUS_TYPE_DICT_ENTRY = 'e', /* not actually used in signatures */
SD_BUS_TYPE_DICT_ENTRY_BEGIN = '{',
SD_BUS_TYPE_DICT_ENTRY_END = '}',
};
/* Endianess */
enum {
_SD_BUS_INVALID_ENDIAN = 0,
SD_BUS_LITTLE_ENDIAN = 'l',
SD_BUS_BIG_ENDIAN = 'B'
};
/* Flags */
enum {
SD_BUS_MESSAGE_NO_REPLY_EXPECTED = 1,
SD_BUS_MESSAGE_NO_AUTO_START = 2
};
/* Header fields */
enum {
_SD_BUS_MESSAGE_HEADER_INVALID = 0,
SD_BUS_MESSAGE_HEADER_PATH,
SD_BUS_MESSAGE_HEADER_INTERFACE,
SD_BUS_MESSAGE_HEADER_MEMBER,
SD_BUS_MESSAGE_HEADER_ERROR_NAME,
SD_BUS_MESSAGE_HEADER_REPLY_SERIAL,
SD_BUS_MESSAGE_HEADER_DESTINATION,
SD_BUS_MESSAGE_HEADER_SENDER,
SD_BUS_MESSAGE_HEADER_SIGNATURE,
SD_BUS_MESSAGE_HEADER_UNIX_FDS,
_SD_BUS_MESSAGE_HEADER_MAX
};
#endif

1437
src/libsystemd-bus/sd-bus.c

File diff suppressed because it is too large

135
src/libsystemd-bus/sd-bus.h

@ -0,0 +1,135 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#ifndef foosdbushfoo
#define foosdbushfoo
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
#include <sys/types.h>
#include "sd-bus-protocol.h"
typedef struct sd_bus sd_bus;
typedef struct sd_bus_message sd_bus_message;
typedef struct {
const char *name;
const char *message;
int need_free;
} sd_bus_error;
typedef int (*sd_message_handler_t)(sd_bus *bus, sd_bus_message *m, void *userdata);
/* Connections */
int sd_bus_open_system(sd_bus **ret);
int sd_bus_open_user(sd_bus **ret);
int sd_bus_open_address(const char *address, sd_bus **ret);
int sd_bus_open_fd(int fd, sd_bus **ret);
void sd_bus_close(sd_bus *bus);
sd_bus *sd_bus_ref(sd_bus *bus);
sd_bus *sd_bus_unref(sd_bus *bus);
int sd_bus_is_running(sd_bus *bus);
int sd_bus_can_send(sd_bus *bus, char type);
int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial);
int sd_bus_send_with_reply(sd_bus *bus, sd_bus_message *m, sd_message_handler_t callback, void *userdata, uint64_t usec, uint64_t *serial);
int sd_bus_send_with_reply_cancel(sd_bus *bus, uint64_t serial);
int sd_bus_send_with_reply_and_block(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *error, sd_bus_message **r);
int sd_bus_get_fd(sd_bus *bus);
int sd_bus_get_events(sd_bus *bus);
int sd_bus_process(sd_bus *bus, sd_bus_message **r);
int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
int sd_bus_flush(sd_bus *bus);
int sd_bus_add_filter(sd_bus *bus, sd_message_handler_t callback, void *userdata);
int sd_bus_remove_filter(sd_bus *bus, sd_message_handler_t callback, void *userdata);
/* Message object */
int sd_bus_message_new_signal(sd_bus *bus, const char *path, const char *interface, const char *member, sd_bus_message **m);
int sd_bus_message_new_method_call(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_message **m);
int sd_bus_message_new_method_return(sd_bus *bus, sd_bus_message *call, sd_bus_message **m);
int sd_bus_message_new_method_error(sd_bus *bus, sd_bus_message *call, const sd_bus_error *e, sd_bus_message **m);
sd_bus_message* sd_bus_message_ref(sd_bus_message *m);
sd_bus_message* sd_bus_message_unref(sd_bus_message *m);
int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type);
int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial);
int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial);
int sd_bus_message_get_no_reply(sd_bus_message *m);
const char *sd_bus_message_get_path(sd_bus_message *m);
const char *sd_bus_message_get_interface(sd_bus_message *m);
const char *sd_bus_message_get_member(sd_bus_message *m);
const char *sd_bus_message_get_destination(sd_bus_message *m);
const char *sd_bus_message_get_sender(sd_bus_message *m);
const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m);
int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid);
int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid);
int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid);
int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid);
int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member);
int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member);
int sd_bus_message_is_method_error(sd_bus_message *m, const char *name);
int sd_bus_message_set_no_reply(sd_bus_message *m, int b);
int sd_bus_message_set_destination(sd_bus_message *m, const char *destination);
int sd_bus_message_append(sd_bus_message *m, const char *types, ...);
int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p);
int sd_bus_message_open_container(sd_bus_message *m, char type, const char *contents);
int sd_bus_message_close_container(sd_bus_message *m);
int sd_bus_message_read_type(sd_bus_message *m, char *type, char *element, size_t *length);
int sd_bus_message_read_basic(sd_bus_message *m, char type, char element, const void **p, size_t *length);
int sd_bus_message_read(sd_bus_message *m, const char *types, ...);
/* Bus management */
const char *sd_bus_get_unique_name(sd_bus *bus);
int sd_bus_request_name(sd_bus *bus, const char *name, int flags);
int sd_bus_release_name(sd_bus *bus, const char *name);
int sd_bus_list_names(sd_bus *bus, char ***l);
int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner);
int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid);
int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid);
int sd_bus_add_match(sd_bus *bus, const char *match);
int sd_bus_remove_match(sd_bus *bus, const char *match);
/* Error objects */
#define SD_BUS_ERROR_INIT (NULL, NULL, false)
void sd_bus_error_free(sd_bus_error *e);
int sd_bus_error_set(sd_bus_error *e, const char *name, const char *format, ...);
void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message);
int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e);
int sd_bus_error_is_set(const sd_bus_error *e);
int sd_bus_error_has_name(const sd_bus_error *e, const char *name);
#endif

129
src/libsystemd-bus/test-bus-marshal.c

@ -0,0 +1,129 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <assert.h>
#include <stdlib.h>
#include <byteswap.h>
#ifdef HAVE_GLIB
#include <gio/gio.h>
#endif
#include <dbus.h>
#include "log.h"
#include "util.h"
#include "sd-bus.h"
#include "bus-message.h"
int main(int argc, char *argv[]) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
int r;
const char *x, *y, *z, *a, *b, *c;
uint8_t u, v;
void *buffer = NULL;
size_t sz;
char *h;
r = sd_bus_message_new_method_call(NULL, "foobar.waldo", "/", "foobar.waldo", "Piep", &m);
assert_se(r >= 0);
r = sd_bus_message_append(m, "s", "a string");
assert_se(r >= 0);
r = sd_bus_message_append(m, "as", 2, "string #1", "string #2");
assert_se(r >= 0);
r = sd_bus_message_append(m, "sass", "foobar", 5, "foo", "bar", "waldo", "piep", "pap", "after");
assert_se(r >= 0);
r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo");
assert_se(r >= 0);
r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
assert_se(r >= 0);
r = sd_bus_message_open_container(m, 'a', "s");
assert_se(r >= 0);
r = sd_bus_message_append_basic(m, 's', "foobar");
assert_se(r >= 0);