bus-util.c revision 460ed929cf2081e5a445b9e8fedbbaf0da7eff44
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering This file is part of systemd.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Copyright 2013 Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering systemd is free software; you can redistribute it and/or modify it
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering under the terms of the GNU Lesser General Public License as published by
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering (at your option) any later version.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering systemd is distributed in the hope that it will be useful, but
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Lesser General Public License for more details.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering You should have received a copy of the GNU Lesser General Public License
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringint bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* We unregister the name here and then wait for the
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * NameOwnerChanged signal for this event to arrive before we
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * quit. We do this in order to make sure that any queued
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering * requests are still processed before we really exit. */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering r = sd_bus_get_unique_name(bus, &unique);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "sender='org.freedesktop.DBus',"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "type='signal',"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "interface='org.freedesktop.DBus',"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "member='NameOwnerChanged',"
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Fallback for dbus1 connections: we
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * unregister the name and wait for the
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * response to come through for it */
90b2de37b80603168f4e9c9c81cff7eea4efa21aZbigniew Jędrzejewski-Szmek /* Inform the service manager that we
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * are going down, so that it will
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * queue all further start requests,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * instead of assuming we are already
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = bus_async_unregister_and_exit(e, bus, name);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringint bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering _cleanup_bus_message_unref_ sd_bus_message *rep = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "org.freedesktop.DBus",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "org.freedesktop.DBus",
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "NameHasOwner",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_message_read_basic(rep, 'b', &has_owner);
cc3773810855956bad92337cee8fa193584ab62eLennart Poetteringstatic int check_good_user(sd_bus_message *m, uid_t good_user) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Don't trust augmented credentials for authorization */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering r = sd_bus_creds_get_euid(creds, &sender_uid);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Tests non-interactively! */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_query_sender_privilege(call, capability);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else if (r > 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *request = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering int authorized = false, challenge = false;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *sender, **k, **v;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering sender = sd_bus_message_get_sender(call);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "org.freedesktop.PolicyKit1",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "org.freedesktop.PolicyKit1.Authority",
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "CheckAuthorization");
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "system-bus-name", 1, "name", "s", sender,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_message_open_container(request, 'a', "{ss}");
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_message_append(request, "{ss}", *k, *v);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_message_close_container(request);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_message_append(request, "us", 0, NULL);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_call(call->bus, request, 0, e, &reply);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Treat no PK available as access denied */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic void async_polkit_query_free(AsyncPolkitQuery *q) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering r = sd_bus_message_rewind(q->request, true);
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering r = sd_bus_reply_method_errno(q->request, r, NULL);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering r = q->callback(q->request, q->userdata, &error_buffer);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering r = bus_maybe_reply_error(q->request, r, &error_buffer);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering const char *sender, **k, **v;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering /* This is the second invocation of this function, and
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * there's already a response from polkit, let's
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * process it */
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (sd_bus_message_is_method_error(q->reply, NULL)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Copy error from polkit reply */
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering /* Treat no PK available as access denied */
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = sd_bus_query_sender_privilege(call, capability);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else if (r > 0)
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering if (sd_bus_get_current_message(call->bus) != call)
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen callback = sd_bus_get_current_handler(call->bus);
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen userdata = sd_bus_get_current_userdata(call->bus);
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen sender = sd_bus_message_get_sender(call);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering c = sd_bus_message_get_allow_interactive_authorization(call);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering r = hashmap_ensure_allocated(registry, NULL);
&pk,
pk,
action);
return -ENOMEM;
return -EACCES;
#ifdef ENABLE_POLKIT
AsyncPolkitQuery *q;
socklen_t l;
int fd;
assert(c);
if (fd < 0)
return fd;
l = sizeof(struct ucred);
return -errno;
if (l != sizeof(struct ucred))
return -E2BIG;
return -EPERM;
if (geteuid() != 0)
return -ENOMEM;
if (!ee)
return -ENOMEM;
return -ENOMEM;
char type;
const char *contents;
switch (type) {
case SD_BUS_TYPE_STRING: {
if (!escaped)
return -ENOMEM;
case SD_BUS_TYPE_BOOLEAN: {
case SD_BUS_TYPE_UINT64: {
uint64_t u;
if (t || all)
case SD_BUS_TYPE_INT64: {
int64_t i;
case SD_BUS_TYPE_UINT32: {
uint32_t u;
case SD_BUS_TYPE_INT32: {
int32_t i;
case SD_BUS_TYPE_DOUBLE: {
case SD_BUS_TYPE_ARRAY:
bool first = true;
const char *str;
if (first)
if (!escaped)
return -ENOMEM;
first = false;
const uint8_t *u;
size_t n;
if (all || n > 0) {
uint32_t *u;
size_t n;
if (all || n > 0) {
int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
dest,
path,
&error,
&reply,
const char *name;
const char *contents;
if (all)
int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
size_t n;
*p = SD_ID128_NULL;
return -EINVAL;
static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
char type;
switch (type) {
case SD_BUS_TYPE_STRING: {
char **p = userdata;
if (isempty(s))
r = free_and_strdup(p, s);
case SD_BUS_TYPE_ARRAY: {
char ***p = userdata;
r = bus_message_read_strv_extend(m, &l);
strv_free(*p);
l = NULL;
case SD_BUS_TYPE_BOOLEAN: {
bool *p = userdata;
case SD_BUS_TYPE_UINT32: {
uint64_t u;
case SD_BUS_TYPE_UINT64: {
uint64_t t;
sd_bus_message *m,
void *userdata) {
assert(m);
const char *member;
const char *contents;
if (prop) {
r = sd_bus_message_exit_container(m);
r = sd_bus_message_exit_container(m);
return sd_bus_message_exit_container(m);
sd_bus_message *m,
void *userdata) {
const char *member;
int r, invalidated, i;
assert(m);
invalidated = 0;
++invalidated;
r = sd_bus_message_exit_container(m);
return invalidated;
const char *destination,
const char *path,
void *userdata) {
r = sd_bus_call_method(
bus,
path,
&error,
switch (transport) {
case BUS_TRANSPORT_LOCAL:
if (user)
case BUS_TRANSPORT_REMOTE:
case BUS_TRANSPORT_MACHINE:
int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
switch (transport) {
case BUS_TRANSPORT_LOCAL:
if (user)
case BUS_TRANSPORT_REMOTE:
case BUS_TRANSPORT_MACHINE:
const char *path,
const char *interface,
const char *property,
void *userdata,
int b = *(bool*) userdata;
const char *path,
const char *interface,
const char *property,
void *userdata,
const char *path,
const char *interface,
const char *property,
void *userdata,
const char *path,
const char *interface,
const char *property,
void *userdata,
int bus_log_parse_error(int r) {
int bus_log_create_error(int r) {
assert(u);
return sd_bus_message_read(
&u->id,
&u->description,
&u->load_state,
&u->active_state,
&u->sub_state,
&u->following,
&u->unit_path,
&u->job_id,
&u->job_type,
&u->job_path);
assert(m);
if (!eq) {
return -EINVAL;
eq ++;
return bus_log_create_error(r);
double percent;
return -EINVAL;
return bus_log_create_error(r);
return -EINVAL;
return bus_log_create_error(r);
return bus_log_create_error(r);
return -EINVAL;
return -EINVAL;
uint64_t n;
return -EINVAL;
uint64_t u;
return -EINVAL;
uint64_t u;
return -EINVAL;
int level;
if (level < 0) {
return -EINVAL;
int facility;
if (facility < 0) {
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
uint64_t u;
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
int32_t i;
return -EINVAL;
int sig;
if (sig < 0) {
return -EINVAL;
usec_t u;
return -EINVAL;
return -EINVAL;
return bus_log_create_error(r);
typedef struct BusWaitForJobs {
char *name;
char *result;
assert(m);
char *found;
assert(m);
assert(d);
if (!found)
free(d);
return -ENOMEM;
r = sd_bus_add_match(
bus,
&d->slot_job_removed,
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"path='/org/freedesktop/systemd1'" :
"interface='org.freedesktop.systemd1.Manager',"
"path='/org/freedesktop/systemd1'",
match_job_removed, d);
r = sd_bus_add_match(
bus,
&d->slot_disconnected,
match_disconnected, d);
*ret = d;
d = NULL;
assert(d);
if (!dbus_path)
return -ENOMEM;
"org.freedesktop.systemd1",
"org.freedesktop.systemd1.Service",
NULL,
result);
} explanations [] = {
log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
goto finish;
log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
if (!quiet) {
if (d->name) {
r = -ECANCELED;
r = -ETIME;
r = -EIO;
r = -ENOEXEC;
r = -EPROTO;
r = -EOPNOTSUPP;
r = -EIO;
assert(d);
if (d->result) {
assert(d);
return log_oom();
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
return bus_log_parse_error(r);
if (!quiet) {
r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(m);
return bus_log_parse_error(r);
* template '/prefix/sender_id/external_id' and returns the new path in
int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
if (!sender_id) {
if (!external_id) {
if (!sender_label)
return -ENOMEM;
if (!external_label)
return -ENOMEM;
return -ENOMEM;
*ret_path = p;
int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
return -ENOMEM;
bool is_kdbus_wanted(void) {
#ifdef ENABLE_KDBUS
const bool configured = true;
const bool configured = false;
return configured;
bool is_kdbus_available(void) {
if (!is_kdbus_wanted())
if (fd < 0)
const char *path,
const char *interface,
const char *property,
void *userdata,
uint64_t u;
rlim_t x;
if (rl)
assert(z >= 0);